Mercurial > pidgin.yaz
changeset 27959:fd3869a9337b
propagate from branch 'im.pidgin.pidgin' (head 8c1fa13e01e278e3a2c91c7c595ff091b87f0c3c)
to branch 'im.pidgin.pidgin.yaz' (head a4c69669e1b622aaf72d11d169f8f8503d0b00b3)
author | Yoshiki Yazawa <yaz@honeyplanet.jp> |
---|---|
date | Wed, 01 Jul 2009 04:12:32 +0000 |
parents | 40a670f599ae (diff) 518b4a900f19 (current diff) |
children | f058edca3d66 |
files | libpurple/protocols/yahoo/yahoo.c libpurple/util.c |
diffstat | 9 files changed, 279 insertions(+), 95 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog Mon Jun 29 06:24:37 2009 +0000 +++ b/ChangeLog Wed Jul 01 04:12:32 2009 +0000 @@ -18,6 +18,8 @@ from you on MSN. * DNS servers are re-read when DNS queries fail in case the system has moved to a new network and the old servers are not accessible. + * DNS SRV records with equal priority are sorted with respect to their + weight as specified in RFC 2782. (Vijay Raghunathan) * GnuTLS logging (disabled by default) can be controlled through the PURPLE_GNUTLS_DEBUG environment variable, which is an integer between 0 and 9 (higher is more verbose). Higher values may reveal sensitive @@ -75,6 +77,7 @@ (Sulabh Mahajan) * Addition of MSN buddies to Yahoo accounts by adding them as 'msn/buddy@somedomain.com' is now supported. (Sulabh Mahajan) + * Further fixes for buddy pictures, aliases etc. Pidgin: * Added -f command line option to tell Pidgin to ignore NetworkManager
--- a/libpurple/dnssrv.c Mon Jun 29 06:24:37 2009 +0000 +++ b/libpurple/dnssrv.c Wed Jul 01 04:12:32 2009 +0000 @@ -94,6 +94,17 @@ char query[256]; } PurpleSrvInternalQuery; +typedef struct _PurpleSrvResponseContainer { + PurpleSrvResponse *response; + int sum; +} PurpleSrvResponseContainer; + +/** + * Sort by priority, then by weight. Strictly numerically--no + * randomness. Technically we only need to sort by pref and then + * make sure any records with weight 0 are at the beginning of + * their group, but it's just as easy to sort by weight. + */ static gint responsecompare(gconstpointer ar, gconstpointer br) { @@ -112,6 +123,129 @@ return 1; } +/** + * Iterate over a list of PurpleSrvResponseContainer making the sum + * the running total of the sums. Select a random integer in the range + * (1, sum+1), then find the first element greater than or equal to the + * number selected. From RFC 2782. + * + * @param list The list of PurpleSrvResponseContainer. This function + * removes a node from this list and returns the new list. + * @param container_ptr The PurpleSrvResponseContainer that was chosen + * will be returned here. + */ +static GList *select_random_response(GList *list, + PurpleSrvResponseContainer **container_ptr) +{ + GList *cur; + size_t runningtotal; + int r; + + runningtotal = 0; + cur = list; + + while (cur) { + PurpleSrvResponseContainer *container = cur->data; + runningtotal += container->response->weight; + container->sum = runningtotal; + cur = cur->next; + } + + /* + * If the running total is greater than 0, pick a number between + * 1 and the runningtotal inclusive. (This is not precisely what + * the RFC algorithm describes, but we wish to deal with integers + * and avoid floats. This is functionally equivalent.) + * If running total is 0, then choose r = 0. + */ + r = runningtotal ? g_random_int_range(1, runningtotal + 1) : 0; + cur = list; + while (r > ((PurpleSrvResponseContainer *)cur->data)->sum) { + cur = cur->next; + } + + /* Set the return parameter and remove cur from the list */ + *container_ptr = cur->data; + return g_list_delete_link(list, cur); +} + +/** + * Reorder a GList of PurpleSrvResponses that have the same priority + * (aka "pref"). + */ +static void srv_reorder(GList *list, int num) +{ + int i; + GList *cur; + GList *container_list = NULL; + PurpleSrvResponseContainer *container; + + if (num < 2) + /* Nothing to sort */ + return; + + /* First build a list of container structs */ + for (i = 0, cur = list; i < num; i++, cur = cur->next) { + container = g_new(PurpleSrvResponseContainer, 1); + container->response = cur->data; + container_list = g_list_prepend(container_list, container); + } + container_list = g_list_reverse(container_list); + + /* + * Re-order the list that was passed in as a parameter. We leave + * the list nodes in place, but replace their data pointers. + */ + cur = list; + while (container_list) { + container_list = select_random_response(container_list, &container); + cur->data = container->response; + g_free(container); + cur = cur->next; + } +} + +/** + * Sorts a GList of PurpleSrvResponse's according to the + * algorithm described in RFC 2782. + * + * @param response GList of PurpleSrvResponse's + * @param The original list, resorted + */ +static GList *purple_srv_sort(GList *list) +{ + GList *cur, *start; + int count; + int pref; + + if (!list || !list->next) + /* Nothing to sort */ + return list; + + list = g_list_sort(list, responsecompare); + + start = cur = list; + count = 1; + while (cur) { + PurpleSrvResponse *next_response; + pref = ((PurpleSrvResponse *)cur->data)->pref; + next_response = cur->next ? cur->next->data : NULL; + if (!next_response || next_response->pref != pref) { + /* + * The 'count' records starting at 'start' all have the same + * priority. Sort them by weight. + */ + srv_reorder(start, count); + start = cur->next; + count = 0; + } + count++; + cur = cur->next; + } + + return list; +} + #ifndef _WIN32 G_GNUC_NORETURN static void @@ -191,7 +325,7 @@ srvres->port = port; srvres->weight = weight; - ret = g_list_insert_sorted(ret, srvres, responsecompare); + ret = g_list_prepend(ret, srvres); } else if (query.type == T_TXT) { txtres = g_new0(PurpleTxtResponse, 1); txtres->content = g_strndup((gchar*)(++cp), dlen-1); @@ -204,6 +338,10 @@ end: size = g_list_length(ret); + + if (query.type == T_SRV) + ret = purple_srv_sort(ret); + /* TODO: Check return value */ write(out, &(query.type), sizeof(query.type)); write(out, &size, sizeof(size)); @@ -397,11 +535,11 @@ srvres->port = srv_data->wPort; srvres->weight = srv_data->wWeight; - lst = g_slist_insert_sorted(lst, srvres, responsecompare); + lst = g_slist_prepend(lst, srvres); } MyDnsRecordListFree(dr, DnsFreeRecordList); - query_data->results = lst; + query_data->results = purple_srv_sort(lst); } else if (type == DNS_TYPE_TXT) { PDNS_RECORD dr_tmp; GSList *lst = NULL;
--- a/libpurple/dnssrv.h Mon Jun 29 06:24:37 2009 +0000 +++ b/libpurple/dnssrv.h Wed Jul 01 04:12:32 2009 +0000 @@ -41,6 +41,12 @@ int pref; }; +/** + * @param resp An array of PurpleSrvResponse of size results. The array + * is sorted based on the order described in the DNS SRV RFC. + * Users of this API should try each record in resp in order, + * starting at the beginning. + */ typedef void (*PurpleSrvCallback)(PurpleSrvResponse *resp, int results, gpointer data); /**
--- a/libpurple/protocols/yahoo/yahoo.c Mon Jun 29 06:24:37 2009 +0000 +++ b/libpurple/protocols/yahoo/yahoo.c Wed Jul 01 04:12:32 2009 +0000 @@ -1689,11 +1689,11 @@ #else while (split_data[++totalelements] != NULL); #endif - if (totalelements >= 5) { - response_no = strtol(split_data[1], NULL, 10); - crumb = g_strdup(split_data[2] + strlen("crumb=")); - yd->cookie_y = g_strdup(split_data[3] + strlen("Y=")); - yd->cookie_t = g_strdup(split_data[4] + strlen("T=")); + if (totalelements >= 4) { + response_no = strtol(split_data[0], NULL, 10); + crumb = g_strdup(split_data[1] + strlen("crumb=")); + yd->cookie_y = g_strdup(split_data[2] + strlen("Y=")); + yd->cookie_t = g_strdup(split_data[3] + strlen("T=")); } g_strfreev(split_data); @@ -1775,9 +1775,9 @@ #else while (split_data[++totalelements] != NULL); #endif - if(totalelements >= 5) { - response_no = strtol(split_data[1], NULL, 10); - token = g_strdup(split_data[2] + strlen("ymsgr=")); + if(totalelements >= 2) { + response_no = strtol(split_data[0], NULL, 10); + token = g_strdup(split_data[1] + strlen("ymsgr=")); } g_strfreev(split_data); @@ -2164,6 +2164,7 @@ } else /* we are already connected. set friend to YAHOO_P2PSTATUS_WE_ARE_CLIENT */ yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_WE_ARE_CLIENT); + g_free(who); return; } @@ -2882,15 +2883,13 @@ case YAHOO_SERVICE_PICTURE: yahoo_process_picture(gc, pkt); break; - case YAHOO_SERVICE_PICTURE_UPDATE: - yahoo_process_picture_update(gc, pkt); - break; case YAHOO_SERVICE_PICTURE_CHECKSUM: yahoo_process_picture_checksum(gc, pkt); break; case YAHOO_SERVICE_PICTURE_UPLOAD: yahoo_process_picture_upload(gc, pkt); break; + case YAHOO_SERVICE_PICTURE_UPDATE: case YAHOO_SERVICE_AVATAR_UPDATE: yahoo_process_avatar_update(gc, pkt); break; @@ -4227,7 +4226,7 @@ } } - msn = g_str_has_prefix(who, "msn/") || g_str_has_prefix(who, "MSN/"); + msn = !g_strncasecmp(who, "msn/", 4); if( strncmp(who, "+", 1) == 0 ) { /* we have an sms to be sent */ @@ -4351,7 +4350,7 @@ { struct yahoo_data *yd = gc->proto_data; struct yahoo_p2p_data *p2p_data; - gboolean msn = (g_str_has_prefix(who, "msn/") || g_str_has_prefix(who, "MSN/")); + gboolean msn = !g_strncasecmp(who, "msn/", 4); struct yahoo_packet *pkt = NULL; /* Don't do anything if sms is being typed */ @@ -4625,7 +4624,7 @@ return; f = yahoo_friend_find(gc, bname); - msn = g_str_has_prefix(bname, "msn/") || g_str_has_prefix(bname, "MSN/"); + msn = !g_strncasecmp(bname, "msn/", 4); g = purple_buddy_get_group(buddy); if (g)
--- a/libpurple/protocols/yahoo/yahoo_picture.c Mon Jun 29 06:24:37 2009 +0000 +++ b/libpurple/protocols/yahoo/yahoo_picture.c Wed Jul 01 04:12:32 2009 +0000 @@ -153,45 +153,6 @@ } } -void yahoo_process_picture_update(PurpleConnection *gc, struct yahoo_packet *pkt) -{ - GSList *l = pkt->hash; - char *who = NULL; - int icon = 0; - - while (l) { - struct yahoo_pair *pair = l->data; - - switch (pair->key) { - case 4: - who = pair->value; - break; - case 5: - /* us */ - break; - /* NOTE: currently the server seems to only send 213; 206 was used - * in older versions. Check whether it's still needed. */ - case 206: - case 213: - icon = strtol(pair->value, NULL, 10); - break; - } - l = l->next; - } - - if (who) { - if (icon == 2) - yahoo_send_picture_request(gc, who); - else if ((icon == 0) || (icon == 1)) { - YahooFriend *f; - purple_buddy_icons_set_for_user(gc->account, who, NULL, 0, NULL); - if ((f = yahoo_friend_find(gc, who))) - yahoo_friend_set_buddy_icon_need_request(f, TRUE); - purple_debug_misc("yahoo", "Setting user %s's icon to NULL.\n", who); - } - } -} - void yahoo_process_picture_checksum(PurpleConnection *gc, struct yahoo_packet *pkt) { GSList *l = pkt->hash; @@ -279,7 +240,8 @@ case 5: /* us */ break; - case 206: + case 206: /* Older versions. Still needed? */ + case 213: /* Newer versions */ /* * 0 - No icon or avatar * 1 - Using an avatar @@ -349,8 +311,8 @@ struct yahoo_data *yd = gc->proto_data; struct yahoo_packet *pkt; - pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE_UPDATE, YAHOO_STATUS_AVAILABLE, 0); - yahoo_packet_hash(pkt, "ssi", 1, purple_connection_get_display_name(gc), 5, who, 206, type); + pkt = yahoo_packet_new(YAHOO_SERVICE_AVATAR_UPDATE, YAHOO_STATUS_AVAILABLE, 0); + yahoo_packet_hash(pkt, "si", 3, who, 213, type); yahoo_packet_send_and_free(pkt, yd); }
--- a/libpurple/protocols/yahoo/yahoo_picture.h Mon Jun 29 06:24:37 2009 +0000 +++ b/libpurple/protocols/yahoo/yahoo_picture.h Wed Jul 01 04:12:32 2009 +0000 @@ -31,7 +31,6 @@ void yahoo_send_picture_update_to_user(PurpleConnection *gc, const char *who, int type); void yahoo_process_picture(PurpleConnection *gc, struct yahoo_packet *pkt); -void yahoo_process_picture_update(PurpleConnection *gc, struct yahoo_packet *pkt); void yahoo_process_picture_checksum(PurpleConnection *gc, struct yahoo_packet *pkt); void yahoo_process_picture_upload(PurpleConnection *gc, struct yahoo_packet *pkt);
--- a/libpurple/util.c Mon Jun 29 06:24:37 2009 +0000 +++ b/libpurple/util.c Wed Jul 01 04:12:32 2009 +0000 @@ -68,6 +68,7 @@ unsigned long len; unsigned long data_len; gssize max_len; + gboolean chunked; }; static char *custom_user_dir = NULL; @@ -219,6 +220,9 @@ gchar * purple_base64_encode(const guchar *data, gsize len) { +#if GLIB_CHECK_VERSION(2,12,0) + return g_base64_encode(data, len); +#else char *out, *rv; g_return_val_if_fail(data != NULL, NULL); @@ -253,11 +257,21 @@ *out = '\0'; return rv; +#endif /* GLIB < 2.12.0 */ } guchar * purple_base64_decode(const char *str, gsize *ret_len) { +#if GLIB_CHECK_VERSION(2,12,0) + /* + * We want to allow ret_len to be NULL for backward compatibility, + * but g_base64_decode() requires a valid length variable. So if + * ret_len is NULL then pass in a dummy variable. + */ + gsize unused; + return g_base64_decode(str, ret_len != NULL ? ret_len : &unused); +#else guchar *out = NULL; char tmp = 0; const char *c; @@ -319,6 +333,7 @@ *ret_len = len; return out; +#endif /* GLIB < 2.12.0 */ } /************************************************************************** @@ -3757,41 +3772,43 @@ return TRUE; } +static const char * +find_header_content(const char *data, size_t data_len, const char *header, size_t header_len) +{ + const char *p = NULL; + + if (header_len <= 0) + header_len = strlen(header); + + /* Note: data is _not_ nul-terminated. */ + if (data_len > header_len) { + if (header[0] == '\n') + p = (g_strncasecmp(data, header + 1, header_len - 1) == 0) ? data : NULL; + if (!p) + p = purple_strcasestr(data, header); + if (p) + p += header_len; + } + + /* If we can find the header at all, try to sscanf it. + * Response headers should end with at least \r\n, so sscanf is safe, + * if we make sure that there is indeed a \n in our header. + */ + if (p && g_strstr_len(p, data_len - (p - data), "\n")) { + return p; + } + + return NULL; +} + static size_t parse_content_len(const char *data, size_t data_len) { size_t content_len = 0; const char *p = NULL; - /* This is still technically wrong, since headers are case-insensitive - * [RFC 2616, section 4.2], though this ought to catch the normal case. - * Note: data is _not_ nul-terminated. - */ - if(data_len > 16) { - p = (strncmp(data, "Content-Length: ", 16) == 0) ? data : NULL; - if(!p) - p = (strncmp(data, "CONTENT-LENGTH: ", 16) == 0) - ? data : NULL; - if(!p) { - p = g_strstr_len(data, data_len, "\nContent-Length: "); - if (p) - p++; - } - if(!p) { - p = g_strstr_len(data, data_len, "\nCONTENT-LENGTH: "); - if (p) - p++; - } - - if(p) - p += 16; - } - - /* If we can find a Content-Length header at all, try to sscanf it. - * Response headers should end with at least \r\n, so sscanf is safe, - * if we make sure that there is indeed a \n in our header. - */ - if (p && g_strstr_len(p, data_len - (p - data), "\n")) { + p = find_header_content(data, data_len, "\nContent-Length: ", sizeof("\nContent-Length: ") - 1); + if (p) { sscanf(p, "%" G_GSIZE_FORMAT, &content_len); purple_debug_misc("util", "parsed %" G_GSIZE_FORMAT "\n", content_len); } @@ -3799,6 +3816,49 @@ return content_len; } +static gboolean +content_is_chunked(const char *data, size_t data_len) +{ + gboolean chunked = FALSE; + const char *p = find_header_content(data, data_len, "\nTransfer-Encoding: ", sizeof("\nTransfer-Encoding: ") - 1); + if (p && g_strncasecmp(p, "chunked", 7) == 0) + chunked = TRUE; + + return chunked; +} + +/* Process in-place */ +static void +process_chunked_data(char *data, gssize *len) +{ + gssize sz; + gssize nlen = 0; + char *p = data; + char *s = data; + + while (*s) { + if (sscanf(s, "%x\r\n", &sz) != 1) { + purple_debug_error("util", "Error processing chunked data. Expected data length, found: %s\n", s); + break; + } + if (sz == 0) + break; + s = strstr(s, "\r\n") + 2; + g_memmove(p, s, sz); + p += sz; + s += sz; + nlen += sz; + if (*s != '\r' && *(s + 1) != '\n') { + purple_debug_error("util", "Error processing chunked data. Expected \\r\\n, found: %s\n", s); + break; + } + s += 2; + } + *p = 0; + + if (len) + *len = nlen; +} static void url_fetch_recv_cb(gpointer url_data, gint source, PurpleInputCondition cond) @@ -3859,6 +3919,7 @@ /* No redirect. See if we can find a content length. */ content_len = parse_content_len(gfud->webdata, header_len); + gfud->chunked = content_is_chunked(gfud->webdata, header_len); if(content_len == 0) { /* We'll stick with an initial 8192 */ @@ -3931,6 +3992,11 @@ gfud->webdata = g_realloc(gfud->webdata, gfud->len + 1); gfud->webdata[gfud->len] = '\0'; + if (!gfud->include_headers && gfud->chunked) { + /* Process only if we don't want the headers. */ + process_chunked_data(gfud->webdata, &gfud->len); + } + gfud->callback(gfud, gfud->user_data, gfud->webdata, gfud->len, NULL); purple_util_fetch_url_cancel(gfud); }
--- a/pidgin/gtkblist-theme-loader.c Mon Jun 29 06:24:37 2009 +0000 +++ b/pidgin/gtkblist-theme-loader.c Wed Jul 01 04:12:32 2009 +0000 @@ -20,6 +20,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ +#include "internal.h" + #include <stdlib.h> #include <string.h>
--- a/po/ca.po Mon Jun 29 06:24:37 2009 +0000 +++ b/po/ca.po Wed Jul 01 04:12:32 2009 +0000 @@ -33,8 +33,8 @@ msgstr "" "Project-Id-Version: Pidgin\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-06-25 21:33+0200\n" -"PO-Revision-Date: 2009-06-25 21:44+0200\n" +"POT-Creation-Date: 2009-06-29 08:35+0200\n" +"PO-Revision-Date: 2009-06-29 08:37+0200\n" "Last-Translator: Josep Puigdemont i Casamajó <josep.puigdemont@gmail.com>\n" "Language-Team: Catalan <tradgnome@softcatala.net>\n" "MIME-Version: 1.0\n" @@ -9784,8 +9784,8 @@ msgid "Start Doodling" msgstr "Comença a dibuixar" -msgid "Activate which ID?" -msgstr "Quin ID voleu activar?" +msgid "Select the ID you want to activate" +msgstr "Seleccioneu l'ID que vulgueu activar" msgid "Join whom in chat?" msgstr "A qui us voleu unir al xat?" @@ -12631,8 +12631,14 @@ msgid "Unknown.... Please report this!" msgstr "Esdeveniment d'avís desconegut, informeu-nos-en." -msgid "Smiley theme failed to unpack." -msgstr "No s'ha pogut desempaquetar el tema d'emoticones." +msgid "Theme failed to unpack." +msgstr "No s'ha pogut desempaquetar el tema." + +msgid "Theme failed to load." +msgstr "No s'ha pogut carregar el tema." + +msgid "Theme failed to copy." +msgstr "No s'ha pogut copiar el tema." msgid "Install Theme" msgstr "Instal·la el tema" @@ -14345,6 +14351,9 @@ msgid "This plugin is useful for debbuging XMPP servers or clients." msgstr "Aquest connector és útil per a depurar servidors i clients XMPP." +#~ msgid "Activate which ID?" +#~ msgstr "Quin ID voleu activar?" + #~ msgid "Account locked: Too many failed login attempts" #~ msgstr "S'ha blocat el compte: s'ha intentat entrar massa vegades"