Mercurial > hg
diff mcabber/mcabber/xmpp.c @ 1999:51f032d5ca22
Add support for XEP-0115 Entity Capabilities, with offline cache
author | Hermitifier |
---|---|
date | Mon, 03 Oct 2011 16:00:34 +0200 |
parents | 41667bc02883 |
children | aa7e03c35488 |
line wrap: on
line diff
--- a/mcabber/mcabber/xmpp.c Sun Jul 24 13:30:47 2011 +0200 +++ b/mcabber/mcabber/xmpp.c Mon Oct 03 16:00:34 2011 +0200 @@ -318,8 +318,9 @@ #ifdef HAVE_LIBOTR int otr_msg = 0; #endif + char *barejid; #if defined HAVE_GPGME || defined XEP0022 || defined XEP0085 - char *rname, *barejid; + char *rname; GSList *sl_buddy; #endif #if defined XEP0022 || defined XEP0085 @@ -349,10 +350,10 @@ subtype = LM_MESSAGE_SUB_TYPE_CHAT; } + barejid = jidtodisp(fjid); #if defined HAVE_GPGME || defined HAVE_LIBOTR || \ defined XEP0022 || defined XEP0085 rname = strchr(fjid, JID_RESOURCE_SEPARATOR); - barejid = jidtodisp(fjid); sl_buddy = roster_find(barejid, jidsearch, ROSTER_TYPE_USER); // If we can get a resource name, we use it. Else we use NULL, @@ -406,7 +407,6 @@ } #endif // HAVE_GPGME - g_free(barejid); #endif // HAVE_GPGME || defined XEP0022 || defined XEP0085 x = lm_message_new_with_sub_type(fjid, LM_MESSAGE_TYPE_MESSAGE, subtype); @@ -428,12 +428,13 @@ // XEP-0184: Message Receipts if (sl_buddy && xep184 && caps_has_feature(buddy_resource_getcaps(sl_buddy->data, rname), - NS_RECEIPTS)) { + NS_RECEIPTS, barejid)) { lm_message_node_set_attribute (lm_message_node_add_child(x->node, "request", NULL), "xmlns", NS_RECEIPTS); *xep184 = lm_message_handler_new(cb_xep184, NULL, NULL); } + g_free(barejid); #if defined XEP0022 || defined XEP0085 // If typing notifications are disabled, we can skip all this stuff... @@ -1326,28 +1327,99 @@ LmMessage *m, gpointer user_data) { char *ver = user_data; + char *hash; + const char *from = lm_message_get_from(m); + char *bjid = jidtodisp(from); LmMessageSubType mstype = lm_message_get_sub_type(m); - caps_add(ver); - if (mstype == LM_MESSAGE_SUB_TYPE_ERROR) { - display_server_error(lm_message_node_get_child(m->node, "error"), - lm_message_get_from(m)); - } else if (mstype == LM_MESSAGE_SUB_TYPE_RESULT) { + hash = strchr(ver, ','); + if (hash) + *hash++ = '\0'; + + if (mstype == LM_MESSAGE_SUB_TYPE_RESULT) { LmMessageNode *info; LmMessageNode *query = lm_message_node_get_child(m->node, "query"); + if (caps_has_hash(ver, bjid)) + goto caps_callback_return; + + caps_add(ver); + info = lm_message_node_get_child(query, "identity"); - if (info) - caps_set_identity(ver, lm_message_node_get_attribute(info, "category"), - lm_message_node_get_attribute(info, "name"), - lm_message_node_get_attribute(info, "type")); + while (info) { + if (!g_strcmp0(info->name, "identity")) + caps_add_identity(ver, lm_message_node_get_attribute(info, "category"), + lm_message_node_get_attribute(info, "name"), + lm_message_node_get_attribute(info, "type"), + lm_message_node_get_attribute(info, "xml:lang")); + info = info->next; + } + info = lm_message_node_get_child(query, "feature"); while (info) { if (!g_strcmp0(info->name, "feature")) caps_add_feature(ver, lm_message_node_get_attribute(info, "var")); info = info->next; } + + info = lm_message_node_get_child(query, "x"); + { + LmMessageNode *field; + LmMessageNode *value; + const char *formtype, *var; + while (info) { + if (!g_strcmp0(info->name, "x") + && !g_strcmp0(lm_message_node_get_attribute(info, "type"), + "result") + && !g_strcmp0(lm_message_node_get_attribute(info, "xmlns"), + "jabber:x:data")) { + field = lm_message_node_get_child(info, "field"); + formtype = NULL; + while (field) { + if (!g_strcmp0(field->name, "field") + && !g_strcmp0(lm_message_node_get_attribute(field, "var"), + "FORM_TYPE") + && !g_strcmp0(lm_message_node_get_attribute(field, "type"), + "hidden")) { + value = lm_message_node_get_child(field, "value"); + if (value) + formtype = lm_message_node_get_value(value); + } + field = field->next; + } + if (formtype) { + caps_add_dataform(ver, formtype); + field = lm_message_node_get_child(info, "field"); + while (field) { + var = lm_message_node_get_attribute(field, "var"); + if (!g_strcmp0(field->name, "field") + && (g_strcmp0(var, "FORM_TYPE") + || g_strcmp0(lm_message_node_get_attribute(field, "type"), + "hidden"))) { + value = lm_message_node_get_child(field, "value"); + while (value) { + if (!g_strcmp0(value->name, "value")) + caps_add_dataform_field(ver, formtype, var, + lm_message_node_get_value(value)); + value = value->next; + } + } + field = field->next; + } + } + } + info = info->next; + } + } + + if (caps_verify(ver, hash)) + caps_copy_to_persistent(ver, lm_message_node_to_string(query)); + else + caps_move_to_local(ver, bjid); } + +caps_callback_return: + g_free(bjid); g_free(ver); return LM_HANDLER_RESULT_REMOVE_MESSAGE; } @@ -1462,12 +1534,15 @@ caps = lm_message_node_find_xmlns(m->node, NS_CAPS); if (caps && ust != offline) { const char *ver = lm_message_node_get_attribute(caps, "ver"); + const char *hash = lm_message_node_get_attribute(caps, "hash"); GSList *sl_buddy = NULL; - if (!ver) { - scr_LogPrint(LPRINT_LOGNORM, "Error: malformed caps version (%s)", bjid); + if (!hash) { + // No support for legacy format goto handle_presence_return; } + if (!ver || !g_strcmp0(ver, "") || !g_strcmp0(hash, "")) + goto handle_presence_return; if (rname) sl_buddy = roster_find(bjid, jidsearch, ROSTER_TYPE_USER); @@ -1475,7 +1550,7 @@ if (sl_buddy && buddy_getonserverflag(sl_buddy->data)) { buddy_resource_setcaps(sl_buddy->data, rname, ver); - if (!caps_has_hash(ver)) { + if (!caps_has_hash(ver, bjid) && !caps_restore_from_persistent(ver)) { char *node; LmMessageHandler *handler; LmMessage *iq = lm_message_new_with_sub_type(from, LM_MESSAGE_TYPE_IQ, @@ -1489,7 +1564,9 @@ "node", node, NULL); g_free(node); - handler = lm_message_handler_new(cb_caps, g_strdup(ver), NULL); + handler = lm_message_handler_new(cb_caps, + g_strdup_printf("%s,%s",ver,hash), + NULL); lm_connection_send_with_reply(connection, iq, handler, NULL); lm_message_unref(iq); lm_message_handler_unref(handler);