changeset 22509:deb07e7d8679

merge of '43597c046102d28beb11884ac70e89943a1b1466' and 'cce3a22f53972bd3834175b08ad5e7b800bf98e9'
author Etan Reisner <pidgin@unreliablesource.net>
date Wed, 05 Mar 2008 01:24:23 +0000
parents 86c18b2a16cc (current diff) 0c098ebe9f16 (diff)
children 69a5f005fdbf
files
diffstat 7 files changed, 241 insertions(+), 177 deletions(-) [+]
line wrap: on
line diff
--- 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.
--- 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);
 }
 
--- 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;
--- 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 */
--- 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;
 }
--- 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)
--- 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 */