cpw.nader.asynclogging-3: 5f58bd44: Added PurpleCommonLog as an intermediate...

morshed.nader at gmail.com morshed.nader at gmail.com
Wed Jan 12 04:31:07 EST 2011


----------------------------------------------------------------------
Revision: 5f58bd44e43d09bdb5d2b3e74482cfc7b1387e10
Parent:   8932371f81a173b349376b1f3f1e86132a7f2209
Author:   morshed.nader at gmail.com
Date:     01/12/11 04:27:14
Branch:   im.pidgin.cpw.nader.asynclogging-3
URL: http://d.pidgin.im/viewmtn/revision/info/5f58bd44e43d09bdb5d2b3e74482cfc7b1387e10

Changelog: 

Added PurpleCommonLog as an intermediate, incomplete class for Txt and Html logs
Disabled perl and log_reader from compiling as they are broken currently
Removed unneeded protocols from the makefile for quicker compiling
libpurple "compiles", needs testing though

Changes against parent 8932371f81a173b349376b1f3f1e86132a7f2209

  added    libpurple/commonlog.c
  added    libpurple/commonlog.h
  patched  libpurple/Makefile.am
  patched  libpurple/Makefile.mingw
  patched  libpurple/htmllog.c
  patched  libpurple/htmllog.h
  patched  libpurple/log.c
  patched  libpurple/log.h
  patched  libpurple/plugins/Makefile.mingw
  patched  libpurple/plugins/log_reader.c
  patched  libpurple/protocols/Makefile.mingw
  patched  libpurple/txtlog.c
  patched  libpurple/txtlog.h

-------------- next part --------------
============================================================
--- libpurple/log.c	4ccbae9983a5ac207fe25d3ced33f1a05dcb91e2
+++ libpurple/log.c	50b511d8bfb743f8ceb7da59e2e0627b23c4bfa3
@@ -107,21 +107,6 @@ typedef struct {
 } _thread_callback_data;
 
 typedef struct {
-	PurpleAccount *account;
-	PurpleLogChatType chat_type;
-	gchar *name;
-	gchar *ext;
-} _purple_logger_total_size_callback_data;
-
-typedef struct {
-	PurpleAccount *account;
-	PurpleLogChatType chat_type;
-	GType log_type;
-	gchar *name;
-	gchar *ext;
-} _purple_logger_lister_callback_data;
-
-typedef struct {
 	GAsyncReadyCallback cb;
 	gpointer userdata;
 	guint counter;
@@ -158,10 +143,8 @@ typedef struct {
 	guint counter;
 } _purple_log_sets_callback_data;
 
-static void purple_logger_lister_callback_data_free(gpointer);
 static void thread_callback_data_free(gpointer);
 static void thread_write_callback_data_free(gpointer);
-static void purple_logger_total_size_callback_data_free(gpointer);
 
 static GHashTable *log_get_log_sets_common(GCancellable *, GError **);
 static void log_get_log_sets_common_thread(GSimpleAsyncResult *, GObject *, GCancellable *);
@@ -529,16 +512,6 @@ static void
 }
 
 static void
-purple_logger_lister_callback_data_free(gpointer userdata)
-{
-	_purple_logger_lister_callback_data *callback_data = userdata;
-
-	g_free(callback_data->name);
-	g_free(callback_data->ext);
-	g_free(callback_data);
-}
-
-static void
 thread_callback_data_free(gpointer userdata)
 {
 	_thread_callback_data *callback_data = userdata;
@@ -561,17 +534,7 @@ thread_write_callback_data_free(gpointer
 	g_free(callback_data);
 }
 
-static void
-purple_logger_total_size_callback_data_free(gpointer userdata)
-{
-	_purple_logger_total_size_callback_data *callback_data = userdata;
 
-	g_free(callback_data->name);
-	g_free(callback_data->ext);
-	g_free(callback_data);
-}
-
-
 /**************************************************************************
  * PUBLIC LOGGING FUNCTIONS ***********************************************
  **************************************************************************/
@@ -1306,7 +1269,7 @@ purple_logs_get_total_size_async(PurpleL
 		callback_data->counter = 1;
 
 		simple = g_simple_async_result_new(NULL, log_total_size_cb,
-			callback_data, purple_log_common_total_sizer_async);
+			callback_data, purple_logs_get_total_size_async);
 
 		g_simple_async_result_set_op_res_gssize(simple, size);
 		g_simple_async_result_complete_in_idle(simple);
@@ -2707,601 +2670,6 @@ _convert_image_tags(const PurpleLog *log
 	return g_string_free(newmsg, FALSE);
 }
 
-gboolean
-purple_log_common_writer(PurpleLog *log, const gchar *ext, GCancellable *cancellable, GError **error)
-{
-	PurpleLogCommonLoggerData *data = purple_log_get_logger_data(log);
-
-	g_return_val_if_fail(PURPLE_IS_LOG(log), FALSE);
-
-	if (data == NULL) {
-		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) {
-			g_set_error_literal(error,
-				G_IO_ERROR,
-				G_IO_ERROR_FAILED,
-				_("Unable to get log directory"));
-
-			return FALSE;
-		}
-
-		if (purple_build_dir(dir, S_IRUSR | S_IWUSR | S_IXUSR) < 0) {
-			g_set_error_literal(error,
-				G_FILE_ERROR,
-				g_file_error_from_errno(errno),
-				g_strerror(errno));
-
-			return FALSE;
-		}
-
-		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);
-
-		data = g_slice_new0(PurpleLogCommonLoggerData);
-		purple_log_set_logger_data(log, data);
-		data->file = g_fopen(path, "a");
-
-		if (data->file == NULL) {
-			PurpleConversation *conv = purple_log_get_conversation(log);
-
-			g_set_error_literal(error,
-				G_FILE_ERROR,
-				g_file_error_from_errno(errno),
-				g_strerror(errno));
-
-			if (conv != NULL)
-				purple_conversation_write(conv, NULL,
-					_("Logging of this conversation failed."),
-					PURPLE_MESSAGE_ERROR, time(NULL));
-
-			g_free(path);
-
-			return FALSE;
-		}
-
-		data->path = path;
-	}
-
-	return TRUE;
-}
-
-static void
-writer_thread(GSimpleAsyncResult *simple, GObject *object, GCancellable *cancellable)
-{
-	PurpleLog *log = PURPLE_LOG(object);
-	PurpleLogCommonLoggerData *data = purple_log_get_logger_data(log);
-
-	if (data == NULL) {
-		_thread_callback_data *callback_data =
-			g_simple_async_result_get_op_res_gpointer(simple);
-		struct tm *tm;
-		const gchar *tz, *date;
-		gchar *dir, *filename, *path, *ext = callback_data->ext;
-		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) {
-			g_simple_async_result_set_error(simple, G_IO_ERROR, G_IO_ERROR_FAILED,
-				_("Unable to get log directory"));
-
-			return;
-		}
-
-		if (purple_build_dir(dir, S_IRUSR | S_IWUSR | S_IXUSR) < 0) {
-			g_simple_async_result_set_error(simple, G_FILE_ERROR, g_file_error_from_errno(errno),
-				"%s", g_strerror(errno));
-
-			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);
-
-		data = g_slice_new0(PurpleLogCommonLoggerData);
-		purple_log_set_logger_data(log, data);
-		data->file = g_fopen(path, "a");
-
-		if (data->file == NULL) {
-			PurpleConversation *conv = purple_log_get_conversation(log);
-
-			g_simple_async_result_set_error(simple, G_FILE_ERROR,
-				g_file_error_from_errno(errno), "%s", g_strerror(errno));
-
-			if (conv != NULL)
-				purple_conversation_write(conv, NULL,
-					_("Logging of this conversation failed."),
-					PURPLE_MESSAGE_ERROR, time(NULL));
-
-			g_free(path);
-
-			return;
-		}
-
-		data->path = path;
-	}
-
-	g_simple_async_result_set_op_res_gboolean(simple, TRUE);
-}
-
-void
-purple_log_common_writer_async(PurpleLog *log, const gchar *ext, gint io_priority,
-	GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
-{
-	_thread_callback_data *callback_data;
-	GSimpleAsyncResult *simple;
-
-	g_return_if_fail(PURPLE_IS_LOG(log));
-
-	callback_data = g_new0(_thread_callback_data, 1);
-	callback_data->ext = g_strdup(ext);
-
-	simple = g_simple_async_result_new(G_OBJECT(log), cb, userdata, purple_log_common_writer_async);
-
-	g_simple_async_result_set_op_res_gpointer(simple, callback_data, thread_callback_data_free);
-	g_simple_async_result_run_in_thread(simple, writer_thread, io_priority, cancellable);
-
-	g_object_unref(simple);
-}
-
-gboolean
-purple_log_common_writer_finish(PurpleLog *log, GAsyncResult *res, GError **error)
-{
-	GSimpleAsyncResult *simple;
-
-	simple = G_SIMPLE_ASYNC_RESULT(res);
-
-	if (g_simple_async_result_propagate_error(simple, error))
-		return FALSE;
-
-	g_return_val_if_fail(g_simple_async_result_get_source_tag(simple) == purple_log_common_writer_async, FALSE);
-
-	return g_simple_async_result_get_op_res_gboolean(simple);
-}
-
-GList *
-purple_log_common_lister(PurpleLogChatType chat_type, const gchar *name, PurpleAccount *account,
-	const gchar *ext, GType log_type, GCancellable *cancellable, GError **error)
-{
-	PurpleLog *log;
-	GDir *dir;
-	GList *list = NULL;
-	const gchar *filename;
-	gchar *path;
-	PurpleLogCommonLoggerData *data;
-	struct tm tm;
-
-	g_return_val_if_fail(name != NULL, NULL);
-	g_return_val_if_fail(account != NULL, 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);
-
-	path = purple_log_get_log_dir(chat_type, name, account);
-
-	if (path == NULL) {
-		g_set_error_literal(error,
-			G_IO_ERROR,
-			G_IO_ERROR_FAILED,
-			_("Unable to get log directory"));
-
-		return NULL;
-	}
-
-	dir = g_dir_open(path, 0, error);
-
-	if (dir == NULL) {
-		g_free(path);
-
-		return NULL;
-	}
-
-	while ((filename = g_dir_read_name(dir)) != NULL) {
-		if (g_cancellable_set_error_if_cancelled(cancellable, error)) {
-			g_dir_close(dir);
-			g_free(path);
-
-			g_list_foreach(list, (GFunc) g_object_unref, NULL);
-			g_list_free(list);
-
-			return NULL;
-		}
-
-		if (purple_str_has_suffix(filename, ext) &&
-		    strlen(filename) >= (17 + strlen(ext))) {
-#if defined (HAVE_TM_GMTOFF) && defined (HAVE_STRUCT_TM_TM_ZONE)
-			long tz_off;
-			const gchar *rest, *end;
-			time_t stamp;
-
-			stamp = purple_str_to_time(purple_unescape_filename(filename), FALSE, &tm, &tz_off, &rest);
-
-			/* As zero is a valid offset, PURPLE_NO_TZ_OFF means no offset was
-			 * provided. See util.h. Yes, it's kinda ugly. */
-			if (tz_off != PURPLE_NO_TZ_OFF)
-				tm.tm_gmtoff = tz_off - tm.tm_gmtoff;
-
-			if (stamp == 0 || rest == NULL || (end = strchr(rest, '.')) == NULL || strchr(rest, ' ') != NULL) {
-				log = purple_log_new(log_type, chat_type, name, account, NULL, stamp, NULL);
-			} else {
-				gchar *tmp = g_strndup(rest, end - rest);
-				tm.tm_zone = tmp;
-				log = purple_log_new(log_type, chat_type, name, account, NULL, stamp, &tm);
-				g_free(tmp);
-			}
-#else
-			time_t stamp = purple_str_to_time(filename, FALSE, &tm, NULL, NULL);
-
-			log = purple_log_new(log_type, chat_type, name, account, NULL, stamp, (stamp != 0) ?  &tm : NULL);
-#endif
-
-			data = g_slice_new0(PurpleLogCommonLoggerData);
-			purple_log_set_logger_data(log, data);
-
-			data->path = g_build_filename(path, filename, NULL);
-			list = g_list_prepend(list, log);
-		}
-	}
-
-	g_dir_close(dir);
-	g_free(path);
-
-	return list;
-}
-
-static void
-common_lister_thread(GSimpleAsyncResult *simple, GObject *object, GCancellable *cancellable)
-{
-	_purple_logger_lister_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;
-	GType log_type = callback_data->log_type;
-	GError *error = NULL;
-	GList *list;
-	gchar *name = callback_data->name, *ext = callback_data->ext;
-
-	list = purple_log_common_lister(chat_type, name, account, ext, log_type, cancellable, &error);
-
-	if (list == NULL)
-		g_simple_async_result_set_from_error(simple, error);
-	else
-		g_simple_async_result_set_op_res_gpointer(simple, list, (GDestroyNotify) g_list_free);
-
-	g_clear_error(&error);
-}
-
-void
-purple_log_common_lister_async(PurpleLogChatType chat_type, const gchar *name, PurpleAccount *account,
-	const gchar *ext, GType log_type, gint io_priority, GCancellable *cancellable,
-	GAsyncReadyCallback cb, gpointer userdata)
-{
-	_purple_logger_lister_callback_data *callback_data;
-	GSimpleAsyncResult *simple;
-
-	g_return_if_fail(name != NULL);
-	g_return_if_fail(account != NULL); // PURPLE_IS_ACCOUNT(account)
-	g_return_if_fail(ext != NULL);
-
-	callback_data = g_new0(_purple_logger_lister_callback_data, 1);
-	callback_data->chat_type = chat_type;
-	callback_data->name = g_strdup(name);
-	callback_data->account = account;
-	callback_data->ext = g_strdup(ext);
-	callback_data->log_type = log_type;
-
-	simple = g_simple_async_result_new(NULL, cb, userdata, purple_log_common_lister_async);
-
-	g_simple_async_result_set_op_res_gpointer(simple, callback_data,
-		purple_logger_lister_callback_data_free);
-	g_simple_async_result_run_in_thread(simple, common_lister_thread, io_priority,
-		cancellable);
-
-	g_object_unref(simple);
-}
-
-GList *
-purple_log_common_lister_finish(GAsyncResult *res, GError **error)
-{
-	GSimpleAsyncResult *simple;
-
-	simple = G_SIMPLE_ASYNC_RESULT(res);
-
-	if (g_simple_async_result_propagate_error(simple, error))
-		return NULL;
-
-	g_return_val_if_fail(g_simple_async_result_get_source_tag(simple) == purple_log_common_lister_async, NULL);
-
-	return g_simple_async_result_get_op_res_gpointer(simple);
-}
-
-// TODO: Rather than calling this multiple times with different extensions,
-// TODO: could we somehow store up all the extensions and do the loop just
-// TODO: once?  This may be possible with the non-blocking stuff...
-gssize
-purple_log_common_total_sizer(PurpleLogChatType chat_type, const gchar *name, PurpleAccount *account, const gchar *ext, GCancellable *cancellable, GError **error)
-{
-	_purple_logsize_user *lu;
-	GDir *dir;
-	GError *err = NULL;
-	const gchar *filename;
-	gchar *path;
-	gssize size = 0, total;
-	gpointer ptrsize;
-
-	g_return_val_if_fail(name != NULL, 0);
-	g_return_val_if_fail(account != NULL, 0);
-	g_return_val_if_fail(ext != NULL, 0);
-
-	path = purple_log_get_log_dir(chat_type, name, account);
-
-	if (path == NULL) {
-		g_set_error_literal(error,
-			G_IO_ERROR,
-			G_IO_ERROR_FAILED,
-			_("Unable to get log directory"));
-
-		return -1;
-	}
-
-	dir = g_dir_open(path, 0, &err);
-
-	if (dir == NULL){
-		g_free(path);
-
-		/* If the directory doesn't exist, we just don't have logs for them */
-		if (err->code == G_FILE_ERROR_NOENT) {
-			G_LOCK(logsize_users);
-
-			lu = g_new(_purple_logsize_user, 1);
-			lu->name = g_strdup(purple_normalize(account, name));
-			lu->account = account; //g_object_ref?
-
-			if (!g_hash_table_lookup_extended(logsize_users, lu, NULL, NULL))
-				g_hash_table_replace(logsize_users, lu, GINT_TO_POINTER(size));
-
-			G_UNLOCK(logsize_users);
-
-			return 0;
-		} else {
-			g_propagate_error(error, err);
-			return -1;
-		}
-	}
-
-	while ((filename = g_dir_read_name(dir)) != NULL) {
-		if (g_cancellable_set_error_if_cancelled(cancellable, error)) {
-			g_dir_close(dir);
-			g_free(path);
-
-			return -1;
-		}
-
-		if (purple_str_has_suffix(filename, ext) &&
-		    strlen(filename) >= 17 + strlen(ext))
-		{
-			GFile *file;
-			GFileInfo *info;
-			gchar *tmp = g_build_filename(path, filename, NULL);
-			guint64 file_size;
-
-			file = g_file_new_for_path(tmp);
-			info = g_file_query_info(file, G_FILE_ATTRIBUTE_STANDARD_SIZE,
-				G_FILE_QUERY_INFO_NONE, cancellable, error);
-
-			if (info == NULL) {
-				g_dir_close(dir);
-				g_object_unref(file);
-				g_free(path);
-				g_free(tmp);
-
-				return -1;
-			}
-
-			file_size = g_file_info_get_attribute_uint64(info,
-				G_FILE_ATTRIBUTE_STANDARD_SIZE);
-			size += file_size;
-
-			g_object_unref(info);
-			g_object_unref(file);
-			g_free(tmp);
-		}
-	}
-
-
-	G_LOCK(logsize_users);
-	lu = g_new(_purple_logsize_user, 1);
-	lu->name = g_strdup(purple_normalize(account, name));
-	lu->account = account; //g_object_ref?
-
-	total = size;
-
-	if (g_hash_table_lookup_extended(logsize_users, lu, NULL, &ptrsize))
-		total += GPOINTER_TO_INT(ptrsize);
-
-	g_hash_table_replace(logsize_users, lu, GINT_TO_POINTER(total));
-	G_UNLOCK(logsize_users);
-
-	g_dir_close(dir);
-	g_free(path);
-
-	return size;
-}
-
-static void
-common_total_sizer_thread(GSimpleAsyncResult *simple, GObject *object, GCancellable *cancellable)
-{
-	_purple_logger_total_size_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, *ext = callback_data->ext;
-	gssize size;
-
-	size = purple_log_common_total_sizer(chat_type, name, account, ext, 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);
-}
-
-void
-purple_log_common_total_sizer_async(PurpleLogChatType chat_type, const gchar *name,
-	PurpleAccount *account, const gchar *ext, gint io_priority, GCancellable *cancellable,
-	GAsyncReadyCallback cb, gpointer userdata)
-{
-	_purple_logger_total_size_callback_data *callback_data;
-	GSimpleAsyncResult *simple;
-
-	g_return_if_fail(name != NULL);
-	g_return_if_fail(account != NULL);
-	g_return_if_fail(ext != NULL);
-
-	callback_data = g_new0(_purple_logger_total_size_callback_data, 1);
-	callback_data->chat_type = chat_type;
-	callback_data->name = g_strdup(name);
-	callback_data->account = account;
-	callback_data->ext = g_strdup(ext);
-
-	simple = g_simple_async_result_new(NULL, cb, userdata, purple_log_common_total_sizer_async);
-
-	g_simple_async_result_set_op_res_gpointer(simple, callback_data,
-		purple_logger_total_size_callback_data_free);
-	g_simple_async_result_run_in_thread(simple, common_total_sizer_thread, io_priority, cancellable);
-
-	g_object_unref(simple);
-}
-
-gssize
-purple_log_common_total_sizer_finish(GAsyncResult *res, GError **error)
-{
-	GSimpleAsyncResult *simple;
-
-	simple = G_SIMPLE_ASYNC_RESULT(res);
-
-	if (g_simple_async_result_propagate_error(simple, error))
-		return -1;
-
-	g_return_val_if_fail(g_simple_async_result_get_source_tag(simple) == purple_log_common_total_sizer_async, -1);
-
-	return g_simple_async_result_get_op_res_gssize(simple);
-}
-
-gssize
-purple_log_common_sizer(PurpleLog *log, GCancellable *cancellable, GError **error)
-{
-	PurpleLogCommonLoggerData *data;
-	GFile *file;
-	GFileInfo *info;
-	guint64 file_size;
-
-	g_return_val_if_fail(PURPLE_IS_LOG(log), -1);
-
-	data = purple_log_get_logger_data(log);
-
-	if (data == NULL || data->path == NULL) {
-		g_set_error_literal(error,
-			G_IO_ERROR,
-			G_IO_ERROR_FAILED,
-			_("Unable to get log path"));
-
-		return -1;
-	}
-
-	file = g_file_new_for_path(data->path);
-	info = g_file_query_info(file, G_FILE_ATTRIBUTE_STANDARD_SIZE,
-		G_FILE_QUERY_INFO_NONE, cancellable, error);
-
-	if (info == NULL) {
-		g_object_unref(file);
-
-		return -1;
-	}
-
-	file_size = g_file_info_get_attribute_uint64(info,
-		G_FILE_ATTRIBUTE_STANDARD_SIZE);
-
-	g_object_unref(info);
-	g_object_unref(file);
-
-	return file_size;
-}
-
-static void
-sizer_thread(GSimpleAsyncResult *simple, GObject *object, GCancellable *cancellable)
-{
-	PurpleLog *log = PURPLE_LOG(object);
-	GError *error = NULL;
-	gssize size;
-
-	size = purple_log_common_sizer(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);
-}
-
-void
-purple_log_common_sizer_async(PurpleLog *log, gint io_priority, GCancellable *cancellable,
-	GAsyncReadyCallback cb, gpointer userdata)
-{
-	GSimpleAsyncResult *simple;
-
-	g_return_if_fail(PURPLE_IS_LOG(log));
-
-	simple = g_simple_async_result_new(G_OBJECT(log), cb, userdata, purple_log_common_sizer_async);
-
-	g_simple_async_result_run_in_thread(simple, sizer_thread, io_priority, cancellable);
-
-	g_object_unref(simple);
-}
-
-gssize
-purple_log_common_sizer_finish(PurpleLog *log, GAsyncResult *res, GError **error)
-{
-	GSimpleAsyncResult *simple;
-
-	g_return_val_if_fail(PURPLE_IS_LOG(log), -1);
-	g_return_val_if_fail(G_IS_SIMPLE_ASYNC_RESULT(res), -1);
-
-	simple = G_SIMPLE_ASYNC_RESULT(res);
-
-	if (g_simple_async_result_propagate_error(simple, error))
-		return -1;
-
-	return g_simple_async_result_get_op_res_gssize(simple);
-}
-
 /* This will build log sets for all loggers that use the common logger
  * functions because they use the same directory structure. */
 static GHashTable *
@@ -3473,116 +2841,7 @@ log_get_log_sets_common_async(gint io_pr
 	g_object_unref(simple);
 }
 
-gboolean
-purple_log_common_remover(PurpleLog *log, GCancellable *cancellable, GError **error)
-{
-	PurpleLogCommonLoggerData *data;
-	GFile *file;
-	gboolean result;
-
-	g_return_val_if_fail(PURPLE_IS_LOG(log), FALSE);
-
-	data = purple_log_get_logger_data(log);
-
-	if (data == NULL || data->path == NULL) {
-		g_set_error_literal(error,
-			G_IO_ERROR,
-			G_IO_ERROR_FAILED,
-			_("Unable to get log path"));
-
-		return FALSE;
-	}
-
-	file = g_file_new_for_path(data->path);
-	result = g_file_delete(file, cancellable, error);
-
-	return result;
-}
-
 static void
-remover_thread(GSimpleAsyncResult *simple, GObject *object, GCancellable *cancellable)
-{
-	PurpleLog *log = PURPLE_LOG(object);
-	GError *error = NULL;
-
-	if (!purple_log_common_remover(log, cancellable, &error))
-		g_simple_async_result_set_from_error(simple, error);
-	else
-		g_simple_async_result_set_op_res_gboolean(simple, TRUE);
-
-	g_clear_error(&error);
-}
-
-void
-purple_log_common_remover_async(PurpleLog *log, gint io_priority, GCancellable *cancellable,
-	GAsyncReadyCallback cb, gpointer userdata)
-{
-	GSimpleAsyncResult *simple;
-
-	g_return_if_fail(PURPLE_IS_LOG(log));
-
-	simple = g_simple_async_result_new(G_OBJECT(log), cb, userdata, purple_log_common_remover_async);
-
-	g_simple_async_result_run_in_thread(simple, remover_thread, io_priority, cancellable);
-	g_object_unref(simple);
-}
-
-gboolean
-purple_log_common_remover_finish(PurpleLog *log, GAsyncResult *res, GError **error)
-{
-	GSimpleAsyncResult *simple;
-
-	g_return_val_if_fail(PURPLE_IS_LOG(log), FALSE);
-	g_return_val_if_fail(G_IS_SIMPLE_ASYNC_RESULT(res), FALSE);
-
-	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
-purple_log_common_is_removable(PurpleLog *log, GCancellable *cancellable, GError **error)
-{
-	PurpleLogCommonLoggerData *data;
-	GFile *file;
-	GFileInfo *info;
-	gboolean ret;
-
-	g_return_val_if_fail(PURPLE_IS_LOG(log), FALSE);
-
-	data = purple_log_get_logger_data(log);
-
-	if (data == NULL || data->path == NULL) {
-		g_set_error_literal(error,
-			G_IO_ERROR,
-			G_IO_ERROR_FAILED,
-			_("Unable to get log path"));
-
-		return FALSE;
-	}
-
-	//file = data->file;
-	file = g_file_new_for_path(data->path);
-	info = g_file_query_info(file, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE,
-		G_FILE_QUERY_INFO_NONE, cancellable, error);
-
-	if (info == NULL) {
-		g_object_unref(file);
-		return FALSE;
-	}
-
-	ret = g_file_info_get_attribute_boolean(info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE);
-
-	g_object_unref(info);
-	g_object_unref(file);
-
-	return ret;
-}
-
-static void
 purple_log_finalize(GObject *object)
 {
 	PurpleLog *log = PURPLE_LOG(object);
@@ -3620,7 +2879,7 @@ log_list_cb(GObject *object, GAsyncResul
 		/* Let the caller know we're done. */
 		if (callback_data->cb) {
 			simple = g_simple_async_result_new(object, callback_data->cb,
-				callback_data->userdata, purple_log_common_lister_async);
+				callback_data->userdata, NULL);//purple_log_common_lister_async);
 
 			g_simple_async_result_set_op_res_gpointer(simple, callback_data->logs, NULL);
 			g_simple_async_result_complete_in_idle(simple);
@@ -3654,7 +2913,7 @@ log_system_list_cb(GObject *object, GAsy
 		/* Let the caller know we're done. */
 		if (callback_data->cb) {
 			simple = g_simple_async_result_new(object, callback_data->cb,
-				callback_data->userdata, purple_log_common_lister_async);
+				callback_data->userdata, NULL);//purple_log_common_lister_async);
 
 			g_simple_async_result_set_op_res_gpointer(simple, callback_data->logs, NULL);
 			g_simple_async_result_complete_in_idle(simple);
@@ -3696,7 +2955,7 @@ log_total_size_cb(GObject *object, GAsyn
 			GSimpleAsyncResult *simple;
 
 			simple = g_simple_async_result_new(NULL, callback_data->cb,
-				callback_data->userdata, purple_log_common_total_sizer_async);
+				callback_data->userdata, NULL); // purple_log_common_total_sizer_async);
 
 			g_simple_async_result_set_op_res_gssize(simple, callback_data->total);
 			g_simple_async_result_complete_in_idle(simple);
============================================================
--- libpurple/log.h	977c0f4af4de0a293e823c61ef5ff6e5ddb1af88
+++ libpurple/log.h	7c23301992187dbcaad13ad078a54fae1b0507da
@@ -35,8 +35,6 @@ typedef struct _PurpleLogClass PurpleLog
 typedef struct _PurpleLog PurpleLog;
 /** @copydoc _PurpleLogClass */
 typedef struct _PurpleLogClass PurpleLogClass;
-/** @copydoc _PurpleLogCommonLoggerData */
-typedef struct _PurpleLogCommonLoggerData PurpleLogCommonLoggerData;
 /** @copydoc _PurpleLogSet */
 typedef struct _PurpleLogSet PurpleLogSet;
 
@@ -200,16 +198,6 @@ struct _PurpleLogClass {
 };
 
 /**
- * A common logger_data struct containing a file handle and path, as well
- * as a pointer to something else for additional data.
- */
-struct _PurpleLogCommonLoggerData {
-	gchar *path;         /**< Path to log */
-	FILE *file;          /**< Log's file handle */
-	gpointer extra_data; /**< Any extra data passed */
-};
-
-/**
  * Describes available logs.
  *
  * By passing the elements of this struct to purple_log_get_logs(), the caller
@@ -278,7 +266,10 @@ gchar *_convert_image_tags(const PurpleL
 gchar *_log_get_timestamp(PurpleLog *log, time_t when);
 //
 gchar *_convert_image_tags(const PurpleLog *log, const gchar *msg);
+//
+gchar *_process_txt_log(gchar *, gchar *);
 
+
 //
 gboolean purple_log_create(PurpleLog *log, GCancellable *cancellable, GError **error);
 //
@@ -719,281 +710,6 @@ void purple_log_set_free(PurpleLogSet *s
 /*@}*/
 
 /******************************************/
-/** @name Common Logger Functions         */
-/******************************************/
-
-/*@{*/
-
-//
-gchar *_process_txt_log(gchar *, gchar *);
-
-/**
- * Opens a new log file in the standard 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 @c write function.
- * It should only be passed to purple_log_logger_new() and never
- * called directly.
- *
- * @param log          The log to write to
- * @param ext          (allow-none): The file extension to give to this log file
- */
-gboolean purple_log_common_writer(PurpleLog *log, const gchar *ext, GCancellable *cancellable, GError **error);
-
-/**
- * Asynchronously opens a new log in the standard log location
- *
- * For more details, see purple_log_common_writer() which is
- * the synchronous version of this call.
- *
- * @param log          The log to write to
- * @param ext          (allow-none): The file extension to give to this log file
- * @param io_priority  The io priority of the request
- * @param cancellable  (allow-none): #GCancellable object
- * @param cb           (allow-none): A #GAsyncReadyCallback to call when the request is satisfied
- * @param userdata     (allow-none): The data to pass to callback function
- */
-void purple_log_common_writer_async(PurpleLog *log, const gchar *ext, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata);
-
-/**
- * Asynchronously opens a new log in the standard log location
- *
- * For more details, see purple_log_common_writer() which is
- * the synchronous version of this call.
- *
- * @param log          The log to write to
- * @param res          A #GAsyncResult
- * @param error        (out) (allow-none): a #GError location to store the error
- *
- * @return             %TRUE if the log was created, %FALSE otherwise
- */
-gboolean purple_log_common_writer_finish(PurpleLog *log, GAsyncResult *res, GError **error);
-
-/**
- * Returns a sorted #GList of #PurpleLog<!-- -->s 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 @c list function.
- * It should only be passed to purple_log_logger_new() and never
- * called directly.
- *
- * @param type         The type of the logs being listed
- * @param name         The name of the log
- * @param account      The account of the log
- * @param ext          The file extension this log format uses
- * @param log_type     The log type to create the new logs with, or G_TYPE_INVALID to use the default type
- *
- * @return             A sorted #GList of #PurpleLog<!-- -->s matching the parameters
- */
-GList *purple_log_common_lister(PurpleLogChatType type, const gchar *name, PurpleAccount *account, const gchar *ext, GType log_type, GCancellable *cancellable, GError **error);
-
-/**
- * Asynchronously gets a sorted #GList of #PurpleLog<!-- -->s of the requested type
- *
- * For more details, see purple_log_common_lister() which is
- * the synchronous version of this call.
- *
- * @param type         The type of the logs being listed
- * @param name         The name of the log
- * @param account      The account of the log
- * @param ext          The file extension this log format uses
- * @param log_type     The log type to create the new logs with, or G_TYPE_INVALID to use the default type
- * @param io_priority  The io priority of the request
- * @param cancellable  (allow-none): #GCancellable object
- * @param cb           (allow-none): A #GAsyncReadyCallback to call when the request is satisfied
- * @param userdata     (allow-none): The data to pass to callback function
- *
- * @since 2.8.0
- */
-void purple_log_common_lister_async(PurpleLogChatType type, const gchar *name, PurpleAccount *account, const gchar *ext, GType log_type, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata);
-
-/**
- * Finishes asynchronously lister listing the #PurpleLog<!-- -->s of a requested type.
- * Remember to free the #GList returned if you do not store it.
- *
- * Note: Make sure to examine that error is not NULL as it is completely possible
- * for the list to be empty and the function to return NULL without an error
- *
- * @param res          A #GAsyncResult
- * @param error        (out) (allow-none): a #GError location to store the error
- *
- * @return             A sorted #GList of #PurpleLog<!-- -->s or %NULL on error
- *
- * @since 2.8.0
- */
-GList *purple_log_common_lister_finish(GAsyncResult *res, GError **error);
-
-/**
- * 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 @c total_size function.
- * It should only be passed to purple_log_logger_new() and never
- * called directly.
- *
- * @param type         The type of the logs being sized
- * @param name         The name of the logs to size
- *                     (e.g. the username or chat name)
- * @param account      The account of the log
- * @param ext          The file extension this log format uses
- *
- * @return             The size of all the logs with the specified extension
- *                     for the specified user
- */
-gssize purple_log_common_total_sizer(PurpleLogChatType purple_log_common_total_sizer_async, const gchar *name, PurpleAccount *account, const gchar *ext, GCancellable *cancellable, GError **error);
-
-/**
- * Asychronously gets the total size of all the logs for a given user, with
- * a given extension.
- *
- * For more details, see purple_log_common_total_sizer() which is
- * the synchronous version of this call.
- *
- * @param type         The type of the logs being sized
- * @param name         The name of the logs to size (e.g. the username or chat name)
- * @param account      The account of the log
- * @param ext          The file extension this log format uses
- * @param io_priority  The io priority of the request
- * @param cancellable  (allow-none): #GCancellable object
- * @param cb           (allow-none): A #GAsyncReadyCallback to call when the request is satisfied
- * @param userdata     (allow-none): The data to pass to callback function
- *
- * @since 2.8.0
- */
-void purple_log_common_total_sizer_async(PurpleLogChatType chat_type, const gchar *name, PurpleAccount *account, const gchar *ext, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata);
-
-/**
- * Finishes asynchronously getting the total size of logs for a given user
- *
- * @param res          A #GAsyncResult
- * @param error        (out) (allow-none): a #GError location to store the error
- *
- * @return             size of file or -1 on error
- *
- * @since 2.8.0
- */
-gssize purple_log_common_total_sizer_finish(GAsyncResult *res, GError **error);
-
-/**
- * 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 @c size function.
- * It should only be passed to purple_log_logger_new() and never
- * called directly.
- *
- * @param log          The #PurpleLog to size
- *
- * @return             An integer indicating the size of the log in bytes
- */
-gssize purple_log_common_sizer(PurpleLog *log, GCancellable *cancellable, GError **error);
-
-/**
- * Asychronously gets the size of a given #PurpleLog
- *
- * For more details, see purple_log_common_sizer() which is
- * the synchronous version of this call.
- *
- * @param log          The #PurpleLog to size
- * @param io_priority  The io priority of the request
- * @param cancellable  (allow-none): #GCancellable object
- * @param cb           (allow-none): A #GAsyncReadyCallback to call when the request is satisfied
- * @param userdata     (allow-none): The data to pass to callback function
- *
- * @since 2.8.0
- */
-void purple_log_common_sizer_async(PurpleLog *log, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata);
-
-/**
- * Finishes asynchronously getting the size of a log
- *
- * @param log          The #PurpleLog to size
- * @param res          A #GAsyncResult
- * @param error        (out) (allow-none): a #GError location to store the error
- *
- * @return             size of file or -1 on error
- *
- * @since 2.8.0
- */
-gssize purple_log_common_sizer_finish(PurpleLog *log, GAsyncResult *res, GError **error);
-
-/**
- * Removes 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 @c remove function.
- * It should only be passed to purple_log_logger_new() and never
- * called directly.
- *
- * @param log          The #PurpleLog to remove
- *
- * @return             %TRUE if the log was removed, %FALSE otherwise
- */
-gboolean purple_log_common_remover(PurpleLog *log, GCancellable *cancellable, GError **error);
-
-/**
- * Asynchronously removes 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 @c remove function.
- * It should only be passed to purple_log_logger_new() and never
- * called directly.
- *
- * @param log          The #PurpleLog to remove
- * @param io_priority  The io priority of the request
- * @param cancellable  (allow-none): #GCancellable object
- * @param cb           (allow-none): A #GAsyncReadyCallback to call when the request is satisfied
- * @param userdata     (allow-none): The data to pass to callback function
- *
- * @since 2.8.0
- */
-void purple_log_common_remover_async(PurpleLog *log, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata);
-
-/**
- * Finish asynchronously deleting a log
- *
- * @param log          The #PurpleLog to remove
- * @param res          A #GAsyncResult
- * @param error        (out) (allow-none): a #GError location to store the error
- *
- * @return             %TRUE if the log was removed, %FALSE otherwise
- *
- * @since 2.8.0
- */
-gboolean purple_log_common_remover_finish(PurpleLog *log, GAsyncResult *res, GError **error);
-
-/**
- * Checks to see if a log is removable
- *
- * 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 @c is_removable function.
- * It should only be passed to purple_log_logger_new() and never
- * called directly.
- *
- * @param log         The #PurpleLog to check
- *
- * @return            %TRUE if the log is removable, %FALSE otherwise
- */
-gboolean purple_log_common_is_removable(PurpleLog *log, GCancellable *cancellable, GError **error);
-
-void purple_log_common_is_removable_async(PurpleLog *log, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata);
-gboolean purple_log_common_is_removable_finish(PurpleLog *log, GAsyncResult *res, GError **error);
-
-/*@}*/
-
-/******************************************/
 /** @name Logger Functions                */
 /******************************************/
 
============================================================
--- libpurple/plugins/log_reader.c	258f4e12810db5d465e4a71338ce08b00eb2f8c2
+++ libpurple/plugins/log_reader.c	5d23fafd05fad811fd30da43fddb5fb92d2c2090
@@ -3,7 +3,7 @@
 #include <stdio.h>
 
 #include "debug.h"
-#include "log.h"
+#include "commonlog.h"
 #include "plugin.h"
 #include "pluginpref.h"
 #include "prefs.h"
@@ -29,7 +29,8 @@ enum name_guesses {
 };
 
 /* Some common functions. */
-static int get_month(const char *month)
+static int
+get_month(const char *month)
 {
 	int iter;
 	const char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
@@ -49,21 +50,61 @@ static int get_month(const char *month)
 /* The adium logger doesn't write logs, only reads them.  This is to include
  * Adium logs in the log viewer transparently.
  */
+#define PURPLE_TYPE_ADIUM_LOG         (purple_adium_log_get_type())
+#define PURPLE_ADIUM_LOG(o)           (G_TYPE_CHECK_INSTANCE_CAST((o), PURPLE_TYPE_ADIUM_LOG, PurpleAdiumLog))
+#define PURPLE_ADIUM_LOG_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), PURPLE_TYPE_ADIUM_LOG, PurpleAdiumLogClass))
+#define PURPLE_IS_ADIUM_LOG(o)        (G_TYPE_CHECK_INSTANCE_TYPE((o), PURPLE_TYPE_ADIUM_LOG))
+#define PURPLE_IS_ADIUM_LOG_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE((k), PURPLE_TYPE_ADIUM_LOG))
+#define PURPLE_ADIUM_LOG_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), PURPLE_TYPE_ADIUM_LOG, PurpleAdiumLogClass))
 
-static PurpleLogLogger *adium_logger;
+typedef struct _PurpleAdiumLog        PurpleAdiumLog;
+typedef struct _PurpleAdiumLogClass   PurpleAdiumLogClass;
 
-enum adium_log_type {
+struct _PurpleAdiumLog {
+	PurpleCommonLog parent_instance;
+};
+
+struct _PurpleAdiumLogClass {
+	PurpleCommonLogClass parent_class;
+};
+
+GType purple_adium_log_get_type(void);
+
+
+G_DEFINE_TYPE (PurpleAdiumLog, purple_adium_log, PURPLE_TYPE_COMMON_LOG)
+
+#define PURPLE_ADIUM_LOG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), PURPLE_TYPE_ADIUM_LOG, PurpleAdiumLogPrivate))
+typedef struct _PurpleAdiumLogPrivate PurpleAdiumLogPrivate;
+
+typedef enum {
 	ADIUM_HTML,
 	ADIUM_TEXT,
-};
+} AdiumLogType;
 
-struct adium_logger_data {
-	char *path;
-	enum adium_log_type type;
+struct _PurpleAdiumLogPrivate {
+	AdiumLogType type;
 };
 
-static GList *adium_logger_list(PurpleLogType type, const char *sn, PurpleAccount *account)
+static void
+purple_adium_log_class_init(PurpleAdiumLogClass *class)
 {
+	GObjectClass *gobject_class = G_OBJECT_CLASS(class);
+	PurpleLogClass *log_class = PURPLE_LOG_CLASS(class);
+
+	log_class->logger_name = _("Adium");
+	log_class->logger_id = "adium";
+
+	g_type_class_add_private(gobject_class, sizeof(PurpleAdiumLogPrivate));
+}
+
+static void
+purple_adium_log_init(PurpleAdiumLog *adium_log)
+{
+}
+
+static GList *
+purple_adium_log_list(PurpleLogChatType chat_type, const char *sn, PurpleAccount *account)
+{
 	GList *list = NULL;
 	const char *logdir;
 	PurplePlugin *plugin;
@@ -118,7 +159,7 @@ static GList *adium_logger_list(PurpleLo
 					FILE *handle = g_fopen(filename, "rb");
 					char contents[57];   /* XXX: This is really inflexible. */
 					char *contents2;
-					struct adium_logger_data *data;
+					struct purple_adium_log_data *data;
 					size_t rd;
 					PurpleLog *log;
 
@@ -145,13 +186,13 @@ static GList *adium_logger_list(PurpleLo
 					if (sscanf(contents2, "%u.%u.%u",
 							&tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 3) {
 
-						purple_debug_error("Adium log parse",
+						purple_debug_error("Adium log parse ",
 						                   "Contents timestamp parsing error\n");
 						g_free(filename);
 						continue;
 					}
 
-					data = g_new0(struct adium_logger_data, 1);
+					data = g_new0(struct purple_adium_log_data, 1);
 					data->path = filename;
 					data->type = ADIUM_HTML;
 
@@ -160,7 +201,7 @@ static GList *adium_logger_list(PurpleLo
 
 					/* XXX: Look into this later... Should we pass in a struct tm? */
 					log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, mktime(&tm), NULL);
-					log->logger = adium_logger;
+					log->logger = purple_adium_log;
 					log->logger_data = data;
 
 					list = g_list_prepend(list, log);
@@ -180,7 +221,7 @@ static GList *adium_logger_list(PurpleLo
 					FILE *handle = g_fopen(filename, "rb");
 					char contents[14];   /* XXX: This is really inflexible. */
 					char *contents2;
-					struct adium_logger_data *data;
+					struct purple_adium_log_data *data;
 					PurpleLog *log;
 					size_t rd;
 
@@ -211,13 +252,13 @@ static GList *adium_logger_list(PurpleLo
 					tm.tm_year -= 1900;
 					tm.tm_mon  -= 1;
 
-					data = g_new0(struct adium_logger_data, 1);
+					data = g_new0(struct purple_adium_log_data, 1);
 					data->path = filename;
 					data->type = ADIUM_TEXT;
 
 					/* XXX: Look into this later... Should we pass in a struct tm? */
 					log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, mktime(&tm), NULL);
-					log->logger = adium_logger;
+					log->logger = purple_adium_log;
 					log->logger_data = data;
 
 					list = g_list_prepend(list, log);
@@ -233,9 +274,10 @@ static GList *adium_logger_list(PurpleLo
 	return list;
 }
 
-static char *adium_logger_read (PurpleLog *log, PurpleLogReadFlags *flags)
+static gchar *
+purple_adium_log_read (PurpleLog *log, PurpleLogReadFlags *flags)
 {
-	struct adium_logger_data *data;
+	PurpleAdiumLogPrivate *priv = PURPLE_ADIUM_LOG_GET_PRIVATE(adium_log);
 	GError *error = NULL;
 	gchar *read = NULL;
 
@@ -286,45 +328,31 @@ static char *adium_logger_read (PurpleLo
 	return read;
 }
 
-static int adium_logger_size (PurpleLog *log)
+static gssize
+purple_adium_log_size(PurpleLog *log, GCancellable *cancellable, GError **error)
 {
-	struct adium_logger_data *data;
-	char *text;
+	PurpleAdiumLogPrivate *priv = PURPLE_ADIUM_LOG_GET_PRIVATE(adium_log);
+	gchar *text;
 	size_t size;
 
-	g_return_val_if_fail(log != NULL, 0);
-
-	data = log->logger_data;
-
 	if (purple_prefs_get_bool("/plugins/core/log_reader/fast_sizes")) {
 		struct stat st;
 
-		if (!data->path || stat(data->path, &st))
+		if (!priv->path || stat(priv->path, &st))
 			st.st_size = 0;
 
 		return st.st_size;
 	}
 
-	text = adium_logger_read(log, NULL);
+	// WHAT THE FUCK
+	text = purple_adium_log_read(log, NULL);
 	size = strlen(text);
 	g_free(text);
+	// WHAT THE FUCK
 
 	return size;
 }
 
-static void adium_logger_finalize(PurpleLog *log)
-{
-	struct adium_logger_data *data;
-
-	g_return_if_fail(log != NULL);
-
-	data = log->logger_data;
-
-	g_free(data->path);
-	g_free(data);
-}
-
-
 /*****************************************************************************
  * Fire Logger                                                               *
  *****************************************************************************/
@@ -2720,14 +2748,14 @@ plugin_load(PurplePlugin *plugin)
 	/* The names of IM clients are marked for translation at the request of
 	   translators who wanted to transliterate them.  Many translators
 	   choose to leave them alone.  Choose what's best for your language. */
-	adium_logger = purple_log_logger_new("adium", _("Adium"), 6,
+	purple_adium_log = purple_log_logger_new("adium", _("Adium"), 6,
 									   NULL,
 									   NULL,
-									   adium_logger_finalize,
-									   adium_logger_list,
-									   adium_logger_read,
-									   adium_logger_size);
-	purple_log_logger_add(adium_logger);
+									   purple_adium_log_finalize,
+									   purple_adium_log_list,
+									   purple_adium_log_read,
+									   purple_adium_log_size);
+	purple_log_logger_add(purple_adium_log);
 
 #if 0
 	/* The names of IM clients are marked for translation at the request of
@@ -2812,9 +2840,9 @@ plugin_unload(PurplePlugin *plugin)
 {
 	g_return_val_if_fail(plugin != NULL, FALSE);
 
-	purple_log_logger_remove(adium_logger);
-	purple_log_logger_free(adium_logger);
-	adium_logger = NULL;
+	purple_log_logger_remove(purple_adium_log);
+	purple_log_logger_free(purple_adium_log);
+	purple_adium_log = NULL;
 
 #if 0
 	purple_log_logger_remove(fire_logger);
============================================================
--- libpurple/Makefile.am	0dfb28f9e50ab5e788bbab49786fb1ed1240d830
+++ libpurple/Makefile.am	104ef9043654e3c763d888a0f714feff42df30df
@@ -43,6 +43,7 @@ purple_coresources = \
 	cipher.c \
 	circbuffer.c \
 	cmds.c \
+	commonlog.c \
 	connection.c \
 	conversation.c \
 	core.c \
@@ -112,6 +113,7 @@ purple_coreheaders = \
 	cipher.h \
 	circbuffer.h \
 	cmds.h \
+	commonlog.h \
 	connection.h \
 	conversation.h \
 	core.h \
============================================================
--- libpurple/Makefile.mingw	9c5823ace4c8012b71275e47dad6090f616f9037
+++ libpurple/Makefile.mingw	03ae406539f09200f617aec46a1079d6f1423166
@@ -37,6 +37,7 @@ C_SRC =	\
 			cipher.c \
 			circbuffer.c \
 			cmds.c \
+			commonlog.c \
 			connection.c \
 			conversation.c \
 			core.c \
============================================================
--- libpurple/plugins/Makefile.mingw	1c0ee251a4396f7ca15a2492e04cb8d6104eea7f
+++ libpurple/plugins/Makefile.mingw	3f82da8af389ddfab2842bf352efc37b9c81e164
@@ -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
 
@@ -45,12 +45,12 @@ all: $(PURPLE_DLL).a plugins
 .PHONY: all clean plugins install
 
 all: $(PURPLE_DLL).a plugins
-	$(MAKE) -C $(PERL_PLUGIN) -f $(MINGW_MAKEFILE)
+#	$(MAKE) -C $(PERL_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 $(PERL_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)
@@ -64,7 +64,7 @@ plugins: \
 		buddynote.dll \
 		idle.dll \
 		joinpart.dll \
-		log_reader.dll \
+#		log_reader.dll \
 		newline.dll \
 		offlinemsg.dll \
 		psychic.dll \
@@ -75,7 +75,7 @@ clean:
 ##
 clean:
 	rm -f *.o *.dll
-	$(MAKE) -C $(PERL_PLUGIN) -f $(MINGW_MAKEFILE) clean
+#	$(MAKE) -C $(PERL_PLUGIN) -f $(MINGW_MAKEFILE) clean
 	$(MAKE) -C $(TCL_PLUGIN) -f $(MINGW_MAKEFILE) clean
 	$(MAKE) -C $(SSL_PLUGIN) -f $(MINGW_MAKEFILE) clean
 
============================================================
--- libpurple/protocols/Makefile.mingw	fdf07fbc5764959793ab1d13ef48a65c261f6f57
+++ libpurple/protocols/Makefile.mingw	53cd9e85635b68427e3a874528a81d22da33faa3
@@ -8,7 +8,7 @@ include $(PIDGIN_TREE_TOP)/libpurple/win
 PIDGIN_TREE_TOP := ../..
 include $(PIDGIN_TREE_TOP)/libpurple/win32/global.mak
 
-SUBDIRS = gg irc jabber msn mxit novell null oscar qq sametime silc simple yahoo bonjour myspace
+SUBDIRS = jabber msn yahoo
 
 .PHONY: all install clean
 
============================================================
--- libpurple/htmllog.c	d85cee560a9a42057e30dedfaa5b22d31a02d4e8
+++ libpurple/htmllog.c	cc202c8cc731b7f07a1479827e9442cb365fa06a
@@ -27,7 +27,7 @@
 #include "internal.h"
 #include "htmllog.h"
 
-G_DEFINE_TYPE (PurpleHtmlLog, purple_html_log, PURPLE_TYPE_LOG)
+G_DEFINE_TYPE (PurpleHtmlLog, purple_html_log, PURPLE_TYPE_COMMON_LOG)
 
 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 **);
@@ -50,11 +50,8 @@ purple_html_log_class_init(PurpleHtmlLog
 	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->size_fn = purple_log_common_sizer;
 	log_class->total_size_fn = purple_html_log_total_size;
 	log_class->list_syslog_fn = purple_html_log_list_syslog;
-	log_class->is_removable_fn = purple_log_common_is_removable;
-	log_class->remove_fn = purple_log_common_remover;
 
 	gobject_class->finalize = purple_html_log_finalize;
 }
@@ -80,7 +77,6 @@ purple_html_log_write(PurpleLog *log, Pu
 static gssize
 purple_html_log_write(PurpleLog *log, PurpleMessageFlags type, const gchar *from, time_t time, const gchar *message, GCancellable *cancellable, GError **error)
 {
-	PurpleLogCommonLoggerData *data = purple_log_get_logger_data(log);
 	GFile *file;
 	GFileOutputStream *stream;
 	GOutputStream *out_stream;
@@ -89,7 +85,9 @@ purple_html_log_write(PurpleLog *log, Pu
 	gssize written, size = 0;
 	gboolean write_header;
 
-	if (data == NULL) {
+	file = purple_common_log_get_file(PURPLE_COMMON_LOG(log));
+
+	if (file == 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.
@@ -98,13 +96,13 @@ purple_html_log_write(PurpleLog *log, Pu
 		if (!purple_html_log_create(log, cancellable, error))
 			return -1;
 
-		data = purple_log_get_logger_data(log);
+		file = purple_common_log_get_file(PURPLE_COMMON_LOG(log));
 		write_header = TRUE;
 	} else
 		write_header = FALSE;
 
 	/* If we can't write to the file, give up before we hurt ourselves */
-	if (data == NULL || data->path == NULL) {
+	if (file == NULL) {
 		g_set_error_literal(error,
 			G_IO_ERROR,
 			G_IO_ERROR_FAILED,
@@ -113,7 +111,6 @@ purple_html_log_write(PurpleLog *log, Pu
 		return -1;
 	}
 
-	file = g_file_new_for_path(data->path);
 	stream = g_file_append_to(file, G_FILE_CREATE_NONE, cancellable, error);
 
 	if (stream == NULL) {
@@ -262,14 +259,15 @@ purple_html_log_read(PurpleLog *log, Pur
 static gchar *
 purple_html_log_read(PurpleLog *log, PurpleLogReadFlags *flags, GCancellable *cancellable, GError **error)
 {
-	PurpleLogCommonLoggerData *data = purple_log_get_logger_data(log);
 	GFile *file;
 	gchar *read, *minus_header;
 
 	if (flags != NULL)
 		*flags = PURPLE_LOG_READ_NO_NEWLINE;
 
-	if (data == NULL || data->path == NULL) {
+	file = purple_common_log_get_file(PURPLE_COMMON_LOG(log));
+
+	if (file == NULL) {
 		g_set_error_literal(error,
 			G_FILE_ERROR,
 			G_IO_ERROR_NOT_FOUND,
@@ -278,13 +276,8 @@ purple_html_log_read(PurpleLog *log, Pur
 		return NULL;
 	}
 
-	file = g_file_new_for_path(data->path);
-
-	if (!g_file_load_contents(file, cancellable, &read, NULL, NULL, error)) {
-		g_object_unref(file);
-
+	if (!g_file_load_contents(file, cancellable, &read, NULL, NULL, error))
 		return NULL;
-	}
 
 	minus_header = strchr(read, '\n');
 
@@ -307,21 +300,32 @@ static void
 }
 
 static void
-purple_html_log_finalize(GObject *object)
+write_footer(PurpleCommonLog *common_log, const gchar *footer)
 {
-	PurpleLog *log = PURPLE_LOG(object);
-	PurpleLogCommonLoggerData *data = purple_log_get_logger_data(log);
+	GFile *file;
+	GFileOutputStream *file_stream;
+	GOutputStream *stream;
+	gssize written;
 
-	if (data != NULL) {
-		if (data->file != NULL) {
-			fprintf(data->file, "</body></html>\n");
-			fclose(data->file);
-		}
+	file = purple_common_log_get_file(common_log);
 
-		g_free(data->path);
-		g_slice_free(PurpleLogCommonLoggerData, data);
-	}
+	if (file == NULL)
+		return;
 
+	file_stream = g_file_append_to(file, G_FILE_CREATE_PRIVATE, NULL, NULL);
+
+	if (file_stream == NULL)
+		return;
+
+	stream = G_OUTPUT_STREAM(file_stream);
+	written = g_output_stream_write(stream, footer, strlen(footer), NULL, NULL);
+	g_object_unref(file_stream);
+}
+
+static void
+purple_html_log_finalize(GObject *object)
+{
+	write_footer(PURPLE_COMMON_LOG(object), "</body></html>\n");
 	G_OBJECT_CLASS(purple_html_log_parent_class)->finalize(object);
 }
 
============================================================
--- libpurple/htmllog.h	c0a404ecb318de42b3d33520de5f2a240714e2cf
+++ libpurple/htmllog.h	59f8a50ecafe6aed88570ebd8ef2397190a7548c
@@ -30,7 +30,7 @@
 
 #include <glib-object.h>
 
-#include "log.h"
+#include "commonlog.h"
 
 G_BEGIN_DECLS
 
@@ -45,11 +45,11 @@ struct _PurpleHtmlLog {
 typedef struct _PurpleHtmlLogClass   PurpleHtmlLogClass;
 
 struct _PurpleHtmlLog {
-	PurpleLog parent_instance;
+	PurpleCommonLog parent_instance;
 };
 
 struct _PurpleHtmlLogClass {
-	PurpleLogClass parent_class;
+	PurpleCommonLogClass parent_class;
 
 	void (*_purple_reserved1)(void);
 	void (*_purple_reserved2)(void);
============================================================
--- libpurple/txtlog.c	d4dfea4a810d83bb0f83388b712f50a9d8c9255f
+++ libpurple/txtlog.c	826e680cd7f4afe55dad6cdfae534f1439971174
@@ -27,7 +27,7 @@
 #include "internal.h"
 #include "txtlog.h"
 
-G_DEFINE_TYPE (PurpleTxtLog, purple_txt_log, PURPLE_TYPE_LOG)
+G_DEFINE_TYPE (PurpleTxtLog, purple_txt_log, PURPLE_TYPE_COMMON_LOG)
 
 static gboolean purple_txt_log_create(PurpleLog *, GCancellable *, GError **);
 static gssize purple_txt_log_write(PurpleLog *, PurpleMessageFlags, const gchar *, time_t, const gchar *, GCancellable *, GError **);
@@ -35,12 +35,10 @@ static GList *purple_txt_log_list_syslog
 static gchar *purple_txt_log_read(PurpleLog *, PurpleLogReadFlags *, GCancellable *, GError **);
 static gssize purple_txt_log_total_size(PurpleLog *, PurpleLogChatType, const gchar *, PurpleAccount *, GCancellable *, GError **);
 static GList *purple_txt_log_list_syslog(PurpleLog *, PurpleAccount *, GCancellable *, GError **);
-static void purple_txt_log_finalize(GObject *);
 
 static void
 purple_txt_log_class_init(PurpleTxtLogClass *class)
 {
-	GObjectClass *gobject_class = G_OBJECT_CLASS(class);
 	PurpleLogClass *log_class = PURPLE_LOG_CLASS(class);
 
 	log_class->logger_name = _("TXT");
@@ -50,13 +48,8 @@ purple_txt_log_class_init(PurpleTxtLogCl
 	log_class->write_fn = purple_txt_log_write;
 	log_class->list_fn = purple_txt_log_list;
 	log_class->read_fn = purple_txt_log_read;
-	log_class->size_fn = purple_log_common_sizer;
 	log_class->total_size_fn = purple_txt_log_total_size;
 	log_class->list_syslog_fn = purple_txt_log_list_syslog;
-	log_class->is_removable_fn = purple_log_common_is_removable;
-	log_class->remove_fn = purple_log_common_remover;
-
-	gobject_class->finalize = purple_txt_log_finalize;
 }
 
 static void
@@ -81,7 +74,7 @@ purple_txt_log_write(PurpleLog *log, Pur
 purple_txt_log_write(PurpleLog *log, PurpleMessageFlags type, const gchar *from, time_t time, const gchar *message, GCancellable *cancellable, GError **error)
 {
 	PurpleLogChatType chat_type = purple_log_get_chat_type(log);
-	PurpleLogCommonLoggerData *data = purple_log_get_logger_data(log);
+	PurpleCommonLog *common_log = PURPLE_COMMON_LOG(log);
 	GFile *file;
 	GFileOutputStream *stream;
 	GOutputStream *out_stream;
@@ -98,7 +91,9 @@ purple_txt_log_write(PurpleLog *log, Pur
 		return -1;
 	}
 
-	if (data == NULL) {
+	file = purple_common_log_get_file(common_log);
+
+	if (file == 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.
@@ -107,13 +102,13 @@ purple_txt_log_write(PurpleLog *log, Pur
 		if (!purple_txt_log_create(log, cancellable, error))
 			return -1;
 
-		data = purple_log_get_logger_data(log);
+		file = purple_common_log_get_file(common_log);
 		write_header = TRUE;
 	} else
 		write_header = FALSE;
 
 	/* If we can't write to the file, give up before we hurt ourselves */
-	if (data == NULL || data->path == NULL) {
+	if (file == NULL) {
 		g_set_error_literal(error,
 			G_IO_ERROR,
 			G_IO_ERROR_FAILED,
@@ -122,14 +117,10 @@ purple_txt_log_write(PurpleLog *log, Pur
 		return -1;
 	}
 
-	file = g_file_new_for_path(data->path);
 	stream = g_file_append_to(file, G_FILE_CREATE_NONE, cancellable, error);
 
-	if (stream == NULL) {
-		g_object_unref(file);
-
+	if (stream == NULL)
 		return -1;
-	}
 
 	out_stream = G_OUTPUT_STREAM(stream);
 
@@ -157,7 +148,6 @@ purple_txt_log_write(PurpleLog *log, Pur
 		g_free(line);
 
 		if (written < 0) {
-			g_object_unref(file);
 			g_object_unref(stream);
 
 			return -1;
@@ -205,7 +195,6 @@ purple_txt_log_write(PurpleLog *log, Pur
 	g_free(line);
 	g_free(date);
 	g_free(stripped);
-	g_object_unref(file);
 	g_object_unref(stream);
 
 	return size;
@@ -226,14 +215,16 @@ purple_txt_log_read(PurpleLog *log, Purp
 static gchar *
 purple_txt_log_read(PurpleLog *log, PurpleLogReadFlags *flags, GCancellable *cancellable, GError **error)
 {
-	PurpleLogCommonLoggerData *data = purple_log_get_logger_data(log);
+	PurpleCommonLog *common_log = PURPLE_COMMON_LOG(log);
 	GFile *file;
 	gchar *read, *minus_header;
 
 	if (flags != NULL)
 		*flags = 0;
 
-	if (data == NULL || data->path == NULL) {
+	file = purple_common_log_get_file(common_log);
+
+	if (file == NULL) {
 		g_set_error_literal(error,
 			G_FILE_ERROR,
 			G_IO_ERROR_NOT_FOUND,
@@ -242,13 +233,8 @@ purple_txt_log_read(PurpleLog *log, Purp
 		return NULL;
 	}
 
-	file = g_file_new_for_path(data->path);
-
-	if (!g_file_load_contents(file, cancellable, &read, NULL, NULL, error)) {
-		g_object_unref(file);
-
+	if (!g_file_load_contents(file, cancellable, &read, NULL, NULL, error))
 		return NULL;
-	}
 
 	purple_str_strip_char(read, '\r');
 	minus_header = strchr(read, '\n');
@@ -265,23 +251,6 @@ purple_txt_log_total_size(PurpleLog *log
 	return purple_log_common_total_sizer(type, name, account, ".txt", cancellable, error);
 }
 
-static void
-purple_txt_log_finalize(GObject *object)
-{
-	PurpleLog *log = PURPLE_LOG(object);
-	PurpleLogCommonLoggerData *data = purple_log_get_logger_data(log);
-
-	if (data != NULL) {
-		if (data->file != NULL)
-			fclose(data->file);
-
-		g_free(data->path);
-		g_slice_free(PurpleLogCommonLoggerData, data);
-	}
-
-	G_OBJECT_CLASS(purple_txt_log_parent_class)->finalize(object);
-}
-
 void
 purple_txt_log_system_init(void)
 {
============================================================
--- libpurple/txtlog.h	8ea7e9aaafe92ee0f3c464b14bc2a1d04dad0b71
+++ libpurple/txtlog.h	5071e96791c31a889d9c88f5e44c62b6a7657e64
@@ -30,7 +30,7 @@
 
 #include <glib-object.h>
 
-#include "log.h"
+#include "commonlog.h"
 
 G_BEGIN_DECLS
 
@@ -45,11 +45,11 @@ struct _PurpleTxtLog {
 typedef struct _PurpleTxtLogClass   PurpleTxtLogClass;
 
 struct _PurpleTxtLog {
-	PurpleLog parent_instance;
+	PurpleCommonLog parent_instance;
 };
 
 struct _PurpleTxtLogClass {
-	PurpleLogClass parent_class;
+	PurpleCommonLogClass parent_class;
 
 	void (*_purple_reserved1)(void);
 	void (*_purple_reserved2)(void);
============================================================
--- /dev/null	
+++ libpurple/commonlog.c	eafb2644e4d53fcf12ead236aa3b01645b82f9f6
@@ -0,0 +1,669 @@
+/**
+ * @file commonlog.c Common Logger API
+ * @ingroup core
+ */
+
+/* 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 "internal.h"
+#include "commonlog.h"
+
+G_DEFINE_TYPE (PurpleCommonLog, purple_common_log, PURPLE_TYPE_LOG)
+
+#define PURPLE_COMMON_LOG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), PURPLE_TYPE_COMMON_LOG, PurpleCommonLogPrivate))
+typedef struct _PurpleCommonLogPrivate PurpleCommonLogPrivate;
+
+struct _PurpleCommonLogPrivate {
+	GFile *file;
+};
+
+typedef struct {
+	PurpleAccount *account;
+	PurpleLogChatType chat_type;
+	gchar *name;
+	gchar *ext;
+} _common_total_size_callback_data;
+
+typedef struct {
+	PurpleAccount *account;
+	PurpleLogChatType chat_type;
+	GType log_type;
+	gchar *name;
+	gchar *ext;
+} _common_lister_callback_data;
+
+static void common_total_size_callback_data_free(gpointer);
+static void common_lister_callback_data_free(gpointer);
+
+// static gboolean purple_log_common_create(PurpleLog *, GCancellable *, GError **);
+static gboolean purple_log_common_remove(PurpleLog *, GCancellable *, GError **);
+static gboolean purple_log_common_is_removable(PurpleLog *, GCancellable *, GError **);
+static gssize purple_log_common_size(PurpleLog *, GCancellable *, GError **);
+static void purple_common_log_finalize(GObject *);
+
+static void
+purple_common_log_class_init(PurpleCommonLogClass *class)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS(class);
+	PurpleLogClass *log_class = PURPLE_LOG_CLASS(class);
+
+	log_class->logger_name = _("Common");
+	log_class->logger_id = "common";
+
+	// log_class->create_fn = purple_common_log_create;
+	log_class->remove_fn = purple_log_common_remove;
+	log_class->is_removable_fn = purple_log_common_is_removable;
+	log_class->size_fn = purple_log_common_size;
+
+	gobject_class->finalize = purple_common_log_finalize;
+}
+
+static void
+purple_common_log_init(PurpleCommonLog *common_log)
+{
+	PurpleCommonLogPrivate *priv = PURPLE_COMMON_LOG_GET_PRIVATE(common_log);
+
+	priv->file = NULL;
+}
+
+PurpleLog *
+purple_common_log_new(PurpleLogChatType type, const gchar *name, PurpleAccount *account,
+	PurpleConversation *conv, time_t time, const struct tm *tm)
+{
+	return purple_log_new(PURPLE_TYPE_COMMON_LOG, type, name, account, conv, time, tm);
+}
+
+GFile *
+purple_common_log_get_file(PurpleCommonLog *common_log)
+{
+	g_return_val_if_fail(PURPLE_IS_COMMON_LOG(common_log), NULL);
+
+	return PURPLE_COMMON_LOG_GET_PRIVATE(common_log)->file;
+}
+
+static void
+common_total_size_callback_data_free(gpointer userdata)
+{
+	_common_total_size_callback_data *callback_data = userdata;
+
+	g_free(callback_data->name);
+	g_free(callback_data->ext);
+	g_free(callback_data);
+}
+
+static void
+common_lister_callback_data_free(gpointer userdata)
+{
+	_common_lister_callback_data *callback_data = userdata;
+
+	g_free(callback_data->name);
+	g_free(callback_data->ext);
+	g_free(callback_data);
+}
+
+static gboolean
+purple_log_common_remove(PurpleLog *log, GCancellable *cancellable, GError **error)
+{
+	PurpleCommonLogPrivate *priv = PURPLE_COMMON_LOG_GET_PRIVATE(log);
+	gboolean result;
+
+	if (priv->file == NULL) {
+		g_set_error_literal(error,
+			G_IO_ERROR,
+			G_IO_ERROR_FAILED,
+			_("Unable to get log path"));
+
+		return FALSE;
+	}
+
+	result = g_file_delete(priv->file, cancellable, error);
+	g_object_unref(priv->file);
+	priv->file = NULL;
+
+	return result;
+}
+
+static gboolean
+purple_log_common_is_removable(PurpleLog *log, GCancellable *cancellable, GError **error)
+{
+	PurpleCommonLogPrivate *priv = PURPLE_COMMON_LOG_GET_PRIVATE(log);
+	GFileInfo *info;
+	gboolean ret;
+
+	if (priv->file == NULL) {
+		g_set_error_literal(error,
+			G_IO_ERROR,
+			G_IO_ERROR_FAILED,
+			_("Unable to get log path"));
+
+		return FALSE;
+	}
+
+	info = g_file_query_info(priv->file, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE,
+		G_FILE_QUERY_INFO_NONE, cancellable, error);
+
+	if (info == NULL)
+		return FALSE;
+
+	ret = g_file_info_get_attribute_boolean(info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE);
+	g_object_unref(info);
+
+	return ret;
+}
+
+gboolean
+purple_log_common_writer(PurpleLog *log, const gchar *ext, GCancellable *cancellable, GError **error)
+{
+	PurpleCommonLogPrivate *priv;
+
+	g_return_val_if_fail(PURPLE_IS_COMMON_LOG(log), FALSE);
+
+	priv = PURPLE_COMMON_LOG_GET_PRIVATE(log);
+
+	if (priv->file == NULL) {
+		GFileOutputStream *stream;
+		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) {
+			g_set_error_literal(error,
+				G_IO_ERROR,
+				G_IO_ERROR_FAILED,
+				_("Unable to get log directory"));
+
+			return FALSE;
+		}
+
+		if (purple_build_dir(dir, S_IRUSR | S_IWUSR | S_IXUSR) < 0) {
+			g_set_error_literal(error,
+				G_FILE_ERROR,
+				g_file_error_from_errno(errno),
+				g_strerror(errno));
+
+			return FALSE;
+		}
+
+		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);
+
+		priv->file = g_file_new_for_path(path);
+		g_free(path);
+
+		/* Make sure the file is writeable */
+		stream = g_file_append_to(priv->file, G_FILE_CREATE_PRIVATE, cancellable, error);
+
+		if (stream == NULL) {
+			// 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));
+
+			g_object_unref(priv->file);
+			priv->file = NULL;
+
+			return FALSE;
+		} else
+			g_object_unref(stream);
+	}
+
+	return TRUE;
+}
+
+static void
+writer_thread(GSimpleAsyncResult *simple, GObject *object, GCancellable *cancellable)
+{
+	PurpleLog *log = PURPLE_LOG(object);
+	GError *error = NULL;
+	gchar *ext = g_simple_async_result_get_op_res_gpointer(simple);
+	gboolean result;
+
+	result = purple_log_common_writer(log, ext, cancellable, &error);
+
+	if (!result)
+		g_simple_async_result_set_from_error(simple, error);
+	else
+		g_simple_async_result_set_op_res_gboolean(simple, TRUE);
+
+	g_clear_error(&error);
+}
+
+void
+purple_log_common_writer_async(PurpleLog *log, const gchar *ext, gint io_priority,
+	GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
+{
+	GSimpleAsyncResult *simple;
+
+	g_return_if_fail(PURPLE_IS_LOG(log));
+
+	simple = g_simple_async_result_new(G_OBJECT(log), cb, userdata, purple_log_common_writer_async);
+
+	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);
+	g_object_unref(simple);
+}
+
+gboolean
+purple_log_common_writer_finish(PurpleLog *log, GAsyncResult *res, GError **error)
+{
+	GSimpleAsyncResult *simple;
+
+	g_return_val_if_fail(PURPLE_IS_COMMON_LOG(log), FALSE);
+	g_return_val_if_fail(G_IS_SIMPLE_ASYNC_RESULT(res), FALSE);
+
+	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(G_SIMPLE_ASYNC_RESULT(res));
+}
+
+GList *
+purple_log_common_lister(PurpleLogChatType chat_type, const gchar *name, PurpleAccount *account,
+	const gchar *ext, GType log_type, GCancellable *cancellable, GError **error)
+{
+	GDir *dir;
+	GList *list = NULL;
+	const gchar *filename;
+	gchar *path;
+
+	g_return_val_if_fail(name != NULL, NULL);
+	g_return_val_if_fail(account != NULL, 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);
+
+	path = purple_log_get_log_dir(chat_type, name, account);
+
+	if (path == NULL) {
+		g_set_error_literal(error,
+			G_IO_ERROR,
+			G_IO_ERROR_FAILED,
+			_("Unable to get log directory"));
+
+		return NULL;
+	}
+
+	dir = g_dir_open(path, 0, error);
+
+	if (dir == NULL) {
+		g_free(path);
+
+		return NULL;
+	}
+
+	while ((filename = g_dir_read_name(dir)) != NULL) {
+		if (g_cancellable_set_error_if_cancelled(cancellable, error)) {
+			g_dir_close(dir);
+			g_free(path);
+
+			g_list_foreach(list, (GFunc) g_object_unref, NULL);
+			g_list_free(list);
+
+			return NULL;
+		}
+
+		if (purple_str_has_suffix(filename, ext) &&
+		    strlen(filename) >= (17 + strlen(ext)))
+		{
+			PurpleCommonLogPrivate *priv;
+			PurpleLog *log;
+			gchar *tmp;
+			struct tm tm;
+#if defined (HAVE_TM_GMTOFF) && defined (HAVE_STRUCT_TM_TM_ZONE)
+			long tz_off;
+			const gchar *rest, *end;
+			time_t stamp;
+
+			stamp = purple_str_to_time(purple_unescape_filename(filename), FALSE, &tm, &tz_off, &rest);
+
+			/* As zero is a valid offset, PURPLE_NO_TZ_OFF means no offset was
+			 * provided. See util.h. Yes, it's kinda ugly. */
+			if (tz_off != PURPLE_NO_TZ_OFF)
+				tm.tm_gmtoff = tz_off - tm.tm_gmtoff;
+
+			if (stamp == 0 || rest == NULL || (end = strchr(rest, '.')) == NULL || strchr(rest, ' ') != NULL) {
+				log = purple_log_new(log_type, chat_type, name, account, NULL, stamp, NULL);
+			} else {
+				gchar *tmp = g_strndup(rest, end - rest);
+				tm.tm_zone = tmp;
+				log = purple_log_new(log_type, chat_type, name, account, NULL, stamp, &tm);
+				g_free(tmp);
+			}
+#else
+			time_t stamp = purple_str_to_time(filename, FALSE, &tm, NULL, NULL);
+
+			log = purple_log_new(log_type, chat_type, name, account, NULL, stamp, (stamp != 0) ?  &tm : NULL);
+#endif
+
+			priv = PURPLE_COMMON_LOG_GET_PRIVATE(log);
+			tmp = g_build_filename(path, filename, NULL);
+			priv->file = g_file_new_for_path(tmp);
+			g_free(tmp);
+
+			list = g_list_prepend(list, log);
+		}
+	}
+
+	g_dir_close(dir);
+	g_free(path);
+
+	return list;
+}
+
+static void
+common_lister_thread(GSimpleAsyncResult *simple, GObject *object, GCancellable *cancellable)
+{
+	_common_lister_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;
+	GType log_type = callback_data->log_type;
+	GError *error = NULL;
+	GList *list;
+	gchar *name = callback_data->name, *ext = callback_data->ext;
+
+	list = purple_log_common_lister(chat_type, name, account, ext, log_type, cancellable, &error);
+
+	if (list == NULL)
+		g_simple_async_result_set_from_error(simple, error);
+	else
+		g_simple_async_result_set_op_res_gpointer(simple, list, (GDestroyNotify) g_list_free);
+
+	g_clear_error(&error);
+}
+
+void
+purple_log_common_lister_async(PurpleLogChatType chat_type, const gchar *name, PurpleAccount *account,
+	const gchar *ext, GType log_type, gint io_priority, GCancellable *cancellable,
+	GAsyncReadyCallback cb, gpointer userdata)
+{
+	_common_lister_callback_data *callback_data;
+	GSimpleAsyncResult *simple;
+
+	g_return_if_fail(name != NULL);
+	g_return_if_fail(account != NULL); // PURPLE_IS_ACCOUNT(account)
+	g_return_if_fail(ext != NULL);
+
+	callback_data = g_new0(_common_lister_callback_data, 1);
+	callback_data->chat_type = chat_type;
+	callback_data->name = g_strdup(name);
+	callback_data->account = account;
+	callback_data->ext = g_strdup(ext);
+	callback_data->log_type = log_type;
+
+	simple = g_simple_async_result_new(NULL, cb, userdata, purple_log_common_lister_async);
+
+	g_simple_async_result_set_op_res_gpointer(simple, callback_data,
+		common_lister_callback_data_free);
+	g_simple_async_result_run_in_thread(simple, common_lister_thread, io_priority,
+		cancellable);
+
+	g_object_unref(simple);
+}
+
+GList *
+purple_log_common_lister_finish(GAsyncResult *res, GError **error)
+{
+	GSimpleAsyncResult *simple;
+
+	simple = G_SIMPLE_ASYNC_RESULT(res);
+
+	if (g_simple_async_result_propagate_error(simple, error))
+		return NULL;
+
+	g_return_val_if_fail(g_simple_async_result_get_source_tag(simple) == purple_log_common_lister_async, NULL);
+
+	return g_simple_async_result_get_op_res_gpointer(simple);
+}
+
+// TODO: Rather than calling this multiple times with different extensions,
+// TODO: could we somehow store up all the extensions and do the loop just
+// TODO: once?  This may be possible with the non-blocking stuff...
+gssize
+purple_log_common_total_sizer(PurpleLogChatType chat_type, const gchar *name, PurpleAccount *account, const gchar *ext, GCancellable *cancellable, GError **error)
+{
+	// _purple_logsize_user *lu;
+	GDir *dir;
+	GError *err = NULL;
+	const gchar *filename;
+	gchar *path;
+	gssize size = 0;//, total;
+	// gpointer ptrsize;
+
+	g_return_val_if_fail(name != NULL, 0);
+	g_return_val_if_fail(account != NULL, 0);
+	g_return_val_if_fail(ext != NULL, 0);
+
+	path = purple_log_get_log_dir(chat_type, name, account);
+
+	if (path == NULL) {
+		g_set_error_literal(error,
+			G_IO_ERROR,
+			G_IO_ERROR_FAILED,
+			_("Unable to get log directory"));
+
+		return -1;
+	}
+
+	dir = g_dir_open(path, 0, &err);
+
+	if (dir == NULL){
+		g_free(path);
+
+		/* If the directory doesn't exist, we just don't have logs for them */
+		if (err->code == G_FILE_ERROR_NOENT) {
+			// G_LOCK(logsize_users);
+
+			// lu = g_new(_purple_logsize_user, 1);
+			// lu->name = g_strdup(purple_normalize(account, name));
+			// lu->account = account; //g_object_ref?
+
+			// if (!g_hash_table_lookup_extended(logsize_users, lu, NULL, NULL))
+				// g_hash_table_replace(logsize_users, lu, GINT_TO_POINTER(size));
+
+			// G_UNLOCK(logsize_users);
+
+			return 0;
+		} else {
+			g_propagate_error(error, err);
+			return -1;
+		}
+	}
+
+	while ((filename = g_dir_read_name(dir)) != NULL) {
+		if (g_cancellable_set_error_if_cancelled(cancellable, error)) {
+			g_dir_close(dir);
+			g_free(path);
+
+			return -1;
+		}
+
+		if (purple_str_has_suffix(filename, ext) &&
+		    strlen(filename) >= 17 + strlen(ext))
+		{
+			GFile *file;
+			GFileInfo *info;
+			gchar *tmp = g_build_filename(path, filename, NULL);
+			guint64 file_size;
+
+			file = g_file_new_for_path(tmp);
+			info = g_file_query_info(file, G_FILE_ATTRIBUTE_STANDARD_SIZE,
+				G_FILE_QUERY_INFO_NONE, cancellable, error);
+
+			if (info == NULL) {
+				g_dir_close(dir);
+				g_object_unref(file);
+				g_free(path);
+				g_free(tmp);
+
+				return -1;
+			}
+
+			file_size = g_file_info_get_attribute_uint64(info,
+				G_FILE_ATTRIBUTE_STANDARD_SIZE);
+			size += file_size;
+
+			g_object_unref(info);
+			g_object_unref(file);
+			g_free(tmp);
+		}
+	}
+
+
+	// G_LOCK(logsize_users);
+	// lu = g_new(_purple_logsize_user, 1);
+	// lu->name = g_strdup(purple_normalize(account, name));
+	// lu->account = account; //g_object_ref?
+
+	// total = size;
+
+	// if (g_hash_table_lookup_extended(logsize_users, lu, NULL, &ptrsize))
+		// total += GPOINTER_TO_INT(ptrsize);
+
+	// g_hash_table_replace(logsize_users, lu, GINT_TO_POINTER(total));
+	// G_UNLOCK(logsize_users);
+
+	g_dir_close(dir);
+	g_free(path);
+
+	return size;
+}
+
+static void
+common_total_sizer_thread(GSimpleAsyncResult *simple, GObject *object, GCancellable *cancellable)
+{
+	_common_total_size_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, *ext = callback_data->ext;
+	gssize size;
+
+	size = purple_log_common_total_sizer(chat_type, name, account, ext, 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);
+}
+
+void
+purple_log_common_total_sizer_async(PurpleLogChatType chat_type, const gchar *name,
+	PurpleAccount *account, const gchar *ext, gint io_priority, GCancellable *cancellable,
+	GAsyncReadyCallback cb, gpointer userdata)
+{
+	_common_total_size_callback_data *callback_data;
+	GSimpleAsyncResult *simple;
+
+	g_return_if_fail(name != NULL);
+	g_return_if_fail(account != NULL);
+	g_return_if_fail(ext != NULL);
+
+	callback_data = g_new0(_common_total_size_callback_data, 1);
+	callback_data->chat_type = chat_type;
+	callback_data->name = g_strdup(name);
+	callback_data->account = account;
+	callback_data->ext = g_strdup(ext);
+
+	simple = g_simple_async_result_new(NULL, cb, userdata, purple_log_common_total_sizer_async);
+
+	g_simple_async_result_set_op_res_gpointer(simple, callback_data,
+		common_total_size_callback_data_free);
+	g_simple_async_result_run_in_thread(simple, common_total_sizer_thread, io_priority, cancellable);
+
+	g_object_unref(simple);
+}
+
+gssize
+purple_log_common_total_sizer_finish(GAsyncResult *res, GError **error)
+{
+	GSimpleAsyncResult *simple;
+
+	simple = G_SIMPLE_ASYNC_RESULT(res);
+
+	if (g_simple_async_result_propagate_error(simple, error))
+		return -1;
+
+	g_return_val_if_fail(g_simple_async_result_get_source_tag(simple) == purple_log_common_total_sizer_async, -1);
+
+	return g_simple_async_result_get_op_res_gssize(simple);
+}
+
+static gssize
+purple_log_common_size(PurpleLog *log, GCancellable *cancellable, GError **error)
+{
+	PurpleCommonLogPrivate *priv = PURPLE_COMMON_LOG_GET_PRIVATE(log);
+	GFileInfo *info;
+	guint64 file_size;
+
+	if (priv->file == NULL) {
+		g_set_error_literal(error,
+			G_IO_ERROR,
+			G_IO_ERROR_FAILED,
+			_("Unable to get log path"));
+
+		return -1;
+	}
+
+	info = g_file_query_info(priv->file, G_FILE_ATTRIBUTE_STANDARD_SIZE,
+		G_FILE_QUERY_INFO_NONE, cancellable, error);
+
+	if (info == NULL)
+		return -1;
+
+	file_size = g_file_info_get_attribute_uint64(info,
+		G_FILE_ATTRIBUTE_STANDARD_SIZE);
+
+	g_object_unref(info);
+
+	return file_size;
+}
+
+static void
+purple_common_log_finalize(GObject *object)
+{
+	PurpleCommonLogPrivate *priv = PURPLE_COMMON_LOG_GET_PRIVATE(object);
+
+	if (priv->file != NULL)
+		g_object_unref(priv->file);
+
+	G_OBJECT_CLASS(purple_common_log_parent_class)->finalize(object);
+}
+
============================================================
--- /dev/null	
+++ libpurple/commonlog.h	8bf62d8086d3c374ec6603dbab347c6edc9f794d
@@ -0,0 +1,233 @@
+/**
+ * @file commonlog.h Logging API
+ * @ingroup core
+ * @see @ref log-signals
+ */
+
+/* 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
+ */
+
+#ifndef _PURPLE_COMMON_LOG_H_
+#define _PURPLE_COMMON_LOG_H_
+
+#include <glib-object.h>
+
+#include "log.h"
+
+G_BEGIN_DECLS
+
+#define PURPLE_TYPE_COMMON_LOG         (purple_common_log_get_type())
+#define PURPLE_COMMON_LOG(o)           (G_TYPE_CHECK_INSTANCE_CAST((o), PURPLE_TYPE_COMMON_LOG, PurpleCommonLog))
+#define PURPLE_COMMON_LOG_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), PURPLE_TYPE_COMMON_LOG, PurpleCommonLogClass))
+#define PURPLE_IS_COMMON_LOG(o)        (G_TYPE_CHECK_INSTANCE_TYPE((o), PURPLE_TYPE_COMMON_LOG))
+#define PURPLE_IS_COMMON_LOG_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE((k), PURPLE_TYPE_COMMON_LOG))
+#define PURPLE_COMMON_LOG_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), PURPLE_TYPE_COMMON_LOG, PurpleCommonLogClass))
+
+typedef struct _PurpleCommonLog        PurpleCommonLog;
+typedef struct _PurpleCommonLogClass   PurpleCommonLogClass;
+
+struct _PurpleCommonLog {
+	PurpleLog parent_instance;
+};
+
+struct _PurpleCommonLogClass {
+	PurpleLogClass parent_class;
+
+	void (*_purple_reserved1)(void);
+	void (*_purple_reserved2)(void);
+	void (*_purple_reserved3)(void);
+	void (*_purple_reserved4)(void);
+};
+
+GType purple_common_log_get_type(void);
+
+PurpleLog *purple_common_log_new(PurpleLogChatType chat_type, const gchar *name, PurpleAccount *account,
+	PurpleConversation *conv, time_t time, const struct tm *tm);
+
+
+/******************************************/
+/** @name Common Logger Functions         */
+/******************************************/
+
+/*@{*/
+
+GFile *purple_common_log_get_file(PurpleCommonLog *common_log);
+
+/**
+ * Opens a new log file in the standard 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 @c write function.
+ * It should only be passed to purple_log_logger_new() and never
+ * called directly.
+ *
+ * @param log          The log to write to
+ * @param ext          (allow-none): The file extension to give to this log file
+ */
+gboolean purple_log_common_writer(PurpleLog *log, const gchar *ext, GCancellable *cancellable, GError **error);
+
+/**
+ * Asynchronously opens a new log in the standard log location
+ *
+ * For more details, see purple_log_common_writer() which is
+ * the synchronous version of this call.
+ *
+ * @param log          The log to write to
+ * @param ext          (allow-none): The file extension to give to this log file
+ * @param io_priority  The io priority of the request
+ * @param cancellable  (allow-none): #GCancellable object
+ * @param cb           (allow-none): A #GAsyncReadyCallback to call when the request is satisfied
+ * @param userdata     (allow-none): The data to pass to callback function
+ */
+void purple_log_common_writer_async(PurpleLog *log, const gchar *ext, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata);
+
+/**
+ * Asynchronously opens a new log in the standard log location
+ *
+ * For more details, see purple_log_common_writer() which is
+ * the synchronous version of this call.
+ *
+ * @param log          The log to write to
+ * @param res          A #GAsyncResult
+ * @param error        (out) (allow-none): a #GError location to store the error
+ *
+ * @return             %TRUE if the log was created, %FALSE otherwise
+ */
+gboolean purple_log_common_writer_finish(PurpleLog *log, GAsyncResult *res, GError **error);
+
+/**
+ * Returns a sorted #GList of #PurpleLog<!-- -->s 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 @c list function.
+ * It should only be passed to purple_log_logger_new() and never
+ * called directly.
+ *
+ * @param type         The type of the logs being listed
+ * @param name         The name of the log
+ * @param account      The account of the log
+ * @param ext          The file extension this log format uses
+ * @param log_type     The log type to create the new logs with, or G_TYPE_INVALID to use the default type
+ *
+ * @return             A sorted #GList of #PurpleLog<!-- -->s matching the parameters
+ */
+GList *purple_log_common_lister(PurpleLogChatType type, const gchar *name, PurpleAccount *account, const gchar *ext, GType log_type, GCancellable *cancellable, GError **error);
+
+/**
+ * Asynchronously gets a sorted #GList of #PurpleLog<!-- -->s of the requested type
+ *
+ * For more details, see purple_log_common_lister() which is
+ * the synchronous version of this call.
+ *
+ * @param type         The type of the logs being listed
+ * @param name         The name of the log
+ * @param account      The account of the log
+ * @param ext          The file extension this log format uses
+ * @param log_type     The log type to create the new logs with, or G_TYPE_INVALID to use the default type
+ * @param io_priority  The io priority of the request
+ * @param cancellable  (allow-none): #GCancellable object
+ * @param cb           (allow-none): A #GAsyncReadyCallback to call when the request is satisfied
+ * @param userdata     (allow-none): The data to pass to callback function
+ *
+ * @since 2.8.0
+ */
+void purple_log_common_lister_async(PurpleLogChatType type, const gchar *name, PurpleAccount *account, const gchar *ext, GType log_type, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata);
+
+/**
+ * Finishes asynchronously lister listing the #PurpleLog<!-- -->s of a requested type.
+ * Remember to free the #GList returned if you do not store it.
+ *
+ * Note: Make sure to examine that error is not NULL as it is completely possible
+ * for the list to be empty and the function to return NULL without an error
+ *
+ * @param res          A #GAsyncResult
+ * @param error        (out) (allow-none): a #GError location to store the error
+ *
+ * @return             A sorted #GList of #PurpleLog<!-- -->s or %NULL on error
+ *
+ * @since 2.8.0
+ */
+GList *purple_log_common_lister_finish(GAsyncResult *res, GError **error);
+
+/**
+ * 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 @c total_size function.
+ * It should only be passed to purple_log_logger_new() and never
+ * called directly.
+ *
+ * @param type         The type of the logs being sized
+ * @param name         The name of the logs to size
+ *                     (e.g. the username or chat name)
+ * @param account      The account of the log
+ * @param ext          The file extension this log format uses
+ *
+ * @return             The size of all the logs with the specified extension
+ *                     for the specified user
+ */
+gssize purple_log_common_total_sizer(PurpleLogChatType purple_log_common_total_sizer_async, const gchar *name, PurpleAccount *account, const gchar *ext, GCancellable *cancellable, GError **error);
+
+/**
+ * Asychronously gets the total size of all the logs for a given user, with
+ * a given extension.
+ *
+ * For more details, see purple_log_common_total_sizer() which is
+ * the synchronous version of this call.
+ *
+ * @param type         The type of the logs being sized
+ * @param name         The name of the logs to size (e.g. the username or chat name)
+ * @param account      The account of the log
+ * @param ext          The file extension this log format uses
+ * @param io_priority  The io priority of the request
+ * @param cancellable  (allow-none): #GCancellable object
+ * @param cb           (allow-none): A #GAsyncReadyCallback to call when the request is satisfied
+ * @param userdata     (allow-none): The data to pass to callback function
+ *
+ * @since 2.8.0
+ */
+void purple_log_common_total_sizer_async(PurpleLogChatType chat_type, const gchar *name, PurpleAccount *account, const gchar *ext, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata);
+
+/**
+ * Finishes asynchronously getting the total size of logs for a given user
+ *
+ * @param res          A #GAsyncResult
+ * @param error        (out) (allow-none): a #GError location to store the error
+ *
+ * @return             size of file or -1 on error
+ *
+ * @since 2.8.0
+ */
+gssize purple_log_common_total_sizer_finish(GAsyncResult *res, GError **error);
+
+/*@}*/
+
+G_END_DECLS
+
+#endif /* _PURPLE_COMMON_LOG_H_ */


More information about the Commits mailing list