📄 oscar.c
字号:
/* * purple * * 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-2005, Mark Doliner <thekingant@users.sourceforge.net> * Some code copyright (C) 2005, Jonathan Clark <ardentlygnarly@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 "cipher.h"#include "conversation.h"#include "core.h"#include "debug.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 "oscarcommon.h"#include "oscar.h"#include "peer.h"#define OSCAR_STATUS_ID_INVISIBLE "invisible"#define OSCAR_STATUS_ID_OFFLINE "offline"#define OSCAR_STATUS_ID_AVAILABLE "available"#define OSCAR_STATUS_ID_AWAY "away"#define OSCAR_STATUS_ID_DND "dnd"#define OSCAR_STATUS_ID_NA "na"#define OSCAR_STATUS_ID_OCCUPIED "occupied"#define OSCAR_STATUS_ID_FREE4CHAT "free4chat"#define OSCAR_STATUS_ID_CUSTOM "custom"#define OSCAR_STATUS_ID_MOBILE "mobile"#define AIMHASHDATA "http://pidgin.im/aim_data.php3"#define OSCAR_CONNECT_STEPS 6static OscarCapability purple_caps = OSCAR_CAPABILITY_CHAT | OSCAR_CAPABILITY_BUDDYICON | OSCAR_CAPABILITY_DIRECTIM | OSCAR_CAPABILITY_SENDFILE | OSCAR_CAPABILITY_UNICODE | OSCAR_CAPABILITY_INTEROPERATE | OSCAR_CAPABILITY_ICHAT;static guint8 features_aim[] = {0x01, 0x01, 0x01, 0x02};static guint8 features_icq[] = {0x01, 0x06};static guint8 features_icq_offline[] = {0x01};static guint8 ck[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};struct create_room { char *name; int exchange;};struct oscar_ask_directim_data{ OscarData *od; char *who;};/* * 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 * * TODO: More of this should use the status API. */struct buddyinfo { gboolean typingnot; guint32 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 { PurpleConnection *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->purple callback functions */static int purple_parse_auth_resp (OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_parse_login (OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_parse_auth_securid_request(OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_handle_redirect (OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_info_change (OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_account_confirm (OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_parse_oncoming (OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_parse_offgoing (OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_parse_incoming_im(OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_parse_misses (OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_parse_clientauto (OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_parse_userinfo (OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_got_infoblock (OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_parse_motd (OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_chatnav_info (OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_conv_chat_join (OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_conv_chat_leave (OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_conv_chat_info_update (OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_conv_chat_incoming_msg(OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_email_parseupdate(OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_icon_error (OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_icon_parseicon (OscarData *, FlapConnection *, FlapFrame *, ...);static int oscar_icon_req (OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_parse_msgack (OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_parse_ratechange (OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_parse_evilnotify (OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_parse_searcherror(OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_parse_searchreply(OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_bosrights (OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_connerr (OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_parse_msgerr (OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_parse_mtn (OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_parse_locaterights(OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_parse_buddyrights(OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_parse_locerr (OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_icbm_param_info (OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_parse_genericerr (OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_memrequest (OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_selfinfo (OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_offlinemsg (OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_offlinemsgdone (OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_icqalias (OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_icqinfo (OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_popup (OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_ssi_parseerr (OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_ssi_parserights (OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_ssi_parselist (OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_ssi_parseack (OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_ssi_parseadd (OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_ssi_authgiven (OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_ssi_authrequest (OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_ssi_authreply (OscarData *, FlapConnection *, FlapFrame *, ...);static int purple_ssi_gotadded (OscarData *, FlapConnection *, FlapFrame *, ...);static gboolean purple_icon_timerfunc(gpointer data);static void recent_buddies_cb(const char *name, PurplePrefType type, gconstpointer value, gpointer data);void oscar_set_info(PurpleConnection *gc, const char *info);static void oscar_set_info_and_status(PurpleAccount *account, gboolean setinfo, const char *rawinfo, gboolean setstatus, PurpleStatus *status);static void oscar_set_extendedstatus(PurpleConnection *gc);static void oscar_format_screenname(PurpleConnection *gc, const char *nick); static gboolean purple_ssi_rerequestdata(gpointer data);static void oscar_free_name_data(struct name_data *data) { g_free(data->name); g_free(data->nick); g_free(data);}#ifdef _WIN32const char *oscar_get_locale_charset(void) { static const char *charset = NULL; if (charset == NULL) g_get_charset(&charset); return charset;}#endif/** * 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. */static guint32oscar_charset_check(const char *utf8){ int i = 0; int charset = AIM_CHARSET_ASCII; /* * Can we get away with using our custom encoding? */ while (utf8[i]) { if ((unsigned char)utf8[i] > 0x7f) { /* not ASCII! */ charset = AIM_CHARSET_CUSTOM; break; } i++; } /* * Must we send this message as UNICODE (in the UCS-2BE encoding)? */ 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. */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) && strncmp(encoding, "text/x-aolrtf; charset=", 23) && strncmp(encoding, "text/plain; charset=", 20)) { 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;}gchar *oscar_encoding_to_utf8(PurpleAccount *account, const char *encoding, const char *text, int textlen){ gchar *utf8 = NULL; if ((encoding == NULL) || encoding[0] == '\0') { purple_debug_info("oscar", "Empty encoding, assuming UTF-8\n"); } else if (!g_ascii_strcasecmp(encoding, "iso-8859-1")) { utf8 = g_convert(text, textlen, "UTF-8", "iso-8859-1", NULL, NULL, NULL); } else if (!g_ascii_strcasecmp(encoding, "ISO-8859-1-Windows-3.1-Latin-1") || !g_ascii_strcasecmp(encoding, "us-ascii")) { utf8 = g_convert(text, textlen, "UTF-8", "Windows-1252", NULL, NULL, NULL); } else if (!g_ascii_strcasecmp(encoding, "unicode-2-0")) { /* Some official ICQ clients are apparently total crack, * and have been known to save a UTF-8 string converted * from the locale character set to UCS-2 (not from UTF-8 * to UCS-2!) in the away message. This hack should find * and do something (un)reasonable with that, and not * mess up too much else. */ const gchar *charset = purple_account_get_string(account, "encoding", NULL); if (charset) { gsize len; utf8 = g_convert(text, textlen, charset, "UCS-2BE", &len, NULL, NULL); if (!utf8 || len != textlen || !g_utf8_validate(utf8, -1, NULL)) { g_free(utf8); utf8 = NULL; } else { purple_debug_info("oscar", "Used broken ICQ fallback encoding\n"); } } if (!utf8) utf8 = g_convert(text, textlen, "UTF-8", "UCS-2BE", NULL, NULL, NULL); } else if (g_ascii_strcasecmp(encoding, "utf-8")) { purple_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 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 with is probably using a different encoding than expected. If you know what encoding he is using, you can specify it in the advanced account options for your AIM/ICQ account.)")); else utf8 = g_strndup(text, textlen); } return utf8;}static gchar *oscar_utf8_try_convert(PurpleAccount *account, const gchar *msg){ const char *charset = NULL; char *ret = NULL; if(aim_sn_is_icq(purple_account_get_username(account))) charset = purple_account_get_string(account, "encoding", NULL); if(charset && *charset) ret = g_convert(msg, -1, "UTF-8", charset, NULL, NULL, NULL); if(!ret) ret = purple_utf8_try_convert(msg); return ret;}static gchar *purple_plugin_oscar_convert_to_utf8(const gchar *data, gsize datalen, const char *charsetstr, gboolean fallback){ gchar *ret = NULL; GError *err = NULL; if ((charsetstr == NULL) || (*charsetstr == '\0')) return NULL; if (g_ascii_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) { purple_debug_warning("oscar", "Conversion 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); else purple_debug_warning("oscar", "String is not valid UTF-8.\n"); } return ret;}/** * This attemps to decode an incoming IM into a UTF8 string. * * We try decoding using two different character sets. The charset * specified in the IM determines the order in which we attempt to * decode. We do this because there are lots of broken ICQ clients * that don't correctly send non-ASCII messages. And if Purple isn't * able to deal with that crap, then people complain like banshees. * charsetstr1 is always set to what the correct encoding should be. */gchar *purple_plugin_oscar_decode_im_part(PurpleAccount *account, const char *sourcesn, guint16 charset, guint16 charsubset, const gchar *data, gsize datalen)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -