changeset 27765:ed6de6a3604f

propagate from branch 'im.pidgin.pidgin' (head 3639bb4d5d5a867f6bdb2a82be21e4887179b929) to branch 'im.pidgin.pidgin.yaz' (head 8d569a6f9423673c795c293426cd53ea41e5e716)
author Yoshiki Yazawa <yaz@honeyplanet.jp>
date Mon, 11 Feb 2008 08:16:15 +0000
parents 5411ca13b878 (diff) 96934545f5be (current diff)
children 056fb36a5770
files libpurple/conversation.c libpurple/protocols/msn/msn.c libpurple/protocols/oscar/oscar.c pidgin/gtkconv.c pidgin/gtkprefs.c
diffstat 41 files changed, 1418 insertions(+), 363 deletions(-) [+]
line wrap: on
line diff
--- a/COPYRIGHT	Fri Feb 01 08:50:44 2008 +0000
+++ b/COPYRIGHT	Mon Feb 11 08:16:15 2008 +0000
@@ -255,6 +255,7 @@
 David Mohr
 Andrew Molloy
 Michael Monreal
+Marco Monteiro
 Benjamin Moody
 John Moody
 Tim Mooney
@@ -274,6 +275,7 @@
 Ruediger Oertel
 Gudmundur Bjarni Olafsson
 Bartosz Oler
+Oliver
 Stefan Ott
 Shawn Outman
 Nathan Owens (pianocomp81)
--- a/ChangeLog	Fri Feb 01 08:50:44 2008 +0000
+++ b/ChangeLog	Mon Feb 11 08:16:15 2008 +0000
@@ -41,6 +41,9 @@
 	* The 'Grouping' plugin can be used for alternate grouping in the
 	  buddylist. The current options are 'Group Online/Offline' and 'No
 	  Group'.
+	* Added a log viewer
+	* Added the ability to block/unblock buddies - see the buddy context menu
+	  and the menu for the buddy list.
 
 version 2.3.1 (12/7/2007):
 	http://developer.pidgin.im/query?status=closed&milestone=2.3.1
--- a/ChangeLog.API	Fri Feb 01 08:50:44 2008 +0000
+++ b/ChangeLog.API	Mon Feb 11 08:16:15 2008 +0000
@@ -75,6 +75,8 @@
 		  util functions finch_blist_install_manager,
 		  finch_blist_uninstall_manager, finch_blist_manager_find and
 		  finch_blist_manager_add_node.
+		* Added finch_log_show, finch_log_show_contact, finch_syslog_show,
+		  finch_log_init, finch_log_get_handle, finch_log_uninit
 
 		libgnt:
 		* Added gnt_tree_set_row_color to set the color for a row in a tree.
--- a/finch/Makefile.am	Fri Feb 01 08:50:44 2008 +0000
+++ b/finch/Makefile.am	Mon Feb 11 08:16:15 2008 +0000
@@ -25,6 +25,7 @@
 	gntft.c \
 	finch.c \
 	gntidle.c \
+	gntlog.c \
 	gntnotify.c \
 	gntplugin.c \
 	gntpounce.c \
@@ -45,6 +46,7 @@
 	gntft.h \
 	finch.h \
 	gntidle.h \
+	gntlog.h \
 	gntnotify.h \
 	gntplugin.h \
 	gntpounce.h \
--- a/finch/gntaccount.c	Fri Feb 01 08:50:44 2008 +0000
+++ b/finch/gntaccount.c	Mon Feb 11 08:16:15 2008 +0000
@@ -632,7 +632,8 @@
 	prompt = g_strdup_printf(_("Are you sure you want to delete %s?"),
 			purple_account_get_username(account));
 
-	purple_request_action(account, _("Delete Account"), prompt, NULL, 0,
+	purple_request_action(account, _("Delete Account"), prompt, NULL,
+						  PURPLE_DEFAULT_ACTION_NONE,
 						  account, NULL, NULL, account, 2,
 						  _("Delete"), really_delete_account,
 						  _("Cancel"), NULL);
--- a/finch/gntblist.c	Fri Feb 01 08:50:44 2008 +0000
+++ b/finch/gntblist.c	Mon Feb 11 08:16:15 2008 +0000
@@ -27,7 +27,9 @@
 
 #include <account.h>
 #include <blist.h>
+#include <log.h>
 #include <notify.h>
+#include <privacy.h>
 #include <request.h>
 #include <savedstatuses.h>
 #include <server.h>
@@ -43,6 +45,7 @@
 #include "gntft.h"
 #include "gntlabel.h"
 #include "gntline.h"
+#include "gntlog.h"
 #include "gntmenu.h"
 #include "gntmenuitem.h"
 #include "gntmenuitemcheck.h"
@@ -1163,10 +1166,23 @@
 	finch_pounce_editor_show(purple_buddy_get_account(b), purple_buddy_get_name(b), NULL);
 }
 
+static void
+toggle_block_buddy(GntMenuItem *item, gpointer buddy)
+{
+	gboolean block = gnt_menuitem_check_get_checked(GNT_MENU_ITEM_CHECK(item));
+	PurpleAccount *account = purple_buddy_get_account(buddy);
+	const char *name = purple_buddy_get_name(buddy);
+
+	block ? purple_privacy_deny(account, name, FALSE, FALSE) :
+		purple_privacy_allow(account, name, FALSE, FALSE);
+}
 
 static void
 create_buddy_menu(GntMenu *menu, PurpleBuddy *buddy)
 {
+	PurpleAccount *account;
+	gboolean permitted;
+	GntMenuItem *item;
 	PurplePluginProtocolInfo *prpl_info;
 	PurpleConnection *gc = purple_account_get_connection(purple_buddy_get_account(buddy));
 
@@ -1187,6 +1203,15 @@
 			add_custom_action(menu, _("Send File"),
 					PURPLE_CALLBACK(finch_blist_menu_send_file_cb), buddy);
 	}
+
+	account = purple_buddy_get_account(buddy);
+	permitted = purple_privacy_check(account, purple_buddy_get_name(buddy));
+
+	item = gnt_menuitem_check_new(_("Blocked"));
+	gnt_menuitem_check_set_checked(GNT_MENU_ITEM_CHECK(item), !permitted);
+	gnt_menuitem_set_callback(item, toggle_block_buddy, buddy);
+	gnt_menu_add_item(menu, item);
+
 #if 0
 	add_custom_action(tree, _("View Log"),
 			PURPLE_CALLBACK(finch_blist_view_log_cb)), buddy);
@@ -1282,6 +1307,43 @@
 	g_free(prompt);
 }
 
+
+static void showlog_cb(PurpleBlistNode *node)
+{
+	PurpleLogType type;
+	PurpleAccount *account;
+	char *name = NULL;
+
+	if (PURPLE_BLIST_NODE_IS_BUDDY(node)) {
+		PurpleBuddy *b = (PurpleBuddy*) node;
+		type = PURPLE_LOG_IM;
+		name = g_strdup(b->name);
+		account = b->account;
+	} else if (PURPLE_BLIST_NODE_IS_CHAT(node)) {
+		PurpleChat *c = (PurpleChat*) node;
+		PurplePluginProtocolInfo *prpl_info = NULL;
+		type = PURPLE_LOG_CHAT;
+		account = c->account;
+		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(purple_find_prpl(purple_account_get_protocol_id(account)));
+		if (prpl_info && prpl_info->get_chat_name) {
+			name = prpl_info->get_chat_name(c->components);
+		}
+	} else if (PURPLE_BLIST_NODE_IS_CONTACT(node)) {
+		finch_log_show_contact((PurpleContact *)node);
+		return;
+	} else {
+		/* This callback should not have been registered for a node
+		 * that doesn't match the type of one of the blocks above. */
+		g_return_if_reached();
+	}
+
+	if (name && account) {
+		finch_log_show(type, name, account);
+		g_free(name);
+	}
+}
+
+
 /* Xeroxed from gtkdialogs.c:purple_gtkdialogs_remove_group_cb*/
 static void
 remove_group(PurpleGroup *group)
@@ -1540,6 +1602,10 @@
 			add_custom_action(GNT_MENU(context), _("Toggle Tag"),
 					PURPLE_CALLBACK(finch_blist_toggle_tag_buddy), node);
 		}
+		if (!PURPLE_BLIST_NODE_IS_GROUP(node)) {
+			add_custom_action(GNT_MENU(context), _("View Log"),
+					PURPLE_CALLBACK(showlog_cb), node);
+		}
 	}
 
 	/* Set the position for the popup */
@@ -2493,6 +2559,61 @@
 	purple_prefs_set_string(PREF_ROOT "/sort_type", n);
 }
 
+static void
+block_select_cb(gpointer data, PurpleRequestFields *fields)
+{
+	PurpleAccount *account = purple_request_fields_get_account(fields, "account");
+	const char *name = purple_request_fields_get_string(fields,  "screenname");
+	if (account && name && *name != '\0') {
+		if (purple_request_fields_get_choice(fields, "block") == 1) {
+			purple_privacy_deny(account, name, FALSE, FALSE);
+		} else {
+			purple_privacy_allow(account, name, FALSE, FALSE);
+		}
+	}
+}
+
+static void
+block_select(GntMenuItem *item, gpointer n)
+{
+	PurpleRequestFields *fields;
+	PurpleRequestFieldGroup *group;
+	PurpleRequestField *field;
+
+	fields = purple_request_fields_new();
+
+	group = purple_request_field_group_new(NULL);
+	purple_request_fields_add_group(fields, group);
+
+	field = purple_request_field_string_new("screenname", _("Name"), NULL, FALSE);
+	purple_request_field_set_type_hint(field, "screenname");
+	purple_request_field_set_required(field, TRUE);
+	purple_request_field_group_add_field(group, field);
+
+	field = purple_request_field_account_new("account", _("Account"), NULL);
+	purple_request_field_set_type_hint(field, "account");
+	purple_request_field_set_visible(field,
+		(purple_connections_get_all() != NULL &&
+		 purple_connections_get_all()->next != NULL));
+	purple_request_field_set_required(field, TRUE);
+	purple_request_field_group_add_field(group, field);
+
+	field = purple_request_field_choice_new("block", _("Block/Unblock"), 1);
+	purple_request_field_choice_add(field, _("Block"));
+	purple_request_field_choice_add(field, _("Unblock"));
+	purple_request_field_group_add_field(group, field);
+
+	purple_request_fields(purple_get_blist(), _("Block/Unblock"),
+						NULL,
+						_("Please enter the screen name or alias of the person "
+						  "you would like to Block/Unblock."),
+						fields,
+						_("OK"), G_CALLBACK(block_select_cb),
+						_("Cancel"), NULL,
+						NULL, NULL, NULL,
+						NULL);
+}
+
 /* send_im_select* -- Xerox */
 static void
 send_im_select_cb(gpointer data, PurpleRequestFields *fields)
@@ -2656,6 +2777,11 @@
 	gnt_menu_add_item(GNT_MENU(sub), item);
 	gnt_menuitem_set_callback(GNT_MENU_ITEM(item), send_im_select, NULL);
 
+	item = gnt_menuitem_new(_("Block/Unblock..."));
+	gnt_menuitem_set_id(GNT_MENU_ITEM(item), "block-unblock");
+	gnt_menu_add_item(GNT_MENU(sub), item);
+	gnt_menuitem_set_callback(GNT_MENU_ITEM(item), block_select, NULL);
+
 	item = gnt_menuitem_new(_("Join Chat..."));
 	gnt_menuitem_set_id(GNT_MENU_ITEM(item), "join-chat");
 	gnt_menu_add_item(GNT_MENU(sub), item);
--- a/finch/gntcertmgr.c	Fri Feb 01 08:50:44 2008 +0000
+++ b/finch/gntcertmgr.c	Mon Feb 11 08:16:15 2008 +0000
@@ -234,7 +234,7 @@
 	purple_request_close_with_handle((void *)key);
 	purple_request_yes_no((void *)key, _("Confirm certificate delete"),
 			primary, NULL,
-			1,
+			0,
 			NULL, NULL, NULL,
 			g_strdup(key),
 			tls_peers_mgmt_delete_confirm_cb,
--- a/finch/gntconv.c	Fri Feb 01 08:50:44 2008 +0000
+++ b/finch/gntconv.c	Mon Feb 11 08:16:15 2008 +0000
@@ -36,6 +36,7 @@
 #include "gntblist.h"
 #include "gntconv.h"
 #include "gntdebug.h"
+#include "gntlog.h"
 #include "gntplugin.h"
 #include "gntprefs.h"
 #include "gntsound.h"
@@ -468,6 +469,44 @@
 }
 
 static void
+view_log_cb(GntMenuItem *n, gpointer ggc)
+{
+	FinchConv *fc;
+	PurpleConversation *conv;
+	PurpleLogType type;
+	const char *name;
+	PurpleAccount *account;
+	GSList *buddies;
+	GSList *cur;
+
+	fc = ggc;
+	conv = fc->active_conv;
+
+	if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM)
+		type = PURPLE_LOG_IM;
+	else if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT)
+		type = PURPLE_LOG_CHAT;
+	else
+		return;
+
+	name = purple_conversation_get_name(conv);
+	account = purple_conversation_get_account(conv);
+
+	buddies = purple_find_buddies(account, name);
+	for (cur = buddies; cur != NULL; cur = cur->next) {
+		PurpleBlistNode *node = cur->data;
+		if ((node != NULL) && ((node->prev != NULL) || (node->next != NULL))) {
+			finch_log_show_contact((PurpleContact *)node->parent);
+			g_slist_free(buddies);
+			return;
+		}
+	}
+	g_slist_free(buddies);
+
+	finch_log_show(type, name, account);
+}
+
+static void
 generate_send_to_menu(FinchConv *ggc)
 {
 	GntWidget *sub, *menu = ggc->menu;
@@ -569,6 +608,10 @@
 		generate_send_to_menu(ggc);
 	}
 
+	item = gnt_menuitem_new(_("View Log..."));
+	gnt_menu_add_item(GNT_MENU(sub), item);
+	gnt_menuitem_set_callback(item, view_log_cb, ggc);
+
 	item = gnt_menuitem_check_new(_("Enable Logging"));
 	gnt_menuitem_check_set_checked(GNT_MENU_ITEM_CHECK(item),
 			purple_conversation_is_logging(ggc->active_conv));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/finch/gntlog.c	Mon Feb 11 08:16:15 2008 +0000
@@ -0,0 +1,504 @@
+/**
+ * @file gntlog.c GNT Log viewer
+ * @ingroup finch
+ */
+
+/* finch
+ *
+ * Finch is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+#include "internal.h"
+
+#include <gnt.h>
+#include <gntbox.h>
+#include <gntbutton.h>
+#include <gntentry.h>
+#include <gntlabel.h>
+#include <gnttextview.h>
+#include <gnttree.h>
+#include <gntwindow.h>
+
+#include "account.h"
+#include "debug.h"
+#include "log.h"
+#include "notify.h"
+#include "request.h"
+#include "util.h"
+
+#include "gntlog.h"
+
+static GHashTable *log_viewers = NULL;
+static void populate_log_tree(FinchLogViewer *lv);
+static FinchLogViewer *syslog_viewer = NULL;
+
+struct log_viewer_hash_t {
+	PurpleLogType type;
+	char *screenname;
+	PurpleAccount *account;
+	PurpleContact *contact;
+};
+
+static guint log_viewer_hash(gconstpointer data)
+{
+	const struct log_viewer_hash_t *viewer = data;
+
+	if (viewer->contact != NULL)
+		return g_direct_hash(viewer->contact);
+
+	return g_str_hash(viewer->screenname) +
+		g_str_hash(purple_account_get_username(viewer->account));
+}
+
+static gboolean log_viewer_equal(gconstpointer y, gconstpointer z)
+{
+	const struct log_viewer_hash_t *a, *b;
+	int ret;
+	char *normal;
+
+	a = y;
+	b = z;
+
+	if (a->contact != NULL) {
+		if (b->contact != NULL)
+			return (a->contact == b->contact);
+		else
+			return FALSE;
+	} else {
+		if (b->contact != NULL)
+			return FALSE;
+	}
+
+	normal = g_strdup(purple_normalize(a->account, a->screenname));
+	ret = (a->account == b->account) &&
+		!strcmp(normal, purple_normalize(b->account, b->screenname));
+	g_free(normal);
+
+	return ret;
+}
+
+static const char *log_get_date(PurpleLog *log)
+{
+	if (log->tm)
+		return purple_date_format_full(log->tm);
+	else
+		return purple_date_format_full(localtime(&log->time));
+}
+
+static void search_cb(GntWidget *button, FinchLogViewer *lv)
+{
+	const char *search_term = gnt_entry_get_text(GNT_ENTRY(lv->entry));
+	GList *logs;
+
+	if (!(*search_term)) {
+		/* reset the tree */
+		gnt_tree_remove_all(GNT_TREE(lv->tree));
+		g_free(lv->search);
+		lv->search = NULL;
+		populate_log_tree(lv);
+		return;
+	}
+
+	if (lv->search != NULL && !strcmp(lv->search, search_term)) {
+		return;
+	}
+
+	g_free(lv->search);
+	lv->search = g_strdup(search_term);
+
+	gnt_tree_remove_all(GNT_TREE(lv->tree));
+	gnt_text_view_clear(GNT_TEXT_VIEW(lv->text));
+
+	for (logs = lv->logs; logs != NULL; logs = logs->next) {
+		char *read = purple_log_read((PurpleLog*)logs->data, NULL);
+		if (read && *read && purple_strcasestr(read, search_term)) {
+			PurpleLog *log = logs->data;
+
+			gnt_tree_add_row_last(GNT_TREE(lv->tree),
+									log,
+									gnt_tree_create_row(GNT_TREE(lv->tree), log_get_date(log)),
+									NULL);
+		}
+		g_free(read);
+	}
+
+}
+
+static void destroy_cb(GntWidget *w, struct log_viewer_hash_t *ht) {
+	FinchLogViewer *lv = syslog_viewer;
+
+	if (ht != NULL) {
+		lv = g_hash_table_lookup(log_viewers, ht);
+		g_hash_table_remove(log_viewers, ht);
+
+		g_free(ht->screenname);
+		g_free(ht);
+	} else
+		syslog_viewer = NULL;
+
+	purple_request_close_with_handle(lv);
+
+	g_list_foreach(lv->logs, (GFunc)purple_log_free, NULL);
+	g_list_free(lv->logs);
+
+	g_free(lv->search);
+	g_free(lv);
+
+	gnt_widget_destroy(w);
+}
+
+static void log_select_cb(GntWidget *w, gpointer old, gpointer new, FinchLogViewer *viewer) {
+	GntTree *tree = GNT_TREE(w);
+	PurpleLog *log = NULL;
+	PurpleLogReadFlags flags;
+	char *read = NULL, *strip, *newline;
+	int h;
+
+	if (!viewer->search && !gnt_tree_get_parent_key(tree, new))
+		return;
+
+	log = (PurpleLog *)new;
+
+	if (log == NULL)
+		return;
+
+	if (log->type != PURPLE_LOG_SYSTEM) {
+		char *title;
+		if (log->type == PURPLE_LOG_CHAT)
+			title = g_strdup_printf(_("Conversation in %s on %s"),
+									log->name, log_get_date(log));
+		else
+			title = g_strdup_printf(_("Conversation with %s on %s"),
+									log->name, log_get_date(log));
+
+		gnt_label_set_text(GNT_LABEL(viewer->label), title);
+		g_free(title);
+	}
+
+	read = purple_log_read(log, &flags);
+	if (flags != PURPLE_LOG_READ_NO_NEWLINE) {
+		newline = purple_strdup_withhtml(read);
+		strip = purple_markup_strip_html(newline);
+		g_free(newline);
+	} else {
+		strip = purple_markup_strip_html(read);
+	}
+	viewer->flags = flags;
+
+	purple_signal_emit(finch_log_get_handle(), "log-displaying", viewer, log);
+
+	gnt_text_view_clear(GNT_TEXT_VIEW(viewer->text));
+	gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(viewer->text), strip, GNT_TEXT_FLAG_NORMAL);
+	gnt_widget_get_size(viewer->text, NULL, &h);
+	gnt_text_view_scroll(GNT_TEXT_VIEW(viewer->text), h - 2);
+	g_free(read);
+	g_free(strip);
+}
+
+/* I want to make this smarter, but haven't come up with a cool algorithm to do so, yet.
+ * I want the tree to be divided into groups like "Today," "Yesterday," "Last week,"
+ * "August," "2002," etc. based on how many conversation took place in each subdivision.
+ *
+ * For now, I'll just make it a flat list.
+ */
+static void populate_log_tree(FinchLogViewer *lv)
+     /* Logs are made from trees in real life.
+        This is a tree made from logs */
+{
+	const char *pmonth;
+	char *month = NULL;
+	char prev_top_month[30] = "";
+	GList *logs = lv->logs;
+
+	while (logs != NULL) {
+		PurpleLog *log = logs->data;
+
+		pmonth = purple_utf8_strftime(_("%B %Y"),
+		                           log->tm ? log->tm : localtime(&log->time));
+
+		if (strcmp(pmonth, prev_top_month) != 0) {
+			month = g_strdup(pmonth);
+			/* top level */
+			gnt_tree_add_row_last(GNT_TREE(lv->tree),
+									month,
+									gnt_tree_create_row(GNT_TREE(lv->tree), month),
+									NULL);
+			gnt_tree_set_expanded(GNT_TREE(lv->tree), month, FALSE);
+
+			strncpy(prev_top_month, month, sizeof(prev_top_month));
+		}
+
+		/* sub */
+		gnt_tree_add_row_last(GNT_TREE(lv->tree),
+								log,
+								gnt_tree_create_row(GNT_TREE(lv->tree), log_get_date(log)),
+								month);
+
+		logs = logs->next;
+	}
+}
+
+static FinchLogViewer *display_log_viewer(struct log_viewer_hash_t *ht, GList *logs,
+						const char *title, int log_size)
+{
+	FinchLogViewer *lv;
+	char *text;
+	GntWidget *vbox, *hbox;
+	GntWidget *size_label;
+
+	if (logs == NULL)
+	{
+		/* No logs were found. */
+		const char *log_preferences = NULL;
+
+		if (ht == NULL) {
+			if (!purple_prefs_get_bool("/purple/logging/log_system"))
+				log_preferences = _("System events will only be logged if the \"Log all status changes to system log\" preference is enabled.");
+		} else {
+			if (ht->type == PURPLE_LOG_IM) {
+				if (!purple_prefs_get_bool("/purple/logging/log_ims"))
+					log_preferences = _("Instant messages will only be logged if the \"Log all instant messages\" preference is enabled.");
+			} else if (ht->type == PURPLE_LOG_CHAT) {
+				if (!purple_prefs_get_bool("/purple/logging/log_chats"))
+					log_preferences = _("Chats will only be logged if the \"Log all chats\" preference is enabled.");
+			}
+			g_free(ht->screenname);
+			g_free(ht);
+		}
+
+		purple_notify_info(NULL, title, _("No logs were found"), log_preferences);
+		return NULL;
+	}
+
+	lv = g_new0(FinchLogViewer, 1);
+	lv->logs = logs;
+
+	if (ht != NULL)
+		g_hash_table_insert(log_viewers, ht, lv);
+
+	/* Window ***********/
+	lv->window = gnt_vwindow_new(FALSE);
+	gnt_box_set_title(GNT_BOX(lv->window), title);
+	gnt_box_set_toplevel(GNT_BOX(lv->window), TRUE);
+	gnt_box_set_pad(GNT_BOX(lv->window), 0);
+	g_signal_connect(G_OBJECT(lv->window), "destroy", G_CALLBACK(destroy_cb), ht);
+
+	vbox = gnt_vbox_new(FALSE);
+	gnt_box_add_widget(GNT_BOX(lv->window), vbox);
+
+	/* Label ************/
+	text = g_strdup_printf("%s", title);
+	lv->label = gnt_label_new(text);
+	g_free(text);
+	gnt_box_add_widget(GNT_BOX(vbox), lv->label);
+
+	hbox = gnt_hbox_new(FALSE);
+	gnt_box_add_widget(GNT_BOX(vbox), hbox);
+	/* List *************/
+	lv->tree = gnt_tree_new();
+	gnt_widget_set_size(lv->tree, 30, 0);
+	populate_log_tree(lv);
+	g_signal_connect (G_OBJECT(lv->tree), "selection-changed",
+			G_CALLBACK (log_select_cb),
+			lv);
+	gnt_box_add_widget(GNT_BOX(hbox), lv->tree);
+
+	/* Viewer ************/
+	lv->text = gnt_text_view_new();
+	gnt_box_add_widget(GNT_BOX(hbox), lv->text);
+
+	hbox = gnt_hbox_new(FALSE);
+	gnt_box_add_widget(GNT_BOX(vbox), hbox);
+	/* Log size ************/
+	if (log_size) {
+		char *sz_txt = purple_str_size_to_units(log_size);
+		text = g_strdup_printf("%s %s", _("Total log size:"), sz_txt);
+		size_label = gnt_label_new(text);
+		gnt_box_add_widget(GNT_BOX(hbox), size_label);
+		g_free(sz_txt);
+		g_free(text);
+	}
+
+	/* Search box **********/
+	gnt_box_add_widget(GNT_BOX(hbox), gnt_label_new(_("Scroll/Search: ")));
+	lv->entry = gnt_entry_new("");
+	gnt_box_add_widget(GNT_BOX(hbox), lv->entry);
+	g_signal_connect(GNT_ENTRY(lv->entry), "activate", G_CALLBACK(search_cb), lv);
+
+	gnt_text_view_attach_scroll_widget(GNT_TEXT_VIEW(lv->text), lv->entry);
+	gnt_text_view_attach_pager_widget(GNT_TEXT_VIEW(lv->text), lv->entry);
+
+	gnt_widget_show(lv->window);
+
+	return lv;
+}
+
+void finch_log_show(PurpleLogType type, const char *screenname, PurpleAccount *account) {
+	struct log_viewer_hash_t *ht;
+	FinchLogViewer *lv = NULL;
+	const char *name = screenname;
+	char *title;
+
+	g_return_if_fail(account != NULL);
+	g_return_if_fail(screenname != NULL);
+
+	ht = g_new0(struct log_viewer_hash_t, 1);
+
+	ht->type = type;
+	ht->screenname = g_strdup(screenname);
+	ht->account = account;
+
+	if (log_viewers == NULL) {
+		log_viewers = g_hash_table_new(log_viewer_hash, log_viewer_equal);
+	} else if ((lv = g_hash_table_lookup(log_viewers, ht))) {
+		gnt_window_present(lv->window);
+		g_free(ht->screenname);
+		g_free(ht);
+		return;
+	}
+
+	if (type == PURPLE_LOG_CHAT) {
+		PurpleChat *chat;
+
+		chat = purple_blist_find_chat(account, screenname);
+		if (chat != NULL)
+			name = purple_chat_get_name(chat);
+
+		title = g_strdup_printf(_("Conversations in %s"), name);
+	} else {
+		PurpleBuddy *buddy;
+
+		buddy = purple_find_buddy(account, screenname);
+		if (buddy != NULL)
+			name = purple_buddy_get_contact_alias(buddy);
+
+		title = g_strdup_printf(_("Conversations with %s"), name);
+	}
+
+	display_log_viewer(ht, purple_log_get_logs(type, screenname, account),
+			title, purple_log_get_total_size(type, screenname, account));
+
+	g_free(title);
+}
+
+void finch_log_show_contact(PurpleContact *contact) {
+	struct log_viewer_hash_t *ht;
+	PurpleBlistNode *child;
+	FinchLogViewer *lv = NULL;
+	GList *logs = NULL;
+	const char *name = NULL;
+	char *title;
+	int total_log_size = 0;
+
+	g_return_if_fail(contact != NULL);
+
+	ht = g_new0(struct log_viewer_hash_t, 1);
+	ht->type = PURPLE_LOG_IM;
+	ht->contact = contact;
+
+	if (log_viewers == NULL) {
+		log_viewers = g_hash_table_new(log_viewer_hash, log_viewer_equal);
+	} else if ((lv = g_hash_table_lookup(log_viewers, ht))) {
+		gnt_window_present(lv->window);
+		g_free(ht);
+		return;
+	}
+
+	for (child = contact->node.child ; child ; child = child->next) {
+		if (!PURPLE_BLIST_NODE_IS_BUDDY(child))
+			continue;
+
+		logs = g_list_concat(purple_log_get_logs(PURPLE_LOG_IM, ((PurpleBuddy *)child)->name,
+						((PurpleBuddy *)child)->account), logs);
+		total_log_size += purple_log_get_total_size(PURPLE_LOG_IM, ((PurpleBuddy *)child)->name, ((PurpleBuddy *)child)->account);
+	}
+	logs = g_list_sort(logs, purple_log_compare);
+
+	if (contact->alias != NULL)
+		name = contact->alias;
+	else if (contact->priority != NULL)
+		name = purple_buddy_get_contact_alias(contact->priority);
+
+	/* This will happen if the contact doesn't have an alias,
+	 * and none of the contact's buddies are online.
+	 * There is probably a better way to deal with this. */
+	if (name == NULL) {
+		if (contact->node.child != NULL && PURPLE_BLIST_NODE_IS_BUDDY(contact->node.child))
+			name = purple_buddy_get_contact_alias((PurpleBuddy *) contact->node.child);
+		if (name == NULL)
+			name = "";
+	}
+
+	title = g_strdup_printf(_("Conversations with %s"), name);
+	display_log_viewer(ht, logs, title, total_log_size);
+	g_free(title);
+}
+
+void finch_syslog_show()
+{
+	GList *accounts = NULL;
+	GList *logs = NULL;
+
+	if (syslog_viewer != NULL) {
+		gnt_window_present(syslog_viewer->window);
+		return;
+	}
+
+	for(accounts = purple_accounts_get_all(); accounts != NULL; accounts = accounts->next) {
+
+		PurpleAccount *account = (PurpleAccount *)accounts->data;
+		if(purple_find_prpl(purple_account_get_protocol_id(account)) == NULL)
+			continue;
+
+		logs = g_list_concat(purple_log_get_system_logs(account), logs);
+	}
+	logs = g_list_sort(logs, purple_log_compare);
+
+	syslog_viewer = display_log_viewer(NULL, logs, _("System Log"), 0);
+}
+
+/****************************************************************************
+ * GNT LOG SUBSYSTEM *******************************************************
+ ****************************************************************************/
+
+void *
+finch_log_get_handle(void)
+{
+	static int handle;
+
+	return &handle;
+}
+
+void finch_log_init(void)
+{
+	void *handle = finch_log_get_handle();
+
+	purple_signal_register(handle, "log-displaying",
+	                     purple_marshal_VOID__POINTER_POINTER,
+	                     NULL, 2,
+	                     purple_value_new(PURPLE_TYPE_BOXED,
+	                                    "FinchLogViewer *"),
+	                     purple_value_new(PURPLE_TYPE_SUBTYPE,
+	                                    PURPLE_SUBTYPE_LOG));
+}
+
+void
+finch_log_uninit(void)
+{
+	purple_signals_unregister_by_instance(finch_log_get_handle());
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/finch/gntlog.h	Mon Feb 11 08:16:15 2008 +0000
@@ -0,0 +1,83 @@
+/**
+ * @file gntlog.h GNT Log viewer
+ * @ingroup finch
+ * @see @ref gntlog-signals
+ */
+
+/* finch
+ *
+ * Finch is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+#ifndef _FINCHLOG_H_
+#define _FINCHLOG_H_
+
+#include "log.h"
+#include "account.h"
+#include "gntwidget.h"
+
+typedef struct _FinchLogViewer FinchLogViewer;
+
+/**
+ * A GNT Log Viewer.  You can look at logs with it.
+ */
+struct _FinchLogViewer {
+	GList *logs;                 /**< The list of logs viewed in this viewer   */
+
+	GntWidget	*window;    /**< The viewer's window                      */
+	GntWidget	*tree;      /**< The tree representing said treestore */
+	GntWidget	*text;      /**< The text to display said logs          */
+	GntWidget	*entry;     /**< The search entry, in which search terms
+	                              *   are entered                              */
+	GntWidget	*label;
+	PurpleLogReadFlags flags;      /**< The most recently used log flags         */
+	char		*search;    /**< The string currently being searched for  */
+};
+
+
+
+void finch_log_show(PurpleLogType type, const char *screenname, PurpleAccount *account);
+void finch_log_show_contact(PurpleContact *contact);
+
+void finch_syslog_show(void);
+
+/**************************************************************************/
+/** @name GNT Log Subsystem                                              */
+/**************************************************************************/
+/*@{*/
+
+/**
+ * Initializes the GNT log subsystem.
+ */
+void finch_log_init(void);
+
+/**
+ * Returns the GNT log subsystem handle.
+ *
+ * @return The GNT log subsystem handle.
+ */
+void *finch_log_get_handle(void);
+
+/**
+ * Uninitializes the GNT log subsystem.
+ */
+void finch_log_uninit(void);
+
+/*@}*/
+
+#endif
--- a/finch/gntpounce.c	Fri Feb 01 08:50:44 2008 +0000
+++ b/finch/gntpounce.c	Mon Feb 11 08:16:15 2008 +0000
@@ -457,7 +457,7 @@
 
 	gnt_box_add_widget(GNT_BOX(window), gnt_line_new(FALSE));
 	gnt_box_add_widget(GNT_BOX(window), gnt_label_new_with_format(_("Options"), GNT_TEXT_FLAG_BOLD));
-	dialog->on_away = gnt_check_box_new(_("Pounce only when my status is not available"));
+	dialog->on_away = gnt_check_box_new(_("Pounce only when my status is not Available"));
 	gnt_box_add_widget(GNT_BOX(window), dialog->on_away);
 	dialog->save_pounce = gnt_check_box_new(_("Recurring"));
 	gnt_box_add_widget(GNT_BOX(window), dialog->save_pounce);
--- a/finch/gntui.c	Fri Feb 01 08:50:44 2008 +0000
+++ b/finch/gntui.c	Mon Feb 11 08:16:15 2008 +0000
@@ -30,6 +30,7 @@
 #include "gntconv.h"
 #include "gntdebug.h"
 #include "gntft.h"
+#include "gntlog.h"
 #include "gntnotify.h"
 #include "gntplugin.h"
 #include "gntpounce.h"
@@ -79,6 +80,9 @@
 	/* Pounce */
 	finch_pounces_init();
 
+	/* Log */
+	finch_log_init();
+
 	/* File transfer */
 	finch_xfers_init();
 	purple_xfers_set_ui_ops(finch_xfers_get_ui_ops());
@@ -124,6 +128,8 @@
 
 	finch_pounces_uninit();
 
+	finch_log_uninit();
+
 	finch_xfers_uninit();
 	purple_xfers_set_ui_ops(NULL);
 
--- a/libpurple/blist.c	Fri Feb 01 08:50:44 2008 +0000
+++ b/libpurple/blist.c	Mon Feb 11 08:16:15 2008 +0000
@@ -1087,11 +1087,18 @@
 	if(old_name && source && strcmp(source->name, old_name)) {
 		for (accts = purple_group_get_accounts(source); accts; accts = g_slist_remove(accts, accts->data)) {
 			PurpleAccount *account = accts->data;
+			PurpleConnection *gc = NULL;
+			PurplePlugin *prpl = NULL;
 			PurplePluginProtocolInfo *prpl_info = NULL;
 			GList *l = NULL, *buddies = NULL;
 
-			if(account->gc && account->gc->prpl)
-				prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(account->gc->prpl);
+			gc = purple_account_get_connection(account);
+			
+			if(gc)
+				prpl = purple_connection_get_prpl(gc);
+
+			if(gc && prpl)
+				prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
 
 			if(!prpl_info)
 				continue;
@@ -1104,7 +1111,7 @@
 			}
 
 			if(prpl_info->rename_group) {
-				prpl_info->rename_group(account->gc, old_name, source, buddies);
+				prpl_info->rename_group(gc, old_name, source, buddies);
 			} else {
 				GList *cur, *groups = NULL;
 
--- a/libpurple/buddyicon.c	Fri Feb 01 08:50:44 2008 +0000
+++ b/libpurple/buddyicon.c	Mon Feb 11 08:16:15 2008 +0000
@@ -707,7 +707,7 @@
 		PurplePluginProtocolInfo *prpl_info;
 
 		gc = purple_account_get_connection(account);
-		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl);
+		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc));
 
 		if (prpl_info && prpl_info->set_buddy_icon)
 			prpl_info->set_buddy_icon(gc, img);
--- a/libpurple/certificate.h	Fri Feb 01 08:50:44 2008 +0000
+++ b/libpurple/certificate.h	Mon Feb 11 08:16:15 2008 +0000
@@ -31,6 +31,8 @@
 #ifndef _PURPLE_CERTIFICATE_H
 #define _PURPLE_CERTIFICATE_H
 
+#include <time.h>
+
 #include <glib.h>
 
 #ifdef __cplusplus
--- a/libpurple/conversation.c	Fri Feb 01 08:50:44 2008 +0000
+++ b/libpurple/conversation.c	Mon Feb 11 08:16:15 2008 +0000
@@ -402,7 +402,7 @@
 	if (gc != NULL)
 	{
 		/* Still connected */
-		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl);
+		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc));
 
 		if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM)
 		{
@@ -1465,7 +1465,7 @@
 	conv      = purple_conv_chat_get_conversation(chat);
 	gc        = purple_conversation_get_gc(conv);
 	account   = purple_connection_get_account(gc);
-	prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl);
+	prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc));
 
 	/* Don't display this if the person who wrote it is ignored. */
 	if (purple_conv_chat_is_user_ignored(chat, who))
@@ -1584,7 +1584,7 @@
 
 	gc = purple_conversation_get_gc(conv);
 	g_return_if_fail(gc != NULL);
-	prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl);
+	prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc));
 	g_return_if_fail(prpl_info != NULL);
 
 	ul = users;
@@ -1685,7 +1685,7 @@
 
 	gc = purple_conversation_get_gc(conv);
 	g_return_if_fail(gc != NULL);
-	prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl);
+	prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc));
 	g_return_if_fail(prpl_info != NULL);
 
 	if (!strcmp(chat->nick, purple_normalize(conv->account, old_user))) {
@@ -1803,7 +1803,7 @@
 
 	gc = purple_conversation_get_gc(conv);
 	g_return_if_fail(gc != NULL);
-	prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl);
+	prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc));
 	g_return_if_fail(prpl_info != NULL);
 
 	ops  = purple_conversation_get_ui_ops(conv);
--- a/libpurple/privacy.c	Fri Feb 01 08:50:44 2008 +0000
+++ b/libpurple/privacy.c	Mon Feb 11 08:16:15 2008 +0000
@@ -207,7 +207,7 @@
  * buddy list and ONLY buddies from your buddy list.
  */
 static void
-add_buddies_in_permit(PurpleAccount *account, gboolean local)
+add_all_buddies_to_permit_list(PurpleAccount *account, gboolean local)
 {
 	GSList *list;
 
@@ -230,6 +230,12 @@
 	}
 }
 
+/*
+ * TODO: All callers of this function pass in FALSE for local and
+ *       restore and I don't understand when you would ever want to
+ *       use TRUE for either of them.  I think both parameters could
+ *       safely be removed in the next major version bump.
+ */
 void
 purple_privacy_allow(PurpleAccount *account, const char *who, gboolean local,
 						gboolean restore)
@@ -259,7 +265,7 @@
 			break;
 		case PURPLE_PRIVACY_ALLOW_BUDDYLIST:
 			if (!purple_find_buddy(account, who)) {
-				add_buddies_in_permit(account, local);
+				add_all_buddies_to_permit_list(account, local);
 				purple_privacy_permit_add(account, who, local);
 				account->perm_deny = PURPLE_PRIVACY_ALLOW_USERS;
 			}
@@ -269,6 +275,12 @@
 	}
 }
 
+/*
+ * TODO: All callers of this function pass in FALSE for local and
+ *       restore and I don't understand when you would ever want to
+ *       use TRUE for either of them.  I think both parameters could
+ *       safely be removed in the next major version bump.
+ */
 void
 purple_privacy_deny(PurpleAccount *account, const char *who, gboolean local,
 					gboolean restore)
@@ -298,7 +310,7 @@
 			break;
 		case PURPLE_PRIVACY_ALLOW_BUDDYLIST:
 			if (purple_find_buddy(account, who)) {
-				add_buddies_in_permit(account, local);
+				add_all_buddies_to_permit_list(account, local);
 				purple_privacy_permit_remove(account, who, local);
 				account->perm_deny = PURPLE_PRIVACY_ALLOW_USERS;
 			}
--- a/libpurple/protocols/msn/msn.c	Fri Feb 01 08:50:44 2008 +0000
+++ b/libpurple/protocols/msn/msn.c	Mon Feb 11 08:16:15 2008 +0000
@@ -674,8 +674,22 @@
 	 */
 	if (full && user)
 	{
+		const char *phone;
+
 		purple_notify_user_info_add_pair(user_info, _("Blocked"),
 									   ((user->list_op & (1 << MSN_LIST_BL)) ? _("Yes") : _("No")));
+
+		phone = msn_user_get_home_phone(user);
+		if (phone != NULL)
+			purple_notify_user_info_add_pair(user_info, _("Home Phone Number"), phone);
+
+		phone = msn_user_get_work_phone(user);
+		if (phone != NULL)
+			purple_notify_user_info_add_pair(user_info, _("Work Phone Number"), phone);
+
+		phone = msn_user_get_mobile_phone(user);
+		if (phone != NULL)
+			purple_notify_user_info_add_pair(user_info, _("Mobile Phone Number"), phone);
 	}
 }
 
--- a/libpurple/protocols/msnp9/msn.c	Fri Feb 01 08:50:44 2008 +0000
+++ b/libpurple/protocols/msnp9/msn.c	Mon Feb 11 08:16:15 2008 +0000
@@ -557,8 +557,22 @@
 	 * you, which is the important information that this is trying to convey. */
 	if (full && user)
 	{
+		const char *phone;
+
 		purple_notify_user_info_add_pair(user_info, _("Blocked"),
 									   ((user->list_op & (1 << MSN_LIST_BL)) ? _("Yes") : _("No")));
+
+		phone = msn_user_get_home_phone(user);
+		if (phone != NULL)
+			purple_notify_user_info_add_pair(user_info, _("Home Phone Number"), phone);
+
+		phone = msn_user_get_work_phone(user);
+		if (phone != NULL)
+			purple_notify_user_info_add_pair(user_info, _("Work Phone Number"), phone);
+
+		phone = msn_user_get_mobile_phone(user);
+		if (phone != NULL)
+			purple_notify_user_info_add_pair(user_info, _("Mobile Phone Number"), phone);
 	}
 }
 
--- a/libpurple/protocols/msnp9/notification.c	Fri Feb 01 08:50:44 2008 +0000
+++ b/libpurple/protocols/msnp9/notification.c	Mon Feb 11 08:16:15 2008 +0000
@@ -840,6 +840,38 @@
 }
 
 static void
+bpr_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+	const char *type, *value, *passport;
+	MsnUser *user;
+
+	passport = cmd->params[1];
+	user = msn_userlist_find_user(cmdproc->session->userlist, passport);
+
+	g_return_if_fail(user != NULL);
+
+	type     = cmd->params[2];
+	value    = cmd->params[3];
+
+	if (value)
+	{
+		if (!strcmp(type, "MOB"))
+		{
+			if (!strcmp(value, "Y"))
+				user->mobile = TRUE;
+			else if (!strcmp(value, "N"))
+				user->mobile = FALSE;
+		}
+		else if (!strcmp(type, "PHH"))
+			msn_user_set_home_phone(user, purple_url_decode(value));
+		else if (!strcmp(type, "PHW"))
+			msn_user_set_work_phone(user, purple_url_decode(value));
+		else if (!strcmp(type, "PHM"))
+			msn_user_set_mobile_phone(user, purple_url_decode(value));
+	}
+}
+
+static void
 reg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
 {
 	MsnSession *session;
@@ -1435,6 +1467,7 @@
 	msn_table_add_cmd(cbs_table, NULL, "IPG", ipg_cmd);
 	msn_table_add_cmd(cbs_table, NULL, "MSG", msg_cmd);
 	msn_table_add_cmd(cbs_table, NULL, "NOT", not_cmd);
+	msn_table_add_cmd(cbs_table, NULL, "BPR", bpr_cmd);
 
 	msn_table_add_cmd(cbs_table, NULL, "CHL", chl_cmd);
 	msn_table_add_cmd(cbs_table, NULL, "REM", rem_cmd);
--- a/libpurple/protocols/msnp9/session.c	Fri Feb 01 08:50:44 2008 +0000
+++ b/libpurple/protocols/msnp9/session.c	Mon Feb 11 08:16:15 2008 +0000
@@ -397,8 +397,13 @@
 	PurpleStoredImage *img;
 	const char *passport;
 
-	if (session->logged_in)
+	if (session->logged_in) {
+		/* We are probably here because of a mid-session notification server XFR
+		 * We must send a CHG now, otherwise the servers default to invisible,
+		 * and prevent things happening, like sending IMs */
+		msn_change_status(session);
 		return;
+	}
 
 	account = session->account;
 	gc = purple_account_get_connection(account);
--- a/libpurple/protocols/msnp9/sync.c	Fri Feb 01 08:50:44 2008 +0000
+++ b/libpurple/protocols/msnp9/sync.c	Mon Feb 11 08:16:15 2008 +0000
@@ -206,6 +206,8 @@
 		{
 			if (!strcmp(value, "Y"))
 				user->mobile = TRUE;
+			else if (!strcmp(value, "N"))
+				user->mobile = FALSE;
 		}
 		else if (!strcmp(type, "PHH"))
 			msn_user_set_home_phone(user, purple_url_decode(value));
--- a/libpurple/protocols/msnp9/user.c	Fri Feb 01 08:50:44 2008 +0000
+++ b/libpurple/protocols/msnp9/user.c	Mon Feb 11 08:16:15 2008 +0000
@@ -36,7 +36,8 @@
 	user->userlist = userlist;
 
 	msn_user_set_passport(user, passport);
-	msn_user_set_friendly_name(user, friendly_name);
+	if (friendly_name != NULL)
+		msn_user_set_friendly_name(user, friendly_name);
 
 	return user;
 }
--- a/libpurple/protocols/myspace/message.c	Fri Feb 01 08:50:44 2008 +0000
+++ b/libpurple/protocols/myspace/message.c	Mon Feb 11 08:16:15 2008 +0000
@@ -50,11 +50,12 @@
 {
 	GString *gs;
 	guint i, j;
+	guint msg_len;
 
 	gs = g_string_new("");
-
+	msg_len = strlen(msg);	
 
-	for (i = 0; i < strlen(msg); ++i) {
+	for (i = 0; i < msg_len; ++i) {
 		struct MSIM_ESCAPE_REPLACEMENT *replacement;
 		gchar *replace;
 
@@ -93,10 +94,12 @@
 {
 	GString *gs;
 	guint i, j;
+	guint msg_len;
 
 	gs = g_string_new("");
+	msg_len = strlen(msg);	
 
-	for (i = 0; i < strlen(msg); ++i) {
+	for (i = 0; i < msg_len; ++i) {
 		struct MSIM_ESCAPE_REPLACEMENT *replacement;
 		gchar replace;
 
@@ -105,7 +108,7 @@
 		for (j = 0; (replacement = &msim_escape_replacements[j]) &&
 				replacement->code != NULL; ++j) {
 			if (msg[i] == replacement->code[0] &&
-			    i + 1 < strlen(msg) &&
+			    i + 1 < msg_len &&
 			    msg[i + 1] == replacement->code[1]) {
 				replace = replacement->text;
 				++i;
--- a/libpurple/protocols/myspace/myspace.c	Fri Feb 01 08:50:44 2008 +0000
+++ b/libpurple/protocols/myspace/myspace.c	Mon Feb 11 08:16:15 2008 +0000
@@ -158,6 +158,20 @@
 	_MSIM_ADD_NEW_STATUS(PURPLE_STATUS_OFFLINE);
 	_MSIM_ADD_NEW_STATUS(PURPLE_STATUS_INVISIBLE);
 
+	/* Except tune status is different... */
+	status = purple_status_type_new_with_attrs(
+			PURPLE_STATUS_TUNE,	/* primitive */
+			"tune",                 /* ID */
+			NULL,                   /* name - use default */
+			TRUE,                   /* savable */
+			TRUE,                   /* should be user_settable some day */
+			TRUE,                   /* independent */
+
+			PURPLE_TUNE_ARTIST, _("Artist"), purple_value_new(PURPLE_TYPE_STRING),
+			PURPLE_TUNE_TITLE, _("Title"), purple_value_new(PURPLE_TYPE_STRING),
+			NULL);
+
+	types = g_list_append(types, status);
 
 	return types;
 }
@@ -277,27 +291,6 @@
 	gc->proto_data = msim_session_new(acct);
 	gc->flags |= PURPLE_CONNECTION_HTML | PURPLE_CONNECTION_NO_URLDESC;
 
-#ifdef MSIM_MAX_PASSWORD_LENGTH
-	/* Passwords are limited in length. */
-	if (strlen(acct->password) > MSIM_MAX_PASSWORD_LENGTH) {
-		gchar *str;
-
-		str = g_strdup_printf(
-				_("Sorry, passwords over %d characters in length (yours is "
-				"%d) are not supported by MySpace."), 
-				MSIM_MAX_PASSWORD_LENGTH,
-				(int)strlen(acct->password));
-
-		/* Notify an error message also, because this is important! */
-		purple_notify_error(acct, _("MySpaceIM Error"), str, NULL);
-
-		purple_connection_error_reason (gc,
-			PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, str);
-		g_free(str);
-		return;
-	}
-#endif
-
 	/* 1. connect to server */
 	purple_connection_update_progress(gc, _("Connecting"),
 								  0,   /* which connection step this is */
@@ -995,8 +988,6 @@
 		g_free(user->headline);
 		g_free(user->display_name);
 		g_free(user->username);
-		g_free(user->band_name);
-		g_free(user->song_name);
 		g_free(user->image_url);
 		g_free(user);
 	}
@@ -1851,6 +1842,24 @@
 				reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
 				if (!purple_account_get_remember_password(session->account))
 					purple_account_set_password(session->account, NULL);
+#ifdef MSIM_MAX_PASSWORD_LENGTH
+				if (strlen(session->account->password) > MSIM_MAX_PASSWORD_LENGTH) {
+					gchar *suggestion;
+
+					suggestion = g_strdup_printf(_("%s Your password is "
+							"%d characters, greater than the "
+							"expected maximum length of %d for "
+							"MySpaceIM. Please shorten your "
+							"password at http://profileedit.myspace.com/index.cfm?fuseaction=accountSettings.changePassword and try again."),
+							full_errmsg, (int)
+							strlen(session->account->password),
+							MSIM_MAX_PASSWORD_LENGTH);
+
+					/* Replace full_errmsg. */
+					g_free(full_errmsg);
+					full_errmsg = suggestion;
+				}
+#endif		
 				break;
 			case MSIM_ERROR_LOGGED_IN_ELSEWHERE: /* Logged in elsewhere */
 				reason = PURPLE_CONNECTION_ERROR_NAME_IN_USE;
--- a/libpurple/protocols/myspace/myspace.h	Fri Feb 01 08:50:44 2008 +0000
+++ b/libpurple/protocols/myspace/myspace.h	Mon Feb 11 08:16:15 2008 +0000
@@ -84,9 +84,9 @@
  * http://settings.myspace.com/index.cfm?fuseaction=user.changepassword
  * (though curiously, not on the 'current password' field). */
 
-/* Not defined; instead have the client reject the password, until libpurple
- * supports specifying a length limit on the protocol's password. */
-/* #define MSIM_MAX_PASSWORD_LENGTH    10	*/
+/* After login fails, if password is greater than this many characters,
+ * warn user that it may be too long. */
+#define MSIM_MAX_PASSWORD_LENGTH    10
 
 /* Build version of MySpaceIM to report to servers (1.0.xxx.0) */
 #define MSIM_CLIENT_VERSION         697
--- a/libpurple/protocols/myspace/user.c	Fri Feb 01 08:50:44 2008 +0000
+++ b/libpurple/protocols/myspace/user.c	Mon Feb 11 08:16:15 2008 +0000
@@ -20,7 +20,7 @@
 #include "myspace.h"
 
 static void msim_store_user_info_each(const gchar *key_str, gchar *value_str, MsimUser *user);
-static gchar *msim_format_now_playing(gchar *band, gchar *song);
+static gchar *msim_format_now_playing(const gchar *band, const gchar *song);
 static void msim_downloaded_buddy_icon(PurpleUtilFetchUrlData *url_data, gpointer user_data, const gchar *url_text,
 		gsize len, const gchar *error_message);
 
@@ -28,7 +28,7 @@
  * @return Return a new string (must be g_free()'d), or NULL.
  */
 static gchar *
-msim_format_now_playing(gchar *band, gchar *song)
+msim_format_now_playing(const gchar *band, const gchar *song)
 {
 	if ((band && *band) || (song && *song)) {
 		return g_strdup_printf("%s - %s",
@@ -85,6 +85,7 @@
 void
 msim_append_user_info(MsimSession *session, PurpleNotifyUserInfo *user_info, MsimUser *user, gboolean full)
 {
+	PurplePresence *presence;
 	gchar *str;
 	guint uid;
 	guint cv;
@@ -128,11 +129,22 @@
 		purple_notify_user_info_add_pair(user_info, _("Headline"), user->headline);
 	}
 
-	str = msim_format_now_playing(user->band_name, user->song_name);
-	if (str && *str) {
-		purple_notify_user_info_add_pair(user_info, _("Song"), str);
+	presence = purple_buddy_get_presence(user->buddy);
+
+	if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_TUNE)) {
+		PurpleStatus *status;
+		const char *artist, *title;
+		
+		status = purple_presence_get_status(presence, "tune");
+		title = purple_status_get_attr_string(status, PURPLE_TUNE_TITLE);
+		artist = purple_status_get_attr_string(status, PURPLE_TUNE_ARTIST);
+
+		str = msim_format_now_playing(artist, title);
+		if (str && *str) {
+			purple_notify_user_info_add_pair(user_info, _("Song"), str);
+		}
+		g_free(str);
 	}
-	g_free(str);
 
 	/* Note: total friends only available if looked up by uid, not username. */
 	if (user->total_friends) {
@@ -161,6 +173,59 @@
 	}
 }
 
+/** Set the currently playing song artist and or title.
+ *
+ * @param user User associated with the now playing information.
+ *
+ * @param new_artist New artist to set, or NULL/empty to not change artist.
+ *
+ * @param new_title New title to set, or NULL/empty to not change title.
+ *
+ * If new_artist and new_title are NULL/empty, deactivate PURPLE_STATUS_TUNE.
+ *
+ * This function is useful because it lets you set the artist or title
+ * individually, which purple_prpl_got_user_status() doesn't do.
+ */
+static void msim_set_artist_or_title(MsimUser *user, const char *new_artist, const char *new_title)
+{
+	PurplePresence *presence;
+	const char *prev_artist, *prev_title;
+
+	prev_artist = NULL;
+	prev_title = NULL;
+
+	if (new_artist && !strlen(new_artist))
+		new_artist = NULL;
+	if (new_title && !strlen(new_title))
+		new_title = NULL;
+
+	if (!new_artist && !new_title) {
+		purple_prpl_got_user_status_deactive(user->buddy->account, user->buddy->name, "tune");
+		return;
+	}
+
+	presence = purple_buddy_get_presence(user->buddy);
+
+	if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_TUNE)) {
+		PurpleStatus *status;
+		
+		status = purple_presence_get_status(presence, "tune");
+		prev_title = purple_status_get_attr_string(status, PURPLE_TUNE_TITLE);
+		prev_artist = purple_status_get_attr_string(status, PURPLE_TUNE_ARTIST);
+	} 
+
+	if (!new_artist)
+		new_artist = prev_artist;
+	
+	if (!new_title)
+		new_title = prev_title;
+
+	purple_prpl_got_user_status(user->buddy->account, user->buddy->name, "tune",
+			PURPLE_TUNE_TITLE, new_title,
+			PURPLE_TUNE_ARTIST, new_artist,
+			NULL);
+}
+
 /** Store a field of information about a buddy. 
  *
  * @param key_str Key to store.
@@ -194,11 +259,9 @@
 		g_free(user->display_name);
 		user->display_name = value_str;
 	} else if (g_str_equal(key_str, "BandName")) {
-		g_free(user->band_name);
-		user->band_name = value_str;
+		msim_set_artist_or_title(user, value_str, NULL);
 	} else if (g_str_equal(key_str, "SongName")) {
-		g_free(user->song_name);
-		user->song_name = value_str;
+		msim_set_artist_or_title(user, NULL, value_str);
 	} else if (g_str_equal(key_str, "UserName") || g_str_equal(key_str, "IMName") || g_str_equal(key_str, "NickName")) {
 		/* Ignore because PurpleBuddy knows this already */
 		g_free(value_str);
--- a/libpurple/protocols/oscar/oscar.c	Fri Feb 01 08:50:44 2008 +0000
+++ b/libpurple/protocols/oscar/oscar.c	Mon Feb 11 08:16:15 2008 +0000
@@ -6636,18 +6636,18 @@
 
 	g_return_val_if_fail(str != NULL, NULL);
 
-	strncpy(buf, str, BUF_LEN);
-	for (i=0, j=0; buf[j]; i++, j++)
+	/* copy str to buf and skip all blanks */
+	for (i=0, j=0; str[j] && i < BUF_LEN; i++, j++)
 	{
-		while (buf[j] == ' ')
+		while (str[j] == ' ')
 			j++;
-		buf[i] = buf[j];
+		buf[i] = str[j];
 	}
 	buf[i] = '\0';
 
 	tmp1 = g_utf8_strdown(buf, -1);
 	tmp2 = g_utf8_normalize(tmp1, -1, G_NORMALIZE_DEFAULT);
-	g_snprintf(buf, sizeof(buf), "%s", tmp2);
+	strcpy(buf, tmp2);
 	g_free(tmp2);
 	g_free(tmp1);
 
--- a/libpurple/protocols/simple/simple.c	Fri Feb 01 08:50:44 2008 +0000
+++ b/libpurple/protocols/simple/simple.c	Mon Feb 11 08:16:15 2008 +0000
@@ -1983,13 +1983,6 @@
 	gc->proto_data = NULL;
 }
 
-/* not needed since privacy is checked for every subscribe */
-static void dummy_add_deny(PurpleConnection *gc, const char *name) {
-}
-
-static void dummy_permit_deny(PurpleConnection *gc) {
-}
-
 static PurplePluginProtocolInfo prpl_info =
 {
 	0,
@@ -2017,11 +2010,11 @@
 	NULL,					/* add_buddies */
 	simple_remove_buddy,	/* remove_buddy */
 	NULL,					/* remove_buddies */
-	dummy_add_deny,			/* add_permit */
-	dummy_add_deny,			/* add_deny */
-	dummy_add_deny,			/* rem_permit */
-	dummy_add_deny,			/* rem_deny */
-	dummy_permit_deny,		/* set_permit_deny */
+	NULL,					/* add_permit */
+	NULL,					/* add_deny */
+	NULL,					/* rem_permit */
+	NULL,					/* rem_deny */
+	NULL,					/* set_permit_deny */
 	NULL,					/* join_chat */
 	NULL,					/* reject_chat */
 	NULL,					/* get_chat_name */
--- a/libpurple/protocols/zephyr/zephyr.c	Fri Feb 01 08:50:44 2008 +0000
+++ b/libpurple/protocols/zephyr/zephyr.c	Mon Feb 11 08:16:15 2008 +0000
@@ -858,52 +858,8 @@
 			
 			if (!g_ascii_strcasecmp(notice.z_opcode,"PING"))
 				serv_got_typing(gc,stripped_sender,ZEPHYR_TYPING_RECV_TIMEOUT, PURPLE_TYPING);
-			else {
-				/* Based on the values of
-				   account->permit_deny,
-				   account->permit, account>deny , and
-				   the buddylist */
-
-				GSList* l;
-				gboolean in_deny;
-
-				switch (gc->account->perm_deny) {
-				case PURPLE_PRIVACY_ALLOW_ALL: 
-					in_deny = 0; break;
-				case PURPLE_PRIVACY_DENY_ALL: 
-					in_deny = 1; break;
-				case PURPLE_PRIVACY_ALLOW_USERS: /* See if stripped_sender is in gc->account->permit and allow appropriately */
-					in_deny = 1;
-					for(l=gc->account->permit;l!=NULL;l=l->next) {
-						if (!purple_utf8_strcasecmp(stripped_sender, purple_normalize(gc->account, (char *)l->data))) {
-							in_deny=0;
-							break;
-						} 
-					}
-					break;
-				case PURPLE_PRIVACY_DENY_USERS: /* See if stripped_sender is in gc->account->deny and deny if so */ 
-					in_deny = 0;
-					for(l=gc->account->deny;l!=NULL;l=l->next) {
-						if (!purple_utf8_strcasecmp(stripped_sender, purple_normalize(gc->account, (char *)l->data))) {
-							in_deny=1;
-							break;
-						} 
-					}
-					break;
-				case PURPLE_PRIVACY_ALLOW_BUDDYLIST: 
-					in_deny = 1;
-					if (purple_find_buddy(gc->account,stripped_sender)!=NULL) {
-						in_deny = 0;
-					}
-					break;
-				default: 
-					in_deny=0; break;
-				}
-				
-				if (!in_deny) {
-					serv_got_im(gc, stripped_sender, buf3, flags, time(NULL));
-				}
-			}
+			else
+				serv_got_im(gc, stripped_sender, buf3, flags, time(NULL));
 
 			g_free(stripped_sender);
 		} else {
@@ -2272,6 +2228,26 @@
 	return buf;
 }
 
+static const char *zephyr_normalize(const PurpleAccount *account, const char *who)
+{
+	static char buf[BUF_LEN];
+	PurpleConnection *gc;
+	char *tmp;
+
+	gc = purple_account_get_connection(account);
+	tmp = local_zephyr_normalize(gc->proto_data, who);
+
+	if (strlen(tmp) >= sizeof(buf)) {
+		g_free(tmp);
+		return NULL;
+	}
+
+	strcpy(buf, tmp);
+	g_free(tmp);
+
+	return buf;
+}
+
 static void zephyr_zloc(PurpleConnection *gc, const char *who)
 {
 	ZAsyncLocateData_t ald;
@@ -2782,36 +2758,6 @@
 }
 
 
-static void
-zephyr_add_deny(PurpleConnection *gc, const char *who)
-{
-	purple_privacy_deny_add(gc->account,who,1);
-}
-
-static void
-zephyr_remove_deny(PurpleConnection *gc, const char *who)
-{
-	purple_privacy_deny_remove(gc->account,who,1);
-}
-
-static void
-zephyr_add_permit(PurpleConnection *gc, const char *who)
-{
-	purple_privacy_permit_add(gc->account,who,1);
-}
-
-static void
-zephyr_remove_permit(PurpleConnection *gc, const char *who)
-{
-	purple_privacy_permit_remove(gc->account,who,1);
-}
-
-static void
-zephyr_set_permit_deny(PurpleConnection *gc)
-{
-	/* This doesn't have to do anything, since really, we can just check account->perm_deny when deciding whether to di */
-	return;
-}
 static int zephyr_resubscribe(PurpleConnection *gc)
 {
 	/* Resubscribe to the in-memory list of subscriptions and also
@@ -2920,11 +2866,11 @@
 	NULL,					/* add_buddies */
 	NULL,					/* remove_buddy */
 	NULL,					/* remove_buddies */
-	zephyr_add_permit,		/* add_permit */
-	zephyr_add_deny,		/* add_deny */
-	zephyr_remove_permit,	/* remove_permit */
-	zephyr_remove_deny,		/* remove_deny */
-	zephyr_set_permit_deny,	/* set_permit_deny */
+	NULL,					/* add_permit */
+	NULL,					/* add_deny */
+	NULL,					/* remove_permit */
+	NULL,					/* remove_deny */
+	NULL,					/* set_permit_deny */
 	zephyr_join_chat,		/* join_chat */
 	NULL,					/* reject_chat -- No chat invites*/
 	zephyr_get_chat_name,	/* get_chat_name */
@@ -2941,7 +2887,7 @@
 	NULL,					/* rename_group */
 	NULL,					/* buddy_free */
 	NULL,					/* convo_closed */
-	NULL,					/* normalize */
+	zephyr_normalize,		/* normalize */
 	NULL,					/* XXX set_buddy_icon */
 	NULL,					/* remove_group */
 	NULL,					/* XXX get_cb_real_name */
--- a/libpurple/roomlist.c	Fri Feb 01 08:50:44 2008 +0000
+++ b/libpurple/roomlist.c	Mon Feb 11 08:16:15 2008 +0000
@@ -169,20 +169,25 @@
 
 PurpleRoomlist *purple_roomlist_get_list(PurpleConnection *gc)
 {
+	PurplePlugin *prpl = NULL;
 	PurplePluginProtocolInfo *prpl_info = NULL;
 
 	g_return_val_if_fail(gc != NULL, NULL);
 
-	if (gc->prpl != NULL)
-		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl);
+	prpl = purple_connection_get_prpl(gc);
 
-	if (prpl_info && prpl_info->roomlist_get_list)
+	if(prpl != NULL)
+		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
+
+	if(prpl_info && prpl_info->roomlist_get_list)
 		return prpl_info->roomlist_get_list(gc);
+
 	return NULL;
 }
 
 void purple_roomlist_cancel_get_list(PurpleRoomlist *list)
 {
+	PurplePlugin *prpl = NULL;
 	PurplePluginProtocolInfo *prpl_info = NULL;
 	PurpleConnection *gc;
 
@@ -192,15 +197,19 @@
 
 	g_return_if_fail(gc != NULL);
 
-	if (gc != NULL && gc->prpl != NULL)
-		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl);
+	if(gc)
+		prpl = purple_connection_get_prpl(gc);
 
-	if (prpl_info && prpl_info->roomlist_cancel)
+	if(prpl)
+		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
+
+	if(prpl_info && prpl_info->roomlist_cancel)
 		prpl_info->roomlist_cancel(list);
 }
 
 void purple_roomlist_expand_category(PurpleRoomlist *list, PurpleRoomlistRoom *category)
 {
+	PurplePlugin *prpl = NULL;
 	PurplePluginProtocolInfo *prpl_info = NULL;
 	PurpleConnection *gc;
 
@@ -211,10 +220,13 @@
 	gc = purple_account_get_connection(list->account);
 	g_return_if_fail(gc != NULL);
 
-	if (gc->prpl != NULL)
-		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl);
+	if(gc)
+		prpl = purple_connection_get_prpl(gc);
 
-	if (prpl_info && prpl_info->roomlist_expand_category)
+	if(prpl)
+		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
+
+	if(prpl_info && prpl_info->roomlist_expand_category)
 		prpl_info->roomlist_expand_category(list, category);
 }
 
--- a/libpurple/server.c	Fri Feb 01 08:50:44 2008 +0000
+++ b/libpurple/server.c	Mon Feb 11 08:16:15 2008 +0000
@@ -44,12 +44,16 @@
 unsigned int
 serv_send_typing(PurpleConnection *gc, const char *name, PurpleTypingState state)
 {
+	PurplePlugin *prpl = NULL;
 	PurplePluginProtocolInfo *prpl_info = NULL;
 
-	if (gc != NULL && gc->prpl != NULL)
-		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl);
+	if(gc)
+		prpl = purple_connection_get_prpl(gc);
 
-	if (prpl_info && prpl_info->send_typing)
+	if(prpl)
+		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
+
+	if(prpl_info && prpl_info->send_typing)
 		return prpl_info->send_typing(gc, name, state);
 
 	return 0;
@@ -117,24 +121,28 @@
 int serv_send_im(PurpleConnection *gc, const char *name, const char *message,
 				 PurpleMessageFlags flags)
 {
-	PurpleConversation *conv;
-	PurpleAccount *account;
-	PurplePresence *presence;
-	PurplePluginProtocolInfo *prpl_info;
+	PurpleConversation *conv = NULL;
+	PurpleAccount *account = NULL;
+	PurplePresence *presence = NULL;
+	PurplePlugin *prpl = NULL;
+	PurplePluginProtocolInfo *prpl_info = NULL;
 	int val = -EINVAL;
-	const gchar *auto_reply_pref;
+	const gchar *auto_reply_pref = NULL;
 
 	g_return_val_if_fail(gc != NULL, val);
-	g_return_val_if_fail(gc->prpl != NULL, val);
+
+	prpl = purple_connection_get_prpl(gc);
 
-	prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl);
+	g_return_val_if_fail(prpl != NULL, val);
+
+	prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
 
 	account  = purple_connection_get_account(gc);
 	presence = purple_account_get_presence(account);
 
-	conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, name, gc->account);
+	conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, name, account);
 
-	if (prpl_info && prpl_info->send_im)
+	if(prpl_info && prpl_info->send_im)
 		val = prpl_info->send_im(gc, name, message, flags);
 
 	/*
@@ -142,7 +150,7 @@
 	 * this only reset lar->sent if we're away AND idle?
 	 */
 	auto_reply_pref = purple_prefs_get_string("/purple/away/auto_reply");
-	if ((gc->flags & PURPLE_CONNECTION_AUTO_RESP) &&
+	if((gc->flags & PURPLE_CONNECTION_AUTO_RESP) &&
 			flags & PURPLE_MESSAGE_AUTO_RESP &&
 			!purple_presence_is_available(presence) &&
 			strcmp(auto_reply_pref, "never")) {
@@ -152,7 +160,7 @@
 		lar->sent = time(NULL);
 	}
 
-	if (conv && purple_conv_im_get_send_typed_timeout(PURPLE_CONV_IM(conv)))
+	if(conv && purple_conv_im_get_send_typed_timeout(PURPLE_CONV_IM(conv)))
 		purple_conv_im_stop_send_typed_timeout(PURPLE_CONV_IM(conv));
 
 	return val;
@@ -160,28 +168,36 @@
 
 void serv_get_info(PurpleConnection *gc, const char *name)
 {
+	PurplePlugin *prpl = NULL;
 	PurplePluginProtocolInfo *prpl_info = NULL;
 
-	if (gc != NULL && gc->prpl != NULL)
-		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl);
+	if(gc)
+		prpl = purple_connection_get_prpl(gc);
+	
+	if(prpl)
+		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
 
-	if (gc && prpl_info && prpl_info->get_info)
+	if(gc && prpl_info && prpl_info->get_info)
 		prpl_info->get_info(gc, name);
 }
 
 void serv_set_info(PurpleConnection *gc, const char *info)
 {
+	PurplePlugin *prpl = NULL;
 	PurplePluginProtocolInfo *prpl_info = NULL;
-	PurpleAccount *account;
+	PurpleAccount *account = NULL;;
 
-	if (gc != NULL && gc->prpl != NULL)
-		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl);
+	if(gc)
+		prpl = purple_connection_get_prpl(gc);
+	
+	if(prpl)
+		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
 
-	if (prpl_info && prpl_info->set_info) {
+	if(prpl_info && prpl_info->set_info) {
 
 		account = purple_connection_get_account(gc);
 
-		if (purple_signal_emit_return_1(purple_accounts_get_handle(),
+		if(purple_signal_emit_return_1(purple_accounts_get_handle(),
 									  "account-setting-info", account, info))
 			return;
 
@@ -197,30 +213,45 @@
  */
 void serv_alias_buddy(PurpleBuddy *b)
 {
+	PurpleAccount *account = NULL;
+	PurpleConnection *gc = NULL;
+	PurplePlugin *prpl = NULL;
 	PurplePluginProtocolInfo *prpl_info = NULL;
 
-	if (b != NULL && b->account->gc && b->account->gc->prpl != NULL)
-		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(b->account->gc->prpl);
+	if(b)
+		account = purple_buddy_get_account(b);
+
+	if(account)
+		gc = purple_account_get_connection(account);
 
-	if (b && prpl_info && prpl_info->alias_buddy) {
-		prpl_info->alias_buddy(b->account->gc, b->name, b->alias);
+	if(gc)
+		prpl = purple_connection_get_prpl(gc);
+
+	if(prpl)
+		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
+
+	if(b && prpl_info && prpl_info->alias_buddy) {
+		prpl_info->alias_buddy(gc, b->name, b->alias);
 	}
 }
 
 void
 serv_got_alias(PurpleConnection *gc, const char *who, const char *alias)
 {
-	PurpleAccount *account = purple_connection_get_account(gc);
-	GSList *buddies = purple_find_buddies(account, who);
+	PurpleAccount *account;
+	GSList *buddies;
 	PurpleBuddy *b;
 	PurpleConversation *conv;
 
+	account = purple_connection_get_account(gc);
+	buddies = purple_find_buddies(account, who);
+
 	while (buddies != NULL)
 	{
 		b = buddies->data;
 		buddies = g_slist_delete_link(buddies, buddies);
 
-		if ((b->server_alias == NULL && alias == NULL) ||
+		if((b->server_alias == NULL && alias == NULL) ||
 		    (b->server_alias && alias && !strcmp(b->server_alias, alias)))
 		{
 			continue;
@@ -229,7 +260,7 @@
 		purple_blist_server_alias_buddy(b, alias);
 
 		conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, b->name, account);
-		if (conv != NULL && alias != NULL && strcmp(alias, who))
+		if(conv != NULL && alias != NULL && strcmp(alias, who))
 		{
 			char *tmp = g_strdup_printf(_("%s is now known as %s.\n"),
 										who, alias);
@@ -296,8 +327,8 @@
 	else
 		alias = who;
 
-	if (attn && attn->outgoing_description) {
-		description = g_strdup_printf(attn->outgoing_description, alias);
+	if (attn && purple_attention_type_get_outgoing_desc(attn)) {
+		description = g_strdup_printf(purple_attention_type_get_outgoing_desc(attn), alias);
 	} else {
 		description = g_strdup_printf(_("Requesting %s's attention..."), alias);
 	}
@@ -341,8 +372,8 @@
 	else
 		alias = who;
 
-	if (attn && attn->incoming_description) {
-		description = g_strdup_printf(attn->incoming_description, alias);
+	if (attn && purple_attention_type_get_incoming_desc(attn)) {
+		description = g_strdup_printf(purple_attention_type_get_incoming_desc(attn), alias);
 	} else {
 		description = g_strdup_printf(_("%s has requested your attention!"), alias);
 	}
@@ -367,72 +398,101 @@
  */
 void serv_move_buddy(PurpleBuddy *b, PurpleGroup *og, PurpleGroup *ng)
 {
+	PurpleAccount *account = NULL;
+	PurpleConnection *gc = NULL;
+	PurplePlugin *prpl = NULL;
 	PurplePluginProtocolInfo *prpl_info = NULL;
 
 	g_return_if_fail(b != NULL);
 	g_return_if_fail(og != NULL);
 	g_return_if_fail(ng != NULL);
 
-	if (b->account->gc != NULL && b->account->gc->prpl != NULL)
-		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(b->account->gc->prpl);
+	account = purple_buddy_get_account(b);
+	gc = purple_account_get_connection(account);
+
+	if(gc)
+		prpl = purple_connection_get_prpl(gc);
 
-	if (b->account->gc && og && ng) {
+	if(prpl)
+		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
+
+	if(gc && og && ng) {
 		if (prpl_info && prpl_info->group_buddy) {
-			prpl_info->group_buddy(b->account->gc, b->name, og->name, ng->name);
+			prpl_info->group_buddy(gc, b->name, og->name, ng->name);
 		}
 	}
 }
 
-void serv_add_permit(PurpleConnection *g, const char *name)
+void serv_add_permit(PurpleConnection *gc, const char *name)
 {
+	PurplePlugin *prpl = NULL;
 	PurplePluginProtocolInfo *prpl_info = NULL;
 
-	if (g != NULL && g->prpl != NULL)
-		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(g->prpl);
+	if(gc)
+		prpl = purple_connection_get_prpl(gc);
 
-	if (prpl_info && prpl_info->add_permit)
-		prpl_info->add_permit(g, name);
+	if(prpl)
+		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
+
+	if(prpl_info && prpl_info->add_permit)
+		prpl_info->add_permit(gc, name);
 }
 
-void serv_add_deny(PurpleConnection *g, const char *name)
+void serv_add_deny(PurpleConnection *gc, const char *name)
 {
+	PurplePlugin *prpl = NULL;
 	PurplePluginProtocolInfo *prpl_info = NULL;
 
-	if (g != NULL && g->prpl != NULL)
-		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(g->prpl);
+	if(gc)
+		prpl = purple_connection_get_prpl(gc);
 
-	if (prpl_info && prpl_info->add_deny)
-		prpl_info->add_deny(g, name);
+	if(prpl)
+		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
+
+	if(prpl_info && prpl_info->add_deny)
+		prpl_info->add_deny(gc, name);
 }
 
-void serv_rem_permit(PurpleConnection *g, const char *name)
+void serv_rem_permit(PurpleConnection *gc, const char *name)
 {
+	PurplePlugin *prpl = NULL;
 	PurplePluginProtocolInfo *prpl_info = NULL;
 
-	if (g != NULL && g->prpl != NULL)
-		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(g->prpl);
+	if(gc)
+		prpl = purple_connection_get_prpl(gc);
 
-	if (prpl_info && prpl_info->rem_permit)
-		prpl_info->rem_permit(g, name);
+	if(prpl)
+		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
+
+	if(prpl_info && prpl_info->rem_permit)
+		prpl_info->rem_permit(gc, name);
 }
 
-void serv_rem_deny(PurpleConnection *g, const char *name)
+void serv_rem_deny(PurpleConnection *gc, const char *name)
 {
+	PurplePlugin *prpl = NULL;
 	PurplePluginProtocolInfo *prpl_info = NULL;
 
-	if (g != NULL && g->prpl != NULL)
-		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(g->prpl);
+	if(gc)
+		prpl = purple_connection_get_prpl(gc);
 
-	if (prpl_info && prpl_info->rem_deny)
-		prpl_info->rem_deny(g, name);
+	if(prpl)
+		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
+
+	if(prpl_info && prpl_info->rem_deny)
+		prpl_info->rem_deny(gc, name);
 }
 
-void serv_set_permit_deny(PurpleConnection *g)
+void serv_set_permit_deny(PurpleConnection *gc)
 {
+	PurplePlugin *prpl = NULL;
 	PurplePluginProtocolInfo *prpl_info = NULL;
 
-	if (g != NULL && g->prpl != NULL)
-		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(g->prpl);
+	if(gc)
+		prpl = purple_connection_get_prpl(gc);
+
+	if(prpl)
+		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
 
 	/*
 	 * this is called when either you import a buddy list, and make lots
@@ -440,52 +500,64 @@
 	 * in the prefs. In either case you should probably be resetting and
 	 * resending the permit/deny info when you get this.
 	 */
-	if (prpl_info && prpl_info->set_permit_deny)
-		prpl_info->set_permit_deny(g);
+	if(prpl_info && prpl_info->set_permit_deny)
+		prpl_info->set_permit_deny(gc);
 }
 
-void serv_join_chat(PurpleConnection *g, GHashTable *data)
+void serv_join_chat(PurpleConnection *gc, GHashTable *data)
 {
+	PurplePlugin *prpl = NULL;
 	PurplePluginProtocolInfo *prpl_info = NULL;
 
-	if (g != NULL && g->prpl != NULL)
-		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(g->prpl);
+	if(gc)
+		prpl = purple_connection_get_prpl(gc);
 
-	if (prpl_info && prpl_info->join_chat)
-		prpl_info->join_chat(g, data);
+	if(prpl)
+		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
+
+	if(prpl_info && prpl_info->join_chat)
+		prpl_info->join_chat(gc, data);
 }
 
 
-void serv_reject_chat(PurpleConnection *g, GHashTable *data)
+void serv_reject_chat(PurpleConnection *gc, GHashTable *data)
 {
+	PurplePlugin *prpl = NULL;
 	PurplePluginProtocolInfo *prpl_info = NULL;
 
-	if (g != NULL && g->prpl != NULL)
-		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(g->prpl);
+	if(gc)
+		prpl = purple_connection_get_prpl(gc);
 
-	if (prpl_info && prpl_info->reject_chat)
-		prpl_info->reject_chat(g, data);
+	if(prpl)
+		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
+
+	if(prpl_info && prpl_info->reject_chat)
+		prpl_info->reject_chat(gc, data);
 }
 
-void serv_chat_invite(PurpleConnection *g, int id, const char *message, const char *name)
+void serv_chat_invite(PurpleConnection *gc, int id, const char *message, const char *name)
 {
+	PurplePlugin *prpl = NULL;
 	PurplePluginProtocolInfo *prpl_info = NULL;
 	PurpleConversation *conv;
 	char *buffy = message && *message ? g_strdup(message) : NULL;
 
-	conv = purple_find_chat(g, id);
+	conv = purple_find_chat(gc, id);
 
-	if (conv == NULL)
+	if(conv == NULL)
 		return;
 
-	if (g != NULL && g->prpl != NULL)
-		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(g->prpl);
+	if(gc)
+		prpl = purple_connection_get_prpl(gc);
+
+	if(prpl)
+		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
 
 	purple_signal_emit(purple_conversations_get_handle(), "chat-inviting-user",
 					 conv, name, &buffy);
 
 	if (prpl_info && prpl_info->chat_invite)
-		prpl_info->chat_invite(g, id, buffy, name);
+		prpl_info->chat_invite(gc, id, buffy, name);
 
 	purple_signal_emit(purple_conversations_get_handle(), "chat-invited-user",
 					 conv, name, buffy);
@@ -499,37 +571,47 @@
  * to leave a chat without destroying the conversation.
  */
 
-void serv_chat_leave(PurpleConnection *g, int id)
+void serv_chat_leave(PurpleConnection *gc, int id)
 {
+	PurplePlugin *prpl = NULL;
 	PurplePluginProtocolInfo *prpl_info = NULL;
 
-	if (g->prpl != NULL)
-		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(g->prpl);
+	prpl = purple_connection_get_prpl(gc);
 
-	if (prpl_info && prpl_info->chat_leave)
-		prpl_info->chat_leave(g, id);
+	if(prpl)
+		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
+
+	if(prpl_info && prpl_info->chat_leave)
+		prpl_info->chat_leave(gc, id);
 }
 
-void serv_chat_whisper(PurpleConnection *g, int id, const char *who, const char *message)
+void serv_chat_whisper(PurpleConnection *gc, int id, const char *who, const char *message)
 {
+	PurplePlugin *prpl = NULL;
 	PurplePluginProtocolInfo *prpl_info = NULL;
 
-	if (g != NULL && g->prpl != NULL)
-		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(g->prpl);
+	if(gc)
+		prpl = purple_connection_get_prpl(gc);
 
-	if (prpl_info && prpl_info->chat_whisper)
-		prpl_info->chat_whisper(g, id, who, message);
+	if(prpl)
+		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
+
+	if(prpl_info && prpl_info->chat_whisper)
+		prpl_info->chat_whisper(gc, id, who, message);
 }
 
 int serv_chat_send(PurpleConnection *gc, int id, const char *message, PurpleMessageFlags flags)
 {
 	int val = -EINVAL;
+	PurplePlugin *prpl = NULL;
 	PurplePluginProtocolInfo *prpl_info = NULL;
 
-	if (gc->prpl != NULL)
-		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl);
+	prpl = purple_connection_get_prpl(gc);
 
-	if (prpl_info && prpl_info->chat_send)
+	if(prpl)
+		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
+
+	if(prpl_info && prpl_info->chat_send)
 		val = prpl_info->chat_send(gc, id, message, flags);
 
 	return val;
@@ -552,7 +634,7 @@
 
 	account  = purple_connection_get_account(gc);
 
-	if (PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->set_permit_deny == NULL) {
+	if (PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc))->set_permit_deny == NULL) {
 		/* protocol does not support privacy, handle it ourselves */
 		if (!purple_privacy_check(account, who))
 			return;
@@ -772,7 +854,7 @@
 	int plugin_return;
 
 	account = purple_connection_get_account(gc);
-	if (PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->set_permit_deny == NULL) {
+	if (PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc))->set_permit_deny == NULL) {
 		/* protocol does not support privacy, handle it ourselves */
 		if (!purple_privacy_check(account, who))
 			return;
@@ -920,10 +1002,14 @@
 
 void serv_send_file(PurpleConnection *gc, const char *who, const char *file)
 {
+	PurplePlugin *prpl = NULL;
 	PurplePluginProtocolInfo *prpl_info = NULL;
 
-	if (gc != NULL && gc->prpl != NULL)
-		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl);
+	if(gc)
+		prpl = purple_connection_get_prpl(gc);
+
+	if(prpl)
+		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
 
 	if (prpl_info && prpl_info->send_file) {
 		if (!prpl_info->can_receive_file || prpl_info->can_receive_file(gc, who)) {
--- a/libpurple/status.c	Fri Feb 01 08:50:44 2008 +0000
+++ b/libpurple/status.c	Mon Feb 11 08:16:15 2008 +0000
@@ -1310,7 +1310,8 @@
 	else if (purple_presence_get_context(presence) == PURPLE_PRESENCE_CONTEXT_ACCOUNT)
 	{
 		PurpleAccount *account;
-		PurpleConnection *gc;
+		PurpleConnection *gc = NULL;
+		PurplePlugin *prpl = NULL;
 		PurplePluginProtocolInfo *prpl_info = NULL;
 
 		account = purple_presence_get_account(presence);
@@ -1339,9 +1340,11 @@
 
 		gc = purple_account_get_connection(account);
 
-		if (gc != NULL && PURPLE_CONNECTION_IS_CONNECTED(gc) &&
-				gc->prpl != NULL)
-			prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl);
+		if(gc)
+			prpl = purple_connection_get_prpl(gc);
+
+		if(PURPLE_CONNECTION_IS_CONNECTED(gc) && prpl != NULL)
+			prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
 
 		if (prpl_info && prpl_info->set_idle)
 			prpl_info->set_idle(gc, (idle ? (current_time - idle_time) : 0));
--- a/libpurple/whiteboard.c	Fri Feb 01 08:50:44 2008 +0000
+++ b/libpurple/whiteboard.c	Mon Feb 11 08:16:15 2008 +0000
@@ -59,7 +59,8 @@
 	wb->state   = state;
 	wb->who     = g_strdup(who);
 
-	prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(account->gc->prpl);
+	prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(
+				purple_account_get_connection(account)));
 	purple_whiteboard_set_prpl_ops(wb, prpl_info->whiteboard_prpl_ops);
 
 	/* Start up protocol specifics */
--- a/pidgin/gtkaccount.c	Fri Feb 01 08:50:44 2008 +0000
+++ b/pidgin/gtkaccount.c	Mon Feb 11 08:16:15 2008 +0000
@@ -1833,7 +1833,8 @@
 							  purple_account_get_username(account));
 
 		purple_request_close_with_handle(account);
-		purple_request_action(account, NULL, buf, NULL, 0,
+		purple_request_action(account, NULL, buf, NULL,
+							PURPLE_DEFAULT_ACTION_NONE,
 							account, NULL, NULL,
 							account, 2,
 							_("Delete"), delete_account_cb,
--- a/pidgin/gtkcertmgr.c	Fri Feb 01 08:50:44 2008 +0000
+++ b/pidgin/gtkcertmgr.c	Mon Feb 11 08:16:15 2008 +0000
@@ -372,7 +372,7 @@
 
 		purple_request_yes_no(tpm_dat, _("Confirm certificate delete"),
 				      primary, NULL, /* Can this be NULL? */
-				      1, /* NO is default action */
+				      0, /* "yes" is the default action */
 				      NULL, NULL, NULL,
 				      id, /* id ownership passed to callback */
 				      tls_peers_mgmt_delete_confirm_cb,
@@ -392,6 +392,7 @@
 {
 	GtkWidget *bbox;
 	GtkListStore *store;
+	GtkWidget *sw;
 
 	/* This block of variables will end up in tpm_dat */
 	GtkTreeView *listview;
@@ -408,7 +409,9 @@
 
 	tpm_dat->mgmt_widget = mgmt_widget =
 		gtk_hbox_new(FALSE, /* Non-homogeneous */
-			     PIDGIN_HIG_BORDER);
+			     PIDGIN_HIG_BOX_SPACE);
+	gtk_container_set_border_width(GTK_CONTAINER(mgmt_widget),
+		PIDGIN_HIG_BOX_SPACE);
 	gtk_widget_show(mgmt_widget);
 
 	/* Ensure that everything gets cleaned up when the dialog box
@@ -416,6 +419,16 @@
 	g_signal_connect(G_OBJECT(mgmt_widget), "destroy",
 			 G_CALLBACK(tls_peers_mgmt_destroy), NULL);
 
+	/* Scrolled window */
+	sw = gtk_scrolled_window_new(NULL,NULL);
+	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
+			GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
+	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN);
+	gtk_box_pack_start(GTK_BOX(mgmt_widget), GTK_WIDGET(sw),
+			TRUE, TRUE, /* Take up lots of space */
+			0);
+	gtk_widget_show(GTK_WIDGET(sw));
+
 	/* List view */
 	store = gtk_list_store_new(TPM_N_COLUMNS, G_TYPE_STRING);
 
@@ -452,9 +465,7 @@
 	g_signal_connect(G_OBJECT(select), "changed",
 			 G_CALLBACK(tls_peers_mgmt_select_chg_cb), NULL);
 
-	gtk_box_pack_start(GTK_BOX(mgmt_widget), GTK_WIDGET(listview),
-			   TRUE, TRUE, /* Take up lots of space */
-			   0); /* TODO: this padding is wrong */
+	gtk_container_add(GTK_CONTAINER(sw), GTK_WIDGET(listview));
 	gtk_widget_show(GTK_WIDGET(listview));
 
 	/* Fill the list for the first time */
@@ -464,7 +475,7 @@
 	bbox = gtk_vbutton_box_new();
 	gtk_box_pack_end(GTK_BOX(mgmt_widget), bbox,
 			 FALSE, FALSE, /* Do not take up space */
-			 0); /* TODO: this padding is probably wrong */
+			 0);
 	gtk_box_set_spacing(GTK_BOX(bbox), PIDGIN_HIG_BOX_SPACE);
 	gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_START);
 	gtk_widget_show(bbox);
--- a/pidgin/gtklog.c	Fri Feb 01 08:50:44 2008 +0000
+++ b/pidgin/gtklog.c	Mon Feb 11 08:16:15 2008 +0000
@@ -242,8 +242,8 @@
 {
 	if (!purple_log_delete((PurpleLog *)data[2]))
 	{
-		purple_notify_error(NULL, NULL, "Log Deletion Failed",
-		                  "Check permissions and try again.");
+		purple_notify_error(NULL, NULL, _("Log Deletion Failed"),
+		                  _("Check permissions and try again."));
 	}
 	else
 	{
@@ -321,7 +321,7 @@
 	data2[0] = lv->treestore;
 	data2[1] = data[3]; /* iter */
 	data2[2] = log;
-	purple_request_action(lv, NULL, "Delete Log?", tmp, 0,
+	purple_request_action(lv, NULL, _("Delete Log?"), tmp, 0,
 						NULL, NULL, NULL,
 						data2, 2,
 						_("Delete"), delete_log_cb,
@@ -332,7 +332,7 @@
 static void log_show_popup_menu(GtkWidget *treeview, GdkEventButton *event, gpointer *data)
 {
 	GtkWidget *menu = gtk_menu_new();
-	GtkWidget *menuitem = gtk_menu_item_new_with_label("Delete Log...");
+	GtkWidget *menuitem = gtk_menu_item_new_with_label(_("Delete Log..."));
 
 	if (!purple_log_is_deletable((PurpleLog *)data[1]))
 		gtk_widget_set_sensitive(menuitem, FALSE);
--- a/pidgin/gtkprefs.c	Fri Feb 01 08:50:44 2008 +0000
+++ b/pidgin/gtkprefs.c	Mon Feb 11 08:16:15 2008 +0000
@@ -980,6 +980,7 @@
 
 	font_name = purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/custom_font");
 	font_button = gtk_font_button_new_with_font(font_name ? font_name : NULL);
+
 	gtk_font_button_set_show_style(GTK_FONT_BUTTON(font_button), TRUE);
 	hbox = pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("Conversation _font:"), NULL, font_button, FALSE, NULL);
 	if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/use_theme_font"))
--- a/pidgin/gtkprivacy.c	Fri Feb 01 08:50:44 2008 +0000
+++ b/pidgin/gtkprivacy.c	Mon Feb 11 08:16:15 2008 +0000
@@ -410,6 +410,7 @@
 	/* Remove button */
 	button = pidgin_dialog_add_button(GTK_DIALOG(dialog->win), GTK_STOCK_REMOVE, G_CALLBACK(remove_cb), dialog);
 	dialog->remove_button = button;
+	/* TODO: This button should be sensitive/invisitive more cleverly */
 	gtk_widget_set_sensitive(button, FALSE);
 
 	/* Remove All button */
--- a/po/POTFILES.in	Fri Feb 01 08:50:44 2008 +0000
+++ b/po/POTFILES.in	Mon Feb 11 08:16:15 2008 +0000
@@ -7,6 +7,7 @@
 finch/gntconv.c
 finch/gntdebug.c
 finch/gntft.c
+finch/gntlog.c
 finch/gntnotify.c
 finch/gntplugin.c
 finch/gntpounce.c
--- a/po/de.po	Fri Feb 01 08:50:44 2008 +0000
+++ b/po/de.po	Mon Feb 11 08:16:15 2008 +0000
@@ -11,8 +11,8 @@
 msgstr ""
 "Project-Id-Version: de\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-01-23 10:20+0100\n"
-"PO-Revision-Date: 2008-01-23 10:19+0100\n"
+"POT-Creation-Date: 2008-02-08 16:08+0100\n"
+"PO-Revision-Date: 2008-02-08 16:08+0100\n"
 "Last-Translator: Jochen Kemnade <jochenkemnade@web.de>\n"
 "Language-Team: Deutsch <de@li.org>\n"
 "MIME-Version: 1.0\n"
@@ -270,6 +270,9 @@
 msgid "Send File"
 msgstr "Datei versenden"
 
+msgid "Blocked"
+msgstr "Blockiert"
+
 msgid "View Log"
 msgstr "Mitschnitt anzeigen"
 
@@ -335,6 +338,28 @@
 msgid "Plugins"
 msgstr "Plugins"
 
+msgid "Block/Unblock"
+msgstr "Sperren/Sperrung aufheben"
+
+msgid "Block"
+msgstr "Sperren"
+
+msgid "Unblock"
+msgstr "Sperrung aufheben"
+
+msgid ""
+"Please enter the screen name or alias of the person you would like to Block/"
+"Unblock."
+msgstr ""
+"Bitte geben Sie den Benutzernamen der Person ein, die Sie blockieren oder "
+"für die Sie die Blockierung aufheben wollen."
+
+#. Not multiline
+#. Not masked?
+#. No hints?
+msgid "OK"
+msgstr "OK"
+
 msgid "New Instant Message"
 msgstr "Neue Sofortnachricht"
 
@@ -343,12 +368,6 @@
 msgstr ""
 "Bitte geben Sie den Benutzernamen der Person ein, mit der Sie chatten wollen."
 
-#. Not multiline
-#. Not masked?
-#. No hints?
-msgid "OK"
-msgstr "OK"
-
 msgid "Channel"
 msgstr "Kanal"
 
@@ -368,6 +387,9 @@
 msgid "Send IM..."
 msgstr "Nachricht senden..."
 
+msgid "Block/Unblock..."
+msgstr "Sperren/Sperrung aufheben..."
+
 msgid "Join Chat..."
 msgstr "Chat betreten..."
 
@@ -582,6 +604,9 @@
 msgid "Add Buddy Pounce..."
 msgstr "Buddy-Alarm hinzufügen..."
 
+msgid "View Log..."
+msgstr "Mitschnitt anzeigen.."
+
 msgid "Enable Logging"
 msgstr "Mitschnitt einschalten"
 
@@ -733,6 +758,58 @@
 msgid "Transferring"
 msgstr "Übertragung"
 
+#, fuzzy, c-format
+msgid "Conversation in %s on %s"
+msgstr "Unterhaltung in %s"
+
+#, fuzzy, c-format
+msgid "Conversation with %s on %s"
+msgstr "Unterhaltung mit %s"
+
+msgid "%B %Y"
+msgstr "%B %Y"
+
+msgid ""
+"System events will only be logged if the \"Log all status changes to system "
+"log\" preference is enabled."
+msgstr ""
+"Systemereignisse werden nur mitgeschnitten, wenn die Option „Schneide alle "
+"Statusveränderungen im System-Mitschnitt mit“ aktiviert ist."
+
+msgid ""
+"Instant messages will only be logged if the \"Log all instant messages\" "
+"preference is enabled."
+msgstr ""
+"Sofortnachrichten werden nur mitgeschnitten, wenn die Option „Alle "
+"Sofortnachrichten mitschneiden“ aktiviert ist."
+
+msgid ""
+"Chats will only be logged if the \"Log all chats\" preference is enabled."
+msgstr ""
+"Chats werden nur mitgeschnitten, wenn die Option „Alle Chats mitschneiden“ "
+"aktiviert ist."
+
+msgid "No logs were found"
+msgstr "Keine Mitschnitte gefunden"
+
+msgid "Total log size:"
+msgstr "Gesamte Mitschnittgröße:"
+
+#. Search box *********
+msgid "Scroll/Search: "
+msgstr "Scrollen/Suchen: "
+
+#, c-format
+msgid "Conversations in %s"
+msgstr "Unterhaltung in %s"
+
+#, c-format
+msgid "Conversations with %s"
+msgstr "Unterhaltung mit %s"
+
+msgid "System Log"
+msgstr "System-Mitschnitt"
+
 msgid "Emails"
 msgstr "E-Mails"
 
@@ -908,7 +985,7 @@
 msgid "Play a sound"
 msgstr "Einen Klang abspielen"
 
-msgid "Pounce only when my status is not available"
+msgid "Pounce only when my status is not Available"
 msgstr "Nur alarmieren, wenn ich nicht verfügbar bin"
 
 msgid "Recurring"
@@ -1348,6 +1425,9 @@
 msgid "Online/Offline"
 msgstr "Online/Offline"
 
+msgid "Meebo"
+msgstr "Meebo"
+
 msgid "No Grouping"
 msgstr "Keine Gruppierung"
 
@@ -2906,18 +2986,9 @@
 msgid "Connection failed."
 msgstr "Verbindung fehlgeschlagen."
 
-msgid "Blocked"
-msgstr "Blockiert"
-
 msgid "Add to chat"
 msgstr "Zum Chat hinzufügen"
 
-msgid "Unblock"
-msgstr "Sperrung aufheben"
-
-msgid "Block"
-msgstr "Sperren"
-
 msgid "Chat _name:"
 msgstr "Chat_name:"
 
@@ -4455,9 +4526,9 @@
 "Kann die Datei nicht an %s senden, Anwesenheit des Benutzers nicht abonniert"
 
 #, c-format
-msgid "Please select which resource of %s you would like to send a file to"
-msgstr ""
-"Bitte wählen Sie, welcher Ressource von %s Sie eine Datei schicken möchten"
+msgid "Please select the resource of %s to which you would like to send a file"
+msgstr ""
+"Bitte wählen Sie die Ressource von %s, an die Sie eine Datei schicken möchten"
 
 msgid "Select a Resource"
 msgstr "Wählen Sie eine Ressource"
@@ -4741,6 +4812,15 @@
 msgid "Page"
 msgstr "Nachricht"
 
+msgid "Home Phone Number"
+msgstr "Private Telefonnummer"
+
+msgid "Work Phone Number"
+msgstr "Geschäftliche Handynummer"
+
+msgid "Mobile Phone Number"
+msgstr "Handynummer"
+
 msgid "Be Right Back"
 msgstr "Bin gleich zurück"
 
@@ -4753,6 +4833,12 @@
 msgid "Out to Lunch"
 msgstr "Zur Mittagspause"
 
+#. primitive
+#. ID
+#. name - use default
+#. savable
+#. should be user_settable some day
+#. independent
 msgid "Artist"
 msgstr "Interpret"
 
@@ -5227,18 +5313,6 @@
 "Benutzen sie libpurple mit RC4-Unterstützung (>= 2.0.1). MySpaceIM-Plugin "
 "wird nicht geladen."
 
-#, c-format
-msgid ""
-"Sorry, passwords over %d characters in length (yours is %d) are not "
-"supported by MySpace."
-msgstr ""
-"Passwörter mit mehr als %d Zeichen (Ihres hat %d) werden von MySpace leider "
-"nicht unterstützt."
-
-#. Notify an error message also, because this is important!
-msgid "MySpaceIM Error"
-msgstr "MySpaceIM-Fehler"
-
 msgid "Reading challenge"
 msgstr "Lese Challenge"
 
@@ -5293,6 +5367,21 @@
 msgid "Protocol error, code %d: %s"
 msgstr "Protokollfehler, Code %d: %s"
 
+#, c-format
+msgid ""
+"%s Your password is %d characters, greater than the expected maximum length "
+"of %d for MySpaceIM. Please shorten your password at http://profileedit."
+"myspace.com/index.cfm?fuseaction=accountSettings.changePassword and try "
+"again."
+msgstr ""
+"%s Ihr Passwort hat %d Buchstaben, mehr als die erwartete maximale Länge von "
+"%d für MySpaceIM. Bitte kürzen Sie ihr Passwort unter http://profileedit."
+"myspace.com/index.cfm?fuseaction=accountSettings.changePassword und "
+"versuchen Sie es erneut."
+
+msgid "MySpaceIM Error"
+msgstr "MySpaceIM-Fehler"
+
 msgid "Failed to add buddy"
 msgstr "Kontakt konnte nicht hinzugefügt werden"
 
@@ -5321,8 +5410,8 @@
 msgid "Invalid input condition"
 msgstr "Ungültige Eingabebedingung"
 
-msgid "Read buffer full"
-msgstr "Lesepuffer voll"
+msgid "Read buffer full (2)"
+msgstr "Lesepuffer voll (2)"
 
 msgid "Unparseable message"
 msgstr "Kann die Nachricht nicht parsen"
@@ -6752,12 +6841,6 @@
 msgid "Search for Buddy by Information"
 msgstr "Suche Buddy nach Information"
 
-msgid "Use recent buddies group"
-msgstr "Benutze neueste Gruppe"
-
-msgid "Show how long you have been idle"
-msgstr "Anzeigen, wie lange ich untätig war"
-
 msgid ""
 "Always use AIM/ICQ proxy server for\n"
 "file transfers and direct IM (slower,\n"
@@ -7116,8 +7199,11 @@
 msgid "Error requesting login token"
 msgstr "Fehler beim Abfragen des Anmelde-Tokens"
 
-msgid "Unable to login, check debug log"
-msgstr "Anmeldung fehlgeschlagen, Debugmitschnitt beachten"
+msgid "Unable to login. Check debug log."
+msgstr "Anmeldung fehlgeschlagen, Debugmitschnitt beachten."
+
+msgid "Unable to login"
+msgstr "Anmeldung fehlgeschlagen"
 
 #. we didn't successfully connect. tdt->toc_fd is valid here
 msgid "Unable to connect."
@@ -8713,9 +8799,6 @@
 msgid "John Noname"
 msgstr "Max Mustermann"
 
-msgid "Cannot find/access ~/.silc directory"
-msgstr "Kann nicht auf das Verzeichnis ~/.silc zugreifen"
-
 #, c-format
 msgid "Could not load SILC key pair: %s"
 msgstr "Konnte SILC-Schlüsselpaar nicht laden: %s"
@@ -11380,6 +11463,12 @@
 msgid "_Smile!"
 msgstr "_Lächeln!"
 
+msgid "Log Deletion Failed"
+msgstr "Löschen des Mitschnitts fehlgeschlagen"
+
+msgid "Check permissions and try again."
+msgstr "Überprüfenb Sie die Berechtigungen und versuchen Sie es erneut."
+
 #, c-format
 msgid ""
 "Are you sure you want to permanently delete the log of the conversation with "
@@ -11404,6 +11493,12 @@
 "Wollen Sie wirklich den System-Mitschnitt, gestartet am %s, permanent "
 "löschen?"
 
+msgid "Delete Log?"
+msgstr "Mitschnitt löschen?"
+
+msgid "Delete Log..."
+msgstr "Mitschnitt löschen..."
+
 #, c-format
 msgid "<span size='larger' weight='bold'>Conversation in %s on %s</span>"
 msgstr "<span size='larger' weight='bold'>Unterhaltung mit %s am %s</span>"
@@ -11412,50 +11507,10 @@
 msgid "<span size='larger' weight='bold'>Conversation with %s on %s</span>"
 msgstr "<span size='larger' weight='bold'>Unterhaltung mit %s am %s</span>"
 
-msgid "%B %Y"
-msgstr "%B %Y"
-
-msgid ""
-"System events will only be logged if the \"Log all status changes to system "
-"log\" preference is enabled."
-msgstr ""
-"Systemereignisse werden nur mitgeschnitten, wenn die Option „Schneide alle "
-"Statusveränderungen im System-Mitschnitt mit“ aktiviert ist."
-
-msgid ""
-"Instant messages will only be logged if the \"Log all instant messages\" "
-"preference is enabled."
-msgstr ""
-"Sofortnachrichten werden nur mitgeschnitten, wenn die Option „Alle "
-"Sofortnachrichten mitschneiden“ aktiviert ist."
-
-msgid ""
-"Chats will only be logged if the \"Log all chats\" preference is enabled."
-msgstr ""
-"Chats werden nur mitgeschnitten, wenn die Option „Alle Chats mitschneiden“ "
-"aktiviert ist."
-
-msgid "No logs were found"
-msgstr "Keine Mitschnitte gefunden"
-
 #. Steal the "HELP" response and use it to trigger browsing to the logs folder
 msgid "_Browse logs folder"
 msgstr "_Mitschnitt-Ordner anschauen"
 
-msgid "Total log size:"
-msgstr "Gesamte Mitschnittgröße:"
-
-#, c-format
-msgid "Conversations in %s"
-msgstr "Unterhaltung in %s"
-
-#, c-format
-msgid "Conversations with %s"
-msgstr "Unterhaltung mit %s"
-
-msgid "System Log"
-msgstr "System-Mitschnitt"
-
 #, c-format
 msgid "%s %s. Try `%s -h' for more information.\n"
 msgstr "%s %s. Versuchen Sie `%s -h' für weitere Informationen.\n"
@@ -11905,6 +11960,9 @@
 msgid "Konqueror"
 msgstr "Konqueror"
 
+msgid "Desktop Default"
+msgstr "Desktop-Standard"
+
 msgid "GNOME Default"
 msgstr "GNOME-Standard"
 
@@ -12084,6 +12142,10 @@
 msgid "Set privacy for:"
 msgstr "Setze Privatsphäre für:"
 
+#. Remove All button
+msgid "Remove Al_l"
+msgstr "A_lle Entfernen"
+
 msgid "Permit User"
 msgstr "Benutzer erlauben"