# HG changeset patch # User Etan Reisner # Date 1204680263 0 # Node ID deb07e7d8679fb9dda4cd094f7321a5233537905 # Parent 86c18b2a16cc08daaf369621c0907f87bc847008# Parent 0c098ebe9f16e682a32e8cc7d5910665c78d7d85 merge of '43597c046102d28beb11884ac70e89943a1b1466' and 'cce3a22f53972bd3834175b08ad5e7b800bf98e9' diff -r 86c18b2a16cc -r deb07e7d8679 doc/pidgin.1.in --- a/doc/pidgin.1.in Tue Mar 04 02:48:30 2008 +0000 +++ b/doc/pidgin.1.in Wed Mar 05 01:24:23 2008 +0000 @@ -57,9 +57,9 @@ \fBOffline\fR. .TP .B \-l, \-\-login[=\fINAME\fR,\fINAME\fR,...] -Sign in the comma-separated list of accounts provided, in addition to the -accounts that would be logged in anyway. If the user does not specify such a -comma-separated list, the first account in accounts.xml will be signed in. +Enable the comma-separated list of accounts provided, disabling all other +accounts. If the user does not specify such a comma-separated list, the +first account in accounts.xml will be enabled. .TP .B \-v, \-\-version Print the current version and exit. diff -r 86c18b2a16cc -r deb07e7d8679 libpurple/buddyicon.c --- a/libpurple/buddyicon.c Tue Mar 04 02:48:30 2008 +0000 +++ b/libpurple/buddyicon.c Wed Mar 05 01:24:23 2008 +0000 @@ -121,13 +121,8 @@ } } - if (!g_file_test(path, G_FILE_TEST_EXISTS)) { - purple_util_write_data_to_file_absolute(path, purple_imgstore_get_data(img), - purple_imgstore_get_size(img)); - } else { - purple_debug_error("buddyicon", "Unable to create file %s: %s\n", - path, "File already exists."); - } + purple_util_write_data_to_file_absolute(path, purple_imgstore_get_data(img), + purple_imgstore_get_size(img)); g_free(path); } diff -r 86c18b2a16cc -r deb07e7d8679 libpurple/protocols/jabber/buddy.c --- a/libpurple/protocols/jabber/buddy.c Tue Mar 04 02:48:30 2008 +0000 +++ b/libpurple/protocols/jabber/buddy.c Wed Mar 05 01:24:23 2008 +0000 @@ -101,8 +101,36 @@ if(!jbr && !resource) { jbr = l->data; } else if(!resource) { - if(((JabberBuddyResource *)l->data)->priority >= jbr->priority) + if(((JabberBuddyResource *)l->data)->priority > jbr->priority) jbr = l->data; + else if(((JabberBuddyResource *)l->data)->priority == jbr->priority) { + /* Determine if this resource is more available than the one we've currently chosen */ + switch(((JabberBuddyResource *)l->data)->state) { + case JABBER_BUDDY_STATE_ONLINE: + case JABBER_BUDDY_STATE_CHAT: + /* This resource is online/chatty. Prefer to one which isn't either. */ + if ((jbr->state != JABBER_BUDDY_STATE_ONLINE) && (jbr->state != JABBER_BUDDY_STATE_CHAT)) + jbr = l->data; + break; + case JABBER_BUDDY_STATE_AWAY: + case JABBER_BUDDY_STATE_DND: + case JABBER_BUDDY_STATE_UNAVAILABLE: + /* This resource is away/dnd/unavailable. Prefer to one which is extended away or unknown. */ + if ((jbr->state == JABBER_BUDDY_STATE_XA) || + (jbr->state == JABBER_BUDDY_STATE_UNKNOWN) || (jbr->state == JABBER_BUDDY_STATE_ERROR)) + jbr = l->data; + break; + case JABBER_BUDDY_STATE_XA: + /* This resource is extended away. That's better than unknown. */ + if ((jbr->state == JABBER_BUDDY_STATE_UNKNOWN) || (jbr->state == JABBER_BUDDY_STATE_ERROR)) + jbr = l->data; + break; + case JABBER_BUDDY_STATE_UNKNOWN: + case JABBER_BUDDY_STATE_ERROR: + /* These are never preferable. */ + break; + } + } } else if(((JabberBuddyResource *)l->data)->name) { if(!strcmp(((JabberBuddyResource *)l->data)->name, resource)) { jbr = l->data; diff -r 86c18b2a16cc -r deb07e7d8679 libpurple/protocols/oscar/family_icbm.c --- a/libpurple/protocols/oscar/family_icbm.c Tue Mar 04 02:48:30 2008 +0000 +++ b/libpurple/protocols/oscar/family_icbm.c Wed Mar 05 01:24:23 2008 +0000 @@ -2332,6 +2332,181 @@ return 0; } +static void parse_status_note_text(OscarData *od, guchar *cookie, char *sn, ByteStream *bs) +{ + struct aim_icq_info *info; + struct aim_icq_info *prev_info; + char *response; + char *encoding; + char *stripped_encoding; + char *status_note_title; + char *status_note_text; + char *stripped_status_note_text; + char *status_note; + guint32 length; + guint16 version; + guint32 capability; + guint8 message_type; + guint16 status_code; + guint16 text_length; + guint32 request_length; + guint32 response_length; + guint32 encoding_length; + PurpleAccount *account; + PurpleBuddy *buddy; + PurplePresence *presence; + PurpleStatus *status; + + for (prev_info = NULL, info = od->icq_info; info != NULL; prev_info = info, info = info->next) + { + if (memcmp(&info->icbm_cookie, cookie, 8) == 0) + { + if (prev_info == NULL) + od->icq_info = info->next; + else + prev_info->next = info->next; + + break; + } + } + + if (info == NULL) + return; + + status_note_title = info->status_note_title; + g_free(info); + + length = byte_stream_getle16(bs); + if (length != 27) { + purple_debug_misc("oscar", "clientautoresp: incorrect header " + "size; expected 27, received %u.\n", length); + g_free(status_note_title); + return; + } + + version = byte_stream_getle16(bs); + if (version != 9) { + purple_debug_misc("oscar", "clientautoresp: incorrect version; " + "expected 9, received %u.\n", version); + g_free(status_note_title); + return; + } + + capability = aim_locate_getcaps(od, bs, 0x10); + if (capability != OSCAR_CAPABILITY_EMPTY) { + purple_debug_misc("oscar", "clientautoresp: plugin ID is not null.\n"); + g_free(status_note_title); + return; + } + + byte_stream_advance(bs, 2); /* unknown */ + byte_stream_advance(bs, 4); /* client capabilities flags */ + byte_stream_advance(bs, 1); /* unknown */ + byte_stream_advance(bs, 2); /* downcouner? */ + + length = byte_stream_getle16(bs); + if (length != 14) { + purple_debug_misc("oscar", "clientautoresp: incorrect header " + "size; expected 14, received %u.\n", length); + g_free(status_note_title); + return; + } + + byte_stream_advance(bs, 2); /* downcounter? */ + byte_stream_advance(bs, 12); /* unknown */ + + message_type = byte_stream_get8(bs); + if (message_type != 0x1a) { + purple_debug_misc("oscar", "clientautoresp: incorrect message " + "type; expected 0x1a, received 0x%x.\n", message_type); + g_free(status_note_title); + return; + } + + byte_stream_advance(bs, 1); /* message flags */ + + status_code = byte_stream_getle16(bs); + if (status_code != 0) { + purple_debug_misc("oscar", "clientautoresp: incorrect status " + "code; expected 0, received %u.\n", status_code); + g_free(status_note_title); + return; + } + + byte_stream_advance(bs, 2); /* priority code */ + + text_length = byte_stream_getle16(bs); + byte_stream_advance(bs, text_length); /* text */ + + length = byte_stream_getle16(bs); + byte_stream_advance(bs, 18); /* unknown */ + + request_length = byte_stream_getle32(bs); + if (length != 18 + 4 + request_length + 17) { + purple_debug_misc("oscar", "clientautoresp: incorrect block; " + "expected length is %u, got %u.\n", + 18 + 4 + request_length + 17, length); + g_free(status_note_title); + return; + } + + byte_stream_advance(bs, request_length); /* x request */ + byte_stream_advance(bs, 17); /* unknown */ + + length = byte_stream_getle32(bs); + response_length = byte_stream_getle32(bs); + response = byte_stream_getstr(bs, response_length); + encoding_length = byte_stream_getle32(bs); + if (length != 4 + response_length + 4 + encoding_length) { + purple_debug_misc("oscar", "clientautoresp: incorrect block; " + "expected length is %u, got %u.\n", + 4 + response_length + 4 + encoding_length, length); + g_free(status_note_title); + g_free(response); + return; + } + + encoding = byte_stream_getstr(bs, encoding_length); + + account = purple_connection_get_account(od->gc); + + stripped_encoding = oscar_encoding_extract(encoding); + status_note_text = oscar_encoding_to_utf8(account, stripped_encoding, response, response_length); + stripped_status_note_text = purple_markup_strip_html(status_note_text); + + if (stripped_status_note_text != NULL && stripped_status_note_text[0] != 0) + status_note = g_strdup_printf("%s: %s", status_note_title, stripped_status_note_text); + else + status_note = g_strdup(status_note_title); + + g_free(status_note_title); + g_free(response); + g_free(encoding); + g_free(stripped_encoding); + g_free(status_note_text); + g_free(stripped_status_note_text); + + buddy = purple_find_buddy(account, sn); + if (buddy == NULL) + { + purple_debug_misc("oscar", "clientautoresp: buddy %s was not found.\n", sn); + g_free(status_note); + return; + } + + purple_debug_misc("oscar", "clientautoresp: setting status " + "message to \"%s\".\n", status_note); + + presence = purple_buddy_get_presence(buddy); + status = purple_presence_get_active_status(presence); + + purple_prpl_got_user_status(account, sn, + purple_status_get_id(status), + "message", status_note, NULL); + + g_free(status_note); +} + /* * Subtype 0x000b - Receive the response from an ICQ status message * request (in which case this contains the ICQ status message) or @@ -2354,158 +2529,9 @@ if (channel == 0x0002) { - /* parse status note text */ - - struct aim_icq_info *info = NULL; - struct aim_icq_info *prev_info = NULL; - char *response = NULL; - char *encoding = NULL; - char *stripped_encoding = NULL; - char *status_note_text = NULL; - char *stripped_status_note_text = NULL; - char *status_note = NULL; - - /* - * TODO: Using a while statement here is kind of an ugly hack - * to be able to use 'break'. We might as well be using - * 'goto'. Should probably get rid of this. - */ - while (reason == 0x0003) /* channel-specific */ - { - guint32 length; - guint16 version; - guint32 capability; - guint8 message_type; - guint16 status_code; - guint16 text_length; - guint32 request_length; - guint32 response_length; - guint32 encoding_length; - PurpleAccount *account; - PurpleBuddy *buddy; - PurplePresence *presence; - PurpleStatus *status; - - for (info = od->icq_info; info != NULL; info = info->next) - { - if (memcmp(&info->icbm_cookie, cookie, 8) == 0) - { - if (prev_info == NULL) - od->icq_info = info->next; - else - prev_info->next = info->next; - - break; - } - - prev_info = info; - } - - if (info == NULL) - break; - - if ((length = byte_stream_getle16(bs)) != 27) - { - purple_debug_misc("oscar", "clientautoresp: incorrect header size; expected 27, received %u.\n", length); - break; - } - if ((version = byte_stream_getle16(bs)) != 9) - { - purple_debug_misc("oscar", "clientautoresp: incorrect version; expected 9, received %u.\n", version); - break; - } - capability = aim_locate_getcaps(od, bs, 0x10); - if (capability != OSCAR_CAPABILITY_EMPTY) - { - purple_debug_misc("oscar", "clientautoresp: plugin ID is not null.\n"); - break; - } - byte_stream_advance(bs, 2); /* unknown */ - byte_stream_advance(bs, 4); /* client capabilities flags */ - byte_stream_advance(bs, 1); /* unknown */ - byte_stream_advance(bs, 2); /* downcouner? */ - - if ((length = byte_stream_getle16(bs)) != 14) - { - purple_debug_misc("oscar", "clientautoresp: incorrect header size; expected 14, received %u.\n", length); - break; - } - byte_stream_advance(bs, 2); /* downcounter? */ - byte_stream_advance(bs, 12); /* unknown */ - - if ((message_type = byte_stream_get8(bs)) != 0x1a) - { - purple_debug_misc("oscar", "clientautoresp: incorrect message type; expected 0x1a, received 0x%x.\n", message_type); - break; - } - byte_stream_advance(bs, 1); /* message flags */ - if ((status_code = byte_stream_getle16(bs)) != 0) - { - purple_debug_misc("oscar", "clientautoresp: incorrect status code; expected 0, received %u.\n", status_code); - break; - } - byte_stream_advance(bs, 2); /* priority code */ - - text_length = byte_stream_getle16(bs); - byte_stream_advance(bs, text_length); /* text */ - - length = byte_stream_getle16(bs); - byte_stream_advance(bs, 18); /* unknown */ - if (length != 18 + 4 + (request_length = byte_stream_getle32(bs)) + 17) - { - purple_debug_misc("oscar", "clientautoresp: incorrect block; expected length is %u, got %u.\n", 18 + 4 + request_length + 17, length); - break; - } - byte_stream_advance(bs, request_length); /* x request */ - byte_stream_advance(bs, 17); /* unknown */ - - length = byte_stream_getle32(bs); - response_length = byte_stream_getle32(bs); - response = byte_stream_getstr(bs, response_length); - if (length != 4 + response_length + 4 + (encoding_length = byte_stream_getle32(bs))) - { - purple_debug_misc("oscar", "clientautoresp: incorrect block; expected length is %u, got %u.\n", 4 + response_length + 4 + encoding_length, length); - break; - } - encoding = byte_stream_getstr(bs, encoding_length); - - account = purple_connection_get_account(od->gc); - stripped_encoding = oscar_encoding_extract(encoding); - status_note_text = oscar_encoding_to_utf8(account, stripped_encoding, response, response_length); - stripped_status_note_text = purple_markup_strip_html(status_note_text); - - if (stripped_status_note_text != NULL && stripped_status_note_text[0] != 0) - status_note = g_strdup_printf("%s: %s", info->status_note_title, stripped_status_note_text); - else - status_note = g_strdup(info->status_note_title); - - buddy = purple_find_buddy(account, sn); - if (buddy == NULL) - { - purple_debug_misc("oscar", "clientautoresp: buddy %s was not found.\n", sn); - break; - } - - purple_debug_misc("oscar", "clientautoresp: setting status message to \"%s\".\n", status_note); - - presence = purple_buddy_get_presence(buddy); - status = purple_presence_get_active_status(presence); - - purple_prpl_got_user_status(account, sn, - purple_status_get_id(status), - "message", status_note, NULL); - - break; - } - - g_free(status_note); - g_free(stripped_status_note_text); - g_free(status_note_text); - g_free(stripped_encoding); - g_free(encoding); - g_free(response); - g_free(info->status_note_title); - g_free(info); + if (reason == 0x0003) /* channel-specific */ + /* parse status note text */ + parse_status_note_text(od, cookie, sn, bs); byte_stream_get16(bs); /* Unknown */ byte_stream_get16(bs); /* Unknown */ diff -r 86c18b2a16cc -r deb07e7d8679 libpurple/protocols/yahoo/yahoo.c --- a/libpurple/protocols/yahoo/yahoo.c Tue Mar 04 02:48:30 2008 +0000 +++ b/libpurple/protocols/yahoo/yahoo.c Wed Mar 05 01:24:23 2008 +0000 @@ -464,7 +464,6 @@ PurpleAccount *account = purple_connection_get_account(gc); struct yahoo_data *yd = gc->proto_data; GHashTable *ht; - char *grp = NULL; char *norm_bud = NULL; YahooFriend *f = NULL; /* It's your friends. They're going to want you to share your StarBursts. */ /* But what if you had no friends? */ @@ -487,8 +486,8 @@ */ if (pair->value && !strcmp(pair->value, "320")) { /* No longer in any group; this indicates the start of the ignore list. */ - g_free(grp); - grp = NULL; + g_free(yd->current_list15_grp); + yd->current_list15_grp = NULL; } break; @@ -497,28 +496,30 @@ case 300: /* This is 318 before a group, 319 before any s/n in a group, and 320 before any ignored s/n. */ break; case 65: /* This is the group */ - g_free(grp); - grp = yahoo_string_decode(gc, pair->value, FALSE); + g_free(yd->current_list15_grp); + yd->current_list15_grp = yahoo_string_decode(gc, pair->value, FALSE); break; case 7: /* buddy's s/n */ g_free(norm_bud); norm_bud = g_strdup(purple_normalize(account, pair->value)); - if (grp) { + if (yd->current_list15_grp) { /* This buddy is in a group */ f = yahoo_friend_find_or_new(gc, norm_bud); if (!(b = purple_find_buddy(account, norm_bud))) { - if (!(g = purple_find_group(grp))) { - g = purple_group_new(grp); + if (!(g = purple_find_group(yd->current_list15_grp))) { + g = purple_group_new(yd->current_list15_grp); purple_blist_add_group(g, NULL); } b = purple_buddy_new(account, norm_bud, NULL); purple_blist_add_buddy(b, NULL, g, NULL); } - yahoo_do_group_check(account, ht, norm_bud, grp); + yahoo_do_group_check(account, ht, norm_bud, yd->current_list15_grp); } else { /* This buddy is on the ignore list (and therefore in no group) */ + purple_debug_info("yahoo", "%s adding %s to the deny list because of the ignore list / no group was found", + account->username, norm_bud); purple_privacy_deny_add(account, norm_bud, 1); } break; @@ -543,7 +544,6 @@ g_hash_table_foreach(ht, yahoo_do_group_cleanup, NULL); g_hash_table_destroy(ht); - g_free(grp); g_free(norm_bud); } @@ -3070,6 +3070,8 @@ g_free(yd->pending_chat_topic); g_free(yd->pending_chat_goto); + g_free(yd->current_list15_grp); + g_free(yd); gc->proto_data = NULL; } diff -r 86c18b2a16cc -r deb07e7d8679 libpurple/protocols/yahoo/yahoo.h --- a/libpurple/protocols/yahoo/yahoo.h Tue Mar 04 02:48:30 2008 +0000 +++ b/libpurple/protocols/yahoo/yahoo.h Wed Mar 05 01:24:23 2008 +0000 @@ -175,6 +175,12 @@ GSList *url_datas; GHashTable *xfer_peer_idstring_map;/*Hey, i dont know, but putting this HashTable next to friends gives a run time fault...*/ GSList *cookies;/*contains all cookies, including _y and _t*/ + + /** + * We may receive a list15 in multiple packets with no prior warning as to how many we'll be getting; + * the server expects us to keep track of the group for which it is sending us contact names. + */ + char *current_list15_grp; }; #define YAHOO_MAX_STATUS_MESSAGE_LENGTH (255) diff -r 86c18b2a16cc -r deb07e7d8679 pidgin/gtkmain.c --- a/pidgin/gtkmain.c Tue Mar 04 02:48:30 2008 +0000 +++ b/pidgin/gtkmain.c Wed Mar 05 01:24:23 2008 +0000 @@ -406,8 +406,9 @@ " -h, --help display this help and exit\n" " -m, --multiple do not ensure single instance\n" " -n, --nologin don't automatically login\n" - " -l, --login[=NAME] automatically login (optional argument NAME specifies\n" - " account(s) to use, separated by commas)\n" + " -l, --login[=NAME] enable specified account(s) (optional argument NAME\n" + " specifies account(s) to use, separated by commas.\n" + " Without this only the first account will be enabled).\n" " --display=DISPLAY X display to use\n" " -v, --version display the current version and exit\n"), PIDGIN_NAME, DISPLAY_VERSION, name); #else @@ -418,8 +419,9 @@ " -h, --help display this help and exit\n" " -m, --multiple do not ensure single instance\n" " -n, --nologin don't automatically login\n" - " -l, --login[=NAME] automatically login (optional argument NAME specifies\n" - " account(s) to use, separated by commas)\n" + " -l, --login[=NAME] enable specified account(s) (optional argument NAME\n" + " specifies account(s) to use, separated by commas.\n" + " Without this only the first account will be enabled).\n" " -v, --version display the current version and exit\n"), PIDGIN_NAME, DISPLAY_VERSION, name); #endif } @@ -476,6 +478,7 @@ gboolean opt_help = FALSE; gboolean opt_login = FALSE; gboolean opt_nologin = FALSE; + gboolean opt_nocrash = FALSE; gboolean opt_version = FALSE; gboolean opt_si = TRUE; /* Check for single instance? */ char *opt_config_dir_arg = NULL; @@ -506,6 +509,7 @@ {"login", optional_argument, NULL, 'l'}, {"multiple", no_argument, NULL, 'm'}, {"nologin", no_argument, NULL, 'n'}, + {"nocrash", no_argument, NULL, 'x'}, {"session", required_argument, NULL, 's'}, {"version", no_argument, NULL, 'v'}, {"display", required_argument, NULL, 'D'}, @@ -655,6 +659,9 @@ case 'm': /* do not ensure single instance. */ opt_si = FALSE; break; + case 'x': /* --nocrash */ + opt_nocrash = TRUE; + break; case 'D': /* --display */ case 'S': /* --sync */ /* handled by gtk_init_check below */