cpw.nader.asynclogging-3: a517b732: Renamed purple_log_common_writer to purp...

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


----------------------------------------------------------------------
Revision: a517b73241843b2f3bd4dc5a15504a99fcd9ad2d
Parent:   ce1bc7375299c883727bafa662aba46657f67d7f
Author:   morshed.nader at gmail.com
Date:     01/02/12 23:52:57
Branch:   im.pidgin.cpw.nader.asynclogging-3
URL: http://d.pidgin.im/viewmtn/revision/info/a517b73241843b2f3bd4dc5a15504a99fcd9ad2d

Changelog: 

Renamed purple_log_common_writer to purple_log_common_create
Renamed purple_log_common_total_sizer to purple_log_common_total_size
Added some helpful macros to commonlog.c to aid in code readability
Fixed the PURPLE_IS_ACCOUNT macro
Removed the GFile property and added simpler socket and file path properties
Fixed the code to be fully asynchronously without using any threads within our code (!)
- Will add read/write functions to commonlog.c soon, too

Changes against parent ce1bc7375299c883727bafa662aba46657f67d7f

  patched  libpurple/commonlog.c
  patched  libpurple/commonlog.h

-------------- next part --------------
============================================================
--- libpurple/commonlog.c	b688977bfa7de76e94b05bd4fec0f2b67c884015
+++ libpurple/commonlog.c	c45e29d47b6e34e6bf88ed98c5587a24fce164e3
@@ -30,9 +30,46 @@
 
 
 /* Helpful macros */
-#define PURPLE_IS_ACCOUNT(account) TRUE
+#define PURPLE_IS_ACCOUNT(account) (account != NULL)
 
+#if GLIB_CHECK_VERSION(2, 26, 0)
+#define G_OBJECT_NOTIFY(obj, prop, name) \
+	g_object_notify_by_pspec(G_OBJECT(obj), \
+		properties[prop]);
+#else
+#define G_OBJECT_NOTIFY(obj, prop, name) \
+	g_object_notify(G_OBJECT(obj), name);
+#endif
 
+#define SIMPLE_ASYNC_RESULT_NEW_GOOD(obj, cb, data, source, cmd) \
+	{ \
+		GSimpleAsyncResult *simple; \
+		simple = g_simple_async_result_new(G_OBJECT(obj), cb, data, source); \
+		cmd; \
+		g_simple_async_result_complete_in_idle(simple); \
+		g_object_unref(simple); \
+	}
+
+#define SIMPLE_ASYNC_RESULT_FROM_ERROR(obj, cb, data, err) \
+	{ \
+		GSimpleAsyncResult *simple; \
+		simple = g_simple_async_result_new_from_error(G_OBJECT(obj), cb, \
+			data, err); \
+		g_clear_error(&err); \
+		g_simple_async_result_complete_in_idle(simple); \
+		g_object_unref(simple); \
+	}
+
+#define SIMPLE_ASYNC_RESULT_FROM_NEW_ERROR(obj, cb, data, domain, code, msg) \
+	{ \
+		GSimpleAsyncResult *simple; \
+		simple = g_simple_async_result_new_error(G_OBJECT(obj), cb, data, \
+			domain, code, msg); \
+		g_simple_async_result_complete_in_idle(simple); \
+		g_object_unref(simple); \
+	}
+
+
 /* Structures */
 G_DEFINE_TYPE (PurpleCommonLog, purple_common_log, PURPLE_TYPE_LOG)
 static void purple_common_log_get_property(GObject *, guint, GValue *,
@@ -43,7 +80,8 @@ enum {
 
 enum {
 	PROP_0,
-	PROP_COMMON_LOG_FILE,
+	PROP_COMMON_LOG_PATH,
+	PROP_COMMON_LOG_SOCKET,
 	PROP_COMMON_LOG_OFFSET,
 	PROP_COMMON_LOG_LENGTH,
 	LAST_PROP
@@ -51,11 +89,13 @@ static GParamSpec *properties[LAST_PROP]
 
 static GParamSpec *properties[LAST_PROP] = { 0 };
 
-#define PURPLE_COMMON_LOG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), PURPLE_TYPE_COMMON_LOG, PurpleCommonLogPrivate))
+#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;
+	gchar *path;
+	gint socket;
 	gssize offset;
 	gssize length;
 };
@@ -69,30 +109,84 @@ typedef struct {
 } _common_thread_callback_data;
 
 typedef struct {
-	PurpleLog *log;
+	PurpleCommonLog *log;
+	GCancellable *cancel;
 	GAsyncReadyCallback cb;
 	gpointer userdata;
-} _writer_callback_data;
+	gchar *path;
+} create_callback_data;
 
+typedef struct {
+	PurpleLogChatType chat_type;
+	gchar *name;
+	PurpleAccount *account;
+	gchar *ext;
+	GType log_type;
+	gint io_priority;
+	GCancellable *cancel;
+	GAsyncReadyCallback cb;
+	gpointer userdata;
+	GList *logs;
+} list_callback_data;
 
+typedef struct {
+	PurpleLogChatType chat_type;
+	gchar *name;
+	PurpleAccount *account;
+	gchar *ext;
+	gint io_priority;
+	GCancellable *cancel;
+	GAsyncReadyCallback cb;
+	gpointer userdata;
+	guint64 total;
+} total_size_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);
+static gboolean purple_log_common_create_async_2(gpointer);
+static void purple_log_common_list_async_2(GObject *, GAsyncResult *, gpointer);
+static void purple_log_common_list_async_3(GObject *, GAsyncResult *, gpointer);
+static void purple_log_common_list_async_4(GObject *, GAsyncResult *, gpointer);
+static void purple_log_common_total_size_async_2(GObject *, GAsyncResult *, gpointer);
+static void purple_log_common_total_size_async_3(GObject *, GAsyncResult *, gpointer);
+static void purple_log_common_total_size_async_4(GObject *, GAsyncResult *, gpointer);
 
 
 /* Main functions */
 static void
-_writer_callback_data_free(_writer_callback_data *data)
+create_callback_data_free(gpointer userdata)
 {
+	create_callback_data *data = userdata;
 	g_object_unref(data->log);
+	g_object_unref(data->cancel);
+	g_free(data->path);
 	g_free(data);
 }
 
 static void
+list_callback_data_free(gpointer userdata)
+{
+	list_callback_data *data = userdata;
+	g_free(data->name);
+	g_free(data->ext);
+	g_object_unref(data->cancel);
+	g_free(data);
+}
+
+static void
+total_size_callback_data_free(gpointer userdata)
+{
+	total_size_callback_data *data = userdata;
+	g_free(data->name);
+	g_free(data->ext);
+	g_object_unref(data->cancel);
+	g_free(data);
+}
+
+static void
 purple_common_log_class_init(PurpleCommonLogClass *class)
 {
 	GObjectClass *gobject_class = G_OBJECT_CLASS(class);
@@ -102,19 +196,28 @@ purple_common_log_class_init(PurpleCommo
 	gobject_class->get_property = purple_common_log_get_property;
 	gobject_class->finalize = purple_common_log_finalize;
 
-	log_class->logger_name = _("Common");
+	log_class->logger_name = _("Common Logger");
 	log_class->logger_id = "common";
 
 	log_class->remove_fn = purple_log_common_remove;
 	log_class->size_fn = purple_log_common_size;
 
-	properties[PROP_COMMON_LOG_FILE] =
-		g_param_spec_object("file",
-			"File",
-			"The log's file containing its path",
-			G_TYPE_FILE,
+	properties[PROP_COMMON_LOG_PATH] =
+		g_param_spec_string("path",
+			"Path",
+			"The path to the log's file on disk",
+			NULL,
 			G_PARAM_READWRITE);
 
+	properties[PROP_COMMON_LOG_SOCKET] =
+		g_param_spec_int("socket",
+			"Socket",
+			"The log's socket upon which to perform IO",
+			-1,
+			G_MAXINT,
+			-1,
+			G_PARAM_READWRITE);
+
 	properties[PROP_COMMON_LOG_OFFSET] =
 		g_param_spec_long("offset",
 			"Offset",
@@ -134,10 +237,14 @@ purple_common_log_class_init(PurpleCommo
 			G_PARAM_READWRITE);
 
 	g_object_class_install_property(gobject_class,
-		PROP_COMMON_LOG_FILE,
-		properties[PROP_COMMON_LOG_FILE]);
+		PROP_COMMON_LOG_PATH,
+		properties[PROP_COMMON_LOG_PATH]);
 
 	g_object_class_install_property(gobject_class,
+		PROP_COMMON_LOG_SOCKET,
+		properties[PROP_COMMON_LOG_SOCKET]);
+
+	g_object_class_install_property(gobject_class,
 		PROP_COMMON_LOG_OFFSET,
 		properties[PROP_COMMON_LOG_OFFSET]);
 
@@ -153,7 +260,8 @@ purple_common_log_init(PurpleCommonLog *
 {
 	PurpleCommonLogPrivate *priv = PURPLE_COMMON_LOG_GET_PRIVATE(common_log);
 
-	priv->file = NULL;
+	priv->path = NULL;
+	priv->socket = -1;
 	priv->offset = -1;
 	priv->length = -1;
 }
@@ -165,9 +273,12 @@ purple_common_log_set_property(GObject *
 	PurpleCommonLog *common_log = PURPLE_COMMON_LOG(object);
 
 	switch (prop_id) {
-	case PROP_COMMON_LOG_FILE:
-		purple_common_log_set_file(common_log, g_value_get_object(value));
+	case PROP_COMMON_LOG_PATH:
+		purple_common_log_set_path(common_log, g_value_get_string(value));
 		break;
+	case PROP_COMMON_LOG_SOCKET:
+		purple_common_log_set_socket(common_log, g_value_get_int(value));
+		break;
 	case PROP_COMMON_LOG_OFFSET:
 		purple_common_log_set_offset(common_log, g_value_get_long(value));
 		break;
@@ -187,9 +298,12 @@ purple_common_log_get_property(GObject *
 	PurpleCommonLog *common_log = PURPLE_COMMON_LOG(object);
 
 	switch (prop_id) {
-	case PROP_COMMON_LOG_FILE:
-		g_value_set_object(value, purple_common_log_get_file(common_log));
+	case PROP_COMMON_LOG_PATH:
+		g_value_set_string(value, purple_common_log_get_path(common_log));
 		break;
+	case PROP_COMMON_LOG_SOCKET:
+		g_value_set_int(value, purple_common_log_get_socket(common_log));
+		break;
 	case PROP_COMMON_LOG_OFFSET:
 		g_value_set_long(value, purple_common_log_get_offset(common_log));
 		break;
@@ -203,29 +317,38 @@ void
 }
 
 void
-purple_common_log_set_file(PurpleCommonLog *common_log, GFile *file)
+purple_common_log_set_path(PurpleCommonLog *common_log, const gchar *path)
 {
 	PurpleCommonLogPrivate *priv;
 
 	g_return_if_fail(PURPLE_IS_COMMON_LOG(common_log));
-	g_return_if_fail(file == NULL || G_IS_FILE(file));
 
 	priv = PURPLE_COMMON_LOG_GET_PRIVATE(common_log);
 
-	if (priv->file != NULL)
-		g_object_unref(priv->file);
+	if (priv->path != NULL)
+		g_free(priv->path);
 
-	if (file != NULL)
-		g_object_ref(file);
+	priv->path = g_strdup(path);
 
-	priv->file = file;
+	G_OBJECT_NOTIFY(common_log, PROP_COMMON_LOG_PATH, "path");
+}
 
-#if GLIB_CHECK_VERSION(2, 26, 0)
-	g_object_notify_by_pspec(G_OBJECT(common_log),
-		properties[PROP_COMMON_LOG_FILE]);
-#else
-	g_object_notify(G_OBJECT(common_log), "file");
-#endif
+void
+purple_common_log_set_socket(PurpleCommonLog *common_log, gint socket)
+{
+	PurpleCommonLogPrivate *priv;
+
+	g_return_if_fail(PURPLE_IS_COMMON_LOG(common_log));
+	g_return_if_fail(socket >= -1);
+
+	priv = PURPLE_COMMON_LOG_GET_PRIVATE(common_log);
+
+	if (priv->socket > -1)
+		close(priv->socket); /* XXX */
+
+	priv->socket = socket;
+
+	G_OBJECT_NOTIFY(common_log, PROP_COMMON_LOG_SOCKET, "socket");
 }
 
 void
@@ -236,12 +359,7 @@ purple_common_log_set_offset(PurpleCommo
 
 	PURPLE_COMMON_LOG_GET_PRIVATE(log)->offset = offset;
 
-#if GLIB_CHECK_VERSION(2, 26, 0)
-	g_object_notify_by_pspec(G_OBJECT(common_log),
-		properties[PROP_COMMON_LOG_OFFSET]);
-#else
-	g_object_notify(G_OBJECT(common_log), "offset");
-#endif
+	G_OBJECT_NOTIFY(common_log, PROP_COMMON_LOG_OFFSET, "offset");
 }
 
 void
@@ -252,22 +370,25 @@ purple_common_log_set_length(PurpleCommo
 
 	PURPLE_COMMON_LOG_GET_PRIVATE(log)->length = length;
 
-#if GLIB_CHECK_VERSION(2, 26, 0)
-	g_object_notify_by_pspec(G_OBJECT(common_log),
-		properties[PROP_COMMON_LOG_LENGTH]);
-#else
-	g_object_notify(G_OBJECT(common_log), "length");
-#endif
+	G_OBJECT_NOTIFY(common_log, PROP_COMMON_LOG_LENGTH, "length");
 }
 
-GFile *
-purple_common_log_get_file(PurpleCommonLog *common_log)
+const gchar *
+purple_common_log_get_path(PurpleCommonLog *common_log)
 {
 	g_return_val_if_fail(PURPLE_IS_COMMON_LOG(common_log), NULL);
 
-	return PURPLE_COMMON_LOG_GET_PRIVATE(common_log)->file;
+	return PURPLE_COMMON_LOG_GET_PRIVATE(common_log)->path;
 }
 
+gint
+purple_common_log_get_socket(PurpleCommonLog *common_log)
+{
+	g_return_val_if_fail(PURPLE_IS_COMMON_LOG(common_log), -1);
+
+	return PURPLE_COMMON_LOG_GET_PRIVATE(common_log)->socket;
+}
+
 gssize
 purple_common_log_get_offset(PurpleCommonLog *common_log)
 {
@@ -284,24 +405,14 @@ purple_common_log_get_length(PurpleCommo
 	return PURPLE_COMMON_LOG_GET_PRIVATE(common_log)->length;
 }
 
-static void
-common_thread_callback_data_free(gpointer userdata)
-{
-	_common_thread_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)
 {
-	GFile *file = purple_common_log_get_file(PURPLE_COMMON_LOG(log));
+	const gchar *path = purple_common_log_get_path(PURPLE_COMMON_LOG(log));
 	gboolean result;
 
-	if (file == NULL) {
+	if (path == NULL) {
 		g_set_error_literal(error,
 			G_IO_ERROR,
 			G_IO_ERROR_FAILED,
@@ -310,32 +421,51 @@ purple_log_common_remove(PurpleLog *log,
 		return FALSE;
 	}
 
-	result = g_file_delete(file, cancellable, error);
-	purple_common_log_set_file(PURPLE_COMMON_LOG(log), NULL);
+	result = g_unlink(path);
+	purple_common_log_set_path(PURPLE_COMMON_LOG(log), NULL);
 
+	if (result < 0)
+		g_set_error_literal(error,
+			G_FILE_ERROR,
+			g_file_error_from_errno(errno),
+			g_strerror(errno));
+
 	return result;
 }
 
+static gchar *
+create_log_path(PurpleLog *log, const gchar *dir, const gchar *ext)
+{
+	struct tm *tm;
+	const gchar *tz, *date;
+	gchar *filename, *path;
+	time_t log_time;
+
+	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(filename);
+
+	return path;
+}
+
 gboolean
-purple_log_common_writer(PurpleLog *log, const gchar *ext,
+purple_log_common_create(PurpleLog *log, const gchar *ext,
 	GCancellable *cancellable, GError **error)
 {
-	PurpleCommonLog *common_log;
-	GFile *file;
+	PurpleConversation *conv;
 
 	g_return_val_if_fail(PURPLE_IS_COMMON_LOG(log), FALSE);
 
-	common_log = PURPLE_COMMON_LOG(log);
-	file = purple_common_log_get_file(common_log);
+	if (purple_common_log_get_path(PURPLE_COMMON_LOG(log)) == NULL) {
+		gchar *dir, *new_path;
+		gint socket;
 
-	if (file == NULL) {
-		GFile *file;
-		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),
@@ -347,7 +477,7 @@ purple_log_common_writer(PurpleLog *log,
 				G_IO_ERROR_FAILED,
 				_("Unable to get log directory"));
 
-			return FALSE;
+			goto failed_write;
 		}
 
 		if (purple_build_dir(dir, S_IRUSR | S_IWUSR | S_IXUSR) < 0) {
@@ -356,174 +486,145 @@ purple_log_common_writer(PurpleLog *log,
 				g_file_error_from_errno(errno),
 				g_strerror(errno));
 
-			return FALSE;
+			goto failed_write;
 		}
 
-		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);
+		new_path = create_log_path(log, dir, ext);
+		g_free(dir);
 
-		filename = g_strdup_printf("%s%s%s", date, tz, ext != NULL ? ext : "");
-		path = g_build_filename(dir, filename, NULL);
+		socket = g_open(new_path, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
 
-		g_free(dir);
-		g_free(filename);
+		if (socket < 0) {
+			g_set_error_literal(error,
+				G_FILE_ERROR,
+				g_file_error_from_errno(errno),
+				g_strerror(errno));
 
-		file = g_file_new_for_path(path);
-		g_free(path);
+			goto failed_write;
+		}
+		
+		purple_common_log_set_socket(PURPLE_COMMON_LOG(log), socket);
+		purple_common_log_set_path(PURPLE_COMMON_LOG(log), new_path);
+	}
 
-		/* Make sure the file is writeable */
-		stream = g_file_append_to(file, G_FILE_CREATE_PRIVATE, cancellable,
-			error);
+	return TRUE;
 
-		if (stream != NULL) {
-			g_object_unref(stream);
-			purple_common_log_set_file(common_log, file);
-			g_object_unref(file);
-		} else {
-			PurpleConversation *conv = purple_log_get_conversation(log);
+failed_write:
+	/* XXX: Ideally this should be done with signals */
+	conv = purple_log_get_conversation(log);
 
-			if (conv != NULL)
-				purple_conversation_write(conv, NULL,
-					_("Logging of this conversation failed."),
-					PURPLE_MESSAGE_ERROR, time(NULL));
+	if (conv != NULL) {
+		gchar *msg;
 
-			g_object_unref(file);
+		msg = g_strdup_printf(_("Logging of this conversation failed: %s"),
+			(*error)->message);
 
-			return FALSE;
-		}
+		purple_conversation_write(conv, NULL,
+			msg, PURPLE_MESSAGE_ERROR, time(NULL));
+
+		g_free(msg);
 	}
 
-	return TRUE;
+	return FALSE;
 }
 
 void
-purple_log_common_writer_async(PurpleLog *log, const gchar *ext,
+purple_log_common_create_async(PurpleLog *log, const gchar *ext,
 	gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb,
 	gpointer userdata)
 {
-	_writer_callback_data *callback_data;
-	PurpleCommonLog *common_log;
-	GFile *file;
-
 	g_return_if_fail(PURPLE_IS_COMMON_LOG(log));
 
-	callback_data = g_new(_writer_callback_data, 1);
-	callback_data->log = g_object_ref(log);
-	callback_data->cb = cb;
-	callback_data->userdata = userdata;
+	if (purple_common_log_get_path(PURPLE_COMMON_LOG(log)) == NULL) {
+		gchar *dir, *new_path;
+		create_callback_data *callback_data;
 
-	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,
+			SIMPLE_ASYNC_RESULT_FROM_NEW_ERROR(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,
+			SIMPLE_ASYNC_RESULT_FROM_NEW_ERROR(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);
-
+		new_path = create_log_path(log, dir, ext);
 		g_free(dir);
-		g_free(filename);
 
-		file = g_file_new_for_path(path);
-		g_free(path);
+		/* Create the file */
+		callback_data = g_new(create_callback_data, 1);
+		callback_data->log = g_object_ref(log);
+		callback_data->cancel = cancellable;
+		callback_data->cb = cb;
+		callback_data->userdata = userdata;
+		callback_data->path = new_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);
+		g_idle_add_full(io_priority, purple_log_common_create_async_2,
+			callback_data, create_callback_data_free);
 	} else
-		purple_log_common_writer_async_2(NULL, NULL, callback_data);
+		SIMPLE_ASYNC_RESULT_NEW_GOOD(log, cb, userdata, 
+			purple_log_common_create_async,
+			g_simple_async_result_set_op_res_gboolean(simple, TRUE));
 }
 
-static void
-purple_log_common_writer_async_2(GObject *obj, GAsyncResult *res,
-	gpointer userdata)
+static gboolean
+purple_log_common_create_async_2(gpointer userdata)
 {
-	_writer_callback_data *callback_data = userdata;
-	PurpleLog *log = callback_data->log;
-	GSimpleAsyncResult *simple;
+	/* Loop creation until we stop getting EWOULDBLOCK */
+	GError *err = NULL;
+	gint socket;
+	create_callback_data *callback_data = userdata;
 	
-	if (obj != NULL) {
-		GError *err = NULL;
-		GFile *file = G_FILE(obj);
-		GFileOutputStream *stream = g_file_append_to_finish(file, res, &err);
+	if (g_cancellable_set_error_if_cancelled(callback_data->cancel, &err)) {
+		SIMPLE_ASYNC_RESULT_FROM_ERROR(callback_data->log,
+			callback_data->cb, callback_data->userdata, err);
 
-		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);
+		return FALSE;
+	}
 
-			if (conv != NULL)
-				purple_conversation_write(conv, NULL,
-					_("Logging of this conversation failed."),
-					PURPLE_MESSAGE_ERROR, time(NULL));
+	socket = g_open(callback_data->path, O_CREAT | O_RDWR | O_NONBLOCK,
+		S_IRUSR | S_IWUSR);
 
-			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);
+	if (socket < 0) {
+		if (errno == EWOULDBLOCK)
+			return TRUE;
 
-			_writer_callback_data_free(callback_data);
+		SIMPLE_ASYNC_RESULT_FROM_NEW_ERROR(callback_data->log,
+			callback_data->cb, callback_data->userdata,
+			G_IO_ERROR,
+			g_file_error_from_errno(errno),
+			g_strerror(errno));
 
-			return;
-		}
+		return FALSE;
 	}
+	
+	purple_common_log_set_socket(callback_data->log, socket);
+	purple_common_log_set_path(callback_data->log, callback_data->path);
 
-	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);
+	SIMPLE_ASYNC_RESULT_NEW_GOOD(callback_data->log, callback_data->cb,
+		callback_data->userdata, purple_log_common_create_async,
+		g_simple_async_result_set_op_res_gboolean(simple, TRUE));
 
-	_writer_callback_data_free(callback_data);
+	return FALSE;
 }
 
 gboolean
-purple_log_common_writer_finish(PurpleLog *log, GAsyncResult *res,
+purple_log_common_create_finish(PurpleLog *log, GAsyncResult *res,
 	GError **error)
 {
 	GSimpleAsyncResult *simple;
@@ -539,8 +640,57 @@ purple_log_common_writer_finish(PurpleLo
 	return g_simple_async_result_get_op_res_gboolean(G_SIMPLE_ASYNC_RESULT(res));
 }
 
+static PurpleLog *
+create_log(const gchar *dir, const gchar *filename, PurpleLogChatType chat_type,
+	const gchar *name, PurpleAccount *account, GType log_type)
+{
+	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
+
+	tmp = g_build_filename(dir, filename, NULL);
+	purple_common_log_set_path(PURPLE_COMMON_LOG(log), tmp);
+	g_free(tmp);
+
+	return log;
+}
+
 GList *
-purple_log_common_lister(PurpleLogChatType chat_type, const gchar *name,
+purple_log_common_list(PurpleLogChatType chat_type, const gchar *name,
 	PurpleAccount *account, const gchar *ext, GType log_type,
 	GCancellable *cancellable, GError **error)
 {
@@ -553,7 +703,8 @@ purple_log_common_lister(PurpleLogChatTy
 	g_return_val_if_fail(name != 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),
+	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);
@@ -592,120 +743,153 @@ purple_log_common_lister(PurpleLogChatTy
 		}
 
 		if (purple_str_has_suffix(filename, ext) &&
-		    strlen(filename) >= (17 + strlen(ext)))
+		    strlen(filename) >= (17 + strlen(ext))) /* XXX: ? */
 		{
-			PurpleLog *log;
-			GFile *file;
-			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;
+			PurpleLog *log = create_log(path, filename, chat_type, name, account,
+				log_type);
+			list = g_list_prepend(list, log);
+		}
+	}
 
-			stamp = purple_str_to_time(purple_unescape_filename(filename),
-				FALSE, &tm, &tz_off, &rest);
+	g_dir_close(dir);
+	g_free(path);
 
-			/**
-			 * 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;
+	return list;
+}
 
-			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);
+void
+purple_log_common_list_async(PurpleLogChatType chat_type, const gchar *name,
+	PurpleAccount *account, const gchar *ext, GType log_type, gint io_priority,
+	GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
+{
+	GFile *dir;
+	gchar *path;
+	list_callback_data *data;
 
-			log = purple_log_new(log_type, chat_type, name, account, NULL,
-				stamp, (stamp != 0) ?  &tm : NULL);
-#endif
+	data = g_new(list_callback_data, 1);
+	data->chat_type = chat_type;
+	data->name = g_strdup(name);
+	data->account = account; /* XXX: g_object_ref(account) */
+	data->ext = g_strdup(ext);
+	data->log_type = log_type;
+	data->io_priority = io_priority;
+	data->cancel = g_object_ref(cancellable);
+	data->cb = cb;
+	data->userdata = userdata;
 
-			tmp = g_build_filename(path, filename, NULL);
-			file = g_file_new_for_path(tmp);
-			purple_common_log_set_file(PURPLE_COMMON_LOG(log), file);
-			g_object_unref(file);
-			g_free(tmp);
+	path = purple_log_get_log_dir(chat_type, name, account);
+	dir = g_file_new_for_path(path);
 
-			list = g_list_prepend(list, log);
-		}
-	}
+	g_file_enumerate_children_async(dir, G_FILE_ATTRIBUTE_STANDARD_NAME,
+		G_FILE_QUERY_INFO_NONE, io_priority, cancellable,
+		purple_log_common_list_async_2, data);
 
-	g_dir_close(dir);
 	g_free(path);
+	g_object_unref(dir);
+}
 
-	return list;
+static void
+purple_log_common_list_async_2(GObject *object, GAsyncResult *res,
+	gpointer userdata)
+{
+	GError *err = NULL;
+	GFile *dir = G_FILE(object);
+	GFileEnumerator *enumerator;
+	list_callback_data *data = userdata;
+
+	enumerator = g_file_enumerate_children_finish(dir, res, &err);
+
+	if (enumerator == NULL) {
+		SIMPLE_ASYNC_RESULT_FROM_ERROR(dir, data->cb, data->userdata, err);
+		list_callback_data_free(data);
+
+		return;
+	}
+
+	g_file_enumerator_next_files_async(enumerator, 20, data->io_priority,
+		data->cancel, purple_log_common_list_async_3, data);
 }
 
 static void
-common_lister_thread(GSimpleAsyncResult *simple, GObject *object,
-	GCancellable *cancellable)
+purple_log_common_list_async_3(GObject *object, GAsyncResult *res,
+	gpointer userdata)
 {
-	_common_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;
-	GType log_type = callback_data->log_type;
-	GError *error = NULL;
-	GList *list;
-	gchar *name = callback_data->name, *ext = callback_data->ext;
+	GError *err = NULL;
+	GFileEnumerator *enumerator = G_FILE_ENUMERATOR(object);
+	GList *files, *file;
+	gchar *dir;
+	list_callback_data *data = userdata;
 
-	list = purple_log_common_lister(chat_type, name, account, ext, log_type,
-		cancellable, &error);
+	files = g_file_enumerator_next_files_finish(enumerator, res, &err);
 
-	if (list == 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);
+	if (files == NULL) {
+		if (err != NULL) {
+			SIMPLE_ASYNC_RESULT_FROM_ERROR(enumerator, data->cb, data->userdata,
+				err);
+			list_callback_data_free(data);
+			purple_log_list_free(data->logs);
 
-	g_clear_error(&error);
+			return;
+		}
+
+		/* Out of files! Close shop */
+		g_file_enumerator_close_async(enumerator, data->io_priority,
+			data->cancel, purple_log_common_list_async_4, data);
+	}
+
+	dir = g_file_get_path(g_file_enumerator_get_container(enumerator));
+
+	for (file = files; file != NULL; file = file->next) {
+		GFileInfo *info = file->data;
+		PurpleLog *log;
+		const gchar *filename;
+
+		filename = g_file_info_get_attribute_byte_string(info,
+			G_FILE_ATTRIBUTE_STANDARD_NAME);
+		g_object_unref(info);
+		printf("%s", filename);
+
+		if (!purple_str_has_suffix(filename, data->ext))
+			continue;
+
+		log = create_log(dir, filename, data->chat_type, data->name,
+			data->account, data->log_type);
+		data->logs = g_list_prepend(data->logs, log);
+	}
+
+	g_list_free(files);
+
+	g_file_enumerator_next_files_async(enumerator, 20, data->io_priority,
+		data->cancel, purple_log_common_list_async_3, data);
 }
 
-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)
+static void
+purple_log_common_list_async_4(GObject *object, GAsyncResult *res,
+	gpointer userdata)
 {
-	_common_thread_callback_data *callback_data;
-	GSimpleAsyncResult *simple;
+	GError *err = NULL;
+	GFileEnumerator *enumerator = G_FILE_ENUMERATOR(object);
+	gboolean result;
+	list_callback_data *data = userdata;
 
-	g_return_if_fail(name != NULL);
-	g_return_if_fail(PURPLE_IS_ACCOUNT(account));
-	g_return_if_fail(ext != NULL);
+	result = g_file_enumerator_close_finish(enumerator, res, &err);
 
-	callback_data = g_new0(_common_thread_callback_data, 1);
-	callback_data->chat_type = chat_type;
-	callback_data->name = g_strdup(name);
-	callback_data->account = account; /* XXX: g_object_ref */
-	callback_data->ext = g_strdup(ext);
-	callback_data->log_type = log_type;
+	if (!result) {
+		SIMPLE_ASYNC_RESULT_FROM_ERROR(enumerator, data->cb, data->userdata,
+			err);
 
-	simple = g_simple_async_result_new(NULL, cb, userdata,
-		purple_log_common_lister_async);
+		purple_log_list_free(data->logs);
+	} else
+		SIMPLE_ASYNC_RESULT_NEW_GOOD(enumerator, data->cb, data->userdata,
+			purple_log_common_list_async,
+			g_simple_async_result_set_op_res_gpointer(simple, data->logs,
+				(GDestroyNotify) purple_log_list_free));
 
-	g_simple_async_result_set_op_res_gpointer(simple, callback_data,
-		common_thread_callback_data_free);
-	g_simple_async_result_run_in_thread(simple, common_lister_thread,
-		io_priority, cancellable);
-
-	g_object_unref(simple);
+	list_callback_data_free(data);
 }
 
 GList *
-purple_log_common_lister_finish(GAsyncResult *res, GError **error)
+purple_log_common_list_finish(GAsyncResult *res, GError **error)
 {
 	GSimpleAsyncResult *simple;
 
@@ -714,7 +898,8 @@ purple_log_common_lister_finish(GAsyncRe
 	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,
+	g_return_val_if_fail(g_simple_async_result_get_source_tag(simple) == 
+		purple_log_common_list_async,
 		NULL);
 
 	return g_simple_async_result_get_op_res_gpointer(simple);
@@ -726,7 +911,7 @@ gssize
  * TODO: once?  This may be possible with the non-blocking stuff...
  */
 gssize
-purple_log_common_total_sizer(PurpleLogChatType chat_type, const gchar *name,
+purple_log_common_total_size(PurpleLogChatType chat_type, const gchar *name,
 	PurpleAccount *account, const gchar *ext, GCancellable *cancellable,
 	GError **error)
 {
@@ -814,61 +999,133 @@ purple_log_common_total_sizer(PurpleLogC
 	return size;
 }
 
+void
+purple_log_common_total_size_async(PurpleLogChatType chat_type,
+	const gchar *name, PurpleAccount *account, const gchar *ext,
+	gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb,
+	gpointer userdata)
+{
+	GFile *dir;
+	gchar *path;
+	total_size_callback_data *data;
+
+	data = g_new(total_size_callback_data, 1);
+	data->chat_type = chat_type;
+	data->name = g_strdup(name);
+	data->account = account; /* XXX: g_object_ref(account) */
+	data->ext = g_strdup(ext);
+	data->io_priority = io_priority;
+	data->cancel = g_object_ref(cancellable);
+	data->cb = cb;
+	data->userdata = userdata;
+	data->total = 0;
+
+	path = purple_log_get_log_dir(chat_type, name, account);
+	dir = g_file_new_for_path(path);
+
+	g_file_enumerate_children_async(dir, G_FILE_ATTRIBUTE_STANDARD_SIZE,
+		G_FILE_QUERY_INFO_NONE, io_priority, cancellable,
+		purple_log_common_total_size_async_2, data);
+
+	g_free(path);
+	g_object_unref(dir);
+}
+
 static void
-common_total_sizer_thread(GSimpleAsyncResult *simple, GObject *object,
-	GCancellable *cancellable)
+purple_log_common_total_size_async_2(GObject *object, GAsyncResult *res,
+	gpointer userdata)
 {
-	_common_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, *ext = callback_data->ext;
-	gssize size;
+	GError *err = NULL;
+	GFile *dir = G_FILE(object);
+	GFileEnumerator *enumerator;
+	total_size_callback_data *data = userdata;
 
-	size = purple_log_common_total_sizer(chat_type, name, account, ext,
-		cancellable, &error);
+	enumerator = g_file_enumerate_children_finish(dir, res, &err);
 
-	if (size < 0)
-		g_simple_async_result_set_from_error(simple, error);
-	else
-		g_simple_async_result_set_op_res_gssize(simple, size);
+	if (enumerator == NULL) {
+		SIMPLE_ASYNC_RESULT_FROM_ERROR(dir, data->cb, data->userdata, err);
+		total_size_callback_data_free(data);
 
-	g_clear_error(&error);
+		return;
+	}
+
+	g_file_enumerator_next_files_async(enumerator, 20, data->io_priority,
+		data->cancel, purple_log_common_total_size_async_3, data);
 }
 
-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,
+static void
+purple_log_common_total_size_async_3(GObject *object, GAsyncResult *res,
 	gpointer userdata)
 {
-	_common_thread_callback_data *callback_data;
-	GSimpleAsyncResult *simple;
+	GError *err = NULL;
+	GFileEnumerator *enumerator = G_FILE_ENUMERATOR(object);
+	GList *files, *file;
+	total_size_callback_data *data = userdata;
 
-	g_return_if_fail(name != NULL);
-	g_return_if_fail(account != NULL);
-	g_return_if_fail(ext != NULL);
+	files = g_file_enumerator_next_files_finish(enumerator, res, &err);
 
-	callback_data = g_new0(_common_thread_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);
+	if (files == NULL) {
+		if (err != NULL) {
+			SIMPLE_ASYNC_RESULT_FROM_ERROR(enumerator, data->cb, data->userdata,
+				err);
+			total_size_callback_data_free(data);
 
-	simple = g_simple_async_result_new(NULL, cb, userdata,
-		purple_log_common_total_sizer_async);
+			return;
+		}
 
-	g_simple_async_result_set_op_res_gpointer(simple, callback_data,
-		common_thread_callback_data_free);
-	g_simple_async_result_run_in_thread(simple, common_total_sizer_thread,
-		io_priority, cancellable);
+		/* Out of files! Close shop */
+		g_file_enumerator_close_async(enumerator, data->io_priority,
+			data->cancel, purple_log_common_total_size_async_4, data);
+	}
 
-	g_object_unref(simple);
+	for (file = files; file != NULL; file = file->next) {
+		GFileInfo *info = file->data;
+		const gchar *path;
+		guint64 size;
+
+		path = g_file_info_get_attribute_string(info,
+			G_FILE_ATTRIBUTE_STANDARD_NAME);
+
+		size = g_file_info_get_attribute_uint64(info,
+			G_FILE_ATTRIBUTE_STANDARD_SIZE);
+		g_object_unref(info);
+
+		if (!purple_str_has_suffix(path, data->ext))
+			continue;
+
+		data->total += size;
+	}
+
+	g_list_free(files);
+
+	g_file_enumerator_next_files_async(enumerator, 20, data->io_priority,
+		data->cancel, purple_log_common_total_size_async_3, data);
 }
 
+static void
+purple_log_common_total_size_async_4(GObject *object, GAsyncResult *res,
+	gpointer userdata)
+{
+	GError *err = NULL;
+	GFileEnumerator *enumerator = G_FILE_ENUMERATOR(object);
+	gboolean result;
+	total_size_callback_data *data = userdata;
+
+	result = g_file_enumerator_close_finish(enumerator, res, &err);
+
+	if (!result) {
+		SIMPLE_ASYNC_RESULT_FROM_ERROR(enumerator, data->cb, data->userdata,
+			err);
+	} else
+		SIMPLE_ASYNC_RESULT_NEW_GOOD(enumerator, data->cb, data->userdata,
+			purple_log_common_list_async,
+			g_simple_async_result_set_op_res_gssize(simple, data->total));
+
+	total_size_callback_data_free(data);
+}
+
 gssize
-purple_log_common_total_sizer_finish(GAsyncResult *res, GError **error)
+purple_log_common_total_size_finish(GAsyncResult *res, GError **error)
 {
 	GSimpleAsyncResult *simple;
 
@@ -877,7 +1134,8 @@ purple_log_common_total_sizer_finish(GAs
 	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,
+	g_return_val_if_fail(g_simple_async_result_get_source_tag(simple) ==
+		purple_log_common_total_size_async,
 		-1);
 
 	return g_simple_async_result_get_op_res_gssize(simple);
@@ -891,6 +1149,7 @@ purple_log_common_size(PurpleLog *log, G
 	GFile *file;
 	GFileInfo *info;
 	gssize length;
+	const gchar *path;
 	guint64 file_size;
 
 	length = purple_common_log_get_length(common_log);
@@ -898,9 +1157,9 @@ purple_log_common_size(PurpleLog *log, G
 	if (length >= 0)
 		return length;
 
-	file = purple_common_log_get_file(common_log);
+	path = purple_common_log_get_path(common_log);
 
-	if (file == NULL) {
+	if (path == NULL) {
 		g_set_error_literal(error,
 			G_IO_ERROR,
 			G_IO_ERROR_FAILED,
@@ -909,6 +1168,8 @@ purple_log_common_size(PurpleLog *log, G
 		return -1;
 	}
 
+	file = g_file_new_for_path(path);
+
 	info = g_file_query_info(file, G_FILE_ATTRIBUTE_STANDARD_SIZE,
 		G_FILE_QUERY_INFO_NONE, cancellable, error);
 
@@ -930,11 +1191,16 @@ purple_common_log_finalize(GObject *obje
 {
 	PurpleCommonLogPrivate *priv = PURPLE_COMMON_LOG_GET_PRIVATE(object);
 
-	if (priv->file != NULL) {
-		g_object_unref(priv->file);
-		priv->file = NULL;
+	if (priv->path != NULL) {
+		g_free(priv->path);
+		priv->path = NULL;
 	}
 
+	if (priv->socket >= 0) {
+		close(priv->socket);
+		priv->socket = -1;
+	}
+
 	G_OBJECT_CLASS(purple_common_log_parent_class)->finalize(object);
 }
 
============================================================
--- libpurple/commonlog.h	f5527bf6f212e62051f7069cd414519600cc2498
+++ libpurple/commonlog.h	a6741ced2f8f65f70d3296778540c065c0f77630
@@ -70,13 +70,23 @@ GType purple_common_log_get_type(void);
  * Sets a log's file location
  *
  * @param common_log   The log
- * @param file         The log's file
+ * @param path         The path to the log on disk
  *
  * @since 3.0.0
  */
-void purple_common_log_set_file(PurpleCommonLog *common_log, GFile *file);
+void purple_common_log_set_path(PurpleCommonLog *common_log, const gchar *path);
 
 /**
+ * Sets a log's IO socket
+ *
+ * @param common_log   The log
+ * @param socket       The log's IO socket
+ *
+ * @since 3.0.0
+ */
+void purple_common_log_set_socket(PurpleCommonLog *common_log, gint socket);
+
+/**
  * Sets a log's offset, useful for storing multiple logs in one file.
  *
  * @param common_log   The log
@@ -98,18 +108,28 @@ void purple_common_log_set_length(Purple
 void purple_common_log_set_length(PurpleCommonLog *common_log, gssize length);
 
 /**
- * Gets the log's file which contains its path and can be used for I/O
- * interaction, depending on its location
+ * Gets the log's path on disk
  *
  * @param common_log   The log
  *
- * @return             The log's file
+ * @return             The log's path
  *
  * @since 3.0.0
  */
-GFile *purple_common_log_get_file(PurpleCommonLog *common_log);
+const gchar *purple_common_log_get_path(PurpleCommonLog *common_log);
 
 /**
+ * Gets the log's IO socket
+ *
+ * @param common_log   The log
+ *
+ * @return             The log's socket
+ *
+ * @since 3.0.0
+ */
+gint purple_common_log_get_socket(PurpleCommonLog *common_log);
+
+/**
  * Gets the log's offset within its file, if available
  *
  * @param common_log   The log
@@ -132,7 +152,7 @@ gssize purple_common_log_get_length(Purp
 gssize purple_common_log_get_length(PurpleCommonLog *common_log);
 
 /**
- * Opens a new log file in the standard log location
+ * Creates 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
@@ -149,13 +169,13 @@ gssize purple_common_log_get_length(Purp
  * @param cancellable  (allow-none): GCancellable object
  * @param error        (out) (allow-none): a GError location to store the error
  */
-gboolean purple_log_common_writer(PurpleLog *log, const gchar *ext,
+gboolean purple_log_common_create(PurpleLog *log, const gchar *ext,
 	GCancellable *cancellable, GError **error);
 
 /**
- * Asynchronously opens a new log in the standard log location
+ * Asynchronously create a new log in the standard log location
  *
- * For more details, see purple_log_common_writer() which is
+ * For more details, see purple_log_common_create() which is
  * the synchronous version of this call.
  *
  * @param log          The log to write to
@@ -167,13 +187,13 @@ gboolean purple_log_common_writer(Purple
  *
  * @since 3.0.0
  */
-void purple_log_common_writer_async(PurpleLog *log, const gchar *ext,
+void purple_log_common_create_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
- * See purple_log_common_writer() for more details.
+ * Finishes asyncronously creating a new log in the standard log location
+ * See purple_log_common_create() for more details.
  *
  * @param log          The log to write to
  * @param res          A GAsyncResult
@@ -183,7 +203,7 @@ void purple_log_common_writer_async(Purp
  *
  * @since 3.0.0
  */
-gboolean purple_log_common_writer_finish(PurpleLog *log, GAsyncResult *res,
+gboolean purple_log_common_create_finish(PurpleLog *log, GAsyncResult *res,
 	GError **error);
 
 /**
@@ -206,13 +226,13 @@ gboolean purple_log_common_writer_finish
  *
  * @return             The sorted list of logs matching the parameters
  */
-GList *purple_log_common_lister(PurpleLogChatType chat_type, const gchar *name,
+GList *purple_log_common_list(PurpleLogChatType chat_type, const gchar *name,
 	PurpleAccount *account, const gchar *ext, GType log_type,
 	GCancellable *cancellable, GError **error);
 
 /**
  * Asynchronously gets a sorted list of log of the requested type.
- * See purple_log_common_lister() for more details.
+ * See purple_log_common_list() for more details.
  *
  * @param type         The type of the logs being listed
  * @param name         The name of the log
@@ -228,7 +248,7 @@ GList *purple_log_common_lister(PurpleLo
  *
  * @since 3.0.0
  */
-void purple_log_common_lister_async(PurpleLogChatType type, const gchar *name,
+void purple_log_common_list_async(PurpleLogChatType type, const gchar *name,
 	PurpleAccount *account, const gchar *ext, GType log_type, gint io_priority,
 	GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata);
 
@@ -246,7 +266,7 @@ void purple_log_common_lister_async(Purp
  *
  * @since 3.0.0
  */
-GList *purple_log_common_lister_finish(GAsyncResult *res, GError **error);
+GList *purple_log_common_list_finish(GAsyncResult *res, GError **error);
 
 /**
  * Returns the total size of all the logs for a given user, with
@@ -269,14 +289,14 @@ GList *purple_log_common_lister_finish(G
  * @return             The size of all the logs with the specified extension
  *                     for the specified user
  */
-gssize purple_log_common_total_sizer(PurpleLogChatType chat_type,
+gssize purple_log_common_total_size(PurpleLogChatType chat_type,
 	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.
- * See purple_log_common_total_sizer() for more details.
+ * See purple_log_common_total_size() for more details.
  *
  * @param chat_type    The type of the logs being sized
  * @param name         The name of the logs to size (e.g. the username or chat name)
@@ -290,7 +310,7 @@ gssize purple_log_common_total_sizer(Pur
  *
  * @since 3.0.0
  */
-void purple_log_common_total_sizer_async(PurpleLogChatType chat_type,
+void purple_log_common_total_size_async(PurpleLogChatType chat_type,
 	const gchar *name, PurpleAccount *account, const gchar *ext,
 	gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb,
 	gpointer userdata);
@@ -305,7 +325,7 @@ void purple_log_common_total_sizer_async
  *
  * @since 3.0.0
  */
-gssize purple_log_common_total_sizer_finish(GAsyncResult *res, GError **error);
+gssize purple_log_common_total_size_finish(GAsyncResult *res, GError **error);
 
 /*@}*/
 


More information about the Commits mailing list