Mercurial > pidgin
changeset 29454:f3b62076fa32
propagate from branch 'im.pidgin.pidgin' (head 3466628f7bdaf9db0a64c730ef9376b3ef78cc1d)
to branch 'im.pidgin.cpw.rekkanoryo.icqxstatus' (head a57df8a0eaa7ce8f5dca4d59d618a06fc0d407f2)
author | Richard Laager <rlaager@wiktel.com> |
---|---|
date | Wed, 26 Nov 2008 22:18:16 +0000 |
parents | ad6d8e627444 (current diff) 05c84351338b (diff) |
children | 93cb9f54df45 |
files | pidgin/pixmaps/emblems/16/mobile.png pidgin/pixmaps/emotes/default/24/eat.png pidgin/pixmaps/emotes/default/24/in-love.png pidgin/pixmaps/emotes/default/24/love.png pidgin/pixmaps/emotes/default/24/nailbiting.png pidgin/pixmaps/emotes/default/24/shock.png pidgin/pixmaps/emotes/default/24/smile-big.png pidgin/pixmaps/emotes/default/24/smile.png pidgin/pixmaps/emotes/default/24/sweat.png pidgin/pixmaps/emotes/default/24/tremble.png pidgin/pixmaps/emotes/default/24/yawn.png pidgin/pixmaps/emotes/small/16/love.png pidgin/pixmaps/emotes/small/16/shock.png pidgin/pixmaps/emotes/small/16/smile-big.png pidgin/pixmaps/emotes/small/16/smile.png pidgin/pixmaps/emotes/small/16/yawn.png |
diffstat | 94 files changed, 1599 insertions(+), 269 deletions(-) [+] |
line wrap: on
line diff
--- a/.mtn-ignore Wed Nov 26 22:17:58 2008 +0000 +++ b/.mtn-ignore Wed Nov 26 22:18:16 2008 +0000 @@ -37,6 +37,41 @@ pidgin-.*.tar.bz2 pidgin-*.*.*-win32bin$ pidgin/pidgin$ +pidgin/pixmaps/emblems/16/afraid.png +pidgin/pixmaps/emblems/16/amorous.png +pidgin/pixmaps/emblems/16/angry.png +pidgin/pixmaps/emblems/16/beer.png +pidgin/pixmaps/emblems/16/busy.png +pidgin/pixmaps/emblems/16/cigarette.png +pidgin/pixmaps/emblems/16/coffee.png +pidgin/pixmaps/emblems/16/confused.png +pidgin/pixmaps/emblems/16/console.png +pidgin/pixmaps/emblems/16/disappointed.png +pidgin/pixmaps/emblems/16/embarrassed.png +pidgin/pixmaps/emblems/16/excited.png +pidgin/pixmaps/emblems/16/happy.png +pidgin/pixmaps/emblems/16/hot.png +pidgin/pixmaps/emblems/16/hungry.png +pidgin/pixmaps/emblems/16/in_love.png +pidgin/pixmaps/emblems/16/mean.png +pidgin/pixmaps/emblems/16/meeting.png +pidgin/pixmaps/emblems/16/mobile.png +pidgin/pixmaps/emblems/16/musical-note.png +pidgin/pixmaps/emblems/16/nervous.png +pidgin/pixmaps/emblems/16/neutral.png +pidgin/pixmaps/emblems/16/party.png +pidgin/pixmaps/emblems/16/phone.png +pidgin/pixmaps/emblems/16/plate.png +pidgin/pixmaps/emblems/16/question.png +pidgin/pixmaps/emblems/16/sad.png +pidgin/pixmaps/emblems/16/sarcastic.png +pidgin/pixmaps/emblems/16/search.png +pidgin/pixmaps/emblems/16/shocked.png +pidgin/pixmaps/emblems/16/sick.png +pidgin/pixmaps/emblems/16/sleeping.png +pidgin/pixmaps/emblems/16/sleepy.png +pidgin/pixmaps/emblems/16/thinking.png +pidgin/pixmaps/emblems/16/tv.png pidgin/pixmaps/emotes/default/24/theme pidgin/pixmaps/emotes/none/theme pidgin/pixmaps/emotes/small/16/theme
--- a/COPYRIGHT Wed Nov 26 22:17:58 2008 +0000 +++ b/COPYRIGHT Wed Nov 26 22:18:16 2008 +0000 @@ -201,12 +201,14 @@ Instant Messaging Freedom, Inc. Vitaliy Ischenko Intel Corporation +Andrew Ivanov Scott Jackson Hans Petter Jansson Henry Jen Benjamin Kahn Anders Kaseorg Praveen Karadakal +Tomáš Kebert John Kelm Jochen Kemnade Akuke Kok @@ -477,6 +479,7 @@ Ma Xuan Jared Yanovich Timmy Yee +Yuriy Yevgrafov Nickolai Zeldovich Tom Zickel Marco Ziech
--- a/ChangeLog.API Wed Nov 26 22:17:58 2008 +0000 +++ b/ChangeLog.API Wed Nov 26 22:18:16 2008 +0000 @@ -1,5 +1,10 @@ Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul +version 2.6.0 (??/??/????): + libpurple: + Added: + * PURPLE_STATUS_MOOD as a new PurpleStatusPrimitive + version 2.5.0 (08/18/2008): libpurple: Added:
--- a/finch/gntplugin.c Wed Nov 26 22:17:58 2008 +0000 +++ b/finch/gntplugin.c Wed Nov 26 22:18:16 2008 +0000 @@ -496,7 +496,7 @@ break; } stringlist = g_list_prepend(stringlist, value); - purple_request_field_list_add(field, label, value); + purple_request_field_list_add_icon(field, label, NULL, value); if (strcmp(value, current_value) == 0) purple_request_field_list_add_selected(field, label); list = list->next->next;
--- a/finch/gntprefs.c Wed Nov 26 22:17:58 2008 +0000 +++ b/finch/gntprefs.c Wed Nov 26 22:18:16 2008 +0000 @@ -170,7 +170,7 @@ default: break; } - purple_request_field_list_add(field, data, iter->data); + purple_request_field_list_add_icon(field, data, NULL, iter->data); if (select) purple_request_field_list_add_selected(field, data); }
--- a/finch/plugins/gnthistory.c Wed Nov 26 22:17:58 2008 +0000 +++ b/finch/plugins/gnthistory.c Wed Nov 26 22:18:16 2008 +0000 @@ -154,7 +154,7 @@ while (list) { const char *label = _(list->data); list = g_list_delete_link(list, list); - purple_request_field_list_add(field, label, list->data); + purple_request_field_list_add_icon(field, label, NULL, list->data); if (system && strcmp(system, list->data) == 0) purple_request_field_list_add_selected(field, label); list = g_list_delete_link(list, list);
--- a/libpurple/plugins/perl/common/Request.xs Wed Nov 26 22:17:58 2008 +0000 +++ b/libpurple/plugins/perl/common/Request.xs Wed Nov 26 22:18:16 2008 +0000 @@ -374,6 +374,13 @@ void * data void +purple_request_field_list_add_icon(field, item, icon_path, data) + Purple::Request::Field field + const char *item + const char *icon_path + void * data + +void purple_request_field_list_add_selected(field, item) Purple::Request::Field field const char *item
--- a/libpurple/protocols/gg/gg.c Wed Nov 26 22:17:58 2008 +0000 +++ b/libpurple/protocols/gg/gg.c Wed Nov 26 22:18:16 2008 +0000 @@ -757,16 +757,16 @@ static void ggp_callback_add_to_chat_ok(PurpleConnection *gc, PurpleRequestFields *fields) { - GGPInfo *info = gc->proto_data; PurpleRequestField *field; - /* TODO: sel may be null. */ GList *sel; field = purple_request_fields_get_field(fields, "name"); sel = purple_request_field_list_get_selected(field); + if (sel == NULL || sel->data == NULL) + return; - ggp_confer_participants_add_uin(gc, sel->data, info->tmp_buddy); - info->tmp_buddy = 0; + ggp_confer_participants_add_uin(gc, sel->data, + GPOINTER_TO_INT(purple_request_field_list_get_data(field, sel->data))); } static void ggp_bmenu_add_to_chat(PurpleBlistNode *node, gpointer ignored) @@ -786,9 +786,6 @@ gc = purple_account_get_connection(purple_buddy_get_account(buddy)); info = gc->proto_data; - /* TODO: It tmp_buddy != 0 then stop! */ - info->tmp_buddy = ggp_str_to_uin(purple_buddy_get_name(buddy)); - fields = purple_request_fields_new(); group = purple_request_field_group_new(NULL); purple_request_fields_add_group(fields, group); @@ -796,8 +793,8 @@ field = purple_request_field_list_new("name", "Chat name"); for (l = info->chats; l != NULL; l = l->next) { GGPChat *chat = l->data; - purple_request_field_list_add(field, g_strdup(chat->name), - g_strdup(chat->name)); + purple_request_field_list_add_icon(field, chat->name, NULL, + GINT_TO_POINTER(ggp_str_to_uin(purple_buddy_get_name(buddy)))); } purple_request_field_group_add_field(group, field);
--- a/libpurple/protocols/gg/gg.h Wed Nov 26 22:17:58 2008 +0000 +++ b/libpurple/protocols/gg/gg.h Wed Nov 26 22:18:16 2008 +0000 @@ -62,7 +62,6 @@ GList *chats; GGPSearches *searches; - uin_t tmp_buddy; int chats_count; GList *pending_richtext_messages;
--- a/libpurple/protocols/jabber/jabber.c Wed Nov 26 22:17:58 2008 +0000 +++ b/libpurple/protocols/jabber/jabber.c Wed Nov 26 22:18:16 2008 +0000 @@ -1567,12 +1567,12 @@ purple_notify_user_info_add_pair(user_info, _("Subscription"), sub); - status = purple_presence_get_active_status(presence); - mood = purple_status_get_attr_string(status, "mood"); - if(mood != NULL) { + status = purple_presence_get_status(presence, "mood"); + mood = purple_status_get_attr_string(status, PURPLE_MOOD_NAME); + if(mood && *mood) { const char *moodtext; - moodtext = purple_status_get_attr_string(status, "moodtext"); - if(moodtext != NULL) { + moodtext = purple_status_get_attr_string(status, PURPLE_MOOD_COMMENT); + if(moodtext && *moodtext) { char *moodplustext = g_strdup_printf("%s (%s)", mood, moodtext); purple_notify_user_info_add_pair(user_info, _("Mood"), moodplustext); @@ -1658,7 +1658,7 @@ "nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING), "buzz", _("Allow Buzz"), purple_value_new(PURPLE_TYPE_BOOLEAN), NULL); - types = g_list_append(types, type); + types = g_list_prepend(types, type); priority_value = purple_value_new(PURPLE_TYPE_INT); purple_value_set_int(priority_value, 1); @@ -1672,7 +1672,7 @@ "nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING), "buzz", _("Allow Buzz"), purple_value_new(PURPLE_TYPE_BOOLEAN), NULL); - types = g_list_append(types, type); + types = g_list_prepend(types, type); priority_value = purple_value_new(PURPLE_TYPE_INT); purple_value_set_int(priority_value, 0); @@ -1686,7 +1686,7 @@ "nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING), "buzz", _("Allow Buzz"), purple_value_new(PURPLE_TYPE_BOOLEAN), NULL); - types = g_list_append(types, type); + types = g_list_prepend(types, type); priority_value = purple_value_new(PURPLE_TYPE_INT); purple_value_set_int(priority_value, 0); @@ -1700,7 +1700,7 @@ "nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING), "buzz", _("Allow Buzz"), purple_value_new(PURPLE_TYPE_BOOLEAN), NULL); - types = g_list_append(types, type); + types = g_list_prepend(types, type); priority_value = purple_value_new(PURPLE_TYPE_INT); purple_value_set_int(priority_value, 0); @@ -1714,11 +1714,11 @@ "nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING), "buzz", _("Allow Buzz"), purple_value_new(PURPLE_TYPE_BOOLEAN), NULL); - types = g_list_append(types, type); + types = g_list_prepend(types, type); /* if(js->protocol_version == JABBER_PROTO_0_9) - m = g_list_append(m, _("Invisible")); + "Invisible" */ type = purple_status_type_new_with_attrs(PURPLE_STATUS_OFFLINE, @@ -1726,7 +1726,7 @@ NULL, FALSE, TRUE, FALSE, "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), NULL); - types = g_list_append(types, type); + types = g_list_prepend(types, type); type = purple_status_type_new_with_attrs(PURPLE_STATUS_TUNE, "tune", NULL, FALSE, TRUE, TRUE, @@ -1740,9 +1740,9 @@ PURPLE_TUNE_YEAR, _("Tune Year"), purple_value_new(PURPLE_TYPE_INT), PURPLE_TUNE_URL, _("Tune URL"), purple_value_new(PURPLE_TYPE_STRING), NULL); - types = g_list_append(types, type); + types = g_list_prepend(types, type); - return types; + return g_list_reverse(types); } static void
--- a/libpurple/protocols/jabber/usermood.c Wed Nov 26 22:17:58 2008 +0000 +++ b/libpurple/protocols/jabber/usermood.c Wed Nov 26 22:18:16 2008 +0000 @@ -28,69 +28,93 @@ #include "request.h" #include "debug.h" -static const char * const moodstrings[] = { - "afraid", - "amazed", - "angry", - "annoyed", - "anxious", - "aroused", - "ashamed", - "bored", - "brave", - "calm", - "cold", - "confused", - "contented", - "cranky", - "curious", - "depressed", - "disappointed", - "disgusted", - "distracted", - "embarrassed", - "excited", - "flirtatious", - "frustrated", - "grumpy", - "guilty", - "happy", - "hot", - "humbled", - "humiliated", - "hungry", - "hurt", - "impressed", - "in_awe", - "in_love", - "indignant", - "interested", - "intoxicated", - "invincible", - "jealous", - "lonely", - "mean", - "moody", - "nervous", - "neutral", - "offended", - "playful", - "proud", - "relieved", - "remorseful", - "restless", - "sad", - "sarcastic", - "serious", - "shocked", - "shy", - "sick", - "sleepy", - "stressed", - "surprised", - "thirsty", - "worried", - NULL +static PurpleMood moods[] = { + {"afraid", N_("Afraid"), NULL}, + {"amazed", N_("Amazed"), NULL}, + {"amorous", N_("Amorous"), NULL}, + {"angry", N_("Angry"), NULL}, + {"annoyed", N_("Annoyed"), NULL}, + {"anxious", N_("Anxious"), NULL}, + {"aroused", N_("Aroused"), NULL}, + {"ashamed", N_("Ashamed"), NULL}, + {"bored", N_("Bored"), NULL}, + {"brave", N_("Brave"), NULL}, + {"calm", N_("Calm"), NULL}, + {"cautious", N_("Cautious"), NULL}, + {"cold", N_("Cold"), NULL}, + {"confident", N_("Confident"), NULL}, + {"confused", N_("Confused"), NULL}, + {"contemplative", N_("Contemplative"), NULL}, + {"contented", N_("Contented"), NULL}, + {"cranky", N_("Cranky"), NULL}, + {"crazy", N_("Crazy"), NULL}, + {"creative", N_("Creative"), NULL}, + {"curious", N_("Curious"), NULL}, + {"dejected", N_("Dejected"), NULL}, + {"depressed", N_("Depressed"), NULL}, + {"disappointed", N_("Disappointed"), NULL}, + {"disgusted", N_("Disgusted"), NULL}, + {"dismayed", N_("Dismayed"), NULL}, + {"distracted", N_("Distracted"), NULL}, + {"embarrassed", N_("Embarrassed"), NULL}, + {"envious", N_("Envious"), NULL}, + {"excited", N_("Excited"), NULL}, + {"flirtatious", N_("Flirtatious"), NULL}, + {"frustrated", N_("Frustrated"), NULL}, + {"grateful", N_("Grateful"), NULL}, + {"grieving", N_("Grieving"), NULL}, + {"grumpy", N_("Grumpy"), NULL}, + {"guilty", N_("Guilty"), NULL}, + {"happy", N_("Happy"), NULL}, + {"hopeful", N_("Hopeful"), NULL}, + {"hot", N_("Hot"), NULL}, + {"humbled", N_("Humbled"), NULL}, + {"humiliated", N_("Humiliated"), NULL}, + {"hungry", N_("Hungry"), NULL}, + {"hurt", N_("Hurt"), NULL}, + {"impressed", N_("Impressed"), NULL}, + {"in_awe", N_("In_awe"), NULL}, + {"in_love", N_("In_love"), NULL}, + {"indignant", N_("Indignant"), NULL}, + {"interested", N_("Interested"), NULL}, + {"intoxicated", N_("Intoxicated"), NULL}, + {"invincible", N_("Invincible"), NULL}, + {"jealous", N_("Jealous"), NULL}, + {"lonely", N_("Lonely"), NULL}, + {"lost", N_("Lost"), NULL}, + {"lucky", N_("Lucky"), NULL}, + {"mean", N_("Mean"), NULL}, + {"moody", N_("Moody"), NULL}, + {"nervous", N_("Nervous"), NULL}, + {"neutral", N_("Neutral"), NULL}, + {"offended", N_("Offended"), NULL}, + {"outraged", N_("Outraged"), NULL}, + {"playful", N_("Playful"), NULL}, + {"proud", N_("Proud"), NULL}, + {"relaxed", N_("Relaxed"), NULL}, + {"relieved", N_("Relieved"), NULL}, + {"remorseful", N_("Remorseful"), NULL}, + {"restless", N_("Restless"), NULL}, + {"sad", N_("Sad"), NULL}, + {"sarcastic", N_("Sarcastic"), NULL}, + {"satisfied", N_("Satisfied"), NULL}, + {"serious", N_("Serious"), NULL}, + {"shocked", N_("Shocked"), NULL}, + {"shy", N_("Shy"), NULL}, + {"sick", N_("Sick"), NULL}, + {"sleepy", N_("Sleepy"), NULL}, + {"spontaneous", N_("Spontaneous"), NULL}, + {"stressed", N_("Stressed"), NULL}, + {"strong", N_("Strong"), NULL}, + {"surprised", N_("Surprised"), NULL}, + {"thankful", N_("Thankful"), NULL}, + {"thirsty", N_("Thirsty"), NULL}, + {"tired", N_("Tired"), NULL}, + {"undefined", N_("Undefined"), NULL}, + {"weak", N_("Weak"), NULL}, + {"worried", N_("Worried"), NULL}, + /* Mark the last record. */ + {NULL, NULL, NULL} }; static void jabber_mood_cb(JabberStream *js, const char *from, xmlnode *items) { @@ -114,10 +138,10 @@ moodtext = xmlnode_get_data(moodinfo); } else { int i; - for (i = 0; moodstrings[i]; ++i) { + for (i = 0; moods[i].mood; ++i) { /* verify that the mood is known (valid) */ - if (!strcmp(moodinfo->name, moodstrings[i])) { - newmood = moodstrings[i]; + if (!strcmp(moodinfo->name, moods[i].mood)) { + newmood = moods[i].mood; break; } } @@ -127,15 +151,12 @@ } } if (newmood != NULL) { - const char *status_id; - JabberBuddyResource *resource = jabber_buddy_find_resource(buddy, NULL); - if(!resource) { /* huh? */ - g_free(moodtext); - return; - } - status_id = jabber_buddy_state_get_status_id(resource->state); - - purple_prpl_got_user_status(js->gc->account, from, status_id, "mood", _(newmood), "moodtext", moodtext?moodtext:"", NULL); + purple_prpl_got_user_status(js->gc->account, from, "mood", + PURPLE_MOOD_NAME, mood, + PURPLE_MOOD_COMMENT, moodtext, + NULL); + } else { + purple_prpl_got_user_status_deactive(js->gc->account, from, "mood"); } g_free(moodtext); } @@ -147,7 +168,7 @@ static void do_mood_set_from_fields(PurpleConnection *gc, PurpleRequestFields *fields) { JabberStream *js; - const int max_mood_idx = sizeof(moodstrings) / sizeof(moodstrings[0]) - 1; + const int max_mood_idx = sizeof(moods) / sizeof(moods[0]) - 1; int selected_mood = purple_request_fields_get_choice(fields, "mood"); if (!PURPLE_CONNECTION_IS_VALID(gc)) { @@ -162,7 +183,7 @@ return; } - jabber_mood_set(js, moodstrings[selected_mood], purple_request_fields_get_string(fields, "text")); + jabber_mood_set(js, moods[selected_mood].mood, purple_request_fields_get_string(fields, "text")); } static void do_mood_set_mood(PurplePluginAction *action) { @@ -180,8 +201,8 @@ field = purple_request_field_choice_new("mood", _("Mood"), 0); - for(i = 0; moodstrings[i]; ++i) - purple_request_field_choice_add(field, _(moodstrings[i])); + for(i = 0; moods[i].mood; ++i) + purple_request_field_choice_add(field, _(moods[i].description)); purple_request_field_set_required(field, TRUE); purple_request_field_group_add_field(group, field);
--- a/libpurple/protocols/jabber/xdata.c Wed Nov 26 22:17:58 2008 +0000 +++ b/libpurple/protocols/jabber/xdata.c Wed Nov 26 22:18:16 2008 +0000 @@ -302,7 +302,7 @@ data->values = g_slist_prepend(data->values, value); - purple_request_field_list_add(field, lbl, value); + purple_request_field_list_add_icon(field, lbl, NULL, value); if(g_list_find_custom(selected, value, (GCompareFunc)strcmp)) purple_request_field_list_add_selected(field, lbl); }
--- a/libpurple/protocols/oscar/family_buddy.c Wed Nov 26 22:17:58 2008 +0000 +++ b/libpurple/protocols/oscar/family_buddy.c Wed Nov 26 22:18:16 2008 +0000 @@ -224,6 +224,18 @@ 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) { + PurpleAccount *account = purple_connection_get_account(od->gc); + PurpleBuddy *buddy = purple_find_buddy(account, userinfo.sn); + + if (buddy) { + PurplePresence *presence = purple_buddy_get_presence(buddy); + + if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_MOOD)) + icq_im_xstatus_request(od, userinfo.sn); + } + } aim_info_free(&userinfo); return ret;
--- a/libpurple/protocols/oscar/family_icbm.c Wed Nov 26 22:17:58 2008 +0000 +++ b/libpurple/protocols/oscar/family_icbm.c Wed Nov 26 22:18:16 2008 +0000 @@ -2533,6 +2533,15 @@ 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 @@ 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); - - 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); + if (channel == 0x0002) { + + 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 @@ g_free(cookie); g_free(sn); + if (xml) g_free(xml); return ret; } @@ -2721,6 +2771,181 @@ } /* + * 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,
--- a/libpurple/protocols/oscar/family_locate.c Wed Nov 26 22:17:58 2008 +0000 +++ b/libpurple/protocols/oscar/family_locate.c Wed Nov 26 22:18:16 2008 +0000 @@ -166,6 +166,16 @@ {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,202 @@ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, }; +/* Keep this array synchronized with icq_purple_moods. */ +static const struct { + const char *mood; + guint8 data[16]; +} icq_custom_icons[] = { + + {"thinking", + {0x3f, 0xb0, 0xbd, 0x36, 0xaf, 0x3b, 0x4a, 0x60, + 0x9e, 0xef, 0xcf, 0x19, 0x0f, 0x6a, 0x5a, 0x7f}}, + + {"busy", + {0x48, 0x8e, 0x14, 0x89, 0x8a, 0xca, 0x4a, 0x08, + 0x82, 0xaa, 0x77, 0xce, 0x7a, 0x16, 0x52, 0x08}}, + + {"shopping", + {0x63, 0x62, 0x73, 0x37, 0xa0, 0x3f, 0x49, 0xff, + 0x80, 0xe5, 0xf7, 0x09, 0xcd, 0xe0, 0xa4, 0xee}}, + + /* This was in the original patch, but isn't what the official client + * (ICQ 6) sets when you choose its typewriter icon. */ + {"typing", + {0x63, 0x4f, 0x6b, 0xd8 ,0xad, 0xd2, 0x4a, 0xa1, + 0xaa, 0xb9, 0x11, 0x5b, 0xc2, 0x6d, 0x05, 0xa1}}, + + {"question", + {0x63, 0x14, 0x36, 0xff, 0x3f, 0x8a, 0x40, 0xd0, + 0xa5, 0xcb, 0x7b, 0x66, 0xe0, 0x51, 0xb3, 0x64}}, + + {"angry", + {0x01, 0xd8, 0xd7, 0xee, 0xac, 0x3b, 0x49, 0x2a, + 0xa5, 0x8d, 0xd3, 0xd8, 0x77, 0xe6, 0x6b, 0x92}}, + + {"plate", + {0xf8, 0xe8, 0xd7, 0xb2, 0x82, 0xc4, 0x41, 0x42, + 0x90, 0xf8, 0x10, 0xc6, 0xce, 0x0a, 0x89, 0xa6}}, + + {"cinema", + {0x10, 0x7a, 0x9a, 0x18, 0x12, 0x32, 0x4d, 0xa4, + 0xb6, 0xcd, 0x08, 0x79, 0xdb, 0x78, 0x0f, 0x09}}, + + {"sick", + {0x1f, 0x7a, 0x40, 0x71, 0xbf, 0x3b, 0x4e, 0x60, + 0xbc, 0x32, 0x4c, 0x57, 0x87, 0xb0, 0x4c, 0xf1}}, + + {"typing", + {0x2c, 0xe0, 0xe4, 0xe5, 0x7c, 0x64, 0x43, 0x70, + 0x9c, 0x3a, 0x7a, 0x1c, 0xe8, 0x78, 0xa7, 0xdc}}, + + {"suit", + {0xb7, 0x08, 0x67, 0xf5, 0x38, 0x25, 0x43, 0x27, + 0xa1, 0xff, 0xcf, 0x4c, 0xc1, 0x93, 0x97, 0x97}}, + + {"bathing", + {0x5a, 0x58, 0x1e, 0xa1, 0xe5, 0x80, 0x43, 0x0c, + 0xa0, 0x6f, 0x61, 0x22, 0x98, 0xb7, 0xe4, 0xc7}}, + + {"tv", + {0x80, 0x53, 0x7d, 0xe2, 0xa4, 0x67, 0x4a, 0x76, + 0xb3, 0x54, 0x6d, 0xfd, 0x07, 0x5f, 0x5e, 0xc6}}, + + {"excited", + {0x6f, 0x49, 0x30, 0x98, 0x4f, 0x7c, 0x4a, 0xff, + 0xa2, 0x76, 0x34, 0xa0, 0x3b, 0xce, 0xae, 0xa7}}, + + {"sleeping", + {0x78, 0x5e, 0x8c, 0x48, 0x40, 0xd3, 0x4c, 0x65, + 0x88, 0x6f, 0x04, 0xcf, 0x3f, 0x3f, 0x43, 0xdf}}, + + {"hiptop", + {0x10, 0x11, 0x17, 0xc9, 0xa3, 0xb0, 0x40, 0xf9, + 0x81, 0xac, 0x49, 0xe1, 0x59, 0xfb, 0xd5, 0xd4}}, + + {"in_love", + {0xdd, 0xcf, 0x0e, 0xa9, 0x71, 0x95, 0x40, 0x48, + 0xa9, 0xc6, 0x41, 0x32, 0x06, 0xd6, 0xf2, 0x80}}, + + {"sleepy", + {0x83, 0xc9, 0xb7, 0x8e, 0x77, 0xe7, 0x43, 0x78, + 0xb2, 0xc5, 0xfb, 0x6c, 0xfc, 0xc3, 0x5b, 0xec}}, + + {"meeting", + {0xf1, 0x8a, 0xb5, 0x2e, 0xdc, 0x57, 0x49, 0x1d, + 0x99, 0xdc, 0x64, 0x44, 0x50, 0x24, 0x57, 0xaf}}, + + {"phone", + {0x12, 0x92, 0xe5, 0x50, 0x1b, 0x64, 0x4f, 0x66, + 0xb2, 0x06, 0xb2, 0x9a, 0xf3, 0x78, 0xe4, 0x8d}}, + + {"surfing", + {0xa6, 0xed, 0x55, 0x7e, 0x6b, 0xf7, 0x44, 0xd4, + 0xa5, 0xd4, 0xd2, 0xe7, 0xd9, 0x5c, 0xe8, 0x1f}}, + + {"mobile", + {0x16, 0x0c, 0x60, 0xbb, 0xdd, 0x44, 0x43, 0xf3, + 0x91, 0x40, 0x05, 0x0f, 0x00, 0xe6, 0xc0, 0x09}}, + + {"search", + {0xd4, 0xe2, 0xb0, 0xba, 0x33, 0x4e, 0x4f, 0xa5, + 0x98, 0xd0, 0x11, 0x7d, 0xbf, 0x4d, 0x3c, 0xc8}}, + + {"party", + {0xe6, 0x01, 0xe4, 0x1c, 0x33, 0x73, 0x4b, 0xd1, + 0xbc, 0x06, 0x81, 0x1d, 0x6c, 0x32, 0x3d, 0x81}}, + + {"coffee", + {0x1b, 0x78, 0xae, 0x31, 0xfa, 0x0b, 0x4d, 0x38, + 0x93, 0xd1, 0x99, 0x7e, 0xee, 0xaf, 0xb2, 0x18}}, + + {"console", + {0xd4, 0xa6, 0x11, 0xd0, 0x8f, 0x01, 0x4e, 0xc0, + 0x92, 0x23, 0xc5, 0xb6, 0xbe, 0xc6, 0xcc, 0xf0}}, + + {"internet", + {0x12, 0xd0, 0x7e, 0x3e, 0xf8, 0x85, 0x48, 0x9e, + 0x8e, 0x97, 0xa7, 0x2a, 0x65, 0x51, 0xe5, 0x8d}}, + + {"cigarette", + {0x64, 0x43, 0xc6, 0xaf, 0x22, 0x60, 0x45, 0x17, + 0xb5, 0x8c, 0xd7, 0xdf, 0x8e, 0x29, 0x03, 0x52}}, + + {"writing", + {0x00, 0x72, 0xd9, 0x08, 0x4a, 0xd1, 0x43, 0xdd, + 0x91, 0x99, 0x6f, 0x02, 0x69, 0x66, 0x02, 0x6f}}, + + {"beer", + {0x8c, 0x50, 0xdb, 0xae, 0x81, 0xed, 0x47, 0x86, + 0xac, 0xca, 0x16, 0xcc, 0x32, 0x13, 0xc7, 0xb7}}, + + {"music", + {0x61, 0xbe, 0xe0, 0xdd, 0x8b, 0xdd, 0x47, 0x5d, + 0x8d, 0xee, 0x5f, 0x4b, 0xaa, 0xcf, 0x19, 0xa7}}, + + {"studying", + {0x60, 0x9d, 0x52, 0xf8, 0xa2, 0x9a, 0x49, 0xa6, + 0xb2, 0xa0, 0x25, 0x24, 0xc5, 0xe9, 0xd2, 0x60}}, + + {"working", + {0xba, 0x74, 0xdb, 0x3e, 0x9e, 0x24, 0x43, 0x4b, + 0x87, 0xb6, 0x2f, 0x6b, 0x8d, 0xfe, 0xe5, 0x0f}}, + + {"restroom", + {0x16, 0xf5, 0xb7, 0x6f, 0xa9, 0xd2, 0x40, 0x35, + 0x8c, 0xc5, 0xc0, 0x84, 0x70, 0x3c, 0x98, 0xfa}}, + + {NULL, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}} +}; + +/* Keep this array synchronized with icq_custom_icons. */ +static PurpleMood icq_purple_moods[] = { + {"thinking", N_("Thinking"), NULL}, + {"busy", N_("Busy"), NULL}, + {"shopping", N_("Shopping"), NULL}, + /* This was in the original patch, but isn't what the official client + * (ICQ 6) sets when you choose its typewriter icon. */ + {"typing", NULL, NULL}, + {"question", N_("Questioning"), NULL}, + {"angry", N_("Angry"), NULL}, + {"plate", N_("Eating"), NULL}, + {"cinema", N_("Watching a movie"), NULL}, + {"sick", N_("Sick"), NULL}, + {"typing", N_("Typing"), NULL}, + {"suit", N_("At the office"), NULL}, + {"bathing", N_("Taking a bath"), NULL}, + {"tv", N_("Watching TV"), NULL}, + {"excited", N_("Having fun"), NULL}, + {"sleeping", N_("Sleeping"), NULL}, + {"hiptop", N_("Using a PDA"), NULL}, + {"in_love", N_("In love"), NULL}, + /* Sleepy / Tired */ + {"sleepy", N_("Sleepy"), NULL}, + {"meeting", N_("Meeting friends"), NULL}, + {"phone", N_("On the phone"), NULL}, + {"surfing", N_("Surfing"), NULL}, + /* "I am mobile." / "John is mobile." */ + {"mobile", N_("Mobile"), NULL}, + {"search", N_("Searching the web"), NULL}, + {"party", N_("At a party"), NULL}, + {"coffee", N_("Having Coffee"), NULL}, + /* Playing video games */ + {"console", N_("Gaming"), NULL}, + {"internet", N_("Browsing the web"), NULL}, + {"cigarette", N_("Smoking"), NULL}, + {"writing", N_("Writing"), NULL}, + /* Drinking [Alcohol] */ + {"beer", N_("Drinking"), NULL}, + {"music", N_("Listening to music"), NULL}, + {"studying", N_("Studying"), NULL}, + {"working", N_("Working"), NULL}, + {"restroom", N_("In the restroom"), NULL}, + /* Mark the last record. */ + {NULL, NULL, NULL}, +}; + + /* * 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 +484,7 @@ cur->sessionlen = userinfo->sessionlen; if (userinfo->capabilities != 0) cur->capabilities = userinfo->capabilities; + cur->present |= userinfo->present; if (userinfo->iconcsumlen > 0) { @@ -469,13 +676,38 @@ cap[8], cap[9], cap[10], cap[11], cap[12], cap[13], cap[14], cap[15]); - g_free(cap); } return flags; } +static const char * +aim_receive_custom_icon(OscarData *od, ByteStream *bs, int len) +{ + int offset; + const char *result = NULL; + + 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 = 0; icq_custom_icons[i].mood; i++) { + if (memcmp(&icq_custom_icons[i].data, cap, 0x10) == 0) { + purple_debug_misc("oscar", "Custom status icon: %s\n", icq_purple_moods[i].description); + result = icq_custom_icons[i].mood; + break; /* should only match once... */ + } + } + g_free(cap); + } + + return result; +} + guint32 aim_locate_getcaps_short(OscarData *od, ByteStream *bs, int len) { @@ -566,6 +798,38 @@ g_free(info->away_encoding); } +static const struct { + char *icqmood; + const char *mood; +} icqmoods[] = { + {"icqmood0", "shopping"}, + {"icqmood1", "bathing"}, + {"icqmood2", "sleepy"}, + {"icqmood3", "party"}, + {"icqmood4", "beer"}, + {"icqmood5", "thinking"}, + {"icqmood6", "plate"}, + {"icqmood7", "tv"}, + {"icqmood8", "meeting"}, + {"icqmood9", "coffee"}, + {"icqmood10", "music"}, + {"icqmood11", "suit"}, + {"icqmood12", "cinema"}, + {"icqmood13", "smile-big"}, + {"icqmood14", "phone"}, + {"icqmood15", "console"}, + {"icqmood16", "studying"}, + {"icqmood17", "sick"}, + {"icqmood18", "sleeping"}, + {"icqmood19", "surfing"}, + {"icqmood20", "internet"}, + {"icqmood21", "working"}, + {"icqmood22", "typing"}, + {"icqmood23", "angry"}, + {NULL, 0} + +}; + /* * AIM is fairly regular about providing user info. This is a generic * routine to extract it in its standard form. @@ -606,11 +870,12 @@ for (curtlv = 0; curtlv < tlvcnt; curtlv++) { guint16 type, length; int endpos; + int curpos; type = byte_stream_get16(bs); length = byte_stream_get16(bs); - - endpos = byte_stream_curpos(bs) + MIN(length, byte_stream_empty(bs)); + curpos = byte_stream_curpos(bs); + endpos = curpos + MIN(length, byte_stream_empty(bs)); if (type == 0x0001) { /* @@ -720,11 +985,23 @@ outinfo->present |= AIM_USERINFO_PRESENT_ICQDATA; } else if (type == 0x000d) { + PurpleAccount *account = purple_connection_get_account(od->gc); + const char *mood; + /* * OSCAR Capability information */ outinfo->capabilities |= aim_locate_getcaps(od, bs, length); outinfo->present |= AIM_USERINFO_PRESENT_CAPABILITIES; + byte_stream_setpos(bs, curpos); + + mood = aim_receive_custom_icon(od, bs, length); + if (mood) + purple_prpl_got_user_status(account, outinfo->sn, "mood", + PURPLE_MOOD_NAME, mood, + NULL); + else + purple_prpl_got_user_status_deactive(account, outinfo->sn, "mood"); } else if (type == 0x000e) { /* @@ -853,6 +1130,37 @@ outinfo->itmsurl_encoding = NULL; } } break; + + case 0x000e: { /* ICQ mood */ + PurpleAccount *account = purple_connection_get_account(od->gc); + char *icqmood; + gint32 i; + const char *mood = NULL; + + icqmood = byte_stream_getstr(bs, length2); + + /* icqmood = "" means X-Status + * with no mood icon. */ + if (*icqmood) { + for (i = 0; icqmoods[i].icqmood; i++) { + if (!strcmp(icqmood, icqmoods[i].icqmood)) { + mood = icqmoods[i].mood; + break; /* should only match once... */ + } + } + + if (!mood) + purple_debug_warning("oscar", "Unknown icqmood: %s\n", icqmood); + } + g_free(icqmood); + + if (mood) + purple_prpl_got_user_status(account, outinfo->sn, "mood", + PURPLE_MOOD_NAME, mood, + NULL); + else + purple_prpl_got_user_status_deactive(account, outinfo->sn, "mood"); + } break; } /* Save ourselves. */ @@ -897,6 +1205,10 @@ return 0; } +/* Apparently, this is never called. + * If you activate it, figure out a way to know what mood to pass to + * aim_tlvlist_add_caps() below. --rlaager */ +#if 0 /* * Inverse of aim_info_extract() */ @@ -932,8 +1244,9 @@ } #endif - if (info->present & AIM_USERINFO_PRESENT_CAPABILITIES) - aim_tlvlist_add_caps(&tlvlist, 0x000d, info->capabilities); + if (info->present & AIM_USERINFO_PRESENT_CAPABILITIES) { + aim_tlvlist_add_caps(&tlvlist, 0x000d, info->capabilities, NULL); + } if (info->present & AIM_USERINFO_PRESENT_SESSIONLEN) aim_tlvlist_add_32(&tlvlist, (guint16)((info->flags & AIM_FLAG_AOL) ? 0x0010 : 0x000f), info->sessionlen); @@ -944,6 +1257,7 @@ return 0; } +#endif /* * Subtype 0x0001 @@ -1133,6 +1447,10 @@ aim_locate_setcaps(OscarData *od, guint32 caps) { FlapConnection *conn; + PurpleAccount *account = purple_connection_get_account(od->gc); + PurplePresence *presence = purple_account_get_presence(account); + PurpleStatus *status = purple_presence_get_status(presence, "mood"); + const char *mood = purple_status_get_attr_string(status, PURPLE_MOOD_NAME); ByteStream bs; aim_snacid_t snacid; GSList *tlvlist = NULL; @@ -1140,7 +1458,7 @@ 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, mood); byte_stream_new(&bs, aim_tlvlist_size(tlvlist)); @@ -1224,9 +1542,21 @@ /* Caps will be 5 */ if ((tlv = aim_tlv_gettlv(tlvlist, 0x0005, 1))) { ByteStream cbs; + PurpleAccount *account = purple_connection_get_account(od->gc); + const char *mood; + byte_stream_init(&cbs, tlv->value, tlv->length); userinfo->capabilities = aim_locate_getcaps(od, &cbs, tlv->length); + byte_stream_rewind(&cbs); userinfo->present = AIM_USERINFO_PRESENT_CAPABILITIES; + + mood = aim_receive_custom_icon(od, &cbs, tlv->length); + if (mood) + purple_prpl_got_user_status(account, userinfo->sn, "mood", + PURPLE_MOOD_NAME, mood, + NULL); + else + purple_prpl_got_user_status_deactive(account, userinfo->sn, "mood"); } aim_tlvlist_free(tlvlist); @@ -1453,3 +1783,57 @@ return 0; } + +#if 0 //rlaager +const char* aim_get_custom_icon_mood(gint32 no) +{ + if (no >= G_N_ELEMENTS(aim_custom_icons) || no < 1) + return NULL; + return aim_custom_icons[no].mood.mood; +} +#endif + +const char* +icq_get_custom_icon_description(const char *mood) +{ + int i; + + if (!(mood && *mood)) + return NULL; + + for (i = 0; icq_custom_icons[i].mood; i++) { + /* We check that description is not NULL to exclude + * duplicates, like the typing duplicate. */ + if (icq_purple_moods[i].description && + !strcmp(mood, icq_custom_icons[i].mood)) { + return icq_purple_moods[i].description; + } + } + + return NULL; +} + +guint8* +icq_get_custom_icon_data(const char *mood) +{ + int i; + + if (!(mood && *mood)) + return NULL; + + for (i = 0; icq_custom_icons[i].mood; i++) { + /* We check that description is not NULL to exclude + * duplicates, like the typing duplicate. */ + if (icq_purple_moods[i].description && + !strcmp(mood, icq_custom_icons[i].mood)) { + return (guint8 *)icq_custom_icons[i].data; + } + } + return NULL; +} + +PurpleMood* +icq_get_purple_moods(PurpleAccount *account) +{ + return icq_purple_moods; +}
--- a/libpurple/protocols/oscar/libicq.c Wed Nov 26 22:17:58 2008 +0000 +++ b/libpurple/protocols/oscar/libicq.c Wed Nov 26 22:18:16 2008 +0000 @@ -107,6 +107,7 @@ sizeof(PurplePluginProtocolInfo), /* struct_size */ icq_get_account_text_table, /* get_account_text_table */ + oscar_get_purple_moods, /* get_moods */ }; static PurplePluginInfo info =
--- a/libpurple/protocols/oscar/oscar.c Wed Nov 26 22:17:58 2008 +0000 +++ b/libpurple/protocols/oscar/oscar.c Wed Nov 26 22:18:16 2008 +0000 @@ -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 = (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 @@ 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 @@ 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")); } @@ -918,6 +934,16 @@ } + if (presence) { + const char *mood; + const char *description; + status = purple_presence_get_status(presence, "mood"); + mood = purple_status_get_attr_string(status, PURPLE_MOOD_NAME); + description = icq_get_custom_icon_description(mood); + if (description && *description) + purple_notify_user_info_add_pair(user_info, _("Mood"), _(description)); + } + purple_notify_user_info_add_pair(user_info, _("Status"), message); g_free(message); } @@ -1984,6 +2010,16 @@ 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 { @@ -2300,7 +2336,9 @@ { 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); @@ -2330,6 +2368,21 @@ } } + + 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; @@ -2415,10 +2468,28 @@ else if (args->type & OSCAR_CAPABILITY_ICQSERVERRELAY) { - purple_debug_error("oscar", "Got an ICQ Server Relay message of " + purple_debug_info("oscar", "Got an ICQ Server Relay message of " "type %d\n", args->info.rtfmsg.msgtype); - } - + purple_debug_info("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 { purple_debug_error("oscar", "Unknown request class %hu\n", @@ -2820,7 +2891,6 @@ 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 " @@ -2968,6 +3038,28 @@ } 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. " @@ -4621,10 +4713,22 @@ 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 @@ -4771,6 +4875,13 @@ if (!purple_account_is_connected(account)) return; + /* There's no need to do the stuff below for mood updates. */ + if (purple_status_type_get_primitive(purple_status_get_type(status)) == PURPLE_STATUS_MOOD) { + PurpleConnection *gc = purple_account_get_connection(account); + aim_locate_setcaps((OscarData *)gc->proto_data, purple_caps); + return; + } + /* Set the AIM-style away message for both AIM and ICQ accounts */ oscar_set_info_and_status(account, FALSE, NULL, TRUE, status); @@ -5697,6 +5808,11 @@ return 0; } +PurpleMood* oscar_get_purple_moods(PurpleAccount *account) +{ + return icq_get_purple_moods(account); +} + const char *oscar_list_icon_icq(PurpleAccount *a, PurpleBuddy *b) { if ((b == NULL) || (b->name == NULL) || aim_snvalid_sms(b->name)) @@ -5763,12 +5879,17 @@ return "admin"; if (userinfo->flags & AIM_FLAG_ACTIVEBUDDY) return "bot"; - if (userinfo->capabilities & OSCAR_CAPABILITY_HIPTOP) - return "hiptop"; if (userinfo->capabilities & OSCAR_CAPABILITY_SECUREIM) return "secure"; if (userinfo->icqinfo.status & AIM_ICQ_STATE_BIRTHDAY) return "birthday"; + + /* Make the mood icon override anything below this. */ + if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_MOOD)) + return NULL; + + if (userinfo->capabilities & OSCAR_CAPABILITY_HIPTOP) + return "hiptop"; } return NULL; } @@ -5990,9 +6111,53 @@ 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, @@ -6002,9 +6167,12 @@ 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); @@ -6037,9 +6205,14 @@ NULL, TRUE, TRUE, FALSE); status_types = g_list_prepend(status_types, type); - status_types = g_list_reverse(status_types); - - return status_types; + type = purple_status_type_new_with_attrs(PURPLE_STATUS_MOOD, + "mood", NULL, TRUE, is_icq, TRUE, + PURPLE_MOOD_NAME, _("Mood Name"), purple_value_new(PURPLE_TYPE_STRING), + PURPLE_MOOD_COMMENT, _("Mood Comment"), purple_value_new(PURPLE_TYPE_STRING), + NULL); + status_types = g_list_prepend(status_types, type); + + return g_list_reverse(status_types); } static void oscar_ssi_editcomment(struct name_data *data, const char *text) { @@ -6172,6 +6345,23 @@ 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) { @@ -6199,15 +6389,14 @@ 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) &&
--- a/libpurple/protocols/oscar/oscar.h Wed Nov 26 22:17:58 2008 +0000 +++ b/libpurple/protocols/oscar/oscar.h Wed Nov 26 22:18:16 2008 +0000 @@ -362,8 +362,10 @@ 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 @@ #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 @@ /* 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); @@ -1096,9 +1105,13 @@ guint32 aim_locate_getcaps_short(OscarData *od, ByteStream *bs, int len); void aim_info_free(aim_userinfo_t *); int aim_info_extract(OscarData *od, ByteStream *bs, aim_userinfo_t *); +#if 0 int aim_putuserinfo(ByteStream *bs, aim_userinfo_t *info); - - +#endif +PurpleMood* icq_get_purple_moods(PurpleAccount *account); +const char* icq_get_custom_icon_description(const char *mood); +guint8* icq_get_custom_icon_data(const char *mood); +int icq_im_xstatus_request(OscarData *od, const char *sn); /* 0x0003 - family_buddy.c */ /* 0x0002 */ void aim_buddylist_reqrights(OscarData *, FlapConnection *); @@ -1428,7 +1441,7 @@ 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, const char *mood); 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);
--- a/libpurple/protocols/oscar/oscarcommon.h Wed Nov 26 22:17:58 2008 +0000 +++ b/libpurple/protocols/oscar/oscarcommon.h Wed Nov 26 22:18:16 2008 +0000 @@ -29,6 +29,7 @@ #include "prpl.h" #include "version.h" #include "notify.h" +#include "status.h" #define OSCAR_DEFAULT_LOGIN_SERVER "login.messaging.aol.com" #define OSCAR_DEFAULT_LOGIN_PORT 5190 @@ -46,6 +47,7 @@ #ifdef _WIN32 const char *oscar_get_locale_charset(void); #endif +PurpleMood* oscar_get_purple_moods(PurpleAccount *account); const char *oscar_list_icon_icq(PurpleAccount *a, PurpleBuddy *b); const char *oscar_list_icon_aim(PurpleAccount *a, PurpleBuddy *b); const char* oscar_list_emblem(PurpleBuddy *b);
--- a/libpurple/protocols/oscar/tlv.c Wed Nov 26 22:17:58 2008 +0000 +++ b/libpurple/protocols/oscar/tlv.c Wed Nov 26 22:18:16 2008 +0000 @@ -407,10 +407,11 @@ * @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 char *mood) { 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,11 @@ byte_stream_init(&bs, buf, sizeof(buf)); byte_stream_putcaps(&bs, caps); + + /* adding of custom icon GUID */ + data = icq_get_custom_icon_data(mood); + if (data != NULL) + byte_stream_putraw(&bs, data, 16); return aim_tlvlist_add_raw(list, type, byte_stream_curpos(&bs), buf); }
--- a/libpurple/protocols/sametime/sametime.c Wed Nov 26 22:17:58 2008 +0000 +++ b/libpurple/protocols/sametime/sametime.c Wed Nov 26 22:18:16 2008 +0000 @@ -3505,10 +3505,10 @@ purple_request_field_list_set_multi_select(f, FALSE); for(; confs; confs = confs->next) { struct mwConference *c = confs->data; - purple_request_field_list_add(f, mwConference_getTitle(c), c); + purple_request_field_list_add_icon(f, mwConference_getTitle(c), NULL, c); } - purple_request_field_list_add(f, _("Create New Conference..."), - GINT_TO_POINTER(0x01)); + purple_request_field_list_add_icon(f, _("Create New Conference..."), + NULL, GINT_TO_POINTER(0x01)); purple_request_field_group_add_field(g, f); f = purple_request_field_string_new(CHAT_KEY_INVITE, "Message", NULL, FALSE); @@ -5434,7 +5434,7 @@ res->id = g_strdup(match->id); res->name = g_strdup(match->name); - purple_request_field_list_add(f, res->name, res); + purple_request_field_list_add_icon(f, res->name, NULL, res); } purple_request_field_group_add_field(g, f);
--- a/libpurple/protocols/silc/buddy.c Wed Nov 26 22:17:58 2008 +0000 +++ b/libpurple/protocols/silc/buddy.c Wed Nov 26 22:18:16 2008 +0000 @@ -1178,7 +1178,7 @@ client_entry->username, *client_entry->hostname ? client_entry->hostname : "", fingerprint ? tmp2 : ""); - purple_request_field_list_add(f, tmp, client_entry); + purple_request_field_list_add_icon(f, tmp, NULL, client_entry); silc_free(fingerprint); }
--- a/libpurple/protocols/silc/chat.c Wed Nov 26 22:17:58 2008 +0000 +++ b/libpurple/protocols/silc/chat.c Wed Nov 26 22:18:16 2008 +0000 @@ -472,7 +472,7 @@ g_snprintf(tmp2, sizeof(tmp2), "%s\n %s\n %s", ident->realname ? ident->realname : ident->username ? ident->username : "", fingerprint, babbleprint); - purple_request_field_list_add(f, tmp2, public_key); + purple_request_field_list_add_icon(f, tmp2, NULL, public_key); silc_free(fingerprint); silc_free(babbleprint);
--- a/libpurple/protocols/silc10/buddy.c Wed Nov 26 22:17:58 2008 +0000 +++ b/libpurple/protocols/silc10/buddy.c Wed Nov 26 22:18:16 2008 +0000 @@ -1176,7 +1176,7 @@ clients[i]->username, clients[i]->hostname ? clients[i]->hostname : "", fingerprint ? tmp2 : ""); - purple_request_field_list_add(f, tmp, clients[i]); + purple_request_field_list_add_icon(f, tmp, NULL, clients[i]); silc_free(fingerprint); }
--- a/libpurple/protocols/silc10/chat.c Wed Nov 26 22:17:58 2008 +0000 +++ b/libpurple/protocols/silc10/chat.c Wed Nov 26 22:18:16 2008 +0000 @@ -449,7 +449,7 @@ g_snprintf(tmp2, sizeof(tmp2), "%s\n %s\n %s", ident->realname ? ident->realname : ident->username ? ident->username : "", fingerprint, babbleprint); - purple_request_field_list_add(f, tmp2, pubkey); + purple_request_field_list_add_icon(f, tmp2, NULL, pubkey); silc_free(fingerprint); silc_free(babbleprint);
--- a/libpurple/prpl.h Wed Nov 26 22:17:58 2008 +0000 +++ b/libpurple/prpl.h Wed Nov 26 22:18:16 2008 +0000 @@ -440,6 +440,12 @@ * destroyed by the caller when it's no longer needed. */ GHashTable *(*get_account_text_table)(PurpleAccount *account); + + /** + * Returns an array of "PurpleMood"s, with the last one having + * "mood" set to @c NULL. + */ + PurpleMood *(*get_moods)(PurpleAccount *account); }; #define PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl, member) \
--- a/libpurple/request.c Wed Nov 26 22:17:58 2008 +0000 +++ b/libpurple/request.c Wed Nov 26 22:18:16 2008 +0000 @@ -23,6 +23,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ +#define _PURPLE_REQUEST_C_ + #include "internal.h" #include "notify.h" @@ -823,13 +825,40 @@ purple_request_field_list_add(PurpleRequestField *field, const char *item, void *data) { + purple_request_field_list_add_icon(field, item, NULL, data); +} + +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(field->type == PURPLE_REQUEST_FIELD_LIST); + if (icon_path) + { + if (field->u.list.icons == NULL) + { + GList *l; + for (l = field->u.list.items ; l != NULL ; l = l->next) + { + /* Order doesn't matter, because we're just + * filing in blank items. So, we use + * g_list_prepend() because it's faster. */ + field->u.list.icons = g_list_prepend(field->u.list.icons, NULL); + } + } + field->u.list.icons = g_list_append(field->u.list.icons, g_strdup(icon_path)); + } + else if (field->u.list.icons) + { + /* Keep this even with the items list. */ + field->u.list.icons = g_list_append(field->u.list.icons, NULL); + } + field->u.list.items = g_list_append(field->u.list.items, g_strdup(item)); - g_hash_table_insert(field->u.list.item_data, g_strdup(item), data); } @@ -935,6 +964,15 @@ 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); + + return field->u.list.icons; +} + PurpleRequestField * purple_request_field_label_new(const char *id, const char *text) {
--- a/libpurple/request.h Wed Nov 26 22:17:58 2008 +0000 +++ b/libpurple/request.h Wed Nov 26 22:18:16 2008 +0000 @@ -146,6 +146,7 @@ struct { GList *items; + GList *icons; GHashTable *item_data; GList *selected; GHashTable *selected_table; @@ -907,15 +908,30 @@ void *purple_request_field_list_get_data(const PurpleRequestField *field, const char *text); +#if !(defined PURPLE_DISABLE_DEPRECATED) || (defined _PURPLE_REQUEST_C_) /** * Adds an item to a list field. * * @param field The list field. * @param item The list item. * @param data The associated data. + * + * @deprecated Use purple_request_field_list_add_icon() instead. */ void purple_request_field_list_add(PurpleRequestField *field, const char *item, void *data); +#endif + +/** + * Adds an item to a list field. + * + * @param field The list field. + * @param item The list item. + * @param icon_path The path to icon file, or @c NULL for no icon. + * @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. @@ -975,6 +991,18 @@ */ GList *purple_request_field_list_get_items(const PurpleRequestField *field); +/** + * Returns a list of icons in a list field. + * + * The icons will correspond with the items, in order. + * + * @param field The field. + * + * @constreturn The list of icons or @c NULL (i.e. the empty GList) if no + * items have icons. + */ +GList *purple_request_field_list_get_icons(const PurpleRequestField *field); + /*@}*/ /**************************************************************************/
--- a/libpurple/status.c Wed Nov 26 22:17:58 2008 +0000 +++ b/libpurple/status.c Wed Nov 26 22:18:16 2008 +0000 @@ -135,6 +135,7 @@ -200, /* extended away */ -400, /* mobile */ 0, /* tune */ + 0, /* mood */ -10, /* idle, special case. */ -5, /* idle time, special case. */ 10 /* Offline messageable */ @@ -155,15 +156,16 @@ } const status_primitive_map[] = { - { PURPLE_STATUS_UNSET, "unset", N_("Unset") }, - { PURPLE_STATUS_OFFLINE, "offline", N_("Offline") }, - { PURPLE_STATUS_AVAILABLE, "available", N_("Available") }, - { PURPLE_STATUS_UNAVAILABLE, "unavailable", N_("Do not disturb") }, - { PURPLE_STATUS_INVISIBLE, "invisible", N_("Invisible") }, - { PURPLE_STATUS_AWAY, "away", N_("Away") }, - { PURPLE_STATUS_EXTENDED_AWAY, "extended_away", N_("Extended away") }, - { PURPLE_STATUS_MOBILE, "mobile", N_("Mobile") }, - { PURPLE_STATUS_TUNE, "tune", N_("Listening to music") } + { PURPLE_STATUS_UNSET, "unset", N_("Unset") }, + { PURPLE_STATUS_OFFLINE, "offline", N_("Offline") }, + { PURPLE_STATUS_AVAILABLE, "available", N_("Available") }, + { PURPLE_STATUS_UNAVAILABLE, "unavailable", N_("Do not disturb") }, + { PURPLE_STATUS_INVISIBLE, "invisible", N_("Invisible") }, + { PURPLE_STATUS_AWAY, "away", N_("Away") }, + { PURPLE_STATUS_EXTENDED_AWAY, "extended_away", N_("Extended away") }, + { PURPLE_STATUS_MOBILE, "mobile", N_("Mobile") }, + { PURPLE_STATUS_TUNE, "tune", N_("Listening to music"), }, + { PURPLE_STATUS_MOOD, "mood", N_("Feeling") }, }; const char *
--- a/libpurple/status.h Wed Nov 26 22:17:58 2008 +0000 +++ b/libpurple/status.h Wed Nov 26 22:18:16 2008 +0000 @@ -50,8 +50,8 @@ * your accounts are saved so that the next time you start Purple, * your accounts will be set to their last known statuses. There * is also a list of saved statuses that are written to the - * status.xml file. Also, each PurpleStatus has a "savable" boolean. - * If "savable" is set to FALSE then the status is NEVER saved. + * status.xml file. Also, each PurpleStatus has a "saveable" boolean. + * If "saveable" is set to FALSE then the status is NEVER saved. * All PurpleStatuses should be inside a PurplePresence. * * @@ -77,6 +77,12 @@ typedef struct _PurplePresence PurplePresence; typedef struct _PurpleStatus PurpleStatus; +typedef struct _PurpleMood { + const char *mood; + const char *description; + gpointer *padding; +} PurpleMood; + /** * A context for a presence. * @@ -96,8 +102,7 @@ */ /* * If you add a value to this enum, make sure you update - * the status_primitive_map array in status.c and the special-cases for idle - * and offline-messagable just below it. + * the status_primitive_map and primitive_scores arrays in status.c. */ typedef enum { @@ -110,6 +115,7 @@ PURPLE_STATUS_EXTENDED_AWAY, PURPLE_STATUS_MOBILE, PURPLE_STATUS_TUNE, + PURPLE_STATUS_MOOD, PURPLE_STATUS_NUM_PRIMITIVES } PurpleStatusPrimitive; @@ -129,6 +135,9 @@ #define PURPLE_TUNE_URL "tune_url" #define PURPLE_TUNE_FULL "tune_full" +#define PURPLE_MOOD_NAME "mood" +#define PURPLE_MOOD_COMMENT "moodtext" + #ifdef __cplusplus extern "C" { #endif @@ -200,7 +209,7 @@ /** * Creates a new status type with some default values (not - * savable and not independent). + * saveable and not independent). * * @param primitive The primitive status type. * @param id The ID of the status type, or @c NULL to use the id of
--- a/pidgin/gtkblist.c Wed Nov 26 22:17:58 2008 +0000 +++ b/pidgin/gtkblist.c Wed Nov 26 22:18:16 2008 +0000 @@ -3625,7 +3625,7 @@ PurplePluginProtocolInfo *prpl_info; const char *name = NULL; char *filename, *path; - PurplePresence *p; + PurplePresence *presence = NULL; if(PURPLE_BLIST_NODE_IS_CONTACT(node)) { if(!gtknode->contact_expanded) { @@ -3635,8 +3635,8 @@ } else if(PURPLE_BLIST_NODE_IS_BUDDY(node)) { buddy = (PurpleBuddy*)node; gtkbuddynode = node->ui_data; - p = purple_buddy_get_presence(buddy); - if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_MOBILE)) { + presence = purple_buddy_get_presence(buddy); + if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_MOBILE)) { path = g_build_filename(DATADIR, "pixmaps", "pidgin", "emblems", "16", "mobile.png", NULL); return _pidgin_blist_get_cached_emblem(path); @@ -3658,13 +3658,17 @@ return _pidgin_blist_get_cached_emblem(path); } - p = purple_buddy_get_presence(buddy); - if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_MOBILE)) { + /* If we came through the contact code flow above, we didn't need + * to get the presence until now. */ + if (presence == NULL) + presence = purple_buddy_get_presence(buddy); + + if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_MOBILE)) { path = g_build_filename(DATADIR, "pixmaps", "pidgin", "emblems", "16", "mobile.png", NULL); return _pidgin_blist_get_cached_emblem(path); } - if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_TUNE)) { + if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_TUNE)) { path = g_build_filename(DATADIR, "pixmaps", "pidgin", "emblems", "16", "music.png", NULL); return _pidgin_blist_get_cached_emblem(path); } @@ -3677,8 +3681,18 @@ if (prpl_info && prpl_info->list_emblem) name = prpl_info->list_emblem(buddy); - if (name == NULL) - return NULL; + if (name == NULL) { + PurpleStatus *status; + + if (!purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_MOOD)) + return NULL; + + status = purple_presence_get_status(presence, "mood"); + name = purple_status_get_attr_string(status, PURPLE_MOOD_NAME); + + if (!(name && *name)) + return NULL; + } filename = g_strdup_printf("%s.png", name); @@ -7629,6 +7643,95 @@ purple_account_set_enabled(account, PIDGIN_UI, FALSE); } +static void +edit_mood_cb(PurpleConnection *gc, PurpleRequestFields *fields) +{ + PurpleRequestField *f; + GList *l; + + f = purple_request_fields_get_field(fields, "mood"); + l = purple_request_field_list_get_selected(f); + + if (l) { + const char *mood = purple_request_field_list_get_data(f, l->data); + PurpleAccount *account = purple_connection_get_account(gc); + + if (mood != NULL) { + purple_account_set_status(account, "mood", TRUE, + PURPLE_MOOD_NAME, mood, + NULL); + } else { + purple_account_set_status(account, "mood", FALSE, NULL); + } + } +} + +static void +set_mood_cb(GtkWidget *widget, PurpleAccount *account) +{ + PurplePresence *presence = purple_account_get_presence(account); + PurpleStatus *status = purple_presence_get_status(presence, "mood"); + const char *current_mood; + PurpleRequestFields *fields; + PurpleRequestFieldGroup *g; + PurpleRequestField *f; + char* na_fn; + PurpleConnection *gc = purple_account_get_connection(account); + PurplePluginProtocolInfo *prpl_info; + PurpleMood *mood; + + g_return_if_fail(gc->prpl != NULL); + prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl); + + current_mood = purple_status_get_attr_string(status, PURPLE_MOOD_NAME); + + fields = purple_request_fields_new(); + g = purple_request_field_group_new(NULL); + f = purple_request_field_list_new("mood", _("Please select your mood from the list")); + + na_fn = g_build_filename("pixmaps", "pidgin", "emblems", "16", "not-authorized.png", NULL); + + purple_request_field_list_add_icon(f, _("None"), na_fn, NULL); + if (current_mood == NULL) + purple_request_field_list_add_selected(f, _("None")); + + g_free(na_fn); + + /* TODO: rlaager wants this sorted. */ + for (mood = prpl_info->get_moods(account); + mood->mood != NULL ; mood++) + { + char *icon_path; + char *filename; + + if (mood->mood == NULL || mood->description == NULL) + continue; + + icon_path = g_strdup_printf("%s.png", mood->mood); + filename = g_build_filename("pixmaps", "pidgin", + "emblems", "16", + icon_path, NULL); + g_free(icon_path); + + purple_request_field_list_add_icon(f, _(mood->description), + filename, mood->mood); + g_free(filename); + + if (current_mood && !strcmp(current_mood, mood->mood)) + purple_request_field_list_add_selected(f, _(mood->description)); + } + purple_request_field_group_add_field(g, f); + + purple_request_fields_add_group(fields, g); + + purple_request_fields(gc, _("Edit User Mood"), _("Edit User Mood"), + NULL, fields, + _("OK"), G_CALLBACK(edit_mood_cb), + _("Cancel"), NULL, + purple_connection_get_account(gc), + NULL, NULL, gc); +} + void pidgin_blist_update_accounts_menu(void) { @@ -7702,6 +7805,8 @@ PurpleAccount *account = NULL; GdkPixbuf *pixbuf = NULL; PurplePlugin *plugin = NULL; + PurplePluginProtocolInfo *prpl_info; + GList *types; account = accounts->data; accel_group = gtk_menu_get_accel_group(GTK_MENU(accountmenu)); @@ -7740,10 +7845,34 @@ gtk_menu_shell_append(GTK_MENU_SHELL(submenu), menuitem); gtk_widget_show(menuitem); - pidgin_separator(submenu); - gc = purple_account_get_connection(account); plugin = gc && PURPLE_CONNECTION_IS_CONNECTED(gc) ? gc->prpl : NULL; + + if (plugin && + (prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(plugin)) && + PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl_info, get_moods)) + { + for (types = purple_account_get_status_types(account); + types != NULL ; types = types->next) + { + PurpleStatusType *type = types->data; + + if (strcmp(purple_status_type_get_id(type), "mood") != 0) + continue; + + menuitem = gtk_menu_item_new_with_mnemonic(_("Set _Mood...")); + g_signal_connect(G_OBJECT(menuitem), "activate", + G_CALLBACK(set_mood_cb), account); + gtk_menu_shell_append(GTK_MENU_SHELL(submenu), menuitem); + gtk_widget_show(menuitem); + + /* Be safe. It shouldn't match more than once anyway */ + break; + } + } + + pidgin_separator(submenu); + if (plugin && PURPLE_PLUGIN_HAS_ACTIONS(plugin)) { build_plugin_actions(submenu, plugin, gc); } else {
--- a/pidgin/gtkrequest.c Wed Nov 26 22:17:58 2008 +0000 +++ b/pidgin/gtkrequest.c Wed Nov 26 22:18:16 2008 +0000 @@ -996,6 +996,9 @@ GtkTreeViewColumn *column; GtkTreeIter iter; GList *l; + GList *icons = NULL; + + icons = purple_request_field_list_get_icons(field); /* Create the scrolled window */ sw = gtk_scrolled_window_new(NULL, NULL); @@ -1007,7 +1010,10 @@ gtk_widget_show(sw); /* Create the list store */ - store = gtk_list_store_new(2, G_TYPE_POINTER, G_TYPE_STRING); + if (icons) + 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,13 +1032,43 @@ gtk_tree_view_column_pack_start(column, renderer, TRUE); gtk_tree_view_column_add_attribute(column, renderer, "text", 1); + if (icons) + { + 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); + } + 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 (icons) + { + const char *icon_path = (const char *)icons->data; + char* filename; + GdkPixbuf* pixbuf = NULL; + + if (icon_path) + { + 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); + icons = icons->next; + } + else + gtk_list_store_set(store, &iter, 0, purple_request_field_list_get_data(field, text), 1, text, -1);
--- a/pidgin/gtksavedstatuses.c Wed Nov 26 22:17:58 2008 +0000 +++ b/pidgin/gtksavedstatuses.c Wed Nov 26 22:18:16 2008 +0000 @@ -921,7 +921,14 @@ for (i = PURPLE_STATUS_UNSET + 1; i < PURPLE_STATUS_NUM_PRIMITIVES; i++) { - if (i == PURPLE_STATUS_MOBILE || i == PURPLE_STATUS_TUNE) + /* Someone should fix this for 3.0.0. The independent boolean + * should probably be set on the status type, not the status. + * I guess that would prevent third party plugins from creating + * independent statuses? + */ + if (i == PURPLE_STATUS_MOBILE || + i == PURPLE_STATUS_MOOD || + i == PURPLE_STATUS_TUNE) /* * Special-case these. They're intended to be independent * status types, so don't show them in the list.
--- a/pidgin/pixmaps/Makefile.am Wed Nov 26 22:17:58 2008 +0000 +++ b/pidgin/pixmaps/Makefile.am Wed Nov 26 22:18:16 2008 +0000 @@ -106,7 +106,58 @@ emblems/16/scalable/video.svg \ emblems/16/scalable/voice.svg + +# Magic to copy files from emotes/small/16 to emblems/16. +# This is necessary because UIs expect emblems in one place and +# smiley themes in another, but we don't want to duplicate these +# images in the source. +emblems/16/%.png: emotes/small/16/%.png + rm -f $@ + cp -f $< $@ + +emblems/16/busy.png: status/16/busy.png + rm -f $@ + cp -f $< $@ + +# The copied emblems. +# Ensure these are in .mtn-ignore. +EMBLEMS_16_COPIED = \ + emblems/16/amorous.png \ + emblems/16/angry.png \ + emblems/16/busy.png \ + emblems/16/beer.png \ + emblems/16/cigarette.png \ + emblems/16/coffee.png \ + emblems/16/confused.png \ + emblems/16/console.png \ + emblems/16/disappointed.png \ + emblems/16/embarrassed.png \ + emblems/16/excited.png \ + emblems/16/in_love.png \ + emblems/16/mean.png \ + emblems/16/meeting.png \ + emblems/16/mobile.png \ + emblems/16/musical-note.png \ + emblems/16/neutral.png \ + emblems/16/party.png \ + emblems/16/phone.png \ + emblems/16/plate.png \ + emblems/16/question.png \ + emblems/16/sad.png \ + emblems/16/sarcastic.png \ + emblems/16/search.png \ + emblems/16/sick.png \ + emblems/16/sleeping.png \ + emblems/16/sleepy.png \ + emblems/16/thinking.png \ + emblems/16/tv.png + + +# Non-copied emblems. +# Ensure these filenames don't clash with files in emotes/small/16 or +# bad things will happen! EMBLEMS_16 = \ + $(EMBLEMS_16_COPIED) \ emblems/16/aol-client.png \ emblems/16/birthday.png \ emblems/16/blocked.png \ @@ -127,7 +178,19 @@ emblems/16/secure.png \ emblems/16/unavailable.png \ emblems/16/video.png \ - emblems/16/voice.png + emblems/16/voice.png \ + emblems/16/bathing.png \ + emblems/16/cinema.png \ + emblems/16/internet.png \ + emblems/16/restroom.png \ + emblems/16/shopping.png \ + emblems/16/studying.png \ + emblems/16/suit.png \ + emblems/16/surfing.png \ + emblems/16/typing.png \ + emblems/16/working.png \ + emblems/16/writing.png + EMOTES_DEFAULT_24_SCALABLE = \ emotes/default/24/scalable/airplane.svg \
--- a/pidgin/pixmaps/emotes/default/24/Makefile.am Wed Nov 26 22:17:58 2008 +0000 +++ b/pidgin/pixmaps/emotes/default/24/Makefile.am Wed Nov 26 22:18:16 2008 +0000 @@ -2,6 +2,7 @@ act-up.png \ airplane.png \ alien.png \ + amorous.png \ angel.png \ angry.png \ arrogant.png \ @@ -56,8 +57,9 @@ dont-know.png \ drink.png \ drool.png \ - eat.png \ + hungry.png \ embarrassed.png \ + excited.png \ excruciating.png \ eyeroll.png \ female-fighter.png \ @@ -81,7 +83,7 @@ hug-left.png \ hug-right.png \ hypnotized.png \ - in-love.png \ + in_love.png \ island.png \ jump.png \ kissed.png \ @@ -94,7 +96,6 @@ liquor.png \ loser.png \ love-over.png \ - love.png \ lying.png \ mad-tongue.png \ mail.png \ @@ -114,7 +115,7 @@ msn.png \ musical-note.png \ music.png \ - nailbiting.png \ + nervous.png \ neutral.png \ on-the-phone.png \ party.png \ @@ -144,7 +145,7 @@ secret.png \ shame.png \ sheep.png \ - shock.png \ + shocked.png \ shout.png \ shut-mouth.png \ sick.png \ @@ -153,9 +154,9 @@ sinister.png \ skeleton.png \ skywalker.png \ + sleeping.png \ sleepy.png \ - smile-big.png \ - smile.png \ + happy.png \ smirk.png \ snail.png \ snicker.png \ @@ -167,7 +168,7 @@ stop.png \ struggle.png \ sun.png \ - sweat.png \ + hot.png \ talktohand.png \ teeth.png \ terror.png \ @@ -175,7 +176,7 @@ thunder.png \ time-out.png \ tongue.png \ - tremble.png \ + afraid.png \ turtle.png \ tv.png \ umbrella.png \ @@ -188,7 +189,6 @@ wilt.png \ wink.png \ worship.png \ - yawn.png \ yin-yang.png
--- a/pidgin/pixmaps/emotes/default/24/default.theme.in Wed Nov 26 22:17:58 2008 +0000 +++ b/pidgin/pixmaps/emotes/default/24/default.theme.in Wed Nov 26 22:18:16 2008 +0000 @@ -6,16 +6,16 @@ # Default smileys [default] -smile.png :) :-) -smile-big.png :-D :-d :D :d +happy.png :) :-) +excited.png :-D :-d :D :d sad.png :-( :( wink.png ;-) ;) tongue.png :P :-P :-p :p -shock.png =-O =-o +shocked.png =-O =-o kiss.png :-* glasses-cool.png 8-) embarrassed.png :-[ -crying.png :'( +crying.png :'( :'-( thinking.png :-/ :-\\ angel.png O:-) o:-) shut-mouth.png :-X @@ -27,16 +27,61 @@ ! cyclops.png O-) o-) +[XMPP] +# Following XEP-0038 + our default set, in default set order +happy.png :) :-) +excited.png :-D :-d :D :d +sad.png :-( :( +wink.png ;-) ;) +tongue.png :P :-P :-p :p +shocked.png =-O =-o +kiss.png :kiss: :-* +glasses-cool.png 8-) +embarrassed.png :-[ +crying.png :'-( :'( +thinking.png :-/ :-\\ +angel.png O:-) o:-) +shut-mouth.png :-X +moneymouth.png :-$ +foot-in-mouth.png :-! +shout.png >:o >:O + +# Following XEP-0038 +angry.png >:-( >:( +good.png :yes: +bad.png :no: +stop.png :wait: +rose.png @->-- :rose: +phone.png :telephone: +mail.png :email: +lamp.png :jabber: +cake.png :cake: +in_love.png :heart: :love: +love-over.png :brokenheart: +musical-note.png :music: +beer.png :beer: +coffee.png :coffee: +coins.png :money: +moon.png :moon: +sun.png :sun: +star.png :star: + +# Hidden icons from the default set. +! skywalker.png C:-) c:-) C:) c:) +! monkey.png :-(|) :(|) 8-|) +! cyclops.png O-) o-) + + # Following AIM 6.1 [AIM] -smile.png :-) :) +happy.png :-) :) wink.png ;-) ;) sad.png :-( :( tongue.png :-P :P :-p :p -shock.png =-O +shocked.png =-O kiss.png :-* shout.png >:o -smile-big.png :-D :D +excited.png :-D :D moneymouth.png :-$ foot-in-mouth.png :-! embarrassed.png :-[ @@ -47,14 +92,15 @@ glasses-cool.png 8-) ! skywalker.png C:-) c:-) C:) c:) ! monkey.png :-(|) :(|) +! cyclops.png O-) o-) # Following Windows Live Messenger 8.1 [MSN] -smile.png :) :-) -smile-big.png :D :d :-D :-d +happy.png :) :-) +excited.png :D :d :-D :-d wink.png ;) ;-) -shock.png :-O :-o :O :o +shocked.png :-O :-o :O :o tongue.png :P :p :-P :-p glasses-cool.png (H) (h) angry.png :@ :-@ @@ -65,7 +111,7 @@ neutral.png :| :-| devil.png (6) angel.png (A) (a) -love.png (L) (l) +in_love.png (L) (l) love-over.png (U) (u) msn.png (M) (m) cat.png (@) @@ -125,10 +171,11 @@ thunder.png (li) party.png <:o) eyeroll.png 8-) -yawn.png |-) +sleepy.png |-) bunny.png ('.') ! skywalker.png C:-) c:-) C:) c:) ! monkey.png :-(|) :(|) +! cyclops.png O-) o-) # Hidden MSN emotes cigarette.png (ci) (CI) @@ -139,7 +186,7 @@ # Following QQ 2006 [QQ] -shock.png /:O /jy /surprised +shocked.png /:O /jy /surprised curl-lip.png /:~ /pz /curl_lip desire.png /:* /se /desire dazed.png /:| /dazed @@ -147,13 +194,13 @@ crying.png /:< /ll /cry bashful.png /:$ /hx /bashful shut-mouth.png /:X /bz /shut_mouth -sleepy.png /:Z /shui /sleep +sleeping.png /:Z /shui /sleep weep.png /:'( /dk /weep embarrassed.png /:-| /gg /embarassed pissed-off.png /:@ /fn /pissed_off act-up.png /:P /tp /act_up -smile-big.png /:D /cy /toothy_smile -smile.png /:) /wx /small_smile +excited.png /:D /cy /toothy_smile +happy.png /:) /wx /small_smile sad.png /:( /ng /sad glasses-cool.png /:+ /kuk /cool doctor.png /:# /feid /SARS @@ -164,9 +211,9 @@ disdain.png /;d /by /disdain arrogant.png /;o /am /arrogant starving.png /:g /jie /starving -yawn.png /|-) /kun /sleepy +sleepy.png /|-) /kun /sleepy terror.png /:! /jk /terror -sweat.png /:L /sweat +hot.png /:L /sweat smirk.png /:> /hanx /smirk soldier.png /:; /db /soldier struggle.png /;f /fendou /struggle @@ -180,8 +227,8 @@ hammer.png /xx /qiao /hammer bye.png /bye /zj /bye go-away.png /go /shan /go -tremble.png /shake /fad /shake -in-love.png /love /aiq /love +afraid.png /shake /fad /shake +amorous.png /love /aiq /love jump.png /jump /tiao /jump search.png /find /zhao /search lashes.png /& /mm /beautiful_eyebrows @@ -200,12 +247,12 @@ musical-note.png /music /yy /music poop.png /shit /bb /shit coffee.png /coffee /kf /coffee -eat.png /eat /fan /eat +hungry.png /eat /fan /eat pill.png /pill /yw /pill rose.png /rose /mg /rose wilt.png /fade /dx /wilt kiss.png /kiss /wen /kiss -love.png /heart /xin /heart +in_love.png /heart /xin /heart love-over.png /break /xs /broken_heart meeting.png /meeting /hy /meeting present.png /gift /lw /gift @@ -234,19 +281,20 @@ boy.png /<11> /nan /man ! skywalker.png C:-) c:-) C:) c:) ! monkey.png :-(|) :(|) +! cyclops.png O-) o-) # Following ICQ 6.0 [ICQ] -smile.png :-) :) +happy.png :-) :) neutral.png :-$ sad.png :-( :( -shock.png =-O +shocked.png =-O wink.png ;-) ;) tongue.png :-P :P :-p :p music.png [:-} laugh.png *JOKINGLY* -sleepy.png *TIRED* +sleeping.png *TIRED* crying.png :'( :'-( sick.png :-! kissed.png *KISSED* @@ -265,26 +313,27 @@ good.png *THUMBS\ UP* shout.png >:o >:O :-@ beer.png *DRINK* -smile-big.png :-D :D +excited.png :-D :D glasses-cool.png 8-) -in-love.png *IN\ LOVE* +amorous.png *IN\ LOVE* ! skywalker.png C:-) c:-) C:) c:) ! monkey.png :-(|) :(|) +! cyclops.png O-) o-) # Following Yahoo! Messenger 8.1 [Yahoo] -smile.png :) :-) +happy.png :) :-) question.png :-/ :-\\ -shock.png :-O :O :-o :o +shocked.png :-O :O :-o :o devil.png >:) angel.png O:-) o:-) 0:-) sick.png :-& -yawn.png (:| +sleepy.png (:| hypnotized.png @-) on-the-phone.png :)] sad.png :( :-( -in-love.png :x :-x :X :-X +amorous.png :x :-x :X :-X angry.png X-( x-( X( x( crying.png :(( glasses-nerdy.png :-B :-b @@ -301,11 +350,11 @@ thinking.png :-? waiting.png :-w :-W at-wits-end.png ~x( ~X( -smile-big.png :D :-D :d :-d +excited.png :D :-D :d :-d tongue.png :-P :P :-p :p glasses-cool.png B-) b-) neutral.png :| :-| -sleepy.png I-) i-) |-) +sleeping.png I-) i-) |-) clown.png :o) :O) doh.png #-o #-O weep.png :-< @@ -321,15 +370,16 @@ time-out.png :-t :-T hug-left.png >:D< >:d< love-over.png =(( -sweat.png #:-S #:-s +hot.png #:-S #:-s rotfl.png =)) :-j :-J loser.png L-) l-) party.png <:-P <:-p -nailbiting.png :-SS :-Ss :-sS :-ss +nervous.png :-SS :-Ss :-sS :-ss cowboy.png <):) desire.png 8-> ! skywalker.png C:-) c:-) C:) c:) ! monkey.png :-(|) :(|) +! cyclops.png O-) o-) # Hidden Yahoo emotes alien.png =:) >-) @@ -367,14 +417,14 @@ # Following MySpaceIM Beta 1.0.697.0 [MySpaceIM] -smile-big.png :D :-D +excited.png :D :-D devil.png }:) confused.png :Z glasses-nerdy.png B) bulgy-eyes.png %) freaked-out.png :E smile.png :) :-) -in-love.png :X +amorous.png :X laugh.png :)) mohawk.png -: mad-tongue.png X( @@ -392,3 +442,7 @@ wink.png ;-) ;) sad.png :[ kiss.png :x +! skywalker.png C:-) c:-) C:) c:) +! monkey.png :-(|) :(|) +! cyclops.png O-) o-) +
--- a/pidgin/pixmaps/emotes/small/16/Makefile.am Wed Nov 26 22:17:58 2008 +0000 +++ b/pidgin/pixmaps/emotes/small/16/Makefile.am Wed Nov 26 22:18:16 2008 +0000 @@ -1,4 +1,5 @@ SMILEYS = \ + amorous.png \ angel.png \ angry.png \ beer.png \ @@ -12,12 +13,15 @@ crying.png \ devil.png \ dont-know.png \ + excited.png \ grin.png \ + happy.png \ hug-left.png \ hug-right.png \ + in_love.png \ kiss.png \ - love.png \ meeting.png \ + mobile.png \ musical-note.png \ nerdy.png \ neutral.png \ @@ -27,18 +31,16 @@ question.png \ sad.png \ shame.png \ - shock.png \ + shocked.png \ sick.png \ silent.png \ + sleeping.png \ sleepy.png \ - smile-big.png \ - smile.png \ thinking.png \ tongue.png \ tv.png \ uhm-yeah.png \ - wink.png \ - yawn.png + wink.png pidginsmileypix_in_files = small.theme.in
--- a/pidgin/pixmaps/emotes/small/16/TODO Wed Nov 26 22:17:58 2008 +0000 +++ b/pidgin/pixmaps/emotes/small/16/TODO Wed Nov 26 22:18:16 2008 +0000 @@ -1,7 +1,18 @@ The following icons where just scaled down from the 24x24 and may need work: + afraid.png + amorous.png + disappointed.png + embarrassed.png + happy.png + hot.png + hungry.png + mean.png meeting.png + nervous.png question.png + sarcastic.png search.png + shocked.png sleepy.png smile-big.png tv.png @@ -13,7 +24,7 @@ cigarette.png coffee.png console.png - love.png + in_love.png musical-note.png party.png phone.png
--- a/pidgin/pixmaps/emotes/small/16/small.theme.in Wed Nov 26 22:17:58 2008 +0000 +++ b/pidgin/pixmaps/emotes/small/16/small.theme.in Wed Nov 26 22:18:16 2008 +0000 @@ -6,27 +6,54 @@ # Default smileys [default] -smile.png :) :-) -smile-big.png :-D :-d :D :d +happy.png :) :-) +excited.png :-D :-d :D :d sad.png :-( :( wink.png ;-) ;) tongue.png :P :-P :-p :p -shock.png =-O =-o +shocked.png =-O =-o kiss.png :-* -crying.png :'( +embarrassed.png :-[ +crying.png :'( :'-( thinking.png :-/ :-\\ angel.png O:-) o:-) +[XMPP] +# Following XEP-0038 + our default set, in default set order +happy.png :) :-) +excited.png :-D :-d :D :d +sad.png :-( :( +wink.png ;-) ;) +tongue.png :P :-P :-p :p +shocked.png =-O =-o +kiss.png :kiss: :-* +embarrassed.png :-[ +crying.png :'-( :'( +thinking.png :-/ :-\\ +angel.png O:-) o:-) + +# Following XEP-0038 +angry.png >:-( >:( +phone.png :telephone: +in_love.png :heart: :love: +musical-note.png :music: +beer.png :beer: +coffee.png :coffee: + +# Hidden icons from the default set. + + # Following AIM 6.1 [AIM] -smile.png :-) :) +happy.png :-) :) wink.png ;-) ;) sad.png :-( :( tongue.png :-P :P :-p :p -shock.png =-O +shocked.png =-O kiss.png :-* -smile-big.png :-D :D +excited.png :-D :D +embarrassed.png :-[ angel.png O:-) thinking.png :-\\ :-/ crying.png :'( @@ -34,19 +61,20 @@ # Following Windows Live Messenger 8.1 [MSN] -smile.png :) :-) -smile-big.png :D :d :-D :-d +happy.png :) :-) +excited.png :D :d :-D :-d wink.png ;) ;-) -shock.png :-O :-o :O :o +shocked.png :-O :-o :O :o tongue.png :P :p :-P :-p angry.png :@ :-@ +embarrassed.png :$ :-$ confused.png :S :s :-S :-s sad.png :( :-( crying.png :'( neutral.png :| :-| devil.png (6) angel.png (A) (a) -love.png (L) (l) +in_love.png (L) (l) musical-note.png (8) kiss.png (K) (k) camera.png (P) (p) @@ -55,12 +83,14 @@ hug-left.png ({) hug-right.png (}) beer.png (B) (b) +sarcastic.png ^o) sick.png +o( plate.png (pl) +mobile.png (mp) dont-know.png :^) thinking.png *-) party.png <:o) -yawn.png |-) +sleepy.png |-) # Hidden MSN emotes cigarette.png (ci) (CI) @@ -69,22 +99,27 @@ # Following QQ 2006 [QQ] -shock.png /:O /jy /surprised +shocked.png /:O /jy /surprised party.png /8-) /dy /revel crying.png /:< /ll /cry -sleepy.png /:Z /shui /sleep -smile-big.png /:D /cy /toothy_smile -smile.png /:) /wx /small_smile +sleeping.png /:Z /shui /sleep +embarrassed.png /:-| /gg /embarassed +excited.png /:D /cy /toothy_smile +happy.png /:) /wx /small_smile sad.png /:( /ng /sad sick.png /:T /tu /vomit -yawn.png /|-) /kun /sleepy +sleepy.png /|-) /kun /sleepy +hot.png /:L /sweat question.png /? /yiw /question +afraid.png /shake /fad /shake +amorous.png /love /aiq /love search.png /find /zhao /search hug-left.png /hug /yb /hug musical-note.png /music /yy /music coffee.png /coffee /kf /coffee +hungry.png /eat /fan /eat kiss.png /kiss /wen /kiss -love.png /heart /xin /heart +in_love.png /heart /xin /heart meeting.png /meeting /hy /meeting phone.png /phone /dh /phone tv.png /TV /ds /TV @@ -93,45 +128,53 @@ # Following ICQ 6.0 [ICQ] -smile.png :-) :) +happy.png :-) :) neutral.png :-$ sad.png :-( :( -shock.png =-O +shocked.png =-O wink.png ;-) ;) tongue.png :-P :P :-p :p -sleepy.png *TIRED* +sleeping.png *TIRED* crying.png :'( :'-( sick.png :-! kiss.png :-{} :-* +embarrassed.png :-[ devil.png ]:-> angel.png O:-) thinking.png :-\\ :-/ beer.png *DRINK* -smile-big.png :-D :D +excited.png :-D :D +amorous.png *IN\ LOVE* # Following Yahoo! Messenger 8.1 [Yahoo] -smile.png :) :-) +happy.png :) :-) question.png :-/ :-\\ -shock.png :-O :O :-o :o +shocked.png :-O :O :-o :o devil.png >:) angel.png O:-) o:-) 0:-) sick.png :-& -yawn.png (:| +sleepy.png (:| sad.png :( :-( +amorous.png :x :-x :X :-X angry.png X-( x-( X( x( crying.png :(( wink.png ;) ;-) +embarrassed.png :"> +mean.png :-> :> thinking.png :-? -smile-big.png :D :-D :d :-d +excited.png :D :-D :d :-d tongue.png :-P :P :-p :p neutral.png :| :-| -sleepy.png I-) i-) |-) +sleeping.png I-) i-) |-) kiss.png :-* :* confused.png :-S :-s +sarcastic.png /:) hug-left.png >:D< >:d< +hot.png #:-S #:-s party.png <:-P <:-p +nervous.png :-SS :-Ss :-sS :-ss # Hidden Yahoo emotes coffee.png ~o) ~O) @@ -144,13 +187,15 @@ # Following MySpaceIM Beta 1.0.697.0 [MySpaceIM] -smile-big.png :D :-D +excited.png :D :-D devil.png }:) confused.png :Z smile.png :) :-) +amorous.png :X shock.png :O neutral.png :| tongue.png :P :p wink.png ;-) ;) sad.png :[ kiss.png :x +
--- a/po/POTFILES.in Wed Nov 26 22:17:58 2008 +0000 +++ b/po/POTFILES.in Wed Nov 26 22:18:16 2008 +0000 @@ -124,6 +124,7 @@ libpurple/protocols/novell/nmuser.c libpurple/protocols/novell/novell.c libpurple/protocols/oscar/family_chatnav.c +libpurple/protocols/oscar/family_locate.c libpurple/protocols/oscar/flap_connection.c libpurple/protocols/oscar/libaim.c libpurple/protocols/oscar/libicq.c