changeset 24656:918738a0bba4

propagate from branch 'im.pidgin.pidgin' (head be9df40b197dab92a74c4bf346f64e538f7f99e5) to branch 'im.pidgin.pidgin.openq' (head d2e4cd570e8e3995be990ee8ddf4fdfb8ce6226c)
author SHiNE CsyFeK <csyfek@gmail.com>
date Sat, 06 Dec 2008 13:30:06 +0000
parents c687fd9c379e (diff) e8c5688afdcd (current diff)
children 59aae7636111 eacf48c09ccc 333c1f6ece5e e1331f6126ba f326cf82e31c a0fd6a41d127
files
diffstat 11 files changed, 233 insertions(+), 142 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Sat Dec 06 13:27:25 2008 +0000
+++ b/ChangeLog	Sat Dec 06 13:30:06 2008 +0000
@@ -16,6 +16,9 @@
 	* Fix a crash in SIMPLE when a malformed message is received.
 	* purple-remote now has a "getstatusmessage" command to retrieve the text
 	  of the current status message.
+	* Various fixes to the nullprpl (Paul Aurich)
+	* Fix a crash when accessing the roomlist for an account that's not
+	  connected (Paul Aurich)
 
 	Gadu-Gadu:
 	* Fix some problems with Gadu-Gadu buddy icons (Adam Strzelecki)
@@ -47,6 +50,9 @@
 	      gtk-enable-tooltips = 0
 	* Moved the release notification dialog to a mini-dialog in the
 	  buddylist.  (Thanks to Casey Ho)
+	* Fix a crash when closing an authorization minidialog with the X then
+	  immediately going offline (Paul Aurich)
+	* Fix compatibility with old GTK+ yet again
 
 	Finch:
 	* Allow binding meta+arrow keys for actions.
--- a/finch/gntaccount.c	Sat Dec 06 13:27:25 2008 +0000
+++ b/finch/gntaccount.c	Sat Dec 06 13:30:06 2008 +0000
@@ -1069,6 +1069,8 @@
 			_("Authorize"), auth_cb,
 			_("Deny"), deny_cb);
 	}
+	g_signal_connect(G_OBJECT(uihandle), "destroy",
+		G_CALLBACK(purple_account_request_close), NULL);
 	g_free(buffer);
 	return uihandle;
 }
--- a/finch/gntroomlist.c	Sat Dec 06 13:27:25 2008 +0000
+++ b/finch/gntroomlist.c	Sat Dec 06 13:30:06 2008 +0000
@@ -239,7 +239,8 @@
 		PurpleConnection *gc = list->data;
 
 		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc));
-		if (prpl_info->roomlist_get_list != NULL) {
+		if (PURPLE_CONNECTION_IS_CONNECTED(gc) &&
+		        prpl_info->roomlist_get_list != NULL) {
 			PurpleAccount *account = purple_connection_get_account(gc);
 			char *text = g_strdup_printf("%s (%s)",
 					purple_account_get_username(account),
--- a/libpurple/protocols/null/nullprpl.c	Sat Dec 06 13:27:25 2008 +0000
+++ b/libpurple/protocols/null/nullprpl.c	Sat Dec 06 13:30:06 2008 +0000
@@ -160,8 +160,8 @@
 
 static void discover_status(PurpleConnection *from, PurpleConnection *to,
                             gpointer userdata) {
-  char *from_username = from->account->username;
-  char *to_username = to->account->username;
+  const char *from_username = from->account->username;
+  const char *to_username = to->account->username;
 
   if (purple_find_buddy(from->account, to_username)) {
     PurpleStatus *status = purple_account_get_active_status(to->account);
@@ -262,7 +262,7 @@
 
   } else {
     purple_debug_info("nullprpl", "...but %s is not logged in\n", buddy->name);
-    return "Not logged in";
+    return g_strdup("Not logged in");
   }
 }
 
@@ -275,9 +275,10 @@
     /* they're logged in */
     PurplePresence *presence = purple_buddy_get_presence(buddy);
     PurpleStatus *status = purple_presence_get_active_status(presence);
-    const char *msg = nullprpl_status_text(buddy);
+    char *msg = nullprpl_status_text(buddy);
     purple_notify_user_info_add_pair(info, purple_status_get_name(status),
                                      msg);
+    g_free(msg);
 
     if (full) {
       const char *user_info = purple_account_get_user_info(gc->account);
@@ -289,7 +290,7 @@
     /* they're not logged in */
     purple_notify_user_info_add_pair(info, _("User info"), _("not logged in"));
   }
-    
+
   purple_debug_info("nullprpl", "showing %s tooltip for %s\n",
                     (full) ? "full" : "short", buddy->name);
 }
@@ -307,21 +308,21 @@
                                 NULL_STATUS_ONLINE, TRUE);
   purple_status_type_add_attr(type, "message", _("Online"),
                               purple_value_new(PURPLE_TYPE_STRING));
-  types = g_list_append(types, type);
+  types = g_list_prepend(types, type);
 
   type = purple_status_type_new(PURPLE_STATUS_AWAY, NULL_STATUS_AWAY,
                                 NULL_STATUS_AWAY, TRUE);
   purple_status_type_add_attr(type, "message", _("Away"),
                               purple_value_new(PURPLE_TYPE_STRING));
-  types = g_list_append(types, type);
+  types = g_list_prepend(types, type);
   
   type = purple_status_type_new(PURPLE_STATUS_OFFLINE, NULL_STATUS_OFFLINE,
                                 NULL_STATUS_OFFLINE, TRUE);
   purple_status_type_add_attr(type, "message", _("Offline"),
                               purple_value_new(PURPLE_TYPE_STRING));
-  types = g_list_append(types, type);
+  types = g_list_prepend(types, type);
 
-  return types;
+  return g_list_reverse(types);
 }
 
 static void blist_example_menu_item(PurpleBlistNode *node, gpointer userdata) {
@@ -355,7 +356,7 @@
   purple_debug_info("nullprpl", "returning chat setting 'room'\n");
 
   pce = g_new0(struct proto_chat_entry, 1);
-  pce->label = _(_("Chat _room"));
+  pce->label = _("Chat _room");
   pce->identifier = "room";
   pce->required = TRUE;
 
@@ -477,7 +478,7 @@
                     gc->account->username, info);
 }
 
-static char *typing_state_to_string(PurpleTypingState typing) {
+static const char *typing_state_to_string(PurpleTypingState typing) {
   switch (typing) {
   case PURPLE_NOT_TYPING:  return "is not typing";
   case PURPLE_TYPING:      return "is typing";
@@ -488,8 +489,8 @@
 
 static void notify_typing(PurpleConnection *from, PurpleConnection *to,
                           gpointer typing) {
-  char *from_username = from->account->username;
-  char *action = typing_state_to_string((PurpleTypingState)typing);
+  const char *from_username = from->account->username;
+  const char *action = typing_state_to_string((PurpleTypingState)typing);
   purple_debug_info("nullprpl", "notifying %s that %s %s\n",
                     to->account->username, from_username, action);
 
@@ -561,7 +562,7 @@
 static void nullprpl_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy,
                                PurpleGroup *group)
 {
-  char *username = gc->account->username;
+  const char *username = gc->account->username;
   PurpleConnection *buddy_gc = get_nullprpl_gc(buddy->name);
 
   purple_debug_info("nullprpl", "adding %s to %s's buddy list\n", buddy->name,
@@ -679,8 +680,8 @@
 }
 
 static void nullprpl_join_chat(PurpleConnection *gc, GHashTable *components) {
-  char *username = gc->account->username;
-  char *room = g_hash_table_lookup(components, "room");
+  const char *username = gc->account->username;
+  const char *room = g_hash_table_lookup(components, "room");
   int chat_id = g_str_hash(room);
   purple_debug_info("nullprpl", "%s is joining chat room %s\n", username, room);
 
@@ -690,20 +691,20 @@
     /* tell everyone that we joined, and add them if they're already there */
     foreach_gc_in_chat(joined_chat, gc, chat_id, NULL);
   } else {
+    char *tmp = g_strdup_printf(_("%s is already in chat room %s."),
+                                username,
+                                room);
     purple_debug_info("nullprpl", "%s is already in chat room %s\n", username,
                       room);
-    purple_notify_info(gc,
-                       _("Join chat"),
-                       _("Join chat"),
-                       g_strdup_printf("%s is already in chat room %s.",
-                                       username, room));
+    purple_notify_info(gc, _("Join chat"), _("Join chat"), tmp);
+    g_free(tmp);
   }
 }
 
 static void nullprpl_reject_chat(PurpleConnection *gc, GHashTable *components) {
-  char *invited_by = g_hash_table_lookup(components, "invited_by");
-  char *room = g_hash_table_lookup(components, "room");
-  char *username = gc->account->username;
+  const char *invited_by = g_hash_table_lookup(components, "invited_by");
+  const char *room = g_hash_table_lookup(components, "room");
+  const char *username = gc->account->username;
   PurpleConnection *invited_by_gc = get_nullprpl_gc(invited_by);
   char *message = g_strdup_printf(
     "%s %s %s.",
@@ -719,19 +720,20 @@
                      _("Chat invitation rejected"),
                      _("Chat invitation rejected"),
                      message);
+  g_free(message);
 }
 
 static char *nullprpl_get_chat_name(GHashTable *components) {
-  char *room = g_hash_table_lookup(components, "room");
+  const char *room = g_hash_table_lookup(components, "room");
   purple_debug_info("nullprpl", "reporting chat room name '%s'\n", room);
-  return room;
+  return g_strdup(room);
 }
 
 static void nullprpl_chat_invite(PurpleConnection *gc, int id,
                                  const char *message, const char *who) {
-  char *username = gc->account->username;
+  const char *username = gc->account->username;
   PurpleConversation *conv = purple_find_chat(gc, id);
-  char *room = conv->name;
+  const char *room = conv->name;
   PurpleAccount *to_acct = purple_accounts_find(who, NULLPRPL_ID);
 
   purple_debug_info("nullprpl", "%s is inviting %s to join chat room %s\n",
@@ -740,18 +742,16 @@
   if (to_acct) {
     PurpleConversation *to_conv = purple_find_chat(to_acct->gc, id);
     if (to_conv) {
+      char *tmp = g_strdup_printf("%s is already in chat room %s.", who, room);
       purple_debug_info("nullprpl",
                         "%s is already in chat room %s; "
                         "ignoring invitation from %s\n",
                         who, room, username);
-      purple_notify_info(gc,
-                         _("Chat invitation"),
-                         _("Chat invitation"),
-                         g_strdup_printf("%s is already in chat room %s.",
-                                         who, room));
+      purple_notify_info(gc, _("Chat invitation"), _("Chat invitation"), tmp);
+      g_free(tmp);
     } else {
       GHashTable *components;
-      components = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, free);
+      components = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free);
       g_hash_table_replace(components, "room", g_strdup(room));
       g_hash_table_replace(components, "invited_by", g_strdup(username));
       serv_got_chat_invite(to_acct->gc, room, username, message, components);
@@ -833,7 +833,7 @@
 
 static void nullprpl_chat_whisper(PurpleConnection *gc, int id, const char *who,
                                   const char *message) {
-  char *username = gc->account->username;
+  const char *username = gc->account->username;
   PurpleConversation *conv = purple_find_chat(gc, id);
   purple_debug_info("nullprpl",
                     "%s receives whisper from %s in chat room %s: %s\n",
@@ -858,7 +858,7 @@
 
 static int nullprpl_chat_send(PurpleConnection *gc, int id, const char *message,
                               PurpleMessageFlags flags) {
-  char *username = gc->account->username;
+  const char *username = gc->account->username;
   PurpleConversation *conv = purple_find_chat(gc, id);
 
   if (conv) {
@@ -981,7 +981,7 @@
 }
 
 static PurpleRoomlist *nullprpl_roomlist_get_list(PurpleConnection *gc) {
-  char *username = gc->account->username;
+  const char *username = gc->account->username;
   PurpleRoomlist *roomlist = purple_roomlist_new(gc->account);
   GList *fields = NULL;
   PurpleRoomlistField *field;
@@ -1005,14 +1005,17 @@
   for (chats  = purple_get_chats(); chats; chats = g_list_next(chats)) {
     PurpleConversation *conv = (PurpleConversation *)chats->data;
     PurpleRoomlistRoom *room;
-    char *name = conv->name;
+    const char *name = conv->name;
     int id = purple_conversation_get_chat_data(conv)->id;
 
     /* have we already added this room? */
     if (g_list_find_custom(seen_ids, name, (GCompareFunc)strcmp))
       continue;                                /* yes! try the next one. */
 
-    seen_ids = g_list_append(seen_ids, name);  /* no, it's new. */
+    /* This cast is OK because this list is only staying around for the life
+     * of this function and none of the conversations are being deleted
+	 * in that timespan. */
+    seen_ids = g_list_prepend(seen_ids, (char *)name); /* no, it's new. */
     purple_debug_info("nullprpl", "%s (%d), ", name, id);
 
     room = purple_roomlist_room_new(PURPLE_ROOMLIST_ROOMTYPE_ROOM, name, NULL);
@@ -1021,6 +1024,7 @@
     purple_roomlist_room_add(roomlist, room);
   }
 
+  g_list_free(seen_ids);
   purple_timeout_add(1 /* ms */, nullprpl_finish_get_roomlist, roomlist);
   return roomlist;
 }
--- a/libpurple/protocols/yahoo/yahoo.c	Sat Dec 06 13:27:25 2008 +0000
+++ b/libpurple/protocols/yahoo/yahoo.c	Sat Dec 06 13:30:06 2008 +0000
@@ -2706,6 +2706,7 @@
 			  strncmp(buf, "HTTP/1.1 302", strlen("HTTP/1.1 302")))) {
 		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
 			_("Received unexpected HTTP response from server."));
+		purple_debug_misc("yahoo", "Unexpected HTTP response: %s\n", buf);
 		return;
 	}
 
@@ -2802,7 +2803,7 @@
 
 static void yahoo_login_page_hash_iter(const char *key, const char *val, GString *url)
 {
-	if (!strcmp(key, "passwd"))
+	if (!strcmp(key, "passwd") || !strcmp(key, "login"))
 		return;
 	g_string_append_c(url, '&');
 	g_string_append(url, key);
--- a/libpurple/roomlist.c	Sat Dec 06 13:27:25 2008 +0000
+++ b/libpurple/roomlist.c	Sat Dec 06 13:30:06 2008 +0000
@@ -173,6 +173,7 @@
 	PurplePluginProtocolInfo *prpl_info = NULL;
 
 	g_return_val_if_fail(gc != NULL, NULL);
+	g_return_val_if_fail(PURPLE_CONNECTION_IS_CONNECTED(gc), NULL);
 
 	prpl = purple_connection_get_prpl(gc);
 
--- a/libpurple/util.c	Sat Dec 06 13:27:25 2008 +0000
+++ b/libpurple/util.c	Sat Dec 06 13:30:06 2008 +0000
@@ -56,6 +56,8 @@
 	gsize request_written;
 	gboolean include_headers;
 
+	gboolean is_ssl;
+	PurpleSslConnection *ssl_connection;
 	PurpleProxyConnectData *connect_data;
 	int fd;
 	guint inpa;
@@ -3443,9 +3445,6 @@
 	char *cmd;
 	GHashTable *params = NULL;
 	int len;
-
-	g_return_if_fail(uri != NULL);
-
 	if (!(tmp = strchr(uri, ':')) || tmp == uri) {
 		purple_debug_error("util", "Malformed protocol handler message - missing protocol.\n");
 		return;
@@ -3518,6 +3517,7 @@
 purple_url_parse(const char *url, char **ret_host, int *ret_port,
 			   char **ret_path, char **ret_user, char **ret_passwd)
 {
+	gboolean is_https = FALSE;
 	char scan_info[255];
 	char port_str[6];
 	int f;
@@ -3541,6 +3541,7 @@
 	}
 	else if ((turl = purple_strcasestr(url, "https://")) != NULL)
 	{
+		is_https = TRUE;
 		turl += 8;
 		url = turl;
 	}
@@ -3581,7 +3582,11 @@
 				   "%%255[%s]/%%255[%s]",
 				   addr_ctrl, page_ctrl);
 		f = sscanf(url, scan_info, host, path);
-		g_snprintf(port_str, sizeof(port_str), "80");
+		/* Use the default port */
+		if (is_https)
+			g_snprintf(port_str, sizeof(port_str), "443");
+		else
+			g_snprintf(port_str, sizeof(port_str), "80");
 	}
 
 	if (f == 0)
@@ -3620,6 +3625,8 @@
 }
 
 static void url_fetch_connect_cb(gpointer url_data, gint source, const gchar *error_message);
+static void ssl_url_fetch_connect_cb(gpointer data, PurpleSslConnection *ssl_connection, PurpleInputCondition cond);
+static void ssl_url_fetch_error_cb(PurpleSslConnection *ssl_connection, PurpleSslErrorType error, gpointer data);
 
 static gboolean
 parse_redirect(const char *data, size_t data_len,
@@ -3686,10 +3693,16 @@
 	g_free(gfud->request);
 	gfud->request = NULL;
 
-	purple_input_remove(gfud->inpa);
-	gfud->inpa = 0;
-	close(gfud->fd);
-	gfud->fd = -1;
+	if (gfud->is_ssl) {
+		gfud->is_ssl = FALSE;
+		purple_ssl_close(gfud->ssl_connection);
+		gfud->ssl_connection = NULL;
+	} else {
+		purple_input_remove(gfud->inpa);
+		gfud->inpa = 0;
+		close(gfud->fd);
+		gfud->fd = -1;
+	}
 	gfud->request_written = 0;
 	gfud->len = 0;
 	gfud->data_len = 0;
@@ -3701,11 +3714,18 @@
 	purple_url_parse(new_url, &gfud->website.address, &gfud->website.port,
 				   &gfud->website.page, &gfud->website.user, &gfud->website.passwd);
 
-	gfud->connect_data = purple_proxy_connect(NULL, NULL,
-			gfud->website.address, gfud->website.port,
-			url_fetch_connect_cb, gfud);
-
-	if (gfud->connect_data == NULL)
+	if (purple_strcasestr(new_url, "https://") != NULL) {
+		gfud->is_ssl = TRUE;
+		gfud->ssl_connection = purple_ssl_connect(NULL,
+				gfud->website.address, gfud->website.port,
+				ssl_url_fetch_connect_cb, ssl_url_fetch_error_cb, gfud);
+	} else {
+		gfud->connect_data = purple_proxy_connect(NULL, NULL,
+				gfud->website.address, gfud->website.port,
+				url_fetch_connect_cb, gfud);
+	}
+
+	if (gfud->ssl_connection == NULL && gfud->connect_data == NULL)
 	{
 		purple_util_fetch_url_error(gfud, _("Unable to connect to %s"),
 				gfud->website.address);
@@ -3766,8 +3786,14 @@
 	char *data_cursor;
 	gboolean got_eof = FALSE;
 
-	while((len = read(source, buf, sizeof(buf))) > 0) {
-
+	/*
+	 * Read data in a loop until we can't read any more!  This is a
+	 * little confusing because we read using a different function
+	 * depending on whether the socket is ssl or cleartext.
+	 */
+	while ((gfud->is_ssl && ((len = purple_ssl_read(gfud->ssl_connection, buf, sizeof(buf))) > 0)) ||
+			(!gfud->is_ssl && (len = read(source, buf, sizeof(buf))) > 0))
+	{
 		if(gfud->max_len != -1 && (gfud->len + len) > gfud->max_len) {
 			purple_util_fetch_url_error(gfud, _("Error reading from %s: response too long (%d bytes limit)"),
 						    gfud->website.address, gfud->max_len);
@@ -3887,6 +3913,21 @@
 	}
 }
 
+static void ssl_url_fetch_recv_cb(gpointer data, PurpleSslConnection *ssl_connection, PurpleInputCondition cond)
+{
+	url_fetch_recv_cb(data, -1, cond);
+}
+
+/*
+ * This function is called when the socket is available to be written
+ * to.
+ *
+ * @param source The file descriptor that can be written to.  This can
+ *        be an http connection or it can be the SSL connection of an
+ *        https request.  So be careful what you use it for!  If it's
+ *        an https request then use purple_ssl_write() instead of
+ *        writing to it directly.
+ */
 static void
 url_fetch_send_cb(gpointer data, gint source, PurpleInputCondition cond)
 {
@@ -3895,53 +3936,14 @@
 
 	gfud = data;
 
-	total_len = strlen(gfud->request);
-
-	len = write(gfud->fd, gfud->request + gfud->request_written,
-			total_len - gfud->request_written);
-
-	if (len < 0 && errno == EAGAIN)
-		return;
-	else if (len < 0) {
-		purple_util_fetch_url_error(gfud, _("Error writing to %s: %s"),
-				gfud->website.address, g_strerror(errno));
-		return;
-	}
-	gfud->request_written += len;
-
-	if (gfud->request_written < total_len)
-		return;
-
-	/* We're done writing our request, now start reading the response */
-	purple_input_remove(gfud->inpa);
-	gfud->inpa = purple_input_add(gfud->fd, PURPLE_INPUT_READ, url_fetch_recv_cb,
-		gfud);
-}
-
-static void
-url_fetch_connect_cb(gpointer url_data, gint source, const gchar *error_message)
-{
-	PurpleUtilFetchUrlData *gfud;
-
-	gfud = url_data;
-	gfud->connect_data = NULL;
-
-	if (source == -1)
+	if (gfud->request == NULL)
 	{
-		purple_util_fetch_url_error(gfud, _("Unable to connect to %s: %s"),
-				(gfud->website.address ? gfud->website.address : ""), error_message);
-		return;
-	}
-
-	gfud->fd = source;
-
-	if (!gfud->request) {
+		/* Host header is not forbidden in HTTP/1.0 requests, and HTTP/1.1
+		 * clients must know how to handle the "chunked" transfer encoding.
+		 * Purple doesn't know how to handle "chunked", so should always send
+		 * the Host header regardless, to get around some observed problems
+		 */
 		if (gfud->user_agent) {
-			/* Host header is not forbidden in HTTP/1.0 requests, and HTTP/1.1
-			 * clients must know how to handle the "chunked" transfer encoding.
-			 * Purple doesn't know how to handle "chunked", so should always send
-			 * the Host header regardless, to get around some observed problems
-			 */
 			gfud->request = g_strdup_printf(
 				"GET %s%s HTTP/%s\r\n"
 				"Connection: close\r\n"
@@ -3968,11 +3970,84 @@
 
 	purple_debug_misc("util", "Request: '%s'\n", gfud->request);
 
+	total_len = strlen(gfud->request);
+
+	if (gfud->is_ssl)
+		len = purple_ssl_write(gfud->ssl_connection, gfud->request + gfud->request_written,
+				total_len - gfud->request_written);
+	else
+		len = write(gfud->fd, gfud->request + gfud->request_written,
+				total_len - gfud->request_written);
+
+	if (len < 0 && errno == EAGAIN)
+		return;
+	else if (len < 0) {
+		purple_util_fetch_url_error(gfud, _("Error writing to %s: %s"),
+				gfud->website.address, g_strerror(errno));
+		return;
+	}
+	gfud->request_written += len;
+
+	if (gfud->request_written < total_len)
+		return;
+
+	/* We're done writing our request, now start reading the response */
+	if (gfud->is_ssl) {
+		purple_input_remove(gfud->inpa);
+		gfud->inpa = 0;
+		purple_ssl_input_add(gfud->ssl_connection, ssl_url_fetch_recv_cb, gfud);
+	} else {
+		purple_input_remove(gfud->inpa);
+		gfud->inpa = purple_input_add(gfud->fd, PURPLE_INPUT_READ, url_fetch_recv_cb,
+			gfud);
+	}
+}
+
+static void
+url_fetch_connect_cb(gpointer url_data, gint source, const gchar *error_message)
+{
+	PurpleUtilFetchUrlData *gfud;
+
+	gfud = url_data;
+	gfud->connect_data = NULL;
+
+	if (source == -1)
+	{
+		purple_util_fetch_url_error(gfud, _("Unable to connect to %s: %s"),
+				(gfud->website.address ? gfud->website.address : ""), error_message);
+		return;
+	}
+
+	gfud->fd = source;
+
 	gfud->inpa = purple_input_add(source, PURPLE_INPUT_WRITE,
 								url_fetch_send_cb, gfud);
 	url_fetch_send_cb(gfud, source, PURPLE_INPUT_WRITE);
 }
 
+static void ssl_url_fetch_connect_cb(gpointer data, PurpleSslConnection *ssl_connection, PurpleInputCondition cond)
+{
+	PurpleUtilFetchUrlData *gfud;
+
+	gfud = data;
+
+	gfud->inpa = purple_input_add(ssl_connection->fd, PURPLE_INPUT_WRITE,
+			url_fetch_send_cb, gfud);
+	url_fetch_send_cb(gfud, ssl_connection->fd, PURPLE_INPUT_WRITE);
+}
+
+static void ssl_url_fetch_error_cb(PurpleSslConnection *ssl_connection, PurpleSslErrorType error, gpointer data)
+{
+	PurpleUtilFetchUrlData *gfud;
+
+	gfud = data;
+	gfud->ssl_connection = NULL;
+
+	purple_util_fetch_url_error(gfud, _("Unable to connect to %s: %s"),
+			(gfud->website.address ? gfud->website.address : ""),
+	purple_ssl_strerror(error));
+}
+
 PurpleUtilFetchUrlData *
 purple_util_fetch_url_request(const char *url, gboolean full,
 		const char *user_agent, gboolean http11,
@@ -3985,13 +4060,6 @@
 					     callback, user_data);
 }
 
-static gboolean
-url_fetch_connect_failed(gpointer data)
-{
-	url_fetch_connect_cb(data, -1, "");
-	return FALSE;
-}
-
 PurpleUtilFetchUrlData *
 purple_util_fetch_url_request_len(const char *url, gboolean full,
 		const char *user_agent, gboolean http11,
@@ -4023,14 +4091,22 @@
 	purple_url_parse(url, &gfud->website.address, &gfud->website.port,
 				   &gfud->website.page, &gfud->website.user, &gfud->website.passwd);
 
-	gfud->connect_data = purple_proxy_connect(NULL, NULL,
-			gfud->website.address, gfud->website.port,
-			url_fetch_connect_cb, gfud);
-
-	if (gfud->connect_data == NULL)
+	if (purple_strcasestr(url, "https://") != NULL) {
+		gfud->is_ssl = TRUE;
+		gfud->ssl_connection = purple_ssl_connect(NULL,
+				gfud->website.address, gfud->website.port,
+				ssl_url_fetch_connect_cb, ssl_url_fetch_error_cb, gfud);
+	} else {
+		gfud->connect_data = purple_proxy_connect(NULL, NULL,
+				gfud->website.address, gfud->website.port,
+				url_fetch_connect_cb, gfud);
+	}
+
+	if (gfud->ssl_connection == NULL && gfud->connect_data == NULL)
 	{
-		/* Trigger the connect_cb asynchronously. */
-		purple_timeout_add(10, url_fetch_connect_failed, gfud);
+		purple_util_fetch_url_error(gfud, _("Unable to connect to %s"),
+				gfud->website.address);
+		return NULL;
 	}
 
 	return gfud;
@@ -4039,6 +4115,9 @@
 void
 purple_util_fetch_url_cancel(PurpleUtilFetchUrlData *gfud)
 {
+	if (gfud->ssl_connection != NULL)
+		purple_ssl_close(gfud->ssl_connection);
+
 	if (gfud->connect_data != NULL)
 		purple_proxy_connect_cancel(gfud->connect_data);
 
--- a/pidgin/gtkaccount.c	Sat Dec 06 13:27:25 2008 +0000
+++ b/pidgin/gtkaccount.c	Sat Dec 06 13:30:06 2008 +0000
@@ -2425,25 +2425,25 @@
 };
 
 static void
-authorize_and_add_cb(struct auth_and_add *aa)
+free_auth_and_add(struct auth_and_add *aa)
 {
-	aa->auth_cb(aa->data);
-	purple_blist_request_add_buddy(aa->account, aa->username,
-	 	                    NULL, aa->alias);
-
 	g_free(aa->username);
 	g_free(aa->alias);
 	g_free(aa);
 }
 
 static void
+authorize_and_add_cb(struct auth_and_add *aa)
+{
+	aa->auth_cb(aa->data);
+	purple_blist_request_add_buddy(aa->account, aa->username,
+	 	                    NULL, aa->alias);
+}
+
+static void
 deny_no_add_cb(struct auth_and_add *aa)
 {
 	aa->deny_cb(aa->data);
-
-	g_free(aa->username);
-	g_free(aa->alias);
-	g_free(aa);
 }
 
 static void *
@@ -2492,7 +2492,7 @@
 						  _("Authorize"), authorize_and_add_cb,
 						  _("Deny"), deny_no_add_cb,
 						  NULL);
-		g_object_set_data(G_OBJECT(alert), "auth_and_add", aa);
+		g_signal_connect_swapped(G_OBJECT(alert), "destroy", G_CALLBACK(free_auth_and_add), aa);
 	} else {
 		alert = pidgin_make_mini_dialog(gc, PIDGIN_STOCK_DIALOG_QUESTION,
 						  _("Authorize buddy?"), buffer, user_data,
@@ -2501,6 +2501,8 @@
 						  NULL);
 	}
 	pidgin_blist_add_alert(alert);
+	g_signal_connect(G_OBJECT(alert), "destroy",
+		G_CALLBACK(purple_account_request_close), NULL);
 
 	g_free(buffer);
 
@@ -2510,13 +2512,6 @@
 static void
 pidgin_accounts_request_close(void *ui_handle)
 {
-	/* This is super ugly, but without API changes, this is how it works */
-	struct auth_and_add *aa = g_object_get_data(G_OBJECT(ui_handle), "auth_and_add");
-	if (aa != NULL) {
-		g_free(aa->username);
-		g_free(aa->alias);
-		g_free(aa);
-	}
 	gtk_widget_destroy(GTK_WIDGET(ui_handle));
 }
 
--- a/pidgin/gtkconv.c	Sat Dec 06 13:27:25 2008 +0000
+++ b/pidgin/gtkconv.c	Sat Dec 06 13:30:06 2008 +0000
@@ -7282,18 +7282,14 @@
 	if(purple_status_is_available(oldstatus) || !purple_status_is_available(newstatus))
 		return;
 
-	while ((l = hidden_convwin->gtkconvs) != NULL)
-	{
+	for (l = hidden_convwin->gtkconvs; l; ) {
 		gtkconv = l->data;
+		l = l->next;
 
 		conv = gtkconv->active_conv;
-
-		while(l && !purple_status_is_available(
-					purple_account_get_active_status(
-					purple_conversation_get_account(conv))))
-			l = l->next;
-		if (!l)
-			break;
+		if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT ||
+				account != purple_conversation_get_account(conv))
+			continue;
 
 		pidgin_conv_attach_to_conversation(conv);
 
--- a/pidgin/gtkroomlist.c	Sat Dec 06 13:27:25 2008 +0000
+++ b/pidgin/gtkroomlist.c	Sat Dec 06 13:30:06 2008 +0000
@@ -488,7 +488,7 @@
 	PurpleConnection *conn = purple_account_get_connection(account);
 	PurplePluginProtocolInfo *prpl_info = NULL;
 
-	if (conn)
+	if (conn && PURPLE_CONNECTION_IS_CONNECTED(conn))
 		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(conn->prpl);
 
 	return (prpl_info && prpl_info->roomlist_get_list != NULL);
--- a/pidgin/gtkutils.c	Sat Dec 06 13:27:25 2008 +0000
+++ b/pidgin/gtkutils.c	Sat Dec 06 13:30:06 2008 +0000
@@ -3276,7 +3276,13 @@
 static void
 combo_box_changed_cb(GtkComboBox *combo_box, GtkEntry *entry)
 {
+#if GTK_CHECK_VERSION(2, 6, 0)
 	char *text = gtk_combo_box_get_active_text(combo_box);
+#else
+	GtkWidget *widget = gtk_bin_get_child(GTK_BIN(combo_box));
+	char *text = g_strdup(gtk_entry_get_text(GTK_ENTRY(widget)));
+#endif
+
 	gtk_entry_set_text(entry, text ? text : "");
 	g_free(text);
 }