changeset 26757:7c3baa45c9c4

propagate from branch 'im.pidgin.pidgin' (head 2476e13ecb1702a744a13c42956b29a962a0c7fb) to branch 'im.pidgin.cpw.darkrain42.docs' (head 0c12c56a9f1f3094bb926125a44c04a556e1dee5)
author Paul Aurich <paul@darkrain42.org>
date Fri, 27 Mar 2009 07:52:26 +0000
parents 247e2a759ed2 (current diff) ba1799f21383 (diff)
children efbbd2e2b29e
files ChangeLog.API libpurple/blist.h libpurple/xmlnode.h
diffstat 46 files changed, 728 insertions(+), 319 deletions(-) [+]
line wrap: on
line diff
--- a/COPYRIGHT	Thu Mar 12 06:19:15 2009 +0000
+++ b/COPYRIGHT	Fri Mar 27 07:52:26 2009 +0000
@@ -8,6 +8,7 @@
 Dave Ahlswede
 Manuel Amador
 Matt Amato
+Josef Andrysek
 Geoffrey Antos
 Daniel Atallah
 Paul Aurich
--- a/ChangeLog	Thu Mar 12 06:19:15 2009 +0000
+++ b/ChangeLog	Fri Mar 27 07:52:26 2009 +0000
@@ -4,10 +4,13 @@
 	General:
 	* Theme support in libpurple thanks to Justin Rodriguez's summer of code
 	  project.  With some minor additions and clean ups from Paul Aurich.
+	* It should no longer be possible to end up with duplicates of buddies
+	  in a group on the buddy list.
 
 	XMPP:
-	* Add support for in-band bytestreams (XEP-0047).
-	* Add support for attention (XEP-0224).
+	* Add support for in-band bytestreams for file transfers (XEP-0047).
+	* Add support for sending attentions (equivalent to "buzz" and "nudge")
+	  using the command /buzz (XEP-0224).
 
 	Pidgin:
 	* Added -f command line option to tell Pidgin to ignore NetworkManager
@@ -18,6 +21,11 @@
 	* Pressing the Enter key in the message entry box of the New Status
 	  dialog and various other dialogs now causes the cursor to move to
 	  the next line.
+	* Created a unified Buddy Pounce notification window for all pounces
+	  where "Pop up a notification" is selected, which avoids having a
+	  new dialog box every time a pounce is triggered. (Jorge VillaseƱor) 
+	* The New Account dialog is now broken into three tabs.  Proxy
+	  configuration has been moved from the Advanced tab to the new tab.
 
 version 2.5.5 (03/01/2009):
 	libpurple:
--- a/ChangeLog.API	Thu Mar 12 06:19:15 2009 +0000
+++ b/ChangeLog.API	Fri Mar 27 07:52:26 2009 +0000
@@ -26,6 +26,14 @@
 		* purple_request_field_set_ui_data
 		* purple_strequal
 		* xmlnode_from_file
+		* xmlnode_set_attrib_full
+
+		Changed:
+		* xmlnode_remove_attrib now removes all attributes with the
+		  same name.  Previously, it would remove the first one found,
+		  which was completely non-deterministic.  If you want to remove
+		  the attribute with no namespace, then use NULL with
+		  xmlnode_remove_with_namespace.
 
 		Deprecated:
 		* purple_buddy_get_local_alias
@@ -41,6 +49,8 @@
 		* purple_status_set_attr_string
 		* purple_presence_add_status
 		* purple_presence_add_list
+		* xmlnode_set_attrib_with_namespace
+		* xmlnode_set_attrib_with_prefix
 
 	pidgin:
 		Added:
@@ -53,6 +63,7 @@
 		* pidgin_blist_get_theme
 		* pidgin_sound_is_customized
 		* pidgin_utils_init, pidgin_utils_uninit
+		* pidgin_notify_pounce_add
 
 	perl:
 		Changed:
--- a/finch/gntblist.c	Thu Mar 12 06:19:15 2009 +0000
+++ b/finch/gntblist.c	Fri Mar 27 07:52:26 2009 +0000
@@ -643,10 +643,14 @@
 		purple_blist_add_group(grp, NULL);
 	}
 
-	/* XXX: Ask if there's already the same buddy in the same group (#4553) */
-
-	buddy = purple_buddy_new(account, username, alias);
-	purple_blist_add_buddy(buddy, NULL, grp, NULL);
+	/* XXX: Ask to merge if there's already a buddy with the same alias in the same group (#4553) */
+
+	if ((buddy = purple_find_buddy_in_group(account, username, grp)) == NULL)
+	{
+		buddy = purple_buddy_new(account, username, alias);
+		purple_blist_add_buddy(buddy, NULL, grp, NULL);
+	}
+
 	purple_account_add_buddy(account, buddy);
 }
 
--- a/finch/gntlog.c	Thu Mar 12 06:19:15 2009 +0000
+++ b/finch/gntlog.c	Fri Mar 27 07:52:26 2009 +0000
@@ -66,7 +66,7 @@
 			g_str_hash(purple_account_get_username(viewer->account));
 	}
 
-	return (guint)viewer;
+	return g_direct_hash(viewer);
 }
 
 static gboolean log_viewer_equal(gconstpointer y, gconstpointer z)
--- a/finch/gntplugin.c	Thu Mar 12 06:19:15 2009 +0000
+++ b/finch/gntplugin.c	Fri Mar 27 07:52:26 2009 +0000
@@ -484,10 +484,10 @@
 				char *value = NULL;
 				switch(type) {
 					case PURPLE_PREF_BOOLEAN:
-						value = g_strdup_printf("%d", (int)list->next->data);
+						value = g_strdup_printf("%d", GPOINTER_TO_INT(list->next->data));
 						break;
 					case PURPLE_PREF_INT:
-						value = g_strdup_printf("%d", (int)list->next->data);
+						value = g_strdup_printf("%d", GPOINTER_TO_INT(list->next->data));
 						break;
 					case PURPLE_PREF_STRING:
 						value = g_strdup(list->next->data);
--- a/finch/gntroomlist.c	Thu Mar 12 06:19:15 2009 +0000
+++ b/finch/gntroomlist.c	Fri Mar 27 07:52:26 2009 +0000
@@ -190,7 +190,7 @@
 				label = g_strdup(iter->data ? "True" : "False");
 				break;
 			case PURPLE_ROOMLIST_FIELD_INT:
-				label = g_strdup_printf("%d", (int)iter->data);
+				label = g_strdup_printf("%d", GPOINTER_TO_INT(iter->data));
 				break;
 			case PURPLE_ROOMLIST_FIELD_STRING:
 				label = g_strdup(iter->data);
--- a/libpurple/account.h	Thu Mar 12 06:19:15 2009 +0000
+++ b/libpurple/account.h	Fri Mar 27 07:52:26 2009 +0000
@@ -42,6 +42,7 @@
 
 #include "connection.h"
 #include "log.h"
+#include "privacy.h"
 #include "proxy.h"
 #include "prpl.h"
 #include "status.h"
@@ -141,7 +142,7 @@
 	 */
 	GSList *permit;             /**< Permit list.                           */
 	GSList *deny;               /**< Deny list.                             */
-	int perm_deny;              /**< The permit/deny setting.               */
+	PurplePrivacyType perm_deny;  /**< The permit/deny setting.               */
 
 	GList *status_types;        /**< Status types.                          */
 
--- a/libpurple/blist.h	Thu Mar 12 06:19:15 2009 +0000
+++ b/libpurple/blist.h	Fri Mar 27 07:52:26 2009 +0000
@@ -609,7 +609,7 @@
  * @param contact The optional contact to place the buddy in.
  * @param group   The group to add the new buddy to.
  * @param node    The insertion point.  Pass in NULL to add the node as
- *                the last child in the given group.
+ *                the first child in the given group.
  */
 void purple_blist_add_buddy(PurpleBuddy *buddy, PurpleContact *contact, PurpleGroup *group, PurpleBlistNode *node);
 
--- a/libpurple/circbuffer.c	Thu Mar 12 06:19:15 2009 +0000
+++ b/libpurple/circbuffer.c	Fri Mar 27 07:52:26 2009 +0000
@@ -68,7 +68,8 @@
 
 	/* If the fill pointer is wrapped to before the remove
 	 * pointer, we need to shift the data */
-	if (in_offset < out_offset) {
+	if (in_offset < out_offset
+			|| (in_offset == out_offset && buf->bufused > 0)) {
 		int shift_n = MIN(buf->buflen - start_buflen,
 			in_offset);
 		memcpy(buf->buffer + start_buflen, buf->buffer,
--- a/libpurple/dnssrv.c	Thu Mar 12 06:19:15 2009 +0000
+++ b/libpurple/dnssrv.c	Fri Mar 27 07:52:26 2009 +0000
@@ -175,9 +175,11 @@
 
 end:
 	size = g_list_length(ret);
+	/* TODO: Check return value */
 	write(out, &size, sizeof(int));
 	while (ret != NULL)
 	{
+		/* TODO: Check return value */
 		write(out, ret->data, sizeof(PurpleSrvResponse));
 		g_free(ret->data);
 		ret = g_list_remove(ret, ret->data);
--- a/libpurple/protocols/bonjour/mdns_win32.c	Thu Mar 12 06:19:15 2009 +0000
+++ b/libpurple/protocols/bonjour/mdns_win32.c	Fri Mar 27 07:52:26 2009 +0000
@@ -169,14 +169,17 @@
 	gboolean delete_buddy = FALSE;
 	PurpleBuddy *pb = NULL;
 
+	if ((pb = purple_find_buddy(args->account, args->res_data->name))) {
+		if (pb->proto_data != args->bb) {
+			purple_debug_error("bonjour", "Found purple buddy for %s not matching bonjour buddy record.",
+				args->res_data->name);
+			goto cleanup;
+		}
 	/* Make sure that the BonjourBuddy associated with this request is still around */
-	if (g_slist_find(pending_buddies, args->bb) == NULL)
+	} else if (g_slist_find(pending_buddies, args->bb) == NULL) {
+		purple_debug_error("bonjour", "host resolution - complete, but buddy no longer pending.\n");
 		goto cleanup;
-
-	if ((pb = purple_find_buddy(args->account, args->bb->name)))
-		if (pb->proto_data != args->bb)
-			purple_debug_error("bonjour", "Found purple buddy for %s not matching bonjour buddy record. "
-				"This is going to be ugly!.\n", args->bb->name);
+	}
 
 	if (!hosts || !hosts->data) {
 		purple_debug_error("bonjour", "host resolution - callback error.\n");
--- a/libpurple/protocols/bonjour/parser.c	Thu Mar 12 06:19:15 2009 +0000
+++ b/libpurple/protocols/bonjour/parser.c	Fri Mar 27 07:52:26 2009 +0000
@@ -91,14 +91,12 @@
 		xmlnode_set_namespace(node, (const char*) namespace);
 
 		for(i=0; i < nb_attributes * 5; i+=5) {
+			const char *name = (const char *)attributes[i];
+			const char *prefix = (const char *)attributes[i+1];
+			const char *attrib_ns = (const char *)attributes[i+2];
 			char *txt;
 			int attrib_len = attributes[i+4] - attributes[i+3];
 			char *attrib = g_malloc(attrib_len + 1);
-			char *attrib_ns = NULL;
-
-			if (attributes[i+2]) {
-				attrib_ns = g_strdup((char*)attributes[i+2]);
-			}
 
 			memcpy(attrib, attributes[i+3], attrib_len);
 			attrib[attrib_len] = '\0';
@@ -106,9 +104,8 @@
 			txt = attrib;
 			attrib = purple_unescape_html(txt);
 			g_free(txt);
-			xmlnode_set_attrib_with_namespace(node, (const char*) attributes[i], attrib_ns, attrib);
+			xmlnode_set_attrib_full(node, name, attrib_ns, prefix, attrib);
 			g_free(attrib);
-			g_free(attrib_ns);
 		}
 
 		bconv->current = node;
--- a/libpurple/protocols/irc/irc.c	Thu Mar 12 06:19:15 2009 +0000
+++ b/libpurple/protocols/irc/irc.c	Fri Mar 27 07:52:26 2009 +0000
@@ -565,7 +565,7 @@
 	struct irc_conn *irc = (struct irc_conn *)gc->proto_data;
 	struct irc_buddy *ib = g_new0(struct irc_buddy, 1);
 	ib->name = g_strdup(purple_buddy_get_name(buddy));
-	g_hash_table_insert(irc->buddies, ib->name, ib);
+	g_hash_table_replace(irc->buddies, ib->name, ib);
 
 	/* if the timer isn't set, this is during signon, so we don't want to flood
 	 * ourself off with ISON's, so we don't, but after that we want to know when
--- a/libpurple/protocols/jabber/parser.c	Thu Mar 12 06:19:15 2009 +0000
+++ b/libpurple/protocols/jabber/parser.c	Fri Mar 27 07:52:26 2009 +0000
@@ -86,6 +86,8 @@
 			}
 		}
 		for(i=0; i < nb_attributes * 5; i+=5) {
+			const char *name = (const char *)attributes[i];
+			const char *prefix = (const char *)attributes[i+1];
 			const char *attrib_ns = (const char *)attributes[i+2];
 			char *txt;
 			int attrib_len = attributes[i+4] - attributes[i+3];
@@ -97,7 +99,7 @@
 			txt = attrib;
 			attrib = purple_unescape_html(txt);
 			g_free(txt);
-			xmlnode_set_attrib_with_namespace(node, (const char*) attributes[i], attrib_ns, attrib);
+			xmlnode_set_attrib_full(node, name, attrib_ns, prefix, attrib);
 			g_free(attrib);
 		}
 
--- a/libpurple/protocols/jabber/si.c	Thu Mar 12 06:19:15 2009 +0000
+++ b/libpurple/protocols/jabber/si.c	Fri Mar 27 07:52:26 2009 +0000
@@ -1096,6 +1096,7 @@
 			"jabber_si_xfer_ibb_send_data: error reading from file\n");
 		purple_xfer_cancel_local(xfer);
 	}
+	g_free(data);
 }
 
 static void
--- a/libpurple/protocols/msn/contact.c	Thu Mar 12 06:19:15 2009 +0000
+++ b/libpurple/protocols/msn/contact.c	Fri Mar 27 07:52:26 2009 +0000
@@ -1482,8 +1482,6 @@
 			  const gchar *passport, const MsnListId list)
 {
 	gchar *body = NULL, *member = NULL;
-	const char *type = "PassportMember";
-	gchar *federate = NULL;
 	MsnSoapPartnerScenario partner_scenario;
 	MsnUser *user;
 
@@ -1501,23 +1499,28 @@
 	msn_callback_state_set_who(state, passport);
 
 	user = msn_userlist_find_user(session->userlist, passport);
-	if (user && user->networkid != MSN_NETWORK_PASSPORT) {
-		type = "EmailMember";
-		federate = g_strdup_printf(MSN_MEMBER_FEDERATED_ANNOTATION_XML,
-		                           user->networkid);
-	}
 	
 	if (list == MSN_LIST_PL) {
 		partner_scenario = MSN_PS_CONTACT_API;
-		member = g_strdup_printf(MSN_MEMBER_MEMBERSHIPID_XML,
-		                         type, user->membership_id[MSN_LIST_PL],
-		                         federate ? federate : "");
+		if (user && user->networkid != MSN_NETWORK_PASSPORT)
+			member = g_strdup_printf(MSN_MEMBER_MEMBERSHIPID_XML,
+			                         "EmailMember", "Email",
+			                         user->membership_id[MSN_LIST_PL]);
+		else
+			member = g_strdup_printf(MSN_MEMBER_MEMBERSHIPID_XML,
+			                         "PassportMember", "Passport",
+			                         user->membership_id[MSN_LIST_PL]);
 	} else {
 		/* list == MSN_LIST_AL || list == MSN_LIST_BL */
 		partner_scenario = MSN_PS_BLOCK_UNBLOCK;
-		member = g_strdup_printf(MSN_MEMBER_PASSPORT_XML,
-		                         type, passport,
-		                         federate ? federate : "");
+		if (user && user->networkid != MSN_NETWORK_PASSPORT)
+			member = g_strdup_printf(MSN_MEMBER_PASSPORT_XML,
+			                         "EmailMember", "Email",
+			                         "Email", passport, "Email");
+		else
+			member = g_strdup_printf(MSN_MEMBER_PASSPORT_XML,
+			                         "PassportMember", "Passport",
+			                         "PassportName", passport, "PassportName");
 	}
 
 	body = g_strdup_printf(MSN_CONTACT_DELETE_FROM_LIST_TEMPLATE,
@@ -1530,7 +1533,6 @@
 	state->cb = msn_del_contact_from_list_read_cb;
 	msn_contact_request(state);
 
-	g_free(federate);
 	g_free(member);
 	g_free(body);
 }
@@ -1578,8 +1580,6 @@
 			const gchar *passport, const MsnListId list)
 {
 	gchar *body = NULL, *member = NULL;
-	const char *type = "PassportMember";
-	gchar *federate = NULL;
 	MsnSoapPartnerScenario partner_scenario;
 	MsnUser *user;
 
@@ -1596,15 +1596,16 @@
 	msn_callback_state_set_who(state, passport);
 
 	user = msn_userlist_find_user(session->userlist, passport);
-	if (user && user->networkid != MSN_NETWORK_PASSPORT) {
-		type = "EmailMember";
-		federate = g_strdup_printf(MSN_MEMBER_FEDERATED_ANNOTATION_XML,
-		                           user->networkid);
-	}
 
 	partner_scenario = (list == MSN_LIST_RL) ? MSN_PS_CONTACT_API : MSN_PS_BLOCK_UNBLOCK;
-	member = g_strdup_printf(MSN_MEMBER_PASSPORT_XML,
-	                         type, state->who, federate ? federate : "");
+	if (user && user->networkid != MSN_NETWORK_PASSPORT)
+		member = g_strdup_printf(MSN_MEMBER_PASSPORT_XML,
+		                         "EmailMember", "Email",
+		                         "Email", state->who, "Email");
+	else
+		member = g_strdup_printf(MSN_MEMBER_PASSPORT_XML,
+		                         "PassportMember", "Passport",
+		                         "PassportName", state->who, "PassportName");
 
 	body = g_strdup_printf(MSN_CONTACT_ADD_TO_LIST_TEMPLATE,
 		MsnSoapPartnerScenarioText[partner_scenario],
@@ -1616,7 +1617,6 @@
 	state->cb = msn_add_contact_to_list_read_cb;
 	msn_contact_request(state);
 
-	g_free(federate);
 	g_free(member);
 	g_free(body);
 }
--- a/libpurple/protocols/msn/contact.h	Thu Mar 12 06:19:15 2009 +0000
+++ b/libpurple/protocols/msn/contact.h	Fri Mar 27 07:52:26 2009 +0000
@@ -397,28 +397,18 @@
 
 #define MSN_MEMBER_PASSPORT_XML	\
 	"<Member xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"%s\">"\
-		"<Type>Passport</Type>"\
+		"<Type>%s</Type>"\
 		"<State>Accepted</State>"\
-		"<PassportName>%s</PassportName>"\
-		"%s"\
+		"<%s>%s</%s>"\
 	"</Member>"
 
 #define MSN_MEMBER_MEMBERSHIPID_XML	\
 	"<Member xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"%s\">"\
-		"<Type>Passport</Type>"\
+		"<Type>%s</Type>"\
 		"<MembershipId>%u</MembershipId>"\
 		"<State>Accepted</State>"\
-		"%s"\
 	"</Member>"
 
-#define MSN_MEMBER_FEDERATED_ANNOTATION_XML \
-	"<Annotations>"\
-		"<Annotation>"\
-			"<Name>MSN.IM.BuddyType</Name>"\
-			"<Value>%02d:</Value>"\
-		"</Annotation>"\
-	"</Annotations>"
-
 /* first delete contact from allow list */
 
 #define MSN_CONTACT_DELETE_FROM_LIST_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\
--- a/libpurple/protocols/msn/notification.c	Thu Mar 12 06:19:15 2009 +0000
+++ b/libpurple/protocols/msn/notification.c	Fri Mar 27 07:52:26 2009 +0000
@@ -1609,7 +1609,7 @@
 
 	if ( (root = xmlnode_from_str(cmd->payload, cmd->payload_len)) == NULL)
 	{
-		purple_debug_error("msn", "Unable to parse GCF payload into a XML tree");
+		purple_debug_error("msn", "Unable to parse GCF payload into a XML tree\n");
 		return;
 	}
 
@@ -1682,7 +1682,7 @@
 	user = msn_userlist_find_user(session->userlist, passport);
 	if (user == NULL) {
 		char *str = g_strndup(payload, len);
-		purple_debug_info("msn", "unknown user %s, payload is %s",
+		purple_debug_info("msn", "unknown user %s, payload is %s\n",
 			passport, str);
 		g_free(str);
 		return;
--- a/libpurple/protocols/msn/oim.c	Thu Mar 12 06:19:15 2009 +0000
+++ b/libpurple/protocols/msn/oim.c	Fri Mar 27 07:52:26 2009 +0000
@@ -174,7 +174,7 @@
 		gchar *faultcode_str = xmlnode_get_data(faultcode);
 
 		if (faultcode_str && g_str_equal(faultcode_str, "q0:BadContextToken")) {
-			purple_debug_warning("msn", "OIM Request Error, Updating token now.");
+			purple_debug_warning("msn", "OIM Request Error, Updating token now.\n");
 			msn_nexus_update_token(data->oim->session->nexus,
 				data->send ? MSN_AUTH_LIVE_SECURE : MSN_AUTH_MESSENGER_WEB,
 				(GSourceFunc)msn_oim_request_helper, data);
@@ -183,7 +183,7 @@
 
 		} else if (faultcode_str && g_str_equal(faultcode_str, "q0:AuthenticationFailed")) {
 			if (xmlnode_get_child(fault, "detail/RequiredAuthPolicy") != NULL) {
-				purple_debug_warning("msn", "OIM Request Error, Updating token now.");
+				purple_debug_warning("msn", "OIM Request Error, Updating token now.\n");
 				msn_nexus_update_token(data->oim->session->nexus,
 					data->send ? MSN_AUTH_LIVE_SECURE : MSN_AUTH_MESSENGER_WEB,
 					(GSourceFunc)msn_oim_request_helper, data);
--- a/libpurple/protocols/msn/state.c	Thu Mar 12 06:19:15 2009 +0000
+++ b/libpurple/protocols/msn/state.c	Fri Mar 27 07:52:26 2009 +0000
@@ -169,7 +169,7 @@
 	}
 	currentmediaNode = xmlnode_get_child(payloadNode, "CurrentMedia");
 	if (currentmediaNode == NULL) {
-		purple_debug_info("msn", "No CurrentMedia Node");
+		purple_debug_info("msn", "No CurrentMedia Node\n");
 		xmlnode_free(payloadNode);
 		return NULL;
 	}
@@ -195,7 +195,7 @@
 	}
 	psmNode = xmlnode_get_child(payloadNode, "PSM");
 	if (psmNode == NULL) {
-		purple_debug_info("msn", "No PSM status Node");
+		purple_debug_info("msn", "No PSM status Node\n");
 		xmlnode_free(payloadNode);
 		return NULL;
 	}
--- a/libpurple/protocols/msn/switchboard.c	Thu Mar 12 06:19:15 2009 +0000
+++ b/libpurple/protocols/msn/switchboard.c	Fri Mar 27 07:52:26 2009 +0000
@@ -590,7 +590,7 @@
 	payload = msn_message_gen_payload(msg, &payload_len);
 
 #ifdef MSN_DEBUG_SB
-	purple_debug_info("msn", "SB length:{%" G_GSIZE_FORMAT "}", payload_len);
+	purple_debug_info("msn", "SB length:{%" G_GSIZE_FORMAT "}\n", payload_len);
 	msn_message_show_readable(msg, "SB SEND", FALSE);
 #endif
 
--- a/libpurple/protocols/msn/userlist.c	Thu Mar 12 06:19:15 2009 +0000
+++ b/libpurple/protocols/msn/userlist.c	Fri Mar 27 07:52:26 2009 +0000
@@ -858,7 +858,7 @@
 	}
 
 	if ( (user = msn_userlist_find_user(userlist, who)) == NULL) {
-		purple_debug_error("msn", "User %s not found!", who);
+		purple_debug_error("msn", "User %s not found!\n", who);
 		return FALSE;
 	}
 
@@ -887,7 +887,7 @@
 	}
 
 	if ( (user = msn_userlist_find_user(userlist, who)) == NULL) {
-		purple_debug_error("msn", "User %s not found!", who);
+		purple_debug_error("msn", "User %s not found!\n", who);
 		return FALSE;
 	}
 
--- a/libpurple/protocols/myspace/myspace.c	Thu Mar 12 06:19:15 2009 +0000
+++ b/libpurple/protocols/myspace/myspace.c	Fri Mar 27 07:52:26 2009 +0000
@@ -388,7 +388,7 @@
 
 	g_return_val_if_fail(buddy != NULL, NULL);
 
-	user = msim_get_user_from_buddy(buddy);
+	user = msim_get_user_from_buddy(buddy, TRUE);
 
 	account = purple_buddy_get_account(buddy);
 	gc = purple_account_get_connection(account);
@@ -436,7 +436,7 @@
 	g_return_if_fail(buddy != NULL);
 	g_return_if_fail(user_info != NULL);
 
-	user = msim_get_user_from_buddy(buddy);
+	user = msim_get_user_from_buddy(buddy, TRUE);
 
 	if (PURPLE_BUDDY_IS_ONLINE(buddy)) {
 		MsimSession *session;
@@ -1053,7 +1053,7 @@
 	g_free(display_name);
 
 	/* 3. Update buddy information */
-	user = msim_get_user_from_buddy(buddy);
+	user = msim_get_user_from_buddy(buddy, TRUE);
 
 	user->id = uid;
 	/* Keep track of the user ID across sessions */
@@ -1377,7 +1377,7 @@
 		buddy = purple_buddy_new(session->account, username, NULL);
 		purple_blist_add_buddy(buddy, NULL, NULL, NULL);
 
-		user = msim_get_user_from_buddy(buddy);
+		user = msim_get_user_from_buddy(buddy, TRUE);
 		user->id = msim_msg_get_integer(msg, "f");
 
 		/* Keep track of the user ID across sessions */
@@ -2641,6 +2641,9 @@
 	name = purple_buddy_get_name(buddy);
 	gname = group ? purple_group_get_name(group) : NULL;
 
+	if (msim_get_user_from_buddy(buddy, FALSE) != NULL)
+		return;
+
 	purple_debug_info("msim", "msim_add_buddy: want to add %s to %s\n",
 			name, gname ? gname : "(no group)");
 
--- a/libpurple/protocols/myspace/user.c	Thu Mar 12 06:19:15 2009 +0000
+++ b/libpurple/protocols/myspace/user.c	Fri Mar 27 07:52:26 2009 +0000
@@ -41,10 +41,10 @@
 }
 
 /**
- * Get the MsimUser from a PurpleBuddy, creating it if needed.
+ * Get the MsimUser from a PurpleBuddy, optionally creating it if needed.
  */
 MsimUser *
-msim_get_user_from_buddy(PurpleBuddy *buddy)
+msim_get_user_from_buddy(PurpleBuddy *buddy, gboolean create)
 {
 	MsimUser *user;
 
@@ -52,7 +52,8 @@
 		return NULL;
 	}
 
-	if (!(user = purple_buddy_get_protocol_data(buddy))) {
+	user = purple_buddy_get_protocol_data(buddy);
+	if (create && !user) {
 		/* No MsimUser for this buddy; make one. */
 
 		user = g_new0(MsimUser, 1);
@@ -94,7 +95,7 @@
 		return NULL;
 	}
 
-	user = msim_get_user_from_buddy(buddy);
+	user = msim_get_user_from_buddy(buddy, TRUE);
 
 	return user;
 }
--- a/libpurple/protocols/myspace/user.h	Thu Mar 12 06:19:15 2009 +0000
+++ b/libpurple/protocols/myspace/user.h	Fri Mar 27 07:52:26 2009 +0000
@@ -46,7 +46,7 @@
  * initiated from a user lookup. */
 typedef void (*MSIM_USER_LOOKUP_CB)(MsimSession *session, const MsimMessage *userinfo, gpointer data);
 
-MsimUser *msim_get_user_from_buddy(PurpleBuddy *buddy);
+MsimUser *msim_get_user_from_buddy(PurpleBuddy *buddy, gboolean create);
 void msim_user_free(MsimUser *user);
 MsimUser *msim_find_user(MsimSession *session, const gchar *username);
 void msim_append_user_info(MsimSession *session, PurpleNotifyUserInfo *user_info, MsimUser *user, gboolean full);
--- a/libpurple/protocols/novell/novell.c	Thu Mar 12 06:19:15 2009 +0000
+++ b/libpurple/protocols/novell/novell.c	Fri Mar 27 07:52:26 2009 +0000
@@ -2547,7 +2547,7 @@
 	if (gc == NULL || buddy == NULL || group == NULL)
 		return;
 
-	user = (NMUser *) gc->proto_data;
+	user = (NMUser *) purple_connection_get_protocol_data(gc);
 	if (user == NULL)
 		return;
 
@@ -2557,6 +2557,10 @@
 	if (!user->clist_synched)
 		return;
 
+	/* Don't re-add a buddy that is already on our contact list */
+	if (nm_find_user_record(user, purple_buddy_get_name(buddy)) != NULL)
+		return;
+
 	contact = nm_create_contact();
 	nm_contact_set_dn(contact, purple_buddy_get_name(buddy));
 
--- a/libpurple/protocols/oscar/oscar.c	Thu Mar 12 06:19:15 2009 +0000
+++ b/libpurple/protocols/oscar/oscar.c	Fri Mar 27 07:52:26 2009 +0000
@@ -4789,7 +4789,7 @@
 
 		status_html = purple_status_get_attr_string(status, "message");
 
-		if (primitive == PURPLE_STATUS_AVAILABLE || primitive == PURPLE_STATUS_INVISIBLE)
+		if (status_html == NULL || primitive == PURPLE_STATUS_AVAILABLE || primitive == PURPLE_STATUS_INVISIBLE)
 		{
 			/* This is needed for us to un-set any previous away message. */
 			away = g_strdup("");
@@ -4917,17 +4917,24 @@
 		return;
 	}
 
-	if ((od->ssi.received_data) && !(aim_ssi_itemlist_finditem(od->ssi.local, gname, bname, AIM_SSI_TYPE_BUDDY))) {
-		purple_debug_info("oscar",
-				   "ssi: adding buddy %s to group %s\n", bname, gname);
-		aim_ssi_addbuddy(od, bname, gname, NULL, purple_buddy_get_alias_only(buddy), NULL, NULL, 0);
-
-		/* Mobile users should always be online */
-		if (bname[0] == '+') {
-			purple_prpl_got_user_status(account,
-					bname, OSCAR_STATUS_ID_AVAILABLE, NULL);
-			purple_prpl_got_user_status(account,
-					bname, OSCAR_STATUS_ID_MOBILE, NULL);
+	if (od->ssi.received_data) {
+		if (!aim_ssi_itemlist_finditem(od->ssi.local, gname, bname, AIM_SSI_TYPE_BUDDY)) {
+			purple_debug_info("oscar",
+					   "ssi: adding buddy %s to group %s\n", bname, gname);
+			aim_ssi_addbuddy(od, bname, gname, NULL, purple_buddy_get_alias_only(buddy), NULL, NULL, 0);
+
+			/* Mobile users should always be online */
+			if (bname[0] == '+') {
+				purple_prpl_got_user_status(account, bname,
+						OSCAR_STATUS_ID_AVAILABLE, NULL);
+				purple_prpl_got_user_status(account, bname,
+						OSCAR_STATUS_ID_MOBILE, NULL);
+			}
+		} else if (aim_ssi_waitingforauth(od->ssi.local,
+		                                  aim_ssi_itemlist_findparentname(od->ssi.local, bname),
+		                                  bname)) {
+			/* Not authorized -- Re-request authorization */
+			purple_auth_sendrequest(gc, bname);
 		}
 	}
 
--- a/libpurple/protocols/silc/buddy.c	Thu Mar 12 06:19:15 2009 +0000
+++ b/libpurple/protocols/silc/buddy.c	Fri Mar 27 07:52:26 2009 +0000
@@ -1397,7 +1397,12 @@
 
 void silcpurple_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group)
 {
-	silcpurple_add_buddy_i(gc, buddy, FALSE);
+	/* Don't add if the buddy is already on the list.
+	 *
+	 * SILC doesn't have groups, so we also don't need to do anything
+	 * for a move. */
+	if (purple_buddy_get_protocol_data(buddy) == NULL)
+		silcpurple_add_buddy_i(gc, buddy, FALSE);
 }
 
 void silcpurple_send_buddylist(PurpleConnection *gc)
--- a/libpurple/protocols/silc10/buddy.c	Thu Mar 12 06:19:15 2009 +0000
+++ b/libpurple/protocols/silc10/buddy.c	Fri Mar 27 07:52:26 2009 +0000
@@ -1390,7 +1390,12 @@
 
 void silcpurple_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group)
 {
-	silcpurple_add_buddy_i(gc, buddy, FALSE);
+	/* Don't add if the buddy is already on the list.
+	 *
+	 * SILC doesn't have groups, so we don't need to do anything
+	 * for a move. */
+	if (purple_buddy_get_protocol_data(buddy) == NULL)
+		silcpurple_add_buddy_i(gc, buddy, FALSE);
 }
 
 void silcpurple_send_buddylist(PurpleConnection *gc)
--- a/libpurple/protocols/yahoo/yahoo_packet.c	Thu Mar 12 06:19:15 2009 +0000
+++ b/libpurple/protocols/yahoo/yahoo_packet.c	Fri Mar 27 07:52:26 2009 +0000
@@ -201,6 +201,8 @@
 		}
 		pos += 2;
 
+		if (pos + 1 > len) break;
+
 		/* Skip over garbage we've noticed in the mail notifications */
 		if (data[0] == '9' && data[pos] == 0x01)
 			pos++;
--- a/libpurple/prpl.h	Thu Mar 12 06:19:15 2009 +0000
+++ b/libpurple/prpl.h	Fri Mar 27 07:52:26 2009 +0000
@@ -296,6 +296,14 @@
 	void (*set_idle)(PurpleConnection *, int idletime);
 	void (*change_passwd)(PurpleConnection *, const char *old_pass,
 						  const char *new_pass);
+	/**
+	 * Add a buddy to a group on the server.
+	 *
+	 * This PRPL function may be called in situations in which the buddy is
+	 * already in the specified group. If the protocol supports
+	 * authorization and the user is not already authorized to see the
+	 * status of \a buddy, \a add_buddy should request authorization.
+	 */
 	void (*add_buddy)(PurpleConnection *, PurpleBuddy *buddy, PurpleGroup *group);
 	void (*add_buddies)(PurpleConnection *, GList *buddies, GList *groups);
 	void (*remove_buddy)(PurpleConnection *, PurpleBuddy *buddy, PurpleGroup *group);
--- a/libpurple/tests/test_util.c	Thu Mar 12 06:19:15 2009 +0000
+++ b/libpurple/tests/test_util.c	Fri Mar 27 07:52:26 2009 +0000
@@ -5,7 +5,7 @@
 
 START_TEST(test_util_base16_encode)
 {
-	assert_string_equal_free("68656c6c6f2c20776f726c642100", purple_base16_encode("hello, world!", 14));
+	assert_string_equal_free("68656c6c6f2c20776f726c642100", purple_base16_encode((const unsigned char *)"hello, world!", 14));
 }
 END_TEST
 
@@ -14,14 +14,14 @@
 	gsize sz = 0;
 	guchar *out = purple_base16_decode("21646c726f77202c6f6c6c656800", &sz);
 	fail_unless(sz == 14, NULL);
-	fail_unless(strcmp("!dlrow ,olleh", out) == 0, NULL);
+	fail_unless(strcmp("!dlrow ,olleh", (const char *)out) == 0, NULL);
 	g_free(out);
 }
 END_TEST
 
 START_TEST(test_util_base64_encode)
 {
-	assert_string_equal_free("Zm9ydHktdHdvAA==", purple_base64_encode("forty-two", 10));
+	assert_string_equal_free("Zm9ydHktdHdvAA==", purple_base64_encode((const unsigned char *)"forty-two", 10));
 }
 END_TEST
 
@@ -30,7 +30,7 @@
 	gsize sz;
 	guchar *out = purple_base64_decode("b3d0LXl0cm9mAA==", &sz);
 	fail_unless(sz == 10, NULL);
-	fail_unless(strcmp("owt-ytrof", out) == 0, NULL);
+	fail_unless(strcmp("owt-ytrof", (const char *)out) == 0, NULL);
 	g_free(out);
 }
 END_TEST
--- a/libpurple/util.c	Thu Mar 12 06:19:15 2009 +0000
+++ b/libpurple/util.c	Fri Mar 27 07:52:26 2009 +0000
@@ -2850,6 +2850,12 @@
 	return "icon";
 }
 
+/*
+ * TODO: Consider using something faster than SHA-1, such as MD5, MD4
+ *       or CRC32.  Are there security implications to that?  Would
+ *       probably be a good idea to benchmark some algorithms with
+ *       3KB-10KB chunks of data (typical buddy icon sizes).
+ */
 char *
 purple_util_get_image_checksum(gconstpointer image_data, size_t image_len)
 {
@@ -4038,6 +4044,13 @@
 				   &gfud->website.page, &gfud->website.user, &gfud->website.passwd);
 
 	if (purple_strcasestr(url, "https://") != NULL) {
+		if (!purple_ssl_is_supported()) {
+			purple_util_fetch_url_error(gfud,
+					_("Unable to connect to %s: Server requires TLS/SSL, but no TLS/SSL support was found."),
+					gfud->website.address);
+			return NULL;
+		}
+
 		gfud->is_ssl = TRUE;
 		gfud->ssl_connection = purple_ssl_connect(NULL,
 				gfud->website.address, gfud->website.port,
--- a/libpurple/xmlnode.c	Thu Mar 12 06:19:15 2009 +0000
+++ b/libpurple/xmlnode.c	Fri Mar 27 07:52:26 2009 +0000
@@ -27,6 +27,7 @@
  * libxode uses memory pools that we simply have no need for, I decided to
  * write my own stuff.  Also, re-writing this lets me be as lightweight
  * as I want to be.  Thank you libxode for giving me a good starting point */
+#define _PURPLE_XMLNODE_C_
 
 #include "debug.h"
 #include "internal.h"
@@ -126,21 +127,28 @@
 	g_return_if_fail(node != NULL);
 	g_return_if_fail(attr != NULL);
 
-	for(attr_node = node->child; attr_node; attr_node = attr_node->next)
-	{
+	attr_node = node->child;
+	while (attr_node) {
 		if(attr_node->type == XMLNODE_TYPE_ATTRIB &&
 				purple_strequal(attr_node->name, attr))
 		{
-			if(sibling == NULL) {
-				node->child = attr_node->next;
-			} else {
-				sibling->next = attr_node->next;
-			}
 			if (node->lastchild == attr_node) {
 				node->lastchild = sibling;
 			}
-			xmlnode_free(attr_node);
-			return;
+			if (sibling == NULL) {
+				node->child = attr_node->next;
+				xmlnode_free(attr_node);
+				attr_node = node->child;
+			} else {
+				sibling->next = attr_node->next;
+				sibling = attr_node->next;
+				xmlnode_free(attr_node);
+				attr_node = sibling;
+			}
+		}
+		else
+		{
+			attr_node = attr_node->next;
 		}
 		sibling = attr_node;
 	}
@@ -178,24 +186,25 @@
 void
 xmlnode_set_attrib(xmlnode *node, const char *attr, const char *value)
 {
-	xmlnode *attrib_node;
-
-	g_return_if_fail(node != NULL);
-	g_return_if_fail(attr != NULL);
-	g_return_if_fail(value != NULL);
-
 	xmlnode_remove_attrib(node, attr);
-
-	attrib_node = new_node(attr, XMLNODE_TYPE_ATTRIB);
-
-	attrib_node->data = g_strdup(value);
-
-	xmlnode_insert_child(node, attrib_node);
+	xmlnode_set_attrib_full(node, attr, NULL, NULL, value);
 }
 
 void
 xmlnode_set_attrib_with_namespace(xmlnode *node, const char *attr, const char *xmlns, const char *value)
 {
+	xmlnode_set_attrib_full(node, attr, xmlns, NULL, value);
+}
+
+void
+xmlnode_set_attrib_with_prefix(xmlnode *node, const char *attr, const char *prefix, const char *value)
+{
+	xmlnode_set_attrib_full(node, attr, NULL, prefix, value);
+}
+
+void
+xmlnode_set_attrib_full(xmlnode *node, const char *attr, const char *xmlns, const char *prefix, const char *value)
+{
 	xmlnode *attrib_node;
 
 	g_return_if_fail(node != NULL);
@@ -207,22 +216,6 @@
 
 	attrib_node->data = g_strdup(value);
 	attrib_node->xmlns = g_strdup(xmlns);
-
-	xmlnode_insert_child(node, attrib_node);
-}
-
-void
-xmlnode_set_attrib_with_prefix(xmlnode *node, const char *attr, const char *prefix, const char *value)
-{
-	xmlnode *attrib_node;
-
-	g_return_if_fail(node != NULL);
-	g_return_if_fail(attr != NULL);
-	g_return_if_fail(value != NULL);
-
-	attrib_node = new_node(attr, XMLNODE_TYPE_ATTRIB);
-
-	attrib_node->data = g_strdup(value);
 	attrib_node->prefix = g_strdup(prefix);
 
 	xmlnode_insert_child(node, attrib_node);
@@ -585,7 +578,8 @@
 		}
 
 		for(i=0; i < nb_attributes * 5; i+=5) {
-			const char *prefix = (const char *)attributes[i + 1];
+			const char *name = (const char *)attributes[i];
+			const char *prefix = (const char *)attributes[i+1];
 			char *txt;
 			int attrib_len = attributes[i+4] - attributes[i+3];
 			char *attrib = g_malloc(attrib_len + 1);
@@ -594,11 +588,7 @@
 			txt = attrib;
 			attrib = purple_unescape_html(txt);
 			g_free(txt);
-			if (prefix && *prefix) {
-				xmlnode_set_attrib_with_prefix(node, (const char*) attributes[i], prefix, attrib);
-			} else {
-				xmlnode_set_attrib(node, (const char*) attributes[i], attrib);
-			}
+			xmlnode_set_attrib_full(node, name, NULL, prefix, attrib);
 			g_free(attrib);
 		}
 
--- a/libpurple/xmlnode.h	Thu Mar 12 06:19:15 2009 +0000
+++ b/libpurple/xmlnode.h	Fri Mar 27 07:52:26 2009 +0000
@@ -157,6 +157,7 @@
  */
 void xmlnode_set_attrib(xmlnode *node, const char *attr, const char *value);
 
+#if !(defined PURPLE_DISABLE_DEPRECATED) || (defined _PURPLE_XMLNODE_C_)
 /**
  * Sets a prefixed attribute for a node
  *
@@ -164,6 +165,8 @@
  * @param attr   The name of the attribute to set
  * @param prefix The prefix of the attribute to ste
  * @param value  The value of the attribute
+ *
+ * @deprecated Use xmlnode_set_attrib_full instead.
  */
 void xmlnode_set_attrib_with_prefix(xmlnode *node, const char *attr, const char *prefix, const char *value);
 
@@ -174,8 +177,25 @@
  * @param attr  The name of the attribute to set
  * @param xmlns The namespace of the attribute to ste
  * @param value The value of the attribute
+ *
+ * @deprecated Use xmlnode_set_attrib_full instead.
  */
 void xmlnode_set_attrib_with_namespace(xmlnode *node, const char *attr, const char *xmlns, const char *value);
+#endif /* PURPLE_DISABLE_DEPRECATED */
+
+/**
+ * Sets a namespaced attribute for a node
+ *
+ * @param node   The node to set an attribute for.
+ * @param attr   The name of the attribute to set
+ * @param xmlns  The namespace of the attribute to ste
+ * @param prefix The prefix of the attribute to ste
+ * @param value  The value of the attribute
+ *
+ * @since 2.6.0
+ */
+void xmlnode_set_attrib_full(xmlnode *node, const char *attr, const char *xmlns,
+	const char *prefix, const char *value);
 
 /**
  * Gets an attribute from a node.
--- a/pidgin/gtkaccount.c	Thu Mar 12 06:19:15 2009 +0000
+++ b/pidgin/gtkaccount.c	Fri Mar 27 07:52:26 2009 +0000
@@ -106,8 +106,8 @@
 	GtkSizeGroup *sg;
 	GtkWidget *window;
 
+	GtkWidget *notebook;
 	GtkWidget *top_vbox;
-	GtkWidget *bottom_vbox;
 	GtkWidget *ok_button;
 	GtkWidget *register_button;
 
@@ -157,8 +157,7 @@
  **************************************************************************/
 static void add_login_options(AccountPrefsDialog *dialog, GtkWidget *parent);
 static void add_user_options(AccountPrefsDialog *dialog, GtkWidget *parent);
-static void add_protocol_options(AccountPrefsDialog *dialog,
-								 GtkWidget *parent);
+static void add_protocol_options(AccountPrefsDialog *dialog);
 static void add_proxy_options(AccountPrefsDialog *dialog, GtkWidget *parent);
 
 static GtkWidget *
@@ -237,7 +236,7 @@
 
 	add_login_options(dialog,    dialog->top_vbox);
 	add_user_options(dialog,     dialog->top_vbox);
-	add_protocol_options(dialog, dialog->bottom_vbox);
+	add_protocol_options(dialog);
 
 	gtk_widget_grab_focus(dialog->protocol_menu);
 
@@ -733,11 +732,11 @@
 }
 
 static void
-add_protocol_options(AccountPrefsDialog *dialog, GtkWidget *parent)
+add_protocol_options(AccountPrefsDialog *dialog)
 {
 	PurpleAccountOption *option;
 	PurpleAccount *account;
-	GtkWidget *frame, *vbox, *check, *entry, *combo;
+	GtkWidget *vbox, *check, *entry, *combo;
 	GList *list, *node;
 	gint i, idx, int_value;
 	GtkListStore *model;
@@ -752,14 +751,10 @@
 	ProtocolOptEntry *opt_entry;
 
 	if (dialog->protocol_frame != NULL) {
-		gtk_widget_destroy(dialog->protocol_frame);
+		gtk_notebook_remove_page (GTK_NOTEBOOK(dialog->notebook), 1);
 		dialog->protocol_frame = NULL;
 	}
 
-	if (dialog->prpl_info == NULL ||
-			dialog->prpl_info->protocol_options == NULL)
-		return;
-
 	while (dialog->protocol_opt_entries != NULL) {
 		ProtocolOptEntry *opt_entry = dialog->protocol_opt_entries->data;
 		g_free(opt_entry->setting);
@@ -767,21 +762,17 @@
 		dialog->protocol_opt_entries = g_list_delete_link(dialog->protocol_opt_entries, dialog->protocol_opt_entries);
 	}
 
+	if (dialog->prpl_info == NULL ||
+			dialog->prpl_info->protocol_options == NULL)
+		return;
+
 	account = dialog->account;
 
-	/* Build the protocol options frame. */
-	g_snprintf(buf, sizeof(buf), _("%s Options"), dialog->plugin->info->name);
-
-	frame = pidgin_make_frame(parent, buf);
-	dialog->protocol_frame =
-		gtk_widget_get_parent(gtk_widget_get_parent(frame));
-
-	gtk_box_reorder_child(GTK_BOX(parent), dialog->protocol_frame, 0);
-	gtk_widget_show(dialog->protocol_frame);
-
 	/* Main vbox */
-	vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
-	gtk_container_add(GTK_CONTAINER(frame), vbox);
+	dialog->protocol_frame = vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
+	gtk_container_set_border_width(GTK_CONTAINER(vbox), PIDGIN_HIG_BORDER);
+	gtk_notebook_insert_page(GTK_NOTEBOOK(dialog->notebook), vbox,
+			gtk_label_new_with_mnemonic(_("_Advanced")), 1);
 	gtk_widget_show(vbox);
 
 	for (l = dialog->prpl_info->protocol_options; l != NULL; l = l->next)
@@ -1046,22 +1037,15 @@
 add_proxy_options(AccountPrefsDialog *dialog, GtkWidget *parent)
 {
 	PurpleProxyInfo *proxy_info;
-	GtkWidget *frame;
 	GtkWidget *vbox;
 	GtkWidget *vbox2;
 
 	if (dialog->proxy_frame != NULL)
 		gtk_widget_destroy(dialog->proxy_frame);
 
-	frame = pidgin_make_frame(parent, _("Proxy Options"));
-	dialog->proxy_frame = gtk_widget_get_parent(gtk_widget_get_parent(frame));
-
-	gtk_box_reorder_child(GTK_BOX(parent), dialog->proxy_frame, 1);
-	gtk_widget_show(dialog->proxy_frame);
-
 	/* Main vbox */
-	vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
-	gtk_container_add(GTK_CONTAINER(frame), vbox);
+	dialog->proxy_frame = vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
+	gtk_container_add(GTK_CONTAINER(parent), vbox);
 	gtk_widget_show(vbox);
 
 	/* Proxy Type drop-down. */
@@ -1496,15 +1480,15 @@
 		dialog->prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(dialog->plugin);
 
 	dialog->window = win = pidgin_create_dialog((type == PIDGIN_ADD_ACCOUNT_DIALOG) ? _("Add Account") : _("Modify Account"),
-		PIDGIN_HIG_BORDER, "account", FALSE);
+		PIDGIN_HIG_BOX_SPACE, "account", FALSE);
 
 	g_signal_connect(G_OBJECT(win), "delete_event",
 					 G_CALLBACK(account_win_destroy_cb), dialog);
 
 	/* Setup the vbox */
-	main_vbox = pidgin_dialog_get_vbox_with_properties(GTK_DIALOG(win), FALSE, PIDGIN_HIG_BORDER);
-
-	notebook = gtk_notebook_new();
+	main_vbox = pidgin_dialog_get_vbox_with_properties(GTK_DIALOG(win), FALSE, PIDGIN_HIG_BOX_SPACE);
+
+	dialog->notebook = notebook = gtk_notebook_new();
 	gtk_box_pack_start(GTK_BOX(main_vbox), notebook, FALSE, FALSE, 0);
 	gtk_widget_show(GTK_WIDGET(notebook));
 
@@ -1530,15 +1514,15 @@
 	if (!dialog->prpl_info || !dialog->prpl_info->register_user)
 		gtk_widget_hide(button);
 
-	/* Setup the page with 'Advanced'. */
-	dialog->bottom_vbox = dbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BORDER);
+	/* Setup the page with 'Advanced' (protocol options). */
+	add_protocol_options(dialog);
+
+	/* Setup the page with 'Proxy'. */
+	dbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BORDER);
 	gtk_container_set_border_width(GTK_CONTAINER(dbox), PIDGIN_HIG_BORDER);
 	gtk_notebook_append_page(GTK_NOTEBOOK(notebook), dbox,
-			gtk_label_new_with_mnemonic(_("_Advanced")));
+			gtk_label_new_with_mnemonic(_("_Proxy")));
 	gtk_widget_show(dbox);
-
-	/** Setup the bottom frames. */
-	add_protocol_options(dialog, dbox);
 	add_proxy_options(dialog, dbox);
 
 	/* Cancel button */
--- a/pidgin/gtkblist.c	Thu Mar 12 06:19:15 2009 +0000
+++ b/pidgin/gtkblist.c	Fri Mar 27 07:52:26 2009 +0000
@@ -3898,7 +3898,7 @@
 	presence = purple_buddy_get_presence(b);
 
 	/* Name is all that is needed */
-	if (aliased && biglist) {
+	if (!aliased || biglist) {
 
 		/* Status Info */
 		prpl = purple_find_prpl(purple_account_get_protocol_id(b->account));
@@ -4038,7 +4038,7 @@
 	}
 
 	/* Put it all together */
-	if (aliased && biglist && (statustext || idletime)) {
+	if ((!aliased || biglist) && (statustext || idletime)) {
 		/* using <span size='smaller'> breaks the status, so it must be seperated into <small><span>*/
 		if (name_color) {
 			text = g_strdup_printf("<span font_desc='%s' foreground='%s'>%s</span>\n"
@@ -6443,7 +6443,7 @@
 		gboolean biglist = purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_buddy_icons");
 		PidginBlistNode *ui;
 		PurpleConversation *conv;
-		gboolean hidden;
+		gboolean hidden = FALSE;
 		GdkColor *bgcolor = NULL;
 		FontColorPair *pair;
 		PidginBlistTheme *theme;
@@ -6701,14 +6701,27 @@
 			whoalias = NULL;
 
 		g = NULL;
-		if ((grp != NULL) && (*grp != '\0') && ((g = purple_find_group(grp)) == NULL))
+		if ((grp != NULL) && (*grp != '\0'))
 		{
-			g = purple_group_new(grp);
-			purple_blist_add_group(g, NULL);
-		}
-
-		b = purple_buddy_new(data->account, who, whoalias);
-		purple_blist_add_buddy(b, NULL, g, NULL);
+			if ((g = purple_find_group(grp)) == NULL)
+			{
+				g = purple_group_new(grp);
+				purple_blist_add_group(g, NULL);
+			}
+
+			b = purple_find_buddy_in_group(data->account, who, g);
+		}
+		else if ((b = purple_find_buddy(data->account, who)) != NULL)
+		{
+			g = purple_buddy_get_group(b);
+		}
+
+		if (b == NULL)
+		{
+			b = purple_buddy_new(data->account, who, whoalias);
+			purple_blist_add_buddy(b, NULL, g, NULL);
+		}
+
 		purple_account_add_buddy(data->account, b);
 
 		/* Offer to merge people with the same alias. */
--- a/pidgin/gtkdialogs.c	Thu Mar 12 06:19:15 2009 +0000
+++ b/pidgin/gtkdialogs.c	Fri Mar 27 07:52:26 2009 +0000
@@ -189,7 +189,7 @@
 	{N_("Italian"),             "it", "Claudio Satriano", "satriano@na.infn.it"},
 	{N_("Japanese"),            "ja", "Takashi Aihana", "aihana@gnome.gr.jp"},
 	{N_("Georgian"),            "ka", N_("Ubuntu Georgian Translators"), "alexander.didebulidze@stusta.mhn.de"},
-	{"Khmer",                   "km", "Khoem Sokhem", "khoemsokhem@khmeros.info"},
+	{N_("Khmer"),               "km", "Khoem Sokhem", "khoemsokhem@khmeros.info"},
 	{N_("Kannada"),             "kn", N_("Kannada Translation team"), "translation@sampada.info"},
 	{N_("Korean"),              "ko", "Sushizang", "sushizang@empal.com"},
 	{N_("Kurdish"),             "ku", "Erdal Ronahi", "erdal.ronahi@gmail.com"},
--- a/pidgin/gtknotify.c	Thu Mar 12 06:19:15 2009 +0000
+++ b/pidgin/gtknotify.c	Fri Mar 27 07:52:26 2009 +0000
@@ -28,6 +28,7 @@
 
 #include <gdk/gdkkeysyms.h>
 
+#include "account.h"
 #include "connection.h"
 #include "debug.h"
 #include "prefs.h"
@@ -37,6 +38,7 @@
 #include "gtkblist.h"
 #include "gtkimhtml.h"
 #include "gtknotify.h"
+#include "gtkpounce.h"
 #include "gtkutils.h"
 
 typedef struct
@@ -57,6 +59,13 @@
 typedef struct
 {
 	PurpleAccount *account;
+	PurplePounce *pounce;
+} PidginNotifyPounceData;
+
+
+typedef struct
+{
+	PurpleAccount *account;
 	GtkListStore *model;
 	GtkWidget *treeview;
 	GtkWidget *window;
@@ -80,21 +89,44 @@
 	COLUMNS_PIDGIN_MAIL
 };
 
-typedef struct _PidginMailDialog PidginMailDialog;
+enum
+{
+	PIDGIN_POUNCE_ICON,
+	PIDGIN_POUNCE_ALIAS,
+	PIDGIN_POUNCE_EVENT,
+	PIDGIN_POUNCE_TEXT,
+	PIDGIN_POUNCE_DATE,
+	PIDGIN_POUNCE_DATA,
+	PIDGIN_POUNCE_COLUMNS
+};
 
-struct _PidginMailDialog
+typedef struct _PidginNotifyDialog PidginNotifyDialog;
+typedef PidginNotifyDialog PidginMailDialog;
+
+struct _PidginNotifyDialog
 {
 	GtkWidget *dialog;
 	GtkWidget *treeview;
 	GtkTreeStore *treemodel;
 	GtkLabel *label;
 	GtkWidget *open_button;
+	GtkWidget *dismiss_button;
+	GtkWidget *edit_button;
 	int total_count;
 	gboolean in_use;
 };
 
-static PidginMailDialog *mail_dialog = NULL;
+typedef enum
+{
+	PIDGIN_NOTIFY_MAIL,
+	PIDGIN_NOTIFY_POUNCE,
+        PIDGIN_NOTIFY_TYPES
+} PidginNotifyType;
 
+static PidginNotifyDialog *mail_dialog = NULL;
+static PidginNotifyDialog *pounce_dialog = NULL;
+
+static GtkWidget *pidgin_get_notification_dialog(PidginNotifyType type);
 static void *pidgin_notify_emails(PurpleConnection *gc, size_t count, gboolean detailed,
 									const char **subjects,
 									const char **froms, const char **tos,
@@ -109,6 +141,159 @@
 }
 
 static void
+pounce_response_close(PidginNotifyDialog *dialog)
+{
+	GtkTreeIter iter;
+	PidginNotifyPounceData *pounce_data;
+
+	while (gtk_tree_model_get_iter_first(
+				GTK_TREE_MODEL(pounce_dialog->treemodel), &iter)) {
+		gtk_tree_model_get(GTK_TREE_MODEL(pounce_dialog->treemodel), &iter,
+				PIDGIN_POUNCE_DATA, &pounce_data,
+				-1);
+		gtk_tree_store_remove(dialog->treemodel, &iter);
+
+		g_free(pounce_data);
+	}
+
+	gtk_widget_destroy(pounce_dialog->dialog);
+	g_free(pounce_dialog);
+	pounce_dialog = NULL;
+}
+
+static void
+delete_foreach(GtkTreeModel *model, GtkTreePath *path,
+		GtkTreeIter *iter, gpointer data)
+{
+	PidginNotifyPounceData *pounce_data;
+
+	gtk_tree_model_get(model, iter,
+			PIDGIN_POUNCE_DATA, &pounce_data,
+			-1);
+
+	if (pounce_data != NULL)
+		g_free(pounce_data);
+}
+
+static void
+append_to_list(GtkTreeModel *model, GtkTreePath *path,
+		GtkTreeIter *iter, gpointer data)
+{
+	GList **list = data;
+	*list = g_list_prepend(*list, gtk_tree_path_copy(path));
+}
+static void
+pounce_response_dismiss()
+{
+	GtkTreeSelection *selection;
+	GList *list = NULL;
+
+	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(pounce_dialog->treeview));
+	gtk_tree_selection_selected_foreach(selection, delete_foreach, pounce_dialog);
+	gtk_tree_selection_selected_foreach(selection, append_to_list, &list);
+
+	while (list) {
+		GtkTreeIter iter;
+		if (gtk_tree_model_get_iter(GTK_TREE_MODEL(pounce_dialog->treemodel), &iter,
+					list->data)) {
+			gtk_tree_store_remove(GTK_TREE_STORE(pounce_dialog->treemodel), &iter);
+		}
+		gtk_tree_path_free(list->data);
+		list = g_list_delete_link(list, list);
+	}
+}
+
+static void
+pounce_response_edit_cb(GtkTreeModel *model, GtkTreePath *path,
+		GtkTreeIter *iter, gpointer data)
+{
+	PidginNotifyPounceData *pounce_data;
+	PidginNotifyDialog *dialog = (PidginNotifyDialog*)data;
+	PurplePounce *pounce;
+	GList *list;
+
+	list = purple_pounces_get_all();
+
+	gtk_tree_model_get(GTK_TREE_MODEL(dialog->treemodel), iter,
+			PIDGIN_POUNCE_DATA, &pounce_data,
+			-1);
+	
+	for (; list != NULL; list = list->next) {
+		pounce = list->data;
+		if (pounce == pounce_data->pounce) {
+			pidgin_pounce_editor_show(pounce_data->account, NULL, pounce_data->pounce);
+			return;
+		}
+	}
+
+	purple_debug_warning("gtknotify", "Pounce was destroyed.\n");
+}
+
+static void
+pounce_response_cb(GtkDialog *dlg, gint id, PidginNotifyDialog *dialog)
+{
+	GtkTreeSelection *selection = NULL;
+
+	switch (id) {
+		case GTK_RESPONSE_CLOSE:
+		case GTK_RESPONSE_DELETE_EVENT:
+			pounce_response_close(dialog);
+			break;
+		case GTK_RESPONSE_NO:
+			pounce_response_dismiss();
+			break;
+		case GTK_RESPONSE_APPLY:
+			selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->treeview));
+			gtk_tree_selection_selected_foreach(selection, pounce_response_edit_cb,
+					dialog);
+			break;
+	}
+}
+
+static void
+pounce_row_selected_cb(GtkTreeView *tv, GtkTreePath *path,
+	GtkTreeViewColumn *col, gpointer data)
+{
+	GtkTreeIter iter;
+	GtkTreeSelection *selection;
+	gboolean selected;
+	GList *list;
+
+	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(pounce_dialog->treeview));
+
+	selected = gtk_tree_selection_get_selected(selection,
+			NULL, &iter);
+
+	if (selected) {
+		PurplePounce *pounce;
+		PidginNotifyPounceData *pounce_data;
+
+		list = purple_pounces_get_all();
+
+		gtk_tree_model_get(GTK_TREE_MODEL(pounce_dialog->treemodel), &iter,
+				PIDGIN_POUNCE_DATA, &pounce_data,
+				-1);
+
+		gtk_widget_set_sensitive(pounce_dialog->edit_button, FALSE);
+
+		for (; list != NULL; list = list->next) {
+			pounce = list->data;
+			if (pounce == pounce_data->pounce) {
+				gtk_widget_set_sensitive(pounce_dialog->edit_button, TRUE);
+				break;
+			}
+		}
+	
+		gtk_widget_set_sensitive(pounce_dialog->dismiss_button, TRUE);
+	} else {
+		gtk_widget_set_sensitive(pounce_dialog->edit_button, FALSE);
+		gtk_widget_set_sensitive(pounce_dialog->dismiss_button, FALSE);
+	}
+
+
+}
+
+static void
 email_response_cb(GtkDialog *dlg, gint id, PidginMailDialog *dialog)
 {
 	PidginNotifyMailData *data = NULL;
@@ -342,89 +527,7 @@
 static GtkWidget *
 pidgin_get_mail_dialog(void)
 {
-	if (mail_dialog == NULL) {
-		GtkWidget *dialog = NULL;
-		GtkWidget *label;
-		GtkWidget *sw;
-		GtkCellRenderer *rend;
-		GtkTreeViewColumn *column;
-		GtkWidget *button = NULL;
-		GtkWidget *vbox = NULL;
-
-		dialog = gtk_dialog_new_with_buttons(_("New Mail"), NULL, 0,
-						     GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
-						     NULL);
-		gtk_window_set_role(GTK_WINDOW(dialog), "new_mail_detailed");
-		g_signal_connect(G_OBJECT(dialog), "focus-in-event",
-					G_CALLBACK(mail_window_focus_cb), NULL);
-
-		gtk_dialog_add_button(GTK_DIALOG(dialog),
-					 _("Open All Messages"), GTK_RESPONSE_ACCEPT);
-
-		button = gtk_dialog_add_button(GTK_DIALOG(dialog),
-						 PIDGIN_STOCK_OPEN_MAIL, GTK_RESPONSE_YES);
-
-		/* make "Open All Messages" the default response */
-		gtk_dialog_set_default_response(GTK_DIALOG(dialog),
-						GTK_RESPONSE_ACCEPT);
-
-		/* Setup the dialog */
-		gtk_container_set_border_width(GTK_CONTAINER(dialog), PIDGIN_HIG_BOX_SPACE);
-		gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), PIDGIN_HIG_BOX_SPACE);
-		gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
-		gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog)->vbox), PIDGIN_HIG_BORDER);
-
-		/* Vertical box */
-		vbox = GTK_DIALOG(dialog)->vbox;
-
-		/* Golden ratio it up! */
-		gtk_widget_set_size_request(dialog, 550, 400);
-
-		sw = gtk_scrolled_window_new(NULL, NULL);
-		gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN);
-		gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
-
-		mail_dialog = g_new0(PidginMailDialog, 1);
-		mail_dialog->dialog = dialog;
-		mail_dialog->open_button = button;
-
-		mail_dialog->treemodel = gtk_tree_store_new(COLUMNS_PIDGIN_MAIL,
-						GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER);
-		mail_dialog->treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(mail_dialog->treemodel));
-		g_object_unref(G_OBJECT(mail_dialog->treemodel));
-		gtk_tree_view_set_search_column(GTK_TREE_VIEW(mail_dialog->treeview), PIDGIN_MAIL_TEXT);
-		gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(mail_dialog->treeview),
-			             pidgin_tree_view_search_equal_func, NULL, NULL);
-
-		g_signal_connect(G_OBJECT(dialog), "response",
-						 G_CALLBACK(email_response_cb), mail_dialog);
-		g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(mail_dialog->treeview))),
-						 "changed", G_CALLBACK(selection_changed_cb), mail_dialog);
-		g_signal_connect(G_OBJECT(mail_dialog->treeview), "row-activated", G_CALLBACK(email_row_activated_cb), NULL);
-
-		gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(mail_dialog->treeview), FALSE);
-		gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(mail_dialog->treeview), TRUE);
-		gtk_container_add(GTK_CONTAINER(sw), mail_dialog->treeview);
-
-		column = gtk_tree_view_column_new();
-		gtk_tree_view_column_set_resizable(column, TRUE);
-		rend = gtk_cell_renderer_pixbuf_new();
-		gtk_tree_view_column_pack_start(column, rend, FALSE);
-		gtk_tree_view_column_set_attributes(column, rend, "pixbuf", PIDGIN_MAIL_ICON, NULL);
-		rend = gtk_cell_renderer_text_new();
-		gtk_tree_view_column_pack_start(column, rend, TRUE);
-		gtk_tree_view_column_set_attributes(column, rend, "markup", PIDGIN_MAIL_TEXT, NULL);
-		gtk_tree_view_append_column(GTK_TREE_VIEW(mail_dialog->treeview), column);
-
-		label = gtk_label_new(NULL);
-		gtk_label_set_markup(GTK_LABEL(label), _("<span weight=\"bold\" size=\"larger\">You have mail!</span>"));
-		gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
-		gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
-		gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
-		gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0);
-	}
-
-	return mail_dialog->dialog;
+	return pidgin_get_notification_dialog(PIDGIN_NOTIFY_MAIL);
 }
 
 /* count == 0 means this is a detailed mail notification.
@@ -1001,8 +1104,10 @@
 	{
 		PidginNotifyMailData *data = (PidginNotifyMailData *)ui_handle;
 
-		g_free(data->url);
-		g_free(data);
+		if (data) {
+			g_free(data->url);
+			g_free(data);
+		}
 	}
 	else if (type == PURPLE_NOTIFY_SEARCHRESULTS)
 	{
@@ -1234,6 +1339,228 @@
 	return NULL;
 }
 
+static GtkWidget *
+pidgin_get_dialog(PidginNotifyType type, GtkTreeStore *treemodel)
+{
+	GtkWidget *dialog = NULL;
+	GtkWidget *label = NULL;
+	GtkWidget *sw;
+	GtkCellRenderer *rend;
+	GtkTreeViewColumn *column;
+	GtkWidget *button = NULL;
+	GtkWidget *vbox = NULL;
+	GtkTreeSelection *sel;
+	PidginNotifyDialog *spec_dialog = NULL;
+	
+	g_return_val_if_fail(type < PIDGIN_NOTIFY_TYPES, NULL);
+	
+	dialog = gtk_dialog_new_with_buttons(NULL, NULL, 0,
+			GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
+			NULL);
+
+	/* Setup the dialog */
+	gtk_container_set_border_width(GTK_CONTAINER(dialog), PIDGIN_HIG_BOX_SPACE);
+	gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), PIDGIN_HIG_BOX_SPACE);
+	gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
+	gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog)->vbox), PIDGIN_HIG_BORDER);
+
+	/* Vertical box */
+	vbox = GTK_DIALOG(dialog)->vbox;
+
+	/* Golden ratio it up! */
+	gtk_widget_set_size_request(dialog, 550, 400);
+
+	sw = gtk_scrolled_window_new(NULL, NULL);
+	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN);
+	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
+
+	spec_dialog = g_new0(PidginNotifyDialog, 1);
+	spec_dialog->dialog = dialog;
+	spec_dialog->open_button = button;
+
+	spec_dialog->treemodel = treemodel;
+	spec_dialog->treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(spec_dialog->treemodel));
+	g_object_unref(G_OBJECT(spec_dialog->treemodel));
+	
+	gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(spec_dialog->treeview), TRUE);
+	gtk_container_add(GTK_CONTAINER(sw), spec_dialog->treeview);
+
+	if (type == PIDGIN_NOTIFY_MAIL) {
+		gtk_window_set_title(GTK_WINDOW(dialog), _("New Mail"));
+		gtk_window_set_role(GTK_WINDOW(dialog), "new_mail_detailed");
+		g_signal_connect(G_OBJECT(dialog), "focus-in-event",
+					G_CALLBACK(mail_window_focus_cb), NULL);
+
+		gtk_dialog_add_button(GTK_DIALOG(dialog),
+					 _("Open All Messages"), GTK_RESPONSE_ACCEPT);
+
+		button = gtk_dialog_add_button(GTK_DIALOG(dialog),
+						 PIDGIN_STOCK_OPEN_MAIL, GTK_RESPONSE_YES);
+
+		gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(spec_dialog->treeview), FALSE);
+
+		gtk_tree_view_set_search_column(GTK_TREE_VIEW(spec_dialog->treeview), PIDGIN_MAIL_TEXT);
+		gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(spec_dialog->treeview),
+			             pidgin_tree_view_search_equal_func, NULL, NULL);
+
+		g_signal_connect(G_OBJECT(dialog), "response",
+						 G_CALLBACK(email_response_cb), spec_dialog);
+		g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(spec_dialog->treeview))),
+						 "changed", G_CALLBACK(selection_changed_cb), spec_dialog);
+		g_signal_connect(G_OBJECT(spec_dialog->treeview), "row-activated", G_CALLBACK(email_row_activated_cb), NULL);
+
+		column = gtk_tree_view_column_new();
+		gtk_tree_view_column_set_resizable(column, TRUE);
+		rend = gtk_cell_renderer_pixbuf_new();
+		gtk_tree_view_column_pack_start(column, rend, FALSE);
+
+		gtk_tree_view_column_set_attributes(column, rend, "pixbuf", PIDGIN_MAIL_ICON, NULL);
+		rend = gtk_cell_renderer_text_new();
+		gtk_tree_view_column_pack_start(column, rend, TRUE);
+		gtk_tree_view_column_set_attributes(column, rend, "markup", PIDGIN_MAIL_TEXT, NULL);
+		gtk_tree_view_append_column(GTK_TREE_VIEW(spec_dialog->treeview), column);
+
+		label = gtk_label_new(NULL);
+		gtk_label_set_markup(GTK_LABEL(label), _("<span weight=\"bold\" size=\"larger\">You have mail!</span>"));
+
+	} else if (type == PIDGIN_NOTIFY_POUNCE) {
+		gtk_window_set_title(GTK_WINDOW(dialog), _("New Pounces"));
+
+		button = gtk_dialog_add_button(GTK_DIALOG(dialog),
+						_("Dismiss"), GTK_RESPONSE_NO);
+		gtk_widget_set_sensitive(button, FALSE);
+		spec_dialog->dismiss_button = button;
+
+		button = gtk_dialog_add_button(GTK_DIALOG(dialog),
+						PIDGIN_STOCK_EDIT, GTK_RESPONSE_APPLY);
+		gtk_widget_set_sensitive(button, FALSE);
+		spec_dialog->edit_button = button;
+
+		g_signal_connect(G_OBJECT(dialog), "response",
+						 G_CALLBACK(pounce_response_cb), spec_dialog);
+
+		column = gtk_tree_view_column_new();
+		gtk_tree_view_column_set_title(column, _("Buddy"));
+		gtk_tree_view_column_set_resizable(column, TRUE);
+		rend = gtk_cell_renderer_pixbuf_new();
+		gtk_tree_view_column_pack_start(column, rend, FALSE);
+
+		gtk_tree_view_column_set_attributes(column, rend, "pixbuf", PIDGIN_POUNCE_ICON, NULL);
+		rend = gtk_cell_renderer_text_new();
+		gtk_tree_view_column_pack_start(column, rend, FALSE);
+		gtk_tree_view_column_add_attribute(column, rend, "text", PIDGIN_POUNCE_ALIAS);
+		gtk_tree_view_append_column(GTK_TREE_VIEW(spec_dialog->treeview), column);
+
+		column = gtk_tree_view_column_new();
+		gtk_tree_view_column_set_title(column, _("Event"));
+		gtk_tree_view_column_set_resizable(column, TRUE);
+		rend = gtk_cell_renderer_text_new();
+		gtk_tree_view_column_pack_start(column, rend, FALSE);
+		gtk_tree_view_column_add_attribute(column, rend, "text", PIDGIN_POUNCE_EVENT);
+		gtk_tree_view_append_column(GTK_TREE_VIEW(spec_dialog->treeview), column);
+
+		column = gtk_tree_view_column_new();
+		gtk_tree_view_column_set_title(column, _("Message"));
+		gtk_tree_view_column_set_resizable(column, TRUE);
+		rend = gtk_cell_renderer_text_new();
+		gtk_tree_view_column_pack_start(column, rend, FALSE);
+		gtk_tree_view_column_add_attribute(column, rend, "text", PIDGIN_POUNCE_TEXT);
+		gtk_tree_view_append_column(GTK_TREE_VIEW(spec_dialog->treeview), column);
+
+		column = gtk_tree_view_column_new();
+		gtk_tree_view_column_set_title(column, _("Date"));
+		gtk_tree_view_column_set_resizable(column, TRUE);
+		rend = gtk_cell_renderer_text_new();
+		gtk_tree_view_column_pack_start(column, rend, FALSE);
+		gtk_tree_view_column_add_attribute(column, rend, "text", PIDGIN_POUNCE_DATE);
+		gtk_tree_view_append_column(GTK_TREE_VIEW(spec_dialog->treeview), column);
+
+		label = gtk_label_new(NULL);
+		gtk_label_set_markup(GTK_LABEL(label), _("<span weight=\"bold\" size=\"larger\">You have pounced!</span>"));
+
+		sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(spec_dialog->treeview));
+		gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
+		g_signal_connect(G_OBJECT(sel), "changed",
+			G_CALLBACK(pounce_row_selected_cb), NULL);
+	}
+
+	gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
+	gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
+	gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
+	gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 2);
+
+	if (type == PIDGIN_NOTIFY_MAIL)
+		mail_dialog = spec_dialog;
+	else if (type == PIDGIN_NOTIFY_POUNCE) {
+		pounce_dialog = spec_dialog;
+        }
+
+	return spec_dialog->dialog;
+
+}
+
+void
+pidgin_notify_pounce_add(PurpleAccount *account, PurplePounce *pounce,
+		const char *alias, const char *event, const char *message, const char *date)
+{
+	GtkWidget *dialog;
+	GdkPixbuf *icon;
+	GtkTreeIter iter;
+	PidginNotifyPounceData *pounce_data;
+
+	dialog = pidgin_get_notification_dialog(PIDGIN_NOTIFY_POUNCE);
+
+	icon = pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_SMALL);
+
+	pounce_data = g_new(PidginNotifyPounceData, 1);
+
+	pounce_data->account = account;
+	pounce_data->pounce = pounce;
+
+	gtk_tree_store_append(pounce_dialog->treemodel, &iter, NULL);
+
+	gtk_tree_store_set(pounce_dialog->treemodel, &iter,
+			PIDGIN_POUNCE_ICON, icon,
+			PIDGIN_POUNCE_ALIAS, alias,
+			PIDGIN_POUNCE_EVENT, event,
+			PIDGIN_POUNCE_TEXT, (message != NULL)? message : _("No message"),
+			PIDGIN_POUNCE_DATE, date,
+			PIDGIN_POUNCE_DATA, pounce_data,
+			-1);
+
+	if (icon)
+		g_object_unref(icon);
+
+	gtk_widget_show_all(dialog);
+
+	return;
+}
+
+static GtkWidget *
+pidgin_get_notification_dialog(PidginNotifyType type)
+{
+	GtkTreeStore *model = NULL;
+
+	if (type == PIDGIN_NOTIFY_MAIL) {
+		if (mail_dialog != NULL)
+			return mail_dialog->dialog;
+
+		model = gtk_tree_store_new(COLUMNS_PIDGIN_MAIL,
+						GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER);
+
+	} else if (type == PIDGIN_NOTIFY_POUNCE) {
+
+		if (pounce_dialog != NULL)
+			return pounce_dialog->dialog;
+
+		model = gtk_tree_store_new(PIDGIN_POUNCE_COLUMNS,
+				GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
+				G_TYPE_STRING, G_TYPE_POINTER);
+	}
+
+	return pidgin_get_dialog(type, model);
+}
+
 static PurpleNotifyUiOps ops =
 {
 	pidgin_notify_message,
--- a/pidgin/gtknotify.h	Thu Mar 12 06:19:15 2009 +0000
+++ b/pidgin/gtknotify.h	Fri Mar 27 07:52:26 2009 +0000
@@ -27,6 +27,18 @@
 #define _PIDGINNOTIFY_H_
 
 #include "notify.h"
+#include "pounce.h"
+
+/**
+ * Adds a buddy pounce to the buddy pounce dialog
+ *
+ * @param alias		The buddy alias
+ * @param event 	Event description
+ * @param message	Pounce message
+ * @param date		Pounce date
+ */
+void pidgin_notify_pounce_add(PurpleAccount *account, PurplePounce *pounce,
+		const char *alias, const char *event, const char *message, const char *date);
 
 /**
  * Returns the UI operations structure for GTK+ notification functions.
--- a/pidgin/gtkpounce.c	Thu Mar 12 06:19:15 2009 +0000
+++ b/pidgin/gtkpounce.c	Fri Mar 27 07:52:26 2009 +0000
@@ -30,7 +30,6 @@
 #include "account.h"
 #include "conversation.h"
 #include "debug.h"
-#include "notify.h"
 #include "prpl.h"
 #include "request.h"
 #include "server.h"
@@ -41,6 +40,7 @@
 #include "gtkdialogs.h"
 #include "gtkimhtml.h"
 #include "gtkpounce.h"
+#include "gtknotify.h"
 #include "pidginstock.h"
 #include "gtkutils.h"
 
@@ -1275,7 +1275,6 @@
 	/* Handle double-clicking */
 	g_signal_connect(G_OBJECT(treeview), "button_press_event",
 					 G_CALLBACK(pounce_double_click_cb), dialog);
-
 	gtk_container_add(GTK_CONTAINER(sw), treeview);
 	gtk_widget_show(treeview);
 
@@ -1458,27 +1457,27 @@
 		 */
 		tmp = g_strdup_printf(
 				   (events & PURPLE_POUNCE_TYPING) ?
-				   _("%s has started typing to you (%s)") :
+				   _("Started typing") :
 				   (events & PURPLE_POUNCE_TYPED) ?
-				   _("%s has paused while typing to you (%s)") :
+				   _("Paused while typing") :
 				   (events & PURPLE_POUNCE_SIGNON) ?
-				   _("%s has signed on (%s)") :
+				   _("Signed on") :
 				   (events & PURPLE_POUNCE_IDLE_RETURN) ?
-				   _("%s has returned from being idle (%s)") :
+				   _("Returned from being idle") :
 				   (events & PURPLE_POUNCE_AWAY_RETURN) ?
-				   _("%s has returned from being away (%s)") :
+				   _("Returned from being away") :
 				   (events & PURPLE_POUNCE_TYPING_STOPPED) ?
-				   _("%s has stopped typing to you (%s)") :
+				   _("Stopped typing") :
 				   (events & PURPLE_POUNCE_SIGNOFF) ?
-				   _("%s has signed off (%s)") :
+				   _("Signed off") :
 				   (events & PURPLE_POUNCE_IDLE) ?
-				   _("%s has become idle (%s)") :
+				   _("Became idle") :
 				   (events & PURPLE_POUNCE_AWAY) ?
-				   _("%s has gone away. (%s)") :
+				   _("Went away") :
 				   (events & PURPLE_POUNCE_MESSAGE_RECEIVED) ?
-				   _("%s has sent you a message. (%s)") :
-				   _("Unknown pounce event. Please report this!"),
-				   alias, purple_account_get_protocol_name(account));
+				   _("Sent a message") :
+				   _("Unknown.... Please report this!")
+				   );
 
 		/*
 		 * Ok here is where I change the second argument, title, from
@@ -1488,16 +1487,9 @@
 		if ((name_shown = purple_account_get_alias(account)) == NULL)
 			name_shown = purple_account_get_username(account);
 
-		if (reason == NULL)
-		{
-			purple_notify_info(NULL, name_shown, tmp, purple_date_format_full(NULL));
-		}
-		else
-		{
-			char *tmp2 = g_strdup_printf("%s\n\n%s", reason, purple_date_format_full(NULL));
-			purple_notify_info(NULL, name_shown, tmp, tmp2);
-			g_free(tmp2);
-		}
+		pidgin_notify_pounce_add(account, pounce, alias, tmp, reason,
+				purple_date_format_full(NULL));
+
 		g_free(tmp);
 	}
 
--- a/pidgin/gtkprefs.c	Thu Mar 12 06:19:15 2009 +0000
+++ b/pidgin/gtkprefs.c	Fri Mar 27 07:52:26 2009 +0000
@@ -2385,14 +2385,12 @@
 	/* Auto-away stuff */
 	vbox = pidgin_make_frame(ret, _("Auto-away"));
 
-	button = pidgin_prefs_checkbox(_("Change status when _idle"),
-						   "/purple/away/away_when_idle", vbox);
-
 	select = pidgin_prefs_labeled_spin_button(vbox,
 			_("_Minutes before becoming idle:"), "/purple/away/mins_before_away",
 			1, 24 * 60, sg);
-	g_signal_connect(G_OBJECT(button), "clicked",
-					 G_CALLBACK(pidgin_toggle_sensitive), select);
+
+	button = pidgin_prefs_checkbox(_("Change status when _idle"),
+						   "/purple/away/away_when_idle", vbox);
 
 	/* TODO: Show something useful if we don't have any saved statuses. */
 	menu = pidgin_status_menu(purple_savedstatus_get_idleaway(), G_CALLBACK(set_idle_away));
@@ -2404,7 +2402,6 @@
 
 	if (!purple_prefs_get_bool("/purple/away/away_when_idle")) {
 		gtk_widget_set_sensitive(GTK_WIDGET(menu), FALSE);
-		gtk_widget_set_sensitive(GTK_WIDGET(select), FALSE);
 		gtk_widget_set_sensitive(GTK_WIDGET(label), FALSE);
 	}
 
--- a/pidgin/plugins/gevolution/gevo-util.c	Thu Mar 12 06:19:15 2009 +0000
+++ b/pidgin/plugins/gevolution/gevo-util.c	Fri Mar 27 07:52:26 2009 +0000
@@ -41,8 +41,12 @@
 		purple_blist_add_group(group, NULL);
 	}
 
-	buddy = purple_buddy_new(account, buddy_name, alias);
-	purple_blist_add_buddy(buddy, NULL, group, NULL);
+	if ((buddy = purple_find_buddy_in_group(account, buddy_name, group)))
+	{	
+		buddy = purple_buddy_new(account, buddy_name, alias);
+		purple_blist_add_buddy(buddy, NULL, group, NULL);
+	}
+
 	purple_account_add_buddy(account, buddy);
 
 	if (conv != NULL)
--- a/pidgin/plugins/gevolution/gevolution.h	Thu Mar 12 06:19:15 2009 +0000
+++ b/pidgin/plugins/gevolution/gevolution.h	Fri Mar 27 07:52:26 2009 +0000
@@ -75,7 +75,7 @@
 
 	GtkWidget *win;
 	GtkWidget *accounts_menu;
-	GtkWidget *screenname;
+	GtkWidget *username;
 	GtkWidget *firstname;
 	GtkWidget *lastname;
 	GtkWidget *email;
--- a/po/POTFILES.in	Thu Mar 12 06:19:15 2009 +0000
+++ b/po/POTFILES.in	Fri Mar 27 07:52:26 2009 +0000
@@ -62,6 +62,7 @@
 libpurple/plugins/mono/loader/mono.c
 libpurple/plugins/newline.c
 libpurple/plugins/offlinemsg.c
+libpurple/plugins/one_time_password.c
 libpurple/plugins/perl/perl.c
 libpurple/plugins/psychic.c
 libpurple/plugins/signals-test.c