# HG changeset patch # User Elliott Sales de Andrade # Date 1247721465 0 # Node ID ccb1f1777df756e61707883f0f1631ea27d55c1e # Parent affa3b67c651b6196ac52573eeaabbd754728b76# Parent 36aa9ed8cd3950d593b287010671121beec9fadc merge of '01d5e162e0d796e96df727bb20f12c2e2bfdd3d0' and 'f09b8fa2cb4486c1ddd4fbc6343caac76d3134a8' diff -r affa3b67c651 -r ccb1f1777df7 ChangeLog --- a/ChangeLog Thu Jul 16 05:15:42 2009 +0000 +++ b/ChangeLog Thu Jul 16 05:17:45 2009 +0000 @@ -7,7 +7,7 @@ * Voice & Video framework in libpurple, thanks to Mike Ruprecht's summer of code project in 2008. * It should no longer be possible to end up with duplicates of buddies - in a group on the buddy list. (Paul Aurich) + in a group on the buddy list. * Removed the unmaintained and unneeded toc protocol plugin. * Fixed NTLM authentication on big-endian systems. * Various memory cleanups when unloading libpurple. (Nick Hebner) @@ -35,6 +35,9 @@ from you on MSN. * Support sending an invite message to buddies when requesting authorization from them on MSN. + * Better handling of corrupt certificates in the TLS Peers cache. + * More efficient purple_find_buddies() and purple_find_group() functions. + (Jan Kaluza and Aman Gupta) AIM and ICQ: * Preliminary support for a new authentication scheme called diff -r affa3b67c651 -r ccb1f1777df7 ChangeLog.API --- a/ChangeLog.API Thu Jul 16 05:15:42 2009 +0000 +++ b/ChangeLog.API Thu Jul 16 05:17:45 2009 +0000 @@ -56,6 +56,7 @@ * purple_request_field_get_group * purple_request_field_get_ui_data * purple_request_field_set_ui_data + * purple_ssl_connect_with_ssl_cn * purple_strequal * purple_utf8_strip_unprintables * purple_util_fetch_url_request_len_with_account @@ -79,6 +80,9 @@ * Added a client_type field in the get_ui_info core UI op. See core.h for details. * Added introspection of signals exposed via the D-Bus API. + * purple_find_buddies is now more efficient in the case where + it is enumerating all the buddies for an account. + * purple_find_group is now more efficient for large numbers of groups. Deprecated: * buddy-added and buddy-removed blist signals diff -r affa3b67c651 -r ccb1f1777df7 libpurple/blist.c --- a/libpurple/blist.c Thu Jul 16 05:15:42 2009 +0000 +++ b/libpurple/blist.c Thu Jul 16 05:17:45 2009 +0000 @@ -48,6 +48,12 @@ */ static GHashTable *buddies_cache = NULL; +/** + * A hash table used for efficient lookups of groups by name. + * UTF-8 collate-key => PurpleGroup*. + */ +static GHashTable *groups_cache = NULL; + static guint save_timer = 0; static gboolean blist_loaded = FALSE; @@ -704,6 +710,10 @@ buddies_cache = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)g_hash_table_destroy); + groups_cache = g_hash_table_new_full((GHashFunc)g_str_hash, + (GEqualFunc)g_str_equal, + (GDestroyNotify)g_free, NULL); + for (account = purple_accounts_get_all(); account != NULL; account = account->next) { purple_blist_buddies_cache_add_account(account->data); @@ -1203,6 +1213,7 @@ } else { /* A simple rename */ PurpleBlistNode *cnode, *bnode; + gchar* key; /* Build a GList of all buddies in this group */ for (cnode = ((PurpleBlistNode *)source)->child; cnode != NULL; cnode = cnode->next) { @@ -1213,6 +1224,13 @@ old_name = source->name; source->name = new_name; + + key = g_utf8_collate_key(old_name, -1); + g_hash_table_remove(groups_cache, key); + g_free(key); + + key = g_utf8_collate_key(new_name, -1); + g_hash_table_insert(groups_cache, key, source); } /* Save our changes */ @@ -1946,6 +1964,7 @@ { PurpleBlistUiOps *ops; PurpleBlistNode *gnode = (PurpleBlistNode*)group; + gchar* key; g_return_if_fail(group != NULL); g_return_if_fail(PURPLE_BLIST_NODE_IS_GROUP((PurpleBlistNode *)group)); @@ -1989,6 +2008,9 @@ purplebuddylist->root = gnode; } + key = g_utf8_collate_key(group->name, -1); + g_hash_table_insert(groups_cache, key, group); + purple_blist_schedule_save(); if (ops && ops->update) { @@ -2174,6 +2196,7 @@ PurpleBlistUiOps *ops = purple_blist_get_ui_ops(); PurpleBlistNode *node; GList *l; + gchar* key; g_return_if_fail(group != NULL); @@ -2191,6 +2214,10 @@ if (node->next) node->next->prev = node->prev; + key = g_utf8_collate_key(group->name, -1); + g_hash_table_remove(groups_cache, key); + g_free(key); + purple_blist_schedule_save(); /* Update the UI */ @@ -2427,17 +2454,17 @@ PurpleGroup *purple_find_group(const char *name) { - PurpleBlistNode *node; + gchar* key; + PurpleGroup *group; g_return_val_if_fail(purplebuddylist != NULL, NULL); g_return_val_if_fail((name != NULL) && (*name != '\0'), NULL); - for (node = purplebuddylist->root; node != NULL; node = node->next) { - if (!purple_utf8_strcasecmp(((PurpleGroup *)node)->name, name)) - return (PurpleGroup *)node; - } - - return NULL; + key = g_utf8_collate_key(name, -1); + group = g_hash_table_lookup(groups_cache, key); + g_free(key); + + return group; } PurpleChat * @@ -3117,6 +3144,10 @@ g_hash_table_destroy(purplebuddylist->buddies); g_hash_table_destroy(buddies_cache); + g_hash_table_destroy(groups_cache); + + buddies_cache = NULL; + groups_cache = NULL; PURPLE_DBUS_UNREGISTER_POINTER(purplebuddylist); g_free(purplebuddylist); diff -r affa3b67c651 -r ccb1f1777df7 libpurple/certificate.c --- a/libpurple/certificate.c Thu Jul 16 05:15:42 2009 +0000 +++ b/libpurple/certificate.c Thu Jul 16 05:17:45 2009 +0000 @@ -1218,20 +1218,6 @@ } static void -x509_tls_cached_peer_cert_changed(PurpleCertificateVerificationRequest *vrq) -{ - /* TODO: Prompt the user, etc. */ - - purple_debug_info("certificate/x509/tls_cached", - "Certificate for %s does not match cached. " - "Auto-rejecting!\n", - vrq->subject_name); - - purple_certificate_verify_complete(vrq, PURPLE_CERTIFICATE_INVALID); - return; -} - -static void x509_tls_cached_unknown_peer(PurpleCertificateVerificationRequest *vrq); static void @@ -1254,12 +1240,11 @@ cached_crt = purple_certificate_pool_retrieve( tls_peers, vrq->subject_name); if ( !cached_crt ) { - purple_debug_error("certificate/x509/tls_cached", + purple_debug_warning("certificate/x509/tls_cached", "Lookup failed on cached certificate!\n" - "It was here just a second ago. Forwarding " - "to cert_changed.\n"); - /* vrq now becomes the problem of cert_changed */ - x509_tls_cached_peer_cert_changed(vrq); + "Falling back to full verification.\n"); + /* vrq now becomes the problem of unknown_peer */ + x509_tls_cached_unknown_peer(vrq); return; } diff -r affa3b67c651 -r ccb1f1777df7 libpurple/plugins/ssl/ssl-nss.c --- a/libpurple/plugins/ssl/ssl-nss.c Thu Jul 16 05:15:42 2009 +0000 +++ b/libpurple/plugins/ssl/ssl-nss.c Thu Jul 16 05:17:45 2009 +0000 @@ -546,12 +546,12 @@ CERTCertificate *crt_dat; PurpleCertificate *crt; - g_return_val_if_fail(filename, NULL); + g_return_val_if_fail(filename != NULL, NULL); purple_debug_info("nss/x509", "Loading certificate from %s\n", filename); - + /* Load the raw data up */ if (!g_file_get_contents(filename, &rawcert, &len, @@ -560,12 +560,20 @@ return NULL; } + if (len == 0) { + purple_debug_error("nss/x509", + "Certificate file has no contents!\n"); + if (rawcert) + g_free(rawcert); + return NULL; + } + /* Decode the certificate */ crt_dat = CERT_DecodeCertFromPackage(rawcert, len); g_free(rawcert); - g_return_val_if_fail(crt_dat, NULL); - + g_return_val_if_fail(crt_dat != NULL, NULL); + crt = g_new0(PurpleCertificate, 1); crt->scheme = &x509_nss; crt->data = crt_dat; diff -r affa3b67c651 -r ccb1f1777df7 libpurple/protocols/jabber/bosh.c --- a/libpurple/protocols/jabber/bosh.c Thu Jul 16 05:15:42 2009 +0000 +++ b/libpurple/protocols/jabber/bosh.c Thu Jul 16 05:17:45 2009 +0000 @@ -51,8 +51,13 @@ PurpleHTTPConnection *connections[MAX_HTTP_CONNECTIONS]; unsigned short failed_connections; - gboolean ready; + enum { + BOSH_CONN_OFFLINE, + BOSH_CONN_BOOTING, + BOSH_CONN_ONLINE + } state; gboolean ssl; + gboolean needs_restart; /* decoded URL */ char *host; @@ -84,7 +89,11 @@ PurpleCircBuffer *write_buffer; - gboolean ready; + enum { + HTTP_CONN_OFFLINE, + HTTP_CONN_CONNECTING, + HTTP_CONN_CONNECTED + } state; int requests; /* number of outstanding HTTP requests */ GString *buf; @@ -129,7 +138,7 @@ PurpleHTTPConnection *conn = g_new0(PurpleHTTPConnection, 1); conn->bosh = bosh; conn->fd = -1; - conn->ready = FALSE; + conn->state = HTTP_CONN_OFFLINE; conn->write_buffer = purple_circ_buffer_new(0 /* default grow size */); @@ -176,6 +185,7 @@ conn->path = g_strdup_printf("/%s", path); g_free(path); conn->pipelining = TRUE; + conn->needs_restart = FALSE; if ((user && user[0] != '\0') || (passwd && passwd[0] != '\0')) { purple_debug_info("jabber", "Ignoring unexpected username and password " @@ -198,7 +208,7 @@ conn->pending = purple_circ_buffer_new(0 /* default grow size */); - conn->ready = FALSE; + conn->state = BOSH_CONN_OFFLINE; if (purple_strcasestr(url, "https://") != NULL) conn->ssl = TRUE; else @@ -243,18 +253,28 @@ /* Easy solution: Does everyone involved support pipelining? Hooray! Just use * one TCP connection! */ if (conn->pipelining) - return conn->connections[0]->ready ? conn->connections[0] : NULL; + return conn->connections[0]->state == HTTP_CONN_CONNECTED ? + conn->connections[0] : NULL; /* First loop, look for a connection that's ready */ for (i = 0; i < MAX_HTTP_CONNECTIONS; ++i) { - if (conn->connections[i] && conn->connections[i]->ready && - conn->connections[i]->requests == 0) + if (conn->connections[i] && + conn->connections[i]->state == HTTP_CONN_CONNECTED && + conn->connections[i]->requests == 0) return conn->connections[i]; } - /* Second loop, look for one that's NULL and create a new connection */ + /* Second loop, is something currently connecting? If so, just queue up. */ + for (i = 0; i < MAX_HTTP_CONNECTIONS; ++i) { + if (conn->connections[i] && + conn->connections[i]->state == HTTP_CONN_CONNECTING) + return NULL; + } + + /* Third loop, look for one that's NULL and create a new connection */ for (i = 0; i < MAX_HTTP_CONNECTIONS; ++i) { if (!conn->connections[i]) { + purple_debug_info("jabber", "bosh: Creating and connecting new httpconn\n"); conn->connections[i] = jabber_bosh_http_connection_init(conn); http_connection_connect(conn->connections[i]); @@ -268,7 +288,7 @@ static void jabber_bosh_connection_send(PurpleBOSHConnection *conn, - PurpleBOSHPacketType type, const char *data) + const PurpleBOSHPacketType type, const char *data) { PurpleHTTPConnection *chosen; GString *packet = NULL; @@ -277,12 +297,12 @@ if (type != PACKET_NORMAL && !chosen) { /* - * For non-ordinary traffic, we don't want to 'buffer' it, so use the + * For non-ordinary traffic, we can't 'buffer' it, so use the * first connection. */ chosen = conn->connections[0]; - if (!chosen->ready) { + if (chosen->state != HTTP_CONN_CONNECTED) { purple_debug_info("jabber", "Unable to find a ready BOSH " "connection. Ignoring send of type 0x%02x.\n", type); return; @@ -300,6 +320,7 @@ int len = data ? strlen(data) : 0; purple_circ_buffer_append(conn->pending, data, len); } + return; } @@ -316,9 +337,11 @@ conn->sid, conn->js->user->domain); - if (type == PACKET_STREAM_RESTART) + if (type == PACKET_STREAM_RESTART) { packet = g_string_append(packet, " xmpp:restart='true'/>"); - else { + /* TODO: Do we need to wait for a response? */ + conn->needs_restart = FALSE; + } else { gsize read_amt; if (type == PACKET_TERMINATE) packet = g_string_append(packet, " type='terminate'"); @@ -343,7 +366,9 @@ jabber_bosh_connection_send(conn, PACKET_TERMINATE, NULL); } -static void jabber_bosh_connection_stream_restart(PurpleBOSHConnection *conn) { +static void jabber_bosh_connection_stream_restart(PurpleBOSHConnection *conn) +{ + conn->needs_restart = TRUE; jabber_bosh_connection_send(conn, PACKET_STREAM_RESTART, NULL); } @@ -353,7 +378,7 @@ type = xmlnode_get_attrib(node, "type"); if (type != NULL && !strcmp(type, "terminate")) { - conn->ready = FALSE; + conn->state = BOSH_CONN_OFFLINE; purple_connection_error_reason(conn->js->gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, _("The BOSH connection manager terminated your session.")); @@ -384,11 +409,6 @@ /* jabber_process_packet might free child */ xmlnode *next = child->next; if (child->type == XMLNODE_TYPE_TAG) { - if (!strcmp(child->name, "iq")) { - if (xmlnode_get_child(child, "session")) - conn->ready = TRUE; - } - jabber_process_packet(js, &child); } @@ -476,9 +496,13 @@ conn->max_inactivity = 0; } else { /* TODO: Integrate this with jabber.c keepalive checks... */ - conn->inactivity_timer = purple_timeout_add_seconds( - conn->max_inactivity - 2 /* rounding */, bosh_inactivity_cb, - conn); + if (conn->inactivity_timer == 0) { + purple_debug_misc("jabber", "Starting BOSH inactivity timer for %d secs (compensating for rounding)\n", + conn->max_inactivity - 5); + conn->inactivity_timer = purple_timeout_add_seconds( + conn->max_inactivity - 5 /* rounding */, + bosh_inactivity_cb, conn); + } } } @@ -487,6 +511,7 @@ /* FIXME: Depending on receiving features might break with some hosts */ packet = xmlnode_get_child(node, "features"); + conn->state = BOSH_CONN_ONLINE; conn->js->use_bosh = TRUE; conn->receive_cb = auth_response_cb; jabber_stream_features_parse(conn->js, packet); @@ -511,6 +536,8 @@ conn->js->user->domain, ++conn->rid); + purple_debug_misc("jabber", "SendBOSH Boot %s(%" G_GSIZE_FORMAT "): %s\n", + conn->ssl ? "(ssl)" : "", buf->len, buf->str); conn->receive_cb = boot_response_cb; http_connection_send_request(conn->connections[0], buf); g_string_free(buf, TRUE); @@ -550,7 +577,7 @@ connection_common_established_cb(PurpleHTTPConnection *conn) { /* Indicate we're ready and reset some variables */ - conn->ready = TRUE; + conn->state = HTTP_CONN_CONNECTED; conn->requests = 0; if (conn->buf) { g_string_free(conn->buf, TRUE); @@ -559,9 +586,11 @@ conn->headers_done = FALSE; conn->handled_len = conn->body_len = 0; - if (conn->bosh->ready) { + if (conn->bosh->needs_restart) + jabber_bosh_connection_stream_restart(conn->bosh); + else if (conn->bosh->state == BOSH_CONN_ONLINE) { purple_debug_info("jabber", "BOSH session already exists. Trying to reuse it.\n"); - if (conn->bosh->pending->bufused > 0) { + if (conn->bosh->requests == 0 || conn->bosh->pending->bufused > 0) { /* Send the pending data */ jabber_bosh_connection_send(conn->bosh, PACKET_NORMAL, NULL); } @@ -585,7 +614,7 @@ * Well, then. Fine! I never liked you anyway, server! I was cheating on you * with AIM! */ - conn->ready = FALSE; + conn->state = HTTP_CONN_OFFLINE; if (conn->psc) { purple_ssl_close(conn->psc); conn->psc = NULL; @@ -620,6 +649,10 @@ void jabber_bosh_connection_connect(PurpleBOSHConnection *bosh) { PurpleHTTPConnection *conn = bosh->connections[0]; + + g_return_if_fail(bosh->state == BOSH_CONN_OFFLINE); + bosh->state = BOSH_CONN_BOOTING; + http_connection_connect(conn); } @@ -679,10 +712,10 @@ http_received_cb(conn->buf->str + conn->handled_len, conn->body_len, conn->bosh); - if (conn->bosh->ready && + if (conn->bosh->state == BOSH_CONN_ONLINE && (conn->bosh->requests == 0 || conn->bosh->pending->bufused > 0)) { + purple_debug_misc("jabber", "BOSH: Sending an empty request\n"); jabber_bosh_connection_send(conn->bosh, PACKET_NORMAL, NULL); - purple_debug_misc("jabber", "BOSH: Sending an empty request\n"); } g_string_free(conn->buf, TRUE); @@ -802,6 +835,8 @@ PurpleConnection *gc = bosh->js->gc; PurpleAccount *account = purple_connection_get_account(gc); + conn->state = HTTP_CONN_CONNECTING; + if (bosh->ssl) { if (purple_ssl_is_supported()) { conn->psc = purple_ssl_connect(account, bosh->host, bosh->port, diff -r affa3b67c651 -r ccb1f1777df7 libpurple/protocols/jabber/buddy.c --- a/libpurple/protocols/jabber/buddy.c Thu Jul 16 05:15:42 2009 +0000 +++ b/libpurple/protocols/jabber/buddy.c Thu Jul 16 05:17:45 2009 +0000 @@ -702,7 +702,7 @@ const char *status_name = jabber_buddy_state_get_name(jbr->state); if (jbr->status) { - purdy = g_markup_escape_text(jbr->status, -1); + purdy = purple_strreplace(jbr->status, "\n", "
\n"); if (purple_strequal(status_name, purdy)) status_name = NULL; diff -r affa3b67c651 -r ccb1f1777df7 libpurple/protocols/jabber/jutil.c --- a/libpurple/protocols/jabber/jutil.c Thu Jul 16 05:15:42 2009 +0000 +++ b/libpurple/protocols/jabber/jutil.c Thu Jul 16 05:17:45 2009 +0000 @@ -257,29 +257,29 @@ /* normalization */ if(at) { - node = g_utf8_normalize(str, at-str, G_NORMALIZE_NFKC); + node = g_utf8_strdown(str, at-str); if(slash) { - domain = g_utf8_normalize(at+1, slash-(at+1), G_NORMALIZE_NFKC); + domain = g_utf8_strdown(at+1, slash-(at+1)); jid->resource = g_utf8_normalize(slash+1, -1, G_NORMALIZE_NFKC); } else { - domain = g_utf8_normalize(at+1, -1, G_NORMALIZE_NFKC); + domain = g_utf8_strdown(at+1, -1); } } else { if(slash) { - domain = g_utf8_normalize(str, slash-str, G_NORMALIZE_NFKC); + domain = g_utf8_strdown(str, slash-str); jid->resource = g_utf8_normalize(slash+1, -1, G_NORMALIZE_NFKC); } else { - domain = g_utf8_normalize(str, -1, G_NORMALIZE_NFKC); + domain = g_utf8_strdown(str, -1); } } if (node) { - jid->node = g_utf8_strdown(node, -1); + jid->node = g_utf8_normalize(node, -1, G_NORMALIZE_NFKC); g_free(node); } if (domain) { - jid->domain = g_utf8_strdown(domain, -1); + jid->domain = g_utf8_normalize(domain, -1, G_NORMALIZE_NFKC); g_free(domain); } diff -r affa3b67c651 -r ccb1f1777df7 libpurple/protocols/jabber/si.c --- a/libpurple/protocols/jabber/si.c Thu Jul 16 05:15:42 2009 +0000 +++ b/libpurple/protocols/jabber/si.c Thu Jul 16 05:17:45 2009 +0000 @@ -51,9 +51,9 @@ char *iq_id; enum { - STREAM_METHOD_UNKNOWN = 0, + STREAM_METHOD_UNKNOWN = 0, STREAM_METHOD_BYTESTREAMS = 2 << 1, - STREAM_METHOD_IBB = 2 << 2, + STREAM_METHOD_IBB = 2 << 2, STREAM_METHOD_UNSUPPORTED = 2 << 31 } stream_method; @@ -1379,6 +1379,31 @@ static void jabber_si_xfer_request_denied(PurpleXfer *xfer) { + JabberSIXfer *jsx = (JabberSIXfer *) xfer->data; + JabberStream *js = jsx->js; + + /* + * TODO: It's probably an error if jsx->iq_id == NULL. g_return_if_fail + * might be warranted. + */ + if (jsx->iq_id && !jsx->accepted) { + JabberIq *iq; + xmlnode *error, *child; + iq = jabber_iq_new(js, JABBER_IQ_ERROR); + xmlnode_set_attrib(iq->node, "to", xfer->who); + jabber_iq_set_id(iq, jsx->iq_id); + + error = xmlnode_new_child(iq->node, "error"); + xmlnode_set_attrib(error, "type", "cancel"); + child = xmlnode_new_child(error, "forbidden"); + xmlnode_set_namespace(child, "urn:ietf:params:xml:ns:xmpp-stanzas"); + child = xmlnode_new_child(error, "text"); + xmlnode_set_namespace(child, "urn:ietf:params:xml:ns:xmpp-stanzas"); + xmlnode_insert_data(child, "Offer Declined", -1); + + jabber_iq_send(iq); + } + jabber_si_xfer_free(xfer); purple_debug(PURPLE_DEBUG_INFO, "jabber", "in jabber_si_xfer_request_denied\n"); } @@ -1421,6 +1446,7 @@ purple_notify_error(js->gc, _("File Send Failed"), _("File Send Failed"), msg); g_free(msg); + purple_xfer_cancel_local(xfer); } } @@ -1434,13 +1460,38 @@ JabberSIXfer *jsx = xfer->data; char **who_v = g_strsplit(xfer->who, "/", 2); char *who; + JabberBuddy *jb; + JabberBuddyResource *jbr = NULL; + + jb = jabber_buddy_find(jsx->js, who_v[0], FALSE); + if (jb) { + jbr = jabber_buddy_find_resource(jb, resource); + } who = g_strdup_printf("%s/%s", who_v[0], resource); g_strfreev(who_v); g_free(xfer->who); xfer->who = who; - jabber_disco_info_do(jsx->js, who, - jabber_si_xfer_send_disco_cb, xfer); + + if (jbr) { + char *msg; + + if (jabber_resource_has_capability(jbr, XEP_0047_NAMESPACE)) + jsx->stream_method |= STREAM_METHOD_IBB; + if (jabber_resource_has_capability(jbr, "http://jabber.org/protocol/si/profile/file-transfer")) { + jabber_si_xfer_send_request(xfer); + return; + } + + msg = g_strdup_printf(_("Unable to send file to %s, user does not support file transfers"), who); + purple_notify_error(jsx->js->gc, _("File Send Failed"), + _("File Send Failed"), msg); + g_free(msg); + purple_xfer_cancel_local(xfer); + } else { + jabber_disco_info_do(jsx->js, who, + jabber_si_xfer_send_disco_cb, xfer); + } } static void resource_select_ok_cb(PurpleXfer *xfer, PurpleRequestFields *fields) @@ -1529,6 +1580,8 @@ xmlnode_set_attrib(iq->node, "to", xfer->who); if(jsx->iq_id) jabber_iq_set_id(iq, jsx->iq_id); + else + purple_debug_error("jabber", "Sending SI result with new IQ id.\n"); jsx->accepted = TRUE; diff -r affa3b67c651 -r ccb1f1777df7 libpurple/protocols/oscar/flap_connection.c --- a/libpurple/protocols/oscar/flap_connection.c Thu Jul 16 05:15:42 2009 +0000 +++ b/libpurple/protocols/oscar/flap_connection.c Thu Jul 16 05:17:45 2009 +0000 @@ -505,7 +505,6 @@ g_free(conn->error_message); g_free(conn->cookie); - g_free(conn->ssl_cert_cn); /* * Free conn->internal, if necessary diff -r affa3b67c651 -r ccb1f1777df7 libpurple/protocols/oscar/oscar.c --- a/libpurple/protocols/oscar/oscar.c Thu Jul 16 05:15:42 2009 +0000 +++ b/libpurple/protocols/oscar/oscar.c Thu Jul 16 05:17:45 2009 +0000 @@ -1246,32 +1246,6 @@ } static void -ssl_proxy_conn_established_cb(gpointer data, gint source, const gchar *error_message) -{ - OscarData *od; - PurpleConnection *gc; - PurpleAccount *account; - FlapConnection *conn; - - conn = data; - od = conn->od; - gc = od->gc; - account = purple_connection_get_account(gc); - - conn->connect_data = NULL; - - if (source < 0) - { - connection_common_error_cb(conn, error_message); - return; - } - - conn->gsc = purple_ssl_connect_with_host_fd(account, source, - ssl_connection_established_cb, ssl_connection_error_cb, - conn->ssl_cert_cn, conn); -} - -static void flap_connection_established_bos(OscarData *od, FlapConnection *conn) { PurpleConnection *gc = od->gc; @@ -1943,12 +1917,13 @@ if (od->use_ssl) { /* - * This shouldn't be hardcoded except that the server isn't sending - * us a name to use for comparing the certificate common name. + * This shouldn't be hardcoded to "bos.oscar.aol.com" except that + * the server isn't sending us a name to use for comparing the + * certificate common name. */ - newconn->ssl_cert_cn = g_strdup("bos.oscar.aol.com"); - newconn->connect_data = purple_proxy_connect(NULL, account, host, port, - ssl_proxy_conn_established_cb, newconn); + newconn->gsc = purple_ssl_connect_with_ssl_cn(account, host, port, + ssl_connection_established_cb, ssl_connection_error_cb, + "bos.oscar.aol.com", newconn); } else { @@ -1957,7 +1932,7 @@ } g_free(host); - if (newconn->connect_data == NULL) + if (newconn->gsc == NULL && newconn->connect_data == NULL) { purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Unable to connect")); return 0; @@ -2114,15 +2089,9 @@ if (redir->use_ssl) { - /* - * TODO: It should be possible to specify a certificate common name - * distinct from the host we're passing to purple_ssl_connect. The - * way to work around that is to use purple_proxy_connect + - * purple_ssl_connect_with_host_fd - */ - newconn->ssl_cert_cn = g_strdup(redir->ssl_cert_cn); - newconn->connect_data = purple_proxy_connect(NULL, account, host, port, - ssl_proxy_conn_established_cb, newconn); + newconn->gsc = purple_ssl_connect_with_ssl_cn(account, host, port, + ssl_connection_established_cb, ssl_connection_error_cb, + redir->ssl_cert_cn, newconn); } else { diff -r affa3b67c651 -r ccb1f1777df7 libpurple/protocols/oscar/oscar.h --- a/libpurple/protocols/oscar/oscar.h Thu Jul 16 05:15:42 2009 +0000 +++ b/libpurple/protocols/oscar/oscar.h Thu Jul 16 05:17:45 2009 +0000 @@ -429,7 +429,6 @@ guint16 cookielen; guint8 *cookie; gpointer new_conn_data; - gchar *ssl_cert_cn; int fd; PurpleSslConnection *gsc; diff -r affa3b67c651 -r ccb1f1777df7 libpurple/sslconn.c --- a/libpurple/sslconn.c Thu Jul 16 05:15:42 2009 +0000 +++ b/libpurple/sslconn.c Thu Jul 16 05:17:45 2009 +0000 @@ -100,6 +100,15 @@ PurpleSslInputFunction func, PurpleSslErrorFunction error_func, void *data) { + return purple_ssl_connect_with_ssl_cn(account, host, port, func, error_func, + NULL, data); +} + +PurpleSslConnection * +purple_ssl_connect_with_ssl_cn(PurpleAccount *account, const char *host, int port, + PurpleSslInputFunction func, PurpleSslErrorFunction error_func, + const char *ssl_cn, void *data) +{ PurpleSslConnection *gsc; g_return_val_if_fail(host != NULL, NULL); @@ -116,7 +125,7 @@ gsc = g_new0(PurpleSslConnection, 1); gsc->fd = -1; - gsc->host = g_strdup(host); + gsc->host = ssl_cn ? g_strdup(ssl_cn) : g_strdup(host); gsc->port = port; gsc->connect_cb_data = data; gsc->connect_cb = func; diff -r affa3b67c651 -r ccb1f1777df7 libpurple/sslconn.h --- a/libpurple/sslconn.h Thu Jul 16 05:15:42 2009 +0000 +++ b/libpurple/sslconn.h Thu Jul 16 05:17:45 2009 +0000 @@ -186,6 +186,31 @@ PurpleSslErrorFunction error_func, void *data); +/** + * Makes a SSL connection to the specified host and port, using the separate + * name to verify with the certificate. The caller should keep track of the + * returned value and use it to cancel the connection, if needed. + * + * @param account The account making the connection. + * @param host The destination host. + * @param port The destination port. + * @param func The SSL input handler function. + * @param error_func The SSL error handler function. This function + * should NOT call purple_ssl_close(). In + * the event of an error the #PurpleSslConnection will be + * destroyed for you. + * @param ssl_host The hostname of the other peer (to verify the CN) + * @param data User-defined data. + * + * @return The SSL connection handle. + * @since 2.6.0 + */ +PurpleSslConnection *purple_ssl_connect_with_ssl_cn(PurpleAccount *account, const char *host, + int port, PurpleSslInputFunction func, + PurpleSslErrorFunction error_func, + const char *ssl_host, + void *data); + #if !(defined PURPLE_DISABLE_DEPRECATED) || (defined _PURPLE_SSLCONN_C_) /** * Makes a SSL connection using an already open file descriptor. diff -r affa3b67c651 -r ccb1f1777df7 libpurple/tests/test_jabber_jutil.c --- a/libpurple/tests/test_jabber_jutil.c Thu Jul 16 05:15:42 2009 +0000 +++ b/libpurple/tests/test_jabber_jutil.c Thu Jul 16 05:17:45 2009 +0000 @@ -80,6 +80,17 @@ jabber_id_free(jid); \ } +#define assert_jid_parts(expect_node, expect_domain, str) { \ + JabberID *jid = jabber_id_new(str); \ + fail_if(jid == NULL, "JID '%s' is valid but jabber_id_new() rejected it", str); \ + fail_if(jid->node == NULL, "JID '%s' is valid but jabber_id_new() didn't return a node", str); \ + fail_if(jid->domain == NULL, "JID '%s' is valid but jabber_id_new() didn't return a domain", str); \ + fail_if(jid->resource != NULL, "JID '%s' doesn't contain a resource", str); \ + assert_string_equal(expect_node, jid->node); \ + assert_string_equal(expect_domain, jid->domain); \ + jabber_id_free(jid); \ +} + START_TEST(test_jabber_id_new) { assert_valid_jid("gmail.com"); @@ -117,6 +128,12 @@ assert_invalid_jid("mark.doliner@gmail\\stuff.org"); assert_invalid_jid("paul@[::1]124"); assert_invalid_jid("paul@2[::1]124/as"); + + /* Ensure that jabber_id_new is properly lowercasing node and domains */ + assert_jid_parts("paul", "darkrain42.org", "PaUL@darkrain42.org"); + assert_jid_parts("paul", "darkrain42.org", "paul@DaRkRaIn42.org"); + assert_jid_parts("ꙥ", "darkrain42.org", "Ꙥ@darkrain42.org"); + assert_jid_parts("paul", "өarkrain42.org", "paul@Өarkrain42.org"); } END_TEST diff -r affa3b67c651 -r ccb1f1777df7 pidgin/gtkdialogs.c --- a/pidgin/gtkdialogs.c Thu Jul 16 05:15:42 2009 +0000 +++ b/pidgin/gtkdialogs.c Thu Jul 16 05:17:45 2009 +0000 @@ -76,7 +76,7 @@ {"Paul 'darkrain42' Aurich", NULL, NULL }, {"John 'rekkanoryo' Bailey", N_("bug master"), NULL}, {"Ethan 'Paco-Paco' Blanton", NULL, NULL}, - {"Hylke Bons", N_("artist"), "h.bons@student.rug.nl"}, + {"Hylke Bons", N_("artist"), "hylkebons@gmail.com"}, {"Thomas Butter", NULL, NULL}, /* feel free to not translate this */ {N_("Ka-Hing Cheung"), NULL, NULL}, diff -r affa3b67c651 -r ccb1f1777df7 pidgin/gtkutils.c --- a/pidgin/gtkutils.c Thu Jul 16 05:15:42 2009 +0000 +++ b/pidgin/gtkutils.c Thu Jul 16 05:17:45 2009 +0000 @@ -3736,10 +3736,9 @@ return; } - if (!g_file_set_contents(file, contents, length, &error)) { - purple_debug_error("gtkutils", "Unable to write contents to %s: %s\n", - file, error->message); - g_error_free(error); + if (!purple_util_write_data_to_file_absolute(file, contents, length)) { + purple_debug_error("gtkutils", "Unable to write contents to %s\n", + file); } }