changeset 21593:b1f36f7652c2

merge of '22963f332a80135af80a80919aee45d70dd0e1c0' and '5268d2ff6deab0c7a6744188ed0062bdeed9cf62'
author Evan Schoenberg <evan.s@dreskin.net>
date Mon, 19 Nov 2007 08:07:11 +0000
parents 25a522f544f9 (diff) 68b036c452f3 (current diff)
children f5874552b8d5
files
diffstat 16 files changed, 210 insertions(+), 137 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile.mingw	Mon Nov 19 08:05:36 2007 +0000
+++ b/Makefile.mingw	Mon Nov 19 08:07:11 2007 +0000
@@ -97,15 +97,15 @@
 
 installer: create_release_install_dir
 	$(MAKENSIS) /V3 /DPIDGIN_VERSION="$(PIDGIN_VERSION)" /DPIDGIN_PRODUCT_VERSION="$(PIDGIN_PRODUCT_VERSION)" /DWITH_GTK /DPIDGIN_INSTALL_DIR="$(STRIPPED_RELEASE_DIR)" /DGTK_INSTALL_VERSION="$(GTK_INSTALL_VERSION)" pidgin/win32/nsis/pidgin-installer.nsi
-	mv pidgin/win32/nsis/pidgin*.exe ./
+	mv pidgin/win32/nsis/pidgin-$(PIDGIN_VERSION).exe ./
 
 installer_nogtk: create_release_install_dir
 	$(MAKENSIS) /V3 /DPIDGIN_VERSION="$(PIDGIN_VERSION)" /DPIDGIN_PRODUCT_VERSION="$(PIDGIN_PRODUCT_VERSION)" /DPIDGIN_INSTALL_DIR="$(STRIPPED_RELEASE_DIR)" /DGTK_INSTALL_VERSION="$(GTK_INSTALL_VERSION)" pidgin/win32/nsis/pidgin-installer.nsi
-	mv pidgin/win32/nsis/pidgin*.exe ./
+	mv pidgin/win32/nsis/pidgin-$(PIDGIN_VERSION)-no-gtk.exe ./
 
 installer_debug: install
 	$(MAKENSIS) /V3 /DPIDGIN_VERSION="$(PIDGIN_VERSION)" /DPIDGIN_PRODUCT_VERSION="$(PIDGIN_PRODUCT_VERSION)" /DPIDGIN_INSTALL_DIR="$(PIDGIN_INSTALL_DIR)" /DDEBUG /DGTK_INSTALL_VERSION="$(GTK_INSTALL_VERSION)" pidgin/win32/nsis/pidgin-installer.nsi
-	mv pidgin/win32/nsis/pidgin*.exe ./
+	mv pidgin/win32/nsis/pidgin-$(PIDGIN_VERSION)-debug.exe ./
 
 installer_zip: create_release_install_dir
 	rm -f pidgin-$(PIDGIN_VERSION)-win32-bin.zip
@@ -124,10 +124,11 @@
 	$(MAKE) -C $(PURPLE_PO_TOP) -f $(MINGW_MAKEFILE) clean
 	$(MAKE) -C $(PIDGIN_TOP) -f $(MINGW_MAKEFILE) clean
 	$(MAKE) -C $(PURPLE_TOP) -f $(MINGW_MAKEFILE) clean
-	rm -f $(PIDGIN_CONFIG_H) ./VERSION pidgin*.exe
+	rm -f $(PIDGIN_CONFIG_H) ./VERSION pidgin-$(PIDGIN_VERSION)*.exe pidgin-$(PIDGIN_VERSION)-win32-bin.zip
 	rm -rf doc/html Doxyfile.mingw
 
 uninstall:
-	rm -rf $(PURPLE_INSTALL_PERLMOD_DIR) $(PIDGIN_INSTALL_PLUGINS_DIR) $(PURPLE_INSTALL_PO_DIR) $(PIDGIN_INSTALL_DIR) $(PIDGIN_INSTALL_DIR).release
+	rm -rf $(PURPLE_INSTALL_PERLMOD_DIR) $(PIDGIN_INSTALL_PLUGINS_DIR) $(PURPLE_INSTALL_PO_DIR) $(PIDGIN_INSTALL_DIR) $(STRIPPED_RELEASE_DIR)
+	rm -f ./VERSION
 
 include $(PIDGIN_COMMON_TARGETS)
--- a/libpurple/Makefile.mingw	Mon Nov 19 08:05:36 2007 +0000
+++ b/libpurple/Makefile.mingw	Mon Nov 19 08:07:11 2007 +0000
@@ -128,7 +128,7 @@
 ## CLEAN RULES
 ##
 clean:
-	rm -f $(OBJECTS) $(RC_SRC) $(PURPLE_VERSION_H)
+	rm -f $(OBJECTS) $(RC_SRC) $(PURPLE_VERSION_H) $(PURPLE_PURPLE_H)
 	rm -f $(TARGET).dll $(TARGET).dll.a $(TARGET).def
 	$(MAKE) -C $(PURPLE_PROTOS_TOP) -f $(MINGW_MAKEFILE) clean
 	$(MAKE) -C $(PURPLE_PLUGINS_TOP) -f $(MINGW_MAKEFILE) clean
--- a/libpurple/buddyicon.c	Mon Nov 19 08:05:36 2007 +0000
+++ b/libpurple/buddyicon.c	Mon Nov 19 08:07:11 2007 +0000
@@ -689,8 +689,6 @@
 	PurpleStoredImage *img = NULL;
 	char *old_icon;
 
-	old_img = g_hash_table_lookup(pointer_icon_cache, account);
-
 	if (icon_data != NULL && icon_len > 0)
 	{
 		img = purple_buddy_icon_data_new(icon_data, icon_len, NULL);
@@ -728,7 +726,7 @@
 			prpl_info->set_buddy_icon(gc, img);
 	}
 
-	if (old_img)
+	if ((old_img = g_hash_table_lookup(pointer_icon_cache, account)))
 		purple_imgstore_unref(old_img);
 	else if (old_icon)
 	{
--- a/libpurple/ft.c	Mon Nov 19 08:05:36 2007 +0000
+++ b/libpurple/ft.c	Mon Nov 19 08:07:11 2007 +0000
@@ -998,6 +998,11 @@
 {
 	PurpleXfer *xfer = (PurpleXfer *)data;
 
+	if (source < 0) {
+		purple_xfer_cancel_local(xfer);
+		return;
+	}
+
 	xfer->fd = source;
 
 	begin_transfer(xfer, PURPLE_INPUT_READ);
--- a/libpurple/protocols/irc/dcc_send.c	Mon Nov 19 08:05:36 2007 +0000
+++ b/libpurple/protocols/irc/dcc_send.c	Mon Nov 19 08:07:11 2007 +0000
@@ -40,9 +40,7 @@
 {
 	struct irc_xfer_rx_data *xd = xfer->data;
 
-	if (xd->ip != NULL)
-		g_free(xd->ip);
-
+	g_free(xd->ip);
 	g_free(xd);
 }
 
@@ -123,8 +121,8 @@
 		} else {
 			xd->ip = g_strdup(token[i]);
 		}
-		purple_debug(PURPLE_DEBUG_INFO, "irc", "Receiving file from %s\n",
-				   xd->ip);
+		purple_debug(PURPLE_DEBUG_INFO, "irc", "Receiving file (%s) from %s\n",
+			     filename->str, xd->ip);
 		purple_xfer_set_size(xfer, token[i+2] ? atoi(token[i+2]) : 0);
 		
 		purple_xfer_set_init_fnc(xfer, irc_dccsend_recv_init);
@@ -166,8 +164,7 @@
 	if (xd->fd != -1)
 		close(xd->fd);
 
-	if (xd->rxqueue)
-		g_free(xd->rxqueue);
+	g_free(xd->rxqueue);
 
 	g_free(xd);
 }
--- a/libpurple/protocols/msn/soap2.c	Mon Nov 19 08:05:36 2007 +0000
+++ b/libpurple/protocols/msn/soap2.c	Mon Nov 19 08:07:11 2007 +0000
@@ -208,45 +208,44 @@
 msn_soap_handle_body(MsnSoapConnection *conn, MsnSoapMessage *response)
 {
 	xmlnode *body = xmlnode_get_child(response->xml, "Body");
-
-	if (body) {
-		MsnSoapRequest *request;
+	xmlnode *fault = xmlnode_get_child(response->xml, "Fault");
 
-		if (strcmp(body->name, "Fault") == 0) {
-			xmlnode *fault = xmlnode_get_child(body, "faultcode");
+	if (fault) {
+		xmlnode *faultcode = xmlnode_get_child(fault, "faultcode");
 
-			if (fault != NULL) {
-				char *faultdata = xmlnode_get_data(fault);
-
-				if (strcmp(faultdata, "psf:Redirect") == 0) {
-					xmlnode *url = xmlnode_get_child(body, "redirectUrl");
+		if (faultcode != NULL) {
+			char *faultdata = xmlnode_get_data(faultcode);
 
-					if (url) {
-						char *urldata = xmlnode_get_data(url);
-						msn_soap_handle_redirect(conn, urldata);
-						g_free(urldata);
-					}
+			if (g_str_equal(faultdata, "psf:Redirect")) {
+				xmlnode *url = xmlnode_get_child(body, "redirectUrl");
 
-					g_free(faultdata);
-					return TRUE;
-				} else if (strcmp(faultdata, "wsse:FailedAuthentication") == 0) {
-					xmlnode *reason = xmlnode_get_child(body, "faultstring");
-					char *reasondata = xmlnode_get_data(reason);
-
-					msn_soap_connection_sanitize(conn, TRUE);
-					msn_session_set_error(conn->session, MSN_ERROR_AUTH,
-						reasondata);
-
-					g_free(reasondata);
-					g_free(faultdata);
-					return FALSE;
+				if (url) {
+					char *urldata = xmlnode_get_data(url);
+					msn_soap_handle_redirect(conn, urldata);
+					g_free(urldata);
 				}
 
 				g_free(faultdata);
+				return TRUE;
+			} else if (g_str_equal(faultdata, "wsse:FailedAuthentication")) {
+				xmlnode *reason = xmlnode_get_child(body, "faultstring");
+				char *reasondata = xmlnode_get_data(reason);
+
+				msn_soap_connection_sanitize(conn, TRUE);
+				msn_session_set_error(conn->session, MSN_ERROR_AUTH,
+					reasondata);
+
+				g_free(reasondata);
+				g_free(faultdata);
+				return FALSE;
 			}
+
+			g_free(faultdata);
 		}
+	}
 
-		request = conn->current_request;
+	if (fault || body) {
+		MsnSoapRequest *request = conn->current_request;
 		conn->current_request = NULL;
 		request->cb(request->message, response,
 			request->cb_data);
--- a/libpurple/protocols/msnp9/notification.c	Mon Nov 19 08:05:36 2007 +0000
+++ b/libpurple/protocols/msnp9/notification.c	Mon Nov 19 08:07:11 2007 +0000
@@ -1348,7 +1348,7 @@
 
 void
 msn_notification_add_buddy(MsnNotification *notification, const char *list,
-						   const char *who, const char *store_name,
+						   const char *who, const char *friendly_name,
 						   int group_id)
 {
 	MsnCmdProc *cmdproc;
@@ -1360,11 +1360,11 @@
 	if (group_id >= 0)
 	{
 		msn_cmdproc_send(cmdproc, "ADD", "%s %s %s %d",
-						 list, who, store_name, group_id);
+						 list, who, friendly_name, group_id);
 	}
 	else
 	{
-		msn_cmdproc_send(cmdproc, "ADD", "%s %s %s", list, who, store_name);
+		msn_cmdproc_send(cmdproc, "ADD", "%s %s %s", list, who, friendly_name);
 	}
 }
 
--- a/libpurple/protocols/msnp9/notification.h	Mon Nov 19 08:05:36 2007 +0000
+++ b/libpurple/protocols/msnp9/notification.h	Mon Nov 19 08:07:11 2007 +0000
@@ -46,7 +46,7 @@
 
 void msn_notification_add_buddy(MsnNotification *notification,
 								const char *list, const char *who,
-								const char *store_name, int group_id);
+								const char *friendly_name, int group_id);
 void msn_notification_rem_buddy(MsnNotification *notification,
 								const char *list, const char *who,
 								int group_id);
--- a/libpurple/protocols/msnp9/user.c	Mon Nov 19 08:05:36 2007 +0000
+++ b/libpurple/protocols/msnp9/user.c	Mon Nov 19 08:07:11 2007 +0000
@@ -27,7 +27,7 @@
 
 MsnUser *
 msn_user_new(MsnUserList *userlist, const char *passport,
-			 const char *store_name)
+			 const char *friendly_name)
 {
 	MsnUser *user;
 
@@ -36,16 +36,7 @@
 	user->userlist = userlist;
 
 	msn_user_set_passport(user, passport);
-	msn_user_set_store_name(user, store_name);
-
-	/*
-	 * XXX This seems to reset the friendly name from what it should be
-	 *     to the passport when moving users. So, screw it :)
-	 */
-#if 0
-	if (name != NULL)
-		msn_user_set_name(user, name);
-#endif
+	msn_user_set_friendly_name(user, friendly_name);
 
 	return user;
 }
@@ -66,7 +57,6 @@
 
 	g_free(user->passport);
 	g_free(user->friendly_name);
-	g_free(user->store_name);
 	g_free(user->phone.home);
 	g_free(user->phone.work);
 	g_free(user->phone.mobile);
@@ -135,22 +125,24 @@
 void
 msn_user_set_friendly_name(MsnUser *user, const char *name)
 {
+	MsnCmdProc *cmdproc;
+
 	g_return_if_fail(user != NULL);
 
+	if (user->friendly_name && strcmp(user->friendly_name, name)) {
+		/* copy the new name to the server list, but only when new */
+		/* should we check this more thoroughly? */
+		cmdproc = user->userlist->session->notification->cmdproc;
+		msn_cmdproc_send(cmdproc, "REA", "%s %s",
+						 user->passport,
+						 purple_url_encode(name));
+	}
+
 	g_free(user->friendly_name);
 	user->friendly_name = g_strdup(name);
 }
 
 void
-msn_user_set_store_name(MsnUser *user, const char *name)
-{
-	g_return_if_fail(user != NULL);
-
-	g_free(user->store_name);
-	user->store_name = g_strdup(name);
-}
-
-void
 msn_user_set_buddy_icon(MsnUser *user, PurpleStoredImage *img)
 {
 	MsnObject *msnobj = msn_user_get_object(user);
@@ -344,14 +336,6 @@
 }
 
 const char *
-msn_user_get_store_name(const MsnUser *user)
-{
-	g_return_val_if_fail(user != NULL, NULL);
-
-	return user->store_name;
-}
-
-const char *
 msn_user_get_home_phone(const MsnUser *user)
 {
 	g_return_val_if_fail(user != NULL, NULL);
--- a/libpurple/protocols/msnp9/user.h	Mon Nov 19 08:05:36 2007 +0000
+++ b/libpurple/protocols/msnp9/user.h	Mon Nov 19 08:07:11 2007 +0000
@@ -42,7 +42,6 @@
 	MsnUserList *userlist;
 
 	char *passport;         /**< The passport account.          */
-	char *store_name;       /**< The name stored in the server. */
 	char *friendly_name;    /**< The friendly name.             */
 
 	const char *status;     /**< The state of the user.         */
@@ -83,7 +82,7 @@
  * @return A new user structure.
  */
 MsnUser *msn_user_new(MsnUserList *userlist, const char *passport,
-					  const char *store_name);
+					  const char *friendly_name);
 
 /**
  * Destroys a user structure.
@@ -127,14 +126,6 @@
 void msn_user_set_friendly_name(MsnUser *user, const char *name);
 
 /**
- * Sets the store name for a user.
- *
- * @param user The user.
- * @param name The store name.
- */
-void msn_user_set_store_name(MsnUser *user, const char *name);
-
-/**
  * Sets the buddy icon for a local user.
  *
  * @param user     The user.
@@ -226,15 +217,6 @@
 const char *msn_user_get_friendly_name(const MsnUser *user);
 
 /**
- * Returns the store name for a user.
- *
- * @param user The user.
- *
- * @return The store name.
- */
-const char *msn_user_get_store_name(const MsnUser *user);
-
-/**
  * Returns the home phone number for a user.
  *
  * @param user The user.
--- a/libpurple/protocols/msnp9/userlist.c	Mon Nov 19 08:05:36 2007 +0000
+++ b/libpurple/protocols/msnp9/userlist.c	Mon Nov 19 08:07:11 2007 +0000
@@ -132,18 +132,18 @@
 }
 
 static const char*
-get_store_name(MsnUser *user)
+get_friendly_name(MsnUser *user)
 {
-	const char *store_name;
+	const char *friendly_name;
 
 	g_return_val_if_fail(user != NULL, NULL);
 
-	store_name = msn_user_get_store_name(user);
+	friendly_name = msn_user_get_friendly_name(user);
 
-	if (store_name != NULL)
-		store_name = purple_url_encode(store_name);
+	if (friendly_name != NULL)
+		friendly_name = purple_url_encode(friendly_name);
 	else
-		store_name = msn_user_get_passport(user);
+		friendly_name = msn_user_get_passport(user);
 
 	/* this might be a bit of a hack, but it should prevent notification server
 	 * disconnections for people who have buddies with insane friendly names
@@ -153,10 +153,10 @@
 	/* Stu: yeah, that's why it's a bit of a hack, as you pointed out, we're
 	 * probably decoding the incoming store_name wrong, or something. bleh. */
 
-	if (strlen(store_name) > BUDDY_ALIAS_MAXLEN)
-		store_name = msn_user_get_passport(user);
+	if (strlen(friendly_name) > BUDDY_ALIAS_MAXLEN)
+		friendly_name = msn_user_get_passport(user);
 
-	return store_name;
+	return friendly_name;
 }
 
 static void
@@ -360,7 +360,7 @@
 	gc = purple_account_get_connection(account);
 
 	passport = msn_user_get_passport(user);
-	store = msn_user_get_store_name(user);
+	store = msn_user_get_friendly_name(user);
 
 	if (list_op & MSN_LIST_FL_OP)
 	{
@@ -639,7 +639,7 @@
 	MsnUser *user;
 	int group_id;
 	const char *list;
-	const char *store_name;
+	const char *friendly_name;
 
 	group_id = -1;
 
@@ -681,13 +681,13 @@
 		return;
 	}
 
-	store_name = (user != NULL) ? get_store_name(user) : who;
+	friendly_name = (user != NULL) ? get_friendly_name(user) : who;
 
 	/* Then request the add to the server. */
 	list = lists[list_id];
 
 	msn_notification_add_buddy(userlist->session->notification, list, who,
-							   store_name, group_id);
+							   friendly_name, group_id);
 }
 
 void
--- a/pidgin/Makefile.mingw	Mon Nov 19 08:05:36 2007 +0000
+++ b/pidgin/Makefile.mingw	Mon Nov 19 08:07:11 2007 +0000
@@ -170,6 +170,7 @@
 clean:
 	$(MAKE) -C $(PIDGIN_IDLETRACK_TOP) -f $(MINGW_MAKEFILE) clean
 	$(MAKE) -C $(PIDGIN_PLUGINS_TOP) -f $(MINGW_MAKEFILE) clean
+	$(MAKE) -C $(PIDGIN_PIXMAPS_TOP) -f $(MINGW_MAKEFILE) clean
 	rm -f $(PIDGIN_OBJECTS) $(PIDGIN_RC_SRC) $(EXE_OBJECTS) $(EXE_RC_SRC)
 	rm -f $(PIDGIN_TARGET).dll $(PIDGIN_TARGET).dll.a $(PIDGIN_TARGET).def
 	rm -f $(EXE_TARGET).exe
--- a/pidgin/gtkblist.c	Mon Nov 19 08:05:36 2007 +0000
+++ b/pidgin/gtkblist.c	Mon Nov 19 08:07:11 2007 +0000
@@ -4226,18 +4226,44 @@
 		pidgin_blist_sort_method_set(val);
 }
 
-static void account_modified(PurpleAccount *account, PidginBuddyList *gtkblist)
-{
+static gboolean pidgin_blist_select_notebook_page_cb(gpointer user_data)
+{
+	PidginBuddyList *gtkblist = (PidginBuddyList *)user_data;
+	int errors = 0;
 	GList *list;
-	if (!gtkblist)
-		return;
-
-	if ((list = purple_accounts_get_all_active()) != NULL) {
+	PidginBuddyListPrivate *priv;
+
+	priv = PIDGIN_BUDDY_LIST_GET_PRIVATE(gtkblist);
+
+	/* this is far too ugly thanks to me not wanting to fix #3989 properly right now */
+	if (priv->error_scrollbook != NULL) {
+#if GTK_CHECK_VERSION(2,2,0)
+		errors = gtk_notebook_get_n_pages(GTK_NOTEBOOK(priv->error_scrollbook->notebook));
+#else
+		errors = g_list_length(GTK_NOTEBOOK(priv->error_scrollbook->notebook)->children);
+#endif
+	}
+	if ((list = purple_accounts_get_all_active()) != NULL || errors ||
+	    (list = gtk_container_get_children(GTK_CONTAINER(priv->error_scrollbook)))) {
 		gtk_notebook_set_current_page(GTK_NOTEBOOK(gtkblist->notebook), 1);
 		g_list_free(list);
 	} else
 		gtk_notebook_set_current_page(GTK_NOTEBOOK(gtkblist->notebook), 0);
 
+	return FALSE;
+}
+
+static void pidgin_blist_select_notebook_page(PidginBuddyList *gtkblist)
+{
+	purple_timeout_add(0, pidgin_blist_select_notebook_page_cb, gtkblist);
+}
+
+static void account_modified(PurpleAccount *account, PidginBuddyList *gtkblist)
+{
+	if (!gtkblist)
+		return;
+
+	pidgin_blist_select_notebook_page(gtkblist);
 	update_menu_bar(gtkblist);
 }
 
@@ -4248,7 +4274,7 @@
 	if (!gtkblist)
 		return;
 
-	update_menu_bar(gtkblist);
+	account_modified(account, gtkblist);
 }
 
 static gboolean
@@ -4429,8 +4455,10 @@
                                PurpleAccount *account)
 {
 	GtkWidget *widget = find_child_widget_by_account(container, account);
-	if(widget)
+	if(widget) {
+		gtk_container_remove(container, widget);
 		gtk_widget_destroy(widget);
+	}
 }
 
 /* Generic error buttons */
@@ -4438,12 +4466,14 @@
 static void
 generic_error_modify_cb(PurpleAccount *account)
 {
+	purple_account_clear_current_error(account);
 	pidgin_account_dialog_show(PIDGIN_MODIFY_ACCOUNT_DIALOG, account);
 }
 
 static void
 generic_error_enable_cb(PurpleAccount *account)
 {
+	purple_account_clear_current_error(account);
 	purple_account_set_enabled(account, purple_core_get_ui(), TRUE);
 }
 
@@ -4530,7 +4560,7 @@
 {
 	PidginBuddyListPrivate *priv = PIDGIN_BUDDY_LIST_GET_PRIVATE(gtkblist);
 	remove_child_widget_by_account(
-		GTK_CONTAINER(priv->error_scrollbook->notebook), account);
+		GTK_CONTAINER(priv->error_scrollbook), account);
 }
 
 
@@ -4712,6 +4742,7 @@
 	else
 		pidgin_blist_update_account_error_state(account, NULL);
 
+	pidgin_blist_select_notebook_page(gtkblist);
 	/* Don't bother updating the error if it hasn't changed.  This stops
 	 * URGENT being repeatedly set for network errors whenever they try to
 	 * reconnect.
@@ -4902,7 +4933,6 @@
 	GtkWidget *sw;
 	GtkWidget *sep;
 	GtkWidget *label;
-	GList *accounts;
 	char *pretty, *tmp;
 	GtkAccelGroup *accel_group;
 	GtkTreeSelection *selection;
@@ -4993,10 +5023,7 @@
 	gtkblist->vbox = gtk_vbox_new(FALSE, 0);
 	gtk_notebook_append_page(GTK_NOTEBOOK(gtkblist->notebook), gtkblist->vbox, NULL);
 	gtk_widget_show_all(gtkblist->notebook);
-	if ((accounts = purple_accounts_get_all_active())) {
-		g_list_free(accounts);
-		gtk_notebook_set_current_page(GTK_NOTEBOOK(gtkblist->notebook), 1);
-	}
+	pidgin_blist_select_notebook_page(gtkblist);
 
 	ebox = gtk_event_box_new();
 	gtk_box_pack_start(GTK_BOX(gtkblist->vbox), ebox, FALSE, FALSE, 0);
@@ -5561,13 +5588,31 @@
 	return TRUE;
 }
 
+static gboolean pidgin_blist_group_has_show_offline_buddy(PurpleGroup *group)
+{
+	PurpleBlistNode *gnode, *cnode, *bnode;
+
+	gnode = (PurpleBlistNode *)group;
+	for(cnode = gnode->child; cnode; cnode = cnode->next) {
+		if(PURPLE_BLIST_NODE_IS_CONTACT(cnode)) {
+			for(bnode = cnode->child; bnode; bnode = bnode->next) {
+				PurpleBuddy *buddy = (PurpleBuddy *)bnode;
+				if (purple_account_is_connected(buddy->account) &&
+					purple_blist_node_get_bool(bnode, "show_offline"))
+					return TRUE;
+			}
+		}
+	}
+	return FALSE;
+}
+
 /*This version of pidgin_blist_update_group can take the original buddy
 or a group, but has much better algorithmic performance with a pre-known buddy*/
 static void pidgin_blist_update_group(PurpleBuddyList *list, PurpleBlistNode *node)
 {
 	PurpleGroup *group;
 	int count;
-	gboolean show = FALSE;
+	gboolean show = FALSE, show_offline = FALSE;
 	PurpleBlistNode* gnode;
 
 	g_return_if_fail(node != NULL);
@@ -5586,16 +5631,21 @@
 
 	group = (PurpleGroup*)gnode;
 
-	if(purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_offline_buddies"))
+	show_offline = purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_offline_buddies");
+
+	if(show_offline)
 		count = purple_blist_get_group_size(group, FALSE);
 	else
 		count = purple_blist_get_group_online_count(group);
 
 	if (count > 0 || purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_empty_groups"))
 		show = TRUE;
-	else if (PURPLE_BLIST_NODE_IS_BUDDY(node)){ /* Or chat? */
+	else if (PURPLE_BLIST_NODE_IS_BUDDY(node)) { /* Or chat? */
 		if (buddy_is_displayable((PurpleBuddy*)node))
-			show = TRUE;}
+			show = TRUE;
+	} else if (!show_offline && PURPLE_BLIST_NODE_IS_GROUP(node)) {
+		show = pidgin_blist_group_has_show_offline_buddy(group);
+	}
 
 	if (show) {
 		GtkTreeIter iter;
--- a/pidgin/gtkscrollbook.c	Mon Nov 19 08:05:36 2007 +0000
+++ b/pidgin/gtkscrollbook.c	Mon Nov 19 08:07:11 2007 +0000
@@ -146,21 +146,74 @@
 static void
 pidgin_scroll_book_add(GtkContainer *container, GtkWidget *widget)
 {
+	GList *children;
+	PidginScrollBook *scroll_book;
+
+	g_return_if_fail(GTK_IS_WIDGET (widget));
+	g_return_if_fail (widget->parent == NULL);
+
+	scroll_book = PIDGIN_SCROLL_BOOK(container);
+	children = scroll_book->children;
+	children = g_list_append(children, widget);
 	gtk_widget_show(widget);
 	gtk_notebook_append_page(GTK_NOTEBOOK(PIDGIN_SCROLL_BOOK(container)->notebook), widget, NULL);
 	page_count_change_cb(PIDGIN_SCROLL_BOOK(container));
 }
 
 static void
+pidgin_scroll_book_remove(GtkContainer *container, GtkWidget *widget)
+{
+	int page;
+	GList *children;
+	GtkWidget *child;
+	PidginScrollBook *scroll_book;
+	g_return_if_fail(GTK_IS_WIDGET(widget));
+
+	scroll_book = PIDGIN_SCROLL_BOOK(container);
+	children = scroll_book->children;
+
+	while (children) {
+		child = children->data;
+		if (child == widget) {
+			gtk_widget_unparent (widget);
+			children = g_list_remove_link (scroll_book->children, children);
+			g_list_free(children);
+			break;
+		}
+	}
+
+	page = gtk_notebook_page_num(GTK_NOTEBOOK(PIDGIN_SCROLL_BOOK(container)->notebook), widget);
+	if (page >= 0) {
+		gtk_notebook_remove_page(GTK_NOTEBOOK(PIDGIN_SCROLL_BOOK(container)->notebook), page);
+	}
+}
+
+static void
 pidgin_scroll_book_forall(GtkContainer *container,
 			   gboolean include_internals,
 			   GtkCallback callback,
 			   gpointer callback_data)
 {
-	PidginScrollBook *scroll_book = PIDGIN_SCROLL_BOOK(container);
-	if (include_internals)
+	GList *children;
+	PidginScrollBook *scroll_book;
+
+	g_return_if_fail(GTK_IS_CONTAINER(container));
+
+	scroll_book = PIDGIN_SCROLL_BOOK(container);
+
+	if (include_internals) {
 		(*callback)(scroll_book->hbox, callback_data);
-	(*callback)(scroll_book->notebook, callback_data);
+		(*callback)(scroll_book->notebook, callback_data);
+	}
+
+	children = scroll_book->children;
+
+	while (children) {
+		GtkWidget *child;
+		child = children->data;
+		children = children->next;
+		(*callback)(child, callback_data);
+	}
 }
 
 static void
@@ -169,6 +222,7 @@
 	GtkContainerClass *container_class = (GtkContainerClass*)klass;
 
 	container_class->add = pidgin_scroll_book_add;
+	container_class->remove = pidgin_scroll_book_remove;
 	container_class->forall = pidgin_scroll_book_forall;	
 	
 }
--- a/pidgin/gtkscrollbook.h	Mon Nov 19 08:05:36 2007 +0000
+++ b/pidgin/gtkscrollbook.h	Mon Nov 19 08:07:11 2007 +0000
@@ -29,10 +29,6 @@
 
 #include <gtk/gtk.h>
 
-#if !GTK_CHECK_VERSION(2,4,0)
-#include "pidgincombobox.h"
-#endif
-
 G_BEGIN_DECLS
 
 #define PIDGIN_TYPE_SCROLL_BOOK             (pidgin_scroll_book_get_type ())
@@ -54,9 +50,9 @@
 	GtkWidget *label;
 	GtkWidget *left_arrow;
 	GtkWidget *right_arrow;
+	GList *children;
 	
 	/* Padding for future expansion */
-	void (*_gtk_reserved0) (void);
 	void (*_gtk_reserved1) (void);
 	void (*_gtk_reserved2) (void);
 	void (*_gtk_reserved3) (void);
@@ -66,7 +62,7 @@
 
 struct _PidginScrollBookClass
 {
-	GtkComboBoxClass parent_class;
+	GtkContainerClass parent_class;
 
 	/* Padding for future expansion */
 	void (*_gtk_reserved0) (void);
--- a/pidgin/pixmaps/Makefile.mingw	Mon Nov 19 08:05:36 2007 +0000
+++ b/pidgin/pixmaps/Makefile.mingw	Mon Nov 19 08:07:11 2007 +0000
@@ -34,3 +34,9 @@
 	  cp $(pidgindistpix_DATA) $(pidgindistpixdir); \
 	fi;
 
+clean:
+	if test '$(SUBDIRS)'; then \
+		list='$(SUBDIRS)'; for subdir in $$list; do \
+		$(MAKE) -C $$subdir -f $(MINGW_MAKEFILE) clean;\
+		done; \
+	fi;