Mercurial > pidgin
comparison libpurple/protocols/jabber/jabber.c @ 26459:81b30f96250e
propagate from branch 'im.pidgin.pidgin' (head 2c36a90a26f2451978aa41b23e9980337514057d)
to branch 'im.pidgin.cpw.darkrain42.xmpp.bosh' (head 3962b427a087df544a52cae8dec0fc6d1d2e1635)
author | Paul Aurich <paul@darkrain42.org> |
---|---|
date | Sat, 04 Apr 2009 20:25:03 +0000 |
parents | 28f1512b0f94 20743d9bd62d |
children | bc7fac8e2f79 |
comparison
equal
deleted
inserted
replaced
26437:9eb8c8ec0a75 | 26459:81b30f96250e |
---|---|
40 #include "version.h" | 40 #include "version.h" |
41 #include "xmlnode.h" | 41 #include "xmlnode.h" |
42 | 42 |
43 #include "auth.h" | 43 #include "auth.h" |
44 #include "buddy.h" | 44 #include "buddy.h" |
45 #include "caps.h" | |
45 #include "chat.h" | 46 #include "chat.h" |
46 #include "data.h" | 47 #include "data.h" |
47 #include "disco.h" | 48 #include "disco.h" |
48 #include "google.h" | 49 #include "google.h" |
49 #include "iq.h" | 50 #include "iq.h" |
64 | 65 |
65 #define JABBER_CONNECT_STEPS (js->gsc ? 9 : 5) | 66 #define JABBER_CONNECT_STEPS (js->gsc ? 9 : 5) |
66 | 67 |
67 static PurplePlugin *my_protocol = NULL; | 68 static PurplePlugin *my_protocol = NULL; |
68 GList *jabber_features = NULL; | 69 GList *jabber_features = NULL; |
70 GList *jabber_identities = NULL; | |
69 | 71 |
70 static void jabber_unregister_account_cb(JabberStream *js); | 72 static void jabber_unregister_account_cb(JabberStream *js); |
71 static void try_srv_connect(JabberStream *js); | 73 static void try_srv_connect(JabberStream *js); |
72 | 74 |
73 static void jabber_stream_init(JabberStream *js) | 75 static void jabber_stream_init(JabberStream *js) |
89 static void | 91 static void |
90 jabber_session_initialized_cb(JabberStream *js, xmlnode *packet, gpointer data) | 92 jabber_session_initialized_cb(JabberStream *js, xmlnode *packet, gpointer data) |
91 { | 93 { |
92 const char *type = xmlnode_get_attrib(packet, "type"); | 94 const char *type = xmlnode_get_attrib(packet, "type"); |
93 if(type && !strcmp(type, "result")) { | 95 if(type && !strcmp(type, "result")) { |
94 jabber_stream_set_state(js, JABBER_STREAM_CONNECTED); | 96 jabber_disco_items_server(js); |
95 if(js->unregistration) | 97 if(js->unregistration) |
96 jabber_unregister_account_cb(js); | 98 jabber_unregister_account_cb(js); |
97 } else { | 99 } else { |
98 purple_connection_error_reason (js->gc, | 100 purple_connection_error_reason (js->gc, |
99 PURPLE_CONNECTION_ERROR_NETWORK_ERROR, | 101 PURPLE_CONNECTION_ERROR_NETWORK_ERROR, |
180 dot = '\0'; | 182 dot = '\0'; |
181 | 183 |
182 return purple_strreplace(input, "__HOSTNAME__", hostname); | 184 return purple_strreplace(input, "__HOSTNAME__", hostname); |
183 } | 185 } |
184 | 186 |
185 static void jabber_stream_features_parse(JabberStream *js, xmlnode *packet) | 187 void jabber_stream_features_parse(JabberStream *js, xmlnode *packet) |
186 { | 188 { |
187 if(xmlnode_get_child(packet, "starttls")) { | 189 if(xmlnode_get_child(packet, "starttls")) { |
188 if(jabber_process_starttls(js, packet)) | 190 if(jabber_process_starttls(js, packet)) |
189 | 191 |
190 return; | 192 return; |
191 } else if(purple_account_get_bool(js->gc->account, "require_tls", FALSE) && !js->gsc) { | 193 } else if(purple_account_get_bool(js->gc->account, "require_tls", FALSE) && !jabber_stream_is_ssl(js)) { |
192 purple_connection_error_reason (js->gc, | 194 purple_connection_error_reason (js->gc, |
193 PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR, | 195 PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR, |
194 _("You require encryption, but it is not available on this server.")); | 196 _("You require encryption, but it is not available on this server.")); |
195 return; | 197 return; |
196 } | 198 } |
379 last_part = strchr(data_start, '<'); | 381 last_part = strchr(data_start, '<'); |
380 *data_start = '\0'; | 382 *data_start = '\0'; |
381 } | 383 } |
382 | 384 |
383 purple_debug(PURPLE_DEBUG_MISC, "jabber", "Sending%s: %s%s%s\n", | 385 purple_debug(PURPLE_DEBUG_MISC, "jabber", "Sending%s: %s%s%s\n", |
384 js->gsc ? " (ssl)" : "", text ? text : data, | 386 jabber_stream_is_ssl(js) ? " (ssl)" : "", text ? text : data, |
385 last_part ? "password removed" : "", | 387 last_part ? "password removed" : "", |
386 last_part ? last_part : ""); | 388 last_part ? last_part : ""); |
387 | 389 |
388 g_free(text); | 390 g_free(text); |
389 } | 391 } |
420 } | 422 } |
421 return; | 423 return; |
422 } | 424 } |
423 #endif | 425 #endif |
424 | 426 |
425 do_jabber_send_raw(js, data, len); | 427 if (len == -1) |
428 len = strlen(data); | |
429 | |
430 if (js->use_bosh) | |
431 jabber_bosh_connection_send_raw(js->bosh, data); | |
432 else | |
433 do_jabber_send_raw(js, data, len); | |
426 } | 434 } |
427 | 435 |
428 int jabber_prpl_send_raw(PurpleConnection *gc, const char *buf, int len) | 436 int jabber_prpl_send_raw(PurpleConnection *gc, const char *buf, int len) |
429 { | 437 { |
430 JabberStream *js = (JabberStream*)gc->proto_data; | 438 JabberStream *js = (JabberStream*)gc->proto_data; |
583 | 591 |
584 /* Tell the app that we're doing encryption */ | 592 /* Tell the app that we're doing encryption */ |
585 jabber_stream_set_state(js, JABBER_STREAM_INITIALIZING_ENCRYPTION); | 593 jabber_stream_set_state(js, JABBER_STREAM_INITIALIZING_ENCRYPTION); |
586 } | 594 } |
587 | 595 |
596 static void | |
597 txt_resolved_cb(PurpleTxtResponse *resp, int results, gpointer data) | |
598 { | |
599 JabberStream *js = data; | |
600 int n; | |
601 | |
602 js->srv_query_data = NULL; | |
603 | |
604 if (results == 0) { | |
605 gchar *tmp; | |
606 tmp = g_strdup_printf(_("Could not find alternative XMPP connection methods after failing to connect directly.\n")); | |
607 purple_connection_error_reason (js->gc, | |
608 PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp); | |
609 g_free(tmp); | |
610 return; | |
611 } | |
612 | |
613 for (n = 0; n < results; n++) { | |
614 gchar **token; | |
615 token = g_strsplit(resp[n].content, "=", 2); | |
616 if (!strcmp(token[0], "_xmpp-client-xbosh")) { | |
617 purple_debug_info("jabber","Found alternative connection method using %s at %s.\n", token[0], token[1]); | |
618 js->bosh = jabber_bosh_connection_init(js, token[1]); | |
619 js->use_bosh = TRUE; | |
620 g_strfreev(token); | |
621 break; | |
622 } | |
623 g_strfreev(token); | |
624 } | |
625 if (js->bosh) { | |
626 jabber_bosh_connection_connect(js->bosh); | |
627 } else { | |
628 purple_debug_info("jabber","Didn't find an alternative connection method.\n"); | |
629 } | |
630 } | |
588 | 631 |
589 static void | 632 static void |
590 jabber_login_callback(gpointer data, gint source, const gchar *error) | 633 jabber_login_callback(gpointer data, gint source, const gchar *error) |
591 { | 634 { |
592 PurpleConnection *gc = data; | 635 PurpleConnection *gc = data; |
595 if (source < 0) { | 638 if (source < 0) { |
596 if (js->srv_rec != NULL) { | 639 if (js->srv_rec != NULL) { |
597 purple_debug_error("jabber", "Unable to connect to server: %s. Trying next SRV record.\n", error); | 640 purple_debug_error("jabber", "Unable to connect to server: %s. Trying next SRV record.\n", error); |
598 try_srv_connect(js); | 641 try_srv_connect(js); |
599 } else { | 642 } else { |
600 gchar *tmp; | 643 purple_debug_info("jabber","Couldn't connect directly to %s. Trying to find alternative connection methods, like BOSH.\n", js->user->domain); |
601 tmp = g_strdup_printf(_("Could not establish a connection with the server:\n%s"), | 644 js->srv_query_data = purple_txt_resolve("_xmppconnect", js->user->domain, txt_resolved_cb, js); |
602 error); | |
603 purple_connection_error_reason(gc, | |
604 PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp); | |
605 g_free(tmp); | |
606 } | 645 } |
607 return; | 646 return; |
608 } | 647 } |
609 | 648 |
610 g_free(js->srv_rec); | 649 g_free(js->srv_rec); |
728 js->user = jabber_id_new(purple_account_get_username(account)); | 767 js->user = jabber_id_new(purple_account_get_username(account)); |
729 js->next_id = g_random_int(); | 768 js->next_id = g_random_int(); |
730 js->write_buffer = purple_circ_buffer_new(512); | 769 js->write_buffer = purple_circ_buffer_new(512); |
731 js->old_length = 0; | 770 js->old_length = 0; |
732 js->keepalive_timeout = -1; | 771 js->keepalive_timeout = -1; |
733 js->certificate_CN = g_strdup(connect_server[0] ? connect_server : js->user ? js->user->domain : NULL); | 772 /* Set the default protocol version to 1.0. Overridden in parser.c. */ |
773 js->protocol_version = JABBER_PROTO_1_0; | |
734 js->sessions = NULL; | 774 js->sessions = NULL; |
735 js->stun_ip = NULL; | 775 js->stun_ip = NULL; |
736 js->stun_port = 0; | 776 js->stun_port = 0; |
737 js->stun_query = NULL; | 777 js->stun_query = NULL; |
738 | 778 |
752 | 792 |
753 if((my_jb = jabber_buddy_find(js, purple_account_get_username(account), TRUE))) | 793 if((my_jb = jabber_buddy_find(js, purple_account_get_username(account), TRUE))) |
754 my_jb->subscription |= JABBER_SUB_BOTH; | 794 my_jb->subscription |= JABBER_SUB_BOTH; |
755 | 795 |
756 jabber_stream_set_state(js, JABBER_STREAM_CONNECTING); | 796 jabber_stream_set_state(js, JABBER_STREAM_CONNECTING); |
797 | |
798 /* TODO: Just use purple_url_parse? */ | |
799 if (!g_ascii_strncasecmp(connect_server, "http://", 7) || !g_ascii_strncasecmp(connect_server, "https://", 8)) { | |
800 js->use_bosh = TRUE; | |
801 js->bosh = jabber_bosh_connection_init(js, connect_server); | |
802 if (!js->bosh) { | |
803 purple_connection_error_reason (js->gc, | |
804 PURPLE_CONNECTION_ERROR_INVALID_SETTINGS, | |
805 _("Malformed BOSH Connect Server")); | |
806 return; | |
807 } | |
808 jabber_bosh_connection_connect(js->bosh); | |
809 return; | |
810 } else { | |
811 js->certificate_CN = g_strdup(connect_server[0] ? connect_server : js->user->domain); | |
812 } | |
757 | 813 |
758 /* if they've got old-ssl mode going, we probably want to ignore SRV lookups */ | 814 /* if they've got old-ssl mode going, we probably want to ignore SRV lookups */ |
759 if(purple_account_get_bool(js->gc->account, "old_ssl", FALSE)) { | 815 if(purple_account_get_bool(js->gc->account, "old_ssl", FALSE)) { |
760 if(purple_ssl_is_supported()) { | 816 if(purple_ssl_is_supported()) { |
761 js->gsc = purple_ssl_connect(js->gc->account, | 817 js->gsc = purple_ssl_connect(js->gc->account, |
762 js->certificate_CN, | 818 js->certificate_CN, |
763 purple_account_get_int(account, "port", 5223), jabber_login_callback_ssl, | 819 purple_account_get_int(account, "port", 5223), jabber_login_callback_ssl, |
764 jabber_ssl_connect_failure, js->gc); | 820 jabber_ssl_connect_failure, js->gc); |
821 if (!js->gsc) { | |
822 purple_connection_error_reason (js->gc, | |
823 PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT, | |
824 _("Unable to establish SSL connection")); | |
825 } | |
765 } else { | 826 } else { |
766 purple_connection_error_reason (js->gc, | 827 purple_connection_error_reason (js->gc, |
767 PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT, | 828 PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT, |
768 _("SSL support unavailable")); | 829 _("SSL support unavailable")); |
769 } | 830 } |
831 | |
832 return; | |
770 } | 833 } |
771 | 834 |
772 /* no old-ssl, so if they've specified a connect server, we'll use that, otherwise we'll | 835 /* no old-ssl, so if they've specified a connect server, we'll use that, otherwise we'll |
773 * invoke the magic of SRV lookups, to figure out host and port */ | 836 * invoke the magic of SRV lookups, to figure out host and port */ |
774 if(!js->gsc) { | 837 if(connect_server[0]) { |
775 if(connect_server[0]) { | 838 jabber_login_connect(js, js->user->domain, connect_server, purple_account_get_int(account, "port", 5222), TRUE); |
776 jabber_login_connect(js, js->user->domain, connect_server, purple_account_get_int(account, "port", 5222), TRUE); | 839 } else { |
777 } else { | 840 js->srv_query_data = purple_srv_resolve("xmpp-client", |
778 js->srv_query_data = purple_srv_resolve("xmpp-client", | 841 "tcp", js->user->domain, srv_resolved_cb, js); |
779 "tcp", js->user->domain, srv_resolved_cb, js); | |
780 } | |
781 } | 842 } |
782 } | 843 } |
783 | 844 |
784 | 845 |
785 static gboolean | 846 static gboolean |
1335 | 1396 |
1336 /* Don't perform any actions on the ssl connection | 1397 /* Don't perform any actions on the ssl connection |
1337 * if we were forcibly disconnected because it will crash | 1398 * if we were forcibly disconnected because it will crash |
1338 * on some SSL backends. | 1399 * on some SSL backends. |
1339 */ | 1400 */ |
1340 if (!gc->disconnect_timeout) | 1401 if (!gc->disconnect_timeout) { |
1341 jabber_send_raw(js, "</stream:stream>", -1); | 1402 if (js->use_bosh) |
1403 jabber_bosh_connection_close(js->bosh); | |
1404 else | |
1405 jabber_send_raw(js, "</stream:stream>", -1); | |
1406 } | |
1342 | 1407 |
1343 if (js->srv_query_data) | 1408 if (js->srv_query_data) |
1344 purple_srv_cancel(js->srv_query_data); | 1409 purple_srv_cancel(js->srv_query_data); |
1345 | 1410 |
1346 if(js->gsc) { | 1411 if(js->gsc) { |
1352 if(js->gc->inpa) | 1417 if(js->gc->inpa) |
1353 purple_input_remove(js->gc->inpa); | 1418 purple_input_remove(js->gc->inpa); |
1354 close(js->fd); | 1419 close(js->fd); |
1355 } | 1420 } |
1356 | 1421 |
1422 if (js->bosh) | |
1423 jabber_bosh_connection_destroy(js->bosh); | |
1424 | |
1357 jabber_buddy_remove_all_pending_buddy_info_requests(js); | 1425 jabber_buddy_remove_all_pending_buddy_info_requests(js); |
1358 | 1426 |
1359 jabber_parser_free(js); | 1427 jabber_parser_free(js); |
1360 | 1428 |
1361 if(js->iq_callbacks) | 1429 if(js->iq_callbacks) |
1393 | 1461 |
1394 g_free(js->stream_id); | 1462 g_free(js->stream_id); |
1395 if(js->user) | 1463 if(js->user) |
1396 jabber_id_free(js->user); | 1464 jabber_id_free(js->user); |
1397 g_free(js->avatar_hash); | 1465 g_free(js->avatar_hash); |
1466 g_free(js->caps_hash); | |
1398 | 1467 |
1399 purple_circ_buffer_destroy(js->write_buffer); | 1468 purple_circ_buffer_destroy(js->write_buffer); |
1400 if(js->writeh) | 1469 if(js->writeh) |
1401 purple_input_remove(js->writeh); | 1470 purple_input_remove(js->writeh); |
1402 #ifdef HAVE_CYRUS_SASL | 1471 #ifdef HAVE_CYRUS_SASL |
1494 | 1563 |
1495 break; | 1564 break; |
1496 case JABBER_STREAM_CONNECTED: | 1565 case JABBER_STREAM_CONNECTED: |
1497 /* now we can alert the core that we're ready to send status */ | 1566 /* now we can alert the core that we're ready to send status */ |
1498 purple_connection_set_state(js->gc, PURPLE_CONNECTED); | 1567 purple_connection_set_state(js->gc, PURPLE_CONNECTED); |
1499 jabber_disco_items_server(js); | |
1500 break; | 1568 break; |
1501 } | 1569 } |
1502 } | 1570 } |
1503 | 1571 |
1504 char *jabber_get_next_id(JabberStream *js) | 1572 char *jabber_get_next_id(JabberStream *js) |
1612 xmlnode_set_attrib(item, "jid", who); | 1680 xmlnode_set_attrib(item, "jid", who); |
1613 | 1681 |
1614 jabber_iq_send(iq); | 1682 jabber_iq_send(iq); |
1615 } | 1683 } |
1616 | 1684 |
1617 void jabber_add_feature(const char *shortname, const char *namespace, JabberFeatureEnabled cb) { | 1685 void jabber_add_feature(const char *namespace, JabberFeatureEnabled cb) { |
1618 JabberFeature *feat; | 1686 JabberFeature *feat; |
1619 | 1687 |
1620 g_return_if_fail(shortname != NULL); | |
1621 g_return_if_fail(namespace != NULL); | 1688 g_return_if_fail(namespace != NULL); |
1622 | 1689 |
1623 feat = g_new0(JabberFeature,1); | 1690 feat = g_new0(JabberFeature,1); |
1624 feat->shortname = g_strdup(shortname); | |
1625 feat->namespace = g_strdup(namespace); | 1691 feat->namespace = g_strdup(namespace); |
1626 feat->is_enabled = cb; | 1692 feat->is_enabled = cb; |
1627 | 1693 |
1628 /* try to remove just in case it already exists in the list */ | 1694 /* try to remove just in case it already exists in the list */ |
1629 jabber_remove_feature(shortname); | 1695 jabber_remove_feature(namespace); |
1630 | 1696 |
1631 jabber_features = g_list_append(jabber_features, feat); | 1697 jabber_features = g_list_append(jabber_features, feat); |
1632 } | 1698 } |
1633 | 1699 |
1634 void jabber_remove_feature(const char *shortname) { | 1700 void jabber_remove_feature(const char *namespace) { |
1635 GList *feature; | 1701 GList *feature; |
1636 for(feature = jabber_features; feature; feature = feature->next) { | 1702 for(feature = jabber_features; feature; feature = feature->next) { |
1637 JabberFeature *feat = (JabberFeature*)feature->data; | 1703 JabberFeature *feat = (JabberFeature*)feature->data; |
1638 if(!strcmp(feat->shortname, shortname)) { | 1704 if(!strcmp(feat->namespace, namespace)) { |
1639 g_free(feat->shortname); | |
1640 g_free(feat->namespace); | 1705 g_free(feat->namespace); |
1641 | |
1642 g_free(feature->data); | 1706 g_free(feature->data); |
1643 jabber_features = g_list_delete_link(jabber_features, feature); | 1707 jabber_features = g_list_delete_link(jabber_features, feature); |
1644 break; | 1708 break; |
1645 } | 1709 } |
1646 } | 1710 } |
1711 } | |
1712 | |
1713 static void jabber_features_destroy(void) | |
1714 { | |
1715 while (jabber_features) { | |
1716 JabberFeature *feature = jabber_features->data; | |
1717 g_free(feature->namespace); | |
1718 g_free(feature); | |
1719 jabber_features = g_list_remove_link(jabber_features, jabber_features); | |
1720 } | |
1721 } | |
1722 | |
1723 void jabber_add_identity(const gchar *category, const gchar *type, const gchar *lang, const gchar *name) { | |
1724 GList *identity; | |
1725 JabberIdentity *ident; | |
1726 /* both required according to XEP-0030 */ | |
1727 g_return_if_fail(category != NULL); | |
1728 g_return_if_fail(type != NULL); | |
1729 | |
1730 for(identity = jabber_identities; identity; identity = identity->next) { | |
1731 JabberIdentity *ident = (JabberIdentity*)identity->data; | |
1732 if (!strcmp(ident->category, category) && | |
1733 !strcmp(ident->type, type) && | |
1734 ((!ident->lang && !lang) || (ident->lang && lang && !strcmp(ident->lang, lang)))) { | |
1735 return; | |
1736 } | |
1737 } | |
1738 | |
1739 ident = g_new0(JabberIdentity, 1); | |
1740 ident->category = g_strdup(category); | |
1741 ident->type = g_strdup(type); | |
1742 ident->lang = g_strdup(lang); | |
1743 ident->name = g_strdup(name); | |
1744 jabber_identities = g_list_append(jabber_identities, ident); | |
1745 } | |
1746 | |
1747 static void jabber_identities_destroy(void) | |
1748 { | |
1749 while (jabber_identities) { | |
1750 JabberIdentity *id = jabber_identities->data; | |
1751 g_free(id->category); | |
1752 g_free(id->type); | |
1753 g_free(id->lang); | |
1754 g_free(id->name); | |
1755 g_free(id); | |
1756 jabber_identities = g_list_remove_link(jabber_identities, jabber_identities); | |
1757 } | |
1758 } | |
1759 | |
1760 gboolean jabber_stream_is_ssl(JabberStream *js) | |
1761 { | |
1762 return (js->bosh && jabber_bosh_connection_is_ssl(js->bosh)) || | |
1763 (!js->bosh && js->gsc); | |
1647 } | 1764 } |
1648 | 1765 |
1649 const char *jabber_list_icon(PurpleAccount *a, PurpleBuddy *b) | 1766 const char *jabber_list_icon(PurpleAccount *a, PurpleBuddy *b) |
1650 { | 1767 { |
1651 return "jabber"; | 1768 return "jabber"; |
2611 { | 2728 { |
2612 return TRUE; | 2729 return TRUE; |
2613 } | 2730 } |
2614 | 2731 |
2615 #ifdef USE_VV | 2732 #ifdef USE_VV |
2733 gboolean | |
2734 jabber_audio_enabled(JabberStream *js, const char *namespace) | |
2735 { | |
2736 PurpleMediaManager *manager = purple_media_manager_get(); | |
2737 PurpleMediaCaps caps = purple_media_manager_get_ui_caps(manager); | |
2738 | |
2739 return (caps & (PURPLE_MEDIA_CAPS_AUDIO | PURPLE_MEDIA_CAPS_AUDIO_SINGLE_DIRECTION)); | |
2740 } | |
2741 | |
2742 static gboolean | |
2743 jabber_video_enabled(JabberStream *js, const char *namespace) | |
2744 { | |
2745 PurpleMediaManager *manager = purple_media_manager_get(); | |
2746 PurpleMediaCaps caps = purple_media_manager_get_ui_caps(manager); | |
2747 | |
2748 return (caps & (PURPLE_MEDIA_CAPS_VIDEO | PURPLE_MEDIA_CAPS_VIDEO_SINGLE_DIRECTION)); | |
2749 } | |
2750 | |
2751 static gboolean | |
2752 jabber_ice_transmitter_present(JabberStream *js, const char *namespace) | |
2753 { | |
2754 return purple_media_transmitter_exists("nice"); | |
2755 } | |
2756 | |
2616 typedef struct { | 2757 typedef struct { |
2617 PurpleConnection *pc; | 2758 PurpleConnection *pc; |
2618 gchar *who; | 2759 gchar *who; |
2619 PurpleMediaSessionType type; | 2760 PurpleMediaSessionType type; |
2620 | 2761 |
2966 PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, | 3107 PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, |
2967 "prpl-jabber", jabber_cmd_buzz, | 3108 "prpl-jabber", jabber_cmd_buzz, |
2968 _("buzz: Buzz a user to get their attention"), NULL); | 3109 _("buzz: Buzz a user to get their attention"), NULL); |
2969 } | 3110 } |
2970 | 3111 |
3112 /* IPC functions */ | |
3113 | |
3114 /** | |
3115 * IPC function for determining if a contact supports a certain feature. | |
3116 * | |
3117 * @param account The PurpleAccount | |
3118 * @param jid The full JID of the contact. | |
3119 * @param feature The feature's namespace. | |
3120 * | |
3121 * @return TRUE if supports feature; else FALSE. | |
3122 */ | |
3123 static gboolean | |
3124 jabber_ipc_contact_has_feature(PurpleAccount *account, const gchar *jid, | |
3125 const gchar *feature) | |
3126 { | |
3127 PurpleConnection *gc = purple_account_get_connection(account); | |
3128 JabberStream *js; | |
3129 JabberBuddy *jb; | |
3130 JabberBuddyResource *jbr; | |
3131 gchar *resource; | |
3132 | |
3133 if (!purple_account_is_connected(account)) | |
3134 return FALSE; | |
3135 js = gc->proto_data; | |
3136 | |
3137 if (!(resource = jabber_get_resource(jid)) || | |
3138 !(jb = jabber_buddy_find(js, jid, FALSE)) || | |
3139 !(jbr = jabber_buddy_find_resource(jb, resource))) { | |
3140 g_free(resource); | |
3141 return FALSE; | |
3142 } | |
3143 | |
3144 g_free(resource); | |
3145 | |
3146 return jabber_resource_has_capability(jbr, feature); | |
3147 } | |
3148 | |
3149 static void | |
3150 jabber_ipc_add_feature(const gchar *feature) | |
3151 { | |
3152 if (!feature) | |
3153 return; | |
3154 jabber_add_feature(feature, 0); | |
3155 | |
3156 /* send presence with new caps info for all connected accounts */ | |
3157 jabber_caps_broadcast_change(); | |
3158 } | |
3159 | |
2971 void | 3160 void |
2972 jabber_init_plugin(PurplePlugin *plugin) | 3161 jabber_init_plugin(PurplePlugin *plugin) |
2973 { | 3162 { |
2974 my_protocol = plugin; | 3163 my_protocol = plugin; |
2975 } | 3164 |
3165 jabber_add_identity("client", "pc", NULL, PACKAGE); | |
3166 | |
3167 /* initialize jabber_features list */ | |
3168 jabber_add_feature("jabber:iq:last", 0); | |
3169 jabber_add_feature("jabber:iq:oob", 0); | |
3170 jabber_add_feature("jabber:iq:time", 0); | |
3171 jabber_add_feature("urn:xmpp:time", 0); | |
3172 jabber_add_feature("jabber:iq:version", 0); | |
3173 jabber_add_feature("jabber:x:conference", 0); | |
3174 jabber_add_feature("http://jabber.org/protocol/bytestreams", 0); | |
3175 jabber_add_feature("http://jabber.org/protocol/caps", 0); | |
3176 jabber_add_feature("http://jabber.org/protocol/chatstates", 0); | |
3177 jabber_add_feature("http://jabber.org/protocol/disco#info", 0); | |
3178 jabber_add_feature("http://jabber.org/protocol/disco#items", 0); | |
3179 jabber_add_feature("http://jabber.org/protocol/ibb", 0); | |
3180 jabber_add_feature("http://jabber.org/protocol/muc", 0); | |
3181 jabber_add_feature("http://jabber.org/protocol/muc#user", 0); | |
3182 jabber_add_feature("http://jabber.org/protocol/si", 0); | |
3183 jabber_add_feature("http://jabber.org/protocol/si/profile/file-transfer", 0); | |
3184 jabber_add_feature("http://jabber.org/protocol/xhtml-im", 0); | |
3185 jabber_add_feature("urn:xmpp:ping", 0); | |
3186 | |
3187 /* Jingle features! */ | |
3188 jabber_add_feature(JINGLE, 0); | |
3189 jabber_add_feature(JINGLE_TRANSPORT_RAWUDP, 0); | |
3190 | |
3191 #ifdef USE_VV | |
3192 jabber_add_feature("http://www.google.com/xmpp/protocol/session", jabber_audio_enabled); | |
3193 jabber_add_feature("http://www.google.com/xmpp/protocol/voice/v1", jabber_audio_enabled); | |
3194 jabber_add_feature(JINGLE_APP_RTP_SUPPORT_AUDIO, jabber_audio_enabled); | |
3195 jabber_add_feature(JINGLE_APP_RTP_SUPPORT_VIDEO, jabber_video_enabled); | |
3196 jabber_add_feature(JINGLE_TRANSPORT_ICEUDP, jabber_ice_transmitter_present); | |
3197 #endif | |
3198 | |
3199 /* IPC functions */ | |
3200 purple_plugin_ipc_register(plugin, "contact_has_feature", PURPLE_CALLBACK(jabber_ipc_contact_has_feature), | |
3201 purple_marshal_BOOLEAN__POINTER_POINTER_POINTER, | |
3202 purple_value_new(PURPLE_TYPE_BOOLEAN), 3, | |
3203 purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_ACCOUNT), | |
3204 purple_value_new(PURPLE_TYPE_STRING), | |
3205 purple_value_new(PURPLE_TYPE_STRING)); | |
3206 purple_plugin_ipc_register(plugin, "add_feature", PURPLE_CALLBACK(jabber_ipc_add_feature), | |
3207 purple_marshal_VOID__POINTER, | |
3208 NULL, 1, | |
3209 purple_value_new(PURPLE_TYPE_STRING)); | |
3210 } | |
3211 | |
3212 void | |
3213 jabber_uninit_plugin(void) | |
3214 { | |
3215 jabber_features_destroy(); | |
3216 jabber_identities_destroy(); | |
3217 } |