| 344 g_hash_table_destroy(capstable); |
344 g_hash_table_destroy(capstable); |
| 345 g_hash_table_destroy(nodetable); |
345 g_hash_table_destroy(nodetable); |
| 346 capstable = nodetable = NULL; |
346 capstable = nodetable = NULL; |
| 347 } |
347 } |
| 348 |
348 |
| |
349 gboolean jabber_caps_exts_known(const JabberCapsClientInfo *info, |
| |
350 char **exts) |
| |
351 { |
| |
352 int i; |
| |
353 g_return_val_if_fail(info != NULL, FALSE); |
| |
354 |
| |
355 if (!exts) |
| |
356 return TRUE; |
| |
357 |
| |
358 for (i = 0; exts[i]; ++i) { |
| |
359 /* Hack since we advertise the ext but don't have any */ |
| |
360 if (g_str_equal(exts[i], "voice-v1") && !info->exts) |
| |
361 continue; |
| |
362 if (!info->exts || |
| |
363 !g_hash_table_lookup(info->exts->exts, exts[i])) |
| |
364 return FALSE; |
| |
365 } |
| |
366 |
| |
367 return TRUE; |
| |
368 } |
| |
369 |
| 349 typedef struct _jabber_caps_cbplususerdata { |
370 typedef struct _jabber_caps_cbplususerdata { |
| 350 guint ref; |
371 guint ref; |
| 351 |
372 |
| 352 jabber_caps_get_info_cb cb; |
373 jabber_caps_get_info_cb cb; |
| 353 gpointer cb_data; |
374 gpointer cb_data; |
| 537 cbplususerdata_unref(userdata->data); |
558 cbplususerdata_unref(userdata->data); |
| 538 g_free(userdata); |
559 g_free(userdata); |
| 539 } |
560 } |
| 540 |
561 |
| 541 void jabber_caps_get_info(JabberStream *js, const char *who, const char *node, |
562 void jabber_caps_get_info(JabberStream *js, const char *who, const char *node, |
| 542 const char *ver, const char *hash, const char *ext, |
563 const char *ver, const char *hash, char **exts, |
| 543 jabber_caps_get_info_cb cb, gpointer user_data) |
564 jabber_caps_get_info_cb cb, gpointer user_data) |
| 544 { |
565 { |
| 545 JabberCapsClientInfo *info; |
566 JabberCapsClientInfo *info; |
| 546 JabberCapsTuple key; |
567 JabberCapsTuple key; |
| 547 jabber_caps_cbplususerdata *userdata; |
568 jabber_caps_cbplususerdata *userdata; |
| 548 |
569 |
| 549 if (ext && *ext && hash) |
570 if (exts && hash) { |
| 550 purple_debug_info("jabber", "Ignoring exts in new-style caps from %s\n", |
571 purple_debug_info("jabber", "Ignoring exts in new-style caps from %s\n", |
| 551 who); |
572 who); |
| |
573 g_strfreev(exts); |
| |
574 exts = NULL; |
| |
575 } |
| 552 |
576 |
| 553 /* Using this in a read-only fashion, so the cast is OK */ |
577 /* Using this in a read-only fashion, so the cast is OK */ |
| 554 key.node = (char *)node; |
578 key.node = (char *)node; |
| 555 key.ver = (char *)ver; |
579 key.ver = (char *)ver; |
| 556 key.hash = (char *)hash; |
580 key.hash = (char *)hash; |
| 609 node_exts = info->exts = jabber_caps_find_exts_by_node(node); |
632 node_exts = info->exts = jabber_caps_find_exts_by_node(node); |
| 610 } else |
633 } else |
| 611 /* We'll put it in later once we have the client info */ |
634 /* We'll put it in later once we have the client info */ |
| 612 node_exts = userdata->node_exts = jabber_caps_find_exts_by_node(node); |
635 node_exts = userdata->node_exts = jabber_caps_find_exts_by_node(node); |
| 613 |
636 |
| 614 for (i = 0; splat[i]; ++i) { |
637 for (i = 0; exts[i]; ++i) { |
| 615 userdata->exts = g_list_prepend(userdata->exts, splat[i]); |
638 userdata->exts = g_list_prepend(userdata->exts, exts[i]); |
| 616 /* Look it up if we don't already know what it means */ |
639 /* Look it up if we don't already know what it means */ |
| 617 if (!g_hash_table_lookup(node_exts->exts, splat[i])) { |
640 if (!g_hash_table_lookup(node_exts->exts, exts[i])) { |
| 618 JabberIq *iq; |
641 JabberIq *iq; |
| 619 xmlnode *query; |
642 xmlnode *query; |
| 620 char *nodeext; |
643 char *nodeext; |
| 621 ext_iq_data *cbdata = g_new(ext_iq_data, 1); |
644 ext_iq_data *cbdata = g_new(ext_iq_data, 1); |
| 622 |
645 |
| 623 cbdata->name = splat[i]; |
646 cbdata->name = exts[i]; |
| 624 cbdata->data = cbplususerdata_ref(userdata); |
647 cbdata->data = cbplususerdata_ref(userdata); |
| 625 |
648 |
| 626 iq = jabber_iq_new_query(js, JABBER_IQ_GET, |
649 iq = jabber_iq_new_query(js, JABBER_IQ_GET, |
| 627 "http://jabber.org/protocol/disco#info"); |
650 "http://jabber.org/protocol/disco#info"); |
| 628 query = xmlnode_get_child_with_namespace(iq->node, "query", |
651 query = xmlnode_get_child_with_namespace(iq->node, "query", |
| 629 "http://jabber.org/protocol/disco#info"); |
652 "http://jabber.org/protocol/disco#info"); |
| 630 nodeext = g_strdup_printf("%s#%s", node, splat[i]); |
653 nodeext = g_strdup_printf("%s#%s", node, exts[i]); |
| 631 xmlnode_set_attrib(query, "node", nodeext); |
654 xmlnode_set_attrib(query, "node", nodeext); |
| 632 g_free(nodeext); |
655 g_free(nodeext); |
| 633 xmlnode_set_attrib(iq->node, "to", who); |
656 xmlnode_set_attrib(iq->node, "to", who); |
| 634 |
657 |
| 635 jabber_iq_set_callback(iq, jabber_caps_ext_iqcb, cbdata); |
658 jabber_iq_set_callback(iq, jabber_caps_ext_iqcb, cbdata); |
| 636 jabber_iq_send(iq); |
659 jabber_iq_send(iq); |
| 637 |
660 |
| 638 ++userdata->extOutstanding; |
661 ++userdata->extOutstanding; |
| 639 } |
662 } |
| 640 splat[i] = NULL; |
663 exts[i] = NULL; |
| 641 } |
664 } |
| 642 /* All the strings are now part of the GList, so don't need |
665 /* All the strings are now part of the GList, so don't need |
| 643 * g_strfreev. */ |
666 * g_strfreev. */ |
| 644 g_free(splat); |
667 g_free(exts); |
| 645 } |
668 } |
| 646 |
669 |
| 647 if (userdata->info && userdata->extOutstanding == 0) { |
670 if (userdata->info && userdata->extOutstanding == 0) { |
| 648 jabber_caps_get_info_complete(userdata); |
671 jabber_caps_get_info_complete(userdata); |
| 649 cbplususerdata_unref(userdata); |
672 cbplususerdata_unref(userdata); |