libpurple/protocols/jabber/jabber.c

branch
cpw.darkrain42.xmpp.bosh
changeset 26764
508b4bd1a7f8
parent 26746
2a2d45ac9774
parent 26707
a4f7c5d5e5ae
child 26765
fc156c427d59
equal deleted inserted replaced
26759:f9faf7492ad7 26764:508b4bd1a7f8
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)
90 jabber_session_initialized_cb(JabberStream *js, const char *from, 92 jabber_session_initialized_cb(JabberStream *js, const char *from,
91 JabberIqType type, const char *id, 93 JabberIqType type, const char *id,
92 xmlnode *packet, gpointer data) 94 xmlnode *packet, gpointer data)
93 { 95 {
94 if (type == JABBER_IQ_RESULT) { 96 if (type == JABBER_IQ_RESULT) {
95 jabber_stream_set_state(js, JABBER_STREAM_CONNECTED); 97 jabber_disco_items_server(js);
96 if(js->unregistration) 98 if(js->unregistration)
97 jabber_unregister_account_cb(js); 99 jabber_unregister_account_cb(js);
98 } else { 100 } else {
99 purple_connection_error_reason (js->gc, 101 purple_connection_error_reason (js->gc,
100 PURPLE_CONNECTION_ERROR_NETWORK_ERROR, 102 PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
181 dot = '\0'; 183 dot = '\0';
182 184
183 return purple_strreplace(input, "__HOSTNAME__", hostname); 185 return purple_strreplace(input, "__HOSTNAME__", hostname);
184 } 186 }
185 187
186 static void jabber_stream_features_parse(JabberStream *js, xmlnode *packet) 188 void jabber_stream_features_parse(JabberStream *js, xmlnode *packet)
187 { 189 {
188 if(xmlnode_get_child(packet, "starttls")) { 190 if(xmlnode_get_child(packet, "starttls")) {
189 if(jabber_process_starttls(js, packet)) 191 if(jabber_process_starttls(js, packet))
190 192
191 return; 193 return;
192 } else if(purple_account_get_bool(js->gc->account, "require_tls", FALSE) && !js->gsc) { 194 } else if(purple_account_get_bool(js->gc->account, "require_tls", FALSE) && !jabber_stream_is_ssl(js)) {
193 purple_connection_error_reason (js->gc, 195 purple_connection_error_reason (js->gc,
194 PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR, 196 PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR,
195 _("You require encryption, but it is not available on this server.")); 197 _("You require encryption, but it is not available on this server."));
196 return; 198 return;
197 } 199 }
380 last_part = strchr(data_start, '<'); 382 last_part = strchr(data_start, '<');
381 *data_start = '\0'; 383 *data_start = '\0';
382 } 384 }
383 385
384 purple_debug(PURPLE_DEBUG_MISC, "jabber", "Sending%s: %s%s%s\n", 386 purple_debug(PURPLE_DEBUG_MISC, "jabber", "Sending%s: %s%s%s\n",
385 js->gsc ? " (ssl)" : "", text ? text : data, 387 jabber_stream_is_ssl(js) ? " (ssl)" : "", text ? text : data,
386 last_part ? "password removed" : "", 388 last_part ? "password removed" : "",
387 last_part ? last_part : ""); 389 last_part ? last_part : "");
388 390
389 g_free(text); 391 g_free(text);
390 } 392 }
421 } 423 }
422 return; 424 return;
423 } 425 }
424 #endif 426 #endif
425 427
426 do_jabber_send_raw(js, data, len); 428 if (len == -1)
429 len = strlen(data);
430
431 if (js->use_bosh)
432 jabber_bosh_connection_send_raw(js->bosh, data);
433 else
434 do_jabber_send_raw(js, data, len);
427 } 435 }
428 436
429 int jabber_prpl_send_raw(PurpleConnection *gc, const char *buf, int len) 437 int jabber_prpl_send_raw(PurpleConnection *gc, const char *buf, int len)
430 { 438 {
431 JabberStream *js = (JabberStream*)gc->proto_data; 439 JabberStream *js = (JabberStream*)gc->proto_data;
573 581
574 /* Tell the app that we're doing encryption */ 582 /* Tell the app that we're doing encryption */
575 jabber_stream_set_state(js, JABBER_STREAM_INITIALIZING_ENCRYPTION); 583 jabber_stream_set_state(js, JABBER_STREAM_INITIALIZING_ENCRYPTION);
576 } 584 }
577 585
586 static void
587 txt_resolved_cb(PurpleTxtResponse *resp, int results, gpointer data)
588 {
589 JabberStream *js = data;
590 int n;
591
592 js->srv_query_data = NULL;
593
594 if (results == 0) {
595 gchar *tmp;
596 tmp = g_strdup_printf(_("Could not find alternative XMPP connection methods after failing to connect directly.\n"));
597 purple_connection_error_reason (js->gc,
598 PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
599 g_free(tmp);
600 return;
601 }
602
603 for (n = 0; n < results; n++) {
604 gchar **token;
605 token = g_strsplit(resp[n].content, "=", 2);
606 if (!strcmp(token[0], "_xmpp-client-xbosh")) {
607 purple_debug_info("jabber","Found alternative connection method using %s at %s.\n", token[0], token[1]);
608 js->bosh = jabber_bosh_connection_init(js, token[1]);
609 js->use_bosh = TRUE;
610 g_strfreev(token);
611 break;
612 }
613 g_strfreev(token);
614 }
615 if (js->bosh) {
616 jabber_bosh_connection_connect(js->bosh);
617 } else {
618 purple_debug_info("jabber","Didn't find an alternative connection method.\n");
619 }
620 }
578 621
579 static void 622 static void
580 jabber_login_callback(gpointer data, gint source, const gchar *error) 623 jabber_login_callback(gpointer data, gint source, const gchar *error)
581 { 624 {
582 PurpleConnection *gc = data; 625 PurpleConnection *gc = data;
585 if (source < 0) { 628 if (source < 0) {
586 if (js->srv_rec != NULL) { 629 if (js->srv_rec != NULL) {
587 purple_debug_error("jabber", "Unable to connect to server: %s. Trying next SRV record.\n", error); 630 purple_debug_error("jabber", "Unable to connect to server: %s. Trying next SRV record.\n", error);
588 try_srv_connect(js); 631 try_srv_connect(js);
589 } else { 632 } else {
590 gchar *tmp; 633 purple_debug_info("jabber","Couldn't connect directly to %s. Trying to find alternative connection methods, like BOSH.\n", js->user->domain);
591 tmp = g_strdup_printf(_("Could not establish a connection with the server:\n%s"), 634 js->srv_query_data = purple_txt_resolve("_xmppconnect", js->user->domain, txt_resolved_cb, js);
592 error);
593 purple_connection_error_reason(gc,
594 PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
595 g_free(tmp);
596 } 635 }
597 return; 636 return;
598 } 637 }
599 638
600 g_free(js->srv_rec); 639 g_free(js->srv_rec);
718 js->user = jabber_id_new(purple_account_get_username(account)); 757 js->user = jabber_id_new(purple_account_get_username(account));
719 js->next_id = g_random_int(); 758 js->next_id = g_random_int();
720 js->write_buffer = purple_circ_buffer_new(512); 759 js->write_buffer = purple_circ_buffer_new(512);
721 js->old_length = 0; 760 js->old_length = 0;
722 js->keepalive_timeout = -1; 761 js->keepalive_timeout = -1;
723 js->certificate_CN = g_strdup(connect_server[0] ? connect_server : js->user ? js->user->domain : NULL); 762 /* Set the default protocol version to 1.0. Overridden in parser.c. */
763 js->protocol_version = JABBER_PROTO_1_0;
724 js->sessions = NULL; 764 js->sessions = NULL;
725 js->stun_ip = NULL; 765 js->stun_ip = NULL;
726 js->stun_port = 0; 766 js->stun_port = 0;
727 js->stun_query = NULL; 767 js->stun_query = NULL;
728 768
742 782
743 if((my_jb = jabber_buddy_find(js, purple_account_get_username(account), TRUE))) 783 if((my_jb = jabber_buddy_find(js, purple_account_get_username(account), TRUE)))
744 my_jb->subscription |= JABBER_SUB_BOTH; 784 my_jb->subscription |= JABBER_SUB_BOTH;
745 785
746 jabber_stream_set_state(js, JABBER_STREAM_CONNECTING); 786 jabber_stream_set_state(js, JABBER_STREAM_CONNECTING);
787
788 /* TODO: Just use purple_url_parse? */
789 if (!g_ascii_strncasecmp(connect_server, "http://", 7) || !g_ascii_strncasecmp(connect_server, "https://", 8)) {
790 js->use_bosh = TRUE;
791 js->bosh = jabber_bosh_connection_init(js, connect_server);
792 if (!js->bosh) {
793 purple_connection_error_reason (js->gc,
794 PURPLE_CONNECTION_ERROR_INVALID_SETTINGS,
795 _("Malformed BOSH Connect Server"));
796 return;
797 }
798 jabber_bosh_connection_connect(js->bosh);
799 return;
800 } else {
801 js->certificate_CN = g_strdup(connect_server[0] ? connect_server : js->user->domain);
802 }
747 803
748 /* if they've got old-ssl mode going, we probably want to ignore SRV lookups */ 804 /* if they've got old-ssl mode going, we probably want to ignore SRV lookups */
749 if(purple_account_get_bool(js->gc->account, "old_ssl", FALSE)) { 805 if(purple_account_get_bool(js->gc->account, "old_ssl", FALSE)) {
750 if(purple_ssl_is_supported()) { 806 if(purple_ssl_is_supported()) {
751 js->gsc = purple_ssl_connect(js->gc->account, 807 js->gsc = purple_ssl_connect(js->gc->account,
752 js->certificate_CN, 808 js->certificate_CN,
753 purple_account_get_int(account, "port", 5223), jabber_login_callback_ssl, 809 purple_account_get_int(account, "port", 5223), jabber_login_callback_ssl,
754 jabber_ssl_connect_failure, js->gc); 810 jabber_ssl_connect_failure, js->gc);
811 if (!js->gsc) {
812 purple_connection_error_reason (js->gc,
813 PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT,
814 _("Unable to establish SSL connection"));
815 }
755 } else { 816 } else {
756 purple_connection_error_reason (js->gc, 817 purple_connection_error_reason (js->gc,
757 PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT, 818 PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT,
758 _("SSL support unavailable")); 819 _("SSL support unavailable"));
759 } 820 }
821
822 return;
760 } 823 }
761 824
762 /* no old-ssl, so if they've specified a connect server, we'll use that, otherwise we'll 825 /* no old-ssl, so if they've specified a connect server, we'll use that, otherwise we'll
763 * invoke the magic of SRV lookups, to figure out host and port */ 826 * invoke the magic of SRV lookups, to figure out host and port */
764 if(!js->gsc) { 827 if(connect_server[0]) {
765 if(connect_server[0]) { 828 jabber_login_connect(js, js->user->domain, connect_server, purple_account_get_int(account, "port", 5222), TRUE);
766 jabber_login_connect(js, js->user->domain, connect_server, purple_account_get_int(account, "port", 5222), TRUE); 829 } else {
767 } else { 830 js->srv_query_data = purple_srv_resolve("xmpp-client",
768 js->srv_query_data = purple_srv_resolve("xmpp-client", 831 "tcp", js->user->domain, srv_resolved_cb, js);
769 "tcp", js->user->domain, srv_resolved_cb, js);
770 }
771 } 832 }
772 } 833 }
773 834
774 835
775 static gboolean 836 static gboolean
1330 1391
1331 /* Don't perform any actions on the ssl connection 1392 /* Don't perform any actions on the ssl connection
1332 * if we were forcibly disconnected because it will crash 1393 * if we were forcibly disconnected because it will crash
1333 * on some SSL backends. 1394 * on some SSL backends.
1334 */ 1395 */
1335 if (!gc->disconnect_timeout) 1396 if (!gc->disconnect_timeout) {
1336 jabber_send_raw(js, "</stream:stream>", -1); 1397 if (js->use_bosh)
1398 jabber_bosh_connection_close(js->bosh);
1399 else
1400 jabber_send_raw(js, "</stream:stream>", -1);
1401 }
1337 1402
1338 if (js->srv_query_data) 1403 if (js->srv_query_data)
1339 purple_srv_cancel(js->srv_query_data); 1404 purple_srv_cancel(js->srv_query_data);
1340 1405
1341 if(js->gsc) { 1406 if(js->gsc) {
1347 if(js->gc->inpa) 1412 if(js->gc->inpa)
1348 purple_input_remove(js->gc->inpa); 1413 purple_input_remove(js->gc->inpa);
1349 close(js->fd); 1414 close(js->fd);
1350 } 1415 }
1351 1416
1417 if (js->bosh)
1418 jabber_bosh_connection_destroy(js->bosh);
1419
1352 jabber_buddy_remove_all_pending_buddy_info_requests(js); 1420 jabber_buddy_remove_all_pending_buddy_info_requests(js);
1353 1421
1354 jabber_parser_free(js); 1422 jabber_parser_free(js);
1355 1423
1356 if(js->iq_callbacks) 1424 if(js->iq_callbacks)
1388 1456
1389 g_free(js->stream_id); 1457 g_free(js->stream_id);
1390 if(js->user) 1458 if(js->user)
1391 jabber_id_free(js->user); 1459 jabber_id_free(js->user);
1392 g_free(js->avatar_hash); 1460 g_free(js->avatar_hash);
1461 g_free(js->caps_hash);
1393 1462
1394 purple_circ_buffer_destroy(js->write_buffer); 1463 purple_circ_buffer_destroy(js->write_buffer);
1395 if(js->writeh) 1464 if(js->writeh)
1396 purple_input_remove(js->writeh); 1465 purple_input_remove(js->writeh);
1397 #ifdef HAVE_CYRUS_SASL 1466 #ifdef HAVE_CYRUS_SASL
1489 1558
1490 break; 1559 break;
1491 case JABBER_STREAM_CONNECTED: 1560 case JABBER_STREAM_CONNECTED:
1492 /* now we can alert the core that we're ready to send status */ 1561 /* now we can alert the core that we're ready to send status */
1493 purple_connection_set_state(js->gc, PURPLE_CONNECTED); 1562 purple_connection_set_state(js->gc, PURPLE_CONNECTED);
1494 jabber_disco_items_server(js);
1495 break; 1563 break;
1496 } 1564 }
1497 } 1565 }
1498 1566
1499 char *jabber_get_next_id(JabberStream *js) 1567 char *jabber_get_next_id(JabberStream *js)
1609 xmlnode_set_attrib(item, "jid", who); 1677 xmlnode_set_attrib(item, "jid", who);
1610 1678
1611 jabber_iq_send(iq); 1679 jabber_iq_send(iq);
1612 } 1680 }
1613 1681
1614 void jabber_add_feature(const char *shortname, const char *namespace, JabberFeatureEnabled cb) { 1682 void jabber_add_feature(const char *namespace, JabberFeatureEnabled cb) {
1615 JabberFeature *feat; 1683 JabberFeature *feat;
1616 1684
1617 g_return_if_fail(shortname != NULL);
1618 g_return_if_fail(namespace != NULL); 1685 g_return_if_fail(namespace != NULL);
1619 1686
1620 feat = g_new0(JabberFeature,1); 1687 feat = g_new0(JabberFeature,1);
1621 feat->shortname = g_strdup(shortname);
1622 feat->namespace = g_strdup(namespace); 1688 feat->namespace = g_strdup(namespace);
1623 feat->is_enabled = cb; 1689 feat->is_enabled = cb;
1624 1690
1625 /* try to remove just in case it already exists in the list */ 1691 /* try to remove just in case it already exists in the list */
1626 jabber_remove_feature(shortname); 1692 jabber_remove_feature(namespace);
1627 1693
1628 jabber_features = g_list_append(jabber_features, feat); 1694 jabber_features = g_list_append(jabber_features, feat);
1629 } 1695 }
1630 1696
1631 void jabber_remove_feature(const char *shortname) { 1697 void jabber_remove_feature(const char *namespace) {
1632 GList *feature; 1698 GList *feature;
1633 for(feature = jabber_features; feature; feature = feature->next) { 1699 for(feature = jabber_features; feature; feature = feature->next) {
1634 JabberFeature *feat = (JabberFeature*)feature->data; 1700 JabberFeature *feat = (JabberFeature*)feature->data;
1635 if(!strcmp(feat->shortname, shortname)) { 1701 if(!strcmp(feat->namespace, namespace)) {
1636 g_free(feat->shortname);
1637 g_free(feat->namespace); 1702 g_free(feat->namespace);
1638
1639 g_free(feature->data); 1703 g_free(feature->data);
1640 jabber_features = g_list_delete_link(jabber_features, feature); 1704 jabber_features = g_list_delete_link(jabber_features, feature);
1641 break; 1705 break;
1642 } 1706 }
1643 } 1707 }
1708 }
1709
1710 static void jabber_features_destroy(void)
1711 {
1712 while (jabber_features) {
1713 JabberFeature *feature = jabber_features->data;
1714 g_free(feature->namespace);
1715 g_free(feature);
1716 jabber_features = g_list_remove_link(jabber_features, jabber_features);
1717 }
1718 }
1719
1720 void jabber_add_identity(const gchar *category, const gchar *type, const gchar *lang, const gchar *name) {
1721 GList *identity;
1722 JabberIdentity *ident;
1723 /* both required according to XEP-0030 */
1724 g_return_if_fail(category != NULL);
1725 g_return_if_fail(type != NULL);
1726
1727 for(identity = jabber_identities; identity; identity = identity->next) {
1728 JabberIdentity *ident = (JabberIdentity*)identity->data;
1729 if (!strcmp(ident->category, category) &&
1730 !strcmp(ident->type, type) &&
1731 ((!ident->lang && !lang) || (ident->lang && lang && !strcmp(ident->lang, lang)))) {
1732 return;
1733 }
1734 }
1735
1736 ident = g_new0(JabberIdentity, 1);
1737 ident->category = g_strdup(category);
1738 ident->type = g_strdup(type);
1739 ident->lang = g_strdup(lang);
1740 ident->name = g_strdup(name);
1741 jabber_identities = g_list_append(jabber_identities, ident);
1742 }
1743
1744 static void jabber_identities_destroy(void)
1745 {
1746 while (jabber_identities) {
1747 JabberIdentity *id = jabber_identities->data;
1748 g_free(id->category);
1749 g_free(id->type);
1750 g_free(id->lang);
1751 g_free(id->name);
1752 g_free(id);
1753 jabber_identities = g_list_remove_link(jabber_identities, jabber_identities);
1754 }
1755 }
1756
1757 gboolean jabber_stream_is_ssl(JabberStream *js)
1758 {
1759 return (js->bosh && jabber_bosh_connection_is_ssl(js->bosh)) ||
1760 (!js->bosh && js->gsc);
1644 } 1761 }
1645 1762
1646 const char *jabber_list_icon(PurpleAccount *a, PurpleBuddy *b) 1763 const char *jabber_list_icon(PurpleAccount *a, PurpleBuddy *b)
1647 { 1764 {
1648 return "jabber"; 1765 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 PurpleAccount *account; 2758 PurpleAccount *account;
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 }

mercurial