Mercurial > pidgin
diff libpurple/protocols/jabber/presence.c @ 27501:6d26258e9f1d
propagate from branch 'im.pidgin.pidgin' (head ac87c285c7056f86005dc157b9870745de471f74)
to branch 'im.pidgin.cpw.darkrain42.roster' (head 976d874853ac9745edb77d3cf107b92ebc037c10)
author | Paul Aurich <paul@darkrain42.org> |
---|---|
date | Mon, 06 Jul 2009 04:37:41 +0000 |
parents | 9a5a9a4e7626 b41b69e8b341 |
children | 3bb1085235d0 |
line wrap: on
line diff
--- a/libpurple/protocols/jabber/presence.c Wed Jun 10 04:42:11 2009 +0000 +++ b/libpurple/protocols/jabber/presence.c Mon Jul 06 04:37:41 2009 +0000 @@ -251,7 +251,9 @@ { xmlnode *show, *status, *presence, *pri, *c; const char *show_string = NULL; +#ifdef USE_VV gboolean audio_enabled, video_enabled; +#endif presence = xmlnode_new("presence"); @@ -464,9 +466,6 @@ { const char *from; const char *type; - const char *real_jid = NULL; - const char *affiliation = NULL; - const char *role = NULL; char *status = NULL; int priority = 0; JabberID *jid; @@ -480,7 +479,6 @@ char *buddy_name; JabberBuddyState state = JABBER_BUDDY_STATE_UNKNOWN; xmlnode *y; - gboolean muc = FALSE; char *avatar_hash = NULL; xmlnode *caps = NULL; int idle = 0; @@ -490,34 +488,57 @@ from = xmlnode_get_attrib(packet, "from"); type = xmlnode_get_attrib(packet, "type"); - if(!(jb = jabber_buddy_find(js, from, TRUE))) - return; + jb = jabber_buddy_find(js, from, TRUE); + g_return_if_fail(jb != NULL); signal_return = GPOINTER_TO_INT(purple_signal_emit_return_1(jabber_plugin, "jabber-receiving-presence", js->gc, type, from, packet)); if (signal_return) return; - if(!(jid = jabber_id_new(from))) + jid = jabber_id_new(from); + if (jid == NULL) { + purple_debug_error("jabber", "Ignoring presence with malformed 'from' " + "JID: %s\n", from); return; + } if(jb->error_msg) { g_free(jb->error_msg); jb->error_msg = NULL; } - if(type && !strcmp(type, "error")) { + if (type == NULL) { + xmlnode *show; + char *show_data = NULL; + + state = JABBER_BUDDY_STATE_ONLINE; + + show = xmlnode_get_child(packet, "show"); + if (show) { + show_data = xmlnode_get_data(show); + if (show_data) { + state = jabber_buddy_show_get_state(show_data); + g_free(show_data); + } else + purple_debug_warning("jabber", "<show/> present on presence, " + "but no contents!\n"); + } + } else if (g_str_equal(type, "error")) { char *msg = jabber_parse_error(js, packet, NULL); state = JABBER_BUDDY_STATE_ERROR; jb->error_msg = msg ? msg : g_strdup(_("Unknown Error in presence")); - } else if(type && !strcmp(type, "subscribe")) { + } else if (g_str_equal(type, "subscribe")) { struct _jabber_add_permit *jap = g_new0(struct _jabber_add_permit, 1); gboolean onlist = FALSE; - PurpleBuddy *buddy = purple_find_buddy(purple_connection_get_account(js->gc), from); + PurpleAccount *account; + PurpleBuddy *buddy; JabberBuddy *jb = NULL; xmlnode *nick; + account = purple_connection_get_account(js->gc); + buddy = purple_find_buddy(account, from); nick = xmlnode_get_child_with_namespace(packet, "nick", "http://jabber.org/protocol/nick"); if (nick) nickname = xmlnode_get_data(nick); @@ -532,16 +553,17 @@ jap->who = g_strdup(from); jap->js = js; - purple_account_request_authorization(purple_connection_get_account(js->gc), from, NULL, nickname, NULL, onlist, - authorize_add_cb, deny_add_cb, jap); + purple_account_request_authorization(account, from, NULL, nickname, + NULL, onlist, authorize_add_cb, deny_add_cb, jap); + g_free(nickname); jabber_id_free(jid); return; - } else if(type && !strcmp(type, "subscribed")) { + } else if (g_str_equal(type, "subscribed")) { /* we've been allowed to see their presence, but we don't care */ jabber_id_free(jid); return; - } else if(type && !strcmp(type, "unsubscribe")) { + } else if (g_str_equal(type, "unsubscribe")) { /* XXX I'm not sure this is the right way to handle this, it * might be better to add "unsubscribe" to the presence status * if lower down, but I'm not sure. */ @@ -550,14 +572,19 @@ * acknowledging this (and the others) at some point. */ jabber_id_free(jid); return; + } else if (g_str_equal(type, "probe")) { + purple_debug_warning("jabber", "Ignoring presence probe\n"); + jabber_id_free(jid); + return; + } else if (g_str_equal(type, "unavailable")) { + state = JABBER_BUDDY_STATE_UNAVAILABLE; + } else if (g_str_equal(type, "unsubscribed")) { + state = JABBER_BUDDY_STATE_UNKNOWN; } else { - if((y = xmlnode_get_child(packet, "show"))) { - char *show = xmlnode_get_data(y); - state = jabber_buddy_show_get_state(show); - g_free(show); - } else { - state = JABBER_BUDDY_STATE_ONLINE; - } + purple_debug_warning("jabber", "Ignoring presence with invalid type " + "'%s'\n", type); + jabber_id_free(jid); + return; } @@ -592,49 +619,6 @@ /* XXX: compare the time. jabber:x:delay can happen on presence packets that aren't really and truly delayed */ delayed = TRUE; stamp = xmlnode_get_attrib(y, "stamp"); - } else if(!strcmp(xmlns, "http://jabber.org/protocol/muc#user")) { - xmlnode *z; - - muc = TRUE; - if((z = xmlnode_get_child(y, "status"))) { - const char *code = xmlnode_get_attrib(z, "code"); - if(code && !strcmp(code, "201")) { - if((chat = jabber_chat_find(js, jid->node, jid->domain))) { - chat->config_dialog_type = PURPLE_REQUEST_ACTION; - chat->config_dialog_handle = - purple_request_action(js->gc, - _("Create New Room"), - _("Create New Room"), - _("You are creating a new room. Would" - " you like to configure it, or" - " accept the default settings?"), - /* Default Action */ 1, - purple_connection_get_account(js->gc), NULL, chat->conv, - chat, 2, - _("_Configure Room"), G_CALLBACK(jabber_chat_request_room_configure), - _("_Accept Defaults"), G_CALLBACK(jabber_chat_create_instant_room)); - } - } else if(code && !strcmp(code, "210")) { - /* server rewrote room-nick */ - if((chat = jabber_chat_find(js, jid->node, jid->domain))) { - g_free(chat->handle); - chat->handle = g_strdup(jid->resource); - } - } - } - if((z = xmlnode_get_child(y, "item"))) { - real_jid = xmlnode_get_attrib(z, "jid"); - affiliation = xmlnode_get_attrib(z, "affiliation"); - role = xmlnode_get_attrib(z, "role"); - if(affiliation != NULL && !strcmp(affiliation, "owner")) - flags |= PURPLE_CBFLAGS_FOUNDER; - if (role != NULL) { - if (!strcmp(role, "moderator")) - flags |= PURPLE_CBFLAGS_OP; - else if (!strcmp(role, "participant")) - flags |= PURPLE_CBFLAGS_VOICE; - } - } } else if(!strcmp(xmlns, "vcard-temp:x:update")) { xmlnode *photo = xmlnode_get_child(y, "photo"); if(photo) { @@ -691,75 +675,12 @@ return; } - - if(type && !strcmp(type, "unavailable")) { - gboolean nick_change = FALSE; - - /* If the chat nick is invalid, we haven't yet joined, or we've - * already left (it was probably us leaving after we closed the - * chat), we don't care. - */ - if (!jid->resource || !chat->conv || chat->left) { - if (chat->left && - jid->resource && chat->handle && !strcmp(jid->resource, chat->handle)) - jabber_chat_destroy(chat); - jabber_id_free(jid); - g_free(status); - g_free(avatar_hash); - g_free(nickname); - return; - } + if (type == NULL) { + xmlnode *x; + const char *real_jid = NULL; + const char *affiliation = NULL; + const char *role = NULL; - jabber_buddy_remove_resource(jb, jid->resource); - if(chat->muc) { - xmlnode *x; - for(x = xmlnode_get_child(packet, "x"); x; x = xmlnode_get_next_twin(x)) { - const char *xmlns, *nick, *code; - xmlnode *stat, *item; - if(!(xmlns = xmlnode_get_namespace(x)) || - strcmp(xmlns, "http://jabber.org/protocol/muc#user")) - continue; - if(!(stat = xmlnode_get_child(x, "status"))) - continue; - if(!(code = xmlnode_get_attrib(stat, "code"))) - continue; - if(!strcmp(code, "301")) { - /* XXX: we got banned */ - } else if(!strcmp(code, "303")) { - if(!(item = xmlnode_get_child(x, "item"))) - continue; - if(!(nick = xmlnode_get_attrib(item, "nick"))) - continue; - nick_change = TRUE; - if(!strcmp(jid->resource, chat->handle)) { - g_free(chat->handle); - chat->handle = g_strdup(nick); - } - purple_conv_chat_rename_user(PURPLE_CONV_CHAT(chat->conv), jid->resource, nick); - jabber_chat_remove_handle(chat, jid->resource); - break; - } else if(!strcmp(code, "307")) { - /* XXX: we got kicked */ - } else if(!strcmp(code, "321")) { - /* XXX: removed due to an affiliation change */ - } else if(!strcmp(code, "322")) { - /* XXX: removed because room is now members-only */ - } else if(!strcmp(code, "332")) { - /* XXX: removed due to system shutdown */ - } - } - } - if(!nick_change) { - if(!g_utf8_collate(jid->resource, chat->handle)) { - serv_got_chat_left(js->gc, chat->id); - jabber_chat_destroy(chat); - } else { - purple_conv_chat_remove_user(PURPLE_CONV_CHAT(chat->conv), jid->resource, - status); - jabber_chat_remove_handle(chat, jid->resource); - } - } - } else { /* * XEP-0045 mandates the presence to include a resource (which is * treated as the chat nick). Some non-compliant servers allow @@ -773,10 +694,61 @@ return; } + x = xmlnode_get_child_with_namespace(packet, "x", + "http://jabber.org/protocol/muc#user"); + if (x) { + xmlnode *status_node; + xmlnode *item_node; + + status_node = xmlnode_get_child(x, "status"); + if (status_node) { + const char *code = xmlnode_get_attrib(status_node, "code"); + if (purple_strequal(code, "201")) { + if ((chat = jabber_chat_find(js, jid->node, jid->domain))) { + chat->config_dialog_type = PURPLE_REQUEST_ACTION; + chat->config_dialog_handle = + purple_request_action(js->gc, + _("Create New Room"), + _("Create New Room"), + _("You are creating a new room. Would" + " you like to configure it, or" + " accept the default settings?"), + /* Default Action */ 1, + purple_connection_get_account(js->gc), NULL, chat->conv, + chat, 2, + _("_Configure Room"), G_CALLBACK(jabber_chat_request_room_configure), + _("_Accept Defaults"), G_CALLBACK(jabber_chat_create_instant_room)); + } + } else if (purple_strequal(code, "210")) { + /* server rewrote room-nick */ + if((chat = jabber_chat_find(js, jid->node, jid->domain))) { + g_free(chat->handle); + chat->handle = g_strdup(jid->resource); + } + } + } + + item_node = xmlnode_get_child(x, "item"); + if (item_node) { + real_jid = xmlnode_get_attrib(item_node, "jid"); + affiliation = xmlnode_get_attrib(item_node, "affiliation"); + role = xmlnode_get_attrib(item_node, "role"); + + if (purple_strequal(affiliation, "owner")) + flags |= PURPLE_CBFLAGS_FOUNDER; + if (role) { + if (g_str_equal(role, "moderator")) + flags |= PURPLE_CBFLAGS_OP; + else if (g_str_equal(role, "participant")) + flags |= PURPLE_CBFLAGS_VOICE; + } + } + } + if(!chat->conv) { char *room_jid = g_strdup_printf("%s@%s", jid->node, jid->domain); chat->id = i++; - chat->muc = muc; + chat->muc = (x != NULL); chat->conv = serv_got_joined_chat(js->gc, chat->id, room_jid); purple_conv_chat_set_nick(PURPLE_CONV_CHAT(chat->conv), chat->handle); @@ -795,6 +767,133 @@ else purple_conv_chat_user_set_flags(PURPLE_CONV_CHAT(chat->conv), jid->resource, flags); + } else if (g_str_equal(type, "unavailable")) { + gboolean nick_change = FALSE; + gboolean kick = FALSE; + gboolean is_our_resource = FALSE; /* Is the presence about us? */ + + /* If the chat nick is invalid, we haven't yet joined, or we've + * already left (it was probably us leaving after we closed the + * chat), we don't care. + */ + if (!jid->resource || !chat->conv || chat->left) { + if (chat->left && + jid->resource && chat->handle && !strcmp(jid->resource, chat->handle)) + jabber_chat_destroy(chat); + jabber_id_free(jid); + g_free(status); + g_free(avatar_hash); + g_free(nickname); + return; + } + + is_our_resource = (0 == g_utf8_collate(jid->resource, chat->handle)); + + jabber_buddy_remove_resource(jb, jid->resource); + if(chat->muc) { + xmlnode *x; + for(x = xmlnode_get_child(packet, "x"); x; x = xmlnode_get_next_twin(x)) { + const char *xmlns, *nick, *code; + xmlnode *stat, *item; + if(!(xmlns = xmlnode_get_namespace(x)) || + strcmp(xmlns, "http://jabber.org/protocol/muc#user")) + continue; + if(!(stat = xmlnode_get_child(x, "status"))) + continue; + if(!(code = xmlnode_get_attrib(stat, "code"))) + continue; + + item = xmlnode_get_child(x, "item"); + + if(!strcmp(code, "301")) { + /* XXX: we got banned */ + } else if(!strcmp(code, "303")) { + if (!item) + continue; + if(!(nick = xmlnode_get_attrib(item, "nick"))) + continue; + nick_change = TRUE; + if(!strcmp(jid->resource, chat->handle)) { + g_free(chat->handle); + chat->handle = g_strdup(nick); + } + purple_conv_chat_rename_user(PURPLE_CONV_CHAT(chat->conv), jid->resource, nick); + jabber_chat_remove_handle(chat, jid->resource); + break; + } else if(!strcmp(code, "307")) { + /* Someone was kicked from the room */ + xmlnode *reason = NULL, *actor = NULL; + const char *actor_name = NULL; + char *reason_text = NULL; + char *tmp; + + kick = TRUE; + + if (item) { + reason = xmlnode_get_child(item, "reason"); + actor = xmlnode_get_child(item, "actor"); + + if (reason != NULL) + reason_text = xmlnode_get_data(reason); + if (actor != NULL) + actor_name = xmlnode_get_attrib(actor, "jid"); + } + + if (reason_text == NULL) + reason_text = g_strdup(_("No reason")); + + if (is_our_resource) { + if (actor_name != NULL) + tmp = g_strdup_printf(_("You have been kicked by %s: (%s)"), + actor_name, reason_text); + else + tmp = g_strdup_printf(_("You have been kicked: (%s)"), + reason_text); + } else { + if (actor_name != NULL) + tmp = g_strdup_printf(_("Kicked by %s (%s)"), + actor_name, reason_text); + else + tmp = g_strdup_printf(_("Kicked (%s)"), + reason_text); + } + + g_free(reason_text); + g_free(status); + status = tmp; + } else if(!strcmp(code, "321")) { + /* XXX: removed due to an affiliation change */ + } else if(!strcmp(code, "322")) { + /* XXX: removed because room is now members-only */ + } else if(!strcmp(code, "332")) { + /* XXX: removed due to system shutdown */ + } + } + } + if(!nick_change) { + if (is_our_resource) { + if (kick) + purple_conv_chat_write(PURPLE_CONV_CHAT(chat->conv), jid->resource, + status, PURPLE_MESSAGE_SYSTEM, time(NULL)); + + serv_got_chat_left(js->gc, chat->id); + jabber_chat_destroy(chat); + } else { + purple_conv_chat_remove_user(PURPLE_CONV_CHAT(chat->conv), jid->resource, + status); + jabber_chat_remove_handle(chat, jid->resource); + } + } + } else { + /* A type that isn't available or unavailable */ + purple_debug_error("jabber", "MUC presence with bad type: %s\n", + type); + + jabber_id_free(jid); + g_free(avatar_hash); + g_free(status); + g_free(nickname); + g_return_if_reached(); } } else { buddy_name = g_strdup_printf("%s%s%s", jid->node ? jid->node : "", @@ -841,8 +940,8 @@ } if(state == JABBER_BUDDY_STATE_ERROR || - (type && (!strcmp(type, "unavailable") || - !strcmp(type, "unsubscribed")))) { + (type && (g_str_equal(type, "unavailable") || + g_str_equal(type, "unsubscribed")))) { PurpleConversation *conv; jabber_buddy_remove_resource(jb, jid->resource); @@ -871,7 +970,7 @@ g_free(buddy_name); } - if (caps && (!type || g_str_equal(type, "available"))) { + if (caps && !type) { /* handle Entity Capabilities (XEP-0115) */ const char *node = xmlnode_get_attrib(caps, "node"); const char *ver = xmlnode_get_attrib(caps, "ver");