/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