Mercurial > pidgin
changeset 29235:816223a49038
merge of '584de5e77d7a29a10037eba7c064d791f2814821'
and '65542da15a8b1f08f18238f3d7223dc65f983822'
author | John Bailey <rekkanoryo@rekkanoryo.org> |
---|---|
date | Sun, 08 Nov 2009 23:38:08 +0000 |
parents | 6652fdb8baf5 (current diff) e77894113a14 (diff) |
children | be31e811cb26 |
files | |
diffstat | 33 files changed, 533 insertions(+), 247 deletions(-) [+] |
line wrap: on
line diff
--- a/COPYRIGHT Sun Nov 08 23:36:28 2009 +0000 +++ b/COPYRIGHT Sun Nov 08 23:38:08 2009 +0000 @@ -268,6 +268,7 @@ Ambrose C. Li Nicolas Lichtmaier Wesley Lin +Shaun Lindsay Artem Litvinovich Josh Littlefield Daniel Ljungborg
--- a/ChangeLog Sun Nov 08 23:36:28 2009 +0000 +++ b/ChangeLog Sun Nov 08 23:38:08 2009 +0000 @@ -1,3 +1,4 @@ + Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul version 2.7.0 (??/??/????): @@ -26,12 +27,23 @@ * Fix DNS TXT query resolution. * Always rejoin open chats after an account reconnects. + AIM and ICQ: + * Better rate limit calculations and other improvements. (Aman Gupta) + * More detailed error messages when messages fail to send. (Aman Gupta) + * The simultaneous login account option is respected when using + the clientLogin authentication method. + * Fix offline message retrieval (broken in 2.6.3) + * Fix SSL when clientLogin is enabled. + MSN: * Don't forget display names for buddies. * Fix a random crash that might occur when idle. * Fix more FQY 240 connection errors. * Fix a crash that could occur when adding a buddy. * Fix an occasional crash when sending message to an offline user. + * Fix a random crash that might occur when idle. + * Fix a crash when logging in with some long non-ASCII passwords. + (Shaun Lindsay) XMPP: * Users connecting to Google Talk now have an "Initiate Chat" context menu @@ -39,6 +51,9 @@ * Fix a crash when attempting to validate an invalid JID. * Resolve an issue when connecting to iChat Server when no resource is specified. + * Try to automatically find a STUN server by using an SRV lookup on the + account's domain, and use that for voice and video if found and the user + didn't set one manually in prefs. * Fix a crash when adding a buddy without an '@'. Yahoo: @@ -58,12 +73,6 @@ * The userlist in a multiuser chat can be styled via gtkrc by using the widget name "pidgin_conv_userlist". (Heiko Schmitt) * Add a hold button to the media window. - * Tooltips for custom smileys should work now. - * Users with unread messages are again bolded in the Buddy List. - * Minor reworking of the Preferences window's Network tab to make it need - less vertical space. - * The global "Use remote DNS with SOCKS4 proxies" preference no longer - disappears when the preference value changes in certain ways. version 2.6.3 (10/16/2009): General:
--- a/finch/libgnt/gnttree.c Sun Nov 08 23:36:28 2009 +0000 +++ b/finch/libgnt/gnttree.c Sun Nov 08 23:38:08 2009 +0000 @@ -815,7 +815,7 @@ gnt_widget_activate(widget); } else if (tree->priv->search) { gboolean changed = TRUE; - if (isalnum(*text)) { + if (g_unichar_isprint(*text)) { tree->priv->search = g_string_append_c(tree->priv->search, *text); } else if (g_utf8_collate(text, GNT_KEY_BACKSPACE) == 0) { if (tree->priv->search->len)
--- a/libpurple/protocols/bonjour/mdns_avahi.c Sun Nov 08 23:36:28 2009 +0000 +++ b/libpurple/protocols/bonjour/mdns_avahi.c Sun Nov 08 23:38:08 2009 +0000 @@ -150,6 +150,10 @@ } break; case AVAHI_RESOLVER_FOUND: + + purple_debug_info("bonjour", "_resolve_callback - name:%s account:%p bb:%p\n", + name, account, bb); + /* create a buddy record */ if (bb == NULL) bb = bonjour_buddy_new(name, account); @@ -173,8 +177,12 @@ /* Get the ip as a string */ + ip[0] = '\0'; avahi_address_snprint(ip, AVAHI_ADDRESS_STR_MAX, a); + purple_debug_info("bonjour", "_resolve_callback - name:%s ip:%s prev_ip:%s\n", + name, ip, rd->ip); + if (rd->ip == NULL || strcmp(rd->ip, ip) != 0) { /* We store duplicates in bb->ips, so we always remove the one */ if (rd->ip != NULL) {
--- a/libpurple/protocols/jabber/auth.c Sun Nov 08 23:36:28 2009 +0000 +++ b/libpurple/protocols/jabber/auth.c Sun Nov 08 23:38:08 2009 +0000 @@ -58,7 +58,7 @@ PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT, _("Server requires TLS/SSL, but no TLS/SSL support was found.")); return TRUE; - } else if(purple_account_get_bool(js->gc->account, "require_tls", FALSE)) { + } else if(purple_account_get_bool(js->gc->account, "require_tls", JABBER_DEFAULT_REQUIRE_TLS)) { purple_connection_error_reason(js->gc, PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT, _("You require encryption, but no TLS/SSL support was found.")); @@ -381,13 +381,13 @@ * due to mechanism specific issues, so we want to try one of the other * supported mechanisms. This code handles that case */ - if (js->current_mech && strlen(js->current_mech) > 0) { + if (js->current_mech && *js->current_mech) { char *pos; if ((pos = strstr(js->sasl_mechs->str, js->current_mech))) { g_string_erase(js->sasl_mechs, pos-js->sasl_mechs->str, strlen(js->current_mech)); } /* Remove space which separated this mech from the next */ - if (strlen(js->sasl_mechs->str) > 0 && ((js->sasl_mechs->str)[0] == ' ')) { + if ((js->sasl_mechs->str)[0] == ' ') { g_string_erase(js->sasl_mechs, 0, 1); } again = TRUE; @@ -511,7 +511,7 @@ * support it and including it gives a false fall-back to other mechs offerred, * leading to incorrect error handling. */ - if (mech_name && !strcmp(mech_name, "X-GOOGLE-TOKEN")) { + if (purple_strequal(mech_name, "X-GOOGLE-TOKEN")) { g_free(mech_name); continue; } @@ -519,9 +519,9 @@ g_string_append(js->sasl_mechs, mech_name); g_string_append_c(js->sasl_mechs, ' '); #else - if(mech_name && !strcmp(mech_name, "DIGEST-MD5")) + if (purple_strequal(mech_name, "DIGEST-MD5")) digest_md5 = TRUE; - else if(mech_name && !strcmp(mech_name, "PLAIN")) + else if (purple_strequal(mech_name, "PLAIN")) plain = TRUE; #endif g_free(mech_name); @@ -586,7 +586,7 @@ /* FIXME: Why is this not in jabber_parse_error? */ if((error = xmlnode_get_child(packet, "error")) && (err_code = xmlnode_get_attrib(error, "code")) && - !strcmp(err_code, "401")) { + g_str_equal(err_code, "401")) { reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED; /* Clear the pasword if it isn't being saved */ if (!purple_account_get_remember_password(js->gc->account)) @@ -698,7 +698,7 @@ * is requiring SSL/TLS, we need to enforce it. */ if (!jabber_stream_is_ssl(js) && - purple_account_get_bool(purple_connection_get_account(js->gc), "require_tls", FALSE)) { + purple_account_get_bool(purple_connection_get_account(js->gc), "require_tls", JABBER_DEFAULT_REQUIRE_TLS)) { purple_connection_error_reason(js->gc, PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR, _("You require encryption, but it is not available on this server.")); @@ -877,7 +877,7 @@ } dec_in = (char *)purple_base64_decode(enc_in, NULL); - purple_debug(PURPLE_DEBUG_MISC, "jabber", "decoded challenge (%" + purple_debug_misc("jabber", "decoded challenge (%" G_GSIZE_FORMAT "): %s\n", strlen(dec_in), dec_in); parts = parse_challenge(dec_in); @@ -887,8 +887,7 @@ char *rspauth = g_hash_table_lookup(parts, "rspauth"); - if(rspauth && js->expected_rspauth && - !strcmp(rspauth, js->expected_rspauth)) { + if (rspauth && purple_strequal(rspauth, js->expected_rspauth)) { jabber_send_raw(js, "<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl' />", -1); @@ -1014,7 +1013,7 @@ * realm are always encoded in UTF-8 (they seem to be the values * we pass in), so we need to ensure charset=utf-8 is set. */ - if (!js->current_mech || !g_str_equal(js->current_mech, "DIGEST-MD5") || + if (!purple_strequal(js->current_mech, "DIGEST-MD5") || strstr(c_out, ",charset=")) /* If we're not using DIGEST-MD5 or Cyrus SASL is fixed */ enc_out = purple_base64_encode((unsigned char*)c_out, clen); @@ -1041,7 +1040,7 @@ const void *x; #endif - if(!ns || strcmp(ns, "urn:ietf:params:xml:ns:xmpp-sasl")) { + if (!purple_strequal(ns, "urn:ietf:params:xml:ns:xmpp-sasl")) { purple_connection_error_reason(js->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Invalid response from server")); @@ -1072,6 +1071,7 @@ purple_connection_error_reason(js->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Invalid response from server")); + g_return_if_reached(); } } /* If we've negotiated a security layer, we need to enable it */ @@ -1099,17 +1099,17 @@ #ifdef HAVE_CYRUS_SASL if(js->auth_fail_count++ < 5) { - if (js->current_mech && strlen(js->current_mech) > 0) { + if (js->current_mech && *js->current_mech) { char *pos; if ((pos = strstr(js->sasl_mechs->str, js->current_mech))) { g_string_erase(js->sasl_mechs, pos-js->sasl_mechs->str, strlen(js->current_mech)); } /* Remove space which separated this mech from the next */ - if (strlen(js->sasl_mechs->str) > 0 && ((js->sasl_mechs->str)[0] == ' ')) { + if ((js->sasl_mechs->str)[0] == ' ') { g_string_erase(js->sasl_mechs, 0, 1); } } - if (strlen(js->sasl_mechs->str)) { + if (*js->sasl_mechs->str) { /* If we have remaining mechs to try, do so */ sasl_dispose(&js->sasl);
--- a/libpurple/protocols/jabber/buddy.c Sun Nov 08 23:36:28 2009 +0000 +++ b/libpurple/protocols/jabber/buddy.c Sun Nov 08 23:38:08 2009 +0000 @@ -581,8 +581,7 @@ if (text != NULL && *text != '\0') { xmlnode *xp; - purple_debug(PURPLE_DEBUG_INFO, "jabber", - "Setting %s to '%s'\n", vc_tp->tag, text); + purple_debug_info("jabber", "Setting %s to '%s'\n", vc_tp->tag, text); if ((xp = insert_tag_to_parent_tag(vc_node, NULL, vc_tp->tag)) != NULL) {
--- a/libpurple/protocols/jabber/disco.c Sun Nov 08 23:36:28 2009 +0000 +++ b/libpurple/protocols/jabber/disco.c Sun Nov 08 23:38:08 2009 +0000 @@ -421,6 +421,76 @@ } +/* should probably share this code with google.c, or maybe from 2.7.0 + introduce an abstracted hostname -> IP function in dns.c */ +static void +jabber_disco_stun_lookup_cb(GSList *hosts, gpointer data, + const char *error_message) +{ + JabberStream *js = (JabberStream *) data; + + if (error_message) { + purple_debug_error("jabber", "STUN lookup failed: %s\n", + error_message); + g_slist_free(hosts); + js->stun_query = NULL; + return; + } + + if (hosts && g_slist_next(hosts)) { + struct sockaddr *addr = g_slist_next(hosts)->data; + char dst[INET6_ADDRSTRLEN]; + int port; + + if (addr->sa_family == AF_INET6) { + inet_ntop(addr->sa_family, &((struct sockaddr_in6 *) addr)->sin6_addr, + dst, sizeof(dst)); + port = ntohs(((struct sockaddr_in6 *) addr)->sin6_port); + } else { + inet_ntop(addr->sa_family, &((struct sockaddr_in *) addr)->sin_addr, + dst, sizeof(dst)); + port = ntohs(((struct sockaddr_in *) addr)->sin_port); + } + + if (js->stun_ip) + g_free(js->stun_ip); + js->stun_ip = g_strdup(dst); + js->stun_port = port; + + purple_debug_info("jabber", "set STUN IP/port address: " + "%s:%d\n", dst, port); + + /* unmark ongoing query */ + js->stun_query = NULL; + } + + while (hosts != NULL) { + hosts = g_slist_delete_link(hosts, hosts); + /* Free the address */ + g_free(hosts->data); + hosts = g_slist_delete_link(hosts, hosts); + } +} + + +static void +jabber_disco_stun_srv_resolve_cb(PurpleSrvResponse *resp, int results, gpointer data) +{ + JabberStream *js = (JabberStream *) data; + + purple_debug_info("jabber", "got %d SRV responses for STUN.\n", results); + js->srv_query_data = NULL; + + if (results > 0) { + purple_debug_info("jabber", "looking up IP for %s:%d\n", + resp[0].hostname, resp[0].port); + js->stun_query = + purple_dnsquery_a(resp[0].hostname, resp[0].port, + jabber_disco_stun_lookup_cb, js); + } +} + + static void jabber_disco_server_info_result_cb(JabberStream *js, const char *from, JabberIqType type, const char *id, @@ -471,7 +541,10 @@ /* autodiscover stun and relays */ jabber_google_send_jingle_info(js); } else { - /* TODO: add external service discovery here... */ + js->srv_query_data = + purple_srv_resolve("stun", "udp", js->user->domain, + jabber_disco_stun_srv_resolve_cb, js); + /* TODO: add TURN support later... */ } }
--- a/libpurple/protocols/jabber/google.c Sun Nov 08 23:36:28 2009 +0000 +++ b/libpurple/protocols/jabber/google.c Sun Nov 08 23:38:08 2009 +0000 @@ -910,7 +910,7 @@ xmlnode_set_attrib(iq->node, "id", id); jabber_iq_send(iq); - purple_debug(PURPLE_DEBUG_MISC, "jabber", + purple_debug_misc("jabber", "Got new mail notification. Sending request for more info\n"); iq = jabber_iq_new_query(js, JABBER_IQ_GET, "google:mail:notify"); @@ -1094,12 +1094,13 @@ jbr = l->data; if (jbr && jbr->name) { - purple_debug(PURPLE_DEBUG_MISC, "jabber", "Removing resource %s\n", jbr->name); + purple_debug_misc("jabber", "Removing resource %s\n", jbr->name); jabber_buddy_remove_resource(jb, jbr->name); } l = l->next; } } + purple_prpl_got_user_status(purple_connection_get_account(gc), who, "offline", NULL); }
--- a/libpurple/protocols/jabber/iq.c Sun Nov 08 23:36:28 2009 +0000 +++ b/libpurple/protocols/jabber/iq.c Sun Nov 08 23:38:08 2009 +0000 @@ -342,7 +342,7 @@ return; } - signal_return = GPOINTER_TO_INT(purple_signal_emit_return_1(jabber_plugin, + signal_return = GPOINTER_TO_INT(purple_signal_emit_return_1(purple_connection_get_prpl(js->gc), "jabber-receiving-iq", js->gc, iq_type, id, from, packet)); if (signal_return) return; @@ -367,7 +367,7 @@ g_free(key); if (signal_ref > 0) { - signal_return = GPOINTER_TO_INT(purple_signal_emit_return_1(jabber_plugin, "jabber-watched-iq", + signal_return = GPOINTER_TO_INT(purple_signal_emit_return_1(purple_connection_get_prpl(js->gc), "jabber-watched-iq", js->gc, iq_type, id, from, child)); if (signal_return) return;
--- a/libpurple/protocols/jabber/jabber.c Sun Nov 08 23:36:28 2009 +0000 +++ b/libpurple/protocols/jabber/jabber.c Sun Nov 08 23:38:08 2009 +0000 @@ -68,10 +68,9 @@ #include "jingle/jingle.h" #include "jingle/rtp.h" -PurplePlugin *jabber_plugin = NULL; GList *jabber_features = NULL; GList *jabber_identities = NULL; -GSList *jabber_cmds = NULL; +static GSList *jabber_cmds = NULL; static void jabber_unregister_account_cb(JabberStream *js); static void try_srv_connect(JabberStream *js); @@ -200,7 +199,7 @@ jabber_stream_set_state(js, JABBER_STREAM_INITIALIZING_ENCRYPTION); return; } - } else if(purple_account_get_bool(js->gc->account, "require_tls", FALSE) && !jabber_stream_is_ssl(js)) { + } else if(purple_account_get_bool(js->gc->account, "require_tls", JABBER_DEFAULT_REQUIRE_TLS) && !jabber_stream_is_ssl(js)) { purple_connection_error_reason(js->gc, PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR, _("You require encryption, but it is not available on this server.")); @@ -255,7 +254,7 @@ { const char *xmlns; - purple_signal_emit(jabber_plugin, "jabber-receiving-xmlnode", js->gc, packet); + purple_signal_emit(purple_connection_get_prpl(js->gc), "jabber-receiving-xmlnode", js->gc, packet); /* if the signal leaves us with a null packet, we're done */ if(NULL == *packet) @@ -294,8 +293,7 @@ else purple_debug_warning("jabber", "Ignoring spurious <proceed/>\n"); } else { - purple_debug(PURPLE_DEBUG_WARNING, "jabber", "Unknown packet: %s\n", - (*packet)->name); + purple_debug_warning("jabber", "Unknown packet: %s\n", (*packet)->name); } } @@ -377,9 +375,9 @@ void jabber_send_raw(JabberStream *js, const char *data, int len) { - /* because printing a tab to debug every minute gets old */ if(strcmp(data, "\t")) { + const char *username; char *text = NULL, *last_part = NULL, *tag_start = NULL; /* Because debug logs with plaintext passwords make me sad */ @@ -404,8 +402,13 @@ *data_start = '\0'; } - purple_debug(PURPLE_DEBUG_MISC, "jabber", "Sending%s: %s%s%s\n", - jabber_stream_is_ssl(js) ? " (ssl)" : "", text ? text : data, + username = purple_connection_get_display_name(js->gc); + if (!username) + username = purple_account_get_username(purple_connection_get_account(js->gc)); + + purple_debug_misc("jabber", "Sending%s (%s): %s%s%s\n", + jabber_stream_is_ssl(js) ? " (ssl)" : "", username, + text ? text : data, last_part ? "password removed" : "", last_part ? last_part : ""); @@ -415,7 +418,7 @@ /* If we've got a security layer, we need to encode the data, * splitting it on the maximum buffer length negotiated */ - purple_signal_emit(jabber_plugin, "jabber-sending-text", js->gc, &data); + purple_signal_emit(purple_connection_get_prpl(js->gc), "jabber-sending-text", js->gc, &data); if (data == NULL) return; @@ -485,7 +488,7 @@ void jabber_send(JabberStream *js, xmlnode *packet) { - purple_signal_emit(jabber_plugin, "jabber-sending-xmlnode", js->gc, &packet); + purple_signal_emit(purple_connection_get_prpl(js->gc), "jabber-sending-xmlnode", js->gc, &packet); } static gboolean jabber_keepalive_timeout(PurpleConnection *gc) @@ -526,7 +529,7 @@ while((len = purple_ssl_read(gsc, buf, sizeof(buf) - 1)) > 0) { gc->last_received = time(NULL); buf[len] = '\0'; - purple_debug(PURPLE_DEBUG_INFO, "jabber", "Recv (ssl)(%d): %s\n", len, buf); + purple_debug_info("jabber", "Recv (ssl)(%d): %s\n", len, buf); jabber_parser_process(js, buf, len); if(js->reinit) jabber_stream_init(js); @@ -566,7 +569,7 @@ unsigned int olen; sasl_decode(js->sasl, buf, len, &out, &olen); if (olen>0) { - purple_debug(PURPLE_DEBUG_INFO, "jabber", "RecvSASL (%u): %s\n", olen, out); + purple_debug_info("jabber", "RecvSASL (%u): %s\n", olen, out); jabber_parser_process(js,out,olen); if(js->reinit) jabber_stream_init(js); @@ -575,7 +578,7 @@ } #endif buf[len] = '\0'; - purple_debug(PURPLE_DEBUG_INFO, "jabber", "Recv (%d): %s\n", len, buf); + purple_debug_info("jabber", "Recv (%d): %s\n", len, buf); jabber_parser_process(js, buf, len); if(js->reinit) jabber_stream_init(js); @@ -3401,8 +3404,6 @@ unspecified */ const gchar *ui_name = NULL; - jabber_plugin = plugin; - ui_type = ui_info ? g_hash_table_lookup(ui_info, "client_type") : NULL; if (ui_type) { if (strcmp(ui_type, "pc") == 0 || @@ -3495,9 +3496,9 @@ } void -jabber_uninit_plugin(void) +jabber_uninit_plugin(PurplePlugin *plugin) { - purple_plugin_ipc_unregister_all(jabber_plugin); + purple_plugin_ipc_unregister_all(plugin); jabber_features_destroy(); jabber_identities_destroy();
--- a/libpurple/protocols/jabber/jabber.h Sun Nov 08 23:36:28 2009 +0000 +++ b/libpurple/protocols/jabber/jabber.h Sun Nov 08 23:38:08 2009 +0000 @@ -76,11 +76,11 @@ #define CAPS0115_NODE "http://pidgin.im/" +#define JABBER_DEFAULT_REQUIRE_TLS TRUE + /* Index into attention_types list */ #define JABBER_BUZZ 0 -extern PurplePlugin *jabber_plugin; - typedef enum { JABBER_STREAM_OFFLINE, JABBER_STREAM_CONNECTING, @@ -193,25 +193,16 @@ char *serverFQDN; - /* OK, this stays at the end of the struct, so plugins can depend - * on the rest of the stuff being in the right place - */ #ifdef HAVE_CYRUS_SASL sasl_conn_t *sasl; sasl_callback_t *sasl_cb; -#else /* keep the struct the same size */ - void *sasl; - void *sasl_cb; -#endif - /* did someone say something about the end of the struct? */ -#ifdef HAVE_CYRUS_SASL const char *current_mech; int auth_fail_count; -#endif int sasl_state; int sasl_maxbuf; GString *sasl_mechs; +#endif gboolean unregistration; PurpleAccountUnregistrationCb unregistration_cb; @@ -382,6 +373,6 @@ void jabber_unregister_commands(void); void jabber_init_plugin(PurplePlugin *plugin); -void jabber_uninit_plugin(void); +void jabber_uninit_plugin(PurplePlugin *plugin); #endif /* PURPLE_JABBER_H_ */
--- a/libpurple/protocols/jabber/jingle/jingle.c Sun Nov 08 23:36:28 2009 +0000 +++ b/libpurple/protocols/jabber/jingle/jingle.c Sun Nov 08 23:38:08 2009 +0000 @@ -442,15 +442,15 @@ if (num_params > 0) { params = g_new0(GParameter, num_params); - purple_debug_info("jabber", - "setting param stun-ip for stream using Google auto-config: %s\n", - js->stun_ip); + purple_debug_info("jabber", + "setting param stun-ip for stream using auto-discovered IP: %s\n", + js->stun_ip); params[0].name = "stun-ip"; g_value_init(¶ms[0].value, G_TYPE_STRING); g_value_set_string(¶ms[0].value, js->stun_ip); purple_debug_info("jabber", - "setting param stun-port for stream using Google auto-config: %d\n", - js->stun_port); + "setting param stun-port for stream using auto-discovered port: %d\n", + js->stun_port); params[1].name = "stun-port"; g_value_init(¶ms[1].value, G_TYPE_UINT); g_value_set_uint(¶ms[1].value, js->stun_port);
--- a/libpurple/protocols/jabber/libxmpp.c Sun Nov 08 23:36:28 2009 +0000 +++ b/libpurple/protocols/jabber/libxmpp.c Sun Nov 08 23:38:08 2009 +0000 @@ -227,7 +227,7 @@ jabber_unregister_commands(); /* Stay on target...stay on target... Almost there... */ - jabber_uninit_plugin(); + jabber_uninit_plugin(plugin); return TRUE; } @@ -355,7 +355,7 @@ purple_account_user_split_set_reverse(split, FALSE); prpl_info.user_splits = g_list_append(prpl_info.user_splits, split); - option = purple_account_option_bool_new(_("Require SSL/TLS"), "require_tls", TRUE); + option = purple_account_option_bool_new(_("Require SSL/TLS"), "require_tls", JABBER_DEFAULT_REQUIRE_TLS); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
--- a/libpurple/protocols/jabber/message.c Sun Nov 08 23:36:28 2009 +0000 +++ b/libpurple/protocols/jabber/message.c Sun Nov 08 23:38:08 2009 +0000 @@ -545,7 +545,7 @@ to = xmlnode_get_attrib(packet, "to"); type = xmlnode_get_attrib(packet, "type"); - signal_return = GPOINTER_TO_INT(purple_signal_emit_return_1(jabber_plugin, + signal_return = GPOINTER_TO_INT(purple_signal_emit_return_1(purple_connection_get_prpl(js->gc), "jabber-receiving-message", js->gc, type, id, from, to, packet)); if (signal_return) return; @@ -812,7 +812,7 @@ switch(jm->type) { case JABBER_MESSAGE_OTHER: - purple_debug(PURPLE_DEBUG_INFO, "jabber", + purple_debug_info("jabber", "Received message of unknown type: %s\n", type); /* Fall-through is intentional */ case JABBER_MESSAGE_NORMAL: @@ -1103,7 +1103,7 @@ if ((child = xmlnode_from_str(jm->xhtml, -1))) { xmlnode_insert_child(message, child); } else { - purple_debug(PURPLE_DEBUG_ERROR, "jabber", + purple_debug_error("jabber", "XHTML translation/validation failed, returning: %s\n", jm->xhtml); }
--- a/libpurple/protocols/jabber/oob.c Sun Nov 08 23:36:28 2009 +0000 +++ b/libpurple/protocols/jabber/oob.c Sun Nov 08 23:38:08 2009 +0000 @@ -95,7 +95,7 @@ if(len < 0 && errno == EAGAIN) return; else if(len < 0) { - purple_debug(PURPLE_DEBUG_ERROR, "jabber", "Write error on oob xfer!\n"); + purple_debug_error("jabber", "Write error on oob xfer!\n"); purple_input_remove(jox->writeh); purple_xfer_cancel_local(xfer); } @@ -150,7 +150,7 @@ } return 0; } else if (errno != EAGAIN) { - purple_debug(PURPLE_DEBUG_ERROR, "jabber", "Read error on oob xfer!\n"); + purple_debug_error("jabber", "Read error on oob xfer!\n"); purple_xfer_cancel_local(xfer); }
--- a/libpurple/protocols/jabber/presence.c Sun Nov 08 23:36:28 2009 +0000 +++ b/libpurple/protocols/jabber/presence.c Sun Nov 08 23:38:08 2009 +0000 @@ -522,7 +522,7 @@ jb = jabber_buddy_find(js, from, TRUE); g_return_if_fail(jb != NULL); - signal_return = GPOINTER_TO_INT(purple_signal_emit_return_1(jabber_plugin, + signal_return = GPOINTER_TO_INT(purple_signal_emit_return_1(purple_connection_get_prpl(js->gc), "jabber-receiving-presence", js->gc, type, from, packet)); if (signal_return) return;
--- a/libpurple/protocols/jabber/si.c Sun Nov 08 23:36:28 2009 +0000 +++ b/libpurple/protocols/jabber/si.c Sun Nov 08 23:38:08 2009 +0000 @@ -1357,7 +1357,7 @@ jabber_ibb_session_close(jsx->ibb_session); } jabber_si_xfer_free(xfer); - purple_debug(PURPLE_DEBUG_INFO, "jabber", "in jabber_si_xfer_cancel_send\n"); + purple_debug_info("jabber", "in jabber_si_xfer_cancel_send\n"); } @@ -1389,7 +1389,7 @@ } jabber_si_xfer_free(xfer); - purple_debug(PURPLE_DEBUG_INFO, "jabber", "in jabber_si_xfer_request_denied\n"); + purple_debug_info("jabber", "in jabber_si_xfer_request_denied\n"); } @@ -1401,7 +1401,7 @@ jabber_ibb_session_close(jsx->ibb_session); } jabber_si_xfer_free(xfer); - purple_debug(PURPLE_DEBUG_INFO, "jabber", "in jabber_si_xfer_cancel_recv\n"); + purple_debug_info("jabber", "in jabber_si_xfer_cancel_recv\n"); }
--- a/libpurple/protocols/jabber/useravatar.c Sun Nov 08 23:36:28 2009 +0000 +++ b/libpurple/protocols/jabber/useravatar.c Sun Nov 08 23:38:08 2009 +0000 @@ -262,7 +262,7 @@ gpointer icon_data; if(!url_text) { - purple_debug(PURPLE_DEBUG_ERROR, "jabber", + purple_debug_error("jabber", "do_buddy_avatar_update_fromurl got error \"%s\"", error_message); goto out;
--- a/libpurple/protocols/msn/nexus.c Sun Nov 08 23:36:28 2009 +0000 +++ b/libpurple/protocols/msn/nexus.c Sun Nov 08 23:38:08 2009 +0000 @@ -385,7 +385,14 @@ username = purple_account_get_username(session->account); password = purple_connection_get_password(session->account->gc); - password_xml = g_markup_escape_text(password, MIN(strlen(password), 16)); + if (g_utf8_strlen(password, -1) > 16) { + /* max byte size for 16 utf8 characters is 64 + 1 for the null */ + gchar truncated[65]; + g_utf8_strncpy(truncated, password, 16); + password_xml = g_markup_escape_text(truncated, -1); + } else { + password_xml = g_markup_escape_text(password, -1); + } purple_debug_info("msn", "Logging on %s, with policy '%s', nonce '%s'\n", username, nexus->policy, nexus->nonce);
--- a/libpurple/protocols/oscar/clientlogin.c Sun Nov 08 23:36:28 2009 +0000 +++ b/libpurple/protocols/oscar/clientlogin.c Sun Nov 08 23:38:08 2009 +0000 @@ -40,6 +40,7 @@ #include "core.h" #include "oscar.h" +#include "oscarcommon.h" #define URL_CLIENT_LOGIN "https://api.screenname.aol.com/auth/clientLogin" #define URL_START_OSCAR_SESSION "http://api.oscar.aol.com/aim/startOSCARSession" @@ -102,11 +103,15 @@ return signature; } -static gboolean parse_start_oscar_session_response(PurpleConnection *gc, const gchar *response, gsize response_len, char **host, unsigned short *port, char **cookie) +static gboolean parse_start_oscar_session_response(PurpleConnection *gc, const gchar *response, gsize response_len, char **host, unsigned short *port, char **cookie, char **tls_certname) { xmlnode *response_node, *tmp_node, *data_node; - xmlnode *host_node = NULL, *port_node = NULL, *cookie_node = NULL; + xmlnode *host_node = NULL, *port_node = NULL, *cookie_node = NULL, *tls_node = NULL; + gboolean use_tls; char *tmp; + guint code; + + use_tls = purple_account_get_bool(purple_connection_get_account(gc), "use_ssl", OSCAR_DEFAULT_USE_SSL); /* Parse the response as XML */ response_node = xmlnode_from_str(response, response_len); @@ -131,6 +136,7 @@ host_node = xmlnode_get_child(data_node, "host"); port_node = xmlnode_get_child(data_node, "port"); cookie_node = xmlnode_get_child(data_node, "cookie"); + tls_node = xmlnode_get_child(data_node, "tlsCertName"); } /* Make sure we have a status code */ @@ -148,12 +154,13 @@ } /* Make sure the status code was 200 */ - if (strcmp(tmp, "200") != 0) + code = atoi(tmp); + if (code != 200) { purple_debug_error("oscar", "startOSCARSession response statusCode " "was %s: %s\n", tmp, response); - if (strcmp(tmp, "401") == 0) + if (code == 401 || code == 607) purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, _("You have been connecting and disconnecting too " @@ -177,7 +184,8 @@ /* Make sure we have everything else */ if (data_node == NULL || host_node == NULL || - port_node == NULL || cookie_node == NULL) + port_node == NULL || cookie_node == NULL || + (use_tls && tls_node == NULL)) { char *msg; purple_debug_error("oscar", "startOSCARSession response was missing " @@ -195,7 +203,12 @@ *host = xmlnode_get_data_unescaped(host_node); tmp = xmlnode_get_data_unescaped(port_node); *cookie = xmlnode_get_data_unescaped(cookie_node); - if (*host == NULL || **host == '\0' || tmp == NULL || *tmp == '\0' || cookie == NULL || *cookie == '\0') + + if (use_tls) + *tls_certname = xmlnode_get_data_unescaped(tls_node); + + if (*host == NULL || **host == '\0' || tmp == NULL || *tmp == '\0' || *cookie == NULL || **cookie == '\0' || + (use_tls && (*tls_certname == NULL || **tls_certname == '\0'))) { char *msg; purple_debug_error("oscar", "startOSCARSession response was missing " @@ -223,6 +236,7 @@ OscarData *od; PurpleConnection *gc; char *host, *cookie; + char *tls_certname = NULL; unsigned short port; guint8 *cookiedata; gsize cookiedata_len; @@ -244,28 +258,30 @@ return; } - if (!parse_start_oscar_session_response(gc, url_text, len, &host, &port, &cookie)) + if (!parse_start_oscar_session_response(gc, url_text, len, &host, &port, &cookie, &tls_certname)) return; cookiedata = purple_base64_decode(cookie, &cookiedata_len); - oscar_connect_to_bos(gc, od, host, port, cookiedata, cookiedata_len); + oscar_connect_to_bos(gc, od, host, port, cookiedata, cookiedata_len, tls_certname); g_free(cookiedata); g_free(host); g_free(cookie); + g_free(tls_certname); } static void send_start_oscar_session(OscarData *od, const char *token, const char *session_key, time_t hosttime) { char *query_string, *signature, *url; + gboolean use_tls = purple_account_get_bool(purple_connection_get_account(od->gc), "use_ssl", OSCAR_DEFAULT_USE_SSL); /* Construct the GET parameters */ query_string = g_strdup_printf("a=%s" "&f=xml" "&k=%s" "&ts=%" PURPLE_TIME_T_MODIFIER - "&useTLS=0", - purple_url_encode(token), get_client_key(od), hosttime); + "&useTLS=%d", + purple_url_encode(token), get_client_key(od), hosttime, use_tls); signature = generate_signature("GET", URL_START_OSCAR_SESSION, query_string, session_key); url = g_strdup_printf(URL_START_OSCAR_SESSION "?%s&sig_sha256=%s",
--- a/libpurple/protocols/oscar/family_feedbag.c Sun Nov 08 23:36:28 2009 +0000 +++ b/libpurple/protocols/oscar/family_feedbag.c Sun Nov 08 23:38:08 2009 +0000 @@ -389,11 +389,10 @@ /** * Locally find the presence flag item, and return the setting. The returned setting is a - * bitmask of the user flags that you are visible to. See the AIM_FLAG_* #defines - * in oscar.h + * bitmask of the preferences. See the AIM_SSI_PRESENCE_FLAG_* #defines in oscar.h. * * @param list A pointer to the current list of items. - * @return Return the current visibility mask. + * @return Return the current set of preferences. */ guint32 aim_ssi_getpresence(struct aim_ssi_item *list) { @@ -1130,9 +1129,11 @@ * should show up as idle or not, etc. * * @param od The oscar odion. - * @param presence I think it's a bitmask, but I only know what one of the bits is: - * 0x00000002 - Hide wireless? + * @param presence A bitmask of the first 32 entries [0-31] from + * http://dev.aol.com/aim/oscar/#FEEDBAG__BUDDY_PREFS + * 0x00000002 - Hide "eBuddy group" (whatever that is) * 0x00000400 - Allow others to see your idle time + * 0x00020000 - Don't show Recent Buddies * @return Return 0 if no errors, otherwise return the error number. */ int aim_ssi_setpresence(OscarData *od, guint32 presence) {
--- a/libpurple/protocols/oscar/family_icbm.c Sun Nov 08 23:36:28 2009 +0000 +++ b/libpurple/protocols/oscar/family_icbm.c Sun Nov 08 23:38:08 2009 +0000 @@ -151,6 +151,55 @@ return AIM_CLIENTTYPE_UNKNOWN; } +/* + * Subtype 0x0001 - Error + */ +static int +error(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) +{ + int ret = 0; + aim_rxcallback_t userfunc; + aim_snac_t *snac2; + guint16 reason, errcode = 0; + char *bn; + GSList *tlvlist; + + if (!(snac2 = aim_remsnac(od, snac->id))) { + purple_debug_misc("oscar", "icbm error: received response from unknown request!\n"); + return 0; + } + + if (snac2->family != SNAC_FAMILY_ICBM) { + purple_debug_misc("oscar", "icbm error: received response from invalid request! %d\n", snac2->family); + g_free(snac2->data); + g_free(snac2); + return 0; + } + + if (!(bn = snac2->data)) { + purple_debug_misc("oscar", "icbm error: received response from request without a buddy name!\n"); + g_free(snac2); + return 0; + } + + reason = byte_stream_get16(bs); + + tlvlist = aim_tlvlist_read(bs); + if (aim_tlv_gettlv(tlvlist, 0x0008, 1)) + errcode = aim_tlv_get16(tlvlist, 0x0008, 1); + aim_tlvlist_free(tlvlist); + + /* Notify the user that the message wasn't delivered */ + if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) + ret = userfunc(od, conn, frame, reason, errcode, bn); + + if (snac2) + g_free(snac2->data); + g_free(snac2); + + return ret; +} + /** * Subtype 0x0002 - Set ICBM parameters. * @@ -2789,7 +2838,9 @@ static int snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) { - if (snac->subtype == 0x0005) + if (snac->subtype == 0x0001) + return error(od, conn, mod, frame, snac, bs); + else if (snac->subtype == 0x0005) return aim_im_paraminfo(od, conn, mod, frame, snac, bs); else if (snac->subtype == 0x0006) return outgoingim(od, conn, mod, frame, snac, bs);
--- a/libpurple/protocols/oscar/family_oservice.c Sun Nov 08 23:36:28 2009 +0000 +++ b/libpurple/protocols/oscar/family_oservice.c Sun Nov 08 23:38:08 2009 +0000 @@ -319,7 +319,10 @@ for (i = 0; i < numclasses; i++) { struct rateclass *rateclass; + guint32 delta; + struct timeval now; + gettimeofday(&now, NULL); rateclass = g_new0(struct rateclass, 1); rateclass->classid = byte_stream_get16(bs); @@ -339,11 +342,24 @@ * the new version hardcoded here. */ if (mod->version >= 3) - byte_stream_getrawbuf(bs, rateclass->unknown, sizeof(rateclass->unknown)); + { + rateclass->delta = byte_stream_get32(bs); + rateclass->dropping_snacs = byte_stream_get8(bs); + + delta = rateclass->delta; + + rateclass->last.tv_sec = now.tv_sec - delta / 1000; + delta %= 1000; + rateclass->last.tv_usec = now.tv_usec - delta * 1000; + } + else + { + rateclass->delta = rateclass->dropping_snacs = 0; + rateclass->last.tv_sec = now.tv_sec; + rateclass->last.tv_usec = now.tv_usec; + } rateclass->members = g_hash_table_new(g_direct_hash, g_direct_equal); - rateclass->last.tv_sec = 0; - rateclass->last.tv_usec = 0; conn->rateclasses = g_slist_prepend(conn->rateclasses, rateclass); } conn->rateclasses = g_slist_reverse(conn->rateclasses); @@ -383,8 +399,7 @@ */ /* - * Last step in the conn init procedure is to acknowledge that we - * agree to these draconian limitations. + * Subscribe to rate change information for all rate classes. */ aim_srv_rates_addparam(od, conn); @@ -451,7 +466,10 @@ aim_rxcallback_t userfunc; guint16 code, classid; struct rateclass *rateclass; + guint32 delta; + struct timeval now; + gettimeofday(&now, NULL); code = byte_stream_get16(bs); classid = byte_stream_get16(bs); @@ -468,8 +486,29 @@ rateclass->current = byte_stream_get32(bs); rateclass->max = byte_stream_get32(bs); - if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) - ret = userfunc(od, conn, frame, code, classid, rateclass->windowsize, rateclass->clear, rateclass->alert, rateclass->limit, rateclass->disconnect, rateclass->current, rateclass->max); + if (mod->version >= 3) + { + rateclass->delta = byte_stream_get32(bs); + rateclass->dropping_snacs = byte_stream_get8(bs); + + delta = rateclass->delta; + + rateclass->last.tv_sec = now.tv_sec - delta / 1000; + delta %= 1000; + rateclass->last.tv_usec = now.tv_usec - delta * 1000; + } + else + { + rateclass->delta = rateclass->dropping_snacs = 0; + rateclass->last.tv_sec = now.tv_sec; + rateclass->last.tv_usec = now.tv_usec; + } + + if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) { + /* Can't pass in guint8 via ... varargs, so we use an unsigned int */ + unsigned int dropping_snacs = rateclass->dropping_snacs; + ret = userfunc(od, conn, frame, code, classid, rateclass->windowsize, rateclass->clear, rateclass->alert, rateclass->limit, rateclass->disconnect, rateclass->current, rateclass->max, rateclass->delta, dropping_snacs); + } return ret; }
--- a/libpurple/protocols/oscar/flap_connection.c Sun Nov 08 23:36:28 2009 +0000 +++ b/libpurple/protocols/oscar/flap_connection.c Sun Nov 08 23:38:08 2009 +0000 @@ -73,7 +73,7 @@ } void -flap_connection_send_version_with_cookie_and_clientinfo(OscarData *od, FlapConnection *conn, guint16 length, const guint8 *chipsahoy, ClientInfo *ci) +flap_connection_send_version_with_cookie_and_clientinfo(OscarData *od, FlapConnection *conn, guint16 length, const guint8 *chipsahoy, ClientInfo *ci, gboolean allow_multiple_logins) { FlapFrame *frame; GSList *tlvlist = NULL; @@ -94,7 +94,7 @@ aim_tlvlist_add_16(&tlvlist, 0x0018, (guint16)ci->minor); aim_tlvlist_add_16(&tlvlist, 0x0019, (guint16)ci->point); aim_tlvlist_add_16(&tlvlist, 0x001a, (guint16)ci->build); - aim_tlvlist_add_8(&tlvlist, 0x004a, 0x01); + aim_tlvlist_add_8(&tlvlist, 0x004a, (allow_multiple_logins ? 0x01 : 0x03)); aim_tlvlist_write(&frame->data, &tlvlist); @@ -131,11 +131,13 @@ rateclass_get_new_current(FlapConnection *conn, struct rateclass *rateclass, struct timeval *now) { unsigned long timediff; /* In milliseconds */ + guint32 current; timediff = (now->tv_sec - rateclass->last.tv_sec) * 1000 + (now->tv_usec - rateclass->last.tv_usec) / 1000; + current = ((rateclass->current * (rateclass->windowsize - 1)) + timediff) / rateclass->windowsize; - /* This formula is taken from the joscar API docs. Preesh. */ - return MIN(((rateclass->current * (rateclass->windowsize - 1)) + timediff) / rateclass->windowsize, rateclass->max); + /* This formula is taken from http://dev.aol.com/aim/oscar/#RATELIMIT */ + return MIN(current, rateclass->max); } /* @@ -161,8 +163,7 @@ new_current = rateclass_get_new_current(conn, rateclass, &now); - /* (Add 100ms padding to account for inaccuracies in the calculation) */ - if (new_current < rateclass->alert + 100) + if (rateclass->dropping_snacs || new_current <= rateclass->alert) /* Not ready to send this SNAC yet--keep waiting. */ return FALSE; @@ -245,10 +246,9 @@ gettimeofday(&now, NULL); new_current = rateclass_get_new_current(conn, rateclass, &now); - /* (Add 100ms padding to account for inaccuracies in the calculation) */ - if (new_current < rateclass->alert + 100) + if (rateclass->dropping_snacs || new_current <= rateclass->alert) { - purple_debug_info("oscar", "Current rate for conn %p would be %u, but we alert at %u; enqueueing\n", conn, new_current, (rateclass->alert + 100)); + purple_debug_info("oscar", "Current rate for conn %p would be %u, but we alert at %u; enqueueing\n", conn, new_current, rateclass->alert); enqueue = TRUE; }
--- a/libpurple/protocols/oscar/libaim.c Sun Nov 08 23:36:28 2009 +0000 +++ b/libpurple/protocols/oscar/libaim.c Sun Nov 08 23:38:08 2009 +0000 @@ -141,7 +141,7 @@ static void init_plugin(PurplePlugin *plugin) { - oscar_init(PURPLE_PLUGIN_PROTOCOL_INFO(plugin)); + oscar_init(plugin); } PURPLE_INIT_PLUGIN(aim, init_plugin, info);
--- a/libpurple/protocols/oscar/libicq.c Sun Nov 08 23:36:28 2009 +0000 +++ b/libpurple/protocols/oscar/libicq.c Sun Nov 08 23:38:08 2009 +0000 @@ -153,7 +153,7 @@ { PurpleAccountOption *option; - oscar_init(PURPLE_PLUGIN_PROTOCOL_INFO(plugin)); + oscar_init(plugin); option = purple_account_option_string_new(_("Encoding"), "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
--- a/libpurple/protocols/oscar/oscar.c Sun Nov 08 23:36:28 2009 +0000 +++ b/libpurple/protocols/oscar/oscar.c Sun Nov 08 23:38:08 2009 +0000 @@ -144,6 +144,26 @@ }; static const int msgerrreasonlen = G_N_ELEMENTS(msgerrreason); +static const char * const errcodereason[] = { + N_("Invalid error"), + N_("Not logged in"), + N_("Cannot receive IM due to parental controls"), + N_("Cannot send SMS without accepting terms"), + N_("Cannot send SMS"), /* SMS_WITHOUT_DISCLAIMER is weird */ + N_("Cannot send SMS to this country"), + N_("Unknown error"), /* Undocumented */ + N_("Unknown error"), /* Undocumented */ + N_("Cannot send SMS to unknown country"), + N_("Bot accounts cannot initiate IMs"), + N_("Bot account cannot IM this user"), + N_("Bot account reached IM limit"), + N_("Bot account reached daily IM limit"), + N_("Bot account reached monthly IM limit"), + N_("Unable to receive offline messages"), + N_("Offline message store full") +}; +static const int errcodereasonlen = G_N_ELEMENTS(errcodereason); + /* All the libfaim->purple callback functions */ /* Only used when connecting with the old-style BUCP login */ @@ -1168,7 +1188,8 @@ ClientInfo icqinfo = CLIENTINFO_PURPLE_ICQ; flap_connection_send_version_with_cookie_and_clientinfo(od, conn, conn->cookielen, conn->cookie, - od->icq ? &icqinfo : &aiminfo); + od->icq ? &icqinfo : &aiminfo, + purple_account_get_bool(account, "allow_multiple_logins", OSCAR_DEFAULT_ALLOW_MULTIPLE_LOGINS)); } else { flap_connection_send_version_with_cookie(od, conn, conn->cookielen, conn->cookie); @@ -1394,9 +1415,9 @@ presence = aim_ssi_getpresence(od->ssi.local); if (report_idle) - aim_ssi_setpresence(od, presence | 0x400); + aim_ssi_setpresence(od, presence | AIM_SSI_PRESENCE_FLAG_SHOWIDLE); else - aim_ssi_setpresence(od, presence & ~0x400); + aim_ssi_setpresence(od, presence & ~AIM_SSI_PRESENCE_FLAG_SHOWIDLE); } /** @@ -1806,17 +1827,35 @@ return 1; } -int oscar_connect_to_bos(PurpleConnection *gc, OscarData *od, const char *host, guint16 port, guint8 *cookie, guint16 cookielen) +int oscar_connect_to_bos(PurpleConnection *gc, OscarData *od, const char *host, guint16 port, guint8 *cookie, guint16 cookielen, const char *tls_certname) { + PurpleAccount *account; FlapConnection *conn; + account = purple_connection_get_account(gc); + conn = flap_connection_new(od, SNAC_FAMILY_LOCATE); conn->cookielen = cookielen; conn->cookie = g_memdup(cookie, cookielen); - conn->connect_data = purple_proxy_connect(NULL, - purple_connection_get_account(gc), host, port, - connection_established_cb, conn); - if (conn->connect_data == NULL) + + /* + * tls_certname is only set (and must be set if we get this far) if + * SSL is enabled. + */ + if (tls_certname) + { + conn->gsc = purple_ssl_connect_with_ssl_cn(account, host, port, + ssl_connection_established_cb, ssl_connection_error_cb, + tls_certname, conn); + } + else + { + conn->connect_data = purple_proxy_connect(NULL, + account, host, port, + connection_established_cb, conn); + } + + if (conn->gsc == NULL && conn->connect_data == NULL) { purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Unable to connect")); return 0; @@ -1877,7 +1916,7 @@ break; case 0x18: /* username connecting too frequently */ - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, _("You have been connecting and disconnecting too frequently. Wait ten minutes and try again. If you continue to try, you will need to wait even longer.")); + purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, _("Your username has been connecting and disconnecting too frequently. Wait ten minutes and try again. If you continue to try, you will need to wait even longer.")); break; case 0x1c: { @@ -1889,7 +1928,7 @@ } case 0x1d: /* IP address connecting too frequently */ - purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, _("You have been connecting and disconnecting too frequently. Wait a minute and try again. If you continue to try, you will need to wait even longer.")); + purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, _("Your IP address has been connecting and disconnecting too frequently. Wait a minute and try again. If you continue to try, you will need to wait even longer.")); break; default: purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, _("Unknown reason")); @@ -2876,7 +2915,7 @@ if (text) { /* Read the number of contacts that we were sent */ errno = 0; - num = strtoul(text[0], NULL, 10); + num = text[0] ? strtoul(text[0], NULL, 10) : 0; if (num > 0 && errno == 0) { for (i=0; i<num; i++) { @@ -3217,17 +3256,18 @@ PurpleXfer *xfer; #endif va_list ap; - guint16 reason; - char *data, *buf; + guint16 reason, errcode; + char *data, *reason_str, *buf; va_start(ap, fr); reason = (guint16)va_arg(ap, unsigned int); + errcode = (guint16)va_arg(ap, unsigned int); data = va_arg(ap, char *); va_end(ap); purple_debug_error("oscar", - "Message error with data %s and reason %hu\n", - (data != NULL ? data : ""), reason); + "Message error with data %s and reason %hu and errcode %hu\n", + (data != NULL ? data : ""), reason, errcode); if ((data == NULL) || (*data == '\0')) /* We can't do anything if data is empty */ @@ -3242,14 +3282,27 @@ #endif /* Data is assumed to be the destination bn */ - buf = g_strdup_printf(_("Unable to send message: %s"), (reason < msgerrreasonlen) ? _(msgerrreason[reason]) : _("Unknown reason.")); + + reason_str = g_strdup((reason < msgerrreasonlen) ? _(msgerrreason[reason]) : _("Unknown reason")); + if (errcode != 0 && errcode < errcodereasonlen) + buf = g_strdup_printf(_("Unable to send message: %s (%s)"), reason_str, + _(errcodereason[errcode])); + else + buf = g_strdup_printf(_("Unable to send message: %s"), reason_str); + if (!purple_conv_present_error(data, purple_connection_get_account(gc), buf)) { g_free(buf); - buf = g_strdup_printf(_("Unable to send message to %s:"), data ? data : "(unknown)"); - purple_notify_error(od->gc, NULL, buf, - (reason < msgerrreasonlen) ? _(msgerrreason[reason]) : _("Unknown reason.")); + if (errcode != 0 && errcode < errcodereasonlen) + buf = g_strdup_printf(_("Unable to send message to %s: %s (%s)"), + data ? data : "(unknown)", reason_str, + _(errcodereason[errcode])); + else + buf = g_strdup_printf(_("Unable to send message to %s: %s"), + data ? data : "(unknown)", reason_str); + purple_notify_error(od->gc, NULL, buf, reason_str); } g_free(buf); + g_free(reason_str); return 1; } @@ -3740,7 +3793,8 @@ }; va_list ap; guint16 code, rateclass; - guint32 windowsize, clear, alert, limit, disconnect, currentavg, maxavg; + guint32 windowsize, clear, alert, limit, disconnect, currentavg, maxavg, delta; + guint8 dropping_snacs; va_start(ap, fr); code = (guint16)va_arg(ap, unsigned int); @@ -3752,23 +3806,28 @@ disconnect = va_arg(ap, guint32); currentavg = va_arg(ap, guint32); maxavg = va_arg(ap, guint32); + delta = va_arg(ap, guint32); + dropping_snacs = (guint8)va_arg(ap, unsigned int); va_end(ap); purple_debug_misc("oscar", "rate %s (param ID 0x%04hx): curavg = %u, maxavg = %u, alert at %u, " - "clear warning at %u, limit at %u, disconnect at %u (window size = %u)\n", + "clear warning at %u, limit at %u, disconnect at %u, delta is %u, dropping is %u (window size = %u)\n", (code < 5) ? codes[code] : codes[0], rateclass, currentavg, maxavg, alert, clear, limit, disconnect, - windowsize); + delta, + dropping_snacs, + windowsize + ); if (code == AIM_RATE_CODE_LIMIT) { purple_debug_warning("oscar", _("The last action you attempted could not be " "performed because you are over the rate limit. " - "Please wait 10 seconds and try again.")); + "Please wait 10 seconds and try again.\n")); } return 1; @@ -3958,9 +4017,6 @@ presence = purple_status_get_presence(status); aim_srv_setidle(od, !purple_presence_is_idle(presence) ? 0 : time(NULL) - purple_presence_get_idle_time(presence)); - /* Request offline messages for AIM and ICQ */ - aim_im_reqofflinemsgs(od); - if (od->icq) { #ifdef OLDSTYLE_ICQ_OFFLINEMSGS aim_icq_reqofflinemsgs(od); @@ -3987,6 +4043,10 @@ */ if (od->ssi.received_data) { aim_srv_clientready(od, conn); + + /* Request offline messages for AIM and ICQ */ + aim_im_reqofflinemsgs(od); + purple_connection_set_state(gc, PURPLE_CONNECTED); } @@ -5184,7 +5244,7 @@ { /* If not in server list then prune from local list */ GSList *cur, *next; GSList *buddies = purple_find_buddies(account, NULL); - + /* Buddies */ cur = NULL; @@ -5264,9 +5324,9 @@ report_idle = strcmp(idle_reporting_pref, "none") != 0; if (report_idle) - aim_ssi_setpresence(od, tmp | 0x400); + aim_ssi_setpresence(od, tmp | AIM_SSI_PRESENCE_FLAG_SHOWIDLE); else - aim_ssi_setpresence(od, tmp & ~0x400); + aim_ssi_setpresence(od, tmp & ~AIM_SSI_PRESENCE_FLAG_SHOWIDLE); } @@ -5274,45 +5334,28 @@ /* Add from server list to local list */ for (curitem=od->ssi.local; curitem; curitem=curitem->next) { - if ((curitem->name == NULL) || (g_utf8_validate(curitem->name, -1, NULL))) switch (curitem->type) { - case 0x0000: { /* Buddy */ + case AIM_SSI_TYPE_BUDDY: { /* Buddy */ if (curitem->name) { struct aim_ssi_item *groupitem; - char *gname, *gname_utf8, *alias, *alias_utf8; + const char *gname, *alias; groupitem = aim_ssi_itemlist_find(od->ssi.local, curitem->gid, 0x0000); gname = groupitem ? groupitem->name : NULL; - if (gname != NULL) { - if (g_utf8_validate(gname, -1, NULL)) - gname_utf8 = g_strdup(gname); - else - gname_utf8 = oscar_utf8_try_convert(account, gname); - } else - gname_utf8 = NULL; - - g = purple_find_group(gname_utf8 ? gname_utf8 : _("Orphans")); + + g = purple_find_group(gname ? gname : _("Orphans")); if (g == NULL) { - g = purple_group_new(gname_utf8 ? gname_utf8 : _("Orphans")); + g = purple_group_new(gname ? gname : _("Orphans")); purple_blist_add_group(g, NULL); } alias = aim_ssi_getalias(od->ssi.local, gname, curitem->name); - if (alias != NULL) { - if (g_utf8_validate(alias, -1, NULL)) - alias_utf8 = g_strdup(alias); - else - alias_utf8 = oscar_utf8_try_convert(account, alias); - g_free(alias); - } else - alias_utf8 = NULL; - b = purple_find_buddy_in_group(account, curitem->name, g); if (b) { /* Get server stored alias */ - purple_blist_alias_buddy(b, alias_utf8); + purple_blist_alias_buddy(b, alias); } else { - b = purple_buddy_new(account, curitem->name, alias_utf8); + b = purple_buddy_new(account, curitem->name, alias); purple_debug_info("oscar", "ssi: adding buddy %s to group %s to local list\n", curitem->name, gname); @@ -5336,33 +5379,18 @@ purple_buddy_get_name(b), OSCAR_STATUS_ID_MOBILE, NULL); } - - g_free(gname_utf8); - g_free(alias_utf8); } } break; - case 0x0001: { /* Group */ - char *gname; - char *gname_utf8; - - gname = curitem->name; - if (gname != NULL) { - if (g_utf8_validate(gname, -1, NULL)) - gname_utf8 = g_strdup(gname); - else - gname_utf8 = oscar_utf8_try_convert(account, gname); - } else - gname_utf8 = NULL; - - if (gname_utf8 != NULL && purple_find_group(gname_utf8) == NULL) { - g = purple_group_new(gname_utf8); + case AIM_SSI_TYPE_GROUP: { /* Group */ + const char *gname = curitem->name; + if (gname != NULL && purple_find_group(gname) == NULL) { + g = purple_group_new(gname); purple_blist_add_group(g, NULL); } - g_free(gname_utf8); } break; - case 0x0002: { /* Permit buddy */ + case AIM_SSI_TYPE_PERMIT: { /* Permit buddy */ if (curitem->name) { /* if (!find_permdeny_by_name(gc->permit, curitem->name)) { AAA */ GSList *list; @@ -5375,7 +5403,7 @@ } } break; - case 0x0003: { /* Deny buddy */ + case AIM_SSI_TYPE_DENY: { /* Deny buddy */ if (curitem->name) { GSList *list; for (list=account->deny; (list && oscar_util_name_compare(curitem->name, list->data)); list=list->next); @@ -5387,7 +5415,7 @@ } } break; - case 0x0004: { /* Permit/deny setting */ + case AIM_SSI_TYPE_PDINFO: { /* Permit/deny setting */ /* * We don't inherit the permit/deny setting from the server * for ICQ because, for ICQ, this setting controls who can @@ -5405,7 +5433,7 @@ } } break; - case 0x0005: { /* Presence setting */ + case AIM_SSI_TYPE_PRESENCEPREFS: { /* Presence setting */ /* We don't want to change Purple's setting because it applies to all accounts */ } break; } /* End of switch on curitem->type */ @@ -5435,6 +5463,10 @@ */ if (od->bos.have_rights) { aim_srv_clientready(od, conn); + + /* Request offline messages for AIM and ICQ */ + aim_im_reqofflinemsgs(od); + purple_connection_set_state(gc, PURPLE_CONNECTED); } @@ -5494,7 +5526,8 @@ { PurpleConnection *gc; PurpleAccount *account; - char *gname, *gname_utf8, *alias, *alias_utf8; + const char *gname; + char *alias; PurpleBuddy *b; PurpleGroup *g; struct aim_ssi_item *ssi_item; @@ -5515,19 +5548,7 @@ return 1; gname = aim_ssi_itemlist_findparentname(od->ssi.local, name); - gname_utf8 = gname ? oscar_utf8_try_convert(account, gname) : NULL; - alias = aim_ssi_getalias(od->ssi.local, gname, name); - if (alias != NULL) - { - if (g_utf8_validate(alias, -1, NULL)) - alias_utf8 = g_strdup(alias); - else - alias_utf8 = oscar_utf8_try_convert(account, alias); - } - else - alias_utf8 = NULL; - g_free(alias); b = purple_find_buddy(account, name); if (b) { @@ -5536,21 +5557,21 @@ * of your buddies, so update our local buddy list with * the person's new alias. */ - purple_blist_alias_buddy(b, alias_utf8); + purple_blist_alias_buddy(b, alias); } else if (snac_subtype == 0x0008) { /* * You're logged in somewhere else and you added a buddy to * your server list, so add them to your local buddy list. */ - b = purple_buddy_new(account, name, alias_utf8); - - if (!(g = purple_find_group(gname_utf8 ? gname_utf8 : _("Orphans")))) { - g = purple_group_new(gname_utf8 ? gname_utf8 : _("Orphans")); + b = purple_buddy_new(account, name, alias); + + if (!(g = purple_find_group(gname ? gname : _("Orphans")))) { + g = purple_group_new(gname ? gname : _("Orphans")); purple_blist_add_group(g, NULL); } purple_debug_info("oscar", - "ssi: adding buddy %s to group %s to local list\n", name, gname_utf8 ? gname_utf8 : _("Orphans")); + "ssi: adding buddy %s to group %s to local list\n", name, gname ? gname : _("Orphans")); purple_blist_add_buddy(b, NULL, g, NULL); /* Mobile users should always be online */ @@ -5563,6 +5584,8 @@ } + g_free(alias); + ssi_item = aim_ssi_itemlist_finditem(od->ssi.local, gname, name, AIM_SSI_TYPE_BUDDY); if (ssi_item == NULL) @@ -5572,9 +5595,6 @@ "group %s\n", name, gname); } - g_free(gname_utf8); - g_free(alias_utf8); - return 1; } @@ -6277,7 +6297,6 @@ struct name_data *data; PurpleGroup *g; char *comment; - gchar *comment_utf8; gchar *title; PurpleAccount *account; const char *name; @@ -6296,7 +6315,6 @@ data = g_new(struct name_data, 1); comment = aim_ssi_getcomment(od->ssi.local, purple_group_get_name(g), name); - comment_utf8 = comment ? oscar_utf8_try_convert(account, comment) : NULL; data->gc = gc; data->name = g_strdup(name); @@ -6304,7 +6322,7 @@ title = g_strdup_printf(_("Buddy Comment for %s"), data->name); purple_request_input(gc, title, _("Buddy Comment:"), NULL, - comment_utf8, TRUE, FALSE, NULL, + comment, TRUE, FALSE, NULL, _("_OK"), G_CALLBACK(oscar_ssi_editcomment), _("_Cancel"), G_CALLBACK(oscar_free_name_data), account, data->name, NULL, @@ -6312,7 +6330,6 @@ g_free(title); g_free(comment); - g_free(comment_utf8); } static void @@ -7118,8 +7135,9 @@ return FALSE; } -void oscar_init(PurplePluginProtocolInfo *prpl_info) +void oscar_init(PurplePlugin *plugin) { + PurplePluginProtocolInfo *prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(plugin); PurpleAccountOption *option; static gboolean init = FALSE; @@ -7142,9 +7160,11 @@ OSCAR_DEFAULT_ALWAYS_USE_RV_PROXY); prpl_info->protocol_options = g_list_append(prpl_info->protocol_options, option); - option = purple_account_option_bool_new(_("Allow multiple simultaneous logins"), "allow_multiple_logins", - OSCAR_DEFAULT_ALLOW_MULTIPLE_LOGINS); - prpl_info->protocol_options = g_list_append(prpl_info->protocol_options, option); + if (g_str_equal(purple_plugin_get_id(plugin), "prpl-aim")) { + option = purple_account_option_bool_new(_("Allow multiple simultaneous logins"), "allow_multiple_logins", + OSCAR_DEFAULT_ALLOW_MULTIPLE_LOGINS); + prpl_info->protocol_options = g_list_append(prpl_info->protocol_options, option); + } if (init) return;
--- a/libpurple/protocols/oscar/oscar.h Sun Nov 08 23:36:28 2009 +0000 +++ b/libpurple/protocols/oscar/oscar.h Sun Nov 08 23:38:08 2009 +0000 @@ -623,7 +623,7 @@ } chat; }; -int oscar_connect_to_bos(PurpleConnection *gc, OscarData *od, const char *host, guint16 port, guint8 *cookie, guint16 cookielen); +int oscar_connect_to_bos(PurpleConnection *gc, OscarData *od, const char *host, guint16 port, guint8 *cookie, guint16 cookielen, const char *tls_certname); /* family_auth.c */ @@ -661,7 +661,7 @@ void flap_connection_send(FlapConnection *conn, FlapFrame *frame); void flap_connection_send_version(OscarData *od, FlapConnection *conn); void flap_connection_send_version_with_cookie(OscarData *od, FlapConnection *conn, guint16 length, const guint8 *chipsahoy); -void flap_connection_send_version_with_cookie_and_clientinfo(OscarData *od, FlapConnection *conn, guint16 length, const guint8 *chipsahoy, ClientInfo *ci); +void flap_connection_send_version_with_cookie_and_clientinfo(OscarData *od, FlapConnection *conn, guint16 length, const guint8 *chipsahoy, ClientInfo *ci, gboolean allow_multiple_login); void flap_connection_send_snac(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, guint16 flags, aim_snacid_t snacid, ByteStream *data); void flap_connection_send_snac_with_priority(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, guint16 flags, aim_snacid_t snacid, ByteStream *data, gboolean high_priority); void flap_connection_send_keepalive(OscarData *od, FlapConnection *conn); @@ -1240,7 +1240,7 @@ #define AIM_SSI_ACK_INVALIDNAME 0x000d #define AIM_SSI_ACK_AUTHREQUIRED 0x000e -/* These flags are set in the 0x00c9 TLV of SSI teyp 0x0005 */ +/* These flags are set in the 0x00c9 TLV of SSI type 0x0005 */ #define AIM_SSI_PRESENCE_FLAG_SHOWIDLE 0x00000400 #define AIM_SSI_PRESENCE_FLAG_NORECENTBUDDIES 0x00020000 @@ -1685,7 +1685,8 @@ guint32 disconnect; guint32 current; guint32 max; - guint8 unknown[5]; /* only present in versions >= 3 */ + guint32 delta; + guint8 dropping_snacs; GHashTable *members; /* Key is family and subtype, value is TRUE. */ struct timeval last; /**< The time when we last sent a SNAC of this rate class. */
--- a/libpurple/protocols/oscar/oscarcommon.h Sun Nov 08 23:36:28 2009 +0000 +++ b/libpurple/protocols/oscar/oscarcommon.h Sun Nov 08 23:38:08 2009 +0000 @@ -94,4 +94,4 @@ gboolean oscar_offline_message(const PurpleBuddy *buddy); void oscar_format_username(PurpleConnection *gc, const char *nick); GList *oscar_actions(PurplePlugin *plugin, gpointer context); -void oscar_init(PurplePluginProtocolInfo *prpl_info); +void oscar_init(PurplePlugin *plugin);
--- a/pidgin.desktop.in Sun Nov 08 23:36:28 2009 +0000 +++ b/pidgin.desktop.in Sun Nov 08 23:38:08 2009 +0000 @@ -1,7 +1,7 @@ [Desktop Entry] _Name=Pidgin Internet Messenger _GenericName=Internet Messenger -_Comment=Send instant messages over multiple protocols +_Comment=Chat over IM. Supports AIM, Google Talk, Jabber/XMPP, MSN, Yahoo and more Exec=pidgin Icon=pidgin StartupNotify=true
--- a/pidgin/gtkmain.c Sun Nov 08 23:36:28 2009 +0000 +++ b/pidgin/gtkmain.c Sun Nov 08 23:38:08 2009 +0000 @@ -143,6 +143,10 @@ } #ifdef HAVE_SIGNAL_H +static char *segfault_message; + +static int signal_sockets[2]; + static void sighandler(int sig); /* @@ -168,31 +172,60 @@ } } -char *segfault_message; +static void sighandler(int sig) +{ + ssize_t written; + + /* + * We won't do any of the heavy lifting for the signal handling here + * because we have no idea what was interrupted. Previously this signal + * handler could result in some calls to malloc/free, which can cause + * deadlock in libc when the signal handler was interrupting a previous + * malloc or free. So instead we'll do an ugly hack where we write the + * signal number to one end of a socket pair. The other half of the + * socket pair is watched by our main loop. When the main loop sees new + * data on the socket it reads in the signal and performs the appropriate + * action without fear of interrupting stuff. + */ + if (sig == SIGSEGV) { + fprintf(stderr, "%s", segfault_message); + abort(); + return; + } -/* - * This signal handler shouldn't be touching this much stuff. - * It should just set a flag and return, and something else in - * Pidgin should monitor the flag to see if something needs to - * be done. Because the signal handler interrupts the program, - * it could be called in the middle of adding a new connection - * to the list of connections, and then if we try to disconnect - * all connections it could lead to a crash because the linked - * list of connections could be in a weird state. But, well, - * this signal handler probably isn't called very often, so it's - * not a big deal. - */ -static void -sighandler(int sig) + written = write(signal_sockets[0], &sig, sizeof(int)); + if (written < 0 || written != sizeof(int)) { + /* This should never happen */ + purple_debug_error("sighandler", "Received signal %d but only " + "wrote %" G_GSSIZE_FORMAT " bytes out of %" + G_GSIZE_FORMAT ": %s\n", + sig, written, sizeof(int), g_strerror(errno)); + exit(1); + } +} + +static gboolean +mainloop_sighandler(GIOChannel *source, GIOCondition cond, gpointer data) { + GIOStatus stat; + int sig; + gsize bytes_read; + GError *error = NULL; + + /* read the signal number off of the io channel */ + stat = g_io_channel_read_chars(source, (gchar *)&sig, sizeof(int), + &bytes_read, &error); + if (stat != G_IO_STATUS_NORMAL) { + purple_debug_error("sighandler", "Signal callback failed to read " + "from signal socket: %s", error->message); + purple_core_quit(); + return FALSE; + } + switch (sig) { case SIGHUP: purple_debug_warning("sighandler", "Caught signal %d\n", sig); break; - case SIGSEGV: - fprintf(stderr, "%s", segfault_message); - abort(); - break; #if defined(USE_GSTREAMER) && !defined(GST_CAN_DISABLE_FORKING) /* By default, gstreamer forks when you initialize it, and waitpids for the * child. But if libpurple reaps the child rather than leaving it to @@ -219,6 +252,8 @@ purple_debug_warning("sighandler", "Caught signal %d\n", sig); purple_core_quit(); } + + return TRUE; } #endif @@ -502,11 +537,13 @@ sigset_t sigset; RETSIGTYPE (*prev_sig_disp)(int); char errmsg[BUFSIZ]; + GIOChannel *signal_channel; + GIOStatus signal_status; #ifndef DEBUG char *segfault_message_tmp; +#endif GError *error = NULL; #endif -#endif int opt; gboolean gui_check; gboolean debug_enabled; @@ -592,6 +629,29 @@ ); #endif + /* + * Create a socket pair for receiving unix signals from a signal + * handler. + */ + if (socketpair(AF_UNIX, SOCK_STREAM, 0, signal_sockets) < 0) { + perror("Failed to create sockets for GLib signal handling"); + exit(1); + } + signal_channel = g_io_channel_unix_new(signal_sockets[1]); + + /* + * Set the channel encoding to raw binary instead of the default of + * UTF-8, because we'll be sending integers across instead of strings. + */ + error = NULL; + signal_status = g_io_channel_set_encoding(signal_channel, NULL, &error); + if (signal_status != G_IO_STATUS_NORMAL) { + fprintf(stderr, "Failed to set the signal channel to raw " + "binary: %s", error->message); + exit(1); + } + g_io_add_watch(signal_channel, G_IO_IN, mainloop_sighandler, NULL); + /* Let's not violate any PLA's!!!! */ /* jseymour: whatever the fsck that means */ /* Robot101: for some reason things like gdm like to block * @@ -743,7 +803,7 @@ return 1; } - g_set_application_name(_("Pidgin")); + g_set_application_name(PIDGIN_NAME); #ifdef _WIN32 winpidgin_init(hint);
--- a/pidgin/plugins/disco/gtkdisco.c Sun Nov 08 23:36:28 2009 +0000 +++ b/pidgin/plugins/disco/gtkdisco.c Sun Nov 08 23:38:08 2009 +0000 @@ -162,12 +162,15 @@ static void discolist_cancel_cb(PidginDiscoList *pdl, const char *server) { + pdl->dialog->prompt_handle = NULL; + pidgin_disco_list_set_in_progress(pdl, FALSE); pidgin_disco_list_unref(pdl); } static void discolist_ok_cb(PidginDiscoList *pdl, const char *server) { + pdl->dialog->prompt_handle = NULL; gtk_widget_set_sensitive(pdl->dialog->browse_button, TRUE); if (!server || !*server) { @@ -236,7 +239,7 @@ /* Note to translators: The string "Enter an XMPP Server" is asking the user to type the name of an XMPP server which will then be queried */ - purple_request_input(my_plugin, _("Server name request"), _("Enter an XMPP Server"), + dialog->prompt_handle = purple_request_input(my_plugin, _("Server name request"), _("Enter an XMPP Server"), _("Select an XMPP server to query"), server, FALSE, FALSE, NULL, _("Find Services"), PURPLE_CALLBACK(discolist_ok_cb), @@ -390,6 +393,9 @@ PidginDiscoDialog *dialog = d; PidginDiscoList *list = dialog->discolist; + if (dialog->prompt_handle) + purple_request_close(PURPLE_REQUEST_INPUT, dialog->prompt_handle); + if (list) { list->dialog = NULL;