📄 oscar.c
字号:
/* * gaim * * Some code copyright (C) 1998-1999, Mark Spencer <markster@marko.net> * Some code copyright (C) 1999-2001, Eric Warmenhoven * Some code copyright (C) 2001-2003, Sean Egan * Some code copyright (C) 2001-2004, Mark Doliner <thekingant@users.sourceforge.net> * * Most libfaim code copyright (C) 1998-2001 Adam Fritzler <afritz@auk.cx> * Some libfaim code copyright (C) 2001-2004 Mark Doliner <thekingant@users.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */#include "internal.h"#include "account.h"#include "accountopt.h"#include "buddyicon.h"#include "conversation.h"#include "core.h"#include "debug.h"#include "ft.h"#include "imgstore.h"#include "network.h"#include "notify.h"#include "privacy.h"#include "prpl.h"#include "proxy.h"#include "request.h"#include "util.h"#include "version.h"#include "aim.h"#include "md5.h"#define UC_AOL 0x02#define UC_ADMIN 0x04#define UC_UNCONFIRMED 0x08#define UC_NORMAL 0x10#define UC_AB 0x20#define UC_WIRELESS 0x40#define AIMHASHDATA "http://gaim.sourceforge.net/aim_data.php3"#define OSCAR_CONNECT_STEPS 6#define OSCAR_DEFAULT_CUSTOM_ENCODING "ISO-8859-1"static GaimPlugin *my_protocol = NULL;static int caps_aim = AIM_CAPS_CHAT | AIM_CAPS_BUDDYICON | AIM_CAPS_DIRECTIM | AIM_CAPS_SENDFILE | AIM_CAPS_INTEROPERATE | AIM_CAPS_ICHAT;static int caps_icq = AIM_CAPS_BUDDYICON | AIM_CAPS_DIRECTIM | AIM_CAPS_SENDFILE | AIM_CAPS_ICQUTF8 | AIM_CAPS_INTEROPERATE | AIM_CAPS_ICHAT;static fu8_t features_aim[] = {0x01, 0x01, 0x01, 0x02};static fu8_t features_icq[] = {0x01, 0x06};static fu8_t ck[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};typedef struct _OscarData OscarData;struct _OscarData { aim_session_t *sess; aim_conn_t *conn; guint cnpa; guint paspa; guint emlpa; guint icopa; gboolean iconconnecting; gboolean set_icon; GSList *create_rooms; gboolean conf; gboolean reqemail; gboolean setemail; char *email; gboolean setnick; char *newsn; gboolean chpass; char *oldp; char *newp; GSList *oscar_chats; GSList *direct_ims; GSList *file_transfers; GHashTable *buddyinfo; GSList *requesticon; gboolean killme; gboolean icq; guint icontimer; guint getblisttimer; guint getinfotimer; struct { guint maxwatchers; /* max users who can watch you */ guint maxbuddies; /* max users you can watch */ guint maxgroups; /* max groups in server list */ guint maxpermits; /* max users on permit list */ guint maxdenies; /* max users on deny list */ guint maxsiglen; /* max size (bytes) of profile */ guint maxawaymsglen; /* max size (bytes) of posted away message */ } rights;};struct create_room { char *name; int exchange;};struct chat_connection { char *name; char *show; /* AOL did something funny to us */ fu16_t exchange; fu16_t instance; int fd; /* this is redundant since we have the conn below */ aim_conn_t *conn; int inpa; int id; GaimConnection *gc; /* i hate this. */ GaimConversation *conv; /* bah. */ int maxlen; int maxvis;};struct oscar_direct_im { GaimConnection *gc; char name[80]; int watcher; aim_conn_t *conn; gboolean connected; gboolean gpc_pend; gboolean killme; gboolean donttryagain;};struct ask_direct { GaimConnection *gc; char *sn; char ip[64]; fu8_t cookie[8]; gboolean donttryagain;};/* * Various PRPL-specific buddy info that we want to keep track of * Some other info is maintained by locate.c, and I'd like to move * the rest of this to libfaim, mostly im.c */struct buddyinfo { gboolean typingnot; gchar *availmsg; fu32_t ipaddr; unsigned long ico_me_len; unsigned long ico_me_csum; time_t ico_me_time; gboolean ico_informed; unsigned long ico_len; unsigned long ico_csum; time_t ico_time; gboolean ico_need; gboolean ico_sent;};struct name_data { GaimConnection *gc; gchar *name; gchar *nick;};static char *msgerrreason[] = { N_("Invalid error"), N_("Invalid SNAC"), N_("Rate to host"), N_("Rate to client"), N_("Not logged in"), N_("Service unavailable"), N_("Service not defined"), N_("Obsolete SNAC"), N_("Not supported by host"), N_("Not supported by client"), N_("Refused by client"), N_("Reply too big"), N_("Responses lost"), N_("Request denied"), N_("Busted SNAC payload"), N_("Insufficient rights"), N_("In local permit/deny"), N_("Too evil (sender)"), N_("Too evil (receiver)"), N_("User temporarily unavailable"), N_("No match"), N_("List overflow"), N_("Request ambiguous"), N_("Queue full"), N_("Not while on AOL")};static int msgerrreasonlen = 25;/* All the libfaim->gaim callback functions */static int gaim_parse_auth_resp (aim_session_t *, aim_frame_t *, ...);static int gaim_parse_login (aim_session_t *, aim_frame_t *, ...);static int gaim_handle_redirect (aim_session_t *, aim_frame_t *, ...);static int gaim_info_change (aim_session_t *, aim_frame_t *, ...);static int gaim_account_confirm (aim_session_t *, aim_frame_t *, ...);static int gaim_parse_oncoming (aim_session_t *, aim_frame_t *, ...);static int gaim_parse_offgoing (aim_session_t *, aim_frame_t *, ...);static int gaim_parse_incoming_im(aim_session_t *, aim_frame_t *, ...);static int gaim_parse_misses (aim_session_t *, aim_frame_t *, ...);static int gaim_parse_clientauto (aim_session_t *, aim_frame_t *, ...);static int gaim_parse_userinfo (aim_session_t *, aim_frame_t *, ...);static int gaim_reqinfo_timeout (aim_session_t *, aim_frame_t *, ...);static int gaim_parse_motd (aim_session_t *, aim_frame_t *, ...);static int gaim_chatnav_info (aim_session_t *, aim_frame_t *, ...);static int gaim_conv_chat_join (aim_session_t *, aim_frame_t *, ...);static int gaim_conv_chat_leave (aim_session_t *, aim_frame_t *, ...);static int gaim_conv_chat_info_update (aim_session_t *, aim_frame_t *, ...);static int gaim_conv_chat_incoming_msg(aim_session_t *, aim_frame_t *, ...);static int gaim_email_parseupdate(aim_session_t *, aim_frame_t *, ...);static int gaim_icon_error (aim_session_t *, aim_frame_t *, ...);static int gaim_icon_parseicon (aim_session_t *, aim_frame_t *, ...);static int oscar_icon_req (aim_session_t *, aim_frame_t *, ...);static int gaim_parse_msgack (aim_session_t *, aim_frame_t *, ...);static int gaim_parse_ratechange (aim_session_t *, aim_frame_t *, ...);static int gaim_parse_evilnotify (aim_session_t *, aim_frame_t *, ...);static int gaim_parse_searcherror(aim_session_t *, aim_frame_t *, ...);static int gaim_parse_searchreply(aim_session_t *, aim_frame_t *, ...);static int gaim_bosrights (aim_session_t *, aim_frame_t *, ...);static int gaim_connerr (aim_session_t *, aim_frame_t *, ...);static int conninitdone_admin (aim_session_t *, aim_frame_t *, ...);static int conninitdone_bos (aim_session_t *, aim_frame_t *, ...);static int conninitdone_chatnav (aim_session_t *, aim_frame_t *, ...);static int conninitdone_chat (aim_session_t *, aim_frame_t *, ...);static int conninitdone_email (aim_session_t *, aim_frame_t *, ...);static int conninitdone_icon (aim_session_t *, aim_frame_t *, ...);static int gaim_parse_msgerr (aim_session_t *, aim_frame_t *, ...);static int gaim_parse_mtn (aim_session_t *, aim_frame_t *, ...);static int gaim_parse_locaterights(aim_session_t *, aim_frame_t *, ...);static int gaim_parse_buddyrights(aim_session_t *, aim_frame_t *, ...);static int gaim_parse_locerr (aim_session_t *, aim_frame_t *, ...);static int gaim_icbm_param_info (aim_session_t *, aim_frame_t *, ...);static int gaim_parse_genericerr (aim_session_t *, aim_frame_t *, ...);static int gaim_memrequest (aim_session_t *, aim_frame_t *, ...);static int gaim_selfinfo (aim_session_t *, aim_frame_t *, ...);static int gaim_offlinemsg (aim_session_t *, aim_frame_t *, ...);static int gaim_offlinemsgdone (aim_session_t *, aim_frame_t *, ...);static int gaim_icqalias (aim_session_t *, aim_frame_t *, ...);static int gaim_icqinfo (aim_session_t *, aim_frame_t *, ...);static int gaim_popup (aim_session_t *, aim_frame_t *, ...);#ifndef NOSSIstatic int gaim_ssi_parseerr (aim_session_t *, aim_frame_t *, ...);static int gaim_ssi_parserights (aim_session_t *, aim_frame_t *, ...);static int gaim_ssi_parselist (aim_session_t *, aim_frame_t *, ...);static int gaim_ssi_parseack (aim_session_t *, aim_frame_t *, ...);static int gaim_ssi_parseadd (aim_session_t *, aim_frame_t *, ...);static int gaim_ssi_authgiven (aim_session_t *, aim_frame_t *, ...);static int gaim_ssi_authrequest (aim_session_t *, aim_frame_t *, ...);static int gaim_ssi_authreply (aim_session_t *, aim_frame_t *, ...);static int gaim_ssi_gotadded (aim_session_t *, aim_frame_t *, ...);#endif/* for DirectIM/image transfer */static int gaim_odc_initiate (aim_session_t *, aim_frame_t *, ...);static int gaim_odc_incoming (aim_session_t *, aim_frame_t *, ...);static int gaim_odc_typing (aim_session_t *, aim_frame_t *, ...);static int gaim_odc_update_ui (aim_session_t *, aim_frame_t *, ...);/* for file transfer */static int oscar_sendfile_estblsh(aim_session_t *, aim_frame_t *, ...);static int oscar_sendfile_prompt (aim_session_t *, aim_frame_t *, ...);static int oscar_sendfile_ack (aim_session_t *, aim_frame_t *, ...);static int oscar_sendfile_done (aim_session_t *, aim_frame_t *, ...);/* for icons */static gboolean gaim_icon_timerfunc(gpointer data);/* just because */static void oscar_callback(gpointer data, gint source, GaimInputCondition condition);static void oscar_direct_im_initiate(GaimConnection *gc, const char *who, const char *cookie);/* remove these at some point? *//* Because I don't like forward declarations? I think that was why... */static void oscar_set_info(GaimConnection *gc, const char *text);static void oscar_set_away(GaimConnection *gc, const char *state, const char *message);static void oscar_free_name_data(struct name_data *data) { g_free(data->name); g_free(data->nick); g_free(data);}static void oscar_free_buddyinfo(void *data) { struct buddyinfo *bi = data; g_free(bi->availmsg); g_free(bi);}static fu32_t oscar_charset_check(const char *utf8){ int i = 0; int charset = AIM_CHARSET_ASCII; /* Determine how we can send this message. Per the warnings elsewhere * in this file, these little checks determine the simplest encoding * we can use for a given message send using it. */ while (utf8[i]) { if ((unsigned char)utf8[i] > 0x7f) { /* not ASCII! */ charset = AIM_CHARSET_CUSTOM; break; } i++; } while (utf8[i]) { /* ISO-8859-1 is 0x00-0xbf in the first byte * followed by 0xc0-0xc3 in the second */ if ((unsigned char)utf8[i] < 0x80) { i++; continue; } else if (((unsigned char)utf8[i] & 0xfc) == 0xc0 && ((unsigned char)utf8[i + 1] & 0xc0) == 0x80) { i += 2; continue; } charset = AIM_CHARSET_UNICODE; break; } return charset;}/* * Take a string of the form charset="bleh" where bleh is * one of us-ascii, utf-8, iso-8859-1, or unicode-2-0, and * return a newly allocated string containing bleh. */static gchar *oscar_encoding_extract(const char *encoding){ gchar *ret = NULL; char *begin, *end; g_return_val_if_fail(encoding != NULL, NULL); /* Make sure encoding begins with charset= */ if (strncmp(encoding, "text/aolrtf; charset=", 21)) return NULL; begin = strchr(encoding, '"'); end = strrchr(encoding, '"'); if ((begin == NULL) || (end == NULL) || (begin >= end)) return NULL; ret = g_strndup(begin+1, (end-1) - begin); return ret;}static gchar *oscar_encoding_to_utf8(const char *encoding, const char *text, int textlen){ gchar *utf8 = NULL; if ((encoding == NULL) || encoding[0] == '\0') { gaim_debug_info("oscar", "Empty encoding, assuming UTF-8\n"); } else if (!strcmp(encoding, "iso-8859-1") || !strcmp(encoding, "ISO-8859-1-Windows-3.1-Latin-1")) { utf8 = g_convert(text, textlen, "UTF-8", "ISO-8859-1", NULL, NULL, NULL); } else if (!strcmp(encoding, "unicode-2-0")) { utf8 = g_convert(text, textlen, "UTF-8", "UCS-2BE", NULL, NULL, NULL); } else if (strcmp(encoding, "us-ascii") && strcmp(encoding, "utf-8")) { gaim_debug_warning("oscar", "Unrecognized character encoding \"%s\", " "attempting to convert to UTF-8 anyway\n", encoding); utf8 = g_convert(text, textlen, "UTF-8", encoding, NULL, NULL, NULL); } /* * If utf8 is still NULL then either the encoding is us-ascii/utf-8 or * we have been unable to convert the text to utf-8 from the encoding * that was specified. So we check if the text is valid utf-8 then * just copy it. */ if (utf8 == NULL) { if (textlen != 0 && *text != '\0' && !g_utf8_validate(text, textlen, NULL)) utf8 = g_strdup(_("(There was an error receiving this message. The buddy you are speaking to most likely has a buggy client.)")); else utf8 = g_strndup(text, textlen); } return utf8;}static gchar *gaim_plugin_oscar_convert_to_utf8(const fu8_t *data, fu16_t datalen, const char *charsetstr, gboolean fallback){ gchar *ret = NULL; GError *err = NULL; if ((charsetstr == NULL) || (*charsetstr == '\0')) return NULL; if (strcasecmp("UTF-8", charsetstr)) { if (fallback) ret = g_convert_with_fallback(data, datalen, "UTF-8", charsetstr, "?", NULL, NULL, &err); else ret = g_convert(data, datalen, "UTF-8", charsetstr, NULL, NULL, &err); if (err != NULL) { gaim_debug_warning("oscar", "Conversation from %s failed: %s.\n", charsetstr, err->message); g_error_free(err); } } else { if (g_utf8_validate(data, datalen, NULL)) ret = g_strndup(data, datalen);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -