/soc/2015/igor.gajowiak/chatlog: 32ede87a799d: Implemented expor...
Igor Gajowiak
igor.gajowiak at gmail.com
Wed Aug 5 18:15:26 EDT 2015
Changeset: 32ede87a799d466b41be373199942310e9520ae3
Author: Igor Gajowiak <igor.gajowiak at gmail.com>
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 <igor.gajowiak at gmail.com>", 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;
More information about the Commits
mailing list