cpw.nader.asynclogging-3: 982507d0: Merged branches

morshed.nader at gmail.com morshed.nader at gmail.com
Tue Jan 3 00:02:25 EST 2012


----------------------------------------------------------------------
Revision: 982507d00201b03d3874b58c6d23a21cfe1c5afc
Parent:   66845be3ca64d98e414fd7165f670b00c1f36d2c
Author:   morshed.nader at gmail.com
Date:     01/02/12 18:42:50
Branch:   im.pidgin.cpw.nader.asynclogging-3
URL: http://d.pidgin.im/viewmtn/revision/info/982507d00201b03d3874b58c6d23a21cfe1c5afc

Changelog: 

Merged branches

Changes against parent 66845be3ca64d98e414fd7165f670b00c1f36d2c

  patched  Makefile.mingw
  patched  libpurple/commonlog.c
  patched  libpurple/htmllog.c
  patched  libpurple/log.c
  patched  libpurple/log.h
  patched  libpurple/plugins/Makefile.mingw
  patched  libpurple/win32/global.mak
  patched  pidgin/Makefile.mingw
  patched  pidgin/gtkconv-theme.c
  patched  pidgin/gtklog.c
  patched  pidgin/gtklog.h
  patched  pidgin/plugins/Makefile.mingw
  patched  pidgin/win32/nsis/generate_gtk_zip.sh

-------------- next part --------------
============================================================
--- Makefile.mingw	745b5307a51ca27e3eeb6ce96b0c4876bb9181e2
+++ Makefile.mingw	22f838c796631cdf06a4fd7d8e262ad8e5a4b15e
@@ -31,7 +31,7 @@ awk 'BEGIN {FS="."} { \
     exit; \
 }' VERSION)
 
-GTK_INSTALL_VERSION = 2.16.6.0
+GTK_INSTALL_VERSION = 2.24.0.1
 
 STRIPPED_RELEASE_DIR = $(PIDGIN_TREE_TOP)/pidgin-$(PIDGIN_VERSION)-win32bin
 DEBUG_SYMBOLS_DIR = $(PIDGIN_TREE_TOP)/pidgin-$(PIDGIN_VERSION)-dbgsym
@@ -56,6 +56,7 @@ EXTERNAL_DLLS = \
 	libplds4.dll \
 	libsasl.dll \
 	libxml2-2.dll \
+	libwebkitgtk-1.0-0.dll \
 	nss3.dll \
 	nssckbi.dll \
 	nssutil3.dll \
============================================================
--- libpurple/win32/global.mak	ac8976b86788f9b1e5f54b90334769367e04dd5a
+++ libpurple/win32/global.mak	bec602d9a0667be05201b505797d6a26c5971036
@@ -8,11 +8,14 @@
 #include optional $(PIDGIN_TREE_TOP)/local.mak to allow overriding of any definitions
 -include $(PIDGIN_TREE_TOP)/local.mak
 
+#TODO that probably should be here ONLY while moving from 2.x.x to 3.0.0
+DEFINES += -DPURPLE_DISABLE_DEPRECATED
+
 # Locations of our various dependencies
 WIN32_DEV_TOP ?= $(PIDGIN_TREE_TOP)/../win32-dev
 GTKSPELL_TOP ?= $(WIN32_DEV_TOP)/gtkspell-2.0.16
 ENCHANT_TOP ?= $(WIN32_DEV_TOP)/enchant_1.5.0-2_win32
-GTK_TOP ?= $(WIN32_DEV_TOP)/gtk_2_0-2.14
+GTK_TOP ?= $(WIN32_DEV_TOP)/gtk_2_0-2.24
 GTK_BIN ?= $(GTK_TOP)/bin
 BONJOUR_TOP ?= $(WIN32_DEV_TOP)/Bonjour_SDK
 LIBXML2_TOP ?= $(WIN32_DEV_TOP)/libxml2-2.7.4
@@ -87,7 +90,7 @@ DEFINES += -DHAVE_CONFIG_H -DWIN32_LEAN_
 # Use -g flag when building debug version of Pidgin (including plugins).
 # Use -fnative-struct instead of -mms-bitfields when using mingw 1.1
 # (gcc 2.95)
-CFLAGS += -O2 -Wall $(GCCWARNINGS) -pipe -mno-cygwin -mms-bitfields -g
+CFLAGS += -O2 -Wall $(GCCWARNINGS) -pipe -mms-bitfields -g
 
 # If not specified, dlls are built with the default base address of 0x10000000.
 # When loaded into a process address space a dll will be rebased if its base
============================================================
--- libpurple/log.c	80b69c7cb3a375af83575e26f0dd30708f2763ef
+++ libpurple/log.c	ccfee6bf8267f44d0db997d6625581711b83daf1
@@ -38,6 +38,9 @@
 #include "imgstore.h"
 #include "time.h"
 
+#define PURPLE_IS_ACCOUNT(account) TRUE
+#define PURPLE_IS_CONVERSATION(account) TRUE
+#define PURPLE_ACCOUNT(account) ((PurpleAccount *) account)
 
 #if ! GLIB_CHECK_VERSION(2, 19, 8)
 /* Fixes strict-aliasing warning */
@@ -81,32 +84,17 @@ struct _PurpleLogPrivate {
 	struct tm *tm;                     /**< The time this conversation started */
 };
 
-
 typedef struct {
 	PurpleAccount *account;
 	gchar *name;
 } _purple_logsize_user;
 
 typedef struct {
-	PurpleMessageFlags flags;
-	gchar *from;
-	gchar *message;
-	time_t time;
-} _thread_write_callback_data;
-
-typedef struct {
 	PurpleLogReadFlags flags;
 	gchar *text;
 } _purple_log_read_res_callback_data;
 
 typedef struct {
-	PurpleAccount *account;
-	PurpleLogChatType chat_type;
-	gchar *name;
-	gchar *ext;
-} _thread_callback_data;
-
-typedef struct {
 	GAsyncReadyCallback cb;
 	gpointer userdata;
 	guint counter;
@@ -133,7 +121,7 @@ typedef struct {
 	GList *logs;
 	gpointer userdata;
 	guint counter;
-} _get_logs_callback_data;
+} _list_logs_callback_data;
 
 typedef struct {
 	GAsyncReadyCallback cb;
@@ -142,66 +130,28 @@ typedef struct {
 	guint counter;
 } _purple_log_sets_callback_data;
 
-static void thread_callback_data_free(gpointer);
-static void thread_write_callback_data_free(gpointer);
-
-static void write_update_size_cache(PurpleLog *, gssize);
-static void write_thread(GSimpleAsyncResult *, GObject *, GCancellable *);
-static void purple_log_real_write_async(PurpleLog *, PurpleMessageFlags,
-	const gchar *, time_t, const gchar *, gint, GCancellable *,
-	GAsyncReadyCallback, gpointer);
-static gssize purple_log_real_write_finish(PurpleLog *, GAsyncResult *,
-	GError **);
-
-static void log_read_res_free(gpointer);
-static void read_thread(GSimpleAsyncResult *, GObject *, GCancellable *);
-static void purple_log_real_read_async(PurpleLog *, gint, GCancellable *,
-	GAsyncReadyCallback, gpointer);
 static gchar *purple_log_real_read_finish(PurpleLog *, GAsyncResult *,
 	PurpleLogReadFlags *, GError **);
 
-static void size_thread(GSimpleAsyncResult *, GObject *, GCancellable *);
-static void purple_log_real_size_async(PurpleLog *, gint, GCancellable *,
-	GAsyncReadyCallback, gpointer);
 static gssize purple_log_real_size_finish(PurpleLog *, GAsyncResult *,
 	GError **);
 
-static void get_logs_thread(GSimpleAsyncResult *, GObject *, GCancellable *);
-static void purple_log_real_get_logs_async(PurpleLog *, PurpleLogChatType,
-	const gchar *, PurpleAccount *, gint, GCancellable *, GAsyncReadyCallback,
-	gpointer);
-static GList *purple_log_real_get_logs_finish(PurpleLog *, GAsyncResult *,
+static GList *purple_log_real_list_logs_finish(PurpleLog *, GAsyncResult *,
 	GError **);
 
-static void list_syslog_thread(GSimpleAsyncResult *, GObject *, GCancellable *);
-static void purple_log_real_list_syslog_async(PurpleLog *, PurpleAccount *,
-	gint, GCancellable *, GAsyncReadyCallback, gpointer);
 static GList *purple_log_real_list_syslog_finish(PurpleLog *, GAsyncResult *,
 	GError **);
 
-static void total_size_thread(GSimpleAsyncResult *, GObject *, GCancellable *);
-static void purple_log_real_total_size_async(PurpleLog *, PurpleLogChatType,
-	const gchar *, PurpleAccount *, gint, GCancellable *, GAsyncReadyCallback,
-	gpointer);
 static gssize purple_log_real_total_size_finish(PurpleLog *, GAsyncResult *,
 	GError **);
 
-static void get_log_sets_thread(GSimpleAsyncResult *, GObject *,
-	GCancellable *);
-static void purple_log_real_get_log_sets_async(PurpleLog *, gint,
-	GCancellable *, GAsyncReadyCallback, gpointer);
 static GHashTable *purple_log_real_get_log_sets_finish(PurpleLog *,
 	GAsyncResult *, GError **);
 
 static GHashTable *log_get_log_sets_common(GCancellable *, GError **);
-static void log_get_log_sets_common_thread(GSimpleAsyncResult *, GObject *,
-	GCancellable *);
 static void log_get_log_sets_common_async(gint, GCancellable *,
 	GAsyncReadyCallback, gpointer);
 
-static void remove_thread(GSimpleAsyncResult *, GObject *, GCancellable *);
-static void purple_log_real_remove_async(PurpleLog *, gint, GCancellable *,
-	GAsyncReadyCallback, gpointer);
 static gboolean purple_log_real_remove_finish(PurpleLog *, GAsyncResult *,
 	GError **);
 
@@ -211,12 +161,6 @@ static void log_hash_cb(GObject *, GAsyn
 static void log_hash_cb(GObject *, GAsyncResult *, gpointer);
 
 
-G_LOCK_DEFINE(loggers);
-G_LOCK_DEFINE(current_logger);
-G_LOCK_DEFINE(logsize_users);
-G_LOCK_DEFINE(logsize_users_decayed);
-
-
 static GArray *loggers = NULL;
 static GType current_logger = G_TYPE_INVALID;
 static GHashTable *logsize_users = NULL;
@@ -278,6 +222,22 @@ static void
 #endif
 
 static void
+_notify_not_supported(GObject *obj, GAsyncReadyCallback cb, gpointer userdata) {
+	if (cb != NULL) {
+		GSimpleAsyncResult *simple;
+
+		simple = g_simple_async_result_new_error(obj, cb, userdata,
+			G_IO_ERROR,
+			G_IO_ERROR_NOT_SUPPORTED,
+			_("Operation not supported"));
+
+		g_simple_async_result_complete_in_idle(simple);
+		g_object_unref(simple);
+	}
+}
+
+
+static void
 purple_log_class_init(PurpleLogClass *class)
 {
 	GObjectClass *gobject_class = G_OBJECT_CLASS(class);
@@ -288,21 +248,13 @@ purple_log_class_init(PurpleLogClass *cl
 
 	class->logger_name = "";
 	class->logger_id = "";
-	class->write_async = purple_log_real_write_async;
-	class->write_finish = purple_log_real_write_finish;
-	class->list_async = purple_log_real_get_logs_async;
-	class->list_finish = purple_log_real_get_logs_finish;
-	class->read_async = purple_log_real_read_async;
+
 	class->read_finish = purple_log_real_read_finish;
-	class->size_async = purple_log_real_size_async;
 	class->size_finish = purple_log_real_size_finish;
-	class->total_size_async = purple_log_real_total_size_async;
 	class->total_size_finish = purple_log_real_total_size_finish;
-	class->list_syslog_async = purple_log_real_list_syslog_async;
+	class->list_finish = purple_log_real_list_logs_finish;
 	class->list_syslog_finish = purple_log_real_list_syslog_finish;
-	class->get_log_sets_async = purple_log_real_get_log_sets_async;
 	class->get_log_sets_finish = purple_log_real_get_log_sets_finish;
-	class->remove_async = purple_log_real_remove_async;
 	class->remove_finish = purple_log_real_remove_finish;
 
 	properties[PROP_LOG_CHAT_TYPE] =
@@ -427,7 +379,7 @@ purple_log_set_account(PurpleLog *log, P
 {
 	g_return_if_fail(PURPLE_IS_LOG(log));
 	/* Account can be NULL when we create our dummy logs */
-	/* XXX: g_return_if_fail(account == NULL || PURPLE_IS_ACCOUNT(account)); */
+	g_return_if_fail(account == NULL || PURPLE_IS_ACCOUNT(account));
 
 	PURPLE_LOG_GET_PRIVATE(log)->account = account; /* XXX: g_object_ref */
 
@@ -442,7 +394,7 @@ purple_log_set_conversation(PurpleLog *l
 purple_log_set_conversation(PurpleLog *log, PurpleConversation *conversation)
 {
 	g_return_if_fail(PURPLE_IS_LOG(log));
-	/* XXX: g_return_if_fail(conversation == NULL || PURPLE_IS_CONVERSATION(conversation)); */
+	g_return_if_fail(conversation == NULL || PURPLE_IS_CONVERSATION(conversation));
 
 	PURPLE_LOG_GET_PRIVATE(log)->conversation = conversation; /* XXX: g_object_ref */
 
@@ -620,30 +572,6 @@ purple_log_get_property(GObject *object,
 	}
 }
 
-static void
-thread_callback_data_free(gpointer userdata)
-{
-	_thread_callback_data *callback_data = userdata;
-
-	/* XXX;
-	if (callback_data->account != NULL)
-		g_object_unref(callback_data->account); */
-
-	g_free(callback_data->name);
-	g_free(callback_data->ext);
-	g_free(callback_data);
-}
-
-static void
-thread_write_callback_data_free(gpointer userdata)
-{
-	_thread_write_callback_data *callback_data = userdata;
-
-	g_free(callback_data->from);
-	g_free(callback_data->message);
-	g_free(callback_data);
-}
-
 PurpleLog *
 purple_log_new(GType log_type, PurpleLogChatType chat_type, const gchar *name,
 	PurpleAccount *account, PurpleConversation *conv, time_t time,
@@ -654,7 +582,7 @@ purple_log_new(GType log_type, PurpleLog
 	g_return_val_if_fail(log_type == G_TYPE_INVALID || g_type_is_a(log_type, PURPLE_TYPE_LOG),
 		NULL);
 	g_return_val_if_fail(name != NULL, NULL);
-	g_return_val_if_fail(account != NULL, NULL); /* XXX: PURPLE_IS_ACCOUNT(account) */
+	g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
 
 	if (log_type == G_TYPE_INVALID)
 		log_type = current_logger;
@@ -673,60 +601,12 @@ purple_log_new(GType log_type, PurpleLog
 	return log;
 }
 
-static void
-write_update_size_cache(PurpleLog *log, gssize size)
-{
-	_purple_logsize_user *lu;
-	gpointer ptrsize;
-	gssize total;
-
-	if (size <= 0)
-		return;
-
-	lu = g_new(_purple_logsize_user, 1);
-	total = 0;
-
-	lu->name = g_strdup(purple_normalize(purple_log_get_account(log),
-		purple_log_get_name(log)));
-	lu->account = purple_log_get_account(log);
-
-	G_LOCK(logsize_users);
-	if (g_hash_table_lookup_extended(logsize_users, lu, NULL, &ptrsize)) {
-		gchar *tmp = lu->name;
-
-		total = GPOINTER_TO_INT(ptrsize);
-		total += size;
-		g_hash_table_replace(logsize_users, lu, GINT_TO_POINTER(total));
-		/* XXX: purple_debug_info("log", "HASH(purple_log_write): total size %i\n", total); */
-
-		/* The hash table takes ownership of lu, so create a new one
-		 * for the logsize_users_decayed check below. */
-		lu = g_new(_purple_logsize_user, 1);
-		lu->name = g_strdup(tmp);
-		lu->account = purple_log_get_account(log);
-	}
-	G_UNLOCK(logsize_users);
-
-	G_LOCK(logsize_users_decayed);
-	if (g_hash_table_lookup_extended(logsize_users_decayed, lu, NULL, &ptrsize))
-	{
-		total = GPOINTER_TO_INT(ptrsize);
-		total += size;
-		g_hash_table_replace(logsize_users_decayed, lu, GINT_TO_POINTER(total));
-	} else {
-		g_free(lu->name);
-		g_free(lu);
-	}
-	G_UNLOCK(logsize_users_decayed);
-}
-
 gssize
 purple_log_write(PurpleLog *log, PurpleMessageFlags type, const gchar *from,
 	time_t time, const gchar *message, GCancellable *cancellable,
 	GError **error)
 {
 	PurpleLogClass *class;
-	gssize size;
 
 	g_return_val_if_fail(PURPLE_IS_LOG(log), -1);
 	g_return_val_if_fail(from != NULL, -1);
@@ -743,97 +623,31 @@ purple_log_write(PurpleLog *log, PurpleM
 		return -1;
 	}
 
-	size = class->write_fn(log, type, from, time, message, cancellable, error);
-	write_update_size_cache(log, size);
-
-	return size;
+	return class->write_fn(log, type, from, time, message, cancellable, error);
 }
 
-static void
-write_thread(GSimpleAsyncResult *simple, GObject *object,
-	GCancellable *cancellable)
-{
-	_thread_write_callback_data *callback_data =
-		g_simple_async_result_get_op_res_gpointer(simple);
-	PurpleLog *log = PURPLE_LOG(object);
-	PurpleMessageFlags flags = callback_data->flags;
-	GError *error = NULL;
-	gchar *from = callback_data->from, *message = callback_data->message;
-	gssize size;
-	time_t time = callback_data->time;
-
-	size = purple_log_write(log, flags, from, time, message, cancellable, &error);
-
-	if (size < 0)
-		g_simple_async_result_set_from_error(simple, error);
-	else {
-		write_update_size_cache(log, size);
-		g_simple_async_result_set_op_res_gssize(simple, size);
-	}
-
-	g_clear_error(&error);
-}
-
-static void
-purple_log_real_write_async(PurpleLog *log, PurpleMessageFlags flags,
-	const gchar *from, time_t time, const gchar *message, gint io_priority,
-	GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
-{
-	_thread_write_callback_data *callback_data;
-	GSimpleAsyncResult *simple;
-
-	callback_data = g_new0(_thread_write_callback_data, 1);
-	callback_data->flags = flags;
-	callback_data->from = g_strdup(from);
-	callback_data->message = g_strdup(message);
-	callback_data->time = time;
-
-	simple = g_simple_async_result_new(G_OBJECT(log), cb, userdata,
-		purple_log_real_write_async);
-
-	g_simple_async_result_set_op_res_gpointer(simple, callback_data,
-		thread_write_callback_data_free);
-	g_simple_async_result_run_in_thread(simple, write_thread, io_priority,
-		cancellable);
-	g_object_unref(simple);
-}
-
 void
 purple_log_write_async(PurpleLog *log, PurpleMessageFlags type,
 	const gchar *from, time_t time, const gchar *message, gint io_priority,
 	GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
 {
+	PurpleLogClass *class;
+
+	g_return_if_fail(PURPLE_IS_LOG(log));
 	g_return_if_fail(message != NULL);
 	g_return_if_fail(from != NULL);
-	g_return_if_fail(PURPLE_IS_LOG(log));
+	g_return_if_fail(cb == NULL);
+	g_return_if_fail(userdata == NULL);
 
-	PURPLE_LOG_GET_CLASS(log)->write_async(log,
-		type, from, time, message, io_priority,
-		cancellable, cb, userdata);
-}
+	class = PURPLE_LOG_GET_CLASS(log);
 
-static gssize
-purple_log_real_write_finish(PurpleLog *log, GAsyncResult *res, GError **error)
-{
-	return g_simple_async_result_get_op_res_gssize(G_SIMPLE_ASYNC_RESULT(res));
+	if (class->write_async == NULL)
+		_notify_not_supported(G_OBJECT(log), cb, userdata);
+	else
+		PURPLE_LOG_GET_CLASS(log)->write_async(log, type, from, time, message,
+			io_priority, cancellable, cb, userdata);
 }
 
-gssize
-purple_log_write_finish(PurpleLog *log, GAsyncResult *res, GError **error)
-{
-	g_return_val_if_fail(PURPLE_IS_LOG(log), -1);
-	g_return_val_if_fail(G_IS_ASYNC_RESULT(res), -1);
-
-	if (G_IS_SIMPLE_ASYNC_RESULT(res)) {
-		GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT(res);
-
-		if (g_simple_async_result_propagate_error(simple, error))
-			return -1;
-	}
-
-	return PURPLE_LOG_GET_CLASS(log)->write_finish(log, res, error);
-}
-
 gchar *
 purple_log_read(PurpleLog *log, PurpleLogReadFlags *flags,
 	GCancellable *cancellable, GError **error)
@@ -856,66 +670,6 @@ purple_log_read(PurpleLog *log, PurpleLo
 	return class->read_fn(log, flags, cancellable, error);
 }
 
-static void
-log_read_res_free(gpointer data)
-{
-	_purple_log_read_res_callback_data *res_data = data;
-
-	g_free(res_data->text);
-	g_free(res_data);
-}
-
-static void
-read_thread(GSimpleAsyncResult *simple, GObject *object,
-	GCancellable *cancellable)
-{
-	PurpleLog *log = PURPLE_LOG(object);
-	PurpleLogClass *class = PURPLE_LOG_GET_CLASS(log);
-	PurpleLogReadFlags flags;
-	GError *error = NULL;
-	gchar *text;
-
-	if (class->read_fn == NULL) {
-		g_simple_async_result_set_error(simple,
-			G_IO_ERROR,
-			G_IO_ERROR_NOT_SUPPORTED,
-			_("Operation not supported"));
-
-		return;
-	}
-
-	text = class->read_fn(log, &flags, cancellable, &error);
-
-	if (text == NULL)
-		g_simple_async_result_set_from_error(simple, error);
-	else {
-		_purple_log_read_res_callback_data *res_data;
-
-		res_data = g_new0(_purple_log_read_res_callback_data, 1);
-		res_data->flags = flags;
-		res_data->text = text;
-
-		g_simple_async_result_set_op_res_gpointer(simple, res_data,
-			log_read_res_free);
-	}
-
-	g_clear_error(&error);
-}
-
-static void
-purple_log_real_read_async(PurpleLog *log, gint io_priority,
-	GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
-{
-	GSimpleAsyncResult *simple;
-
-	simple = g_simple_async_result_new(G_OBJECT(log), cb, userdata,
-		purple_log_real_read_async);
-
-	g_simple_async_result_run_in_thread(simple, read_thread, io_priority,
-		cancellable);
-	g_object_unref(simple);
-}
-
 void
 purple_log_read_async(PurpleLog *log, gint io_priority,
 	GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
@@ -980,56 +734,21 @@ purple_log_get_size(PurpleLog *log, GCan
 	return class->size_fn(log, cancellable, error);
 }
 
-static void
-size_thread(GSimpleAsyncResult *simple, GObject *object,
-	GCancellable *cancellable)
-{
-	PurpleLog *log = PURPLE_LOG(object);
-	PurpleLogClass *class = PURPLE_LOG_GET_CLASS(log);
-	GError *error = NULL;
-	gssize size;
-
-	if (class->size_fn == NULL) {
-		g_simple_async_result_set_error(simple,
-			G_IO_ERROR,
-			G_IO_ERROR_NOT_SUPPORTED,
-			_("Operation not supported"));
-
-		return;
-	}
-
-	size = class->size_fn(log, cancellable, &error);
-
-	if (size < 0)
-		g_simple_async_result_set_from_error(simple, error);
-	else
-		g_simple_async_result_set_op_res_gssize(simple, size);
-
-	g_clear_error(&error);
-}
-
-static void
-purple_log_real_size_async(PurpleLog *log, gint io_priority,
-	GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
-{
-	GSimpleAsyncResult *simple;
-
-	simple = g_simple_async_result_new(G_OBJECT(log), cb, userdata,
-		purple_log_real_size_async);
-
-	g_simple_async_result_run_in_thread(simple, size_thread, io_priority,
-		cancellable);
-	g_object_unref(simple);
-}
-
 void
 purple_log_get_size_async(PurpleLog *log, gint io_priority,
 	GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
 {
+	PurpleLogClass *class;
+
 	g_return_if_fail(PURPLE_IS_LOG(log));
 
-	PURPLE_LOG_GET_CLASS(log)->size_async(log, io_priority, cancellable, cb,
-		userdata);
+	class = PURPLE_LOG_GET_CLASS(log);
+
+	if (class->size_async == NULL)
+		_notify_not_supported(G_OBJECT(log), cb, userdata);
+	else
+		PURPLE_LOG_GET_CLASS(log)->size_async(log, io_priority, cancellable, cb,
+			userdata);
 }
 
 static gssize
@@ -1055,7 +774,7 @@ GList *
 }
 
 GList *
-purple_log_get_logs(PurpleLog *log, PurpleLogChatType chat_type,
+purple_log_list_logs(PurpleLog *log, PurpleLogChatType chat_type,
 	const gchar *name, PurpleAccount *account, GCancellable *cancellable,
 	GError **error)
 {
@@ -1063,7 +782,7 @@ purple_log_get_logs(PurpleLog *log, Purp
 
 	g_return_val_if_fail(PURPLE_IS_LOG(log), NULL);
 	g_return_val_if_fail(name != NULL, NULL);
-	g_return_val_if_fail(account != NULL, NULL); /* XXX: PURPLE_IS_ACCOUNT(account) */
+	g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
 
 	class = PURPLE_LOG_GET_CLASS(log);
 
@@ -1079,76 +798,35 @@ purple_log_get_logs(PurpleLog *log, Purp
 	return class->list_fn(log, chat_type, name, account, cancellable, error);
 }
 
-static void
-get_logs_thread(GSimpleAsyncResult *simple, GObject *object,
-	GCancellable *cancellable)
-{
-	_thread_callback_data *callback_data =
-		g_simple_async_result_get_op_res_gpointer(simple);
-	PurpleAccount *account = callback_data->account;
-	PurpleLog *log = PURPLE_LOG(object);
-	PurpleLogChatType chat_type = callback_data->chat_type;
-	GError *error = NULL;
-	GList *logs;
-	gchar *name = callback_data->name;
-
-	logs = purple_log_get_logs(log, chat_type, name, account, cancellable,
-		&error);
-
-	if (logs == NULL && error != NULL)
-		g_simple_async_result_set_from_error(simple, error);
-	else
-		g_simple_async_result_set_op_res_gpointer(simple, logs,
-			(GDestroyNotify) purple_log_list_free);
-
-	g_clear_error(&error);
-}
-
-static void
-purple_log_real_get_logs_async(PurpleLog *log, PurpleLogChatType chat_type,
+void
+purple_log_list_logs_async(PurpleLog *log, PurpleLogChatType chat_type,
 	const gchar *name, PurpleAccount *account, gint io_priority,
 	GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
 {
-	_thread_callback_data *callback_data;
-	GSimpleAsyncResult *simple;
+	PurpleLogClass *class;
 
-	callback_data = g_new0(_thread_callback_data, 1);
-	callback_data->chat_type = chat_type;
-	callback_data->name = g_strdup(name);
-	callback_data->account = account; /* XXX: g_object_ref */
-
-	simple = g_simple_async_result_new(G_OBJECT(log), cb, userdata,
-		purple_log_real_get_logs_async);
-
-	g_simple_async_result_set_op_res_gpointer(simple, callback_data,
-		thread_callback_data_free);
-	g_simple_async_result_run_in_thread(simple, get_logs_thread, io_priority,
-		cancellable);
-	g_object_unref(simple);
-}
-
-void
-purple_log_get_logs_async(PurpleLog *log, PurpleLogChatType chat_type,
-	const gchar *name, PurpleAccount *account, gint io_priority,
-	GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
-{
 	g_return_if_fail(PURPLE_IS_LOG(log));
 	g_return_if_fail(name != NULL);
-	g_return_if_fail(account != NULL); /* XXX: PURPLE_IS_ACCOUNT(account) */
+	g_return_if_fail(PURPLE_IS_ACCOUNT(account));
 
-	PURPLE_LOG_GET_CLASS(log)->list_async(log, chat_type, name, account,
-		io_priority, cancellable, cb, userdata);
+	class = PURPLE_LOG_GET_CLASS(log);
+
+	if (class->list_async == NULL)
+		_notify_not_supported(G_OBJECT(log), cb, userdata);
+	else
+		class->list_async(log, chat_type, name, account, io_priority,
+			cancellable, cb, userdata);
 }
 
 static GList *
-purple_log_real_get_logs_finish(PurpleLog *log, GAsyncResult *res,
+purple_log_real_list_logs_finish(PurpleLog *log, GAsyncResult *res,
 	GError **error)
 {
 	return purple_log_list_copy(g_simple_async_result_get_op_res_gpointer(G_SIMPLE_ASYNC_RESULT(res)));
 }
 
 GList *
-purple_log_get_logs_finish(PurpleLog *log, GAsyncResult *res, GError **error)
+purple_log_list_logs_finish(PurpleLog *log, GAsyncResult *res, GError **error)
 {
 	g_return_val_if_fail(PURPLE_IS_LOG(log), NULL);
 	g_return_val_if_fail(G_IS_ASYNC_RESULT(res), NULL);
@@ -1164,7 +842,7 @@ GList *
 }
 
 GList *
-purple_logs_get_logs(PurpleLogChatType chat_type, const gchar *name,
+purple_logs_list_logs(PurpleLogChatType chat_type, const gchar *name,
 	PurpleAccount *account, GCancellable *cancellable, GError **error)
 {
 	GArray *array;
@@ -1172,7 +850,7 @@ purple_logs_get_logs(PurpleLogChatType c
 	guint i;
 
 	g_return_val_if_fail(name != NULL, NULL);
-	g_return_val_if_fail(account != NULL, NULL); /* XXX: PURPLE_IS_ACCOUNT(account) */
+	g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
 
 	array = purple_log_logger_get_all();
 
@@ -1183,7 +861,7 @@ purple_logs_get_logs(PurpleLogChatType c
 		GType log_type = g_array_index(array, GType, i);
 
 		log = g_object_new(log_type, NULL);
-		list = purple_log_get_logs(log, chat_type, name, account, cancellable,
+		list = purple_log_list_logs(log, chat_type, name, account, cancellable,
 			&err);
 
 		if (list == NULL && err != NULL) {
@@ -1202,11 +880,11 @@ void
 }
 
 void
-purple_logs_get_logs_async(PurpleLogChatType chat_type, const gchar *name,
+purple_logs_list_logs_async(PurpleLogChatType chat_type, const gchar *name,
 	PurpleAccount *account, gint io_priority, GCancellable *cancellable,
 	GAsyncReadyCallback cb, gpointer userdata)
 {
-	_get_logs_callback_data *callback_data;
+	_list_logs_callback_data *callback_data;
 	GArray *array;
 	guint i;
 
@@ -1215,7 +893,7 @@ purple_logs_get_logs_async(PurpleLogChat
 
 	array = purple_log_logger_get_all();
 
-	callback_data = g_new0(_get_logs_callback_data, 1);
+	callback_data = g_new0(_list_logs_callback_data, 1);
 	callback_data->cb = cb;
 	callback_data->userdata = userdata;
 	callback_data->counter = array->len;
@@ -1226,14 +904,14 @@ purple_logs_get_logs_async(PurpleLogChat
 		GType log_type = g_array_index(array, GType, i);
 
 		log = g_object_new(log_type, NULL);
-		purple_log_get_logs_async(log, chat_type, name, account, io_priority,
+		purple_log_list_logs_async(log, chat_type, name, account, io_priority,
 			cancellable, log_list_cb, callback_data);
 		g_object_unref(log);
 	}
 }
 
 GList *
-purple_logs_get_logs_finish(GAsyncResult *res, GError **error)
+purple_logs_list_logs_finish(GAsyncResult *res, GError **error)
 {
 	GSimpleAsyncResult *simple;
 
@@ -1248,7 +926,7 @@ GList *
 }
 
 GList *
-purple_log_get_system_logs(PurpleLog *log, PurpleAccount *account,
+purple_log_list_system_logs(PurpleLog *log, PurpleAccount *account,
 	GCancellable *cancellable, GError **error)
 {
 	PurpleLogClass *class;
@@ -1271,7 +949,7 @@ GList *
 }
 
 GList *
-purple_logs_get_system_logs(PurpleAccount *account, GCancellable *cancellable,
+purple_logs_list_system_logs(PurpleAccount *account, GCancellable *cancellable,
 	GError **error)
 {
 	GArray *array;
@@ -1288,7 +966,7 @@ purple_logs_get_system_logs(PurpleAccoun
 		GType log_type = g_array_index(array, GType, i);
 
 		log = g_object_new(log_type, NULL);
-		list = purple_log_get_system_logs(log, account, cancellable, error);
+		list = purple_log_list_system_logs(log, account, cancellable, error);
 
 		if (list == NULL) {
 			purple_log_list_free(logs);
@@ -1304,66 +982,30 @@ purple_logs_get_system_logs(PurpleAccoun
 	return g_list_sort(logs, purple_log_compare);
 }
 
-static void
-list_syslog_thread(GSimpleAsyncResult *simple, GObject *object,
-	GCancellable *cancellable)
-{
-	_thread_callback_data *callback_data =
-		g_simple_async_result_get_op_res_gpointer(simple);
-	PurpleAccount *account = callback_data->account;
-	GError *error = NULL;
-	GList *list;
-
-	list = purple_log_get_system_logs(PURPLE_LOG(object), account, cancellable,
-		&error);
-
-	if (list == NULL && error != NULL)
-		g_simple_async_result_set_from_error(simple, error);
-	else
-		g_simple_async_result_set_op_res_gpointer(simple, list,
-			(GDestroyNotify) purple_log_list_free);
-
-	g_clear_error(&error);
-}
-
-static void
-purple_log_real_list_syslog_async(PurpleLog *log, PurpleAccount *account,
+void
+purple_log_list_system_logs_async(PurpleLog *log, PurpleAccount *account,
 	gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb,
 	gpointer userdata)
 {
-	_thread_callback_data *callback_data;
-	GSimpleAsyncResult *simple;
+	PurpleLogClass *class;
 
-	callback_data = g_new0(_thread_callback_data, 1);
-	callback_data->account = account; /* XXX: g_object_ref */
-
-	simple = g_simple_async_result_new(G_OBJECT(log), cb, userdata,
-		purple_log_real_list_syslog_async);
-
-	g_simple_async_result_set_op_res_gpointer(simple, callback_data,
-		thread_callback_data_free);
-	g_simple_async_result_run_in_thread(simple, list_syslog_thread, io_priority,
-		cancellable);
-	g_object_unref(simple);
-}
-
-void
-purple_log_get_system_logs_async(PurpleLog *log, PurpleAccount *account,
-	gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb,
-	gpointer userdata)
-{
 	g_return_if_fail(PURPLE_IS_LOG(log));
 	g_return_if_fail(account != NULL); /* XXX: PURPLE_IS_ACCOUNT(account) */
 
-	PURPLE_LOG_GET_CLASS(log)->list_syslog_async(log, account, io_priority,
-		cancellable, cb, userdata);
+	class = PURPLE_LOG_GET_CLASS(log);
+
+	if (class->list_syslog_async == NULL)
+		_notify_not_supported(G_OBJECT(log), cb, userdata);
+	else
+		class->list_syslog_async(log, account, io_priority, cancellable, cb,
+			userdata);
 }
 
 void
-purple_logs_get_system_logs_async(PurpleAccount *account, gint io_priority,
+purple_logs_list_system_logs_async(PurpleAccount *account, gint io_priority,
 	GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
 {
-	_get_logs_callback_data *callback_data;
+	_list_logs_callback_data *callback_data;
 	GArray *array;
 	guint i;
 
@@ -1371,7 +1013,7 @@ purple_logs_get_system_logs_async(Purple
 
 	array = purple_log_logger_get_all();
 
-	callback_data = g_new0(_get_logs_callback_data, 1);
+	callback_data = g_new0(_list_logs_callback_data, 1);
 	callback_data->userdata = userdata;
 	callback_data->cb = cb;
 	callback_data->counter = array->len;
@@ -1382,7 +1024,7 @@ purple_logs_get_system_logs_async(Purple
 		GType log_type = g_array_index(array, GType, i);
 
 		log = g_object_new(log_type, NULL);
-		purple_log_get_system_logs_async(log, account, io_priority, cancellable,
+		purple_log_list_system_logs_async(log, account, io_priority, cancellable,
 			log_system_list_cb, callback_data);
 
 		g_object_unref(log);
@@ -1397,7 +1039,7 @@ GList *
 }
 
 GList *
-purple_log_get_system_logs_finish(PurpleLog *log, GAsyncResult *res,
+purple_log_list_system_logs_finish(PurpleLog *log, GAsyncResult *res,
 	GError **error)
 {
 	g_return_val_if_fail(PURPLE_IS_LOG(log), NULL);
@@ -1414,7 +1056,7 @@ GList *
 }
 
 GList *
-purple_logs_get_system_logs_finish(GAsyncResult *res, GError **error)
+purple_logs_list_system_logs_finish(GAsyncResult *res, GError **error)
 {
 	GSimpleAsyncResult *simple;
 
@@ -1465,7 +1107,7 @@ purple_log_get_total_size(PurpleLog *log
 		return class->total_size_fn(log, chat_type, name, account, cancellable,
 			error);
 	} else {
-		GList *logs = purple_log_get_logs(log, chat_type, name, account,
+		GList *logs = purple_log_list_logs(log, chat_type, name, account,
 			cancellable, error);
 		gssize size, total = 0;
 
@@ -1490,105 +1132,24 @@ purple_log_get_total_size(PurpleLog *log
 	}
 }
 
-static void
-total_size_thread(GSimpleAsyncResult *simple, GObject *object,
-	GCancellable *cancellable)
-{
-	_thread_callback_data *callback_data =
-		g_simple_async_result_get_op_res_gpointer(simple);
-	PurpleAccount *account = callback_data->account; /* XXX: g_object_unref */
-	PurpleLog *log = PURPLE_LOG(object);
-	PurpleLogClass *class = PURPLE_LOG_GET_CLASS(log);
-	PurpleLogChatType chat_type = callback_data->chat_type;
-	GError *error = NULL;
-	gchar *name = callback_data->name;
-	gssize size;
-
-	if (class->total_size_fn != NULL) {
-		size = class->total_size_fn(log, chat_type, name, account, cancellable,
-			&error);
-
-		if (size < 0)
-			g_simple_async_result_set_from_error(simple, error);
-		else
-			g_simple_async_result_set_op_res_gssize(simple, size);
-
-		g_clear_error(&error);
-	} else if (class->list_fn != NULL) {
-		/* List the logs and manually size them all up */
-		GList *logs = purple_logs_get_logs(chat_type, name, account,
-			cancellable, &error);
-		gssize total;
-
-		if (logs == NULL && error != NULL) {
-			g_simple_async_result_set_from_error(simple, error);
-			return;
-		}
-
-		g_clear_error(&error);
-
-		for (total = 0; logs != NULL; logs = g_list_delete_link(logs, logs)) {
-			PurpleLog *log_to_size = logs->data;
-
-			size = purple_log_get_size(log_to_size, cancellable, &error);
-
-			if (size < 0) {
-				g_simple_async_result_set_from_error(simple, error);
-				purple_log_list_free(logs);
-
-				return;
-			}
-
-			total += size;
-
-			g_object_unref(log_to_size);
-			g_clear_error(&error);
-		}
-
-		g_simple_async_result_set_op_res_gssize(simple, total);
-	} else {
-		g_simple_async_result_set_error(simple,
-			G_IO_ERROR,
-			G_IO_ERROR_NOT_SUPPORTED,
-			_("Operation not supported"));
-
-		return;
-	}
-}
-
-static void
-purple_log_real_total_size_async(PurpleLog *log, PurpleLogChatType chat_type,
-	const gchar *name, PurpleAccount *account, gint io_priority,
-	GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
-{
-	_thread_callback_data *callback_data;
-	GSimpleAsyncResult *simple;
-
-	callback_data = g_new0(_thread_callback_data, 1);
-	callback_data->chat_type = chat_type;
-	callback_data->name = g_strdup(name);
-	callback_data->account = account; /* XXX: g_object_ref */
-
-	simple = g_simple_async_result_new(G_OBJECT(log), cb, userdata,
-		purple_log_real_total_size_async);
-
-	g_simple_async_result_set_op_res_gpointer(simple, callback_data,
-		thread_callback_data_free);
-	g_simple_async_result_run_in_thread(simple, total_size_thread, io_priority,
-		cancellable);
-	g_object_unref(simple);
-}
-
 void
 purple_log_get_total_size_async(PurpleLog *log, PurpleLogChatType chat_type,
 	const gchar *name, PurpleAccount *account, gint io_priority,
 	GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
 {
+	PurpleLogClass *class;
+
+	g_return_if_fail(PURPLE_IS_LOG(log));
 	g_return_if_fail(name != NULL);
-	g_return_if_fail(account != NULL); /* XXX: PURPLE_IS_ACCOUNT(account) */
+	g_return_if_fail(PURPLE_IS_ACCOUNT(account));
 
-	PURPLE_LOG_GET_CLASS(log)->total_size_async(log, chat_type, name, account,
-		io_priority, cancellable, cb, userdata);
+	class = PURPLE_LOG_GET_CLASS(log);
+
+	if (class->total_size_async == NULL)
+		_notify_not_supported(G_OBJECT(log), cb, userdata);
+	else
+		class->total_size_async(log, chat_type, name, account, io_priority,
+			cancellable, cb, userdata);
 }
 
 static gssize
@@ -1631,9 +1192,7 @@ purple_logs_get_total_size(PurpleLogChat
 	lu->name = g_strdup(purple_normalize(account, name));
 	lu->account = account; /* XXX: g_object_ref? */
 
-	G_LOCK(logsize_users);
 	result = g_hash_table_lookup_extended(logsize_users, lu, NULL, &ptrsize);
-	G_UNLOCK(logsize_users);
 
 	if (result) {
 		total = GPOINTER_TO_INT(ptrsize);
@@ -1658,9 +1217,7 @@ purple_logs_get_total_size(PurpleLogChat
 			total += size;
 		}
 
-		G_LOCK(logsize_users);
 		g_hash_table_replace(logsize_users, lu, GINT_TO_POINTER(total));
-		G_UNLOCK(logsize_users);
 	}
 
 	return total;
@@ -1668,7 +1225,7 @@ purple_logs_get_total_size(PurpleLogChat
 
 /**
  * XXX: Would it make sense to allow the caller to pass in a list of logs, if
- * it just got them from purple_logs_get_logs_async()?  Pidgin asks
+ * it just got them from purple_logs_list_logs_async()?  Pidgin asks
  * for the total size, which means that for some loggers, we end up
  * calling list *again* needlessly (to loop over them and size them).
  * If we had a list of logs, we could loop over them and find those
@@ -1705,9 +1262,7 @@ purple_logs_get_total_size_async(PurpleL
 	callback_data->cb = cb;
 	callback_data->userdata = userdata;
 
-	G_LOCK(logsize_users);
 	result = g_hash_table_lookup_extended(logsize_users, lu, NULL, &ptrsize);
-	G_UNLOCK(logsize_users);
 
 	/* XXX: Fix this up? */
 	if (result) {
@@ -1791,57 +1346,20 @@ purple_log_get_log_sets(PurpleLog *log, 
 	return class->get_log_sets_fn(log, cancellable, error);
 }
 
-static void
-get_log_sets_thread(GSimpleAsyncResult *simple, GObject *object,
-	GCancellable *cancellable)
-{
-	PurpleLog *log = PURPLE_LOG(object);
-	PurpleLogClass *class = PURPLE_LOG_GET_CLASS(log);
-	GError *error = NULL;
-	GHashTable *sets;
-
-	if (class->get_log_sets_fn == NULL) {
-		g_simple_async_result_set_error(simple,
-			G_IO_ERROR,
-			G_IO_ERROR_NOT_SUPPORTED,
-			_("Operation not supported"));
-
-		return;
-	}
-
-	sets = class->get_log_sets_fn(log, cancellable, &error);
-
-	if (sets == NULL)
-		g_simple_async_result_set_from_error(simple, error);
-	else
-		g_simple_async_result_set_op_res_gpointer(simple, sets,
-			(GDestroyNotify) g_hash_table_unref);
-
-	g_clear_error(&error);
-}
-
-static void
-purple_log_real_get_log_sets_async(PurpleLog *log, gint io_priority,
-	GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
-{
-	GSimpleAsyncResult *simple;
-
-	simple = g_simple_async_result_new(G_OBJECT(log), cb, userdata,
-		purple_log_real_get_log_sets_async);
-
-	g_simple_async_result_run_in_thread(simple, get_log_sets_thread,
-		io_priority, cancellable);
-	g_object_unref(simple);
-}
-
 void
 purple_log_get_log_sets_async(PurpleLog *log, gint io_priority,
 	GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
 {
+	PurpleLogClass *class;
+
 	g_return_if_fail(PURPLE_IS_LOG(log));
 
-	PURPLE_LOG_GET_CLASS(log)->get_log_sets_async(log, io_priority, cancellable,
-		cb, userdata);
+	class = PURPLE_LOG_GET_CLASS(log);
+
+	if (class->get_log_sets_async == NULL)
+		_notify_not_supported(G_OBJECT(log), cb, userdata);
+	else
+		class->get_log_sets_async(log, io_priority, cancellable, cb, userdata);
 }
 
 static GHashTable *
@@ -1989,10 +1507,8 @@ purple_log_get_activity_score(PurpleLogC
 	lu->name = g_strdup(purple_normalize(account, name));
 	lu->account = account; /* XXX: g_object_ref? */
 
-	G_LOCK(logsize_users_decayed);
 	result = g_hash_table_lookup_extended(logsize_users_decayed, lu, NULL,
 		&ptrscore);
-	G_UNLOCK(logsize_users_decayed);
 
 	if (result) {
 		score = GPOINTER_TO_INT(ptrscore);
@@ -2006,7 +1522,7 @@ purple_log_get_activity_score(PurpleLogC
 		for (i = 0; i < array->len; i++) {
 			GList *logs;
 
-			logs = purple_logs_get_logs(chat_type, name, account, cancellable,
+			logs = purple_logs_list_logs(chat_type, name, account, cancellable,
 				error);
 
 			if (logs == NULL && error != NULL)
@@ -2035,67 +1551,25 @@ purple_log_get_activity_score(PurpleLogC
 
 		score = (gssize) ceil(score_double);
 
-		G_LOCK(logsize_users_decayed);
 		g_hash_table_replace(logsize_users_decayed, lu, GINT_TO_POINTER(score));
-		G_UNLOCK(logsize_users_decayed);
 	}
 
 	return score;
 }
 
-static void
-activity_score_thread(GSimpleAsyncResult *simple, GObject *object,
-	GCancellable *cancellable)
-{
-	_thread_callback_data *callback_data =
-		g_simple_async_result_get_op_res_gpointer(simple);
-	PurpleAccount *account = callback_data->account;
-	PurpleLogChatType chat_type = callback_data->chat_type;
-	GError *error = NULL;
-	gchar *name = callback_data->name;
-	gssize score;
-
-	score = purple_log_get_activity_score(chat_type, name, account, cancellable,
-		&error);
-
-	if (score < 0)
-		g_simple_async_result_set_from_error(simple, error);
-	else
-		g_simple_async_result_set_op_res_gssize(simple, score);
-
-	g_clear_error(&error);
-}
-
 void
 purple_log_get_activity_score_async(PurpleLogChatType chat_type,
 	const gchar *name, PurpleAccount *account, gint io_priority,
 	GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
 {
-	_thread_callback_data *callback_data;
-	GSimpleAsyncResult *simple;
-
-	callback_data = g_new0(_thread_callback_data, 1);
-	callback_data->chat_type = chat_type;
-	callback_data->name = g_strdup(name);
-	callback_data->account = account; /* XXX: g_object_ref */
-
-	simple = g_simple_async_result_new(G_OBJECT(log), cb, userdata,
-		purple_log_get_activity_score_async);
-
-	g_simple_async_result_set_op_res_gpointer(simple, callback_data,
-		thread_callback_data_free);
-	g_simple_async_result_run_in_thread(simple, activity_score_thread,
-		io_priority, cancellable);
-	g_object_unref(simple);
+	/* XXX: To-do... */
 }
 
 gssize
 purple_log_get_activity_score_finish(GAsyncResult *res, GError **error)
 {
-	GSimpleAsyncResult *simple;
+	GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT(res);
 
-	simple = G_SIMPLE_ASYNC_RESULT(res);
-
 	if (g_simple_async_result_propagate_error(simple, error))
 		return FALSE;
 
@@ -2119,7 +1593,6 @@ purple_log_remove(PurpleLog *log, GCance
 purple_log_remove(PurpleLog *log, GCancellable *cancellable, GError **error)
 {
 	PurpleLogClass *class;
-	gboolean ret;
 
 	g_return_val_if_fail(PURPLE_IS_LOG(log), FALSE);
 
@@ -2134,59 +1607,34 @@ purple_log_remove(PurpleLog *log, GCance
 		return FALSE;
 	}
 
-	ret = class->remove_fn(log, cancellable, error);
-
-	return ret;
+	return class->remove_fn(log, cancellable, error);
 }
 
-static void
-remove_thread(GSimpleAsyncResult *simple, GObject *object,
-	GCancellable *cancellable)
-{
-	PurpleLog *log = PURPLE_LOG(object);
-	GError *error = NULL;
-	gboolean result;
-
-	result = purple_log_remove(log, cancellable, &error);
-
-	if (!result)
-		g_simple_async_result_set_from_error(simple, error);
-	else
-		g_simple_async_result_set_op_res_gboolean(simple, result);
-
-	g_clear_error(&error);
-}
-
-static void
-purple_log_real_remove_async(PurpleLog *log, gint io_priority,
+void
+purple_log_remove_async(PurpleLog *log, gint io_priority,
 	GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
 {
-	GSimpleAsyncResult *simple;
+	PurpleLogClass *class;
 
 	g_return_if_fail(PURPLE_IS_LOG(log));
 
-	simple = g_simple_async_result_new(G_OBJECT(log), cb, userdata,
-		purple_log_real_remove_async);
+	class = PURPLE_LOG_GET_CLASS(log);
 
-	g_simple_async_result_run_in_thread(simple, remove_thread, io_priority,
-		cancellable);
-	g_object_unref(simple);
+	if (class->remove_async == NULL)
+		_notify_not_supported(G_OBJECT(log), cb, userdata);
+	else
+		class->remove_async(log, io_priority, cancellable, cb, userdata);
 }
 
-void
-purple_log_remove_async(PurpleLog *log, gint io_priority,
-	GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
-{
-	g_return_if_fail(PURPLE_IS_LOG(log));
-
-	PURPLE_LOG_GET_CLASS(log)->remove_async(log, io_priority, cancellable, cb,
-		userdata);
-}
-
 static gboolean
 purple_log_real_remove_finish(PurpleLog *log, GAsyncResult *res, GError **error)
 {
-	return g_simple_async_result_get_op_res_gboolean(G_SIMPLE_ASYNC_RESULT(res));
+	GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT(res);
+
+	if (g_simple_async_result_propagate_error(simple, error))
+		return FALSE;
+
+	return g_simple_async_result_get_op_res_gboolean(simple);
 }
 
 gboolean
@@ -2195,13 +1643,6 @@ purple_log_remove_finish(PurpleLog *log,
 	g_return_val_if_fail(PURPLE_IS_LOG(log), FALSE);
 	g_return_val_if_fail(G_IS_ASYNC_RESULT(res), FALSE);
 
-	if (G_IS_SIMPLE_ASYNC_RESULT(res)) {
-		GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT(res);
-
-		if (g_simple_async_result_propagate_error(simple, error))
-			return FALSE;
-	}
-
 	return PURPLE_LOG_GET_CLASS(log)->remove_finish(log, res, error);
 }
 
@@ -2215,7 +1656,7 @@ purple_log_get_log_dir(PurpleLogChatType
 	gchar *acct_name, *dir, *temp;
 
 	g_return_val_if_fail(name != NULL, NULL);
-	g_return_val_if_fail(account != NULL, NULL); /* XXX: PURPLE_IS_ACCOUNT(account) */
+	g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
 
 	prpl = purple_find_prpl(purple_account_get_protocol_id(account));
 
@@ -2280,16 +1721,13 @@ purple_log_logger_add(GType log_type)
 
 	g_return_if_fail(log_type == G_TYPE_INVALID || g_type_is_a(log_type, PURPLE_TYPE_LOG));
 
-	G_LOCK(loggers);
 	for (i = 0; i < loggers->len; i++) {
 		if (log_type == g_array_index(loggers, GType, i)) {
-			G_UNLOCK(loggers);
 			return;
 		}
 	}
 
 	loggers = g_array_append_val(loggers, log_type);
-	G_UNLOCK(loggers);
 
 	class = g_type_class_ref(log_type);
 
@@ -2305,7 +1743,6 @@ purple_log_logger_remove(GType log_type)
 
 	g_return_if_fail(log_type == G_TYPE_INVALID || g_type_is_a(log_type, PURPLE_TYPE_LOG));
 
-	G_LOCK(loggers);
 	for (i = 0; i < loggers->len; i++) {
 		if (log_type == g_array_index(loggers, GType, i)) {
 			loggers = g_array_remove_index_fast(loggers, i);
@@ -2314,7 +1751,6 @@ purple_log_logger_remove(GType log_type)
 			break;
 		}
 	}
-	G_UNLOCK(loggers);
 }
 
 void
@@ -2322,33 +1758,19 @@ purple_log_logger_set(GType log_type)
 {
 	g_return_if_fail(log_type == G_TYPE_INVALID || g_type_is_a(log_type, PURPLE_TYPE_LOG));
 
-	G_LOCK(current_logger);
 	current_logger = log_type;
-	G_UNLOCK(current_logger);
 }
 
 GType
 purple_log_logger_get_default(void)
 {
-	GType log_type;
-
-	G_LOCK(current_logger);
-	log_type = current_logger;
-	G_UNLOCK(current_logger);
-
-	return log_type;
+	return current_logger;
 }
 
 GArray *
 purple_log_logger_get_all(void)
 {
-	GArray *array;
-
-	G_LOCK(loggers);
-	array = loggers;
-	G_UNLOCK(loggers);
-
-	return array;
+	return loggers;
 }
 
 GList *
@@ -2488,12 +1910,7 @@ purple_log_system_init(void)
 {
 	void *handle = purple_log_system_get_handle();
 
-	if (!g_thread_supported())
-		g_thread_init(NULL);
-
-	G_LOCK(loggers);
 	loggers = g_array_sized_new(FALSE, FALSE, sizeof(GType), 3);
-	G_UNLOCK(loggers);
 
 	purple_prefs_add_none("/purple/logging");
 	purple_prefs_add_bool("/purple/logging/log_ims", TRUE);
@@ -2527,17 +1944,13 @@ purple_log_system_init(void)
 		logger_pref_cb, NULL);
 	purple_prefs_trigger_callback("/purple/logging/format");
 
-	G_LOCK(logsize_users);
 	logsize_users = g_hash_table_new_full((GHashFunc) _purple_logsize_user_hash,
 		(GEqualFunc) _purple_logsize_user_equal,
 		(GDestroyNotify) _purple_logsize_user_free_key, NULL);
-	G_UNLOCK(logsize_users);
 
-	G_LOCK(logsize_users_decayed);
 	logsize_users_decayed = g_hash_table_new_full((GHashFunc) _purple_logsize_user_hash,
 		(GEqualFunc) _purple_logsize_user_equal,
 		(GDestroyNotify) _purple_logsize_user_free_key, NULL);
-	G_UNLOCK(logsize_users_decayed);
 }
 
 void *
@@ -2557,21 +1970,15 @@ purple_log_system_uninit(void)
 	purple_txt_log_system_uninit();
 	purple_old_log_system_uninit();
 
-	G_LOCK(loggers);
 	g_array_free(loggers, TRUE);
 	loggers = NULL;
 	current_logger = G_TYPE_INVALID;
-	G_UNLOCK(loggers);
 
-	G_LOCK(logsize_users);
 	g_hash_table_destroy(logsize_users);
 	logsize_users = NULL;
-	G_UNLOCK(logsize_users);
 
-	G_LOCK(logsize_users_decayed);
 	g_hash_table_destroy(logsize_users_decayed);
 	logsize_users_decayed = NULL;
-	G_UNLOCK(logsize_users_decayed);
 }
 
 gchar *
@@ -2729,9 +2136,8 @@ log_get_log_sets_common(GCancellable *ca
 				account_iter != NULL;
 				account_iter = g_list_next(account_iter))
 			{
-				/* XXX: PURPLE_ACCOUNT(...)->username */
 				if (purple_strequal(username_unescaped,
-					purple_normalize(account_iter->data, ((PurpleAccount *) account_iter->data)->username)))
+					purple_normalize(account_iter->data, PURPLE_ACCOUNT(account_iter->data)->username)))
 				{
 					account = account_iter->data;
 					break;
@@ -2807,35 +2213,10 @@ static void
 }
 
 static void
-log_get_log_sets_common_thread(GSimpleAsyncResult *simple, GObject *object,
-	GCancellable *cancellable)
-{
-	GError *error = NULL;
-	GHashTable *sets;
-
-	sets = log_get_log_sets_common(cancellable, &error);
-
-	if (sets == NULL)
-		g_simple_async_result_set_from_error(simple, error);
-	else
-		g_simple_async_result_set_op_res_gpointer(simple, sets,
-			(GDestroyNotify) g_hash_table_unref);
-
-	g_clear_error(&error);
-}
-
-static void
 log_get_log_sets_common_async(gint io_priority, GCancellable *cancellable,
 	GAsyncReadyCallback cb, gpointer userdata)
 {
-	GSimpleAsyncResult *simple;
-
-	simple = g_simple_async_result_new(NULL, cb, userdata,
-		log_get_log_sets_common_async);
-
-	g_simple_async_result_run_in_thread(simple, log_get_log_sets_common_thread,
-		io_priority, cancellable);
-	g_object_unref(simple);
+	/* XXX: To-do */
 }
 
 static void
@@ -2861,12 +2242,12 @@ log_list_cb(GObject *object, GAsyncResul
 static void
 log_list_cb(GObject *object, GAsyncResult *res, gpointer userdata)
 {
-	_get_logs_callback_data *callback_data = userdata;
+	_list_logs_callback_data *callback_data = userdata;
 	PurpleLog *log = PURPLE_LOG(object);
 	GError *error = NULL;
 	GList *list;
 
-	list = purple_log_get_logs_finish(log, res, &error);
+	list = purple_log_list_logs_finish(log, res, &error);
 
 	if (list == NULL) {
 		if (error != NULL && error->code != G_IO_ERROR_NOT_SUPPORTED)
@@ -2882,7 +2263,7 @@ log_list_cb(GObject *object, GAsyncResul
 	if (callback_data->counter < 1) {
 		GSimpleAsyncResult *simple = g_simple_async_result_new(NULL,
 			callback_data->cb, callback_data->userdata,
-			purple_logs_get_logs_async);
+			purple_logs_list_logs_async);
 
 		g_simple_async_result_set_op_res_gpointer(simple, callback_data->logs,
 			(GDestroyNotify) purple_log_list_free);
@@ -2896,12 +2277,12 @@ log_system_list_cb(GObject *object, GAsy
 static void
 log_system_list_cb(GObject *object, GAsyncResult *res, gpointer userdata)
 {
-	_get_logs_callback_data *callback_data = userdata;
+	_list_logs_callback_data *callback_data = userdata;
 	PurpleLog *log = PURPLE_LOG(object);
 	GError *error = NULL;
 	GList *list;
 
-	list = purple_log_get_system_logs_finish(log, res, &error);
+	list = purple_log_list_system_logs_finish(log, res, &error);
 
 	if (list == NULL) {
 		if (error != NULL && error->code != G_IO_ERROR_NOT_SUPPORTED)
@@ -2917,7 +2298,7 @@ log_system_list_cb(GObject *object, GAsy
 	if (callback_data->counter < 1) {
 		GSimpleAsyncResult *simple = g_simple_async_result_new(NULL,
 			callback_data->cb, callback_data->userdata,
-			purple_logs_get_system_logs_async);
+			purple_logs_list_system_logs_async);
 
 		g_simple_async_result_set_op_res_gpointer(simple, callback_data->logs,
 			(GDestroyNotify) purple_log_list_free);
@@ -2979,7 +2360,7 @@ log_hash_cb(GObject *object, GAsyncResul
 	if (one_set == NULL) {
 		if (error->code != G_IO_ERROR_NOT_SUPPORTED)
 			purple_debug_error("log", "Error getting log sets for %s: %s\n",
-				log != NULL ? PURPLE_LOG_GET_CLASS(log)->logger_name : "log_get_log_sets_common",
+				log != NULL ? PURPLE_LOG_GET_CLASS(log)->logger_name : "log_list_log_sets_common",
 				error->message);
 	} else {
 		g_hash_table_foreach_steal(one_set, steal_log_sets,
============================================================
--- libpurple/log.h	5401d5b806003e6ece8afb49622f92e0ad4632a8
+++ libpurple/log.h	36314213686f35f7ae39ac217fe5d35fc0032246
@@ -121,10 +121,11 @@ struct _PurpleLogClass {
 	void (* write_async) (PurpleLog *log, PurpleMessageFlags type,
 		const gchar *from, time_t time, const gchar *message,
 		gint io_priority, GCancellable *cancellable,
-		GAsyncReadyCallback callback, gpointer user_data);
+		GAsyncReadyCallback cb, gpointer userdata);
 
-	/** Finishes an asynchronous write operation */
-	gssize (* write_finish) (PurpleLog *log, GAsyncResult *res, GError **error);
+	/** Finishes writing a message to a log (Unused currently) */
+	/*gssize (* write_finish) (PurpleLog *log, GCancellable *cancellable,
+		GError **error);*/
 
 	/** Reads all messages from a log */
 	gchar * (* read_fn) (PurpleLog *log, PurpleLogReadFlags *flags,
@@ -132,8 +133,8 @@ struct _PurpleLogClass {
 
 	/** Asynchronously reads all messages from a log */
 	void (* read_async) (PurpleLog *log, gint io_priority,
-		GCancellable *cancellable, GAsyncReadyCallback callback,
-		gpointer user_data);
+		GCancellable *cancellable, GAsyncReadyCallback cb,
+		gpointer userdata);
 
 	/** Finishes an asynchronous read operation */
 	gchar * (* read_finish) (PurpleLog *log, GAsyncResult *res,
@@ -145,8 +146,8 @@ struct _PurpleLogClass {
 
 	/** Asynchronously gets the size of a log */
 	void (* size_async) (PurpleLog *log, gint io_priority,
-		GCancellable *cancellable, GAsyncReadyCallback callback,
-		gpointer user_data);
+		GCancellable *cancellable, GAsyncReadyCallback cb,
+		gpointer userdata);
 
 	/** Finishes an asynchronous size operation */
 	gssize (* size_finish) (PurpleLog *log, GAsyncResult *res, GError **error);
@@ -167,8 +168,7 @@ struct _PurpleLogClass {
 	 */
 	void (* list_async) (PurpleLog *log, PurpleLogChatType type,
 		const gchar *name, PurpleAccount *account, gint io_priority,
-		GCancellable *cancellable, GAsyncReadyCallback callback,
-		gpointer user_data);
+		GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata);
 
 	/**
 	 * Finishes an asynchronous list logs operation
@@ -191,8 +191,8 @@ struct _PurpleLogClass {
 	 * The log argument is a dummy object, only used to keep track of the class
 	 */
 	void (* list_syslog_async) (PurpleLog *log, PurpleAccount *account,
-		gint io_priority, GCancellable *cancellable,
-		GAsyncReadyCallback callback, gpointer user_data);
+		gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb,
+		gpointer userdata);
 
 	/**
 	 * Finishes an asynchronous list system logs operation
@@ -220,8 +220,7 @@ struct _PurpleLogClass {
 	 */
 	void (* total_size_async) (PurpleLog *log, PurpleLogChatType type,
 		const gchar *name, PurpleAccount *account, gint io_priority,
-		GCancellable *cancellable, GAsyncReadyCallback callback,
-		gpointer user_data);
+		GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata);
 
 	/**
 	 * Finishes an asynchronous total size operation
@@ -246,8 +245,7 @@ struct _PurpleLogClass {
 
 	/** Asynchronously gets all available log sets */
 	void (* get_log_sets_async) (PurpleLog *log, gint io_priority,
-		GCancellable *cancellable, GAsyncReadyCallback callback,
-		gpointer user_data);
+		GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata);
 
 	/** Finishes an asynchronous get log sets operation */
 	GHashTable * (* get_log_sets_finish) (PurpleLog *log, GAsyncResult *res,
@@ -259,8 +257,7 @@ struct _PurpleLogClass {
 
 	/** Asynchronously removes a log */
 	void (* remove_async) (PurpleLog *log, gint io_priority,
-		GCancellable *cancellable, GAsyncReadyCallback callback,
-		gpointer user_data);
+		GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata);
 
 	/** Finishes an asynchronously remove operation */
 	gboolean (* remove_finish) (PurpleLog *log, GAsyncResult *res,
@@ -402,6 +399,8 @@ G_CONST_RETURN struct tm *purple_log_get
  * @param message      The message to log
  * @param cancellable  (allow-none): GCancellable object
  * @param error        (out) (allow-none): a GError location to store the error
+ *
+ * @return             Number of bytes written, -1 on error.
  */
 gssize purple_log_write(PurpleLog *log, PurpleMessageFlags type,
 	const gchar *from, time_t time, const gchar *message,
@@ -410,6 +409,9 @@ gssize purple_log_write(PurpleLog *log, 
 /**
  * Writes to a log file asychronously. Assumes you have checked preferences already.
  *
+ * Note: Currently the cb and userdata are ignored, they are just here to allow
+ * the API to be extended further in the future.
+ *
  * @param log          The log to write to
  * @param type         The type of message being logged
  * @param from         Whom this message is coming from, or @c %NULL for system messages
@@ -428,20 +430,6 @@ void purple_log_write_async(PurpleLog *l
 	GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata);
 
 /**
- * Finishing asynchronously writing to a log
- *
- * @param log          The log that was to be written to
- * @param res          A GAsyncResult
- * @param error        (out) (allow-none): a GError location to store the error
- *
- * @return             Number of bytes written, -1 on failure
- *
- * @since 3.0.0
- */
-gssize purple_log_write_finish(PurpleLog *log, GAsyncResult *res,
-	GError **error);
-
-/**
  * Reads from a log
  *
  * @param log          The log to read from
@@ -541,7 +529,7 @@ gssize purple_log_get_size_finish(Purple
  *
  * @return             A sorted list of logs
  */
-GList *purple_log_get_logs(PurpleLog *log, PurpleLogChatType type,
+GList *purple_log_list_logs(PurpleLog *log, PurpleLogChatType type,
 	const gchar *name, PurpleAccount *account, GCancellable *cancellable,
 	GError **error);
 
@@ -560,7 +548,7 @@ GList *purple_log_get_logs(PurpleLog *lo
  *
  * @since 3.0.0
  */
-void purple_log_get_logs_async(PurpleLog *log, PurpleLogChatType type,
+void purple_log_list_logs_async(PurpleLog *log, PurpleLogChatType type,
 	const gchar *name, PurpleAccount *account, gint io_priority,
 	GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata);
 
@@ -579,7 +567,7 @@ void purple_log_get_logs_async(PurpleLog
  *
  * @since 3.0.0
  */
-GList *purple_log_get_logs_finish(PurpleLog *log, GAsyncResult *res,
+GList *purple_log_list_logs_finish(PurpleLog *log, GAsyncResult *res,
 	GError **error);
 
 /**
@@ -596,7 +584,7 @@ GList *purple_log_get_logs_finish(Purple
  *
  * @since 3.0.0
  */
-GList *purple_logs_get_logs(PurpleLogChatType chat_type, const gchar *name,
+GList *purple_logs_list_logs(PurpleLogChatType chat_type, const gchar *name,
 	PurpleAccount *account, GCancellable *cancellable, GError **error);
 
 /**
@@ -617,7 +605,7 @@ GList *purple_logs_get_logs(PurpleLogCha
  *
  * @since 3.0.0
  */
-void purple_logs_get_logs_async(PurpleLogChatType type, const gchar *name,
+void purple_logs_list_logs_async(PurpleLogChatType type, const gchar *name,
 	PurpleAccount *account, gint io_priority, GCancellable *cancellable,
 	GAsyncReadyCallback cb, gpointer userdata);
 
@@ -632,7 +620,7 @@ void purple_logs_get_logs_async(PurpleLo
  *
  * @since 3.0.0
  */
-GList *purple_logs_get_logs_finish(GAsyncResult *res, GError **error);
+GList *purple_logs_list_logs_finish(GAsyncResult *res, GError **error);
 
 /**
  * Returns a list of all available system logs
@@ -644,7 +632,7 @@ GList *purple_logs_get_logs_finish(GAsyn
  *
  * @return             A sorted list of logs
  */
-GList *purple_log_get_system_logs(PurpleLog *log, PurpleAccount *account,
+GList *purple_log_list_system_logs(PurpleLog *log, PurpleAccount *account,
 	GCancellable *cancellable, GError **error);
 
 /**
@@ -660,7 +648,7 @@ GList *purple_log_get_system_logs(Purple
  *
  * @since 3.0.0
  */
-void purple_log_get_system_logs_async(PurpleLog *log, PurpleAccount *account,
+void purple_log_list_system_logs_async(PurpleLog *log, PurpleAccount *account,
 	gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb,
 	gpointer userdata);
 
@@ -678,7 +666,7 @@ void purple_log_get_system_logs_async(Pu
  *
  * @since 3.0.0
  */
-GList *purple_log_get_system_logs_finish(PurpleLog *log, GAsyncResult *res,
+GList *purple_log_list_system_logs_finish(PurpleLog *log, GAsyncResult *res,
 	GError **error);
 
 /**
@@ -693,7 +681,7 @@ GList *purple_log_get_system_logs_finish
  *
  * @since 3.0.0
  */
-GList *purple_logs_get_system_logs(PurpleAccount *account,
+GList *purple_logs_list_system_logs(PurpleAccount *account,
 	GCancellable *cancellable, GError **error);
 
 /**
@@ -710,7 +698,7 @@ GList *purple_logs_get_system_logs(Purpl
  *
  * @since 3.0.0
  */
-void purple_logs_get_system_logs_async(PurpleAccount *account,
+void purple_logs_list_system_logs_async(PurpleAccount *account,
 	gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb,
 	gpointer userdata);
 
@@ -726,7 +714,7 @@ void purple_logs_get_system_logs_async(P
  *
  * @since 3.0.0
  */
-GList *purple_logs_get_system_logs_finish(GAsyncResult *res, GError **error);
+GList *purple_logs_list_system_logs_finish(GAsyncResult *res, GError **error);
 
 /**
  * Returns the size, in bytes, of all logs of a conversation
============================================================
--- pidgin/gtklog.c	32e9b991f41f55d5f5d499f874dbcf1b4a3a7da5
+++ pidgin/gtklog.c	b5d00dacd9ac018f989a85737b28be4fed6879f2
@@ -39,6 +39,7 @@
 #include "gtkutils.h"
 #include "gtkwebview.h"
 
+
 /* Helpful macros */
 #define G_OBJECT_CHECK_UNREF(obj) \
 	{ \
@@ -156,7 +157,7 @@ typedef struct {
 } log_viewer_hash_t;
 
 
-/* Function prototypes */
+/* Prototypes */
 static void pidgin_log_data_free(_pidgin_log_data *);
 static void pidgin_window_destroy_cb(_pidgin_log_data *);
 static guint log_viewer_hash(gconstpointer);
@@ -198,6 +199,7 @@ static void pidgin_log_viewer_set_select
 static void pidgin_log_viewer_set_selected(PidginLogViewer *,
 	gboolean);
 
+
 /* Globals */
 static GHashTable *log_viewers = NULL;
 static PidginLogViewer *syslog_viewer = NULL;
@@ -795,7 +797,6 @@ pidgin_log_read_cb(GObject *object, GAsy
 		purple_signal_emit(pidgin_log_get_handle(), "log-displaying", lv, log);
 
 		webkit_web_view_load_html_string(wv, text, "");
-		g_free(text);
 
 		/**
 		 * If we have something in the search bar, scroll to it in the
============================================================
--- pidgin/gtklog.h	4c1cf591166e27075c53a323cbce435f2e320480
+++ pidgin/gtklog.h	d992054bda64fef187374c9ea3209d412f83a8a4
@@ -61,7 +61,6 @@ struct _PidginLogViewerClass {
 struct _PidginLogViewerClass {
 	GtkDialogClass parent_class;
 
-	GtkWidget        *web_view;  /**< The webkit web view to display said logs */
 	void (*_purple_reserved1)(void);
 	void (*_purple_reserved2)(void);
 	void (*_purple_reserved3)(void);
============================================================
--- pidgin/Makefile.mingw	a53a15e518f04d76945363cafd54fbbdd4d2c4c8
+++ pidgin/Makefile.mingw	08760710a3a91a2475f10c9fbf5ecbf99a7e0e7e
@@ -40,6 +40,7 @@ INCLUDE_PATHS +=	\
 			-I$(GTK_TOP)/include/atk-1.0 \
 			-I$(GTK_TOP)/include/cairo \
 			-I$(GTK_TOP)/lib/gtk-2.0/include \
+			-I$(GTK_TOP)/../mingw/include \
 			-I$(GTKSPELL_TOP)/include/gtkspell-2.0
 
 LIB_PATHS +=		-L$(GTK_TOP)/lib \
@@ -129,6 +130,7 @@ PIDGIN_LIBS =	\
 		-lgdk-win32-2.0 \
 		-lgdk_pixbuf-2.0 \
 		-lgdi32 \
+		-lwebkitgtk-1.0-0 \
 		-lwinmm
 
 include $(PIDGIN_COMMON_RULES)
============================================================
--- pidgin/plugins/Makefile.mingw	2ca9d675de9f481f12e31c48166361bea5373eb8
+++ pidgin/plugins/Makefile.mingw	81986167ee8e02c85f202cd226af4f2332196a22
@@ -20,6 +20,7 @@ INCLUDE_PATHS +=	\
 ## INCLUDE PATHS
 ##
 INCLUDE_PATHS +=	\
+			-I$(GTK_TOP)/../mingw/include \
 			-I$(GTK_TOP)/include \
 			-I$(GTK_TOP)/include/gtk-2.0 \
 			-I$(GTK_TOP)/include/glib-2.0 \
@@ -94,7 +95,7 @@ plugins: \
 		gtkbuddynote.dll \
 		history.dll \
 		iconaway.dll \
-		markerline.dll \
+#		markerline.dll \
 		notify.dll \
 		pidginrc.dll \
 		relnot.dll \
============================================================
--- libpurple/plugins/Makefile.mingw	3f82da8af389ddfab2842bf352efc37b9c81e164
+++ libpurple/plugins/Makefile.mingw	75d115aa01d572d8cd16cbce1f3de29054c75750
@@ -7,7 +7,7 @@ include $(PIDGIN_TREE_TOP)/libpurple/win
 PIDGIN_TREE_TOP := ../..
 include $(PIDGIN_TREE_TOP)/libpurple/win32/global.mak
 
-#PERL_PLUGIN := ./perl
+PERL_PLUGIN := ./perl
 TCL_PLUGIN := ./tcl
 SSL_PLUGIN := ./ssl
 
@@ -46,12 +46,12 @@ all: $(PURPLE_DLL).a plugins
 
 all: $(PURPLE_DLL).a plugins
 #	$(MAKE) -C $(PERL_PLUGIN) -f $(MINGW_MAKEFILE)
-	$(MAKE) -C $(TCL_PLUGIN) -f $(MINGW_MAKEFILE)
+#	$(MAKE) -C $(TCL_PLUGIN) -f $(MINGW_MAKEFILE)
 	$(MAKE) -C $(SSL_PLUGIN) -f $(MINGW_MAKEFILE)
 
 install: all $(PURPLE_INSTALL_PLUGINS_DIR)
 #	$(MAKE) -C $(PERL_PLUGIN) -f $(MINGW_MAKEFILE) install
-	$(MAKE) -C $(TCL_PLUGIN) -f $(MINGW_MAKEFILE) install
+#	$(MAKE) -C $(TCL_PLUGIN) -f $(MINGW_MAKEFILE) install
 	$(MAKE) -C $(SSL_PLUGIN) -f $(MINGW_MAKEFILE) install
 	cp *.dll $(PURPLE_INSTALL_PLUGINS_DIR)
 
@@ -76,7 +76,7 @@ clean:
 clean:
 	rm -f *.o *.dll
 #	$(MAKE) -C $(PERL_PLUGIN) -f $(MINGW_MAKEFILE) clean
-	$(MAKE) -C $(TCL_PLUGIN) -f $(MINGW_MAKEFILE) clean
+#	$(MAKE) -C $(TCL_PLUGIN) -f $(MINGW_MAKEFILE) clean
 	$(MAKE) -C $(SSL_PLUGIN) -f $(MINGW_MAKEFILE) clean
 
 include $(PIDGIN_COMMON_TARGETS)
============================================================
--- pidgin/win32/nsis/generate_gtk_zip.sh	92ff2c0ade607716d4f6ea8751473a4a7da4b4c9
+++ pidgin/win32/nsis/generate_gtk_zip.sh	2c435157ca1d9f3518512079cbc137333db51a91
@@ -14,21 +14,22 @@ CONTENTS_FILE=$INSTALL_DIR/CONTENTS
 CONTENTS_FILE=$INSTALL_DIR/CONTENTS
 
 #This needs to be changed every time there is any sort of change.
-BUNDLE_VERSION=2.16.6.0
+BUNDLE_VERSION=2.24.0.1
 
-ATK="http://ftp.acc.umu.se/pub/gnome/binaries/win32/atk/1.26/atk_1.26.0-1_win32.zip ATK 1.26.0-1"
-CAIRO="http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/cairo_1.8.10-1_win32.zip Cairo 1.8.10-1"
+ATK="http://ftp.gnome.org/pub/gnome/binaries/win32/atk/1.32/atk_1.32.0-1_win32.zip ATK 1.32.0-1"
+CAIRO="http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/cairo_1.10.2-1_win32.zip Cairo 1.10.2-1"
 EXPAT="http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/expat_2.0.1-1_win32.zip Expat 2.0.1-1"
 FONTCONFIG="http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/fontconfig_2.8.0-2_win32.zip Fontconfig 2.8.0-2"
-FREETYPE="http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/freetype_2.3.11-2_win32.zip Freetype 2.3.11-2"
-GETTEXT="http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/gettext-runtime-0.17-1.zip Gettext 0.17-1"
-GLIB="http://ftp.gnome.org/pub/gnome/binaries/win32/glib/2.20/glib_2.20.5-1_win32.zip Glib 2.20.5-1"
-GTK="http://ftp.acc.umu.se/pub/gnome/binaries/win32/gtk+/2.16/gtk+_2.16.6-2_win32.zip GTK+ 2.16.6-2"
-LIBPNG="http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/libpng_1.4.0-1_win32.zip libpng 1.4.0-1"
-PANGO="http://ftp.gnome.org/pub/gnome/binaries/win32/pango/1.26/pango_1.26.2-1_win32.zip Pango 1.26.2-1"
-ZLIB="http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/zlib-1.2.3.zip zlib 1.2.3"
+FREETYPE="http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/freetype_2.4.4-1_win32.zip Freetype 2.4.4-1"
+GETTEXT="http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/gettext-runtime_0.18.1.1-2_win32.zip Gettext 0.18.1.1-2"
+GLIB="http://ftp.gnome.org/pub/gnome/binaries/win32/glib/2.28/glib_2.28.1-1_win32.zip Glib 2.28.1-1"
+GDK_PIXBUF="http://ftp.gnome.org/pub/gnome/binaries/win32/gdk-pixbuf/2.22/gdk-pixbuf_2.22.1-1_win32.zip Gdk-pixbuf 2.22.1-1"
+GTK="http://ftp.gnome.org/pub/gnome/binaries/win32/gtk+/2.24/gtk+_2.24.0-1_win32.zip GTK+ 2.24.0-1"
+LIBPNG="http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/libpng_1.4.3-1_win32.zip libpng 1.4.3-1"
+PANGO="http://ftp.gnome.org/pub/gnome/binaries/win32/pango/1.28/pango_1.28.3-1_win32.zip Pango 1.28.3-1"
+ZLIB="http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/zlib_1.2.5-2_win32.zip zlib 1.2.5-2"
 
-ALL="ATK CAIRO EXPAT FONTCONFIG FREETYPE GETTEXT GLIB GTK LIBPNG PANGO ZLIB"
+ALL="ATK CAIRO EXPAT FONTCONFIG FREETYPE GETTEXT GLIB GDK_PIXBUF GTK LIBPNG PANGO ZLIB"
 
 mkdir -p $STAGE_DIR
 cd $STAGE_DIR
============================================================
--- libpurple/htmllog.c	a54e51eb531b008a5b64c756115a2934c070b67c
+++ libpurple/htmllog.c	ba0f5c5b13a3fc73a9989f92ec83922a04c66c53
@@ -28,49 +28,50 @@
 #include "debug.h"
 #include "htmllog.h"
 
-G_DEFINE_TYPE (PurpleHtmlLog, purple_html_log, PURPLE_TYPE_COMMON_LOG)
+/* Local structures */
+typedef struct {
+	PurpleLog *log;
+	PurpleMessageFlags type;
+	gchar *from;
+	time_t time;
+	gchar *message;
+	gint io_priority;
+	GCancellable *cancellable;
+	GAsyncReadyCallback cb;
+	gpointer userdata;
+	gboolean write_header;
+	GOutputStream *out_stream;
+} _purple_html_write_callback_data;
 
-static gboolean purple_html_log_create(PurpleLog *, GCancellable *, GError **);
-static gssize purple_html_log_write(PurpleLog *, PurpleMessageFlags,
-	const gchar *, time_t, const gchar *, GCancellable *, GError **);
-static GList *purple_html_log_list(PurpleLog *, PurpleLogChatType,
-	const gchar *, PurpleAccount *, GCancellable *, GError **);
-static gchar *purple_html_log_read(PurpleLog *, PurpleLogReadFlags *,
-	GCancellable *, GError **);
-static gssize purple_html_log_total_size(PurpleLog *, PurpleLogChatType,
-	const gchar *, PurpleAccount *, GCancellable *, GError **);
-static GList *purple_html_log_list_syslog(PurpleLog *, PurpleAccount *,
-	GCancellable *, GError **);
-static void purple_html_log_finalize(GObject *);
+/* Function prototypes */
+static void purple_html_log_write_async_2(PurpleLog *, GAsyncResult *,
+	_purple_html_write_callback_data *);
+static void purple_html_log_write_async_3(GFile *, GAsyncResult *,
+	_purple_html_write_callback_data *);
 
-static void
-purple_html_log_class_init(PurpleHtmlLogClass *class)
-{
-	GObjectClass *gobject_class = G_OBJECT_CLASS(class);
-	PurpleLogClass *log_class = PURPLE_LOG_CLASS(class);
+G_DEFINE_TYPE (PurpleHtmlLog, purple_html_log, PURPLE_TYPE_COMMON_LOG)
 
-	log_class->logger_name = _("HTML");
-	log_class->logger_id = "html";
-
-	log_class->write_fn = purple_html_log_write;
-	log_class->list_fn = purple_html_log_list;
-	log_class->read_fn = purple_html_log_read;
-	log_class->total_size_fn = purple_html_log_total_size;
-	log_class->list_syslog_fn = purple_html_log_list_syslog;
-
-	gobject_class->finalize = purple_html_log_finalize;
+/* XXX: Move the extension in CommonLog somehow to reduce duplicate code here/txt
+ * and make things more configurable for future loggers? */
+static gboolean
+purple_html_log_create(PurpleLog *log, GCancellable *cancellable,
+	GError **error)
+{
+	return purple_log_common_writer(log, ".html", cancellable, error);
 }
 
 static void
-purple_html_log_init(PurpleHtmlLog *html_log)
+purple_html_log_create_async(PurpleLog *log, gint io_priority,
+	GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
 {
+	purple_log_common_writer_async(log, ".html", io_priority, cancellable, cb,
+		userdata);
 }
 
 static gboolean
-purple_html_log_create(PurpleLog *log, GCancellable *cancellable,
-	GError **error)
+purple_html_log_create_finish(PurpleLog *log, GAsyncResult *res, GError **error)
 {
-	return purple_log_common_writer(log, ".html", cancellable, error);
+	return purple_log_common_writer_finish(log, res, error);
 }
 
 /* NOTE: This can return msg (which you may or may not want to g_free())
@@ -334,6 +335,262 @@ purple_html_log_write(PurpleLog *log, Pu
 	return size;
 }
 
+static void
+purple_html_write_callback_data_free(_purple_html_write_callback_data *data)
+{
+	g_object_unref(log);
+	g_free(data->from);
+	g_free(data->message);
+
+	if (data->cancellable != NULL)
+		g_object_unref(data->cancellable);
+
+	if (data->out_stream != NULL)
+		g_object_unref(data->out_stream);
+
+	g_free(data);
+}
+
+/* Create the file on disk if necessary */
+static void
+purple_html_log_write_async(PurpleLog *log, PurpleMessageFlags type,
+	const gchar *from, time_t time, const gchar *message, gint io_priority,
+	GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
+{
+	_purple_html_write_callback_data *callback_data;
+
+	/* Set up the callback data and create the file if needed */
+	callback_data = g_new(_purple_html_write_callback_data, 1);
+	callback_data->log = g_object_ref(log);
+	callback_data->type = type;
+	callback_data->from = g_strdup(from);
+	callback_data->time = time;
+	callback_data->message = g_strdup(message);
+	callback_data->io_priority = io_priority;
+	callback_data->cancellable = cancellable != NULL ?
+		g_object_ref(cancellable) : NULL;
+	callback_data->cb = cb;
+	callback_data->userdata = userdata;
+	callback_data->write_header = FALSE;
+	callback_data->out_stream = NULL;
+
+	if (purple_common_log_get_file(PURPLE_COMMON_LOG(log)) == NULL)
+		/* This log is new.  We could use a logger '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.
+		 */
+		purple_html_log_create_async(log, io_priority, cancellable,
+			(GAsyncReadyCallback) purple_html_log_write_async_2, callback_data);
+	else
+		purple_html_log_write_async_2(log, NULL, callback_data);
+}
+
+/* Open the file up for writing */
+static void
+purple_html_log_write_async_2(PurpleLog *log, GAsyncResult *res,
+	_purple_html_write_callback_data *data)
+{
+	GFile *file;
+	GSimpleAsyncResult *simple;
+
+	if (res != NULL) {
+		GError *error = NULL;
+
+		if (!purple_html_log_create_finish(log, res, &error)) {
+			simple = g_simple_async_result_new_from_error(G_OBJECT(log),
+				data->cb, data->userdata, error);
+
+			g_simple_async_result_complete_in_idle(simple);
+			g_object_unref(simple);
+			g_clear_error(&error);
+			purple_html_write_callback_data_free(data);
+			return;
+		}
+
+		g_clear_error(&error);
+		data->write_header = TRUE;
+	}
+
+	file = purple_common_log_get_file(PURPLE_COMMON_LOG(log));
+
+	/* If we can't write to the file, give up before we hurt ourselves */
+	if (file == NULL) {
+		simple = g_simple_async_result_new_error(G_OBJECT(log), data->cb,
+			data->userdata,
+			G_IO_ERROR,
+			G_IO_ERROR_FAILED,
+			_("Unable to find log path"));
+
+		g_simple_async_result_complete_in_idle(simple);
+		g_object_unref(simple);
+		purple_html_write_callback_data_free(data);
+		return;
+	}
+
+	g_file_append_to_async(file, G_FILE_CREATE_NONE,
+		data->io_priority, data->cancellable,
+		(GAsyncReadyCallback) purple_html_log_write_async_3, data);
+}
+
+/* Create the header and write it to the file */
+static void
+purple_html_log_write_async_3(GFile *file, GAsyncResult *res,
+	_purple_html_write_callback_data *data)
+{
+	PurpleLog *log = data->log;
+	GError *error;
+	GFileOutputStream *stream;
+	GSimpleAsyncResult *simple;
+	gchar *date, *escaped_from;
+	gchar *image_corrected_msg, *msg_fixed, *line;
+	gsize written, size = 0;
+	gboolean success;
+
+	stream = g_file_append_to_finish(file, res, &error);
+	if (stream == NULL) {
+		simple = g_simple_async_result_new_from_error(G_OBJECT(log),
+			data->cb, data->userdata, error);
+
+		g_simple_async_result_complete_in_idle(simple);
+		g_object_unref(simple);
+		g_clear_error(&error);
+		purple_html_write_callback_data_free(data);
+		return;
+	}
+
+	data->out_stream = G_OUTPUT_STREAM(stream);
+
+	if (data->write_header) {
+		PurpleAccount *account = purple_log_get_account(log);
+		PurplePlugin *plugin;
+		const gchar *prpl;
+		const gchar *date_full;
+		gchar *header;
+		time_t log_time = purple_log_get_time(log);
+
+		plugin = purple_find_prpl(purple_account_get_protocol_id(account));
+		prpl = PURPLE_PLUGIN_PROTOCOL_INFO(plugin)->list_icon(account, NULL);
+		date_full = purple_date_format_full(localtime(&log_time));
+
+		if (purple_log_get_chat_type(log) == PURPLE_LOG_SYSTEM)
+			header = g_strdup_printf(_("System log for account %s (%s) "
+				"connected at %s"),
+				purple_account_get_username(account), prpl, date_full);
+		else
+			header = g_strdup_printf(_("Conversation with %s at %s on %s (%s)"),
+				purple_log_get_name(log), date_full,
+				purple_account_get_username(account), prpl);
+
+		line = g_strdup_printf("<html><head>"
+			"<meta http-equiv=\"content-type\" "
+			"content=\"text/html; charset=UTF-8\">"
+			"<title>"
+			"%s"
+			"</title></head><body>"
+			"<h3>%s</h3>\n",
+			header, header);
+
+		g_free(header);
+
+		success = g_output_stream_write_all(data->out_stream, line,
+			strlen(line), &written, data->cancellable, &error);
+		g_free(line);
+
+		if (!success) {
+			simple = g_simple_async_result_new_from_error(G_OBJECT(log),
+				data->cb, data->userdata, error);
+
+			g_simple_async_result_complete_in_idle(simple);
+			g_object_unref(simple);
+			g_clear_error(&error);
+			purple_html_write_callback_data_free(data);
+
+			return;
+		}
+
+		size += written;
+	}
+
+	escaped_from = g_markup_escape_text(data->from, -1);
+	image_corrected_msg = convert_image_tags(log, data->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 != data->message)
+		g_free(image_corrected_msg);
+
+	date = _log_get_timestamp(log, data->time);
+
+	if (purple_log_get_chat_type(log) == PURPLE_LOG_SYSTEM){
+		line = g_strdup_printf("---- %s @ %s ----<br/>\n", msg_fixed, date);
+	} else {
+		if (data->type & PURPLE_MESSAGE_SYSTEM)
+			line = g_strdup_printf("<font size=\"2\">(%s)</font><b> %s"
+				"</b><br/>\n", date, msg_fixed);
+		else if (data->type & PURPLE_MESSAGE_RAW)
+			line = g_strdup_printf("<font size=\"2\">(%s)</font> %s<br/>\n",
+				date, msg_fixed);
+		else if (data->type & PURPLE_MESSAGE_ERROR)
+			line = g_strdup_printf("<font color=\"#FF0000\"><font "
+				"size=\"2\">(%s)</font><b> %s</b></font><br/>\n",
+				date, msg_fixed);
+		else if (data->type & PURPLE_MESSAGE_WHISPER)
+			line = g_strdup_printf("<font color=\"#6C2585\"><font "
+				"size=\"2\">(%s)</font><b> %s:</b></font> %s<br/>\n",
+				date, escaped_from, msg_fixed);
+		else if (data->type & PURPLE_MESSAGE_AUTO_RESP) {
+			if (data->type & PURPLE_MESSAGE_SEND)
+				line = g_strdup_printf("<font color=\"#16569E\"><font "
+					"size=\"2\">(%s)</font> <b>%s <%s>:</b>"
+					"</font> %s<br/>\n", date, escaped_from, _("AUTO-REPLY"),
+					msg_fixed);
+			else
+				line = g_strdup_printf(_("<font color=\"#A82F2F\"><font "
+					"size=\"2\">(%s)</font> <b>%s <%s>:</b>"
+					"</font> %s<br/>\n"), date, escaped_from, _("AUTO-REPLY"),
+					msg_fixed);
+		} else if (data->type & PURPLE_MESSAGE_RECV) {
+			if (purple_message_meify(msg_fixed, -1))
+				line = g_strdup_printf("<font color=\"#062585\"><font "
+					"size=\"2\">(%s)</font> <b>***%s</b></font> %s<br/>\n",
+					date, escaped_from, msg_fixed);
+			else
+				line = g_strdup_printf("<font color=\"#A82F2F\"><font "
+					"size=\"2\">(%s)</font> <b>%s:</b></font> %s<br/>\n",
+					date, escaped_from, msg_fixed);
+		} else if (data->type & PURPLE_MESSAGE_SEND) {
+			if (purple_message_meify(msg_fixed, -1))
+				line = g_strdup_printf("<font color=\"#062585\"><font "
+					"size=\"2\">(%s)</font> <b>***%s</b></font> %s<br/>\n",
+					date, escaped_from, msg_fixed);
+			else
+				line = g_strdup_printf("<font color=\"#16569E\"><font "
+					"size=\"2\">(%s)</font> <b>%s:</b></font> %s<br/>\n",
+					date, escaped_from, msg_fixed);
+		} else {
+			line = g_strdup_printf("<font size=\"2\">(%s)</font>"
+				"<b> %s:</b></font> %s<br/>\n",
+				date, escaped_from, msg_fixed);
+		}
+	}
+
+	success = g_output_stream_write_all(data->out_stream, line, strlen(line),
+		&written, data->cancellable, &error);
+
+	if (success)
+		size += written;
+	else
+		size = -1;
+
+	g_free(date);
+	g_free(msg_fixed);
+	g_free(escaped_from);
+	g_object_unref(stream);
+
+//	return size;
+}
+
 static GList *
 purple_html_log_list(PurpleLog *log, PurpleLogChatType type, const gchar *sn,
 	PurpleAccount *account, GCancellable *cancellable, GError **error)
@@ -342,6 +599,15 @@ purple_html_log_list(PurpleLog *log, Pur
 		PURPLE_TYPE_HTML_LOG, cancellable, error);
 }
 
+static void
+purple_html_log_list_async(PurpleLog *log, PurpleLogChatType type,
+	const gchar *sn, PurpleAccount *account, gint io_priority,
+	GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
+{
+	purple_log_common_lister_async(type, sn, account, ".html",
+		PURPLE_TYPE_HTML_LOG, io_priority, cancellable, cb, userdata);
+}
+
 static GList *
 purple_html_log_list_syslog(PurpleLog *log, PurpleAccount *account,
 	GCancellable *cancellable, GError **error)
@@ -350,6 +616,15 @@ purple_html_log_list_syslog(PurpleLog *l
 		".html", PURPLE_TYPE_HTML_LOG, cancellable, error);
 }
 
+static void
+purple_html_log_list_syslog_async(PurpleLog *log, PurpleAccount *account,
+	gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb,
+	gpointer userdata)
+{
+	purple_log_common_lister_async(PURPLE_LOG_SYSTEM, ".system", account,
+		".html", PURPLE_TYPE_HTML_LOG, io_priority, cancellable, cb, userdata);
+}
+
 static gchar *
 purple_html_log_read(PurpleLog *log, PurpleLogReadFlags *flags,
 	GCancellable *cancellable, GError **error)
@@ -388,6 +663,14 @@ purple_html_log_read(PurpleLog *log, Pur
 	return minus_header;
 }
 
+static void
+purple_html_log_read_async(PurpleLog *log, gint io_priority,
+	GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
+{
+	
+}
+
+
 static gssize
 purple_html_log_total_size(PurpleLog *log, PurpleLogChatType type,
 	const gchar *name, PurpleAccount *account, GCancellable *cancellable,
@@ -398,6 +681,15 @@ static void
 }
 
 static void
+purple_html_log_total_size_async(PurpleLog *log, PurpleLogChatType type,
+	const gchar *name, PurpleAccount *account, gint io_priority,
+	GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
+{
+	purple_log_common_total_sizer_async(type, name, account, ".html",
+		io_priority, cancellable, cb, userdata);
+}
+
+static void
 write_footer(PurpleCommonLog *common_log, const gchar *footer)
 {
 	GError *error = NULL;
@@ -435,6 +727,34 @@ purple_html_log_finalize(GObject *object
 	G_OBJECT_CLASS(purple_html_log_parent_class)->finalize(object);
 }
 
+static void
+purple_html_log_class_init(PurpleHtmlLogClass *class)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS(class);
+	PurpleLogClass *log_class = PURPLE_LOG_CLASS(class);
+
+	log_class->logger_name = _("HTML");
+	log_class->logger_id = "html";
+
+	log_class->write_fn = purple_html_log_write;
+	log_class->write_async = purple_html_log_write_async;
+	log_class->list_fn = purple_html_log_list;
+	log_class->list_async = purple_html_log_list_async;
+	log_class->read_fn = purple_html_log_read;
+	log_class->read_async = purple_html_log_read_async;
+	log_class->total_size_fn = purple_html_log_total_size;
+	log_class->total_size_async = purple_html_log_total_size_async;
+	log_class->list_syslog_fn = purple_html_log_list_syslog;
+	log_class->list_syslog_async = purple_html_log_list_syslog_async;
+
+	gobject_class->finalize = purple_html_log_finalize;
+}
+
+static void
+purple_html_log_init(PurpleHtmlLog *html_log)
+{
+}
+
 void
 purple_html_log_system_init(void)
 {
============================================================
--- libpurple/commonlog.c	e3887f90da7510c2534f7f48f7beb510876fbd1f
+++ libpurple/commonlog.c	b688977bfa7de76e94b05bd4fec0f2b67c884015
@@ -26,7 +26,14 @@
 
 #include "internal.h"
 #include "commonlog.h"
+#include "debug.h"
 
+
+/* Helpful macros */
+#define PURPLE_IS_ACCOUNT(account) TRUE
+
+
+/* Structures */
 G_DEFINE_TYPE (PurpleCommonLog, purple_common_log, PURPLE_TYPE_LOG)
 static void purple_common_log_get_property(GObject *, guint, GValue *,
 	GParamSpec *);
@@ -61,13 +68,31 @@ typedef struct {
 	gchar *ext;
 } _common_thread_callback_data;
 
-static void common_thread_callback_data_free(gpointer);
+typedef struct {
+	PurpleLog *log;
+	GAsyncReadyCallback cb;
+	gpointer userdata;
+} _writer_callback_data;
 
+
+/* Prototypes */
+static void common_thread_callback_data_free(gpointer);
 static gboolean purple_log_common_remove(PurpleLog *, GCancellable *,
 	GError **);
 static gssize purple_log_common_size(PurpleLog *, GCancellable *, GError **);
+static void purple_log_common_writer_async_2(GObject *, GAsyncResult *,
+	gpointer);
 
+
+/* Main functions */
 static void
+_writer_callback_data_free(_writer_callback_data *data)
+{
+	g_object_unref(data->log);
+	g_free(data);
+}
+
+static void
 purple_common_log_class_init(PurpleCommonLogClass *class)
 {
 	GObjectClass *gobject_class = G_OBJECT_CLASS(class);
@@ -357,15 +382,15 @@ purple_log_common_writer(PurpleLog *log,
 			purple_common_log_set_file(common_log, file);
 			g_object_unref(file);
 		} else {
-			/* XXX: Can uncomment this when the rest of libpurple is thread-safe
 			PurpleConversation *conv = purple_log_get_conversation(log);
 
 			if (conv != NULL)
 				purple_conversation_write(conv, NULL,
 					_("Logging of this conversation failed."),
-					PURPLE_MESSAGE_ERROR, time(NULL));*/
+					PURPLE_MESSAGE_ERROR, time(NULL));
 
 			g_object_unref(file);
+
 			return FALSE;
 		}
 	}
@@ -373,41 +398,128 @@ purple_log_common_writer(PurpleLog *log,
 	return TRUE;
 }
 
-static void
-writer_thread(GSimpleAsyncResult *simple, GObject *object,
-	GCancellable *cancellable)
+void
+purple_log_common_writer_async(PurpleLog *log, const gchar *ext,
+	gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb,
+	gpointer userdata)
 {
-	PurpleLog *log = PURPLE_LOG(object);
-	GError *error = NULL;
-	gchar *ext = g_simple_async_result_get_op_res_gpointer(simple);
-	gboolean result;
+	_writer_callback_data *callback_data;
+	PurpleCommonLog *common_log;
+	GFile *file;
 
-	result = purple_log_common_writer(log, ext, cancellable, &error);
+	g_return_if_fail(PURPLE_IS_COMMON_LOG(log));
 
-	if (!result)
-		g_simple_async_result_set_from_error(simple, error);
-	else
-		g_simple_async_result_set_op_res_gboolean(simple, TRUE);
+	callback_data = g_new(_writer_callback_data, 1);
+	callback_data->log = g_object_ref(log);
+	callback_data->cb = cb;
+	callback_data->userdata = userdata;
 
-	g_clear_error(&error);
+	common_log = PURPLE_COMMON_LOG(log);
+	file = purple_common_log_get_file(common_log);
+
+	if (file == NULL) {
+		GSimpleAsyncResult *simple;
+		struct tm *tm;
+		const gchar *tz, *date;
+		gchar *dir, *filename, *path;
+		time_t log_time;
+
+		/* This log is new */
+		dir = purple_log_get_log_dir(purple_log_get_chat_type(log),
+			purple_log_get_name(log),
+			purple_log_get_account(log));
+
+		if (dir == NULL) {
+			simple = g_simple_async_result_new_error(G_OBJECT(log), cb, userdata,
+				G_IO_ERROR,
+				G_IO_ERROR_FAILED,
+				_("Unable to get log directory"));
+
+			g_simple_async_result_complete_in_idle(simple);
+			g_object_unref(simple);
+			_writer_callback_data_free(callback_data);
+
+			return;
+		}
+
+		/* Blocks */
+		if (purple_build_dir(dir, S_IRUSR | S_IWUSR | S_IXUSR) < 0) {
+			simple = g_simple_async_result_new_error(G_OBJECT(log), cb, userdata,
+				G_IO_ERROR,
+				g_file_error_from_errno(errno),
+				g_strerror(errno));
+
+			g_simple_async_result_complete_in_idle(simple);
+			g_object_unref(simple);
+			_writer_callback_data_free(callback_data);
+
+			return;
+		}
+
+		log_time = purple_log_get_time(log);
+		tm = localtime(&log_time);
+		tz = purple_escape_filename(purple_utf8_strftime("%Z", tm));
+		date = purple_utf8_strftime("%Y-%m-%d.%H%M%S%z", tm);
+
+		filename = g_strdup_printf("%s%s%s", date, tz, ext != NULL ? ext : "");
+		path = g_build_filename(dir, filename, NULL);
+
+		g_free(dir);
+		g_free(filename);
+
+		file = g_file_new_for_path(path);
+		g_free(path);
+
+		/* Make sure the file is writeable */
+		g_file_append_to_async(file, G_FILE_CREATE_PRIVATE, io_priority,
+			cancellable, purple_log_common_writer_async_2, callback_data);
+	} else
+		purple_log_common_writer_async_2(NULL, NULL, callback_data);
 }
 
-void
-purple_log_common_writer_async(PurpleLog *log, const gchar *ext,
-	gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb,
+static void
+purple_log_common_writer_async_2(GObject *obj, GAsyncResult *res,
 	gpointer userdata)
 {
+	_writer_callback_data *callback_data = userdata;
+	PurpleLog *log = callback_data->log;
 	GSimpleAsyncResult *simple;
+	
+	if (obj != NULL) {
+		GError *err = NULL;
+		GFile *file = G_FILE(obj);
+		GFileOutputStream *stream = g_file_append_to_finish(file, res, &err);
 
-	g_return_if_fail(PURPLE_IS_LOG(log));
+		if (stream != NULL) {
+			g_object_unref(stream);
+			purple_common_log_set_file(PURPLE_COMMON_LOG(log), file);
+		} else {
+			PurpleConversation *conv = purple_log_get_conversation(log);
 
-	simple = g_simple_async_result_new(G_OBJECT(log), cb, userdata,
-		purple_log_common_writer_async);
+			if (conv != NULL)
+				purple_conversation_write(conv, NULL,
+					_("Logging of this conversation failed."),
+					PURPLE_MESSAGE_ERROR, time(NULL));
 
-	g_simple_async_result_set_op_res_gpointer(simple, g_strdup(ext), g_free);
-	g_simple_async_result_run_in_thread(simple, writer_thread, io_priority,
-		cancellable);
+			simple = g_simple_async_result_new_from_error(G_OBJECT(log),
+				callback_data->cb, callback_data->userdata, err);
+			g_simple_async_result_complete_in_idle(simple);
+			g_object_unref(simple);
+
+			_writer_callback_data_free(callback_data);
+
+			return;
+		}
+	}
+
+	simple = g_simple_async_result_new(G_OBJECT(log),
+		callback_data->cb, callback_data->userdata,
+		purple_log_common_writer_async);
+	g_simple_async_result_set_op_res_gboolean(simple, TRUE);
+	g_simple_async_result_complete_in_idle(simple);
 	g_object_unref(simple);
+
+	_writer_callback_data_free(callback_data);
 }
 
 gboolean
@@ -439,7 +551,7 @@ purple_log_common_lister(PurpleLogChatTy
 	gchar *path;
 
 	g_return_val_if_fail(name != NULL, NULL);
-	g_return_val_if_fail(account != NULL, NULL);
+	g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
 	g_return_val_if_fail(ext != NULL, NULL);
 	g_return_val_if_fail(log_type == G_TYPE_INVALID || g_type_is_a(log_type, PURPLE_TYPE_LOG),
 		NULL);
@@ -571,7 +683,7 @@ purple_log_common_lister_async(PurpleLog
 	GSimpleAsyncResult *simple;
 
 	g_return_if_fail(name != NULL);
-	g_return_if_fail(account != NULL); /* XXX: PURPLE_IS_ACCOUNT(account) */
+	g_return_if_fail(PURPLE_IS_ACCOUNT(account));
 	g_return_if_fail(ext != NULL);
 
 	callback_data = g_new0(_common_thread_callback_data, 1);
@@ -688,6 +800,8 @@ purple_log_common_total_sizer(PurpleLogC
 				G_FILE_ATTRIBUTE_STANDARD_SIZE);
 			size += file_size;
 
+			purple_debug_info("commonlog", "file size for %s: %" G_GUINT64_FORMAT "\n", tmp, file_size);
+
 			g_object_unref(info);
 			g_object_unref(file);
 			g_free(tmp);
@@ -804,6 +918,8 @@ purple_log_common_size(PurpleLog *log, G
 	file_size = g_file_info_get_attribute_uint64(info,
 		G_FILE_ATTRIBUTE_STANDARD_SIZE);
 
+	purple_debug_info("commonlog", "file size for %s: %" G_GUINT64_FORMAT "\n", g_file_get_path(file), file_size);
+
 	g_object_unref(info);
 
 	return file_size;
============================================================
--- pidgin/gtkconv-theme.c	7edc929135fd2fb191b23e0d6219f168e4a67502
+++ pidgin/gtkconv-theme.c	bb1cbf344e82f7a46c4ea4535da27026f4af6923
@@ -28,6 +28,7 @@
 #include "xmlnode.h"
 
 #include "pidgin.h"
+#include "internal.h"
 #include "gtkconv.h"
 #include "gtkwebview.h"
 


More information about the Commits mailing list