# HG changeset patch # User Etan Reisner # Date 1234927624 0 # Node ID 463d8501e4e0bf60557d1f2892396f01c0fecff7 # Parent c1f85543556d9b2beacbdd9cdf03524db98ffb87# Parent e859785b49d8bff8c56cd0d6d18ba8633f2b5593 merge of '021b2e6a0a1a494338bfc1491b59acee849ec048' and '123a3369e1dd05078b2707f46de36749d4147153' diff -r c1f85543556d -r 463d8501e4e0 COPYRIGHT --- a/COPYRIGHT Thu Feb 12 06:06:40 2009 +0000 +++ b/COPYRIGHT Wed Feb 18 03:27:04 2009 +0000 @@ -14,6 +14,7 @@ Patrick Aussems Anibal Avelar Ali Albazaz +Kosta Arvanitis Christopher Ayoup Alex Badea John Bailey @@ -66,6 +67,7 @@ Ludovico Cavedon Steve Cavilia Julien Cegarra +Matěj Cepl Cerulean Studios, LLC Jonathan Champ Christophe Chapuis @@ -204,6 +206,7 @@ Intel Corporation Scott Jackson Hans Petter Jansson +David Jedelsky Henry Jen Benjamin Kahn Anders Kaseorg @@ -419,6 +422,7 @@ Andreas Stührk Oleg Sukhodolsky Sun Microsystems +Marcus Sundberg Mårten Svantesson (fursten) Amir Szekely (kichik) Robert T. diff -r c1f85543556d -r 463d8501e4e0 ChangeLog --- a/ChangeLog Thu Feb 12 06:06:40 2009 +0000 +++ b/ChangeLog Wed Feb 18 03:27:04 2009 +0000 @@ -7,6 +7,9 @@ enable, check the "Use SSL" option from the Advanced tab when editing your AIM or ICQ account. (Paul Aurich) * Fix a memory leak in SILC. (Luke Petre) + * Fix some string handling in the SIMPLE prpl, which fixes some buddy name + handling and other issues. (Paul Aurich, Marcus Sundberg) + * Implement support for resolving DNS via the SOCKS4 proxy (SOCKS4a). ICQ: * Fix retrieval of status messages from users of ICQ 6.x, Miranda, and @@ -15,6 +18,7 @@ of buddy icons and available messages. * Properly publish status messages for statuses other than Available. ICQ 6.x users can now see these status messages. (Daniel Ljungborg) + * Fix recipt of messages from the mobile client Slick. (David Jedelsky) MSN: * Fix transfer of buddy icons, custom smileys, and files from the @@ -23,8 +27,45 @@ * Large (multi-part) messages are now correctly re-combined. * Federated/Yahoo! buddies should now stop creating sync issues at every signin. You may need to remove duplicates in the Address - Book. See the FAQ for more information. + Book. See the FAQ for more information. Thanks to Jason Lingohr + for lots of debugging and testing. * Messages from Yahoo! buddies are no longer silently dropped. + * We now save and use the CacheKey for ABCH SOAP requests. + * Don't try to parse Personal Status Messages or Current Media if they + don't exist. + * Convert from ISO-8859-1 encoding to UTF-8 when no charset is specified + on incoming messages. This should fix some issues with messages from + older clients. + * Force sending the font "Segoe UI" if outgoing formatting doesn't specify + a font already. + * Queue callbacks when token updates are in progress to prevent two token + update attempts from trampling each other. + * Fixed a crash on Windows when removing a buddy's alias. + * Update the Address Book when buddies' friendly names change. This + prevents seeing an outdated alias or not seeing an alias at all for + buddies who are offline when you sign in. + * Update tokens for FindMembership and ABFindAll SOAP requests. + * We no longer try to send empty messages. This could happen when a + message contained only formatting and that formatting was not supported + on MSN. + * Buddies on both the Allow and Block list are now automatically + removed from the Allow list. Users with this problem will now no + longer receive an ADL 241 error. The problematic buddy should now + appear on the buddy list and can be removed or unblocked as desired. + + XMPP: + * Resources using __HOSTNAME__ substitution will now grab only the short + hostname instead of the FQDN on systems which put the FQDN in the + hostname. (Matěj Cepl) + * No longer send a 'to' attribute on an outgoing stanza when we haven't + received one. This fixes a registration bug as described in ticket + #6635. + + Pidgin: + * Tooltip windows now appear below the mouse cursor. (Kosta Arvanitis) + * Tooltip windows now disappear on keypress events. (Kosta Arvanitis) + * Tooltip windows no longer linger when scrolling the buddy list. (Kosta + Arvanitis) Finch: * Allow rebinding keys to change the focused widget (details in the diff -r c1f85543556d -r 463d8501e4e0 finch/libgnt/gntwm.c --- a/finch/libgnt/gntwm.c Thu Feb 12 06:06:40 2009 +0000 +++ b/finch/libgnt/gntwm.c Wed Feb 18 03:27:04 2009 +0000 @@ -353,7 +353,8 @@ p->y = y; g_hash_table_replace(wm->positions, g_strdup(title + 1), p); } else { - gnt_warning("Invalid number of arguments (%d) for positioning a window.", l); + gnt_warning("Invalid number of arguments (%" G_GSIZE_FORMAT + ") for positioning a window.", l); } g_strfreev(coords); } diff -r c1f85543556d -r 463d8501e4e0 libpurple/protocols/jabber/jabber.c --- a/libpurple/protocols/jabber/jabber.c Thu Feb 12 06:06:40 2009 +0000 +++ b/libpurple/protocols/jabber/jabber.c Wed Feb 18 03:27:04 2009 +0000 @@ -148,7 +148,8 @@ } static char *jabber_prep_resource(char *input) { - char hostname[256]; /* current hostname */ + char hostname[256], /* current hostname */ + *dot = NULL; /* Empty resource == don't send any */ if (input == NULL || *input == '\0') @@ -170,6 +171,12 @@ } hostname[sizeof(hostname) - 1] = '\0'; + /* We want only the short hostname, not the FQDN - this will prevent the + * resource string from being unreasonably long on systems which stuff the + * whole FQDN in the hostname */ + if((dot = strchr(hostname, '.'))) + dot = '\0'; + return purple_strreplace(input, "__HOSTNAME__", hostname); } @@ -802,10 +809,11 @@ js->user->node, js->user->domain); if(account->registration_cb) (account->registration_cb)(account, TRUE, account->registration_cb_user_data); - } - else + } else { + g_return_if_fail(to != NULL); buf = g_strdup_printf(_("Registration to %s successful"), to); + } purple_notify_info(NULL, _("Registration Successful"), _("Registration Successful"), buf); g_free(buf); @@ -832,7 +840,11 @@ const char *type = xmlnode_get_attrib(packet, "type"); char *buf; char *to = data; - + + /* This function is never called for unregistering our XMPP account from + * the server, so there should always be a 'to' address. */ + g_return_if_fail(to != NULL); + if(!strcmp(type, "result")) { buf = g_strdup_printf(_("Registration from %s successfully removed"), to); @@ -867,7 +879,8 @@ iq = jabber_iq_new_query(cbdata->js, JABBER_IQ_SET, "jabber:iq:register"); query = xmlnode_get_child(iq->node, "query"); - xmlnode_set_attrib(iq->node, "to", cbdata->who); + if (cbdata->who) + xmlnode_set_attrib(iq->node, "to", cbdata->who); for(groups = purple_request_fields_get_groups(fields); groups; groups = groups->next) { @@ -883,7 +896,8 @@ jabber_iq_free(iq); iq = jabber_iq_new_query(cbdata->js, JABBER_IQ_SET, "jabber:iq:register"); query = xmlnode_get_child(iq->node, "query"); - xmlnode_set_attrib(iq->node,"to",cbdata->who); + if (cbdata->who) + xmlnode_set_attrib(iq->node,"to",cbdata->who); xmlnode_new_child(query, "remove"); jabber_iq_set_callback(iq, jabber_unregistration_result_cb, cbdata->who); @@ -928,8 +942,7 @@ } xmlnode_insert_data(y, value, -1); if(cbdata->js->registration && !strcmp(id, "username")) { - if(cbdata->js->user->node) - g_free(cbdata->js->user->node); + g_free(cbdata->js->user->node); cbdata->js->user->node = g_strdup(value); } if(cbdata->js->registration && !strcmp(id, "password")) @@ -972,7 +985,8 @@ iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:register"); query = xmlnode_get_child(iq->node, "query"); - xmlnode_set_attrib(iq->node,"to",to); + if (to) + xmlnode_set_attrib(iq->node,"to",to); xmlnode_insert_child(query, result); @@ -997,10 +1011,7 @@ return; from = xmlnode_get_attrib(packet, "from"); - if (!from) - from = js->serverFQDN; - g_return_if_fail(from != NULL); - + if(js->registration) { /* get rid of the login thingy */ purple_connection_set_state(js->gc, PURPLE_CONNECTED); @@ -1145,7 +1156,9 @@ purple_connection_get_account(js->gc), NULL, NULL, cbdata); else { - char *title = registered?g_strdup_printf(_("Change Account Registration at %s"), from) + char *title; + g_return_if_fail(from != NULL); + title = registered ? g_strdup_printf(_("Change Account Registration at %s"), from) :g_strdup_printf(_("Register New Account at %s"), from); purple_request_fields(js->gc, title, title, instructions, fields, diff -r c1f85543556d -r 463d8501e4e0 libpurple/protocols/jabber/parser.c --- a/libpurple/protocols/jabber/parser.c Thu Feb 12 06:06:40 2009 +0000 +++ b/libpurple/protocols/jabber/parser.c Wed Feb 18 03:27:04 2009 +0000 @@ -86,15 +86,10 @@ } } for(i=0; i < nb_attributes * 5; i+=5) { - const char *prefix = (const char *)attributes[i + 1]; + const char *attrib_ns = (const char *)attributes[i+2]; char *txt; int attrib_len = attributes[i+4] - attributes[i+3]; char *attrib = g_malloc(attrib_len + 1); - char *attrib_ns = NULL; - - if (attributes[i+2]) { - attrib_ns = g_strdup((char*)attributes[i+2]); - } memcpy(attrib, attributes[i+3], attrib_len); attrib[attrib_len] = '\0'; @@ -103,11 +98,7 @@ attrib = purple_unescape_html(txt); g_free(txt); xmlnode_set_attrib_with_namespace(node, (const char*) attributes[i], attrib_ns, attrib); - if (prefix && *prefix) { - node->prefix = g_strdup(prefix); - } g_free(attrib); - g_free(attrib_ns); } js->current = node; diff -r c1f85543556d -r 463d8501e4e0 libpurple/protocols/msn/contact.c --- a/libpurple/protocols/msn/contact.c Thu Feb 12 06:06:40 2009 +0000 +++ b/libpurple/protocols/msn/contact.c Wed Feb 18 03:27:04 2009 +0000 @@ -198,6 +198,8 @@ MsnCallbackState *state = data; xmlnode *fault; char *faultcode_str; + xmlnode *cachekey; + char *changed; if (resp == NULL) { purple_debug_error("msn", @@ -206,12 +208,27 @@ return; } + /* Update CacheKey if necessary */ + cachekey = xmlnode_get_child(resp->xml, "Header/ServiceHeader/CacheKeyChanged"); + if (cachekey != NULL) { + changed = xmlnode_get_data(cachekey); + if (changed && !strcmp(changed, "true")) { + cachekey = xmlnode_get_child(resp->xml, "Header/ServiceHeader/CacheKey"); + g_free(state->session->abch_cachekey); + state->session->abch_cachekey = xmlnode_get_data(cachekey); + purple_debug_info("msn", "Updated CacheKey for %s to '%s'.\n", + purple_account_get_username(state->session->account), + state->session->abch_cachekey); + } + g_free(changed); + } + fault = xmlnode_get_child(resp->xml, "Body/Fault"); if (fault == NULL) { /* No errors */ if (state->cb) - ((MsnSoapCallback)state->cb)(req, resp, data); + state->cb(req, resp, data); msn_callback_state_free(state); return; } @@ -230,7 +247,7 @@ else { if (state->cb) { - ((MsnSoapCallback)state->cb)(req, resp, data); + state->cb(req, resp, data); } else { /* We don't know how to respond to this faultcode, so log it */ char *str = xmlnode_to_str(fault, NULL); @@ -247,6 +264,14 @@ static gboolean msn_contact_request(MsnCallbackState *state) { + xmlnode *cachekey = xmlnode_get_child(state->body, + "Header/ABApplicationHeader/CacheKey"); + if (cachekey != NULL) + xmlnode_free(cachekey); + if (state->session->abch_cachekey != NULL) { + cachekey = xmlnode_new_child(xmlnode_get_child(state->body, "Header/ABApplicationHeader"), "CacheKey"); + xmlnode_insert_data(cachekey, state->session->abch_cachekey, -1); + } if (state->token == NULL) state->token = xmlnode_get_child(state->body, "Header/ABAuthHeader/TicketToken"); diff -r c1f85543556d -r 463d8501e4e0 libpurple/protocols/msn/msg.c --- a/libpurple/protocols/msn/msg.c Thu Feb 12 06:06:40 2009 +0000 +++ b/libpurple/protocols/msn/msg.c Wed Feb 18 03:27:04 2009 +0000 @@ -352,6 +352,14 @@ memcpy(msg->body, tmp, msg->body_len); msg->body[msg->body_len] = '\0'; } + + if (msg->charset == NULL) { + char *body = g_convert(msg->body, msg->body_len, "UTF-8", + "ISO-8859-1", NULL, &msg->body_len, NULL); + g_free(msg->body); + msg->body = body; + msg->charset = g_strdup("UTF-8"); + } } g_free(tmp_base); diff -r c1f85543556d -r 463d8501e4e0 libpurple/protocols/msn/msnutils.c --- a/libpurple/protocols/msn/msnutils.c Thu Feb 12 06:06:40 2009 +0000 +++ b/libpurple/protocols/msn/msnutils.c Wed Feb 18 03:27:04 2009 +0000 @@ -446,7 +446,7 @@ } if (fontface == NULL) - fontface = g_strdup("MS Sans Serif"); + fontface = g_strdup("Segoe UI"); *attributes = g_strdup_printf("FN=%s; EF=%s; CO=%s; PF=0; RL=%c", encode_spaces(fontface), diff -r c1f85543556d -r 463d8501e4e0 libpurple/protocols/msn/nexus.c --- a/libpurple/protocols/msn/nexus.c Thu Feb 12 06:06:40 2009 +0000 +++ b/libpurple/protocols/msn/nexus.c Wed Feb 18 03:27:04 2009 +0000 @@ -74,6 +74,7 @@ for (i = 0; i < nexus->token_len; i++) { g_hash_table_destroy(nexus->tokens[i].token); g_free(nexus->tokens[i].secret); + g_slist_free(nexus->tokens[i].updates); } g_free(nexus->tokens); @@ -235,6 +236,10 @@ struct _MsnNexusUpdateData { MsnNexus *nexus; int id; +}; + +typedef struct _MsnNexusUpdateCallback MsnNexusUpdateCallback; +struct _MsnNexusUpdateCallback { GSourceFunc cb; gpointer data; }; @@ -428,6 +433,7 @@ char *nonce; gsize len; char *key; + GSList *updates; #if 0 char *decrypted_pp; @@ -489,8 +495,15 @@ g_free(decrypted_data); } - if (ud->cb) - purple_timeout_add(0, ud->cb, ud->data); + updates = nexus->tokens[ud->id].updates; + nexus->tokens[ud->id].updates = NULL; + while (updates != NULL) { + MsnNexusUpdateCallback *update = updates->data; + if (update->cb) + purple_timeout_add(0, update->cb, update->data); + g_free(update); + updates = g_slist_delete_link(updates, updates); + } g_free(ud); } @@ -500,6 +513,7 @@ { MsnSession *session = nexus->session; MsnNexusUpdateData *ud; + MsnNexusUpdateCallback *update; PurpleCipherContext *sha1; PurpleCipherContext *hmac; @@ -526,16 +540,31 @@ char *request; MsnSoapMessage *soap; - purple_debug_info("msn", - "Updating ticket for user '%s' on domain '%s'\n", - purple_account_get_username(session->account), - ticket_domains[id][SSO_VALID_TICKET_DOMAIN]); + update = g_new0(MsnNexusUpdateCallback, 1); + update->cb = cb; + update->data = data; + + if (nexus->tokens[id].updates != NULL) { + /* Update already in progress. Just add to list and return. */ + purple_debug_info("msn", + "Ticket update for user '%s' on domain '%s' in progress. Adding request to queue.\n", + purple_account_get_username(session->account), + ticket_domains[id][SSO_VALID_TICKET_DOMAIN]); + nexus->tokens[id].updates = g_slist_prepend(nexus->tokens[id].updates, + update); + return; + } else { + purple_debug_info("msn", + "Updating ticket for user '%s' on domain '%s'\n", + purple_account_get_username(session->account), + ticket_domains[id][SSO_VALID_TICKET_DOMAIN]); + nexus->tokens[id].updates = g_slist_prepend(nexus->tokens[id].updates, + update); + } ud = g_new0(MsnNexusUpdateData, 1); ud->nexus = nexus; ud->id = id; - ud->cb = cb; - ud->data = data; sha1 = purple_cipher_context_new_by_name("sha1", NULL); diff -r c1f85543556d -r 463d8501e4e0 libpurple/protocols/msn/nexus.h --- a/libpurple/protocols/msn/nexus.h Thu Feb 12 06:06:40 2009 +0000 +++ b/libpurple/protocols/msn/nexus.h Wed Feb 18 03:27:04 2009 +0000 @@ -204,6 +204,7 @@ GHashTable *token; char *secret; time_t expiry; + GSList *updates; }; typedef struct _MsnNexus MsnNexus; diff -r c1f85543556d -r 463d8501e4e0 libpurple/protocols/msn/notification.c --- a/libpurple/protocols/msn/notification.c Thu Feb 12 06:06:40 2009 +0000 +++ b/libpurple/protocols/msn/notification.c Wed Feb 18 03:27:04 2009 +0000 @@ -623,6 +623,18 @@ if (user->passport && !strcmp(user->passport, "messenger@microsoft.com")) continue; + if ((user->list_op & MSN_LIST_OP_MASK) == (MSN_LIST_AL_OP | MSN_LIST_BL_OP)) { + /* The server will complain if we send it a user on both the + Allow and Block lists. So assume they're on the Block list + and remove them from the Allow list in the membership lists to + stop this from happening again. */ + purple_debug_warning("msn", + "User %s is on both Allow and Block list," + "removing from Allow list.\n", + user->passport); + msn_userlist_rem_buddy_from_list(session->userlist, user->passport, MSN_LIST_AL); + } + msn_add_contact_xml(session, adl_node, user->passport, user->list_op & MSN_LIST_OP_MASK, user->networkid); @@ -1619,19 +1631,25 @@ return; } - psm_str = msn_get_psm(cmd->payload,len); - msn_user_set_statusline(user, psm_str); - g_free(psm_str); + if (len != 0) { + psm_str = msn_get_psm(cmd->payload,len); + msn_user_set_statusline(user, psm_str); + g_free(psm_str); - str = msn_get_currentmedia(cmd->payload, len); - if (msn_parse_currentmedia(str, &media)) - msn_user_set_currentmedia(user, &media); - else + str = msn_get_currentmedia(cmd->payload, len); + if (msn_parse_currentmedia(str, &media)) + msn_user_set_currentmedia(user, &media); + else + msn_user_set_currentmedia(user, NULL); + g_free(media.title); + g_free(media.album); + g_free(media.artist); + g_free(str); + + } else { + msn_user_set_statusline(user, NULL); msn_user_set_currentmedia(user, NULL); - g_free(media.title); - g_free(media.album); - g_free(media.artist); - g_free(str); + } msn_user_update(user); } diff -r c1f85543556d -r 463d8501e4e0 libpurple/protocols/msn/session.c --- a/libpurple/protocols/msn/session.c Thu Feb 12 06:06:40 2009 +0000 +++ b/libpurple/protocols/msn/session.c Wed Feb 18 03:27:04 2009 +0000 @@ -90,8 +90,10 @@ msn_userlist_destroy(session->userlist); g_free(session->psm); - + g_free(session->abch_cachekey); +#if 0 g_free(session->blocked_text); +#endif g_free(session->passport_info.kv); g_free(session->passport_info.sid); diff -r c1f85543556d -r 463d8501e4e0 libpurple/protocols/msn/session.h --- a/libpurple/protocols/msn/session.h Thu Feb 12 06:06:40 2009 +0000 +++ b/libpurple/protocols/msn/session.h Wed Feb 18 03:27:04 2009 +0000 @@ -94,11 +94,11 @@ gboolean http_method; MsnNotification *notification; - MsnNexus *nexus; - MsnOim *oim; - MsnSync *sync; - - MsnUserList *userlist; + MsnNexus *nexus; + MsnOim *oim; + MsnSync *sync; + MsnUserList *userlist; + char *abch_cachekey; int servconns_count; /**< The count of server connections. */ GList *switches; /**< The list of all the switchboards. */ @@ -107,7 +107,9 @@ /*psm info*/ char *psm; +#if 0 char *blocked_text; +#endif struct { diff -r c1f85543556d -r 463d8501e4e0 libpurple/protocols/oscar/family_icbm.c --- a/libpurple/protocols/oscar/family_icbm.c Thu Feb 12 06:06:40 2009 +0000 +++ b/libpurple/protocols/oscar/family_icbm.c Wed Feb 18 03:27:04 2009 +0000 @@ -1566,9 +1566,10 @@ static int incomingim_ch1(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, guint16 channel, aim_userinfo_t *userinfo, ByteStream *bs, guint8 *cookie) { - guint16 type, length; + guint16 type, length, magic1, msglen; aim_rxcallback_t userfunc; int ret = 0; + int rev = 0; struct aim_incomingim_ch1_args args; unsigned int endpos; @@ -1603,10 +1604,30 @@ * - 0101 -- Unknown * - Message * + * Slick and possible others reverse 'Features' and 'Messages' section. + * Thus, the TLV could have following layout: + * - 0101 -- Unknown (possibly magic for message section) + * - Message + * - 0501 -- Unknown (possibly magic for features section) + * - Features: Don't know how to interpret these */ - byte_stream_get8(bs); /* 05 */ - byte_stream_get8(bs); /* 01 */ + magic1 = byte_stream_get16(bs); /* 0501 or 0101 */ + if (magic1 == 0x101) /* Bad, message comes before attributes */ + { + /* Jump to the features section */ + msglen = byte_stream_get16(bs); + bs->offset += msglen; + rev = 1; + + magic1 = byte_stream_get16(bs); /* 0501 */ + } + + if (magic1 != 0x501) + { + purple_debug_misc("oscar", "Received an IM containing an invalid message part from %s. They are probably trying to do something malicious.\n", userinfo->sn); + break; + } args.featureslen = byte_stream_get16(bs); if (args.featureslen > byte_stream_empty(bs)) @@ -1624,11 +1645,25 @@ args.icbmflags |= AIM_IMFLAGS_CUSTOMFEATURES; } + if (rev) + { + /* Fix buffer back to message */ + bs->offset -= args.featureslen + 2 + 2 + msglen + 2 + 2; + } + + magic1 = byte_stream_get16(bs); /* 01 01 */ + if (magic1 != 0x101) /* Bad, message comes before attributes */ + { + purple_debug_misc("oscar", "Received an IM containing an invalid message part from %s. They are probably trying to do something malicious.\n", userinfo->sn); + break; + } + msglen = byte_stream_get16(bs); + /* * The rest of the TLV contains one or more message * blocks... */ - incomingim_ch1_parsemsgs(od, userinfo, bs->data + bs->offset /* XXX evil!!! */, length - 2 - 2 - args.featureslen, &args); + incomingim_ch1_parsemsgs(od, userinfo, bs->data + bs->offset - 2 - 2 /* XXX evil!!! */, msglen + 2 + 2, &args); } else if (type == 0x0003) { /* Server Ack Requested */ diff -r c1f85543556d -r 463d8501e4e0 libpurple/protocols/simple/simple.c --- a/libpurple/protocols/simple/simple.c Thu Feb 12 06:06:40 2009 +0000 +++ b/libpurple/protocols/simple/simple.c Wed Feb 18 03:27:04 2009 +0000 @@ -196,7 +196,7 @@ { struct simple_account_data *sip = (struct simple_account_data *)gc->proto_data; struct simple_buddy *b; - if(strcmp("sip:", buddy->name)) { + if(strncmp(buddy->name, "sip:", 4)) { gchar *buf = g_strdup_printf("sip:%s", buddy->name); purple_blist_rename_buddy(buddy, buf); g_free(buf); @@ -834,10 +834,10 @@ "Event: presence\r\n", expiration); - if(strstr(buddy->name, "sip:")) + if(strncmp(buddy->name, "sip:", 4)) + to = g_strdup_printf("sip:%s", buddy->name); + else to = g_strdup(buddy->name); - else - to = g_strdup_printf("sip:%s", buddy->name); tmp = get_contact(sip); contact = g_strdup_printf("%sContact: %s\r\n", tmp2, tmp); @@ -881,7 +881,7 @@ tmp = sipmsg_find_header(msg, "Event"); - if(tmp && !strcmp(tmp, "vnd-microsoft-roaming-contacts")){ + if(tmp && !strncmp(tmp, "vnd-microsoft-roaming-contacts", 30)){ purple_debug_info("simple", "simple_add_lcs_contacts->%s-%d\n", msg->body, len); /*Convert the contact from XML to Purple Buddies*/ @@ -1013,11 +1013,11 @@ static void simple_send_message(struct simple_account_data *sip, const char *to, const char *msg, const char *type) { gchar *hdr; gchar *fullto; - if(strcmp("sip:", to)) { + if(strncmp(to, "sip:", 4)) fullto = g_strdup_printf("sip:%s", to); - } else { + else fullto = g_strdup(to); - } + if(type) { hdr = g_strdup_printf("Content-Type: %s\r\n", type); } else { @@ -1050,12 +1050,12 @@ purple_debug(PURPLE_DEBUG_MISC, "simple", "got message from %s: %s\n", from, msg->body); contenttype = sipmsg_find_header(msg, "Content-Type"); - if(!contenttype || !strcmp(contenttype, "text/plain") || !strcmp(contenttype, "text/html")) { + if(!contenttype || !strncmp(contenttype, "text/plain", 10) || !strncmp(contenttype, "text/html", 9)) { serv_got_im(sip->gc, from, msg->body, 0, time(NULL)); send_sip_response(sip->gc, msg, 200, "OK", NULL); found = TRUE; } - else if(!strcmp(contenttype, "application/im-iscomposing+xml")) { + else if(!strncmp(contenttype, "application/im-iscomposing+xml", 30)) { xmlnode *isc = xmlnode_from_str(msg->body, msg->bodylen); xmlnode *state; gchar *statedata; diff -r c1f85543556d -r 463d8501e4e0 libpurple/proxy.c --- a/libpurple/proxy.c Thu Feb 12 06:06:40 2009 +0000 +++ b/libpurple/proxy.c Wed Feb 18 03:27:04 2009 +0000 @@ -1177,56 +1177,47 @@ } static void -s4_canwrite(gpointer data, gint source, PurpleInputCondition cond) +s4_host_resolved(GSList *hosts, gpointer data, const char *error_message) { - unsigned char packet[9]; - struct hostent *hp; PurpleProxyConnectData *connect_data = data; - int error = ETIMEDOUT; - int ret; - - purple_debug_info("socks4 proxy", "Connected.\n"); + unsigned char packet[9]; + struct sockaddr *addr; - if (connect_data->inpa > 0) - { - purple_input_remove(connect_data->inpa); - connect_data->inpa = 0; - } + connect_data->query_data = NULL; - ret = purple_input_get_error(connect_data->fd, &error); - if ((ret != 0) || (error != 0)) - { - if (ret != 0) - error = errno; - purple_proxy_connect_data_disconnect(connect_data, g_strerror(error)); + if (error_message != NULL) { + purple_proxy_connect_data_disconnect(connect_data, error_message); return; } - /* - * The socks4 spec doesn't include support for doing host name - * lookups by the proxy. Some socks4 servers do this via - * extensions to the protocol. Since we don't know if a - * server supports this, it would need to be implemented - * with an option, or some detection mechanism - in the - * meantime, stick with plain old SOCKS4. - */ - /* TODO: Use purple_dnsquery_a() */ - hp = gethostbyname(connect_data->host); - if (hp == NULL) { + if (hosts == NULL) { purple_proxy_connect_data_disconnect_formatted(connect_data, _("Error resolving %s"), connect_data->host); return; } - packet[0] = 4; - packet[1] = 1; + /* Discard the length... */ + hosts = g_slist_delete_link(hosts, hosts); + addr = hosts->data; + hosts = g_slist_delete_link(hosts, hosts); + + packet[0] = 0x04; + packet[1] = 0x01; packet[2] = connect_data->port >> 8; packet[3] = connect_data->port & 0xff; - packet[4] = (unsigned char)(hp->h_addr_list[0])[0]; - packet[5] = (unsigned char)(hp->h_addr_list[0])[1]; - packet[6] = (unsigned char)(hp->h_addr_list[0])[2]; - packet[7] = (unsigned char)(hp->h_addr_list[0])[3]; - packet[8] = 0; + memcpy(packet + 4, &((struct sockaddr_in *)addr)->sin_addr.s_addr, 4); + packet[8] = 0x00; + + g_free(addr); + + /* We could try the other hosts, but hopefully that shouldn't be necessary */ + while (hosts != NULL) { + /* Discard the length... */ + hosts = g_slist_delete_link(hosts, hosts); + /* Free the address... */ + g_free(hosts->data); + hosts = g_slist_delete_link(hosts, hosts); + } connect_data->write_buffer = g_memdup(packet, sizeof(packet)); connect_data->write_buf_len = sizeof(packet); @@ -1235,7 +1226,74 @@ connect_data->inpa = purple_input_add(connect_data->fd, PURPLE_INPUT_WRITE, proxy_do_write, connect_data); - proxy_do_write(connect_data, connect_data->fd, cond); + proxy_do_write(connect_data, connect_data->fd, PURPLE_INPUT_WRITE); +} + +static void +s4_canwrite(gpointer data, gint source, PurpleInputCondition cond) +{ + PurpleProxyConnectData *connect_data = data; + int error = ETIMEDOUT; + int ret; + + purple_debug_info("socks4 proxy", "Connected.\n"); + + if (connect_data->inpa > 0) { + purple_input_remove(connect_data->inpa); + connect_data->inpa = 0; + } + + ret = purple_input_get_error(connect_data->fd, &error); + if ((ret != 0) || (error != 0)) { + if (ret != 0) + error = errno; + purple_proxy_connect_data_disconnect(connect_data, g_strerror(error)); + return; + } + + /* + * The socks4 spec doesn't include support for doing host name lookups by + * the proxy. Many socks4 servers do this via the "socks4a" extension to + * the protocol. There doesn't appear to be a way to detect if a server + * supports this, so we require that the user set a global option. + */ + if (purple_prefs_get_bool("/purple/proxy/socks4_remotedns")) { + unsigned char packet[9]; + int len; + + purple_debug_info("socks4 proxy", "Attempting to use remote DNS.\n"); + + packet[0] = 0x04; + packet[1] = 0x01; + packet[2] = connect_data->port >> 8; + packet[3] = connect_data->port & 0xff; + packet[4] = 0x00; + packet[5] = 0x00; + packet[6] = 0x00; + packet[7] = 0x01; + packet[8] = 0x00; + + len = sizeof(packet) + strlen(connect_data->host) + 1; + + connect_data->write_buffer = g_malloc0(len); + memcpy(connect_data->write_buffer, packet, sizeof(packet)); + memcpy(connect_data->write_buffer + sizeof(packet), connect_data->host, strlen(connect_data->host)); + connect_data->write_buf_len = len; + connect_data->written_len = 0; + connect_data->read_cb = s4_canread; + + connect_data->inpa = purple_input_add(connect_data->fd, PURPLE_INPUT_WRITE, proxy_do_write, connect_data); + + proxy_do_write(connect_data, connect_data->fd, PURPLE_INPUT_WRITE); + } else { + connect_data->query_data = purple_dnsquery_a(connect_data->host, + connect_data->port, s4_host_resolved, connect_data); + + if (connect_data->query_data == NULL) { + purple_debug_error("proxy", "dns query failed unexpectedly.\n"); + purple_proxy_connect_data_destroy(connect_data); + } + } } static void @@ -1396,7 +1454,7 @@ s5_sendconnect(gpointer data, int source) { PurpleProxyConnectData *connect_data = data; - int hlen = strlen(connect_data->host); + size_t hlen = strlen(connect_data->host); connect_data->write_buf_len = 5 + hlen + 2; connect_data->write_buffer = g_malloc(connect_data->write_buf_len); connect_data->written_len = 0; @@ -1479,7 +1537,7 @@ int i; unsigned char Kxoripad[65]; unsigned char Kxoropad[65]; - int pwlen; + size_t pwlen; cipher = purple_ciphers_find_cipher("md5"); ctx = purple_cipher_context_new(cipher, NULL); @@ -1697,7 +1755,7 @@ return; msg_ret = s5_parse_chap_msg(connect_data); - + if (msg_ret < 0) return; @@ -1777,7 +1835,7 @@ } if (connect_data->read_buffer[1] == 0x02) { - gsize i, j; + size_t i, j; const char *u, *p; u = purple_proxy_info_get_username(connect_data->gpi); @@ -1810,7 +1868,7 @@ return; } else if (connect_data->read_buffer[1] == 0x03) { - gsize userlen; + size_t userlen; userlen = strlen(purple_proxy_info_get_username(connect_data->gpi)); connect_data->write_buf_len = 7 + userlen; @@ -1957,7 +2015,7 @@ static void try_connect(PurpleProxyConnectData *connect_data) { - size_t addrlen; + socklen_t addrlen; struct sockaddr *addr; char ipaddr[INET6_ADDRSTRLEN]; @@ -1969,7 +2027,7 @@ inet_ntop(addr->sa_family, &((struct sockaddr_in *)addr)->sin_addr, ipaddr, sizeof(ipaddr)); #else - memcpy(ipaddr,inet_ntoa(((struct sockaddr_in *)addr)->sin_addr), + memcpy(ipaddr, inet_ntoa(((struct sockaddr_in *)addr)->sin_addr), sizeof(ipaddr)); #endif purple_debug_info("proxy", "Attempting connection to %s\n", ipaddr); @@ -2293,6 +2351,7 @@ purple_prefs_add_int("/purple/proxy/port", 0); purple_prefs_add_string("/purple/proxy/username", ""); purple_prefs_add_string("/purple/proxy/password", ""); + purple_prefs_add_bool("/purple/proxy/socks4_remotedns", FALSE); /* Setup callbacks for the preferences. */ handle = purple_proxy_get_handle(); diff -r c1f85543556d -r 463d8501e4e0 libpurple/savedstatuses.c --- a/libpurple/savedstatuses.c Thu Feb 12 06:06:40 2009 +0000 +++ b/libpurple/savedstatuses.c Wed Feb 18 03:27:04 2009 +0000 @@ -148,11 +148,11 @@ /* Avoid using 0 because it's an invalid hash key */ status->creation_time = creation_time != 0 ? creation_time : 1; - while (g_hash_table_lookup(creation_times, &status->creation_time) != NULL) + while (g_hash_table_lookup(creation_times, (gconstpointer)status->creation_time) != NULL) status->creation_time++; g_hash_table_insert(creation_times, - &status->creation_time, + (gpointer)status->creation_time, status); } @@ -217,7 +217,7 @@ { saved_statuses = g_list_remove(saved_statuses, saved_status); creation_time = purple_savedstatus_get_creation_time(saved_status); - g_hash_table_remove(creation_times, &creation_time); + g_hash_table_remove(creation_times, (gconstpointer)creation_time); free_saved_status(saved_status); } } @@ -713,7 +713,7 @@ saved_statuses = g_list_remove(saved_statuses, status); creation_time = purple_savedstatus_get_creation_time(status); - g_hash_table_remove(creation_times, &creation_time); + g_hash_table_remove(creation_times, (gconstpointer)creation_time); free_saved_status(status); schedule_save(); @@ -801,13 +801,13 @@ PurpleSavedStatus * purple_savedstatus_get_default() { - int creation_time; + time_t creation_time; PurpleSavedStatus *saved_status = NULL; creation_time = purple_prefs_get_int("/purple/savedstatus/default"); if (creation_time != 0) - saved_status = g_hash_table_lookup(creation_times, &creation_time); + saved_status = g_hash_table_lookup(creation_times, (gconstpointer)creation_time); if (saved_status == NULL) { @@ -828,13 +828,13 @@ PurpleSavedStatus * purple_savedstatus_get_idleaway() { - int creation_time; + time_t creation_time; PurpleSavedStatus *saved_status = NULL; creation_time = purple_prefs_get_int("/purple/savedstatus/idleaway"); if (creation_time != 0) - saved_status = g_hash_table_lookup(creation_times, &creation_time); + saved_status = g_hash_table_lookup(creation_times, (gconstpointer)creation_time); if (saved_status == NULL) { @@ -907,13 +907,13 @@ PurpleSavedStatus * purple_savedstatus_get_startup() { - int creation_time; + time_t creation_time; PurpleSavedStatus *saved_status = NULL; creation_time = purple_prefs_get_int("/purple/savedstatus/startup"); if (creation_time != 0) - saved_status = g_hash_table_lookup(creation_times, &creation_time); + saved_status = g_hash_table_lookup(creation_times, (gconstpointer)creation_time); if (saved_status == NULL) { @@ -1187,7 +1187,7 @@ { void *handle = purple_savedstatuses_get_handle(); - creation_times = g_hash_table_new(g_int_hash, g_int_equal); + creation_times = g_hash_table_new(g_direct_hash, g_direct_equal); /* * Using 0 as the creation_time is a special case. diff -r c1f85543556d -r 463d8501e4e0 pidgin/gtkblist.c --- a/pidgin/gtkblist.c Thu Feb 12 06:06:40 2009 +0000 +++ b/pidgin/gtkblist.c Wed Feb 18 03:27:04 2009 +0000 @@ -66,7 +66,7 @@ #include #include -#define HEADLINE_CLOSE_SIZE 12 +#define HEADLINE_CLOSE_SIZE 11 typedef struct { @@ -4554,6 +4554,9 @@ if (!gtkblist) return FALSE; + /* clear any tooltips */ + pidgin_blist_tooltip_destroy(); + widget = gtk_window_get_focus(GTK_WINDOW(gtkblist->window)); if (GTK_IS_IMHTML(widget) || GTK_IS_ENTRY(widget)) { @@ -5387,7 +5390,8 @@ NULL); gtk_widget_set_name(gtkblist->headline_hbox, "gtk-tooltips"); - gtkblist->headline_close = gtk_widget_render_icon(ebox, GTK_STOCK_CLOSE, HEADLINE_CLOSE_SIZE, NULL); + gtkblist->headline_close = gtk_widget_render_icon(ebox, GTK_STOCK_CLOSE, + gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_MICROSCOPIC), NULL); gtkblist->hand_cursor = gdk_cursor_new (GDK_HAND2); gtkblist->arrow_cursor = gdk_cursor_new (GDK_LEFT_PTR); diff -r c1f85543556d -r 463d8501e4e0 pidgin/gtkconv.c --- a/pidgin/gtkconv.c Thu Feb 12 06:06:40 2009 +0000 +++ b/pidgin/gtkconv.c Wed Feb 18 03:27:04 2009 +0000 @@ -1959,6 +1959,9 @@ win = gtkconv->win; curconv = gtk_notebook_get_current_page(GTK_NOTEBOOK(win->notebook)); + /* clear any tooltips */ + pidgin_tooltip_destroy(); + /* If CTRL was held down... */ if (event->state & GDK_CONTROL_MASK) { switch (event->keyval) { diff -r c1f85543556d -r 463d8501e4e0 pidgin/gtkdialogs.c --- a/pidgin/gtkdialogs.c Thu Feb 12 06:06:40 2009 +0000 +++ b/pidgin/gtkdialogs.c Wed Feb 18 03:27:04 2009 +0000 @@ -457,12 +457,17 @@ "warranty for this program.

"), PIDGIN_NAME, PIDGIN_NAME, PIDGIN_NAME); g_string_append(str, "URL: " PURPLE_WEBSITE "

"); - g_string_append(str, "FAQ: " - "http://developer.pidgin.im/wiki/FAQ

"); - g_string_append_printf(str, _("IRC: " - "#pidgin on irc.freenode.net

")); + PURPLE_WEBSITE "\">" PURPLE_WEBSITE "

"); + g_string_append_printf(str, _("FAQ: " + "http://developer.pidgin.im/wiki/FAQ

")); + g_string_append_printf(str, _("Help via e-mail:" + " support@pidgin.im" + "

")); + g_string_append_printf(str, _("IRC Channel: " + "#pidgin on irc.freenode.net

")); + g_string_append_printf(str, _("XMPP MUC: " + "devel@conference.pidgin.im

")); /* Current Developers */ g_string_append_printf(str, "%s:
", diff -r c1f85543556d -r 463d8501e4e0 pidgin/gtkprefs.c --- a/pidgin/gtkprefs.c Thu Feb 12 06:06:40 2009 +0000 +++ b/pidgin/gtkprefs.c Wed Feb 18 03:27:04 2009 +0000 @@ -1342,6 +1342,10 @@ purple_prefs_connect_callback(prefs, "/purple/proxy/type", proxy_changed_cb, prefs_proxy_frame); + /* This is a global option that affects SOCKS4 usage even with account-specific proxy settings */ + pidgin_prefs_checkbox(_("Use remote DNS with SOCKS4 proxies"), + "/purple/proxy/socks4_remotedns", prefs_proxy_frame); + table = gtk_table_new(4, 2, FALSE); gtk_container_set_border_width(GTK_CONTAINER(table), 0); gtk_table_set_col_spacings(GTK_TABLE(table), 5); diff -r c1f85543556d -r 463d8501e4e0 pidgin/pidgintooltip.c --- a/pidgin/pidgintooltip.c Thu Feb 12 06:06:40 2009 +0000 +++ b/pidgin/pidgintooltip.c Wed Feb 18 03:27:04 2009 +0000 @@ -135,14 +135,14 @@ setup_tooltip_window_position(gpointer data, int w, int h) { int sig; - int scr_w, scr_h, x, y; + int scr_w, scr_h, x, y, dy; #if GTK_CHECK_VERSION(2,2,0) int mon_num; GdkScreen *screen = NULL; #endif GdkRectangle mon_size; GtkWidget *tipwindow = pidgin_tooltip.tipwindow; - + #if GTK_CHECK_VERSION(2,2,0) gdk_display_get_pointer(gdk_display_get_default(), &screen, &x, &y, NULL); mon_num = gdk_screen_get_monitor_at_point(screen, x, y); @@ -158,6 +158,12 @@ mon_size.y = 0; #endif +#if GTK_CHECK_VERSION(2,4,0) + dy = gdk_display_get_default_cursor_size(gdk_display_get_default()) / 2; +#else + dy = 0; +#endif + #if GTK_CHECK_VERSION(2,2,0) if (w > mon_size.width) w = mon_size.width - 10; @@ -168,9 +174,9 @@ x -= ((w >> 1) + 4); if ((y + h + 4) > scr_h) - y = y - h - 5; + y = y - h - dy - 5; else - y = y + 6; + y = y + dy + 6; if (y < mon_size.y) y = mon_size.y; @@ -353,6 +359,7 @@ g_signal_connect(G_OBJECT(tree), "motion-notify-event", G_CALLBACK(row_motion_cb), tdata); g_signal_connect(G_OBJECT(tree), "leave-notify-event", G_CALLBACK(widget_leave_cb), NULL); + g_signal_connect(G_OBJECT(tree), "scroll-event", G_CALLBACK(widget_leave_cb), NULL); g_signal_connect_swapped(G_OBJECT(tree), "destroy", G_CALLBACK(destroy_tooltip_data), tdata); return TRUE; } @@ -381,6 +388,7 @@ g_signal_connect(G_OBJECT(widget), "motion-notify-event", G_CALLBACK(widget_motion_cb), wdata); g_signal_connect(G_OBJECT(widget), "leave-notify-event", G_CALLBACK(widget_leave_cb), NULL); + g_signal_connect(G_OBJECT(widget), "scroll-event", G_CALLBACK(widget_leave_cb), NULL); g_signal_connect_swapped(G_OBJECT(widget), "destroy", G_CALLBACK(destroy_tooltip_data), wdata); return TRUE; }