Mercurial > ~mikael > mcabber > hg
comparison 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 |
comparison
equal
deleted
inserted
replaced
1998:41667bc02883 | 1999:51f032d5ca22 |
---|---|
316 LmMessage *x; | 316 LmMessage *x; |
317 LmMessageSubType subtype; | 317 LmMessageSubType subtype; |
318 #ifdef HAVE_LIBOTR | 318 #ifdef HAVE_LIBOTR |
319 int otr_msg = 0; | 319 int otr_msg = 0; |
320 #endif | 320 #endif |
321 char *barejid; | |
321 #if defined HAVE_GPGME || defined XEP0022 || defined XEP0085 | 322 #if defined HAVE_GPGME || defined XEP0022 || defined XEP0085 |
322 char *rname, *barejid; | 323 char *rname; |
323 GSList *sl_buddy; | 324 GSList *sl_buddy; |
324 #endif | 325 #endif |
325 #if defined XEP0022 || defined XEP0085 | 326 #if defined XEP0022 || defined XEP0085 |
326 LmMessageNode *event; | 327 LmMessageNode *event; |
327 struct xep0085 *xep85 = NULL; | 328 struct xep0085 *xep85 = NULL; |
347 subtype = LM_MESSAGE_SUB_TYPE_GROUPCHAT; | 348 subtype = LM_MESSAGE_SUB_TYPE_GROUPCHAT; |
348 else | 349 else |
349 subtype = LM_MESSAGE_SUB_TYPE_CHAT; | 350 subtype = LM_MESSAGE_SUB_TYPE_CHAT; |
350 } | 351 } |
351 | 352 |
353 barejid = jidtodisp(fjid); | |
352 #if defined HAVE_GPGME || defined HAVE_LIBOTR || \ | 354 #if defined HAVE_GPGME || defined HAVE_LIBOTR || \ |
353 defined XEP0022 || defined XEP0085 | 355 defined XEP0022 || defined XEP0085 |
354 rname = strchr(fjid, JID_RESOURCE_SEPARATOR); | 356 rname = strchr(fjid, JID_RESOURCE_SEPARATOR); |
355 barejid = jidtodisp(fjid); | |
356 sl_buddy = roster_find(barejid, jidsearch, ROSTER_TYPE_USER); | 357 sl_buddy = roster_find(barejid, jidsearch, ROSTER_TYPE_USER); |
357 | 358 |
358 // If we can get a resource name, we use it. Else we use NULL, | 359 // If we can get a resource name, we use it. Else we use NULL, |
359 // which hopefully will give us the most likely resource. | 360 // which hopefully will give us the most likely resource. |
360 if (rname) | 361 if (rname) |
404 } | 405 } |
405 } | 406 } |
406 } | 407 } |
407 #endif // HAVE_GPGME | 408 #endif // HAVE_GPGME |
408 | 409 |
409 g_free(barejid); | |
410 #endif // HAVE_GPGME || defined XEP0022 || defined XEP0085 | 410 #endif // HAVE_GPGME || defined XEP0022 || defined XEP0085 |
411 | 411 |
412 x = lm_message_new_with_sub_type(fjid, LM_MESSAGE_TYPE_MESSAGE, subtype); | 412 x = lm_message_new_with_sub_type(fjid, LM_MESSAGE_TYPE_MESSAGE, subtype); |
413 lm_message_node_add_child(x->node, "body", | 413 lm_message_node_add_child(x->node, "body", |
414 enc ? "This message is PGP-encrypted." : text); | 414 enc ? "This message is PGP-encrypted." : text); |
426 } | 426 } |
427 | 427 |
428 // XEP-0184: Message Receipts | 428 // XEP-0184: Message Receipts |
429 if (sl_buddy && xep184 && | 429 if (sl_buddy && xep184 && |
430 caps_has_feature(buddy_resource_getcaps(sl_buddy->data, rname), | 430 caps_has_feature(buddy_resource_getcaps(sl_buddy->data, rname), |
431 NS_RECEIPTS)) { | 431 NS_RECEIPTS, barejid)) { |
432 lm_message_node_set_attribute | 432 lm_message_node_set_attribute |
433 (lm_message_node_add_child(x->node, "request", NULL), | 433 (lm_message_node_add_child(x->node, "request", NULL), |
434 "xmlns", NS_RECEIPTS); | 434 "xmlns", NS_RECEIPTS); |
435 *xep184 = lm_message_handler_new(cb_xep184, NULL, NULL); | 435 *xep184 = lm_message_handler_new(cb_xep184, NULL, NULL); |
436 } | 436 } |
437 g_free(barejid); | |
437 | 438 |
438 #if defined XEP0022 || defined XEP0085 | 439 #if defined XEP0022 || defined XEP0085 |
439 // If typing notifications are disabled, we can skip all this stuff... | 440 // If typing notifications are disabled, we can skip all this stuff... |
440 if (chatstates_disabled || type == ROSTER_TYPE_ROOM) | 441 if (chatstates_disabled || type == ROSTER_TYPE_ROOM) |
441 goto xmpp_send_msg_no_chatstates; | 442 goto xmpp_send_msg_no_chatstates; |
1324 | 1325 |
1325 static LmHandlerResult cb_caps(LmMessageHandler *h, LmConnection *c, | 1326 static LmHandlerResult cb_caps(LmMessageHandler *h, LmConnection *c, |
1326 LmMessage *m, gpointer user_data) | 1327 LmMessage *m, gpointer user_data) |
1327 { | 1328 { |
1328 char *ver = user_data; | 1329 char *ver = user_data; |
1330 char *hash; | |
1331 const char *from = lm_message_get_from(m); | |
1332 char *bjid = jidtodisp(from); | |
1329 LmMessageSubType mstype = lm_message_get_sub_type(m); | 1333 LmMessageSubType mstype = lm_message_get_sub_type(m); |
1330 | 1334 |
1331 caps_add(ver); | 1335 hash = strchr(ver, ','); |
1332 if (mstype == LM_MESSAGE_SUB_TYPE_ERROR) { | 1336 if (hash) |
1333 display_server_error(lm_message_node_get_child(m->node, "error"), | 1337 *hash++ = '\0'; |
1334 lm_message_get_from(m)); | 1338 |
1335 } else if (mstype == LM_MESSAGE_SUB_TYPE_RESULT) { | 1339 if (mstype == LM_MESSAGE_SUB_TYPE_RESULT) { |
1336 LmMessageNode *info; | 1340 LmMessageNode *info; |
1337 LmMessageNode *query = lm_message_node_get_child(m->node, "query"); | 1341 LmMessageNode *query = lm_message_node_get_child(m->node, "query"); |
1338 | 1342 |
1343 if (caps_has_hash(ver, bjid)) | |
1344 goto caps_callback_return; | |
1345 | |
1346 caps_add(ver); | |
1347 | |
1339 info = lm_message_node_get_child(query, "identity"); | 1348 info = lm_message_node_get_child(query, "identity"); |
1340 if (info) | 1349 while (info) { |
1341 caps_set_identity(ver, lm_message_node_get_attribute(info, "category"), | 1350 if (!g_strcmp0(info->name, "identity")) |
1342 lm_message_node_get_attribute(info, "name"), | 1351 caps_add_identity(ver, lm_message_node_get_attribute(info, "category"), |
1343 lm_message_node_get_attribute(info, "type")); | 1352 lm_message_node_get_attribute(info, "name"), |
1353 lm_message_node_get_attribute(info, "type"), | |
1354 lm_message_node_get_attribute(info, "xml:lang")); | |
1355 info = info->next; | |
1356 } | |
1357 | |
1344 info = lm_message_node_get_child(query, "feature"); | 1358 info = lm_message_node_get_child(query, "feature"); |
1345 while (info) { | 1359 while (info) { |
1346 if (!g_strcmp0(info->name, "feature")) | 1360 if (!g_strcmp0(info->name, "feature")) |
1347 caps_add_feature(ver, lm_message_node_get_attribute(info, "var")); | 1361 caps_add_feature(ver, lm_message_node_get_attribute(info, "var")); |
1348 info = info->next; | 1362 info = info->next; |
1349 } | 1363 } |
1350 } | 1364 |
1365 info = lm_message_node_get_child(query, "x"); | |
1366 { | |
1367 LmMessageNode *field; | |
1368 LmMessageNode *value; | |
1369 const char *formtype, *var; | |
1370 while (info) { | |
1371 if (!g_strcmp0(info->name, "x") | |
1372 && !g_strcmp0(lm_message_node_get_attribute(info, "type"), | |
1373 "result") | |
1374 && !g_strcmp0(lm_message_node_get_attribute(info, "xmlns"), | |
1375 "jabber:x:data")) { | |
1376 field = lm_message_node_get_child(info, "field"); | |
1377 formtype = NULL; | |
1378 while (field) { | |
1379 if (!g_strcmp0(field->name, "field") | |
1380 && !g_strcmp0(lm_message_node_get_attribute(field, "var"), | |
1381 "FORM_TYPE") | |
1382 && !g_strcmp0(lm_message_node_get_attribute(field, "type"), | |
1383 "hidden")) { | |
1384 value = lm_message_node_get_child(field, "value"); | |
1385 if (value) | |
1386 formtype = lm_message_node_get_value(value); | |
1387 } | |
1388 field = field->next; | |
1389 } | |
1390 if (formtype) { | |
1391 caps_add_dataform(ver, formtype); | |
1392 field = lm_message_node_get_child(info, "field"); | |
1393 while (field) { | |
1394 var = lm_message_node_get_attribute(field, "var"); | |
1395 if (!g_strcmp0(field->name, "field") | |
1396 && (g_strcmp0(var, "FORM_TYPE") | |
1397 || g_strcmp0(lm_message_node_get_attribute(field, "type"), | |
1398 "hidden"))) { | |
1399 value = lm_message_node_get_child(field, "value"); | |
1400 while (value) { | |
1401 if (!g_strcmp0(value->name, "value")) | |
1402 caps_add_dataform_field(ver, formtype, var, | |
1403 lm_message_node_get_value(value)); | |
1404 value = value->next; | |
1405 } | |
1406 } | |
1407 field = field->next; | |
1408 } | |
1409 } | |
1410 } | |
1411 info = info->next; | |
1412 } | |
1413 } | |
1414 | |
1415 if (caps_verify(ver, hash)) | |
1416 caps_copy_to_persistent(ver, lm_message_node_to_string(query)); | |
1417 else | |
1418 caps_move_to_local(ver, bjid); | |
1419 } | |
1420 | |
1421 caps_callback_return: | |
1422 g_free(bjid); | |
1351 g_free(ver); | 1423 g_free(ver); |
1352 return LM_HANDLER_RESULT_REMOVE_MESSAGE; | 1424 return LM_HANDLER_RESULT_REMOVE_MESSAGE; |
1353 } | 1425 } |
1354 | 1426 |
1355 static LmHandlerResult handle_presence(LmMessageHandler *handler, | 1427 static LmHandlerResult handle_presence(LmMessageHandler *handler, |
1460 | 1532 |
1461 // XEP-0115 Entity Capabilities | 1533 // XEP-0115 Entity Capabilities |
1462 caps = lm_message_node_find_xmlns(m->node, NS_CAPS); | 1534 caps = lm_message_node_find_xmlns(m->node, NS_CAPS); |
1463 if (caps && ust != offline) { | 1535 if (caps && ust != offline) { |
1464 const char *ver = lm_message_node_get_attribute(caps, "ver"); | 1536 const char *ver = lm_message_node_get_attribute(caps, "ver"); |
1537 const char *hash = lm_message_node_get_attribute(caps, "hash"); | |
1465 GSList *sl_buddy = NULL; | 1538 GSList *sl_buddy = NULL; |
1466 | 1539 |
1467 if (!ver) { | 1540 if (!hash) { |
1468 scr_LogPrint(LPRINT_LOGNORM, "Error: malformed caps version (%s)", bjid); | 1541 // No support for legacy format |
1469 goto handle_presence_return; | 1542 goto handle_presence_return; |
1470 } | 1543 } |
1544 if (!ver || !g_strcmp0(ver, "") || !g_strcmp0(hash, "")) | |
1545 goto handle_presence_return; | |
1471 | 1546 |
1472 if (rname) | 1547 if (rname) |
1473 sl_buddy = roster_find(bjid, jidsearch, ROSTER_TYPE_USER); | 1548 sl_buddy = roster_find(bjid, jidsearch, ROSTER_TYPE_USER); |
1474 // Only cache the caps if the user is on the roster | 1549 // Only cache the caps if the user is on the roster |
1475 if (sl_buddy && buddy_getonserverflag(sl_buddy->data)) { | 1550 if (sl_buddy && buddy_getonserverflag(sl_buddy->data)) { |
1476 buddy_resource_setcaps(sl_buddy->data, rname, ver); | 1551 buddy_resource_setcaps(sl_buddy->data, rname, ver); |
1477 | 1552 |
1478 if (!caps_has_hash(ver)) { | 1553 if (!caps_has_hash(ver, bjid) && !caps_restore_from_persistent(ver)) { |
1479 char *node; | 1554 char *node; |
1480 LmMessageHandler *handler; | 1555 LmMessageHandler *handler; |
1481 LmMessage *iq = lm_message_new_with_sub_type(from, LM_MESSAGE_TYPE_IQ, | 1556 LmMessage *iq = lm_message_new_with_sub_type(from, LM_MESSAGE_TYPE_IQ, |
1482 LM_MESSAGE_SUB_TYPE_GET); | 1557 LM_MESSAGE_SUB_TYPE_GET); |
1483 node = g_strdup_printf("%s#%s", | 1558 node = g_strdup_printf("%s#%s", |
1487 (lm_message_node_add_child(iq->node, "query", NULL), | 1562 (lm_message_node_add_child(iq->node, "query", NULL), |
1488 "xmlns", NS_DISCO_INFO, | 1563 "xmlns", NS_DISCO_INFO, |
1489 "node", node, | 1564 "node", node, |
1490 NULL); | 1565 NULL); |
1491 g_free(node); | 1566 g_free(node); |
1492 handler = lm_message_handler_new(cb_caps, g_strdup(ver), NULL); | 1567 handler = lm_message_handler_new(cb_caps, |
1568 g_strdup_printf("%s,%s",ver,hash), | |
1569 NULL); | |
1493 lm_connection_send_with_reply(connection, iq, handler, NULL); | 1570 lm_connection_send_with_reply(connection, iq, handler, NULL); |
1494 lm_message_unref(iq); | 1571 lm_message_unref(iq); |
1495 lm_message_handler_unref(handler); | 1572 lm_message_handler_unref(handler); |
1496 } | 1573 } |
1497 } | 1574 } |