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 }