# HG changeset patch
# Node ID 3b0d15826668
# Parent  445f5cc52e1a
diff --git a/ChangeLog.API b/ChangeLog.API
--- a/ChangeLog.API
+++ b/ChangeLog.API
@@ -320,7 +320,9 @@
 		* PurpleAccountPrefsUiOps
 		* purple_account_add_buddies_with_invite
 		* purple_account_add_buddy_with_invite
+		* purple_account_destroy_log
 		* purple_account_get_check_mail
+		* purple_account_get_log
 		* purple_account_get_password.  Use
 		  purple_credential_manager_read_password_async instead.
 		* purple_account_get_public_alias
@@ -367,8 +369,10 @@
 		* purple_conv_custom_smiley_write
 		* PurpleConversationType
 		* purple_conversation_add_smiley
+		* purple_conversation_close_logs
 		* purple_conversation_get_remote_smileys
 		* purple_conversation_get_smiley
+		* purple_conversation_is_logging
 		* purple_conversations_add. Use purple_conversation_manager_register
 		  instead.
 		* purple_conversations_remove. Use
@@ -383,6 +387,7 @@
 		  purple_conversation_manager_find_chat instead.
 		* purple_conversations_find_chat. Use
 		  purple_conversation_manager_find_chat_by_id instead.
+		* purple_conversation_set_logging
 		* purple_core_ensure_single_instance. Check via GApplication
 		  or whatever is appropriate for your UI.
 		* purple_core_migrate
diff --git a/doc/reference/libpurple/libpurple-docs.xml b/doc/reference/libpurple/libpurple-docs.xml
--- a/doc/reference/libpurple/libpurple-docs.xml
+++ b/doc/reference/libpurple/libpurple-docs.xml
@@ -138,7 +138,6 @@
 
         <xi:include href="xml/purplemessage.xml" />
         <xi:include href="xml/purpleattachment.xml" />
-        <xi:include href="xml/log.xml" />
         <xi:include href="xml/cmds.xml" />
     </chapter>
 
diff --git a/finch/gntblist.c b/finch/gntblist.c
--- a/finch/gntblist.c
+++ b/finch/gntblist.c
@@ -131,7 +131,6 @@
 static int blist_node_compare_position(PurpleBlistNode *n1, PurpleBlistNode *n2);
 static int blist_node_compare_text(PurpleBlistNode *n1, PurpleBlistNode *n2);
 static int blist_node_compare_status(PurpleBlistNode *n1, PurpleBlistNode *n2);
-static int blist_node_compare_log(PurpleBlistNode *n1, PurpleBlistNode *n2);
 
 static int color_available;
 static int color_away;
@@ -1843,9 +1842,6 @@
 	} else if (purple_strequal(purple_prefs_get_string(PREF_ROOT "/sort_type"), "status")) {
 		gnt_tree_set_compare_func(GNT_TREE(ggblist->tree),
 			(GCompareFunc)blist_node_compare_status);
-	} else if (purple_strequal(purple_prefs_get_string(PREF_ROOT "/sort_type"), "log")) {
-		gnt_tree_set_compare_func(GNT_TREE(ggblist->tree),
-			(GCompareFunc)blist_node_compare_log);
 	}
 
 	list = purple_blist_get_default();
@@ -2228,49 +2224,6 @@
 	return ret;
 }
 
-static int
-get_contact_log_size(PurpleBlistNode *c)
-{
-	int log = 0;
-	PurpleBlistNode *node;
-
-	for (node = purple_blist_node_get_first_child(c); node; node = purple_blist_node_get_sibling_next(node)) {
-		PurpleBuddy *b = (PurpleBuddy*)node;
-		log += purple_log_get_total_size(PURPLE_LOG_IM, purple_buddy_get_name(b),
-				purple_buddy_get_account(b));
-	}
-
-	return log;
-}
-
-static int
-blist_node_compare_log(PurpleBlistNode *n1, PurpleBlistNode *n2)
-{
-	int ret;
-	PurpleBuddy *b1, *b2;
-
-	if (G_OBJECT_TYPE(n1) != G_OBJECT_TYPE(n2))
-		return blist_node_compare_position(n1, n2);
-
-	if (PURPLE_IS_BUDDY(n1)) {
-		b1 = (PurpleBuddy*)n1;
-		b2 = (PurpleBuddy*)n2;
-		ret = purple_log_get_total_size(PURPLE_LOG_IM, purple_buddy_get_name(b2), purple_buddy_get_account(b2)) -
-				purple_log_get_total_size(PURPLE_LOG_IM, purple_buddy_get_name(b1), purple_buddy_get_account(b1));
-		if (ret != 0)
-			return ret;
-	} else if (PURPLE_IS_CONTACT(n1)) {
-		ret = get_contact_log_size(n2) - get_contact_log_size(n1);
-		if (ret != 0)
-			return ret;
-	} else {
-		return blist_node_compare_position(n1, n2);
-	}
-
-	ret = blist_node_compare_text(n1, n2);
-	return ret;
-}
-
 static void
 plugin_action(GntMenuItem *item, gpointer data)
 {
diff --git a/finch/gntconv.c b/finch/gntconv.c
--- a/finch/gntconv.c
+++ b/finch/gntconv.c
@@ -490,42 +490,6 @@
 }
 
 static void
-toggle_logging_cb(GntMenuItem *item, gpointer ggconv)
-{
-	FinchConv *fc = ggconv;
-	PurpleConversation *conv = fc->active_conv;
-	gboolean logging = gnt_menuitem_check_get_checked(GNT_MENU_ITEM_CHECK(item));
-	GList *iter;
-
-	if (logging == purple_conversation_is_logging(conv))
-		return;
-
-	/* Xerox */
-	if (logging) {
-		/* Enable logging first so the message below can be logged. */
-		purple_conversation_set_logging(conv, TRUE);
-
-		purple_conversation_write_system_message(conv,
-			_("Logging started. Future messages in this "
-			"conversation will be logged."), 0);
-	} else {
-		purple_conversation_write_system_message(conv,
-			_("Logging stopped. Future messages in this "
-			"conversation will not be logged."), 0);
-
-		/* Disable the logging second, so that the above message can be logged. */
-		purple_conversation_set_logging(conv, FALSE);
-	}
-
-	/* Each conversation with the same person will have the same logging setting */
-	for (iter = fc->list; iter; iter = iter->next) {
-		if (iter->data == conv)
-			continue;
-		purple_conversation_set_logging(iter->data, logging);
-	}
-}
-
-static void
 send_to_cb(GntMenuItem *m, gpointer n)
 {
 	PurpleAccount *account = g_object_get_data(G_OBJECT(m), "purple_account");
@@ -654,12 +618,6 @@
 		gnt_menuitem_set_callback(item, invite_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));
-	gnt_menu_add_item(GNT_MENU(sub), item);
-	gnt_menuitem_set_callback(item, toggle_logging_cb, ggc);
-
 	item = gnt_menuitem_new(_("Plugins"));
 	gnt_menu_add_item(GNT_MENU(menu), item);
 	ggc->plugins = item;
@@ -768,12 +726,6 @@
 	else
 		ggc = g_new0(FinchConv, 1);
 
-	/* Each conversation with the same person will have the same logging setting */
-	if (ggc->list) {
-		purple_conversation_set_logging(conv,
-				purple_conversation_is_logging(ggc->list->data));
-	}
-
 	ggc->list = g_list_prepend(ggc->list, conv);
 	ggc->active_conv = conv;
 	g_object_set_data(G_OBJECT(conv), "finch", ggc);
diff --git a/finch/gntprefs.c b/finch/gntprefs.c
--- a/finch/gntprefs.c
+++ b/finch/gntprefs.c
@@ -68,12 +68,6 @@
 } Prefs;
 
 static GList *
-get_log_options(void)
-{
-	return purple_log_logger_get_options();
-}
-
-static GList *
 get_idle_options(void)
 {
 	GList *list = NULL;
@@ -185,7 +179,6 @@
 
 static Prefs logging[] =
 {
-	{PURPLE_PREF_STRING, "/purple/logging/format", N_("Log format"), get_log_options},
 	{PURPLE_PREF_BOOLEAN, "/purple/logging/log_ims", N_("Log IMs"), NULL},
 	{PURPLE_PREF_BOOLEAN, "/purple/logging/log_chats", N_("Log chats"), NULL},
 	{PURPLE_PREF_BOOLEAN, "/purple/logging/log_system", N_("Log status change events"), NULL},
diff --git a/finch/plugins/gnthistory.c b/finch/plugins/gnthistory.c
deleted file mode 100644
--- a/finch/plugins/gnthistory.c
+++ /dev/null
@@ -1,230 +0,0 @@
-/**
- * Copyright (C) 2006 Sadrul Habib Chowdhury <sadrul@users.sourceforge.net>
- *
- * 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
- */
-
-/* Ripped from gtk/plugins/history.c */
-
-#include <glib/gi18n-lib.h>
-
-#include <purple.h>
-
-#include <finch.h>
-
-#define HISTORY_PLUGIN_ID "gnt-history"
-
-#define HISTORY_SIZE (4 * 1024)
-
-static void historize(PurpleConversation *c)
-{
-	PurpleAccount *account = purple_conversation_get_account(c);
-	const char *name = purple_conversation_get_name(c);
-	GList *logs = NULL;
-	const char *alias = name;
-	PurpleLogReadFlags flags;
-	GDateTime *dt;
-	char *date;
-	char *history;
-	char *header;
-	PurpleMessageFlags mflag;
-
-	if (PURPLE_IS_IM_CONVERSATION(c)) {
-		GSList *buddies;
-		GSList *cur;
-		FinchConv *fc = FINCH_CONV(c);
-		if (fc->list && fc->list->next) /* We were already in the middle of a conversation. */
-			return;
-
-		/* If we're not logging, don't show anything.
-		 * Otherwise, we might show a very old log. */
-		if (!purple_prefs_get_bool("/purple/logging/log_ims"))
-			return;
-
-		/* Find buddies for this conversation. */
-		buddies = purple_blist_find_buddies(account, name);
-
-		/* If we found at least one buddy, save the first buddy's alias. */
-		if (buddies != NULL)
-			alias = purple_buddy_get_contact_alias(PURPLE_BUDDY(buddies->data));
-
-		for (cur = buddies; cur != NULL; cur = cur->next) {
-			PurpleBlistNode *node = cur->data;
-			if ((node != NULL) &&
-					((purple_blist_node_get_sibling_prev(node) != NULL) ||
-						(purple_blist_node_get_sibling_next(node) != NULL))) {
-				PurpleBlistNode *node2;
-
-				alias = purple_buddy_get_contact_alias(PURPLE_BUDDY(node));
-
-				/* We've found a buddy that matches this conversation.  It's part of a
-				 * PurpleContact with more than one PurpleBuddy.  Loop through the PurpleBuddies
-				 * in the contact and get all the logs. */
-				for (node2 = purple_blist_node_get_first_child(purple_blist_node_get_parent(node));
-						node2 != NULL ; node2 = purple_blist_node_get_sibling_next(node2)) {
-					logs = g_list_concat(
-							purple_log_get_logs(PURPLE_LOG_IM,
-								purple_buddy_get_name(PURPLE_BUDDY(node2)),
-								purple_buddy_get_account(PURPLE_BUDDY(node2))),
-							logs);
-				}
-				break;
-			}
-		}
-		g_slist_free(buddies);
-
-		if (logs == NULL)
-			logs = purple_log_get_logs(PURPLE_LOG_IM, name, account);
-		else
-			logs = g_list_sort(logs, purple_log_compare);
-	} else if (PURPLE_IS_CHAT_CONVERSATION(c)) {
-		/* If we're not logging, don't show anything.
-		 * Otherwise, we might show a very old log. */
-		if (!purple_prefs_get_bool("/purple/logging/log_chats"))
-			return;
-
-		logs = purple_log_get_logs(PURPLE_LOG_CHAT, name, account);
-	}
-
-	if (logs == NULL)
-		return;
-
-	mflag = PURPLE_MESSAGE_NO_LOG | PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_DELAYED;
-	history = purple_log_read((PurpleLog*)logs->data, &flags);
-
-	dt = g_date_time_to_local(((PurpleLog *)logs->data)->time);
-	date = g_date_time_format(dt, "%c");
-	header = g_strdup_printf(_("<b>Conversation with %s on %s:</b><br>"), alias, date);
-	purple_conversation_write_system_message(c, header, mflag);
-	g_free(date);
-	g_free(header);
-
-	if (flags & PURPLE_LOG_READ_NO_NEWLINE)
-		purple_str_strip_char(history, '\n');
-	purple_conversation_write_system_message(c, history, mflag);
-	g_free(history);
-
-	purple_conversation_write_system_message(c, "<hr>", mflag);
-
-	g_list_free_full(logs, (GDestroyNotify)purple_log_free);
-}
-
-static void
-history_prefs_check(PurplePlugin *plugin)
-{
-	if (!purple_prefs_get_bool("/purple/logging/log_ims") &&
-	    !purple_prefs_get_bool("/purple/logging/log_chats"))
-	{
-		PurpleRequestFields *fields = purple_request_fields_new();
-		PurpleRequestFieldGroup *group;
-		PurpleRequestField *field;
-		struct {
-			const char *pref;
-			const char *label;
-		} prefs[] = {
-			{"/purple/logging/log_ims", N_("Log IMs")},
-			{"/purple/logging/log_chats", N_("Log chats")},
-			{NULL, NULL}
-		};
-		int iter;
-		GList *list = purple_log_logger_get_options();
-		const char *system = purple_prefs_get_string("/purple/logging/format");
-
-		group = purple_request_field_group_new(_("Logging"));
-
-		field = purple_request_field_list_new("/purple/logging/format", _("Log format"));
-		while (list) {
-			const char *label = _(list->data);
-			list = g_list_delete_link(list, list);
-			purple_request_field_list_add_icon(field, label, NULL, list->data);
-			if (purple_strequal(system, list->data))
-				purple_request_field_list_add_selected(field, label);
-			list = g_list_delete_link(list, list);
-		}
-		purple_request_field_group_add_field(group, field);
-
-		for (iter = 0; prefs[iter].pref; iter++) {
-			field = purple_request_field_bool_new(prefs[iter].pref, _(prefs[iter].label),
-						purple_prefs_get_bool(prefs[iter].pref));
-			purple_request_field_group_add_field(group, field);
-		}
-
-		purple_request_fields_add_group(fields, group);
-
-		/* Translators: Please maintain the use of ⇦ or ⇨ to represent the menu hierarchy */
-		purple_request_fields(plugin, NULL, _("History Plugin Requires Logging"),
-				      _("Logging can be enabled from Tools ⇨ Preferences ⇨ Logging.\n\n"
-				      "Enabling logs for instant messages and/or chats will activate "
-				      "history for the same conversation type(s)."),
-				      fields,
-				      _("OK"), G_CALLBACK(finch_request_save_in_prefs),
-				      _("Cancel"), NULL,
-				      NULL, plugin);
-	}
-}
-
-static void history_prefs_cb(const char *name, PurplePrefType type,
-							 gconstpointer val, gpointer data)
-{
-	history_prefs_check((PurplePlugin *)data);
-}
-
-static GPluginPluginInfo *
-gnt_history_query(GError **error) {
-	const gchar * const authors[] = {
-		"Sean Egan <seanegan@gmail.com>",
-		"Sadrul H Chowdhury <sadrul@users.sourceforge.net>",
-		NULL
-	};
-
-	return finch_plugin_info_new(
-		"id",           HISTORY_PLUGIN_ID,
-		"name",         N_("GntHistory"),
-		"version",      DISPLAY_VERSION,
-		"category",     N_("User interface"),
-		"summary",      N_("Shows recently logged conversations in new "
-		                   "conversations."),
-		"description",  N_("When a new conversation is opened this plugin will "
-		                   "insert the last conversation into the current "
-		                   "conversation."),
-		"authors",      authors,
-		"website",      PURPLE_WEBSITE,
-		"abi-version",  PURPLE_ABI_VERSION,
-		NULL
-	);
-}
-
-static gboolean
-gnt_history_load(GPluginPlugin *plugin, GError **error) {
-	purple_signal_connect(purple_conversations_get_handle(),
-						"conversation-created",
-						plugin, PURPLE_CALLBACK(historize), NULL);
-
-	purple_prefs_connect_callback(plugin, "/purple/logging/log_ims",
-								history_prefs_cb, plugin);
-	purple_prefs_connect_callback(plugin, "/purple/logging/log_chats",
-								history_prefs_cb, plugin);
-
-	history_prefs_check(plugin);
-
-	return TRUE;
-}
-
-static gboolean
-gnt_history_unload(GPluginPlugin *plugin, gboolean shutdown, GError **error) {
-	return TRUE;
-}
-
-GPLUGIN_NATIVE_PLUGIN_DECLARE(gnt_history)
\ No newline at end of file
diff --git a/finch/plugins/meson.build b/finch/plugins/meson.build
--- a/finch/plugins/meson.build
+++ b/finch/plugins/meson.build
@@ -16,12 +16,6 @@
 	    install : true, install_dir : FINCH_PLUGINDIR)
 endif
 
-gnthistory = library('gnthistory', 'gnthistory.c',
-    c_args : ['-DG_LOG_USE_STRUCTURED', '-DG_LOG_DOMAIN="Gnt-History"'],
-    dependencies : [libpurple_dep, libfinch_dep, glib],
-    name_prefix : '',
-    install : true, install_dir : FINCH_PLUGINDIR)
-
 gntlastlog = library('gntlastlog', 'lastlog.c',
     c_args : ['-DG_LOG_USE_STRUCTURED', '-DG_LOG_DOMAIN="Gnt-LastLog"'],
     dependencies : [libpurple_dep, libfinch_dep, ncurses, glib],
diff --git a/libpurple/account.h b/libpurple/account.h
--- a/libpurple/account.h
+++ b/libpurple/account.h
@@ -56,7 +56,7 @@
 
 #include "buddy.h"
 #include "connection.h"
-#include "log.h"
+#include "group.h"
 #include "proxy.h"
 #include "protocol.h"
 #include "status.h"
@@ -1041,31 +1041,6 @@
 gboolean purple_account_get_ui_bool(PurpleAccount *account, const char *ui,
 								  const char *name, gboolean default_value);
 
-
-/**
- * purple_account_get_log:
- * @account: The account.
- * @create:  Should it be created if it doesn't exist?
- *
- * Returns the system log for an account.
- *
- * Note: Callers should almost always pass %FALSE for @a create.
- *       Passing %TRUE could result in an existing log being reopened,
- *       if the log has already been closed, which not all loggers deal
- *       with appropriately.
- *
- * Returns: The log.
- */
-PurpleLog *purple_account_get_log(PurpleAccount *account, gboolean create);
-
-/**
- * purple_account_destroy_log:
- * @account: The account.
- *
- * Frees the system log of an account
- */
-void purple_account_destroy_log(PurpleAccount *account);
-
 /**
  * purple_account_add_buddy:
  * @account: The account.
diff --git a/libpurple/account.c b/libpurple/account.c
--- a/libpurple/account.c
+++ b/libpurple/account.c
@@ -92,7 +92,6 @@
 	GList *status_types;        /* Status types.                          */
 
 	PurplePresence *presence;     /* Presence.                            */
-	PurpleLog *system_log;        /* The system log                       */
 
 	PurpleAccountRegistrationCb registration_cb;
 	void *registration_cb_user_data;
@@ -976,7 +975,6 @@
 			g_free, delete_setting);
 	priv->ui_settings = g_hash_table_new_full(g_str_hash, g_str_equal,
 			g_free, (GDestroyNotify)g_hash_table_destroy);
-	priv->system_log = NULL;
 
 	priv->privacy_type = PURPLE_ACCOUNT_PRIVACY_ALLOW_ALL;
 }
@@ -1075,9 +1073,6 @@
 	if (priv->proxy_info)
 		purple_proxy_info_destroy(priv->proxy_info);
 
-	if(priv->system_log)
-		purple_log_free(priv->system_log);
-
 	if (priv->current_error) {
 		g_free(priv->current_error->description);
 		g_free(priv->current_error);
@@ -2730,52 +2725,6 @@
 	return g_value_get_boolean(&setting->value);
 }
 
-PurpleLog *
-purple_account_get_log(PurpleAccount *account, gboolean create)
-{
-	PurpleAccountPrivate *priv;
-
-	g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
-
-	priv = purple_account_get_instance_private(account);
-
-	if(!priv->system_log && create){
-		PurplePresence *presence;
-		int login_time;
-		GDateTime *dt;
-
-		presence = purple_account_get_presence(account);
-		login_time = purple_presence_get_login_time(presence);
-		if (login_time != 0) {
-			dt = g_date_time_new_from_unix_local(login_time);
-		} else {
-			dt = g_date_time_new_now_local();
-		}
-
-		priv->system_log = purple_log_new(PURPLE_LOG_SYSTEM,
-		                                  purple_account_get_username(account),
-		                                  account, NULL, dt);
-		g_date_time_unref(dt);
-	}
-
-	return priv->system_log;
-}
-
-void
-purple_account_destroy_log(PurpleAccount *account)
-{
-	PurpleAccountPrivate *priv;
-
-	g_return_if_fail(PURPLE_IS_ACCOUNT(account));
-
-	priv = purple_account_get_instance_private(account);
-
-	if(priv->system_log){
-		purple_log_free(priv->system_log);
-		priv->system_log = NULL;
-	}
-}
-
 void
 purple_account_add_buddy(PurpleAccount *account, PurpleBuddy *buddy, const char *message)
 {
diff --git a/libpurple/buddyicon.h b/libpurple/buddyicon.h
--- a/libpurple/buddyicon.h
+++ b/libpurple/buddyicon.h
@@ -53,6 +53,7 @@
 typedef struct _PurpleBuddyIconSpec PurpleBuddyIconSpec;
 
 #include "account.h"
+#include "blistnode.h"
 #include "buddylist.h"
 #include "image.h"
 #include "protocols.h"
diff --git a/libpurple/buddylist.c b/libpurple/buddylist.c
--- a/libpurple/buddylist.c
+++ b/libpurple/buddylist.c
@@ -24,6 +24,7 @@
 #include <glib/gi18n-lib.h>
 
 #include "internal.h"
+#include "account.h"
 #include "buddylist.h"
 #include "debug.h"
 #include "notify.h"
diff --git a/libpurple/connection.c b/libpurple/connection.c
--- a/libpurple/connection.c
+++ b/libpurple/connection.c
@@ -27,7 +27,6 @@
 #include "buddylist.h"
 #include "connection.h"
 #include "debug.h"
-#include "log.h"
 #include "notify.h"
 #include "prefs.h"
 #include "proxy.h"
@@ -201,23 +200,6 @@
 		/* Set the time the account came online */
 		purple_presence_set_login_time(presence, time(NULL));
 
-		if (purple_prefs_get_bool("/purple/logging/log_system"))
-		{
-			PurpleLog *log = purple_account_get_log(account, TRUE);
-
-			if (log != NULL)
-			{
-				char *msg = g_strdup_printf(_("+++ %s signed on"),
-											purple_account_get_username(account));
-				GDateTime *dt = g_date_time_new_from_unix_local(purple_presence_get_login_time(presence));
-				purple_log_write(log, PURPLE_MESSAGE_SYSTEM,
-				                 purple_account_get_username(account),
-				                 dt, msg);
-				g_date_time_unref(dt);
-				g_free(msg);
-			}
-		}
-
 		if (ops != NULL && ops->connected != NULL)
 			ops->connected(gc);
 
@@ -244,27 +226,6 @@
 		}
 	}
 	else if (priv->state == PURPLE_CONNECTION_DISCONNECTED) {
-		PurpleAccount *account = purple_connection_get_account(gc);
-
-		if (purple_prefs_get_bool("/purple/logging/log_system"))
-		{
-			PurpleLog *log = purple_account_get_log(account, FALSE);
-
-			if (log != NULL)
-			{
-				char *msg = g_strdup_printf(_("+++ %s signed off"),
-											purple_account_get_username(account));
-				GDateTime *dt = g_date_time_new_now_utc();
-				purple_log_write(log, PURPLE_MESSAGE_SYSTEM,
-				                 purple_account_get_username(account),
-				                 dt, msg);
-				g_date_time_unref(dt);
-				g_free(msg);
-			}
-		}
-
-		purple_account_destroy_log(account);
-
 		if (ops != NULL && ops->disconnected != NULL)
 			ops->disconnected(gc);
 	}
diff --git a/libpurple/conversations.c b/libpurple/conversations.c
--- a/libpurple/conversations.c
+++ b/libpurple/conversations.c
@@ -20,6 +20,8 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
 #include "internal.h"
+
+#include "conversations.h"
 #include "purpleprivate.h"
 
 #include "purpleconversationmanager.h"
diff --git a/libpurple/core.c b/libpurple/core.c
--- a/libpurple/core.c
+++ b/libpurple/core.c
@@ -24,6 +24,7 @@
 #include "internal.h"
 #include "cmds.h"
 #include "connection.h"
+#include "conversations.h"
 #include "core.h"
 #include "debug.h"
 #include "xfer.h"
@@ -169,7 +170,6 @@
 	purple_conversation_manager_startup();
 	purple_whiteboard_manager_startup();
 	purple_blist_init();
-	purple_log_init();
 	purple_history_manager_startup();
 	purple_network_init();
 	purple_proxy_init();
@@ -249,7 +249,6 @@
 
 	purple_history_manager_shutdown();
 
-	purple_log_uninit();
 	/* Everything after util_uninit cannot try to write things to the
 	 * confdir.
 	 */
@@ -365,7 +364,6 @@
 	xdg_dir_exists = g_file_test(purple_data_dir(), G_FILE_TEST_EXISTS);
 	if (!xdg_dir_exists) {
 		MIGRATE_TO_XDG_DIR(purple_data_dir(), "certificates");
-		MIGRATE_TO_XDG_DIR(purple_data_dir(), "logs");
 		MIGRATE_TO_XDG_DIR(purple_config_dir(), "accounts.xml");
 		MIGRATE_TO_XDG_DIR(purple_config_dir(), "blist.xml");
 		MIGRATE_TO_XDG_DIR(purple_config_dir(), "fs-codec.conf");
diff --git a/libpurple/idle.c b/libpurple/idle.c
--- a/libpurple/idle.c
+++ b/libpurple/idle.c
@@ -22,10 +22,10 @@
  */
 
 #include "connection.h"
+#include "conversations.h"
 #include "debug.h"
 #include "eventloop.h"
 #include "idle.h"
-#include "log.h"
 #include "prefs.h"
 #include "savedstatuses.h"
 #include "signals.h"
diff --git a/libpurple/log.h b/libpurple/log.h
deleted file mode 100644
--- a/libpurple/log.h
+++ /dev/null
@@ -1,665 +0,0 @@
-/* purple
- *
- * Purple 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
- */
-
-#if !defined(PURPLE_GLOBAL_HEADER_INSIDE) && !defined(PURPLE_COMPILATION)
-# error "only <purple.h> may be included directly"
-#endif
-
-#ifndef PURPLE_LOG_H
-#define PURPLE_LOG_H
-/**
- * SECTION:log
- * @section_id: libpurple-log
- * @short_description: <filename>log.h</filename>
- * @title: Logging API
- * @see_also: <link linkend="chapter-signals-log">Log signals</link>
- */
-
-#include <stdio.h>
-
-#define PURPLE_TYPE_LOG  (purple_log_get_type())
-
-/********************************************************
- * DATA STRUCTURES **************************************
- ********************************************************/
-
-typedef struct _PurpleLog PurpleLog;
-typedef struct _PurpleLogLogger PurpleLogLogger;
-typedef struct _PurpleLogCommonLoggerData PurpleLogCommonLoggerData;
-typedef struct _PurpleLogSet PurpleLogSet;
-
-/**
- * PurpleLogType:
- * @PURPLE_LOG_IM: Indicates an IM conversation.
- * @PURPLE_LOG_CHAT: Indicates a chat.
- * @PURPLE_LOG_SYSTEM: Indicates a server log.
- *
- * The individual types of logs.
- */
-typedef enum {
-	PURPLE_LOG_IM,
-	PURPLE_LOG_CHAT,
-	PURPLE_LOG_SYSTEM
-} PurpleLogType;
-
-/**
- * PurpleLogReadFlags:
- * @PURPLE_LOG_READ_NO_NEWLINE: Defines that newlines should be ignored.
- *
- * Flags that should be used when reading a log.
- */
-typedef enum {
-	PURPLE_LOG_READ_NO_NEWLINE = 1
-} PurpleLogReadFlags;
-
-#include "account.h"
-#include "conversations.h"
-
-typedef void (*PurpleLogSetCallback) (GHashTable *sets, PurpleLogSet *set);
-
-/**
- * PurpleLogLogger:
- * @name:         The logger's name
- * @id:           An identifier to refer to this logger
- * @create:       This gets called when the log is first created. I don't think
- *                this is actually needed.
- * @write:        This is used to write to the log file
- * @finalize:     Called when the log is destroyed
- * @list:         This function returns a sorted #GList of available PurpleLogs
- * @read:         Given one of the logs returned by the logger's list function,
- *                this returns the contents of the log
- * @size:         Given one of the logs returned by the logger's list function,
- *                this returns the size of the log in bytes
- * @total_size:   Returns the total size of all the logs. If this is undefined a
- *                default implementation is used
- * @list_syslog:  This function returns a sorted #GList of available system
- *                #PurpleLog's
- * @get_log_sets: Adds #PurpleLogSet's to a #GHashTable. By passing the data in
- *                the #PurpleLogSet's to list, the caller can get every
- *                available #PurpleLog from the logger. Loggers using
- *                purple_log_common_writer() (or otherwise storing their logs in
- *                the same directory structure as the stock loggers) do not
- *                need to implement this function.
- *                <sbr/>Loggers which implement this function must create a
- *                #PurpleLogSet, then call @cb with @sets and the newly created
- *                #PurpleLogSet.
- * @remove:       Attempts to delete the specified log, indicating success or
- *                failure
- * @is_deletable: Tests whether a log is deletable
- *
- * A log logger.
- *
- * This struct gets filled out and is included in the PurpleLog.  It contains
- * everything needed to write and read from logs.
- */
-struct _PurpleLogLogger {
-	char *name;
-	char *id;
-
-	void (*create)(PurpleLog *log);
-
-	gsize (*write)(PurpleLog *log,
-		     PurpleMessageFlags type,
-		     const char *from,
-		     GDateTime *time,
-		     const char *message);
-
-	void (*finalize)(PurpleLog *log);
-
-	GList *(*list)(PurpleLogType type, const char *name, PurpleAccount *account);
-
-	char *(*read)(PurpleLog *log, PurpleLogReadFlags *flags);
-
-	int (*size)(PurpleLog *log);
-
-	int (*total_size)(PurpleLogType type, const char *name, PurpleAccount *account);
-
-	GList *(*list_syslog)(PurpleAccount *account);
-
-	void (*get_log_sets)(PurpleLogSetCallback cb, GHashTable *sets);
-
-	gboolean (*remove)(PurpleLog *log);
-
-	gboolean (*is_deletable)(PurpleLog *log);
-
-	/*< private >*/
-	void (*_purple_reserved1)(void);
-	void (*_purple_reserved2)(void);
-	void (*_purple_reserved3)(void);
-	void (*_purple_reserved4)(void);
-};
-
-/**
- * PurpleLog:
- * @type:        The type of log this is
- * @name:        The name of this log
- * @account:     The account this log is taking place on
- * @conv:        The conversation being logged
- * @time:        The time this conversation started, converted to the local
- *               timezone
- * @logger:      The logging mechanism this log is to use
- * @logger_data: Data used by the log logger
- *
- * A log.  Not the wooden type.
- */
-struct _PurpleLog {
-	PurpleLogType type;
-	char *name;
-	PurpleAccount *account;
-	PurpleConversation *conv;
-	GDateTime *time;
-
-	PurpleLogLogger *logger;
-	void *logger_data;
-
-	/* IMPORTANT: Some code in log.c allocates these without zeroing them.
-	 * IMPORTANT: Update that code if you add members here. */
-};
-
-/**
- * PurpleLogCommonLoggerData:
- * @path: The path to the file.
- * @file: The pointer to the open file handle.
- * @extra_data: User supplied data.
- *
- * A common logger_data struct containing a file handle and path, as well
- * as a pointer to something else for additional data.
- */
-struct _PurpleLogCommonLoggerData {
-	char *path;
-	FILE *file;
-	void *extra_data;
-};
-
-/**
- * PurpleLogSet:
- * @type:            The type of logs available
- * @name:            The name of the logs available
- * @account:         The account the available logs took place on. This will be
- *                   %NULL if the account no longer exists. (Depending on a
- *                   logger's implementation of list, it may not be possible to
- *                   load such logs.)
- * @buddy:           Is this (account, name) a buddy on the buddy list?
- * @normalized_name: The normalized version of @name. It must be set, and may
- *                   be set to the same pointer value as @name.
- *
- * Describes available logs.
- *
- * By passing the elements of this struct to purple_log_get_logs(), the caller
- * can get all available PurpleLogs.
- */
-struct _PurpleLogSet {
-	PurpleLogType type;
-	char *name;
-	PurpleAccount *account;
-	gboolean buddy;
-	char *normalized_name;
-
-	/* IMPORTANT: Some code in log.c allocates these without zeroing them.
-	 * IMPORTANT: Update that code if you add members here. */
-};
-
-G_BEGIN_DECLS
-
-/***************************************/
-/* Log Functions                       */
-/***************************************/
-
-/**
- * purple_log_get_type:
- *
- * Returns: The #GType for the #PurpleLog boxed structure.
- */
-/* TODO Boxing of PurpleLog is a temporary solution to having a GType for
- *      logs. This should rather be a GObject instead of a GBoxed.
- */
-GType purple_log_get_type(void);
-
-/**
- * purple_log_new:
- * @type:        The type of log this is.
- * @name:        The name of this conversation (buddy name, chat name,
- *                    etc.)
- * @account:     The account the conversation is occurring on
- * @conv:        The conversation being logged
- * @time:        The time this conversation started
- *
- * Creates a new log
- *
- * Returns:            The new log
- */
-PurpleLog *purple_log_new(PurpleLogType type, const char *name, PurpleAccount *account,
-                      PurpleConversation *conv, GDateTime *time);
-
-/**
- * purple_log_free:
- * @log:         The log to destroy
- *
- * Frees a log
- */
-void purple_log_free(PurpleLog *log);
-
-/**
- * purple_log_write:
- * @log:          The log to write to
- * @type:         The type of message being logged
- * @from:         Whom this message is coming from, or %NULL for
- *                     system messages
- * @time:         A timestamp in UNIX time
- * @message:      The message to log
- *
- * Writes to a log file. Assumes you have checked preferences already.
- */
-void purple_log_write(PurpleLog *log,
-		    PurpleMessageFlags type,
-		    const char *from,
-		    GDateTime *time,
-		    const char *message);
-
-/**
- * purple_log_read:
- * @log:   The log to read from
- * @flags: The returned logging flags.
- *
- * Reads from a log
- *
- * Returns: The contents of this log in Purple Markup.
- */
-char *purple_log_read(PurpleLog *log, PurpleLogReadFlags *flags);
-
-/**
- * purple_log_get_logs:
- * @type:                The type of the log
- * @name:                The name of the log
- * @account:             The account
- *
- * Returns a list of all available logs
- *
- * Returns: (element-type PurpleLog) (transfer full): A sorted list of logs.
- */
-GList *purple_log_get_logs(PurpleLogType type, const char *name, PurpleAccount *account);
-
-/**
- * purple_log_get_log_sets:
- *
- * Returns a GHashTable of PurpleLogSets.
- *
- * A "log set" here means the information necessary to gather the
- * PurpleLogs for a given buddy/chat. This information would be passed
- * to purple_log_list to get a list of PurpleLogs.
- *
- * The primary use of this function is to get a list of everyone the
- * user has ever talked to (assuming he or she uses logging).
- *
- * The GHashTable that's returned will free all log sets in it when
- * destroyed. If a PurpleLogSet is removed from the GHashTable, it
- * must be freed with purple_log_set_free().
- *
- * Returns: (element-type PurpleLogSet PurpleLogSet) (transfer full): All
- *          available unique log sets.
- */
-GHashTable *purple_log_get_log_sets(void);
-
-/**
- * purple_log_get_system_logs:
- * @account: The account
- *
- * Returns a list of all available system logs
- *
- * Returns: (element-type PurpleLog) (transfer full): A sorted list of logs.
- */
-GList *purple_log_get_system_logs(PurpleAccount *account);
-
-/**
- * purple_log_get_size:
- * @log:                 The log
- *
- * Returns the size of a log
- *
- * Returns:                    The size of the log, in bytes
- */
-int purple_log_get_size(PurpleLog *log);
-
-/**
- * purple_log_get_total_size:
- * @type:                The type of the log
- * @name:                The name of the log
- * @account:             The account
- *
- * Returns the size, in bytes, of all available logs in this conversation
- *
- * Returns:                    The size in bytes
- */
-int purple_log_get_total_size(PurpleLogType type, const char *name, PurpleAccount *account);
-
-/**
- * purple_log_get_activity_score:
- * @type:                The type of the log
- * @name:                The name of the log
- * @account:             The account
- *
- * Returns the activity score of a log, based on total size in bytes,
- * which is then decayed based on age
- *
- * Returns:                    The activity score
- */
-int purple_log_get_activity_score(PurpleLogType type, const char *name, PurpleAccount *account);
-
-/**
- * purple_log_is_deletable:
- * @log:                 The log
- *
- * Tests whether a log is deletable
- *
- * A return value of %FALSE indicates that purple_log_delete() will fail on this
- * log, unless something changes between the two calls.  A return value of %TRUE,
- * however, does not guarantee the log can be deleted.
- *
- * Returns:                    A boolean indicating if the log is deletable
- */
-gboolean purple_log_is_deletable(PurpleLog *log);
-
-/**
- * purple_log_delete:
- * @log:                 The log
- *
- * Deletes a log
- *
- * Returns:                    A boolean indicating success or failure
- */
-gboolean purple_log_delete(PurpleLog *log);
-
-/**
- * purple_log_get_log_dir:
- * @type:                The type of the log.
- * @name:                The name of the log.
- * @account:             The account.
- *
- * Returns the default logger directory Purple uses for a given account
- * and username.  This would be where Purple stores logs created by
- * the built-in text or HTML loggers.
- *
- * Returns:                    The default logger directory for Purple.
- */
-char *purple_log_get_log_dir(PurpleLogType type, const char *name, PurpleAccount *account);
-
-/**
- * purple_log_compare:
- * @y:                   A PurpleLog
- * @z:                   Another PurpleLog
- *
- * Implements GCompareFunc for PurpleLogs
- *
- * Returns:                    A value as specified by GCompareFunc
- */
-gint purple_log_compare(gconstpointer y, gconstpointer z);
-
-/**
- * purple_log_set_compare:
- * @y:                   A PurpleLogSet
- * @z:                   Another PurpleLogSet
- *
- * Implements GCompareFunc for PurpleLogSets
- *
- * Returns:                    A value as specified by GCompareFunc
- */
-gint purple_log_set_compare(gconstpointer y, gconstpointer z);
-
-/**
- * purple_log_set_free:
- * @set:         The log set to destroy
- *
- * Frees a log set
- */
-void purple_log_set_free(PurpleLogSet *set);
-
-/******************************************/
-/* Common Logger Functions                */
-/******************************************/
-
-/**
- * purple_log_common_writer:
- * @log:   The log to write to.
- * @ext:   The file extension to give to this log file.
- *
- * Opens a new log file in the standard Purple log location
- * with the given file extension, named for the current time,
- * for writing.  If a log file is already open, the existing
- * file handle is retained.  The log's logger_data value is
- * set to a PurpleLogCommonLoggerData struct containing the log
- * file handle and log path.
- *
- * This function is intended to be used as a "common"
- * implementation of a logger's <literal>write</literal> function.
- * It should only be passed to purple_log_logger_new() and never
- * called directly.
- */
-void purple_log_common_writer(PurpleLog *log, const char *ext);
-
-/**
- * purple_log_common_lister:
- * @type:     The type of the logs being listed.
- * @name:     The name of the log.
- * @account:  The account of the log.
- * @ext:      The file extension this log format uses.
- * @logger:   A reference to the logger struct for this log.
- *
- * Returns a sorted list of logs of the requested type.
- *
- * This function should only be used with logs that are written
- * with purple_log_common_writer().  It's intended to be used as
- * a "common" implementation of a logger's <literal>list</literal> function.
- * It should only be passed to purple_log_logger_new() and never
- * called directly.
- *
- * Returns: (element-type PurpleLog) (transfer full): A sorted list of logs
- *          matching the parameters.
- */
-GList *purple_log_common_lister(PurpleLogType type, const char *name,
-							  PurpleAccount *account, const char *ext,
-							  PurpleLogLogger *logger);
-
-/**
- * purple_log_common_total_sizer:
- * @type:     The type of the logs being sized.
- * @name:     The name of the logs to size
- *                 (e.g. the username or chat name).
- * @account:  The account of the log.
- * @ext:      The file extension this log format uses.
- *
- * Returns the total size of all the logs for a given user, with
- * a given extension.
- *
- * This function should only be used with logs that are written
- * with purple_log_common_writer().  It's intended to be used as
- * a "common" implementation of a logger's <literal>total_size</literal>
- * function. It should only be passed to purple_log_logger_new() and never
- * called directly.
- *
- * Returns: The size of all the logs with the specified extension
- *         for the specified user.
- */
-int purple_log_common_total_sizer(PurpleLogType type, const char *name,
-								PurpleAccount *account, const char *ext);
-
-/**
- * purple_log_common_sizer:
- * @log:      The PurpleLog to size.
- *
- * Returns the size of a given PurpleLog.
- *
- * This function should only be used with logs that are written
- * with purple_log_common_writer().  It's intended to be used as
- * a "common" implementation of a logger's <literal>size</literal> function.
- * It should only be passed to purple_log_logger_new() and never
- * called directly.
- *
- * Returns: An integer indicating the size of the log in bytes.
- */
-int purple_log_common_sizer(PurpleLog *log);
-
-/**
- * purple_log_common_deleter:
- * @log:      The PurpleLog to delete.
- *
- * Deletes a log
- *
- * This function should only be used with logs that are written
- * with purple_log_common_writer().  It's intended to be used as
- * a "common" implementation of a logger's <literal>delete</literal> function.
- * It should only be passed to purple_log_logger_new() and never
- * called directly.
- *
- * Returns: A boolean indicating success or failure.
- */
-gboolean purple_log_common_deleter(PurpleLog *log);
-
-/**
- * purple_log_common_is_deletable:
- * @log:      The PurpleLog to check.
- *
- * Checks to see if a log is deletable
- *
- * This function should only be used with logs that are written
- * with purple_log_common_writer().  It's intended to be used as
- * a "common" implementation of a logger's <literal>is_deletable</literal>
- * function. It should only be passed to purple_log_logger_new() and never
- * called directly.
- *
- * Returns: A boolean indicating if the log is deletable.
- */
-gboolean purple_log_common_is_deletable(PurpleLog *log);
-
-/******************************************/
-/* Logger Functions                       */
-/******************************************/
-
-/**
- * purple_log_logger_new:
- * @id:           The logger's id.
- * @name:         The logger's name.
- * @functions:    The number of functions being passed. The following
- *                functions are currently available (in order):
- *                <literal>create</literal>, <literal>write</literal>,
- *                <literal>finalize</literal>, <literal>list</literal>,
- *                <literal>read</literal>, <literal>size</literal>,
- *                <literal>total_size</literal>, <literal>list_syslog</literal>,
- *                <literal>get_log_sets</literal>, <literal>remove</literal>,
- *                <literal>is_deletable</literal>.
- *                For details on these functions, see PurpleLogLogger.
- *                Functions may not be skipped. For example, passing
- *                <literal>create</literal> and <literal>write</literal> is
- *                acceptable (for a total of two functions). Passing
- *                <literal>create</literal> and <literal>finalize</literal>,
- *                however, is not. To accomplish that, the caller must pass
- *                <literal>create</literal>, %NULL (a placeholder for
- *                <literal>write</literal>), and <literal>finalize</literal>
- *                (for a total of 3 functions).
- * @...: The functions used to log.
- *
- * Creates a new logger
- *
- * Returns: (transfer full): The new logger.
- */
-PurpleLogLogger *purple_log_logger_new(const char *id, const char *name, int functions, ...);
-
-/**
- * purple_log_logger_free:
- * @logger:       The logger to free
- *
- * Frees a logger
- */
-void purple_log_logger_free(PurpleLogLogger *logger);
-
-/**
- * purple_log_logger_add:
- * @logger:       The new logger to add
- *
- * Adds a new logger
- */
-void purple_log_logger_add (PurpleLogLogger *logger);
-
-/**
- * purple_log_logger_remove:
- * @logger:       The logger to remove
- *
- * Removes a logger
- */
-void purple_log_logger_remove (PurpleLogLogger *logger);
-
-/**
- * purple_log_logger_set:
- * @logger:       The logger to set
- *
- * Sets the current logger
- */
-void purple_log_logger_set (PurpleLogLogger *logger);
-
-/**
- * purple_log_logger_get:
- *
- * Returns the current logger
- *
- * Returns: (transfer none): The current logger.
- */
-PurpleLogLogger *purple_log_logger_get(void);
-
-/**
- * purple_log_logger_get_options:
- *
- * Returns a GList containing the IDs and names of the registered
- * loggers.
- *
- * Returns: (element-type utf8) (transfer container): The list of IDs and names.
- */
-GList *purple_log_logger_get_options(void);
-
-/**************************************************************************/
-/* Log Subsystem                                                          */
-/**************************************************************************/
-
-/**
- * purple_log_init:
- *
- * Initializes the log subsystem.
- */
-void purple_log_init(void);
-
-/**
- * purple_log_get_handle:
- *
- * Returns the log subsystem handle.
- *
- * Returns: The log subsystem handle.
- */
-void *purple_log_get_handle(void);
-
-/**
- * purple_log_uninit:
- *
- * Uninitializes the log subsystem.
- */
-void purple_log_uninit(void);
-
-
-G_END_DECLS
-
-#endif /* PURPLE_LOG_H */
diff --git a/libpurple/log.c b/libpurple/log.c
deleted file mode 100644
--- a/libpurple/log.c
+++ /dev/null
@@ -1,1457 +0,0 @@
-/* purple
- *
- * Purple 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 <glib/gi18n-lib.h>
-
-#include "internal.h"
-
-#include <glib.h>
-#include <glib/gstdio.h>
-
-#include "glibcompat.h" /* for purple_g_stat on win32 */
-
-#include "account.h"
-#include "debug.h"
-#include "image-store.h"
-#include "log.h"
-#include "prefs.h"
-#include "purplemarkup.h"
-#include "time.h"
-
-static GSList *loggers = NULL;
-
-static PurpleLogLogger *html_logger;
-static PurpleLogLogger *txt_logger;
-
-static GHashTable *logsize_users = NULL;
-static GHashTable *logsize_users_decayed = NULL;
-
-static void log_get_log_sets_common(GHashTable *sets);
-
-static gsize html_logger_write(PurpleLog *log, PurpleMessageFlags type,
-                               const char *from, GDateTime *time, const char *message);
-static void html_logger_finalize(PurpleLog *log);
-static GList *html_logger_list(PurpleLogType type, const char *sn, PurpleAccount *account);
-static GList *html_logger_list_syslog(PurpleAccount *account);
-static char *html_logger_read(PurpleLog *log, PurpleLogReadFlags *flags);
-static int html_logger_total_size(PurpleLogType type, const char *name, PurpleAccount *account);
-
-static gsize txt_logger_write(PurpleLog *log, PurpleMessageFlags type,
-                              const char *from, GDateTime *time, const char *message);
-static void txt_logger_finalize(PurpleLog *log);
-static GList *txt_logger_list(PurpleLogType type, const char *sn, PurpleAccount *account);
-static GList *txt_logger_list_syslog(PurpleAccount *account);
-static char *txt_logger_read(PurpleLog *log, PurpleLogReadFlags *flags);
-static int txt_logger_total_size(PurpleLogType type, const char *name, PurpleAccount *account);
-
-/**************************************************************************
- * PUBLIC LOGGING FUNCTIONS ***********************************************
- **************************************************************************/
-
-PurpleLog *purple_log_new(PurpleLogType type, const char *name, PurpleAccount *account,
-                      PurpleConversation *conv, GDateTime *time)
-{
-	PurpleLog *log;
-
-	/* IMPORTANT: Make sure to initialize all the members of PurpleLog */
-	log = g_slice_new(PurpleLog);
-
-	log->type = type;
-	log->name = g_strdup(purple_normalize(account, name));
-	log->account = account;
-	log->conv = conv;
-	if (time)
-		log->time = g_date_time_ref(time);
-	else
-		log->time = NULL;
-	log->logger = purple_log_logger_get();
-	log->logger_data = NULL;
-
-	if (log->logger && log->logger->create)
-		log->logger->create(log);
-	return log;
-}
-
-void purple_log_free(PurpleLog *log)
-{
-	g_return_if_fail(log);
-	if (log->logger && log->logger->finalize)
-		log->logger->finalize(log);
-	g_free(log->name);
-	if (log->time)
-		g_date_time_unref(log->time);
-
-	g_slice_free(PurpleLog, log);
-}
-
-void purple_log_write(PurpleLog *log, PurpleMessageFlags type,
-                      const char *from, GDateTime *time, const char *message)
-{
-	PurpleKeyValuePair *lu;
-	gsize written, total = 0;
-	gpointer ptrsize;
-
-	g_return_if_fail(log);
-	g_return_if_fail(log->logger);
-	g_return_if_fail(log->logger->write);
-
-	written = (log->logger->write)(log, type, from, time, message);
-
-	lu = purple_key_value_pair_new(purple_normalize(log->account, log->name), log->account);
-
-	if(g_hash_table_lookup_extended(logsize_users, lu, NULL, &ptrsize)) {
-		total = GPOINTER_TO_INT(ptrsize);
-		total += written;
-		g_hash_table_replace(logsize_users, lu, GINT_TO_POINTER(total));
-
-		/* The hash table takes ownership of lu, so create a new one
-		 * for the logsize_users_decayed check below. */
-		lu = purple_key_value_pair_new(lu->key, log->account);
-	}
-
-	if(g_hash_table_lookup_extended(logsize_users_decayed, lu, NULL, &ptrsize)) {
-		total = GPOINTER_TO_INT(ptrsize);
-		total += written;
-		g_hash_table_replace(logsize_users_decayed, lu, GINT_TO_POINTER(total));
-	} else {
-		purple_key_value_pair_free(lu);
-	}
-}
-
-char *purple_log_read(PurpleLog *log, PurpleLogReadFlags *flags)
-{
-	PurpleLogReadFlags mflags;
-	g_return_val_if_fail(log && log->logger, NULL);
-	if (log->logger->read) {
-		char *ret = (log->logger->read)(log, flags ? flags : &mflags);
-		purple_str_strip_char(ret, '\r');
-		return ret;
-	}
-	return g_strdup(_("<b><font color=\"red\">The logger has no read function</font></b>"));
-}
-
-int purple_log_get_size(PurpleLog *log)
-{
-	g_return_val_if_fail(log && log->logger, 0);
-
-	if (log->logger->size)
-		return log->logger->size(log);
-	return 0;
-}
-
-static guint
-_purple_logsize_user_hash(PurpleKeyValuePair *lu)
-{
-	return g_str_hash(lu->key);
-}
-
-static guint
-_purple_logsize_user_equal(PurpleKeyValuePair *lu1, PurpleKeyValuePair *lu2)
-{
-	return (lu1->value == lu2->value && purple_strequal(lu1->key, lu2->key));
-}
-
-int purple_log_get_total_size(PurpleLogType type, const char *name, PurpleAccount *account)
-{
-	gpointer ptrsize;
-	int size = 0;
-	GSList *n;
-	PurpleKeyValuePair *lu;
-
-	lu = purple_key_value_pair_new(purple_normalize(account, name), account);
-	if(g_hash_table_lookup_extended(logsize_users, lu, NULL, &ptrsize)) {
-		size = GPOINTER_TO_INT(ptrsize);
-		purple_key_value_pair_free(lu);
-	} else {
-		for (n = loggers; n; n = n->next) {
-			PurpleLogLogger *logger = n->data;
-
-			if(logger->total_size){
-				size += (logger->total_size)(type, name, account);
-			} else if(logger->list) {
-				GList *logs = (logger->list)(type, name, account);
-				int this_size = 0;
-
-				while (logs) {
-					PurpleLog *log = (PurpleLog*)(logs->data);
-					this_size += purple_log_get_size(log);
-					purple_log_free(log);
-					logs = g_list_delete_link(logs, logs);
-				}
-
-				size += this_size;
-			}
-		}
-
-		g_hash_table_replace(logsize_users, lu, GINT_TO_POINTER(size));
-	}
-	return size;
-}
-
-gint purple_log_get_activity_score(PurpleLogType type, const char *name, PurpleAccount *account)
-{
-	gpointer ptrscore;
-	int score;
-	GSList *n;
-	PurpleKeyValuePair *lu;
-
-	lu = purple_key_value_pair_new(purple_normalize(account, name), account);
-	if(g_hash_table_lookup_extended(logsize_users_decayed, lu, NULL, &ptrscore)) {
-		score = GPOINTER_TO_INT(ptrscore);
-		purple_key_value_pair_free(lu);
-	} else {
-		GDateTime *now = g_date_time_new_now_utc();
-		double score_double = 0.0;
-		for (n = loggers; n; n = n->next) {
-			PurpleLogLogger *logger = n->data;
-
-			if(logger->list) {
-				GList *logs = (logger->list)(type, name, account);
-
-				while (logs) {
-					PurpleLog *log = (PurpleLog*)(logs->data);
-					if (!log) {
-						g_warn_if_reached();
-						continue;
-					}
-					/* Activity score counts bytes in the log, exponentially
-					   decayed with a half-life of 14 days. */
-					score_double += purple_log_get_size(log) *
-						pow(0.5, g_date_time_difference(now, log->time)/(14LL*G_TIME_SPAN_DAY));
-					purple_log_free(log);
-					logs = g_list_delete_link(logs, logs);
-				}
-			}
-		}
-		g_date_time_unref(now);
-
-		score = (gint) ceil(score_double);
-		g_hash_table_replace(logsize_users_decayed, lu, GINT_TO_POINTER(score));
-	}
-	return score;
-}
-
-gboolean purple_log_is_deletable(PurpleLog *log)
-{
-	g_return_val_if_fail(log != NULL, FALSE);
-	g_return_val_if_fail(log->logger != NULL, FALSE);
-
-	if (log->logger->remove == NULL)
-		return FALSE;
-
-	if (log->logger->is_deletable != NULL)
-		return log->logger->is_deletable(log);
-
-	return TRUE;
-}
-
-gboolean purple_log_delete(PurpleLog *log)
-{
-	g_return_val_if_fail(log != NULL, FALSE);
-	g_return_val_if_fail(log->logger != NULL, FALSE);
-
-	if (log->logger->remove != NULL)
-		return log->logger->remove(log);
-
-	return FALSE;
-}
-
-char *
-purple_log_get_log_dir(PurpleLogType type, const char *name, PurpleAccount *account)
-{
-	PurpleProtocol *protocol;
-	const char *protocol_name;
-	char *acct_name;
-	const char *target;
-	char *dir;
-
-	protocol = purple_account_get_protocol(account);
-	if (!protocol)
-		return NULL;
-
-	protocol_name = purple_protocol_get_list_icon(protocol, account, NULL);
-
-	acct_name = g_strdup(purple_escape_filename(purple_normalize(account,
-				purple_account_get_username(account))));
-
-	if (type == PURPLE_LOG_CHAT) {
-		char *temp = g_strdup_printf("%s.chat", purple_normalize(account, name));
-		target = purple_escape_filename(temp);
-		g_free(temp);
-	} else if(type == PURPLE_LOG_SYSTEM) {
-		target = ".system";
-	} else {
-		target = purple_escape_filename(purple_normalize(account, name));
-	}
-
-	dir = g_build_filename(purple_data_dir(), "logs", protocol_name, acct_name, target, NULL);
-
-	g_free(acct_name);
-
-	return dir;
-}
-
-/****************************************************************************
- * LOGGER FUNCTIONS *********************************************************
- ****************************************************************************/
-
-static PurpleLogLogger *current_logger = NULL;
-
-static void logger_pref_cb(const char *name, PurplePrefType type,
-						   gconstpointer value, gpointer data)
-{
-	PurpleLogLogger *logger;
-	GSList *l = loggers;
-	while (l) {
-		logger = l->data;
-		if (purple_strequal(logger->id, value)) {
-			purple_log_logger_set(logger);
-			return;
-		}
-		l = l->next;
-	}
-	purple_log_logger_set(txt_logger);
-}
-
-
-PurpleLogLogger *purple_log_logger_new(const char *id, const char *name, int functions, ...)
-{
-	PurpleLogLogger *logger;
-	va_list args;
-
-	g_return_val_if_fail(id != NULL, NULL);
-	g_return_val_if_fail(name != NULL, NULL);
-	g_return_val_if_fail(functions >= 1, NULL);
-
-	logger = g_new0(PurpleLogLogger, 1);
-	logger->id = g_strdup(id);
-	logger->name = g_strdup(name);
-
-	va_start(args, functions);
-
-	if (functions >= 1)
-		logger->create = va_arg(args, void *);
-	if (functions >= 2)
-		logger->write = va_arg(args, void *);
-	if (functions >= 3)
-		logger->finalize = va_arg(args, void *);
-	if (functions >= 4)
-		logger->list = va_arg(args, void *);
-	if (functions >= 5)
-		logger->read = va_arg(args, void *);
-	if (functions >= 6)
-		logger->size = va_arg(args, void *);
-	if (functions >= 7)
-		logger->total_size = va_arg(args, void *);
-	if (functions >= 8)
-		logger->list_syslog = va_arg(args, void *);
-	if (functions >= 9)
-		logger->get_log_sets = va_arg(args, void *);
-	if (functions >= 10)
-		logger->remove = va_arg(args, void *);
-	if (functions >= 11)
-		logger->is_deletable = va_arg(args, void *);
-
-	if (functions >= 12)
-		purple_debug_info("log", "Dropping new functions for logger: %s (%s)\n", name, id);
-
-	va_end(args);
-
-	return logger;
-}
-
-void purple_log_logger_free(PurpleLogLogger *logger)
-{
-	if (!logger)
-		return;
-	g_free(logger->name);
-	g_free(logger->id);
-	g_free(logger);
-}
-
-void purple_log_logger_add (PurpleLogLogger *logger)
-{
-	g_return_if_fail(logger);
-	if (g_slist_find(loggers, logger))
-		return;
-	loggers = g_slist_append(loggers, logger);
-	if (purple_strequal(purple_prefs_get_string("/purple/logging/format"), logger->id)) {
-		purple_prefs_trigger_callback("/purple/logging/format");
-	}
-}
-
-void purple_log_logger_remove (PurpleLogLogger *logger)
-{
-	g_return_if_fail(logger);
-	loggers = g_slist_remove(loggers, logger);
-}
-
-void purple_log_logger_set (PurpleLogLogger *logger)
-{
-	g_return_if_fail(logger);
-	current_logger = logger;
-}
-
-PurpleLogLogger *purple_log_logger_get()
-{
-	return current_logger;
-}
-
-GList *purple_log_logger_get_options(void)
-{
-	GSList *n;
-	GList *list = NULL;
-	PurpleLogLogger *data;
-
-	for (n = loggers; n; n = n->next) {
-		data = n->data;
-		if (!data->write)
-			continue;
-		list = g_list_append(list, data->name);
-		list = g_list_append(list, data->id);
-	}
-
-	return list;
-}
-
-gint purple_log_compare(gconstpointer y, gconstpointer z)
-{
-	const PurpleLog *a = y;
-	const PurpleLog *b = z;
-
-	/* Sort in reverse order. */
-	return g_date_time_compare(b->time, a->time);
-}
-
-GList *purple_log_get_logs(PurpleLogType type, const char *name, PurpleAccount *account)
-{
-	GList *logs = NULL;
-	GSList *n;
-	for (n = loggers; n; n = n->next) {
-		PurpleLogLogger *logger = n->data;
-		if (!logger->list)
-			continue;
-		logs = g_list_concat(logger->list(type, name, account), logs);
-	}
-
-	return g_list_sort(logs, purple_log_compare);
-}
-
-gint purple_log_set_compare(gconstpointer y, gconstpointer z)
-{
-	const PurpleLogSet *a = y;
-	const PurpleLogSet *b = z;
-	gint ret = 0;
-
-	/* This logic seems weird at first...
-	 * If either account is NULL, we pretend the accounts are
-	 * equal. This allows us to detect duplicates that will
-	 * exist if one logger knows the account and another
-	 * doesn't. */
-	if (a->account != NULL && b->account != NULL) {
-		ret = strcmp(purple_account_get_username(a->account), purple_account_get_username(b->account));
-		if (ret != 0)
-			return ret;
-	}
-
-	ret = strcmp(a->normalized_name, b->normalized_name);
-	if (ret != 0)
-		return ret;
-
-	return (gint)b->type - (gint)a->type;
-}
-
-static guint
-log_set_hash(gconstpointer key)
-{
-	const PurpleLogSet *set = key;
-
-	/* The account isn't hashed because we need PurpleLogSets with NULL accounts
-	 * to be found when we search by a PurpleLogSet that has a non-NULL account
-	 * but the same type and name. */
-	return g_int_hash(&set->type) + g_str_hash(set->name);
-}
-
-static gboolean
-log_set_equal(gconstpointer a, gconstpointer b)
-{
-	/* I realize that the choices made for GList and GHashTable
-	 * make sense for those data types, but I wish the comparison
-	 * functions were compatible. */
-	return !purple_log_set_compare(a, b);
-}
-
-static void
-log_add_log_set_to_hash(GHashTable *sets, PurpleLogSet *set)
-{
-	PurpleLogSet *existing_set = g_hash_table_lookup(sets, set);
-
-	if (existing_set == NULL)
-		g_hash_table_insert(sets, set, set);
-	else if (existing_set->account == NULL && set->account != NULL)
-		g_hash_table_replace(sets, set, set);
-	else
-		purple_log_set_free(set);
-}
-
-GHashTable *purple_log_get_log_sets(void)
-{
-	GSList *n;
-	GHashTable *sets = g_hash_table_new_full(log_set_hash, log_set_equal,
-											 (GDestroyNotify)purple_log_set_free, NULL);
-
-	/* Get the log sets from all the loggers. */
-	for (n = loggers; n; n = n->next) {
-		PurpleLogLogger *logger = n->data;
-
-		if (!logger->get_log_sets)
-			continue;
-
-		logger->get_log_sets(log_add_log_set_to_hash, sets);
-	}
-
-	log_get_log_sets_common(sets);
-
-	/* Return the GHashTable of unique PurpleLogSets. */
-	return sets;
-}
-
-void purple_log_set_free(PurpleLogSet *set)
-{
-	g_return_if_fail(set != NULL);
-
-	g_free(set->name);
-	if (set->normalized_name != set->name)
-		g_free(set->normalized_name);
-
-	g_slice_free(PurpleLogSet, set);
-}
-
-GList *purple_log_get_system_logs(PurpleAccount *account)
-{
-	GList *logs = NULL;
-	GSList *n;
-	for (n = loggers; n; n = n->next) {
-		PurpleLogLogger *logger = n->data;
-		if (!logger->list_syslog)
-			continue;
-		logs = g_list_concat(logger->list_syslog(account), logs);
-	}
-
-	return g_list_sort(logs, purple_log_compare);
-}
-
-/****************************************************************************
- * LOG SUBSYSTEM ************************************************************
- ****************************************************************************/
-
-void *
-purple_log_get_handle(void)
-{
-	static int handle;
-
-	return &handle;
-}
-
-void purple_log_init(void)
-{
-	void *handle = purple_log_get_handle();
-
-	purple_prefs_add_none("/purple/logging");
-	purple_prefs_add_bool("/purple/logging/log_ims", TRUE);
-	purple_prefs_add_bool("/purple/logging/log_chats", TRUE);
-	purple_prefs_add_bool("/purple/logging/log_system", FALSE);
-
-	purple_prefs_add_string("/purple/logging/format", "html");
-
-	html_logger = purple_log_logger_new("html", _("HTML"), 11,
-									  NULL,
-									  html_logger_write,
-									  html_logger_finalize,
-									  html_logger_list,
-									  html_logger_read,
-									  purple_log_common_sizer,
-									  html_logger_total_size,
-									  html_logger_list_syslog,
-									  NULL,
-									  purple_log_common_deleter,
-									  purple_log_common_is_deletable);
-	purple_log_logger_add(html_logger);
-
-	txt_logger = purple_log_logger_new("txt", _("Plain text"), 11,
-									 NULL,
-									 txt_logger_write,
-									 txt_logger_finalize,
-									 txt_logger_list,
-									 txt_logger_read,
-									 purple_log_common_sizer,
-									 txt_logger_total_size,
-									 txt_logger_list_syslog,
-									 NULL,
-									 purple_log_common_deleter,
-									 purple_log_common_is_deletable);
-	purple_log_logger_add(txt_logger);
-
-	purple_signal_register(handle, "log-timestamp",
-			     purple_marshal_POINTER__POINTER_POINTER_BOOLEAN,
-	                     G_TYPE_STRING, 3,
-	                     PURPLE_TYPE_LOG,
-	                     G_TYPE_OBJECT,
-	                     G_TYPE_BOOLEAN);
-
-	purple_prefs_connect_callback(NULL, "/purple/logging/format",
-							    logger_pref_cb, NULL);
-	purple_prefs_trigger_callback("/purple/logging/format");
-
-	logsize_users = g_hash_table_new_full((GHashFunc)_purple_logsize_user_hash,
-	                                      (GEqualFunc)_purple_logsize_user_equal,
-	                                      (GDestroyNotify)purple_key_value_pair_free, NULL);
-	logsize_users_decayed = g_hash_table_new_full((GHashFunc)_purple_logsize_user_hash,
-	                                              (GEqualFunc)_purple_logsize_user_equal,
-	                                              (GDestroyNotify)purple_key_value_pair_free, NULL);
-}
-
-void
-purple_log_uninit(void)
-{
-	purple_signals_unregister_by_instance(purple_log_get_handle());
-
-	purple_log_logger_remove(html_logger);
-	purple_log_logger_free(html_logger);
-	html_logger = NULL;
-
-	purple_log_logger_remove(txt_logger);
-	purple_log_logger_free(txt_logger);
-	txt_logger = NULL;
-
-	g_hash_table_destroy(logsize_users);
-	g_hash_table_destroy(logsize_users_decayed);
-}
-
-static PurpleLog *
-purple_log_copy(PurpleLog *log)
-{
-	PurpleLog *log_copy;
-
-	g_return_val_if_fail(log != NULL, NULL);
-
-	log_copy = g_new(PurpleLog, 1);
-	*log_copy = *log;
-
-	return log_copy;
-}
-
-GType
-purple_log_get_type(void)
-{
-	static GType type = 0;
-
-	if (type == 0) {
-		type = g_boxed_type_register_static("PurpleLog",
-				(GBoxedCopyFunc)purple_log_copy,
-				(GBoxedFreeFunc)g_free);
-	}
-
-	return type;
-}
-
-/****************************************************************************
- * LOGGERS ******************************************************************
- ****************************************************************************/
-
-static char *log_get_timestamp(PurpleLog *log, GDateTime *when)
-{
-	gboolean show_date;
-	char *date;
-	GDateTime *dt;
-
-	dt = g_date_time_new_now_utc();
-	show_date = (log->type == PURPLE_LOG_SYSTEM) || (g_date_time_difference(dt, when) > 20L * G_TIME_SPAN_MINUTE);
-	g_date_time_unref(dt);
-
-	date = purple_signal_emit_return_1(purple_log_get_handle(),
-	                          "log-timestamp",
-	                          log, when, show_date);
-	if (date != NULL)
-		return date;
-
-	dt = g_date_time_to_local(when);
-	if (show_date)
-		date = g_date_time_format(dt, _("%x %X"));
-	else
-		date = g_date_time_format(dt, "%X");
-	g_date_time_unref(dt);
-
-	return date;
-}
-
-/* NOTE: This can return msg (which you may or may not want to g_free())
- * NOTE: or a newly allocated string which you MUST g_free().
- * TODO: XXX: does it really works?
- */
-static char *
-convert_image_tags(const PurpleLog *log, const char *msg)
-{
-	const char *tmp;
-	const char *start;
-	const char *end;
-	GData *attributes;
-	GString *newmsg = NULL;
-
-	tmp = msg;
-
-	while (purple_markup_find_tag("img", tmp, &start, &end, &attributes)) {
-		int imgid = 0;
-		char *idstr = NULL;
-
-		if (newmsg == NULL)
-			newmsg = g_string_new("");
-
-		/* copy any text before the img tag */
-		if (tmp < start)
-			g_string_append_len(newmsg, tmp, start - tmp);
-
-		if ((idstr = g_datalist_get_data(&attributes, "id")) != NULL)
-			imgid = atoi(idstr);
-
-		if (imgid != 0)
-		{
-			FILE *image_file;
-			char *dir;
-			PurpleImage *image;
-			gconstpointer image_data;
-			const gchar *new_filename = NULL;
-			char *path = NULL;
-			size_t image_byte_count;
-
-			image = purple_image_store_get(imgid);
-			if (image == NULL)
-			{
-				/* This should never happen. */
-				/* This *does* happen for failed Direct-IMs -DAA */
-				g_string_free(newmsg, TRUE);
-				g_return_val_if_reached((char *)msg);
-			}
-
-			image_data       = purple_image_get_data(image);
-			image_byte_count = purple_image_get_data_size(image);
-			dir              = purple_log_get_log_dir(log->type, log->name, log->account);
-			new_filename = purple_image_generate_filename(image);
-
-			path = g_build_filename(dir, new_filename, NULL);
-
-			/* Only save unique files. */
-			if (!g_file_test(path, G_FILE_TEST_EXISTS))
-			{
-				if ((image_file = g_fopen(path, "wb")) != NULL)
-				{
-					if (!fwrite(image_data, image_byte_count, 1, image_file))
-					{
-						purple_debug_error("log", "Error writing %s: %s\n",
-						                   path, g_strerror(errno));
-						fclose(image_file);
-
-						/* Attempt to not leave half-written files around. */
-						if (g_unlink(path)) {
-							purple_debug_error("log", "Error deleting partial "
-									"file %s: %s\n", path, g_strerror(errno));
-						}
-					}
-					else
-					{
-						purple_debug_info("log", "Wrote image file: %s\n", path);
-						fclose(image_file);
-					}
-				}
-				else
-				{
-					purple_debug_error("log", "Unable to create file %s: %s\n",
-					                   path, g_strerror(errno));
-				}
-			}
-
-			/* Write the new image tag */
-			g_string_append_printf(newmsg, "<img src=\"%s\">", new_filename);
-			g_free(path);
-			g_free(dir);
-		}
-
-		/* Continue from the end of the tag */
-		tmp = end + 1;
-	}
-
-	if (newmsg == NULL)
-	{
-		/* No images were found to change. */
-		return (char *)msg;
-	}
-
-	/* Append any remaining message data */
-	g_string_append(newmsg, tmp);
-
-	return g_string_free(newmsg, FALSE);
-}
-
-void purple_log_common_writer(PurpleLog *log, const char *ext)
-{
-	PurpleLogCommonLoggerData *data = log->logger_data;
-
-	if (data == NULL)
-	{
-		/* This log is new */
-		char *dir;
-		GDateTime *dt;
-		const char *tz;
-		gchar *date;
-		char *filename;
-		char *path;
-
-		dir = purple_log_get_log_dir(log->type, log->name, log->account);
-		if (dir == NULL)
-			return;
-
-		g_mkdir_with_parents(dir, S_IRUSR | S_IWUSR | S_IXUSR);
-
-		dt = g_date_time_to_local(log->time);
-		tz = purple_escape_filename(g_date_time_get_timezone_abbreviation(dt));
-		date = g_date_time_format(dt, "%Y-%m-%d.%H%M%S%z");
-		g_date_time_unref(dt);
-
-		filename = g_strdup_printf("%s%s%s", date, tz, ext ? ext : "");
-
-		path = g_build_filename(dir, filename, NULL);
-		g_free(dir);
-		g_free(date);
-		g_free(filename);
-
-		log->logger_data = data = g_slice_new0(PurpleLogCommonLoggerData);
-
-		data->file = g_fopen(path, "a");
-		if (data->file == NULL)
-		{
-			purple_debug_error("log", "Could not create log file %s", path);
-
-			if (log->conv != NULL)
-				purple_conversation_write_system_message(log->conv,
-					_("Logging of this conversation failed."),
-					PURPLE_MESSAGE_ERROR);
-
-			g_free(path);
-			return;
-		}
-		g_free(path);
-	}
-}
-
-GList *purple_log_common_lister(PurpleLogType type, const char *name, PurpleAccount *account, const char *ext, PurpleLogLogger *logger)
-{
-	GDir *dir;
-	GList *list = NULL;
-	const char *filename;
-	char *path;
-
-	if(!account)
-		return NULL;
-
-	path = purple_log_get_log_dir(type, name, account);
-	if (path == NULL)
-		return NULL;
-
-	if (!(dir = g_dir_open(path, 0, NULL)))
-	{
-		g_free(path);
-		return NULL;
-	}
-
-	while ((filename = g_dir_read_name(dir)))
-	{
-		if (g_str_has_suffix(filename, ext) &&
-		    strlen(filename) >= (17 + strlen(ext))) {
-			PurpleLog *log;
-			PurpleLogCommonLoggerData *data;
-			GDateTime *stamp = purple_str_to_date_time(purple_unescape_filename(filename), FALSE);
-
-			log = purple_log_new(type, name, account, NULL, stamp);
-			log->logger = logger;
-			log->logger_data = data = g_slice_new0(PurpleLogCommonLoggerData);
-
-			data->path = g_build_filename(path, filename, NULL);
-			list = g_list_prepend(list, log);
-
-			g_date_time_unref(stamp);
-		}
-	}
-	g_dir_close(dir);
-	g_free(path);
-	return list;
-}
-
-int purple_log_common_total_sizer(PurpleLogType type, const char *name, PurpleAccount *account, const char *ext)
-{
-	GDir *dir;
-	int size = 0;
-	const char *filename;
-	char *path;
-
-	if(!account)
-		return 0;
-
-	path = purple_log_get_log_dir(type, name, account);
-	if (path == NULL)
-		return 0;
-
-	if (!(dir = g_dir_open(path, 0, NULL)))
-	{
-		g_free(path);
-		return 0;
-	}
-
-	while ((filename = g_dir_read_name(dir)))
-	{
-		if (g_str_has_suffix(filename, ext) &&
-		    strlen(filename) >= (17 + strlen(ext))) {
-			char *tmp = g_build_filename(path, filename, NULL);
-			GStatBuf st;
-			if (g_stat(tmp, &st))
-			{
-				purple_debug_error("log", "Error stating log file: %s\n", tmp);
-				g_free(tmp);
-				continue;
-			}
-			g_free(tmp);
-			size += st.st_size;
-		}
-	}
-	g_dir_close(dir);
-	g_free(path);
-	return size;
-}
-
-int purple_log_common_sizer(PurpleLog *log)
-{
-	GStatBuf st;
-	PurpleLogCommonLoggerData *data = log->logger_data;
-
-	g_return_val_if_fail(data != NULL, 0);
-
-	if (!data->path || g_stat(data->path, &st))
-		st.st_size = 0;
-
-	return st.st_size;
-}
-
-/* This will build log sets for all loggers that use the common logger
- * functions because they use the same directory structure. */
-static void log_get_log_sets_common(GHashTable *sets)
-{
-	gchar *log_path = g_build_filename(purple_data_dir(), "logs", NULL);
-	GDir *log_dir = g_dir_open(log_path, 0, NULL);
-	const gchar *protocol;
-
-	if (log_dir == NULL) {
-		g_free(log_path);
-		return;
-	}
-
-	while ((protocol = g_dir_read_name(log_dir)) != NULL) {
-		gchar *protocol_path = g_build_filename(log_path, protocol, NULL);
-		GDir *protocol_dir;
-		const gchar *username;
-		gchar *protocol_unescaped;
-		GList *account_iter;
-		GList *accounts = NULL;
-
-		if ((protocol_dir = g_dir_open(protocol_path, 0, NULL)) == NULL) {
-			g_free(protocol_path);
-			continue;
-		}
-
-		/* Using g_strdup() to cover the one-in-a-million chance that a
-		 * protocol's list_icon function uses purple_unescape_filename(). */
-		protocol_unescaped = g_strdup(purple_unescape_filename(protocol));
-
-		/* Find all the accounts for protocol. */
-		for (account_iter = purple_accounts_get_all() ; account_iter != NULL ; account_iter = account_iter->next) {
-			PurpleProtocol *protocol;
-
-			protocol = purple_account_get_protocol((PurpleAccount *)account_iter->data);
-			if (!protocol)
-				continue;
-
-			if (purple_strequal(protocol_unescaped, purple_protocol_get_list_icon(protocol, (PurpleAccount *)account_iter->data, NULL)))
-				accounts = g_list_prepend(accounts, account_iter->data);
-		}
-		g_free(protocol_unescaped);
-
-		while ((username = g_dir_read_name(protocol_dir)) != NULL) {
-			gchar *username_path = g_build_filename(protocol_path, username, NULL);
-			GDir *username_dir;
-			const gchar *username_unescaped;
-			PurpleAccount *account = NULL;
-			gchar *name;
-
-			if ((username_dir = g_dir_open(username_path, 0, NULL)) == NULL) {
-				g_free(username_path);
-				continue;
-			}
-
-			/* Find the account for username in the list of accounts for protocol. */
-			username_unescaped = purple_unescape_filename(username);
-			for (account_iter = g_list_first(accounts) ; account_iter != NULL ; account_iter = account_iter->next) {
-				if (purple_strequal(purple_account_get_username((PurpleAccount *)account_iter->data), username_unescaped)) {
-					account = account_iter->data;
-					break;
-				}
-			}
-
-			/* Don't worry about the cast, name will point to dynamically allocated memory shortly. */
-			while ((name = (gchar *)g_dir_read_name(username_dir)) != NULL) {
-				size_t len;
-				PurpleLogSet *set;
-
-				/* IMPORTANT: Always initialize all members of PurpleLogSet */
-				set = g_slice_new(PurpleLogSet);
-
-				/* Unescape the filename. */
-				name = g_strdup(purple_unescape_filename(name));
-
-				/* Get the (possibly new) length of name. */
-				len = strlen(name);
-
-				set->type = PURPLE_LOG_IM;
-				set->name = name;
-				set->account = account;
-				/* set->buddy is always set below */
-				set->normalized_name = g_strdup(purple_normalize(account, name));
-
-				/* Check for .chat or .system at the end of the name to determine the type. */
-				if (len >= 7) {
-					gchar *tmp = &name[len - 7];
-					if (purple_strequal(tmp, ".system")) {
-						set->type = PURPLE_LOG_SYSTEM;
-						*tmp = '\0';
-					}
-				}
-				if (len > 5) {
-					gchar *tmp = &name[len - 5];
-					if (purple_strequal(tmp, ".chat")) {
-						set->type = PURPLE_LOG_CHAT;
-						*tmp = '\0';
-					}
-				}
-
-				/* Determine if this (account, name) combination exists as a buddy. */
-				if (account != NULL && *name != '\0')
-					set->buddy = (purple_blist_find_buddy(account, name) != NULL);
-				else
-					set->buddy = FALSE;
-
-				log_add_log_set_to_hash(sets, set);
-			}
-			g_free(username_path);
-			g_dir_close(username_dir);
-		}
-		g_free(protocol_path);
-		g_list_free(accounts);
-		g_dir_close(protocol_dir);
-	}
-	g_free(log_path);
-	g_dir_close(log_dir);
-}
-
-gboolean purple_log_common_deleter(PurpleLog *log)
-{
-	PurpleLogCommonLoggerData *data;
-	int ret;
-
-	g_return_val_if_fail(log != NULL, FALSE);
-
-	data = log->logger_data;
-	if (data == NULL)
-		return FALSE;
-
-	if (data->path == NULL)
-		return FALSE;
-
-	ret = g_unlink(data->path);
-	if (ret == 0)
-		return TRUE;
-	else if (ret == -1)
-	{
-		purple_debug_error("log", "Failed to delete: %s - %s\n", data->path, g_strerror(errno));
-	}
-	else
-	{
-		/* I'm not sure that g_unlink() will ever return
-		 * something other than 0 or -1. -- rlaager */
-		purple_debug_error("log", "Failed to delete: %s\n", data->path);
-	}
-
-	return FALSE;
-}
-
-gboolean purple_log_common_is_deletable(PurpleLog *log)
-{
-	PurpleLogCommonLoggerData *data;
-#ifndef _WIN32
-	gchar *dirname;
-#endif
-
-	g_return_val_if_fail(log != NULL, FALSE);
-
-	data = log->logger_data;
-	if (data == NULL)
-		return FALSE;
-
-	if (data->path == NULL)
-		return FALSE;
-
-#ifndef _WIN32
-	dirname = g_path_get_dirname(data->path);
-	if (g_access(dirname, W_OK) == 0)
-	{
-		g_free(dirname);
-		return TRUE;
-	}
-	purple_debug_info("log", "access(%s) failed: %s\n", dirname, g_strerror(errno));
-	g_free(dirname);
-#else
-	/* Unless and until someone writes equivalent win32 code,
-	 * we'll assume the file is deletable. */
-	return TRUE;
-#endif
-
-	return FALSE;
-}
-
-static char *process_txt_log(char *txt, char *to_free)
-{
-	char *tmp;
-
-	/* The to_free argument allows us to save a
-	 * g_strdup() in some cases. */
-
-	if (to_free == NULL)
-		to_free = txt;
-
-	/* g_markup_escape_text requires valid UTF-8 */
-	tmp = g_utf8_make_valid(txt, -1);
-	g_free(to_free);
-	to_free = txt = tmp;
-
-	tmp = g_markup_escape_text(txt, -1);
-	g_free(to_free);
-	txt = purple_markup_linkify(tmp);
-	g_free(tmp);
-
-	return txt;
-}
-
-/****************************
- ** HTML LOGGER *************
- ****************************/
-
-static gsize html_logger_write(PurpleLog *log, PurpleMessageFlags type,
-                               const char *from, GDateTime *time, const char *message)
-{
-	char *msg_fixed;
-	char *image_corrected_msg;
-	char *date;
-	char *header;
-	char *escaped_from;
-	PurpleProtocol *protocol = purple_account_get_protocol(log->account);
-	PurpleLogCommonLoggerData *data = log->logger_data;
-	gsize written = 0;
-
-	if(!data) {
-		const char *proto = purple_protocol_get_list_icon(protocol, log->account, NULL);
-		GDateTime *dt;
-		gchar *date;
-		purple_log_common_writer(log, ".html");
-
-		data = log->logger_data;
-
-		/* if we can't write to the file, give up before we hurt ourselves */
-		if (!data || !data->file) {
-			return 0;
-		}
-
-		dt = g_date_time_to_local(log->time);
-		date = g_date_time_format(dt, "%c");
-		g_date_time_unref(dt);
-
-		written += fprintf(data->file, "<html><head>");
-		written += fprintf(data->file, "<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">");
-		written += fprintf(data->file, "<title>");
-		if (log->type == PURPLE_LOG_SYSTEM)
-			header = g_strdup_printf("System log for account %s (%s) connected at %s",
-					purple_account_get_username(log->account), proto, date);
-		else
-			header = g_strdup_printf("Conversation with %s at %s on %s (%s)",
-					log->name, date, purple_account_get_username(log->account), proto);
-
-		written += fprintf(data->file, "%s", header);
-		written += fprintf(data->file, "</title></head><body>");
-		written += fprintf(data->file, "<h3>%s</h3>\n", header);
-		g_free(date);
-		g_free(header);
-	}
-
-	/* if we can't write to the file, give up before we hurt ourselves */
-	if(!data->file)
-		return 0;
-
-	escaped_from = g_markup_escape_text(from != NULL ? from : "<NULL>",
-			-1);
-
-	image_corrected_msg = convert_image_tags(log, message);
-	purple_markup_html_to_xhtml(image_corrected_msg, &msg_fixed, NULL);
-
-	/* Yes, this breaks encapsulation.  But it's a static function and
-	 * this saves a needless strdup(). */
-	if (image_corrected_msg != message)
-		g_free(image_corrected_msg);
-
-	date = log_get_timestamp(log, time);
-
-	if(log->type == PURPLE_LOG_SYSTEM){
-		written += fprintf(data->file, "---- %s @ %s ----<br/>\n", msg_fixed, date);
-	} else {
-		if (type & PURPLE_MESSAGE_SYSTEM)
-			written += fprintf(data->file, "<font size=\"2\">(%s)</font><b> %s</b><br/>\n", date, msg_fixed);
-		else if (type & PURPLE_MESSAGE_RAW)
-			written += fprintf(data->file, "<font size=\"2\">(%s)</font> %s<br/>\n", date, msg_fixed);
-		else if (type & PURPLE_MESSAGE_ERROR)
-			written += fprintf(data->file, "<font color=\"#FF0000\"><font size=\"2\">(%s)</font><b> %s</b></font><br/>\n", date, msg_fixed);
-		else if (type & PURPLE_MESSAGE_AUTO_RESP) {
-			if (type & PURPLE_MESSAGE_SEND)
-				written += fprintf(data->file, _("<font color=\"#16569E\"><font size=\"2\">(%s)</font> <b>%s &lt;AUTO-REPLY&gt;:</b></font> %s<br/>\n"), date, escaped_from, msg_fixed);
-			else if (type & PURPLE_MESSAGE_RECV)
-				written += fprintf(data->file, _("<font color=\"#A82F2F\"><font size=\"2\">(%s)</font> <b>%s &lt;AUTO-REPLY&gt;:</b></font> %s<br/>\n"), date, escaped_from, msg_fixed);
-		} else if (type & PURPLE_MESSAGE_RECV) {
-			if(purple_message_meify(msg_fixed, -1))
-				written += fprintf(data->file, "<font color=\"#062585\"><font size=\"2\">(%s)</font> <b>***%s</b></font> %s<br/>\n",
-						date, escaped_from, msg_fixed);
-			else
-				written += fprintf(data->file, "<font color=\"#A82F2F\"><font size=\"2\">(%s)</font> <b>%s:</b></font> %s<br/>\n",
-						date, escaped_from, msg_fixed);
-		} else if (type & PURPLE_MESSAGE_SEND) {
-			if(purple_message_meify(msg_fixed, -1))
-				written += fprintf(data->file, "<font color=\"#062585\"><font size=\"2\">(%s)</font> <b>***%s</b></font> %s<br/>\n",
-						date, escaped_from, msg_fixed);
-			else
-				written += fprintf(data->file, "<font color=\"#16569E\"><font size=\"2\">(%s)</font> <b>%s:</b></font> %s<br/>\n",
-						date, escaped_from, msg_fixed);
-		} else {
-			purple_debug_error("log", "Unhandled message type.\n");
-			written += fprintf(data->file, "<font size=\"2\">(%s)</font><b> %s:</b></font> %s<br/>\n",
-						date, escaped_from, msg_fixed);
-		}
-	}
-	g_free(date);
-	g_free(msg_fixed);
-	g_free(escaped_from);
-	fflush(data->file);
-
-	return written;
-}
-
-static void html_logger_finalize(PurpleLog *log)
-{
-	PurpleLogCommonLoggerData *data = log->logger_data;
-	if (data) {
-		if(data->file) {
-			fprintf(data->file, "</body></html>\n");
-			fclose(data->file);
-		}
-		g_free(data->path);
-
-		g_slice_free(PurpleLogCommonLoggerData, data);
-	}
-}
-
-static GList *html_logger_list(PurpleLogType type, const char *sn, PurpleAccount *account)
-{
-	return purple_log_common_lister(type, sn, account, ".html", html_logger);
-}
-
-static GList *html_logger_list_syslog(PurpleAccount *account)
-{
-	return purple_log_common_lister(PURPLE_LOG_SYSTEM, ".system", account, ".html", html_logger);
-}
-
-static char *html_logger_read(PurpleLog *log, PurpleLogReadFlags *flags)
-{
-	char *read;
-	PurpleLogCommonLoggerData *data = log->logger_data;
-	*flags = PURPLE_LOG_READ_NO_NEWLINE;
-	if (!data || !data->path)
-		return g_strdup(_("<font color=\"red\"><b>Unable to find log path!</b></font>"));
-	if (g_file_get_contents(data->path, &read, NULL, NULL)) {
-		char *minus_header = strchr(read, '\n');
-
-		if (!minus_header)
-			return read;
-
-		minus_header = g_strdup(minus_header + 1);
-		g_free(read);
-
-		return minus_header;
-	}
-	return g_strdup_printf(_("<font color=\"red\"><b>Could not read file: %s</b></font>"), data->path);
-}
-
-static int html_logger_total_size(PurpleLogType type, const char *name, PurpleAccount *account)
-{
-	return purple_log_common_total_sizer(type, name, account, ".html");
-}
-
-
-/****************************
- ** PLAIN TEXT LOGGER *******
- ****************************/
-
-static gsize txt_logger_write(PurpleLog *log, PurpleMessageFlags type,
-                              const char *from, GDateTime *time, const char *message)
-{
-	char *date;
-	PurpleProtocol *protocol = purple_account_get_protocol(log->account);
-	PurpleLogCommonLoggerData *data = log->logger_data;
-	char *stripped = NULL;
-
-	gsize written = 0;
-
-	if (data == NULL) {
-		/* This log is new.  We could use the loggers 'new' function, but
-		 * creating a new file there would result in empty files in the case
-		 * that you open a convo with someone, but don't say anything.
-		 */
-		const char *proto = purple_protocol_get_list_icon(protocol, log->account, NULL);
-		GDateTime *dt;
-		gchar *date;
-		purple_log_common_writer(log, ".txt");
-
-		data = log->logger_data;
-
-		/* if we can't write to the file, give up before we hurt ourselves */
-		if(!data || !data->file)
-			return 0;
-
-		dt = g_date_time_to_local(log->time);
-		date = g_date_time_format(dt, "%c");
-		if (log->type == PURPLE_LOG_SYSTEM)
-			written += fprintf(data->file, "System log for account %s (%s) connected at %s\n",
-				purple_account_get_username(log->account), proto,
-				date);
-		else
-			written += fprintf(data->file, "Conversation with %s at %s on %s (%s)\n",
-				log->name, date,
-				purple_account_get_username(log->account), proto);
-		g_free(date);
-		g_date_time_unref(dt);
-	}
-
-	/* if we can't write to the file, give up before we hurt ourselves */
-	if(!data->file)
-		return 0;
-
-	stripped = purple_markup_strip_html(message);
-	date = log_get_timestamp(log, time);
-
-	if(log->type == PURPLE_LOG_SYSTEM){
-		written += fprintf(data->file, "---- %s @ %s ----\n", stripped, date);
-	} else {
-		if (type & PURPLE_MESSAGE_SEND ||
-			type & PURPLE_MESSAGE_RECV) {
-			if (type & PURPLE_MESSAGE_AUTO_RESP) {
-				written += fprintf(data->file, _("(%s) %s <AUTO-REPLY>: %s\n"), date,
-						from, stripped);
-			} else {
-				if(purple_message_meify(stripped, -1))
-					written += fprintf(data->file, "(%s) ***%s %s\n", date, from,
-							stripped);
-				else
-					written += fprintf(data->file, "(%s) %s: %s\n", date, from,
-							stripped);
-			}
-		} else if (type & PURPLE_MESSAGE_SYSTEM ||
-			type & PURPLE_MESSAGE_ERROR ||
-			type & PURPLE_MESSAGE_RAW)
-			written += fprintf(data->file, "(%s) %s\n", date, stripped);
-		else if (type & PURPLE_MESSAGE_NO_LOG) {
-			/* This shouldn't happen */
-			g_free(stripped);
-			return written;
-		} else
-			written += fprintf(data->file, "(%s) %s%s %s\n", date, from ? from : "",
-					from ? ":" : "", stripped);
-	}
-	g_free(date);
-	g_free(stripped);
-	fflush(data->file);
-
-	return written;
-}
-
-static void txt_logger_finalize(PurpleLog *log)
-{
-	PurpleLogCommonLoggerData *data = log->logger_data;
-	if (data) {
-		if(data->file)
-			fclose(data->file);
-		g_free(data->path);
-
-		g_slice_free(PurpleLogCommonLoggerData, data);
-	}
-}
-
-static GList *txt_logger_list(PurpleLogType type, const char *sn, PurpleAccount *account)
-{
-	return purple_log_common_lister(type, sn, account, ".txt", txt_logger);
-}
-
-static GList *txt_logger_list_syslog(PurpleAccount *account)
-{
-	return purple_log_common_lister(PURPLE_LOG_SYSTEM, ".system", account, ".txt", txt_logger);
-}
-
-static char *txt_logger_read(PurpleLog *log, PurpleLogReadFlags *flags)
-{
-	char *read, *minus_header;
-	PurpleLogCommonLoggerData *data = log->logger_data;
-	*flags = 0;
-	if (!data || !data->path)
-		return g_strdup(_("<font color=\"red\"><b>Unable to find log path!</b></font>"));
-	if (g_file_get_contents(data->path, &read, NULL, NULL)) {
-		minus_header = strchr(read, '\n');
-
-		if (minus_header)
-			return process_txt_log(minus_header + 1, read);
-		else
-			return process_txt_log(read, NULL);
-	}
-	return g_strdup_printf(_("<font color=\"red\"><b>Could not read file: %s</b></font>"), data->path);
-}
-
-static int txt_logger_total_size(PurpleLogType type, const char *name, PurpleAccount *account)
-{
-	return purple_log_common_total_sizer(type, name, account, ".txt");
-}
diff --git a/libpurple/meson.build b/libpurple/meson.build
--- a/libpurple/meson.build
+++ b/libpurple/meson.build
@@ -20,7 +20,6 @@
 	'idle.c',
 	'image.c',
 	'image-store.c',
-	'log.c',
 	'media/backend-fs2.c',
 	'media/backend-iface.c',
 	'media/candidate.c',
@@ -120,7 +119,6 @@
 	'idle.h',
 	'image.h',
 	'image-store.h',
-	'log.h',
 	'media.h',
 	'mediamanager.h',
 	'memorypool.h',
diff --git a/libpurple/protocol.c b/libpurple/protocol.c
--- a/libpurple/protocol.c
+++ b/libpurple/protocol.c
@@ -22,6 +22,7 @@
 
 #include "protocol.h"
 
+#include "accounts.h"
 #include "purpleenums.h"
 
 enum {
diff --git a/libpurple/protocols.c b/libpurple/protocols.c
--- a/libpurple/protocols.c
+++ b/libpurple/protocols.c
@@ -37,6 +37,7 @@
 #include "purpleprotocolmedia.h"
 #include "purpleprotocolserver.h"
 #include "request.h"
+#include "server.h"
 #include "util.h"
 
 /**************************************************************************
diff --git a/libpurple/purpleaccountpresence.c b/libpurple/purpleaccountpresence.c
--- a/libpurple/purpleaccountpresence.c
+++ b/libpurple/purpleaccountpresence.c
@@ -64,32 +64,6 @@
 	time_t idle_time = purple_presence_get_idle_time(presence);
 	time_t current_time = time(NULL);
 
-	if(purple_prefs_get_bool("/purple/logging/log_system")) {
-		PurpleLog *log = purple_account_get_log(account_presence->account,
-		                                        FALSE);
-
-		if(log != NULL) {
-			gchar *msg, *tmp;
-			GDateTime *dt;
-
-			if(idle) {
-				tmp = g_strdup_printf(_("+++ %s became idle"), purple_account_get_username(account_presence->account));
-				dt = g_date_time_new_from_unix_local(idle_time);
-			} else {
-				tmp = g_strdup_printf(_("+++ %s became unidle"), purple_account_get_username(account_presence->account));
-				dt = g_date_time_new_now_utc();
-			}
-
-			msg = g_markup_escape_text(tmp, -1);
-			g_free(tmp);
-			purple_log_write(log, PURPLE_MESSAGE_SYSTEM,
-			                 purple_account_get_username(account_presence->account),
-			                 dt, msg);
-			g_date_time_unref(dt);
-			g_free(msg);
-		}
-	}
-
 	gc = purple_account_get_connection(account_presence->account);
 
 	if(PURPLE_CONNECTION_IS_CONNECTED(gc)) {
diff --git a/libpurple/purplebuddypresence.c b/libpurple/purplebuddypresence.c
--- a/libpurple/purplebuddypresence.c
+++ b/libpurple/purplebuddypresence.c
@@ -135,52 +135,8 @@
 {
 	PurpleBuddy *buddy = purple_buddy_presence_get_buddy(PURPLE_BUDDY_PRESENCE(presence));
 	GDateTime *current_time = g_date_time_new_now_utc();
-	PurpleAccount *account = purple_buddy_get_account(buddy);
 	gboolean idle = purple_presence_is_idle(presence);
 
-	if (!old_idle && idle)
-	{
-		if (purple_prefs_get_bool("/purple/logging/log_system"))
-		{
-			PurpleLog *log = purple_account_get_log(account, FALSE);
-
-			if (log != NULL)
-			{
-				char *tmp, *tmp2;
-				tmp = g_strdup_printf(_("%s became idle"),
-				purple_buddy_get_alias(buddy));
-				tmp2 = g_markup_escape_text(tmp, -1);
-				g_free(tmp);
-
-				purple_log_write(log, PURPLE_MESSAGE_SYSTEM,
-				                 purple_buddy_get_alias(buddy),
-				                 current_time, tmp2);
-				g_free(tmp2);
-			}
-		}
-	}
-	else if (old_idle && !idle)
-	{
-		if (purple_prefs_get_bool("/purple/logging/log_system"))
-		{
-			PurpleLog *log = purple_account_get_log(account, FALSE);
-
-			if (log != NULL)
-			{
-				char *tmp, *tmp2;
-				tmp = g_strdup_printf(_("%s became unidle"),
-				purple_buddy_get_alias(buddy));
-				tmp2 = g_markup_escape_text(tmp, -1);
-				g_free(tmp);
-
-				purple_log_write(log, PURPLE_MESSAGE_SYSTEM,
-				                 purple_buddy_get_alias(buddy),
-				                 current_time, tmp2);
-				g_free(tmp2);
-			}
-		}
-	}
-
 	if (old_idle != idle)
 		purple_signal_emit(purple_blist_get_handle(), "buddy-idle-changed", buddy,
 		                 old_idle, idle);
diff --git a/libpurple/purplechatconversation.c b/libpurple/purplechatconversation.c
--- a/libpurple/purplechatconversation.c
+++ b/libpurple/purplechatconversation.c
@@ -28,6 +28,7 @@
 #include "purplechatconversation.h"
 #include "purpleenums.h"
 #include "purpleprivate.h"
+#include "server.h"
 
 typedef struct {
 	GList *ignored;     /* Ignored users.                            */
@@ -203,10 +204,6 @@
 		purple_chat_conversation_set_nick(chat, username);
 	}
 
-	if(purple_prefs_get_bool("/purple/logging/log_chats")) {
-		purple_conversation_set_logging(PURPLE_CONVERSATION(chat), TRUE);
-	}
-
 	g_object_unref(account);
 }
 
diff --git a/libpurple/purplechatuser.c b/libpurple/purplechatuser.c
--- a/libpurple/purplechatuser.c
+++ b/libpurple/purplechatuser.c
@@ -21,6 +21,8 @@
  */
 
 #include "purplechatuser.h"
+
+#include "conversations.h"
 #include "purpleenums.h"
 
 struct _PurpleChatUser {
diff --git a/libpurple/purpleconversation.h b/libpurple/purpleconversation.h
--- a/libpurple/purpleconversation.h
+++ b/libpurple/purpleconversation.h
@@ -139,7 +139,6 @@
 #include <purpleconversationuiops.h>
 #include "account.h"
 #include "buddyicon.h"
-#include "log.h"
 
 G_BEGIN_DECLS
 
@@ -263,37 +262,6 @@
 const char *purple_conversation_get_name(PurpleConversation *conv);
 
 /**
- * purple_conversation_set_logging:
- * @conv: The conversation.
- * @log:  %TRUE if logging should be enabled, or %FALSE otherwise.
- *
- * Enables or disables logging for this conversation.
- */
-void purple_conversation_set_logging(PurpleConversation *conv, gboolean log);
-
-/**
- * purple_conversation_is_logging:
- * @conv: The conversation.
- *
- * Returns whether or not logging is enabled for this conversation.
- *
- * Returns: %TRUE if logging is enabled, or %FALSE otherwise.
- */
-gboolean purple_conversation_is_logging(PurpleConversation *conv);
-
-/**
- * purple_conversation_close_logs:
- * @conv: The conversation.
- *
- * Closes any open logs for this conversation.
- *
- * Note that new logs will be opened as necessary (e.g. upon receipt of a
- * message, if the conversation has logging enabled. To disable logging for
- * the remainder of the conversation, use purple_conversation_set_logging().
- */
-void purple_conversation_close_logs(PurpleConversation *conv);
-
-/**
  * purple_conversation_write_message:
  * @conv: The conversation.
  * @msg:  The message to write.
diff --git a/libpurple/purpleconversation.c b/libpurple/purpleconversation.c
--- a/libpurple/purpleconversation.c
+++ b/libpurple/purpleconversation.c
@@ -26,6 +26,7 @@
 
 #include "buddylist.h"
 #include "cmds.h"
+#include "conversations.h"
 #include "debug.h"
 #include "notify.h"
 #include "prefs.h"
@@ -46,10 +47,6 @@
 	char *name;                       /* The name of the conversation.     */
 	char *title;                      /* The window title.                 */
 
-	gboolean logging;                 /* The status of logging.            */
-
-	GList *logs;                      /* This conversation's logs          */
-
 	PurpleConversationUiOps *ui_ops;  /* UI-specific operations.           */
 
 	PurpleConnectionFlags features;   /* The supported features            */
@@ -61,7 +58,6 @@
 	PROP_ACCOUNT,
 	PROP_NAME,
 	PROP_TITLE,
-	PROP_LOGGING,
 	PROP_FEATURES,
 	N_PROPERTIES
 };
@@ -235,9 +231,6 @@
 			g_free(priv->title);
 			priv->title = g_value_dup_string(value);
 			break;
-		case PROP_LOGGING:
-			purple_conversation_set_logging(conv, g_value_get_boolean(value));
-			break;
 		case PROP_FEATURES:
 			purple_conversation_set_features(conv, g_value_get_flags(value));
 			break;
@@ -263,9 +256,6 @@
 		case PROP_TITLE:
 			g_value_set_string(value, purple_conversation_get_title(conv));
 			break;
-		case PROP_LOGGING:
-			g_value_set_boolean(value, purple_conversation_is_logging(conv));
-			break;
 		case PROP_FEATURES:
 			g_value_set_flags(value, purple_conversation_get_features(conv));
 			break;
@@ -345,7 +335,6 @@
 	purple_signal_emit(purple_conversations_get_handle(),
 	                   "deleting-conversation", conv);
 
-	purple_conversation_close_logs(conv);
 	purple_conversation_clear_message_history(conv);
 
 	if(ops != NULL && ops->destroy_conversation != NULL) {
@@ -388,12 +377,6 @@
 		NULL,
 		G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
 
-	properties[PROP_LOGGING] = g_param_spec_boolean(
-		"logging", "Logging status",
-		"Whether logging is enabled or not.",
-		FALSE,
-		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-
 	properties[PROP_FEATURES] = g_param_spec_flags(
 		"features", "Connection features",
 		"The connection features of the conversation.",
@@ -606,58 +589,6 @@
 }
 
 void
-purple_conversation_set_logging(PurpleConversation *conv, gboolean log) {
-	PurpleConversationPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_CONVERSATION(conv));
-	priv = purple_conversation_get_instance_private(conv);
-
-	if(priv->logging != log) {
-		priv->logging = log;
-		if(log && priv->logs == NULL) {
-			GDateTime *dt;
-			PurpleLog *log;
-
-			dt = g_date_time_new_now_local();
-			log = purple_log_new(PURPLE_IS_CHAT_CONVERSATION(conv)
-			                     ? PURPLE_LOG_CHAT
-			                     : PURPLE_LOG_IM,
-			                     priv->name, priv->account, conv,
-			                     dt);
-			g_date_time_unref(dt);
-
-			priv->logs = g_list_append(NULL, log);
-		}
-
-		g_object_notify_by_pspec(G_OBJECT(conv), properties[PROP_LOGGING]);
-
-		purple_conversation_update(conv, PURPLE_CONVERSATION_UPDATE_LOGGING);
-	}
-}
-
-gboolean
-purple_conversation_is_logging(PurpleConversation *conv) {
-	PurpleConversationPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_CONVERSATION(conv), FALSE);
-
-	priv = purple_conversation_get_instance_private(conv);
-
-	return priv->logging;
-}
-
-void
-purple_conversation_close_logs(PurpleConversation *conv) {
-	PurpleConversationPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_CONVERSATION(conv));
-
-	priv = purple_conversation_get_instance_private(conv);
-	g_list_free_full(priv->logs, (GDestroyNotify)purple_log_free);
-	priv->logs = NULL;
-}
-
-void
 _purple_conversation_write_common(PurpleConversation *conv,
                                   PurpleMessage *pmsg)
 {
@@ -746,11 +677,8 @@
 		}
 	}
 
-	if(!(purple_message_get_flags(pmsg) & PURPLE_MESSAGE_NO_LOG) &&
-	   purple_conversation_is_logging(conv))
+	if(!(purple_message_get_flags(pmsg) & PURPLE_MESSAGE_NO_LOG))
 	{
-		GList *log;
-		GDateTime *dt;
 		GError *error = NULL;
 		PurpleHistoryManager *manager = NULL;
 
@@ -763,20 +691,6 @@
 
 			g_clear_error(&error);
 		}
-
-
-		/* The following should be deleted when the history api is stable. */
-		dt = g_date_time_ref(purple_message_get_timestamp(pmsg));
-		log = priv->logs;
-		while(log != NULL) {
-			purple_log_write((PurpleLog *)log->data,
-			                 purple_message_get_flags(pmsg),
-			                 purple_message_get_author_alias(pmsg),
-			                 dt,
-			                 purple_message_get_contents(pmsg));
-			log = log->next;
-		}
-		g_date_time_unref(dt);
 	}
 
 	if(ops) {
diff --git a/libpurple/purpleimconversation.c b/libpurple/purpleimconversation.c
--- a/libpurple/purpleimconversation.c
+++ b/libpurple/purpleimconversation.c
@@ -22,6 +22,7 @@
 #include <libpurple/purpleimconversation.h>
 
 #include <libpurple/debug.h>
+#include <libpurple/conversations.h>
 #include <libpurple/purpleconversationmanager.h>
 #include <libpurple/purpleenums.h>
 #include <libpurple/purpleprivate.h>
@@ -178,10 +179,6 @@
 		purple_buddy_icon_unref(icon);
 	}
 
-	if(purple_prefs_get_bool("/purple/logging/log_ims")) {
-		purple_conversation_set_logging(PURPLE_CONVERSATION(im), TRUE);
-	}
-
 	g_object_unref(account);
 	g_free(name);
 }
diff --git a/libpurple/savedstatuses.c b/libpurple/savedstatuses.c
--- a/libpurple/savedstatuses.c
+++ b/libpurple/savedstatuses.c
@@ -23,6 +23,7 @@
 
 #include "internal.h"
 
+#include "accounts.h"
 #include "debug.h"
 #include "idle.h"
 #include "notify.h"
diff --git a/libpurple/server.c b/libpurple/server.c
--- a/libpurple/server.c
+++ b/libpurple/server.c
@@ -28,7 +28,6 @@
 #include "internal.h"
 #include "buddylist.h"
 #include "debug.h"
-#include "log.h"
 #include "notify.h"
 #include "prefs.h"
 #include "protocol.h"
diff --git a/libpurple/status.c b/libpurple/status.c
--- a/libpurple/status.c
+++ b/libpurple/status.c
@@ -503,58 +503,6 @@
 * PurpleStatus API
 **************************************************************************/
 static void
-notify_buddy_status_update(PurpleBuddy *buddy, PurplePresence *presence,
-		PurpleStatus *old_status, PurpleStatus *new_status)
-{
-	if (purple_prefs_get_bool("/purple/logging/log_system"))
-	{
-		GDateTime *current_time = g_date_time_new_now_utc();
-		const char *buddy_alias = purple_buddy_get_alias(buddy);
-		char *tmp, *logtmp;
-		PurpleLog *log;
-
-		if (old_status != NULL)
-		{
-			tmp = g_strdup_printf(_("%s (%s) changed status from %s to %s"), buddy_alias,
-			                      purple_buddy_get_name(buddy),
-			                      purple_status_get_name(old_status),
-			                      purple_status_get_name(new_status));
-			logtmp = g_markup_escape_text(tmp, -1);
-		}
-		else
-		{
-			/* old_status == NULL when an independent status is toggled. */
-
-			if (purple_status_is_active(new_status))
-			{
-				tmp = g_strdup_printf(_("%s (%s) is now %s"), buddy_alias,
-				                      purple_buddy_get_name(buddy),
-				                      purple_status_get_name(new_status));
-				logtmp = g_markup_escape_text(tmp, -1);
-			}
-			else
-			{
-				tmp = g_strdup_printf(_("%s (%s) is no longer %s"), buddy_alias,
-				                      purple_buddy_get_name(buddy),
-				                      purple_status_get_name(new_status));
-				logtmp = g_markup_escape_text(tmp, -1);
-			}
-		}
-
-		log = purple_account_get_log(purple_buddy_get_account(buddy), FALSE);
-		if (log != NULL)
-		{
-			purple_log_write(log, PURPLE_MESSAGE_SYSTEM, buddy_alias,
-			               current_time, logtmp);
-		}
-
-		g_date_time_unref(current_time);
-		g_free(tmp);
-		g_free(logtmp);
-	}
-}
-
-static void
 notify_status_update(PurplePresence *presence, PurpleStatus *old_status,
 					 PurpleStatus *new_status)
 {
@@ -572,12 +520,6 @@
 			ops->status_changed(account, new_status);
 		}
 	}
-	else if (PURPLE_IS_BUDDY_PRESENCE(presence))
-	{
-		notify_buddy_status_update(purple_buddy_presence_get_buddy(
-				PURPLE_BUDDY_PRESENCE(presence)), presence, old_status,
-				new_status);
-	}
 }
 
 static void
diff --git a/libpurple/xfer.c b/libpurple/xfer.c
--- a/libpurple/xfer.c
+++ b/libpurple/xfer.c
@@ -38,6 +38,7 @@
 #include "purpleconversationmanager.h"
 #include "purpleenums.h"
 #include "request.h"
+#include "server.h"
 #include "util.h"
 #include "xfer.h"
 
diff --git a/pidgin/gtkblist.c b/pidgin/gtkblist.c
--- a/pidgin/gtkblist.c
+++ b/pidgin/gtkblist.c
@@ -156,7 +156,6 @@
 
 static void sort_method_alphabetical(PurpleBlistNode *node, PurpleBuddyList *blist, GtkTreeIter groupiter, GtkTreeIter *cur, GtkTreeIter *iter);
 static void sort_method_status(PurpleBlistNode *node, PurpleBuddyList *blist, GtkTreeIter groupiter, GtkTreeIter *cur, GtkTreeIter *iter);
-static void sort_method_log_activity(PurpleBlistNode *node, PurpleBuddyList *blist, GtkTreeIter groupiter, GtkTreeIter *cur, GtkTreeIter *iter);
 
 static PidginBuddyList *gtkblist = NULL;
 
@@ -3846,7 +3845,6 @@
 	pidgin_blist_sort_method_reg("none", _("Manually"), sort_method_none);
 	pidgin_blist_sort_method_reg("alphabetical", _("Alphabetically"), sort_method_alphabetical);
 	pidgin_blist_sort_method_reg("status", _("By status"), sort_method_status);
-	pidgin_blist_sort_method_reg("log_size", _("By recent log activity"), sort_method_log_activity);
 
 	id = purple_prefs_get_string(PIDGIN_PREFS_ROOT "/blist/sort_type");
 	if (id == NULL) {
@@ -6506,93 +6504,6 @@
 	}
 }
 
-static void sort_method_log_activity(PurpleBlistNode *node, PurpleBuddyList *blist, GtkTreeIter groupiter, GtkTreeIter *cur, GtkTreeIter *iter)
-{
-	GtkTreeIter more_z;
-
-	int activity_score = 0, this_log_activity_score = 0;
-	const char *buddy_name, *this_buddy_name;
-
-	if(cur && (gtk_tree_model_iter_n_children(GTK_TREE_MODEL(gtkblist->treemodel), &groupiter) == 1)) {
-		*iter = *cur;
-		return;
-	}
-
-	if(PURPLE_IS_CONTACT(node)) {
-		PurpleBlistNode *n;
-		PurpleBuddy *buddy;
-		for (n = node->child; n; n = n->next) {
-			buddy = (PurpleBuddy*)n;
-			activity_score += purple_log_get_activity_score(PURPLE_LOG_IM, purple_buddy_get_name(buddy), purple_buddy_get_account(buddy));
-		}
-		buddy_name = purple_contact_get_alias((PurpleContact*)node);
-	} else if(PURPLE_IS_CHAT(node)) {
-		/* we don't have a reliable way of getting the log filename
-		 * from the chat info in the blist, yet */
-		if (cur != NULL) {
-			*iter = *cur;
-			return;
-		}
-
-		gtk_tree_store_append(gtkblist->treemodel, iter, &groupiter);
-		return;
-	} else {
-		sort_method_none(node, blist, groupiter, cur, iter);
-		return;
-	}
-
-
-	if (!gtk_tree_model_iter_children(GTK_TREE_MODEL(gtkblist->treemodel), &more_z, &groupiter)) {
-		gtk_tree_store_insert(gtkblist->treemodel, iter, &groupiter, 0);
-		return;
-	}
-
-	do {
-		PurpleBlistNode *n;
-		PurpleBlistNode *n2;
-		PurpleBuddy *buddy;
-		int cmp;
-
-		gtk_tree_model_get(GTK_TREE_MODEL(gtkblist->treemodel), &more_z, NODE_COLUMN, &n, -1);
-		this_log_activity_score = 0;
-
-		if(PURPLE_IS_CONTACT(n)) {
-			for (n2 = n->child; n2; n2 = n2->next) {
-				buddy = (PurpleBuddy*)n2;
-				this_log_activity_score += purple_log_get_activity_score(PURPLE_LOG_IM, purple_buddy_get_name(buddy), purple_buddy_get_account(buddy));
-			}
-			this_buddy_name = purple_contact_get_alias((PurpleContact*)n);
-		} else {
-			this_buddy_name = NULL;
-		}
-
-		cmp = purple_utf8_strcasecmp(buddy_name, this_buddy_name);
-
-		if (!PURPLE_IS_CONTACT(n) || activity_score > this_log_activity_score ||
-				((activity_score == this_log_activity_score) &&
-				 (cmp < 0 || (cmp == 0 && node < n)))) {
-			if (cur != NULL) {
-				gtk_tree_store_move_before(gtkblist->treemodel, cur, &more_z);
-				*iter = *cur;
-				return;
-			} else {
-				gtk_tree_store_insert_before(gtkblist->treemodel, iter,
-						&groupiter, &more_z);
-				return;
-			}
-		}
-	} while (gtk_tree_model_iter_next (GTK_TREE_MODEL(gtkblist->treemodel), &more_z));
-
-	if (cur != NULL) {
-		gtk_tree_store_move_before(gtkblist->treemodel, cur, NULL);
-		*iter = *cur;
-		return;
-	} else {
-		gtk_tree_store_append(gtkblist->treemodel, iter, &groupiter);
-		return;
-	}
-}
-
 void
 pidgin_blist_update_sort_methods(void)
 {
diff --git a/pidgin/gtkconv.c b/pidgin/gtkconv.c
--- a/pidgin/gtkconv.c
+++ b/pidgin/gtkconv.c
@@ -149,22 +149,6 @@
 static void pidgin_conv_set_position_size(PidginConvWindow *win, int x, int y,
 		int width, int height);
 
-static PurpleBlistNode *
-get_conversation_blist_node(PurpleConversation *conv)
-{
-	PurpleAccount *account = purple_conversation_get_account(conv);
-	PurpleBlistNode *node = NULL;
-
-	if (PURPLE_IS_IM_CONVERSATION(conv)) {
-		node = PURPLE_BLIST_NODE(purple_blist_find_buddy(account, purple_conversation_get_name(conv)));
-		node = node ? node->parent : NULL;
-	} else if (PURPLE_IS_CHAT_CONVERSATION(conv)) {
-		node = PURPLE_BLIST_NODE(purple_blist_find_chat(account, purple_conversation_get_name(conv)));
-	}
-
-	return node;
-}
-
 /**************************************************************************
  * Callbacks
  **************************************************************************/
@@ -1425,7 +1409,6 @@
 	if (old_conv == conv)
 		return;
 
-	purple_conversation_close_logs(old_conv);
 	gtkconv->active_conv = conv;
 
 	purple_signal_emit(pidgin_conversations_get_handle(), "conversation-switched", conv);
@@ -2509,7 +2492,6 @@
 	PidginConversation *gtkconv;
 	GtkWidget *pane = NULL;
 	GtkWidget *tab_cont;
-	PurpleBlistNode *convnode;
 
 	if (PURPLE_IS_IM_CONVERSATION(conv) && (gtkconv = pidgin_conv_find_gtkconv(conv))) {
 		g_object_set_data(G_OBJECT(conv), "pidgin", gtkconv);
@@ -2558,12 +2540,6 @@
 	gtk_box_pack_start(GTK_BOX(tab_cont), pane, TRUE, TRUE, 0);
 	gtk_widget_show(pane);
 
-	convnode = get_conversation_blist_node(conv);
-	if (convnode != NULL && purple_blist_node_has_setting(convnode, "enable-logging")) {
-		gboolean logging = purple_blist_node_get_bool(convnode, "enable-logging");
-		purple_conversation_set_logging(conv, logging);
-	}
-
 	talkatu_editor_set_toolbar_visible(
 		TALKATU_EDITOR(gtkconv->editor),
 		purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/show_formatting_toolbar")
diff --git a/pidgin/gtkutils.h b/pidgin/gtkutils.h
--- a/pidgin/gtkutils.h
+++ b/pidgin/gtkutils.h
@@ -46,10 +46,7 @@
 
 typedef struct {
 	gboolean is_buddy;
-	union {
-		PurpleBuddy *buddy;
-		PurpleLogSet *logged_buddy;
-	} entry;
+	PurpleBuddy *buddy;
 } PidginBuddyCompletionEntry;
 
 typedef gboolean (*PidginFilterBuddyCompletionEntryFunc) (const PidginBuddyCompletionEntry *completion_entry, gpointer user_data);
diff --git a/pidgin/gtkutils.c b/pidgin/gtkutils.c
--- a/pidgin/gtkutils.c
+++ b/pidgin/gtkutils.c
@@ -1137,32 +1137,12 @@
 	g_free(normalized_buddyname);
 }
 
-static void get_log_set_name(PurpleLogSet *set, gpointer value, PidginCompletionData *data)
-{
-	PidginFilterBuddyCompletionEntryFunc filter_func = data->filter_func;
-	gpointer user_data = data->filter_func_user_data;
-
-	/* 1. Don't show buddies because we will have gotten them already.
-	 * 2. The boxes that use this autocomplete code handle only IMs. */
-	if (!set->buddy && set->type == PURPLE_LOG_IM) {
-		PidginBuddyCompletionEntry entry;
-		entry.is_buddy = FALSE;
-		entry.entry.logged_buddy = set;
-
-		if (filter_func(&entry, user_data)) {
-			add_buddyname_autocomplete_entry(data->store,
-												NULL, NULL, set->account, set->name);
-		}
-	}
-}
-
 static void
 add_completion_list(PidginCompletionData *data)
 {
 	PurpleBlistNode *gnode, *cnode, *bnode;
 	PidginFilterBuddyCompletionEntryFunc filter_func = data->filter_func;
 	gpointer user_data = data->filter_func_user_data;
-	GHashTable *sets;
 	gchar *alias;
 
 	gtk_list_store_clear(data->store);
@@ -1183,14 +1163,14 @@
 			{
 				PidginBuddyCompletionEntry entry;
 				entry.is_buddy = TRUE;
-				entry.entry.buddy = (PurpleBuddy *) bnode;
+				entry.buddy = (PurpleBuddy *) bnode;
 
 				if (filter_func(&entry, user_data)) {
 					add_buddyname_autocomplete_entry(data->store,
 														alias,
-														purple_buddy_get_contact_alias(entry.entry.buddy),
-														purple_buddy_get_account(entry.entry.buddy),
-														purple_buddy_get_name(entry.entry.buddy)
+														purple_buddy_get_contact_alias(entry.buddy),
+														purple_buddy_get_account(entry.buddy),
+														purple_buddy_get_name(entry.buddy)
 													 );
 				}
 			}
@@ -1198,11 +1178,6 @@
 			g_free(alias);
 		}
 	}
-
-	sets = purple_log_get_log_sets();
-	g_hash_table_foreach(sets, (GHFunc)get_log_set_name, data);
-	g_hash_table_destroy(sets);
-
 }
 
 static void
@@ -1288,11 +1263,7 @@
 pidgin_screenname_autocomplete_default_filter(const PidginBuddyCompletionEntry *completion_entry, gpointer all_accounts) {
 	gboolean all = GPOINTER_TO_INT(all_accounts);
 
-	if (completion_entry->is_buddy) {
-		return all || purple_account_is_connected(purple_buddy_get_account(completion_entry->entry.buddy));
-	} else {
-		return all || (completion_entry->entry.logged_buddy->account != NULL && purple_account_is_connected(completion_entry->entry.logged_buddy->account));
-	}
+	return all || purple_account_is_connected(purple_buddy_get_account(completion_entry->buddy));
 }
 
 void pidgin_set_cursor(GtkWidget *widget, GdkCursorType cursor_type)
diff --git a/pidgin/prefs/pidginprefs.c b/pidgin/prefs/pidginprefs.c
--- a/pidgin/prefs/pidginprefs.c
+++ b/pidgin/prefs/pidginprefs.c
@@ -128,14 +128,6 @@
 		GtkWidget *custom_font;
 	} conversations;
 
-	/* Logging page */
-	struct {
-		PidginPrefCombo format;
-		GtkWidget *log_ims;
-		GtkWidget *log_chats;
-		GtkWidget *log_system;
-	} logging;
-
 	/* Network page */
 	struct {
 		GtkWidget *stun_server;
@@ -1701,25 +1693,6 @@
 }
 
 static void
-bind_logging_page(PidginPrefsWindow *win)
-{
-	GList *names;
-
-	win->logging.format.type = PURPLE_PREF_STRING;
-	win->logging.format.key = "/purple/logging/format";
-	names = purple_log_logger_get_options();
-	pidgin_prefs_bind_dropdown_from_list(&win->logging.format, names);
-	g_list_free(names);
-
-	pidgin_prefs_bind_checkbox("/purple/logging/log_ims",
-			win->logging.log_ims);
-	pidgin_prefs_bind_checkbox("/purple/logging/log_chats",
-			win->logging.log_chats);
-	pidgin_prefs_bind_checkbox("/purple/logging/log_system",
-			win->logging.log_system);
-}
-
-static void
 set_idle_away(PurpleSavedStatus *status)
 {
 	purple_prefs_set_int("/purple/savedstatus/idleaway", purple_savedstatus_get_creation_time(status));
@@ -2293,7 +2266,6 @@
 
 	bind_interface_page(win);
 	bind_conv_page(win);
-	bind_logging_page(win);
 	bind_network_page(win);
 	bind_proxy_page(win);
 	bind_away_page(win);
@@ -2384,16 +2356,6 @@
 	gtk_widget_class_bind_template_callback(widget_class,
 			pidgin_custom_font_set);
 
-	/* Logging page */
-	gtk_widget_class_bind_template_child(
-			widget_class, PidginPrefsWindow, logging.format.combo);
-	gtk_widget_class_bind_template_child(
-			widget_class, PidginPrefsWindow, logging.log_ims);
-	gtk_widget_class_bind_template_child(
-			widget_class, PidginPrefsWindow, logging.log_chats);
-	gtk_widget_class_bind_template_child(
-			widget_class, PidginPrefsWindow, logging.log_system);
-
 	/* Network page */
 	gtk_widget_class_bind_template_child(
 			widget_class, PidginPrefsWindow, network.stun_server);
@@ -2570,9 +2532,6 @@
 	const gchar *video_sink = NULL;
 
 	/* Rename some old prefs */
-	purple_prefs_rename(PIDGIN_PREFS_ROOT "/logging/log_ims", "/purple/logging/log_ims");
-	purple_prefs_rename(PIDGIN_PREFS_ROOT "/logging/log_chats", "/purple/logging/log_chats");
-
 	purple_prefs_rename(PIDGIN_PREFS_ROOT "/conversations/im/raise_on_events", "/plugins/gtk/X11/notify/method_raise");
 
 	purple_prefs_rename_boolean_toggle(PIDGIN_PREFS_ROOT "/conversations/ignore_colors",
@@ -2615,7 +2574,6 @@
 	purple_prefs_remove(PIDGIN_PREFS_ROOT "/conversations/passthrough_unknown_commands");
 	purple_prefs_remove(PIDGIN_PREFS_ROOT "/debug/timestamps");
 	purple_prefs_remove(PIDGIN_PREFS_ROOT "/idle");
-	purple_prefs_remove(PIDGIN_PREFS_ROOT "/logging/individual_logs");
 	purple_prefs_remove(PIDGIN_PREFS_ROOT "/sound/signon");
 	purple_prefs_remove(PIDGIN_PREFS_ROOT "/sound/silent_signon");
 	purple_prefs_remove(PIDGIN_PREFS_ROOT "/sound/command");
diff --git a/pidgin/resources/Prefs/prefs.ui b/pidgin/resources/Prefs/prefs.ui
--- a/pidgin/resources/Prefs/prefs.ui
+++ b/pidgin/resources/Prefs/prefs.ui
@@ -199,14 +199,6 @@
       </row>
     </data>
   </object>
-  <object class="GtkListStore" id="logging.format.store">
-    <columns>
-      <!-- column-name text -->
-      <column type="gchararray"/>
-      <!-- column-name value -->
-      <column type="gchararray"/>
-    </columns>
-  </object>
   <object class="GtkAdjustment" id="network.ports_range_end.adjustment">
     <property name="upper">65535</property>
     <property name="step-increment">1</property>
@@ -889,147 +881,6 @@
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkBox" id="logging.page">
-                    <property name="visible">True</property>
-                    <property name="can-focus">False</property>
-                    <property name="border-width">12</property>
-                    <property name="orientation">vertical</property>
-                    <property name="spacing">18</property>
-                    <child>
-                      <object class="GtkFrame">
-                        <property name="visible">True</property>
-                        <property name="can-focus">False</property>
-                        <property name="label-xalign">0</property>
-                        <property name="shadow-type">none</property>
-                        <child>
-                          <object class="GtkAlignment">
-                            <property name="visible">True</property>
-                            <property name="can-focus">False</property>
-                            <property name="left-padding">12</property>
-                            <child>
-                              <object class="GtkBox">
-                                <property name="visible">True</property>
-                                <property name="can-focus">False</property>
-                                <property name="orientation">vertical</property>
-                                <property name="spacing">6</property>
-                                <child>
-                                  <object class="GtkBox">
-                                    <property name="visible">True</property>
-                                    <property name="can-focus">False</property>
-                                    <property name="spacing">6</property>
-                                    <child>
-                                      <object class="GtkLabel">
-                                        <property name="visible">True</property>
-                                        <property name="can-focus">False</property>
-                                        <property name="label" translatable="yes">Log _format:</property>
-                                        <property name="use-underline">True</property>
-                                        <property name="mnemonic-widget">logging.format.combo</property>
-                                      </object>
-                                      <packing>
-                                        <property name="expand">False</property>
-                                        <property name="fill">True</property>
-                                        <property name="position">0</property>
-                                      </packing>
-                                    </child>
-                                    <child>
-                                      <object class="GtkComboBox" id="logging.format.combo">
-                                        <property name="visible">True</property>
-                                        <property name="can-focus">False</property>
-                                        <property name="model">logging.format.store</property>
-                                        <child>
-                                          <object class="GtkCellRendererText"/>
-                                          <attributes>
-                                            <attribute name="text">0</attribute>
-                                          </attributes>
-                                        </child>
-                                      </object>
-                                      <packing>
-                                        <property name="expand">False</property>
-                                        <property name="fill">True</property>
-                                        <property name="position">1</property>
-                                      </packing>
-                                    </child>
-                                  </object>
-                                  <packing>
-                                    <property name="expand">False</property>
-                                    <property name="fill">True</property>
-                                    <property name="position">0</property>
-                                  </packing>
-                                </child>
-                                <child>
-                                  <object class="GtkCheckButton" id="logging.log_ims">
-                                    <property name="label" translatable="yes">Log all _instant messages</property>
-                                    <property name="visible">True</property>
-                                    <property name="can-focus">True</property>
-                                    <property name="receives-default">False</property>
-                                    <property name="use-underline">True</property>
-                                    <property name="draw-indicator">True</property>
-                                  </object>
-                                  <packing>
-                                    <property name="expand">False</property>
-                                    <property name="fill">True</property>
-                                    <property name="position">1</property>
-                                  </packing>
-                                </child>
-                                <child>
-                                  <object class="GtkCheckButton" id="logging.log_chats">
-                                    <property name="label" translatable="yes">Log all c_hats</property>
-                                    <property name="visible">True</property>
-                                    <property name="can-focus">True</property>
-                                    <property name="receives-default">False</property>
-                                    <property name="use-underline">True</property>
-                                    <property name="draw-indicator">True</property>
-                                  </object>
-                                  <packing>
-                                    <property name="expand">False</property>
-                                    <property name="fill">True</property>
-                                    <property name="position">2</property>
-                                  </packing>
-                                </child>
-                                <child>
-                                  <object class="GtkCheckButton" id="logging.log_system">
-                                    <property name="label" translatable="yes">Log all _status changes to system log</property>
-                                    <property name="visible">True</property>
-                                    <property name="can-focus">True</property>
-                                    <property name="receives-default">False</property>
-                                    <property name="use-underline">True</property>
-                                    <property name="draw-indicator">True</property>
-                                  </object>
-                                  <packing>
-                                    <property name="expand">False</property>
-                                    <property name="fill">True</property>
-                                    <property name="position">3</property>
-                                  </packing>
-                                </child>
-                              </object>
-                            </child>
-                          </object>
-                        </child>
-                        <child type="label">
-                          <object class="GtkLabel">
-                            <property name="visible">True</property>
-                            <property name="can-focus">False</property>
-                            <property name="label" translatable="yes">Logging</property>
-                            <attributes>
-                              <attribute name="weight" value="bold"/>
-                            </attributes>
-                          </object>
-                        </child>
-                      </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">True</property>
-                        <property name="position">0</property>
-                      </packing>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="name">logging</property>
-                    <property name="title" translatable="yes">Logging</property>
-                    <property name="position">2</property>
-                  </packing>
-                </child>
-                <child>
                   <object class="GtkBox" id="network.page">
                     <property name="visible">True</property>
                     <property name="can-focus">False</property>
diff --git a/po/POTFILES.in b/po/POTFILES.in
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -44,7 +44,6 @@
 libpurple/idle.c
 libpurple/image.c
 libpurple/image-store.c
-libpurple/log.c
 libpurple/media/backend-fs2.c
 libpurple/media/backend-iface.c
 libpurple/media.c
