comparison libpurple/protocols/jabber/jabber.c @ 26817:3912f55a1633

propagate from branch 'im.pidgin.pidgin' (head fbb4fe5da444943eecc76bdcd6c8ba967790b6c8) to branch 'im.pidgin.cpw.darkrain42.xmpp.bosh' (head 601bc627c9430320848361f0ed81c6c4c6ee53e0)
author Paul Aurich <paul@darkrain42.org>
date Tue, 28 Apr 2009 18:43:57 +0000
parents 91b70522776e baa3867f2281
children a0e48796defb
comparison
equal deleted inserted replaced
26743:de9816c970fe 26817:3912f55a1633
26 #include "cmds.h" 26 #include "cmds.h"
27 #include "connection.h" 27 #include "connection.h"
28 #include "conversation.h" 28 #include "conversation.h"
29 #include "debug.h" 29 #include "debug.h"
30 #include "dnssrv.h" 30 #include "dnssrv.h"
31 #include "imgstore.h"
31 #include "message.h" 32 #include "message.h"
32 #include "notify.h" 33 #include "notify.h"
33 #include "pluginpref.h" 34 #include "pluginpref.h"
34 #include "privacy.h" 35 #include "privacy.h"
35 #include "proxy.h" 36 #include "proxy.h"
36 #include "prpl.h" 37 #include "prpl.h"
37 #include "request.h" 38 #include "request.h"
38 #include "server.h" 39 #include "server.h"
40 #include "status.h"
39 #include "util.h" 41 #include "util.h"
40 #include "version.h" 42 #include "version.h"
41 #include "xmlnode.h" 43 #include "xmlnode.h"
42 44
43 #include "auth.h" 45 #include "auth.h"
79 open_stream = g_strdup_printf("<stream:stream to='%s' " 81 open_stream = g_strdup_printf("<stream:stream to='%s' "
80 "xmlns='jabber:client' " 82 "xmlns='jabber:client' "
81 "xmlns:stream='http://etherx.jabber.org/streams' " 83 "xmlns:stream='http://etherx.jabber.org/streams' "
82 "version='1.0'>", 84 "version='1.0'>",
83 js->user->domain); 85 js->user->domain);
86 if (js->reinit)
87 /* Close down the current stream to keep the XML parser happy */
88 jabber_parser_close_stream(js);
89
84 /* setup the parser fresh for each stream */ 90 /* setup the parser fresh for each stream */
85 jabber_parser_setup(js); 91 jabber_parser_setup(js);
86 jabber_send_raw(js, open_stream, -1); 92 jabber_send_raw(js, open_stream, -1);
87 js->reinit = FALSE; 93 js->reinit = FALSE;
88 g_free(open_stream); 94 g_free(open_stream);
673 purple_connection_ssl_error (gc, error); 679 purple_connection_ssl_error (gc, error);
674 } 680 }
675 681
676 static void tls_init(JabberStream *js) 682 static void tls_init(JabberStream *js)
677 { 683 {
684 /* Close down the current stream to keep the XML parser happy */
685 jabber_parser_close_stream(js);
686
678 purple_input_remove(js->gc->inpa); 687 purple_input_remove(js->gc->inpa);
679 js->gc->inpa = 0; 688 js->gc->inpa = 0;
680 js->gsc = purple_ssl_connect_with_host_fd(js->gc->account, js->fd, 689 js->gsc = purple_ssl_connect_with_host_fd(js->gc->account, js->fd,
681 jabber_login_callback_ssl, jabber_ssl_connect_failure, js->certificate_CN, js->gc); 690 jabber_login_callback_ssl, jabber_ssl_connect_failure, js->certificate_CN, js->gc);
682 } 691 }
745 { 754 {
746 PurpleConnection *gc = purple_account_get_connection(account); 755 PurpleConnection *gc = purple_account_get_connection(account);
747 const char *connect_server = purple_account_get_string(account, 756 const char *connect_server = purple_account_get_string(account,
748 "connect_server", ""); 757 "connect_server", "");
749 JabberStream *js; 758 JabberStream *js;
759 PurplePresence *presence;
760 PurpleStoredImage *image;
750 JabberBuddy *my_jb = NULL; 761 JabberBuddy *my_jb = NULL;
751 762
752 gc->flags |= PURPLE_CONNECTION_HTML | 763 gc->flags |= PURPLE_CONNECTION_HTML |
753 PURPLE_CONNECTION_ALLOW_CUSTOM_SMILEY; 764 PURPLE_CONNECTION_ALLOW_CUSTOM_SMILEY;
754 js = gc->proto_data = g_new0(JabberStream, 1); 765 js = gc->proto_data = g_new0(JabberStream, 1);
763 js->chats = g_hash_table_new_full(g_str_hash, g_str_equal, 774 js->chats = g_hash_table_new_full(g_str_hash, g_str_equal,
764 g_free, (GDestroyNotify)jabber_chat_free); 775 g_free, (GDestroyNotify)jabber_chat_free);
765 js->user = jabber_id_new(purple_account_get_username(account)); 776 js->user = jabber_id_new(purple_account_get_username(account));
766 js->next_id = g_random_int(); 777 js->next_id = g_random_int();
767 js->write_buffer = purple_circ_buffer_new(512); 778 js->write_buffer = purple_circ_buffer_new(512);
768 js->old_length = 0; 779 js->old_length = -1;
769 js->keepalive_timeout = -1; 780 js->keepalive_timeout = -1;
770 /* Set the default protocol version to 1.0. Overridden in parser.c. */ 781 /* Set the default protocol version to 1.0. Overridden in parser.c. */
771 js->protocol_version = JABBER_PROTO_1_0; 782 js->protocol_version = JABBER_PROTO_1_0;
772 js->sessions = NULL; 783 js->sessions = NULL;
773 js->stun_ip = NULL; 784 js->stun_ip = NULL;
774 js->stun_port = 0; 785 js->stun_port = 0;
775 js->stun_query = NULL; 786 js->stun_query = NULL;
776 787
788 /* if we are idle, set idle-ness on the stream (this could happen if we get
789 disconnected and the reconnects while being idle. I don't think it makes
790 sense to do this when registering a new account... */
791 presence = purple_account_get_presence(account);
792 if (purple_presence_is_idle(presence))
793 js->idle = purple_presence_get_idle_time(presence);
794
777 if(!js->user) { 795 if(!js->user) {
778 purple_connection_error_reason (gc, 796 purple_connection_error_reason (gc,
779 PURPLE_CONNECTION_ERROR_INVALID_SETTINGS, 797 PURPLE_CONNECTION_ERROR_INVALID_SETTINGS,
780 _("Invalid XMPP ID")); 798 _("Invalid XMPP ID"));
781 return; 799 return;
784 if (!js->user->domain || *(js->user->domain) == '\0') { 802 if (!js->user->domain || *(js->user->domain) == '\0') {
785 purple_connection_error_reason (gc, 803 purple_connection_error_reason (gc,
786 PURPLE_CONNECTION_ERROR_INVALID_SETTINGS, 804 PURPLE_CONNECTION_ERROR_INVALID_SETTINGS,
787 _("Invalid XMPP ID. Domain must be set.")); 805 _("Invalid XMPP ID. Domain must be set."));
788 return; 806 return;
807 }
808
809 /*
810 * Calculate the avatar hash for our current image so we know (when we
811 * fetch our vCard and PEP avatar) if we should send our avatar to the
812 * server.
813 */
814 if ((image = purple_buddy_icons_find_account_icon(account))) {
815 js->initial_avatar_hash = jabber_calculate_data_sha1sum(purple_imgstore_get_data(image),
816 purple_imgstore_get_size(image));
817 purple_imgstore_unref(image);
789 } 818 }
790 819
791 if((my_jb = jabber_buddy_find(js, purple_account_get_username(account), TRUE))) 820 if((my_jb = jabber_buddy_find(js, purple_account_get_username(account), TRUE)))
792 my_jb->subscription |= JABBER_SUB_BOTH; 821 my_jb->subscription |= JABBER_SUB_BOTH;
793 822
1409 js->unregistration_user_data = user_data; 1438 js->unregistration_user_data = user_data;
1410 1439
1411 jabber_unregister_account_cb(js); 1440 jabber_unregister_account_cb(js);
1412 } 1441 }
1413 1442
1443 /* TODO: As Will pointed out in IRC, after being notified by the core to
1444 * shutdown, we should async. wait for the server to send us the stream
1445 * termination before destorying everything. That seems like it would require
1446 * changing the semantics of prpl->close(), so it's a good idea for 3.0.0.
1447 */
1414 void jabber_close(PurpleConnection *gc) 1448 void jabber_close(PurpleConnection *gc)
1415 { 1449 {
1416 JabberStream *js = gc->proto_data; 1450 JabberStream *js = gc->proto_data;
1417 1451
1418 /* Close all of the open Jingle sessions on this stream */ 1452 /* Close all of the open Jingle sessions on this stream */
1484 } 1518 }
1485 1519
1486 g_free(js->stream_id); 1520 g_free(js->stream_id);
1487 if(js->user) 1521 if(js->user)
1488 jabber_id_free(js->user); 1522 jabber_id_free(js->user);
1523 g_free(js->initial_avatar_hash);
1489 g_free(js->avatar_hash); 1524 g_free(js->avatar_hash);
1490 g_free(js->caps_hash); 1525 g_free(js->caps_hash);
1491 1526
1492 purple_circ_buffer_destroy(js->write_buffer); 1527 purple_circ_buffer_destroy(js->write_buffer);
1493 if(js->writeh) 1528 if(js->writeh)
1600 1635
1601 1636
1602 void jabber_idle_set(PurpleConnection *gc, int idle) 1637 void jabber_idle_set(PurpleConnection *gc, int idle)
1603 { 1638 {
1604 JabberStream *js = gc->proto_data; 1639 JabberStream *js = gc->proto_data;
1640 PurpleAccount *account = purple_connection_get_account(gc);
1641 PurpleStatus *status = purple_account_get_active_status(account);
1605 1642
1606 js->idle = idle ? time(NULL) - idle : idle; 1643 js->idle = idle ? time(NULL) - idle : idle;
1644
1645 /* send out an updated prescence */
1646 purple_debug_info("jabber", "sending updated presence for idle\n");
1647 jabber_presence_send(account, status);
1607 } 1648 }
1608 1649
1609 static void jabber_blocklist_parse(JabberStream *js, const char *from, 1650 static void jabber_blocklist_parse(JabberStream *js, const char *from,
1610 JabberIqType type, const char *id, 1651 JabberIqType type, const char *id,
1611 xmlnode *packet, gpointer data) 1652 xmlnode *packet, gpointer data)
1828 if(jb && !PURPLE_BUDDY_IS_ONLINE(b) && (jb->subscription & JABBER_SUB_PENDING || !(jb->subscription & JABBER_SUB_TO))) { 1869 if(jb && !PURPLE_BUDDY_IS_ONLINE(b) && (jb->subscription & JABBER_SUB_PENDING || !(jb->subscription & JABBER_SUB_TO))) {
1829 ret = g_strdup(_("Not Authorized")); 1870 ret = g_strdup(_("Not Authorized"));
1830 } else if(jb && !PURPLE_BUDDY_IS_ONLINE(b) && jb->error_msg) { 1871 } else if(jb && !PURPLE_BUDDY_IS_ONLINE(b) && jb->error_msg) {
1831 ret = g_strdup(jb->error_msg); 1872 ret = g_strdup(jb->error_msg);
1832 } else { 1873 } else {
1874 PurplePresence *presence = purple_buddy_get_presence(b);
1875 PurpleStatus *status =purple_presence_get_active_status(presence);
1833 char *stripped; 1876 char *stripped;
1834 1877
1835 if(!(stripped = purple_markup_strip_html(jabber_buddy_get_status_msg(jb)))) { 1878 if(!(stripped = purple_markup_strip_html(purple_status_get_attr_string(status, "message")))) {
1836 PurplePresence *presence = purple_buddy_get_presence(b);
1837 if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_TUNE)) { 1879 if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_TUNE)) {
1838 PurpleStatus *status = purple_presence_get_status(presence, "tune"); 1880 PurpleStatus *status = purple_presence_get_status(presence, "tune");
1839 stripped = g_strdup(purple_status_get_attr_string(status, PURPLE_TUNE_TITLE)); 1881 stripped = g_strdup(purple_status_get_attr_string(status, PURPLE_TUNE_TITLE));
1840 } 1882 }
1841 } 1883 }
1845 g_free(stripped); 1887 g_free(stripped);
1846 } 1888 }
1847 } 1889 }
1848 1890
1849 return ret; 1891 return ret;
1892 }
1893
1894 static void
1895 jabber_tooltip_add_resource_text(JabberBuddyResource *jbr,
1896 PurpleNotifyUserInfo *user_info, gboolean multiple_resources)
1897 {
1898 char *text = NULL;
1899 char *res = NULL;
1900 char *label, *value;
1901 const char *state;
1902
1903 if(jbr->status) {
1904 char *tmp;
1905 text = purple_strreplace(jbr->status, "\n", "<br />\n");
1906 tmp = purple_markup_strip_html(text);
1907 g_free(text);
1908 text = g_markup_escape_text(tmp, -1);
1909 g_free(tmp);
1910 }
1911
1912 if(jbr->name)
1913 res = g_strdup_printf(" (%s)", jbr->name);
1914
1915 state = jabber_buddy_state_get_name(jbr->state);
1916 if (text != NULL && !purple_utf8_strcasecmp(state, text)) {
1917 g_free(text);
1918 text = NULL;
1919 }
1920
1921 label = g_strdup_printf("%s%s", _("Status"), (res ? res : ""));
1922 value = g_strdup_printf("%s%s%s", state, (text ? ": " : ""), (text ? text : ""));
1923
1924 purple_notify_user_info_add_pair(user_info, label, value);
1925 g_free(label);
1926 g_free(value);
1927 g_free(text);
1928
1929 /* if the resource is idle, show that */
1930 /* only show it if there is more than one resource available for
1931 the buddy, since the "general" idleness will be shown anyway,
1932 this way we can see see the idleness of lower-priority resources */
1933 if (jbr->idle && multiple_resources) {
1934 gchar *idle_str =
1935 purple_str_seconds_to_string(time(NULL) - jbr->idle);
1936 label = g_strdup_printf("%s%s", _("Idle"), (res ? res : ""));
1937 purple_notify_user_info_add_pair(user_info, label, idle_str);
1938 g_free(idle_str);
1939 g_free(label);
1940 }
1941 g_free(res);
1850 } 1942 }
1851 1943
1852 void jabber_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full) 1944 void jabber_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full)
1853 { 1945 {
1854 JabberBuddy *jb; 1946 JabberBuddy *jb;
1870 JabberBuddyResource *jbr = NULL; 1962 JabberBuddyResource *jbr = NULL;
1871 PurplePresence *presence = purple_buddy_get_presence(b); 1963 PurplePresence *presence = purple_buddy_get_presence(b);
1872 const char *sub; 1964 const char *sub;
1873 GList *l; 1965 GList *l;
1874 const char *mood; 1966 const char *mood;
1875 1967 gboolean multiple_resources =
1968 jb->resources && g_list_next(jb->resources);
1969 JabberBuddyResource *top_jbr = jabber_buddy_find_resource(jb, NULL);
1970
1971 /* resource-specific info for the top resource */
1972 if (top_jbr) {
1973 jabber_tooltip_add_resource_text(top_jbr, user_info,
1974 multiple_resources);
1975 }
1976
1977 for(l=jb->resources; l; l = l->next) {
1978 jbr = l->data;
1979 /* the remaining resources */
1980 if (jbr != top_jbr) {
1981 jabber_tooltip_add_resource_text(jbr, user_info,
1982 multiple_resources);
1983 }
1984 }
1985
1876 if (full) { 1986 if (full) {
1877 PurpleStatus *status; 1987 PurpleStatus *status;
1878
1879 if(jb->subscription & JABBER_SUB_FROM) {
1880 if(jb->subscription & JABBER_SUB_TO)
1881 sub = _("Both");
1882 else if(jb->subscription & JABBER_SUB_PENDING)
1883 sub = _("From (To pending)");
1884 else
1885 sub = _("From");
1886 } else {
1887 if(jb->subscription & JABBER_SUB_TO)
1888 sub = _("To");
1889 else if(jb->subscription & JABBER_SUB_PENDING)
1890 sub = _("None (To pending)");
1891 else
1892 sub = _("None");
1893 }
1894
1895 purple_notify_user_info_add_pair(user_info, _("Subscription"), sub);
1896 1988
1897 status = purple_presence_get_active_status(presence); 1989 status = purple_presence_get_active_status(presence);
1898 mood = purple_status_get_attr_string(status, "mood"); 1990 mood = purple_status_get_attr_string(status, "mood");
1899 if(mood != NULL) { 1991 if(mood != NULL) {
1900 const char *moodtext; 1992 const char *moodtext;
1916 if (playing) { 2008 if (playing) {
1917 purple_notify_user_info_add_pair(user_info, _("Now Listening"), playing); 2009 purple_notify_user_info_add_pair(user_info, _("Now Listening"), playing);
1918 g_free(playing); 2010 g_free(playing);
1919 } 2011 }
1920 } 2012 }
1921 } 2013
1922 2014 if(jb->subscription & JABBER_SUB_FROM) {
1923 for(l=jb->resources; l; l = l->next) { 2015 if(jb->subscription & JABBER_SUB_TO)
1924 char *text = NULL; 2016 sub = _("Both");
1925 char *res = NULL; 2017 else if(jb->subscription & JABBER_SUB_PENDING)
1926 char *label, *value; 2018 sub = _("From (To pending)");
1927 const char *state; 2019 else
1928 2020 sub = _("From");
1929 jbr = l->data; 2021 } else {
1930 2022 if(jb->subscription & JABBER_SUB_TO)
1931 if(jbr->status) { 2023 sub = _("To");
1932 char *tmp; 2024 else if(jb->subscription & JABBER_SUB_PENDING)
1933 text = purple_strreplace(jbr->status, "\n", "<br />\n"); 2025 sub = _("None (To pending)");
1934 tmp = purple_markup_strip_html(text); 2026 else
1935 g_free(text); 2027 sub = _("None");
1936 text = g_markup_escape_text(tmp, -1);
1937 g_free(tmp);
1938 } 2028 }
1939 2029
1940 if(jbr->name) 2030 purple_notify_user_info_add_pair(user_info, _("Subscription"), sub);
1941 res = g_strdup_printf(" (%s)", jbr->name); 2031
1942
1943 state = jabber_buddy_state_get_name(jbr->state);
1944 if (text != NULL && !purple_utf8_strcasecmp(state, text)) {
1945 g_free(text);
1946 text = NULL;
1947 }
1948
1949 label = g_strdup_printf("%s%s",
1950 _("Status"), (res ? res : ""));
1951 value = g_strdup_printf("%s%s%s",
1952 state,
1953 (text ? ": " : ""),
1954 (text ? text : ""));
1955
1956 purple_notify_user_info_add_pair(user_info, label, value);
1957
1958 g_free(label);
1959 g_free(value);
1960 g_free(text);
1961 g_free(res);
1962 } 2032 }
1963 2033
1964 if(!PURPLE_BUDDY_IS_ONLINE(b) && jb->error_msg) { 2034 if(!PURPLE_BUDDY_IS_ONLINE(b) && jb->error_msg) {
1965 purple_notify_user_info_add_pair(user_info, _("Error"), jb->error_msg); 2035 purple_notify_user_info_add_pair(user_info, _("Error"), jb->error_msg);
1966 } 2036 }
2449 JabberChat *chat = jabber_chat_find_by_conv(conv); 2519 JabberChat *chat = jabber_chat_find_by_conv(conv);
2450 2520
2451 if (!chat) 2521 if (!chat)
2452 return PURPLE_CMD_RET_FAILED; 2522 return PURPLE_CMD_RET_FAILED;
2453 2523
2454 jabber_chat_change_topic(chat, args ? args[0] : NULL); 2524 if (args && args[0] && *args[0])
2525 jabber_chat_change_topic(chat, args[0]);
2526 else {
2527 const char *cur = purple_conv_chat_get_topic(PURPLE_CONV_CHAT(conv));
2528 char *buf, *tmp, *tmp2;
2529
2530 if (cur) {
2531 tmp = g_markup_escape_text(cur, -1);
2532 tmp2 = purple_markup_linkify(tmp);
2533 buf = g_strdup_printf(_("current topic is: %s"), tmp2);
2534 g_free(tmp);
2535 g_free(tmp2);
2536 } else
2537 buf = g_strdup(_("No topic is set"));
2538 purple_conv_chat_write(PURPLE_CONV_CHAT(conv), "", buf,
2539 PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_NO_LOG, time(NULL));
2540 g_free(buf);
2541 }
2542
2455 return PURPLE_CMD_RET_OK; 2543 return PURPLE_CMD_RET_OK;
2456 } 2544 }
2457 2545
2458 static PurpleCmdRet jabber_cmd_chat_nick(PurpleConversation *conv, 2546 static PurpleCmdRet jabber_cmd_chat_nick(PurpleConversation *conv,
2459 const char *cmd, char **args, char **error, void *data) 2547 const char *cmd, char **args, char **error, void *data)