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