changeset 18068:0b3d6ea61760

propagate from branch 'im.pidgin.pidgin' (head 4b50880d8517570eaa67d4cd9d88c5934bb832f1) to branch 'im.pidgin.pidgin.2.1.0' (head fefd59692d4177b91d52f6d71b1565b76c88725d)
author Richard Laager <rlaager@wiktel.com>
date Thu, 07 Jun 2007 14:48:33 +0000
parents 5eebb9b24e30 (diff) 098a1d6896be (current diff)
children 08776fc5c06f 3fc94e7c7056
files ChangeLog.API pidgin/gtkconv.c pidgin/gtkrequest.c pidgin/gtksavedstatuses.c
diffstat 16 files changed, 365 insertions(+), 317 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog.API	Thu Jun 07 12:33:23 2007 +0000
+++ b/ChangeLog.API	Thu Jun 07 14:48:33 2007 +0000
@@ -67,6 +67,12 @@
 		Added:
 		* finch_retrieve_user_info
 
+version 2.0.2 (6/14/2007):
+	Pidgin:
+		Deprecated:
+		* pidgin_dialogs_alias_contact:  This will be removed in 3.0.0
+		  unless there is sufficient demand to keep it.
+
 version 2.0.0 (5/3/2007):
 	Please note all functions, defines, and data structures have been
 	re-namespaced to match the new names of Pidgin, Finch, and libpurple.
--- a/config.h.mingw	Thu Jun 07 12:33:23 2007 +0000
+++ b/config.h.mingw	Thu Jun 07 14:48:33 2007 +0000
@@ -344,9 +344,6 @@
 /* Define to the version of this package. */
 /* #define PACKAGE_VERSION "2.0.0dev" */
 
-/* Define to make assertions fatal (useful for debugging). */
-/* #define PURPLE_FATAL_ASSERTS 1 */
-
 /* Define if plugins are enabled. */
 #define PURPLE_PLUGINS 1
 
--- a/libpurple/plugins/log_reader.c	Thu Jun 07 12:33:23 2007 +0000
+++ b/libpurple/plugins/log_reader.c	Thu Jun 07 14:48:33 2007 +0000
@@ -1425,7 +1425,7 @@
 	char *escaped;
 	GString *formatted;
 	char *c;
-	char *line;
+	const char *line;
 
 	g_return_val_if_fail(log != NULL, g_strdup(""));
 
@@ -1460,240 +1460,234 @@
 	read = escaped;
 
 	/* Apply formatting... */
-	formatted = g_string_new("");
+	formatted = g_string_sized_new(strlen(read));
 	c = read;
 	line = read;
-	while (*c)
+	while (c)
 	{
-		if (*c == '\n')
-		{
-			char *link_temp_line;
-			char *link;
-			char *timestamp;
-			char *footer = NULL;
-			*c = '\0';
+		const char *link;
+		const char *footer = NULL;
+		GString *temp = NULL;
 
-			/* Convert links.
-			 *
-			 * The format is (Link: URL)URL
-			 * So, I want to find each occurance of "(Link: " and replace that chunk with:
-			 * <a href="
-			 * Then, replace the next ")" with:
-			 * ">
-			 * Then, replace the next " " (or add this if the end-of-line is reached) with:
-			 * </a>
-			 * 
-			 * As implemented, this isn't perfect, but it should cover common cases.
-			 */
-			link_temp_line = NULL;
-			while ((link = strstr(line, "(Link: ")))
-			{
-				char *tmp = link;
-
-				link += 7;
-				if (*link)
-				{
-					char *end_paren;
-					char *space;
-					GString *temp;
-
-					if (!(end_paren = strstr(link, ")")))
-					{
-						/* Something is not as we expect.  Bail out. */
-						break;
-					}
-
-					*tmp = '\0';
-					temp = g_string_new(line);
-
-					/* Start an <a> tag. */
-					g_string_append(temp, "<a href=\"");
-
-					/* Append up to the ) */
-					g_string_append_len(temp, link, end_paren - link);
+		if ((c = strstr(c, "\n")))
+		{
+			*c = '\0';
+			c++;
+		}
 
-					/* Finish the <a> tag. */
-					g_string_append(temp, "\">");
-
-					/* The \r is a bit of a hack to keep there from being a \r in
-					 * the link text, which may not matter. */
-					if ((space = strstr(end_paren, " ")) || (space = strstr(end_paren, "\r")))
-					{
-						g_string_append_len(temp, end_paren + 1, space - end_paren - 1);
-
-						/* Close the <a> tag. */
-						g_string_append(temp, "</a>");
+		/* Convert links.
+		 *
+		 * The format is (Link: URL)URL
+		 * So, I want to find each occurance of "(Link: " and replace that chunk with:
+		 * <a href="
+		 * Then, replace the next ")" with:
+		 * ">
+		 * Then, replace the next " " (or add this if the end-of-line is reached) with:
+		 * </a>
+		 * 
+		 * As implemented, this isn't perfect, but it should cover common cases.
+		 */
+		while (line && (link = strstr(line, "(Link: ")))
+		{
+			const char *tmp = link;
 
-						space++;
-						if (*space)
-						{
-							g_string_append_c(temp, ' ');
-							/* Keep the rest of the line. */
-							g_string_append(temp, space);
-						}
-					}
-					else
-					{
-						/* There is no space before the end of the line. */
-						g_string_append(temp, end_paren + 1);
-						/* Close the <a> tag. */
-						g_string_append(temp, "</a>");
-					}
-
-					g_free(link_temp_line);
-					line = g_string_free(temp, FALSE);
+			link += 7;
+			if (*link)
+			{
+				char *end_paren;
+				char *space;
 
-					/* Save this memory location so we can free it later. */
-					link_temp_line = line;
-				}
-			}
-
-			timestamp = "";
-			if (*line == '[') {
-				timestamp = line;
-				while (*timestamp && *timestamp != ']')
-					timestamp++;
-				if (*timestamp == ']') {
-					*timestamp = '\0';
-					line++;
-					/* TODO: Parse the timestamp and convert it to Purple's format. */
-					g_string_append_printf(formatted,
-						"<font size=\"2\">(%s)</font> ", line);
-					line = timestamp;
-					if (line[1] && line[2])
-						line += 2;
+				if (!(end_paren = strstr(link, ")")))
+				{
+					/* Something is not as we expect.  Bail out. */
+					break;
 				}
 
-				if (purple_str_has_prefix(line, "*** ")) {
-					line += (sizeof("*** ") - 1);
-					g_string_append(formatted, "<b>");
-					footer = "</b>";
-					if (purple_str_has_prefix(line, "NOTE: This user is offline.")) {
-						line = _("User is offline.");
-					} else if (purple_str_has_prefix(line,
-							"NOTE: Your status is currently set to ")) {
+				if (!temp)
+					temp = g_string_sized_new(c ? (c - 1 - line) : strlen(line));
+
+				g_string_append_len(temp, line, (tmp - line));
+
+				/* Start an <a> tag. */
+				g_string_append(temp, "<a href=\"");
+
+				/* Append up to the ) */
+				g_string_append_len(temp, link, end_paren - link);
+
+				/* Finish the <a> tag. */
+				g_string_append(temp, "\">");
+
+				/* The \r is a bit of a hack to keep there from being a \r in
+				 * the link text, which may not matter. */
+				if ((space = strstr(end_paren, " ")) || (space = strstr(end_paren, "\r")))
+				{
+					g_string_append_len(temp, end_paren + 1, space - end_paren - 1);
+
+					/* Close the <a> tag. */
+					g_string_append(temp, "</a>");
+
+					space++;
+				}
+				else
+				{
+					/* There is no space before the end of the line. */
+					g_string_append(temp, end_paren + 1);
+					/* Close the <a> tag. */
+					g_string_append(temp, "</a>");
+				}
+				line = space;
+			}
+			else
+			{
+				/* Something is not as we expect.  Bail out. */
+				break;
+			}
+		}
+
+		if (temp)
+		{
+			if (line)
+				g_string_append(temp, line);
+			line = temp->str;
+		}
+
+		if (*line == '[') {
+			const char *timestamp;
+
+			if ((timestamp = strstr(line, "]"))) {
+				line++;
+				/* TODO: Parse the timestamp and convert it to Purple's format. */
+				g_string_append(formatted, "<font size=\"2\">(");
+				g_string_append_len(formatted, line, (timestamp - line));
+				g_string_append(formatted,")</font> ");
+				line = timestamp + 1;
+				if (line[0] && line[1])
+					line++;
+			}
 
-						line += (sizeof("NOTE: ") - 1);
-					} else if (purple_str_has_prefix(line, "Auto-response sent to ")) {
-						g_string_append(formatted, _("Auto-response sent:"));
-						while (*line && *line != ':')
-							line++;
-						if (*line)
-							line++;
-						g_string_append(formatted, "</b>");
-						footer = NULL;
-					} else if (strstr(line, " signed off ")) {
-						if (buddy != NULL && buddy->alias)
-							g_string_append_printf(formatted,
-								_("%s has signed off."), buddy->alias);
-						else
-							g_string_append_printf(formatted,
-								_("%s has signed off."), log->name);
-						line = "";
-					} else if (strstr(line, " signed on ")) {
-						if (buddy != NULL && buddy->alias)
-							g_string_append(formatted, buddy->alias);
-						else
-							g_string_append(formatted, log->name);
-						line = " logged in.";
-					} else if (purple_str_has_prefix(line,
-						"One or more messages may have been undeliverable.")) {
+			if (purple_str_has_prefix(line, "*** ")) {
+				line += (sizeof("*** ") - 1);
+				g_string_append(formatted, "<b>");
+				footer = "</b>";
+				if (purple_str_has_prefix(line, "NOTE: This user is offline.")) {
+					line = _("User is offline.");
+				} else if (purple_str_has_prefix(line,
+						"NOTE: Your status is currently set to ")) {
+
+					line += (sizeof("NOTE: ") - 1);
+				} else if (purple_str_has_prefix(line, "Auto-response sent to ")) {
+					g_string_append(formatted, _("Auto-response sent:"));
+					while (*line && *line != ':')
+						line++;
+					if (*line)
+						line++;
+					g_string_append(formatted, "</b>");
+					footer = NULL;
+				} else if (strstr(line, " signed off ")) {
+					if (buddy != NULL && buddy->alias)
+						g_string_append_printf(formatted,
+							_("%s has signed off."), buddy->alias);
+					else
+						g_string_append_printf(formatted,
+							_("%s has signed off."), log->name);
+					line = "";
+				} else if (strstr(line, " signed on ")) {
+					if (buddy != NULL && buddy->alias)
+						g_string_append(formatted, buddy->alias);
+					else
+						g_string_append(formatted, log->name);
+					line = " logged in.";
+				} else if (purple_str_has_prefix(line,
+					"One or more messages may have been undeliverable.")) {
 
-						g_string_append(formatted,
-							"<span style=\"color: #ff0000;\">");
-						g_string_append(formatted,
-							_("One or more messages may have been "
-							  "undeliverable."));
-						line = "";
-						footer = "</span></b>";
-					} else if (purple_str_has_prefix(line,
-							"You have been disconnected.")) {
+					g_string_append(formatted,
+						"<span style=\"color: #ff0000;\">");
+					g_string_append(formatted,
+						_("One or more messages may have been "
+						  "undeliverable."));
+					line = "";
+					footer = "</span></b>";
+				} else if (purple_str_has_prefix(line,
+						"You have been disconnected.")) {
 
-						g_string_append(formatted,
-							"<span style=\"color: #ff0000;\">");
-						g_string_append(formatted,
-							_("You were disconnected from the server."));
-						line = "";
-						footer = "</span></b>";
-					} else if (purple_str_has_prefix(line,
-							"You are currently disconnected.")) {
+					g_string_append(formatted,
+						"<span style=\"color: #ff0000;\">");
+					g_string_append(formatted,
+						_("You were disconnected from the server."));
+					line = "";
+					footer = "</span></b>";
+				} else if (purple_str_has_prefix(line,
+						"You are currently disconnected.")) {
+
+					g_string_append(formatted,
+						"<span style=\"color: #ff0000;\">");
+					line = _("You are currently disconnected. Messages "
+					         "will not be received unless you are "
+					         "logged in.");
+					footer = "</span></b>";
+				} else if (purple_str_has_prefix(line,
+						"Your previous message has not been sent.")) {
+
+					g_string_append(formatted,
+						"<span style=\"color: #ff0000;\">");
+
+					if (purple_str_has_prefix(line,
+						"Your previous message has not been sent.  "
+						"Reason: Maximum length exceeded.")) {
 
 						g_string_append(formatted,
-							"<span style=\"color: #ff0000;\">");
-						line = _("You are currently disconnected. Messages "
-						         "will not be received unless you are "
-						         "logged in.");
-						footer = "</span></b>";
-					} else if (purple_str_has_prefix(line,
-							"Your previous message has not been sent.")) {
-
+							_("Message could not be sent because "
+							  "the maximum length was exceeded."));
+						line = "";
+					} else {
 						g_string_append(formatted,
-							"<span style=\"color: #ff0000;\">");
-
-						if (purple_str_has_prefix(line,
-							"Your previous message has not been sent.  "
-							"Reason: Maximum length exceeded.")) {
+							_("Message could not be sent."));
+						line += (sizeof(
+							"Your previous message "
+							"has not been sent. ") - 1);
+					}
 
-							g_string_append(formatted,
-								_("Message could not be sent because "
-								  "the maximum length was exceeded."));
-							line = "";
-						} else {
-							g_string_append(formatted,
-								_("Message could not be sent."));
-							line += (sizeof(
-								"Your previous message "
-								"has not been sent. ") - 1);
-						}
+					footer = "</span></b>";
+				}
+			} else if (purple_str_has_prefix(line, data->their_nickname)) {
+				if (buddy != NULL && buddy->alias) {
+					line += strlen(data->their_nickname) + 2;
+					g_string_append_printf(formatted,
+						"<span style=\"color: #A82F2F;\">"
+						"<b>%s</b></span>: ", buddy->alias);
+				}
+			} else {
+				const char *line2 = strstr(line, ":");
+				if (line2) {
+					const char *acct_name;
+					line2++;
+					line = line2;
+					acct_name = purple_account_get_alias(log->account);
+					if (!acct_name)
+						acct_name = purple_account_get_username(log->account);
 
-						footer = "</span></b>";
-					}
-				} else if (purple_str_has_prefix(line, data->their_nickname)) {
-					if (buddy != NULL && buddy->alias) {
-						line += strlen(data->their_nickname) + 2;
-						g_string_append_printf(formatted,
-							"<span style=\"color: #A82F2F;\">"
-							"<b>%s</b></span>: ", buddy->alias);
-					}
-				} else {
-					char *line2 = line;
-					while (*line2 && *line2 != ':')
-						line2++;
-					if (*line2 == ':') {
-						const char *acct_name;
-						line2++;
-						line = line2;
-						acct_name = purple_account_get_alias(log->account);
-						if (!acct_name)
-							acct_name = purple_account_get_username(log->account);
-
-						g_string_append_printf(formatted,
-							"<span style=\"color: #16569E;\">"
-							"<b>%s</b></span>:", acct_name);
-					}
+					g_string_append_printf(formatted,
+						"<span style=\"color: #16569E;\">"
+						"<b>%s</b></span>:", acct_name);
 				}
 			}
-
-			g_string_append(formatted, line);
+		}
 
-			if (footer)
-				g_string_append(formatted, footer);
+		g_string_append(formatted, line);
 
-			g_string_append_c(formatted, '\n');
-
-			g_free(link_temp_line);
+		line = c;
+		if (temp)
+			g_string_free(temp, TRUE);
 
-			c++;
-			line = c;
-		} else
-			c++;
+		if (footer)
+			g_string_append(formatted, footer);
+
+		g_string_append_c(formatted, '\n');
 	}
 
 	g_free(read);
-	read = formatted->str;
-	g_string_free(formatted, FALSE);
-
-	return read;
+	/* XXX: TODO: Avoid this g_strchomp() */
+	return g_strchomp(g_string_free(formatted, FALSE));
 }
 
 static int trillian_logger_size (PurpleLog *log)
--- a/libpurple/protocols/bonjour/bonjour.c	Thu Jun 07 12:33:23 2007 +0000
+++ b/libpurple/protocols/bonjour/bonjour.c	Thu Jun 07 14:48:33 2007 +0000
@@ -94,14 +94,13 @@
 bonjour_login(PurpleAccount *account)
 {
 	PurpleConnection *gc = purple_account_get_connection(account);
-	PurpleGroup *bonjour_group = NULL;
-	BonjourData *bd = NULL;
+	PurpleGroup *bonjour_group;
+	BonjourData *bd;
 	PurpleStatus *status;
 	PurplePresence *presence;
 
 	gc->flags |= PURPLE_CONNECTION_HTML;
-	gc->proto_data = g_new0(BonjourData, 1);
-	bd = gc->proto_data;
+	gc->proto_data = bd = g_new0(BonjourData, 1);
 
 	/* Start waiting for jabber connections (iChat style) */
 	bd->jabber_data = g_new(BonjourJabber, 1);
@@ -111,10 +110,6 @@
 	if (bonjour_jabber_start(bd->jabber_data) == -1) {
 		/* Send a message about the connection error */
 		purple_connection_error(gc, _("Unable to listen for incoming IM connections\n"));
-
-		/* Free the data */
-		g_free(bd->jabber_data);
-		bd->jabber_data = NULL;
 		return;
 	}
 
@@ -155,7 +150,7 @@
 bonjour_close(PurpleConnection *connection)
 {
 	PurpleGroup *bonjour_group;
-	BonjourData *bd = (BonjourData*)connection->proto_data;
+	BonjourData *bd = connection->proto_data;
 
 	/* Stop looking for buddies in the LAN */
 	if (bd->dns_sd_data != NULL)
--- a/libpurple/protocols/bonjour/buddy.c	Thu Jun 07 12:33:23 2007 +0000
+++ b/libpurple/protocols/bonjour/buddy.c	Thu Jun 07 14:48:33 2007 +0000
@@ -162,6 +162,8 @@
 bonjour_buddy_delete(BonjourBuddy *buddy)
 {
 	g_free(buddy->name);
+	g_free(buddy->ip);
+
 	g_free(buddy->first);
 	g_free(buddy->phsh);
 	g_free(buddy->status);
@@ -170,8 +172,11 @@
 	g_free(buddy->jid);
 	g_free(buddy->AIM);
 	g_free(buddy->vc);
-	g_free(buddy->ip);
 	g_free(buddy->msg);
+	g_free(buddy->ext);
+	g_free(buddy->nick);
+	g_free(buddy->node);
+	g_free(buddy->ver);
 
 	if (buddy->conversation != NULL)
 	{
--- a/libpurple/protocols/bonjour/jabber.c	Thu Jun 07 12:33:23 2007 +0000
+++ b/libpurple/protocols/bonjour/jabber.c	Thu Jun 07 14:48:33 2007 +0000
@@ -123,46 +123,41 @@
 
 	return "1";
 }
+
 static void
 _jabber_parse_and_write_message_to_ui(char *message, PurpleConnection *connection, PurpleBuddy *gb)
 {
-	xmlnode *body_node = NULL;
-	char *body = NULL;
-	xmlnode *html_node = NULL;
-	gboolean isHTML = FALSE;
-	xmlnode *html_body_node = NULL;
+	xmlnode *message_node, *body_node, *html_node, *events_node;
+	char *body, *html_body = NULL;
 	const char *ichat_balloon_color = NULL;
 	const char *ichat_text_color = NULL;
-	xmlnode *html_body_font_node = NULL;
 	const char *font_face = NULL;
 	const char *font_size = NULL;
 	const char *font_color = NULL;
-	char *html_body = NULL;
-	xmlnode *events_node = NULL;
 	gboolean composing_event = FALSE;
-	gint garbage = -1;
-	xmlnode *message_node = NULL;
 
 	/* Parsing of the message */
 	message_node = xmlnode_from_str(message, strlen(message));
-	if (message_node == NULL) {
+	if (message_node == NULL)
 		return;
-	}
 
 	body_node = xmlnode_get_child(message_node, "body");
-	if (body_node != NULL) {
-		body = xmlnode_get_data(body_node);
-	} else {
+	if (body_node == NULL) {
+		xmlnode_free(message_node);
 		return;
 	}
+	body = xmlnode_get_data(body_node);
 
 	html_node = xmlnode_get_child(message_node, "html");
 	if (html_node != NULL)
 	{
-		isHTML = TRUE;
+		xmlnode *html_body_node;
+
 		html_body_node = xmlnode_get_child(html_node, "body");
 		if (html_body_node != NULL)
 		{
+			xmlnode *html_body_font_node;
+
 			ichat_balloon_color = xmlnode_get_attrib(html_body_node, "ichatballooncolor");
 			ichat_text_color = xmlnode_get_attrib(html_body_node, "ichattextcolor");
 			html_body_font_node = xmlnode_get_child(html_body_node, "font");
@@ -172,23 +167,17 @@
 				/* The absolute iChat font sizes should be converted to 1..7 range */
 				font_size = xmlnode_get_attrib(html_body_font_node, "ABSZ");
 				if (font_size != NULL)
-				{
 					font_size = _font_size_ichat_to_purple(atoi(font_size));
-				}
 				font_color = xmlnode_get_attrib(html_body_font_node, "color");
 				html_body = xmlnode_get_data(html_body_font_node);
 				if (html_body == NULL)
 				{
+					gint garbage = -1;
 					/* This is the kind of formated messages that Purple creates */
 					html_body = xmlnode_to_str(html_body_font_node, &garbage);
 				}
-			} else {
-				isHTML = FALSE;
 			}
-		} else {
-			isHTML = FALSE;
 		}
-
 	}
 
 	events_node = xmlnode_get_child_with_namespace(message_node, "x", "jabber:x:event");
@@ -201,6 +190,7 @@
 		if (xmlnode_get_child(events_node, "id") != NULL)
 		{
 			/* The user is just typing */
+			/* TODO: Deal with typing notification */
 			xmlnode_free(message_node);
 			g_free(body);
 			g_free(html_body);
@@ -209,8 +199,10 @@
 	}
 
 	/* Compose the message */
-	if (isHTML)
+	if (html_body != NULL)
 	{
+		g_free(body);
+
 		if (font_face == NULL) font_face = "Helvetica";
 		if (font_size == NULL) font_size = "3";
 		if (ichat_text_color == NULL) ichat_text_color = "#000000";
@@ -219,6 +211,8 @@
 							"' back='", ichat_balloon_color, "'>", html_body, "</font>", NULL);
 	}
 
+	/* TODO: Should we do something with "composing_event" here? */
+
 	/* Send the message to the UI */
 	serv_got_im(connection, gb->name, body, 0, time(NULL));
 
@@ -229,7 +223,7 @@
 }
 
 struct _check_buddy_by_address_t {
-	char *address;
+	const char *address;
 	PurpleBuddy **gb;
 	BonjourJabber *bj;
 };
@@ -237,12 +231,9 @@
 static void
 _check_buddy_by_address(gpointer key, gpointer value, gpointer data)
 {
-	PurpleBuddy *gb = (PurpleBuddy*)value;
+	PurpleBuddy *gb = value;
 	BonjourBuddy *bb;
-	struct _check_buddy_by_address_t *cbba;
-
-	gb = value;
-	cbba = data;
+	struct _check_buddy_by_address_t *cbba = data;
 
 	/*
 	 * If the current PurpleBuddy's data is not null and the PurpleBuddy's account
@@ -274,14 +265,14 @@
 
 	if (partial_message_length == -1)
 	{
-		purple_debug_warning("bonjour", "receive error: %s\n", strerror(errno));
+		if (errno != EAGAIN)
+			purple_debug_warning("bonjour", "receive error: %s\n", strerror(errno));
 		if (total_message_length == 0) {
 			return -1;
 		}
 	}
 
-	*message = data->str;
-	g_string_free(data, FALSE);
+	*message = g_string_free(data, FALSE);
 	if (total_message_length != 0)
 		purple_debug_info("bonjour", "Receive: -%s- %d bytes\n", *message, total_message_length);
 
@@ -313,17 +304,17 @@
 {
 	char *message = NULL;
 	gint message_length;
-	PurpleBuddy *gb = (PurpleBuddy*)data;
+	PurpleBuddy *gb = data;
 	PurpleAccount *account = gb->account;
 	PurpleConversation *conversation;
-	char *closed_conv_message;
-	BonjourBuddy *bb = (BonjourBuddy*)gb->proto_data;
+	BonjourBuddy *bb = gb->proto_data;
 	gboolean closed_conversation = FALSE;
-	xmlnode *message_node = NULL;
+	xmlnode *message_node;
 
 	/* Read the data from the socket */
 	if ((message_length = _read_data(socket, &message)) == -1) {
 		/* There have been an error reading from the socket */
+		/* TODO: Shouldn't we handle the error if it isn't EAGAIN? */
 		return;
 	} else if (message_length == 0) { /* The other end has closed the socket */
 		closed_conversation = TRUE;
@@ -345,8 +336,8 @@
 	{
 		/* Check if this is the start of the stream */
 		if ((message_node != NULL) &&
-		   g_ascii_strcasecmp(xmlnode_get_attrib(message_node, "xmlns"), "jabber:client") &&
-		   (xmlnode_get_attrib(message_node,"xmlns:stream") != NULL))
+			g_ascii_strcasecmp(xmlnode_get_attrib(message_node, "xmlns"), "jabber:client") &&
+			(xmlnode_get_attrib(message_node,"xmlns:stream") != NULL))
 		{
 			bb->conversation->stream_started = TRUE;
 		}
@@ -354,13 +345,9 @@
 		{
 			/* TODO: This needs to be nonblocking! */
 			if (send(bb->conversation->socket, DOCTYPE, strlen(DOCTYPE), 0) == -1)
-			{
 				purple_debug_error("bonjour", "Unable to start a conversation with %s\n", bb->name);
-			}
 			else
-			{
 				bb->conversation->stream_started = TRUE;
-			}
 		}
 	}
 
@@ -370,6 +357,8 @@
 	 * parsing an end tag
 	 */
 	if (purple_str_has_prefix(message, STREAM_END) || (closed_conversation == TRUE)) {
+		char *closed_conv_message;
+
 		/* Close the socket, clear the watcher and free memory */
 		if (bb->conversation != NULL) {
 			close(bb->conversation->socket);
@@ -400,21 +389,18 @@
 	struct sockaddr_in their_addr; /* connector's address information */
 	socklen_t sin_size = sizeof(struct sockaddr);
 	int client_socket;
-	BonjourBuddy *bb = NULL;
-	BonjourJabber *bj = data;
+	BonjourBuddy *bb;
 	char *address_text = NULL;
 	PurpleBuddyList *bl = purple_get_blist();
 	struct _check_buddy_by_address_t *cbba;
 
 	/* Check that it is a read condition */
-	if (condition != PURPLE_INPUT_READ) {
+	if (condition != PURPLE_INPUT_READ)
 		return;
-	}
 
 	if ((client_socket = accept(server_socket, (struct sockaddr *)&their_addr, &sin_size)) == -1)
-	{
 		return;
-	}
+
 	fcntl(client_socket, F_SETFL, O_NONBLOCK);
 
 	/* Look for the buddy that has opened the conversation and fill information */
@@ -422,7 +408,7 @@
 	cbba = g_new0(struct _check_buddy_by_address_t, 1);
 	cbba->address = address_text;
 	cbba->gb = &gb;
-	cbba->bj = bj;
+	cbba->bj = data;
 	g_hash_table_foreach(bl->buddies, _check_buddy_by_address, cbba);
 	g_free(cbba);
 	if (gb == NULL)
@@ -431,7 +417,7 @@
 		close(client_socket);
 		return;
 	}
-	bb = (BonjourBuddy*)gb->proto_data;
+	bb = gb->proto_data;
 
 	/* Check if the conversation has been previously started */
 	if (bb->conversation == NULL)
@@ -608,28 +594,28 @@
 		/* Start the stream */
 		if (send(bb->conversation->socket, DOCTYPE, strlen(DOCTYPE), 0) == -1)
 		{
-				purple_debug_error("bonjour", "Unable to start a conversation\n");
-				purple_debug_warning("bonjour", "send error: %s\n", strerror(errno));
-				conversation = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bb->name, data->account);
-				purple_conversation_write(conversation, NULL, 
-										_("Unable to send the message, the conversation couldn't be started."),
-										PURPLE_MESSAGE_SYSTEM, time(NULL));
-				close(bb->conversation->socket);
-				purple_input_remove(bb->conversation->watcher_id);
+			purple_debug_error("bonjour", "Unable to start a conversation\n");
+			purple_debug_warning("bonjour", "send error: %s\n", strerror(errno));
+			conversation = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bb->name, data->account);
+			purple_conversation_write(conversation, NULL,
+						  _("Unable to send the message, the conversation couldn't be started."),
+						  PURPLE_MESSAGE_SYSTEM, time(NULL));
+			close(bb->conversation->socket);
+			purple_input_remove(bb->conversation->watcher_id);
 
-				/* Free all the data related to the conversation */
-				g_free(bb->conversation->buddy_name);
-				g_free(bb->conversation);
-				bb->conversation = NULL;
-				g_free(message);
-				return 0;
+			/* Free all the data related to the conversation */
+			g_free(bb->conversation->buddy_name);
+			g_free(bb->conversation);
+			bb->conversation = NULL;
+			g_free(message);
+			return 0;
 		}
 
 		bb->conversation->stream_started = TRUE;
 	}
 
 	/* Send the message */
-	ret = _send_data(bb->conversation->socket, message) == -1;
+	ret = (_send_data(bb->conversation->socket, message) == -1);
 	g_free(message);
 
 	if (ret == -1)
@@ -662,30 +648,21 @@
 void
 bonjour_jabber_stop(BonjourJabber *data)
 {
-	PurpleBuddy *gb = NULL;
-	BonjourBuddy *bb = NULL;
-	GSList *buddies;
-	GSList *l;
+	/* Close the server socket and remove the watcher */
+	if (data->socket >= 0)
+		close(data->socket);
+	if (data->watcher_id > 0)
+		purple_input_remove(data->watcher_id);
 
-	/* Close the server socket and remove all the watcher */
-	close(data->socket);
-	purple_input_remove(data->watcher_id);
-
-	/* Close all the sockets and remove all the watchers after sending end streams */
+	/* Close all the conversation sockets and remove all the watchers after sending end streams */
 	if (data->account->gc != NULL)
 	{
+		GSList *buddies;
+		GSList *l;
+
 		buddies = purple_find_buddies(data->account, data->account->username);
 		for (l = buddies; l; l = l->next)
-		{
-			gb = (PurpleBuddy*)l->data;
-			bb = (BonjourBuddy*)gb->proto_data;
-			if (bb->conversation != NULL)
-			{
-				send(bb->conversation->socket, STREAM_END, strlen(STREAM_END), 0);
-				close(bb->conversation->socket);
-				purple_input_remove(bb->conversation->watcher_id);
-			}
-		}
+			bonjour_jabber_close_conversation(data, l->data);
 		g_slist_free(buddies);
 	}
 }
--- a/libpurple/protocols/jabber/jabber.c	Thu Jun 07 12:33:23 2007 +0000
+++ b/libpurple/protocols/jabber/jabber.c	Thu Jun 07 14:48:33 2007 +0000
@@ -463,7 +463,11 @@
 	JabberStream *js = gc->proto_data;
 
 	if (source < 0) {
-		purple_connection_error(gc, _("Couldn't connect to host"));
+		gchar *tmp;
+		tmp = g_strdup_printf(_("Could not establish a connection with the server:\n%s"),
+				error);
+		purple_connection_error(gc, tmp);
+		g_free(tmp);
 		return;
 	}
 
--- a/libpurple/protocols/jabber/si.c	Thu Jun 07 12:33:23 2007 +0000
+++ b/libpurple/protocols/jabber/si.c	Thu Jun 07 14:48:33 2007 +0000
@@ -105,6 +105,9 @@
 	jsx->connect_data = NULL;
 
 	if(source < 0) {
+		purple_debug_warning("jabber",
+				"si connection failed, jid was %s, host was %s, error was %s\n",
+				streamhost->jid, streamhost->host, error_message);
 		jsx->streamhosts = g_list_remove(jsx->streamhosts, streamhost);
 		g_free(streamhost->jid);
 		g_free(streamhost->host);
--- a/libpurple/protocols/msn/servconn.c	Thu Jun 07 12:33:23 2007 +0000
+++ b/libpurple/protocols/msn/servconn.c	Thu Jun 07 14:48:33 2007 +0000
@@ -195,6 +195,7 @@
 	}
 	else
 	{
+		purple_debug_error("msn", "Connection error: %s\n", error_message);
 		msn_servconn_got_error(servconn, MSN_SERVCONN_ERROR_CONNECT);
 	}
 }
--- a/pidgin/gtkconv.c	Thu Jun 07 12:33:23 2007 +0000
+++ b/pidgin/gtkconv.c	Thu Jun 07 14:48:33 2007 +0000
@@ -1212,6 +1212,37 @@
 }
 
 static void
+menu_insert_link_cb(gpointer data, guint action, GtkWidget *widget)
+{
+	PidginWindow *win = data;
+	PidginConversation *gtkconv;
+	GtkIMHtmlToolbar *toolbar;
+
+	gtkconv = pidgin_conv_window_get_active_gtkconv(win);
+	toolbar = GTK_IMHTMLTOOLBAR(gtkconv->toolbar);
+
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toolbar->link),
+			!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toolbar->link)));
+}
+
+static void
+menu_insert_image_cb(gpointer data, guint action, GtkWidget *widget)
+{
+	PidginWindow *win = data;
+	PurpleConversation *conv;
+	PidginConversation *gtkconv;
+	GtkIMHtmlToolbar *toolbar;
+
+	gtkconv = pidgin_conv_window_get_active_gtkconv(win);
+	conv    = gtkconv->active_conv;
+	toolbar = GTK_IMHTMLTOOLBAR(gtkconv->toolbar);
+
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toolbar->image),
+			!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toolbar->image)));
+}
+
+
+static void
 menu_alias_cb(gpointer data, guint action, GtkWidget *widget)
 {
 	PidginWindow *win = data;
@@ -2767,6 +2798,14 @@
 
 	{ "/Conversation/sep3", NULL, NULL, 0, "<Separator>", NULL },
 
+	{ N_("/Conversation/Insert Lin_k..."), NULL, menu_insert_link_cb, 0,
+		"<StockItem>", PIDGIN_STOCK_TOOLBAR_INSERT_LINK },
+	{ N_("/Conversation/Insert Imag_e..."), NULL, menu_insert_image_cb, 0,
+		"<StockItem>", PIDGIN_STOCK_TOOLBAR_INSERT_IMAGE },
+
+	{ "/Conversation/sep4", NULL, NULL, 0, "<Separator>", NULL },
+
+
 	{ N_("/Conversation/_Close"), NULL, menu_close_conv_cb, 0,
 			"<StockItem>", GTK_STOCK_CLOSE },
 
@@ -3046,6 +3085,18 @@
 		gtk_item_factory_get_widget(win->menu.item_factory,
 		                            N_("/Conversation/Remove..."));
 
+	/* --- */
+
+	win->menu.insert_link =
+		gtk_item_factory_get_widget(win->menu.item_factory,
+				N_("/Conversation/Insert Link..."));
+
+	win->menu.insert_image =
+		gtk_item_factory_get_widget(win->menu.item_factory,
+				N_("/Conversation/Insert Image..."));
+
+	/* --- */
+
 	win->menu.logging =
 		gtk_item_factory_get_widget(win->menu.item_factory,
 		                            N_("/Options/Enable Logging"));
@@ -5823,6 +5874,8 @@
 			gtk_widget_hide(win->menu.add);
 		}
 
+		gtk_widget_show(win->menu.insert_link);
+		gtk_widget_show(win->menu.insert_image);
 		gtk_widget_show(win->menu.show_icon);
 	} else if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) {
 		/* Show stuff that applies to Chats, hide stuff that applies to IMs */
@@ -5848,6 +5901,8 @@
 			gtk_widget_show(win->menu.remove);
 		}
 
+		gtk_widget_show(win->menu.insert_link);
+		gtk_widget_show(win->menu.insert_image);
 	}
 
 	/*
@@ -5889,6 +5944,8 @@
 		gtk_widget_set_sensitive(win->menu.add_pounce, TRUE);
 		gtk_widget_set_sensitive(win->menu.get_info, (prpl_info->get_info != NULL));
 		gtk_widget_set_sensitive(win->menu.invite, (prpl_info->chat_invite != NULL));
+		gtk_widget_set_sensitive(win->menu.insert_link, (conv->features & PURPLE_CONNECTION_HTML));
+		gtk_widget_set_sensitive(win->menu.insert_image, (prpl_info->options & OPT_PROTO_IM_IMAGE) && !(conv->features & PURPLE_CONNECTION_NO_IMAGES));
 
 		if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM)
 		{
@@ -5923,6 +5980,8 @@
 		gtk_widget_set_sensitive(win->menu.alias, FALSE);
 		gtk_widget_set_sensitive(win->menu.add, FALSE);
 		gtk_widget_set_sensitive(win->menu.remove, FALSE);
+		gtk_widget_set_sensitive(win->menu.insert_link, TRUE);
+		gtk_widget_set_sensitive(win->menu.insert_image, FALSE);
 	}
 
 	/*
--- a/pidgin/gtkdialogs.h	Thu Jun 07 12:33:23 2007 +0000
+++ b/pidgin/gtkdialogs.h	Thu Jun 07 14:48:33 2007 +0000
@@ -36,10 +36,15 @@
 void pidgin_dialogs_im_with_user(PurpleAccount *, const char *);
 void pidgin_dialogs_info(void);
 void pidgin_dialogs_log(void);
+
+/**
+ * @deprecated This function is no longer used and will be removed in
+ *             Pidgin 3.0.0 unless there is sufficient demand to keep it.
+ */
 void pidgin_dialogs_alias_contact(PurpleContact *);
+
 void pidgin_dialogs_alias_buddy(PurpleBuddy *);
 void pidgin_dialogs_alias_chat(PurpleChat *);
-
 void pidgin_dialogs_remove_buddy(PurpleBuddy *);
 void pidgin_dialogs_remove_group(PurpleGroup *);
 void pidgin_dialogs_remove_chat(PurpleChat *);
--- a/pidgin/gtkdocklet-x11.c	Thu Jun 07 12:33:23 2007 +0000
+++ b/pidgin/gtkdocklet-x11.c	Thu Jun 07 14:48:33 2007 +0000
@@ -281,7 +281,7 @@
 	 * The x11 docklet tracks whether it successfully embedded in a pref and
 	 * allows for a longer timeout period if it successfully embedded the last
 	 * time it was run. This should hopefully solve problems with the buddy
-	 * list not properly starting hidden when gaim is started on login.
+	 * list not properly starting hidden when Pidgin is started on login.
 	 */
 	if(!recreate) {
 		pidgin_docklet_embedded();
--- a/pidgin/gtkrequest.c	Thu Jun 07 12:33:23 2007 +0000
+++ b/pidgin/gtkrequest.c	Thu Jun 07 14:48:33 2007 +0000
@@ -323,7 +323,8 @@
 	/* Setup the dialog */
 	gtk_container_set_border_width(GTK_CONTAINER(dialog), PIDGIN_HIG_BORDER/2);
 	gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), PIDGIN_HIG_BORDER/2);
-	gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
+	if (!multiline)
+		gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
 	gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
 	gtk_dialog_set_default_response(GTK_DIALOG(dialog), 0);
 	gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog)->vbox), PIDGIN_HIG_BORDER);
@@ -341,7 +342,7 @@
 	/* Vertical box */
 	vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BORDER);
 
-	gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
+	gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 0);
 
 	/* Descriptive label */
 	primary_esc = (primary != NULL) ? g_markup_escape_text(primary, -1) : NULL;
@@ -359,7 +360,7 @@
 	gtk_label_set_markup(GTK_LABEL(label), label_text);
 	gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
 	gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
-	gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
+	gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
 
 	g_free(label_text);
 
--- a/pidgin/gtksavedstatuses.c	Thu Jun 07 12:33:23 2007 +0000
+++ b/pidgin/gtksavedstatuses.c	Thu Jun 07 14:48:33 2007 +0000
@@ -1130,7 +1130,7 @@
 
 	/* Status message */
 	hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
-	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
+	gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
 
 	label = gtk_label_new_with_mnemonic(_("_Message:"));
 	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
--- a/pidgin/win32/nsis/pidgin-installer.nsi	Thu Jun 07 12:33:23 2007 +0000
+++ b/pidgin/win32/nsis/pidgin-installer.nsi	Thu Jun 07 14:48:33 2007 +0000
@@ -1068,6 +1068,7 @@
 
   have_gtk:
     ; GTK+ is already installed; check version.
+	; Change this to not even run the GTK installer if this version is already installed.
     ${VersionCompare} ${GTK_INSTALL_VERSION} $0 $3
     IntCmp $3 1 +1 good_version good_version
     ${VersionCompare} ${GTK_MIN_VERSION} $0 $3
--- a/valgrind-suppressions	Thu Jun 07 12:33:23 2007 +0000
+++ b/valgrind-suppressions	Thu Jun 07 14:48:33 2007 +0000
@@ -147,8 +147,8 @@
    fun:PR_Init
    fun:rsa_nss_init
    fun:GE_plugin_load
-   fun:gaim_plugin_load
-   fun:gaim_plugins_load_saved
+   fun:purple_plugin_load
+   fun:purple_plugins_load_saved
    fun:main
 }