cpw.rekkanoryo.icqxstatus: 14315067: This patch comes from the combined work ...
rekkanoryo at pidgin.im
rekkanoryo at pidgin.im
Thu Nov 13 12:15:35 EST 2008
-----------------------------------------------------------------
Revision: 1431506710bed6b8f0c837b670ee314b1692990e
Ancestor: 311b4db51b575e1baa7f78d751ff926475edecc3
Author: rekkanoryo at pidgin.im
Date: 2008-11-13T17:04:53
Branch: im.pidgin.cpw.rekkanoryo.icqxstatus
URL: http://d.pidgin.im/viewmtn/revision/info/1431506710bed6b8f0c837b670ee314b1692990e
Modified files:
libpurple/protocols/oscar/family_buddy.c
libpurple/protocols/oscar/family_icbm.c
libpurple/protocols/oscar/family_locate.c
libpurple/protocols/oscar/oscar.c
libpurple/protocols/oscar/oscar.h
libpurple/protocols/oscar/tlv.c libpurple/request.c
libpurple/request.h pidgin/gtkrequest.c
pidgin/pixmaps/Makefile.am
ChangeLog:
This patch comes from the combined work of contributors minstrel, NightFox,
bob007, salieff, and nops (these are their trac usernames). I have made
some minor tweaks to the patch, but these shouldn't be a problem. This patch
needs some TLC before we can merge it anywhere else; it adds API so it must
hit im.pidgin.pidgin.next.minor before hitting im.pidgin.pidgin. Refs #4508.
-------------- next part --------------
============================================================
--- libpurple/protocols/oscar/family_buddy.c ea016d2eed0651a6b6622bdfcba4da957534a082
+++ libpurple/protocols/oscar/family_buddy.c 93f5d852204a01fc609f77bc101972992eca47d0
@@ -224,6 +224,10 @@ buddychange(OscarData *od, FlapConnectio
if (snac->subtype == SNAC_SUBTYPE_BUDDY_ONCOMING && userinfo.flags & AIM_FLAG_AWAY)
aim_locate_autofetch_away_message(od, userinfo.sn);
+ if (snac->subtype == SNAC_SUBTYPE_BUDDY_ONCOMING &&
+ userinfo.capabilities & OSCAR_CAPABILITY_XTRAZ && userinfo.customicon > 0)
+ icq_im_xstatus_request(od, userinfo.sn);
+
aim_info_free(&userinfo);
return ret;
============================================================
--- libpurple/protocols/oscar/family_icbm.c ffadc235ea5229783fcc3cf7f92b5abd8e26dd6d
+++ libpurple/protocols/oscar/family_icbm.c 43eced84e1ece4e29162bdb56066de02a3cc35c9
@@ -2533,6 +2533,15 @@ static int clientautoresp(OscarData *od,
char *sn;
guchar *cookie;
guint8 snlen;
+ char *xml = NULL;
+ int hdrlen;
+ int curpos;
+ int num1,num2;
+ char *desc, *title, *temp;
+ PurpleAccount *account;
+ PurpleBuddy *buddy;
+ PurplePresence *presence;
+ PurpleStatus *status;
cookie = byte_stream_getraw(bs, 8);
channel = byte_stream_get16(bs);
@@ -2540,16 +2549,56 @@ static int clientautoresp(OscarData *od,
sn = byte_stream_getstr(bs, snlen);
reason = byte_stream_get16(bs);
- if (channel == 0x0002)
- {
- if (reason == 0x0003) /* channel-specific */
- /* parse status note text */
- parse_status_note_text(od, cookie, sn, bs);
+ if (channel == 0x0002) {
- byte_stream_get16(bs); /* Unknown */
- byte_stream_get16(bs); /* Unknown */
- if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
- ret = userfunc(od, conn, frame, channel, sn, reason, cookie);
+ hdrlen = byte_stream_getle16(bs);
+ if ( ((hdrlen == 27 ) && (bs->len > (27 + 51)))) {
+ byte_stream_advance(bs, 51);
+ num1 = byte_stream_getle16(bs);
+ num2 = byte_stream_getle16(bs);
+ purple_debug_misc("oscar", "X-Status: Num1 %i, num2 %i\n",num1, num2);
+
+ if(((num1 == 0x4f00)&&(num2 == 0x3b00))) {
+ byte_stream_advance(bs, 86);
+ curpos = byte_stream_curpos(bs);
+ xml = byte_stream_getstr(bs, bs->len - curpos);
+ purple_debug_misc("oscar", "X-Status: Received XML reply\n");
+ if(xml) {
+ /* purple_debug_misc("oscar", "X-Status: XML reply: %s\n", (const char*) xml); */
+ if ((desc=strstr(xml,"<desc>")) != NULL) {
+ temp=strstr(xml,"</desc>");
+ temp[0]=0;
+ desc=desc+12;
+ }
+ if ((title=strstr(xml,"<title>")) != NULL) {
+ temp=strstr(xml,"</title>");
+ temp[0]=0;
+ title=title+13;
+ } else {
+ title="";
+ }
+ strcpy(xml,title);
+ if (desc) {
+ strcat(xml, " - ");
+ strcat(xml, desc);
+ }
+ purple_debug_misc("oscar", "X-Status reply: %s\n", (const char*)xml);
+ account = purple_connection_get_account(od->gc);
+ buddy = purple_find_buddy(account, sn);
+ presence = purple_buddy_get_presence(buddy);
+ status = purple_presence_get_active_status(presence);
+ purple_prpl_got_user_status(account, sn,
+ purple_status_get_id(status), "message", xml, NULL);
+ } else {
+ purple_debug_misc("oscar", "X-Status: Can't get XML reply string\n");
+ }
+ } else {
+ purple_debug_misc("oscar", "X-Status: 0x0004, 0x000b not an xstatus reply\n" );
+ /* if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+ ret = userfunc(od, conn, frame, channel, sn, reason); */
+ }
+
+ }
} else if (channel == 0x0004) { /* ICQ message */
switch (reason) {
@@ -2608,6 +2657,7 @@ static int clientautoresp(OscarData *od,
g_free(cookie);
g_free(sn);
+ if (xml) g_free(xml);
return ret;
}
@@ -2721,6 +2771,181 @@ int aim_im_sendmtn(OscarData *od, guint1
}
/*
+ * Subtype 0x0006 - Send eXtra Status request
+ */
+int icq_im_xstatus_request(OscarData *od, const char *sn)
+{
+ FlapConnection *conn;
+ aim_snacid_t snacid;
+ guchar cookie[8];
+ GSList *outer_tlvlist = NULL, *inner_tlvlist = NULL;
+ ByteStream bs, header, plugindata;
+ PurpleAccount *account;
+ const char *fmt;
+ char *statxml;
+ int xmllen;
+
+ static const guint8 pluginid[] =
+ {
+ 0x09, 0x46, 0x13, 0x49, 0x4C, 0x7F, 0x11, 0xD1,
+ 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00
+ };
+
+ static const guint8 c_plugindata[] =
+ {
+ 0x1B, 0x00, 0x0A,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0xF9, 0xD1, 0x0E, 0x00, 0xF9, 0xD1, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x00, 0x4F, 0x00, 0x3B, 0x60, 0xB3, 0xEF, 0xD8, 0x2A, 0x6C, 0x45, 0xA4, 0xE0, 0x9C,
+ 0x5A, 0x5E, 0x67, 0xE8, 0x65, 0x08, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x53, 0x63, 0x72, 0x69, 0x70,
+ 0x74, 0x20, 0x50, 0x6C, 0x75, 0x67, 0x2D, 0x69, 0x6E, 0x3A, 0x20, 0x52, 0x65, 0x6D, 0x6F, 0x74,
+ 0x65, 0x20, 0x4E, 0x6F, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x41,
+ 0x72, 0x72, 0x69, 0x76, 0x65, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00
+ };
+
+ if (!od || !(conn = flap_connection_findbygroup(od, 0x0004)))
+ return -EINVAL;
+
+ if (!sn)
+ return -EINVAL;
+
+ fmt = "<N><QUERY><Q><PluginID>srvMng</PluginID></Q></QUERY><NOTIFY><srv><id>cAwaySrv</id><req><id>AwayStat</id><trans>2</trans><senderId>%s</senderId></req></srv></NOTIFY></N>\r\n";
+
+ account = purple_connection_get_account(od->gc);
+ xmllen = strlen(fmt) - 2 + strlen(account->username);
+
+ statxml = (char*) g_malloc(xmllen);
+ snprintf(statxml, xmllen, fmt, account->username);
+
+ aim_icbm_makecookie(cookie);
+
+ byte_stream_new(&bs, 10 + 8 + 2 + 1 + strlen(sn) + 2
+ + 2 + 2 + 8 + 16 + 2 + 2 + 2 + 2 + 2
+ + 2 + 2 + sizeof(c_plugindata) + xmllen
+ + 2 + 2);
+
+ snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, NULL, 0);
+ aim_im_puticbm(&bs, cookie, 0x0002, sn);
+
+ byte_stream_new(&header, (7*2) + 16 + 8 + 2 + sizeof(c_plugindata) + xmllen); /* TLV 0x0005 Stream + Size */
+ byte_stream_new(&plugindata, (sizeof(c_plugindata) + xmllen));
+
+ byte_stream_put16(&header, 0x0000); /* Message Type: Request */
+ byte_stream_putraw(&header, cookie, sizeof(cookie)); /* Message ID */
+ byte_stream_putraw(&header, pluginid, sizeof(pluginid)); /* Plugin ID */
+
+ aim_tlvlist_add_16(&inner_tlvlist, 0x000a, 0x0001);
+ aim_tlvlist_add_noval(&inner_tlvlist, 0x000f);
+
+ /* Add Plugin Specific Data */
+ byte_stream_putraw(&plugindata, c_plugindata, sizeof(c_plugindata)); /* Content of TLV 0x2711 */
+ byte_stream_putstr(&plugindata, statxml);
+
+ aim_tlvlist_add_raw(&inner_tlvlist, 0x2711, (sizeof(c_plugindata) + xmllen), plugindata.data);
+
+ aim_tlvlist_write(&header, &inner_tlvlist);
+
+
+ aim_tlvlist_add_raw(&outer_tlvlist, 0x0005, byte_stream_curpos(&header), header.data);
+ aim_tlvlist_add_noval(&outer_tlvlist, 0x0003); /* Empty TLV 0x0003 */
+
+ aim_tlvlist_write(&bs, &outer_tlvlist);
+
+ purple_debug_misc("oscar", "X-Status Request\n");
+ flap_connection_send_snac_with_priority(od, conn, 0x0004, 0x0006, 0x0000, snacid, &bs, TRUE);
+
+ aim_tlvlist_free(inner_tlvlist);
+ aim_tlvlist_free(outer_tlvlist);
+ byte_stream_destroy(&header);
+ byte_stream_destroy(&plugindata);
+ byte_stream_destroy(&bs);
+ g_free(statxml);
+
+ return 0;
+}
+
+int icq_relay_xstatus(OscarData *od, const char *sn, const guchar *cookie)
+{
+ FlapConnection *conn;
+ ByteStream bs;
+ aim_snacid_t snacid;
+ PurpleAccount *account;
+ PurpleStatus *status;
+ const char *fmt;
+ const char *formatted_msg;
+ char *msg;
+ char *statxml;
+ const char *title;
+ int len;
+
+ static const guint8 plugindata[] = {
+ 0x1B, 0x00,
+ 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0xF9, 0xD1, 0x0E, 0x00, 0xF9, 0xD1,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x4F,
+ 0x00, 0x3B, 0x60, 0xB3, 0xEF, 0xD8, 0x2A, 0x6C, 0x45, 0xA4, 0xE0,
+ 0x9C, 0x5A, 0x5E, 0x67, 0xE8, 0x65, 0x08, 0x00, 0x2A, 0x00, 0x00,
+ 0x00, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x20, 0x50, 0x6C, 0x75,
+ 0x67, 0x2D, 0x69, 0x6E, 0x3A, 0x20, 0x52, 0x65, 0x6D, 0x6F, 0x74,
+ 0x65, 0x20, 0x4E, 0x6F, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
+ 0x69, 0x6F, 0x6E, 0x20, 0x41, 0x72, 0x72, 0x69, 0x76, 0x65, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xF3, 0x01, 0x00, 0x00, 0xEF, 0x01, 0x00, 0x00
+ };
+
+ fmt = "<NR><RES><ret event='OnRemoteNotification'><srv><id>cAwaySrv</id><val srv_id='cAwaySrv'><Root><CASXtraSetAwayMessage></CASXtraSetAwayMessage>&l t;uin>%s</uin><index>1</index><title>%s</title><desc>%s</desc></Root></val></srv><srv><id>cRandomizerSrv</id><val srv_id='cRandomizerSrv'>undefined</val></srv></ret></RES></NR>\r\n";
+
+
+ if (!od || !(conn = flap_connection_findbygroup(od, 0x0002)))
+ return -EINVAL;
+
+ if (!sn)
+ return -EINVAL;
+
+ account = purple_connection_get_account(od->gc);
+ if(!account) return -EINVAL;
+
+/* if (!strcmp(account->username, sn))
+ icq_im_xstatus_request(od, sn); */
+
+ status = purple_presence_get_active_status(account->presence);
+ if (!status) return -EINVAL;
+ title = purple_status_get_name(status);
+ if (!title) return -EINVAL;
+ formatted_msg = purple_status_get_attr_string(status, "message");
+ if (!formatted_msg) return -EINVAL;
+ msg = purple_markup_strip_html(formatted_msg);
+ if (!msg) return -EINVAL;
+ len = strlen(fmt)-6+strlen(account->username)+strlen(title)+strlen(msg);
+ statxml = (char*) g_malloc(len);
+
+ snprintf(statxml, len, fmt,
+ account->username, title, msg);
+
+ purple_debug_misc("oscar", "X-Status AutoReply: %s, %s\n", formatted_msg, msg);
+
+ byte_stream_new(&bs, 10 + 8 + 2 + 1 + strlen(sn) + 2 + sizeof(plugindata) + strlen(statxml)); /* 16 extra */
+
+ snacid = aim_cachesnac(od, 0x0004, 0x000b, 0x0000, NULL, 0);
+ aim_im_puticbm(&bs, cookie, 0x0002, sn);
+ byte_stream_put16(&bs, 0x0003);
+ byte_stream_putraw(&bs, plugindata, sizeof(plugindata));
+ byte_stream_putraw(&bs, (const guint8*)statxml, strlen(statxml));
+
+ flap_connection_send_snac_with_priority(od, conn, 0x0004, 0x000b, 0x0000, snacid, &bs, TRUE);
+
+ g_free(statxml);
+ g_free(msg);
+ byte_stream_destroy(&bs);
+
+ return 0;
+}
+
+/*
* Subtype 0x0014 - Receive a mini typing notification (mtn) packet.
*
* This is supported by winaim5 and newer, MacAIM bleh and newer, iChat bleh and newer,
============================================================
--- libpurple/protocols/oscar/family_locate.c d3e1dde388003a3e3fa9bed022440c1a95a2e9e7
+++ libpurple/protocols/oscar/family_locate.c f7eed21b345c8530789dd0d2ce28138fc9917c9e
@@ -166,6 +166,16 @@ static const struct {
{0x09, 0x46, 0x13, 0x4a, 0x4c, 0x7f, 0x11, 0xd1,
0x22, 0x82, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
+ /* New format of caps (xtraz icons) */
+ {OSCAR_CAPABILITY_NEWCAPS,
+ {0x09, 0x46, 0x00, 0x00, 0x4c, 0x7f, 0x11, 0xd1,
+ 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
+
+ /* Support xtraz statuses */
+ {OSCAR_CAPABILITY_XTRAZ,
+ {0x1a, 0x09, 0x3c, 0x6c, 0xd7, 0xFD, 0x4e, 0xc5,
+ 0x9d, 0x51, 0xa6, 0x47, 0x4e, 0x34, 0xf5, 0xa0}},
+
{OSCAR_CAPABILITY_SENDBUDDYLIST,
{0x09, 0x46, 0x13, 0x4b, 0x4c, 0x7f, 0x11, 0xd1,
0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}},
@@ -242,6 +252,155 @@ static const struct {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
};
+#define AIM_CUSTOM_ICONS_COUNT 35
+
+static const struct {
+ char *filename;
+ char *descriptivename;
+ guint8 data[16];
+} aim_custom_icons[AIM_CUSTOM_ICONS_COUNT] = {
+ /* empty X-Status for the case when customicon == 0 */
+ {NULL, NULL,
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+
+ {"xstatus_thinking", "Thinking",
+ {0x3f, 0xb0, 0xbd, 0x36, 0xaf, 0x3b, 0x4a, 0x60,
+ 0x9e, 0xef, 0xcf, 0x19, 0x0f, 0x6a, 0x5a, 0x7f}},
+
+ {"xstatus_busy", "Busy",
+ {0x48, 0x8e, 0x14, 0x89, 0x8a, 0xca, 0x4a, 0x08,
+ 0x82, 0xaa, 0x77, 0xce, 0x7a, 0x16, 0x52, 0x08}},
+
+ {"xstatus_shopping", "Shopping",
+ {0x63, 0x62, 0x73, 0x37, 0xa0, 0x3f, 0x49, 0xff,
+ 0x80, 0xe5, 0xf7, 0x09, 0xcd, 0xe0, 0xa4, 0xee}},
+
+ {"xstatus_typing", "Typing",
+ {0x63, 0x4f, 0x6b, 0xd8 ,0xad, 0xd2, 0x4a, 0xa1,
+ 0xaa, 0xb9, 0x11, 0x5b, 0xc2, 0x6d, 0x05, 0xa1}},
+
+ {"xstatus_question", "Question Mark",
+ {0x63, 0x14, 0x36, 0xff, 0x3f, 0x8a, 0x40, 0xd0,
+ 0xa5, 0xcb, 0x7b, 0x66, 0xe0, 0x51, 0xb3, 0x64}},
+
+ {"xstatus_angry", "Angry",
+ {0x01, 0xd8, 0xd7, 0xee, 0xac, 0x3b, 0x49, 0x2a,
+ 0xa5, 0x8d, 0xd3, 0xd8, 0x77, 0xe6, 0x6b, 0x92}},
+
+ {"xstatus_eating", "Eating",
+ {0xf8, 0xe8, 0xd7, 0xb2, 0x82, 0xc4, 0x41, 0x42,
+ 0x90, 0xf8, 0x10, 0xc6, 0xce, 0x0a, 0x89, 0xa6}},
+
+ {"xstatus_cinema", "Cinema",
+ {0x10, 0x7a, 0x9a, 0x18, 0x12, 0x32, 0x4d, 0xa4,
+ 0xb6, 0xcd, 0x08, 0x79, 0xdb, 0x78, 0x0f, 0x09}},
+
+ {"xstatus_sick", "Sick",
+ {0x1f, 0x7a, 0x40, 0x71, 0xbf, 0x3b, 0x4e, 0x60,
+ 0xbc, 0x32, 0x4c, 0x57, 0x87, 0xb0, 0x4c, 0xf1}},
+
+ {"xstatus_crap", "Unknown 1",
+ {0x2c, 0xe0, 0xe4, 0xe5, 0x7c, 0x64, 0x43, 0x70,
+ 0x9c, 0x3a, 0x7a, 0x1c, 0xe8, 0x78, 0xa7, 0xdc}},
+
+ {"xstatus_iron", "Unknown 2",
+ {0xb7, 0x08, 0x67, 0xf5, 0x38, 0x25, 0x43, 0x27,
+ 0xa1, 0xff, 0xcf, 0x4c, 0xc1, 0x93, 0x97, 0x97}},
+
+ {"xstatus_bathing", "Bathing",
+ {0x5a, 0x58, 0x1e, 0xa1, 0xe5, 0x80, 0x43, 0x0c,
+ 0xa0, 0x6f, 0x61, 0x22, 0x98, 0xb7, 0xe4, 0xc7}},
+
+ {"xstatus_tv", "Watching TV",
+ {0x80, 0x53, 0x7d, 0xe2, 0xa4, 0x67, 0x4a, 0x76,
+ 0xb3, 0x54, 0x6d, 0xfd, 0x07, 0x5f, 0x5e, 0xc6}},
+
+ {"xstatus_fun", "Having fun",
+ {0x6f, 0x49, 0x30, 0x98, 0x4f, 0x7c, 0x4a, 0xff,
+ 0xa2, 0x76, 0x34, 0xa0, 0x3b, 0xce, 0xae, 0xa7}},
+
+ {"xstatus_sleeping", "Sleeping",
+ {0x78, 0x5e, 0x8c, 0x48, 0x40, 0xd3, 0x4c, 0x65,
+ 0x88, 0x6f, 0x04, 0xcf, 0x3f, 0x3f, 0x43, 0xdf}},
+
+ {"xstatus_pda", "PDA device",
+ {0x10, 0x11, 0x17, 0xc9, 0xa3, 0xb0, 0x40, 0xf9,
+ 0x81, 0xac, 0x49, 0xe1, 0x59, 0xfb, 0xd5, 0xd4}},
+
+ {"xstatus_heart", "In love",
+ {0xdd, 0xcf, 0x0e, 0xa9, 0x71, 0x95, 0x40, 0x48,
+ 0xa9, 0xc6, 0x41, 0x32, 0x06, 0xd6, 0xf2, 0x80}},
+
+ {"xstatus_tired", "Tired",
+ {0x83, 0xc9, 0xb7, 0x8e, 0x77, 0xe7, 0x43, 0x78,
+ 0xb2, 0xc5, 0xfb, 0x6c, 0xfc, 0xc3, 0x5b, 0xec}},
+
+ {"xstatus_friends", "Friends",
+ {0xf1, 0x8a, 0xb5, 0x2e, 0xdc, 0x57, 0x49, 0x1d,
+ 0x99, 0xdc, 0x64, 0x44, 0x50, 0x24, 0x57, 0xaf}},
+
+ {"xstatus_phone", "On the phone",
+ {0x12, 0x92, 0xe5, 0x50, 0x1b, 0x64, 0x4f, 0x66,
+ 0xb2, 0x06, 0xb2, 0x9a, 0xf3, 0x78, 0xe4, 0x8d}},
+
+ {"xstatus_surfing", "Surfing",
+ {0xa6, 0xed, 0x55, 0x7e, 0x6b, 0xf7, 0x44, 0xd4,
+ 0xa5, 0xd4, 0xd2, 0xe7, 0xd9, 0x5c, 0xe8, 0x1f}},
+
+ {"xstatus_mobile", "Cell phone",
+ {0x16, 0x0c, 0x60, 0xbb, 0xdd, 0x44, 0x43, 0xf3,
+ 0x91, 0x40, 0x05, 0x0f, 0x00, 0xe6, 0xc0, 0x09}},
+
+ {"xstatus_google", "Googling",
+ {0xd4, 0xe2, 0xb0, 0xba, 0x33, 0x4e, 0x4f, 0xa5,
+ 0x98, 0xd0, 0x11, 0x7d, 0xbf, 0x4d, 0x3c, 0xc8}},
+
+ {"xstatus_party", "Party",
+ {0xe6, 0x01, 0xe4, 0x1c, 0x33, 0x73, 0x4b, 0xd1,
+ 0xbc, 0x06, 0x81, 0x1d, 0x6c, 0x32, 0x3d, 0x81}},
+
+ {"xstatus_coffee", "Coffee",
+ {0x1b, 0x78, 0xae, 0x31, 0xfa, 0x0b, 0x4d, 0x38,
+ 0x93, 0xd1, 0x99, 0x7e, 0xee, 0xaf, 0xb2, 0x18}},
+
+ {"xstatus_gaming", "Playing",
+ {0xd4, 0xa6, 0x11, 0xd0, 0x8f, 0x01, 0x4e, 0xc0,
+ 0x92, 0x23, 0xc5, 0xb6, 0xbe, 0xc6, 0xcc, 0xf0}},
+
+ {"xstatus_internet", "Internet",
+ {0x12, 0xd0, 0x7e, 0x3e, 0xf8, 0x85, 0x48, 0x9e,
+ 0x8e, 0x97, 0xa7, 0x2a, 0x65, 0x51, 0xe5, 0x8d}},
+
+ {"xstatus_zzz", "Snoozing",
+ {0x64, 0x43, 0xc6, 0xaf, 0x22, 0x60, 0x45, 0x17,
+ 0xb5, 0x8c, 0xd7, 0xdf, 0x8e, 0x29, 0x03, 0x52}},
+
+ {"xstatus_writing", "Writing",
+ {0x00, 0x72, 0xd9, 0x08, 0x4a, 0xd1, 0x43, 0xdd,
+ 0x91, 0x99, 0x6f, 0x02, 0x69, 0x66, 0x02, 0x6f}},
+
+ {"xstatus_beer", "Drinking",
+ {0x8c, 0x50, 0xdb, 0xae, 0x81, 0xed, 0x47, 0x86,
+ 0xac, 0xca, 0x16, 0xcc, 0x32, 0x13, 0xc7, 0xb7}},
+
+ {"xstatus_music", "Music",
+ {0x61, 0xbe, 0xe0, 0xdd, 0x8b, 0xdd, 0x47, 0x5d,
+ 0x8d, 0xee, 0x5f, 0x4b, 0xaa, 0xcf, 0x19, 0xa7}},
+
+ {"xstatus_studying", "Studying",
+ {0x60, 0x9d, 0x52, 0xf8, 0xa2, 0x9a, 0x49, 0xa6,
+ 0xb2, 0xa0, 0x25, 0x24, 0xc5, 0xe9, 0xd2, 0x60}},
+
+ {"xstatus_engineering", "Engineering",
+ {0xba, 0x74, 0xdb, 0x3e, 0x9e, 0x24, 0x43, 0x4b,
+ 0x87, 0xb6, 0x2f, 0x6b, 0x8d, 0xfe, 0xe5, 0x0f}},
+
+ {"xstatus_crapping", "In the restroom",
+ {0x16, 0xf5, 0xb7, 0x6f, 0xa9, 0xd2, 0x40, 0x35,
+ 0x8c, 0xc5, 0xc0, 0x84, 0x70, 0x3c, 0x98, 0xfa}}
+};
+
/*
* Add the userinfo to our linked list. If we already have userinfo
* for this buddy, then just overwrite parts of the old data.
@@ -278,6 +437,9 @@ aim_locate_adduserinfo(OscarData *od, ai
cur->sessionlen = userinfo->sessionlen;
if (userinfo->capabilities != 0)
cur->capabilities = userinfo->capabilities;
+ if (userinfo->customicon != 0)
+ cur->customicon = userinfo->customicon;
+
cur->present |= userinfo->present;
if (userinfo->iconcsumlen > 0) {
@@ -469,11 +631,36 @@ aim_locate_getcaps(OscarData *od, ByteSt
cap[8], cap[9],
cap[10], cap[11], cap[12], cap[13],
cap[14], cap[15]);
+ g_free(cap);
+ }
+ return flags;
+}
+
+gint32
+aim_get_custom_icon(OscarData *od, ByteStream *bs, int len)
+{
+ int offset;
+ gint32 result = -1;
+
+ for (offset = 0; byte_stream_empty(bs) && (offset < len); offset += 0x10) {
+ /* check wheather this capability is a custom user icon */
+ guint8 *cap;
+ int i;
+
+ cap = byte_stream_getraw(bs, 0x10);
+
+ for (i = 1; i < AIM_CUSTOM_ICONS_COUNT; i++) {
+ if (memcmp(&aim_custom_icons[i].data, cap, 0x10) == 0) {
+ purple_debug_misc("oscar", "Custom user icon: %s\n", aim_custom_icons[i].descriptivename);
+ result = i;
+ break; /* should only match once... */
+ }
+ }
g_free(cap);
}
- return flags;
+ return result;
}
guint32
@@ -566,6 +753,37 @@ aim_info_free(aim_userinfo_t *info)
g_free(info->away_encoding);
}
+#define ICQMOODS_COUNT 23
+
+static const struct {
+ char *mood;
+ gint32 icon_num;
+} icqmoods[ICQMOODS_COUNT] = {
+ {"icqmood1", 12},
+ {"icqmood2", 18},
+ {"icqmood3", 24},
+ {"icqmood4", 30},
+ {"icqmood5", 1},
+ {"icqmood6", 7},
+ {"icqmood7", 13},
+ {"icqmood8", 19},
+ {"icqmood9", 25},
+ {"icqmood10", 31},
+ {"icqmood11", 11},
+ {"icqmood12", 8},
+ {"icqmood13", 14},
+ {"icqmood14", 20},
+ {"icqmood15", 26},
+ {"icqmood16", 32},
+ {"icqmood17", 9},
+ {"icqmood18", 15},
+ {"icqmood19", 21},
+ {"icqmood20", 27},
+ {"icqmood21", 33},
+ {"icqmood22", 10},
+ {"icqmood23", 6},
+};
+
/*
* AIM is fairly regular about providing user info. This is a generic
* routine to extract it in its standard form.
@@ -606,12 +824,13 @@ aim_info_extract(OscarData *od, ByteStre
for (curtlv = 0; curtlv < tlvcnt; curtlv++) {
guint16 type, length;
int endpos;
+ int curpos;
type = byte_stream_get16(bs);
length = byte_stream_get16(bs);
+ curpos = byte_stream_curpos(bs);
+ endpos = curpos + MIN(length, byte_stream_empty(bs));
- endpos = byte_stream_curpos(bs) + MIN(length, byte_stream_empty(bs));
-
if (type == 0x0001) {
/*
* User flags
@@ -725,6 +944,8 @@ aim_info_extract(OscarData *od, ByteStre
*/
outinfo->capabilities |= aim_locate_getcaps(od, bs, length);
outinfo->present |= AIM_USERINFO_PRESENT_CAPABILITIES;
+ byte_stream_setpos(bs, curpos);
+ outinfo->customicon = aim_get_custom_icon(od, bs, length);
} else if (type == 0x000e) {
/*
@@ -853,6 +1074,27 @@ aim_info_extract(OscarData *od, ByteStre
outinfo->itmsurl_encoding = NULL;
}
} break;
+
+ case 0x000e: { /* ICQ mood */
+ char *mood;
+ gint32 i;
+ gint32 icon_num = -1;
+
+ mood = byte_stream_getstr(bs, length2);
+
+ for (i = 0; i < ICQMOODS_COUNT; i++)
+ if (!strcmp(mood, icqmoods[i].mood)) {
+ icon_num = icqmoods[i].icon_num;
+ break; /* should only match once... */
+ }
+
+ if (icon_num >= 0)
+ outinfo->customicon = icon_num;
+ else
+ purple_debug_warning("oscar", "Unknown icqmood: %s", mood);
+
+ g_free(mood);
+ } break;
}
/* Save ourselves. */
@@ -933,7 +1175,7 @@ aim_putuserinfo(ByteStream *bs, aim_user
#endif
if (info->present & AIM_USERINFO_PRESENT_CAPABILITIES)
- aim_tlvlist_add_caps(&tlvlist, 0x000d, info->capabilities);
+ aim_tlvlist_add_caps(&tlvlist, 0x000d, info->capabilities, info->customicon);
if (info->present & AIM_USERINFO_PRESENT_SESSIONLEN)
aim_tlvlist_add_32(&tlvlist, (guint16)((info->flags & AIM_FLAG_AOL) ? 0x0010 : 0x000f), info->sessionlen);
@@ -1140,7 +1382,7 @@ aim_locate_setcaps(OscarData *od, guint3
if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)))
return -EINVAL;
- aim_tlvlist_add_caps(&tlvlist, 0x0005, caps);
+ aim_tlvlist_add_caps(&tlvlist, 0x0005, caps, purple_account_get_int(purple_connection_get_account(od->gc), "customicon", -1));
byte_stream_new(&bs, aim_tlvlist_size(tlvlist));
@@ -1226,6 +1468,8 @@ userinfo(OscarData *od, FlapConnection *
ByteStream cbs;
byte_stream_init(&cbs, tlv->value, tlv->length);
userinfo->capabilities = aim_locate_getcaps(od, &cbs, tlv->length);
+ byte_stream_rewind(&cbs);
+ userinfo->customicon = aim_get_custom_icon(od, &cbs, tlv->length);
userinfo->present = AIM_USERINFO_PRESENT_CAPABILITIES;
}
aim_tlvlist_free(tlvlist);
@@ -1453,3 +1697,33 @@ locate_modfirst(OscarData *od, aim_modul
return 0;
}
+
+guint32
+aim_get_custom_icons_count()
+{
+ return AIM_CUSTOM_ICONS_COUNT;
+}
+
+char*
+aim_get_custom_icon_filename(gint32 no)
+{
+ if (no >= AIM_CUSTOM_ICONS_COUNT || no < 1)
+ return NULL;
+ return aim_custom_icons[no].filename;
+}
+
+char*
+aim_get_custom_icon_descriptivename(gint32 no)
+{
+ if (no >= AIM_CUSTOM_ICONS_COUNT || no < 1)
+ return NULL;
+ return aim_custom_icons[no].descriptivename;
+}
+
+guint8*
+aim_get_custom_icon_data(gint32 no)
+{
+ if (no >= AIM_CUSTOM_ICONS_COUNT || no < 1)
+ return NULL;
+ return (guint8 *)aim_custom_icons[no].data;
+}
============================================================
--- libpurple/protocols/oscar/oscar.c b85a13700ff626e2ccbc8e65173ed1666bc8977d
+++ libpurple/protocols/oscar/oscar.c 8055b0c7e2ab435b1ca7019ce012b3d55743a758
@@ -59,6 +59,11 @@
#define OSCAR_STATUS_ID_NA "na"
#define OSCAR_STATUS_ID_OCCUPIED "occupied"
#define OSCAR_STATUS_ID_FREE4CHAT "free4chat"
+#define OSCAR_STATUS_ID_EVIL "evil"
+#define OSCAR_STATUS_ID_DEPRESSION "depression"
+#define OSCAR_STATUS_ID_ATHOME "athome"
+#define OSCAR_STATUS_ID_ATWORK "atwork"
+#define OSCAR_STATUS_ID_LUNCH "lunch"
#define OSCAR_STATUS_ID_CUSTOM "custom"
#define OSCAR_STATUS_ID_MOBILE "mobile"
@@ -68,7 +73,7 @@ static OscarCapability purple_caps = (OS
static OscarCapability purple_caps = (OSCAR_CAPABILITY_CHAT | OSCAR_CAPABILITY_BUDDYICON | OSCAR_CAPABILITY_DIRECTIM |
OSCAR_CAPABILITY_SENDFILE | OSCAR_CAPABILITY_UNICODE | OSCAR_CAPABILITY_INTEROPERATE |
- OSCAR_CAPABILITY_SHORTCAPS);
+ OSCAR_CAPABILITY_SHORTCAPS | OSCAR_CAPABILITY_ICQSERVERRELAY | OSCAR_CAPABILITY_NEWCAPS | OSCAR_CAPABILITY_XTRAZ);
static guint8 features_aim[] = {0x01, 0x01, 0x01, 0x02};
static guint8 features_icq[] = {0x01, 0x06};
@@ -670,6 +675,9 @@ static gchar *oscar_caps_to_string(Oscar
case OSCAR_CAPABILITY_GAMES:
case OSCAR_CAPABILITY_GAMES2:
tmp = _("Games");
+ case OSCAR_CAPABILITY_XTRAZ:
+ case OSCAR_CAPABILITY_NEWCAPS:
+ tmp = _("ICQ Xtraz");
break;
case OSCAR_CAPABILITY_ADDINS:
tmp = _("Add-Ins");
@@ -750,9 +758,17 @@ static char *oscar_icqstatus(int state)
return g_strdup_printf(_("Away"));
else if (state & AIM_ICQ_STATE_WEBAWARE)
return g_strdup_printf(_("Web Aware"));
- else if (state & AIM_ICQ_STATE_INVISIBLE)
- return g_strdup_printf(_("Invisible"));
- else
+ else if (state & AIM_ICQ_STATE_EVIL)
+ return g_strdup_printf(_("Evil"));
+ else if (state & AIM_ICQ_STATE_DEPRESSION)
+ return g_strdup_printf(_("Depression"));
+ else if (state & AIM_ICQ_STATE_ATHOME)
+ return g_strdup_printf(_("At home"));
+ else if (state & AIM_ICQ_STATE_ATWORK)
+ return g_strdup_printf(_("At work"));
+ else if (state & AIM_ICQ_STATE_LUNCH)
+ return g_strdup_printf(_("At lunch"));
+ else
return g_strdup_printf(_("Online"));
}
@@ -1992,6 +2008,16 @@ static int purple_parse_oncoming(OscarDa
status_id = OSCAR_STATUS_ID_AWAY;
else if (type & AIM_ICQ_STATE_INVISIBLE)
status_id = OSCAR_STATUS_ID_INVISIBLE;
+ else if (type & AIM_ICQ_STATE_EVIL)
+ status_id = OSCAR_STATUS_ID_EVIL;
+ else if (type & AIM_ICQ_STATE_DEPRESSION)
+ status_id = OSCAR_STATUS_ID_DEPRESSION;
+ else if (type & AIM_ICQ_STATE_ATHOME)
+ status_id = OSCAR_STATUS_ID_ATHOME;
+ else if (type & AIM_ICQ_STATE_ATWORK)
+ status_id = OSCAR_STATUS_ID_ATWORK;
+ else if (type & AIM_ICQ_STATE_LUNCH)
+ status_id = OSCAR_STATUS_ID_LUNCH;
else
status_id = OSCAR_STATUS_ID_AVAILABLE;
} else {
@@ -2308,7 +2334,9 @@ incomingim_chan2(OscarData *od, FlapConn
{
PurpleConnection *gc;
PurpleAccount *account;
+ PurpleMessageFlags flags = 0;
char *message = NULL;
+ char *rtfmsg = NULL;
g_return_val_if_fail(od != NULL, 0);
g_return_val_if_fail(od->gc != NULL, 0);
@@ -2338,6 +2366,21 @@ incomingim_chan2(OscarData *od, FlapConn
}
}
+
+ if (args->info.rtfmsg.rtfmsg != NULL)
+ {
+ if (args->encoding != NULL)
+ {
+ char *encoding = NULL;
+ encoding = oscar_encoding_extract(args->encoding);
+ rtfmsg = oscar_encoding_to_utf8(account, encoding, args->info.rtfmsg.rtfmsg,
+ strlen(args->info.rtfmsg.rtfmsg));
+ g_free(encoding);
+ } else {
+ if (g_utf8_validate(args->info.rtfmsg.rtfmsg, strlen(args->info.rtfmsg.rtfmsg), NULL))
+ rtfmsg = g_strdup(args->info.rtfmsg.rtfmsg);
+ }
+ }
if (args->type & OSCAR_CAPABILITY_CHAT)
{
char *encoding, *utf8name, *tmp;
@@ -2425,6 +2468,21 @@ incomingim_chan2(OscarData *od, FlapConn
{
purple_debug_error("oscar", "Got an ICQ Server Relay message of "
"type %d\n", args->info.rtfmsg.msgtype);
+ purple_debug_error("oscar", "Sending X-Status Reply\n");
+
+ if(args->info.rtfmsg.msgtype == 26)
+ icq_relay_xstatus(od, userinfo->sn, args->cookie);
+
+ if(args->info.rtfmsg.msgtype == 1)
+ {
+ if(rtfmsg)
+ serv_got_im(gc, userinfo->sn, rtfmsg, flags,
+ time(NULL));
+ else
+ serv_got_im(gc, userinfo->sn, args->info.rtfmsg.rtfmsg, flags,
+ time(NULL));
+
+ }
}
else
@@ -2828,7 +2886,6 @@ static int purple_parse_incoming_im(Osca
args = va_arg(ap, struct aim_incomingim_ch4_args *);
ret = incomingim_chan4(od, conn, userinfo, args, 0);
} break;
-
default: {
purple_debug_warning("oscar",
"ICBM received on unsupported channel (channel "
@@ -2976,6 +3033,28 @@ static int purple_parse_clientauto_ch4(O
} break;
+ case 0x0006: { /* Reply from an ICQ status message request */
+ char *statusmsg, **splitmsg;
+ PurpleNotifyUserInfo *user_info;
+
+ /* Split at (carriage return/newline)'s, then rejoin later with BRs between. */
+ statusmsg = oscar_icqstatus(state);
+ splitmsg = g_strsplit(msg, "\r\n", 0);
+
+ user_info = purple_notify_user_info_new();
+
+ purple_notify_user_info_add_pair(user_info, _("UIN"), who);
+ purple_notify_user_info_add_pair(user_info, _("Status"), statusmsg);
+ purple_notify_user_info_add_section_break(user_info);
+ purple_notify_user_info_add_pair(user_info, NULL, g_strjoinv("<BR>", splitmsg));
+
+ g_free(statusmsg);
+ g_strfreev(splitmsg);
+
+ purple_notify_userinfo(gc, who, user_info, NULL, NULL);
+ purple_notify_user_info_destroy(user_info);
+
+ } break;
default: {
purple_debug_warning("oscar",
"Received an unknown client auto-response from %s. "
@@ -4629,10 +4708,22 @@ oscar_set_extendedstatus(PurpleConnectio
data |= AIM_ICQ_STATE_CHAT;
else if (!strcmp(status_id, OSCAR_STATUS_ID_INVISIBLE))
data |= AIM_ICQ_STATE_INVISIBLE;
+ else if (!strcmp(status_id, OSCAR_STATUS_ID_EVIL))
+ data |= AIM_ICQ_STATE_EVIL;
+ else if (!strcmp(status_id, OSCAR_STATUS_ID_DEPRESSION))
+ data |= AIM_ICQ_STATE_DEPRESSION;
+ else if (!strcmp(status_id, OSCAR_STATUS_ID_ATWORK))
+ data |= AIM_ICQ_STATE_ATWORK;
+ else if (!strcmp(status_id, OSCAR_STATUS_ID_ATHOME))
+ data |= AIM_ICQ_STATE_ATHOME;
+ else if (!strcmp(status_id, OSCAR_STATUS_ID_LUNCH))
+ data |= AIM_ICQ_STATE_LUNCH;
else if (!strcmp(status_id, OSCAR_STATUS_ID_CUSTOM))
data |= AIM_ICQ_STATE_OUT | AIM_ICQ_STATE_AWAY;
+
aim_srv_setextrainfo(od, TRUE, data, FALSE, NULL, NULL);
+
}
static void
@@ -5777,6 +5868,7 @@ const char *oscar_list_emblem(PurpleBudd
return "secure";
if (userinfo->icqinfo.status & AIM_ICQ_STATE_BIRTHDAY)
return "birthday";
+ return aim_get_custom_icon_filename(userinfo->customicon);
}
return NULL;
}
@@ -5998,11 +6090,55 @@ oscar_status_types(PurpleAccount *accoun
purple_value_new(PURPLE_TYPE_STRING), NULL);
status_types = g_list_prepend(status_types, type);
- type = purple_status_type_new_full(PURPLE_STATUS_AVAILABLE,
+ type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE,
OSCAR_STATUS_ID_FREE4CHAT,
- _("Free For Chat"), TRUE, is_icq, FALSE);
+ _("Free For Chat"), TRUE, is_icq, FALSE,
+ "message", _("Message"),
+ purple_value_new(PURPLE_TYPE_STRING), NULL);
+
status_types = g_list_prepend(status_types, type);
+
+ type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE,
+ OSCAR_STATUS_ID_EVIL,
+ _("Evil"), TRUE, is_icq, FALSE,
+ "message", _("Message"),
+ purple_value_new(PURPLE_TYPE_STRING), NULL);
+ status_types = g_list_prepend(status_types, type);
+
+ type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE,
+ OSCAR_STATUS_ID_DEPRESSION,
+ _("Depression"), TRUE, is_icq, FALSE,
+ "message", _("Message"),
+ purple_value_new(PURPLE_TYPE_STRING), NULL);
+ status_types = g_list_prepend(status_types, type);
+
+
+ type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE,
+ OSCAR_STATUS_ID_ATHOME,
+ _("At home"), TRUE, is_icq, FALSE,
+ "message", _("Message"),
+ purple_value_new(PURPLE_TYPE_STRING), NULL);
+ status_types = g_list_prepend(status_types, type);
+
+
+ type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE,
+ OSCAR_STATUS_ID_ATWORK,
+ _("At work"), TRUE, is_icq, FALSE,
+ "message", _("Message"),
+ purple_value_new(PURPLE_TYPE_STRING), NULL);
+
+ status_types = g_list_prepend(status_types, type);
+
+
+ type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE,
+ OSCAR_STATUS_ID_LUNCH,
+ _("Lunch"), TRUE, is_icq, FALSE,
+ "message", _("Message"),
+ purple_value_new(PURPLE_TYPE_STRING), NULL);
+
+ status_types = g_list_prepend(status_types, type);
+
type = purple_status_type_new_with_attrs(PURPLE_STATUS_AWAY,
OSCAR_STATUS_ID_AWAY,
NULL, TRUE, TRUE, FALSE,
@@ -6010,9 +6146,12 @@ oscar_status_types(PurpleAccount *accoun
purple_value_new(PURPLE_TYPE_STRING), NULL);
status_types = g_list_prepend(status_types, type);
- type = purple_status_type_new_full(PURPLE_STATUS_INVISIBLE,
+ type = purple_status_type_new_with_attrs(PURPLE_STATUS_INVISIBLE,
OSCAR_STATUS_ID_INVISIBLE,
- NULL, TRUE, TRUE, FALSE);
+ NULL, TRUE, TRUE, FALSE,
+ "message", _("Message"),
+ purple_value_new(PURPLE_TYPE_STRING), NULL);
+
status_types = g_list_prepend(status_types, type);
type = purple_status_type_new_full(PURPLE_STATUS_MOBILE, OSCAR_STATUS_ID_MOBILE, NULL, FALSE, FALSE, TRUE);
@@ -6180,6 +6319,23 @@ oscar_get_aim_info_cb(PurpleBlistNode *n
aim_locate_getinfoshort(gc->proto_data, purple_buddy_get_name(buddy), 0x00000003);
}
+static void oscar_get_icqxstatusmsg (PurpleBlistNode *node, gpointer ignore)
+{
+ PurpleBuddy *buddy;
+ PurpleConnection *gc;
+ PurpleAccount *account;
+
+
+ g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
+
+ buddy = (PurpleBuddy *)node;
+ gc = purple_account_get_connection(buddy->account);
+ account = purple_connection_get_account(gc);
+ purple_debug_info("oscar", "Manual X-Status Get From %s to %s:\n", purple_buddy_get_name(buddy), account->username);
+
+ icq_im_xstatus_request(gc->proto_data, purple_buddy_get_name(buddy));
+}
+
static GList *
oscar_buddy_menu(PurpleBuddy *buddy) {
@@ -6207,15 +6363,14 @@ oscar_buddy_menu(PurpleBuddy *buddy) {
NULL, NULL);
menu = g_list_prepend(menu, act);
-#if 0
if (od->icq)
{
- act = purple_menu_action_new(_("Get Status Msg"),
- PURPLE_CALLBACK(oscar_get_icqstatusmsg),
+ act = purple_menu_action_new(_("Get X-Status Msg"),
+ PURPLE_CALLBACK(oscar_get_icqxstatusmsg),
NULL, NULL);
menu = g_list_prepend(menu, act);
}
-#endif
+
if (userinfo &&
aim_sncmp(purple_account_get_username(buddy->account), buddy->name) &&
@@ -6599,6 +6754,79 @@ oscar_send_file(PurpleConnection *gc, co
purple_xfer_request(xfer);
}
+static void
+oscar_show_icq_custom_icons_cb(PurpleConnection *gc, PurpleRequestFields *fields) {
+ OscarData *od = gc->proto_data;
+ PurpleAccount *account = purple_connection_get_account(gc);
+ PurpleRequestField *f;
+ GList *l;
+
+ f = purple_request_fields_get_field(fields, "customicon");
+ l = purple_request_field_list_get_selected(f);
+
+ if (l) {
+ gpointer d = purple_request_field_list_get_data(f, l->data);
+ purple_account_set_int(account, "customicon", GPOINTER_TO_INT(d));
+ }
+
+ aim_locate_setcaps(od, purple_caps);
+}
+
+static void
+oscar_show_icq_custom_icons(PurplePluginAction *action)
+{
+ guint32 i;
+ gint32 customicon;
+ PurpleConnection *gc = (PurpleConnection *) action->context;
+ PurpleAccount *account = purple_connection_get_account(gc);
+ PurpleRequestFields *fields;
+ PurpleRequestFieldGroup *g;
+ PurpleRequestField *f;
+ char* na_fn;
+
+ customicon = purple_account_get_int(account, "customicon", 0);
+
+ fields = purple_request_fields_new();
+
+ g = purple_request_field_group_new(NULL);
+
+ f = purple_request_field_list_new("customicon", _("XStatus"));
+
+ purple_request_field_list_set_pixbuf(f, TRUE);
+
+ na_fn = g_build_filename("pixmaps", "pidgin", "emblems", "16", "not-authorized.png", NULL);
+
+ purple_request_field_list_add_icon(f, _("None"), na_fn, GINT_TO_POINTER(-1));
+ if (customicon == 0)
+ purple_request_field_list_add_selected(f, _("None"));
+
+ g_free(na_fn);
+
+ for (i = 1; i < aim_get_custom_icons_count(); i++) {
+ char* icon_path = g_strdup_printf("%s.png", aim_get_custom_icon_filename(i));
+ char* filename = g_build_filename("pixmaps", "pidgin", "emblems", "16", icon_path, NULL);
+
+ purple_request_field_list_add_icon(f, _(aim_get_custom_icon_descriptivename(i)), filename, GINT_TO_POINTER(i));
+
+ if (customicon == i)
+ purple_request_field_list_add_selected(f, _(aim_get_custom_icon_descriptivename(i)));
+
+ g_free(filename);
+ g_free(icon_path);
+ }
+ purple_request_field_group_add_field(g, f);
+
+ purple_request_fields_add_group(fields, g);
+
+ purple_request_fields(gc, _("Set Custom Icon"), _("Set Custom Icon"),
+ NULL, fields,
+ _("OK"), G_CALLBACK(oscar_show_icq_custom_icons_cb),
+ _("Cancel"), NULL,
+ purple_connection_get_account(gc), NULL, NULL,
+ gc);
+}
+
+
GList *
oscar_actions(PurplePlugin *plugin, gpointer context)
{
@@ -6641,6 +6869,10 @@ oscar_actions(PurplePlugin *plugin, gpoi
act = purple_plugin_action_new(_("Set Privacy Options..."),
oscar_show_icq_privacy_opts);
menu = g_list_prepend(menu, act);
+
+ act = purple_plugin_action_new(_("Set Custom Icon..."),
+ oscar_show_icq_custom_icons);
+ menu = g_list_prepend(menu, act);
}
else
{
============================================================
--- libpurple/protocols/oscar/oscar.h 0b3efb1e5875bcfb27daa458b8e7f020a6556c36
+++ libpurple/protocols/oscar/oscar.h bc6b717b2456bbc92e8b3465481aff72751762da
@@ -362,8 +362,10 @@ typedef enum
OSCAR_CAPABILITY_LIVEVIDEO = 0x02000000,
OSCAR_CAPABILITY_CAMERA = 0x04000000,
OSCAR_CAPABILITY_ICHAT_SCREENSHARE = 0x08000000,
- OSCAR_CAPABILITY_GENERICUNKNOWN = 0x10000000,
- OSCAR_CAPABILITY_LAST = 0x20000000
+ OSCAR_CAPABILITY_NEWCAPS = 0x10000000,
+ OSCAR_CAPABILITY_XTRAZ = 0x20000000,
+ OSCAR_CAPABILITY_GENERICUNKNOWN = 0x40000000,
+ OSCAR_CAPABILITY_LAST = 0x80000000
} OscarCapability;
/*
@@ -557,6 +559,12 @@ struct _OscarData
#define AIM_ICQ_STATE_OUT 0x00000004
#define AIM_ICQ_STATE_BUSY 0x00000010
#define AIM_ICQ_STATE_CHAT 0x00000020
+#define AIM_ICQ_STATE_EVIL 0x00003000
+#define AIM_ICQ_STATE_DEPRESSION 0x00004000
+#define AIM_ICQ_STATE_ATHOME 0x00005000
+#define AIM_ICQ_STATE_ATWORK 0x00006000
+#define AIM_ICQ_STATE_LUNCH 0x00002001
+#define AIM_ICQ_STATE_EVIL 0x00003000
#define AIM_ICQ_STATE_INVISIBLE 0x00000100
#define AIM_ICQ_STATE_WEBAWARE 0x00010000
#define AIM_ICQ_STATE_HIDEIP 0x00020000
@@ -966,6 +974,7 @@ struct aim_incomingim_ch4_args
/* 0x000b */ int aim_im_denytransfer(OscarData *od, const char *sn, const guchar *cookie, guint16 code);
/* 0x0010 */ int aim_im_reqofflinemsgs(OscarData *od);
/* 0x0014 */ int aim_im_sendmtn(OscarData *od, guint16 type1, const char *sn, guint16 type2);
+/* 0x000b */ int icq_relay_xstatus (OscarData *od, const char *sn, const guchar* cookie);
void aim_icbm_makecookie(guchar* cookie);
gchar *oscar_encoding_extract(const char *encoding);
gchar *oscar_encoding_to_utf8(PurpleAccount *account, const char *encoding, const char *text, int textlen);
@@ -1019,6 +1028,7 @@ typedef struct aim_userinfo_s
guint32 onlinesince; /* time_t */
guint32 sessionlen; /* in seconds */
guint32 capabilities;
+ gint32 customicon;
struct {
guint32 status;
guint32 ipaddr;
@@ -1097,9 +1107,13 @@ int aim_putuserinfo(ByteStream *bs, aim_
void aim_info_free(aim_userinfo_t *);
int aim_info_extract(OscarData *od, ByteStream *bs, aim_userinfo_t *);
int aim_putuserinfo(ByteStream *bs, aim_userinfo_t *info);
+gint32 aim_get_custom_icon(OscarData *od, ByteStream *bs, int len);
+guint32 aim_get_custom_icons_count(void);
+char* aim_get_custom_icon_filename(gint32 no);
+char* aim_get_custom_icon_descriptivename(gint32 no);
+guint8* aim_get_custom_icon_data(gint32 no);
+int icq_im_xstatus_request(OscarData *od, const char *sn);
-
-
/* 0x0003 - family_buddy.c */
/* 0x0002 */ void aim_buddylist_reqrights(OscarData *, FlapConnection *);
/* 0x0004 */ int aim_buddylist_set(OscarData *, FlapConnection *, const char *);
@@ -1428,7 +1442,7 @@ int aim_tlvlist_add_str(GSList **list, c
int aim_tlvlist_add_16(GSList **list, const guint16 type, const guint16 value);
int aim_tlvlist_add_32(GSList **list, const guint16 type, const guint32 value);
int aim_tlvlist_add_str(GSList **list, const guint16 type, const char *value);
-int aim_tlvlist_add_caps(GSList **list, const guint16 type, const guint32 caps);
+int aim_tlvlist_add_caps(GSList **list, const guint16 type, const guint32 caps, gint32 customicon);
int aim_tlvlist_add_userinfo(GSList **list, guint16 type, aim_userinfo_t *userinfo);
int aim_tlvlist_add_chatroom(GSList **list, guint16 type, guint16 exchange, const char *roomname, guint16 instance);
int aim_tlvlist_add_frozentlvlist(GSList **list, guint16 type, GSList **tl);
============================================================
--- libpurple/protocols/oscar/tlv.c 1f8884b597b2eb9424be5ea9058bdebaa7923e8c
+++ libpurple/protocols/oscar/tlv.c 238cf3fe0378d9523f4263fe92a77e33f44419e8
@@ -407,10 +407,11 @@ int aim_tlvlist_add_str(GSList **list, c
* @param caps Bitfield of capability flags to send
* @return The size of the value added.
*/
-int aim_tlvlist_add_caps(GSList **list, const guint16 type, const guint32 caps)
+int aim_tlvlist_add_caps(GSList **list, const guint16 type, const guint32 caps, const gint32 customicon)
{
guint8 buf[256]; /* TODO: Don't use a fixed length buffer */
ByteStream bs;
+ guint8 *data;
if (caps == 0)
return 0; /* nothing there anyway */
@@ -418,6 +419,12 @@ int aim_tlvlist_add_caps(GSList **list,
byte_stream_init(&bs, buf, sizeof(buf));
byte_stream_putcaps(&bs, caps);
+
+ /* adding of custom icon GUID */
+ data = aim_get_custom_icon_data(customicon);
+ if (data != NULL) {
+ byte_stream_putraw(&bs, data, 16);
+ }
return aim_tlvlist_add_raw(list, type, byte_stream_curpos(&bs), buf);
}
============================================================
--- libpurple/request.c e86343376dc7ccb6922a25824ebdf02897f82bde
+++ libpurple/request.c 34e899aaec6dc8c20090afc86fcdbd68237c4090
@@ -790,6 +790,25 @@ void
}
void
+purple_request_field_list_set_pixbuf(PurpleRequestField *field,
+ gboolean pixbuf)
+{
+ g_return_if_fail(field != NULL);
+ g_return_if_fail(field->type == PURPLE_REQUEST_FIELD_LIST);
+
+ field->u.list.pixbuf = pixbuf;
+}
+
+gboolean
+purple_request_field_list_get_pixbuf(const PurpleRequestField *field)
+{
+ g_return_val_if_fail(field != NULL, FALSE);
+ g_return_val_if_fail(field->type == PURPLE_REQUEST_FIELD_LIST, FALSE);
+
+ return field->u.list.pixbuf;
+}
+
+void
purple_request_field_list_set_multi_select(PurpleRequestField *field,
gboolean multi_select)
{
@@ -834,6 +853,22 @@ void
}
void
+purple_request_field_list_add_icon(PurpleRequestField *field, const char *item, const char* icon_path,
+ void *data)
+{
+ g_return_if_fail(field != NULL);
+ g_return_if_fail(item != NULL);
+ g_return_if_fail(data != NULL);
+ g_return_if_fail(icon_path != NULL);
+ g_return_if_fail(field->type == PURPLE_REQUEST_FIELD_LIST);
+
+ field->u.list.items = g_list_append(field->u.list.items, g_strdup(item));
+ field->u.list.icons = g_list_append(field->u.list.icons, g_strdup(icon_path));
+
+ g_hash_table_insert(field->u.list.item_data, g_strdup(item), data);
+}
+
+void
purple_request_field_list_add_selected(PurpleRequestField *field, const char *item)
{
g_return_if_fail(field != NULL);
@@ -935,6 +970,16 @@ purple_request_field_list_get_items(cons
return field->u.list.items;
}
+GList *
+purple_request_field_list_get_icons(const PurpleRequestField *field)
+{
+ g_return_val_if_fail(field != NULL, NULL);
+ g_return_val_if_fail(field->type == PURPLE_REQUEST_FIELD_LIST, NULL);
+ g_return_val_if_fail(field->u.list.pixbuf == TRUE, NULL);
+
+ return field->u.list.icons;
+}
+
PurpleRequestField *
purple_request_field_label_new(const char *id, const char *text)
{
============================================================
--- libpurple/request.h dba31fd34a54648e6140e75fe3f847f6d30f7d4b
+++ libpurple/request.h a7e32128bc8e770fa57ccc1a254406b6e9fc8fa6
@@ -147,10 +147,12 @@ typedef struct
{
GList *items;
GHashTable *item_data;
+ GList *icons;
GList *selected;
GHashTable *selected_table;
gboolean multiple_selection;
+ gboolean pixbuf;
} list;
@@ -877,6 +879,26 @@ PurpleRequestField *purple_request_field
PurpleRequestField *purple_request_field_list_new(const char *id, const char *text);
/**
+ * Sets whether or not a list field allows icons.
+ *
+ * @param field The list field.
+ * @param multi_select TRUE if icons are enabled,
+ * or FALSE otherwise.
+ */
+void purple_request_field_list_set_pixbuf(PurpleRequestField *field,
+ gboolean pixbuf);
+
+/**
+ * Returns whether or not a list field allows icons.
+ *
+ * @param field The list field.
+ *
+ * @return TRUE if icons are enabled, or FALSE otherwise.
+ */
+gboolean purple_request_field_list_get_pixbuf(
+ const PurpleRequestField *field);
+
+/**
* Sets whether or not a list field allows multiple selection.
*
* @param field The list field.
@@ -918,6 +940,17 @@ void purple_request_field_list_add(Purpl
const char *item, void *data);
/**
+ * Adds an item with icon to a list field.
+ *
+ * @param field The list field.
+ * @param item The list item.
+ * @param icon_path The path to icon file.
+ * @param data The associated data.
+ */
+void purple_request_field_list_add_icon(PurpleRequestField *field,
+ const char *item, const char* icon_path, void* data);
+
+/**
* Adds a selected item to the list field.
*
* @param field The field.
@@ -975,6 +1008,15 @@ GList *purple_request_field_list_get_ite
*/
GList *purple_request_field_list_get_items(const PurpleRequestField *field);
+/**
+ * Returns a list of icons in a list field.
+ *
+ * @param field The field.
+ *
+ * @constreturn The list of icons.
+ */
+GList *purple_request_field_list_get_icons(const PurpleRequestField *field);
+
/*@}*/
/**************************************************************************/
============================================================
--- pidgin/gtkrequest.c 1042456ad81552b5eca35413c526a8136185cb9f
+++ pidgin/gtkrequest.c 74416ba6c32104cc1079d2dc1b03af0d5a5e2ce4
@@ -995,7 +995,9 @@ create_list_field(PurpleRequestField *fi
GtkTreeSelection *sel;
GtkTreeViewColumn *column;
GtkTreeIter iter;
- GList *l;
+ GList *l, *ic = NULL;
+ GdkPixbuf* pixbuf;
+ gboolean icon = purple_request_field_list_get_pixbuf(field);
/* Create the scrolled window */
sw = gtk_scrolled_window_new(NULL, NULL);
@@ -1007,7 +1009,10 @@ create_list_field(PurpleRequestField *fi
gtk_widget_show(sw);
/* Create the list store */
- store = gtk_list_store_new(2, G_TYPE_POINTER, G_TYPE_STRING);
+ if (icon)
+ store = gtk_list_store_new(3, G_TYPE_POINTER, G_TYPE_STRING, GDK_TYPE_PIXBUF);
+ else
+ store = gtk_list_store_new(2, G_TYPE_POINTER, G_TYPE_STRING);
/* Create the tree view */
treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
@@ -1026,16 +1031,45 @@ create_list_field(PurpleRequestField *fi
gtk_tree_view_column_pack_start(column, renderer, TRUE);
gtk_tree_view_column_add_attribute(column, renderer, "text", 1);
+ if(icon == TRUE)
+ {
+ renderer = gtk_cell_renderer_pixbuf_new();
+ gtk_tree_view_column_pack_start(column, renderer, TRUE);
+ gtk_tree_view_column_add_attribute(column, renderer, "pixbuf", 2);
+
+ gtk_widget_set_size_request(treeview, 200, 400);
+ }
+
+ if(icon == TRUE)
+ ic = purple_request_field_list_get_icons(field);
+
for (l = purple_request_field_list_get_items(field); l != NULL; l = l->next)
{
const char *text = (const char *)l->data;
gtk_list_store_append(store, &iter);
- gtk_list_store_set(store, &iter,
+ if(icon == TRUE)
+ {
+ const char *icon_path = (const char *)ic->data;
+ char* filename = g_build_filename(DATADIR, icon_path, NULL);
+
+ pixbuf = gdk_pixbuf_new_from_file(filename, NULL);
+
+ g_free(filename);
+
+ gtk_list_store_set(store, &iter,
0, purple_request_field_list_get_data(field, text),
1, text,
+ 2, pixbuf,
-1);
+ ic = ic->next;
+ }
+ else
+ gtk_list_store_set(store, &iter,
+ 0, purple_request_field_list_get_data(field, text),
+ 1, text,
+ -1);
if (purple_request_field_list_is_selected(field, text))
gtk_tree_selection_select_iter(sel, &iter);
============================================================
--- pidgin/pixmaps/Makefile.am afe4586dfd4d2049b0545009555652cde33d3e00
+++ pidgin/pixmaps/Makefile.am fb755e735b8816f787ad3080ed3eb3ef8b82e212
@@ -126,8 +126,43 @@ EMBLEMS_16 = \
emblems/16/secure.png \
emblems/16/unavailable.png \
emblems/16/video.png \
- emblems/16/voice.png
+ emblems/16/voice.png \
+ emblems/16/xstatus_angry.png \
+ emblems/16/xstatus_bathing.png \
+ emblems/16/xstatus_beer.png \
+ emblems/16/xstatus_busy.png \
+ emblems/16/xstatus_cinema.png \
+ emblems/16/xstatus_coffee.png \
+ emblems/16/xstatus_crap.png \
+ emblems/16/xstatus_crapping.png \
+ emblems/16/xstatus_eating.png \
+ emblems/16/xstatus_engineering.png \
+ emblems/16/xstatus_friends.png \
+ emblems/16/xstatus_fun.png \
+ emblems/16/xstatus_gaming.png \
+ emblems/16/xstatus_google.png \
+ emblems/16/xstatus_heart.png \
+ emblems/16/xstatus_internet.png \
+ emblems/16/xstatus_iron.png \
+ emblems/16/xstatus_mobile.png \
+ emblems/16/xstatus_music.png \
+ emblems/16/xstatus_party.png \
+ emblems/16/xstatus_pda.png \
+ emblems/16/xstatus_phone.png \
+ emblems/16/xstatus_question.png \
+ emblems/16/xstatus_shopping.png \
+ emblems/16/xstatus_sick.png \
+ emblems/16/xstatus_sleeping.png \
+ emblems/16/xstatus_studying.png \
+ emblems/16/xstatus_surfing.png \
+ emblems/16/xstatus_thinking.png \
+ emblems/16/xstatus_tired.png \
+ emblems/16/xstatus_tv.png \
+ emblems/16/xstatus_typing.png \
+ emblems/16/xstatus_writing.png \
+ emblems/16/xstatus_zzz.png
+
EMOTES_DEFAULT_24_SCALABLE = \
emotes/default/24/scalable/airplane.svg \
emotes/default/24/scalable/bad.svg \
More information about the Commits
mailing list