changeset 18948:22838745420a

propagate from branch 'im.pidgin.pidgin' (head 704b8c18f7c29f1fc8bfcf640275d2a9928ed03c) to branch 'im.pidgin.soc.2007.certmgr' (head 66c83d19227970a035a46be54fb419e0d9102d44)
author William Ehlhardt <williamehlhardt@gmail.com>
date Mon, 25 Jun 2007 21:38:40 +0000
parents 3c6bf77bf7c4 (current diff) 51ebbe199514 (diff)
children 8902f0d7e40f
files libpurple/protocols/jabber/jabber.c
diffstat 39 files changed, 373 insertions(+), 191 deletions(-) [+]
line wrap: on
line diff
--- a/COPYRIGHT	Sat Jun 23 20:34:07 2007 +0000
+++ b/COPYRIGHT	Mon Jun 25 21:38:40 2007 +0000
@@ -276,6 +276,7 @@
 Julien Pivotto
 Ari Pollak
 Robey Pointer
+Eric Polino
 Stephen Pope
 Nathan Poznick
 Jory A. Pratt
@@ -355,6 +356,7 @@
 Cestonaro Thilo
 Will Thompson
 Douglas Thrift (douglaswth)
+Mark Tiefenbruck
 Andrew Tinney
 Jeffery To
 Warren Togami
--- a/finch/gntconv.c	Sat Jun 23 20:34:07 2007 +0000
+++ b/finch/gntconv.c	Mon Jun 25 21:38:40 2007 +0000
@@ -485,7 +485,24 @@
 	gnt_box_set_title(GNT_BOX(ggc->window), title);
 	gnt_box_set_toplevel(GNT_BOX(ggc->window), TRUE);
 	gnt_box_set_pad(GNT_BOX(ggc->window), 0);
-	gnt_widget_set_name(ggc->window, "conversation-window");
+
+	switch(conv->type){
+		case PURPLE_CONV_TYPE_UNKNOWN:
+			gnt_widget_set_name(ggc->window, "conversation-window-unknown" );
+			break;
+		case PURPLE_CONV_TYPE_IM:
+			gnt_widget_set_name(ggc->window, "conversation-window-im" );
+			break;
+		case PURPLE_CONV_TYPE_CHAT:
+			gnt_widget_set_name(ggc->window, "conversation-window-chat" );
+			break;
+		case PURPLE_CONV_TYPE_MISC:
+			gnt_widget_set_name(ggc->window, "conversation-window-misc" );
+			break;
+		case PURPLE_CONV_TYPE_ANY:
+			gnt_widget_set_name(ggc->window, "conversation-window-any" );
+			break;
+	}
 
 	gg_create_menu(ggc);
 
@@ -554,7 +571,8 @@
 	
 	if (ggc->list == NULL) {
 		g_free(ggc->u.chat);
-		gnt_widget_destroy(ggc->window);
+		if (ggc->window)
+			gnt_widget_destroy(ggc->window);
 		g_free(ggc);
 	}
 }
--- a/finch/gntplugin.c	Sat Jun 23 20:34:07 2007 +0000
+++ b/finch/gntplugin.c	Mon Jun 25 21:38:40 2007 +0000
@@ -47,7 +47,7 @@
 
 static GHashTable *confwins;
 
-static void process_pref_frame(PurplePluginPrefFrame *frame);
+static GntWidget *process_pref_frame(PurplePluginPrefFrame *frame);
 
 static void
 decide_conf_button(PurplePlugin *plugin)
@@ -84,7 +84,7 @@
 			gnt_tree_set_choice(GNT_TREE(tree), plugin, TRUE);
 		}
 
-		if ((win = g_hash_table_lookup(confwins, plugin)) != NULL)
+		if (confwins && (win = g_hash_table_lookup(confwins, plugin)) != NULL)
 		{
 			gnt_widget_destroy(win);
 		}
@@ -221,7 +221,11 @@
 	else if (plugin->info->prefs_info &&
 			plugin->info->prefs_info->get_plugin_pref_frame)
 	{
-		process_pref_frame(plugin->info->prefs_info->get_plugin_pref_frame(plugin));
+		GntWidget *win = process_pref_frame(plugin->info->prefs_info->get_plugin_pref_frame(plugin));
+		if (confwins == NULL)
+			confwin_init();
+		g_signal_connect(G_OBJECT(win), "destroy", G_CALLBACK(remove_confwin), plugin);
+		g_hash_table_insert(confwins, plugin, win);
 		return;
 	}
 	else
@@ -273,6 +277,14 @@
 	{
 		PurplePlugin *plug = iter->data;
 
+		if (plug->info->type == PURPLE_PLUGIN_LOADER) {
+			GList *cur;
+			for (cur = PURPLE_PLUGIN_LOADER_INFO(plug)->exts; cur != NULL;
+					 cur = cur->next)
+				purple_plugins_probe(cur->data);
+			continue;
+		}
+
 		if (plug->info->type != PURPLE_PLUGIN_STANDARD ||
 			(plug->info->flags & PURPLE_PLUGIN_FLAG_INVISIBLE) ||
 			plug->error)
@@ -308,7 +320,7 @@
 	decide_conf_button(gnt_tree_get_selection_data(GNT_TREE(tree)));
 }
 
-static void
+static GntWidget*
 process_pref_frame(PurplePluginPrefFrame *frame)
 {
 	PurpleRequestField *field;
@@ -360,7 +372,7 @@
 		}
 	}
 
-	purple_request_fields(NULL, _("Preferences"), NULL, NULL, fields,
+	return purple_request_fields(NULL, _("Preferences"), NULL, NULL, fields,
 			_("Save"), G_CALLBACK(finch_request_save_in_prefs), _("Cancel"), NULL,
 			NULL, NULL, NULL,
 			NULL);
--- a/finch/gntrequest.c	Sat Jun 23 20:34:07 2007 +0000
+++ b/finch/gntrequest.c	Mon Jun 25 21:38:40 2007 +0000
@@ -399,7 +399,7 @@
 							purple_request_field_string_get_default_value(field));
 				gnt_entry_set_masked(GNT_ENTRY(entry),
 						purple_request_field_string_is_masked(field));
-				if (purple_str_has_prefix(hint, "screenname")) {
+				if (hint && purple_str_has_prefix(hint, "screenname")) {
 					PurpleBlistNode *node = purple_blist_get_root();
 					gboolean offline = purple_str_has_suffix(hint, "all");
 					for (; node; node = purple_blist_node_next(node, offline)) {
@@ -673,7 +673,7 @@
 			switch (pt) {
 				case PURPLE_PREF_INT:
 				{
-					long int tmp;
+					long int tmp = GPOINTER_TO_INT(val);
 					if (type == PURPLE_REQUEST_FIELD_LIST) /* Lists always return string */
 						sscanf(val, "%ld", &tmp);
 					purple_prefs_set_int(id, (gint)tmp);
--- a/finch/libgnt/gntwidget.c	Sat Jun 23 20:34:07 2007 +0000
+++ b/finch/libgnt/gntwidget.c	Mon Jun 25 21:38:40 2007 +0000
@@ -576,7 +576,7 @@
 		GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_HAS_FOCUS);
 		g_signal_emit(widget, signals[SIG_GIVE_FOCUS], 0);
 	}
-	else if (!set)
+	else if (!set && GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_HAS_FOCUS))
 	{
 		GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_HAS_FOCUS);
 		g_signal_emit(widget, signals[SIG_LOST_FOCUS], 0);
--- a/finch/libgnt/gntwm.c	Sat Jun 23 20:34:07 2007 +0000
+++ b/finch/libgnt/gntwm.c	Mon Jun 25 21:38:40 2007 +0000
@@ -1458,50 +1458,50 @@
 static gboolean
 match_title(gpointer title, gpointer n, gpointer wid_title)
 {
-	/* maybe check for regex.h? */
+	/* XXX: do any regex magic here. */
 	if (g_strrstr((gchar *)wid_title, (gchar *)title))
 		return TRUE;
 	return FALSE;
 }
 
 #if !GLIB_CHECK_VERSION(2,4,0)
-typedef struct
+struct
 {
-	GntWM *wm;
-	GntWS *ret;
-	gchar *title;
-} title_search;
+	gpointer data;
+	gpointer value;
+} table_find_data;
 
-static void match_title_search(gpointer key, gpointer value, gpointer search)
+static void
+table_find_helper(gpointer key, gpointer value, gpointer data)
 {
-	title_search *s = search;
-	if (s->ret)
-		return;
-	if (match_title(key, NULL, s->title))
-		s->ret = g_hash_table_lookup(s->wm->title_places, key);
+	GHRFunc func = data;
+	if (func(key, value, table_find_data.data))
+		table_find_data.value = value;
+}
+
+static gpointer
+g_hash_table_find(GHashTable * table, GHRFunc func, gpointer data)
+{
+	table_find_data.data = data;
+	table_find_data.value = NULL;
+	g_hash_table_foreach(table, table_find_helper, func);
+	return table_find_data.value;
 }
 #endif
 
 static GntWS *
-new_widget_find_workspace(GntWM *wm, GntWidget *widget, gchar *wid_title)
+new_widget_find_workspace(GntWM *wm, GntWidget *widget)
 {
-	GntWS *ret;
-	const gchar *name;
-#if GLIB_CHECK_VERSION(2,4,0)
-	ret = g_hash_table_find(wm->title_places, match_title, wid_title);
-#else
-	title_search *s = NULL;
-	s = g_new0(title_search, 1);
-	s->wm = wm;
-	s->title = wid_title;
-	g_hash_table_foreach(wm->title_places, match_title_search, s);
-	ret = s->ret;
-#endif
+	GntWS *ret = NULL;
+	const gchar *name, *title;
+	title = GNT_BOX(widget)->title;
+	if (title)
+		ret = g_hash_table_find(wm->title_places, match_title, (gpointer)title);
 	if (ret)
 		return ret;
 	name = gnt_widget_get_name(widget);
 	if (name)
-		ret = g_hash_table_lookup(wm->name_places, name);
+		ret = g_hash_table_find(wm->name_places, match_title, (gpointer)name);
 	return ret ? ret : wm->cws;
 }
 
@@ -1564,8 +1564,7 @@
 			GntWidget *w = NULL;
 
 			if (GNT_IS_BOX(widget)) {
-				char *title = GNT_BOX(widget)->title;
-				ws = new_widget_find_workspace(wm, widget, title);
+				ws = new_widget_find_workspace(wm, widget);
 			}
 
 			if (ws->ordered)
--- a/finch/libgnt/gntws.c	Sat Jun 23 20:34:07 2007 +0000
+++ b/finch/libgnt/gntws.c	Mon Jun 25 21:38:40 2007 +0000
@@ -87,8 +87,12 @@
 
 void gnt_ws_add_widget(GntWS *ws, GntWidget* wid)
 {
+	GntWidget *oldfocus;
+	oldfocus = ws->ordered ? ws->ordered->data : NULL;
 	ws->list = g_list_append(ws->list, wid);
 	ws->ordered = g_list_prepend(ws->ordered, wid);
+	if (oldfocus)
+		gnt_widget_set_focus(oldfocus, FALSE);
 }
 
 void gnt_ws_remove_widget(GntWS *ws, GntWidget* wid)
--- a/libpurple/core.c	Sat Jun 23 20:34:07 2007 +0000
+++ b/libpurple/core.c	Mon Jun 25 21:38:40 2007 +0000
@@ -222,11 +222,10 @@
 	purple_sound_uninit();
 
 	purple_plugins_uninit();
-	purple_signals_uninit();
-
 #ifdef HAVE_DBUS
 	purple_dbus_uninit();
 #endif
+	purple_signals_uninit();
 
 	g_free(core->ui);
 	g_free(core);
--- a/libpurple/plugins/perl/scripts/signals-test.pl	Sat Jun 23 20:34:07 2007 +0000
+++ b/libpurple/plugins/perl/scripts/signals-test.pl	Mon Jun 25 21:38:40 2007 +0000
@@ -7,7 +7,7 @@
 	name => "Perl: $MODULE_NAME",
 	version => "0.1",
 	summary => "Signals Test plugin for the Perl interpreter.",
-	description => "Demonstrate the user of purple signals from " .
+	description => "Demonstrate the use of purple signals from " .
 		       "a perl plugin.",
 	author => "Sadrul Habib Chowdhury <sadrul\@pidgin.im>",
 	url => "http://developer.pidgin.im/wiki/sadrul/",
--- a/libpurple/protocols/bonjour/buddy.c	Sat Jun 23 20:34:07 2007 +0000
+++ b/libpurple/protocols/bonjour/buddy.c	Mon Jun 25 21:38:40 2007 +0000
@@ -17,6 +17,7 @@
 #include <glib.h>
 #include <stdlib.h>
 
+#include "internal.h"
 #include "buddy.h"
 #include "account.h"
 #include "blist.h"
--- a/libpurple/protocols/bonjour/jabber.c	Sat Jun 23 20:34:07 2007 +0000
+++ b/libpurple/protocols/bonjour/jabber.c	Mon Jun 25 21:38:40 2007 +0000
@@ -31,6 +31,7 @@
 #include <unistd.h>
 #include <fcntl.h>
 
+#include "internal.h"
 #include "network.h"
 #include "eventloop.h"
 #include "connection.h"
--- a/libpurple/protocols/bonjour/mdns_common.c	Sat Jun 23 20:34:07 2007 +0000
+++ b/libpurple/protocols/bonjour/mdns_common.c	Mon Jun 25 21:38:40 2007 +0000
@@ -16,6 +16,7 @@
 
 #include <string.h>
 
+#include "internal.h"
 #include "config.h"
 #include "mdns_common.h"
 #include "bonjour.h"
--- a/libpurple/protocols/bonjour/mdns_win32.c	Sat Jun 23 20:34:07 2007 +0000
+++ b/libpurple/protocols/bonjour/mdns_win32.c	Mon Jun 25 21:38:40 2007 +0000
@@ -14,6 +14,7 @@
  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
+#include "internal.h"
 #include "mdns_win32.h"
 
 #include "debug.h"
--- a/libpurple/protocols/jabber/.todo	Sat Jun 23 20:34:07 2007 +0000
+++ b/libpurple/protocols/jabber/.todo	Mon Jun 25 21:38:40 2007 +0000
@@ -1,13 +1,4 @@
 <todo version="0.1.19">
-    <note priority="verylow" time="1036043981" done="1089237837">
-        *sigh* file transfer (do we really need/want this?)
-        <comment>
-            faceprint did this
-        </comment>
-    </note>
-    <note priority="high" time="1036043427">
-        problem seeing buddies with long blist?
-    </note>
     <note priority="medium" time="1036044198">
         Browsing
     </note>
@@ -17,12 +8,6 @@
     <note priority="medium" time="1036044448">
         Add option for user info to be published or not in JUD.
     </note>
-    <note priority="medium" time="1036044571">
-        Show self on buddylist
-        <comment>
-            is this done?
-        </comment>
-    </note>
     <note priority="medium" time="1036044583">
         Delete server account.
     </note>
@@ -37,9 +22,6 @@
         <note priority="medium" time="1037893000">
             formatted. enhancement-request so that the birthday field in the setinfo form would split up into relevant fields allowing for a strict syntax (like year--month--day or so, perhaps even dropdown menus)
         </note>
-        <note priority="low" time="1037890968">
-            have set info pre-fill values from the server when no local vcard exists. this will help people migrating to libpurple-based clients
-        </note>
     </note>
     <note priority="verylow" time="1036044192">
         Jabber Transports (having them show up on the buddy list should be fairly easy; having an appropriate right-click menu for them should also be somewhat easy. Providing a UI for adding transports should be rather difficult.)
--- a/libpurple/protocols/jabber/buddy.c	Sat Jun 23 20:34:07 2007 +0000
+++ b/libpurple/protocols/jabber/buddy.c	Mon Jun 25 21:38:40 2007 +0000
@@ -419,6 +419,10 @@
 
 			avatar_data = purple_imgstore_get_data(img);
 			avatar_len = purple_imgstore_get_size(img);
+			/* have to get rid of the old PHOTO if it exists */
+			if((photo = xmlnode_get_child(vc_node, "PHOTO"))) {
+				xmlnode_free(photo);
+			}
 			photo = xmlnode_new_child(vc_node, "PHOTO");
 			binval = xmlnode_new_child(photo, "BINVAL");
 			enc = purple_base64_encode(avatar_data, avatar_len);
--- a/libpurple/protocols/jabber/disco.c	Sat Jun 23 20:34:07 2007 +0000
+++ b/libpurple/protocols/jabber/disco.c	Mon Jun 25 21:38:40 2007 +0000
@@ -83,6 +83,7 @@
 			SUPPORT_FEATURE("jabber:iq:last")
 			SUPPORT_FEATURE("jabber:iq:oob")
 			SUPPORT_FEATURE("jabber:iq:time")
+			SUPPORT_FEATURE("xmpp:urn:time")
 			SUPPORT_FEATURE("jabber:iq:version")
 			SUPPORT_FEATURE("jabber:x:conference")
 			SUPPORT_FEATURE("http://jabber.org/protocol/bytestreams")
--- a/libpurple/protocols/jabber/iq.c	Sat Jun 23 20:34:07 2007 +0000
+++ b/libpurple/protocols/jabber/iq.c	Mon Jun 25 21:38:40 2007 +0000
@@ -169,7 +169,7 @@
 
 static void jabber_iq_time_parse(JabberStream *js, xmlnode *packet)
 {
-	const char *type, *from, *id;
+	const char *type, *from, *id, *xmlns;
 	JabberIq *iq;
 	xmlnode *query;
 	time_t now_t;
@@ -182,27 +182,40 @@
 	from = xmlnode_get_attrib(packet, "from");
 	id = xmlnode_get_attrib(packet, "id");
 
+	/* we're gonna throw this away in a moment, but we need it
+	 * to get the xmlns, so we can figure out if this is
+	 * jabber:iq:time or urn:xmpp:time */
+	query = xmlnode_get_child(packet, "query");
+	xmlns = xmlnode_get_namespace(query);
+
 	if(type && !strcmp(type, "get")) {
+		xmlnode *utc;
 		const char *date;
 
-		iq = jabber_iq_new_query(js, JABBER_IQ_RESULT, "jabber:iq:time");
+		iq = jabber_iq_new_query(js, JABBER_IQ_RESULT, xmlns);
 		jabber_iq_set_id(iq, id);
 		xmlnode_set_attrib(iq->node, "to", from);
 
 		query = xmlnode_get_child(iq->node, "query");
 
 		date = purple_utf8_strftime("%Y%m%dT%T", now);
-		xmlnode_insert_data(xmlnode_new_child(query, "utc"), date, -1);
+		utc = xmlnode_new_child(query, "utc");
+		xmlnode_insert_data(utc, date, -1);
+
+		if(!strcmp("urn:xmpp:time", xmlns)) {
+			xmlnode_insert_data(utc, "Z", 1); /* of COURSE the thing that is the same is different */
 
-		date = purple_utf8_strftime("%Z", now);
-		xmlnode_insert_data(xmlnode_new_child(query, "tz"), date, -1);
+			date = purple_get_tzoff_str(now, TRUE);
+			xmlnode_insert_data(xmlnode_new_child(query, "tzo"), date, -1);
+		} else { /* jabber:iq:time */
+			date = purple_utf8_strftime("%Z", now);
+			xmlnode_insert_data(xmlnode_new_child(query, "tz"), date, -1);
 
-		date = purple_utf8_strftime("%d %b %Y %T", now);
-		xmlnode_insert_data(xmlnode_new_child(query, "display"), date, -1);
+			date = purple_utf8_strftime("%d %b %Y %T", now);
+			xmlnode_insert_data(xmlnode_new_child(query, "display"), date, -1);
+		}
 
 		jabber_iq_send(iq);
-	} else {
-		/* XXX: error */
 	}
 }
 
@@ -347,6 +360,7 @@
 	jabber_iq_register_handler("http://jabber.org/protocol/bytestreams", jabber_bytestreams_parse);
 	jabber_iq_register_handler("jabber:iq:last", jabber_iq_last_parse);
 	jabber_iq_register_handler("jabber:iq:time", jabber_iq_time_parse);
+	jabber_iq_register_handler("urn:xmpp:time", jabber_iq_time_parse);
 	jabber_iq_register_handler("jabber:iq:version", jabber_iq_version_parse);
 	jabber_iq_register_handler("http://jabber.org/protocol/disco#info", jabber_disco_info_parse);
 	jabber_iq_register_handler("http://jabber.org/protocol/disco#items", jabber_disco_items_parse);
--- a/libpurple/protocols/jabber/jabber.c	Sat Jun 23 20:34:07 2007 +0000
+++ b/libpurple/protocols/jabber/jabber.c	Mon Jun 25 21:38:40 2007 +0000
@@ -1114,9 +1114,11 @@
 
 char *jabber_status_text(PurpleBuddy *b)
 {
-	JabberBuddy *jb = jabber_buddy_find(b->account->gc->proto_data, b->name,
-			FALSE);
 	char *ret = NULL;
+	JabberBuddy *jb = NULL;
+	
+	if (b->account->gc && b->account->gc->proto_data)
+		jb = jabber_buddy_find(b->account->gc->proto_data, b->name, FALSE);
 
 	if(jb && !PURPLE_BUDDY_IS_ONLINE(b) && (jb->subscription & JABBER_SUB_PENDING || !(jb->subscription & JABBER_SUB_TO))) {
 		ret = g_strdup(_("Not Authorized"));
--- a/libpurple/protocols/jabber/presence.c	Sat Jun 23 20:34:07 2007 +0000
+++ b/libpurple/protocols/jabber/presence.c	Mon Jun 25 21:38:40 2007 +0000
@@ -515,7 +515,7 @@
 		buddy_name = g_strdup_printf("%s%s%s", jid->node ? jid->node : "",
 				jid->node ? "@" : "", jid->domain);
 		if((b = purple_find_buddy(js->gc->account, buddy_name)) == NULL) {
-			purple_debug_warning("jabber", "Got presence for unknown buddy %s on account %s (%x)",
+			purple_debug_warning("jabber", "Got presence for unknown buddy %s on account %s (%x)\n",
 				buddy_name, purple_account_get_username(js->gc->account), js->gc->account);
 			jabber_id_free(jid);
 			g_free(avatar_hash);
@@ -565,9 +565,7 @@
 		}
 
 		if((found_jbr = jabber_buddy_find_resource(jb, NULL))) {
-			if(!jbr || jbr == found_jbr) {
-				purple_prpl_got_user_status(js->gc->account, buddy_name, jabber_buddy_state_get_status_id(state), "priority", found_jbr->priority, found_jbr->status ? "message" : NULL, found_jbr->status, NULL);
-			}
+			purple_prpl_got_user_status(js->gc->account, buddy_name, jabber_buddy_state_get_status_id(state), "priority", found_jbr->priority, found_jbr->status ? "message" : NULL, found_jbr->status, NULL);
 		} else {
 			purple_prpl_got_user_status(js->gc->account, buddy_name, "offline", status ? "message" : NULL, status, NULL);
 		}
--- a/libpurple/protocols/oscar/family_auth.c	Sat Jun 23 20:34:07 2007 +0000
+++ b/libpurple/protocols/oscar/family_auth.c	Mon Jun 25 21:38:40 2007 +0000
@@ -211,7 +211,7 @@
 
 #ifdef USE_XOR_FOR_ICQ
 	/* If we're signing on an ICQ account then use the older, XOR login method */
-	if (isdigit(sn[0]))
+	if (aim_sn_is_icq(sn))
 		return goddamnicq2(od, conn, sn, password, ci);
 #endif
 
@@ -224,7 +224,7 @@
 
 	/* Truncate ICQ and AOL passwords, if necessary */
 	password_len = strlen(password);
-	if (isdigit(sn[0]) && (password_len > MAXICQPASSLEN))
+	if (aim_sn_is_icq(sn) && (password_len > MAXICQPASSLEN))
 		password_len = MAXICQPASSLEN;
 	else if (truncate_pass && password_len > 8)
 		password_len = 8;
@@ -477,7 +477,7 @@
 		return -EINVAL;
 
 #ifdef USE_XOR_FOR_ICQ
-	if (isdigit(sn[0]))
+	if (aim_sn_is_icq(sn))
 		return goddamnicq(od, conn, sn);
 #endif
 
--- a/libpurple/protocols/oscar/oscar.c	Sat Jun 23 20:34:07 2007 +0000
+++ b/libpurple/protocols/oscar/oscar.c	Mon Jun 25 21:38:40 2007 +0000
@@ -425,7 +425,7 @@
 		charsetstr1 = "UCS-2BE";
 		charsetstr2 = "UTF-8";
 	} else if (charset == AIM_CHARSET_CUSTOM) {
-		if ((sourcesn != NULL) && isdigit(sourcesn[0]))
+		if ((sourcesn != NULL) && aim_sn_is_icq(sourcesn))
 			charsetstr1 = purple_account_get_string(account, "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING);
 		else
 			charsetstr1 = "ISO-8859-1";
@@ -1258,7 +1258,7 @@
 
 	if (!aim_snvalid(purple_account_get_username(account))) {
 		gchar *buf;
-		buf = g_strdup_printf(_("Unable to login: Could not sign on as %s because the screen name is invalid.  Screen names must either start with a letter and contain only letters, numbers and spaces, or contain only numbers."), purple_account_get_username(account));
+		buf = g_strdup_printf(_("Unable to login: Could not sign on as %s because the screen name is invalid.  Screen names must be a valid email address, or start with a letter and contain only letters, numbers and spaces, or contain only numbers."), purple_account_get_username(account));
 		gc->wants_to_die = TRUE;
 		purple_connection_error(gc, buf);
 		g_free(buf);
@@ -4623,7 +4623,7 @@
 
 	if (!aim_snvalid(buddy->name)) {
 		gchar *buf;
-		buf = g_strdup_printf(_("Could not add the buddy %s because the screen name is invalid.  Screen names must either start with a letter and contain only letters, numbers and spaces, or contain only numbers."), buddy->name);
+		buf = g_strdup_printf(_("Could not add the buddy %s because the screen name is invalid.  Screen names must be a valid email address, or start with a letter and contain only letters, numbers and spaces, or contain only numbers."), buddy->name);
 		if (!purple_conv_present_error(buddy->name, purple_connection_get_account(gc), buf))
 			purple_notify_error(gc, NULL, _("Unable To Add"), buf);
 		g_free(buf);
@@ -5060,7 +5060,8 @@
 			default: { /* La la la */
 				gchar *buf;
 				purple_debug_error("oscar", "ssi: Action 0x%04hx was unsuccessful with error 0x%04hx\n", retval->action, retval->ack);
-				buf = g_strdup_printf(_("Could not add the buddy %s for an unknown reason.  The most common reason for this is that you have the maximum number of allowed buddies in your buddy list."), (retval->name ? retval->name : _("(no name)")));
+				buf = g_strdup_printf(_("Could not add the buddy %s for an unknown reason."),
+						(retval->name ? retval->name : _("(no name)")));
 				if ((retval->name != NULL) && !purple_conv_present_error(retval->name, purple_connection_get_account(gc), buf))
 					purple_notify_error(gc, NULL, _("Unable To Add"), buf);
 				g_free(buf);
--- a/libpurple/protocols/oscar/peer.c	Sat Jun 23 20:34:07 2007 +0000
+++ b/libpurple/protocols/oscar/peer.c	Mon Jun 25 21:38:40 2007 +0000
@@ -1019,7 +1019,7 @@
 						PURPLE_DEFAULT_ACTION_NONE,
 						account, sn, NULL,
 						conn, 2,
-						_("_Connect"), G_CALLBACK(peer_connection_got_proposition_yes_cb),
+						_("C_onnect"), G_CALLBACK(peer_connection_got_proposition_yes_cb),
 						_("Cancel"), G_CALLBACK(peer_connection_got_proposition_no_cb));
 	}
 	else if (args->type == OSCAR_CAPABILITY_SENDFILE)
--- a/libpurple/protocols/oscar/util.c	Sat Jun 23 20:34:07 2007 +0000
+++ b/libpurple/protocols/oscar/util.c	Mon Jun 25 21:38:40 2007 +0000
@@ -37,6 +37,7 @@
  *   -- DMP.
  *
  */
+/* TODO: Get rid of this and use glib functions */
 int
 aimutil_tokslen(char *toSearch, int theindex, char dl)
 {
@@ -138,6 +139,7 @@
  * Check if the given screen name is a valid AIM screen name.
  * Example: BobDole
  * Example: Henry_Ford@mac.com
+ * Example: 1KrazyKat@example.com
  *
  * @return TRUE if the screen name is valid, FALSE if not.
  */
@@ -146,9 +148,16 @@
 {
 	int i;
 
+	if (purple_email_is_valid(sn))
+		return TRUE;
+
+	/* Normal AIM screen names can't start with a number */
+	if (isdigit(sn[0]))
+		return FALSE;
+
 	for (i = 0; sn[i] != '\0'; i++) {
 		if (!isalnum(sn[i]) && (sn[i] != ' ') &&
-			(sn[i] != '@') && (sn[i] != '.') &&
+			(sn[i] != '.') &&
 			(sn[i] != '_') && (sn[i] != '-'))
 			return FALSE;
 	}
@@ -169,10 +178,10 @@
 
 	for (i = 0; sn[i] != '\0'; i++) {
 		if (!isdigit(sn[i]))
-			return 0;
+			return FALSE;
 	}
 
-	return 1;
+	return TRUE;
 }
 
 /**
@@ -187,14 +196,14 @@
 	int i;
 
 	if (sn[0] != '+')
-		return 0;
+		return FALSE;
 
 	for (i = 1; sn[i] != '\0'; i++) {
 		if (!isdigit(sn[i]))
-			return 0;
+			return FALSE;
 	}
 
-	return 1;
+	return TRUE;
 }
 
 /**
@@ -206,70 +215,37 @@
 aim_snvalid(const char *sn)
 {
 	if ((sn == NULL) || (*sn == '\0'))
-		return 0;
+		return FALSE;
 
-	if (isalpha(sn[0]))
-		return aim_snvalid_aim(sn);
-	else if (isdigit(sn[0]))
-		return aim_snvalid_icq(sn);
-	else if (sn[0] == '+')
-		return aim_snvalid_sms(sn);
-
-	return 0;
+	return aim_snvalid_icq(sn) || aim_snvalid_sms(sn) || aim_snvalid_aim(sn);
 }
 
 /**
  * Determine if a given screen name is an ICQ screen name
- * (i.e. it begins with a number).
+ * (i.e. it is composed of only numbers).
  *
- * @sn A valid AIM or ICQ screen name.
+ * @param sn A valid AIM or ICQ screen name.
  * @return TRUE if the screen name is an ICQ screen name.  Otherwise
  *         FALSE is returned.
  */
 gboolean
 aim_sn_is_icq(const char *sn)
 {
-	if (isalpha(sn[0]))
-		return FALSE;
-	return TRUE;
+	return aim_snvalid_icq(sn);
 }
 
 /**
  * Determine if a given screen name is an SMS number
  * (i.e. it begins with a +).
  *
- * @sn A valid AIM or ICQ screen name.
+ * @param sn A valid AIM or ICQ screen name.
  * @return TRUE if the screen name is an SMS number.  Otherwise
  *         FALSE is returned.
  */
 gboolean
 aim_sn_is_sms(const char *sn)
 {
-	if (sn[0] != '+')
-		return FALSE;
-	return TRUE;
-}
-
-/**
- * This takes a screen name and returns its length without
- * spaces.  If there are no spaces in the SN, then the
- * return is equal to that of strlen().
- */
-int
-aim_snlen(const char *sn)
-{
-	int i = 0;
-
-	if (!sn)
-		return 0;
-
-	while (*sn != '\0') {
-		if (*sn != ' ')
-			i++;
-		sn++;
-	}
-
-	return i;
+	return (sn[0] == '+');
 }
 
 /**
@@ -279,9 +255,9 @@
  * ignored, with the exception that screen names can not start with
  * a space).
  *
- * Return: 0 if equal
- *     non-0 if different
+ * @return 0 if equal, non-0 if different
  */
+/* TODO: Do something different for email addresses. */
 int
 aim_sncmp(const char *sn1, const char *sn2)
 {
--- a/libpurple/protocols/qq/Makefile.mingw	Sat Jun 23 20:34:07 2007 +0000
+++ b/libpurple/protocols/qq/Makefile.mingw	Mon Jun 25 21:38:40 2007 +0000
@@ -54,7 +54,6 @@
 	group_im.c \
 	group_info.c \
 	group_join.c \
-	group_misc.c \
 	group_network.c \
 	group_opt.c \
 	group_search.c \
--- a/libpurple/server.c	Sat Jun 23 20:34:07 2007 +0000
+++ b/libpurple/server.c	Mon Jun 25 21:38:40 2007 +0000
@@ -198,7 +198,7 @@
 {
 	PurplePluginProtocolInfo *prpl_info = NULL;
 
-	if (b != NULL && b->account->gc->prpl != NULL)
+	if (b != NULL && b->account->gc && b->account->gc->prpl != NULL)
 		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(b->account->gc->prpl);
 
 	if (b && prpl_info && prpl_info->alias_buddy) {
--- a/libpurple/status.c	Sat Jun 23 20:34:07 2007 +0000
+++ b/libpurple/status.c	Mon Jun 25 21:38:40 2007 +0000
@@ -152,10 +152,10 @@
 	{ PURPLE_STATUS_UNSET,           "unset",           N_("Unset")           },
 	{ PURPLE_STATUS_OFFLINE,         "offline",         N_("Offline")         },
 	{ PURPLE_STATUS_AVAILABLE,       "available",       N_("Available")       },
-	{ PURPLE_STATUS_UNAVAILABLE,     "unavailable",     N_("Unavailable")     },
+	{ PURPLE_STATUS_UNAVAILABLE,     "unavailable",     N_("Do not disturb")     },
 	{ PURPLE_STATUS_INVISIBLE,       "invisible",       N_("Invisible")       },
 	{ PURPLE_STATUS_AWAY,            "away",            N_("Away")            },
-	{ PURPLE_STATUS_EXTENDED_AWAY,   "extended_away",   N_("Extended Away")   },
+	{ PURPLE_STATUS_EXTENDED_AWAY,   "extended_away",   N_("Extended away")   },
 	{ PURPLE_STATUS_MOBILE,          "mobile",          N_("Mobile")          }
 };
 
--- a/libpurple/util.c	Sat Jun 23 20:34:07 2007 +0000
+++ b/libpurple/util.c	Mon Jun 25 21:38:40 2007 +0000
@@ -531,10 +531,9 @@
 }
 #endif
 
-#ifndef HAVE_STRFTIME_Z_FORMAT
-static const char *get_tmoff(const struct tm *tm)
+const char *purple_get_tzoff_str(const struct tm *tm, gboolean iso)
 {
-	static char buf[6];
+	static char buf[7];
 	long off;
 	gint8 min;
 	gint8 hrs;
@@ -554,7 +553,7 @@
 # else
 #  ifdef HAVE_TIMEZONE
 	tzset();
-	off = -timezone;
+	off = -1 * timezone;
 #  endif /* HAVE_TIMEZONE */
 # endif /* !HAVE_TM_GMTOFF */
 #endif /* _WIN32 */
@@ -562,12 +561,22 @@
 	min = (off / 60) % 60;
 	hrs = ((off / 60) - min) / 60;
 
-	if (g_snprintf(buf, sizeof(buf), "%+03d%02d", hrs, ABS(min)) > 5)
-		g_return_val_if_reached("");
+	if(iso) {
+		if (0 == off) {
+			strcpy(buf, "Z");
+		} else {
+			/* please leave the colons...they're optional for iso, but jabber
+			 * wants them */
+			if(g_snprintf(buf, sizeof(buf), "%+03d:%02d", hrs, ABS(min)) > 6)
+				g_return_val_if_reached("");
+		}
+	} else {
+		if (g_snprintf(buf, sizeof(buf), "%+03d%02d", hrs, ABS(min)) > 5)
+			g_return_val_if_reached("");
+	}
 
 	return buf;
 }
-#endif
 
 /* Windows doesn't HAVE_STRFTIME_Z_FORMAT, but this seems clearer. -- rlaager */
 #if !defined(HAVE_STRFTIME_Z_FORMAT) || defined(_WIN32)
@@ -600,7 +609,7 @@
 			                            fmt ? fmt : "",
 			                            c - start - 1,
 			                            start,
-			                            get_tmoff(tm));
+			                            purple_get_tzoff_str(tm, FALSE));
 			g_free(fmt);
 			fmt = tmp;
 			start = c + 1;
--- a/libpurple/util.h	Sat Jun 23 20:34:07 2007 +0000
+++ b/libpurple/util.h	Mon Jun 25 21:38:40 2007 +0000
@@ -257,6 +257,16 @@
 const char *purple_utf8_strftime(const char *format, const struct tm *tm);
 
 /**
+ * Gets a string representation of the local timezone offset
+ *
+ * @param tm   The time to get the timezone for
+ * @param iso  TRUE to format the offset according to ISO-8601, FALSE to
+ *             not substitute 'Z' for 0 offset, and to not separate
+ *             hours and minutes with a colon.
+ */
+const char *purple_get_tzoff_str(const struct tm *tm, gboolean iso);
+
+/**
  * Formats a time into the user's preferred short date format.
  *
  * The returned string is stored in a static buffer, so the result
--- a/libpurple/win32/win32dep.c	Sat Jun 23 20:34:07 2007 +0000
+++ b/libpurple/win32/win32dep.c	Mon Jun 25 21:38:40 2007 +0000
@@ -32,6 +32,7 @@
 #include <glib.h>
 #include <glib/gstdio.h>
 
+#include "internal.h"
 #include "debug.h"
 #include "notify.h"
 
--- a/libpurple/xmlnode.c	Sat Jun 23 20:34:07 2007 +0000
+++ b/libpurple/xmlnode.c	Mon Jun 25 21:38:40 2007 +0000
@@ -268,6 +268,22 @@
 
 	g_return_if_fail(node != NULL);
 
+	/* if we're part of a tree, remove ourselves from the tree first */
+	if(NULL != node->parent) {
+		if(node->parent->child == node) {
+			node->parent->child = node->next;
+		} else {
+			xmlnode *prev = node->parent->child;
+			while(prev && prev->next != node) {
+				prev = prev->next;
+			}
+			if(prev) {
+				prev->next = node->next;
+			}
+		}
+	}
+
+	/* now free our children */
 	x = node->child;
 	while(x) {
 		y = x->next;
@@ -275,6 +291,7 @@
 		x = y;
 	}
 
+	/* now dispose of ourselves */
 	g_free(node->name);
 	g_free(node->data);
 	g_free(node->xmlns);
--- a/pidgin/eggtrayicon.c	Sat Jun 23 20:34:07 2007 +0000
+++ b/pidgin/eggtrayicon.c	Mon Jun 25 21:38:40 2007 +0000
@@ -152,6 +152,26 @@
     }
 }
 
+static Display *
+egg_tray_icon_get_x_display(EggTrayIcon *icon)
+{
+  Display *xdisplay = NULL;
+
+#if GTK_CHECK_VERSION(2,1,0)
+  {
+    GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (icon));
+    if (!GDK_IS_DISPLAY (display))
+      display = gdk_display_get_default ();
+
+    xdisplay = GDK_DISPLAY_XDISPLAY (display);
+  }
+#else
+  xdisplay = gdk_display;
+#endif
+
+  return xdisplay;
+}
+
 static void
 egg_tray_icon_get_orientation_property (EggTrayIcon *icon)
 {
@@ -168,11 +188,10 @@
 
   g_return_if_fail(icon->manager_window != None);
 
-#if GTK_CHECK_VERSION(2,1,0)
-  xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon)));
-#else
-  xdisplay = gdk_display;
-#endif
+  xdisplay = egg_tray_icon_get_x_display(icon);
+
+  if (xdisplay == NULL)
+    return;
 
   gdk_error_trap_push ();
   type = None;
@@ -321,11 +340,10 @@
   if (icon->manager_window != None)
     return;
 
-#if GTK_CHECK_VERSION(2,1,0)
-  xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon)));
-#else
-  xdisplay = gdk_display;
-#endif
+  xdisplay = egg_tray_icon_get_x_display(icon);
+
+  if (xdisplay == NULL)
+    return;
 
   XGrabServer (xdisplay);
   
@@ -424,12 +442,15 @@
 
   make_transparent (widget, NULL);
 
+  xdisplay = egg_tray_icon_get_x_display(icon);
+
+  if (xdisplay == NULL)
+    return;
+
 #if GTK_CHECK_VERSION(2,1,0)
   screen = gdk_screen_get_number (gtk_widget_get_screen (widget));
-  xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (widget));
 #else
   screen = XScreenNumberOfScreen (DefaultScreenOfDisplay (gdk_display));
-  xdisplay = gdk_display;
 #endif
 
   /* Now see if there's a manager window around */
@@ -519,11 +540,10 @@
       XClientMessageEvent ev;
       Display *xdisplay;
 
-#if GTK_CHECK_VERSION(2,1,0)
-      xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon)));
-#else
-      xdisplay = gdk_display;
-#endif
+      xdisplay = egg_tray_icon_get_x_display(icon);
+
+      if (xdisplay == NULL)
+        return;
 
       ev.type = ClientMessage;
       ev.window = (Window)gtk_plug_get_id (GTK_PLUG (icon));
--- a/pidgin/gtkblist.c	Sat Jun 23 20:34:07 2007 +0000
+++ b/pidgin/gtkblist.c	Mon Jun 25 21:38:40 2007 +0000
@@ -174,6 +174,7 @@
 
 static gboolean gtk_blist_window_state_cb(GtkWidget *w, GdkEventWindowState *event, gpointer data)
 {
+#if GTK_CHECK_VERSION(2,2,0)
 	if(event->changed_mask & GDK_WINDOW_STATE_WITHDRAWN) {
 		if(event->new_window_state & GDK_WINDOW_STATE_WITHDRAWN)
 			purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/blist/list_visible", FALSE);
@@ -195,6 +196,28 @@
 		if (!(event->new_window_state & GDK_WINDOW_STATE_ICONIFIED))
 			pidgin_blist_refresh_timer(purple_get_blist());
 	}
+#else
+	/* At least gtk+ 2.0.6 does not properly set the change_mask when unsetting a
+	 * GdkWindowState flag. To work around, the window state will be explicitly
+	 * queried on these older versions of gtk+. See pidgin ticket #739.
+	 */
+	GdkWindowState new_window_state = gdk_window_get_state(G_OBJECT(gtkblist->window->window));
+
+	if(new_window_state & GDK_WINDOW_STATE_WITHDRAWN) {
+		purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/blist/list_visible", FALSE);
+	} else {
+		purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/blist/list_visible", TRUE);
+		pidgin_blist_refresh_timer(purple_get_blist());
+	}
+
+	if(new_window_state & GDK_WINDOW_STATE_MAXIMIZED)
+		purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/blist/list_maximized", TRUE);
+	else
+		purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/blist/list_maximized", FALSE);
+
+	if (!(new_window_state & GDK_WINDOW_STATE_ICONIFIED))
+		pidgin_blist_refresh_timer(purple_get_blist());
+#endif
 
 	return FALSE;
 }
@@ -2976,10 +2999,11 @@
 		signon = purple_presence_get_login_time(presence);
 		if (full && PURPLE_BUDDY_IS_ONLINE(b) && signon > 0)
 		{
-			if (time(NULL) - signon > 63072000 /* 2 years */) {
+			if (signon > time(NULL)) {
 				/*
-				 * Our local clock must be wrong, show the actual
-				 * date instead of "4 days", etc.
+				 * They signed on in the future?!  Our local clock
+				 * must be wrong, show the actual date instead of
+				 * "4 days", etc.
 				 */
 				tmp = g_strdup(purple_date_format_long(localtime(&signon)));
 			} else
--- a/pidgin/gtkconv.c	Sat Jun 23 20:34:07 2007 +0000
+++ b/pidgin/gtkconv.c	Mon Jun 25 21:38:40 2007 +0000
@@ -184,6 +184,8 @@
 static void pidgin_conv_update_fields(PurpleConversation *conv, PidginConvFields fields);
 static void focus_out_from_menubar(GtkWidget *wid, PidginWindow *win);
 static void pidgin_conv_tab_pack(PidginWindow *win, PidginConversation *gtkconv);
+static gboolean infopane_release_cb(GtkWidget *widget, GdkEventButton *e, PidginConversation *conv);
+static gboolean infopane_press_cb(GtkWidget *widget, GdkEventButton *e, PidginConversation *conv);
 
 static GdkColor *get_nick_color(PidginConversation *gtkconv, const char *name) {
 	static GdkColor col;
@@ -4377,7 +4379,7 @@
 static GtkWidget *
 setup_common_pane(PidginConversation *gtkconv)
 {
-	GtkWidget *paned, *vbox, *frame, *imhtml_sw;
+	GtkWidget *paned, *vbox, *frame, *imhtml_sw, *event_box;
 	GtkCellRenderer *rend;
 	GtkTreePath *path;
 	PurpleConversation *conv = gtkconv->active_conv;
@@ -4393,9 +4395,19 @@
 	gtk_widget_show(vbox);
 
 	/* Setup the info pane */
+	event_box = gtk_event_box_new();
+	gtk_widget_show(event_box);
 	gtkconv->infopane_hbox = gtk_hbox_new(FALSE, 0);
-	gtk_box_pack_start(GTK_BOX(vbox), gtkconv->infopane_hbox, FALSE, FALSE, 0);
+	gtk_box_pack_start(GTK_BOX(vbox), event_box, FALSE, FALSE, 0);
+	gtk_container_add(GTK_CONTAINER(event_box), gtkconv->infopane_hbox);
 	gtk_widget_show(gtkconv->infopane_hbox);
+	gtk_widget_add_events(event_box,
+	                      GDK_BUTTON1_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK);
+	g_signal_connect(G_OBJECT(event_box), "button_press_event",
+	                 G_CALLBACK(infopane_press_cb), gtkconv);
+	g_signal_connect(G_OBJECT(event_box), "button_release_event",
+	                 G_CALLBACK(infopane_release_cb), gtkconv);
+
 
 	gtkconv->infopane = gtk_cell_view_new();
 	gtkconv->infopane_model = gtk_list_store_new(NUM_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING);
@@ -7594,6 +7606,45 @@
 /*
  * THANK YOU GALEON!
  */
+
+static gboolean
+infopane_press_cb(GtkWidget *widget, GdkEventButton *e, PidginConversation *gtkconv)
+{
+	int nb_x, nb_y;
+
+	if (e->button != 1 || e->type != GDK_BUTTON_PRESS)
+		return FALSE;
+
+	if (gtkconv->win->in_drag) {
+		  purple_debug(PURPLE_DEBUG_WARNING, "gtkconv",
+                           "Already in the middle of a window drag at tab_press_cb\n");
+                return TRUE;
+        }
+	
+	gtkconv->win->in_predrag = TRUE;
+	gtkconv->win->drag_tab = gtk_notebook_page_num(GTK_NOTEBOOK(gtkconv->win->notebook), gtkconv->tab_cont);
+
+        gdk_window_get_origin(gtkconv->infopane_hbox->window, &nb_x, &nb_y);
+
+        gtkconv->win->drag_min_x = gtkconv->infopane_hbox->allocation.x      + nb_x;
+        gtkconv->win->drag_min_y = gtkconv->infopane_hbox->allocation.y      + nb_y;
+        gtkconv->win->drag_max_x = gtkconv->infopane_hbox->allocation.width  + gtkconv->win->drag_min_x;
+        gtkconv->win->drag_max_y = gtkconv->infopane_hbox->allocation.height + gtkconv->win->drag_min_y;
+
+
+	/* Connect the new motion signals. */
+	gtkconv->win->drag_motion_signal =
+		g_signal_connect(G_OBJECT(gtkconv->win->notebook), "motion_notify_event",
+		                 G_CALLBACK(notebook_motion_cb), gtkconv->win);
+
+	gtkconv->win->drag_leave_signal =
+		g_signal_connect(G_OBJECT(gtkconv->win->notebook), "leave_notify_event",
+		                 G_CALLBACK(notebook_leave_cb), gtkconv->win);
+
+	return FALSE;
+
+}
+
 static gboolean
 notebook_press_cb(GtkWidget *widget, GdkEventButton *e, PidginWindow *win)
 {
@@ -7683,6 +7734,12 @@
 }
 
 static gboolean
+infopane_release_cb(GtkWidget *widget, GdkEventButton *e, PidginConversation *gtkconv)
+{
+	return FALSE;
+}
+
+static gboolean
 notebook_release_cb(GtkWidget *widget, GdkEventButton *e, PidginWindow *win)
 {
 	PidginWindow *dest_win;
@@ -8013,6 +8070,11 @@
 		return FALSE;
 	}
 
+	if (!purple_account_is_connected(gtkconv->active_conv->account)) {
+		/* Do not allow aliasing someone on a disconnected account. */
+		return FALSE;
+	}
+
 	/* alias label */
 	entry = gtk_entry_new();
 	gtk_entry_set_has_frame(GTK_ENTRY(entry), FALSE);
@@ -8374,8 +8436,7 @@
 		/* Er, bug in notebooks? Switch to the page manually. */
 		gtk_notebook_set_current_page(GTK_NOTEBOOK(win->notebook), 0);
 
-		gtk_notebook_set_show_tabs(GTK_NOTEBOOK(win->notebook),
-		                           purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/tabs"));
+		gtk_notebook_set_show_tabs(GTK_NOTEBOOK(win->notebook), FALSE);
 	} else
 		gtk_notebook_set_show_tabs(GTK_NOTEBOOK(win->notebook), TRUE);
 
@@ -8491,14 +8552,16 @@
 
 	gtk_notebook_remove_page(GTK_NOTEBOOK(win->notebook), index);
 
-	/* go back to tabless if need be */
+	/* go back to tabless */
 	if (pidgin_conv_window_get_gtkconv_count(win) <= 2) {
-		gtk_notebook_set_show_tabs(GTK_NOTEBOOK(win->notebook),
-		                           purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/tabs"));
+		gtk_notebook_set_show_tabs(GTK_NOTEBOOK(win->notebook), FALSE);
 	}
 
 	win->gtkconvs = g_list_remove(win->gtkconvs, gtkconv);
 
+	if (!win->gtkconvs || !win->gtkconvs->next)
+		gtk_notebook_set_show_tabs(GTK_NOTEBOOK(win->notebook), FALSE);
+
 	if (!win->gtkconvs && win != hidden_convwin)
 		pidgin_conv_window_destroy(win);
 }
--- a/pidgin/gtkprivacy.c	Sat Jun 23 20:34:07 2007 +0000
+++ b/pidgin/gtkprivacy.c	Mon Jun 25 21:38:40 2007 +0000
@@ -366,7 +366,7 @@
 
 	dialog = g_new0(PidginPrivacyDialog, 1);
 
-	dialog->win = pidgin_create_window(_("Privacy"), PIDGIN_HIG_BORDER, "privacy", FALSE);
+	dialog->win = pidgin_create_window(_("Privacy"), PIDGIN_HIG_BORDER, "privacy", TRUE);
 
 	g_signal_connect(G_OBJECT(dialog->win), "delete_event",
 					 G_CALLBACK(destroy_cb), dialog);
--- a/pidgin/gtksavedstatuses.c	Sat Jun 23 20:34:07 2007 +0000
+++ b/pidgin/gtksavedstatuses.c	Mon Jun 25 21:38:40 2007 +0000
@@ -658,17 +658,16 @@
 					 G_CALLBACK(status_window_close_cb), dialog);
 
 	purple_signal_connect(purple_savedstatuses_get_handle(),
-			"savedstatus-changed", dialog,
+			"savedstatus-changed", status_window,
 			PURPLE_CALLBACK(current_status_changed), dialog);
-
 	purple_signal_connect(purple_savedstatuses_get_handle(),
-			"savedstatus-added", dialog,
+			"savedstatus-added", status_window,
 			PURPLE_CALLBACK(saved_status_updated_cb), dialog);
 	purple_signal_connect(purple_savedstatuses_get_handle(),
-			"savedstatus-deleted", dialog,
+			"savedstatus-deleted", status_window,
 			PURPLE_CALLBACK(saved_status_updated_cb), dialog);
 	purple_signal_connect(purple_savedstatuses_get_handle(),
-			"savedstatus-modified", dialog,
+			"savedstatus-modified", status_window,
 			PURPLE_CALLBACK(saved_status_updated_cb), dialog);
 
 	gtk_widget_show_all(win);
@@ -685,6 +684,7 @@
 
 	purple_request_close_with_handle(status_window);
 	purple_notify_close_with_handle(status_window);
+	purple_signals_disconnect_by_handle(status_window);
 	g_free(status_window);
 	status_window = NULL;
 }
@@ -1140,7 +1140,7 @@
 	if (edit)
 		dialog->original_title = g_strdup(purple_savedstatus_get_title(saved_status));
 
-	dialog->window = win = pidgin_create_window (_("Status"), PIDGIN_HIG_BORDER, "status", FALSE) ;
+	dialog->window = win = pidgin_create_window(_("Status"), PIDGIN_HIG_BORDER, "status", TRUE);
 
 	g_signal_connect(G_OBJECT(win), "delete_event",
 					 G_CALLBACK(status_editor_destroy_cb), dialog);
@@ -1475,7 +1475,7 @@
 	dialog->account = account;
 
 	tmp = g_strdup_printf(_("Status for %s"), purple_account_get_username(account));
-	dialog->window = win = pidgin_create_window(tmp, PIDGIN_HIG_BORDER, "substatus", FALSE) ;
+	dialog->window = win = pidgin_create_window(tmp, PIDGIN_HIG_BORDER, "substatus", TRUE);
 	g_free(tmp);
 
 	g_signal_connect(G_OBJECT(win), "delete_event",
@@ -1520,7 +1520,7 @@
 
 	/* Status mesage */
 	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/gtkstatusbox.c	Sat Jun 23 20:34:07 2007 +0000
+++ b/pidgin/gtkstatusbox.c	Mon Jun 25 21:38:40 2007 +0000
@@ -1016,10 +1016,10 @@
 	}
 }
 
-static void
-pidgin_status_box_regenerate(PidginStatusBox *status_box)
+static gboolean
+pidgin_status_box_regenerate_real(PidginStatusBox *status_box)
 {
-	GdkPixbuf *pixbuf, *pixbuf2, *pixbuf3, *pixbuf4;
+	GdkPixbuf *pixbuf, *pixbuf2, *pixbuf3, *pixbuf4, *pixbuf5;
 	GtkIconSize icon_size;
 
 	icon_size = gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL);
@@ -1049,15 +1049,19 @@
 			                                  icon_size, "PidginStatusBox");
 			pixbuf4 = gtk_widget_render_icon (GTK_WIDGET(status_box->vbox), PIDGIN_STOCK_STATUS_INVISIBLE,
 			                                  icon_size, "PidginStatusBox");
+			pixbuf5 = gtk_widget_render_icon (GTK_WIDGET(status_box->vbox), PIDGIN_STOCK_STATUS_BUSY,
+							  icon_size, "PidginStatusBox");
 
 			pidgin_status_box_add(PIDGIN_STATUS_BOX(status_box), PIDGIN_STATUS_BOX_TYPE_PRIMITIVE, pixbuf, _("Available"), NULL, GINT_TO_POINTER(PURPLE_STATUS_AVAILABLE));
 			pidgin_status_box_add(PIDGIN_STATUS_BOX(status_box), PIDGIN_STATUS_BOX_TYPE_PRIMITIVE, pixbuf2, _("Away"), NULL, GINT_TO_POINTER(PURPLE_STATUS_AWAY));
+			pidgin_status_box_add(PIDGIN_STATUS_BOX(status_box), PIDGIN_STATUS_BOX_TYPE_PRIMITIVE, pixbuf5, _("Do not disturb"), NULL, GINT_TO_POINTER(PURPLE_STATUS_UNAVAILABLE));
 			pidgin_status_box_add(PIDGIN_STATUS_BOX(status_box), PIDGIN_STATUS_BOX_TYPE_PRIMITIVE, pixbuf4, _("Invisible"), NULL, GINT_TO_POINTER(PURPLE_STATUS_INVISIBLE));
 			pidgin_status_box_add(PIDGIN_STATUS_BOX(status_box), PIDGIN_STATUS_BOX_TYPE_PRIMITIVE, pixbuf3, _("Offline"), NULL, GINT_TO_POINTER(PURPLE_STATUS_OFFLINE));
 
 			if (pixbuf2)	g_object_unref(G_OBJECT(pixbuf2));
 			if (pixbuf3)	g_object_unref(G_OBJECT(pixbuf3));
 			if (pixbuf4)	g_object_unref(G_OBJECT(pixbuf4));
+			if (pixbuf5)	g_object_unref(G_OBJECT(pixbuf5));
 		}
 
 		add_popular_statuses(status_box);
@@ -1077,11 +1081,21 @@
 	}
 	gtk_tree_view_set_model(GTK_TREE_VIEW(status_box->tree_view), GTK_TREE_MODEL(status_box->dropdown_store));
 	gtk_tree_view_set_search_column(GTK_TREE_VIEW(status_box->tree_view), TEXT_COLUMN);
+
+	return FALSE;
+}
+
+static void
+pidgin_status_box_regenerate(PidginStatusBox *status_box)
+{
+	/* we have to do this in a timeout, so we avoid recursing
+	 * to infinity (and beyond) */
+	purple_timeout_add(0, (GSourceFunc)pidgin_status_box_regenerate_real, status_box);
 }
 
 static gboolean combo_box_scroll_event_cb(GtkWidget *w, GdkEventScroll *event, GtkIMHtml *imhtml)
 {
-  	pidgin_status_box_popup(PIDGIN_STATUS_BOX(w));
+	pidgin_status_box_popup(PIDGIN_STATUS_BOX(w));
 	return TRUE;
 }
 
--- a/pidgin/pidginstock.c	Sat Jun 23 20:34:07 2007 +0000
+++ b/pidgin/pidginstock.c	Mon Jun 25 21:38:40 2007 +0000
@@ -169,10 +169,8 @@
 	{ PIDGIN_STOCK_TRAY_XA, "tray", "tray-extended-away.png", TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL  },
 	{ PIDGIN_STOCK_TRAY_OFFLINE, "tray", "tray-offline.png", TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL  },
 	{ PIDGIN_STOCK_TRAY_CONNECT, "tray", "tray-connecting.png", TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL  },
-	{ PIDGIN_STOCK_TRAY_PENDING, "tray", "tray-new-im.png", TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL  }
-/* Uncomment me after 2.0.2!
- *	{ PIDGIN_STOCK_TRAY_EMAIL, "tray", "tray-message.png", TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL  }
- */
+	{ PIDGIN_STOCK_TRAY_PENDING, "tray", "tray-new-im.png", TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL  },
+	{ PIDGIN_STOCK_TRAY_EMAIL, "tray", "tray-message.png", TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, NULL  }
 };
 
 static gchar *
--- a/pidgin/pidginstock.h	Sat Jun 23 20:34:07 2007 +0000
+++ b/pidgin/pidginstock.h	Mon Jun 25 21:38:40 2007 +0000
@@ -137,9 +137,7 @@
 #define PIDGIN_STOCK_TRAY_OFFLINE         "pidgin-tray-offline"
 #define PIDGIN_STOCK_TRAY_CONNECT         "pidgin-tray-connect"
 #define PIDGIN_STOCK_TRAY_PENDING         "pidgin-tray-pending"
-/* Uncomment me after 2.0.2! 
- * #define PIDGIN_STOCK_TRAY_EMAIL		  "pidgin-tray-email"
- */
+#define PIDGIN_STOCK_TRAY_EMAIL		  "pidgin-tray-email"
 
 
 /*@}*/
--- a/pidgin/plugins/gtkbuddynote.c	Sat Jun 23 20:34:07 2007 +0000
+++ b/pidgin/plugins/gtkbuddynote.c	Mon Jun 25 21:38:40 2007 +0000
@@ -30,8 +30,8 @@
 	if (full) {
 		const gchar *note = purple_blist_node_get_string(node, "notes");
 
-		if (note != NULL) {
-			g_string_append_printf(text, _("\nBuddy Note: %s"),
+		if ((note != NULL) && (*note != '\0')) {
+			g_string_append_printf(text, _("\n<b>Buddy Note</b>: %s"),
 			                       note);
 		}
 	}
@@ -94,6 +94,7 @@
 check_for_buddynote(gpointer data)
 {
 	PurplePlugin *buddynote = NULL;
+	PurplePlugin *plugin = (PurplePlugin *)data;
 
 	buddynote = purple_plugins_find_with_id("core-plugin_pack-buddynote");
 
@@ -108,6 +109,18 @@
 
 		info.dependencies = g_list_append(info.dependencies,
 		                                  "core-plugin_pack-buddynote");
+
+		/* If non-gtk buddy note plugin is loaded, but we are not, then load
+		 * ourselves, otherwise people upgrading from pre-gtkbuddynote days
+		 * will not have 'Buddy Notes' showing as loaded in the plugins list.
+		 * We also trigger a save on the list of plugins because it's not been
+		 * loaded through the UI. */
+		if (purple_plugin_is_loaded(buddynote) &&
+		    !purple_plugin_is_loaded(plugin)) {
+			purple_plugin_load(plugin);
+			pidgin_plugins_save();
+		}
+
 	} else {
 		info.flags = PURPLE_PLUGIN_FLAG_INVISIBLE;
 	}