/soc/2015/igor.gajowiak/chatlog: 32ede87a799d: Implemented expor...

Igor Gajowiak <[email protected]>
Newsgroups gmane.comp.gnome.gaim.cvs
Message-ID <[email protected]>
Changeset: 32ede87a799d466b41be373199942310e9520ae3
Author:	 Igor Gajowiak <[email protected]>
Date:	 2015-08-06 00:14 +0200
Branch:	 default
URL: https://hg.pidgin.im/soc/2015/igor.gajowiak/chatlog/rev/32ede87a799d

Description:

Implemented exporting messages from legacy log.

diffstat:

 libpurple/genericlog.c            |  140 ++++++++++
 libpurple/genericlog.h            |   30 +-
 libpurple/plugins/log/legacylog.c |  496 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 661 insertions(+), 5 deletions(-)

diffs (truncated from 764 to 300 lines):

diff --git a/libpurple/genericlog.c b/libpurple/genericlog.c
--- a/libpurple/genericlog.c
+++ b/libpurple/genericlog.c
@@ -26,6 +26,8 @@
 #define PURPLE_GENERICLOG_GET_PRIVATE(obj) \
 	(G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_GENERICLOG, PurpleGenericLogPrivate))
 
+#define PURPLE_GENERICLOG_IMPORT_CHUNK_SIZE 500
+
 typedef struct
 {
 	gchar *id;
@@ -47,6 +49,17 @@ static GList *purple_genericlogs = NULL;
 static PurpleGenericLog *purple_genericlog_inuse = NULL;
 static GList *purple_genericlog_loaded_plugins = NULL;
 
+typedef struct
+{
+	PurpleGenericLog *src_log;
+	PurpleGenericLog_OnImportFinished on_finished;
+	void *export_state;
+	guint timer;
+	guint imported_messages_count;
+} PurpleGenericLogImportState;
+
+PurpleGenericLogImportState *import_state = NULL;
+
 /**************************************************************************/
 /* PurpleGenericLog intance methods                                       */
 /**************************************************************************/
@@ -293,6 +306,133 @@ purple_genericlog_wipe_log_for_buddy(Pur
 
 #undef DEFINE_GENERICLOG_FUNC_WITH_RETURN
 
+static void
+uninit_import_state(PurpleGenericLogImportState *import_state)
+{
+	g_assert(import_state);
+
+	PurpleGenericLogClass *klass = PURPLE_GENERICLOG_GET_CLASS(
+		import_state->src_log);
+
+	klass->finalize_export(import_state->export_state);
+	klass->deactivate();
+	purple_timeout_remove(import_state->timer);
+}
+
+static void
+unref_g_object_pointee(gpointer data)
+{
+	g_object_unref(G_OBJECT(*(GObject**) data));
+}
+
+static gboolean
+run_import_iteration(gpointer unused)
+{
+	PurpleGenericLogClass *klass = PURPLE_GENERICLOG_GET_CLASS(
+		import_state->src_log);
+
+	GArray *accounts = g_array_new(FALSE, FALSE, sizeof(PurpleAccount*));
+	g_array_set_clear_func(accounts, unref_g_object_pointee);
+
+	GArray *messages = g_array_new(FALSE, FALSE, sizeof(PurpleMessage*));
+	g_array_set_clear_func(messages, unref_g_object_pointee);
+
+	gboolean status = klass->read_chunk(import_state->export_state,
+		PURPLE_GENERICLOG_IMPORT_CHUNK_SIZE, accounts, messages);
+
+	if (!status || messages->len == 0) {
+		g_array_unref(accounts);
+		g_array_unref(messages);
+
+		uninit_import_state(import_state);
+
+		import_state->on_finished(status,
+			import_state->imported_messages_count);
+
+		g_free(import_state);
+		import_state = NULL;
+
+		return FALSE;
+	}
+
+	g_assert(accounts->len == messages->len);
+
+	for (guint i = 0; i < messages->len; ++i) {
+		PurpleAccount *account = g_array_index(accounts, PurpleAccount*, i);
+		PurpleMessage *message = g_array_index(messages, PurpleMessage*, i);
+
+		/* Should we stop if logging fails? */
+		if (purple_genericlog_logim(account, message, NULL))
+			++(import_state->imported_messages_count);
+	}
+
+	g_array_free(accounts, TRUE);
+	g_array_free(messages, TRUE);
+
+	return TRUE;
+}
+
+gboolean
+purple_genericlog_import_msgs(PurpleGenericLog *src_log,
+	PurpleGenericLog_OnImportFinished on_finished, GError **error)
+{
+	if (!purple_genericlog_inuse) {
+		if (!error) return FALSE;
+
+		*error = g_error_new(purple_genericlog_error_domain(),
+			PURPLE_GENERICLOG_ERROR_NOLOG, "No active log");
+		return FALSE;
+	}
+
+	if (src_log == purple_genericlog_inuse) {
+		if (!error) return FALSE;
+
+		*error = g_error_new(purple_genericlog_error_domain(),
+			PURPLE_GENERICLOG_ERROR_INTERNAL, "Self import is not allowed");
+		return FALSE;
+	}
+
+	if (import_state) {
+		if (!error) return FALSE;
+
+		*error = g_error_new(purple_genericlog_error_domain(),
+			PURPLE_GENERICLOG_ERROR_INTERNAL, "Import is already running");
+		return FALSE;
+	}
+
+	PurpleGenericLogClass *klass = PURPLE_GENERICLOG_GET_CLASS(src_log);
+	if (!klass->activate()) {
+		if (!error) return FALSE;
+
+		*error = g_error_new(purple_genericlog_error_domain(),
+			PURPLE_GENERICLOG_ERROR_BACKENDFAIL, "Failed to activate %s",
+			purple_genericlog_get_id(src_log));
+		return FALSE;
+	}
+
+	void *export_state;
+	if (!klass->init_export(&export_state)) {
+		klass->deactivate();
+
+		if (!error) return FALSE;
+
+		*error = g_error_new(purple_genericlog_error_domain(),
+			PURPLE_GENERICLOG_ERROR_BACKENDFAIL,
+			"Failed to init export from %s", purple_genericlog_get_id(src_log));
+		return FALSE;
+	}
+
+	import_state = g_new0(PurpleGenericLogImportState, 1);
+	import_state->src_log = src_log;
+	import_state->on_finished = on_finished;
+	import_state->export_state = export_state;
+
+	import_state->timer = purple_timeout_add(1, run_import_iteration,
+		import_state);
+
+	return TRUE;
+}
+
 /**************************************************************************/
 /* Error Codes                                                            */
 /**************************************************************************/
diff --git a/libpurple/genericlog.h b/libpurple/genericlog.h
--- a/libpurple/genericlog.h
+++ b/libpurple/genericlog.h
@@ -95,8 +95,7 @@ struct _PurpleGenericLog
  *                   UI responsiveness. Returning no messages means end of
  *                   export. Returns %TRUE if operation succeeds,
  *                   %FALSE otherwise.
- * @finalize_export: Finalizes an export procedure. Returns %TRUE if operation
- *                   succeeds, %FALSE otherwise.
+ * @finalize_export: Finalizes an export procedure.
  *
  * The abstract base class for all log implementations. A conforming plugin
  * must implement at least activate and deactivate methods. Not supported
@@ -133,7 +132,7 @@ struct _PurpleGenericLogClass
 	gboolean (*read_chunk) (void *export_state, guint chunk_size,
 		GArray *accounts, GArray *messages);
 
-	gboolean (*finalize_export) (void *export_state);
+	void (*finalize_export) (void *export_state);
 
 	void (*reserved1)(void);
 	void (*reserved2)(void);
@@ -141,6 +140,8 @@ struct _PurpleGenericLogClass
 	void (*reserved4)(void);
 };
 
+typedef void (*PurpleGenericLog_OnImportFinished)(gboolean, guint);
+
 #define PURPLE_GENERICLOG_DEFAULT "genericlog-sqlitelog"
 
 #define PURPLE_GENERICLOG_PROPERTY_ID   "id"
@@ -374,11 +375,27 @@ purple_genericlog_get_all_days(PurpleBud
  * Deletes all messages sent to or received from a given buddy from the
  * active log.
  *
- * Returns: %TRUE if succeeds. %FALSE otherwise.
+ * Returns: %TRUE if succeeds, %FALSE otherwise.
  */
 gboolean
 purple_genericlog_wipe_log_for_buddy(PurpleBuddy *buddy, GError **error);
 
+/**
+ * purple_genericlog_import_msgs:
+ * @src_log:     The log from which to import messages.
+ * @on_finished: The callback to call when import is done. Parameters passed
+ *               to it are a success status and the number of imported messages.
+ * @error:       Return location for a #GError or %NULL. If provided, this
+ *               will be set to the reason if getting days fails.
+ *
+ * Asynchronously imports messages from src_log to the active log.
+ *
+ * Returns: %TRUE if starting import succeeded, %FALSE otherwise.
+ */
+gboolean
+purple_genericlog_import_msgs(PurpleGenericLog *src_log,
+	PurpleGenericLog_OnImportFinished on_finished, GError **error);
+
 /**************************************************************************/
 /* Error Codes                                                            */
 /**************************************************************************/
@@ -397,6 +414,8 @@ GQuark purple_genericlog_error_domain(vo
  *
  * @PURPLE_GENERICLOG_ERROR_UNKNOWN:               Unknown error.
  * @PURPLE_GENERICLOG_ERROR_NOLOG:                 No log configured.
+ * @PURPLE_GENERICLOG_ERROR_INTERNAL:              Internal generic log system
+ *                                                 error.
  * @PURPLE_GENERICLOG_ERROR_BACKENDFAIL:           Failed to communicate with
  *                                                 the backend or internal
  *                                                 backend error.
@@ -408,8 +427,9 @@ enum PurpleGenericLogError
 	PURPLE_GENERICLOG_ERROR_UNKNOWN = 0,
 
 	PURPLE_GENERICLOG_ERROR_NOLOG = 10,
+	PURPLE_GENERICLOG_ERROR_INTERNAL,
+	PURPLE_GENERICLOG_ERROR_BACKENDFAIL,
 	PURPLE_GENERICLOG_ERROR_OPERATIONNOTSUPPORTED,
-	PURPLE_GENERICLOG_ERROR_BACKENDFAIL,
 };
 
 /**************************************************************************/
diff --git a/libpurple/plugins/log/legacylog.c b/libpurple/plugins/log/legacylog.c
--- a/libpurple/plugins/log/legacylog.c
+++ b/libpurple/plugins/log/legacylog.c
@@ -31,6 +31,438 @@
 #define LEGACYLOG_AUTHORS \
 	{ "Igor Gajowiak <[email protected]>", NULL }
 
+#define LEGACYLOG_DEBUG_CATEGORY "legacy-log"
+
+/**************************************************************************/
+/* PurpleGenericLog API implementation                                    */
+/**************************************************************************/
+
+typedef enum
+{
+	DIR_DEPTH_PROTOCOL  = 1,
+	DIR_DEPTH_ACCOUNT   = 2,
+	DIR_DEPTH_BUDDYNAME = 3,
+	DIR_DEPTH_LAST      = 3,
+	DIR_DEPTH_MAX       = 4
+} DirDepth;
+
+typedef struct _Iter
+{
+	const gchar *dir_names[DIR_DEPTH_MAX];
+	gchar *dir_paths[DIR_DEPTH_MAX];
+	GDir *dirs[DIR_DEPTH_MAX];
+
+	const gchar* log_file_name;
+	FILE* log_file;
+} Iter;
+
+static void
+open_next_subfile(GDir *dir, const gchar *dir_path, FILE **file_res,
+	const gchar **filename_res)
+{
+	g_assert(dir);
+	g_assert(dir_path);
+	g_assert(file_res);
+
+	const gchar *filename;
+	while ((filename = g_dir_read_name(dir)) != NULL) {
+		gchar *filepath  = g_strdup_printf(
+			"%s/%s", dir_path, filename);
+
+		FILE *file = fopen(filepath, "rb");
+		g_free(filepath);
+
+		if (file) {
+			*file_res = file;
+			*filename_res = filename;
+			return;
+		}
+	}
+
+	*file_res = NULL;

_______________________________________________
Commits mailing list
[email protected]
https://pidgin.im/cgi-bin/mailman/listinfo/commits
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.