# HG changeset patch # User Mark Doliner # Date 1047873750 0 # Node ID 9810ce8e7a96dcd2194d1acabbaed6f6d8af9a6d # Parent 6f04901ef7293f646c41f3fdf83f0a072edc8067 [gaim-migrate @ 5124] Here ya go, Rob. committer: Tailor Script diff -r 6f04901ef729 -r 9810ce8e7a96 src/protocols/oscar/Makefile.am --- a/src/protocols/oscar/Makefile.am Mon Mar 17 01:57:37 2003 +0000 +++ b/src/protocols/oscar/Makefile.am Mon Mar 17 04:02:30 2003 +0000 @@ -18,6 +18,7 @@ email.c \ faimconfig.h \ ft.c \ + icon.c \ icq.c \ im.c \ info.c \ diff -r 6f04901ef729 -r 9810ce8e7a96 src/protocols/oscar/Makefile.mingw --- a/src/protocols/oscar/Makefile.mingw Mon Mar 17 01:57:37 2003 +0000 +++ b/src/protocols/oscar/Makefile.mingw Mon Mar 17 04:02:30 2003 +0000 @@ -78,6 +78,7 @@ conn.c \ email.c \ ft.c \ + icon.c \ icq.c \ im.c \ info.c \ diff -r 6f04901ef729 -r 9810ce8e7a96 src/protocols/oscar/aim.h --- a/src/protocols/oscar/aim.h Mon Mar 17 01:57:37 2003 +0000 +++ b/src/protocols/oscar/aim.h Mon Mar 17 04:02:30 2003 +0000 @@ -258,6 +258,7 @@ #define AIM_CONN_TYPE_CHATNAV 0x000d #define AIM_CONN_TYPE_CHAT 0x000e #define AIM_CONN_TYPE_SEARCH 0x000f +#define AIM_CONN_TYPE_ICON 0x0010 #define AIM_CONN_TYPE_EMAIL 0x0018 /* they start getting arbitrary for rendezvous stuff =) */ @@ -476,6 +477,8 @@ fu8_t crap[0x25]; /* until we figure it out... */ } icqinfo; fu32_t present; + fu16_t iconstrlen; + fu8_t iconstr[30]; } aim_userinfo_t; #define AIM_USERINFO_PRESENT_FLAGS 0x00000001 @@ -1118,6 +1121,12 @@ faim_export int aim_usersearch_interest(aim_session_t *, const char *, const char *); + +/* icon.c */ +faim_export int aim_icon_requesticon(aim_session_t *sess, const char *sn, const fu8_t *iconstr, fu16_t iconstrlen); + + + /* These apply to exchanges as well. */ #define AIM_CHATROOM_FLAG_EVILABLE 0x0001 #define AIM_CHATROOM_FLAG_NAV_ONLY 0x0002 diff -r 6f04901ef729 -r 9810ce8e7a96 src/protocols/oscar/aim_cbtypes.h --- a/src/protocols/oscar/aim_cbtypes.h Mon Mar 17 01:57:37 2003 +0000 +++ b/src/protocols/oscar/aim_cbtypes.h Mon Mar 17 04:02:30 2003 +0000 @@ -179,14 +179,19 @@ /* * SNAC Family: "New" Search - * - * Most of these are actually special. */ #define AIM_CB_SCH_ERROR 0x0001 #define AIM_CB_SCH_SEARCH 0x0002 #define AIM_CB_SCH_RESULTS 0x0003 /* + * SNAC Family: Buddy icons + */ +#define AIM_CB_ICO_ERROR 0x0001 +#define AIM_CB_ICO_REQUEST 0x0004 +#define AIM_CB_ICO_RESPONSE 0x0005 + +/* * SNAC Family: ICQ * * Most of these are actually special. diff -r 6f04901ef729 -r 9810ce8e7a96 src/protocols/oscar/aim_internal.h --- a/src/protocols/oscar/aim_internal.h Mon Mar 17 01:57:37 2003 +0000 +++ b/src/protocols/oscar/aim_internal.h Mon Mar 17 04:02:30 2003 +0000 @@ -35,8 +35,8 @@ faim_internal aim_module_t *aim__findmodulebygroup(aim_session_t *sess, fu16_t group); faim_internal aim_module_t *aim__findmodule(aim_session_t *sess, const char *name); +faim_internal int admin_modfirst(aim_session_t *sess, aim_module_t *mod); faim_internal int buddylist_modfirst(aim_session_t *sess, aim_module_t *mod); -faim_internal int admin_modfirst(aim_session_t *sess, aim_module_t *mod); faim_internal int bos_modfirst(aim_session_t *sess, aim_module_t *mod); faim_internal int search_modfirst(aim_session_t *sess, aim_module_t *mod); faim_internal int stats_modfirst(aim_session_t *sess, aim_module_t *mod); @@ -47,14 +47,15 @@ faim_internal int chat_modfirst(aim_session_t *sess, aim_module_t *mod); faim_internal int locate_modfirst(aim_session_t *sess, aim_module_t *mod); faim_internal int general_modfirst(aim_session_t *sess, aim_module_t *mod); -faim_internal int ssi_modfirst(aim_session_t *sess, aim_module_t *mod); faim_internal int invite_modfirst(aim_session_t *sess, aim_module_t *mod); faim_internal int translate_modfirst(aim_session_t *sess, aim_module_t *mod); faim_internal int popups_modfirst(aim_session_t *sess, aim_module_t *mod); faim_internal int adverts_modfirst(aim_session_t *sess, aim_module_t *mod); +faim_internal int newsearch_modfirst(aim_session_t *sess, aim_module_t *mod); +faim_internal int icon_modfirst(aim_session_t *sess, aim_module_t *mod); +faim_internal int ssi_modfirst(aim_session_t *sess, aim_module_t *mod); faim_internal int icq_modfirst(aim_session_t *sess, aim_module_t *mod); faim_internal int email_modfirst(aim_session_t *sess, aim_module_t *mod); -faim_internal int newsearch_modfirst(aim_session_t *sess, aim_module_t *mod); faim_internal int aim_genericreq_n(aim_session_t *, aim_conn_t *conn, fu16_t family, fu16_t subtype); faim_internal int aim_genericreq_n_snacid(aim_session_t *, aim_conn_t *conn, fu16_t family, fu16_t subtype); diff -r 6f04901ef729 -r 9810ce8e7a96 src/protocols/oscar/conn.c --- a/src/protocols/oscar/conn.c Mon Mar 17 01:57:37 2003 +0000 +++ b/src/protocols/oscar/conn.c Mon Mar 17 04:02:30 2003 +0000 @@ -919,7 +919,8 @@ aim__registermodule(sess, chatnav_modfirst); aim__registermodule(sess, chat_modfirst); aim__registermodule(sess, newsearch_modfirst); - /* missing 0x10 - 0x12 */ + aim__registermodule(sess, icon_modfirst); + /* missing 0x11 - 0x12 */ aim__registermodule(sess, ssi_modfirst); /* missing 0x14 */ aim__registermodule(sess, icq_modfirst); /* XXX - Make sure this isn't sent for AIM */ diff -r 6f04901ef729 -r 9810ce8e7a96 src/protocols/oscar/email.c --- a/src/protocols/oscar/email.c Mon Mar 17 01:57:37 2003 +0000 +++ b/src/protocols/oscar/email.c Mon Mar 17 04:02:30 2003 +0000 @@ -62,6 +62,7 @@ /** * Subtype 0x0007 - Receive information about your email account + * * So I don't even know if you can have multiple 16 byte keys, * but this is coded so it will handle that, and handle it well. * This tells you if you have unread mail or not, the URL you diff -r 6f04901ef729 -r 9810ce8e7a96 src/protocols/oscar/info.c --- a/src/protocols/oscar/info.c Mon Mar 17 01:57:37 2003 +0000 +++ b/src/protocols/oscar/info.c Mon Mar 17 04:02:30 2003 +0000 @@ -618,10 +618,22 @@ } else if (type == 0x001d) { /* - * Type 29: Unknown. + * Type = 0x001d * - * Currently very rare. Always 18 bytes of mostly zero. + * Buddy icon information. This contains the info + * about the buddy icon that the user has stored on + * the server. */ + char *iconstr; + outinfo->iconstrlen = length-4; + outinfo->iconstrlen -= aim_bstream_advance(bs, aimbs_get16(bs)); + outinfo->iconstrlen -= aim_bstream_advance(bs, aimbs_get16(bs)); + if (aim_bstream_empty(bs) >= outinfo->iconstrlen) { + iconstr = aimbs_getraw(bs, outinfo->iconstrlen); + memcpy(outinfo->iconstr, iconstr, outinfo->iconstrlen); + } else + outinfo->iconstrlen = 0; + free(iconstr); } else if (type == 0x001e) { /* diff -r 6f04901ef729 -r 9810ce8e7a96 src/protocols/oscar/oscar.c --- a/src/protocols/oscar/oscar.c Mon Mar 17 01:57:37 2003 +0000 +++ b/src/protocols/oscar/oscar.c Mon Mar 17 04:02:30 2003 +0000 @@ -87,6 +87,7 @@ guint cnpa; guint paspa; guint emlpa; + guint icopa; GSList *create_rooms; @@ -104,10 +105,12 @@ GSList *direct_ims; GSList *file_transfers; GHashTable *buddyinfo; + GSList *requesticon; gboolean killme; gboolean icq; GSList *evilhack; + guint icontimer; struct { guint maxwatchers; /* max users who can watch you */ @@ -182,6 +185,9 @@ unsigned long ico_me_csum; time_t ico_me_time; gboolean ico_informed; + + fu16_t iconstrlen; + fu8_t iconstr[30]; }; struct name_data { @@ -289,6 +295,8 @@ static int gaim_chat_info_update (aim_session_t *, aim_frame_t *, ...); static int gaim_chat_incoming_msg(aim_session_t *, aim_frame_t *, ...); static int gaim_email_parseupdate(aim_session_t *, aim_frame_t *, ...); +static int gaim_icon_error (aim_session_t *, aim_frame_t *, ...); +static int gaim_icon_parseicon (aim_session_t *, aim_frame_t *, ...); static int gaim_parse_msgack (aim_session_t *, aim_frame_t *, ...); static int gaim_parse_ratechange (aim_session_t *, aim_frame_t *, ...); static int gaim_parse_evilnotify (aim_session_t *, aim_frame_t *, ...); @@ -301,6 +309,7 @@ static int conninitdone_chatnav (aim_session_t *, aim_frame_t *, ...); static int conninitdone_chat (aim_session_t *, aim_frame_t *, ...); static int conninitdone_email (aim_session_t *, aim_frame_t *, ...); +static int conninitdone_icon (aim_session_t *, aim_frame_t *, ...); static int gaim_parse_msgerr (aim_session_t *, aim_frame_t *, ...); static int gaim_parse_mtn (aim_session_t *, aim_frame_t *, ...); static int gaim_parse_locaterights(aim_session_t *, aim_frame_t *, ...); @@ -338,6 +347,9 @@ static int oscar_sendfile_ack (aim_session_t *, aim_frame_t *, ...); static int oscar_sendfile_done (aim_session_t *, aim_frame_t *, ...); +/* for icons */ +static gboolean gaim_icon_timerfunc(gpointer data); + static fu32_t check_encoding(const char *utf8); static fu32_t parse_encoding(const char *enc); @@ -479,6 +491,12 @@ od->emlpa = 0; debug_printf("removing email input watcher\n"); aim_conn_kill(od->sess, &conn); + } else if (conn->type == AIM_CONN_TYPE_ICON) { + if (od->icopa > 0) + gaim_input_remove(od->icopa); + od->icopa = 0; + debug_printf("removing icon input watcher\n"); + aim_conn_kill(od->sess, &conn); } else if (conn->type == AIM_CONN_TYPE_RENDEZVOUS) { if (conn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) gaim_odc_disconnect(od->sess, conn); @@ -611,14 +629,17 @@ od->direct_ims = g_slist_remove(od->direct_ims, n); g_free(n); } - /* BBB */ while (od->file_transfers) { struct gaim_xfer *xfer; xfer = (struct gaim_xfer *)od->file_transfers->data; gaim_xfer_destroy(xfer); } - + while (od->requesticon) { + char *sn = od->requesticon->data; + od->requesticon = g_slist_remove(od->requesticon, sn); + free(sn); + } g_hash_table_destroy(od->buddyinfo); while (od->evilhack) { g_free(od->evilhack->data); @@ -644,6 +665,8 @@ gaim_input_remove(od->paspa); if (od->emlpa > 0) gaim_input_remove(od->emlpa); + if (od->icopa > 0) + gaim_input_remove(od->icopa); aim_session_kill(od->sess); g_free(od->sess); od->sess = NULL; @@ -1347,6 +1370,23 @@ return 1; } +static int conninitdone_icon(aim_session_t *sess, aim_frame_t *fr, ...) { + struct gaim_connection *gc = sess->aux_data; + struct oscar_data *od = gc->proto_data; + + aim_conn_addhandler(sess, fr->conn, 0x0018, 0x0001, gaim_parse_genericerr, 0); + aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_ICO, AIM_CB_ICO_ERROR, gaim_icon_error, 0); + aim_conn_addhandler(sess, fr->conn, AIM_CB_FAM_ICO, AIM_CB_ICO_RESPONSE, gaim_icon_parseicon, 0); + + aim_clientready(sess, fr->conn); + + if (od->icontimer) + g_source_remove(od->icontimer); + od->icontimer = g_timeout_add(100, gaim_icon_timerfunc, gc); + + return 1; +} + static void oscar_chatnav_connect(gpointer data, gint source, GaimInputCondition cond) { struct gaim_connection *gc = data; struct oscar_data *od; @@ -1463,6 +1503,33 @@ debug_printf("email: connected\n"); } +static void oscar_icon_connect(gpointer data, gint source, GaimInputCondition cond) { + struct gaim_connection *gc = data; + struct oscar_data *od; + aim_session_t *sess; + aim_conn_t *tstconn; + + if (!g_slist_find(connections, gc)) { + close(source); + return; + } + + od = gc->proto_data; + sess = od->sess; + tstconn = aim_getconn_type_all(sess, AIM_CONN_TYPE_ICON); + tstconn->fd = source; + + if (source < 0) { + aim_conn_kill(sess, &tstconn); + debug_printf("unable to connect to icon server\n"); + return; + } + + aim_conn_completeconnect(sess, tstconn); + od->icopa = gaim_input_add(tstconn->fd, GAIM_INPUT_READ, oscar_callback, tstconn); + debug_printf("icon: connected\n"); +} + /* Hrmph. I don't know how to make this look better. --mid */ static int gaim_handle_redirect(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; @@ -1570,6 +1637,25 @@ debug_printf("Connected to chat room %s exchange %hu\n", ccon->name, ccon->exchange); } break; + case 0x0010: { /* icon */ + if (!(tstconn = aim_newconn(sess, AIM_CONN_TYPE_ICON, NULL))) { + debug_printf("unable to connect to icon server\n"); + g_free(host); + return 1; + } + aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR, gaim_connerr, 0); + aim_conn_addhandler(sess, tstconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_icon, 0); + + tstconn->status |= AIM_CONN_STATUS_INPROGRESS; + if (proxy_connect(account, host, port, oscar_icon_connect, gc) != 0) { + aim_conn_kill(sess, &tstconn); + debug_printf("unable to connect to icon server\n"); + g_free(host); + return 1; + } + aim_sendcookie(sess, tstconn, redir->cookielen, redir->cookie); + } break; + case 0x0018: { /* email */ if (!(tstconn = aim_newconn(sess, AIM_CONN_TYPE_EMAIL, NULL))) { debug_printf("unable to connect to email server\n"); @@ -1663,6 +1749,16 @@ bi->typingnot = FALSE; bi->ico_informed = FALSE; + /* Server stored icon stuff */ + if (info->iconstrlen) { + od->requesticon = g_slist_append(od->requesticon, strdup(normalize(info->sn))); + if (od->icontimer) + g_source_remove(od->icontimer); + od->icontimer = g_timeout_add(500, gaim_icon_timerfunc, gc); + } + bi->iconstrlen = info->iconstrlen; + memcpy(bi->iconstr, info->iconstr, info->iconstrlen); + serv_got_update(gc, info->sn, 1, info->warnlevel/10, signon, time_idle, type); @@ -3226,6 +3322,96 @@ return 1; } +static int gaim_icon_error(aim_session_t *sess, aim_frame_t *fr, ...) { + struct gaim_connection *gc = sess->aux_data; + struct oscar_data *od = gc->proto_data; + char *sn; + + sn = od->requesticon->data; + debug_printf("removing %s from hash table\n", sn); + od->requesticon = g_slist_remove(od->requesticon, sn); + free(sn); + + if (od->icontimer) + g_source_remove(od->icontimer); + od->icontimer = g_timeout_add(500, gaim_icon_timerfunc, gc); + + return 1; +} + +static int gaim_icon_parseicon(aim_session_t *sess, aim_frame_t *fr, ...) { + struct gaim_connection *gc = sess->aux_data; + struct oscar_data *od = gc->proto_data; + GSList *cur; + va_list ap; + char *sn; + fu8_t *iconstr, *icon; + fu16_t iconstrlen, iconlen; + + va_start(ap, fr); + sn = va_arg(ap, char *); + iconstr = va_arg(ap, fu8_t *); + iconstrlen = va_arg(ap, int); + icon = va_arg(ap, fu8_t *); + iconlen = va_arg(ap, int); + va_end(ap); + + if (iconlen > 0) + set_icon_data(gc, sn, icon, iconlen); + + cur = od->requesticon; + while (cur) { + char *cursn = cur->data; + if (!aim_sncmp(cursn, sn)) { + od->requesticon = g_slist_remove(od->requesticon, cursn); + free(cursn); + cur = od->requesticon; + } else + cur = cur->next; + } + + if (od->icontimer) + g_source_remove(od->icontimer); + od->icontimer = g_timeout_add(250, gaim_icon_timerfunc, gc); + + return 1; +} + +static gboolean gaim_icon_timerfunc(gpointer data) { + struct gaim_connection *gc = data; + struct oscar_data *od = gc->proto_data; + struct buddy *b; + struct buddyinfo *bi; + aim_conn_t *conn; + char *buddy_icon; + + if (!od->requesticon) { + debug_printf("no more icons to request\n"); + return FALSE; + } + + conn = aim_getconn_type(od->sess, AIM_CONN_TYPE_ICON); + if (!conn) { + aim_reqservice(od->sess, od->conn, AIM_CONN_TYPE_ICON); + return FALSE; + } + + bi = g_hash_table_lookup(od->buddyinfo, (char *)od->requesticon->data); + b = gaim_find_buddy(gc->account, (char *)od->requesticon->data); + buddy_icon = gaim_buddy_get_setting(b, "buddy_icon"); + if (bi && (bi->iconstrlen > 0) && !buddy_icon) { + aim_icon_requesticon(od->sess, od->requesticon->data, bi->iconstr, bi->iconstrlen); + return FALSE; + } else { + char *sn = od->requesticon->data; + od->requesticon = g_slist_remove(od->requesticon, sn); + free(sn); + } + free(buddy_icon); + + return TRUE; +} + /* * Recieved in response to an IM sent with the AIM_IMFLAGS_ACK option. */