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 }