Annotation of ChivanetAimPidgin/oscarprpl/src/c/oscar.c, revision 1.1
1.1 ! snw 1: /*
! 2: * purple
! 3: *
! 4: * Some code copyright (C) 1998-1999, Mark Spencer <markster@marko.net>
! 5: * Some code copyright (C) 1999-2001, Eric Warmenhoven
! 6: * Some code copyright (C) 2001-2003, Sean Egan
! 7: * Some code copyright (C) 2001-2007, Mark Doliner <thekingant@users.sourceforge.net>
! 8: * Some code copyright (C) 2005, Jonathan Clark <ardentlygnarly@users.sourceforge.net>
! 9: * Some code copyright (C) 2007, ComBOTS Product GmbH (htfv) <foss@combots.com>
! 10: * Some code copyright (C) 2008, Aman Gupta
! 11: *
! 12: * Most libfaim code copyright (C) 1998-2001 Adam Fritzler <afritz@auk.cx>
! 13: * Some libfaim code copyright (C) 2001-2004 Mark Doliner <thekingant@users.sourceforge.net>
! 14: *
! 15: * This program is free software; you can redistribute it and/or modify
! 16: * it under the terms of the GNU General Public License as published by
! 17: * the Free Software Foundation; either version 2 of the License, or
! 18: * (at your option) any later version.
! 19: *
! 20: * This program is distributed in the hope that it will be useful,
! 21: * but WITHOUT ANY WARRANTY; without even the implied warranty of
! 22: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
! 23: * GNU General Public License for more details.
! 24: *
! 25: * You should have received a copy of the GNU General Public License
! 26: * along with this program; if not, write to the Free Software
! 27: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
! 28: *
! 29: */
! 30:
! 31: #include "internal.h"
! 32:
! 33: #include "account.h"
! 34: #include "accountopt.h"
! 35: #include "buddyicon.h"
! 36: #include "cipher.h"
! 37: #include "conversation.h"
! 38: #include "core.h"
! 39: #include "debug.h"
! 40: #include "encoding.h"
! 41: #include "imgstore.h"
! 42: #include "network.h"
! 43: #include "notify.h"
! 44: #include "privacy.h"
! 45: #include "prpl.h"
! 46: #include "proxy.h"
! 47: #include "request.h"
! 48: #include "util.h"
! 49: #include "version.h"
! 50: #include "visibility.h"
! 51: #include <ctype.h>
! 52: #include "oscarcommon.h"
! 53: #include "oscar.h"
! 54: #include "peer.h"
! 55:
! 56: #define AIMHASHDATA "http://pidgin.im/aim_data.php3"
! 57:
! 58: #define OSCAR_CONNECT_STEPS 6
! 59:
! 60: static guint64 purple_caps =
! 61: OSCAR_CAPABILITY_CHAT
! 62: | OSCAR_CAPABILITY_BUDDYICON
! 63: | OSCAR_CAPABILITY_DIRECTIM
! 64: | OSCAR_CAPABILITY_SENDFILE
! 65: | OSCAR_CAPABILITY_UNICODE
! 66: | OSCAR_CAPABILITY_INTEROPERATE
! 67: | OSCAR_CAPABILITY_SHORTCAPS
! 68: | OSCAR_CAPABILITY_TYPING
! 69: | OSCAR_CAPABILITY_ICQSERVERRELAY
! 70: | OSCAR_CAPABILITY_NEWCAPS
! 71: | OSCAR_CAPABILITY_XTRAZ
! 72: | OSCAR_CAPABILITY_HTML_MSGS;
! 73:
! 74: static guint8 features_aim[] = {0x01, 0x01, 0x01, 0x02};
! 75: static guint8 features_icq[] = {0x01};
! 76:
! 77: struct create_room {
! 78: char *name;
! 79: int exchange;
! 80: };
! 81:
! 82: struct oscar_ask_directim_data
! 83: {
! 84: OscarData *od;
! 85: char *who;
! 86: };
! 87:
! 88: /* All the libfaim->purple callback functions */
! 89:
! 90: /* Only used when connecting with the old-style BUCP login */
! 91: static int purple_parse_auth_resp (OscarData *, FlapConnection *, FlapFrame *, ...);
! 92: static int purple_parse_login (OscarData *, FlapConnection *, FlapFrame *, ...);
! 93: static int purple_parse_auth_securid_request(OscarData *, FlapConnection *, FlapFrame *, ...);
! 94:
! 95: static int purple_handle_redirect (OscarData *, FlapConnection *, FlapFrame *, ...);
! 96: static int purple_info_change (OscarData *, FlapConnection *, FlapFrame *, ...);
! 97: static int purple_account_confirm (OscarData *, FlapConnection *, FlapFrame *, ...);
! 98: static int purple_parse_oncoming (OscarData *, FlapConnection *, FlapFrame *, ...);
! 99: static int purple_parse_offgoing (OscarData *, FlapConnection *, FlapFrame *, ...);
! 100: static int purple_parse_incoming_im(OscarData *, FlapConnection *, FlapFrame *, ...);
! 101: static int purple_parse_misses (OscarData *, FlapConnection *, FlapFrame *, ...);
! 102: static int purple_parse_clientauto (OscarData *, FlapConnection *, FlapFrame *, ...);
! 103: static int purple_parse_motd (OscarData *, FlapConnection *, FlapFrame *, ...);
! 104: static int purple_chatnav_info (OscarData *, FlapConnection *, FlapFrame *, ...);
! 105: static int purple_conv_chat_join (OscarData *, FlapConnection *, FlapFrame *, ...);
! 106: static int purple_conv_chat_leave (OscarData *, FlapConnection *, FlapFrame *, ...);
! 107: static int purple_conv_chat_info_update (OscarData *, FlapConnection *, FlapFrame *, ...);
! 108: static int purple_conv_chat_incoming_msg(OscarData *, FlapConnection *, FlapFrame *, ...);
! 109: static int purple_email_parseupdate(OscarData *, FlapConnection *, FlapFrame *, ...);
! 110: static int purple_icon_parseicon (OscarData *, FlapConnection *, FlapFrame *, ...);
! 111: static int purple_parse_searcherror(OscarData *, FlapConnection *, FlapFrame *, ...);
! 112: static int purple_parse_searchreply(OscarData *, FlapConnection *, FlapFrame *, ...);
! 113: static int purple_bosrights (OscarData *, FlapConnection *, FlapFrame *, ...);
! 114: static int purple_connerr (OscarData *, FlapConnection *, FlapFrame *, ...);
! 115: static int purple_parse_mtn (OscarData *, FlapConnection *, FlapFrame *, ...);
! 116: static int purple_parse_locaterights(OscarData *, FlapConnection *, FlapFrame *, ...);
! 117: static int purple_parse_buddyrights(OscarData *, FlapConnection *, FlapFrame *, ...);
! 118: static int purple_parse_genericerr (OscarData *, FlapConnection *, FlapFrame *, ...);
! 119: static int purple_memrequest (OscarData *, FlapConnection *, FlapFrame *, ...);
! 120: static int purple_selfinfo (OscarData *, FlapConnection *, FlapFrame *, ...);
! 121: static int purple_popup (OscarData *, FlapConnection *, FlapFrame *, ...);
! 122: static int purple_ssi_parseerr (OscarData *, FlapConnection *, FlapFrame *, ...);
! 123: static int purple_ssi_parserights (OscarData *, FlapConnection *, FlapFrame *, ...);
! 124: static int purple_ssi_parselist (OscarData *, FlapConnection *, FlapFrame *, ...);
! 125: static int purple_ssi_parseack (OscarData *, FlapConnection *, FlapFrame *, ...);
! 126: static int purple_ssi_parseaddmod (OscarData *, FlapConnection *, FlapFrame *, ...);
! 127: static int purple_ssi_authgiven (OscarData *, FlapConnection *, FlapFrame *, ...);
! 128: static int purple_ssi_authrequest (OscarData *, FlapConnection *, FlapFrame *, ...);
! 129: static int purple_ssi_authreply (OscarData *, FlapConnection *, FlapFrame *, ...);
! 130: static int purple_ssi_gotadded (OscarData *, FlapConnection *, FlapFrame *, ...);
! 131:
! 132: static void purple_icons_fetch(PurpleConnection *gc);
! 133:
! 134: void oscar_set_info(PurpleConnection *gc, const char *info);
! 135: static void oscar_set_info_and_status(PurpleAccount *account, gboolean setinfo, const char *rawinfo, gboolean setstatus, PurpleStatus *status);
! 136: static void oscar_set_extended_status(PurpleConnection *gc);
! 137: static gboolean purple_ssi_rerequestdata(gpointer data);
! 138:
! 139: void oscar_free_name_data(struct name_data *data) {
! 140: g_free(data->name);
! 141: g_free(data->nick);
! 142: g_free(data);
! 143: }
! 144:
! 145: #ifdef _WIN32
! 146: const char *oscar_get_locale_charset(void) {
! 147: static const char *charset = NULL;
! 148: if (charset == NULL)
! 149: g_get_charset(&charset);
! 150: return charset;
! 151: }
! 152: #endif
! 153:
! 154: static char *oscar_icqstatus(int state) {
! 155: /* Make a cute little string that shows the status of the dude or dudet */
! 156: if (state & AIM_ICQ_STATE_CHAT)
! 157: return g_strdup(_("Free For Chat"));
! 158: else if (state & AIM_ICQ_STATE_DND)
! 159: return g_strdup(_("Do Not Disturb"));
! 160: else if (state & AIM_ICQ_STATE_OUT)
! 161: return g_strdup(_("Not Available"));
! 162: else if (state & AIM_ICQ_STATE_BUSY)
! 163: return g_strdup(_("Occupied"));
! 164: else if (state & AIM_ICQ_STATE_AWAY)
! 165: return g_strdup(_("Away"));
! 166: else if (state & AIM_ICQ_STATE_WEBAWARE)
! 167: return g_strdup(_("Web Aware"));
! 168: else if (state & AIM_ICQ_STATE_INVISIBLE)
! 169: return g_strdup(_("Invisible"));
! 170: else if (state & AIM_ICQ_STATE_EVIL)
! 171: return g_strdup(_("Evil"));
! 172: else if (state & AIM_ICQ_STATE_DEPRESSION)
! 173: return g_strdup(_("Depression"));
! 174: else if (state & AIM_ICQ_STATE_ATHOME)
! 175: return g_strdup(_("At home"));
! 176: else if (state & AIM_ICQ_STATE_ATWORK)
! 177: return g_strdup(_("At work"));
! 178: else if (state & AIM_ICQ_STATE_LUNCH)
! 179: return g_strdup(_("At lunch"));
! 180: else
! 181: return g_strdup(_("Online"));
! 182: }
! 183:
! 184: static char *extract_name(const char *name) {
! 185: char *tmp, *x;
! 186: int i, j;
! 187:
! 188: if (!name)
! 189: return NULL;
! 190:
! 191: x = strchr(name, '-');
! 192: if (!x)
! 193: return NULL;
! 194:
! 195: x = strchr(x + 1, '-');
! 196: if (!x)
! 197: return NULL;
! 198:
! 199: tmp = g_strdup(++x);
! 200:
! 201: for (i = 0, j = 0; x[i]; i++) {
! 202: char hex[3];
! 203: if (x[i] != '%') {
! 204: tmp[j++] = x[i];
! 205: continue;
! 206: }
! 207: strncpy(hex, x + ++i, 2);
! 208: hex[2] = 0;
! 209: i++;
! 210: tmp[j++] = strtol(hex, NULL, 16);
! 211: }
! 212:
! 213: tmp[j] = 0;
! 214: return tmp;
! 215: }
! 216:
! 217: static struct chat_connection *
! 218: find_oscar_chat(PurpleConnection *gc, int id)
! 219: {
! 220: OscarData *od = purple_connection_get_protocol_data(gc);
! 221: GSList *cur;
! 222: struct chat_connection *cc;
! 223:
! 224: for (cur = od->oscar_chats; cur != NULL; cur = cur->next)
! 225: {
! 226: cc = (struct chat_connection *)cur->data;
! 227: if (cc->id == id)
! 228: return cc;
! 229: }
! 230:
! 231: return NULL;
! 232: }
! 233:
! 234: static struct chat_connection *
! 235: find_oscar_chat_by_conn(PurpleConnection *gc, FlapConnection *conn)
! 236: {
! 237: OscarData *od = purple_connection_get_protocol_data(gc);
! 238: GSList *cur;
! 239: struct chat_connection *cc;
! 240:
! 241: for (cur = od->oscar_chats; cur != NULL; cur = cur->next)
! 242: {
! 243: cc = (struct chat_connection *)cur->data;
! 244: if (cc->conn == conn)
! 245: return cc;
! 246: }
! 247:
! 248: return NULL;
! 249: }
! 250:
! 251: static struct chat_connection *
! 252: find_oscar_chat_by_conv(PurpleConnection *gc, PurpleConversation *conv)
! 253: {
! 254: OscarData *od = purple_connection_get_protocol_data(gc);
! 255: GSList *cur;
! 256: struct chat_connection *cc;
! 257:
! 258: for (cur = od->oscar_chats; cur != NULL; cur = cur->next)
! 259: {
! 260: cc = (struct chat_connection *)cur->data;
! 261: if (cc->conv == conv)
! 262: return cc;
! 263: }
! 264:
! 265: return NULL;
! 266: }
! 267:
! 268: void
! 269: oscar_chat_destroy(struct chat_connection *cc)
! 270: {
! 271: g_free(cc->name);
! 272: g_free(cc->show);
! 273: g_free(cc);
! 274: }
! 275:
! 276: static void
! 277: oscar_chat_kill(PurpleConnection *gc, struct chat_connection *cc)
! 278: {
! 279: OscarData *od = purple_connection_get_protocol_data(gc);
! 280:
! 281: /* Notify the conversation window that we've left the chat */
! 282: serv_got_chat_left(gc, purple_conv_chat_get_id(PURPLE_CONV_CHAT(cc->conv)));
! 283:
! 284: /* Destroy the chat_connection */
! 285: od->oscar_chats = g_slist_remove(od->oscar_chats, cc);
! 286: oscar_chat_destroy(cc);
! 287: }
! 288:
! 289: /**
! 290: * This is called from the callback functions for establishing
! 291: * a TCP connection with an oscar host if an error occurred.
! 292: */
! 293: static void
! 294: connection_common_error_cb(FlapConnection *conn, const gchar *error_message)
! 295: {
! 296: OscarData *od;
! 297: PurpleConnection *gc;
! 298:
! 299: od = conn->od;
! 300: gc = od->gc;
! 301:
! 302: purple_debug_error("oscar", "unable to connect to FLAP "
! 303: "server of type 0x%04hx\n", conn->type);
! 304:
! 305: if (conn->type == SNAC_FAMILY_AUTH)
! 306: {
! 307: /* This only happens when connecting with the old-style BUCP login */
! 308: gchar *msg;
! 309: msg = g_strdup_printf(_("Unable to connect to authentication server: %s"),
! 310: error_message);
! 311: purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, msg);
! 312: g_free(msg);
! 313: }
! 314: else if (conn->type == SNAC_FAMILY_LOCATE)
! 315: {
! 316: gchar *msg;
! 317: msg = g_strdup_printf(_("Unable to connect to BOS server: %s"),
! 318: error_message);
! 319: purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, msg);
! 320: g_free(msg);
! 321: }
! 322: else
! 323: {
! 324: /* Maybe we should call this for BOS connections, too? */
! 325: flap_connection_schedule_destroy(conn,
! 326: OSCAR_DISCONNECT_COULD_NOT_CONNECT, error_message);
! 327: }
! 328: }
! 329:
! 330: /**
! 331: * This is called from the callback functions for establishing
! 332: * a TCP connection with an oscar host. Depending on the type
! 333: * of host, we do a few different things here.
! 334: */
! 335: static void
! 336: connection_common_established_cb(FlapConnection *conn)
! 337: {
! 338: OscarData *od;
! 339: PurpleConnection *gc;
! 340: PurpleAccount *account;
! 341:
! 342: od = conn->od;
! 343: gc = od->gc;
! 344: account = purple_connection_get_account(gc);
! 345:
! 346: purple_debug_info("oscar", "connected to FLAP server of type 0x%04hx\n",
! 347: conn->type);
! 348:
! 349: if (conn->cookie == NULL)
! 350: flap_connection_send_version(od, conn);
! 351: else
! 352: {
! 353: const gchar *login_type = purple_account_get_string(account, "login_type", OSCAR_DEFAULT_LOGIN);
! 354:
! 355: if (!purple_strequal(login_type, OSCAR_MD5_LOGIN))
! 356: {
! 357: ClientInfo aiminfo = CLIENTINFO_PURPLE_AIM;
! 358: ClientInfo icqinfo = CLIENTINFO_PURPLE_ICQ;
! 359: flap_connection_send_version_with_cookie_and_clientinfo(od,
! 360: conn, conn->cookielen, conn->cookie,
! 361: od->icq ? &icqinfo : &aiminfo,
! 362: purple_account_get_bool(account, "allow_multiple_logins", OSCAR_DEFAULT_ALLOW_MULTIPLE_LOGINS));
! 363: } else {
! 364: flap_connection_send_version_with_cookie(od, conn,
! 365: conn->cookielen, conn->cookie);
! 366: }
! 367:
! 368:
! 369: g_free(conn->cookie);
! 370: conn->cookie = NULL;
! 371: }
! 372:
! 373: if (conn->type == SNAC_FAMILY_AUTH)
! 374: {
! 375: /* This only happens when connecting with the old-style BUCP login */
! 376: aim_request_login(od, conn, purple_account_get_username(account));
! 377: purple_debug_info("oscar", "Username sent, waiting for response\n");
! 378: purple_connection_update_progress(gc, _("Username sent"), 1, OSCAR_CONNECT_STEPS);
! 379: }
! 380: else if (conn->type == SNAC_FAMILY_LOCATE)
! 381: {
! 382: purple_connection_update_progress(gc, _("Connection established, cookie sent"), 4, OSCAR_CONNECT_STEPS);
! 383: }
! 384: else if (conn->type == SNAC_FAMILY_CHAT)
! 385: {
! 386: od->oscar_chats = g_slist_prepend(od->oscar_chats, conn->new_conn_data);
! 387: conn->new_conn_data = NULL;
! 388: }
! 389: }
! 390:
! 391: static void
! 392: connection_established_cb(gpointer data, gint source, const gchar *error_message)
! 393: {
! 394: FlapConnection *conn;
! 395:
! 396: conn = data;
! 397:
! 398: conn->connect_data = NULL;
! 399: conn->fd = source;
! 400:
! 401: if (source < 0)
! 402: {
! 403: connection_common_error_cb(conn, error_message);
! 404: return;
! 405: }
! 406:
! 407: conn->watcher_incoming = purple_input_add(conn->fd,
! 408: PURPLE_INPUT_READ, flap_connection_recv_cb, conn);
! 409: connection_common_established_cb(conn);
! 410: }
! 411:
! 412: static void
! 413: ssl_connection_established_cb(gpointer data, PurpleSslConnection *gsc,
! 414: PurpleInputCondition cond)
! 415: {
! 416: FlapConnection *conn;
! 417:
! 418: conn = data;
! 419:
! 420: purple_ssl_input_add(gsc, flap_connection_recv_cb_ssl, conn);
! 421: connection_common_established_cb(conn);
! 422: }
! 423:
! 424: static void
! 425: ssl_connection_error_cb(PurpleSslConnection *gsc, PurpleSslErrorType error,
! 426: gpointer data)
! 427: {
! 428: FlapConnection *conn;
! 429:
! 430: conn = data;
! 431:
! 432: if (conn->watcher_outgoing)
! 433: {
! 434: purple_input_remove(conn->watcher_outgoing);
! 435: conn->watcher_outgoing = 0;
! 436: }
! 437:
! 438: /* sslconn frees the connection on error */
! 439: conn->gsc = NULL;
! 440:
! 441: connection_common_error_cb(conn, purple_ssl_strerror(error));
! 442: }
! 443:
! 444: static void
! 445: flap_connection_established_bos(OscarData *od, FlapConnection *conn)
! 446: {
! 447: PurpleConnection *gc = od->gc;
! 448:
! 449: aim_srv_reqpersonalinfo(od, conn);
! 450:
! 451: purple_debug_info("oscar", "ssi: requesting rights and list\n");
! 452: aim_ssi_reqrights(od);
! 453: aim_ssi_reqdata(od);
! 454: if (od->getblisttimer > 0)
! 455: purple_timeout_remove(od->getblisttimer);
! 456: od->getblisttimer = purple_timeout_add_seconds(30, purple_ssi_rerequestdata, od);
! 457:
! 458: aim_locate_reqrights(od);
! 459: aim_buddylist_reqrights(od, conn);
! 460: aim_im_reqparams(od);
! 461: aim_bos_reqrights(od, conn); /* TODO: Don't call this with ssi */
! 462:
! 463: purple_connection_update_progress(gc, _("Finalizing connection"), 5, OSCAR_CONNECT_STEPS);
! 464: }
! 465:
! 466: static void
! 467: flap_connection_established_admin(OscarData *od, FlapConnection *conn)
! 468: {
! 469: aim_srv_clientready(od, conn);
! 470: purple_debug_info("oscar", "connected to admin\n");
! 471:
! 472: if (od->chpass) {
! 473: purple_debug_info("oscar", "changing password\n");
! 474: aim_admin_changepasswd(od, conn, od->newp, od->oldp);
! 475: g_free(od->oldp);
! 476: od->oldp = NULL;
! 477: g_free(od->newp);
! 478: od->newp = NULL;
! 479: od->chpass = FALSE;
! 480: }
! 481: if (od->setnick) {
! 482: purple_debug_info("oscar", "formatting username\n");
! 483: aim_admin_setnick(od, conn, od->newformatting);
! 484: g_free(od->newformatting);
! 485: od->newformatting = NULL;
! 486: od->setnick = FALSE;
! 487: }
! 488: if (od->conf) {
! 489: purple_debug_info("oscar", "confirming account\n");
! 490: aim_admin_reqconfirm(od, conn);
! 491: od->conf = FALSE;
! 492: }
! 493: if (od->reqemail) {
! 494: purple_debug_info("oscar", "requesting email address\n");
! 495: aim_admin_getinfo(od, conn, 0x0011);
! 496: od->reqemail = FALSE;
! 497: }
! 498: if (od->setemail) {
! 499: purple_debug_info("oscar", "setting email address\n");
! 500: aim_admin_setemail(od, conn, od->email);
! 501: g_free(od->email);
! 502: od->email = NULL;
! 503: od->setemail = FALSE;
! 504: }
! 505: }
! 506:
! 507: static void
! 508: flap_connection_established_chat(OscarData *od, FlapConnection *conn)
! 509: {
! 510: PurpleConnection *gc = od->gc;
! 511: struct chat_connection *chatcon;
! 512: static int id = 1;
! 513:
! 514: aim_srv_clientready(od, conn);
! 515:
! 516: chatcon = find_oscar_chat_by_conn(gc, conn);
! 517: if (chatcon) {
! 518: chatcon->id = id;
! 519: chatcon->conv = serv_got_joined_chat(gc, id++, chatcon->show);
! 520: }
! 521: }
! 522:
! 523: static void
! 524: flap_connection_established_chatnav(OscarData *od, FlapConnection *conn)
! 525: {
! 526: aim_srv_clientready(od, conn);
! 527: aim_chatnav_reqrights(od, conn);
! 528: }
! 529:
! 530: static void
! 531: flap_connection_established_alert(OscarData *od, FlapConnection *conn)
! 532: {
! 533: aim_email_sendcookies(od);
! 534: aim_email_activate(od);
! 535: aim_srv_clientready(od, conn);
! 536: }
! 537:
! 538: static void
! 539: flap_connection_established_bart(OscarData *od, FlapConnection *conn)
! 540: {
! 541: PurpleConnection *gc = od->gc;
! 542:
! 543: aim_srv_clientready(od, conn);
! 544:
! 545: od->iconconnecting = FALSE;
! 546:
! 547: purple_icons_fetch(gc);
! 548: }
! 549:
! 550: static int
! 551: flap_connection_established(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
! 552: {
! 553: conn->connected = TRUE;
! 554: purple_debug_info("oscar", "FLAP connection of type 0x%04hx is "
! 555: "now fully connected\n", conn->type);
! 556: if (conn->type == SNAC_FAMILY_LOCATE)
! 557: flap_connection_established_bos(od, conn);
! 558: else if (conn->type == SNAC_FAMILY_ADMIN)
! 559: flap_connection_established_admin(od, conn);
! 560: else if (conn->type == SNAC_FAMILY_CHAT)
! 561: flap_connection_established_chat(od, conn);
! 562: else if (conn->type == SNAC_FAMILY_CHATNAV)
! 563: flap_connection_established_chatnav(od, conn);
! 564: else if (conn->type == SNAC_FAMILY_ALERT)
! 565: flap_connection_established_alert(od, conn);
! 566: else if (conn->type == SNAC_FAMILY_BART)
! 567: flap_connection_established_bart(od, conn);
! 568:
! 569: return 1;
! 570: }
! 571:
! 572: static void
! 573: idle_reporting_pref_cb(const char *name, PurplePrefType type,
! 574: gconstpointer value, gpointer data)
! 575: {
! 576: PurpleConnection *gc;
! 577: OscarData *od;
! 578: gboolean report_idle;
! 579: guint32 presence;
! 580:
! 581: gc = data;
! 582: od = purple_connection_get_protocol_data(gc);
! 583: report_idle = !purple_strequal((const char *)value, "none");
! 584: presence = aim_ssi_getpresence(od->ssi.local);
! 585:
! 586: if (report_idle)
! 587: aim_ssi_setpresence(od, presence | AIM_SSI_PRESENCE_FLAG_SHOWIDLE);
! 588: else
! 589: aim_ssi_setpresence(od, presence & ~AIM_SSI_PRESENCE_FLAG_SHOWIDLE);
! 590: }
! 591:
! 592: /**
! 593: * Should probably make a "Use recent buddies group" account preference
! 594: * so that this option is surfaced to the user.
! 595: */
! 596: static void
! 597: recent_buddies_pref_cb(const char *name, PurplePrefType type,
! 598: gconstpointer value, gpointer data)
! 599: {
! 600: PurpleConnection *gc;
! 601: OscarData *od;
! 602: guint32 presence;
! 603:
! 604: gc = data;
! 605: od = purple_connection_get_protocol_data(gc);
! 606: presence = aim_ssi_getpresence(od->ssi.local);
! 607:
! 608: if (value)
! 609: aim_ssi_setpresence(od, presence & ~AIM_SSI_PRESENCE_FLAG_NORECENTBUDDIES);
! 610: else
! 611: aim_ssi_setpresence(od, presence | AIM_SSI_PRESENCE_FLAG_NORECENTBUDDIES);
! 612: }
! 613:
! 614: static const gchar *login_servers[] = {
! 615: AIM_DEFAULT_LOGIN_SERVER,
! 616: AIM_DEFAULT_SSL_LOGIN_SERVER,
! 617: ICQ_DEFAULT_LOGIN_SERVER,
! 618: ICQ_DEFAULT_SSL_LOGIN_SERVER,
! 619: };
! 620:
! 621: static const gchar *
! 622: get_login_server(gboolean is_icq, gboolean use_ssl)
! 623: {
! 624: return login_servers[(is_icq ? 2 : 0) + (use_ssl ? 1 : 0)];
! 625: }
! 626:
! 627: static gint
! 628: compare_handlers(gconstpointer a, gconstpointer b)
! 629: {
! 630: guint aa = GPOINTER_TO_UINT(a);
! 631: guint bb = GPOINTER_TO_UINT(b);
! 632: guint family1 = aa >> 16;
! 633: guint family2 = bb >> 16;
! 634: guint subtype1 = aa & 0xFFFF;
! 635: guint subtype2 = bb & 0xFFFF;
! 636: if (family1 != family2) {
! 637: return family1 - family2;
! 638: }
! 639: return subtype1 - subtype2;
! 640: }
! 641:
! 642: #if !GLIB_CHECK_VERSION(2,14,0)
! 643: static void hash_table_get_list_of_keys(gpointer key, gpointer value, gpointer user_data)
! 644: {
! 645: GList **handlers = (GList **)user_data;
! 646:
! 647: *handlers = g_list_prepend(*handlers, key);
! 648: }
! 649: #endif /* GLIB < 2.14.0 */
! 650:
! 651: void
! 652: oscar_login(PurpleAccount *account)
! 653: {
! 654: PurpleConnection *gc;
! 655: OscarData *od;
! 656: const gchar *encryption_type;
! 657: const gchar *login_type;
! 658: GList *handlers;
! 659: GList *sorted_handlers;
! 660: GList *cur;
! 661: GString *msg = g_string_new("");
! 662:
! 663: gc = purple_account_get_connection(account);
! 664: od = oscar_data_new();
! 665: od->gc = gc;
! 666: purple_connection_set_protocol_data(gc, od);
! 667:
! 668: oscar_data_addhandler(od, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR, purple_connerr, 0);
! 669: oscar_data_addhandler(od, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, flap_connection_established, 0);
! 670:
! 671: oscar_data_addhandler(od, SNAC_FAMILY_ADMIN, 0x0003, purple_info_change, 0);
! 672: oscar_data_addhandler(od, SNAC_FAMILY_ADMIN, 0x0005, purple_info_change, 0);
! 673: oscar_data_addhandler(od, SNAC_FAMILY_ADMIN, 0x0007, purple_account_confirm, 0);
! 674: oscar_data_addhandler(od, SNAC_FAMILY_ALERT, 0x0001, purple_parse_genericerr, 0);
! 675: oscar_data_addhandler(od, SNAC_FAMILY_ALERT, SNAC_SUBTYPE_ALERT_MAILSTATUS, purple_email_parseupdate, 0);
! 676:
! 677: /* These are only needed when connecting with the old-style BUCP login */
! 678: oscar_data_addhandler(od, SNAC_FAMILY_AUTH, 0x0003, purple_parse_auth_resp, 0);
! 679: oscar_data_addhandler(od, SNAC_FAMILY_AUTH, 0x0007, purple_parse_login, 0);
! 680: oscar_data_addhandler(od, SNAC_FAMILY_AUTH, SNAC_SUBTYPE_AUTH_SECURID_REQUEST, purple_parse_auth_securid_request, 0);
! 681:
! 682: oscar_data_addhandler(od, SNAC_FAMILY_BART, SNAC_SUBTYPE_BART_RESPONSE, purple_icon_parseicon, 0);
! 683: oscar_data_addhandler(od, SNAC_FAMILY_BOS, 0x0001, purple_parse_genericerr, 0);
! 684: oscar_data_addhandler(od, SNAC_FAMILY_BOS, 0x0003, purple_bosrights, 0);
! 685: oscar_data_addhandler(od, SNAC_FAMILY_BUDDY, 0x0001, purple_parse_genericerr, 0);
! 686: oscar_data_addhandler(od, SNAC_FAMILY_BUDDY, SNAC_SUBTYPE_BUDDY_RIGHTSINFO, purple_parse_buddyrights, 0);
! 687: oscar_data_addhandler(od, SNAC_FAMILY_BUDDY, SNAC_SUBTYPE_BUDDY_ONCOMING, purple_parse_oncoming, 0);
! 688: oscar_data_addhandler(od, SNAC_FAMILY_BUDDY, SNAC_SUBTYPE_BUDDY_OFFGOING, purple_parse_offgoing, 0);
! 689: oscar_data_addhandler(od, SNAC_FAMILY_CHAT, 0x0001, purple_parse_genericerr, 0);
! 690: oscar_data_addhandler(od, SNAC_FAMILY_CHAT, SNAC_SUBTYPE_CHAT_USERJOIN, purple_conv_chat_join, 0);
! 691: oscar_data_addhandler(od, SNAC_FAMILY_CHAT, SNAC_SUBTYPE_CHAT_USERLEAVE, purple_conv_chat_leave, 0);
! 692: oscar_data_addhandler(od, SNAC_FAMILY_CHAT, SNAC_SUBTYPE_CHAT_ROOMINFOUPDATE, purple_conv_chat_info_update, 0);
! 693: oscar_data_addhandler(od, SNAC_FAMILY_CHAT, SNAC_SUBTYPE_CHAT_INCOMINGMSG, purple_conv_chat_incoming_msg, 0);
! 694: oscar_data_addhandler(od, SNAC_FAMILY_CHATNAV, 0x0001, purple_parse_genericerr, 0);
! 695: oscar_data_addhandler(od, SNAC_FAMILY_CHATNAV, SNAC_SUBTYPE_CHATNAV_INFO, purple_chatnav_info, 0);
! 696: oscar_data_addhandler(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_ERROR, purple_ssi_parseerr, 0);
! 697: oscar_data_addhandler(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_RIGHTSINFO, purple_ssi_parserights, 0);
! 698: oscar_data_addhandler(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_LIST, purple_ssi_parselist, 0);
! 699: oscar_data_addhandler(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SRVACK, purple_ssi_parseack, 0);
! 700: oscar_data_addhandler(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_ADD, purple_ssi_parseaddmod, 0);
! 701: oscar_data_addhandler(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_MOD, purple_ssi_parseaddmod, 0);
! 702: oscar_data_addhandler(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_RECVAUTH, purple_ssi_authgiven, 0);
! 703: oscar_data_addhandler(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_RECVAUTHREQ, purple_ssi_authrequest, 0);
! 704: oscar_data_addhandler(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_RECVAUTHREP, purple_ssi_authreply, 0);
! 705: oscar_data_addhandler(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_ADDED, purple_ssi_gotadded, 0);
! 706: oscar_data_addhandler(od, SNAC_FAMILY_ICBM, SNAC_SUBTYPE_ICBM_INCOMING, purple_parse_incoming_im, 0);
! 707: oscar_data_addhandler(od, SNAC_FAMILY_ICBM, SNAC_SUBTYPE_ICBM_MISSEDCALL, purple_parse_misses, 0);
! 708: oscar_data_addhandler(od, SNAC_FAMILY_ICBM, SNAC_SUBTYPE_ICBM_CLIENTAUTORESP, purple_parse_clientauto, 0);
! 709: oscar_data_addhandler(od, SNAC_FAMILY_ICBM, SNAC_SUBTYPE_ICBM_MTN, purple_parse_mtn, 0);
! 710: oscar_data_addhandler(od, SNAC_FAMILY_LOCATE, SNAC_SUBTYPE_LOCATE_RIGHTSINFO, purple_parse_locaterights, 0);
! 711: oscar_data_addhandler(od, SNAC_FAMILY_OSERVICE, 0x0001, purple_parse_genericerr, 0);
! 712: oscar_data_addhandler(od, SNAC_FAMILY_OSERVICE, 0x000f, purple_selfinfo, 0);
! 713: oscar_data_addhandler(od, SNAC_FAMILY_OSERVICE, 0x001f, purple_memrequest, 0);
! 714: oscar_data_addhandler(od, SNAC_FAMILY_OSERVICE, SNAC_SUBTYPE_OSERVICE_REDIRECT, purple_handle_redirect, 0);
! 715: oscar_data_addhandler(od, SNAC_FAMILY_OSERVICE, SNAC_SUBTYPE_OSERVICE_MOTD, purple_parse_motd, 0);
! 716: oscar_data_addhandler(od, SNAC_FAMILY_POPUP, 0x0002, purple_popup, 0);
! 717: oscar_data_addhandler(od, SNAC_FAMILY_USERLOOKUP, SNAC_SUBTYPE_USERLOOKUP_ERROR, purple_parse_searcherror, 0);
! 718: oscar_data_addhandler(od, SNAC_FAMILY_USERLOOKUP, 0x0003, purple_parse_searchreply, 0);
! 719:
! 720: g_string_append(msg, "Registered handlers: ");
! 721: #if GLIB_CHECK_VERSION(2,14,0)
! 722: handlers = g_hash_table_get_keys(od->handlerlist);
! 723: #else
! 724: handlers = NULL;
! 725: g_hash_table_foreach(od->handlerlist, hash_table_get_list_of_keys, &handlers);
! 726: #endif /* GLIB < 2.14.0 */
! 727: sorted_handlers = g_list_sort(g_list_copy(handlers), compare_handlers);
! 728: for (cur = sorted_handlers; cur; cur = cur->next) {
! 729: guint x = GPOINTER_TO_UINT(cur->data);
! 730: g_string_append_printf(msg, "%04x/%04x, ", x >> 16, x & 0xFFFF);
! 731: }
! 732: g_list_free(sorted_handlers);
! 733: g_list_free(handlers);
! 734: purple_debug_misc("oscar", "%s\n", msg->str);
! 735: g_string_free(msg, TRUE);
! 736:
! 737: purple_debug_misc("oscar", "oscar_login: gc = %p\n", gc);
! 738:
! 739: if (!oscar_util_valid_name(purple_account_get_username(account))) {
! 740: gchar *buf;
! 741: buf = g_strdup_printf(_("Unable to sign on as %s because the username is invalid. Usernames must be a valid email address, or start with a letter and contain only letters, numbers and spaces, or contain only numbers."), purple_account_get_username(account));
! 742: purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_INVALID_SETTINGS, buf);
! 743: g_free(buf);
! 744: return;
! 745: }
! 746:
! 747: gc->flags |= PURPLE_CONNECTION_HTML;
! 748: if (purple_strequal(purple_account_get_protocol_id(account), "prpl-icq")) {
! 749: od->icq = TRUE;
! 750: } else {
! 751: gc->flags |= PURPLE_CONNECTION_AUTO_RESP;
! 752: }
! 753:
! 754: /* Set this flag based on the protocol_id rather than the username,
! 755: because that is what's tied to the get_moods prpl callback. */
! 756: if (purple_strequal(purple_account_get_protocol_id(account), "prpl-icq"))
! 757: gc->flags |= PURPLE_CONNECTION_SUPPORT_MOODS;
! 758:
! 759: od->default_port = purple_account_get_int(account, "port", OSCAR_DEFAULT_LOGIN_PORT);
! 760:
! 761: login_type = purple_account_get_string(account, "login_type", OSCAR_DEFAULT_LOGIN);
! 762: encryption_type = purple_account_get_string(account, "encryption", OSCAR_DEFAULT_ENCRYPTION);
! 763: if (!purple_ssl_is_supported() && purple_strequal(encryption_type, OSCAR_REQUIRE_ENCRYPTION)) {
! 764: purple_connection_error_reason(
! 765: gc,
! 766: PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT,
! 767: _("You required encryption in your account settings, but encryption is not supported by your system."));
! 768: return;
! 769: }
! 770: od->use_ssl = purple_ssl_is_supported() && !purple_strequal(encryption_type, OSCAR_NO_ENCRYPTION);
! 771:
! 772: /* Connect to core Purple signals */
! 773: purple_prefs_connect_callback(gc, "/purple/away/idle_reporting", idle_reporting_pref_cb, gc);
! 774: purple_prefs_connect_callback(gc, "/plugins/prpl/oscar/recent_buddies", recent_buddies_pref_cb, gc);
! 775:
! 776: /*
! 777: * On 2008-03-05 AOL released some documentation on the OSCAR protocol
! 778: * which includes a new login method called clientLogin. It is similar
! 779: * (though not the same?) as what the AIM 6.0 series uses to
! 780: * authenticate.
! 781: *
! 782: * AIM 5.9 and lower use an MD5-based login procedure called "BUCP".
! 783: * This authentication method is used for both ICQ and AIM when
! 784: * clientLogin is not enabled.
! 785: */
! 786: if (purple_strequal(login_type, OSCAR_CLIENT_LOGIN)) {
! 787: /* Note: Actual server/port configuration is ignored here */
! 788: send_client_login(od, purple_account_get_username(account));
! 789: } else if (purple_strequal(login_type, OSCAR_KERBEROS_LOGIN)) {
! 790: const char *server;
! 791:
! 792: if (!od->use_ssl) {
! 793: purple_connection_error_reason(
! 794: gc,
! 795: PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT,
! 796: _("You required Kerberos authentication but encryption is disabled in your account settings."));
! 797: return;
! 798: }
! 799: server = purple_account_get_string(account, "server", AIM_DEFAULT_KDC_SERVER);
! 800: /*
! 801: * If the account's server is what the oscar protocol has offered as
! 802: * the default login server through the vast eons (all two of
! 803: * said default options, AFAIK) and the user wants KDC, we'll
! 804: * do what we know is best for them and change the setting out
! 805: * from under them to the KDC login server.
! 806: */
! 807: if (purple_strequal(server, get_login_server(od->icq, FALSE)) ||
! 808: purple_strequal(server, get_login_server(od->icq, TRUE)) ||
! 809: purple_strequal(server, AIM_ALT_LOGIN_SERVER) ||
! 810: purple_strequal(server, "")) {
! 811: purple_debug_info("oscar", "Account uses Kerberos auth, so changing server to default KDC server\n");
! 812: purple_account_set_string(account, "server", AIM_DEFAULT_KDC_SERVER);
! 813: purple_account_set_int(account, "port", AIM_DEFAULT_KDC_PORT);
! 814: }
! 815: send_kerberos_login(od, purple_account_get_username(account));
! 816: } else {
! 817: FlapConnection *newconn;
! 818: const char *server;
! 819:
! 820: newconn = flap_connection_new(od, SNAC_FAMILY_AUTH);
! 821:
! 822: if (od->use_ssl) {
! 823: server = purple_account_get_string(account, "server", get_login_server(od->icq, TRUE));
! 824:
! 825: /*
! 826: * If the account's server is what the oscar prpl has offered as
! 827: * the default login server through the vast eons (all two of
! 828: * said default options, AFAIK) and the user wants SSL, we'll
! 829: * do what we know is best for them and change the setting out
! 830: * from under them to the SSL login server.
! 831: */
! 832: if (purple_strequal(server, get_login_server(od->icq, FALSE)) ||
! 833: purple_strequal(server, AIM_ALT_LOGIN_SERVER) ||
! 834: purple_strequal(server, AIM_DEFAULT_KDC_SERVER) ||
! 835: purple_strequal(server, "")) {
! 836: purple_debug_info("oscar", "Account uses SSL, so changing server to default SSL server\n");
! 837: purple_account_set_string(account, "server", get_login_server(od->icq, TRUE));
! 838: purple_account_set_int(account, "port", OSCAR_DEFAULT_LOGIN_PORT),
! 839: server = get_login_server(od->icq, TRUE);
! 840: }
! 841:
! 842: newconn->gsc = purple_ssl_connect(account, server,
! 843: purple_account_get_int(account, "port", OSCAR_DEFAULT_LOGIN_PORT),
! 844: ssl_connection_established_cb, ssl_connection_error_cb, newconn);
! 845: } else {
! 846: server = purple_account_get_string(account, "server", get_login_server(od->icq, FALSE));
! 847:
! 848: /*
! 849: * See the comment above. We do the reverse here. If they don't want
! 850: * SSL but their server is set to OSCAR_DEFAULT_SSL_LOGIN_SERVER,
! 851: * set it back to the default.
! 852: */
! 853: if (purple_strequal(server, get_login_server(od->icq, TRUE)) ||
! 854: purple_strequal(server, AIM_DEFAULT_KDC_SERVER) ||
! 855: purple_strequal(server, "")) {
! 856: purple_debug_info("oscar", "Account does not use SSL, so changing server back to non-SSL\n");
! 857: purple_account_set_string(account, "server", get_login_server(od->icq, FALSE));
! 858: purple_account_set_int(account, "port", OSCAR_DEFAULT_LOGIN_PORT),
! 859: server = get_login_server(od->icq, FALSE);
! 860: }
! 861:
! 862: newconn->connect_data = purple_proxy_connect(NULL, account, server,
! 863: purple_account_get_int(account, "port", OSCAR_DEFAULT_LOGIN_PORT),
! 864: connection_established_cb, newconn);
! 865: }
! 866:
! 867: if (newconn->gsc == NULL && newconn->connect_data == NULL) {
! 868: purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
! 869: _("Unable to connect"));
! 870: return;
! 871: }
! 872: }
! 873:
! 874: purple_connection_update_progress(gc, _("Connecting"), 0, OSCAR_CONNECT_STEPS);
! 875: }
! 876:
! 877: void
! 878: oscar_close(PurpleConnection *gc)
! 879: {
! 880: OscarData *od;
! 881:
! 882: od = purple_connection_get_protocol_data(gc);
! 883:
! 884: while (od->oscar_chats)
! 885: {
! 886: struct chat_connection *cc = od->oscar_chats->data;
! 887: od->oscar_chats = g_slist_remove(od->oscar_chats, cc);
! 888: oscar_chat_destroy(cc);
! 889: }
! 890: while (od->create_rooms)
! 891: {
! 892: struct create_room *cr = od->create_rooms->data;
! 893: g_free(cr->name);
! 894: od->create_rooms = g_slist_remove(od->create_rooms, cr);
! 895: g_free(cr);
! 896: }
! 897: oscar_data_destroy(od);
! 898: purple_connection_set_protocol_data(gc, NULL);
! 899:
! 900: purple_prefs_disconnect_by_handle(gc);
! 901:
! 902: purple_debug_info("oscar", "Signed off.\n");
! 903: }
! 904:
! 905: /* XXX - Should use purple_util_fetch_url for the below stuff */
! 906: struct pieceofcrap {
! 907: PurpleConnection *gc;
! 908: unsigned long offset;
! 909: unsigned long len;
! 910: char *modname;
! 911: int fd;
! 912: FlapConnection *conn;
! 913: unsigned int inpa;
! 914: };
! 915:
! 916: static void damn_you(gpointer data, gint source, PurpleInputCondition c)
! 917: {
! 918: struct pieceofcrap *pos = data;
! 919: OscarData *od = purple_connection_get_protocol_data(pos->gc);
! 920: char in = '\0';
! 921: int x = 0;
! 922: unsigned char m[17];
! 923: GString *msg;
! 924:
! 925: while (read(pos->fd, &in, 1) == 1) {
! 926: if (in == '\n')
! 927: x++;
! 928: else if (in != '\r')
! 929: x = 0;
! 930: if (x == 2)
! 931: break;
! 932: in = '\0';
! 933: }
! 934: if (in != '\n') {
! 935: char buf[256];
! 936: g_snprintf(buf, sizeof(buf), _("You may be disconnected shortly. "
! 937: "If so, check %s for updates."),
! 938: oscar_get_ui_info_string("website", PURPLE_WEBSITE));
! 939: purple_notify_warning(pos->gc, NULL,
! 940: _("Unable to get a valid AIM login hash."),
! 941: buf);
! 942: purple_input_remove(pos->inpa);
! 943: close(pos->fd);
! 944: g_free(pos);
! 945: return;
! 946: }
! 947: if (read(pos->fd, m, 16) != 16)
! 948: {
! 949: purple_debug_warning("oscar", "Could not read full AIM login hash "
! 950: "from " AIMHASHDATA "--that's bad.\n");
! 951: }
! 952: m[16] = '\0';
! 953:
! 954: msg = g_string_new("Sending hash: ");
! 955: for (x = 0; x < 16; x++)
! 956: g_string_append_printf(msg, "%02hhx ", (unsigned char)m[x]);
! 957: g_string_append(msg, "\n");
! 958: purple_debug_misc("oscar", "%s", msg->str);
! 959: g_string_free(msg, TRUE);
! 960:
! 961: purple_input_remove(pos->inpa);
! 962: close(pos->fd);
! 963: aim_sendmemblock(od, pos->conn, 0, 16, m, AIM_SENDMEMBLOCK_FLAG_ISHASH);
! 964: g_free(pos);
! 965: }
! 966:
! 967: static void
! 968: straight_to_hell(gpointer data, gint source, const gchar *error_message)
! 969: {
! 970: struct pieceofcrap *pos = data;
! 971: gchar *buf;
! 972: gssize result;
! 973:
! 974: pos->fd = source;
! 975:
! 976: if (source < 0) {
! 977: buf = g_strdup_printf(_("You may be disconnected shortly. "
! 978: "If so, check %s for updates."),
! 979: oscar_get_ui_info_string("website", PURPLE_WEBSITE));
! 980: purple_notify_warning(pos->gc, NULL,
! 981: _("Unable to get a valid AIM login hash."),
! 982: buf);
! 983: g_free(buf);
! 984: g_free(pos->modname);
! 985: g_free(pos);
! 986: return;
! 987: }
! 988:
! 989: buf = g_strdup_printf("GET " AIMHASHDATA "?offset=%ld&len=%ld&modname=%s HTTP/1.0\n\n",
! 990: pos->offset, pos->len, pos->modname ? pos->modname : "");
! 991: result = send(pos->fd, buf, strlen(buf), 0);
! 992: if (result < 0)
! 993: purple_debug_error("oscar", "Error writing %" G_GSIZE_FORMAT
! 994: " bytes to fetch AIM hash data: %s\n",
! 995: strlen(buf), g_strerror(errno));
! 996: else if ((gsize)result != strlen(buf))
! 997: purple_debug_error("oscar", "Tried to write %"
! 998: G_GSIZE_FORMAT " bytes to fetch AIM hash data but "
! 999: "instead wrote %" G_GSSIZE_FORMAT " bytes\n",
! 1000: strlen(buf), result);
! 1001: g_free(buf);
! 1002: g_free(pos->modname);
! 1003: pos->inpa = purple_input_add(pos->fd, PURPLE_INPUT_READ, damn_you, pos);
! 1004: return;
! 1005: }
! 1006:
! 1007: /* size of icbmui.ocm, the largest module in AIM 3.5 */
! 1008: #define AIM_MAX_FILE_SIZE 98304
! 1009:
! 1010: static int purple_memrequest(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
! 1011: {
! 1012: va_list ap;
! 1013: struct pieceofcrap *pos;
! 1014: guint32 offset, len;
! 1015: char *modname;
! 1016:
! 1017: va_start(ap, fr);
! 1018: offset = va_arg(ap, guint32);
! 1019: len = va_arg(ap, guint32);
! 1020: modname = va_arg(ap, char *);
! 1021: va_end(ap);
! 1022:
! 1023: purple_debug_misc("oscar", "offset: %u, len: %u, file: %s\n",
! 1024: offset, len, (modname ? modname : "aim.exe"));
! 1025:
! 1026: if (len == 0) {
! 1027: purple_debug_misc("oscar", "len is 0, hashing NULL\n");
! 1028: aim_sendmemblock(od, conn, offset, len, NULL,
! 1029: AIM_SENDMEMBLOCK_FLAG_ISREQUEST);
! 1030: return 1;
! 1031: }
! 1032:
! 1033: pos = g_new0(struct pieceofcrap, 1);
! 1034: pos->gc = od->gc;
! 1035: pos->conn = conn;
! 1036:
! 1037: pos->offset = offset;
! 1038: pos->len = len;
! 1039: pos->modname = g_strdup(modname);
! 1040:
! 1041: if (purple_proxy_connect(pos->gc, pos->gc->account, "pidgin.im", 80,
! 1042: straight_to_hell, pos) == NULL)
! 1043: {
! 1044: char buf[256];
! 1045: g_free(pos->modname);
! 1046: g_free(pos);
! 1047:
! 1048: g_snprintf(buf, sizeof(buf), _("You may be disconnected shortly. "
! 1049: "If so, check %s for updates."),
! 1050: oscar_get_ui_info_string("website", PURPLE_WEBSITE));
! 1051: purple_notify_warning(pos->gc, NULL,
! 1052: _("Unable to get a valid login hash."),
! 1053: buf);
! 1054: }
! 1055:
! 1056: return 1;
! 1057: }
! 1058:
! 1059: int oscar_connect_to_bos(PurpleConnection *gc, OscarData *od, const char *host, guint16 port, guint8 *cookie, guint16 cookielen, const char *tls_certname)
! 1060: {
! 1061: PurpleAccount *account;
! 1062: FlapConnection *conn;
! 1063:
! 1064: account = purple_connection_get_account(gc);
! 1065:
! 1066: conn = flap_connection_new(od, SNAC_FAMILY_LOCATE);
! 1067: conn->cookielen = cookielen;
! 1068: conn->cookie = g_memdup(cookie, cookielen);
! 1069:
! 1070: /*
! 1071: * Use TLS only if the server provided us with a tls_certname. The server might not specify a tls_certname even if we requested to use TLS,
! 1072: * and that is something we should be prepared to.
! 1073: */
! 1074: if (tls_certname)
! 1075: {
! 1076: conn->gsc = purple_ssl_connect_with_ssl_cn(account, host, port,
! 1077: ssl_connection_established_cb, ssl_connection_error_cb,
! 1078: tls_certname, conn);
! 1079: }
! 1080: else
! 1081: {
! 1082: conn->connect_data = purple_proxy_connect(NULL,
! 1083: account, host, port,
! 1084: connection_established_cb, conn);
! 1085: }
! 1086:
! 1087: if (conn->gsc == NULL && conn->connect_data == NULL)
! 1088: {
! 1089: purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Unable to connect"));
! 1090: return 0;
! 1091: }
! 1092:
! 1093: od->default_port = port;
! 1094:
! 1095: purple_connection_update_progress(gc, _("Received authorization"), 3, OSCAR_CONNECT_STEPS);
! 1096:
! 1097: return 1;
! 1098: }
! 1099:
! 1100: /**
! 1101: * Only used when connecting with the old-style BUCP login.
! 1102: */
! 1103: static int
! 1104: purple_parse_auth_resp(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
! 1105: {
! 1106: PurpleConnection *gc = od->gc;
! 1107: PurpleAccount *account = purple_connection_get_account(gc);
! 1108: char *host; int port;
! 1109: size_t i;
! 1110: FlapConnection *newconn;
! 1111: va_list ap;
! 1112: struct aim_authresp_info *info;
! 1113:
! 1114: port = purple_account_get_int(account, "port", od->default_port);
! 1115:
! 1116: va_start(ap, fr);
! 1117: info = va_arg(ap, struct aim_authresp_info *);
! 1118: va_end(ap);
! 1119:
! 1120: purple_debug_info("oscar",
! 1121: "inside auth_resp (Username: %s)\n", info->bn);
! 1122:
! 1123: if (info->errorcode || !info->bosip || !info->cookielen || !info->cookie) {
! 1124: char buf[256];
! 1125: switch (info->errorcode) {
! 1126: case 0x01:
! 1127: /* Unregistered username */
! 1128: purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_INVALID_USERNAME, _("Username does not exist"));
! 1129: break;
! 1130: case 0x05:
! 1131: /* Incorrect password */
! 1132: if (!purple_account_get_remember_password(account))
! 1133: purple_account_set_password(account, NULL);
! 1134: purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, _("Incorrect password"));
! 1135: break;
! 1136: case 0x11:
! 1137: /* Suspended account */
! 1138: purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, _("Your account is currently suspended"));
! 1139: break;
! 1140: case 0x02:
! 1141: case 0x14:
! 1142: /* service temporarily unavailable */
! 1143: purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("The AOL Instant Messenger service is temporarily unavailable."));
! 1144: break;
! 1145: case 0x18:
! 1146: /* username connecting too frequently */
! 1147: purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, _("Your username has been connecting and disconnecting too frequently. Wait ten minutes and try again. If you continue to try, you will need to wait even longer."));
! 1148: break;
! 1149: case 0x1c:
! 1150: {
! 1151: /* client too old */
! 1152: g_snprintf(buf, sizeof(buf), _("The client version you are using is too old. Please upgrade at %s"),
! 1153: oscar_get_ui_info_string("website", PURPLE_WEBSITE));
! 1154: purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, buf);
! 1155: break;
! 1156: }
! 1157: case 0x1d:
! 1158: /* IP address connecting too frequently */
! 1159: purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, _("Your IP address has been connecting and disconnecting too frequently. Wait a minute and try again. If you continue to try, you will need to wait even longer."));
! 1160: break;
! 1161: default:
! 1162: purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, _("Unknown reason"));
! 1163: break;
! 1164: }
! 1165: purple_debug_info("oscar", "Login Error Code 0x%04hx\n", info->errorcode);
! 1166: purple_debug_info("oscar", "Error URL: %s\n", info->errorurl ? info->errorurl : "");
! 1167: return 1;
! 1168: }
! 1169:
! 1170: purple_debug_misc("oscar", "Reg status: %hu\n"
! 1171: "Email: %s\n"
! 1172: "BOSIP: %s\n",
! 1173: info->regstatus,
! 1174: info->email ? info->email : "null",
! 1175: info->bosip ? info->bosip : "null");
! 1176: purple_debug_info("oscar", "Closing auth connection...\n");
! 1177: flap_connection_schedule_destroy(conn, OSCAR_DISCONNECT_DONE, NULL);
! 1178:
! 1179: for (i = 0; i < strlen(info->bosip); i++) {
! 1180: if (info->bosip[i] == ':') {
! 1181: port = atoi(&(info->bosip[i+1]));
! 1182: break;
! 1183: }
! 1184: }
! 1185: host = g_strndup(info->bosip, i);
! 1186: newconn = flap_connection_new(od, SNAC_FAMILY_LOCATE);
! 1187: newconn->cookielen = info->cookielen;
! 1188: newconn->cookie = g_memdup(info->cookie, info->cookielen);
! 1189:
! 1190: if (od->use_ssl)
! 1191: {
! 1192: /*
! 1193: * This shouldn't be hardcoded to "bos.oscar.aol.com" except that
! 1194: * the server isn't sending us a name to use for comparing the
! 1195: * certificate common name.
! 1196: */
! 1197: newconn->gsc = purple_ssl_connect_with_ssl_cn(account, host, port,
! 1198: ssl_connection_established_cb, ssl_connection_error_cb,
! 1199: "bos.oscar.aol.com", newconn);
! 1200: }
! 1201: else
! 1202: {
! 1203: newconn->connect_data = purple_proxy_connect(NULL, account, host, port,
! 1204: connection_established_cb, newconn);
! 1205: }
! 1206:
! 1207: g_free(host);
! 1208: if (newconn->gsc == NULL && newconn->connect_data == NULL)
! 1209: {
! 1210: purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Unable to connect"));
! 1211: return 0;
! 1212: }
! 1213:
! 1214: purple_connection_update_progress(gc, _("Received authorization"), 3, OSCAR_CONNECT_STEPS);
! 1215:
! 1216: return 1;
! 1217: }
! 1218:
! 1219: /**
! 1220: * Only used when connecting with the old-style BUCP login.
! 1221: */
! 1222: static void
! 1223: purple_parse_auth_securid_request_yes_cb(gpointer user_data, const char *msg)
! 1224: {
! 1225: PurpleConnection *gc = user_data;
! 1226: OscarData *od = purple_connection_get_protocol_data(gc);
! 1227:
! 1228: aim_auth_securid_send(od, msg);
! 1229: }
! 1230:
! 1231: /**
! 1232: * Only used when connecting with the old-style BUCP login.
! 1233: */
! 1234: static void
! 1235: purple_parse_auth_securid_request_no_cb(gpointer user_data, const char *value)
! 1236: {
! 1237: PurpleConnection *gc = user_data;
! 1238:
! 1239: /* Disconnect */
! 1240: purple_connection_error_reason(gc,
! 1241: PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
! 1242: _("The SecurID key entered is invalid"));
! 1243: }
! 1244:
! 1245: /**
! 1246: * Only used when connecting with the old-style BUCP login.
! 1247: */
! 1248: static int
! 1249: purple_parse_auth_securid_request(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
! 1250: {
! 1251: PurpleConnection *gc = od->gc;
! 1252: PurpleAccount *account = purple_connection_get_account(gc);
! 1253: gchar *primary;
! 1254:
! 1255: purple_debug_info("oscar", "Got SecurID request\n");
! 1256:
! 1257: primary = g_strdup_printf("Enter the SecurID key for %s.", purple_account_get_username(account));
! 1258: purple_request_input(gc, NULL, _("Enter SecurID"), primary,
! 1259: _("Enter the 6 digit number from the digital display."),
! 1260: FALSE, FALSE, NULL,
! 1261: _("_OK"), G_CALLBACK(purple_parse_auth_securid_request_yes_cb),
! 1262: _("_Cancel"), G_CALLBACK(purple_parse_auth_securid_request_no_cb),
! 1263: account, NULL, NULL,
! 1264: gc);
! 1265: g_free(primary);
! 1266:
! 1267: return 1;
! 1268: }
! 1269:
! 1270: /**
! 1271: * Only used when connecting with the old-style BUCP login.
! 1272: */
! 1273: static int
! 1274: purple_parse_login(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
! 1275: {
! 1276: PurpleConnection *gc;
! 1277: PurpleAccount *account;
! 1278: ClientInfo aiminfo = CLIENTINFO_PURPLE_AIM;
! 1279: ClientInfo icqinfo = CLIENTINFO_PURPLE_ICQ;
! 1280: va_list ap;
! 1281: char *key;
! 1282: gboolean truncate_pass;
! 1283:
! 1284: gc = od->gc;
! 1285: account = purple_connection_get_account(gc);
! 1286:
! 1287: va_start(ap, fr);
! 1288: key = va_arg(ap, char *);
! 1289: truncate_pass = va_arg(ap, int);
! 1290: va_end(ap);
! 1291:
! 1292: aim_send_login(od, conn, purple_account_get_username(account),
! 1293: purple_connection_get_password(gc), truncate_pass,
! 1294: od->icq ? &icqinfo : &aiminfo, key,
! 1295: purple_account_get_bool(account, "allow_multiple_logins", OSCAR_DEFAULT_ALLOW_MULTIPLE_LOGINS));
! 1296:
! 1297: purple_connection_update_progress(gc, _("Password sent"), 2, OSCAR_CONNECT_STEPS);
! 1298:
! 1299: return 1;
! 1300: }
! 1301:
! 1302: static int
! 1303: purple_handle_redirect(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
! 1304: {
! 1305: PurpleConnection *gc = od->gc;
! 1306: PurpleAccount *account = purple_connection_get_account(gc);
! 1307: char *host, *separator;
! 1308: int port;
! 1309: FlapConnection *newconn;
! 1310: va_list ap;
! 1311: struct aim_redirect_data *redir;
! 1312:
! 1313: va_start(ap, fr);
! 1314: redir = va_arg(ap, struct aim_redirect_data *);
! 1315: va_end(ap);
! 1316:
! 1317: port = od->default_port;
! 1318: separator = strchr(redir->ip, ':');
! 1319: if (separator != NULL)
! 1320: {
! 1321: host = g_strndup(redir->ip, separator - redir->ip);
! 1322: port = atoi(separator + 1);
! 1323: }
! 1324: else
! 1325: host = g_strdup(redir->ip);
! 1326:
! 1327: if (!redir->use_ssl) {
! 1328: const gchar *encryption_type = purple_account_get_string(account, "encryption", OSCAR_DEFAULT_ENCRYPTION);
! 1329: if (purple_strequal(encryption_type, OSCAR_OPPORTUNISTIC_ENCRYPTION)) {
! 1330: purple_debug_warning("oscar", "We won't use SSL for FLAP type 0x%04hx.\n", redir->group);
! 1331: } else if (purple_strequal(encryption_type, OSCAR_REQUIRE_ENCRYPTION)) {
! 1332: purple_debug_error("oscar", "FLAP server %s:%d of type 0x%04hx doesn't support encryption.", host, port, redir->group);
! 1333: purple_connection_error_reason(
! 1334: gc,
! 1335: PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT,
! 1336: _("You required encryption in your account settings, but one of the servers doesn't support it."));
! 1337: return 0;
! 1338: }
! 1339: }
! 1340:
! 1341: /*
! 1342: * These FLAP servers advertise SSL (type "0x02"), but SSL connections to these hosts
! 1343: * die a painful death. iChat and Miranda, when using SSL, still do these in plaintext.
! 1344: */
! 1345: if (redir->use_ssl && (redir->group == SNAC_FAMILY_ADMIN ||
! 1346: redir->group == SNAC_FAMILY_BART))
! 1347: {
! 1348: purple_debug_info("oscar", "Ignoring broken SSL for FLAP type 0x%04hx.\n", redir->group);
! 1349: redir->use_ssl = 0;
! 1350: }
! 1351:
! 1352: purple_debug_info("oscar", "Connecting to FLAP server %s:%d of type 0x%04hx\n", host, port, redir->group);
! 1353:
! 1354: newconn = flap_connection_new(od, redir->group);
! 1355: newconn->cookielen = redir->cookielen;
! 1356: newconn->cookie = g_memdup(redir->cookie, redir->cookielen);
! 1357: if (newconn->type == SNAC_FAMILY_CHAT)
! 1358: {
! 1359: struct chat_connection *cc;
! 1360: cc = g_new0(struct chat_connection, 1);
! 1361: cc->conn = newconn;
! 1362: cc->gc = gc;
! 1363: cc->name = g_strdup(redir->chat.room);
! 1364: cc->exchange = redir->chat.exchange;
! 1365: cc->instance = redir->chat.instance;
! 1366: cc->show = extract_name(redir->chat.room);
! 1367: newconn->new_conn_data = cc;
! 1368: purple_debug_info("oscar", "Connecting to chat room %s exchange %hu\n", cc->name, cc->exchange);
! 1369: }
! 1370:
! 1371:
! 1372: if (redir->use_ssl)
! 1373: {
! 1374: newconn->gsc = purple_ssl_connect_with_ssl_cn(account, host, port,
! 1375: ssl_connection_established_cb, ssl_connection_error_cb,
! 1376: redir->ssl_cert_cn, newconn);
! 1377: }
! 1378: else
! 1379: {
! 1380: newconn->connect_data = purple_proxy_connect(NULL, account, host, port,
! 1381: connection_established_cb, newconn);
! 1382: }
! 1383:
! 1384: if (newconn->gsc == NULL && newconn->connect_data == NULL)
! 1385: {
! 1386: flap_connection_schedule_destroy(newconn,
! 1387: OSCAR_DISCONNECT_COULD_NOT_CONNECT,
! 1388: _("Unable to initialize connection"));
! 1389: purple_debug_error("oscar", "Unable to connect to FLAP server "
! 1390: "of type 0x%04hx\n", redir->group);
! 1391: }
! 1392: g_free(host);
! 1393:
! 1394: return 1;
! 1395: }
! 1396:
! 1397:
! 1398: static int purple_parse_oncoming(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
! 1399: {
! 1400: PurpleConnection *gc;
! 1401: PurpleAccount *account;
! 1402: PurpleBuddy *buddy = NULL;
! 1403: PurpleStatus *previous_status = NULL;
! 1404: struct buddyinfo *bi;
! 1405: time_t time_idle = 0, signon = 0;
! 1406: int type = 0;
! 1407: gboolean buddy_is_away = FALSE;
! 1408: const char *status_id;
! 1409: va_list ap;
! 1410: aim_userinfo_t *info;
! 1411: char *message;
! 1412: char *itmsurl = NULL;
! 1413:
! 1414: gc = od->gc;
! 1415: account = purple_connection_get_account(gc);
! 1416:
! 1417: va_start(ap, fr);
! 1418: info = va_arg(ap, aim_userinfo_t *);
! 1419: va_end(ap);
! 1420:
! 1421: g_return_val_if_fail(info != NULL, 1);
! 1422: g_return_val_if_fail(info->bn != NULL, 1);
! 1423:
! 1424: buddy = purple_find_buddy(account, info->bn);
! 1425: if (buddy) {
! 1426: previous_status = purple_presence_get_active_status(purple_buddy_get_presence(buddy));
! 1427: }
! 1428:
! 1429: /*
! 1430: * If this is an AIM buddy and their name has formatting, set their
! 1431: * server alias.
! 1432: */
! 1433: if (!oscar_util_valid_name_icq(info->bn)) {
! 1434: gboolean bn_has_formatting = FALSE;
! 1435: char *c;
! 1436: for (c = info->bn; *c != '\0'; c++) {
! 1437: if (!islower(*c)) {
! 1438: bn_has_formatting = TRUE;
! 1439: break;
! 1440: }
! 1441: }
! 1442: serv_got_alias(gc, info->bn,
! 1443: bn_has_formatting ? info->bn : NULL);
! 1444: }
! 1445:
! 1446: if (info->present & AIM_USERINFO_PRESENT_FLAGS) {
! 1447: if (info->flags & AIM_FLAG_AWAY)
! 1448: buddy_is_away = TRUE;
! 1449: }
! 1450: if (info->present & AIM_USERINFO_PRESENT_ICQEXTSTATUS) {
! 1451: type = info->icqinfo.status;
! 1452: if (!(info->icqinfo.status & AIM_ICQ_STATE_CHAT) &&
! 1453: (info->icqinfo.status != AIM_ICQ_STATE_NORMAL)) {
! 1454: buddy_is_away = TRUE;
! 1455: }
! 1456: }
! 1457:
! 1458: if (oscar_util_valid_name_icq(info->bn)) {
! 1459: if (type & AIM_ICQ_STATE_CHAT)
! 1460: status_id = OSCAR_STATUS_ID_FREE4CHAT;
! 1461: else if (type & AIM_ICQ_STATE_DND)
! 1462: status_id = OSCAR_STATUS_ID_DND;
! 1463: else if (type & AIM_ICQ_STATE_OUT)
! 1464: status_id = OSCAR_STATUS_ID_NA;
! 1465: else if (type & AIM_ICQ_STATE_BUSY)
! 1466: status_id = OSCAR_STATUS_ID_OCCUPIED;
! 1467: else if (type & AIM_ICQ_STATE_AWAY)
! 1468: status_id = OSCAR_STATUS_ID_AWAY;
! 1469: else if (type & AIM_ICQ_STATE_INVISIBLE)
! 1470: status_id = OSCAR_STATUS_ID_INVISIBLE;
! 1471: else if (type & AIM_ICQ_STATE_EVIL)
! 1472: status_id = OSCAR_STATUS_ID_EVIL;
! 1473: else if (type & AIM_ICQ_STATE_DEPRESSION)
! 1474: status_id = OSCAR_STATUS_ID_DEPRESSION;
! 1475: else if (type & AIM_ICQ_STATE_ATHOME)
! 1476: status_id = OSCAR_STATUS_ID_ATHOME;
! 1477: else if (type & AIM_ICQ_STATE_ATWORK)
! 1478: status_id = OSCAR_STATUS_ID_ATWORK;
! 1479: else if (type & AIM_ICQ_STATE_LUNCH)
! 1480: status_id = OSCAR_STATUS_ID_LUNCH;
! 1481: else
! 1482: status_id = OSCAR_STATUS_ID_AVAILABLE;
! 1483: } else {
! 1484: if (type & AIM_ICQ_STATE_INVISIBLE)
! 1485: status_id = OSCAR_STATUS_ID_INVISIBLE;
! 1486: else if (buddy_is_away)
! 1487: status_id = OSCAR_STATUS_ID_AWAY;
! 1488: else
! 1489: status_id = OSCAR_STATUS_ID_AVAILABLE;
! 1490: }
! 1491:
! 1492: if (info->flags & AIM_FLAG_WIRELESS) {
! 1493: purple_prpl_got_user_status(account, info->bn, OSCAR_STATUS_ID_MOBILE, NULL);
! 1494: } else {
! 1495: purple_prpl_got_user_status_deactive(account, info->bn, OSCAR_STATUS_ID_MOBILE);
! 1496: }
! 1497:
! 1498: message = (info->status && info->status_len > 0)
! 1499: ? oscar_encoding_to_utf8(info->status_encoding, info->status, info->status_len)
! 1500: : NULL;
! 1501:
! 1502: if (purple_strequal(status_id, OSCAR_STATUS_ID_AVAILABLE)) {
! 1503: /* TODO: If itmsurl is NULL, does that mean the URL has been
! 1504: cleared? Or does it mean the URL should remain unchanged? */
! 1505: if (info->itmsurl != NULL) {
! 1506: itmsurl = (info->itmsurl_len > 0) ? oscar_encoding_to_utf8(info->itmsurl_encoding, info->itmsurl, info->itmsurl_len) : NULL;
! 1507: } else if (previous_status != NULL && purple_status_is_available(previous_status)) {
! 1508: itmsurl = g_strdup(purple_status_get_attr_string(previous_status, "itmsurl"));
! 1509: }
! 1510: purple_debug_info("oscar", "Activating status '%s' for buddy %s, message = '%s', itmsurl = '%s'\n", status_id, info->bn, message ? message : "(null)", itmsurl ? itmsurl : "(null)");
! 1511: purple_prpl_got_user_status(account, info->bn, status_id, "message", message, "itmsurl", itmsurl, NULL);
! 1512: } else {
! 1513: purple_debug_info("oscar", "Activating status '%s' for buddy %s, message = '%s'\n", status_id, info->bn, message ? message : "(null)");
! 1514: purple_prpl_got_user_status(account, info->bn, status_id, "message", message, NULL);
! 1515: }
! 1516:
! 1517: g_free(message);
! 1518: g_free(itmsurl);
! 1519:
! 1520: /* Login time stuff */
! 1521: if (info->present & AIM_USERINFO_PRESENT_ONLINESINCE)
! 1522: signon = info->onlinesince;
! 1523: else if (info->present & AIM_USERINFO_PRESENT_SESSIONLEN)
! 1524: signon = time(NULL) - info->sessionlen;
! 1525: purple_prpl_got_user_login_time(account, info->bn, signon);
! 1526:
! 1527: /* Idle time stuff */
! 1528: /* info->idletime is the number of minutes that this user has been idle */
! 1529: if (info->present & AIM_USERINFO_PRESENT_IDLE)
! 1530: time_idle = time(NULL) - info->idletime * 60;
! 1531:
! 1532: if (time_idle > 0)
! 1533: purple_prpl_got_user_idle(account, info->bn, TRUE, time_idle);
! 1534: else
! 1535: purple_prpl_got_user_idle(account, info->bn, FALSE, 0);
! 1536:
! 1537: /* Server stored icon stuff */
! 1538: bi = g_hash_table_lookup(od->buddyinfo, purple_normalize(account, info->bn));
! 1539: if (!bi) {
! 1540: bi = g_new0(struct buddyinfo, 1);
! 1541: g_hash_table_insert(od->buddyinfo, g_strdup(purple_normalize(account, info->bn)), bi);
! 1542: }
! 1543: bi->typingnot = FALSE;
! 1544: bi->ico_informed = FALSE;
! 1545: bi->ipaddr = info->icqinfo.ipaddr;
! 1546:
! 1547: if (info->iconcsumlen) {
! 1548: const char *saved_b16 = NULL;
! 1549: char *b16 = NULL;
! 1550: PurpleBuddy *b = NULL;
! 1551:
! 1552: b16 = purple_base16_encode(info->iconcsum, info->iconcsumlen);
! 1553: b = purple_find_buddy(account, info->bn);
! 1554: if (b != NULL)
! 1555: saved_b16 = purple_buddy_icons_get_checksum_for_user(b);
! 1556:
! 1557: if (!b16 || !saved_b16 || !purple_strequal(b16, saved_b16)) {
! 1558: /* Invalidate the old icon for this user */
! 1559: purple_buddy_icons_set_for_user(account, info->bn, NULL, 0, NULL);
! 1560:
! 1561: /* Fetch the new icon (if we're not already doing so) */
! 1562: if (g_slist_find_custom(od->requesticon, info->bn,
! 1563: (GCompareFunc)oscar_util_name_compare) == NULL)
! 1564: {
! 1565: od->requesticon = g_slist_prepend(od->requesticon,
! 1566: g_strdup(purple_normalize(account, info->bn)));
! 1567: purple_icons_fetch(gc);
! 1568: }
! 1569: }
! 1570: g_free(b16);
! 1571: }
! 1572:
! 1573: return 1;
! 1574: }
! 1575:
! 1576: static int purple_parse_offgoing(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
! 1577: PurpleConnection *gc = od->gc;
! 1578: PurpleAccount *account = purple_connection_get_account(gc);
! 1579: va_list ap;
! 1580: aim_userinfo_t *info;
! 1581:
! 1582: va_start(ap, fr);
! 1583: info = va_arg(ap, aim_userinfo_t *);
! 1584: va_end(ap);
! 1585:
! 1586: purple_prpl_got_user_status(account, info->bn, OSCAR_STATUS_ID_OFFLINE, NULL);
! 1587: purple_prpl_got_user_status_deactive(account, info->bn, OSCAR_STATUS_ID_MOBILE);
! 1588: g_hash_table_remove(od->buddyinfo, purple_normalize(gc->account, info->bn));
! 1589:
! 1590: return 1;
! 1591: }
! 1592:
! 1593: static int incomingim_chan1(OscarData *od, FlapConnection *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch1_args *args) {
! 1594: PurpleConnection *gc = od->gc;
! 1595: PurpleAccount *account = purple_connection_get_account(gc);
! 1596: PurpleMessageFlags flags = 0;
! 1597: struct buddyinfo *bi;
! 1598: PurpleStoredImage *img;
! 1599: gchar *tmp;
! 1600: const char *start, *end;
! 1601: GData *attribs;
! 1602:
! 1603: purple_debug_misc("oscar", "Received IM from %s\n", userinfo->bn);
! 1604:
! 1605: bi = g_hash_table_lookup(od->buddyinfo, purple_normalize(account, userinfo->bn));
! 1606: if (!bi) {
! 1607: bi = g_new0(struct buddyinfo, 1);
! 1608: g_hash_table_insert(od->buddyinfo, g_strdup(purple_normalize(account, userinfo->bn)), bi);
! 1609: }
! 1610:
! 1611: if (args->icbmflags & AIM_IMFLAGS_AWAY)
! 1612: flags |= PURPLE_MESSAGE_AUTO_RESP;
! 1613:
! 1614: if (args->icbmflags & AIM_IMFLAGS_TYPINGNOT)
! 1615: bi->typingnot = TRUE;
! 1616: else
! 1617: bi->typingnot = FALSE;
! 1618:
! 1619: if ((args->icbmflags & AIM_IMFLAGS_HASICON) && (args->iconlen) && (args->iconsum) && (args->iconstamp)) {
! 1620: purple_debug_misc("oscar", "%s has an icon\n", userinfo->bn);
! 1621: if ((args->iconlen != bi->ico_len) || (args->iconsum != bi->ico_csum) || (args->iconstamp != bi->ico_time)) {
! 1622: bi->ico_need = TRUE;
! 1623: bi->ico_len = args->iconlen;
! 1624: bi->ico_csum = args->iconsum;
! 1625: bi->ico_time = args->iconstamp;
! 1626: }
! 1627: }
! 1628:
! 1629: img = purple_buddy_icons_find_account_icon(account);
! 1630: if ((img != NULL) &&
! 1631: (args->icbmflags & AIM_IMFLAGS_BUDDYREQ) && !bi->ico_sent && bi->ico_informed) {
! 1632: gconstpointer data = purple_imgstore_get_data(img);
! 1633: size_t len = purple_imgstore_get_size(img);
! 1634: purple_debug_info("oscar",
! 1635: "Sending buddy icon to %s (%" G_GSIZE_FORMAT " bytes)\n",
! 1636: userinfo->bn, len);
! 1637: aim_im_sendch2_icon(od, userinfo->bn, data, len,
! 1638: purple_buddy_icons_get_account_icon_timestamp(account),
! 1639: aimutil_iconsum(data, len));
! 1640: }
! 1641: purple_imgstore_unref(img);
! 1642:
! 1643: tmp = g_strdup(args->msg);
! 1644:
! 1645: /*
! 1646: * Convert iChat color tags to normal font tags.
! 1647: */
! 1648: if (purple_markup_find_tag("body", tmp, &start, &end, &attribs))
! 1649: {
! 1650: int len;
! 1651: char *tmp2, *body;
! 1652: const char *ichattextcolor, *ichatballooncolor;
! 1653: const char *slash_body_start, *slash_body_end = NULL; /* </body> */
! 1654: GData *unused;
! 1655:
! 1656: /*
! 1657: * Find the ending </body> so we can strip off the outer <html/>
! 1658: * and <body/>
! 1659: */
! 1660: if (purple_markup_find_tag("/body", end + 1, &slash_body_start, &slash_body_end, &unused))
! 1661: {
! 1662: body = g_strndup(start, slash_body_end - start + 1);
! 1663: g_datalist_clear(&unused);
! 1664: }
! 1665: else
! 1666: {
! 1667: purple_debug_warning("oscar", "Broken message contains <body> but not </body>!\n");
! 1668: /* Take everything after <body> */
! 1669: body = g_strdup(start);
! 1670: }
! 1671:
! 1672: ichattextcolor = g_datalist_get_data(&attribs, "ichattextcolor");
! 1673: if (ichattextcolor != NULL)
! 1674: {
! 1675: tmp2 = g_strdup_printf("<font color=\"%s\">%s</font>", ichattextcolor, body);
! 1676: g_free(body);
! 1677: body = tmp2;
! 1678: }
! 1679:
! 1680: ichatballooncolor = g_datalist_get_data(&attribs, "ichatballooncolor");
! 1681: if (ichatballooncolor != NULL)
! 1682: {
! 1683: tmp2 = g_strdup_printf("<font back=\"%s\">%s</font>", ichatballooncolor, body);
! 1684: g_free(body);
! 1685: body = tmp2;
! 1686: }
! 1687:
! 1688: g_datalist_clear(&attribs);
! 1689:
! 1690: len = start - tmp;
! 1691: tmp2 = g_strdup_printf("%.*s%s%s", len, tmp, body, slash_body_end ? slash_body_end + 1: "</body>");
! 1692: g_free(tmp);
! 1693: g_free(body);
! 1694:
! 1695: tmp = tmp2;
! 1696: }
! 1697:
! 1698: /*
! 1699: * Are there <html/> surrounding tags? If so, strip them out, too.
! 1700: */
! 1701: if (purple_markup_find_tag("html", tmp, &start, &end, &attribs))
! 1702: {
! 1703: gchar *tmp2;
! 1704: int len;
! 1705:
! 1706: g_datalist_clear(&attribs);
! 1707:
! 1708: len = start - tmp;
! 1709: tmp2 = g_strdup_printf("%.*s%s", len, tmp, end + 1);
! 1710: g_free(tmp);
! 1711: tmp = tmp2;
! 1712: }
! 1713:
! 1714: if (purple_markup_find_tag("/html", tmp, &start, &end, &attribs))
! 1715: {
! 1716: gchar *tmp2;
! 1717: int len;
! 1718:
! 1719: g_datalist_clear(&attribs);
! 1720:
! 1721: len = start - tmp;
! 1722: tmp2 = g_strdup_printf("%.*s%s", len, tmp, end + 1);
! 1723: g_free(tmp);
! 1724: tmp = tmp2;
! 1725: }
! 1726:
! 1727: serv_got_im(gc, userinfo->bn, tmp, flags, (args->icbmflags & AIM_IMFLAGS_OFFLINE) ? args->timestamp : time(NULL));
! 1728: g_free(tmp);
! 1729:
! 1730: return 1;
! 1731: }
! 1732:
! 1733: static int
! 1734: incomingim_chan2(OscarData *od, FlapConnection *conn, aim_userinfo_t *userinfo, IcbmArgsCh2 *args)
! 1735: {
! 1736: PurpleConnection *gc;
! 1737: PurpleAccount *account;
! 1738: PurpleMessageFlags flags = 0;
! 1739: char *message = NULL;
! 1740:
! 1741: g_return_val_if_fail(od != NULL, 0);
! 1742: g_return_val_if_fail(od->gc != NULL, 0);
! 1743:
! 1744: gc = od->gc;
! 1745: account = purple_connection_get_account(gc);
! 1746: od = purple_connection_get_protocol_data(gc);
! 1747:
! 1748: if (args == NULL)
! 1749: return 0;
! 1750:
! 1751: purple_debug_misc("oscar", "Incoming rendezvous message of type %"
! 1752: G_GUINT64_FORMAT ", user %s, status %hu\n",
! 1753: args->type, userinfo->bn, args->status);
! 1754:
! 1755: if (args->msg != NULL) {
! 1756: message = oscar_encoding_to_utf8(args->encoding, args->msg, args->msglen);
! 1757: }
! 1758:
! 1759: if (args->type & OSCAR_CAPABILITY_CHAT)
! 1760: {
! 1761: char *utf8name, *tmp;
! 1762: GHashTable *components;
! 1763:
! 1764: if (!args->info.chat.roominfo.name || !args->info.chat.roominfo.exchange) {
! 1765: g_free(message);
! 1766: return 1;
! 1767: }
! 1768: utf8name = oscar_encoding_to_utf8(args->encoding, args->info.chat.roominfo.name, args->info.chat.roominfo.namelen);
! 1769:
! 1770: tmp = extract_name(utf8name);
! 1771: if (tmp != NULL)
! 1772: {
! 1773: g_free(utf8name);
! 1774: utf8name = tmp;
! 1775: }
! 1776:
! 1777: components = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
! 1778: g_free);
! 1779: g_hash_table_replace(components, g_strdup("room"), utf8name);
! 1780: g_hash_table_replace(components, g_strdup("exchange"),
! 1781: g_strdup_printf("%d", args->info.chat.roominfo.exchange));
! 1782: serv_got_chat_invite(gc,
! 1783: utf8name,
! 1784: userinfo->bn,
! 1785: message,
! 1786: components);
! 1787: }
! 1788:
! 1789: else if ((args->type & OSCAR_CAPABILITY_SENDFILE) || (args->type & OSCAR_CAPABILITY_DIRECTIM))
! 1790: {
! 1791: if (args->status == AIM_RENDEZVOUS_PROPOSE)
! 1792: {
! 1793: peer_connection_got_proposition(od, userinfo->bn, message, args);
! 1794: }
! 1795: else if (args->status == AIM_RENDEZVOUS_CANCEL)
! 1796: {
! 1797: /* The other user cancelled a peer request */
! 1798: PeerConnection *conn;
! 1799:
! 1800: conn = peer_connection_find_by_cookie(od, userinfo->bn, args->cookie);
! 1801: /*
! 1802: * If conn is NULL it means we haven't tried to create
! 1803: * a connection with that user. They may be trying to
! 1804: * do something malicious.
! 1805: */
! 1806: if (conn != NULL)
! 1807: {
! 1808: peer_connection_destroy(conn, OSCAR_DISCONNECT_REMOTE_CLOSED, NULL);
! 1809: }
! 1810: }
! 1811: else if (args->status == AIM_RENDEZVOUS_CONNECTED)
! 1812: {
! 1813: /*
! 1814: * Remote user has accepted our peer request. If we
! 1815: * wanted to we could look up the PeerConnection using
! 1816: * args->cookie, but we don't need to do anything here.
! 1817: */
! 1818: }
! 1819: }
! 1820:
! 1821: else if (args->type & OSCAR_CAPABILITY_GETFILE)
! 1822: {
! 1823: }
! 1824:
! 1825: else if (args->type & OSCAR_CAPABILITY_TALK)
! 1826: {
! 1827: }
! 1828:
! 1829: else if (args->type & OSCAR_CAPABILITY_BUDDYICON)
! 1830: {
! 1831: purple_buddy_icons_set_for_user(account, userinfo->bn,
! 1832: g_memdup(args->info.icon.icon, args->info.icon.length),
! 1833: args->info.icon.length,
! 1834: NULL);
! 1835: }
! 1836:
! 1837: else if (args->type & OSCAR_CAPABILITY_ICQSERVERRELAY)
! 1838: {
! 1839: purple_debug_info("oscar", "Got an ICQ Server Relay message of "
! 1840: "type %d\n", args->info.rtfmsg.msgtype);
! 1841:
! 1842: if (args->info.rtfmsg.msgtype == 1) {
! 1843: if (args->info.rtfmsg.msg != NULL) {
! 1844: char *rtfmsg;
! 1845: const char *encoding = args->encoding;
! 1846: size_t len = strlen(args->info.rtfmsg.msg);
! 1847: char *tmp, *tmp2;
! 1848:
! 1849: if (encoding == NULL && !g_utf8_validate(args->info.rtfmsg.msg, len, NULL)) {
! 1850: /* Yet another wonderful Miranda-related hack. If their user disables the "Send Unicode messages" setting,
! 1851: * Miranda sends us ch2 messages in whatever Windows codepage is set as default on their user's system (instead of UTF-8).
! 1852: * Of course, they don't bother to specify that codepage. Let's just fallback to the encoding OUR users can
! 1853: * specify in account options as a last resort.
! 1854: */
! 1855: encoding = purple_account_get_string(account, "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING);
! 1856: purple_debug_info("oscar", "Miranda, is that you? Using '%s' as encoding\n", encoding);
! 1857: }
! 1858:
! 1859: rtfmsg = oscar_encoding_to_utf8(encoding, args->info.rtfmsg.msg, len);
! 1860:
! 1861: /* Channel 2 messages are supposed to be plain-text (never mind the name "rtfmsg", even
! 1862: * the official client doesn't parse them as RTF). Therefore, we should escape them before
! 1863: * showing to the user. */
! 1864: tmp = g_markup_escape_text(rtfmsg, -1);
! 1865: g_free(rtfmsg);
! 1866: tmp2 = purple_strreplace(tmp, "\r\n", "<br>");
! 1867: g_free(tmp);
! 1868:
! 1869: serv_got_im(gc, userinfo->bn, tmp2, flags, time(NULL));
! 1870: aim_im_send_icq_confirmation(od, userinfo->bn, args->cookie);
! 1871: g_free(tmp2);
! 1872: }
! 1873: } else if (args->info.rtfmsg.msgtype == 26) {
! 1874: purple_debug_info("oscar", "Sending X-Status Reply\n");
! 1875: icq_relay_xstatus(od, userinfo->bn, args->cookie);
! 1876: }
! 1877: }
! 1878: else
! 1879: {
! 1880: purple_debug_error("oscar", "Unknown request class %"
! 1881: G_GUINT64_FORMAT "\n", args->type);
! 1882: }
! 1883:
! 1884: g_free(message);
! 1885:
! 1886: return 1;
! 1887: }
! 1888:
! 1889: /* When someone sends you buddies */
! 1890: static void
! 1891: purple_icq_buddyadd(struct name_data *data)
! 1892: {
! 1893: PurpleConnection *gc = data->gc;
! 1894:
! 1895: purple_blist_request_add_buddy(purple_connection_get_account(gc), data->name, NULL, data->nick);
! 1896:
! 1897: oscar_free_name_data(data);
! 1898: }
! 1899:
! 1900: static int
! 1901: incomingim_chan4(OscarData *od, FlapConnection *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch4_args *args, time_t t)
! 1902: {
! 1903: PurpleConnection *gc = od->gc;
! 1904: PurpleAccount *account = purple_connection_get_account(gc);
! 1905: gchar **msg1, **msg2;
! 1906: int i, numtoks;
! 1907:
! 1908: if (!args->type || !args->msg || !args->uin)
! 1909: return 1;
! 1910:
! 1911: purple_debug_info("oscar",
! 1912: "Received a channel 4 message of type 0x%02hx.\n",
! 1913: (guint16)args->type);
! 1914:
! 1915: /*
! 1916: * Split up the message at the delimeter character, then convert each
! 1917: * string to UTF-8. Unless, of course, this is a type 1 message. If
! 1918: * this is a type 1 message, then the delimiter 0xfe could be a valid
! 1919: * character in whatever encoding the message was sent in. Type 1
! 1920: * messages are always made up of only one part, so we can easily account
! 1921: * for this suck-ass part of the protocol by splitting the string into at
! 1922: * most 1 baby string.
! 1923: */
! 1924: msg1 = g_strsplit(args->msg, "\376", (args->type == 0x01 ? 1 : 0));
! 1925: for (numtoks=0; msg1[numtoks]; numtoks++);
! 1926: msg2 = (gchar **)g_malloc((numtoks+1)*sizeof(gchar *));
! 1927: for (i=0; msg1[i]; i++) {
! 1928: gchar *uin = g_strdup_printf("%u", args->uin);
! 1929:
! 1930: purple_str_strip_char(msg1[i], '\r');
! 1931: /* TODO: Should use an encoding other than ASCII? */
! 1932: msg2[i] = oscar_decode_im(account, uin, AIM_CHARSET_ASCII, msg1[i], strlen(msg1[i]));
! 1933: g_free(uin);
! 1934: }
! 1935: msg2[i] = NULL;
! 1936:
! 1937: switch (args->type) {
! 1938: case 0x01: { /* MacICQ message or basic offline message */
! 1939: if (i >= 1) {
! 1940: gchar *uin = g_strdup_printf("%u", args->uin);
! 1941: gchar *tmp;
! 1942:
! 1943: /* If the message came from an ICQ user then escape any HTML */
! 1944: tmp = g_markup_escape_text(msg2[0], -1);
! 1945:
! 1946: if (t) { /* This is an offline message */
! 1947: /* The timestamp is UTC-ish, so we need to get the offset */
! 1948: #ifdef HAVE_TM_GMTOFF
! 1949: time_t now;
! 1950: struct tm *tm;
! 1951: now = time(NULL);
! 1952: tm = localtime(&now);
! 1953: t += tm->tm_gmtoff;
! 1954: #else
! 1955: # ifdef HAVE_TIMEZONE
! 1956: tzset();
! 1957: t -= timezone;
! 1958: # endif
! 1959: #endif
! 1960: serv_got_im(gc, uin, tmp, 0, t);
! 1961: } else { /* This is a message from MacICQ/Miranda */
! 1962: serv_got_im(gc, uin, tmp, 0, time(NULL));
! 1963: }
! 1964: g_free(uin);
! 1965: g_free(tmp);
! 1966: }
! 1967: } break;
! 1968:
! 1969: case 0x04: { /* Someone sent you a URL */
! 1970: if (i >= 2) {
! 1971: if (msg2[1] != NULL) {
! 1972: gchar *uin = g_strdup_printf("%u", args->uin);
! 1973: gchar *message = g_strdup_printf("<A HREF=\"%s\">%s</A>",
! 1974: msg2[1],
! 1975: (msg2[0] && msg2[0][0]) ? msg2[0] : msg2[1]);
! 1976: serv_got_im(gc, uin, message, 0, time(NULL));
! 1977: g_free(uin);
! 1978: g_free(message);
! 1979: }
! 1980: }
! 1981: } break;
! 1982:
! 1983: case 0x06: { /* Someone requested authorization */
! 1984: if (i >= 6) {
! 1985: gchar *bn = g_strdup_printf("%u", args->uin);
! 1986: gchar *reason = NULL;
! 1987:
! 1988: if (msg2[5] != NULL)
! 1989: reason = oscar_decode_im(account, bn, AIM_CHARSET_LATIN_1, msg2[5], strlen(msg2[5]));
! 1990:
! 1991: purple_debug_info("oscar",
! 1992: "Received an authorization request from UIN %u\n",
! 1993: args->uin);
! 1994: aim_icq_getalias(od, bn, TRUE, reason);
! 1995: g_free(bn);
! 1996: g_free(reason);
! 1997: }
! 1998: } break;
! 1999:
! 2000: case 0x07: { /* Someone has denied you authorization */
! 2001: if (i >= 1) {
! 2002: gchar *dialog_msg = g_strdup_printf(_("The user %u has denied your request to add them to your buddy list for the following reason:\n%s"), args->uin, msg2[0] ? msg2[0] : _("No reason given."));
! 2003: purple_notify_info(gc, NULL, _("ICQ authorization denied."),
! 2004: dialog_msg);
! 2005: g_free(dialog_msg);
! 2006: }
! 2007: } break;
! 2008:
! 2009: case 0x08: { /* Someone has granted you authorization */
! 2010: gchar *dialog_msg = g_strdup_printf(_("The user %u has granted your request to add them to your buddy list."), args->uin);
! 2011: purple_notify_info(gc, NULL, "ICQ authorization accepted.",
! 2012: dialog_msg);
! 2013: g_free(dialog_msg);
! 2014: } break;
! 2015:
! 2016: case 0x09: { /* Message from the Godly ICQ server itself, I think */
! 2017: if (i >= 5) {
! 2018: gchar *dialog_msg = g_strdup_printf(_("You have received a special message\n\nFrom: %s [%s]\n%s"), msg2[0], msg2[3], msg2[5]);
! 2019: purple_notify_info(gc, NULL, "ICQ Server Message", dialog_msg);
! 2020: g_free(dialog_msg);
! 2021: }
! 2022: } break;
! 2023:
! 2024: case 0x0d: { /* Someone has sent you a pager message from http://www.icq.com/your_uin */
! 2025: if (i >= 6) {
! 2026: gchar *dialog_msg = g_strdup_printf(_("You have received an ICQ page\n\nFrom: %s [%s]\n%s"), msg2[0], msg2[3], msg2[5]);
! 2027: purple_notify_info(gc, NULL, "ICQ Page", dialog_msg);
! 2028: g_free(dialog_msg);
! 2029: }
! 2030: } break;
! 2031:
! 2032: case 0x0e: { /* Someone has emailed you at your_uin@pager.icq.com */
! 2033: if (i >= 6) {
! 2034: gchar *dialog_msg = g_strdup_printf(_("You have received an ICQ email from %s [%s]\n\nMessage is:\n%s"), msg2[0], msg2[3], msg2[5]);
! 2035: purple_notify_info(gc, NULL, "ICQ Email", dialog_msg);
! 2036: g_free(dialog_msg);
! 2037: }
! 2038: } break;
! 2039:
! 2040: case 0x12: {
! 2041: /* Ack for authorizing/denying someone. Or possibly an ack for sending any system notice */
! 2042: /* Someone added you to their buddy list? */
! 2043: } break;
! 2044:
! 2045: case 0x13: { /* Someone has sent you some ICQ buddies */
! 2046: guint i, num;
! 2047: gchar **text;
! 2048: text = g_strsplit(args->msg, "\376", 0);
! 2049: if (text) {
! 2050: /* Read the number of contacts that we were sent */
! 2051: errno = 0;
! 2052: num = text[0] ? strtoul(text[0], NULL, 10) : 0;
! 2053:
! 2054: if (num > 0 && errno == 0) {
! 2055: for (i=0; i<num; i++) {
! 2056: struct name_data *data;
! 2057: gchar *message;
! 2058:
! 2059: if (!text[i*2 + 1] || !text[i*2 + 2]) {
! 2060: /* We're missing the contact name or nickname. Bail out. */
! 2061: gchar *tmp = g_strescape(args->msg, NULL);
! 2062: purple_debug_error("oscar", "Unknown syntax parsing "
! 2063: "ICQ buddies. args->msg=%s\n", tmp);
! 2064: g_free(tmp);
! 2065: break;
! 2066: }
! 2067:
! 2068: message = g_strdup_printf(_("ICQ user %u has sent you a buddy: %s (%s)"), args->uin, text[i*2+2], text[i*2+1]);
! 2069:
! 2070: data = g_new(struct name_data, 1);
! 2071: data->gc = gc;
! 2072: data->name = g_strdup(text[i*2+1]);
! 2073: data->nick = g_strdup(text[i*2+2]);
! 2074:
! 2075: purple_request_action(gc, NULL, message,
! 2076: _("Do you want to add this buddy "
! 2077: "to your buddy list?"),
! 2078: PURPLE_DEFAULT_ACTION_NONE,
! 2079: purple_connection_get_account(gc), data->name, NULL,
! 2080: data, 2,
! 2081: _("_Add"), G_CALLBACK(purple_icq_buddyadd),
! 2082: _("_Decline"), G_CALLBACK(oscar_free_name_data));
! 2083: g_free(message);
! 2084: }
! 2085: } else {
! 2086: gchar *tmp = g_strescape(args->msg, NULL);
! 2087: purple_debug_error("oscar", "Unknown syntax parsing "
! 2088: "ICQ buddies. args->msg=%s\n", tmp);
! 2089: g_free(tmp);
! 2090: }
! 2091: g_strfreev(text);
! 2092: }
! 2093: } break;
! 2094:
! 2095: case 0x1a: { /* Handle SMS or someone has sent you a greeting card or requested buddies? */
! 2096: ByteStream qbs;
! 2097: guint16 smstype;
! 2098: guint32 taglen, smslen;
! 2099: char *tagstr = NULL, *smsmsg = NULL;
! 2100: xmlnode *xmlroot = NULL, *xmltmp = NULL;
! 2101: gchar *uin = NULL, *message = NULL;
! 2102:
! 2103: /* From libicq2000-0.3.2/src/ICQ.cpp */
! 2104: byte_stream_init(&qbs, (guint8 *)args->msg, args->msglen);
! 2105: byte_stream_advance(&qbs, 21);
! 2106: /* expected: 01 00 00 20 00 0e 28 f6 00 11 e7 d3 11 bc f3 00 04 ac 96 9d c2 | 00 00 | 06 00 00 00 | 49 43 51 53 43 53 ...*/
! 2107: /* unexpected: 00 00 26 00 81 1a 18 bc 0e 6c 18 47 a5 91 6f 18 dc c7 6f 1a | 00 00 | 0d 00 00 00 | 49 43 51 57 65 62 4d 65 73 73 61 67 65 ... */
! 2108: smstype = byte_stream_getle16(&qbs);
! 2109: if (smstype != 0)
! 2110: break;
! 2111: taglen = byte_stream_getle32(&qbs);
! 2112: if (taglen > 2000) {
! 2113: /* Avoid trying to allocate large amounts of memory, in
! 2114: case we get something unexpected. */
! 2115: break;
! 2116: }
! 2117: tagstr = byte_stream_getstr(&qbs, taglen);
! 2118: if (tagstr == NULL)
! 2119: break;
! 2120: byte_stream_advance(&qbs, 3);
! 2121: byte_stream_advance(&qbs, 4);
! 2122: smslen = byte_stream_getle32(&qbs);
! 2123: if (smslen > 2000) {
! 2124: /* Avoid trying to allocate large amounts of memory, in
! 2125: case we get something unexpected. */
! 2126: g_free(tagstr);
! 2127: break;
! 2128: }
! 2129: smsmsg = byte_stream_getstr(&qbs, smslen);
! 2130:
! 2131: /* Check if this is an SMS being sent from server */
! 2132: if ((smstype == 0) && (purple_strequal(tagstr, "ICQSMS")) && (smsmsg != NULL))
! 2133: {
! 2134: xmlroot = xmlnode_from_str(smsmsg, -1);
! 2135: if (xmlroot != NULL)
! 2136: {
! 2137: xmltmp = xmlnode_get_child(xmlroot, "sender");
! 2138: if (xmltmp != NULL)
! 2139: uin = xmlnode_get_data(xmltmp);
! 2140:
! 2141: xmltmp = xmlnode_get_child(xmlroot, "text");
! 2142: if (xmltmp != NULL)
! 2143: message = xmlnode_get_data(xmltmp);
! 2144:
! 2145: if ((uin != NULL) && (message != NULL))
! 2146: serv_got_im(gc, uin, message, 0, time(NULL));
! 2147:
! 2148: g_free(uin);
! 2149: g_free(message);
! 2150: xmlnode_free(xmlroot);
! 2151: }
! 2152: }
! 2153: g_free(tagstr);
! 2154: g_free(smsmsg);
! 2155: } break;
! 2156:
! 2157: default: {
! 2158: purple_debug_info("oscar",
! 2159: "Received a channel 4 message of unknown type "
! 2160: "(type 0x%02hhx).\n", args->type);
! 2161: } break;
! 2162: }
! 2163:
! 2164: g_strfreev(msg1);
! 2165: g_strfreev(msg2);
! 2166:
! 2167: return 1;
! 2168: }
! 2169:
! 2170: static int purple_parse_incoming_im(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
! 2171: guint16 channel;
! 2172: int ret = 0;
! 2173: aim_userinfo_t *userinfo;
! 2174: va_list ap;
! 2175:
! 2176: va_start(ap, fr);
! 2177: channel = (guint16)va_arg(ap, unsigned int);
! 2178: userinfo = va_arg(ap, aim_userinfo_t *);
! 2179:
! 2180: switch (channel) {
! 2181: case 1: { /* standard message */
! 2182: struct aim_incomingim_ch1_args *args;
! 2183: args = va_arg(ap, struct aim_incomingim_ch1_args *);
! 2184: ret = incomingim_chan1(od, conn, userinfo, args);
! 2185: } break;
! 2186:
! 2187: case 2: { /* rendezvous */
! 2188: IcbmArgsCh2 *args;
! 2189: args = va_arg(ap, IcbmArgsCh2 *);
! 2190: ret = incomingim_chan2(od, conn, userinfo, args);
! 2191: } break;
! 2192:
! 2193: case 4: { /* ICQ */
! 2194: struct aim_incomingim_ch4_args *args;
! 2195: args = va_arg(ap, struct aim_incomingim_ch4_args *);
! 2196: ret = incomingim_chan4(od, conn, userinfo, args, 0);
! 2197: } break;
! 2198:
! 2199: default: {
! 2200: purple_debug_warning("oscar",
! 2201: "ICBM received on unsupported channel (channel "
! 2202: "0x%04hx).", channel);
! 2203: } break;
! 2204: }
! 2205:
! 2206: va_end(ap);
! 2207:
! 2208: return ret;
! 2209: }
! 2210:
! 2211: static int purple_parse_misses(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
! 2212: PurpleConnection *gc = od->gc;
! 2213: PurpleAccount *account = purple_connection_get_account(gc);
! 2214: char *buf;
! 2215: va_list ap;
! 2216: guint16 nummissed, reason;
! 2217: aim_userinfo_t *userinfo;
! 2218:
! 2219: va_start(ap, fr);
! 2220: va_arg(ap, unsigned int); /* guint16 chan */
! 2221: userinfo = va_arg(ap, aim_userinfo_t *);
! 2222: nummissed = (guint16)va_arg(ap, unsigned int);
! 2223: reason = (guint16)va_arg(ap, unsigned int);
! 2224: va_end(ap);
! 2225:
! 2226: switch(reason) {
! 2227: case 0: /* Invalid (0) */
! 2228: buf = g_strdup_printf(
! 2229: dngettext(PACKAGE,
! 2230: "You missed %hu message from %s because it was invalid.",
! 2231: "You missed %hu messages from %s because they were invalid.",
! 2232: nummissed),
! 2233: nummissed,
! 2234: userinfo->bn);
! 2235: break;
! 2236: case 1: /* Message too large */
! 2237: buf = g_strdup_printf(
! 2238: dngettext(PACKAGE,
! 2239: "You missed %hu message from %s because it was too large.",
! 2240: "You missed %hu messages from %s because they were too large.",
! 2241: nummissed),
! 2242: nummissed,
! 2243: userinfo->bn);
! 2244: break;
! 2245: case 2: /* Rate exceeded */
! 2246: buf = g_strdup_printf(
! 2247: dngettext(PACKAGE,
! 2248: "You missed %hu message from %s because the rate limit has been exceeded.",
! 2249: "You missed %hu messages from %s because the rate limit has been exceeded.",
! 2250: nummissed),
! 2251: nummissed,
! 2252: userinfo->bn);
! 2253: break;
! 2254: case 3: /* Evil Sender */
! 2255: buf = g_strdup_printf(
! 2256: dngettext(PACKAGE,
! 2257: "You missed %hu message from %s because his/her warning level is too high.",
! 2258: "You missed %hu messages from %s because his/her warning level is too high.",
! 2259: nummissed),
! 2260: nummissed,
! 2261: userinfo->bn);
! 2262: break;
! 2263: case 4: /* Evil Receiver */
! 2264: buf = g_strdup_printf(
! 2265: dngettext(PACKAGE,
! 2266: "You missed %hu message from %s because your warning level is too high.",
! 2267: "You missed %hu messages from %s because your warning level is too high.",
! 2268: nummissed),
! 2269: nummissed,
! 2270: userinfo->bn);
! 2271: break;
! 2272: default:
! 2273: buf = g_strdup_printf(
! 2274: dngettext(PACKAGE,
! 2275: "You missed %hu message from %s for an unknown reason.",
! 2276: "You missed %hu messages from %s for an unknown reason.",
! 2277: nummissed),
! 2278: nummissed,
! 2279: userinfo->bn);
! 2280: break;
! 2281: }
! 2282:
! 2283: if (!purple_conv_present_error(userinfo->bn, account, buf))
! 2284: purple_notify_error(od->gc, NULL, buf, NULL);
! 2285: g_free(buf);
! 2286:
! 2287: return 1;
! 2288: }
! 2289:
! 2290: static int
! 2291: purple_parse_clientauto_ch2(OscarData *od, const char *who, guint16 reason, const guchar *cookie)
! 2292: {
! 2293: if (reason == 0x0003)
! 2294: {
! 2295: /* Rendezvous was refused. */
! 2296: PeerConnection *conn;
! 2297:
! 2298: conn = peer_connection_find_by_cookie(od, who, cookie);
! 2299:
! 2300: if (conn == NULL)
! 2301: {
! 2302: purple_debug_info("oscar", "Received a rendezvous cancel message "
! 2303: "for a nonexistant connection from %s.\n", who);
! 2304: }
! 2305: else
! 2306: {
! 2307: peer_connection_destroy(conn, OSCAR_DISCONNECT_REMOTE_REFUSED, NULL);
! 2308: }
! 2309: }
! 2310: else
! 2311: {
! 2312: purple_debug_warning("oscar", "Received an unknown rendezvous "
! 2313: "message from %s. Type 0x%04hx\n", who, reason);
! 2314: }
! 2315:
! 2316: return 0;
! 2317: }
! 2318:
! 2319: static int purple_parse_clientauto_ch4(OscarData *od, char *who, guint16 reason, guint32 state, char *msg) {
! 2320: PurpleConnection *gc = od->gc;
! 2321:
! 2322: switch(reason) {
! 2323: case 0x0003: { /* Reply from an ICQ status message request */
! 2324: char *statusmsg, **splitmsg;
! 2325: PurpleNotifyUserInfo *user_info;
! 2326:
! 2327: /* Split at (carriage return/newline)'s, then rejoin later with BRs between. */
! 2328: statusmsg = oscar_icqstatus(state);
! 2329: splitmsg = g_strsplit(msg, "\r\n", 0);
! 2330:
! 2331: user_info = purple_notify_user_info_new();
! 2332:
! 2333: purple_notify_user_info_add_pair(user_info, _("UIN"), who);
! 2334: purple_notify_user_info_add_pair(user_info, _("Status"), statusmsg);
! 2335: purple_notify_user_info_add_section_break(user_info);
! 2336: purple_notify_user_info_add_pair(user_info, NULL, g_strjoinv("<BR>", splitmsg));
! 2337:
! 2338: g_free(statusmsg);
! 2339: g_strfreev(splitmsg);
! 2340:
! 2341: purple_notify_userinfo(gc, who, user_info, NULL, NULL);
! 2342: purple_notify_user_info_destroy(user_info);
! 2343:
! 2344: } break;
! 2345:
! 2346: case 0x0006: { /* Reply from an ICQ status message request */
! 2347: char *statusmsg, **splitmsg;
! 2348: PurpleNotifyUserInfo *user_info;
! 2349:
! 2350: /* Split at (carriage return/newline)'s, then rejoin later with BRs between. */
! 2351: statusmsg = oscar_icqstatus(state);
! 2352: splitmsg = g_strsplit(msg, "\r\n", 0);
! 2353:
! 2354: user_info = purple_notify_user_info_new();
! 2355:
! 2356: purple_notify_user_info_add_pair(user_info, _("UIN"), who);
! 2357: purple_notify_user_info_add_pair(user_info, _("Status"), statusmsg);
! 2358: purple_notify_user_info_add_section_break(user_info);
! 2359: purple_notify_user_info_add_pair(user_info, NULL, g_strjoinv("<BR>", splitmsg));
! 2360:
! 2361: g_free(statusmsg);
! 2362: g_strfreev(splitmsg);
! 2363:
! 2364: purple_notify_userinfo(gc, who, user_info, NULL, NULL);
! 2365: purple_notify_user_info_destroy(user_info);
! 2366:
! 2367: } break;
! 2368:
! 2369: default: {
! 2370: purple_debug_warning("oscar",
! 2371: "Received an unknown client auto-response from %s. "
! 2372: "Type 0x%04hx\n", who, reason);
! 2373: } break;
! 2374: } /* end of switch */
! 2375:
! 2376: return 0;
! 2377: }
! 2378:
! 2379: static int purple_parse_clientauto(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
! 2380: va_list ap;
! 2381: guint16 chan, reason;
! 2382: char *who;
! 2383: int ret = 1;
! 2384:
! 2385: va_start(ap, fr);
! 2386: chan = (guint16)va_arg(ap, unsigned int);
! 2387: who = va_arg(ap, char *);
! 2388: reason = (guint16)va_arg(ap, unsigned int);
! 2389:
! 2390: if (chan == 0x0002) { /* File transfer declined */
! 2391: guchar *cookie = va_arg(ap, guchar *);
! 2392: ret = purple_parse_clientauto_ch2(od, who, reason, cookie);
! 2393: } else if (chan == 0x0004) { /* ICQ message */
! 2394: guint32 state = 0;
! 2395: char *msg = NULL;
! 2396: if (reason == 0x0003) {
! 2397: state = va_arg(ap, guint32);
! 2398: msg = va_arg(ap, char *);
! 2399: }
! 2400: ret = purple_parse_clientauto_ch4(od, who, reason, state, msg);
! 2401: }
! 2402:
! 2403: va_end(ap);
! 2404:
! 2405: return ret;
! 2406: }
! 2407:
! 2408: static int purple_parse_genericerr(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
! 2409: va_list ap;
! 2410: guint16 reason;
! 2411:
! 2412: va_start(ap, fr);
! 2413: reason = (guint16) va_arg(ap, unsigned int);
! 2414: va_end(ap);
! 2415:
! 2416: purple_debug_error("oscar", "snac threw error (reason 0x%04hx: %s)\n",
! 2417: reason, oscar_get_msgerr_reason(reason));
! 2418: return 1;
! 2419: }
! 2420:
! 2421: static int purple_parse_mtn(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
! 2422: PurpleConnection *gc = od->gc;
! 2423: va_list ap;
! 2424: guint16 channel, event;
! 2425: char *bn;
! 2426:
! 2427: va_start(ap, fr);
! 2428: channel = (guint16) va_arg(ap, unsigned int);
! 2429: bn = va_arg(ap, char *);
! 2430: event = (guint16) va_arg(ap, unsigned int);
! 2431: va_end(ap);
! 2432:
! 2433: switch (event) {
! 2434: case 0x0000: { /* Text has been cleared */
! 2435: serv_got_typing_stopped(gc, bn);
! 2436: } break;
! 2437:
! 2438: case 0x0001: { /* Paused typing */
! 2439: serv_got_typing(gc, bn, 0, PURPLE_TYPED);
! 2440: } break;
! 2441:
! 2442: case 0x0002: { /* Typing */
! 2443: serv_got_typing(gc, bn, 0, PURPLE_TYPING);
! 2444: } break;
! 2445:
! 2446: case 0x000f: { /* Closed IM window */
! 2447: serv_got_typing_stopped(gc, bn);
! 2448: } break;
! 2449:
! 2450: default: {
! 2451: purple_debug_info("oscar", "Received unknown typing "
! 2452: "notification message from %s. Channel is 0x%04x "
! 2453: "and event is 0x%04hx.\n", bn, channel, event);
! 2454: } break;
! 2455: }
! 2456:
! 2457: return 1;
! 2458: }
! 2459:
! 2460: static int purple_parse_motd(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
! 2461: {
! 2462: char *msg;
! 2463: guint16 id;
! 2464: va_list ap;
! 2465:
! 2466: va_start(ap, fr);
! 2467: id = (guint16) va_arg(ap, unsigned int);
! 2468: msg = va_arg(ap, char *);
! 2469: va_end(ap);
! 2470:
! 2471: purple_debug_misc("oscar",
! 2472: "MOTD: %s (%hu)\n", msg ? msg : "Unknown", id);
! 2473: if (id < 4)
! 2474: purple_notify_warning(od->gc, NULL,
! 2475: _("Your AIM connection may be lost."), NULL);
! 2476:
! 2477: return 1;
! 2478: }
! 2479:
! 2480: static int purple_chatnav_info(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
! 2481: va_list ap;
! 2482: guint16 type;
! 2483:
! 2484: va_start(ap, fr);
! 2485: type = (guint16) va_arg(ap, unsigned int);
! 2486:
! 2487: switch(type) {
! 2488: case 0x0002: {
! 2489: GString *msg = g_string_new("");
! 2490: guint8 maxrooms;
! 2491: struct aim_chat_exchangeinfo *exchanges;
! 2492: int exchangecount, i;
! 2493:
! 2494: maxrooms = (guint8) va_arg(ap, unsigned int);
! 2495: exchangecount = va_arg(ap, int);
! 2496: exchanges = va_arg(ap, struct aim_chat_exchangeinfo *);
! 2497:
! 2498: g_string_append_printf(msg, "chat info: Max Concurrent Rooms: %hhd, Exchange List (%d total): ", maxrooms, exchangecount);
! 2499: for (i = 0; i < exchangecount; i++) {
! 2500: g_string_append_printf(msg, "%hu", exchanges[i].number);
! 2501: if (exchanges[i].name) {
! 2502: g_string_append_printf(msg, " %s", exchanges[i].name);
! 2503: }
! 2504: g_string_append(msg, ", ");
! 2505: }
! 2506: purple_debug_misc("oscar", "%s\n", msg->str);
! 2507: g_string_free(msg, TRUE);
! 2508:
! 2509: while (od->create_rooms) {
! 2510: struct create_room *cr = od->create_rooms->data;
! 2511: purple_debug_info("oscar",
! 2512: "creating room %s\n", cr->name);
! 2513: aim_chatnav_createroom(od, conn, cr->name, cr->exchange);
! 2514: g_free(cr->name);
! 2515: od->create_rooms = g_slist_remove(od->create_rooms, cr);
! 2516: g_free(cr);
! 2517: }
! 2518: }
! 2519: break;
! 2520: case 0x0008: {
! 2521: char *fqcn, *name, *ck;
! 2522: guint16 instance, flags, maxmsglen, maxoccupancy, unknown, exchange;
! 2523: guint8 createperms;
! 2524: guint32 createtime;
! 2525:
! 2526: fqcn = va_arg(ap, char *);
! 2527: instance = (guint16)va_arg(ap, unsigned int);
! 2528: exchange = (guint16)va_arg(ap, unsigned int);
! 2529: flags = (guint16)va_arg(ap, unsigned int);
! 2530: createtime = va_arg(ap, guint32);
! 2531: maxmsglen = (guint16)va_arg(ap, unsigned int);
! 2532: maxoccupancy = (guint16)va_arg(ap, unsigned int);
! 2533: createperms = (guint8)va_arg(ap, unsigned int);
! 2534: unknown = (guint16)va_arg(ap, unsigned int);
! 2535: name = va_arg(ap, char *);
! 2536: ck = va_arg(ap, char *);
! 2537:
! 2538: purple_debug_misc("oscar",
! 2539: "created room: %s %hu %hu %hu %u %hu %hu %hhu %hu %s %s\n",
! 2540: fqcn ? fqcn : "(null)", exchange, instance, flags, createtime,
! 2541: maxmsglen, maxoccupancy, createperms, unknown,
! 2542: name ? name : "(null)", ck);
! 2543: aim_chat_join(od, exchange, ck, instance);
! 2544: }
! 2545: break;
! 2546: default:
! 2547: purple_debug_warning("oscar",
! 2548: "chatnav info: unknown type (%04hx)\n", type);
! 2549: break;
! 2550: }
! 2551:
! 2552: va_end(ap);
! 2553:
! 2554: return 1;
! 2555: }
! 2556:
! 2557: static int purple_conv_chat_join(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
! 2558: va_list ap;
! 2559: int count, i;
! 2560: aim_userinfo_t *info;
! 2561: PurpleConnection *gc = od->gc;
! 2562:
! 2563: struct chat_connection *c = NULL;
! 2564:
! 2565: va_start(ap, fr);
! 2566: count = va_arg(ap, int);
! 2567: info = va_arg(ap, aim_userinfo_t *);
! 2568: va_end(ap);
! 2569:
! 2570: c = find_oscar_chat_by_conn(gc, conn);
! 2571: if (!c)
! 2572: return 1;
! 2573:
! 2574: for (i = 0; i < count; i++)
! 2575: purple_conv_chat_add_user(PURPLE_CONV_CHAT(c->conv), info[i].bn, NULL, PURPLE_CBFLAGS_NONE, TRUE);
! 2576:
! 2577: return 1;
! 2578: }
! 2579:
! 2580: static int purple_conv_chat_leave(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
! 2581: va_list ap;
! 2582: int count, i;
! 2583: aim_userinfo_t *info;
! 2584: PurpleConnection *gc = od->gc;
! 2585:
! 2586: struct chat_connection *c = NULL;
! 2587:
! 2588: va_start(ap, fr);
! 2589: count = va_arg(ap, int);
! 2590: info = va_arg(ap, aim_userinfo_t *);
! 2591: va_end(ap);
! 2592:
! 2593: c = find_oscar_chat_by_conn(gc, conn);
! 2594: if (!c)
! 2595: return 1;
! 2596:
! 2597: for (i = 0; i < count; i++)
! 2598: purple_conv_chat_remove_user(PURPLE_CONV_CHAT(c->conv), info[i].bn, NULL);
! 2599:
! 2600: return 1;
! 2601: }
! 2602:
! 2603: static int purple_conv_chat_info_update(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
! 2604: va_list ap;
! 2605: guint16 maxmsglen, maxvisiblemsglen;
! 2606: PurpleConnection *gc = od->gc;
! 2607: struct chat_connection *ccon = find_oscar_chat_by_conn(gc, conn);
! 2608:
! 2609: if (!ccon)
! 2610: return 1;
! 2611:
! 2612: va_start(ap, fr);
! 2613: maxmsglen = (guint16)va_arg(ap, unsigned int);
! 2614: maxvisiblemsglen = (guint16)va_arg(ap, unsigned int);
! 2615: va_end(ap);
! 2616:
! 2617: purple_debug_misc("oscar",
! 2618: "inside chat_info_update (maxmsglen = %hu, maxvislen = %hu)\n",
! 2619: maxmsglen, maxvisiblemsglen);
! 2620:
! 2621: ccon->maxlen = maxmsglen;
! 2622: ccon->maxvis = maxvisiblemsglen;
! 2623:
! 2624: return 1;
! 2625: }
! 2626:
! 2627: static int purple_conv_chat_incoming_msg(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
! 2628: PurpleConnection *gc = od->gc;
! 2629: struct chat_connection *ccon = find_oscar_chat_by_conn(gc, conn);
! 2630: gchar *utf8;
! 2631: va_list ap;
! 2632: aim_userinfo_t *info;
! 2633: int len;
! 2634: char *msg;
! 2635: char *charset;
! 2636:
! 2637: if (!ccon)
! 2638: return 1;
! 2639:
! 2640: va_start(ap, fr);
! 2641: info = va_arg(ap, aim_userinfo_t *);
! 2642: len = va_arg(ap, int);
! 2643: msg = va_arg(ap, char *);
! 2644: charset = va_arg(ap, char *);
! 2645: va_end(ap);
! 2646:
! 2647: utf8 = oscar_encoding_to_utf8(charset, msg, len);
! 2648: serv_got_chat_in(gc, ccon->id, info->bn, 0, utf8, time(NULL));
! 2649: g_free(utf8);
! 2650:
! 2651: return 1;
! 2652: }
! 2653:
! 2654: static int purple_email_parseupdate(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
! 2655: va_list ap;
! 2656: PurpleConnection *gc;
! 2657: PurpleAccount *account;
! 2658: struct aim_emailinfo *emailinfo;
! 2659: int havenewmail;
! 2660: char *alertitle, *alerturl;
! 2661:
! 2662: gc = od->gc;
! 2663: account = purple_connection_get_account(gc);
! 2664:
! 2665: va_start(ap, fr);
! 2666: emailinfo = va_arg(ap, struct aim_emailinfo *);
! 2667: havenewmail = va_arg(ap, int);
! 2668: alertitle = va_arg(ap, char *);
! 2669: alerturl = va_arg(ap, char *);
! 2670: va_end(ap);
! 2671:
! 2672: if (account != NULL && emailinfo != NULL && purple_account_get_check_mail(account) &&
! 2673: emailinfo->unread && havenewmail) {
! 2674: gchar *to = g_strdup_printf("%s%s%s",
! 2675: purple_account_get_username(account),
! 2676: emailinfo->domain ? "@" : "",
! 2677: emailinfo->domain ? emailinfo->domain : "");
! 2678: const char *tos[2] = { to };
! 2679: const char *urls[2] = { emailinfo->url };
! 2680: purple_notify_emails(gc, emailinfo->nummsgs, FALSE, NULL, NULL,
! 2681: tos, urls, NULL, NULL);
! 2682: g_free(to);
! 2683: }
! 2684:
! 2685: if (alertitle)
! 2686: purple_debug_misc("oscar", "Got an alert '%s' %s\n", alertitle, alerturl ? alerturl : "");
! 2687:
! 2688: return 1;
! 2689: }
! 2690:
! 2691: static int purple_icon_parseicon(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
! 2692: PurpleConnection *gc = od->gc;
! 2693: va_list ap;
! 2694: char *bn;
! 2695: guint8 *iconcsum, *icon;
! 2696: guint16 iconcsumlen, iconlen;
! 2697:
! 2698: va_start(ap, fr);
! 2699: bn = va_arg(ap, char *);
! 2700: va_arg(ap, int); /* iconsumtype */
! 2701: iconcsum = va_arg(ap, guint8 *);
! 2702: iconcsumlen = va_arg(ap, int);
! 2703: icon = va_arg(ap, guint8 *);
! 2704: iconlen = va_arg(ap, int);
! 2705: va_end(ap);
! 2706:
! 2707: /*
! 2708: * Some AIM clients will send a blank GIF image with iconlen 90 when
! 2709: * no icon is set. Ignore these.
! 2710: */
! 2711: if ((iconlen > 0) && (iconlen != 90)) {
! 2712: char *b16 = purple_base16_encode(iconcsum, iconcsumlen);
! 2713: purple_buddy_icons_set_for_user(purple_connection_get_account(gc),
! 2714: bn, g_memdup(icon, iconlen), iconlen, b16);
! 2715: g_free(b16);
! 2716: }
! 2717:
! 2718: return 1;
! 2719: }
! 2720:
! 2721: static void
! 2722: purple_icons_fetch(PurpleConnection *gc)
! 2723: {
! 2724: OscarData *od = purple_connection_get_protocol_data(gc);
! 2725: aim_userinfo_t *userinfo;
! 2726: FlapConnection *conn;
! 2727:
! 2728: conn = flap_connection_getbytype(od, SNAC_FAMILY_BART);
! 2729: if (!conn) {
! 2730: if (!od->iconconnecting) {
! 2731: aim_srv_requestnew(od, SNAC_FAMILY_BART);
! 2732: od->iconconnecting = TRUE;
! 2733: }
! 2734: return;
! 2735: }
! 2736:
! 2737: if (od->set_icon) {
! 2738: PurpleAccount *account = purple_connection_get_account(gc);
! 2739: PurpleStoredImage *img = purple_buddy_icons_find_account_icon(account);
! 2740: if (img == NULL) {
! 2741: aim_ssi_delicon(od);
! 2742: } else {
! 2743: purple_debug_info("oscar",
! 2744: "Uploading icon to icon server\n");
! 2745: aim_bart_upload(od, purple_imgstore_get_data(img),
! 2746: purple_imgstore_get_size(img));
! 2747: purple_imgstore_unref(img);
! 2748: }
! 2749: od->set_icon = FALSE;
! 2750: }
! 2751:
! 2752: while (od->requesticon != NULL)
! 2753: {
! 2754: userinfo = aim_locate_finduserinfo(od, (char *)od->requesticon->data);
! 2755: if ((userinfo != NULL) && (userinfo->iconcsumlen > 0))
! 2756: aim_bart_request(od, od->requesticon->data, userinfo->iconcsumtype, userinfo->iconcsum, userinfo->iconcsumlen);
! 2757:
! 2758: g_free(od->requesticon->data);
! 2759: od->requesticon = g_slist_delete_link(od->requesticon, od->requesticon);
! 2760: }
! 2761:
! 2762: purple_debug_misc("oscar", "no more icons to request\n");
! 2763: }
! 2764:
! 2765: static int purple_selfinfo(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
! 2766: va_list ap;
! 2767: aim_userinfo_t *info;
! 2768:
! 2769: va_start(ap, fr);
! 2770: info = va_arg(ap, aim_userinfo_t *);
! 2771: va_end(ap);
! 2772:
! 2773: purple_connection_set_display_name(od->gc, info->bn);
! 2774:
! 2775: return 1;
! 2776: }
! 2777:
! 2778: static int purple_connerr(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
! 2779: PurpleConnection *gc = od->gc;
! 2780: va_list ap;
! 2781: guint16 code;
! 2782: char *msg;
! 2783:
! 2784: va_start(ap, fr);
! 2785: code = (guint16)va_arg(ap, int);
! 2786: msg = va_arg(ap, char *);
! 2787: va_end(ap);
! 2788:
! 2789: purple_debug_info("oscar", "Disconnected. Code is 0x%04x and msg is %s\n",
! 2790: code, (msg != NULL ? msg : ""));
! 2791:
! 2792: g_return_val_if_fail(conn != NULL, 1);
! 2793:
! 2794: if (conn->type == SNAC_FAMILY_CHAT) {
! 2795: struct chat_connection *cc;
! 2796: PurpleConversation *conv = NULL;
! 2797:
! 2798: cc = find_oscar_chat_by_conn(gc, conn);
! 2799: if (cc != NULL)
! 2800: {
! 2801: conv = purple_find_chat(gc, cc->id);
! 2802:
! 2803: if (conv != NULL)
! 2804: {
! 2805: /*
! 2806: * TOOD: Have flap_connection_destroy_cb() send us the
! 2807: * error message stored in 'tmp', which should be
! 2808: * human-friendly, and print that to the chat room.
! 2809: */
! 2810: gchar *buf;
! 2811: buf = g_strdup_printf(_("You have been disconnected from chat "
! 2812: "room %s."), cc->name);
! 2813: purple_conversation_write(conv, NULL, buf, PURPLE_MESSAGE_ERROR, time(NULL));
! 2814: g_free(buf);
! 2815: }
! 2816: oscar_chat_kill(gc, cc);
! 2817: }
! 2818: }
! 2819:
! 2820: return 1;
! 2821: }
! 2822:
! 2823: static int purple_parse_locaterights(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
! 2824: {
! 2825: PurpleConnection *gc = od->gc;
! 2826: PurpleAccount *account = purple_connection_get_account(gc);
! 2827: va_list ap;
! 2828: guint16 maxsiglen;
! 2829:
! 2830: va_start(ap, fr);
! 2831: maxsiglen = (guint16) va_arg(ap, int);
! 2832: va_end(ap);
! 2833:
! 2834: purple_debug_misc("oscar",
! 2835: "locate rights: max sig len = %d\n", maxsiglen);
! 2836:
! 2837: od->rights.maxsiglen = od->rights.maxawaymsglen = (guint)maxsiglen;
! 2838:
! 2839: aim_locate_setcaps(od, purple_caps);
! 2840: oscar_set_info_and_status(account, TRUE, account->user_info, TRUE,
! 2841: purple_account_get_active_status(account));
! 2842:
! 2843: return 1;
! 2844: }
! 2845:
! 2846: static int purple_parse_buddyrights(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
! 2847: va_list ap;
! 2848: guint16 maxbuddies, maxwatchers;
! 2849:
! 2850: va_start(ap, fr);
! 2851: maxbuddies = (guint16) va_arg(ap, unsigned int);
! 2852: maxwatchers = (guint16) va_arg(ap, unsigned int);
! 2853: va_end(ap);
! 2854:
! 2855: purple_debug_misc("oscar",
! 2856: "buddy list rights: Max buddies = %hu / Max watchers = %hu\n", maxbuddies, maxwatchers);
! 2857:
! 2858: od->rights.maxbuddies = (guint)maxbuddies;
! 2859: od->rights.maxwatchers = (guint)maxwatchers;
! 2860:
! 2861: return 1;
! 2862: }
! 2863:
! 2864: static void oscar_format_username(PurpleConnection *gc, const char *new_display_name)
! 2865: {
! 2866: OscarData *od;
! 2867: const char *old_display_name, *username;
! 2868: char *tmp, *at_sign;
! 2869:
! 2870: old_display_name = purple_connection_get_display_name(gc);
! 2871: if (old_display_name && strchr(old_display_name, '@')) {
! 2872: purple_debug_info("oscar", "Cowardly refusing to attempt to format "
! 2873: "screen name because the current formatting according to "
! 2874: "the server (%s) appears to be an email address\n",
! 2875: old_display_name);
! 2876: return;
! 2877: }
! 2878:
! 2879: username = purple_account_get_username(purple_connection_get_account(gc));
! 2880: if (oscar_util_name_compare(username, new_display_name)) {
! 2881: purple_notify_error(gc, NULL, _("The new formatting is invalid."),
! 2882: _("Username formatting can change only capitalization and whitespace."));
! 2883: return;
! 2884: }
! 2885:
! 2886: tmp = g_strdup(new_display_name);
! 2887:
! 2888: /*
! 2889: * If our local username is an email address then strip off the domain.
! 2890: * This allows formatting to work if the user entered their username as
! 2891: * 'something@aim.com' or possibly other AOL-owned domains.
! 2892: */
! 2893: at_sign = strchr(tmp, '@');
! 2894: if (at_sign)
! 2895: at_sign[0] = '\0';
! 2896:
! 2897: od = purple_connection_get_protocol_data(gc);
! 2898: if (!flap_connection_getbytype(od, SNAC_FAMILY_ADMIN)) {
! 2899: /* We don't have a connection to an "admin" server. Make one. */
! 2900: od->setnick = TRUE;
! 2901: g_free(od->newformatting);
! 2902: od->newformatting = tmp;
! 2903: aim_srv_requestnew(od, SNAC_FAMILY_ADMIN);
! 2904: } else {
! 2905: aim_admin_setnick(od, flap_connection_getbytype(od, SNAC_FAMILY_ADMIN), tmp);
! 2906: g_free(tmp);
! 2907: }
! 2908: }
! 2909:
! 2910: static int purple_bosrights(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
! 2911: PurpleConnection *gc;
! 2912: PurpleAccount *account;
! 2913: PurpleStatus *status;
! 2914: gboolean is_available;
! 2915: PurplePresence *presence;
! 2916: const char *username, *message, *itmsurl;
! 2917: char *tmp;
! 2918: va_list ap;
! 2919: guint16 maxpermits, maxdenies;
! 2920:
! 2921: gc = od->gc;
! 2922: od = purple_connection_get_protocol_data(gc);
! 2923: account = purple_connection_get_account(gc);
! 2924:
! 2925: va_start(ap, fr);
! 2926: maxpermits = (guint16) va_arg(ap, unsigned int);
! 2927: maxdenies = (guint16) va_arg(ap, unsigned int);
! 2928: va_end(ap);
! 2929:
! 2930: purple_debug_misc("oscar",
! 2931: "BOS rights: Max permit = %hu / Max deny = %hu\n", maxpermits, maxdenies);
! 2932:
! 2933: od->rights.maxpermits = (guint)maxpermits;
! 2934: od->rights.maxdenies = (guint)maxdenies;
! 2935:
! 2936: purple_debug_info("oscar", "buddy list loaded\n");
! 2937:
! 2938: if (purple_account_get_user_info(account) != NULL)
! 2939: serv_set_info(gc, purple_account_get_user_info(account));
! 2940:
! 2941: username = purple_account_get_username(account);
! 2942: if (!od->icq && !purple_strequal(username, purple_connection_get_display_name(gc))) {
! 2943: /*
! 2944: * Format the username for AIM accounts if it's different
! 2945: * than what's currently set.
! 2946: */
! 2947: oscar_format_username(gc, username);
! 2948: }
! 2949:
! 2950: /* Set our available message based on the current status */
! 2951: status = purple_account_get_active_status(account);
! 2952: is_available = purple_status_is_available(status);
! 2953: if (is_available)
! 2954: message = purple_status_get_attr_string(status, "message");
! 2955: else
! 2956: message = NULL;
! 2957: tmp = purple_markup_strip_html(message);
! 2958: itmsurl = purple_status_get_attr_string(status, "itmsurl");
! 2959: aim_srv_setextrainfo(od, FALSE, 0, is_available, tmp, itmsurl);
! 2960: aim_srv_set_dc_info(od);
! 2961: g_free(tmp);
! 2962:
! 2963: presence = purple_status_get_presence(status);
! 2964: aim_srv_setidle(od, !purple_presence_is_idle(presence) ? 0 : time(NULL) - purple_presence_get_idle_time(presence));
! 2965:
! 2966: if (od->icq) {
! 2967: oscar_set_extended_status(gc);
! 2968: aim_icq_setsecurity(od,
! 2969: purple_account_get_bool(account, "authorization", OSCAR_DEFAULT_AUTHORIZATION),
! 2970: purple_account_get_bool(account, "web_aware", OSCAR_DEFAULT_WEB_AWARE));
! 2971: }
! 2972:
! 2973: aim_srv_requestnew(od, SNAC_FAMILY_ALERT);
! 2974: aim_srv_requestnew(od, SNAC_FAMILY_CHATNAV);
! 2975:
! 2976: od->bos.have_rights = TRUE;
! 2977:
! 2978: /*
! 2979: * If we've already received our feedbag data then we're not waiting on
! 2980: * anything else, so send the server clientready.
! 2981: *
! 2982: * Normally we get bos rights before we get our feedbag data, so this
! 2983: * rarely (never?) happens. And I'm not sure it actually matters if we
! 2984: * wait for bos rights before calling clientready. But it seems safer
! 2985: * to do it this way.
! 2986: */
! 2987: if (od->ssi.received_data) {
! 2988: aim_srv_clientready(od, conn);
! 2989:
! 2990: /* Request offline messages for AIM and ICQ */
! 2991: aim_im_reqofflinemsgs(od);
! 2992:
! 2993: purple_connection_set_state(gc, PURPLE_CONNECTED);
! 2994: }
! 2995:
! 2996: return 1;
! 2997: }
! 2998:
! 2999: static int purple_popup(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
! 3000: {
! 3001: PurpleConnection *gc = od->gc;
! 3002: gchar *text;
! 3003: va_list ap;
! 3004: char *msg, *url;
! 3005:
! 3006: va_start(ap, fr);
! 3007: msg = va_arg(ap, char *);
! 3008: url = va_arg(ap, char *);
! 3009: va_arg(ap, int); /* guint16 wid */
! 3010: va_arg(ap, int); /* guint16 hei */
! 3011: va_arg(ap, int); /* guint16 delay */
! 3012: va_end(ap);
! 3013:
! 3014: text = g_strdup_printf("%s<br><a href=\"%s\">%s</a>", msg, url, url);
! 3015: purple_notify_formatted(gc, NULL, _("Pop-Up Message"), NULL, text, NULL, NULL);
! 3016: g_free(text);
! 3017:
! 3018: return 1;
! 3019: }
! 3020:
! 3021: static void oscar_searchresults_add_buddy_cb(PurpleConnection *gc, GList *row, void *user_data)
! 3022: {
! 3023: purple_blist_request_add_buddy(purple_connection_get_account(gc),
! 3024: g_list_nth_data(row, 0), NULL, NULL);
! 3025: }
! 3026:
! 3027: static int purple_parse_searchreply(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
! 3028: {
! 3029: PurpleConnection *gc = od->gc;
! 3030: PurpleNotifySearchResults *results;
! 3031: PurpleNotifySearchColumn *column;
! 3032: gchar *secondary;
! 3033: int i, num;
! 3034: va_list ap;
! 3035: char *email, *usernames;
! 3036:
! 3037: va_start(ap, fr);
! 3038: email = va_arg(ap, char *);
! 3039: num = va_arg(ap, int);
! 3040: usernames = va_arg(ap, char *);
! 3041: va_end(ap);
! 3042:
! 3043: results = purple_notify_searchresults_new();
! 3044:
! 3045: if (results == NULL) {
! 3046: purple_debug_error("oscar", "purple_parse_searchreply: "
! 3047: "Unable to display the search results.\n");
! 3048: purple_notify_error(gc, NULL,
! 3049: _("Unable to display the search results."),
! 3050: NULL);
! 3051: return 1;
! 3052: }
! 3053:
! 3054: secondary = g_strdup_printf(
! 3055: dngettext(PACKAGE, "The following username is associated with %s",
! 3056: "The following usernames are associated with %s",
! 3057: num),
! 3058: email);
! 3059:
! 3060: column = purple_notify_searchresults_column_new(_("Username"));
! 3061: purple_notify_searchresults_column_add(results, column);
! 3062:
! 3063: for (i = 0; i < num; i++) {
! 3064: GList *row;
! 3065: row = g_list_append(NULL, g_strdup(&usernames[i * (MAXSNLEN + 1)]));
! 3066: purple_notify_searchresults_row_add(results, row);
! 3067: }
! 3068: purple_notify_searchresults_button_add(results, PURPLE_NOTIFY_BUTTON_ADD,
! 3069: oscar_searchresults_add_buddy_cb);
! 3070: purple_notify_searchresults(gc, NULL, NULL, secondary, results, NULL, NULL);
! 3071:
! 3072: g_free(secondary);
! 3073:
! 3074: return 1;
! 3075: }
! 3076:
! 3077: static int purple_parse_searcherror(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
! 3078: va_list ap;
! 3079: char *email;
! 3080: char *buf;
! 3081:
! 3082: va_start(ap, fr);
! 3083: email = va_arg(ap, char *);
! 3084: va_end(ap);
! 3085:
! 3086: buf = g_strdup_printf(_("No results found for email address %s"), email);
! 3087: purple_notify_error(od->gc, NULL, buf, NULL);
! 3088: g_free(buf);
! 3089:
! 3090: return 1;
! 3091: }
! 3092:
! 3093: static int purple_account_confirm(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
! 3094: PurpleConnection *gc = od->gc;
! 3095: guint16 status;
! 3096: va_list ap;
! 3097: char msg[256];
! 3098:
! 3099: va_start(ap, fr);
! 3100: status = (guint16) va_arg(ap, unsigned int); /* status code of confirmation request */
! 3101: va_end(ap);
! 3102:
! 3103: purple_debug_info("oscar",
! 3104: "account confirmation returned status 0x%04x (%s)\n", status,
! 3105: status ? "unknown" : "email sent");
! 3106: if (!status) {
! 3107: g_snprintf(msg, sizeof(msg), _("You should receive an email asking to confirm %s."),
! 3108: purple_account_get_username(purple_connection_get_account(gc)));
! 3109: purple_notify_info(gc, NULL, _("Account Confirmation Requested"), msg);
! 3110: }
! 3111:
! 3112: return 1;
! 3113: }
! 3114:
! 3115: static int purple_info_change(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
! 3116: PurpleConnection *gc = od->gc;
! 3117: va_list ap;
! 3118: guint16 perms, err;
! 3119: char *url, *bn, *email;
! 3120: int change;
! 3121:
! 3122: va_start(ap, fr);
! 3123: change = va_arg(ap, int);
! 3124: perms = (guint16) va_arg(ap, unsigned int);
! 3125: err = (guint16) va_arg(ap, unsigned int);
! 3126: url = va_arg(ap, char *);
! 3127: bn = va_arg(ap, char *);
! 3128: email = va_arg(ap, char *);
! 3129: va_end(ap);
! 3130:
! 3131: purple_debug_misc("oscar",
! 3132: "account info: because of %s, perms=0x%04x, err=0x%04x, url=%s, bn=%s, email=%s\n",
! 3133: change ? "change" : "request", perms, err,
! 3134: (url != NULL) ? url : "(null)",
! 3135: (bn != NULL) ? bn : "(null)",
! 3136: (email != NULL) ? email : "(null)");
! 3137:
! 3138: if ((err > 0) && (url != NULL)) {
! 3139: char *dialog_msg;
! 3140:
! 3141: if (err == 0x0001)
! 3142: dialog_msg = g_strdup_printf(_("Error 0x%04x: Unable to format username because the requested name differs from the original."), err);
! 3143: else if (err == 0x0006)
! 3144: dialog_msg = g_strdup_printf(_("Error 0x%04x: Unable to format username because it is invalid."), err);
! 3145: else if (err == 0x00b)
! 3146: dialog_msg = g_strdup_printf(_("Error 0x%04x: Unable to format username because the requested name is too long."), err);
! 3147: else if (err == 0x001d)
! 3148: dialog_msg = g_strdup_printf(_("Error 0x%04x: Unable to change email address because there is already a request pending for this username."), err);
! 3149: else if (err == 0x0021)
! 3150: dialog_msg = g_strdup_printf(_("Error 0x%04x: Unable to change email address because the given address has too many usernames associated with it."), err);
! 3151: else if (err == 0x0023)
! 3152: dialog_msg = g_strdup_printf(_("Error 0x%04x: Unable to change email address because the given address is invalid."), err);
! 3153: else
! 3154: dialog_msg = g_strdup_printf(_("Error 0x%04x: Unknown error."), err);
! 3155: purple_notify_error(gc, NULL,
! 3156: _("Error Changing Account Info"), dialog_msg);
! 3157: g_free(dialog_msg);
! 3158: return 1;
! 3159: }
! 3160:
! 3161: if (email != NULL) {
! 3162: char *dialog_msg = g_strdup_printf(_("The email address for %s is %s"),
! 3163: purple_account_get_username(purple_connection_get_account(gc)), email);
! 3164: purple_notify_info(gc, NULL, _("Account Info"), dialog_msg);
! 3165: g_free(dialog_msg);
! 3166: }
! 3167:
! 3168: return 1;
! 3169: }
! 3170:
! 3171: void
! 3172: oscar_keepalive(PurpleConnection *gc)
! 3173: {
! 3174: OscarData *od;
! 3175: GSList *l;
! 3176:
! 3177: od = purple_connection_get_protocol_data(gc);
! 3178: for (l = od->oscar_connections; l; l = l->next) {
! 3179: flap_connection_send_keepalive(od, l->data);
! 3180: }
! 3181: }
! 3182:
! 3183: unsigned int
! 3184: oscar_send_typing(PurpleConnection *gc, const char *name, PurpleTypingState state)
! 3185: {
! 3186: OscarData *od;
! 3187: PeerConnection *conn;
! 3188:
! 3189: od = purple_connection_get_protocol_data(gc);
! 3190: conn = peer_connection_find_by_type(od, name, OSCAR_CAPABILITY_DIRECTIM);
! 3191:
! 3192: if ((conn != NULL) && (conn->ready))
! 3193: {
! 3194: peer_odc_send_typing(conn, state);
! 3195: }
! 3196: else {
! 3197: /* Don't send if this turkey is in our deny list */
! 3198: GSList *list;
! 3199: for (list=gc->account->deny; (list && oscar_util_name_compare(name, list->data)); list=list->next);
! 3200: if (!list) {
! 3201: struct buddyinfo *bi = g_hash_table_lookup(od->buddyinfo, purple_normalize(gc->account, name));
! 3202: if (bi && bi->typingnot) {
! 3203: if (state == PURPLE_TYPING)
! 3204: aim_im_sendmtn(od, 0x0001, name, 0x0002);
! 3205: else if (state == PURPLE_TYPED)
! 3206: aim_im_sendmtn(od, 0x0001, name, 0x0001);
! 3207: else
! 3208: aim_im_sendmtn(od, 0x0001, name, 0x0000);
! 3209: }
! 3210: }
! 3211: }
! 3212: return 0;
! 3213: }
! 3214:
! 3215: /* TODO: Move this into odc.c! */
! 3216: static void
! 3217: purple_odc_send_im(PeerConnection *conn, const char *message, PurpleMessageFlags imflags)
! 3218: {
! 3219: GString *msg;
! 3220: GString *data;
! 3221: gchar *tmp;
! 3222: gsize tmplen;
! 3223: guint16 charset;
! 3224: GData *attribs;
! 3225: const char *start, *end, *last;
! 3226: int oscar_id = 0;
! 3227:
! 3228: msg = g_string_new("<HTML><BODY>");
! 3229: data = g_string_new("<BINARY>");
! 3230: last = message;
! 3231:
! 3232: /* for each valid IMG tag... */
! 3233: while (last && *last && purple_markup_find_tag("img", last, &start, &end, &attribs))
! 3234: {
! 3235: PurpleStoredImage *image = NULL;
! 3236: const char *id;
! 3237:
! 3238: if (start - last) {
! 3239: g_string_append_len(msg, last, start - last);
! 3240: }
! 3241:
! 3242: id = g_datalist_get_data(&attribs, "id");
! 3243:
! 3244: /* ... if it refers to a valid purple image ... */
! 3245: if (id && (image = purple_imgstore_find_by_id(atoi(id)))) {
! 3246: /* ... append the message from start to the tag ... */
! 3247: unsigned long size = purple_imgstore_get_size(image);
! 3248: const char *filename = purple_imgstore_get_filename(image);
! 3249: gconstpointer imgdata = purple_imgstore_get_data(image);
! 3250:
! 3251: oscar_id++;
! 3252:
! 3253: /* ... insert a new img tag with the oscar id ... */
! 3254: if (filename)
! 3255: g_string_append_printf(msg,
! 3256: "<IMG SRC=\"%s\" ID=\"%d\" DATASIZE=\"%lu\">",
! 3257: filename, oscar_id, size);
! 3258: else
! 3259: g_string_append_printf(msg,
! 3260: "<IMG ID=\"%d\" DATASIZE=\"%lu\">",
! 3261: oscar_id, size);
! 3262:
! 3263: /* ... and append the data to the binary section ... */
! 3264: g_string_append_printf(data, "<DATA ID=\"%d\" SIZE=\"%lu\">",
! 3265: oscar_id, size);
! 3266: g_string_append_len(data, imgdata, size);
! 3267: g_string_append(data, "</DATA>");
! 3268: }
! 3269: /* If the tag is invalid, skip it, thus no else here */
! 3270:
! 3271: g_datalist_clear(&attribs);
! 3272:
! 3273: /* continue from the end of the tag */
! 3274: last = end + 1;
! 3275: }
! 3276:
! 3277: /* append any remaining message data */
! 3278: if (last && *last)
! 3279: g_string_append(msg, last);
! 3280:
! 3281: g_string_append(msg, "</BODY></HTML>");
! 3282:
! 3283: /* Convert the message to a good encoding */
! 3284: tmp = oscar_encode_im(msg->str, &tmplen, &charset, NULL);
! 3285: g_string_free(msg, TRUE);
! 3286: msg = g_string_new_len(tmp, tmplen);
! 3287: g_free(tmp);
! 3288:
! 3289: /* Append any binary data that we may have */
! 3290: if (oscar_id) {
! 3291: msg = g_string_append_len(msg, data->str, data->len);
! 3292: msg = g_string_append(msg, "</BINARY>");
! 3293: }
! 3294: g_string_free(data, TRUE);
! 3295:
! 3296: purple_debug_info("oscar", "sending direct IM %s using charset %i", msg->str, charset);
! 3297:
! 3298: peer_odc_send_im(conn, msg->str, msg->len, charset,
! 3299: imflags & PURPLE_MESSAGE_AUTO_RESP);
! 3300: g_string_free(msg, TRUE);
! 3301: }
! 3302:
! 3303: int
! 3304: oscar_send_im(PurpleConnection *gc, const char *name, const char *message, PurpleMessageFlags imflags)
! 3305: {
! 3306: OscarData *od;
! 3307: PurpleAccount *account;
! 3308: PeerConnection *conn;
! 3309: int ret;
! 3310: char *tmp1, *tmp2;
! 3311: gboolean is_sms, is_html;
! 3312:
! 3313: od = purple_connection_get_protocol_data(gc);
! 3314: account = purple_connection_get_account(gc);
! 3315: ret = 0;
! 3316:
! 3317: is_sms = oscar_util_valid_name_sms(name);
! 3318:
! 3319: if (od->icq && is_sms) {
! 3320: /*
! 3321: * We're sending to a phone number and this is ICQ,
! 3322: * so send the message as an SMS using aim_icq_sendsms()
! 3323: */
! 3324: int ret;
! 3325: purple_debug_info("oscar", "Sending SMS to %s.\n", name);
! 3326: ret = aim_icq_sendsms(od, name, message, purple_account_get_username(account));
! 3327: return (ret >= 0 ? 1 : ret);
! 3328: }
! 3329:
! 3330: if (imflags & PURPLE_MESSAGE_AUTO_RESP)
! 3331: tmp1 = oscar_util_format_string(message, name);
! 3332: else
! 3333: tmp1 = g_strdup(message);
! 3334:
! 3335: conn = peer_connection_find_by_type(od, name, OSCAR_CAPABILITY_DIRECTIM);
! 3336: if ((conn != NULL) && (conn->ready))
! 3337: {
! 3338: /* If we're directly connected, send a direct IM */
! 3339: purple_debug_info("oscar", "Sending direct IM with flags %i\n", imflags);
! 3340: purple_odc_send_im(conn, tmp1, imflags);
! 3341: } else {
! 3342: struct buddyinfo *bi;
! 3343: struct aim_sendimext_args args;
! 3344: PurpleConversation *conv;
! 3345: PurpleStoredImage *img;
! 3346: PurpleBuddy *buddy;
! 3347:
! 3348: conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, name, account);
! 3349:
! 3350: if (strstr(tmp1, "<IMG "))
! 3351: purple_conversation_write(conv, "",
! 3352: _("Your IM Image was not sent. "
! 3353: "You must be Direct Connected to send IM Images."),
! 3354: PURPLE_MESSAGE_ERROR, time(NULL));
! 3355:
! 3356: buddy = purple_find_buddy(account, name);
! 3357:
! 3358: bi = g_hash_table_lookup(od->buddyinfo, purple_normalize(account, name));
! 3359: if (!bi) {
! 3360: bi = g_new0(struct buddyinfo, 1);
! 3361: g_hash_table_insert(od->buddyinfo, g_strdup(purple_normalize(account, name)), bi);
! 3362: }
! 3363:
! 3364: args.flags = 0;
! 3365:
! 3366: if (!is_sms && (!buddy || !PURPLE_BUDDY_IS_ONLINE(buddy)))
! 3367: args.flags |= AIM_IMFLAGS_OFFLINE;
! 3368:
! 3369: if (od->icq) {
! 3370: args.features = features_icq;
! 3371: args.featureslen = sizeof(features_icq);
! 3372: } else {
! 3373: args.features = features_aim;
! 3374: args.featureslen = sizeof(features_aim);
! 3375:
! 3376: if (imflags & PURPLE_MESSAGE_AUTO_RESP)
! 3377: args.flags |= AIM_IMFLAGS_AWAY;
! 3378: }
! 3379:
! 3380: if (bi->ico_need) {
! 3381: purple_debug_info("oscar",
! 3382: "Sending buddy icon request with message\n");
! 3383: args.flags |= AIM_IMFLAGS_BUDDYREQ;
! 3384: bi->ico_need = FALSE;
! 3385: }
! 3386:
! 3387: img = purple_buddy_icons_find_account_icon(account);
! 3388: if (img) {
! 3389: gconstpointer data = purple_imgstore_get_data(img);
! 3390: args.iconlen = purple_imgstore_get_size(img);
! 3391: args.iconsum = aimutil_iconsum(data, args.iconlen);
! 3392: args.iconstamp = purple_buddy_icons_get_account_icon_timestamp(account);
! 3393:
! 3394: if ((args.iconlen != bi->ico_me_len) || (args.iconsum != bi->ico_me_csum) || (args.iconstamp != bi->ico_me_time)) {
! 3395: bi->ico_informed = FALSE;
! 3396: bi->ico_sent = FALSE;
! 3397: }
! 3398:
! 3399: /*
! 3400: * TODO:
! 3401: * For some reason sending our icon to people only works
! 3402: * when we're the ones who initiated the conversation. If
! 3403: * the other person sends the first IM then they never get
! 3404: * the icon. We should fix that.
! 3405: */
! 3406: if (!bi->ico_informed) {
! 3407: purple_debug_info("oscar",
! 3408: "Claiming to have a buddy icon\n");
! 3409: args.flags |= AIM_IMFLAGS_HASICON;
! 3410: bi->ico_me_len = args.iconlen;
! 3411: bi->ico_me_csum = args.iconsum;
! 3412: bi->ico_me_time = args.iconstamp;
! 3413: bi->ico_informed = TRUE;
! 3414: }
! 3415:
! 3416: purple_imgstore_unref(img);
! 3417: }
! 3418:
! 3419: args.destbn = name;
! 3420:
! 3421: if (oscar_util_valid_name_sms(name)) {
! 3422: /* Messaging an SMS (mobile) user--strip HTML */
! 3423: tmp2 = purple_markup_strip_html(tmp1);
! 3424: is_html = FALSE;
! 3425: } else {
! 3426: /* ICQ 6 wants its HTML wrapped in these tags. Oblige it. */
! 3427: tmp2 = g_strdup_printf("<HTML><BODY>%s</BODY></HTML>", tmp1);
! 3428: is_html = TRUE;
! 3429: }
! 3430: g_free(tmp1);
! 3431: tmp1 = tmp2;
! 3432:
! 3433: args.msg = oscar_encode_im(tmp1, &args.msglen, &args.charset, NULL);
! 3434: if (is_html && (args.msglen > MAXMSGLEN)) {
! 3435: /* If the length was too long, try stripping the HTML and then running it back through
! 3436: * purple_strdup_withhtml() and the encoding process. The result may be shorter. */
! 3437: g_free((char *)args.msg);
! 3438:
! 3439: tmp2 = purple_markup_strip_html(tmp1);
! 3440: g_free(tmp1);
! 3441:
! 3442: /* re-escape the entities */
! 3443: tmp1 = g_markup_escape_text(tmp2, -1);
! 3444: g_free(tmp2);
! 3445:
! 3446: tmp2 = purple_strdup_withhtml(tmp1);
! 3447: g_free(tmp1);
! 3448: tmp1 = tmp2;
! 3449:
! 3450: args.msg = oscar_encode_im(tmp1, &args.msglen, &args.charset, NULL);
! 3451: purple_debug_info("oscar", "Sending %s as %s because the original was too long.\n",
! 3452: message, (char *)args.msg);
! 3453: }
! 3454:
! 3455: purple_debug_info("oscar", "Sending IM, charset=0x%04hx, length=%" G_GSIZE_FORMAT "\n", args.charset, args.msglen);
! 3456: ret = aim_im_sendch1_ext(od, &args);
! 3457: g_free((char *)args.msg);
! 3458: }
! 3459:
! 3460: g_free(tmp1);
! 3461:
! 3462: if (ret >= 0)
! 3463: return 1;
! 3464:
! 3465: return ret;
! 3466: }
! 3467:
! 3468: /*
! 3469: * As of 26 June 2006, ICQ users can request AIM info from
! 3470: * everyone, and can request ICQ info from ICQ users, and
! 3471: * AIM users can only request AIM info.
! 3472: */
! 3473: void oscar_get_info(PurpleConnection *gc, const char *name) {
! 3474: OscarData *od = purple_connection_get_protocol_data(gc);
! 3475:
! 3476: if (od->icq && oscar_util_valid_name_icq(name))
! 3477: aim_icq_getallinfo(od, name);
! 3478: else
! 3479: aim_locate_getinfoshort(od, name, 0x00000003);
! 3480: }
! 3481:
! 3482: void oscar_set_idle(PurpleConnection *gc, int time) {
! 3483: OscarData *od = purple_connection_get_protocol_data(gc);
! 3484: aim_srv_setidle(od, time);
! 3485: }
! 3486:
! 3487: void
! 3488: oscar_set_info(PurpleConnection *gc, const char *rawinfo)
! 3489: {
! 3490: PurpleAccount *account;
! 3491: PurpleStatus *status;
! 3492:
! 3493: account = purple_connection_get_account(gc);
! 3494: status = purple_account_get_active_status(account);
! 3495: oscar_set_info_and_status(account, TRUE, rawinfo, FALSE, status);
! 3496: }
! 3497:
! 3498: static guint32
! 3499: oscar_get_extended_status(PurpleConnection *gc)
! 3500: {
! 3501: PurpleAccount *account;
! 3502: PurpleStatus *status;
! 3503: const gchar *status_id;
! 3504: guint32 data = 0x00000000;
! 3505:
! 3506: account = purple_connection_get_account(gc);
! 3507: status = purple_account_get_active_status(account);
! 3508: status_id = purple_status_get_id(status);
! 3509:
! 3510: data |= AIM_ICQ_STATE_HIDEIP;
! 3511: if (purple_account_get_bool(account, "web_aware", OSCAR_DEFAULT_WEB_AWARE))
! 3512: data |= AIM_ICQ_STATE_WEBAWARE;
! 3513:
! 3514: if (purple_strequal(status_id, OSCAR_STATUS_ID_AVAILABLE))
! 3515: data |= AIM_ICQ_STATE_NORMAL;
! 3516: else if (purple_strequal(status_id, OSCAR_STATUS_ID_AWAY))
! 3517: data |= AIM_ICQ_STATE_AWAY;
! 3518: else if (purple_strequal(status_id, OSCAR_STATUS_ID_DND))
! 3519: data |= AIM_ICQ_STATE_AWAY | AIM_ICQ_STATE_DND | AIM_ICQ_STATE_BUSY;
! 3520: else if (purple_strequal(status_id, OSCAR_STATUS_ID_NA))
! 3521: data |= AIM_ICQ_STATE_OUT | AIM_ICQ_STATE_AWAY;
! 3522: else if (purple_strequal(status_id, OSCAR_STATUS_ID_OCCUPIED))
! 3523: data |= AIM_ICQ_STATE_AWAY | AIM_ICQ_STATE_BUSY;
! 3524: else if (purple_strequal(status_id, OSCAR_STATUS_ID_FREE4CHAT))
! 3525: data |= AIM_ICQ_STATE_CHAT;
! 3526: else if (purple_strequal(status_id, OSCAR_STATUS_ID_INVISIBLE))
! 3527: data |= AIM_ICQ_STATE_INVISIBLE;
! 3528: else if (purple_strequal(status_id, OSCAR_STATUS_ID_EVIL))
! 3529: data |= AIM_ICQ_STATE_EVIL;
! 3530: else if (purple_strequal(status_id, OSCAR_STATUS_ID_DEPRESSION))
! 3531: data |= AIM_ICQ_STATE_DEPRESSION;
! 3532: else if (purple_strequal(status_id, OSCAR_STATUS_ID_ATWORK))
! 3533: data |= AIM_ICQ_STATE_ATWORK;
! 3534: else if (purple_strequal(status_id, OSCAR_STATUS_ID_ATHOME))
! 3535: data |= AIM_ICQ_STATE_ATHOME;
! 3536: else if (purple_strequal(status_id, OSCAR_STATUS_ID_LUNCH))
! 3537: data |= AIM_ICQ_STATE_LUNCH;
! 3538: else if (purple_strequal(status_id, OSCAR_STATUS_ID_CUSTOM))
! 3539: data |= AIM_ICQ_STATE_OUT | AIM_ICQ_STATE_AWAY;
! 3540:
! 3541: return data;
! 3542: }
! 3543:
! 3544: static void
! 3545: oscar_set_extended_status(PurpleConnection *gc)
! 3546: {
! 3547: aim_srv_setextrainfo(purple_connection_get_protocol_data(gc), TRUE, oscar_get_extended_status(gc), FALSE, NULL, NULL);
! 3548: }
! 3549:
! 3550: static void
! 3551: oscar_set_info_and_status(PurpleAccount *account, gboolean setinfo, const char *rawinfo,
! 3552: gboolean setstatus, PurpleStatus *status)
! 3553: {
! 3554: PurpleConnection *gc = purple_account_get_connection(account);
! 3555: OscarData *od = purple_connection_get_protocol_data(gc);
! 3556: PurpleStatusType *status_type;
! 3557: PurpleStatusPrimitive primitive;
! 3558:
! 3559: char *info_encoding = NULL;
! 3560: char *info = NULL;
! 3561: gsize infolen = 0;
! 3562:
! 3563: char *away_encoding = NULL;
! 3564: char *away = NULL;
! 3565: gsize awaylen = 0;
! 3566:
! 3567: char *status_text = NULL;
! 3568: const char *itmsurl = NULL;
! 3569:
! 3570: status_type = purple_status_get_type(status);
! 3571: primitive = purple_status_type_get_primitive(status_type);
! 3572:
! 3573: if (!setinfo)
! 3574: {
! 3575: /* Do nothing! */
! 3576: }
! 3577: else if (od->rights.maxsiglen == 0)
! 3578: {
! 3579: purple_notify_warning(gc, NULL, _("Unable to set AIM profile."),
! 3580: _("You have probably requested to set your "
! 3581: "profile before the login procedure completed. "
! 3582: "Your profile remains unset; try setting it "
! 3583: "again when you are fully connected."));
! 3584: }
! 3585: else if (rawinfo != NULL)
! 3586: {
! 3587: char *htmlinfo = purple_strdup_withhtml(rawinfo);
! 3588: info = oscar_encode_im(htmlinfo, &infolen, NULL, &info_encoding);
! 3589: g_free(htmlinfo);
! 3590:
! 3591: if (infolen > od->rights.maxsiglen)
! 3592: {
! 3593: gchar *errstr;
! 3594: errstr = g_strdup_printf(dngettext(PACKAGE, "The maximum profile length of %d byte "
! 3595: "has been exceeded. It has been truncated for you.",
! 3596: "The maximum profile length of %d bytes "
! 3597: "has been exceeded. It has been truncated for you.",
! 3598: od->rights.maxsiglen), od->rights.maxsiglen);
! 3599: purple_notify_warning(gc, NULL, _("Profile too long."), errstr);
! 3600: g_free(errstr);
! 3601: }
! 3602: }
! 3603:
! 3604: if (setstatus)
! 3605: {
! 3606: const char *status_html;
! 3607:
! 3608: status_html = purple_status_get_attr_string(status, "message");
! 3609:
! 3610: if (status_html == NULL || primitive == PURPLE_STATUS_AVAILABLE || primitive == PURPLE_STATUS_INVISIBLE)
! 3611: {
! 3612: /* This is needed for us to un-set any previous away message. */
! 3613: away = g_strdup("");
! 3614: }
! 3615: else
! 3616: {
! 3617: gchar *linkified;
! 3618:
! 3619: /* We do this for icq too so that they work for old third party clients */
! 3620: linkified = purple_markup_linkify(status_html);
! 3621: away = oscar_encode_im(linkified, &awaylen, NULL, &away_encoding);
! 3622: g_free(linkified);
! 3623:
! 3624: if (awaylen > od->rights.maxawaymsglen)
! 3625: {
! 3626: gchar *errstr;
! 3627:
! 3628: errstr = g_strdup_printf(dngettext(PACKAGE, "The maximum away message length of %d byte "
! 3629: "has been exceeded. It has been truncated for you.",
! 3630: "The maximum away message length of %d bytes "
! 3631: "has been exceeded. It has been truncated for you.",
! 3632: od->rights.maxawaymsglen), od->rights.maxawaymsglen);
! 3633: purple_notify_warning(gc, NULL, _("Away message too long."), errstr);
! 3634: g_free(errstr);
! 3635: }
! 3636: }
! 3637: }
! 3638:
! 3639: aim_locate_setprofile(od,
! 3640: info_encoding, info, MIN(infolen, od->rights.maxsiglen),
! 3641: away_encoding, away, MIN(awaylen, od->rights.maxawaymsglen));
! 3642: g_free(info);
! 3643: g_free(away);
! 3644:
! 3645: if (setstatus)
! 3646: {
! 3647: const char *status_html;
! 3648:
! 3649: status_html = purple_status_get_attr_string(status, "message");
! 3650: if (status_html != NULL)
! 3651: {
! 3652: status_text = purple_markup_strip_html(status_html);
! 3653: /* If the status_text is longer than 251 characters then truncate it */
! 3654: if (strlen(status_text) > MAXAVAILMSGLEN)
! 3655: {
! 3656: char *tmp = g_utf8_find_prev_char(status_text, &status_text[MAXAVAILMSGLEN - 2]);
! 3657: strcpy(tmp, "...");
! 3658: }
! 3659: }
! 3660:
! 3661: itmsurl = purple_status_get_attr_string(status, "itmsurl");
! 3662:
! 3663: aim_srv_setextrainfo(od, TRUE, oscar_get_extended_status(gc), TRUE, status_text, itmsurl);
! 3664: g_free(status_text);
! 3665: }
! 3666: }
! 3667:
! 3668: static void
! 3669: oscar_set_icq_permdeny(PurpleAccount *account)
! 3670: {
! 3671: PurpleConnection *gc = purple_account_get_connection(account);
! 3672: OscarData *od = purple_connection_get_protocol_data(gc);
! 3673: gboolean invisible = purple_account_is_status_active(account, OSCAR_STATUS_ID_INVISIBLE);
! 3674:
! 3675: /*
! 3676: * For ICQ the permit/deny setting controls who can see you
! 3677: * online. Mimicking the official client's behavior, we use PURPLE_PRIVACY_ALLOW_USERS
! 3678: * when our status is "invisible" and PURPLE_PRIVACY_DENY_USERS otherwise.
! 3679: * In the former case, we are visible only to buddies on our "permanently visible" list.
! 3680: * In the latter, we are invisible only to buddies on our "permanently invisible" list.
! 3681: */
! 3682: aim_ssi_setpermdeny(od, invisible ? PURPLE_PRIVACY_ALLOW_USERS : PURPLE_PRIVACY_DENY_USERS);
! 3683: }
! 3684:
! 3685: void
! 3686: oscar_set_status(PurpleAccount *account, PurpleStatus *status)
! 3687: {
! 3688: PurpleConnection *pc;
! 3689: OscarData *od;
! 3690:
! 3691: purple_debug_info("oscar", "Set status to %s\n", purple_status_get_name(status));
! 3692:
! 3693: /* Either setting a new status active or setting a status inactive.
! 3694: * (Only possible for independent status (i.e. X-Status moods.) */
! 3695: if (!purple_status_is_active(status) && !purple_status_is_independent(status))
! 3696: return;
! 3697:
! 3698: if (!purple_account_is_connected(account))
! 3699: return;
! 3700:
! 3701: pc = purple_account_get_connection(account);
! 3702: od = purple_connection_get_protocol_data(pc);
! 3703:
! 3704: /* There's no need to do the stuff below for mood updates. */
! 3705: if (purple_status_type_get_primitive(purple_status_get_type(status)) == PURPLE_STATUS_MOOD) {
! 3706: aim_locate_setcaps(od, purple_caps);
! 3707: return;
! 3708: }
! 3709:
! 3710: if (od->icq) {
! 3711: /* Set visibility */
! 3712: oscar_set_icq_permdeny(account);
! 3713: }
! 3714:
! 3715: /* Set the AIM-style away message for both AIM and ICQ accounts */
! 3716: oscar_set_info_and_status(account, FALSE, NULL, TRUE, status);
! 3717: }
! 3718:
! 3719: void
! 3720: oscar_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group, const char *msg)
! 3721: {
! 3722: OscarData *od;
! 3723: PurpleAccount *account;
! 3724: const char *bname, *gname;
! 3725:
! 3726: od = purple_connection_get_protocol_data(gc);
! 3727: account = purple_connection_get_account(gc);
! 3728: bname = purple_buddy_get_name(buddy);
! 3729: gname = purple_group_get_name(group);
! 3730:
! 3731: if (!oscar_util_valid_name(bname)) {
! 3732: gchar *buf;
! 3733: buf = g_strdup_printf(_("Unable to add the buddy %s because the username is invalid. Usernames must be a valid email address, or start with a letter and contain only letters, numbers and spaces, or contain only numbers."), bname);
! 3734: if (!purple_conv_present_error(bname, account, buf))
! 3735: purple_notify_error(gc, NULL, _("Unable to Add"), buf);
! 3736: g_free(buf);
! 3737:
! 3738: /* Remove from local list */
! 3739: purple_blist_remove_buddy(buddy);
! 3740:
! 3741: return;
! 3742: }
! 3743:
! 3744: if (od->ssi.received_data) {
! 3745: if (!aim_ssi_itemlist_finditem(od->ssi.local, gname, bname, AIM_SSI_TYPE_BUDDY)) {
! 3746: purple_debug_info("oscar",
! 3747: "ssi: adding buddy %s to group %s\n", bname, gname);
! 3748: aim_ssi_addbuddy(od, bname, gname, NULL, purple_buddy_get_alias_only(buddy), NULL, NULL, 0);
! 3749:
! 3750: /* Mobile users should always be online */
! 3751: if (bname[0] == '+') {
! 3752: purple_prpl_got_user_status(account, bname,
! 3753: OSCAR_STATUS_ID_AVAILABLE, NULL);
! 3754: purple_prpl_got_user_status(account, bname,
! 3755: OSCAR_STATUS_ID_MOBILE, NULL);
! 3756: }
! 3757: } else if (aim_ssi_waitingforauth(od->ssi.local,
! 3758: aim_ssi_itemlist_findparentname(od->ssi.local, bname),
! 3759: bname)) {
! 3760: /* Not authorized -- Re-request authorization */
! 3761: oscar_auth_sendrequest(gc, bname, msg);
! 3762: }
! 3763: }
! 3764:
! 3765: /* XXX - Should this be done from AIM accounts, as well? */
! 3766: if (od->icq)
! 3767: aim_icq_getalias(od, bname, FALSE, NULL);
! 3768: }
! 3769:
! 3770: void oscar_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) {
! 3771: OscarData *od = purple_connection_get_protocol_data(gc);
! 3772:
! 3773: if (od->ssi.received_data) {
! 3774: const char *gname = purple_group_get_name(group);
! 3775: const char *bname = purple_buddy_get_name(buddy);
! 3776: purple_debug_info("oscar",
! 3777: "ssi: deleting buddy %s from group %s\n", bname, gname);
! 3778: aim_ssi_delbuddy(od, bname, gname);
! 3779: }
! 3780: }
! 3781:
! 3782: void oscar_move_buddy(PurpleConnection *gc, const char *name, const char *old_group, const char *new_group) {
! 3783: OscarData *od = purple_connection_get_protocol_data(gc);
! 3784:
! 3785: if (od->ssi.received_data && !purple_strequal(old_group, new_group)) {
! 3786: purple_debug_info("oscar",
! 3787: "ssi: moving buddy %s from group %s to group %s\n", name, old_group, new_group);
! 3788: aim_ssi_movebuddy(od, old_group, new_group, name);
! 3789: }
! 3790: }
! 3791:
! 3792: void oscar_alias_buddy(PurpleConnection *gc, const char *name, const char *alias) {
! 3793: OscarData *od = purple_connection_get_protocol_data(gc);
! 3794:
! 3795: if (od->ssi.received_data) {
! 3796: char *gname = aim_ssi_itemlist_findparentname(od->ssi.local, name);
! 3797: if (gname) {
! 3798: purple_debug_info("oscar",
! 3799: "ssi: changing the alias for buddy %s to %s\n", name, alias ? alias : "(none)");
! 3800: aim_ssi_aliasbuddy(od, gname, name, alias);
! 3801: }
! 3802: }
! 3803: }
! 3804:
! 3805: /*
! 3806: * FYI, the OSCAR SSI code removes empty groups automatically.
! 3807: */
! 3808: void oscar_rename_group(PurpleConnection *gc, const char *old_name, PurpleGroup *group, GList *moved_buddies) {
! 3809: OscarData *od = purple_connection_get_protocol_data(gc);
! 3810:
! 3811: if (od->ssi.received_data) {
! 3812: const char *gname = purple_group_get_name(group);
! 3813: if (aim_ssi_itemlist_finditem(od->ssi.local, gname, NULL, AIM_SSI_TYPE_GROUP)) {
! 3814: GList *cur, *groups = NULL;
! 3815: PurpleAccount *account = purple_connection_get_account(gc);
! 3816:
! 3817: /* Make a list of what the groups each buddy is in */
! 3818: for (cur = moved_buddies; cur != NULL; cur = cur->next) {
! 3819: PurpleBlistNode *node = cur->data;
! 3820: /* node is PurpleBuddy, parent is a PurpleContact.
! 3821: * We must go two levels up to get the Group */
! 3822: groups = g_list_append(groups,
! 3823: purple_buddy_get_group((PurpleBuddy*)node));
! 3824: }
! 3825:
! 3826: purple_account_remove_buddies(account, moved_buddies, groups);
! 3827: purple_account_add_buddies(account, moved_buddies);
! 3828: g_list_free(groups);
! 3829: purple_debug_info("oscar",
! 3830: "ssi: moved all buddies from group %s to %s\n", old_name, gname);
! 3831: } else {
! 3832: aim_ssi_rename_group(od, old_name, gname);
! 3833: purple_debug_info("oscar",
! 3834: "ssi: renamed group %s to %s\n", old_name, gname);
! 3835: }
! 3836: }
! 3837: }
! 3838:
! 3839: void oscar_remove_group(PurpleConnection *gc, PurpleGroup *group)
! 3840: {
! 3841: aim_ssi_delgroup(purple_connection_get_protocol_data(gc), purple_group_get_name(group));
! 3842: }
! 3843:
! 3844: static gboolean purple_ssi_rerequestdata(gpointer data) {
! 3845: OscarData *od = data;
! 3846:
! 3847: aim_ssi_reqdata(od);
! 3848:
! 3849: return TRUE;
! 3850: }
! 3851:
! 3852: static int purple_ssi_parseerr(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
! 3853: PurpleConnection *gc = od->gc;
! 3854: va_list ap;
! 3855: guint16 reason;
! 3856:
! 3857: va_start(ap, fr);
! 3858: reason = (guint16)va_arg(ap, unsigned int);
! 3859: va_end(ap);
! 3860:
! 3861: purple_debug_error("oscar", "ssi: SNAC error %hu\n", reason);
! 3862:
! 3863: if (reason == 0x0005) {
! 3864: if (od->getblisttimer > 0)
! 3865: purple_timeout_remove(od->getblisttimer);
! 3866: else
! 3867: /* We only show this error the first time it happens */
! 3868: purple_notify_error(gc, NULL,
! 3869: _("Unable to Retrieve Buddy List"),
! 3870: _("The AIM servers were temporarily unable to send "
! 3871: "your buddy list. Your buddy list is not lost, and "
! 3872: "will probably become available in a few minutes."));
! 3873: od->getblisttimer = purple_timeout_add_seconds(30, purple_ssi_rerequestdata, od);
! 3874: return 1;
! 3875: }
! 3876:
! 3877: return 1;
! 3878: }
! 3879:
! 3880: static int purple_ssi_parserights(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
! 3881: int i;
! 3882: va_list ap;
! 3883: int numtypes;
! 3884: guint16 *maxitems;
! 3885: GString *msg;
! 3886:
! 3887: va_start(ap, fr);
! 3888: numtypes = va_arg(ap, int);
! 3889: maxitems = va_arg(ap, guint16 *);
! 3890: va_end(ap);
! 3891:
! 3892: msg = g_string_new("ssi rights:");
! 3893: for (i=0; i<numtypes; i++)
! 3894: g_string_append_printf(msg, " max type 0x%04x=%hd,", i, maxitems[i]);
! 3895: g_string_append(msg, "\n");
! 3896: purple_debug_misc("oscar", "%s", msg->str);
! 3897: g_string_free(msg, TRUE);
! 3898:
! 3899: if (numtypes >= 0)
! 3900: od->rights.maxbuddies = maxitems[0];
! 3901: if (numtypes >= 1)
! 3902: od->rights.maxgroups = maxitems[1];
! 3903: if (numtypes >= 2)
! 3904: od->rights.maxpermits = maxitems[2];
! 3905: if (numtypes >= 3)
! 3906: od->rights.maxdenies = maxitems[3];
! 3907:
! 3908: return 1;
! 3909: }
! 3910:
! 3911: static int purple_ssi_parselist(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
! 3912: {
! 3913: PurpleConnection *gc;
! 3914: PurpleAccount *account;
! 3915: PurpleGroup *g;
! 3916: PurpleBuddy *b;
! 3917: GSList *cur, *next, *buddies;
! 3918: struct aim_ssi_item *curitem;
! 3919: guint32 tmp;
! 3920: PurpleStoredImage *img;
! 3921: va_list ap;
! 3922: guint16 deny_entry_type = aim_ssi_getdenyentrytype(od);
! 3923:
! 3924: gc = od->gc;
! 3925: od = purple_connection_get_protocol_data(gc);
! 3926: account = purple_connection_get_account(gc);
! 3927:
! 3928: va_start(ap, fr);
! 3929: va_arg(ap, int); /* guint16 fmtver */
! 3930: va_arg(ap, int); /* guint16 numitems */
! 3931: va_arg(ap, guint32); /* timestamp */
! 3932: va_end(ap);
! 3933:
! 3934: /* Don't attempt to re-request our buddy list later */
! 3935: if (od->getblisttimer != 0) {
! 3936: purple_timeout_remove(od->getblisttimer);
! 3937: od->getblisttimer = 0;
! 3938: }
! 3939:
! 3940: purple_debug_info("oscar", "ssi: syncing local list and server list\n");
! 3941:
! 3942: /* Clean the buddy list */
! 3943: aim_ssi_cleanlist(od);
! 3944:
! 3945: /*** Begin code for pruning buddies from local list if they're not in server list ***/
! 3946:
! 3947: /* Buddies */
! 3948: cur = NULL;
! 3949: for (buddies = purple_find_buddies(account, NULL);
! 3950: buddies;
! 3951: buddies = g_slist_delete_link(buddies, buddies))
! 3952: {
! 3953: PurpleGroup *g;
! 3954: const char *gname;
! 3955: const char *bname;
! 3956:
! 3957: b = buddies->data;
! 3958: g = purple_buddy_get_group(b);
! 3959: gname = purple_group_get_name(g);
! 3960: bname = purple_buddy_get_name(b);
! 3961:
! 3962: if (aim_ssi_itemlist_exists(od->ssi.local, bname)) {
! 3963: /* If the buddy is an ICQ user then load his nickname */
! 3964: const char *servernick = purple_blist_node_get_string((PurpleBlistNode*)b, "servernick");
! 3965: char *alias;
! 3966: const char *balias;
! 3967: if (servernick)
! 3968: serv_got_alias(gc, bname, servernick);
! 3969:
! 3970: /* Store local alias on server */
! 3971: alias = aim_ssi_getalias(od->ssi.local, gname, bname);
! 3972: balias = purple_buddy_get_local_buddy_alias(b);
! 3973: if (!alias && balias && *balias)
! 3974: aim_ssi_aliasbuddy(od, gname, bname, balias);
! 3975: g_free(alias);
! 3976: } else {
! 3977: purple_debug_info("oscar",
! 3978: "ssi: removing buddy %s from local list\n", bname);
! 3979: /* Queue the buddy for removal from the local list */
! 3980: cur = g_slist_prepend(cur, b);
! 3981: }
! 3982: }
! 3983: while (cur != NULL) {
! 3984: purple_blist_remove_buddy(cur->data);
! 3985: cur = g_slist_delete_link(cur, cur);
! 3986: }
! 3987:
! 3988: /* Permit list (ICQ doesn't have one) */
! 3989: if (!od->icq) {
! 3990: next = account->permit;
! 3991: while (next != NULL) {
! 3992: cur = next;
! 3993: next = next->next;
! 3994: if (!aim_ssi_itemlist_finditem(od->ssi.local, NULL, cur->data, AIM_SSI_TYPE_PERMIT)) {
! 3995: purple_debug_info("oscar",
! 3996: "ssi: removing permit %s from local list\n", (const char *)cur->data);
! 3997: purple_privacy_permit_remove(account, cur->data, TRUE);
! 3998: }
! 3999: }
! 4000: }
! 4001:
! 4002: /* Deny list */
! 4003: next = account->deny;
! 4004: while (next != NULL) {
! 4005: cur = next;
! 4006: next = next->next;
! 4007: if (!aim_ssi_itemlist_finditem(od->ssi.local, NULL, cur->data, deny_entry_type)) {
! 4008: purple_debug_info("oscar",
! 4009: "ssi: removing deny %s from local list\n", (const char *)cur->data);
! 4010: purple_privacy_deny_remove(account, cur->data, TRUE);
! 4011: }
! 4012: }
! 4013:
! 4014: /* Presence settings (idle time visibility) */
! 4015: tmp = aim_ssi_getpresence(od->ssi.local);
! 4016: if (tmp != 0xFFFFFFFF) {
! 4017: const char *idle_reporting_pref;
! 4018: gboolean report_idle;
! 4019:
! 4020: idle_reporting_pref = purple_prefs_get_string("/purple/away/idle_reporting");
! 4021: report_idle = !purple_strequal(idle_reporting_pref, "none");
! 4022:
! 4023: if (report_idle)
! 4024: aim_ssi_setpresence(od, tmp | AIM_SSI_PRESENCE_FLAG_SHOWIDLE);
! 4025: else
! 4026: aim_ssi_setpresence(od, tmp & ~AIM_SSI_PRESENCE_FLAG_SHOWIDLE);
! 4027: }
! 4028:
! 4029: /*** End code for pruning buddies from local list ***/
! 4030:
! 4031: /*** Begin code for adding from server list to local list ***/
! 4032:
! 4033: for (curitem=od->ssi.local; curitem; curitem=curitem->next) {
! 4034: if (curitem->name && !g_utf8_validate(curitem->name, -1, NULL)) {
! 4035: /* Got node with invalid UTF-8 in the name. Skip it. */
! 4036: purple_debug_warning("oscar", "ssi: server list contains item of "
! 4037: "type 0x%04hx with a non-utf8 name\n", curitem->type);
! 4038: continue;
! 4039: }
! 4040:
! 4041: switch (curitem->type) {
! 4042: case AIM_SSI_TYPE_BUDDY: { /* Buddy */
! 4043: if (curitem->name) {
! 4044: struct aim_ssi_item *groupitem;
! 4045: char *gname, *gname_utf8, *alias, *alias_utf8;
! 4046:
! 4047: groupitem = aim_ssi_itemlist_find(od->ssi.local, curitem->gid, 0x0000);
! 4048: gname = groupitem ? groupitem->name : NULL;
! 4049: gname_utf8 = oscar_utf8_try_convert(account, od, gname);
! 4050:
! 4051: g = purple_find_group(gname_utf8 ? gname_utf8 : _("Orphans"));
! 4052: if (g == NULL) {
! 4053: g = purple_group_new(gname_utf8 ? gname_utf8 : _("Orphans"));
! 4054: purple_blist_add_group(g, NULL);
! 4055: }
! 4056:
! 4057: alias = aim_ssi_getalias(od->ssi.local, gname, curitem->name);
! 4058: alias_utf8 = oscar_utf8_try_convert(account, od, alias);
! 4059:
! 4060: b = purple_find_buddy_in_group(account, curitem->name, g);
! 4061: if (b) {
! 4062: /* Get server stored alias */
! 4063: purple_blist_alias_buddy(b, alias_utf8);
! 4064: } else {
! 4065: b = purple_buddy_new(account, curitem->name, alias_utf8);
! 4066:
! 4067: purple_debug_info("oscar",
! 4068: "ssi: adding buddy %s to group %s to local list\n", curitem->name, gname);
! 4069: purple_blist_add_buddy(b, NULL, g, NULL);
! 4070: }
! 4071:
! 4072: /* Mobile users should always be online */
! 4073: if (curitem->name[0] == '+') {
! 4074: purple_prpl_got_user_status(account,
! 4075: purple_buddy_get_name(b),
! 4076: OSCAR_STATUS_ID_AVAILABLE, NULL);
! 4077: purple_prpl_got_user_status(account,
! 4078: purple_buddy_get_name(b),
! 4079: OSCAR_STATUS_ID_MOBILE, NULL);
! 4080: }
! 4081:
! 4082: g_free(gname_utf8);
! 4083: g_free(alias);
! 4084: g_free(alias_utf8);
! 4085: }
! 4086: } break;
! 4087:
! 4088: case AIM_SSI_TYPE_GROUP: { /* Group */
! 4089: if (curitem->name != NULL && purple_find_group(curitem->name) == NULL) {
! 4090: g = purple_group_new(curitem->name);
! 4091: purple_blist_add_group(g, NULL);
! 4092: }
! 4093: } break;
! 4094:
! 4095: case AIM_SSI_TYPE_PERMIT: { /* Permit buddy (unless we're on ICQ) */
! 4096: if (!od->icq && curitem->name) {
! 4097: for (cur = account->permit; (cur && oscar_util_name_compare(curitem->name, cur->data)); cur = cur->next);
! 4098: if (!cur) {
! 4099: purple_debug_info("oscar",
! 4100: "ssi: adding permit buddy %s to local list\n", curitem->name);
! 4101: purple_privacy_permit_add(account, curitem->name, TRUE);
! 4102: }
! 4103: }
! 4104: } break;
! 4105:
! 4106: case AIM_SSI_TYPE_ICQDENY:
! 4107: case AIM_SSI_TYPE_DENY: { /* Deny buddy */
! 4108: if (curitem->type == deny_entry_type && curitem->name) {
! 4109: for (cur = account->deny; (cur && oscar_util_name_compare(curitem->name, cur->data)); cur = cur->next);
! 4110: if (!cur) {
! 4111: purple_debug_info("oscar",
! 4112: "ssi: adding deny buddy %s to local list\n", curitem->name);
! 4113: purple_privacy_deny_add(account, curitem->name, TRUE);
! 4114: }
! 4115: }
! 4116: } break;
! 4117:
! 4118: case AIM_SSI_TYPE_PDINFO: { /* Permit/deny setting */
! 4119: /*
! 4120: * We don't inherit the permit/deny setting from the server
! 4121: * for ICQ because, for ICQ, this setting controls who can
! 4122: * see your online status when you are invisible. Thus it is
! 4123: * a part of your status and not really related to blocking.
! 4124: */
! 4125: if (!od->icq && curitem->data) {
! 4126: guint8 perm_deny = aim_ssi_getpermdeny(od->ssi.local);
! 4127: if (perm_deny != 0 && perm_deny != account->perm_deny)
! 4128: {
! 4129: purple_debug_info("oscar",
! 4130: "ssi: changing permdeny from %d to %hhu\n", account->perm_deny, perm_deny);
! 4131: account->perm_deny = perm_deny;
! 4132: }
! 4133: }
! 4134: } break;
! 4135:
! 4136: case AIM_SSI_TYPE_PRESENCEPREFS: { /* Presence setting */
! 4137: /* We don't want to change Purple's setting because it applies to all accounts */
! 4138: } break;
! 4139: } /* End of switch on curitem->type */
! 4140: } /* End of for loop */
! 4141:
! 4142: /*** End code for adding from server list to local list ***/
! 4143:
! 4144: if (od->icq) {
! 4145: oscar_set_icq_permdeny(account);
! 4146: } else {
! 4147: oscar_set_aim_permdeny(gc);
! 4148: }
! 4149:
! 4150: /* Activate SSI */
! 4151: /* Sending the enable causes other people to be able to see you, and you to see them */
! 4152: /* Make sure your privacy setting/invisibility is set how you want it before this! */
! 4153: purple_debug_info("oscar",
! 4154: "ssi: activating server-stored buddy list\n");
! 4155: aim_ssi_enable(od);
! 4156:
! 4157: /*
! 4158: * Make sure our server-stored icon is updated correctly in
! 4159: * the event that the local user set a new icon while this
! 4160: * account was offline.
! 4161: */
! 4162: img = purple_buddy_icons_find_account_icon(account);
! 4163: oscar_set_icon(gc, img);
! 4164: purple_imgstore_unref(img);
! 4165:
! 4166: /*
! 4167: * If we've already received our bos rights then we're not waiting on
! 4168: * anything else, so send the server clientready.
! 4169: */
! 4170: if (od->bos.have_rights) {
! 4171: aim_srv_clientready(od, conn);
! 4172:
! 4173: /* Request offline messages for AIM and ICQ */
! 4174: aim_im_reqofflinemsgs(od);
! 4175:
! 4176: purple_connection_set_state(gc, PURPLE_CONNECTED);
! 4177: }
! 4178:
! 4179: return 1;
! 4180: }
! 4181:
! 4182: static int purple_ssi_parseack(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
! 4183: PurpleConnection *gc = od->gc;
! 4184: va_list ap;
! 4185: struct aim_ssi_tmp *retval;
! 4186:
! 4187: va_start(ap, fr);
! 4188: retval = va_arg(ap, struct aim_ssi_tmp *);
! 4189: va_end(ap);
! 4190:
! 4191: while (retval) {
! 4192: purple_debug_misc("oscar",
! 4193: "ssi: status is 0x%04hx for a 0x%04hx action with name %s\n", retval->ack, retval->action, retval->item ? (retval->item->name ? retval->item->name : "no name") : "no item");
! 4194:
! 4195: if (retval->ack != 0xffff)
! 4196: switch (retval->ack) {
! 4197: case 0x0000: { /* added successfully */
! 4198: } break;
! 4199:
! 4200: case 0x000c: { /* you are over the limit, the cheat is to the limit, come on fhqwhgads */
! 4201: gchar *buf;
! 4202: buf = g_strdup_printf(_("Unable to add the buddy %s because you have too many buddies in your buddy list. Please remove one and try again."), (retval->name ? retval->name : _("(no name)")));
! 4203: if ((retval->name != NULL) && !purple_conv_present_error(retval->name, purple_connection_get_account(gc), buf))
! 4204: purple_notify_error(gc, NULL, _("Unable to Add"), buf);
! 4205: g_free(buf);
! 4206: } break;
! 4207:
! 4208: case 0x000e: { /* buddy requires authorization */
! 4209: if ((retval->action == SNAC_SUBTYPE_FEEDBAG_ADD) && (retval->name))
! 4210: oscar_auth_sendrequest(gc, retval->name, NULL);
! 4211: } break;
! 4212:
! 4213: default: { /* La la la */
! 4214: gchar *buf;
! 4215: purple_debug_error("oscar", "ssi: Action 0x%04hx was unsuccessful with error 0x%04hx\n", retval->action, retval->ack);
! 4216: buf = g_strdup_printf(_("Unable to add the buddy %s for an unknown reason."),
! 4217: (retval->name ? retval->name : _("(no name)")));
! 4218: if ((retval->name != NULL) && !purple_conv_present_error(retval->name, purple_connection_get_account(gc), buf))
! 4219: purple_notify_error(gc, NULL, _("Unable to Add"), buf);
! 4220: g_free(buf);
! 4221: } break;
! 4222: }
! 4223:
! 4224: retval = retval->next;
! 4225: }
! 4226:
! 4227: return 1;
! 4228: }
! 4229:
! 4230: static int
! 4231: purple_ssi_parseaddmod(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
! 4232: {
! 4233: PurpleConnection *gc;
! 4234: PurpleAccount *account;
! 4235: char *gname, *gname_utf8, *alias, *alias_utf8;
! 4236: PurpleBuddy *b;
! 4237: PurpleGroup *g;
! 4238: struct aim_ssi_item *ssi_item;
! 4239: va_list ap;
! 4240: guint16 snac_subtype, type;
! 4241: const char *name;
! 4242:
! 4243: gc = od->gc;
! 4244: account = purple_connection_get_account(gc);
! 4245:
! 4246: va_start(ap, fr);
! 4247: snac_subtype = (guint16)va_arg(ap, int);
! 4248: type = (guint16)va_arg(ap, int);
! 4249: name = va_arg(ap, char *);
! 4250: va_end(ap);
! 4251:
! 4252: if ((type != 0x0000) || (name == NULL))
! 4253: return 1;
! 4254:
! 4255: gname = aim_ssi_itemlist_findparentname(od->ssi.local, name);
! 4256: gname_utf8 = gname ? oscar_utf8_try_convert(account, od, gname) : NULL;
! 4257:
! 4258: alias = aim_ssi_getalias(od->ssi.local, gname, name);
! 4259: alias_utf8 = oscar_utf8_try_convert(account, od, alias);
! 4260: g_free(alias);
! 4261:
! 4262: b = purple_find_buddy(account, name);
! 4263: if (b) {
! 4264: /*
! 4265: * You're logged in somewhere else and you aliased one
! 4266: * of your buddies, so update our local buddy list with
! 4267: * the person's new alias.
! 4268: */
! 4269: purple_blist_alias_buddy(b, alias_utf8);
! 4270: } else if (snac_subtype == 0x0008) {
! 4271: /*
! 4272: * You're logged in somewhere else and you added a buddy to
! 4273: * your server list, so add them to your local buddy list.
! 4274: */
! 4275: b = purple_buddy_new(account, name, alias_utf8);
! 4276:
! 4277: if (!(g = purple_find_group(gname_utf8 ? gname_utf8 : _("Orphans")))) {
! 4278: g = purple_group_new(gname_utf8 ? gname_utf8 : _("Orphans"));
! 4279: purple_blist_add_group(g, NULL);
! 4280: }
! 4281:
! 4282: purple_debug_info("oscar",
! 4283: "ssi: adding buddy %s to group %s to local list\n", name, gname_utf8 ? gname_utf8 : _("Orphans"));
! 4284: purple_blist_add_buddy(b, NULL, g, NULL);
! 4285:
! 4286: /* Mobile users should always be online */
! 4287: if (name[0] == '+') {
! 4288: purple_prpl_got_user_status(account,
! 4289: name, OSCAR_STATUS_ID_AVAILABLE, NULL);
! 4290: purple_prpl_got_user_status(account,
! 4291: name, OSCAR_STATUS_ID_MOBILE, NULL);
! 4292: }
! 4293:
! 4294: }
! 4295:
! 4296: ssi_item = aim_ssi_itemlist_finditem(od->ssi.local,
! 4297: gname, name, AIM_SSI_TYPE_BUDDY);
! 4298: if (ssi_item == NULL)
! 4299: {
! 4300: purple_debug_error("oscar", "purple_ssi_parseaddmod: "
! 4301: "Could not find ssi item for oncoming buddy %s, "
! 4302: "group %s\n", name, gname);
! 4303: }
! 4304:
! 4305: g_free(gname_utf8);
! 4306: g_free(alias_utf8);
! 4307:
! 4308: return 1;
! 4309: }
! 4310:
! 4311: static int purple_ssi_authgiven(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
! 4312: PurpleConnection *gc = od->gc;
! 4313: va_list ap;
! 4314: char *bn;
! 4315: gchar *dialog_msg, *nombre;
! 4316: struct name_data *data;
! 4317: PurpleBuddy *buddy;
! 4318:
! 4319: va_start(ap, fr);
! 4320: bn = va_arg(ap, char *);
! 4321: va_arg(ap, char *); /* msg */
! 4322: va_end(ap);
! 4323:
! 4324: purple_debug_info("oscar",
! 4325: "ssi: %s has given you permission to add him to your buddy list\n", bn);
! 4326:
! 4327: buddy = purple_find_buddy(purple_connection_get_account(gc), bn);
! 4328: if (buddy && (purple_buddy_get_alias_only(buddy)))
! 4329: nombre = g_strdup_printf("%s (%s)", bn, purple_buddy_get_alias_only(buddy));
! 4330: else
! 4331: nombre = g_strdup(bn);
! 4332:
! 4333: dialog_msg = g_strdup_printf(_("The user %s has given you permission to add him or her to your buddy list. Do you want to add this user?"), nombre);
! 4334: g_free(nombre);
! 4335:
! 4336: data = g_new(struct name_data, 1);
! 4337: data->gc = gc;
! 4338: data->name = g_strdup(bn);
! 4339: data->nick = (buddy ? g_strdup(purple_buddy_get_alias_only(buddy)) : NULL);
! 4340:
! 4341: purple_request_yes_no(gc, NULL, _("Authorization Given"), dialog_msg,
! 4342: PURPLE_DEFAULT_ACTION_NONE,
! 4343: purple_connection_get_account(gc), bn, NULL,
! 4344: data,
! 4345: G_CALLBACK(purple_icq_buddyadd),
! 4346: G_CALLBACK(oscar_free_name_data));
! 4347: g_free(dialog_msg);
! 4348:
! 4349: return 1;
! 4350: }
! 4351:
! 4352: static int purple_ssi_authrequest(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
! 4353: {
! 4354: va_list ap;
! 4355: const char *bn;
! 4356: char *msg;
! 4357:
! 4358: va_start(ap, fr);
! 4359: bn = va_arg(ap, const char *);
! 4360: msg = va_arg(ap, char *);
! 4361: va_end(ap);
! 4362:
! 4363: purple_debug_info("oscar",
! 4364: "ssi: received authorization request from %s\n", bn);
! 4365:
! 4366: if (!msg) {
! 4367: purple_debug_warning("oscar", "Received auth request from %s with "
! 4368: "empty message\n", bn);
! 4369: } else if (!g_utf8_validate(msg, -1, NULL)) {
! 4370: purple_debug_warning("oscar", "Received auth request from %s with "
! 4371: "invalid UTF-8 message\n", bn);
! 4372: msg = NULL;
! 4373: }
! 4374:
! 4375: aim_icq_getalias(od, bn, TRUE, msg);
! 4376: return 1;
! 4377: }
! 4378:
! 4379: static int purple_ssi_authreply(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
! 4380: PurpleConnection *gc = od->gc;
! 4381: va_list ap;
! 4382: char *bn, *msg;
! 4383: gchar *dialog_msg, *nombre;
! 4384: guint8 reply;
! 4385: PurpleBuddy *buddy;
! 4386:
! 4387: va_start(ap, fr);
! 4388: bn = va_arg(ap, char *);
! 4389: reply = (guint8)va_arg(ap, int);
! 4390: msg = va_arg(ap, char *);
! 4391: va_end(ap);
! 4392:
! 4393: purple_debug_info("oscar",
! 4394: "ssi: received authorization reply from %s. Reply is 0x%04hhx\n", bn, reply);
! 4395:
! 4396: buddy = purple_find_buddy(purple_connection_get_account(gc), bn);
! 4397: if (buddy && (purple_buddy_get_alias_only(buddy)))
! 4398: nombre = g_strdup_printf("%s (%s)", bn, purple_buddy_get_alias_only(buddy));
! 4399: else
! 4400: nombre = g_strdup(bn);
! 4401:
! 4402: if (reply) {
! 4403: /* Granted */
! 4404: dialog_msg = g_strdup_printf(_("The user %s has granted your request to add them to your buddy list."), nombre);
! 4405: purple_notify_info(gc, NULL, _("Authorization Granted"), dialog_msg);
! 4406: } else {
! 4407: /* Denied */
! 4408: dialog_msg = g_strdup_printf(_("The user %s has denied your request to add them to your buddy list for the following reason:\n%s"), nombre, msg ? msg : _("No reason given."));
! 4409: purple_notify_info(gc, NULL, _("Authorization Denied"), dialog_msg);
! 4410: }
! 4411: g_free(dialog_msg);
! 4412: g_free(nombre);
! 4413:
! 4414: return 1;
! 4415: }
! 4416:
! 4417: static int purple_ssi_gotadded(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
! 4418: PurpleConnection *gc = od->gc;
! 4419: PurpleAccount *account = purple_connection_get_account(gc);
! 4420: va_list ap;
! 4421: char *bn;
! 4422: PurpleBuddy *buddy;
! 4423:
! 4424: va_start(ap, fr);
! 4425: bn = va_arg(ap, char *);
! 4426: va_end(ap);
! 4427:
! 4428: buddy = purple_find_buddy(account, bn);
! 4429: purple_debug_info("oscar", "ssi: %s added you to their buddy list\n", bn);
! 4430: purple_account_notify_added(account, bn, NULL,
! 4431: (buddy ? purple_buddy_get_alias_only(buddy) : NULL), NULL);
! 4432:
! 4433: return 1;
! 4434: }
! 4435:
! 4436: GList *oscar_chat_info(PurpleConnection *gc) {
! 4437: GList *m = NULL;
! 4438: struct proto_chat_entry *pce;
! 4439:
! 4440: pce = g_new0(struct proto_chat_entry, 1);
! 4441: pce->label = _("_Room:");
! 4442: pce->identifier = "room";
! 4443: pce->required = TRUE;
! 4444: m = g_list_append(m, pce);
! 4445:
! 4446: pce = g_new0(struct proto_chat_entry, 1);
! 4447: pce->label = _("_Exchange:");
! 4448: pce->identifier = "exchange";
! 4449: pce->required = TRUE;
! 4450: pce->is_int = TRUE;
! 4451: pce->min = 4;
! 4452: pce->max = 20;
! 4453: m = g_list_append(m, pce);
! 4454:
! 4455: return m;
! 4456: }
! 4457:
! 4458: GHashTable *oscar_chat_info_defaults(PurpleConnection *gc, const char *chat_name)
! 4459: {
! 4460: GHashTable *defaults;
! 4461:
! 4462: defaults = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free);
! 4463:
! 4464: if (chat_name != NULL)
! 4465: g_hash_table_insert(defaults, "room", g_strdup(chat_name));
! 4466: g_hash_table_insert(defaults, "exchange", g_strdup("4"));
! 4467:
! 4468: return defaults;
! 4469: }
! 4470:
! 4471: char *
! 4472: oscar_get_chat_name(GHashTable *data)
! 4473: {
! 4474: return g_strdup(g_hash_table_lookup(data, "room"));
! 4475: }
! 4476:
! 4477: void
! 4478: oscar_join_chat(PurpleConnection *gc, GHashTable *data)
! 4479: {
! 4480: OscarData *od = purple_connection_get_protocol_data(gc);
! 4481: FlapConnection *conn;
! 4482: char *name, *exchange;
! 4483: int exchange_int;
! 4484:
! 4485: name = g_hash_table_lookup(data, "room");
! 4486: exchange = g_hash_table_lookup(data, "exchange");
! 4487:
! 4488: g_return_if_fail(name != NULL && *name != '\0');
! 4489: g_return_if_fail(exchange != NULL);
! 4490:
! 4491: errno = 0;
! 4492: exchange_int = strtol(exchange, NULL, 10);
! 4493: g_return_if_fail(errno == 0);
! 4494:
! 4495: purple_debug_info("oscar", "Attempting to join chat room %s.\n", name);
! 4496:
! 4497: if ((conn = flap_connection_getbytype(od, SNAC_FAMILY_CHATNAV)))
! 4498: {
! 4499: purple_debug_info("oscar", "chatnav exists, creating room\n");
! 4500: aim_chatnav_createroom(od, conn, name, exchange_int);
! 4501: } else {
! 4502: /* this gets tricky */
! 4503: struct create_room *cr = g_new0(struct create_room, 1);
! 4504: purple_debug_info("oscar", "chatnav does not exist, opening chatnav\n");
! 4505: cr->exchange = exchange_int;
! 4506: cr->name = g_strdup(name);
! 4507: od->create_rooms = g_slist_prepend(od->create_rooms, cr);
! 4508: aim_srv_requestnew(od, SNAC_FAMILY_CHATNAV);
! 4509: }
! 4510: }
! 4511:
! 4512: void
! 4513: oscar_chat_invite(PurpleConnection *gc, int id, const char *message, const char *name)
! 4514: {
! 4515: OscarData *od = purple_connection_get_protocol_data(gc);
! 4516: struct chat_connection *ccon = find_oscar_chat(gc, id);
! 4517:
! 4518: if (ccon == NULL)
! 4519: return;
! 4520:
! 4521: aim_im_sendch2_chatinvite(od, name, message ? message : "",
! 4522: ccon->exchange, ccon->name, 0x0);
! 4523: }
! 4524:
! 4525: void
! 4526: oscar_chat_leave(PurpleConnection *gc, int id)
! 4527: {
! 4528: PurpleConversation *conv;
! 4529: struct chat_connection *cc;
! 4530:
! 4531: conv = purple_find_chat(gc, id);
! 4532:
! 4533: g_return_if_fail(conv != NULL);
! 4534:
! 4535: purple_debug_info("oscar", "Leaving chat room %s\n",
! 4536: purple_conversation_get_name(conv));
! 4537:
! 4538: cc = find_oscar_chat(gc, purple_conv_chat_get_id(PURPLE_CONV_CHAT(conv)));
! 4539: flap_connection_schedule_destroy(cc->conn, OSCAR_DISCONNECT_DONE, NULL);
! 4540: oscar_chat_kill(gc, cc);
! 4541: }
! 4542:
! 4543: int oscar_send_chat(PurpleConnection *gc, int id, const char *message, PurpleMessageFlags flags)
! 4544: {
! 4545: OscarData *od = purple_connection_get_protocol_data(gc);
! 4546: PurpleConversation *conv = NULL;
! 4547: struct chat_connection *c = NULL;
! 4548: char *buf, *buf2, *buf3;
! 4549: guint16 charset;
! 4550: char *charsetstr;
! 4551: gsize len;
! 4552:
! 4553: if (!(conv = purple_find_chat(gc, id)))
! 4554: return -EINVAL;
! 4555:
! 4556: if (!(c = find_oscar_chat_by_conv(gc, conv)))
! 4557: return -EINVAL;
! 4558:
! 4559: buf = purple_strdup_withhtml(message);
! 4560:
! 4561: if (strstr(buf, "<IMG "))
! 4562: purple_conversation_write(conv, "",
! 4563: _("Your IM Image was not sent. "
! 4564: "You cannot send IM Images in AIM chats."),
! 4565: PURPLE_MESSAGE_ERROR, time(NULL));
! 4566:
! 4567: buf2 = oscar_encode_im(buf, &len, &charset, &charsetstr);
! 4568: /*
! 4569: * Evan S. suggested that maxvis really does mean "number of
! 4570: * visible characters" and not "number of bytes"
! 4571: */
! 4572: if ((len > c->maxlen) || (len > c->maxvis)) {
! 4573: /* If the length was too long, try stripping the HTML and then running it back through
! 4574: * purple_strdup_withhtml() and the encoding process. The result may be shorter. */
! 4575: g_free(buf2);
! 4576:
! 4577: buf3 = purple_markup_strip_html(buf);
! 4578: g_free(buf);
! 4579:
! 4580: buf = purple_strdup_withhtml(buf3);
! 4581: g_free(buf3);
! 4582:
! 4583: buf2 = oscar_encode_im(buf, &len, &charset, &charsetstr);
! 4584:
! 4585: if ((len > c->maxlen) || (len > c->maxvis)) {
! 4586: purple_debug_warning("oscar",
! 4587: "Could not send %s because (%" G_GSIZE_FORMAT " > maxlen %i) or (%" G_GSIZE_FORMAT " > maxvis %i)\n",
! 4588: buf2, len, c->maxlen, len, c->maxvis);
! 4589: g_free(buf);
! 4590: g_free(buf2);
! 4591: return -E2BIG;
! 4592: }
! 4593:
! 4594: purple_debug_info("oscar", "Sending %s as %s because the original was too long.\n",
! 4595: message, buf2);
! 4596: }
! 4597:
! 4598: aim_chat_send_im(od, c->conn, 0, buf2, len, charsetstr, "en");
! 4599: g_free(buf2);
! 4600: g_free(buf);
! 4601:
! 4602: return 0;
! 4603: }
! 4604:
! 4605: PurpleMood* oscar_get_purple_moods(PurpleAccount *account)
! 4606: {
! 4607: return icq_get_purple_moods(account);
! 4608: }
! 4609:
! 4610: const char *oscar_list_icon_icq(PurpleAccount *a, PurpleBuddy *b)
! 4611: {
! 4612: const char *name = b ? purple_buddy_get_name(b) : NULL;
! 4613: if (name && !oscar_util_valid_name_sms(name) && oscar_util_valid_name_icq(name))
! 4614: return "icq";
! 4615:
! 4616: return "icq";
! 4617: }
! 4618:
! 4619: const char *oscar_list_icon_aim(PurpleAccount *a, PurpleBuddy *b)
! 4620: {
! 4621: const char *name = b ? purple_buddy_get_name(b) : NULL;
! 4622: if (name && !oscar_util_valid_name_sms(name) && oscar_util_valid_name_icq(name))
! 4623: return "icq";
! 4624:
! 4625: return "aim";
! 4626: }
! 4627:
! 4628: const char *oscar_list_emblem(PurpleBuddy *b)
! 4629: {
! 4630: PurpleConnection *gc = NULL;
! 4631: OscarData *od = NULL;
! 4632: PurpleAccount *account = NULL;
! 4633: PurplePresence *presence;
! 4634: aim_userinfo_t *userinfo = NULL;
! 4635: const char *name;
! 4636:
! 4637: account = purple_buddy_get_account(b);
! 4638: name = purple_buddy_get_name(b);
! 4639: if (account != NULL)
! 4640: gc = purple_account_get_connection(account);
! 4641: if (gc != NULL)
! 4642: od = purple_connection_get_protocol_data(gc);
! 4643: if (od != NULL)
! 4644: userinfo = aim_locate_finduserinfo(od, name);
! 4645:
! 4646: presence = purple_buddy_get_presence(b);
! 4647:
! 4648: if (purple_presence_is_online(presence) == FALSE) {
! 4649: char *gname;
! 4650: if ((name) && (od) && (od->ssi.received_data) &&
! 4651: (gname = aim_ssi_itemlist_findparentname(od->ssi.local, name)) &&
! 4652: (aim_ssi_waitingforauth(od->ssi.local, gname, name))) {
! 4653: return "not-authorized";
! 4654: }
! 4655: }
! 4656:
! 4657: if (userinfo != NULL ) {
! 4658: if (userinfo->flags & AIM_FLAG_ADMINISTRATOR)
! 4659: return "admin";
! 4660: if (userinfo->flags & AIM_FLAG_ACTIVEBUDDY)
! 4661: return "bot";
! 4662: if (userinfo->capabilities & OSCAR_CAPABILITY_SECUREIM)
! 4663: return "secure";
! 4664: if (userinfo->icqinfo.status & AIM_ICQ_STATE_BIRTHDAY)
! 4665: return "birthday";
! 4666:
! 4667: /* Make the mood icon override anything below this. */
! 4668: if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_MOOD))
! 4669: return NULL;
! 4670:
! 4671: if (userinfo->capabilities & OSCAR_CAPABILITY_HIPTOP)
! 4672: return "hiptop";
! 4673: }
! 4674: return NULL;
! 4675: }
! 4676:
! 4677: void oscar_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full)
! 4678: {
! 4679: PurpleConnection *gc;
! 4680: PurpleAccount *account;
! 4681: OscarData *od;
! 4682: aim_userinfo_t *userinfo;
! 4683:
! 4684: if (!PURPLE_BUDDY_IS_ONLINE(b))
! 4685: return;
! 4686:
! 4687: account = purple_buddy_get_account(b);
! 4688: gc = purple_account_get_connection(account);
! 4689: od = purple_connection_get_protocol_data(gc);
! 4690: userinfo = aim_locate_finduserinfo(od, purple_buddy_get_name(b));
! 4691:
! 4692: oscar_user_info_append_status(gc, user_info, b, userinfo, /* use_html_status */ FALSE);
! 4693:
! 4694: if (full)
! 4695: oscar_user_info_append_extra_info(gc, user_info, b, userinfo);
! 4696: }
! 4697:
! 4698: char *oscar_status_text(PurpleBuddy *b)
! 4699: {
! 4700: PurpleConnection *gc;
! 4701: PurpleAccount *account;
! 4702: OscarData *od;
! 4703: const PurplePresence *presence;
! 4704: const PurpleStatus *status;
! 4705: const char *message;
! 4706: gchar *ret = NULL;
! 4707:
! 4708: gc = purple_account_get_connection(purple_buddy_get_account(b));
! 4709: account = purple_connection_get_account(gc);
! 4710: od = purple_connection_get_protocol_data(gc);
! 4711: presence = purple_buddy_get_presence(b);
! 4712: status = purple_presence_get_active_status(presence);
! 4713:
! 4714: if ((od != NULL) && !purple_presence_is_online(presence))
! 4715: {
! 4716: const char *name = purple_buddy_get_name(b);
! 4717: char *gname = aim_ssi_itemlist_findparentname(od->ssi.local, name);
! 4718: if (aim_ssi_waitingforauth(od->ssi.local, gname, name))
! 4719: ret = g_strdup(_("Not Authorized"));
! 4720: else
! 4721: ret = g_strdup(_("Offline"));
! 4722: }
! 4723: else
! 4724: {
! 4725: message = purple_status_get_attr_string(status, "message");
! 4726: if (message != NULL)
! 4727: {
! 4728: gchar *tmp = oscar_util_format_string(message, purple_account_get_username(account));
! 4729: ret = purple_markup_escape_text(tmp, -1);
! 4730: g_free(tmp);
! 4731: }
! 4732: else if (purple_status_is_available(status))
! 4733: {
! 4734: /* Don't show "Available" as status message in case buddy doesn't have a status message */
! 4735: }
! 4736: else
! 4737: {
! 4738: ret = g_strdup(purple_status_get_name(status));
! 4739: }
! 4740: }
! 4741:
! 4742: return ret;
! 4743: }
! 4744:
! 4745: void oscar_set_aim_permdeny(PurpleConnection *gc) {
! 4746: PurpleAccount *account = purple_connection_get_account(gc);
! 4747: OscarData *od = purple_connection_get_protocol_data(gc);
! 4748:
! 4749: /*
! 4750: * Conveniently there is a one-to-one mapping between the
! 4751: * values of libpurple's PurplePrivacyType and the values used
! 4752: * by the oscar protocol.
! 4753: */
! 4754: aim_ssi_setpermdeny(od, account->perm_deny);
! 4755: }
! 4756:
! 4757: void oscar_add_permit(PurpleConnection *gc, const char *who) {
! 4758: OscarData *od = purple_connection_get_protocol_data(gc);
! 4759: purple_debug_info("oscar", "ssi: About to add a permit\n");
! 4760: aim_ssi_add_to_private_list(od, who, AIM_SSI_TYPE_PERMIT);
! 4761: }
! 4762:
! 4763: void oscar_add_deny(PurpleConnection *gc, const char *who) {
! 4764: OscarData *od = purple_connection_get_protocol_data(gc);
! 4765: purple_debug_info("oscar", "ssi: About to add a deny\n");
! 4766: aim_ssi_add_to_private_list(od, who, aim_ssi_getdenyentrytype(od));
! 4767: }
! 4768:
! 4769: void oscar_rem_permit(PurpleConnection *gc, const char *who) {
! 4770: OscarData *od = purple_connection_get_protocol_data(gc);
! 4771: purple_debug_info("oscar", "ssi: About to delete a permit\n");
! 4772: aim_ssi_del_from_private_list(od, who, AIM_SSI_TYPE_PERMIT);
! 4773: }
! 4774:
! 4775: void oscar_rem_deny(PurpleConnection *gc, const char *who) {
! 4776: OscarData *od = purple_connection_get_protocol_data(gc);
! 4777: purple_debug_info("oscar", "ssi: About to delete a deny\n");
! 4778: aim_ssi_del_from_private_list(od, who, aim_ssi_getdenyentrytype(od));
! 4779: }
! 4780:
! 4781: GList *
! 4782: oscar_status_types(PurpleAccount *account)
! 4783: {
! 4784: gboolean is_icq;
! 4785: GList *status_types = NULL;
! 4786: PurpleStatusType *type;
! 4787:
! 4788: g_return_val_if_fail(account != NULL, NULL);
! 4789:
! 4790: /* Used to flag some statuses as "user settable" or not */
! 4791: is_icq = oscar_util_valid_name_icq(purple_account_get_username(account));
! 4792:
! 4793: /* Common status types */
! 4794: /* Really the available message should only be settable for AIM accounts */
! 4795: type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE,
! 4796: OSCAR_STATUS_ID_AVAILABLE,
! 4797: NULL, TRUE, TRUE, FALSE,
! 4798: "message", _("Message"),
! 4799: purple_value_new(PURPLE_TYPE_STRING),
! 4800: "itmsurl", _("iTunes Music Store Link"),
! 4801: purple_value_new(PURPLE_TYPE_STRING), NULL);
! 4802: status_types = g_list_prepend(status_types, type);
! 4803:
! 4804: type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE,
! 4805: OSCAR_STATUS_ID_FREE4CHAT,
! 4806: _("Free For Chat"), TRUE, is_icq, FALSE,
! 4807: "message", _("Message"),
! 4808: purple_value_new(PURPLE_TYPE_STRING), NULL);
! 4809:
! 4810: status_types = g_list_prepend(status_types, type);
! 4811:
! 4812: type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE,
! 4813: OSCAR_STATUS_ID_EVIL,
! 4814: _("Evil"), TRUE, is_icq, FALSE,
! 4815: "message", _("Message"),
! 4816: purple_value_new(PURPLE_TYPE_STRING), NULL);
! 4817: status_types = g_list_prepend(status_types, type);
! 4818:
! 4819:
! 4820: type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE,
! 4821: OSCAR_STATUS_ID_DEPRESSION,
! 4822: _("Depression"), TRUE, is_icq, FALSE,
! 4823: "message", _("Message"),
! 4824: purple_value_new(PURPLE_TYPE_STRING), NULL);
! 4825: status_types = g_list_prepend(status_types, type);
! 4826:
! 4827:
! 4828: type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE,
! 4829: OSCAR_STATUS_ID_ATHOME,
! 4830: _("At home"), TRUE, is_icq, FALSE,
! 4831: "message", _("Message"),
! 4832: purple_value_new(PURPLE_TYPE_STRING), NULL);
! 4833: status_types = g_list_prepend(status_types, type);
! 4834:
! 4835:
! 4836: type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE,
! 4837: OSCAR_STATUS_ID_ATWORK,
! 4838: _("At work"), TRUE, is_icq, FALSE,
! 4839: "message", _("Message"),
! 4840: purple_value_new(PURPLE_TYPE_STRING), NULL);
! 4841:
! 4842: status_types = g_list_prepend(status_types, type);
! 4843:
! 4844:
! 4845: type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE,
! 4846: OSCAR_STATUS_ID_LUNCH,
! 4847: _("Lunch"), TRUE, is_icq, FALSE,
! 4848: "message", _("Message"),
! 4849: purple_value_new(PURPLE_TYPE_STRING), NULL);
! 4850:
! 4851: status_types = g_list_prepend(status_types, type);
! 4852:
! 4853: type = purple_status_type_new_with_attrs(PURPLE_STATUS_AWAY,
! 4854: OSCAR_STATUS_ID_AWAY,
! 4855: NULL, TRUE, TRUE, FALSE,
! 4856: "message", _("Message"),
! 4857: purple_value_new(PURPLE_TYPE_STRING), NULL);
! 4858: status_types = g_list_prepend(status_types, type);
! 4859:
! 4860: type = purple_status_type_new_with_attrs(PURPLE_STATUS_INVISIBLE,
! 4861: OSCAR_STATUS_ID_INVISIBLE,
! 4862: NULL, TRUE, TRUE, FALSE,
! 4863: "message", _("Message"),
! 4864: purple_value_new(PURPLE_TYPE_STRING), NULL);
! 4865:
! 4866: status_types = g_list_prepend(status_types, type);
! 4867:
! 4868: type = purple_status_type_new_full(PURPLE_STATUS_MOBILE, OSCAR_STATUS_ID_MOBILE, NULL, FALSE, FALSE, TRUE);
! 4869: status_types = g_list_prepend(status_types, type);
! 4870:
! 4871: /* ICQ-specific status types */
! 4872: type = purple_status_type_new_with_attrs(PURPLE_STATUS_UNAVAILABLE,
! 4873: OSCAR_STATUS_ID_OCCUPIED,
! 4874: _("Occupied"), TRUE, is_icq, FALSE,
! 4875: "message", _("Message"),
! 4876: purple_value_new(PURPLE_TYPE_STRING), NULL);
! 4877: status_types = g_list_prepend(status_types, type);
! 4878:
! 4879: type = purple_status_type_new_with_attrs(PURPLE_STATUS_UNAVAILABLE,
! 4880: OSCAR_STATUS_ID_DND,
! 4881: _("Do Not Disturb"), TRUE, is_icq, FALSE,
! 4882: "message", _("Message"),
! 4883: purple_value_new(PURPLE_TYPE_STRING), NULL);
! 4884: status_types = g_list_prepend(status_types, type);
! 4885:
! 4886: type = purple_status_type_new_with_attrs(PURPLE_STATUS_EXTENDED_AWAY,
! 4887: OSCAR_STATUS_ID_NA,
! 4888: _("Not Available"), TRUE, is_icq, FALSE,
! 4889: "message", _("Message"),
! 4890: purple_value_new(PURPLE_TYPE_STRING), NULL);
! 4891: status_types = g_list_prepend(status_types, type);
! 4892:
! 4893: type = purple_status_type_new_full(PURPLE_STATUS_OFFLINE,
! 4894: OSCAR_STATUS_ID_OFFLINE,
! 4895: NULL, TRUE, TRUE, FALSE);
! 4896: status_types = g_list_prepend(status_types, type);
! 4897:
! 4898: type = purple_status_type_new_with_attrs(PURPLE_STATUS_MOOD,
! 4899: "mood", NULL, TRUE, is_icq, TRUE,
! 4900: PURPLE_MOOD_NAME, _("Mood Name"), purple_value_new(PURPLE_TYPE_STRING),
! 4901: PURPLE_MOOD_COMMENT, _("Mood Comment"), purple_value_new(PURPLE_TYPE_STRING),
! 4902: NULL);
! 4903: status_types = g_list_prepend(status_types, type);
! 4904:
! 4905: return g_list_reverse(status_types);
! 4906: }
! 4907:
! 4908: static void oscar_ssi_editcomment(struct name_data *data, const char *text) {
! 4909: PurpleConnection *gc;
! 4910: PurpleAccount *account;
! 4911: OscarData *od;
! 4912: PurpleBuddy *b;
! 4913: PurpleGroup *g;
! 4914:
! 4915: gc = data->gc;
! 4916: od = purple_connection_get_protocol_data(gc);
! 4917: account = purple_connection_get_account(gc);
! 4918:
! 4919: b = purple_find_buddy(account, data->name);
! 4920: if (b == NULL) {
! 4921: oscar_free_name_data(data);
! 4922: return;
! 4923: }
! 4924:
! 4925: g = purple_buddy_get_group(b);
! 4926: if (g == NULL) {
! 4927: oscar_free_name_data(data);
! 4928: return;
! 4929: }
! 4930:
! 4931: aim_ssi_editcomment(od, purple_group_get_name(g), data->name, text);
! 4932: oscar_free_name_data(data);
! 4933: }
! 4934:
! 4935: static void oscar_buddycb_edit_comment(PurpleBlistNode *node, gpointer ignore) {
! 4936:
! 4937: PurpleBuddy *buddy;
! 4938: PurpleConnection *gc;
! 4939: OscarData *od;
! 4940: struct name_data *data;
! 4941: PurpleGroup *g;
! 4942: char *comment;
! 4943: gchar *comment_utf8;
! 4944: gchar *title;
! 4945: PurpleAccount *account;
! 4946: const char *name;
! 4947:
! 4948: g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
! 4949:
! 4950: buddy = (PurpleBuddy *) node;
! 4951: name = purple_buddy_get_name(buddy);
! 4952: account = purple_buddy_get_account(buddy);
! 4953: gc = purple_account_get_connection(account);
! 4954: od = purple_connection_get_protocol_data(gc);
! 4955:
! 4956: if (!(g = purple_buddy_get_group(buddy)))
! 4957: return;
! 4958:
! 4959: data = g_new(struct name_data, 1);
! 4960:
! 4961: comment = aim_ssi_getcomment(od->ssi.local, purple_group_get_name(g), name);
! 4962: comment_utf8 = comment ? oscar_utf8_try_convert(account, od, comment) : NULL;
! 4963:
! 4964: data->gc = gc;
! 4965: data->name = g_strdup(name);
! 4966: data->nick = g_strdup(purple_buddy_get_alias_only(buddy));
! 4967:
! 4968: title = g_strdup_printf(_("Buddy Comment for %s"), data->name);
! 4969: purple_request_input(gc, title, _("Buddy Comment:"), NULL,
! 4970: comment_utf8, TRUE, FALSE, NULL,
! 4971: _("_OK"), G_CALLBACK(oscar_ssi_editcomment),
! 4972: _("_Cancel"), G_CALLBACK(oscar_free_name_data),
! 4973: account, data->name, NULL,
! 4974: data);
! 4975: g_free(title);
! 4976:
! 4977: g_free(comment);
! 4978: g_free(comment_utf8);
! 4979: }
! 4980:
! 4981: static void
! 4982: oscar_ask_directim_yes_cb(struct oscar_ask_directim_data *data)
! 4983: {
! 4984: peer_connection_propose(data->od, OSCAR_CAPABILITY_DIRECTIM, data->who);
! 4985: g_free(data->who);
! 4986: g_free(data);
! 4987: }
! 4988:
! 4989: static void
! 4990: oscar_ask_directim_no_cb(struct oscar_ask_directim_data *data)
! 4991: {
! 4992: g_free(data->who);
! 4993: g_free(data);
! 4994: }
! 4995:
! 4996: /* This is called from right-click menu on a buddy node. */
! 4997: static void
! 4998: oscar_ask_directim(gpointer object, gpointer ignored)
! 4999: {
! 5000: PurpleBlistNode *node;
! 5001: PurpleBuddy *buddy;
! 5002: PurpleConnection *gc;
! 5003: gchar *buf;
! 5004: struct oscar_ask_directim_data *data;
! 5005: PurpleAccount *account;
! 5006:
! 5007: node = object;
! 5008:
! 5009: g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
! 5010:
! 5011: buddy = (PurpleBuddy *)node;
! 5012: account = purple_buddy_get_account(buddy);
! 5013: gc = purple_account_get_connection(account);
! 5014:
! 5015: data = g_new0(struct oscar_ask_directim_data, 1);
! 5016: data->who = g_strdup(purple_buddy_get_name(buddy));
! 5017: data->od = purple_connection_get_protocol_data(gc);
! 5018: buf = g_strdup_printf(_("You have selected to open a Direct IM connection with %s."),
! 5019: data->who);
! 5020:
! 5021: purple_request_action(gc, NULL, buf,
! 5022: _("Because this reveals your IP address, it "
! 5023: "may be considered a security risk. Do you "
! 5024: "wish to continue?"),
! 5025: 0, /* Default action is "connect" */
! 5026: account, data->who, NULL,
! 5027: data, 2,
! 5028: _("C_onnect"), G_CALLBACK(oscar_ask_directim_yes_cb),
! 5029: _("_Cancel"), G_CALLBACK(oscar_ask_directim_no_cb));
! 5030: g_free(buf);
! 5031: }
! 5032:
! 5033: static void
! 5034: oscar_close_directim(gpointer object, gpointer ignored)
! 5035: {
! 5036: PurpleBlistNode *node;
! 5037: PurpleBuddy *buddy;
! 5038: PurpleAccount *account;
! 5039: PurpleConnection *gc;
! 5040: PurpleConversation *conv;
! 5041: OscarData *od;
! 5042: PeerConnection *conn;
! 5043: const char *name;
! 5044:
! 5045: node = object;
! 5046:
! 5047: g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
! 5048:
! 5049: buddy = (PurpleBuddy*)node;
! 5050: name = purple_buddy_get_name(buddy);
! 5051: account = purple_buddy_get_account(buddy);
! 5052: gc = purple_account_get_connection(account);
! 5053: od = gc->proto_data;
! 5054: conn = peer_connection_find_by_type(od, name, OSCAR_CAPABILITY_DIRECTIM);
! 5055:
! 5056: if (conn != NULL)
! 5057: {
! 5058: if (!conn->ready)
! 5059: aim_im_sendch2_cancel(conn);
! 5060:
! 5061: peer_connection_destroy(conn, OSCAR_DISCONNECT_LOCAL_CLOSED, NULL);
! 5062:
! 5063: /* OSCAR_DISCONNECT_LOCAL_CLOSED doesn't write anything to the convo
! 5064: * window. Let the user know that we cancelled the Direct IM. */
! 5065: conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, name);
! 5066: purple_conversation_write(conv, NULL, _("You closed the connection."),
! 5067: PURPLE_MESSAGE_SYSTEM, time(NULL));
! 5068: }
! 5069: }
! 5070:
! 5071: static void oscar_get_icqxstatusmsg(PurpleBlistNode *node, gpointer ignore)
! 5072: {
! 5073: PurpleBuddy *buddy;
! 5074: PurpleConnection *gc;
! 5075: OscarData *od;
! 5076: PurpleAccount *account;
! 5077: const char *bname;
! 5078:
! 5079: g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
! 5080:
! 5081: buddy = (PurpleBuddy *)node;
! 5082: bname = purple_buddy_get_name(buddy);
! 5083:
! 5084: account = purple_buddy_get_account(buddy);
! 5085: gc = purple_account_get_connection(account);
! 5086: od = purple_connection_get_protocol_data(gc);
! 5087:
! 5088: purple_debug_info("oscar", "Manual X-Status Get From %s to %s:\n", bname, purple_account_get_username(account));
! 5089:
! 5090: icq_im_xstatus_request(od, bname);
! 5091: }
! 5092:
! 5093: static void
! 5094: oscar_get_aim_info_cb(PurpleBlistNode *node, gpointer ignore)
! 5095: {
! 5096: PurpleBuddy *buddy;
! 5097: PurpleConnection *gc;
! 5098:
! 5099: g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
! 5100:
! 5101: buddy = (PurpleBuddy *)node;
! 5102: gc = purple_account_get_connection(purple_buddy_get_account(buddy));
! 5103:
! 5104: aim_locate_getinfoshort(purple_connection_get_protocol_data(gc),
! 5105: purple_buddy_get_name(buddy), 0x00000003);
! 5106: }
! 5107:
! 5108: static GList *
! 5109: oscar_buddy_menu(PurpleBuddy *buddy) {
! 5110: PurpleConnection *gc;
! 5111: OscarData *od;
! 5112: GList *menu;
! 5113: PurpleMenuAction *act;
! 5114: aim_userinfo_t *userinfo;
! 5115: PurpleAccount *account;
! 5116: const char *bname = purple_buddy_get_name(buddy);
! 5117:
! 5118: account = purple_buddy_get_account(buddy);
! 5119: gc = purple_account_get_connection(account);
! 5120: od = purple_connection_get_protocol_data(gc);
! 5121: userinfo = aim_locate_finduserinfo(od, bname);
! 5122: menu = NULL;
! 5123:
! 5124: if (od->icq && oscar_util_valid_name_icq(bname))
! 5125: {
! 5126: act = purple_menu_action_new(_("Get AIM Info"),
! 5127: PURPLE_CALLBACK(oscar_get_aim_info_cb),
! 5128: NULL, NULL);
! 5129: menu = g_list_prepend(menu, act);
! 5130: }
! 5131:
! 5132: if (purple_buddy_get_group(buddy) != NULL)
! 5133: {
! 5134: /* We only do this if the user is in our buddy list */
! 5135: act = purple_menu_action_new(_("Edit Buddy Comment"),
! 5136: PURPLE_CALLBACK(oscar_buddycb_edit_comment),
! 5137: NULL, NULL);
! 5138: menu = g_list_prepend(menu, act);
! 5139: }
! 5140:
! 5141: if (od->icq)
! 5142: {
! 5143: act = purple_menu_action_new(_("Get X-Status Msg"),
! 5144: PURPLE_CALLBACK(oscar_get_icqxstatusmsg),
! 5145: NULL, NULL);
! 5146: menu = g_list_prepend(menu, act);
! 5147: menu = g_list_prepend(menu, create_visibility_menu_item(od, bname));
! 5148: }
! 5149:
! 5150: if (userinfo &&
! 5151: oscar_util_name_compare(purple_account_get_username(account), bname) &&
! 5152: PURPLE_BUDDY_IS_ONLINE(buddy))
! 5153: {
! 5154: PeerConnection *conn;
! 5155: conn = peer_connection_find_by_type(od, bname, OSCAR_CAPABILITY_DIRECTIM);
! 5156:
! 5157: if (userinfo->capabilities & OSCAR_CAPABILITY_DIRECTIM)
! 5158: {
! 5159: if (conn)
! 5160: {
! 5161: act = purple_menu_action_new(_("End Direct IM Session"),
! 5162: PURPLE_CALLBACK(oscar_close_directim),
! 5163: NULL, NULL);
! 5164: }
! 5165: else
! 5166: {
! 5167: act = purple_menu_action_new(_("Direct IM"),
! 5168: PURPLE_CALLBACK(oscar_ask_directim),
! 5169: NULL, NULL);
! 5170: }
! 5171: menu = g_list_prepend(menu, act);
! 5172: }
! 5173: }
! 5174:
! 5175: if (od->ssi.received_data && purple_buddy_get_group(buddy) != NULL)
! 5176: {
! 5177: /*
! 5178: * We only do this if the user is in our buddy list and we're
! 5179: * waiting for authorization.
! 5180: */
! 5181: char *gname;
! 5182: gname = aim_ssi_itemlist_findparentname(od->ssi.local, bname);
! 5183: if (gname && aim_ssi_waitingforauth(od->ssi.local, gname, bname))
! 5184: {
! 5185: act = purple_menu_action_new(_("Re-request Authorization"),
! 5186: PURPLE_CALLBACK(oscar_auth_sendrequest_menu),
! 5187: NULL, NULL);
! 5188: menu = g_list_prepend(menu, act);
! 5189: }
! 5190: }
! 5191:
! 5192: menu = g_list_reverse(menu);
! 5193:
! 5194: return menu;
! 5195: }
! 5196:
! 5197:
! 5198: GList *oscar_blist_node_menu(PurpleBlistNode *node) {
! 5199: if(PURPLE_BLIST_NODE_IS_BUDDY(node)) {
! 5200: return oscar_buddy_menu((PurpleBuddy *) node);
! 5201: } else {
! 5202: return NULL;
! 5203: }
! 5204: }
! 5205:
! 5206: static void
! 5207: oscar_icq_privacy_opts(PurpleConnection *gc, PurpleRequestFields *fields)
! 5208: {
! 5209: OscarData *od = purple_connection_get_protocol_data(gc);
! 5210: PurpleAccount *account = purple_connection_get_account(gc);
! 5211: PurpleRequestField *f;
! 5212: gboolean auth, web_aware;
! 5213:
! 5214: f = purple_request_fields_get_field(fields, "authorization");
! 5215: auth = purple_request_field_bool_get_value(f);
! 5216:
! 5217: f = purple_request_fields_get_field(fields, "web_aware");
! 5218: web_aware = purple_request_field_bool_get_value(f);
! 5219:
! 5220: purple_account_set_bool(account, "authorization", auth);
! 5221: purple_account_set_bool(account, "web_aware", web_aware);
! 5222:
! 5223: oscar_set_extended_status(gc);
! 5224: aim_icq_setsecurity(od, auth, web_aware);
! 5225: }
! 5226:
! 5227: static void
! 5228: oscar_show_icq_privacy_opts(PurplePluginAction *action)
! 5229: {
! 5230: PurpleConnection *gc = (PurpleConnection *) action->context;
! 5231: PurpleAccount *account = purple_connection_get_account(gc);
! 5232: PurpleRequestFields *fields;
! 5233: PurpleRequestFieldGroup *g;
! 5234: PurpleRequestField *f;
! 5235: gboolean auth, web_aware;
! 5236:
! 5237: auth = purple_account_get_bool(account, "authorization", OSCAR_DEFAULT_AUTHORIZATION);
! 5238: web_aware = purple_account_get_bool(account, "web_aware", OSCAR_DEFAULT_WEB_AWARE);
! 5239:
! 5240: fields = purple_request_fields_new();
! 5241:
! 5242: g = purple_request_field_group_new(NULL);
! 5243:
! 5244: f = purple_request_field_bool_new("authorization", _("Require authorization"), auth);
! 5245: purple_request_field_group_add_field(g, f);
! 5246:
! 5247: f = purple_request_field_bool_new("web_aware", _("Web aware (enabling this will cause you to receive SPAM!)"), web_aware);
! 5248: purple_request_field_group_add_field(g, f);
! 5249:
! 5250: purple_request_fields_add_group(fields, g);
! 5251:
! 5252: purple_request_fields(gc, _("ICQ Privacy Options"), _("ICQ Privacy Options"),
! 5253: NULL, fields,
! 5254: _("OK"), G_CALLBACK(oscar_icq_privacy_opts),
! 5255: _("Cancel"), NULL,
! 5256: purple_connection_get_account(gc), NULL, NULL,
! 5257: gc);
! 5258: }
! 5259:
! 5260: static void oscar_confirm_account(PurplePluginAction *action)
! 5261: {
! 5262: PurpleConnection *gc;
! 5263: OscarData *od;
! 5264: FlapConnection *conn;
! 5265:
! 5266: gc = (PurpleConnection *)action->context;
! 5267: od = purple_connection_get_protocol_data(gc);
! 5268:
! 5269: conn = flap_connection_getbytype(od, SNAC_FAMILY_ADMIN);
! 5270: if (conn != NULL) {
! 5271: aim_admin_reqconfirm(od, conn);
! 5272: } else {
! 5273: od->conf = TRUE;
! 5274: aim_srv_requestnew(od, SNAC_FAMILY_ADMIN);
! 5275: }
! 5276: }
! 5277:
! 5278: static void oscar_show_email(PurplePluginAction *action)
! 5279: {
! 5280: PurpleConnection *gc = (PurpleConnection *) action->context;
! 5281: OscarData *od = purple_connection_get_protocol_data(gc);
! 5282: FlapConnection *conn = flap_connection_getbytype(od, SNAC_FAMILY_ADMIN);
! 5283:
! 5284: if (conn) {
! 5285: aim_admin_getinfo(od, conn, 0x11);
! 5286: } else {
! 5287: od->reqemail = TRUE;
! 5288: aim_srv_requestnew(od, SNAC_FAMILY_ADMIN);
! 5289: }
! 5290: }
! 5291:
! 5292: static void oscar_change_email(PurpleConnection *gc, const char *email)
! 5293: {
! 5294: OscarData *od = purple_connection_get_protocol_data(gc);
! 5295: FlapConnection *conn = flap_connection_getbytype(od, SNAC_FAMILY_ADMIN);
! 5296:
! 5297: if (conn) {
! 5298: aim_admin_setemail(od, conn, email);
! 5299: } else {
! 5300: od->setemail = TRUE;
! 5301: od->email = g_strdup(email);
! 5302: aim_srv_requestnew(od, SNAC_FAMILY_ADMIN);
! 5303: }
! 5304: }
! 5305:
! 5306: static void oscar_show_change_email(PurplePluginAction *action)
! 5307: {
! 5308: PurpleConnection *gc = (PurpleConnection *) action->context;
! 5309: purple_request_input(gc, NULL, _("Change Address To:"), NULL, NULL,
! 5310: FALSE, FALSE, NULL,
! 5311: _("_OK"), G_CALLBACK(oscar_change_email),
! 5312: _("_Cancel"), NULL,
! 5313: purple_connection_get_account(gc), NULL, NULL,
! 5314: gc);
! 5315: }
! 5316:
! 5317: static void oscar_show_awaitingauth(PurplePluginAction *action)
! 5318: {
! 5319: PurpleConnection *gc = (PurpleConnection *) action->context;
! 5320: OscarData *od = purple_connection_get_protocol_data(gc);
! 5321: PurpleAccount *account = purple_connection_get_account(gc);
! 5322: GSList *buddies, *filtered_buddies, *cur;
! 5323: gchar *text;
! 5324:
! 5325: buddies = purple_find_buddies(account, NULL);
! 5326: filtered_buddies = NULL;
! 5327: for (cur = buddies; cur != NULL; cur = cur->next) {
! 5328: PurpleBuddy *buddy;
! 5329: const gchar *bname, *gname;
! 5330:
! 5331: buddy = cur->data;
! 5332: bname = purple_buddy_get_name(buddy);
! 5333: gname = purple_group_get_name(purple_buddy_get_group(buddy));
! 5334: if (aim_ssi_waitingforauth(od->ssi.local, gname, bname)) {
! 5335: filtered_buddies = g_slist_prepend(filtered_buddies, buddy);
! 5336: }
! 5337: }
! 5338:
! 5339: g_slist_free(buddies);
! 5340:
! 5341: filtered_buddies = g_slist_reverse(filtered_buddies);
! 5342: text = oscar_format_buddies(filtered_buddies, _("you are not waiting for authorization"));
! 5343: g_slist_free(filtered_buddies);
! 5344:
! 5345: purple_notify_formatted(gc, NULL, _("You are awaiting authorization from "
! 5346: "the following buddies"), _("You can re-request "
! 5347: "authorization from these buddies by "
! 5348: "right-clicking on them and selecting "
! 5349: "\"Re-request Authorization.\""), text, NULL, NULL);
! 5350: g_free(text);
! 5351: }
! 5352:
! 5353: static void search_by_email_cb(PurpleConnection *gc, const char *email)
! 5354: {
! 5355: OscarData *od = purple_connection_get_protocol_data(gc);
! 5356:
! 5357: aim_search_address(od, email);
! 5358: }
! 5359:
! 5360: static void oscar_show_find_email(PurplePluginAction *action)
! 5361: {
! 5362: PurpleConnection *gc = (PurpleConnection *) action->context;
! 5363: purple_request_input(gc, _("Find Buddy by Email"),
! 5364: _("Search for a buddy by email address"),
! 5365: _("Type the email address of the buddy you are "
! 5366: "searching for."),
! 5367: NULL, FALSE, FALSE, NULL,
! 5368: _("_Search"), G_CALLBACK(search_by_email_cb),
! 5369: _("_Cancel"), NULL,
! 5370: purple_connection_get_account(gc), NULL, NULL,
! 5371: gc);
! 5372: }
! 5373:
! 5374: static void oscar_show_set_info(PurplePluginAction *action)
! 5375: {
! 5376: PurpleConnection *gc = (PurpleConnection *) action->context;
! 5377: purple_account_request_change_user_info(purple_connection_get_account(gc));
! 5378: }
! 5379:
! 5380: static void oscar_show_set_info_icqurl(PurplePluginAction *action)
! 5381: {
! 5382: PurpleConnection *gc = (PurpleConnection *) action->context;
! 5383: purple_notify_uri(gc, "http://www.icq.com/whitepages/user_details.php");
! 5384: }
! 5385:
! 5386: static void oscar_change_pass(PurplePluginAction *action)
! 5387: {
! 5388: PurpleConnection *gc = (PurpleConnection *) action->context;
! 5389: purple_account_request_change_password(purple_connection_get_account(gc));
! 5390: }
! 5391:
! 5392: /**
! 5393: * Only used when connecting with the old-style BUCP login.
! 5394: */
! 5395: static void oscar_show_chpassurl(PurplePluginAction *action)
! 5396: {
! 5397: PurpleConnection *gc = (PurpleConnection *) action->context;
! 5398: OscarData *od = purple_connection_get_protocol_data(gc);
! 5399: gchar *substituted = purple_strreplace(od->authinfo->chpassurl, "%s", purple_account_get_username(purple_connection_get_account(gc)));
! 5400: purple_notify_uri(gc, substituted);
! 5401: g_free(substituted);
! 5402: }
! 5403:
! 5404: static void oscar_show_imforwardingurl(PurplePluginAction *action)
! 5405: {
! 5406: PurpleConnection *gc = (PurpleConnection *) action->context;
! 5407: purple_notify_uri(gc, "http://mymobile.aol.com/dbreg/register?action=imf&clientID=1");
! 5408: }
! 5409:
! 5410: void oscar_set_icon(PurpleConnection *gc, PurpleStoredImage *img)
! 5411: {
! 5412: OscarData *od = purple_connection_get_protocol_data(gc);
! 5413:
! 5414: if (img == NULL) {
! 5415: aim_ssi_delicon(od);
! 5416: } else {
! 5417: PurpleCipherContext *context;
! 5418: guchar md5[16];
! 5419: gconstpointer data = purple_imgstore_get_data(img);
! 5420: size_t len = purple_imgstore_get_size(img);
! 5421:
! 5422: context = purple_cipher_context_new_by_name("md5", NULL);
! 5423: purple_cipher_context_append(context, data, len);
! 5424: purple_cipher_context_digest(context, 16, md5, NULL);
! 5425: purple_cipher_context_destroy(context);
! 5426:
! 5427: aim_ssi_seticon(od, md5, 16);
! 5428: }
! 5429: }
! 5430:
! 5431: /**
! 5432: * Called by the Purple core to determine whether or not we're
! 5433: * allowed to send a file to this user.
! 5434: */
! 5435: gboolean
! 5436: oscar_can_receive_file(PurpleConnection *gc, const char *who)
! 5437: {
! 5438: OscarData *od;
! 5439: PurpleAccount *account;
! 5440:
! 5441: od = purple_connection_get_protocol_data(gc);
! 5442: account = purple_connection_get_account(gc);
! 5443:
! 5444: if (od != NULL)
! 5445: {
! 5446: aim_userinfo_t *userinfo;
! 5447: userinfo = aim_locate_finduserinfo(od, who);
! 5448:
! 5449: /*
! 5450: * Don't allowing sending a file to a user that does not support
! 5451: * file transfer, and don't allow sending to ourselves.
! 5452: */
! 5453: if (((userinfo == NULL) ||
! 5454: (userinfo->capabilities & OSCAR_CAPABILITY_SENDFILE)) &&
! 5455: oscar_util_name_compare(who, purple_account_get_username(account)))
! 5456: {
! 5457: return TRUE;
! 5458: }
! 5459: }
! 5460:
! 5461: return FALSE;
! 5462: }
! 5463:
! 5464: PurpleXfer *
! 5465: oscar_new_xfer(PurpleConnection *gc, const char *who)
! 5466: {
! 5467: PurpleXfer *xfer;
! 5468: OscarData *od;
! 5469: PurpleAccount *account;
! 5470: PeerConnection *conn;
! 5471:
! 5472: od = purple_connection_get_protocol_data(gc);
! 5473: account = purple_connection_get_account(gc);
! 5474:
! 5475: xfer = purple_xfer_new(account, PURPLE_XFER_SEND, who);
! 5476: if (xfer)
! 5477: {
! 5478: purple_xfer_ref(xfer);
! 5479: purple_xfer_set_init_fnc(xfer, peer_oft_sendcb_init);
! 5480: purple_xfer_set_cancel_send_fnc(xfer, peer_oft_cb_generic_cancel);
! 5481: purple_xfer_set_request_denied_fnc(xfer, peer_oft_cb_generic_cancel);
! 5482: purple_xfer_set_ack_fnc(xfer, peer_oft_sendcb_ack);
! 5483:
! 5484: conn = peer_connection_new(od, OSCAR_CAPABILITY_SENDFILE, who);
! 5485: conn->flags |= PEER_CONNECTION_FLAG_INITIATED_BY_ME;
! 5486: conn->flags |= PEER_CONNECTION_FLAG_APPROVED;
! 5487: aim_icbm_makecookie(conn->cookie);
! 5488: conn->xfer = xfer;
! 5489: xfer->data = conn;
! 5490: }
! 5491:
! 5492: return xfer;
! 5493: }
! 5494:
! 5495: /*
! 5496: * Called by the Purple core when the user indicates that a
! 5497: * file is to be sent to a special someone.
! 5498: */
! 5499: void
! 5500: oscar_send_file(PurpleConnection *gc, const char *who, const char *file)
! 5501: {
! 5502: PurpleXfer *xfer;
! 5503:
! 5504: xfer = oscar_new_xfer(gc, who);
! 5505:
! 5506: if (file != NULL)
! 5507: purple_xfer_request_accepted(xfer, file);
! 5508: else
! 5509: purple_xfer_request(xfer);
! 5510: }
! 5511:
! 5512: GList *
! 5513: oscar_actions(PurplePlugin *plugin, gpointer context)
! 5514: {
! 5515: PurpleConnection *gc = (PurpleConnection *) context;
! 5516: OscarData *od = purple_connection_get_protocol_data(gc);
! 5517: GList *menu = NULL;
! 5518: PurplePluginAction *act;
! 5519:
! 5520: act = purple_plugin_action_new(_("Set User Info..."),
! 5521: oscar_show_set_info);
! 5522: menu = g_list_prepend(menu, act);
! 5523:
! 5524: if (od->icq)
! 5525: {
! 5526: act = purple_plugin_action_new(_("Set User Info (web)..."),
! 5527: oscar_show_set_info_icqurl);
! 5528: menu = g_list_prepend(menu, act);
! 5529: }
! 5530:
! 5531: act = purple_plugin_action_new(_("Change Password..."),
! 5532: oscar_change_pass);
! 5533: menu = g_list_prepend(menu, act);
! 5534:
! 5535: if (od->authinfo != NULL && od->authinfo->chpassurl != NULL)
! 5536: {
! 5537: /* This only happens when connecting with the old-style BUCP login */
! 5538: act = purple_plugin_action_new(_("Change Password (web)"),
! 5539: oscar_show_chpassurl);
! 5540: menu = g_list_prepend(menu, act);
! 5541: }
! 5542:
! 5543: if (!od->icq)
! 5544: {
! 5545: act = purple_plugin_action_new(_("Configure IM Forwarding (web)"),
! 5546: oscar_show_imforwardingurl);
! 5547: menu = g_list_prepend(menu, act);
! 5548: }
! 5549:
! 5550: menu = g_list_prepend(menu, NULL);
! 5551:
! 5552: if (od->icq)
! 5553: {
! 5554: /* ICQ actions */
! 5555: act = purple_plugin_action_new(_("Set Privacy Options..."),
! 5556: oscar_show_icq_privacy_opts);
! 5557: menu = g_list_prepend(menu, act);
! 5558:
! 5559: act = purple_plugin_action_new(_("Show Visible List"), oscar_show_visible_list);
! 5560: menu = g_list_prepend(menu, act);
! 5561:
! 5562: act = purple_plugin_action_new(_("Show Invisible List"), oscar_show_invisible_list);
! 5563: menu = g_list_prepend(menu, act);
! 5564: }
! 5565: else
! 5566: {
! 5567: /* AIM actions */
! 5568: act = purple_plugin_action_new(_("Confirm Account"),
! 5569: oscar_confirm_account);
! 5570: menu = g_list_prepend(menu, act);
! 5571:
! 5572: act = purple_plugin_action_new(_("Display Currently Registered Email Address"),
! 5573: oscar_show_email);
! 5574: menu = g_list_prepend(menu, act);
! 5575:
! 5576: act = purple_plugin_action_new(_("Change Currently Registered Email Address..."),
! 5577: oscar_show_change_email);
! 5578: menu = g_list_prepend(menu, act);
! 5579: }
! 5580:
! 5581: menu = g_list_prepend(menu, NULL);
! 5582:
! 5583: act = purple_plugin_action_new(_("Show Buddies Awaiting Authorization"),
! 5584: oscar_show_awaitingauth);
! 5585: menu = g_list_prepend(menu, act);
! 5586:
! 5587: menu = g_list_prepend(menu, NULL);
! 5588:
! 5589: act = purple_plugin_action_new(_("Search for Buddy by Email Address..."),
! 5590: oscar_show_find_email);
! 5591: menu = g_list_prepend(menu, act);
! 5592:
! 5593: menu = g_list_reverse(menu);
! 5594:
! 5595: return menu;
! 5596: }
! 5597:
! 5598: void oscar_change_passwd(PurpleConnection *gc, const char *old, const char *new)
! 5599: {
! 5600: OscarData *od = purple_connection_get_protocol_data(gc);
! 5601:
! 5602: if (od->icq) {
! 5603: aim_icq_changepasswd(od, new);
! 5604: } else {
! 5605: FlapConnection *conn;
! 5606: conn = flap_connection_getbytype(od, SNAC_FAMILY_ADMIN);
! 5607: if (conn) {
! 5608: aim_admin_changepasswd(od, conn, new, old);
! 5609: } else {
! 5610: od->chpass = TRUE;
! 5611: od->oldp = g_strdup(old);
! 5612: od->newp = g_strdup(new);
! 5613: aim_srv_requestnew(od, SNAC_FAMILY_ADMIN);
! 5614: }
! 5615: }
! 5616: }
! 5617:
! 5618: void
! 5619: oscar_convo_closed(PurpleConnection *gc, const char *who)
! 5620: {
! 5621: OscarData *od;
! 5622: PeerConnection *conn;
! 5623:
! 5624: od = purple_connection_get_protocol_data(gc);
! 5625: conn = peer_connection_find_by_type(od, who, OSCAR_CAPABILITY_DIRECTIM);
! 5626:
! 5627: if (conn != NULL)
! 5628: {
! 5629: if (!conn->ready)
! 5630: aim_im_sendch2_cancel(conn);
! 5631:
! 5632: peer_connection_destroy(conn, OSCAR_DISCONNECT_LOCAL_CLOSED, NULL);
! 5633: }
! 5634: }
! 5635:
! 5636: const char *
! 5637: oscar_normalize(const PurpleAccount *account, const char *str)
! 5638: {
! 5639: static char buf[BUF_LEN];
! 5640: char *tmp1, *tmp2;
! 5641: int i, j;
! 5642:
! 5643: g_return_val_if_fail(str != NULL, NULL);
! 5644:
! 5645: /* copy str to buf and skip all blanks */
! 5646: i = 0;
! 5647: for (j = 0; str[j]; j++) {
! 5648: if (str[j] != ' ') {
! 5649: buf[i++] = str[j];
! 5650: if (i >= BUF_LEN - 1)
! 5651: break;
! 5652: }
! 5653: }
! 5654: buf[i] = '\0';
! 5655:
! 5656: tmp1 = g_utf8_strdown(buf, -1);
! 5657: tmp2 = g_utf8_normalize(tmp1, -1, G_NORMALIZE_DEFAULT);
! 5658: if (strlen(tmp2) > sizeof(buf) - 1) {
! 5659: purple_debug_error("oscar", "normalized string exceeds buffer length!\n");
! 5660: }
! 5661: g_strlcpy(buf, tmp2, sizeof(buf));
! 5662: g_free(tmp2);
! 5663: g_free(tmp1);
! 5664:
! 5665: return buf;
! 5666: }
! 5667:
! 5668: gboolean
! 5669: oscar_offline_message(const PurpleBuddy *buddy)
! 5670: {
! 5671: return TRUE;
! 5672: }
! 5673:
! 5674: /* TODO: Find somewhere to put this instead of including it in a bunch of places.
! 5675: * Maybe just change purple_accounts_find() to return anything for the prpl if there is no acct_id.
! 5676: */
! 5677: static PurpleAccount *find_acct(const char *prpl, const char *acct_id)
! 5678: {
! 5679: PurpleAccount *acct = NULL;
! 5680:
! 5681: /* If we have a specific acct, use it */
! 5682: if (acct_id) {
! 5683: acct = purple_accounts_find(acct_id, prpl);
! 5684: if (acct && !purple_account_is_connected(acct))
! 5685: acct = NULL;
! 5686: } else { /* Otherwise find an active account for the protocol */
! 5687: GList *l = purple_accounts_get_all();
! 5688: while (l) {
! 5689: if (purple_strequal(prpl, purple_account_get_protocol_id(l->data))
! 5690: && purple_account_is_connected(l->data)) {
! 5691: acct = l->data;
! 5692: break;
! 5693: }
! 5694: l = l->next;
! 5695: }
! 5696: }
! 5697:
! 5698: return acct;
! 5699: }
! 5700:
! 5701:
! 5702: static gboolean oscar_uri_handler(const char *proto, const char *cmd, GHashTable *params)
! 5703: {
! 5704: char *acct_id = g_hash_table_lookup(params, "account");
! 5705: char prpl[11];
! 5706: PurpleAccount *acct;
! 5707:
! 5708: if (g_ascii_strcasecmp(proto, "aim") && g_ascii_strcasecmp(proto, "icq"))
! 5709: return FALSE;
! 5710:
! 5711: g_snprintf(prpl, sizeof(prpl), "prpl-%s", proto);
! 5712:
! 5713: acct = find_acct(prpl, acct_id);
! 5714:
! 5715: if (!acct)
! 5716: return FALSE;
! 5717:
! 5718: /* aim:GoIM?screenname=SCREENNAME&message=MESSAGE */
! 5719: if (!g_ascii_strcasecmp(cmd, "GoIM")) {
! 5720: char *bname = g_hash_table_lookup(params, "screenname");
! 5721: if (bname) {
! 5722: char *message = g_hash_table_lookup(params, "message");
! 5723:
! 5724: PurpleConversation *conv = purple_find_conversation_with_account(
! 5725: PURPLE_CONV_TYPE_IM, bname, acct);
! 5726: if (conv == NULL)
! 5727: conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, acct, bname);
! 5728: purple_conversation_present(conv);
! 5729:
! 5730: if (message) {
! 5731: /* Spaces are encoded as '+' */
! 5732: g_strdelimit(message, "+", ' ');
! 5733: purple_conv_send_confirm(conv, message);
! 5734: }
! 5735: }
! 5736: /*else
! 5737: **If pidgindialogs_im() was in the core, we could use it here.
! 5738: * It is all purple_request_* based, but I'm not sure it really belongs in the core
! 5739: pidgindialogs_im();*/
! 5740:
! 5741: return TRUE;
! 5742: }
! 5743: /* aim:GoChat?roomname=CHATROOMNAME&exchange=4 */
! 5744: else if (!g_ascii_strcasecmp(cmd, "GoChat")) {
! 5745: char *rname = g_hash_table_lookup(params, "roomname");
! 5746: if (rname) {
! 5747: /* This is somewhat hacky, but the params aren't useful after this command */
! 5748: g_hash_table_insert(params, g_strdup("exchange"), g_strdup("4"));
! 5749: g_hash_table_insert(params, g_strdup("room"), g_strdup(rname));
! 5750: serv_join_chat(purple_account_get_connection(acct), params);
! 5751: }
! 5752: /*else
! 5753: ** Same as above (except that this would have to be re-written using purple_request_*)
! 5754: pidgin_blist_joinchat_show(); */
! 5755:
! 5756: return TRUE;
! 5757: }
! 5758: /* aim:AddBuddy?screenname=SCREENNAME&groupname=GROUPNAME*/
! 5759: else if (!g_ascii_strcasecmp(cmd, "AddBuddy")) {
! 5760: char *bname = g_hash_table_lookup(params, "screenname");
! 5761: char *gname = g_hash_table_lookup(params, "groupname");
! 5762: purple_blist_request_add_buddy(acct, bname, gname, NULL);
! 5763: return TRUE;
! 5764: }
! 5765:
! 5766: return FALSE;
! 5767: }
! 5768:
! 5769: void oscar_init(PurplePlugin *plugin, gboolean is_icq)
! 5770: {
! 5771: PurplePluginProtocolInfo *prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(plugin);
! 5772: PurpleAccountOption *option;
! 5773: static gboolean init = FALSE;
! 5774: static const gchar *encryption_keys[] = {
! 5775: N_("Use encryption if available"),
! 5776: N_("Require encryption"),
! 5777: N_("Don't use encryption"),
! 5778: NULL
! 5779: };
! 5780: static const gchar *encryption_values[] = {
! 5781: OSCAR_OPPORTUNISTIC_ENCRYPTION,
! 5782: OSCAR_REQUIRE_ENCRYPTION,
! 5783: OSCAR_NO_ENCRYPTION,
! 5784: NULL
! 5785: };
! 5786: static const gchar *aim_login_keys[] = {
! 5787: N_("clientLogin"),
! 5788: N_("Kerberos"),
! 5789: N_("MD5-based"),
! 5790: NULL
! 5791: };
! 5792: static const gchar *aim_login_values[] = {
! 5793: OSCAR_CLIENT_LOGIN,
! 5794: OSCAR_KERBEROS_LOGIN,
! 5795: OSCAR_MD5_LOGIN,
! 5796: NULL
! 5797: };
! 5798: static const gchar *icq_login_keys[] = {
! 5799: N_("clientLogin"),
! 5800: N_("MD5-based"),
! 5801: NULL
! 5802: };
! 5803: static const gchar *icq_login_values[] = {
! 5804: OSCAR_CLIENT_LOGIN,
! 5805: OSCAR_MD5_LOGIN,
! 5806: NULL
! 5807: };
! 5808: const gchar **login_keys;
! 5809: const gchar **login_values;
! 5810: GList *encryption_options = NULL;
! 5811: GList *login_options = NULL;
! 5812: int i;
! 5813:
! 5814: option = purple_account_option_string_new(_("Server"), "server", get_login_server(is_icq, TRUE));
! 5815: prpl_info->protocol_options = g_list_append(prpl_info->protocol_options, option);
! 5816:
! 5817: option = purple_account_option_int_new(_("Port"), "port", OSCAR_DEFAULT_LOGIN_PORT);
! 5818: prpl_info->protocol_options = g_list_append(prpl_info->protocol_options, option);
! 5819:
! 5820: for (i = 0; encryption_keys[i]; i++) {
! 5821: PurpleKeyValuePair *kvp = g_new0(PurpleKeyValuePair, 1);
! 5822: kvp->key = g_strdup(_(encryption_keys[i]));
! 5823: kvp->value = g_strdup(encryption_values[i]);
! 5824: encryption_options = g_list_append(encryption_options, kvp);
! 5825: }
! 5826: option = purple_account_option_list_new(_("Connection security"), "encryption", encryption_options);
! 5827: prpl_info->protocol_options = g_list_append(prpl_info->protocol_options, option);
! 5828:
! 5829: if (is_icq) {
! 5830: login_keys = icq_login_keys;
! 5831: login_values = icq_login_values;
! 5832: } else {
! 5833: login_keys = aim_login_keys;
! 5834: login_values = aim_login_values;
! 5835: }
! 5836: for (i = 0; login_keys[i]; i++) {
! 5837: PurpleKeyValuePair *kvp = g_new0(PurpleKeyValuePair, 1);
! 5838: kvp->key = g_strdup(_(login_keys[i]));
! 5839: kvp->value = g_strdup(login_values[i]);
! 5840: login_options = g_list_append(login_options, kvp);
! 5841: }
! 5842: option = purple_account_option_list_new(_("Authentication method"), "login_type", login_options);
! 5843: prpl_info->protocol_options = g_list_append(prpl_info->protocol_options, option);
! 5844:
! 5845: option = purple_account_option_bool_new(
! 5846: _("Always use AIM/ICQ proxy server for\nfile transfers and direct IM (slower,\nbut does not reveal your IP address)"), "always_use_rv_proxy",
! 5847: OSCAR_DEFAULT_ALWAYS_USE_RV_PROXY);
! 5848: prpl_info->protocol_options = g_list_append(prpl_info->protocol_options, option);
! 5849:
! 5850: if (purple_strequal(purple_plugin_get_id(plugin), "prpl-aim")) {
! 5851: option = purple_account_option_bool_new(_("Allow multiple simultaneous logins"), "allow_multiple_logins",
! 5852: OSCAR_DEFAULT_ALLOW_MULTIPLE_LOGINS);
! 5853: prpl_info->protocol_options = g_list_append(prpl_info->protocol_options, option);
! 5854: }
! 5855:
! 5856: if (init)
! 5857: return;
! 5858: init = TRUE;
! 5859:
! 5860: /* Preferences */
! 5861: purple_prefs_add_none("/plugins/prpl/oscar");
! 5862: purple_prefs_add_bool("/plugins/prpl/oscar/recent_buddies", FALSE);
! 5863:
! 5864: purple_prefs_remove("/plugins/prpl/oscar/show_idle");
! 5865: purple_prefs_remove("/plugins/prpl/oscar/always_use_rv_proxy");
! 5866:
! 5867: /* protocol handler */
! 5868: /* TODO: figure out a good instance to use here */
! 5869: purple_signal_connect(purple_get_core(), "uri-handler", &init,
! 5870: PURPLE_CALLBACK(oscar_uri_handler), NULL);
! 5871: }
! 5872:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>