comparison libpurple/protocols/jabber/jabber.c @ 25716:ba362a67278c

propagate from branch 'im.pidgin.pidgin' (head 2747d5e0324ca6b81e83bbb8b75e1efebcbbad6e) to branch 'im.pidgin.soc.2008.xmpp' (head 72d6870ed2c62423a05ed89822db25d9916ecf2b)
author Tobias Markmann <tfar@soc.pidgin.im>
date Sun, 03 Aug 2008 23:16:24 +0000
parents fa8567fa0ca0 9f8951284a2e
children 907ca9a36fe0
comparison
equal deleted inserted replaced
23685:58bb7fc244e4 25716:ba362a67278c
37 #include "server.h" 37 #include "server.h"
38 #include "util.h" 38 #include "util.h"
39 #include "version.h" 39 #include "version.h"
40 #include "xmlnode.h" 40 #include "xmlnode.h"
41 41
42 #include "caps.h"
42 #include "auth.h" 43 #include "auth.h"
43 #include "buddy.h" 44 #include "buddy.h"
44 #include "chat.h" 45 #include "chat.h"
45 #include "disco.h" 46 #include "disco.h"
46 #include "google.h" 47 #include "google.h"
58 #include "adhoccommands.h" 59 #include "adhoccommands.h"
59 60
60 #define JABBER_CONNECT_STEPS (js->gsc ? 9 : 5) 61 #define JABBER_CONNECT_STEPS (js->gsc ? 9 : 5)
61 62
62 static PurplePlugin *my_protocol = NULL; 63 static PurplePlugin *my_protocol = NULL;
64
63 GList *jabber_features = NULL; 65 GList *jabber_features = NULL;
66 GList *jabber_identities = NULL;
67
68 GHashTable *jabber_contact_info = NULL;
64 69
65 static void jabber_unregister_account_cb(JabberStream *js); 70 static void jabber_unregister_account_cb(JabberStream *js);
66 static void try_srv_connect(JabberStream *js); 71 static void try_srv_connect(JabberStream *js);
67 72
68 static void jabber_stream_init(JabberStream *js) 73 static void jabber_stream_init(JabberStream *js)
511 516
512 /* Tell the app that we're doing encryption */ 517 /* Tell the app that we're doing encryption */
513 jabber_stream_set_state(js, JABBER_STREAM_INITIALIZING_ENCRYPTION); 518 jabber_stream_set_state(js, JABBER_STREAM_INITIALIZING_ENCRYPTION);
514 } 519 }
515 520
521 static void
522 txt_resolved_cb(PurpleTxtResponse *resp, int results, gpointer data)
523 {
524 PurpleConnection *gc = data;
525 JabberStream *js = gc->proto_data;
526 int n;
527
528 if (results == 0) {
529 gchar *tmp;
530 tmp = g_strdup_printf(_("Could not find alternative XMPP connection methods after failing to connect directly.\n"));
531 purple_connection_error_reason (gc,
532 PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
533 g_free(tmp);
534 }
535
536 for (n = 0; n < results; n++) {
537 gchar **token;
538 token = g_strsplit(resp[n].content, "=", 2);
539 if (!strcmp(token[0], "_xmpp-client-xbosh")) {
540 purple_debug_info("jabber","Found alternative connection method using %s at %s.\n", token[0], token[1]);
541 js->bosh.url = g_strdup(token[1]);
542 g_strfreev(token);
543 break;
544 }
545 g_strfreev(token);
546 }
547 }
516 548
517 static void 549 static void
518 jabber_login_callback(gpointer data, gint source, const gchar *error) 550 jabber_login_callback(gpointer data, gint source, const gchar *error)
519 { 551 {
520 PurpleConnection *gc = data; 552 PurpleConnection *gc = data;
523 if (source < 0) { 555 if (source < 0) {
524 if (js->srv_rec != NULL) { 556 if (js->srv_rec != NULL) {
525 purple_debug_error("jabber", "Unable to connect to server: %s. Trying next SRV record.\n", error); 557 purple_debug_error("jabber", "Unable to connect to server: %s. Trying next SRV record.\n", error);
526 try_srv_connect(js); 558 try_srv_connect(js);
527 } else { 559 } else {
528 gchar *tmp; 560 purple_debug_info("jabber","Couldn't connect directly to %s. Trying to find alternative connection methods, like BOSH.\n", js->user->domain);
529 tmp = g_strdup_printf(_("Could not establish a connection with the server:\n%s"), 561 purple_txt_resolve("_xmppconnect", js->user->domain, txt_resolved_cb, gc);
530 error);
531 purple_connection_error_reason(gc,
532 PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
533 g_free(tmp);
534 } 562 }
535 return; 563 return;
536 } 564 }
537 565
538 g_free(js->srv_rec); 566 g_free(js->srv_rec);
706 } 734 }
707 735
708 /* no old-ssl, so if they've specified a connect server, we'll use that, otherwise we'll 736 /* no old-ssl, so if they've specified a connect server, we'll use that, otherwise we'll
709 * invoke the magic of SRV lookups, to figure out host and port */ 737 * invoke the magic of SRV lookups, to figure out host and port */
710 if(!js->gsc) { 738 if(!js->gsc) {
711 if(connect_server[0]) { 739 if(connect_server[0]) {
712 jabber_login_connect(js, js->user->domain, connect_server, purple_account_get_int(account, "port", 5222), TRUE); 740 jabber_login_connect(js, js->user->domain, connect_server, purple_account_get_int(account, "port", 5222), TRUE);
713 } else { 741 } else {
714 js->srv_query_data = purple_srv_resolve("xmpp-client", 742 js->srv_query_data = purple_srv_resolve("xmpp-client",
715 "tcp", js->user->domain, srv_resolved_cb, js); 743 "tcp", js->user->domain, srv_resolved_cb, js);
716 } 744 }
1425 JabberStream *js = gc->proto_data; 1453 JabberStream *js = gc->proto_data;
1426 1454
1427 js->idle = idle ? time(NULL) - idle : idle; 1455 js->idle = idle ? time(NULL) - idle : idle;
1428 } 1456 }
1429 1457
1430 void jabber_add_feature(const char *shortname, const char *namespace, JabberFeatureEnabled cb) { 1458 void jabber_add_feature(const char *namespace, JabberFeatureEnabled cb) {
1431 JabberFeature *feat; 1459 JabberFeature *feat;
1432 1460
1433 g_return_if_fail(shortname != NULL);
1434 g_return_if_fail(namespace != NULL); 1461 g_return_if_fail(namespace != NULL);
1435 1462
1436 feat = g_new0(JabberFeature,1); 1463 feat = g_new0(JabberFeature,1);
1437 feat->shortname = g_strdup(shortname);
1438 feat->namespace = g_strdup(namespace); 1464 feat->namespace = g_strdup(namespace);
1439 feat->is_enabled = cb; 1465 feat->is_enabled = cb;
1440 1466
1441 /* try to remove just in case it already exists in the list */ 1467 /* try to remove just in case it already exists in the list */
1442 jabber_remove_feature(shortname); 1468 jabber_remove_feature(namespace);
1443 1469
1444 jabber_features = g_list_append(jabber_features, feat); 1470 jabber_features = g_list_append(jabber_features, feat);
1445 } 1471 }
1446 1472
1447 void jabber_remove_feature(const char *shortname) { 1473 void jabber_remove_feature(const char *namespace) {
1448 GList *feature; 1474 GList *feature;
1449 for(feature = jabber_features; feature; feature = feature->next) { 1475 for(feature = jabber_features; feature; feature = feature->next) {
1450 JabberFeature *feat = (JabberFeature*)feature->data; 1476 JabberFeature *feat = (JabberFeature*)feature->data;
1451 if(!strcmp(feat->shortname, shortname)) { 1477 if(!strcmp(feat->namespace, namespace)) {
1452 g_free(feat->shortname);
1453 g_free(feat->namespace); 1478 g_free(feat->namespace);
1454
1455 g_free(feature->data); 1479 g_free(feature->data);
1456 jabber_features = g_list_delete_link(jabber_features, feature); 1480 jabber_features = g_list_delete_link(jabber_features, feature);
1457 break; 1481 break;
1458 } 1482 }
1459 } 1483 }
1484 }
1485
1486 void jabber_add_identity(const gchar *category, const gchar *type, const gchar *name) {
1487 GList *identity;
1488 JabberIdentity *ident;
1489 /* both required according to XEP-0030 */
1490 g_return_if_fail(category != NULL);
1491 g_return_if_fail(type != NULL);
1492
1493 for(identity = jabber_identities; identity; identity = identity->next) {
1494 JabberIdentity *ident = (JabberIdentity*)identity->data;
1495 if(!strcmp(ident->category, category)) {
1496 if (!strcmp(ident->type, type)) return;
1497 }
1498 }
1499
1500 ident = g_new0(JabberIdentity, 1);
1501 ident->category = g_strdup(category);
1502 ident->type = g_strdup(type);
1503 ident->name = g_strdup(name);
1504 jabber_identities = g_list_append(jabber_identities, ident);
1460 } 1505 }
1461 1506
1462 const char *jabber_list_icon(PurpleAccount *a, PurpleBuddy *b) 1507 const char *jabber_list_icon(PurpleAccount *a, PurpleBuddy *b)
1463 { 1508 {
1464 return "jabber"; 1509 return "jabber";
2457 PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_PRPL_ONLY, 2502 PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_PRPL_ONLY,
2458 "prpl-jabber", jabber_cmd_buzz, 2503 "prpl-jabber", jabber_cmd_buzz,
2459 _("buzz: Buzz a user to get their attention"), NULL); 2504 _("buzz: Buzz a user to get their attention"), NULL);
2460 } 2505 }
2461 2506
2507 /* IPC fucntions*/
2508
2509 /*
2510 * IPC function for checking wheather a client at a full JID supports a certain feature.
2511 *
2512 * @param fulljid The full JID of the client.
2513 * @param featrure The feature's namespace.
2514 *
2515 * @return TRUE if supports feature; else FALSE.
2516 */
2517 static gboolean
2518 jabber_ipc_contact_has_feature(gchar *fulljid, gchar *feature)
2519 {
2520 JabberCapsKey *caps_info = NULL;
2521 JabberCapsValueExt *capabilities = NULL;
2522
2523 caps_info = g_hash_table_lookup(jabber_contact_info, fulljid);
2524
2525 if (!caps_info) return FALSE;
2526 capabilities = g_hash_table_lookup(capstable, caps_info);
2527
2528 if (g_list_find_custom(capabilities->features, feature, strcmp) == NULL) return FALSE ;
2529 return TRUE;
2530 }
2531
2532 static void
2533 jabber_ipc_add_feature(gchar *feature)
2534 {
2535 if (feature == 0) return;
2536 jabber_add_feature(feature, 0);
2537
2538 // send presence with new caps info for all connected accounts
2539 jabber_caps_broadcast_change();
2540 }
2541
2462 void 2542 void
2463 jabber_init_plugin(PurplePlugin *plugin) 2543 jabber_init_plugin(PurplePlugin *plugin)
2464 { 2544 {
2465 my_protocol = plugin; 2545 my_protocol = plugin;
2466 } 2546
2547 jabber_add_identity("client", "pc", PACKAGE);
2548
2549 /* initialize jabber_features list */
2550 jabber_add_feature("jabber:iq:last", 0);
2551 jabber_add_feature("jabber:iq:oob", 0);
2552 jabber_add_feature("jabber:iq:time", 0);
2553 jabber_add_feature("xmpp:urn:time", 0);
2554 jabber_add_feature("jabber:iq:version", 0);
2555 jabber_add_feature("jabber:x:conference", 0);
2556 jabber_add_feature("http://jabber.org/protocol/bytestreams", 0);
2557 jabber_add_feature("http://jabber.org/protocol/disco#info", 0);
2558 jabber_add_feature("http://jabber.org/protocol/disco#items", 0);
2559 #if 0
2560 jabber_add_feature("http://jabber.org/protocol/ibb", 0);
2561 #endif
2562 jabber_add_feature("http://jabber.org/protocol/muc", 0);
2563 jabber_add_feature("http://jabber.org/protocol/muc#user", 0);
2564 jabber_add_feature("http://jabber.org/protocol/si", 0);
2565 jabber_add_feature("http://jabber.org/protocol/si/profile/file-transfer", 0);
2566 jabber_add_feature("http://jabber.org/protocol/xhtml-im", 0);
2567 jabber_add_feature("urn:xmpp:ping", 0);
2568
2569 jabber_contact_info = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, jabber_caps_destroy_key);
2570
2571 /* IPC functions */
2572 purple_plugin_ipc_register(plugin, "contact_has_feature", PURPLE_CALLBACK(jabber_ipc_contact_has_feature),
2573 purple_marshal_BOOLEAN__POINTER_POINTER,
2574 purple_value_new(PURPLE_TYPE_BOOLEAN), 2,
2575 purple_value_new(PURPLE_TYPE_STRING),
2576 purple_value_new(PURPLE_TYPE_STRING));
2577 purple_plugin_ipc_register(plugin, "add_feature", PURPLE_CALLBACK(jabber_ipc_add_feature),
2578 purple_marshal_VOID__POINTER,
2579 NULL, 1,
2580 purple_value_new(PURPLE_TYPE_STRING));
2581 }