Mercurial > pidgin.yaz
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 } |