cpw.nader.asynclogging-3: 5dcc469a: Began work on gobjectifying the logger s...
morshed.nader at gmail.com
morshed.nader at gmail.com
Tue Jan 11 22:25:50 EST 2011
----------------------------------------------------------------------
Revision: 5dcc469a155e3384d5d6adf07cf4229633cc9dad
Parent: 8caaf0ca0385ed083a5f8e05073a89225efadeb1
Author: morshed.nader at gmail.com
Date: 01/11/11 22:21:08
Branch: im.pidgin.cpw.nader.asynclogging-3
URL: http://d.pidgin.im/viewmtn/revision/info/5dcc469a155e3384d5d6adf07cf4229633cc9dad
Changelog:
Began work on gobjectifying the logger stuff and re-writing a lot of things, progress looks good so far, just a lot of grunt work
Moved the html/txt/old loggers into their own files
Changes against parent 8caaf0ca0385ed083a5f8e05073a89225efadeb1
added libpurple/htmllog.c
added libpurple/htmllog.h
added libpurple/oldlog.c
added libpurple/oldlog.h
added libpurple/txtlog.c
added libpurple/txtlog.h
added libpurple/xmllog.c
added libpurple/xmllog.h
patched libpurple/Makefile.am
patched libpurple/Makefile.mingw
patched libpurple/account.c
patched libpurple/conversation.c
patched libpurple/core.c
patched libpurple/log.c
patched libpurple/log.h
patched pidgin/gtklog.c
-------------- next part --------------
============================================================
--- libpurple/conversation.c 5189741e8d77163db36db82793df9a1f5a37693b
+++ libpurple/conversation.c cae696ec52d118bcb15f3e51abee287a8bbc964a
@@ -226,7 +226,8 @@ open_log(PurpleConversation *conv)
static void
open_log(PurpleConversation *conv)
{
- conv->logs = g_list_append(NULL, purple_log_new(conv->type == PURPLE_CONV_TYPE_CHAT ? PURPLE_LOG_CHAT :
+ conv->logs = g_list_append(NULL, purple_log_new(G_TYPE_INVALID,
+ conv->type == PURPLE_CONV_TYPE_CHAT ? PURPLE_LOG_CHAT :
PURPLE_LOG_IM, conv->name, conv->account,
conv, time(NULL), NULL));
}
@@ -805,7 +806,7 @@ purple_conversation_close_logs(PurpleCon
{
g_return_if_fail(conv != NULL);
- g_list_foreach(conv->logs, (GFunc)purple_log_free, NULL);
+ g_list_foreach(conv->logs, (GFunc) g_object_unref, NULL);
g_list_free(conv->logs);
conv->logs = NULL;
}
============================================================
--- libpurple/core.c 2431d70fed20726a6a5ad9ac00b90938d628f01d
+++ libpurple/core.c aedd34e95744a3f856b81d15db1ece18d0161f28
@@ -163,7 +163,7 @@ purple_core_init(const char *ui)
purple_certificate_init();
purple_conversations_init();
purple_blist_init();
- purple_log_init();
+ purple_log_system_init();
purple_network_init();
purple_privacy_init();
purple_pounces_init();
@@ -260,7 +260,7 @@ purple_core_quit(void)
purple_cmds_uninit();
/* Everything after util_uninit cannot try to write things to the confdir */
purple_util_uninit();
- purple_log_uninit();
+ purple_log_system_uninit();
purple_signals_uninit();
============================================================
--- libpurple/log.c a190fb11d41f65733874f305d45724048e02f66a
+++ libpurple/log.c 224d1d377ac7d62ed2d31962910eac5d5cf4f4ba
@@ -30,13 +30,15 @@
#include "debug.h"
#include "internal.h"
#include "log.h"
+#include "htmllog.h"
+#include "txtlog.h"
+#include "oldlog.h"
#include "prefs.h"
#include "util.h"
#include "stringref.h"
#include "imgstore.h"
#include "time.h"
-
#if ! GLIB_CHECK_VERSION(2, 19, 8)
//Fixes strict-aliasing warning
#undef g_static_mutex_get_mutex_impl_shortcut
@@ -48,94 +50,80 @@
#endif
-typedef struct {
- PurpleAccount *account;
- gchar *name;
-} _purple_logsize_user;
+G_DEFINE_TYPE (PurpleLog, purple_log, G_TYPE_OBJECT)
+static void purple_log_get_property(GObject *, guint, GValue *, GParamSpec *);
+static void purple_log_set_property(GObject *, guint, const GValue *, GParamSpec *);
+static void purple_log_finalize(GObject *);
-typedef struct {
- PurpleLog *log;
- GAsyncReadyCallback cb;
- gpointer userdata;
-} _purple_log_free_callback_data;
+enum {
+ PROP_0,
+ PROP_LOG_CHAT_TYPE,
+ PROP_LOG_NAME,
+ PROP_LOG_ACCOUNT,
+ PROP_LOG_TIME,
+ PROP_LOG_CONV,
+ PROP_LOG_LOGGER_DATA,
+ PROP_LOG_TM,
+ LAST_PROP
+};
-typedef struct {
- PurpleLog *log;
- GAsyncReadyCallback cb;
- gpointer userdata;
-} _purple_log_delete_callback_data;
+static GParamSpec *properties[LAST_PROP] = { 0 };
-typedef struct {
- _purple_logsize_user *lu;
- PurpleLog *log;
- GAsyncReadyCallback cb;
- gpointer userdata;
-} _purple_log_write_callback_data;
+#define PURPLE_LOG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), PURPLE_TYPE_LOG, PurpleLogPrivate))
+typedef struct _PurpleLogPrivate PurpleLogPrivate;
-typedef struct {
- PurpleLog *log;
- GAsyncReadyCallback cb;
- gpointer userdata;
-} _purple_log_read_callback_data;
+struct _PurpleLogPrivate {
+ PurpleLogChatType chat_type; /**< The type of log this is */
+ gchar *name; /**< The name of this log */
+ PurpleAccount *account; /**< The account this log is taking place on */
+ time_t time; /**< The time this conversation started, converted to the local timezone */
+ PurpleConversation *conv; /**< The conversation being logged */
+ gpointer logger_data; /**< Data used by the log logger */
+ struct tm *tm; /**< The time this conversation started */
+};
typedef struct {
- PurpleLog *log;
- GAsyncReadyCallback cb;
- gpointer userdata;
-} _purple_log_size_callback_data;
+ PurpleAccount *account;
+ gchar *name;
+} _purple_logsize_user;
typedef struct {
- PurpleLog *log;
- PurpleMessageFlags type;
+ PurpleMessageFlags flags;
gchar *from;
gchar *message;
time_t time;
-} _purple_log_logger_write_callback_data;
+} _thread_write_callback_data;
typedef struct {
- PurpleLog *log;
- PurpleLogReadFlags *flags;
-} _purple_log_logger_read_callback_data;
+ PurpleLogReadFlags flags;
+ gchar *text;
+} _purple_log_read_res_callback_data;
typedef struct {
PurpleAccount *account;
- PurpleLogType type;
+ PurpleLogChatType chat_type;
gchar *name;
gchar *ext;
-} _purple_logger_total_size_callback_data;
+} _thread_callback_data;
typedef struct {
- PurpleLog *log;
-} _purple_logger_sizer_callback_data;
-
-typedef struct {
- PurpleLogSetCallback set_cb;
- GHashTable *sets;
- GMutex *mutex;
-} _purple_logger_get_sets_common_callback_data;
-
-typedef struct {
- PurpleLog *log;
-} _purple_logger_deleter_callback_data;
-
-typedef struct {
- PurpleLog *log;
+ PurpleAccount *account;
+ PurpleLogChatType chat_type;
+ gchar *name;
gchar *ext;
-} _purple_logger_writer_callback_data;
+} _purple_logger_total_size_callback_data;
typedef struct {
PurpleAccount *account;
- PurpleLogLogger *logger;
- PurpleLogType type;
+ PurpleLogChatType chat_type;
+ GType log_type;
gchar *name;
gchar *ext;
} _purple_logger_lister_callback_data;
typedef struct {
GAsyncReadyCallback cb;
- GCancellable *cancellable;
gpointer userdata;
- gint io_priority;
guint counter;
gssize total;
} _purple_log_total_size_callback_data;
@@ -160,7 +148,7 @@ typedef struct {
GList *logs;
gpointer userdata;
guint counter;
-} _purple_log_logs_callback_data;
+} _get_logs_callback_data;
typedef struct {
GAsyncReadyCallback cb;
@@ -170,309 +158,514 @@ typedef struct {
guint counter;
} _purple_log_sets_callback_data;
-static void purple_log_logger_write_callback_data_free(gpointer);
-static void purple_logger_writer_callback_data_free(gpointer);
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 PurpleLog *purple_log_ref(PurpleLog *);
-static void purple_log_unref(PurpleLog *);
-
static guint log_set_hash(gconstpointer);
static gboolean log_set_equal(gconstpointer, gconstpointer);
static void log_add_log_set_to_hash(GHashTable *, PurpleLogSet *);
-static gboolean log_get_log_sets_common(GHashTable *, GMutex *, PurpleLogSetCallback, GError **);
+static GHashTable *log_get_log_sets_common(GCancellable *, GError **);
static void log_get_log_sets_common_thread(GSimpleAsyncResult *, GObject *, GCancellable *);
-static void log_get_log_sets_common_async(GHashTable *, GMutex *, PurpleLogSetCallback,
- gint, GCancellable *, GAsyncReadyCallback, gpointer);
+static void log_get_log_sets_common_async(gint, GCancellable *, GAsyncReadyCallback, gpointer);
-static void deleter_thread(GSimpleAsyncResult *, GObject *, GCancellable *);
+static void create_thread(GSimpleAsyncResult *, GObject *, GCancellable *);
+static void purple_log_real_create_async(PurpleLog *, gint, GCancellable *, GAsyncReadyCallback, gpointer);
+static gboolean purple_log_real_create_finish(PurpleLog *, GAsyncResult *, GError **);
-static gchar *process_txt_log(gchar *, gchar *);
+static void log_read_res_free(gpointer);
+static void read_thread(GSimpleAsyncResult *, GObject *, GCancellable *);
+static void purple_log_real_read_async(PurpleLog *, gint, GCancellable *, GAsyncReadyCallback, gpointer);
+static gchar *purple_log_real_read_finish(PurpleLog *, GAsyncResult *, PurpleLogReadFlags *, GError **);
-static gsize html_logger_write(PurpleLog *, PurpleMessageFlags, const gchar *,
- time_t, const gchar *);
-static void html_logger_write_async(PurpleLog *, PurpleMessageFlags, const gchar *,
- time_t, const gchar *, gint, GCancellable *, GAsyncReadyCallback, gpointer);
-static void html_logger_finalize(PurpleLog *);
-static GList *html_logger_list(PurpleLogType, const gchar *, PurpleAccount *);
-static void html_logger_list_async(PurpleLogType, const gchar *, PurpleAccount *,
- gint, GCancellable *, GAsyncReadyCallback, gpointer);
-static GList *html_logger_list_syslog(PurpleAccount *);
-static void html_logger_list_syslog_async(PurpleAccount *, gint, GCancellable *,
- GAsyncReadyCallback, gpointer);
-static gchar *html_logger_read(PurpleLog *, PurpleLogReadFlags *);
-static void html_logger_read_thread(GSimpleAsyncResult *, GObject *, GCancellable *);
-static void html_logger_read_async(PurpleLog *, PurpleLogReadFlags *,
- gint, GCancellable *, GAsyncReadyCallback, gpointer);
-static gint html_logger_total_size(PurpleLogType, const gchar *, PurpleAccount *);
-static void html_logger_total_size_async(PurpleLogType, const gchar *, PurpleAccount *,
- gint, GCancellable *, GAsyncReadyCallback, gpointer);
+static void size_thread(GSimpleAsyncResult *, GObject *, GCancellable *);
+static void purple_log_real_size_async(PurpleLog *, gint, GCancellable *, GAsyncReadyCallback, gpointer);
+static gssize purple_log_real_size_finish(PurpleLog *, GAsyncResult *, GError **);
-static GList *old_logger_list(PurpleLogType, const gchar *, PurpleAccount *);
-static gint old_logger_total_size(PurpleLogType, const gchar *, PurpleAccount *);
-static gchar *old_logger_read(PurpleLog *, PurpleLogReadFlags *);
-static gint old_logger_size(PurpleLog *);
-static void old_logger_get_log_sets(PurpleLogSetCallback, GHashTable *);
-static void old_logger_finalize(PurpleLog *);
+static void write_update_size_cache(PurpleLog *, gssize);
+static void write_thread(GSimpleAsyncResult *, GObject *, GCancellable *);
+static void purple_log_real_write_async(PurpleLog *, PurpleMessageFlags, const gchar *, time_t, const gchar *, gint, GCancellable *, GAsyncReadyCallback, gpointer);
+static gssize purple_log_real_write_finish(PurpleLog *, GAsyncResult *, GError **);
-static gsize txt_logger_write(PurpleLog *, PurpleMessageFlags, const gchar *, time_t,
- const gchar *);
-static void txt_logger_write_thread(GSimpleAsyncResult *, GObject *, GCancellable *);
-static void txt_logger_write_async(PurpleLog *, PurpleMessageFlags, const gchar *, time_t,
- const gchar *, gint, GCancellable *, GAsyncReadyCallback, gpointer);
-static void txt_logger_finalize(PurpleLog *);
-static GList *txt_logger_list(PurpleLogType, const gchar *, PurpleAccount *);
-static void txt_logger_list_async(PurpleLogType, const gchar *, PurpleAccount *,
- gint, GCancellable *, GAsyncReadyCallback, gpointer);
-static GList *txt_logger_list_syslog(PurpleAccount *);
-static void txt_logger_list_syslog_async(PurpleAccount *, gint, GCancellable *,
- GAsyncReadyCallback, gpointer);
-static gchar *txt_logger_read(PurpleLog *, PurpleLogReadFlags *);
-static void txt_logger_read_thread(GSimpleAsyncResult *, GObject *, GCancellable *);
-static void txt_logger_read_async(PurpleLog *, PurpleLogReadFlags *, gint, GCancellable *,
- GAsyncReadyCallback, gpointer);
-static gint txt_logger_total_size(PurpleLogType, const gchar *, PurpleAccount *);
-static void txt_logger_total_size_async(PurpleLogType, const gchar *, PurpleAccount *,
- gint, GCancellable *, GAsyncReadyCallback, gpointer);
+static void total_size_thread(GSimpleAsyncResult *, GObject *, GCancellable *);
+static void purple_log_real_total_size_async(PurpleLog *, PurpleLogChatType, const gchar *, PurpleAccount *, gint, GCancellable *, GAsyncReadyCallback, gpointer);
+static gssize purple_log_real_total_size_finish(PurpleLog *, GAsyncResult *, GError **);
-static void log_free_cb(GObject *, GAsyncResult *, gpointer);
-static void log_delete_cb(GObject *, GAsyncResult *, gpointer);
-static void log_write_cb(GObject *, GAsyncResult *, gpointer);
-static void log_read_cb(GObject *, GAsyncResult *, gpointer);
-static void log_size_cb(GObject *, GAsyncResult *, gpointer);
+static void remove_thread(GSimpleAsyncResult *, GObject *, GCancellable *);
+static void purple_log_real_remove_async(PurpleLog *, gint, GCancellable *, GAsyncReadyCallback, gpointer);
+static gboolean purple_log_real_remove_finish(PurpleLog *, GAsyncResult *, GError **);
+
+static void get_logs_thread(GSimpleAsyncResult *, GObject *, GCancellable *);
+static void purple_log_real_get_logs_async(PurpleLog *, PurpleLogChatType, const gchar *, PurpleAccount *, gint, GCancellable *, GAsyncReadyCallback, gpointer);
+static GList *purple_log_real_get_logs_finish(PurpleLog *, GAsyncResult *, GError **);
+
+static void get_log_sets_thread(GSimpleAsyncResult *, GObject *, GCancellable *);
+static void purple_log_real_get_log_sets_async(PurpleLog *, gint, GCancellable *, GAsyncReadyCallback, gpointer);
+static GHashTable *purple_log_real_get_log_sets_finish(PurpleLog *, GAsyncResult *, GError **);
+
+static void list_syslog_thread(GSimpleAsyncResult *, GObject *, GCancellable *);
+static void purple_log_real_list_syslog_async(PurpleLog *, PurpleAccount *, gint, GCancellable *, GAsyncReadyCallback, gpointer);
+static GList *purple_log_real_list_syslog_finish(PurpleLog *, GAsyncResult *, GError **);
+
static void log_list_cb(GObject *, GAsyncResult *, gpointer);
static void log_system_list_cb(GObject *, GAsyncResult *, gpointer);
static void log_total_size_cb(GObject *, GAsyncResult *, gpointer);
-static void log_total_size_intermediate_cb(GObject *, GAsyncResult *, gpointer);
static void log_total_size_list_cb(GObject *, GAsyncResult *, gpointer);
static void log_hash_cb(GObject *, GAsyncResult *, gpointer);
-static void log_get_activity_score_cb(GObject *, GAsyncResult *, gpointer);
-static void log_get_activity_score_size_cb(GObject *, GAsyncResult *, gpointer);
G_LOCK_DEFINE(loggers);
G_LOCK_DEFINE(current_logger);
-G_LOCK_DEFINE(html_logger);
-G_LOCK_DEFINE(txt_logger);
-G_LOCK_DEFINE(old_logger);
G_LOCK_DEFINE(logsize_users);
G_LOCK_DEFINE(logsize_users_decayed);
-G_LOCK_DEFINE(log_ref_table);
-static GSList *loggers = NULL;
-static PurpleLogLogger *current_logger = NULL;
+static GArray *loggers = NULL;
+static GType current_logger = G_TYPE_INVALID;
+static GHashTable *logsize_users = NULL;
+static GHashTable *logsize_users_decayed = NULL;
-static PurpleLogLogger *html_logger;
-static PurpleLogLogger *txt_logger;
-static PurpleLogLogger *old_logger;
-static GHashTable *logsize_users = NULL;
-static GHashTable *logsize_users_decayed = NULL;
-static GHashTable *log_ref_table = NULL;
+GType
+purple_log_chat_type_get_type(void)
+{
+ static GType etype = 0;
+ if (G_UNLIKELY(etype == 0)) {
+ static const GEnumValue values[] = {
+ { PURPLE_LOG_IM, "PURPLE_LOG_IM", "Purple Log IM" },
+ { PURPLE_LOG_IM, "PURPLE_LOG_CHAT", "Purple Log Chat" },
+ { PURPLE_LOG_IM, "PURPLE_LOG_SYSTEM", "Purple Log System" },
+ { 0, NULL, NULL }
+ };
+ etype = g_enum_register_static(g_intern_static_string("PurpleLogChatType"), values);
+ }
+
+ return etype;
+}
+
+static gpointer
+purple_struct_tm_copy(gpointer original)
+{
+ struct tm *copy;
+
+ copy = g_new(struct tm, 1);
+ memcpy(copy, original, sizeof(struct tm));
+
+ return copy;
+}
+
+#if GLIB_CHECK_VERSION(2, 26, 0)
+
+typedef struct tm PurpleStructTM;
+G_DEFINE_BOXED_TYPE (PurpleStructTM, purple_struct_tm, purple_struct_tm_copy, g_free);
+
+#else
+
+GType
+purple_struct_tm_get_type(void)
+{
+ static GType object_type = 0;
+
+ if (G_UNLIKELY (object_type == 0))
+ object_type = g_boxed_type_register_static(g_intern_static_string("PurpleStructTm"),
+ purple_struct_tm_copy, g_free);
+
+ return object_type;
+}
+
+#endif
+
static void
-purple_log_logger_write_callback_data_free(gpointer userdata)
+purple_log_class_init(PurpleLogClass *class)
{
- _purple_log_logger_write_callback_data *callback_data = userdata;
+ GObjectClass *gobject_class = G_OBJECT_CLASS(class);
- g_free(callback_data->from);
- g_free(callback_data->message);
- g_free(callback_data);
+ gobject_class->set_property = purple_log_set_property;
+ gobject_class->get_property = purple_log_get_property;
+ gobject_class->finalize = purple_log_finalize;
+
+ class->logger_name = "";
+ class->logger_id = "";
+ class->create_async = purple_log_real_create_async;
+ class->create_finish = purple_log_real_create_finish;
+ class->write_async = purple_log_real_write_async;
+ class->write_finish = purple_log_real_write_finish;
+ class->list_async = purple_log_real_get_logs_async;
+ class->list_finish = purple_log_real_get_logs_finish;
+ class->read_async = purple_log_real_read_async;
+ class->read_finish = purple_log_real_read_finish;
+ class->size_async = purple_log_real_size_async;
+ class->size_finish = purple_log_real_size_finish;
+ class->total_size_async = purple_log_real_total_size_async;
+ class->total_size_finish = purple_log_real_total_size_finish;
+ class->list_syslog_async = purple_log_real_list_syslog_async;
+ class->list_syslog_finish = purple_log_real_list_syslog_finish;
+ class->get_log_sets_async = purple_log_real_get_log_sets_async;
+ class->get_log_sets_finish = purple_log_real_get_log_sets_finish;
+ class->remove_async = purple_log_real_remove_async;
+ class->remove_finish = purple_log_real_remove_finish;
+ class->is_removable_async = purple_log_real_is_removable_async;
+ class->is_removable_finish = purple_log_real_is_removable_finish;
+
+ properties[PROP_LOG_CHAT_TYPE] =
+ g_param_spec_enum("chat-type",
+ "Chat Type",
+ "The chat type of the log",
+ PURPLE_TYPE_LOG_CHAT_TYPE,
+ PURPLE_LOG_SYSTEM,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READABLE);
+
+ properties[PROP_LOG_NAME] =
+ g_param_spec_string("name",
+ "Name",
+ "The name of the conversation (buddy name, chat name, etc.)",
+ "",
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READABLE);
+
+ properties[PROP_LOG_ACCOUNT] =
+ //Ideally should be g_param_spec_object
+ g_param_spec_pointer("account",
+ "Account",
+ "The account the conversation is occurring on",
+// PURPLE_TYPE_ACCOUNT,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READABLE);
+
+ properties[PROP_LOG_TIME] =
+ g_param_spec_long("time",
+ "Time",
+ "The time this conversation started, converted to the local timezone",
+ 0,
+ G_MAXLONG,
+ 0,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READABLE);
+
+ properties[PROP_LOG_CONV] =
+ //Ideally should be g_param_spec_object
+ g_param_spec_pointer("conv",
+ "Conversation",
+ "The conversation being logged",
+// PURPLE_TYPE_CONVERSATION,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READABLE);
+
+ properties[PROP_LOG_LOGGER_DATA] =
+ //Ideally should be g_param_spec_object
+ g_param_spec_pointer("logger-data",
+ "Logger Data",
+ "Data used by loggers", //better description
+// PURPLE_TYPE_CONVERSATION,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READABLE);
+
+ properties[PROP_LOG_TM] =
+ g_param_spec_boxed("tm",
+ "Time (tm)",
+ "The time this conversation started",
+ PURPLE_TYPE_STRUCT_TM,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READABLE);
+
+ g_object_class_install_property(gobject_class,
+ PROP_LOG_CHAT_TYPE,
+ properties[PROP_LOG_CHAT_TYPE]);
+
+ g_object_class_install_property(gobject_class,
+ PROP_LOG_NAME,
+ properties[PROP_LOG_NAME]);
+
+ g_object_class_install_property(gobject_class,
+ PROP_LOG_ACCOUNT,
+ properties[PROP_LOG_ACCOUNT]);
+
+ g_object_class_install_property(gobject_class,
+ PROP_LOG_TIME,
+ properties[PROP_LOG_TIME]);
+
+ g_object_class_install_property(gobject_class,
+ PROP_LOG_CONV,
+ properties[PROP_LOG_CONV]);
+
+ g_object_class_install_property(gobject_class,
+ PROP_LOG_LOGGER_DATA,
+ properties[PROP_LOG_LOGGER_DATA]);
+
+ g_object_class_install_property(gobject_class,
+ PROP_LOG_TM,
+ properties[PROP_LOG_TM]);
+
+ g_type_class_add_private(gobject_class, sizeof(PurpleLogPrivate));
}
static void
-purple_logger_writer_callback_data_free(gpointer userdata)
+purple_log_init(PurpleLog *log)
{
- _purple_logger_writer_callback_data *callback_data = userdata;
+ PurpleLogPrivate *priv = PURPLE_LOG_GET_PRIVATE(log);
- g_free(callback_data->ext);
- g_free(callback_data);
+ priv->chat_type = PURPLE_LOG_SYSTEM;
+ priv->name = NULL;
+ priv->account = NULL;
+ priv->time = 0;
+ priv->conv = NULL;
+ priv->logger_data = NULL;
+ //These needed?
+ priv->tm = NULL;
}
static void
-purple_logger_lister_callback_data_free(gpointer userdata)
+purple_log_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
{
- _purple_logger_lister_callback_data *callback_data = userdata;
+ PurpleLog *log = PURPLE_LOG(object);
- g_free(callback_data->name);
- g_free(callback_data->ext);
- g_free(callback_data);
+ switch (prop_id) {
+ case PROP_LOG_LOGGER_DATA:
+ purple_log_set_logger_data(log, g_value_get_pointer(value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
}
static void
-purple_logger_total_size_callback_data_free(gpointer userdata)
+purple_log_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
{
- _purple_logger_total_size_callback_data *callback_data = userdata;
+ PurpleLog *log = PURPLE_LOG(object);
- g_free(callback_data->name);
- g_free(callback_data->ext);
- g_free(callback_data);
+ switch (prop_id) {
+ case PROP_LOG_CHAT_TYPE:
+ g_value_set_enum(value, purple_log_get_chat_type(log));
+ break;
+ case PROP_LOG_NAME:
+ g_value_set_string(value, purple_log_get_name(log));
+ break;
+ case PROP_LOG_ACCOUNT:
+ //g_value_set_object
+ g_value_set_pointer(value, purple_log_get_account(log));
+ break;
+ case PROP_LOG_TIME:
+ g_value_set_long(value, purple_log_get_time(log));
+ break;
+ case PROP_LOG_CONV:
+ //g_value_set_object
+ g_value_set_pointer(value, purple_log_get_conversation(log));
+ break;
+ case PROP_LOG_LOGGER_DATA:
+ g_value_set_pointer(value, purple_log_get_logger_data(log));
+ break;
+ case PROP_LOG_TM:
+ g_value_set_boxed(value, purple_log_get_tm(log));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
}
+void
+purple_log_set_logger_data(PurpleLog *log, gpointer logger_data)
+{
+ g_return_if_fail(PURPLE_IS_LOG(log));
-/**************************************************************************
- * PUBLIC LOGGING FUNCTIONS ***********************************************
- **************************************************************************/
+ PURPLE_LOG_GET_PRIVATE(log)->logger_data = logger_data;
-PurpleLog *
-purple_log_new(PurpleLogType type, const gchar *name, PurpleAccount *account,
- PurpleConversation *conv, time_t time, const struct tm *tm)
+ g_object_notify(G_OBJECT(log), "logger-data");
+}
+
+PurpleLogChatType
+purple_log_get_chat_type(const PurpleLog *log)
{
- PurpleLog *log;
+ g_return_val_if_fail(PURPLE_IS_LOG(log), PURPLE_LOG_SYSTEM);
- g_return_val_if_fail(name != NULL, NULL);
- g_return_val_if_fail(account != NULL, NULL);
+ return PURPLE_LOG_GET_PRIVATE(log)->chat_type;
+}
- log = purple_log_ref(g_slice_new(PurpleLog));
- /* IMPORTANT: Make sure to initialize all the members of PurpleLog */
- PURPLE_DBUS_REGISTER_POINTER(log, PurpleLog);
+G_CONST_RETURN gchar *
+purple_log_get_name(const PurpleLog *log)
+{
+ g_return_val_if_fail(PURPLE_IS_LOG(log), NULL);
- log->type = type;
- log->name = g_strdup(purple_normalize(account, name));
- log->account = account;
- log->conv = conv;
- log->time = time;
- log->logger = purple_log_logger_get();
- log->logger_data = NULL;
+ return PURPLE_LOG_GET_PRIVATE(log)->name;
+}
- if (tm == NULL)
- log->tm = NULL;
- else {
- /* There's no need to zero this as we immediately do a direct copy. */
- log->tm = g_slice_new(struct tm);
+PurpleAccount *
+purple_log_get_account(const PurpleLog *log)
+{
+ g_return_val_if_fail(PURPLE_IS_LOG(log), NULL);
- *(log->tm) = *tm;
+ return PURPLE_LOG_GET_PRIVATE(log)->account;
+}
-#ifdef HAVE_STRUCT_TM_TM_ZONE
- /* XXX: This is so wrong... */
- if (log->tm->tm_zone != NULL) {
- gchar *tmp = g_locale_from_utf8(log->tm->tm_zone, -1, NULL, NULL, NULL);
+time_t
+purple_log_get_time(const PurpleLog *log)
+{
+ g_return_val_if_fail(PURPLE_IS_LOG(log), 0);
- if (tmp != NULL)
- log->tm->tm_zone = tmp;
- else
- /* Just shove the UTF-8 bytes in and hope... */
- log->tm->tm_zone = g_strdup(log->tm->tm_zone);
- }
-#endif
- }
+ return PURPLE_LOG_GET_PRIVATE(log)->time;
+}
- // TODO: Non-blocking create?
- if (log->logger && log->logger->create)
- (log->logger->create)(log);
+PurpleConversation *
+purple_log_get_conversation(const PurpleLog *log)
+{
+ g_return_val_if_fail(PURPLE_IS_LOG(log), NULL);
- return log;
+ return PURPLE_LOG_GET_PRIVATE(log)->conv;
}
-static PurpleLog *
-purple_log_ref(PurpleLog *log)
+gpointer
+purple_log_get_logger_data(const PurpleLog *log)
{
- guint ref_count;
- gpointer value;
+ g_return_val_if_fail(PURPLE_IS_LOG(log), NULL);
- G_LOCK(log_ref_table);
+ return PURPLE_LOG_GET_PRIVATE(log)->logger_data;
+}
- if (g_hash_table_lookup_extended(log_ref_table, log, NULL, &value)) {
- ref_count = GPOINTER_TO_UINT(value);
- ref_count++;
- } else
- ref_count = 1;
+G_CONST_RETURN struct tm *
+purple_log_get_tm(const PurpleLog *log)
+{
+ g_return_val_if_fail(PURPLE_IS_LOG(log), NULL);
- g_hash_table_insert(log_ref_table, log, GUINT_TO_POINTER(ref_count));
+ return PURPLE_LOG_GET_PRIVATE(log)->tm;
+}
- G_UNLOCK(log_ref_table);
+static void
+purple_logger_lister_callback_data_free(gpointer userdata)
+{
+ _purple_logger_lister_callback_data *callback_data = userdata;
- return log;
+ g_free(callback_data->name);
+ g_free(callback_data->ext);
+ g_free(callback_data);
}
static void
-purple_log_unref(PurpleLog *log)
+thread_callback_data_free(gpointer userdata)
{
- guint ref_count;
- gpointer value;
+ _thread_callback_data *callback_data = userdata;
- G_LOCK(log_ref_table);
+ // if (callback_data->account != NULL)
+ // g_object_unref(callback_data->account);
- if (g_hash_table_lookup_extended(log_ref_table, log, NULL, &value)) {
- ref_count = GPOINTER_TO_UINT(value);
- ref_count--;
- g_hash_table_insert(log_ref_table, log, GUINT_TO_POINTER(ref_count));
- } else
- // Spit out an error?
- ref_count = 0;
+ g_free(callback_data->name);
+ g_free(callback_data->ext);
+ g_free(callback_data);
+}
- G_UNLOCK(log_ref_table);
+static void
+thread_write_callback_data_free(gpointer userdata)
+{
+ _thread_write_callback_data *callback_data = userdata;
- if (ref_count < 1) {
- if (log->logger->async->finalize_async != NULL)
- log->logger->async->finalize_async(log, G_PRIORITY_LOW, NULL, log_free_cb, log);
- else if (log->logger->finalize != NULL) {
- GSimpleAsyncResult *simple;
+ g_free(callback_data->from);
+ g_free(callback_data->message);
+ g_free(callback_data);
+}
- log->logger->finalize(log);
+static void
+purple_logger_total_size_callback_data_free(gpointer userdata)
+{
+ _purple_logger_total_size_callback_data *callback_data = userdata;
- simple = g_simple_async_result_new(NULL, log_free_cb, log, purple_log_free);
- g_simple_async_result_complete_in_idle(simple);
- g_object_unref(simple);
- }
- }
+ g_free(callback_data->name);
+ g_free(callback_data->ext);
+ g_free(callback_data);
}
-void
-purple_log_free(PurpleLog *log)
+
+/**************************************************************************
+ * PUBLIC LOGGING FUNCTIONS ***********************************************
+ **************************************************************************/
+
+PurpleLog *
+purple_log_new(GType log_type, PurpleLogChatType chat_type, const gchar *name, PurpleAccount *account,
+ PurpleConversation *conv, time_t time, const struct tm *tm)
{
- g_return_if_fail(log != NULL);
+ PurpleLog *log;
- purple_log_unref(log);
+ g_return_val_if_fail(log_type == G_TYPE_INVALID || g_type_is_a(log_type, PURPLE_TYPE_LOG), NULL);
+ g_return_val_if_fail(name != NULL, NULL);
+ g_return_val_if_fail(account != NULL, NULL);
+
+ if (log_type == G_TYPE_INVALID)
+ log_type = current_logger;
+
+ log = g_object_new(log_type,
+ "type", chat_type,
+ "name", g_strdup(purple_normalize(account, name)),
+ "account", account,
+ "conv", conv,
+ "time", time,
+ "tm", tm,
+ NULL);
+
+ PURPLE_DBUS_REGISTER_POINTER(log, PurpleLog);
+
+ // if (tm == NULL)
+ // log->tm = NULL;
+ // else {
+ // /* There's no need to zero this as we immediately do a direct copy. */
+ // log->tm = g_slice_new(struct tm);
+
+ // *(log->tm) = *tm;
+
+// #ifdef HAVE_STRUCT_TM_TM_ZONE
+ // /* XXX: This is so wrong... */
+ // if (log->tm->tm_zone != NULL) {
+ // gchar *tmp = g_locale_from_utf8(log->tm->tm_zone, -1, NULL, NULL, NULL);
+
+ // if (tmp != NULL)
+ // log->tm->tm_zone = tmp;
+ // else
+ // /* Just shove the UTF-8 bytes in and hope... */
+ // log->tm->tm_zone = g_strdup(log->tm->tm_zone);
+ // }
+// #endif
+ // }
+
+ // TODO: Non-blocking create?
+ // if (log->logger->create)
+ // (log->logger->create_fn)(log);
+
+ return log;
}
-void
-purple_log_write(PurpleLog *log, PurpleMessageFlags type, const gchar *from, time_t time,
- const gchar *message)
+static void
+write_update_size_cache(PurpleLog *log, gssize size)
{
_purple_logsize_user *lu;
gpointer ptrsize;
- gsize written, total;
+ gssize total;
- g_return_if_fail(from != NULL);
- g_return_if_fail(message != NULL);
- g_return_if_fail(log != NULL);
- g_return_if_fail(log->logger != NULL);
- g_return_if_fail(log->logger->write != NULL);
+ if (size <= 0)
+ return;
- written = (log->logger->write)(log, type, from, time, message);
-
lu = g_new(_purple_logsize_user, 1);
total = 0;
- lu->name = g_strdup(purple_normalize(log->account, log->name));
- lu->account = log->account;
+ lu->name = g_strdup(purple_normalize(purple_log_get_account(log), purple_log_get_name(log)));
+ lu->account = purple_log_get_account(log);
G_LOCK(logsize_users);
if(g_hash_table_lookup_extended(logsize_users, lu, NULL, &ptrsize)) {
gchar *tmp = lu->name;
total = GPOINTER_TO_INT(ptrsize);
- total += written;
+ total += size;
g_hash_table_replace(logsize_users, lu, GINT_TO_POINTER(total));
- purple_debug_info("log", "HASH(purple_log_write): total size %i\n", total);
+ // purple_debug_info("log", "HASH(purple_log_write): total size %i\n", total);
/* The hash table takes ownership of lu, so create a new one
* for the logsize_users_decayed check below. */
lu = g_new(_purple_logsize_user, 1);
lu->name = g_strdup(tmp);
- lu->account = log->account;
+ lu->account = purple_log_get_account(log);
}
G_UNLOCK(logsize_users);
G_LOCK(logsize_users_decayed);
if(g_hash_table_lookup_extended(logsize_users_decayed, lu, NULL, &ptrsize)) {
total = GPOINTER_TO_INT(ptrsize);
- total += written;
+ total += size;
g_hash_table_replace(logsize_users_decayed, lu, GINT_TO_POINTER(total));
} else {
g_free(lu->name);
@@ -481,204 +674,393 @@ purple_log_write(PurpleLog *log, PurpleM
G_UNLOCK(logsize_users_decayed);
}
+gssize
+purple_log_write(PurpleLog *log, PurpleMessageFlags type, const gchar *from, time_t time, const gchar *message, GCancellable *cancellable, GError **error)
+{
+ PurpleLogClass *class;
+ gssize size;
+
+ g_return_val_if_fail(PURPLE_IS_LOG(log), -1);
+ g_return_val_if_fail(from != NULL, -1);
+ g_return_val_if_fail(message != NULL, -1);
+
+ class = PURPLE_LOG_GET_CLASS(log);
+
+ if (class->write_fn == NULL) {
+ g_set_error_literal(error,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported"));
+
+ return -1;
+ }
+
+ size = class->write_fn(log, type, from, time, message, cancellable, error);
+ write_update_size_cache(log, size);
+
+ return size;
+}
+
+static void
+write_thread(GSimpleAsyncResult *simple, GObject *object, GCancellable *cancellable)
+{
+ _thread_write_callback_data *callback_data =
+ g_simple_async_result_get_op_res_gpointer(simple);
+ PurpleLog *log = PURPLE_LOG(object);
+ PurpleMessageFlags flags = callback_data->flags;
+ GError *error = NULL;
+ gchar *from = callback_data->from, *message = callback_data->message;
+ gssize size;
+ time_t time = callback_data->time;
+
+ size = purple_log_write(log, flags, from, time, message, cancellable, &error);
+
+ if (size < 0)
+ g_simple_async_result_set_from_error(simple, error);
+ else {
+ write_update_size_cache(log, size);
+ g_simple_async_result_set_op_res_gssize(simple, size);
+ }
+
+ g_clear_error(&error);
+}
+
+static void
+purple_log_real_write_async(PurpleLog *log, PurpleMessageFlags flags, const gchar *from, time_t time, const gchar *message, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
+{
+ _thread_write_callback_data *callback_data;
+ GSimpleAsyncResult *simple;
+
+ callback_data = g_new0(_thread_write_callback_data, 1);
+ callback_data->flags = flags;
+ callback_data->from = g_strdup(from);
+ callback_data->message = g_strdup(message);
+ callback_data->time = time;
+
+ simple = g_simple_async_result_new(G_OBJECT(log), cb, userdata,
+ purple_log_real_write_async);
+
+ g_simple_async_result_set_op_res_gpointer(simple, callback_data, thread_write_callback_data_free);
+ g_simple_async_result_run_in_thread(simple, write_thread, io_priority, cancellable);
+ g_object_unref(simple);
+}
+
void
purple_log_write_async(PurpleLog *log, PurpleMessageFlags type, const gchar *from,
time_t time, const gchar *message, gint io_priority, GCancellable *cancellable,
GAsyncReadyCallback cb, gpointer userdata)
{
- _purple_log_write_callback_data *callback_data;
- _purple_logsize_user *lu;
- GSimpleAsyncResult *simple;
- gssize size;
-
g_return_if_fail(message != NULL);
g_return_if_fail(from != NULL);
- g_return_if_fail(log != NULL);
- g_return_if_fail(log->logger != NULL);
+ g_return_if_fail(PURPLE_IS_LOG(log));
- lu = g_new(_purple_logsize_user, 1);
+ PURPLE_LOG_GET_CLASS(log)->write_async(log,
+ type, from, time, message, io_priority,
+ cancellable, cb, userdata);
+}
- lu->name = g_strdup(purple_normalize(log->account, log->name));
- lu->account = log->account;
+static gssize
+purple_log_real_write_finish(PurpleLog *log, GAsyncResult *res, GError **error)
+{
+ return g_simple_async_result_get_op_res_gssize(G_SIMPLE_ASYNC_RESULT(res));
+}
- callback_data = g_new0(_purple_log_write_callback_data, 1);
- callback_data->cb = cb;
- callback_data->userdata = userdata;
- callback_data->lu = lu;
- callback_data->log = log;
+gssize
+purple_log_write_finish(PurpleLog *log, GAsyncResult *res, GError **error)
+{
+ g_return_val_if_fail(PURPLE_IS_LOG(log), -1);
+ g_return_val_if_fail(G_IS_ASYNC_RESULT(res), -1);
- purple_log_ref(log);
+ if (G_IS_SIMPLE_ASYNC_RESULT(res)) {
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT(res);
- if (log->logger->async->write_async)
- (log->logger->async->write_async)(log, type, from,
- time, message, io_priority, cancellable, log_write_cb, callback_data);
- else if (log->logger->write) {
- size = (log->logger->write)(log, type, from, time, message);
+ if (g_simple_async_result_propagate_error(simple, error))
+ return -1;
+ }
- simple = g_simple_async_result_new(NULL, log_write_cb, callback_data,
- purple_log_write_async);
+ return PURPLE_LOG_GET_CLASS(log)->write_finish(log, res, error);
+}
- g_simple_async_result_set_op_res_gssize(simple, size);
- g_simple_async_result_complete_in_idle(simple);
+gboolean
+purple_log_create(PurpleLog *log, GCancellable *cancellable, GError **error)
+{
+ PurpleLogClass *class;
- g_object_unref(simple);
- } else {
- simple = g_simple_async_result_new_error(NULL, log_write_cb, callback_data,
- G_IO_ERROR, G_IO_ERROR_FAILED, _("The logger has no write function"));
+ g_return_val_if_fail(PURPLE_IS_LOG(log), FALSE);
- g_simple_async_result_complete_in_idle(simple);
+ class = PURPLE_LOG_GET_CLASS(log);
- g_object_unref(simple);
+ if (class->create_fn == NULL) {
+ g_set_error_literal(error,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported"));
+
+ return FALSE;
}
+
+ return class->create_fn(log, cancellable, error);
}
-gssize
-purple_log_write_finish(PurpleLog *log, GAsyncResult *res, GError **error)
+static void
+create_thread(GSimpleAsyncResult *simple, GObject *object, GCancellable *cancellable)
{
+ PurpleLog *log = PURPLE_LOG(object);
+ GError *error = NULL;
+ gboolean result;
+
+ result = purple_log_create(log, 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);
+}
+
+static void
+purple_log_real_create_async(PurpleLog *log, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
+{
GSimpleAsyncResult *simple;
- simple = G_SIMPLE_ASYNC_RESULT(res);
+ simple = g_simple_async_result_new(G_OBJECT(log), cb, userdata, purple_log_real_create_async);
- if (g_simple_async_result_propagate_error(simple, error))
- return -1;
+ g_simple_async_result_run_in_thread(simple, create_thread, io_priority, cancellable);
+ g_object_unref(simple);
+}
- g_return_val_if_fail(g_simple_async_result_get_source_tag(simple) == purple_log_write_async, -1);
+void
+purple_log_create_async(PurpleLog *log, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
+{
+ g_return_if_fail(PURPLE_IS_LOG(log));
- return g_simple_async_result_get_op_res_gssize(simple);
+ PURPLE_LOG_GET_CLASS(log)->create_async(log, io_priority, cancellable, cb, userdata);
}
+static gboolean
+purple_log_real_create_finish(PurpleLog *log, GAsyncResult *res, GError **error)
+{
+ return g_simple_async_result_get_op_res_gboolean(G_SIMPLE_ASYNC_RESULT(res));
+}
+
+gboolean
+purple_log_create_finish(PurpleLog *log, GAsyncResult *res, GError **error)
+{
+ g_return_val_if_fail(PURPLE_IS_LOG(log), FALSE);
+ g_return_val_if_fail(G_IS_ASYNC_RESULT(res), FALSE);
+
+ if (G_IS_SIMPLE_ASYNC_RESULT(res)) {
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT(res);
+
+ if (g_simple_async_result_propagate_error(simple, error))
+ return FALSE;
+ }
+
+ return PURPLE_LOG_GET_CLASS(log)->create_finish(log, res, error);
+}
+
gchar *
-purple_log_read(PurpleLog *log, PurpleLogReadFlags *flags)
+purple_log_read(PurpleLog *log, PurpleLogReadFlags *flags, GCancellable *cancellable, GError **error)
{
- gchar *ret;
+ PurpleLogClass *class;
- g_return_val_if_fail(log != NULL, NULL);
- g_return_val_if_fail(log->logger != NULL, NULL);
+ g_return_val_if_fail(PURPLE_IS_LOG(log), NULL);
- if (log->logger->read) {
- ret = (log->logger->read)(log, flags);
- purple_str_strip_char(ret, '\r');
+ class = PURPLE_LOG_GET_CLASS(log);
- return ret;
+ if (class->read_fn == NULL) {
+ g_set_error_literal(error,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported"));
+
+ return NULL;
}
- return g_strdup_printf("<b><font color=\"red\">%s</font></b>",
- _("The logger has no read function"));
+ return class->read_fn(log, flags, cancellable, error);
}
-void
-purple_log_read_async(PurpleLog *log, PurpleLogReadFlags *flags, gint io_priority,
- GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
+static void
+log_read_res_free(gpointer data)
{
- _purple_log_read_callback_data *callback_data;
- GSimpleAsyncResult *simple;
- gchar *read;
+ _purple_log_read_res_callback_data *res_data = data;
- g_return_if_fail(log != NULL);
- g_return_if_fail(log->logger != NULL);
+ g_free(res_data->text);
+ g_free(res_data);
+}
- callback_data = g_new0(_purple_log_read_callback_data, 1);
- callback_data->cb = cb;
- callback_data->userdata = userdata;
- callback_data->log = log;
+static void
+read_thread(GSimpleAsyncResult *simple, GObject *object, GCancellable *cancellable)
+{
+ PurpleLog *log = PURPLE_LOG(object);
+ PurpleLogClass *class = PURPLE_LOG_GET_CLASS(log);
+ PurpleLogReadFlags flags;
+ GError *error = NULL;
+ gchar *text;
- purple_log_ref(log);
+ if (class->read_fn == NULL) {
+ g_simple_async_result_set_error(simple, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported"));
- if (log->logger->async->read_async)
- (log->logger->async->read_async)(log, flags,
- io_priority, cancellable, log_read_cb, callback_data);
- else if (log->logger->read) {
- read = (log->logger->read)(log, flags);
+ return;
+ }
- simple = g_simple_async_result_new(NULL, log_read_cb, callback_data,
- purple_log_read_async);
+ text = class->read_fn(log, &flags, cancellable, &error);
- g_simple_async_result_set_op_res_gpointer(simple, read, g_free);
- g_simple_async_result_complete_in_idle(simple);
+ if (text == NULL)
+ g_simple_async_result_set_from_error(simple, error);
+ else {
+ _purple_log_read_res_callback_data *res_data;
- g_object_unref(simple);
- } else {
- simple = g_simple_async_result_new_error(NULL, log_read_cb, callback_data,
- G_IO_ERROR, G_IO_ERROR_FAILED, "<font color=\"red\"><b>%s</b></font>",
- _("The logger has no read function"));
+ res_data = g_new0(_purple_log_read_res_callback_data, 1);
+ res_data->flags = flags;
+ res_data->text = text;
- g_simple_async_result_complete_in_idle(simple);
+ g_simple_async_result_set_op_res_gpointer(simple, res_data, log_read_res_free);
+ }
- g_object_unref(simple);
- }
+ g_clear_error(&error);
}
-gchar *
-purple_log_read_finish(PurpleLog *log, GAsyncResult *res, GError **error)
+static void
+purple_log_real_read_async(PurpleLog *log, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
{
GSimpleAsyncResult *simple;
+ simple = g_simple_async_result_new(G_OBJECT(log), cb, userdata,
+ purple_log_real_read_async);
+
+ g_simple_async_result_run_in_thread(simple, read_thread, io_priority, cancellable);
+ g_object_unref(simple);
+}
+
+void
+purple_log_read_async(PurpleLog *log, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
+{
+ g_return_if_fail(PURPLE_IS_LOG(log));
+
+ PURPLE_LOG_GET_CLASS(log)->read_async(log,
+ io_priority, cancellable, cb, userdata);
+}
+
+static gchar *
+purple_log_real_read_finish(PurpleLog *log, GAsyncResult *res, PurpleLogReadFlags *flags, GError **error)
+{
+ _purple_log_read_res_callback_data *res_data;
+ GSimpleAsyncResult *simple;
+
simple = G_SIMPLE_ASYNC_RESULT(res);
+ res_data = g_simple_async_result_get_op_res_gpointer(simple);
- if (g_simple_async_result_propagate_error(simple, error))
- return NULL;
+ if (flags != NULL)
+ *flags = res_data->flags;
- g_return_val_if_fail(g_simple_async_result_get_source_tag(simple) == purple_log_read_async, NULL);
+ return res_data->text;
+}
- return g_simple_async_result_get_op_res_gpointer(simple);
+gchar *
+purple_log_read_finish(PurpleLog *log, GAsyncResult *res, PurpleLogReadFlags *flags, GError **error)
+{
+ g_return_val_if_fail(PURPLE_IS_LOG(log), NULL);
+ g_return_val_if_fail(G_IS_ASYNC_RESULT(res), NULL);
+
+ if (G_IS_SIMPLE_ASYNC_RESULT(res)) {
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT(res);
+
+ if (g_simple_async_result_propagate_error(simple, error))
+ return NULL;
+ }
+
+ return PURPLE_LOG_GET_CLASS(log)->read_finish(log, res, flags, error);
}
-gint
-purple_log_get_size(PurpleLog *log)
+gssize
+purple_log_get_size(PurpleLog *log, GCancellable *cancellable, GError **error)
{
- g_return_val_if_fail(log != NULL, 0);
- g_return_val_if_fail(log->logger != NULL, 0);
+ PurpleLogClass *class;
- if (log->logger->size)
- return (log->logger->size)(log);
+ g_return_val_if_fail(PURPLE_IS_LOG(log), 0);
- return 0;
+ class = PURPLE_LOG_GET_CLASS(log);
+
+ if (class->size_fn == NULL) {
+ g_set_error_literal(error,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported"));
+
+ return -1;
+ }
+
+ return class->size_fn(log, cancellable, error);
}
-void
-purple_log_get_size_async(PurpleLog *log, gint io_priority, GCancellable *cancellable,
- GAsyncReadyCallback cb, gpointer userdata)
+static void
+size_thread(GSimpleAsyncResult *simple, GObject *object, GCancellable *cancellable)
{
- _purple_log_size_callback_data *callback_data;
- GSimpleAsyncResult *simple;
+ PurpleLog *log = PURPLE_LOG(object);
+ PurpleLogClass *class = PURPLE_LOG_GET_CLASS(log);
+ GError *error = NULL;
+ gssize size;
- g_return_if_fail(log != NULL);
- g_return_if_fail(log->logger != NULL);
+ if (class->size_fn == NULL) {
+ g_simple_async_result_set_error(simple, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported"));
- callback_data = g_new0(_purple_log_size_callback_data, 1);
- callback_data->cb = cb;
- callback_data->userdata = userdata;
- callback_data->log = log;
+ return;
+ }
- purple_log_ref(log);
+ size = class->size_fn(log, cancellable, &error);
- if (log->logger->async->size_async)
- (log->logger->async->size_async)(log, io_priority, cancellable,
- log_size_cb, callback_data);
- else if (log->logger->size) {
- gssize size = (log->logger->size)(log);
+ if (size < 0)
+ g_simple_async_result_set_from_error(simple, error);
+ else
+ g_simple_async_result_set_op_res_gssize(simple, size);
- simple = g_simple_async_result_new(NULL, log_size_cb, callback_data,
- purple_log_get_size_async);
+ g_clear_error(&error);
+}
- g_simple_async_result_set_op_res_gssize(simple, size);
- g_simple_async_result_complete_in_idle(simple);
+static void
+purple_log_real_size_async(PurpleLog *log, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
+{
+ GSimpleAsyncResult *simple;
- g_object_unref(simple);
- } else {
- simple = g_simple_async_result_new_error(NULL, log_size_cb, callback_data,
- G_IO_ERROR, G_IO_ERROR_FAILED, _("Logger has no get-size function"));
+ simple = g_simple_async_result_new(G_OBJECT(log), cb, userdata,
+ purple_log_real_size_async);
- g_simple_async_result_complete_in_idle(simple);
+ g_simple_async_result_run_in_thread(simple, size_thread, io_priority, cancellable);
+ g_object_unref(simple);
+}
- g_object_unref(simple);
- }
+void
+purple_log_get_size_async(PurpleLog *log, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
+{
+ g_return_if_fail(PURPLE_IS_LOG(log));
+
+ PURPLE_LOG_GET_CLASS(log)->size_async(log, io_priority, cancellable, cb, userdata);
}
+static gssize
+purple_log_real_size_finish(PurpleLog *log, GAsyncResult *res, GError **error)
+{
+ return g_simple_async_result_get_op_res_gssize(G_SIMPLE_ASYNC_RESULT(res));
+}
+
gssize
purple_log_get_size_finish(PurpleLog *log, GAsyncResult *res, GError **error)
{
- return purple_log_common_sizer_finish(log, res, error);
+ g_return_val_if_fail(PURPLE_IS_LOG(log), -1);
+ g_return_val_if_fail(G_IS_ASYNC_RESULT(res), -1);
+
+ if (G_IS_SIMPLE_ASYNC_RESULT(res)) {
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT(res);
+
+ if (g_simple_async_result_propagate_error(simple, error))
+ return -1;
+ }
+
+ return PURPLE_LOG_GET_CLASS(log)->size_finish(log, res, error);
}
static guint
@@ -700,14 +1082,13 @@ _purple_logsize_user_free_key(_purple_lo
g_free(lu);
}
-gint
-purple_log_get_total_size(PurpleLogType type, const gchar *name, PurpleAccount *account)
+gssize
+purple_logs_get_total_size(PurpleLogChatType chat_type, const gchar *name, PurpleAccount *account, GCancellable *cancellable, GError **error)
{
_purple_logsize_user *lu;
- GSList *n;
gpointer ptrsize;
gboolean result;
- gint size = 0;
+ gssize size = 0, total = 0;
g_return_val_if_fail(name != NULL, 0);
g_return_val_if_fail(account != NULL, 0);
@@ -720,41 +1101,147 @@ purple_log_get_total_size(PurpleLogType
result = g_hash_table_lookup_extended(logsize_users, lu, NULL, &ptrsize);
G_UNLOCK(logsize_users);
- if(result) {
- size = GPOINTER_TO_INT(ptrsize);
- purple_debug_info("log", "HASH(purple_log_get_total_size): using size from hash %i {name = \"%s\"\n}", size, name);
+ if (result) {
+ total = GPOINTER_TO_INT(ptrsize);
+ // purple_debug_info("log", "HASH(purple_log_get_total_size): using size from hash %i {name = \"%s\"\n}", size, name);
g_free(lu->name);
g_free(lu);
} else {
- for (n = purple_log_logger_get_all(); n; n = g_slist_next(n)) {
- PurpleLogLogger *logger = n->data;
+ GArray *array = purple_log_logger_get_all();
+ guint i;
- if(logger->total_size){
- size += (logger->total_size)(type, name, account);
- } else if(logger->list) {
- GList *logs = (logger->list)(type, name, account);
+ for (i = 0; i < array->len; i++) {
+ PurpleLogClass *class;
+ GType log_type = g_array_index(array, GType, i);
+ class = g_type_class_peek(log_type);
+
+ if (class->total_size_fn){
+ size = class->total_size_fn(chat_type, name, account, cancellable, error);
+
+ if (size < 0)
+ return -1;
+
+ total += size;
+ } else {
+ GList *logs = purple_logs_get_logs(chat_type, name, account, cancellable, error);
+
+ if (logs == NULL)
+ return -1;
+
for ( ; logs != NULL; logs = g_list_delete_link(logs, logs)) {
PurpleLog *log = logs->data;
- size += purple_log_get_size(log);
- purple_log_free(log);
+
+ size = purple_log_get_size(log, cancellable, error);
+
+ if (size < 0) {
+ for ( ; logs != NULL; logs = g_list_delete_link(logs, logs))
+ g_object_unref(logs->data);
+
+ return -1;
+ }
+
+ total += size;
+ g_object_unref(log);
}
}
}
- purple_debug_info("log", "HASH(purple_log_get_total_size): write size to hash %i {name = \"%s\"\n}", size, name);
+ // purple_debug_info("log", "HASH(purple_log_get_total_size): write size to hash %i {name = \"%s\"\n}", total, name);
G_LOCK(logsize_users);
- g_hash_table_replace(logsize_users, lu, GINT_TO_POINTER(size));
+ g_hash_table_replace(logsize_users, lu, GINT_TO_POINTER(total));
G_LOCK(logsize_users);
}
- return size;
+ return total;
}
+static void
+total_size_thread(GSimpleAsyncResult *simple, GObject *object, GCancellable *cancellable)
+{
+ _thread_callback_data *callback_data =
+ g_simple_async_result_get_op_res_gpointer(simple);
+ PurpleAccount *account = callback_data->account; // g_object_unref
+ PurpleLog *log = PURPLE_LOG(object);
+ PurpleLogClass *class = PURPLE_LOG_GET_CLASS(log);
+ PurpleLogChatType chat_type = callback_data->chat_type;
+ GError *error = NULL;
+ gchar *name = callback_data->name;
+ gssize size;
+
+ if (class->total_size_fn != NULL) {
+ size = class->total_size_fn(chat_type, name, account, 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);
+ } else if (class->list_fn != NULL) {
+ /* List the logs and manually size them all up */
+ GList *logs = purple_logs_get_logs(chat_type, name, account, cancellable, &error);
+ gssize total;
+
+ if (logs == NULL) {
+ g_simple_async_result_set_from_error(simple, error);
+ return;
+ }
+
+ g_clear_error(&error);
+
+ for (total = 0; logs != NULL; logs = g_list_delete_link(logs, logs)) {
+ PurpleLog *log_to_size = logs->data;
+
+ size = purple_log_get_size(log_to_size, cancellable, &error);
+
+ if (size < 0) {
+ g_simple_async_result_set_from_error(simple, error);
+
+ for ( ; logs != NULL; logs = g_list_delete_link(logs, logs))
+ g_object_unref(logs->data);
+
+ return;
+ }
+
+ total += size;
+
+ g_object_unref(log_to_size);
+ g_clear_error(&error);
+ }
+
+ g_simple_async_result_set_op_res_gssize(simple, total);
+ } else {
+ g_simple_async_result_set_error(simple, G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED, _("Operation not supported"));
+
+ return;
+ }
+}
+
+static void
+purple_log_real_total_size_async(PurpleLog *log, PurpleLogChatType chat_type, const gchar *name, PurpleAccount *account, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
+{
+ _thread_callback_data *callback_data;
+ GSimpleAsyncResult *simple;
+
+ callback_data = g_new0(_thread_callback_data, 1);
+ callback_data->chat_type = chat_type;
+ callback_data->name = g_strdup(name);
+ callback_data->account = account; // g_object_ref
+
+ simple = g_simple_async_result_new(G_OBJECT(log), cb, userdata,
+ purple_log_real_total_size_async);
+
+ g_simple_async_result_set_op_res_gpointer(simple, callback_data, thread_callback_data_free);
+ g_simple_async_result_run_in_thread(simple, total_size_thread, io_priority, cancellable);
+ g_object_unref(simple);
+}
+
// TODO: Would it make sense to allow the caller to pass in a list of logs, if
-// TODO: it just got them from purple_log_get_logs_async()? Pidgin asks
+// TODO: it just got them from purple_logs_get_logs_async()? Pidgin asks
// TODO: for the total size, which means that for some loggers, we end up
// TODO: calling list *again* needlessly (to loop over them and size them).
// TODO: If we had a list of logs, we could loop over them and find those
@@ -765,16 +1252,16 @@ void
// TODO: if (!log->logger->total_size && log->logger->size)
// TODO: Call the size function.
void
-purple_log_get_total_size_async(PurpleLogType type, const gchar *name, PurpleAccount *account,
- gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
+purple_logs_get_total_size_async(PurpleLogChatType chat_type, const gchar *name, PurpleAccount *account, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
{
_purple_log_total_size_callback_data *callback_data;
_purple_logsize_user *lu;
GSimpleAsyncResult *simple;
- GSList *n;
+ GArray *array;
gpointer ptrsize;
gboolean result;
gssize size = 0;
+ guint i;
g_return_if_fail(name != NULL);
g_return_if_fail(account != NULL);
@@ -786,12 +1273,12 @@ purple_log_get_total_size_async(PurpleLo
callback_data = g_new0(_purple_log_total_size_callback_data, 1);
callback_data->cb = cb;
callback_data->userdata = userdata;
- callback_data->total = 0;
G_LOCK(logsize_users);
result = g_hash_table_lookup_extended(logsize_users, lu, NULL, &ptrsize);
G_UNLOCK(logsize_users);
+ // Fix this up?
if (result) {
size = GPOINTER_TO_INT(ptrsize);
@@ -800,7 +1287,7 @@ purple_log_get_total_size_async(PurpleLo
callback_data->counter = 1;
- simple = g_simple_async_result_new(NULL, log_total_size_list_cb,
+ simple = g_simple_async_result_new(NULL, log_total_size_cb,
callback_data, purple_log_common_total_sizer_async);
g_simple_async_result_set_op_res_gssize(simple, size);
@@ -814,75 +1301,53 @@ purple_log_get_total_size_async(PurpleLo
g_free(lu->name);
g_free(lu);
- n = purple_log_logger_get_all();
- callback_data->counter = g_slist_length(n);
- callback_data->cancellable = g_object_ref(cancellable);
- callback_data->io_priority = io_priority;
+ array = purple_log_logger_get_all();
+ callback_data->counter = array->len;
+ callback_data->total = 0;
- for ( ; n; n = g_slist_next(n)) {
- PurpleLogLogger *logger = n->data;
+ for (i = 0; i < array->len; i++) {
+ PurpleLog *log;
+ GType log_type = g_array_index(array, GType, i);
- if (logger->async->total_size_async)
- (logger->async->total_size_async)(type, name, account, io_priority,
- cancellable, log_total_size_cb, callback_data);
- else if (logger->async->list_async)
- /* List the logs and manually size them all up */
- (logger->async->list_async)(type, name, account, io_priority,
- cancellable, log_total_size_list_cb, callback_data);
- else if (logger->total_size) {
- size = (logger->total_size)(type, name, account);
+ log = g_object_new(log_type, NULL);
- simple = g_simple_async_result_new(NULL, log_total_size_cb, callback_data,
- purple_log_common_total_sizer_async);
+ PURPLE_LOG_GET_CLASS(log)->total_size_async(log, chat_type, name, account, io_priority, cancellable, log_total_size_cb, callback_data);
+ }
+}
- g_simple_async_result_set_op_res_gssize(simple, size);
- g_simple_async_result_complete_in_idle(simple);
+static gssize
+purple_log_real_total_size_finish(PurpleLog *log, GAsyncResult *res, GError **error)
+{
+ return g_simple_async_result_get_op_res_gssize(G_SIMPLE_ASYNC_RESULT(res));
+}
- g_object_unref(simple);
- } else if (logger->list) {
- /* List the logs and manually size them all up */
- GList *logs = (logger->list)(type, name, account);
+gssize
+purple_log_get_total_size_finish(PurpleLog *log, GAsyncResult *res, GError **error)
+{
+ g_return_val_if_fail(PURPLE_IS_LOG(log), -1);
+ g_return_val_if_fail(G_IS_ASYNC_RESULT(res), -1);
- simple = g_simple_async_result_new(NULL, log_total_size_list_cb, callback_data,
- purple_log_common_lister_async);
+ if (G_IS_SIMPLE_ASYNC_RESULT(res)) {
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT(res);
- g_simple_async_result_set_op_res_gpointer(simple, logs, (GDestroyNotify) g_list_free);
- g_simple_async_result_complete_in_idle(simple);
-
- g_object_unref(simple);
- } else {
- simple = g_simple_async_result_new_error(NULL, log_total_size_list_cb, callback_data,
- G_IO_ERROR, G_IO_ERROR_FAILED, _("Logger has no get-size or list function"));
-
- g_simple_async_result_complete_in_idle(simple);
-
- g_object_unref(simple);
- }
+ if (g_simple_async_result_propagate_error(simple, error))
+ return -1;
}
-}
-gssize
-purple_log_get_total_size_finish(GAsyncResult *res, GError **error)
-{
- return purple_log_common_total_sizer_finish(res, &err);
+ return PURPLE_LOG_GET_CLASS(log)->total_size_finish(log, res, error);
}
-gint
-purple_log_get_activity_score(PurpleLogType type, const gchar *name, PurpleAccount *account)
+gssize
+purple_log_get_activity_score(PurpleLogChatType chat_type, const gchar *name, PurpleAccount *account, GCancellable *cancellable, GError **error)
{
_purple_logsize_user *lu;
- PurpleLogLogger *logger;
- PurpleLog *log;
- GList *logs;
- GSList *n;
gpointer ptrscore;
time_t now;
gboolean result;
- gdouble score_double;
gint score;
- g_return_val_if_fail(name != NULL, 0);
- g_return_val_if_fail(account != NULL, 0);
+ g_return_val_if_fail(name != NULL, -1);
+ g_return_val_if_fail(account != NULL, -1); //PURPLE_IS_ACCOUNT(account)
time(&now);
@@ -899,23 +1364,37 @@ purple_log_get_activity_score(PurpleLogT
g_free(lu->name);
g_free(lu);
} else {
- score_double = 0.0;
+ GArray *array = purple_log_logger_get_all();
+ gdouble score_double = 0.0;
+ guint i;
- for (n = purple_log_logger_get_all(); n; n = g_slist_next(n)) {
- logger = n->data;
+ for (i = 0; i < array->len; i++) {
+ GList *logs;
- if(logger->list) {
- logs = (logger->list)(type, name, account);
+ logs = purple_logs_get_logs(chat_type, name, account, cancellable, error);
- while (logs) {
- log = logs->data;
- /* Activity score counts bytes in the log, exponentially
- decayed with a half-life of 14 days. */
- score_double += purple_log_get_size(log) *
- pow(0.5, difftime(now, log->time)/1209600.0);
- purple_log_free(log);
- logs = g_list_delete_link(logs, logs);
+ if (logs == NULL)
+ return -1;
+
+ for ( ; logs != NULL; logs = g_list_delete_link(logs, logs)) {
+ PurpleLog *log = PURPLE_LOG(logs->data);
+ gssize size;
+ time_t log_time;
+
+ size = purple_log_get_size(log, cancellable, error);
+
+ if (size < 0) {
+ for ( ; logs != NULL; logs = g_list_delete_link(logs, logs))
+ g_object_unref(logs->data);
+
+ return -1;
}
+
+ /* Activity score counts bytes in the log, exponentially
+ decayed with a half-life of 14 days. */
+ log_time = purple_log_get_time(log);
+ score_double += size * pow(0.5, difftime(now, log_time) / 1209600.0);
+ g_object_unref(log);
}
}
@@ -929,57 +1408,45 @@ purple_log_get_activity_score(PurpleLogT
return score;
}
-void
-purple_log_get_activity_score_async(PurpleLogType type, const gchar *name, PurpleAccount *account,
- gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
+static void
+activity_score_thread(GSimpleAsyncResult *simple, GObject *object, GCancellable *cancellable)
{
- _purple_log_activity_score_data *callback_data;
- _purple_logsize_user *lu;
- GSimpleAsyncResult *simple;
- gpointer ptrscore;
- gint score;
- gboolean result;
+ _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;
+ gssize score;
- g_return_if_fail(name != NULL);
- g_return_if_fail(account != NULL);
+ score = purple_log_get_activity_score(chat_type, name, account, cancellable, &error);
- lu = g_new(_purple_logsize_user, 1);
- lu->name = g_strdup(purple_normalize(account, name));
- lu->account = account; //g_object_ref?
-
- G_LOCK(logsize_users_decayed);
- result = g_hash_table_lookup_extended(logsize_users_decayed, lu, NULL, &ptrscore);
- G_UNLOCK(logsize_users_decayed);
-
- if (result) {
- score = GPOINTER_TO_INT(ptrscore);
-
- g_free(lu->name);
- g_free(lu);
-
- simple = g_simple_async_result_new(NULL, cb,
- userdata, purple_log_get_activity_score_async);
-
+ if (score < 0)
+ g_simple_async_result_set_from_error(simple, error);
+ else
g_simple_async_result_set_op_res_gssize(simple, score);
- g_simple_async_result_complete_in_idle(simple);
- g_object_unref(simple);
+ g_clear_error(&error);
+}
- return;
- }
+void
+purple_log_get_activity_score_async(PurpleLogChatType chat_type, const gchar *name, PurpleAccount *account,
+ gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
+{
+ _thread_callback_data *callback_data;
+ GSimpleAsyncResult *simple;
- callback_data = g_new0(_purple_log_activity_score_data, 1);
- callback_data->cb = cb;
- callback_data->userdata = userdata;
- callback_data->lu = lu;
- callback_data->cancel = cancellable;
- callback_data->io_priority = io_priority;
+ callback_data = g_new0(_thread_callback_data, 1);
+ callback_data->chat_type = chat_type;
+ callback_data->name = g_strdup(name);
+ callback_data->account = account; // g_object_ref
- if (cancellable != NULL)
- g_object_ref(cancellable);
+ simple = g_simple_async_result_new(G_OBJECT(log), cb, userdata,
+ purple_log_get_activity_score_async);
- purple_log_get_logs_async(type, name, account, io_priority, cancellable,
- log_get_activity_score_cb, callback_data);
+ g_simple_async_result_set_op_res_gpointer(simple, callback_data, thread_callback_data_free);
+ g_simple_async_result_run_in_thread(simple, activity_score_thread, io_priority, cancellable);
+ g_object_unref(simple);
}
gint
@@ -998,85 +1465,119 @@ gboolean
}
gboolean
-purple_log_is_deletable(PurpleLog *log)
+purple_log_is_removable(PurpleLog *log, GCancellable *cancellable, GError **error)
{
- g_return_val_if_fail(log != NULL, FALSE);
- g_return_val_if_fail(log->logger != NULL, FALSE);
+ PurpleLogClass *class;
- if (log->logger->remove == NULL && log->logger->async->remove_async == NULL)
+ g_return_val_if_fail(PURPLE_IS_LOG(log), FALSE);
+
+ class = PURPLE_LOG_GET_CLASS(log);
+
+ if (class->remove_fn == NULL && class->remove_async == NULL) {
+ g_set_error_literal(error,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported"));
+
return FALSE;
+ }
- if (log->logger->is_deletable != NULL)
- return log->logger->is_deletable(log);
+ if (class->is_removable_fn != NULL)
+ return class->is_removable_fn(log, cancellable, error);
return TRUE;
}
gboolean
-purple_log_delete(PurpleLog *log)
+purple_log_remove(PurpleLog *log, GCancellable *cancellable, GError **error)
{
- g_return_val_if_fail(log != NULL, FALSE);
- g_return_val_if_fail(log->logger != NULL, FALSE);
+ PurpleLogClass *class;
+ gboolean ret;
- if (log->logger->remove != NULL)
- return log->logger->remove(log);
+ g_return_val_if_fail(PURPLE_IS_LOG(log), FALSE);
- return FALSE;
+ class = PURPLE_LOG_GET_CLASS(log);
+
+ if (class->remove_fn == NULL) {
+ g_set_error_literal(error,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported"));
+
+ return FALSE;
+ }
+
+ ret = class->remove_fn(log, cancellable, error);
+
+ return ret;
}
-void
-purple_log_delete_async(PurpleLog *log, gint io_priority, GCancellable *cancellable,
- GAsyncReadyCallback cb, gpointer userdata)
+static void
+remove_thread(GSimpleAsyncResult *simple, GObject *object, GCancellable *cancellable)
{
- _purple_log_delete_callback_data *callback_data;
- GSimpleAsyncResult *simple;
+ PurpleLog *log = PURPLE_LOG(object);
+ GError *error = NULL;
gboolean result;
- g_return_if_fail(log != NULL);
- g_return_if_fail(log->logger != NULL);
+ result = purple_log_remove(log, cancellable, &error);
- callback_data = g_new0(_purple_log_delete_callback_data, 1);
- callback_data->cb = cb;
- callback_data->userdata = userdata;
- callback_data->log = log;
+ if (!result)
+ g_simple_async_result_set_from_error(simple, error);
+ else
+ g_simple_async_result_set_op_res_gboolean(simple, result);
- if (log->logger->async->remove_async != NULL)
- (log->logger->async->remove_async)(log, io_priority, cancellable,
- log_delete_cb, callback_data);
- else {
- /* As there is no nonblocking function we can call blocking analog */
- result = FALSE;
+ g_clear_error(&error);
+}
- if (log->logger->remove != NULL)
- result = (log->logger->remove)(log);
+static void
+purple_log_real_remove_async(PurpleLog *log, gint io_priority, GCancellable *cancellable,
+ GAsyncReadyCallback cb, gpointer userdata)
+{
+ GSimpleAsyncResult *simple;
- simple = g_simple_async_result_new(NULL, cb, userdata, purple_log_delete_async);
+ g_return_if_fail(PURPLE_IS_LOG(log));
- g_simple_async_result_set_op_res_gboolean(simple, result);
- g_simple_async_result_complete_in_idle(simple);
+ simple = g_simple_async_result_new(G_OBJECT(log), cb, userdata,
+ purple_log_real_remove_async);
- g_object_unref(simple);
- }
+ g_simple_async_result_run_in_thread(simple, remove_thread, io_priority, cancellable);
+ g_object_unref(simple);
}
+void
+purple_log_remove_async(PurpleLog *log, gint io_priority, GCancellable *cancellable,
+ GAsyncReadyCallback cb, gpointer userdata)
+{
+ g_return_if_fail(PURPLE_IS_LOG(log));
+
+ PURPLE_LOG_GET_CLASS(log)->remove_async(log, io_priority,
+ cancellable, cb, userdata);
+}
+
+static gboolean
+purple_log_real_remove_finish(PurpleLog *log, GAsyncResult *res, GError **error)
+{
+ return g_simple_async_result_get_op_res_gboolean(G_SIMPLE_ASYNC_RESULT(res));
+}
+
gboolean
-purple_log_delete_finish(PurpleLog *log, GAsyncResult *res, GError **error)
+purple_log_remove_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_ASYNC_RESULT(res), -1);
- simple = G_SIMPLE_ASYNC_RESULT(res);
+ if (G_IS_SIMPLE_ASYNC_RESULT(res)) {
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT(res);
- if (g_simple_async_result_propagate_error(simple, error))
- return FALSE;
+ if (g_simple_async_result_propagate_error(simple, error))
+ return -1;
+ }
- if (g_simple_async_result_get_source_tag(simple) == purple_log_delete_async)
- return g_simple_async_result_get_op_res_gboolean(simple);
- else
- return purple_log_common_deleter_finish(log, res, error);
+ return PURPLE_LOG_GET_CLASS(log)->remove_finish(log, res, error);
}
gchar *
-purple_log_get_log_dir(PurpleLogType type, const gchar *name, PurpleAccount *account)
+purple_log_get_log_dir(PurpleLogChatType chat_type, const gchar *name, PurpleAccount *account)
{
PurplePlugin *prpl;
PurplePluginProtocolInfo *prpl_info;
@@ -1097,11 +1598,11 @@ purple_log_get_log_dir(PurpleLogType typ
acct_name = g_strdup(purple_escape_filename(purple_normalize(account,
purple_account_get_username(account))));
- if (type == PURPLE_LOG_CHAT) {
+ if (chat_type == PURPLE_LOG_CHAT) {
temp = g_strdup_printf("%s.chat", purple_normalize(account, name));
target = purple_escape_filename(temp);
g_free(temp);
- } else if(type == PURPLE_LOG_SYSTEM) {
+ } else if (chat_type == PURPLE_LOG_SYSTEM) {
target = ".system";
} else {
target = purple_escape_filename(purple_normalize(account, name));
@@ -1124,180 +1625,126 @@ logger_pref_cb(const gchar *name, Purple
static void
logger_pref_cb(const gchar *name, PurplePrefType type, gconstpointer value, gpointer data)
{
- PurpleLogLogger *logger;
- GSList *l;
+ GArray *array;
+ guint i;
- for (l = purple_log_logger_get_all(); l; l = g_slist_next(l)) {
- logger = l->data;
+ array = purple_log_logger_get_all();
- if (purple_strequal(logger->id, value)) {
- purple_log_logger_set(logger);
+ for (i = 0; i < array->len; i++) {
+ PurpleLogClass *class;
+ GType log_type = g_array_index(array, GType, i);
+
+ class = g_type_class_peek(log_type);
+
+ if (purple_strequal(class->logger_id, value)) {
+ purple_log_logger_set(log_type);
return;
}
}
- G_LOCK(txt_logger);
- purple_log_logger_set(txt_logger);
- G_UNLOCK(txt_logger);
+ purple_log_logger_set(PURPLE_TYPE_TXT_LOG);
}
-
-PurpleLogLogger *
-purple_log_logger_new(const gchar *id, const gchar *name, gint functions, ...)
+void
+purple_log_logger_add(GType log_type)
{
- PurpleLogLogger *logger;
- va_list args;
+ PurpleLogClass *class;
+ guint i;
- g_return_val_if_fail(id != NULL, NULL);
- g_return_val_if_fail(name != NULL, NULL);
- g_return_val_if_fail(functions >= 1, NULL);
+ g_return_if_fail(log_type == G_TYPE_INVALID || g_type_is_a(log_type, PURPLE_TYPE_LOG));
- logger = g_new0(PurpleLogLogger, 1);
- logger->id = g_strdup(id);
- logger->name = g_strdup(name);
+ G_LOCK(loggers);
+ for (i = 0; i < loggers->len; i++) {
+ if (log_type == g_array_index(loggers, GType, i)) {
+ G_UNLOCK(loggers);
+ return;
+ }
+ }
- va_start(args, functions);
+ loggers = g_array_append_val(loggers, log_type);
+ G_UNLOCK(loggers);
- if (functions >= 1)
- logger->create = va_arg(args, void *);
- if (functions >= 2)
- logger->write = va_arg(args, void *);
- if (functions >= 3)
- logger->finalize = va_arg(args, void *);
- if (functions >= 4)
- logger->list = va_arg(args, void *);
- if (functions >= 5)
- logger->read = va_arg(args, void *);
- if (functions >= 6)
- logger->size = va_arg(args, void *);
- if (functions >= 7)
- logger->total_size = va_arg(args, void *);
- if (functions >= 8)
- logger->list_syslog = va_arg(args, void *);
- if (functions >= 9)
- logger->get_log_sets = va_arg(args, void *);
- if (functions >= 10)
- logger->remove = va_arg(args, void *);
- if (functions >= 11)
- logger->is_deletable = va_arg(args, void *);
+ class = g_type_class_ref(log_type);
- logger->async = g_new0(PurpleLogLoggerAsyncFuncs, 1);
-
- /* callbacks functions */
- if (functions >= 12)
- logger->async->create_async = va_arg(args, void *);
- if (functions >= 13)
- logger->async->write_async = va_arg(args, void *);
- if (functions >= 14)
- logger->async->finalize_async = va_arg(args, void *);
- if (functions >= 15)
- logger->async->list_async = va_arg(args, void *);
- if (functions >= 16)
- logger->async->read_async = va_arg(args, void *);
- if (functions >= 17)
- logger->async->size_async = va_arg(args, void *);
- if (functions >= 18)
- logger->async->total_size_async = va_arg(args, void *);
- if (functions >= 19)
- logger->async->list_syslog_async = va_arg(args, void *);
- if (functions >= 20)
- logger->async->get_log_sets_async = va_arg(args, void *);
- if (functions >= 21)
- logger->async->remove_async = va_arg(args, void *);
-
- if (functions >= 22)
- purple_debug_info("log", "Dropping new functions for logger: %s (%s)\n", name, id);
-
- va_end(args);
-
- return logger;
+ if (purple_strequal(purple_prefs_get_string("/purple/logging/format"), class->logger_id))
+ purple_prefs_trigger_callback("/purple/logging/format");
}
void
-purple_log_logger_free(PurpleLogLogger *logger)
+purple_log_logger_remove(GType log_type)
{
- g_return_if_fail(logger != NULL);
+ guint i;
- g_free(logger->name);
- g_free(logger->id);
- g_free(logger->async);
- g_free(logger);
-}
+ g_return_if_fail(log_type == G_TYPE_INVALID || g_type_is_a(log_type, PURPLE_TYPE_LOG));
-void
-purple_log_logger_add(PurpleLogLogger *logger)
-{
- g_return_if_fail(logger != NULL);
-
G_LOCK(loggers);
- if (g_slist_find(loggers, logger))
- return;
+ for (i = 0; i < loggers->len; i++) {
+ if (log_type == g_array_index(loggers, GType, i)) {
+ loggers = g_array_remove_index_fast(loggers, i);
+ g_type_class_unref(g_type_class_peek(log_type));
- loggers = g_slist_append(loggers, logger);
+ return;
+ }
+ }
G_UNLOCK(loggers);
- if (purple_strequal(purple_prefs_get_string("/purple/logging/format"), logger->id))
- purple_prefs_trigger_callback("/purple/logging/format");
+ //warning?
}
void
-purple_log_logger_remove(PurpleLogLogger *logger)
+purple_log_logger_set(GType log_type)
{
- g_return_if_fail(logger != NULL);
+ g_return_if_fail(log_type == G_TYPE_INVALID || g_type_is_a(log_type, PURPLE_TYPE_LOG));
- G_LOCK(loggers);
- loggers = g_slist_remove(loggers, logger);
- G_UNLOCK(loggers);
-}
-
-void
-purple_log_logger_set(PurpleLogLogger *logger)
-{
- g_return_if_fail(logger != NULL);
-
G_LOCK(current_logger);
- current_logger = logger;
+ current_logger = log_type;
G_UNLOCK(current_logger);
}
-PurpleLogLogger *
-purple_log_logger_get(void)
+GType
+purple_log_logger_get_default(void)
{
- PurpleLogLogger *logger;
+ GType log_type;
G_LOCK(current_logger);
- logger = current_logger;
+ log_type = current_logger;
G_UNLOCK(current_logger);
- return logger;
+ return log_type;
}
-GSList *
+GArray *
purple_log_logger_get_all(void)
{
- GSList *list;
+ GArray *array;
G_LOCK(loggers);
- list = loggers;
+ array = loggers;
G_UNLOCK(loggers);
- return list;
+ return array;
}
GList *
purple_log_logger_get_options(void)
{
- GSList *n;
+ GArray *array;
GList *list = NULL;
+ guint i;
- for (n = purple_log_logger_get_all(); n; n = g_slist_next(n)) {
- PurpleLogLogger *data = n->data;
+ array = purple_log_logger_get_all();
- if (!data->write && !data->async->write_async)
+ for (i = 0; i < array->len; i++) {
+ PurpleLogClass *class;
+ GType log_type = g_array_index(array, GType, i);
+
+ class = g_type_class_ref(log_type);
+
+ if (class->write_fn == NULL && class->write_async == NULL)
continue;
- list = g_list_append(list, data->name);
- list = g_list_append(list, data->id);
+ list = g_list_append(list, (void *) class->logger_name);
+ list = g_list_append(list, (void *) class->logger_id);
}
return list;
@@ -1308,95 +1755,167 @@ purple_log_compare(gconstpointer y, gcon
{
const PurpleLog *a = y, *b = z;
- return b->time - a->time;
+ return purple_log_get_time(b) - purple_log_get_time(a);
}
GList *
-purple_log_get_logs(PurpleLogType type, const gchar *name, PurpleAccount *account)
+purple_log_get_logs(PurpleLog *log, PurpleLogChatType chat_type, const gchar *name, PurpleAccount *account, GCancellable *cancellable, GError **error)
{
+ PurpleLogClass *class;
+
+ g_return_val_if_fail(PURPLE_IS_LOG(log), NULL);
+ g_return_val_if_fail(name != NULL, NULL);
+ g_return_val_if_fail(account != NULL, NULL); // PURPLE_IS_ACCOUNT(account)
+
+ class = PURPLE_LOG_GET_CLASS(log);
+
+ if (class->list_fn == NULL) {
+ g_set_error_literal(error,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported"));
+
+ return NULL;
+ }
+
+ return class->list_fn(log, chat_type, name, account, cancellable, error);
+}
+
+GList *
+purple_logs_get_logs(PurpleLogChatType chat_type, const gchar *name, PurpleAccount *account, GCancellable *cancellable, GError **error)
+{
+ GArray *array;
GList *logs = NULL;
- GSList *n;
+ guint i;
g_return_val_if_fail(name != NULL, NULL);
- g_return_val_if_fail(account != NULL, NULL);
+ g_return_val_if_fail(account != NULL, NULL); // PURPLE_IS_ACCOUNT(account)
- for (n = purple_log_logger_get_all(); n; n = g_slist_next(n)) {
- PurpleLogLogger *logger = n->data;
+ array = purple_log_logger_get_all();
- if (!logger->list)
- continue;
+ for (i = 0; i < array->len; i++) {
+ PurpleLog *log;
+ GList *list;
+ GType log_type = g_array_index(array, GType, i);
- logs = g_list_concat(logger->list(type, name, account), logs);
+ log = g_object_new(log_type, NULL);
+ list = purple_log_get_logs(log, chat_type, name, account, cancellable, error);
+
+ if (list == NULL) {
+ for ( ; logs != NULL; logs = g_list_delete_link(logs, logs))
+ g_object_unref(logs->data);
+
+ g_object_unref(log);
+
+ return NULL;
+ }
+
+ logs = g_list_concat(list, logs);
+ g_object_unref(log);
}
return g_list_sort(logs, purple_log_compare);
}
-void
-purple_log_get_logs_async(PurpleLogType type, const gchar *name, PurpleAccount *account,
- gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
+static void
+get_logs_thread(GSimpleAsyncResult *simple, GObject *object, GCancellable *cancellable)
{
- _purple_log_logs_callback_data *callback_data;
+ _thread_callback_data *callback_data =
+ g_simple_async_result_get_op_res_gpointer(simple);
+ PurpleAccount *account = callback_data->account; // g_object_unref
+ PurpleLog *log = PURPLE_LOG(object);
+ PurpleLogChatType chat_type = callback_data->chat_type;
+ GError *error = NULL;
+ GList *logs;
+ gchar *name = callback_data->name;
+
+ logs = purple_log_get_logs(log, chat_type, name, account, cancellable, &error);
+
+ if (logs == NULL)
+ g_simple_async_result_set_from_error(simple, error);
+ else
+ g_simple_async_result_set_op_res_gpointer(simple, logs, NULL);
+
+ g_clear_error(&error);
+}
+
+static void
+purple_log_real_get_logs_async(PurpleLog *log, PurpleLogChatType chat_type, const gchar *name, PurpleAccount *account, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
+{
+ _thread_callback_data *callback_data;
GSimpleAsyncResult *simple;
- GSList *n;
- g_return_if_fail(name != NULL);
- g_return_if_fail(account != NULL);
+ callback_data = g_new0(_thread_callback_data, 1);
+ callback_data->chat_type = chat_type;
+ callback_data->name = g_strdup(name);
+ callback_data->account = account; // g_object_ref
- n = purple_log_logger_get_all();
+ simple = g_simple_async_result_new(G_OBJECT(log), cb, userdata,
+ purple_log_real_get_logs_async);
- callback_data = g_new0(_purple_log_logs_callback_data, 1);
- callback_data->cb = cb;
- callback_data->userdata = userdata;
- callback_data->counter = g_slist_length(n);
- callback_data->logs = NULL;
+ g_simple_async_result_set_op_res_gpointer(simple, callback_data, thread_callback_data_free);
+ g_simple_async_result_run_in_thread(simple, get_logs_thread, io_priority, cancellable);
+ g_object_unref(simple);
+}
- for ( ; n; n = g_slist_next(n)) {
- PurpleLogLogger *logger = n->data;
+void
+purple_log_get_logs_async(PurpleLog *log, PurpleLogChatType chat_type, const gchar *name, PurpleAccount *account, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
+{
+ g_return_if_fail(PURPLE_IS_LOG(log));
+ g_return_if_fail(name != NULL);
+ g_return_if_fail(account != NULL); // PURPLE_IS_ACCOUNT(account)
- if (logger->async->list_async)
- (logger->async->list_async)(type, name, account, io_priority, cancellable,
- log_list_cb, callback_data);
- else if (logger->list) {
- /* Call the blocking list function instead. */
- GList *logs = (logger->list)(type, name, account);
+ PURPLE_LOG_GET_CLASS(log)->list_async(log, chat_type, name, account, io_priority, cancellable, cb, userdata);
+}
- simple = g_simple_async_result_new(NULL,
- log_list_cb,
- callback_data,
- purple_log_common_lister_async);
- g_simple_async_result_set_op_res_gpointer(simple, logs, NULL);
+void
+purple_logs_get_logs_async(PurpleLogChatType chat_type, const gchar *name, PurpleAccount *account, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
+{
+ _get_logs_callback_data *callback_data;
+ GArray *array;
+ guint i;
- g_simple_async_result_complete_in_idle(simple);
+ g_return_if_fail(name != NULL);
+ g_return_if_fail(account != NULL); // PURPLE_IS_ACCOUNT(account)
- g_object_unref(simple);
- } else {
- simple = g_simple_async_result_new_error(NULL, log_list_cb,
- callback_data,
- G_FILE_ERROR,
- G_FILE_ERROR_FAILED,
- _("No available non-blocking log-getting function"));
+ array = purple_log_logger_get_all();
- g_simple_async_result_complete_in_idle(simple);
+ callback_data = g_new0(_get_logs_callback_data, 1);
+ callback_data->cb = cb;
+ callback_data->userdata = userdata;
+ callback_data->counter = array->len;
+ callback_data->logs = NULL;
- g_object_unref(simple);
- }
+ for (i = 0; i < array->len; i++) {
+ PurpleLog *log;
+ GType log_type = g_array_index(array, GType, i);
+
+ log = g_object_new(log_type, NULL);
+ purple_log_get_logs_async(log, chat_type, name, account, io_priority, cancellable, log_list_cb, callback_data);
+ g_object_unref(log);
}
}
+static GList *
+purple_log_real_get_logs_finish(PurpleLog *log, GAsyncResult *res, GError **error)
+{
+ return g_simple_async_result_get_op_res_gpointer(G_SIMPLE_ASYNC_RESULT(res));
+}
+
GList *
-purple_log_get_logs_finish(GAsyncResult *res, GError **error)
+purple_log_get_logs_finish(PurpleLog *log, GAsyncResult *res, GError **error)
{
- GSimpleAsyncResult *simple;
+ g_return_val_if_fail(PURPLE_IS_LOG(log), NULL);
+ g_return_val_if_fail(G_IS_ASYNC_RESULT(res), NULL);
- simple = G_SIMPLE_ASYNC_RESULT(res);
+ if (G_IS_SIMPLE_ASYNC_RESULT(res)) {
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT(res);
- if (g_simple_async_result_propagate_error(simple, error))
- return NULL;
+ 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);
+ return PURPLE_LOG_GET_CLASS(log)->list_finish(log, res, error);
}
gint
@@ -1458,94 +1977,189 @@ log_add_log_set_to_hash(GHashTable *sets
purple_log_set_free(set);
}
+static gboolean
+steal_log_sets(gpointer key, gpointer value, gpointer sets)
+{
+ log_add_log_set_to_hash(sets, key);
+ return TRUE;
+}
+
GHashTable *
-purple_log_get_log_sets(void)
+purple_log_get_log_sets(PurpleLog *log, GCancellable *cancellable, GError **error)
{
- GHashTable *sets;
- GSList *n;
+ PurpleLogClass *class;
+ g_return_val_if_fail(PURPLE_IS_LOG(log), NULL);
+
+ class = PURPLE_LOG_GET_CLASS(log);
+
+ if (class->get_log_sets_fn == NULL) {
+ g_set_error_literal(error,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported"));
+
+ return NULL;
+ }
+
+ return class->get_log_sets_fn(log, cancellable, error);
+}
+
+GHashTable *
+purple_logs_get_log_sets(GCancellable *cancellable, GError **error)
+{
+ GArray *array;
+ GHashTable *sets, *one_set;
+ GError *err = NULL;
+ guint i;
+
sets = g_hash_table_new_full(log_set_hash, log_set_equal,
(GDestroyNotify) purple_log_set_free, NULL);
- /* Get the log sets from all the loggers. */
- for (n = purple_log_logger_get_all(); n; n = g_slist_next(n)) {
- PurpleLogLogger *logger = n->data;
+ array = purple_log_logger_get_all();
- if (!logger->get_log_sets)
- continue;
+ for (i = 0; i < array->len; i++) {
+ PurpleLog *log;
+ GType log_type = g_array_index(array, GType, i);
- logger->get_log_sets(log_add_log_set_to_hash, sets);
+ log = g_object_new(log_type, NULL);
+ purple_log_get_log_sets(log, cancellable, &err);
+
+ if (one_set == NULL) {
+ g_object_unref(log);
+
+ if (err->code == G_IO_ERROR_NOT_SUPPORTED) {
+ g_clear_error(&err);
+ continue;
+ } else {
+ g_propagate_error(error, err);
+ g_hash_table_destroy(sets);
+ return NULL;
+ }
+ }
+
+ g_hash_table_foreach_steal(one_set, steal_log_sets, sets);
+ g_hash_table_destroy(one_set);
+ g_object_unref(log);
}
- log_get_log_sets_common(sets, NULL, log_add_log_set_to_hash, NULL);
+ one_set = log_get_log_sets_common(cancellable, error);
+ if (one_set == NULL) {
+ g_hash_table_destroy(sets);
+ return NULL;
+ }
+
+ g_hash_table_foreach_steal(one_set, steal_log_sets, sets);
+ g_hash_table_destroy(one_set);
+
/* Return the GHashTable of unique PurpleLogSets. */
return sets;
}
+static void
+get_log_sets_thread(GSimpleAsyncResult *simple, GObject *object, GCancellable *cancellable)
+{
+ PurpleLog *log = PURPLE_LOG(object);
+ PurpleLogClass *class = PURPLE_LOG_GET_CLASS(log);
+ GError *error = NULL;
+ GHashTable *sets;
+
+ if (class->get_log_sets_fn == NULL) {
+ g_simple_async_result_set_error(simple, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported"));
+
+ return;
+ }
+
+ sets = class->get_log_sets_fn(log, cancellable, &error);
+
+ if (sets == NULL)
+ g_simple_async_result_set_from_error(simple, error);
+ else
+ g_simple_async_result_set_op_res_gpointer(simple, sets, (GDestroyNotify) g_hash_table_unref);
+
+ g_clear_error(&error);
+}
+
+static void
+purple_log_real_get_log_sets_async(PurpleLog *log, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
+{
+ GSimpleAsyncResult *simple;
+
+ simple = g_simple_async_result_new(G_OBJECT(log), cb, userdata,
+ purple_log_real_get_log_sets_async);
+
+ g_simple_async_result_run_in_thread(simple, get_log_sets_thread, io_priority, cancellable);
+ g_object_unref(simple);
+}
+
void
-purple_log_get_log_sets_async(gint io_priority, GCancellable *cancellable,
+purple_log_get_log_sets_async(PurpleLog *log, gint io_priority,
+ GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
+{
+ g_return_if_fail(PURPLE_IS_LOG(log));
+
+ PURPLE_LOG_GET_CLASS(log)->get_log_sets_async(log,
+ io_priority, cancellable, cb, userdata);
+}
+
+void
+purple_logs_get_log_sets_async(gint io_priority, GCancellable *cancellable,
GAsyncReadyCallback cb, gpointer userdata)
{
_purple_log_sets_callback_data *callback_data;
- GSList *n;
+ GArray *array;
+ guint i;
callback_data = g_new0(_purple_log_sets_callback_data, 1);
callback_data->cb = cb;
- callback_data->mutex = g_mutex_new();
callback_data->userdata = userdata;
callback_data->sets = g_hash_table_new_full(log_set_hash, log_set_equal,
(GDestroyNotify) purple_log_set_free, NULL);
/* +1 is need special for log_get_log_sets_common_async call */
- n = purple_log_logger_get_all();
- callback_data->counter = g_slist_length(n) + 1;
+ array = purple_log_logger_get_all();
+ callback_data->counter = array->len + 1;
/* Get the log sets from all the loggers. */
- for ( ; n; n = g_slist_next(n)) {
- PurpleLogLogger *logger = n->data;
+ for (i = 0; i < array->len; i++) {
+ PurpleLog *log;
+ GType log_type = g_array_index(array, GType, i);
- if (logger->async->get_log_sets_async)
- (logger->async->get_log_sets_async)(log_add_log_set_to_hash, callback_data->sets,
- io_priority, cancellable, log_hash_cb, callback_data);
- else if (logger->get_log_sets) {
- GSimpleAsyncResult *simple;
+ log = g_object_new(log_type, NULL);
- /* As there is no nonblocking function we can call blocking analog */
- g_mutex_lock(callback_data->mutex);
- (logger->get_log_sets)(log_add_log_set_to_hash, callback_data->sets);
- g_mutex_unlock(callback_data->mutex);
+ purple_log_get_log_sets_async(log, io_priority, cancellable,
+ log_hash_cb, callback_data);
+ }
- simple = g_simple_async_result_new(NULL, log_hash_cb, callback_data,
- log_get_log_sets_common_async);
+ log_get_log_sets_common_async(io_priority, cancellable, log_hash_cb, callback_data);
+}
- g_hash_table_ref(callback_data->sets);
- g_simple_async_result_set_op_res_gpointer(simple, callback_data->sets,
- (GDestroyNotify) g_hash_table_unref);
- g_simple_async_result_complete_in_idle(simple);
-
- g_object_unref(simple);
- } else
- callback_data->counter--;
- }
-
- log_get_log_sets_common_async(callback_data->sets, callback_data->mutex,
- log_add_log_set_to_hash, io_priority, cancellable, log_hash_cb, callback_data);
+static GHashTable *
+purple_log_real_get_log_sets_finish(PurpleLog *log, GAsyncResult *res, GError **error)
+{
+ return g_hash_table_ref(g_simple_async_result_get_op_res_gpointer(G_SIMPLE_ASYNC_RESULT(res)));
}
GHashTable *
-purple_log_get_log_sets_finish(GAsyncResult *res, GError **error)
+purple_log_get_log_sets_finish(PurpleLog *log, GAsyncResult *res, GError **error)
{
- GSimpleAsyncResult *simple;
+ g_return_val_if_fail(log == NULL || PURPLE_IS_LOG(log), NULL);
+ g_return_val_if_fail(G_IS_ASYNC_RESULT(res), NULL);
- simple = G_SIMPLE_ASYNC_RESULT(res);
+ if (G_IS_SIMPLE_ASYNC_RESULT(res)) {
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT(res);
- if (g_simple_async_result_propagate_error(simple, error))
- return NULL;
+ if (g_simple_async_result_propagate_error(simple, error))
+ return NULL;
+ }
- g_return_val_if_fail(g_simple_async_result_get_source_tag(simple) == log_get_log_sets_common_async, NULL);
-
- return g_hash_table_ref(g_simple_async_result_get_op_res_gpointer(simple));
+ if (log == NULL)
+ /* Result of purple_log_common */
+ return g_hash_table_ref(g_simple_async_result_get_op_res_gpointer(G_SIMPLE_ASYNC_RESULT(res)));
+ else
+ return PURPLE_LOG_GET_CLASS(log)->get_log_sets_finish(log, res, error);
}
void
@@ -1562,80 +2176,156 @@ GList *
}
GList *
-purple_log_get_system_logs(PurpleAccount *account)
+purple_log_get_system_logs(PurpleLog *log, PurpleAccount *account, GCancellable *cancellable, GError **error)
{
+ PurpleLogClass *class;
+
+ g_return_val_if_fail(PURPLE_IS_LOG(log), NULL);
+ g_return_val_if_fail(account != NULL, NULL); // PURPLE_IS_ACCOUNT(account)
+
+ class = PURPLE_LOG_GET_CLASS(log);
+
+ if (class->list_syslog_fn == NULL) {
+ g_set_error_literal(error,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported"));
+
+ return NULL;
+ }
+
+ return class->list_syslog_fn(log, account, cancellable, error);
+}
+
+GList *
+purple_logs_get_system_logs(PurpleAccount *account, GCancellable *cancellable, GError **error)
+{
+ GArray *array;
GList *logs = NULL;
- GSList *n;
+ guint i;
+ // PURPLE_IS_ACCOUNT(account)
g_return_val_if_fail(account != NULL, NULL);
- for (n = purple_log_logger_get_all(); n; n = g_slist_next(n)) {
- PurpleLogLogger *logger = n->data;
+ array = purple_log_logger_get_all();
- if (!logger->list_syslog)
- continue;
+ for (i = 0; i < array->len; i++) {
+ PurpleLog *log;
+ GList *list;
+ GType log_type = g_array_index(array, GType, i);
- logs = g_list_concat(logger->list_syslog(account), logs);
+ log = g_object_new(log_type, NULL);
+ list = purple_log_get_system_logs(log, account, cancellable, error);
+
+ if (list == NULL) {
+ for ( ; logs != NULL; logs = g_list_delete_link(logs, logs))
+ g_object_unref(logs->data);
+
+ g_object_unref(log);
+
+ return NULL;
+ }
+
+ logs = g_list_concat(list, logs);
+ g_object_unref(log);
}
return g_list_sort(logs, purple_log_compare);
}
-void
-purple_log_get_system_logs_async(PurpleAccount *account, gint io_priority,
- GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
+static void
+list_syslog_thread(GSimpleAsyncResult *simple, GObject *object, GCancellable *cancellable)
{
- _purple_log_logs_callback_data *callback_data;
+ _thread_callback_data *callback_data =
+ g_simple_async_result_get_op_res_gpointer(simple);
+ PurpleAccount *account = callback_data->account;
+ GError *error = NULL;
+ GList *list;
+
+ list = purple_log_get_system_logs(PURPLE_LOG(object), account, 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, NULL);
+
+ g_clear_error(&error);
+}
+
+static void
+purple_log_real_list_syslog_async(PurpleLog *log, PurpleAccount *account, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
+{
+ _thread_callback_data *callback_data;
GSimpleAsyncResult *simple;
- GSList *n;
- g_return_if_fail(account != NULL);
+ callback_data = g_new0(_thread_callback_data, 1);
+ callback_data->account = account; // g_object_ref
- n = purple_log_logger_get_all();
+ simple = g_simple_async_result_new(G_OBJECT(log), cb, userdata,
+ purple_log_real_list_syslog_async);
- callback_data = g_new0(_purple_log_logs_callback_data, 1);
- callback_data->userdata = userdata;
- callback_data->cb = cb;
- callback_data->counter = g_slist_length(n);
- callback_data->logs = NULL;
+ g_simple_async_result_set_op_res_gpointer(simple, callback_data, thread_callback_data_free);
+ g_simple_async_result_run_in_thread(simple, list_syslog_thread, io_priority, cancellable);
+ g_object_unref(simple);
+}
- for ( ; n; n = g_slist_next(n)) {
- PurpleLogLogger *logger = n->data;
+void
+purple_log_get_system_logs_async(PurpleLog *log, PurpleAccount *account, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
+{
+ g_return_if_fail(PURPLE_IS_LOG(log));
+ g_return_if_fail(account != NULL); // PURPLE_IS_ACCOUNT(account)
- if (logger->async->list_syslog_async)
- (logger->async->list_syslog_async)(account, io_priority, cancellable,
- log_system_list_cb, callback_data);
- else if (logger->list_syslog) {
- /* Call the blocking list function instead. */
- GList *logs = (logger->list_syslog)(account);
+ PURPLE_LOG_GET_CLASS(log)->list_syslog_async(log, account, io_priority, cancellable, cb, userdata);
+}
- simple = g_simple_async_result_new(NULL,
- log_system_list_cb,
- callback_data,
- purple_log_common_lister_async);
+void
+purple_logs_get_system_logs_async(PurpleAccount *account, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
+{
+ _get_logs_callback_data *callback_data;
+ GArray *array;
+ guint i;
- g_simple_async_result_set_op_res_gpointer(simple, logs, NULL);
- g_simple_async_result_complete_in_idle(simple);
+ g_return_if_fail(account != NULL); // PURPLE_IS_ACCOUNT(account)
- g_object_unref(simple);
- } else {
- simple = g_simple_async_result_new_error(NULL, log_system_list_cb,
- callback_data,
- G_FILE_ERROR,
- G_FILE_ERROR_FAILED,
- _("No available non-blocking system-log-getting function"));
+ array = purple_log_logger_get_all();
- g_simple_async_result_complete_in_idle(simple);
+ callback_data = g_new0(_get_logs_callback_data, 1);
+ callback_data->userdata = userdata;
+ callback_data->cb = cb;
+ callback_data->counter = array->len;
+ callback_data->logs = NULL;
- g_object_unref(simple);
- }
+ for (i = 0; i < array->len; i++) {
+ PurpleLog *log;
+ GType log_type = g_array_index(array, GType, i);
+
+ log = g_object_new(log_type, NULL);
+ purple_log_get_system_logs_async(log, account, io_priority, cancellable, log_system_list_cb, callback_data);
+
+ g_object_unref(log);
}
}
+static GList *
+purple_log_real_list_syslog_finish(PurpleLog *log, GAsyncResult *res, GError **error)
+{
+ return g_simple_async_result_get_op_res_gpointer(G_SIMPLE_ASYNC_RESULT(res));
+}
+
GList *
-purple_log_get_system_logs_finish(GAsyncResult *res, GError **error)
+purple_log_get_system_logs_finish(PurpleLog *log, GAsyncResult *res, GError **error)
{
- return purple_log_common_lister_finish(res, error);
+ g_return_val_if_fail(PURPLE_IS_LOG(log), NULL);
+ g_return_val_if_fail(G_IS_ASYNC_RESULT(res), NULL);
+
+ if (G_IS_SIMPLE_ASYNC_RESULT(res)) {
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT(res);
+
+ if (g_simple_async_result_propagate_error(simple, error))
+ return NULL;
+ }
+
+ return PURPLE_LOG_GET_CLASS(log)->list_syslog_finish(log, res, error);
}
/****************************************************************************
@@ -1643,87 +2333,91 @@ void
****************************************************************************/
void
-purple_log_init(void)
+purple_log_system_init(void)
{
- void *handle;
+ void *handle = purple_log_system_get_handle();
if (!g_thread_supported())
g_thread_init(NULL);
- handle = purple_log_get_handle();
+ G_LOCK(loggers);
+ loggers = g_array_sized_new(FALSE, FALSE, sizeof(GType), 3);
+ G_UNLOCK(loggers);
purple_prefs_add_none("/purple/logging");
purple_prefs_add_bool("/purple/logging/log_ims", TRUE);
purple_prefs_add_bool("/purple/logging/log_chats", TRUE);
purple_prefs_add_bool("/purple/logging/log_system", FALSE);
- purple_prefs_add_string("/purple/logging/format", "html");
+ purple_html_log_system_init();
+ purple_txt_log_system_init();
+ purple_old_log_system_init();
- G_LOCK(html_logger);
- html_logger = purple_log_logger_new("html", _("HTML"), 21,
- NULL,
- html_logger_write,
- html_logger_finalize,
- html_logger_list,
- html_logger_read,
- purple_log_common_sizer,
- html_logger_total_size,
- html_logger_list_syslog,
- NULL,
- purple_log_common_deleter,
- purple_log_common_is_deletable,
- NULL,
- html_logger_write_async,
- NULL,
- html_logger_list_async,
- html_logger_read_async,
- purple_log_common_sizer_async,
- html_logger_total_size_async,
- html_logger_list_syslog_async,
- NULL,
- purple_log_common_deleter_async);
- purple_log_logger_add(html_logger);
- G_UNLOCK(html_logger);
+ // G_LOCK(html_logger);
+ // html_logger = purple_log_logger_new("html", _("HTML"), 21,
+ // NULL,
+ // html_logger_write,
+ // html_logger_finalize,
+ // html_logger_list,
+ // html_logger_read,
+ // purple_log_common_sizer,
+ // html_logger_total_size,
+ // html_logger_list_syslog,
+ // NULL,
+ // purple_log_common_deleter,
+ // purple_log_common_is_removable,
+ // NULL,
+ // html_logger_write_async,
+ // NULL,
+ // html_logger_list_async,
+ // html_logger_read_async,
+ // purple_log_common_sizer_async,
+ // html_logger_total_size_async,
+ // html_logger_list_syslog_async,
+ // NULL,
+ // purple_log_common_deleter_async);
+ // purple_log_logger_add(html_logger);
+ // G_UNLOCK(html_logger);
- G_LOCK(txt_logger);
- txt_logger = purple_log_logger_new("txt", _("Plain text"), 21,
- NULL,
- txt_logger_write,
- txt_logger_finalize,
- txt_logger_list,
- txt_logger_read,
- purple_log_common_sizer,
- txt_logger_total_size,
- txt_logger_list_syslog,
- NULL,
- purple_log_common_deleter,
- purple_log_common_is_deletable,
- NULL,
- txt_logger_write_async,
- NULL,
- txt_logger_list_async,
- txt_logger_read_async,
- purple_log_common_sizer_async,
- txt_logger_total_size_async,
- txt_logger_list_syslog_async,
- NULL,
- purple_log_common_deleter_async);
- purple_log_logger_add(txt_logger);
- G_UNLOCK(txt_logger);
+ // G_LOCK(txt_logger);
+ // txt_logger = purple_log_logger_new("txt", _("Plain text"), 21,
+ // NULL,
+ // txt_logger_write,
+ // txt_logger_finalize,
+ // txt_logger_list,
+ // txt_logger_read,
+ // purple_log_common_sizer,
+ // txt_logger_total_size,
+ // txt_logger_list_syslog,
+ // NULL,
+ // purple_log_common_deleter,
+ // purple_log_common_is_removable,
+ // NULL,
+ // txt_logger_write_async,
+ // NULL,
+ // txt_logger_list_async,
+ // txt_logger_read_async,
+ // purple_log_common_sizer_async,
+ // txt_logger_total_size_async,
+ // txt_logger_list_syslog_async,
+ // NULL,
+ // purple_log_common_deleter_async);
+ // purple_log_logger_add(txt_logger);
+ // G_UNLOCK(txt_logger);
- G_LOCK(old_logger);
- old_logger = purple_log_logger_new("old", _("Old flat format"), 9,
- NULL,
- NULL,
- old_logger_finalize,
- old_logger_list,
- old_logger_read,
- old_logger_size,
- old_logger_total_size,
- NULL,
- old_logger_get_log_sets);
- purple_log_logger_add(old_logger);
- G_UNLOCK(old_logger);
+ // G_LOCK(old_logger);
+ // old_logger = purple_log_logger_new("old", _("Old flat format"), 9,
+ // NULL,
+ // NULL,
+ // old_logger_finalize,
+ // old_logger_list,
+ // old_logger_read,
+ // old_logger_size,
+ // old_logger_total_size,
+ // NULL,
+ // old_logger_get_log_sets);
+ // purple_log_logger_add(old_logger);
+ // G_UNLOCK(old_logger);
purple_signal_register(handle, "log-timestamp",
#if SIZEOF_TIME_T == 4
@@ -1758,14 +2452,10 @@ purple_log_init(void)
(GEqualFunc) _purple_logsize_user_equal,
(GDestroyNotify) _purple_logsize_user_free_key, NULL);
G_UNLOCK(logsize_users_decayed);
-
- G_LOCK(log_ref_table);
- log_ref_table = g_hash_table_new(NULL, NULL);
- G_UNLOCK(log_ref_table);
}
void *
-purple_log_get_handle(void)
+purple_log_system_get_handle(void)
{
static gint handle;
@@ -1773,55 +2463,42 @@ void
}
void
-purple_log_uninit(void)
+purple_log_system_uninit(void)
{
- purple_signals_unregister_by_instance(purple_log_get_handle());
+ purple_signals_unregister_by_instance(purple_log_system_get_handle());
- G_LOCK(html_logger);
- purple_log_logger_remove(html_logger);
- purple_log_logger_free(html_logger);
- html_logger = NULL;
- G_UNLOCK(html_logger);
+ purple_html_log_system_uninit();
+ purple_txt_log_system_uninit();
+ purple_old_log_system_uninit();
- G_LOCK(txt_logger);
- purple_log_logger_remove(txt_logger);
- purple_log_logger_free(txt_logger);
- txt_logger = NULL;
- G_UNLOCK(txt_logger);
+ G_LOCK(loggers);
+ g_array_free(loggers, TRUE);
+ loggers = NULL;
+ current_logger = G_TYPE_INVALID;
+ G_UNLOCK(loggers);
- G_LOCK(old_logger);
- purple_log_logger_remove(old_logger);
- purple_log_logger_free(old_logger);
- old_logger = NULL;
- G_UNLOCK(old_logger);
-
G_LOCK(logsize_users);
g_hash_table_destroy(logsize_users);
+ logsize_users = NULL;
G_UNLOCK(logsize_users);
G_LOCK(logsize_users_decayed);
g_hash_table_destroy(logsize_users_decayed);
+ logsize_users_decayed = NULL;
G_UNLOCK(logsize_users_decayed);
-
- G_LOCK(log_ref_table);
- g_hash_table_destroy(log_ref_table);
- G_UNLOCK(log_ref_table);
}
-/****************************************************************************
- * LOGGERS ******************************************************************
- ****************************************************************************/
-
-static gchar *
-log_get_timestamp(PurpleLog *log, time_t when)
+gchar *
+_log_get_timestamp(PurpleLog *log, time_t when)
{
gboolean show_date;
gchar *date;
struct tm tm;
- show_date = log->type == PURPLE_LOG_SYSTEM || time(NULL) > when + 20 * 60;
+ show_date = purple_log_get_chat_type(log) == PURPLE_LOG_SYSTEM ||
+ time(NULL) > when + 20 * 60;
- date = purple_signal_emit_return_1(purple_log_get_handle(), "log-timestamp",
+ date = purple_signal_emit_return_1(purple_log_system_get_handle(), "log-timestamp",
log, when, show_date);
if (date != NULL)
@@ -1837,8 +2514,8 @@ log_get_timestamp(PurpleLog *log, time_t
/* NOTE: This can return msg (which you may or may not want to g_free())
* NOTE: or a newly allocated string which you MUST g_free(). */
-static gchar *
-convert_image_tags(const PurpleLog *log, const gchar *msg)
+gchar *
+_convert_image_tags(const PurpleLog *log, const gchar *msg)
{
GString *newmsg = NULL;
GData *attributes;
@@ -1859,8 +2536,11 @@ convert_image_tags(const PurpleLog *log,
imgid = atoi(idstr);
if (imgid != 0) {
+ PurpleAccount *account = purple_log_get_account(log);
+ PurpleLogChatType chat_type = purple_log_get_chat_type(log);
PurpleStoredImage *image = purple_imgstore_find_by_id(imgid);
gchar *new_filename = NULL, *path = NULL, *dir;
+ const gchar *name = purple_log_get_name(log);
gconstpointer image_data;
size_t image_byte_count;
@@ -1873,7 +2553,7 @@ convert_image_tags(const PurpleLog *log,
image_data = purple_imgstore_get_data(image);
image_byte_count = purple_imgstore_get_size(image);
- dir = purple_log_get_log_dir(log->type, log->name, log->account);
+ dir = purple_log_get_log_dir(chat_type, name, account);
new_filename = purple_util_get_image_filename(image_data, image_byte_count);
path = g_build_filename(dir, new_filename, NULL);
@@ -1921,70 +2601,95 @@ convert_image_tags(const PurpleLog *log,
return g_string_free(newmsg, FALSE);
}
-void
-purple_log_common_writer(PurpleLog *log, const gchar *ext)
+gboolean
+purple_log_common_writer(PurpleLog *log, const gchar *ext, GCancellable *cancellable, GError **error)
{
- g_return_if_fail(log != NULL);
+ PurpleLogCommonLoggerData *data = purple_log_get_logger_data(log);
- if (log->logger_data == NULL) {
- PurpleLogCommonLoggerData *data = log->logger_data;
+ 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(log->type, log->name, log->account);
+ 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)
- return;
+ if (dir == NULL) {
+ g_set_error_literal(error,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ _("Unable to get log directory"));
- purple_build_dir (dir, S_IRUSR | S_IWUSR | S_IXUSR);
+ return FALSE;
+ }
- tm = localtime(&log->time);
+ 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);
- path = g_build_filename(dir, filename, NULL);
g_free(dir);
g_free(filename);
- log->logger_data = data = g_slice_new0(PurpleLogCommonLoggerData);
-
+ data = g_slice_new0(PurpleLogCommonLoggerData);
+ purple_log_set_logger_data(log, data);
data->file = g_fopen(path, "a");
if (data->file == NULL) {
- purple_debug_error("log", "Could not create log file %s\n", path);
+ PurpleConversation *conv = purple_log_get_conversation(log);
- if (log->conv != NULL)
- purple_conversation_write(log->conv, NULL, _("Logging of this conversation failed."),
+ 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;
+ return FALSE;
}
data->path = path;
}
+
+ return TRUE;
}
static void
writer_thread(GSimpleAsyncResult *simple, GObject *object, GCancellable *cancellable)
{
- _purple_logger_writer_callback_data *callback_data =
- g_simple_async_result_get_op_res_gpointer(simple);
- PurpleLog *log = callback_data->log;
- PurpleLogCommonLoggerData *data = log->logger_data;
+ 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(log->type, log->name, log->account);
+ 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,
@@ -2000,7 +2705,8 @@ writer_thread(GSimpleAsyncResult *simple
return;
}
- tm = localtime(&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);
@@ -2010,15 +2716,18 @@ writer_thread(GSimpleAsyncResult *simple
g_free(dir);
g_free(filename);
- log->logger_data = data = g_slice_new0(PurpleLogCommonLoggerData);
+ 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 (log->conv != NULL)
- purple_conversation_write(log->conv, NULL,
+ if (conv != NULL)
+ purple_conversation_write(conv, NULL,
_("Logging of this conversation failed."),
PURPLE_MESSAGE_ERROR, time(NULL));
@@ -2037,18 +2746,17 @@ purple_log_common_writer_async(PurpleLog
purple_log_common_writer_async(PurpleLog *log, const gchar *ext, gint io_priority,
GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
{
- _purple_logger_writer_callback_data *callback_data;
+ _thread_callback_data *callback_data;
GSimpleAsyncResult *simple;
- g_return_if_fail(log != NULL);
+ g_return_if_fail(PURPLE_IS_LOG(log));
- callback_data = g_new0(_purple_logger_writer_callback_data, 1);
- callback_data->log = log;
+ callback_data = g_new0(_thread_callback_data, 1);
callback_data->ext = g_strdup(ext);
- simple = g_simple_async_result_new(NULL, cb, userdata, purple_log_common_writer_async);
+ 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, purple_logger_writer_callback_data_free);
+ 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);
@@ -2070,8 +2778,8 @@ GList *
}
GList *
-purple_log_common_lister(PurpleLogType type, const gchar *name, PurpleAccount *account,
- const gchar *ext, PurpleLogLogger *logger)
+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;
@@ -2084,14 +2792,20 @@ purple_log_common_lister(PurpleLogType t
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(logger != 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(type, name, account);
+ path = purple_log_get_log_dir(chat_type, name, account);
- if (path == NULL)
+ 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, NULL);
+ dir = g_dir_open(path, 0, error);
if (dir == NULL) {
g_free(path);
@@ -2100,6 +2814,13 @@ purple_log_common_lister(PurpleLogType t
}
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 NULL;
+ }
+
if (purple_str_has_suffix(filename, ext) &&
strlen(filename) >= (17 + strlen(ext))) {
#if defined (HAVE_TM_GMTOFF) && defined (HAVE_STRUCT_TM_TM_ZONE)
@@ -2115,21 +2836,21 @@ purple_log_common_lister(PurpleLogType t
tm.tm_gmtoff = tz_off - tm.tm_gmtoff;
if (stamp == 0 || rest == NULL || (end = strchr(rest, '.')) == NULL || strchr(rest, ' ') != NULL) {
- log = purple_log_new(type, name, account, NULL, stamp, 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(type, name, account, NULL, stamp, &tm);
+ 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(type, name, account, NULL, stamp, (stamp != 0) ? &tm : NULL);
+ log = purple_log_new(log_type, chat_type, name, account, NULL, stamp, (stamp != 0) ? &tm : NULL);
#endif
- log->logger = logger;
- log->logger_data = data = g_slice_new0(PurpleLogCommonLoggerData);
+ 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);
@@ -2148,112 +2869,40 @@ common_lister_thread(GSimpleAsyncResult
_purple_logger_lister_callback_data *callback_data =
g_simple_async_result_get_op_res_gpointer(simple);
PurpleAccount *account = callback_data->account;
- PurpleLog *log;
- PurpleLogCommonLoggerData *data;
- PurpleLogLogger *logger = callback_data->logger;
- PurpleLogType type = callback_data->type;
- GError *err = NULL;
- GList *list = NULL;
- GDir *dir;
- const gchar *name = callback_data->name, *ext = callback_data->ext, *filename;
- gchar *path;
- struct tm tm;
+ 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;
- path = purple_log_get_log_dir(type, name, account);
+ list = purple_log_common_lister(chat_type, name, account, ext, log_type, cancellable, &error);
- if (path == NULL) {
- g_simple_async_result_set_error(simple, G_IO_ERROR, G_IO_ERROR_FAILED,
- _("Unable to get log directory"));
+ 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);
- return;
- }
-
- dir = g_dir_open(path, 0, &err);
-
- if (dir == NULL) {
- /* Should we indicate if the directory was just empty, as we do with total_sizer?
- * or just let the caller figure that sort of thing out? Feels weird to be inconsistent...
- */
- g_simple_async_result_set_from_error(simple, err);
-
- g_free(path);
- g_clear_error(&err);
-
- return;
- }
-
- g_clear_error(&err);
-
- while ((filename = g_dir_read_name(dir)) != NULL) {
- if (g_cancellable_set_error_if_cancelled(cancellable, &err)) {
- g_simple_async_result_set_from_error(simple, err);
-
- g_dir_close(dir);
- g_free(path);
- g_clear_error(&err);
-
- return;
- }
-
- 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 = 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(type, name, account, NULL, stamp, NULL);
- } else {
- gchar *tmp = g_strndup(rest, end - rest);
- tm.tm_zone = tmp;
- log = purple_log_new(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(type, name, account, NULL, stamp, (stamp != 0) ? &tm : NULL);
-#endif
-
- log->logger = logger;
- log->logger_data = data = g_slice_new0(PurpleLogCommonLoggerData);
-
- data->path = g_build_filename(path, filename, NULL);
- list = g_list_prepend(list, log);
- }
- }
-
- g_dir_close(dir);
- g_free(path);
-
- g_simple_async_result_set_op_res_gpointer(simple, list, NULL);
+ g_clear_error(&error);
}
void
-purple_log_common_lister_async(PurpleLogType type, const gchar *name, PurpleAccount *account,
- const gchar *ext, PurpleLogLogger *logger, gint io_priority, GCancellable *cancellable,
+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);
+ g_return_if_fail(account != NULL); // PURPLE_IS_ACCOUNT(account)
g_return_if_fail(ext != NULL);
- g_return_if_fail(logger != NULL);
callback_data = g_new0(_purple_logger_lister_callback_data, 1);
- callback_data->type = type;
+ callback_data->chat_type = chat_type;
callback_data->name = g_strdup(name);
callback_data->account = account;
callback_data->ext = g_strdup(ext);
- callback_data->logger = logger;
+ callback_data->log_type = log_type;
simple = g_simple_async_result_new(NULL, cb, userdata, purple_log_common_lister_async);
@@ -2283,106 +2932,41 @@ purple_log_common_lister_finish(GAsyncRe
// 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...
-gint
-purple_log_common_total_sizer(PurpleLogType type, const gchar *name, PurpleAccount *account,
- const gchar *ext)
+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;
- gint size;
+ GError *err = NULL;
const gchar *filename;
- gchar *tmp, *path;
- struct stat st;
+ 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(type, name, account);
+ path = purple_log_get_log_dir(chat_type, name, account);
- if (path == NULL)
- return 0;
-
- if (!(dir = g_dir_open(path, 0, NULL))){
- g_free(path);
- return 0;
- }
-
- size = 0;
-
- while ((filename = g_dir_read_name(dir))) {
- if (purple_str_has_suffix(filename, ext) &&
- strlen(filename) >= (17 + strlen(ext))) {
- tmp = g_build_filename(path, filename, NULL);
-
- if (g_stat(tmp, &st)) {
- purple_debug_error("log", "Error stating log file: %s\n", tmp);
- g_free(tmp);
-
- continue;
- }
-
- g_free(tmp);
- size += st.st_size;
- }
- }
-
- g_dir_close(dir);
- g_free(path);
-
- 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, &ptrsize))
- size += GPOINTER_TO_INT(ptrsize);
-
- g_hash_table_replace(logsize_users, lu, GINT_TO_POINTER(size));
- G_UNLOCK(logsize_users);
-
- return size;
-}
-
-static void
-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);
- _purple_logsize_user *lu;
- PurpleAccount *account = callback_data->account;
- PurpleLogType type = callback_data->type;
- GDir *dir;
- GError *err = NULL;
- gchar *tmp, *path, *name = callback_data->name, *ext = callback_data->ext;
- const gchar *filename;
- struct stat st;
- gssize size = 0, total;
- gpointer ptrsize;
-
- if(account == NULL) {
- g_simple_async_result_set_error(simple, G_IO_ERROR, G_IO_ERROR_FAILED,
- _("Account is NULL"));
-
- return;
- }
-
- path = purple_log_get_log_dir(type, name, account);
-
if (path == NULL) {
- g_simple_async_result_set_error(simple, G_IO_ERROR, G_IO_ERROR_FAILED,
+ g_set_error_literal(error,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
_("Unable to get log directory"));
- return;
+ 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?
@@ -2392,40 +2976,35 @@ total_sizer_thread(GSimpleAsyncResult *s
G_UNLOCK(logsize_users);
- g_simple_async_result_set_op_res_gssize(simple, size);
- } else
- g_simple_async_result_set_from_error(simple, err);
-
- g_free(path);
- g_clear_error(&err);
-
- return;
+ return 0;
+ } else {
+ g_propagate_error(error, err);
+ return -1;
+ }
}
- g_clear_error(&err);
-
while ((filename = g_dir_read_name(dir)) != NULL) {
- if (g_cancellable_set_error_if_cancelled(cancellable, &err)) {
- g_simple_async_result_set_from_error(simple, err);
-
+ if (g_cancellable_set_error_if_cancelled(cancellable, error)) {
g_dir_close(dir);
g_free(path);
- g_clear_error(&err);
- return;
+ return -1;
}
- g_clear_error(&err);
-
if (purple_str_has_suffix(filename, ext) &&
strlen(filename) >= 17 + strlen(ext)) {
- tmp = g_build_filename(path, filename, NULL);
+ struct stat st;
+ gchar *tmp = g_build_filename(path, filename, NULL);
if (g_stat(tmp, &st)) {
- purple_debug_error("log", "Error stating log file: %s\n", tmp);
g_free(tmp);
- continue;
+ g_set_error_literal(error,
+ G_FILE_ERROR,
+ g_file_error_from_errno(errno),
+ g_strerror(errno));
+
+ return -1;
}
g_free(tmp);
@@ -2450,11 +3029,32 @@ total_sizer_thread(GSimpleAsyncResult *s
g_dir_close(dir);
g_free(path);
- g_simple_async_result_set_op_res_gssize(simple, size);
+ 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(PurpleLogType type, const gchar *name,
+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)
{
@@ -2466,7 +3066,7 @@ purple_log_common_total_sizer_async(Purp
g_return_if_fail(ext != NULL);
callback_data = g_new0(_purple_logger_total_size_callback_data, 1);
- callback_data->type = type;
+ callback_data->chat_type = chat_type;
callback_data->name = g_strdup(name);
callback_data->account = account;
callback_data->ext = g_strdup(ext);
@@ -2475,7 +3075,7 @@ purple_log_common_total_sizer_async(Purp
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, total_sizer_thread, io_priority, cancellable);
+ g_simple_async_result_run_in_thread(simple, common_total_sizer_thread, io_priority, cancellable);
g_object_unref(simple);
}
@@ -2495,67 +3095,64 @@ purple_log_common_total_sizer_finish(GAs
return g_simple_async_result_get_op_res_gssize(simple);
}
-gint
-purple_log_common_sizer(PurpleLog *log)
+gssize
+purple_log_common_sizer(PurpleLog *log, GCancellable *cancellable, GError **error)
{
+ PurpleLogCommonLoggerData *data;
struct stat st;
- PurpleLogCommonLoggerData *data;
- g_return_val_if_fail(log != NULL, 0);
+ g_return_val_if_fail(PURPLE_IS_LOG(log), 0);
- data = log->logger_data;
+ data = purple_log_get_logger_data(log);
- g_return_val_if_fail(data != NULL, 0);
+ if (data == NULL || data->path == NULL) {
+ g_set_error_literal(error,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ _("Unable to get log path"));
- if (!data->path || g_stat(data->path, &st))
- st.st_size = 0;
+ return -1;
+ } else if (g_stat(data->path, &st)) {
+ g_set_error_literal(error,
+ G_FILE_ERROR,
+ g_file_error_from_errno(errno),
+ g_strerror(errno));
+ return -1;
+ }
+
return st.st_size;
}
static void
sizer_thread(GSimpleAsyncResult *simple, GObject *object, GCancellable *cancellable)
{
- _purple_logger_sizer_callback_data *callback_data =
- g_simple_async_result_get_op_res_gpointer(simple);
- PurpleLogCommonLoggerData *data = callback_data->log->logger_data;
- struct stat st;
+ PurpleLog *log = PURPLE_LOG(object);
+ GError *error = NULL;
+ gssize size;
- if (data == NULL || data->path == NULL) {
- g_simple_async_result_set_error(simple, G_IO_ERROR, G_IO_ERROR_FAILED,
- _("Unable to get log path"));
+ size = purple_log_common_sizer(log, cancellable, &error);
- return;
- }
+ if (size < 0)
+ g_simple_async_result_set_from_error(simple, error);
+ else
+ g_simple_async_result_set_op_res_gssize(simple, size);
- if (g_stat(data->path, &st)) {
- g_simple_async_result_set_error(simple, G_IO_ERROR, G_IO_ERROR_FAILED,
- _("Error stating log file"));
-
- return;
- }
-
- g_simple_async_result_set_op_res_gssize(simple, st.st_size);
+ g_clear_error(&error);
}
void
purple_log_common_sizer_async(PurpleLog *log, gint io_priority, GCancellable *cancellable,
GAsyncReadyCallback cb, gpointer userdata)
{
- _purple_logger_sizer_callback_data *callback_data;
GSimpleAsyncResult *simple;
- g_return_if_fail(log != NULL);
+ g_return_if_fail(PURPLE_IS_LOG(log));
- callback_data = g_new0(_purple_logger_sizer_callback_data, 1);
- callback_data->log = log;
+ simple = g_simple_async_result_new(G_OBJECT(log), cb, userdata, purple_log_common_sizer_async);
- simple = g_simple_async_result_new(NULL, cb, userdata, purple_log_common_sizer_async);
+ g_simple_async_result_run_in_thread(simple, sizer_thread, io_priority, cancellable);
- g_simple_async_result_set_op_res_gpointer(simple, callback_data, g_free);
- g_simple_async_result_run_in_thread(simple, sizer_thread, io_priority,
- cancellable);
-
g_object_unref(simple);
}
@@ -2564,46 +3161,45 @@ purple_log_common_sizer_finish(PurpleLog
{
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;
- g_return_val_if_fail(g_simple_async_result_get_source_tag(simple) == purple_log_common_sizer_async, -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 gboolean
-log_get_log_sets_common(GHashTable *sets, GMutex *mutex, PurpleLogSetCallback set_cb, GError **error)
+static GHashTable *
+log_get_log_sets_common(GCancellable *cancel, GError **error)
{
- PurpleAccount *account;
- PurplePlugin *prpl;
- PurplePluginProtocolInfo *prpl_info;
- GDir *log_dir, *protocol_dir, *username_dir;
- GError *err = NULL;
- GList *accounts, *account_iter;
- const gchar *protocol, *prpl_protocol, *username, *username_unescaped;
- gchar *log_path, *protocol_path, *protocol_unescaped, *username_path, *name, *tmp;
- guint len;
+ GDir *log_dir, *username_dir;
+ GHashTable *sets;
+ const gchar *protocol;
+ gchar *log_path;
log_path = g_build_filename(purple_user_dir(), "logs", NULL);
- log_dir = g_dir_open(log_path, 0, &err);
+ log_dir = g_dir_open(log_path, 0, error);
if (log_dir == NULL) {
- if (error != NULL)
- *error = err;
-
g_free(log_path);
- return FALSE;
+ return NULL;
}
- g_clear_error(&err);
+ sets = g_hash_table_new_full(log_set_hash, log_set_equal,
+ (GDestroyNotify) purple_log_set_free, NULL);
while ((protocol = g_dir_read_name(log_dir)) != NULL) {
- protocol_path = g_build_filename(log_path, protocol, NULL);
+ GDir *protocol_dir;
+ GList *accounts = NULL, *account_iter;
+ const gchar *username;
+ gchar *protocol_path = g_build_filename(log_path, protocol, NULL);
+ gchar *protocol_unescaped;
+
protocol_dir = g_dir_open(protocol_path, 0, NULL);
if (protocol_dir == NULL) {
@@ -2614,13 +3210,18 @@ log_get_log_sets_common(GHashTable *sets
/* Using g_strdup() to cover the one-in-a-million chance that a
* prpl's list_icon function uses purple_unescape_filename(). */
protocol_unescaped = g_strdup(purple_unescape_filename(protocol));
- accounts = NULL;
/* Find all the accounts for protocol. */
- for (account_iter = purple_accounts_get_all(); account_iter != NULL; account_iter = g_list_next(account_iter)) {
+ for (account_iter = purple_accounts_get_all(); account_iter != NULL;
+ account_iter = g_list_next(account_iter))
+ {
+ PurplePlugin *prpl;
+ PurplePluginProtocolInfo *prpl_info;
+ const gchar *prpl_protocol;
+
prpl = purple_find_prpl(purple_account_get_protocol_id((PurpleAccount *) account_iter->data));
- if (!prpl)
+ if (prpl == NULL)
continue;
prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
@@ -2633,8 +3234,10 @@ log_get_log_sets_common(GHashTable *sets
g_free(protocol_unescaped);
while ((username = g_dir_read_name(protocol_dir)) != NULL) {
- username_path = g_build_filename(protocol_path, username, NULL);
- account = NULL;
+ PurpleAccount *account = NULL;
+ const gchar *username_unescaped;
+ gchar *username_path = g_build_filename(protocol_path, username, NULL);
+ gchar *name;
if ((username_dir = g_dir_open(username_path, 0, NULL)) == NULL) {
g_free(username_path);
@@ -2655,6 +3258,8 @@ log_get_log_sets_common(GHashTable *sets
while ((name = (gchar *) g_dir_read_name(username_dir)) != NULL) {
/* IMPORTANT: Always initialize all members of PurpleLogSet */
PurpleLogSet *set = g_slice_new(PurpleLogSet);
+ gchar *tmp;
+ guint len;
/* Unescape the filename. */
name = g_strdup(purple_unescape_filename(name));
@@ -2693,12 +3298,7 @@ log_get_log_sets_common(GHashTable *sets
else
set->buddy = FALSE;
- if (mutex != NULL) {
- g_mutex_lock(mutex);
- set_cb(sets, set);
- g_mutex_unlock(mutex);
- } else
- set_cb(sets, set);
+ log_add_log_set_to_hash(sets, set);
}
g_free(username_path);
@@ -2712,1714 +3312,176 @@ log_get_log_sets_common(GHashTable *sets
g_free(log_path);
g_dir_close(log_dir);
- return TRUE;
+ return sets;
}
static void
log_get_log_sets_common_thread(GSimpleAsyncResult *simple, GObject *object,
GCancellable *cancellable)
{
- _purple_logger_get_sets_common_callback_data *callback_data =
- g_simple_async_result_get_op_res_gpointer(simple);
- GError *err = NULL;
- GHashTable *sets = callback_data->sets;
+ GError *error = NULL;
+ GHashTable *sets;
- if (!log_get_log_sets_common(sets, callback_data->mutex,
- callback_data->set_cb, &err))
- g_simple_async_result_set_from_error(simple, err);
+ sets = log_get_log_sets_common(cancellable, &error);
+
+ if (sets == NULL)
+ g_simple_async_result_set_from_error(simple, error);
else
- g_simple_async_result_set_op_res_gpointer(simple, sets,
- (GDestroyNotify) g_hash_table_unref);
+ g_simple_async_result_set_op_res_gpointer(simple, sets, (GDestroyNotify) g_hash_table_unref);
- g_clear_error(&err);
+ g_clear_error(&error);
}
static void
-log_get_log_sets_common_async(GHashTable *sets, GMutex *mutex, PurpleLogSetCallback set_cb,
- gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
+log_get_log_sets_common_async(gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
{
- _purple_logger_get_sets_common_callback_data *callback_data;
GSimpleAsyncResult *simple;
- callback_data = g_new0(_purple_logger_get_sets_common_callback_data, 1);
- callback_data->sets = g_hash_table_ref(sets);
- callback_data->mutex = mutex;
- callback_data->set_cb = set_cb;
-
simple = g_simple_async_result_new(NULL, cb, userdata, log_get_log_sets_common_async);
- g_simple_async_result_set_op_res_gpointer(simple, callback_data, g_free);
- g_simple_async_result_run_in_thread(simple, log_get_log_sets_common_thread, io_priority,
- cancellable);
-
+ g_simple_async_result_run_in_thread(simple, log_get_log_sets_common_thread, io_priority, cancellable);
g_object_unref(simple);
}
gboolean
-purple_log_common_deleter(PurpleLog *log)
+purple_log_common_remover(PurpleLog *log, GCancellable *cancellable, GError **error)
{
PurpleLogCommonLoggerData *data;
GFile *file;
- GError *err;
gboolean result;
- g_return_val_if_fail(log != NULL, FALSE);
+ g_return_val_if_fail(PURPLE_IS_LOG(log), FALSE);
- data = log->logger_data;
+ data = purple_log_get_logger_data(log);
- if (data == NULL || data->path == NULL)
+ 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;
+ }
- err = NULL;
file = g_file_new_for_path(data->path);
- result = g_file_delete(file, NULL, &err);
+ result = g_file_delete(file, cancellable, error);
- if (!result && err->code != G_IO_ERROR_CANCELLED)
- purple_debug_error("log", "Failed to delete: %s - %s\n", data->path, err->message);
-
- g_clear_error(&err);
-
return result;
}
static void
-deleter_thread(GSimpleAsyncResult *simple, GObject *object, GCancellable *cancellable)
+remover_thread(GSimpleAsyncResult *simple, GObject *object, GCancellable *cancellable)
{
- _purple_logger_deleter_callback_data *callback_data =
- g_simple_async_result_get_op_res_gpointer(simple);
- PurpleLogCommonLoggerData *data = callback_data->log->logger_data;
- GError *err = NULL;
- GFile *file;
+ PurpleLog *log = PURPLE_LOG(object);
+ GError *error = NULL;
- if (data == NULL || data->path == NULL) {
- g_simple_async_result_set_error(simple, G_IO_ERROR, G_IO_ERROR_FAILED,
- _("Unable to get log path"));
-
- return;
- }
-
- file = g_file_new_for_path(data->path);
-
- if (!g_file_delete(file, cancellable, &err))
- g_simple_async_result_set_from_error(simple, err);
+ 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_object_unref(file);
- g_clear_error(&err);
+ g_clear_error(&error);
}
void
-purple_log_common_deleter_async(PurpleLog *log, gint io_priority, GCancellable *cancellable,
+purple_log_common_remover_async(PurpleLog *log, gint io_priority, GCancellable *cancellable,
GAsyncReadyCallback cb, gpointer userdata)
{
- _purple_logger_deleter_callback_data *callback_data;
GSimpleAsyncResult *simple;
- g_return_if_fail(log != NULL);
+ g_return_if_fail(PURPLE_IS_LOG(log));
- callback_data = g_new0(_purple_logger_deleter_callback_data, 1);
- callback_data->log = log;
+ simple = g_simple_async_result_new(G_OBJECT(log), cb, userdata, purple_log_common_remover_async);
- simple = g_simple_async_result_new(NULL, cb, userdata, purple_log_common_deleter_async);
-
- g_simple_async_result_set_op_res_gpointer(simple, callback_data, g_free);
- g_simple_async_result_run_in_thread(simple, deleter_thread, io_priority, cancellable);
-
+ g_simple_async_result_run_in_thread(simple, remover_thread, io_priority, cancellable);
g_object_unref(simple);
}
gboolean
-purple_log_common_deleter_finish(PurpleLog *log, GAsyncResult *res, GError **error)
+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;
- g_return_val_if_fail(g_simple_async_result_get_source_tag(simple) == purple_log_common_deleter_async, FALSE);
-
return g_simple_async_result_get_op_res_gboolean(simple);
}
gboolean
-purple_log_common_is_deletable(PurpleLog *log)
+purple_log_common_is_removable(PurpleLog *log, GCancellable *cancellable, GError **error)
{
PurpleLogCommonLoggerData *data;
-
- g_return_val_if_fail(log != NULL, FALSE);
-
- data = log->logger_data;
-
- if (data == NULL || data->path == NULL)
- return FALSE;
-
-#ifndef G_OS_WIN32
- {
- gchar *dirname = g_path_get_dirname(data->path);
-
- if (g_access(dirname, W_OK) == 0) {
- g_free(dirname);
- return TRUE;
- }
-
- purple_debug_info("log", "access(%s) failed: %s\n", dirname, g_strerror(errno));
- g_free(dirname);
-
- return FALSE;
- }
-#else
- /* Unless and until someone writes equivalent win32 code,
- * we'll assume the file is deletable. */
- return TRUE;
-#endif
-}
-
-static gchar *
-process_txt_log(gchar *txt, gchar *to_free)
-{
- gchar *tmp;
-
- /* The to_free argument allows us to save a
- * g_strdup() in some cases. */
-
- if (to_free == NULL)
- to_free = txt;
-
- /* g_markup_escape_text requires valid UTF-8 */
- if (!g_utf8_validate(txt, -1, NULL))
- {
- tmp = purple_utf8_salvage(txt);
- g_free(to_free);
- to_free = txt = tmp;
- }
-
- tmp = g_markup_escape_text(txt, -1);
- g_free(to_free);
- txt = purple_markup_linkify(tmp);
- g_free(tmp);
-
- return txt;
-}
-
-#if 0 /* Maybe some other time. */
-/****************
- ** XML LOGGER **
- ****************/
-
-static const gchar *
-str_from_msg_type (PurpleMessageFlags type)
-{
- return "";
-}
-
-static void
-xml_logger_write(PurpleLog *log, PurpleMessageFlags type, const gchar *from, time_t time,
- const gchar *message)
-{
- gchar *xhtml = NULL;
-
- if (!log->logger_data) {
- /* 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.
- */
- struct tm *tm;
- const gchar *tz;
- const gchar *date;
- gchar *dir = purple_log_get_log_dir(log->type, log->name, log->account);
- gchar *name;
- gchar *filename;
-
- if (dir == NULL)
- return;
-
- 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);
-
- name = g_strdup_printf("%s%s%s", date, tz, ext ? ext : "");
-
- purple_build_dir (dir, S_IRUSR | S_IWUSR | S_IXUSR);
-
- filename = g_build_filename(dir, name, NULL);
- g_free(dir);
- g_free(name);
-
- log->logger_data = g_fopen(filename, "a");
- if (!log->logger_data) {
- purple_debug(PURPLE_DEBUG_ERROR, "log", "Could not create log file %s\n", filename);
- g_free(filename);
- return;
- }
- g_free(filename);
- fprintf(log->logger_data, "<?xml version='1.0' encoding='UTF-8' ?>\n"
- "<?xml-stylesheet href='file:///usr/src/web/htdocs/log-stylesheet.xsl' type='text/xml' ?>\n");
-
- date = purple_utf8_strftime("%Y-%m-%d %H:%M:%S", localtime(&log->time));
- fprintf(log->logger_data, "<conversation time='%s' screenname='%s' protocol='%s'>\n",
- date, log->name, prpl);
- }
-
- /* if we can't write to the file, give up before we hurt ourselves */
- if(!data->file)
- return;
-
- date = log_get_timestamp(log, time);
-
- purple_markup_html_to_xhtml(message, &xhtml, NULL);
- if (from)
- fprintf(log->logger_data, "<message %s %s from='%s' time='%s'>%s</message>\n",
- str_from_msg_type(type),
- type & PURPLE_MESSAGE_SEND ? "direction='sent'" :
- type & PURPLE_MESSAGE_RECV ? "direction='received'" : "",
- from, date, xhtml);
- else
- fprintf(log->logger_data, "<message %s %s time='%s'>%s</message>\n",
- str_from_msg_type(type),
- type & PURPLE_MESSAGE_SEND ? "direction='sent'" :
- type & PURPLE_MESSAGE_RECV ? "direction='received'" : "",
- date, xhtml):
- fflush(log->logger_data);
- g_free(date);
- g_free(xhtml);
-}
-
- static void
- xml_logger_finalize(PurpleLog *log)
-{
- if (log->logger_data) {
- fprintf(log->logger_data, "</conversation>\n");
- fclose(log->logger_data);
- log->logger_data = NULL;
- }
-}
-
-static GList *
-xml_logger_list(PurpleLogType type, const gchar *sn, PurpleAccount *account)
-{
- return purple_log_common_lister(type, sn, account, ".xml", &xml_logger);
-}
-
-static PurpleLogLogger xml_logger = {
- N_("XML"), "xml",
- NULL,
- xml_logger_write,
- xml_logger_finalize,
- xml_logger_list,
- NULL,
- NULL,
- NULL
-};
-#endif
-
-/****************************
- ** HTML LOGGER *************
- ****************************/
-
-static gsize
-html_logger_write(PurpleLog *log, PurpleMessageFlags type, const gchar *from, time_t time,
- const gchar *message)
-{
- PurpleLogCommonLoggerData *data;
- PurplePlugin *plugin;
- const gchar *date_full, *prpl;
- gchar *date, *escaped_from, *header, *image_corrected_msg, *msg_fixed;
- gsize written;
-
- plugin = purple_find_prpl(purple_account_get_protocol_id(log->account));
- data = log->logger_data;
- written = 0;
-
- if(!data) {
- prpl = PURPLE_PLUGIN_PROTOCOL_INFO(plugin)->list_icon(log->account, NULL);
- purple_log_common_writer(log, ".html");
-
- data = log->logger_data;
-
- /* if we can't write to the file, give up before we hurt ourselves */
- if(!data->file)
- return 0;
-
- date_full = purple_date_format_full(localtime(&log->time));
-
- written += fprintf(data->file, "<html><head>");
- written += fprintf(data->file, "<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">");
- written += fprintf(data->file, "<title>");
-
- if (log->type == PURPLE_LOG_SYSTEM)
- header = g_strdup_printf("System log for account %s (%s) connected at %s",
- purple_account_get_username(log->account), prpl, date_full);
- else
- header = g_strdup_printf("Conversation with %s at %s on %s (%s)",
- log->name, date_full, purple_account_get_username(log->account), prpl);
-
- written += fprintf(data->file, "%s", header);
- written += fprintf(data->file, "</title></head><body>");
- written += fprintf(data->file, "<h3>%s</h3>\n", header);
- g_free(header);
- }
-
- /* if we can't write to the file, give up before we hurt ourselves */
- if(!data->file)
- return 0;
-
- escaped_from = g_markup_escape_text(from, -1);
-
- image_corrected_msg = convert_image_tags(log, message);
- purple_markup_html_to_xhtml(image_corrected_msg, &msg_fixed, NULL);
-
- /* Yes, this breaks encapsulation. But it's a static function and
- * this saves a needless strdup(). */
- if (image_corrected_msg != message)
- g_free(image_corrected_msg);
-
- date = log_get_timestamp(log, time);
-
- if(log->type == PURPLE_LOG_SYSTEM){
- written += fprintf(data->file, "---- %s @ %s ----<br/>\n", msg_fixed, date);
- } else {
- if (type & PURPLE_MESSAGE_SYSTEM)
- written += fprintf(data->file, "<font size=\"2\">(%s)</font><b> %s</b><br/>\n", date, msg_fixed);
- else if (type & PURPLE_MESSAGE_RAW)
- written += fprintf(data->file, "<font size=\"2\">(%s)</font> %s<br/>\n", date, msg_fixed);
- else if (type & PURPLE_MESSAGE_ERROR)
- written += fprintf(data->file, "<font color=\"#FF0000\"><font size=\"2\">(%s)</font><b> %s</b></font><br/>\n", date, msg_fixed);
- else if (type & PURPLE_MESSAGE_WHISPER)
- written += fprintf(data->file, "<font color=\"#6C2585\"><font size=\"2\">(%s)</font><b> %s:</b></font> %s<br/>\n",
- date, escaped_from, msg_fixed);
- else if (type & PURPLE_MESSAGE_AUTO_RESP) {
- if (type & PURPLE_MESSAGE_SEND)
- written += fprintf(data->file, _("<font color=\"#16569E\"><font size=\"2\">(%s)</font> <b>%s <AUTO-REPLY>:</b></font> %s<br/>\n"), date, escaped_from, msg_fixed);
- else if (type & PURPLE_MESSAGE_RECV)
- written += fprintf(data->file, _("<font color=\"#A82F2F\"><font size=\"2\">(%s)</font> <b>%s <AUTO-REPLY>:</b></font> %s<br/>\n"), date, escaped_from, msg_fixed);
- } else if (type & PURPLE_MESSAGE_RECV) {
- if(purple_message_meify(msg_fixed, -1))
- written += fprintf(data->file, "<font color=\"#062585\"><font size=\"2\">(%s)</font> <b>***%s</b></font> %s<br/>\n",
- date, escaped_from, msg_fixed);
- else
- written += fprintf(data->file, "<font color=\"#A82F2F\"><font size=\"2\">(%s)</font> <b>%s:</b></font> %s<br/>\n",
- date, escaped_from, msg_fixed);
- } else if (type & PURPLE_MESSAGE_SEND) {
- if(purple_message_meify(msg_fixed, -1))
- written += fprintf(data->file, "<font color=\"#062585\"><font size=\"2\">(%s)</font> <b>***%s</b></font> %s<br/>\n",
- date, escaped_from, msg_fixed);
- else
- written += fprintf(data->file, "<font color=\"#16569E\"><font size=\"2\">(%s)</font> <b>%s:</b></font> %s<br/>\n",
- date, escaped_from, msg_fixed);
- } else {
- purple_debug_error("log", "Unhandled message type.\n");
- written += fprintf(data->file, "<font size=\"2\">(%s)</font><b> %s:</b></font> %s<br/>\n",
- date, escaped_from, msg_fixed);
- }
- }
-
- g_free(date);
- g_free(msg_fixed);
- g_free(escaped_from);
- fflush(data->file);
-
- return written;
-}
-
-static void
-html_logger_write_thread(GSimpleAsyncResult *simple, GObject *object, GCancellable *cancellable)
-{
- _purple_log_logger_write_callback_data *callback_data =
- g_simple_async_result_get_op_res_gpointer(simple);
- PurpleLog *log = callback_data->log;
- PurpleLogCommonLoggerData *data = log->logger_data;
- PurpleLogType type = callback_data->type;
- GError *err = NULL;
GFile *file;
- GFileOutputStream *stream;
- GOutputStream *out_stream;
- gchar *date, *escaped_from, *message = callback_data->message, *from = callback_data->from;
- gchar *image_corrected_msg, *msg_fixed, *line;
- gssize written, size = 0;
- gboolean write_header;
+ GFileInfo *info;
+ gboolean ret;
- if (data == 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.
- */
- purple_log_common_writer(log, ".html");
- data = log->logger_data;
- write_header = TRUE;
- } else
- write_header = FALSE;
+ g_return_val_if_fail(PURPLE_IS_LOG(log), FALSE);
- /* If we can't write to the file, give up before we hurt ourselves */
- if (data == NULL || data->path == NULL) {
- g_simple_async_result_set_error(simple,
- G_IO_ERROR,
- G_IO_ERROR_FAILED,
- _("Unable to find log path"));
+ data = purple_log_get_logger_data(log);
- return;
- }
-
- file = g_file_new_for_path(data->path);
- stream = g_file_append_to(file, G_FILE_CREATE_NONE, cancellable, &err);
-
- if (stream == NULL) {
- g_simple_async_result_set_from_error(simple, err);
-
- g_object_unref(file);
- g_clear_error(&err);
-
- return;
- }
-
- g_clear_error(&err);
- out_stream = G_OUTPUT_STREAM(stream);
-
- if (write_header) {
- PurplePlugin *plugin;
- const gchar *prpl;
- const gchar *date_full;
- gchar *header;
-
- plugin = purple_find_prpl(purple_account_get_protocol_id(log->account));
- prpl = PURPLE_PLUGIN_PROTOCOL_INFO(plugin)->list_icon(log->account, NULL);
- date_full = purple_date_format_full(localtime(&log->time));
-
- if (log->type == PURPLE_LOG_SYSTEM)
- header = g_strdup_printf("System log for account %s (%s) connected at %s",
- purple_account_get_username(log->account), prpl, date_full);
- else
- header = g_strdup_printf("Conversation with %s at %s on %s (%s)",
- log->name, date_full,
- purple_account_get_username(log->account), prpl);
-
- line = g_strdup_printf("<html><head>"
- "<meta http-equiv=\"content-type\" "
- "content=\"text/html; charset=UTF-8\">"
- "<title>"
- "%s"
- "</title></head><body>"
- "<h3>%s</h3>\n",
- header, header);
-
- g_free(header);
-
- written = g_output_stream_write(out_stream, line,
- strlen(line), cancellable, &err);
- g_free(line);
-
- if (written < 0) {
- g_simple_async_result_set_from_error(simple, err);
-
- g_object_unref(file);
- g_object_unref(stream);
- g_clear_error(&err);
-
- return;
- }
-
- g_clear_error(&err);
- size += written;
- }
-
- escaped_from = g_markup_escape_text(from, -1);
- image_corrected_msg = convert_image_tags(log, message);
- purple_markup_html_to_xhtml(image_corrected_msg, &msg_fixed, NULL);
-
- /* Yes, this breaks encapsulation. But it's a static function and
- * this saves a needless strdup(). */
- if (image_corrected_msg != message)
- g_free(image_corrected_msg);
-
- date = log_get_timestamp(log, callback_data->time);
-
- if(log->type == PURPLE_LOG_SYSTEM){
- line = g_strdup_printf("---- %s @ %s ----<br/>\n", msg_fixed, date);
- } else {
- if (type & PURPLE_MESSAGE_SYSTEM)
- line = g_strdup_printf("<font size=\"2\">(%s)</font><b> %s</b><br/>\n", date, msg_fixed);
- else if (type & PURPLE_MESSAGE_RAW)
- line = g_strdup_printf("<font size=\"2\">(%s)</font> %s<br/>\n",
- date, msg_fixed);
- else if (type & PURPLE_MESSAGE_ERROR)
- line = g_strdup_printf("<font color=\"#FF0000\"><font "
- "size=\"2\">(%s)</font><b> %s</b></font><br/>\n",
- date, msg_fixed);
- else if (type & PURPLE_MESSAGE_WHISPER)
- line = g_strdup_printf("<font color=\"#6C2585\"><font "
- "size=\"2\">(%s)</font><b> %s:</b></font> %s<br/>\n",
- date, escaped_from, msg_fixed);
- else if (type & PURPLE_MESSAGE_AUTO_RESP) {
- if (type & PURPLE_MESSAGE_SEND)
- line = g_strdup_printf(_("<font color=\"#16569E\"><font "
- "size=\"2\">(%s)</font> <b>%s <AUTO-REPLY>:</b>"
- "</font> %s<br/>\n"), date, escaped_from, msg_fixed);
- else
- line = g_strdup_printf(_("<font color=\"#A82F2F\"><font "
- "size=\"2\">(%s)</font> <b>%s <AUTO-REPLY>:</b>"
- "</font> %s<br/>\n"), date, escaped_from, msg_fixed);
- } else if (type & PURPLE_MESSAGE_RECV) {
- if (purple_message_meify(msg_fixed, -1))
- line = g_strdup_printf("<font color=\"#062585\"><font "
- "size=\"2\">(%s)</font> <b>***%s</b></font> %s<br/>\n",
- date, escaped_from, msg_fixed);
- else
- line = g_strdup_printf("<font color=\"#A82F2F\"><font "
- "size=\"2\">(%s)</font> <b>%s:</b></font> %s<br/>\n",
- date, escaped_from, msg_fixed);
- } else if (type & PURPLE_MESSAGE_SEND) {
- if (purple_message_meify(msg_fixed, -1))
- line = g_strdup_printf("<font color=\"#062585\"><font "
- "size=\"2\">(%s)</font> <b>***%s</b></font> %s<br/>\n",
- date, escaped_from, msg_fixed);
- else
- line = g_strdup_printf("<font color=\"#16569E\"><font "
- "size=\"2\">(%s)</font> <b>%s:</b></font> %s<br/>\n",
- date, escaped_from, msg_fixed);
- } else {
- line = g_strdup_printf("<font size=\"2\">(%s)</font>"
- "<b> %s:</b></font> %s<br/>\n",
- date, escaped_from, msg_fixed);
- }
- }
-
- written = g_output_stream_write(out_stream, line, strlen(line),
- cancellable, &err);
-
- if (written < 0)
- g_simple_async_result_set_from_error(simple, err);
- else
- g_simple_async_result_set_op_res_gssize(simple, size + written);
-
- g_clear_error(&err);
- g_free(date);
- g_free(msg_fixed);
- g_free(escaped_from);
- g_object_unref(file);
- g_object_unref(stream);
-}
-
-static void
-html_logger_write_async(PurpleLog *log, PurpleMessageFlags type, const gchar *from, time_t time,
- const gchar *message, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb,
- gpointer userdata)
-{
- _purple_log_logger_write_callback_data *callback_data;
- GSimpleAsyncResult *simple;
-
- callback_data = g_new0(_purple_log_logger_write_callback_data, 1);
- callback_data->log = log;
- callback_data->type = type;
- callback_data->from = g_strdup(from);
- callback_data->time = time;
- callback_data->message = g_strdup(message);
-
- simple = g_simple_async_result_new(NULL, cb, userdata, purple_log_write_async);
-
- g_simple_async_result_set_op_res_gpointer(simple, callback_data,
- purple_log_logger_write_callback_data_free);
- g_simple_async_result_run_in_thread(simple, html_logger_write_thread,
- io_priority, cancellable);
-
- g_object_unref(simple);
-}
-
-static void
-html_logger_finalize(PurpleLog *log)
-{
- PurpleLogCommonLoggerData *data = log->logger_data;
-
- if (data != NULL) {
- if (data->file != NULL) {
- fprintf(data->file, "</body></html>\n");
- fclose(data->file);
- }
-
- g_free(data->path);
- g_slice_free(PurpleLogCommonLoggerData, data);
- }
-}
-
-static GList *
-html_logger_list(PurpleLogType type, const gchar *sn, PurpleAccount *account)
-{
- GList *list;
-
- G_LOCK(html_logger);
- list = purple_log_common_lister(type, sn, account, ".html", html_logger);
- G_UNLOCK(html_logger);
-
- return list;
-}
-
-static void
-html_logger_list_async(PurpleLogType type, const gchar *sn, PurpleAccount *account,
- gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
-{
- G_LOCK(html_logger);
- purple_log_common_lister_async(type, sn, account, ".html", html_logger,
- io_priority, cancellable, cb, userdata);
- G_UNLOCK(html_logger);
-}
-
-static GList *
-html_logger_list_syslog(PurpleAccount *account)
-{
- GList *list;
-
- G_LOCK(html_logger);
- list = purple_log_common_lister(PURPLE_LOG_SYSTEM, ".system", account, ".html", html_logger);
- G_UNLOCK(html_logger);
-
- return list;
-}
-
-static void
-html_logger_list_syslog_async(PurpleAccount *account, gint io_priority,
- GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
-{
- G_LOCK(html_logger);
- purple_log_common_lister_async(PURPLE_LOG_SYSTEM, ".system", account, ".html", html_logger,
- io_priority, cancellable, cb, userdata);
- G_UNLOCK(html_logger);
-}
-
-static gchar *
-html_logger_read(PurpleLog *log, PurpleLogReadFlags *flags)
-{
- PurpleLogCommonLoggerData *data;
- gchar *read, *minus_header;
-
- data = log->logger_data;
-
- if (flags != NULL)
- *flags = PURPLE_LOG_READ_NO_NEWLINE;
-
- if (!data || !data->path)
- return g_strdup_printf("<font color=\"red\"><b>%s</b></font>",
- _("Unable to find log path"));
-
- if (g_file_get_contents(data->path, &read, NULL, NULL)) {
- minus_header = strchr(read, '\n');
-
- if (!minus_header)
- return read;
-
- minus_header = g_strdup(minus_header + 1);
- g_free(read);
-
- return minus_header;
- }
-
- return g_strdup_printf("<font color=\"red\"><b>%s: %s</b></font>",
- _("Could not read file"), data->path);
-}
-
-static void
-html_logger_read_thread(GSimpleAsyncResult *simple, GObject *object, GCancellable *cancellable)
-{
- _purple_log_logger_read_callback_data *callback_data =
- g_simple_async_result_get_op_res_gpointer(simple);
- PurpleLog *log = callback_data->log;
- PurpleLogCommonLoggerData *data = log->logger_data;
- PurpleLogReadFlags *flags = callback_data->flags;
- GError *err = NULL;
- GFile *file;
- gchar *read, *minus_header;
-
- if (flags != NULL)
- *flags = PURPLE_LOG_READ_NO_NEWLINE;
-
if (data == NULL || data->path == NULL) {
- g_simple_async_result_set_error(simple,
- G_FILE_ERROR,
- G_IO_ERROR_NOT_FOUND,
- "<font color=\"red\"><b>%s</b></font>",
- _("Unable to find log path"));
-
- return;
- }
-
- file = g_file_new_for_path(data->path);
-
- if (!g_file_load_contents(file, cancellable, &read, NULL, NULL, &err)) {
- g_simple_async_result_set_error(simple,
- err->domain,
- err->code,
- "<font color=\"red\"><b>%s</b></font>",
- err->message);
-
- g_clear_error(&err);
-
- return;
- }
-
- g_clear_error(&err);
-
- minus_header = strchr(read, '\n');
-
- if (minus_header == NULL)
- minus_header = read;
- else {
- minus_header = g_strdup(minus_header + 1);
- g_free(read);
- }
-
- purple_str_strip_char(minus_header, '\r');
-
- g_simple_async_result_set_op_res_gpointer(simple, minus_header, g_free);
-}
-
-static void
-html_logger_read_async(PurpleLog *log, PurpleLogReadFlags *flags, gint io_priority,
- GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
-{
- _purple_log_logger_read_callback_data *callback_data;
- GSimpleAsyncResult *simple;
-
- callback_data = g_new0(_purple_log_logger_read_callback_data, 1);
- callback_data->flags = flags;
- callback_data->log = log;
-
- simple = g_simple_async_result_new(NULL, cb, userdata, purple_log_read_async);
-
- g_simple_async_result_set_op_res_gpointer(simple, callback_data, g_free);
- g_simple_async_result_run_in_thread(simple, html_logger_read_thread,
- io_priority, cancellable);
-
- g_object_unref(simple);
-}
-
-static gint
-html_logger_total_size(PurpleLogType type, const gchar *name, PurpleAccount *account)
-{
- return purple_log_common_total_sizer(type, name, account, ".html");
-}
-
-static void
-html_logger_total_size_async(PurpleLogType type, const gchar *name, PurpleAccount *account,
- gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
-{
- purple_log_common_total_sizer_async(type, name, account, ".html",
- io_priority, cancellable, cb, userdata);
-}
-
-
-/****************************
- ** PLAIN TEXT LOGGER *******
- ****************************/
-
-static gsize
-txt_logger_write(PurpleLog *log, PurpleMessageFlags type, const gchar *from, time_t time,
- const gchar *message)
-{
- PurplePlugin *plugin;
- PurpleLogCommonLoggerData *data;
- const gchar *prpl;
- gchar *stripped, *date;
- gsize written;
-
- plugin = purple_find_prpl(purple_account_get_protocol_id(log->account));
- data = log->logger_data;
- stripped = NULL;
- written = 0;
-
- if (data == 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.
- */
- prpl = PURPLE_PLUGIN_PROTOCOL_INFO(plugin)->list_icon(log->account, NULL);
- purple_log_common_writer(log, ".txt");
-
- data = log->logger_data;
-
- /* if we can't write to the file, give up before we hurt ourselves */
- if(!data->file)
- return 0;
-
- if (log->type == PURPLE_LOG_SYSTEM)
- written += fprintf(data->file, "System log for account %s (%s) connected at %s\n",
- purple_account_get_username(log->account), prpl,
- purple_date_format_full(localtime(&log->time)));
- else
- written += fprintf(data->file, "Conversation with %s at %s on %s (%s)\n",
- log->name, purple_date_format_full(localtime(&log->time)),
- purple_account_get_username(log->account), prpl);
- }
-
- /* if we can't write to the file, give up before we hurt ourselves */
- if(!data->file)
- return 0;
-
- stripped = purple_markup_strip_html(message);
- date = log_get_timestamp(log, time);
-
- if(log->type == PURPLE_LOG_SYSTEM){
- written += fprintf(data->file, "---- %s @ %s ----\n", stripped, date);
- } else {
- if (type & PURPLE_MESSAGE_SEND ||
- type & PURPLE_MESSAGE_RECV) {
- if (type & PURPLE_MESSAGE_AUTO_RESP) {
- written += fprintf(data->file, _("(%s) %s <AUTO-REPLY>: %s\n"), date,
- from, stripped);
- } else {
- if (purple_message_meify(stripped, -1))
- written += fprintf(data->file, "(%s) ***%s %s\n", date, from, stripped);
- else
- written += fprintf(data->file, "(%s) %s: %s\n", date, from, stripped);
- }
- } else if (type & PURPLE_MESSAGE_SYSTEM ||
- type & PURPLE_MESSAGE_ERROR ||
- type & PURPLE_MESSAGE_RAW)
- written += fprintf(data->file, "(%s) %s\n", date, stripped);
- else if (type & PURPLE_MESSAGE_NO_LOG) {
- /* This shouldn't happen */
- g_free(stripped);
-
- return written;
- } else if (type & PURPLE_MESSAGE_WHISPER)
- written += fprintf(data->file, "(%s) *%s* %s", date, from, stripped);
- else
- written += fprintf(data->file, "(%s) %s%s %s\n", date, from ? from : "",
- from ? ":" : "", stripped);
- }
-
- g_free(date);
- g_free(stripped);
- fflush(data->file);
-
- return written;
-}
-
-static void
-txt_logger_write_thread(GSimpleAsyncResult *simple, GObject *object, GCancellable *cancellable)
-{
- _purple_log_logger_write_callback_data *callback_data =
- g_simple_async_result_get_op_res_gpointer(simple);
- PurpleLog *log = callback_data->log;
- PurpleLogCommonLoggerData *data = log->logger_data;
- PurpleLogType type = callback_data->type;
- GError *err = NULL;
- GFile *file;
- GFileOutputStream *stream;
- GOutputStream *out_stream;
- const gchar *from = callback_data->from, *message = callback_data->message;
- gchar *stripped = NULL, *date, *line;
- gssize written, size = 0;
- gboolean write_header;
-
- if (type & PURPLE_MESSAGE_NO_LOG) {
- g_simple_async_result_set_error(simple,
+ g_set_error_literal(error,
G_IO_ERROR,
G_IO_ERROR_FAILED,
- _("Trying to log when flagged not to"));
+ _("Unable to get log path"));
- return;
+ return FALSE;
}
- if (data == 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.
- */
- purple_log_common_writer(log, ".txt");
- data = log->logger_data;
- 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) {
- g_simple_async_result_set_error(simple,
- G_IO_ERROR,
- G_IO_ERROR_FAILED,
- _("Unable to find log path"));
-
- return;
- }
-
+ //file = data->file;
file = g_file_new_for_path(data->path);
- stream = g_file_append_to(file, G_FILE_CREATE_NONE, cancellable, &err);
+ info = g_file_query_info(file, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE,
+ G_FILE_QUERY_INFO_NONE, cancellable, error);
- if (stream == NULL) {
- g_simple_async_result_set_from_error(simple, err);
-
+ if (info == NULL) {
g_object_unref(file);
- g_clear_error(&err);
-
- return;
+ return FALSE;
}
- g_clear_error(&err);
- out_stream = G_OUTPUT_STREAM(stream);
+ ret = g_file_info_get_attribute_boolean(info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE);
- if (write_header) {
- PurplePlugin *plugin;
- const gchar *prpl;
-
- plugin = purple_find_prpl(purple_account_get_protocol_id(log->account));
- prpl = PURPLE_PLUGIN_PROTOCOL_INFO(plugin)->list_icon(log->account, NULL);
-
- if (log->type == PURPLE_LOG_SYSTEM)
- line = g_strdup_printf("System log for account %s (%s) connected at %s\n",
- purple_account_get_username(log->account), prpl,
- purple_date_format_full(localtime(&log->time)));
- else
- line = g_strdup_printf("Conversation with %s at %s on %s (%s)\n",
- log->name, purple_date_format_full(localtime(&log->time)),
- purple_account_get_username(log->account), prpl);
-
- written = g_output_stream_write(out_stream, line,
- strlen(line), cancellable, &err);
- g_free(line);
-
- if (written < 0) {
- g_simple_async_result_set_from_error(simple, err);
-
- g_object_unref(file);
- g_object_unref(stream);
- g_clear_error(&err);
-
- return;
- }
-
- g_clear_error(&err);
- size += written;
- }
-
- stripped = purple_markup_strip_html(message);
- date = log_get_timestamp(log, callback_data->time);
-
- if (log->type == PURPLE_LOG_SYSTEM)
- line = g_strdup_printf("---- %s @ %s ----\n", stripped, date);
- else {
- if (type & PURPLE_MESSAGE_SEND ||
- type & PURPLE_MESSAGE_RECV)
- {
- if (type & PURPLE_MESSAGE_AUTO_RESP)
- line = g_strdup_printf(_("(%s) %s <AUTO-REPLY>: %s\n"), date, from, stripped);
- else {
- if (purple_message_meify(stripped, -1))
- line = g_strdup_printf("(%s) ***%s %s\n", date, from, stripped);
- else
- line = g_strdup_printf("(%s) %s: %s\n", date, from, stripped);
- }
- } else if (type & PURPLE_MESSAGE_SYSTEM ||
- type & PURPLE_MESSAGE_ERROR ||
- type & PURPLE_MESSAGE_RAW)
- line = g_strdup_printf("(%s) %s\n", date, stripped);
- else if (type & PURPLE_MESSAGE_WHISPER)
- line = g_strdup_printf("(%s) *%s* %s", date, from, stripped);
- else
- line = g_strdup_printf("(%s) %s%s %s\n", date, from ? from : "",
- from ? ":" : "", stripped);
- }
-
- written = g_output_stream_write(out_stream, line, strlen(line),
- cancellable, &err);
-
- if (written < 0)
- g_simple_async_result_set_from_error(simple, err);
- else
- g_simple_async_result_set_op_res_gssize(simple, size + written);
-
- g_clear_error(&err);
- g_free(line);
- g_free(date);
- g_free(stripped);
+ g_object_unref(info);
g_object_unref(file);
- g_object_unref(stream);
-}
-static void
-txt_logger_write_async(PurpleLog *log, PurpleMessageFlags type, const gchar *from, time_t time,
- const gchar *message, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb,
- gpointer userdata)
-{
- _purple_log_logger_write_callback_data *callback_data;
- GSimpleAsyncResult *simple;
-
- callback_data = g_new0(_purple_log_logger_write_callback_data, 1);
- callback_data->log = log;
- callback_data->type = type;
- callback_data->from = g_strdup(from);
- callback_data->time = time;
- callback_data->message = g_strdup(message);
-
- simple = g_simple_async_result_new(NULL, cb, userdata, purple_log_write_async);
-
- g_simple_async_result_set_op_res_gpointer(simple, callback_data,
- purple_log_logger_write_callback_data_free);
- g_simple_async_result_run_in_thread(simple, txt_logger_write_thread,
- io_priority, cancellable);
-
- g_object_unref(simple);
+ return ret;
}
static void
-txt_logger_finalize(PurpleLog *log)
+purple_log_finalize(GObject *object)
{
- PurpleLogCommonLoggerData *data = log->logger_data;
+ PurpleLog *log = PURPLE_LOG(object);
+ PurpleLogPrivate *priv = PURPLE_LOG_GET_PRIVATE(log);
- if (data != NULL) {
- if (data->file != NULL)
- fclose(data->file);
+ g_free(priv->name);
- g_free(data->path);
- g_slice_free(PurpleLogCommonLoggerData, data);
- }
-}
-
-static GList *
-txt_logger_list(PurpleLogType type, const gchar *sn, PurpleAccount *account)
-{
- GList *list;
-
- G_LOCK(txt_logger);
- list = purple_log_common_lister(type, sn, account, ".txt", txt_logger);
- G_UNLOCK(txt_logger);
-
- return list;
-}
-
-static void
-txt_logger_list_async(PurpleLogType type, const gchar *sn, PurpleAccount *account,
- gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
-{
- G_LOCK(txt_logger);
- purple_log_common_lister_async(type, sn, account, ".txt", txt_logger,
- io_priority, cancellable, cb, userdata);
- G_UNLOCK(txt_logger);
-}
-
-static GList *
-txt_logger_list_syslog(PurpleAccount *account)
-{
- GList *list;
-
- G_LOCK(txt_logger);
- list = purple_log_common_lister(PURPLE_LOG_SYSTEM, ".system", account, ".txt", txt_logger);
- G_UNLOCK(txt_logger);
-
- return list;
-}
-
-static void
-txt_logger_list_syslog_async(PurpleAccount *account, gint io_priority, GCancellable *cancellable,
- GAsyncReadyCallback cb, gpointer userdata)
-{
- G_LOCK(txt_logger);
- purple_log_common_lister_async(PURPLE_LOG_SYSTEM, ".system", account, ".txt", txt_logger,
- io_priority, cancellable, cb, userdata);
- G_UNLOCK(txt_logger);
-}
-
-static gchar *
-txt_logger_read(PurpleLog *log, PurpleLogReadFlags *flags)
-{
- PurpleLogCommonLoggerData *data;
- gchar *read, *minus_header;
-
- data = log->logger_data;
-
- if (flags != NULL)
- *flags = 0;
-
- if (!data || !data->path)
- return g_strdup_printf("<font color=\"red\"><b>%s</b></font>",
- _("Unable to find log path"));
-
- if (g_file_get_contents(data->path, &read, NULL, NULL)) {
- minus_header = strchr(read, '\n');
-
- if (minus_header)
- return process_txt_log(minus_header + 1, read);
- else
- return process_txt_log(read, NULL);
- }
-
- return g_strdup_printf("<font color=\"red\"><b>%s: %s</b></font>",
- _("Could not read file"), data->path);
-}
-
-static void
-txt_logger_read_thread(GSimpleAsyncResult *simple, GObject *object, GCancellable *cancellable)
-{
- _purple_log_logger_read_callback_data *callback_data =
- g_simple_async_result_get_op_res_gpointer(simple);
- PurpleLog *log = callback_data->log;
- PurpleLogCommonLoggerData *data = log->logger_data;
- PurpleLogReadFlags *flags = callback_data->flags;
- GError *err = NULL;
- GFile *file;
- gchar *read, *minus_header;
-
- if (flags != NULL)
- *flags = 0;
-
- if (data == NULL || data->path == NULL) {
- g_simple_async_result_set_error(simple,
- G_FILE_ERROR,
- G_IO_ERROR_NOT_FOUND,
- "<font color=\"red\"><b>%s</b></font>",
- _("Unable to find log path"));
-
- return;
- }
-
- file = g_file_new_for_path(data->path);
-
- if (!g_file_load_contents(file, cancellable, &read, NULL, NULL, &err)) {
- g_simple_async_result_set_error(simple,
- err->domain,
- err->code,
- "<font color=\"red\"><b>%s</b></font>",
- err->message);
-
- g_clear_error(&err);
-
- return;
- }
-
- g_clear_error(&err);
-
- minus_header = strchr(read, '\n');
-
- if (minus_header != NULL)
- read = process_txt_log(minus_header + 1, read);
- else
- read = process_txt_log(read, NULL);
-
- purple_str_strip_char(read, '\r');
-
- g_simple_async_result_set_op_res_gpointer(simple, read, g_free);
-}
-
-static void
-txt_logger_read_async(PurpleLog *log, PurpleLogReadFlags *flags, gint io_priority,
- GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
-{
- _purple_log_logger_read_callback_data *callback_data;
- GSimpleAsyncResult *simple;
-
- callback_data = g_new0(_purple_log_logger_read_callback_data, 1);
- callback_data->flags = flags;
- callback_data->log = log;
-
- simple = g_simple_async_result_new(NULL, cb, userdata, purple_log_read_async);
-
- g_simple_async_result_set_op_res_gpointer(simple, callback_data, g_free);
- g_simple_async_result_run_in_thread(simple, txt_logger_read_thread,
- io_priority, cancellable);
-
- g_object_unref(simple);
-}
-
-static gint
-txt_logger_total_size(PurpleLogType type, const gchar *name, PurpleAccount *account)
-{
- return purple_log_common_total_sizer(type, name, account, ".txt");
-}
-
-static void
-txt_logger_total_size_async(PurpleLogType type, const gchar *name, PurpleAccount *account,
- gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
-{
- purple_log_common_total_sizer_async(type, name, account, ".txt",
- io_priority, cancellable, cb, userdata);
-}
-
-
-/****************
- * OLD LOGGER ***
- ****************/
-
-/* The old logger doesn't write logs, only reads them. This is to include
- * old logs in the log viewer transparently.
- */
-
-typedef struct {
- PurpleStringref *pathref;
- gint offset;
- gint length;
-} old_logger_data;
-
-static GList *
-old_logger_list(PurpleLogType type, const gchar *sn, PurpleAccount *account)
-{
- old_logger_data *data;
- PurpleStringref *pathref;
- PurpleLog *log;
- GList *list;
- FILE *index, *file;
- time_t log_last_modified, lasttime;
- struct stat st;
- struct tm tm;
- gchar *logfile, *pathstr, *index_tmp, buf[BUF_LONG], month[4], convostart[32], *temp;
- gint index_fd, logfound, lastoff, newlen, length, offset;
- gulong idx_time;
-
- logfile = g_strdup_printf("%s.log", purple_normalize(account, sn));
- pathstr = g_build_filename(purple_user_dir(), "logs", logfile, NULL);
- pathref = purple_stringref_new(pathstr);
- g_free(logfile);
-
- log = NULL;
- list = NULL;
- data = NULL;
-
- logfound = 0;
- lastoff = 0;
- lasttime = 0;
-
- if (g_stat(purple_stringref_value(pathref), &st)) {
- purple_stringref_unref(pathref);
- g_free(pathstr);
-
- return NULL;
- } else
- log_last_modified = st.st_mtime;
-
- /* Change the .log extension to .idx */
- strcpy(pathstr + strlen(pathstr) - 3, "idx");
-
- if (g_stat(pathstr, &st) == 0) {
- if (st.st_mtime < log_last_modified) {
- purple_debug_warning("log", "Index \"%s\" exists, but is older than the log.\n", pathstr);
- } else {
- /* The index file exists and is at least as new as the log, so open it. */
- if (!(index = g_fopen(pathstr, "rb")))
- {
- purple_debug_error("log", "Failed to open index file \"%s\" for reading: %s\n",
- pathstr, g_strerror(errno));
-
- /* Fall through so that we'll parse the log file. */
- } else {
- purple_debug_info("log", "Using index: %s\n", pathstr);
- g_free(pathstr);
-
- while (fgets(buf, BUF_LONG, index)) {
- if (sscanf(buf, "%d\t%d\t%lu", &lastoff, &newlen, &idx_time) == 3) {
- log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, -1, NULL);
- log->time = (time_t) idx_time;
-
- G_LOCK(old_logger);
- log->logger = old_logger;
- G_UNLOCK(old_logger);
-
- /* IMPORTANT: Always set all members of old_logger_data */
- data = g_slice_new(old_logger_data);
-
- data->pathref = purple_stringref_ref(pathref);
- data->offset = lastoff;
- data->length = newlen;
-
- log->logger_data = data;
- list = g_list_prepend(list, log);
- }
- }
-
- fclose(index);
- purple_stringref_unref(pathref);
-
- return list;
- }
- }
- }
-
- if (!(file = g_fopen(purple_stringref_value(pathref), "rb"))) {
- purple_debug_error("log", "Failed to open log file \"%s\" for reading: %s\n",
- purple_stringref_value(pathref), g_strerror(errno));
- purple_stringref_unref(pathref);
- g_free(pathstr);
-
- return NULL;
- }
-
- index_tmp = g_strdup_printf("%s.XXXXXX", pathstr);
-
- if ((index_fd = g_mkstemp(index_tmp)) == -1) {
- purple_debug_error("log", "Failed to open index temp file: %s\n",
- g_strerror(errno));
-
- g_free(pathstr);
- g_free(index_tmp);
- index = NULL;
- } else {
- index = fdopen(index_fd, "wb");
-
- if (index == NULL) {
- purple_debug_error("log", "Failed to fdopen() index temp file: %s\n",
- g_strerror(errno));
- close(index_fd);
-
- if (index_tmp != NULL) {
- g_unlink(index_tmp);
- g_free(index_tmp);
- }
-
- g_free(pathstr);
- }
- }
-
- while (fgets(buf, BUF_LONG, file)) {
- if (strstr(buf, "---- New C") != NULL) {
- temp = strchr(buf, '@');
-
- if (temp == NULL || strlen(temp) < 2)
- continue;
-
- temp++;
- length = strcspn(temp, "-");
- if (length > 31) length = 31;
-
- offset = ftell(file);
-
- if (logfound) {
- newlen = offset - lastoff - length;
- if(strstr(buf, "----</H3><BR>")) {
- newlen -=
- sizeof("<HR><BR><H3 Align=Center> ---- New Conversation @ ") +
- sizeof("----</H3><BR>") - 2;
- } else {
- newlen -= sizeof("---- New Conversation @ ") + sizeof("----") - 2;
- }
-
- if(strchr(buf, '\r'))
- newlen--;
-
- if (newlen != 0) {
- log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, -1, NULL);
- log->time = lasttime;
-
- G_LOCK(old_logger);
- log->logger = old_logger;
- G_UNLOCK(old_logger);
-
- /* IMPORTANT: Always set all members of old_logger_data */
- data = g_slice_new(old_logger_data);
-
- data->pathref = purple_stringref_ref(pathref);
- data->offset = lastoff;
- data->length = newlen;
-
- log->logger_data = data;
- list = g_list_prepend(list, log);
-
- /* XXX: There is apparently Is there a proper way to print a time_t? */
- if (index != NULL)
- fprintf(index, "%d\t%d\t%lu\n", data->offset, data->length,
- (unsigned long)log->time);
- }
- }
-
- logfound = 1;
- lastoff = offset;
-
- g_snprintf(convostart, length, "%s", temp);
- memset(&tm, 0, sizeof(tm));
- sscanf(convostart, "%*s %s %d %d:%d:%d %d", month, &tm.tm_mday,
- &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &tm.tm_year);
-
- /* Ugly hack, in case current locale is not English */
- if (purple_strequal(month, "Jan")) {
- tm.tm_mon= 0;
- } else if (purple_strequal(month, "Feb")) {
- tm.tm_mon = 1;
- } else if (purple_strequal(month, "Mar")) {
- tm.tm_mon = 2;
- } else if (purple_strequal(month, "Apr")) {
- tm.tm_mon = 3;
- } else if (purple_strequal(month, "May")) {
- tm.tm_mon = 4;
- } else if (purple_strequal(month, "Jun")) {
- tm.tm_mon = 5;
- } else if (purple_strequal(month, "Jul")) {
- tm.tm_mon = 6;
- } else if (purple_strequal(month, "Aug")) {
- tm.tm_mon = 7;
- } else if (purple_strequal(month, "Sep")) {
- tm.tm_mon = 8;
- } else if (purple_strequal(month, "Oct")) {
- tm.tm_mon = 9;
- } else if (purple_strequal(month, "Nov")) {
- tm.tm_mon = 10;
- } else if (purple_strequal(month, "Dec")) {
- tm.tm_mon = 11;
- }
- tm.tm_year -= 1900;
- lasttime = mktime(&tm);
- }
- }
-
- if (logfound) {
- if ((newlen = ftell(file) - lastoff) != 0) {
- log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, -1, NULL);
- log->time = lasttime;
-
- G_LOCK(old_logger);
- log->logger = old_logger;
- G_UNLOCK(old_logger);
-
- /* IMPORTANT: Always set all members of old_logger_data */
- data = g_slice_new(old_logger_data);
-
- data->pathref = purple_stringref_ref(pathref);
- data->offset = lastoff;
- data->length = newlen;
-
- log->logger_data = data;
- list = g_list_prepend(list, log);
-
- /* XXX: Is there a proper way to print a time_t? */
- if (index != NULL)
- fprintf(index, "%d\t%d\t%d\n", data->offset, data->length, (gint) log->time);
- }
- }
-
- purple_stringref_unref(pathref);
- fclose(file);
-
- if (index != NULL) {
- fclose(index);
-
- if (index_tmp == NULL) {
- g_free(pathstr);
- g_return_val_if_reached(list);
- }
-
- if (g_rename(index_tmp, pathstr)) {
- purple_debug_warning("log", "Failed to rename index temp file \"%s\" to \"%s\": %s\n",
- index_tmp, pathstr, g_strerror(errno));
- g_unlink(index_tmp);
- } else
- purple_debug_info("log", "Built index: %s\n", pathstr);
-
- g_free(index_tmp);
- g_free(pathstr);
- }
-
- return list;
-}
-
-static gint
-old_logger_total_size(PurpleLogType type, const gchar *name, PurpleAccount *account)
-{
- gchar *logfile, *pathstr;
- gint size;
- struct stat st;
-
- logfile = g_strdup_printf("%s.log", purple_normalize(account, name));
- pathstr = g_build_filename(purple_user_dir(), "logs", logfile, NULL);
-
- if (g_stat(pathstr, &st))
- size = 0;
- else
- size = st.st_size;
-
- g_free(logfile);
- g_free(pathstr);
-
- return size;
-}
-
-static gchar *
-old_logger_read(PurpleLog *log, PurpleLogReadFlags *flags)
-{
- size_t result;
- old_logger_data *data;
- const gchar *path;
- FILE *file;
- gchar *read;
-
- data = log->logger_data;
- path = purple_stringref_value(data->pathref);
- file = g_fopen(path, "rb");
- read = g_malloc(data->length + 1);
-
- fseek(file, data->offset, SEEK_SET);
- result = fread(read, data->length, 1, file);
-
- if (result != 1)
- purple_debug_error("log", "Unable to read from log file: %s\n", path);
-
- fclose(file);
- read[data->length] = '\0';
-
- if (flags != NULL)
- *flags = 0;
-
- if (strstr(read, "<BR>")) {
- if (flags != NULL)
- *flags |= PURPLE_LOG_READ_NO_NEWLINE;
-
- return read;
- }
-
- return process_txt_log(read, NULL);
-}
-
-static gint
-old_logger_size(PurpleLog *log)
-{
- old_logger_data *data;
-
- data = log->logger_data;
-
- return data ? data->length : 0;
-}
-
-static void
-old_logger_get_log_sets(PurpleLogSetCallback cb, GHashTable *sets)
-{
- PurpleBlistNode *gnode, *cnode, *bnode;
- PurpleBuddy *buddy;
- PurpleLogSet *set;
- GDir *log_dir;
- gchar *log_path, *name, *tmp, *ext;
- size_t len;
- gboolean found;
-
- log_path = g_build_filename(purple_user_dir(), "logs", NULL);
- log_dir = g_dir_open(log_path, 0, NULL);
- g_free(log_path);
-
- if (log_dir == NULL)
- return;
-
- /* Don't worry about the cast, name will be filled with a dynamically allocated data shortly. */
- while ((name = (gchar *) g_dir_read_name(log_dir)) != NULL) {
- found = FALSE;
-
- /* Unescape the filename. */
- name = g_strdup(purple_unescape_filename(name));
-
- /* Get the (possibly new) length of name. */
- len = strlen(name);
-
- if (len < 5) {
- g_free(name);
- continue;
- }
-
- /* Make sure we're dealing with a log file. */
- ext = &name[len - 4];
- if (!purple_strequal(ext, ".log")) {
- g_free(name);
- continue;
- }
-
- /* IMPORTANT: Always set all members of PurpleLogSet */
- set = g_slice_new(PurpleLogSet);
-
- /* Chat for .chat at the end of the name to determine the type. */
- *ext = '\0';
- set->type = PURPLE_LOG_IM;
-
- if (len > 9) {
- tmp = &name[len - 9];
- if (purple_strequal(tmp, ".chat")) {
- set->type = PURPLE_LOG_CHAT;
- *tmp = '\0';
- }
- }
-
- set->name = set->normalized_name = name;
-
- /* Search the buddy list to find the account and to determine if this is a buddy. */
- for (gnode = purple_blist_get_root();
- !found && gnode != NULL;
- gnode = purple_blist_node_get_sibling_next(gnode)) {
- if (!PURPLE_BLIST_NODE_IS_GROUP(gnode))
- continue;
-
- for (cnode = purple_blist_node_get_first_child(gnode);
- !found && cnode != NULL;
- cnode = purple_blist_node_get_sibling_next(cnode)) {
- if (!PURPLE_BLIST_NODE_IS_CONTACT(cnode))
- continue;
-
- for (bnode = purple_blist_node_get_first_child(cnode);
- !found && bnode != NULL;
- bnode = purple_blist_node_get_sibling_next(bnode)) {
- buddy = (PurpleBuddy *) bnode;
-
- if (purple_strequal(purple_buddy_get_name(buddy), name)) {
- set->account = purple_buddy_get_account(buddy);
- set->buddy = TRUE;
- found = TRUE;
- }
- }
- }
- }
-
- if (!found) {
- set->account = NULL;
- set->buddy = FALSE;
- }
-
- cb(sets, set);
- }
-
- g_dir_close(log_dir);
-}
-
-static void
-old_logger_finalize(PurpleLog *log)
-{
- old_logger_data *data;
-
- data = log->logger_data;
- purple_stringref_unref(data->pathref);
- g_slice_free(old_logger_data, data);
-}
-
-static void
-log_delete_cb(GObject *object, GAsyncResult *res, gpointer userdata)
-{
- _purple_log_free_callback_data *callback_data = userdata;
- PurpleLog *log = callback_data->log;
- GError *err = NULL;
-
- if (callback_data->cb)
- callback_data->cb(object, res, callback_data->userdata);
- else if (!purple_log_delete_finish(log, res, &err) && err->code != G_IO_ERROR_CANCELLED)
- purple_debug_error("log", "Error freeing log: %s\n", err->message);
-
- g_clear_error(&err);
- g_free(callback_data);
-}
-
-static void
-log_free_cb(GObject *object, GAsyncResult *res, gpointer userdata)
-{
- PurpleLog *log = userdata;
-
- g_free(log->name);
-
- if (log->tm != NULL) {
+ if (priv->tm != NULL) {
#ifdef HAVE_STRUCT_TM_TM_ZONE
/* XXX: This is so wrong... */
- g_free((gchar *) log->tm->tm_zone);
+ g_free((gchar *) priv->tm->tm_zone);
#endif
- g_slice_free(struct tm, log->tm);
+ g_slice_free(struct tm, priv->tm);
}
PURPLE_DBUS_UNREGISTER_POINTER(log);
- g_slice_free(PurpleLog, log);
+
+ G_OBJECT_CLASS(purple_log_parent_class)->finalize(object);
}
static void
log_list_cb(GObject *object, GAsyncResult *res, gpointer userdata)
{
- _purple_log_logs_callback_data *callback_data = userdata;
+ _get_logs_callback_data *callback_data = userdata;
+ PurpleLog *log = PURPLE_LOG(object);
GSimpleAsyncResult *simple;
GList *list, *n;
- list = purple_log_get_logs_finish(res, NULL);
+ list = purple_log_get_logs_finish(log, res, NULL);
callback_data->logs = g_list_concat(callback_data->logs, list);
callback_data->counter--;
@@ -4436,7 +3498,7 @@ log_list_cb(GObject *object, GAsyncResul
g_object_unref(simple);
} else {
for (n = callback_data->logs; n != NULL; n = g_list_next(n))
- purple_log_free(n->data);
+ g_object_unref(n->data);
g_list_free(callback_data->logs);
}
@@ -4448,11 +3510,12 @@ log_system_list_cb(GObject *object, GAsy
static void
log_system_list_cb(GObject *object, GAsyncResult *res, gpointer userdata)
{
- _purple_log_logs_callback_data *callback_data = userdata;
+ _get_logs_callback_data *callback_data = userdata;
+ PurpleLog *log = PURPLE_LOG(object);
GSimpleAsyncResult *simple;
GList *list, *n;
- list = purple_log_get_logs_finish(res, NULL);
+ list = purple_log_get_system_logs_finish(log, res, NULL);
callback_data->logs = g_list_concat(callback_data->logs, list);
callback_data->counter--;
@@ -4469,7 +3532,7 @@ log_system_list_cb(GObject *object, GAsy
g_object_unref(simple);
} else {
for (n = callback_data->logs; n != NULL; n = g_list_next(n))
- purple_log_free(n->data);
+ g_object_unref(n->data);
g_list_free(callback_data->logs);
}
@@ -4482,10 +3545,11 @@ log_total_size_cb(GObject *object, GAsyn
log_total_size_cb(GObject *object, GAsyncResult *res, gpointer userdata)
{
_purple_log_total_size_callback_data *callback_data = userdata;
+ PurpleLog *log = PURPLE_LOG(object);
GError *err = NULL;
gssize size;
- size = purple_log_get_total_size_finish(res, &err);
+ size = purple_log_get_total_size_finish(log, res, &err);
/* It's hard to pass all the errors up, so just log them :( */
if (size < 0 && err != NULL)
@@ -4518,38 +3582,16 @@ static void
}
static void
-log_total_size_intermediate_cb(GObject *object, GAsyncResult *res, gpointer userdata)
-{
- GSimpleAsyncResult *simple;
- GError *err = NULL;
- gssize size;
-
- size = purple_log_get_size_finish(object, res, &err);
-
- simple = g_simple_async_result_new(NULL, log_total_size_cb, userdata,
- purple_log_common_total_sizer_async);
-
- if (size < 0)
- g_simple_async_result_set_from_error(simple, err);
- else
- g_simple_async_result_set_op_res_gssize(simple, size);
-
- g_simple_async_result_complete_in_idle(simple);
-
- g_object_unref(simple);
- g_clear_error(&err);
-}
-
-static void
log_total_size_list_cb(GObject *object, GAsyncResult *res, gpointer userdata)
{
/* Gets the size for all the logs in the list as part of purple_log_get_total_size_async */
_purple_log_total_size_callback_data *callback_data = userdata;
+ PurpleLog *log = PURPLE_LOG(object);
GError *err = NULL;
GList *list, *n;
GSimpleAsyncResult *simple;
- list = purple_log_get_logs_finish(res, &err);
+ list = purple_log_get_logs_finish(log, res, &err);
if (list == NULL && err != NULL) {
simple = g_simple_async_result_new(NULL, log_total_size_cb,
@@ -4584,81 +3626,6 @@ static void
}
static void
-log_write_cb(GObject *object, GAsyncResult *res, gpointer userdata)
-{
- _purple_log_write_callback_data *callback_data = userdata;
- _purple_logsize_user *lu = callback_data->lu;
- PurpleLog *log = callback_data->log;
- GError *err = NULL;
- gpointer ptrsize;
- gsize total = 0;
- gssize size;
-
- size = purple_log_write_finish(log, res, &err);
-
- if (size > 0) {
- G_LOCK(logsize_users);
- if (g_hash_table_lookup_extended(logsize_users, lu, NULL, &ptrsize)) {
- total = GPOINTER_TO_INT(ptrsize);
- total += size;
- g_hash_table_replace(logsize_users, lu, GINT_TO_POINTER(total));
- } else {
- g_free(lu->name);
- g_free(lu);
- }
- G_UNLOCK(logsize_users);
- }
-
- if (callback_data->cb) {
- /* Restore the error in GSimpleAsyncResult as _finish would have cleared it */
- if (size < 0)
- g_simple_async_result_set_from_error(G_SIMPLE_ASYNC_RESULT(res), err);
-
- callback_data->cb(object, res, callback_data->userdata);
- } else if (size < 0 && err->code != G_IO_ERROR_CANCELLED)
- purple_debug_error("log", "Error writing message: %s\n", err->message);
-
- g_clear_error(&err);
- g_free(callback_data);
- purple_log_unref(log);
-}
-
-static void
-log_read_cb(GObject *object, GAsyncResult *res, gpointer userdata)
-{
- _purple_log_read_callback_data *callback_data = userdata;
- PurpleLog *log = callback_data->log;
- GError *err = NULL;
-
- if (callback_data->cb)
- callback_data->cb(object, res, callback_data->userdata);
- else if (purple_log_read_finish(log, res, &err) == NULL &&
- err->code != G_IO_ERROR_CANCELLED)
- purple_debug_error("log", "Error reading log: %s\n", err->message);
-
- g_clear_error(&err);
- g_free(callback_data);
- purple_log_unref(log);
-}
-
-static void
-log_size_cb(GObject *object, GAsyncResult *res, gpointer userdata)
-{
- _purple_log_size_callback_data *callback_data = userdata;
- PurpleLog *log = callback_data->log;
- GError *err = NULL;
-
- if (callback_data->cb)
- callback_data->cb(object, res, callback_data->userdata);
- else if (purple_log_get_size_finish(log, res, &err) < 0 && err->code != G_IO_ERROR_CANCELLED)
- purple_debug_error("log", "Error sizing log: %s\n", err->message);
-
- g_clear_error(&err);
- g_free(callback_data);
- purple_log_unref(log);
-}
-
-static void
log_hash_cb(GObject *object, GAsyncResult *res, gpointer userdata)
{
_purple_log_sets_callback_data *callback_data = userdata;
@@ -4685,96 +3652,3 @@ log_hash_cb(GObject *object, GAsyncResul
}
}
-static void
-log_get_activity_score_cb(GObject *object, GAsyncResult *res, gpointer userdata)
-{
- _purple_log_activity_score_data *callback_data = userdata;
- _purple_log_activity_score_size_data *size_data;
- GSimpleAsyncResult *simple;
- PurpleLog *log;
- GError *err = NULL;
- GList *list;
-
- list = purple_log_get_logs_finish(res, &err);
-
- if (list == NULL) {
- simple = g_simple_async_result_new_from_error(object, callback_data->cb,
- callback_data->userdata, err);
-
- g_simple_async_result_complete_in_idle(simple);
-
- g_object_unref(simple);
- g_object_unref(callback_data->cancel);
- g_free(callback_data->lu->name);
- g_free(callback_data->lu);
- g_free(callback_data);
- } else {
- callback_data->count = g_list_length(list);
-
- for (callback_data->total = 0.0, callback_data->count = 0; list != NULL;
- list = g_list_delete_link(list, list))
- {
- log = list->data;
-
- size_data = g_new0(_purple_log_activity_score_size_data, 1);
- size_data->score_data = callback_data;
- size_data->log = log;
-
- purple_log_get_size_async(log, callback_data->io_priority,
- callback_data->cancel, log_get_activity_score_size_cb, size_data);
- }
- }
-
- g_clear_error(&err);
-}
-
-static void
-log_get_activity_score_size_cb(GObject *object, GAsyncResult *res, gpointer userdata)
-{
- _purple_log_activity_score_size_data *callback_data = userdata;
- _purple_log_activity_score_data *score_data = callback_data->score_data;
- GSimpleAsyncResult *simple;
- PurpleLog *log = callback_data->log;
- GError *err = NULL;
- time_t now;
- gssize size;
- gint score;
-
- size = purple_log_get_size_finish(log, res, &err);
-
- if (size < 0 && err->code != G_IO_ERROR_CANCELLED) {
- purple_debug_error("log", "Error getting log size for activity score: %s\n",
- err->message);
- } else if (size > 0) {
- /* Activity score counts bytes in the log, exponentially
- decayed with a half-life of 14 days. */
- time(&now);
- score_data->total += size * pow(0.5, difftime(now, log->time) / 1209600.0);
- }
-
- g_clear_error(&err);
- purple_log_free(log);
- g_free(callback_data);
-
- score_data->count--;
-
- if (score_data->count < 1) {
- score = ceil(score_data->total);
-
- G_LOCK(logsize_users_decayed);
- g_hash_table_replace(logsize_users_decayed, score_data->lu,
- GINT_TO_POINTER(score));
- G_UNLOCK(logsize_users_decayed);
-
- simple = g_simple_async_result_new(object, score_data->cb,
- score_data->userdata, purple_log_get_activity_score_async);
-
- g_simple_async_result_set_op_res_gssize(simple, score);
- g_simple_async_result_complete_in_idle(simple);
-
- g_object_unref(simple);
- g_object_unref(score_data->cancel);
- g_free(score_data);
- }
-}
-
============================================================
--- libpurple/account.c fc325241ba835c68c655ad8fff1f3e9e5ac39033
+++ libpurple/account.c 1a164776d6aa486560a63c569619ae198d43a66f
@@ -1095,7 +1095,7 @@ purple_account_destroy(PurpleAccount *ac
purple_presence_destroy(account->presence);
if(account->system_log)
- purple_log_free(account->system_log);
+ g_object_unref(account->system_log);
while (account->deny) {
g_free(account->deny->data);
@@ -2469,7 +2469,7 @@ purple_account_get_log(PurpleAccount *ac
presence = purple_account_get_presence(account);
login_time = purple_presence_get_login_time(presence);
- account->system_log = purple_log_new(PURPLE_LOG_SYSTEM,
+ account->system_log = purple_log_new(G_TYPE_INVALID, PURPLE_LOG_SYSTEM,
purple_account_get_username(account), account, NULL,
(login_time != 0) ? login_time : time(NULL), NULL);
}
@@ -2483,7 +2483,7 @@ purple_account_destroy_log(PurpleAccount
g_return_if_fail(account != NULL);
if(account->system_log){
- purple_log_free(account->system_log);
+ g_object_unref(account->system_log);
account->system_log = NULL;
}
}
============================================================
--- libpurple/log.h 3c17a97c416587ac26aa4e54eddf8355a37f5270
+++ libpurple/log.h cabb0f6e40e0e58bfc63d830436d43461cadebad
@@ -24,28 +24,45 @@
* 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_LOG_H_
#define _PURPLE_LOG_H_
#include <stdio.h>
-#include <glib.h>
#include <gio/gio.h>
-#include "account.h"
-#include "conversation.h"
-
-
/** @copydoc _PurpleLog */
typedef struct _PurpleLog PurpleLog;
-/** @copydoc _PurpleLogLogger */
-typedef struct _PurpleLogLogger PurpleLogLogger;
-/** @copydoc _PurpleLogLoggerAsyncFuncs */
-typedef struct _PurpleLogLoggerAsyncFuncs PurpleLogLoggerAsyncFuncs;
+/** @copydoc _PurpleLogClass */
+typedef struct _PurpleLogClass PurpleLogClass;
/** @copydoc _PurpleLogCommonLoggerData */
typedef struct _PurpleLogCommonLoggerData PurpleLogCommonLoggerData;
/** @copydoc _PurpleLogSet */
typedef struct _PurpleLogSet PurpleLogSet;
+
+#include "account.h"
+#include "conversation.h"
+
+
+G_BEGIN_DECLS
+
+#define PURPLE_TYPE_LOG (purple_log_get_type())
+#define PURPLE_LOG(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), PURPLE_TYPE_LOG, PurpleLog))
+#define PURPLE_LOG_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), PURPLE_TYPE_LOG, PurpleLogClass))
+#define PURPLE_IS_LOG(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), PURPLE_TYPE_LOG))
+#define PURPLE_IS_LOG_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), PURPLE_TYPE_LOG))
+#define PURPLE_LOG_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), PURPLE_TYPE_LOG, PurpleLogClass))
+
+// Would rather have this generated by glib-mkenums
+#define PURPLE_TYPE_LOG_CHAT_TYPE (purple_log_chat_type_get_type())
+GType purple_log_chat_type_get_type(void);
+
+// To be used until PurpleLog changes to using a GDateTime
+#define PURPLE_TYPE_STRUCT_TM (purple_struct_tm_get_type())
+GType purple_struct_tm_get_type(void);
+
+
/**************************************************************************/
/* Enumerations */
/**************************************************************************/
@@ -57,7 +74,7 @@ typedef enum {
PURPLE_LOG_IM, /**< Chat log with one person */
PURPLE_LOG_CHAT, /**< Group chat log */
PURPLE_LOG_SYSTEM /**< System log */
-} PurpleLogType;
+} PurpleLogChatType;
/**
* Flags for purple_log_read() and purple_log_read_async()
@@ -67,9 +84,6 @@ typedef enum {
} PurpleLogReadFlags;
-typedef void (*PurpleLogSetCallback) (GHashTable *sets, PurpleLogSet *set);
-
-
/********************************************************
* DATA STRUCTURES **************************************
********************************************************/
@@ -78,65 +92,79 @@ struct _PurpleLog {
* A log. Not the wooden type.
*/
struct _PurpleLog {
- PurpleLogType type; /**< The type of log this is */
- gchar *name; /**< The name of this log */
- PurpleAccount *account; /**< The account this log is taking place on */
- PurpleConversation *conv; /**< The conversation being logged */
- time_t time; /**< The time this conversation started, converted to the local timezone */
- PurpleLogLogger *logger; /**< The logging mechanism this log is to use */
- gpointer logger_data; /**< Data used by the log logger */
+ GObject parent_instance;
+};
- // TODO: On ABI break, it would be really helpful to turn this into a GDateTime!
- struct tm *tm; /**< The time this conversation started, saved with original timezone data,
- * if available and if struct tm has the BSD timezone fields, else @c %NULL.
- * Do NOT modify anything in this struct.
- */
- /* IMPORTANT: Some code in log.c allocates these without zeroing them.
- * IMPORTANT: Update that code if you add members here. */
-};
-
/**
- * A log logger.
- *
- * This struct gets filled out and is included in the PurpleLog. It contains everything
+ * This struct gets filled out and is included in the PurpleLog. It contains everything
* needed to write and read from logs.
*/
-struct _PurpleLogLogger {
- gchar *name; /**< The logger's name */
- gchar *id; /**< An identifier to refer to this logger */
+struct _PurpleLogClass {
+ GObjectClass parent_class;
+ /** The logger's name */
+ const gchar *logger_name;
+
+ /** An identifier to refer to this logger */
+ const gchar *logger_id;
+
/** This gets called when the log is first created, likely not actually needed */
- void (*create)(PurpleLog *log);
+ gboolean (* create_fn) (PurpleLog *log, GCancellable *cancellable, GError **error);
+ void (* create_async) (PurpleLog *log, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+
+ gboolean (* create_finish) (PurpleLog *log, GAsyncResult *res, GError **error);
+
/** This is used to write to the log file */
- gsize (*write)(PurpleLog *log,
- PurpleMessageFlags type,
- const gchar *from,
- time_t time,
- const gchar *message);
+ gssize (* write_fn) (PurpleLog *log, PurpleMessageFlags type, const gchar *from, time_t time, const gchar *message, GCancellable *cancellable, GError **error);
- /** Called when the log is destroyed */
- void (*finalize)(PurpleLog *log);
+ void (* write_async) (PurpleLog *log, PurpleMessageFlags type, const gchar *from, time_t time, const gchar *message, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+ gssize (* write_finish) (PurpleLog *log, GAsyncResult *res, GError **error);
+
/** This function returns a sorted #GList of available #PurpleLog<!-- -->s */
- GList *(*list)(PurpleLogType type, const gchar *name, PurpleAccount *account);
+ GList * (* list_fn) (PurpleLog *log, PurpleLogChatType type, const gchar *name, PurpleAccount *account, GCancellable *cancellable, GError **error);
+ //log is a dummy, only used to keep track of the class
+ void (* list_async) (PurpleLog *log, PurpleLogChatType type, const gchar *name, PurpleAccount *account, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+
+ //log is a dummy, only used to keep track of the class
+ GList * (* list_finish) (PurpleLog *log, GAsyncResult *res, GError **error);
+
/** Given one of the logs returned by the logger's list function,
* this returns the contents of the log in GtkIMHtml markup */
- gchar *(*read)(PurpleLog *log, PurpleLogReadFlags *flags);
+ gchar * (* read_fn) (PurpleLog *log, PurpleLogReadFlags *flags, GCancellable *cancellable, GError **error);
+ void (* read_async) (PurpleLog *log, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+
+ gchar * (* read_finish) (PurpleLog *log, GAsyncResult *res, PurpleLogReadFlags *flags, GError **error);
+
/** Given one of the logs returned by the logger's list function,
* this returns the size of the log in bytes */
- gint (*size)(PurpleLog *log);
+ gssize (* size_fn) (PurpleLog *log, GCancellable *cancellable, GError **error);
+ void (* size_async) (PurpleLog *log, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+
+ gssize (* size_finish) (PurpleLog *log, GAsyncResult *res, GError **error);
+
/** Returns the total size of all the logs. If this is undefined a default
* implementation is used */
- gint (*total_size)(PurpleLogType type, const gchar *name, PurpleAccount *account);
+ gssize (* total_size_fn) (PurpleLogChatType type, const gchar *name, PurpleAccount *account, GCancellable *cancellable, GError **error);
+ //log is a dummy, only used to keep track of the class
+ void (* total_size_async) (PurpleLog *log, PurpleLogChatType type, const gchar *name, PurpleAccount *account, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+
+ //log is a dummy, only used to keep track of the class
+ gssize (* total_size_finish) (PurpleLog *log, GAsyncResult *res, GError **error);
+
/** This function returns a sorted #GList of available system #PurpleLog<!-- -->s */
- GList *(*list_syslog)(PurpleAccount *account);
+ GList * (* list_syslog_fn) (PurpleLog *log, PurpleAccount *account, GCancellable *cancellable, GError **error);
+ void (* list_syslog_async) (PurpleLog *log, PurpleAccount *account, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+
+ GList * (* list_syslog_finish) (PurpleLog *log, GAsyncResult *res, GError **error);
+
/** Adds #PurpleLogSet<!-- -->s to a #GHashTable. By passing the data in the #PurpleLogSet<!-- -->s
* to list, the caller can get every available PurpleLog from the logger.
* Loggers using purple_log_common_writer() (or otherwise storing their
@@ -145,74 +173,26 @@ struct _PurpleLogLogger {
*
* Loggers which implement this function must create a #PurpleLogSet,
* then call @a cb with @a sets and the newly created #PurpleLogSet. */
- void (*get_log_sets)(PurpleLogSetCallback cb, GHashTable *sets);
+ GHashTable * (* get_log_sets_fn) (PurpleLog *log, GCancellable *cancellable, GError **error);
- /* Attempts to delete the specified log, indicating success or failure */
- gboolean (*remove)(PurpleLog *log);
+ void (* get_log_sets_async) (PurpleLog *log, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
- /* Tests whether a log is deletable */
- gboolean (*is_deletable)(PurpleLog *log);
+ GHashTable * (* get_log_sets_finish) (PurpleLog *log, GAsyncResult *res, GError **error);
- /** A pointer to a #PurpleLogLoggerAsyncFuncs structure containing the non-blocking
- * versions of the calls above */
- // Note: This will only be used up until the 3.x API break, when we will create
- // threads that directly call the blocking methods, which will be altered to accept
- // cancellable/error objects
- PurpleLogLoggerAsyncFuncs *async;
+ /** Attempts to remove the specified log, indicating success or failure */
+ gboolean (* remove_fn) (PurpleLog *log, GCancellable *cancellable, GError **error);
- void (*_purple_reserved2)(void);
- void (*_purple_reserved3)(void);
- void (*_purple_reserved4)(void);
-};
+ void (* remove_async) (PurpleLog *log, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
-/**
- * This struct contains the non-blocking versions of the #PurpleLogLogger functions
- */
-struct _PurpleLogLoggerAsyncFuncs {
- // TODO: We could probably drop this. There's really no reason to use it.
- // TODO: If we do, we should deprecate create at the same time.
- /** Non-blocking version of create */
- void (*create_async)(PurpleLog *log, gint io_priority, GCancellable *cancellable,
- GAsyncReadyCallback cb, gpointer data);
+ gboolean (* remove_finish) (PurpleLog *log, GAsyncResult *res, GError **error);
- /** Non-blocking version of write */
- void (*write_async)(PurpleLog *log, PurpleMessageFlags type, const gchar *from,
- time_t time, const gchar *message, gint io_priority, GCancellable *cancellable,
- GAsyncReadyCallback cb, gpointer data);
+ /** Tests whether a log is removable */
+ gboolean (* is_removable_fn) (PurpleLog *log, GCancellable *cancellable, GError **error);
- /** Non-blocking version of finalize */
- void (*finalize_async)(PurpleLog *log, gint io_priority, GCancellable *cancellable,
- GAsyncReadyCallback cb, gpointer data);
+ void (* is_removable_async) (PurpleLog *log, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
- /** Non-blocking version of list */
- void (*list_async)(PurpleLogType type, const gchar *name, PurpleAccount *account,
- gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer data);
+ gboolean (* is_removable_finish) (PurpleLog *log, GAsyncResult *res, GError **error);
- /** Non-blocking version of read */
- void (*read_async)(PurpleLog *log, PurpleLogReadFlags *flags, gint io_priority,
- GCancellable *cancellable, GAsyncReadyCallback cb, gpointer data);
-
- /** Non-blocking version of size */
- void (*size_async)(PurpleLog *log, gint io_priority, GCancellable *cancellable,
- GAsyncReadyCallback cb, gpointer data);
-
- /** Non-blocking version of total_size */
- void (*total_size_async)(PurpleLogType type, const gchar *name, PurpleAccount *account,
- gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer data);
-
- /** Non-blocking version of list_syslog */
- void (*list_syslog_async)(PurpleAccount *account, gint io_priority,
- GCancellable *cancellable, GAsyncReadyCallback cb, gpointer data);
-
- /** Non-blocking version of get_log_sets */
- void (*get_log_sets_async)(PurpleLogSetCallback set_cb, GHashTable *sets,
- gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer data);
-
- /** Non-blocking version of remove */
- void (*remove_async)(PurpleLog *log, gint io_priority, GCancellable *cancellable,
- GAsyncReadyCallback cb, gpointer data);
-
-
void (*_purple_reserved1)(void);
void (*_purple_reserved2)(void);
void (*_purple_reserved3)(void);
@@ -236,7 +216,7 @@ struct _PurpleLogSet {
* can get all available #PurpleLog<!-- -->s.
*/
struct _PurpleLogSet {
- PurpleLogType type; /**< The type of logs available */
+ PurpleLogChatType type; /**< The type of logs available */
gchar *name; /**< The name of the logs available */
PurpleAccount *account; /**< The account the available logs took place on.
* This will be @c %NULL if the account no longer exists.
@@ -252,18 +232,19 @@ struct _PurpleLogSet {
* IMPORTANT: Update that code if you add members here. */
};
-G_BEGIN_DECLS
-
/***************************************/
/** @name Log Functions */
/***************************************/
/*@{*/
+GType purple_log_get_type(void);
+
/**
* Creates a new log
*
- * @param type The type of log this is
+ * @param log_type The type for the log class, must extend PURPLE_LOG_TYPE
+ * @param chat_type The type of log this is
* @param name The name of this conversation (buddy name, chat name, etc.)
* @param account The account the conversation is occurring on
* @param conv (allow-none): The conversation being logged
@@ -273,16 +254,39 @@ G_BEGIN_DECLS
*
* @return The new log
*/
-PurpleLog *purple_log_new(PurpleLogType type, const gchar *name, PurpleAccount *account,
- PurpleConversation *conv, time_t time, const struct tm *tm);
+PurpleLog *purple_log_new(GType log_type, PurpleLogChatType chat_type, const gchar *name, PurpleAccount *account, PurpleConversation *conv, time_t time, const struct tm *tm);
-/**
- * Frees a log
- *
- * @param log The log to destroy
- */
-void purple_log_free(PurpleLog *log);
+//void purple_log_create?
+//
+void purple_log_set_logger_data(PurpleLog *log, gpointer logger_data);
+//
+PurpleLogChatType purple_log_get_chat_type(const PurpleLog *log);
+//
+G_CONST_RETURN gchar *purple_log_get_name(const PurpleLog *log);
+//
+PurpleAccount *purple_log_get_account(const PurpleLog *log);
+//
+time_t purple_log_get_time(const PurpleLog *log);
+//
+PurpleConversation *purple_log_get_conversation(const PurpleLog *log);
+//
+gpointer purple_log_get_logger_data(const PurpleLog *log);
+//
+G_CONST_RETURN struct tm *purple_log_get_tm(const PurpleLog *log);
+//
+gchar *_log_get_timestamp(PurpleLog *log, time_t when);
+//
+gchar *_convert_image_tags(const PurpleLog *log, const gchar *msg);
+
+//
+gboolean purple_log_create(PurpleLog *log, GCancellable *cancellable, GError **error);
+//
+void purple_log_create_async(PurpleLog *log, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata);
+//
+gboolean purple_log_create_finish(PurpleLog *log, GAsyncResult *res, GError **error);
+
+
/**
* Writes to a log file. Assumes you have checked preferences already.
*
@@ -292,9 +296,10 @@ void purple_log_free(PurpleLog *log);
* system messages
* @param time A timestamp in UNIX time
* @param message The message to log
+ * @param cancellable (allow-none): #GCancellable object
+ * @param error (out) (allow-none): a #GError location to store the error
*/
-void purple_log_write(PurpleLog *log, PurpleMessageFlags type, const gchar *from,
- time_t time, const gchar *message);
+gssize purple_log_write(PurpleLog *log, PurpleMessageFlags type, const gchar *from, time_t time, const gchar *message, GCancellable *cancellable, GError **error);
/**
* Writes to a log file asychronously. Assumes you have checked preferences already.
@@ -303,7 +308,7 @@ void purple_log_write(PurpleLog *log, Pu
* @param type The type of message being logged
* @param from Whom this message is coming from, or @c %NULL for system messages
* @param time A timestamp in UNIX time
- * @param message The message to log (will be deleted in function)
+ * @param message The message to log (will be removed in function)
* @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
@@ -311,9 +316,7 @@ void purple_log_write(PurpleLog *log, Pu
*
* @since 2.8.0
*/
-void purple_log_write_async(PurpleLog *log, PurpleMessageFlags type, const gchar *from, time_t time,
- const gchar *message, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb,
- gpointer userdata);
+void purple_log_write_async(PurpleLog *log, PurpleMessageFlags type, const gchar *from, time_t time, const gchar *message, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata);
/**
* Finishing asynchronously writing to a log
@@ -333,16 +336,18 @@ gssize purple_log_write_finish(PurpleLog
*
* @param log The log to read from
* @param flags (allow-none): Location to store the returned logging flags
+ * @param cancellable (allow-none): #GCancellable object
+ * @param error (out) (allow-none): a #GError location to store the error
*
* @return The contents of this log in Purple Markup
*/
-gchar *purple_log_read(PurpleLog *log, PurpleLogReadFlags *flags);
+// NOTE: Error does not have HTML formatting applied
+gchar *purple_log_read(PurpleLog *log, PurpleLogReadFlags *flags, GCancellable *cancellable, GError **error);
/**
* Reads from a log asynchronously
*
* @param log The log to read from
- * @param flags (allow-none): Location to store the returned logging flags
* @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
@@ -350,8 +355,7 @@ gchar *purple_log_read(PurpleLog *log, P
*
* @since 2.8.0
*/
-void purple_log_read_async(PurpleLog *log, PurpleLogReadFlags *flags, gint io_priority,
- GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata);
+void purple_log_read_async(PurpleLog *log, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata);
/**
* Finishes asynchronously reading a log
@@ -360,13 +364,14 @@ void purple_log_read_async(PurpleLog *lo
*
* @param log The #PurpleLog that was read
* @param res A #GAsyncResult
+ * @param flags (out) (allow-none): Location to store the returned logging flags
* @param error (out) (allow-none): a #GError location to store the error
*
* @return pointer to contents of file or %NULL on error
*
* @since 2.8.0
*/
-gchar *purple_log_read_finish(PurpleLog *log, GAsyncResult *res, GError **error);
+gchar *purple_log_read_finish(PurpleLog *log, GAsyncResult *res, PurpleLogReadFlags *flags, GError **error);
/**
* Returns a list of all available logs
@@ -377,7 +382,8 @@ gchar *purple_log_read_finish(PurpleLog
*
* @return A sorted list of #PurpleLog<!-- -->s
*/
-GList *purple_log_get_logs(PurpleLogType type, const gchar *name, PurpleAccount *account);
+GList *purple_log_get_logs(PurpleLog *log, PurpleLogChatType type, const gchar *name, PurpleAccount *account, GCancellable *cancellable, GError **error);
+GList *purple_logs_get_logs(PurpleLogChatType type, const gchar *name, PurpleAccount *account, GCancellable *cancellable, GError **error);
/**
* Asynchronously gets a list of all available logs
@@ -392,8 +398,8 @@ GList *purple_log_get_logs(PurpleLogType
*
* @since 2.8.0
*/
-void purple_log_get_logs_async(PurpleLogType type, const gchar *name, PurpleAccount *account,
- gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata);
+void purple_log_get_logs_async(PurpleLog *log, PurpleLogChatType type, const gchar *name, PurpleAccount *account, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata);
+void purple_logs_get_logs_async(PurpleLogChatType type, const gchar *name, PurpleAccount *account, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata);
/**
* Finishes asynchronously getting a list of all available logs
@@ -408,7 +414,7 @@ void purple_log_get_logs_async(PurpleLog
*
* @since 2.8.0
*/
-GList *purple_log_get_logs_finish(GAsyncResult *res, GError **error);
+GList *purple_log_get_logs_finish(PurpleLog *log, GAsyncResult *res, GError **error);
/**
* Returns a GHashTable of #PurpleLogSet<!-- -->s.
@@ -426,7 +432,8 @@ GList *purple_log_get_logs_finish(GAsync
*
* @return A GHashTable of all available unique #PurpleLogSet<!-- -->s
*/
-GHashTable *purple_log_get_log_sets(void);
+GHashTable *purple_log_get_log_sets(PurpleLog *, GCancellable *cancellable, GError **error);
+GHashTable *purple_logs_get_log_sets(GCancellable *cancellable, GError **error);
/**
* Asychronously gets a #GHashTable of #PurpleLogSet<!-- -->s.
@@ -441,9 +448,9 @@ GHashTable *purple_log_get_log_sets(void
*
* @since 2.8.0
*/
-void purple_log_get_log_sets_async(gint io_priority, GCancellable *cancellable,
- GAsyncReadyCallback cb, gpointer userdata);
+void purple_logs_get_log_sets_async(gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata);
+void purple_log_get_log_sets_async(PurpleLog *log, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata);
/**
* Finishes asynchronously getting a hash table of log sets
*
@@ -454,7 +461,7 @@ void purple_log_get_log_sets_async(gint
*
* @since 2.8.0
*/
-GHashTable *purple_log_get_log_sets_finish(GAsyncResult *res, GError **error);
+GHashTable *purple_log_get_log_sets_finish(PurpleLog *log, GAsyncResult *res, GError **error);
/**
* Returns a list of all available system logs
@@ -463,7 +470,8 @@ GHashTable *purple_log_get_log_sets_fini
*
* @return A sorted list of #PurpleLog<!-- -->s
*/
-GList *purple_log_get_system_logs(PurpleAccount *account);
+GList *purple_log_get_system_logs(PurpleLog *log, PurpleAccount *account, GCancellable *cancellable, GError **error);
+GList *purple_logs_get_system_logs(PurpleAccount *account, GCancellable *cancellable, GError **error);
/**
* Asychronously gets a list of all available system logs
@@ -476,8 +484,8 @@ GList *purple_log_get_system_logs(Purple
*
* @since 2.8.0
*/
-void purple_log_get_system_logs_async(PurpleAccount *account, gint io_priority,
- GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata);
+void purple_log_get_system_logs_async(PurpleLog *log, PurpleAccount *account, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata);
+void purple_logs_get_system_logs_async(PurpleAccount *account, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata);
/**
* Finishes asychronously getting a list of all available system logs
@@ -492,7 +500,7 @@ void purple_log_get_system_logs_async(Pu
*
* @since 2.8.0
*/
-GList *purple_log_get_system_logs_finish(GAsyncResult *res, GError **error);
+GList *purple_log_get_system_logs_finish(PurpleLog *log, GAsyncResult *res, GError **error);
/**
* Returns the size of a log
@@ -501,7 +509,7 @@ GList *purple_log_get_system_logs_finish
*
* @return The size of the log, in bytes
*/
-gint purple_log_get_size(PurpleLog *log);
+gint purple_log_get_size(PurpleLog *log, GCancellable *cancellable, GError **error);
/**
* Asychronously gets the size of a log
@@ -514,8 +522,7 @@ gint purple_log_get_size(PurpleLog *log)
*
* @since 2.8.0
*/
-void purple_log_get_size_async(PurpleLog *log, gint io_priority, GCancellable *cancellable,
- GAsyncReadyCallback cb, gpointer userdata);
+void purple_log_get_size_async(PurpleLog *log, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata);
/**
* Finishes asynchronously getting the size of a log
@@ -539,7 +546,7 @@ gssize purple_log_get_size_finish(Purple
*
* @return The size in bytes
*/
-gint purple_log_get_total_size(PurpleLogType type, const gchar *name, PurpleAccount *account);
+gssize purple_logs_get_total_size(PurpleLogChatType type, const gchar *name, PurpleAccount *account, GCancellable *cancellable, GError **error);
/**
* Asychronously gets the size, in bytes, of all available logs in this conversation
@@ -554,8 +561,7 @@ gint purple_log_get_total_size(PurpleLog
*
* @since 2.8.0
*/
-void purple_log_get_total_size_async(PurpleLogType type, const gchar *name, PurpleAccount *account,
- gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata);
+void purple_logs_get_total_size_async(PurpleLogChatType type, const gchar *name, PurpleAccount *account, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata);
/**
* Finishes asynchronously getting the total size of a conversation
@@ -567,7 +573,7 @@ void purple_log_get_total_size_async(Pur
*
* @since 2.8.0
*/
-gssize purple_log_get_total_size_finish(GAsyncResult *res, GError **error);
+gssize purple_log_get_total_size_finish(PurpleLog *log, GAsyncResult *res, GError **error);
/**
* Returns the activity score of a log, based on total size in bytes,
@@ -581,7 +587,7 @@ gssize purple_log_get_total_size_finish(
*
* @since 2.6.0
*/
-gint purple_log_get_activity_score(PurpleLogType type, const gchar *name, PurpleAccount *account);
+gssize purple_log_get_activity_score(PurpleLogChatType type, const gchar *name, PurpleAccount *account, GCancellable *cancellable, GError **error);
/**
* Asychronously gets the activity score of a log
@@ -596,8 +602,7 @@ gint purple_log_get_activity_score(Purpl
*
* @since 2.8.0
*/
-void purple_log_get_activity_score_async(PurpleLogType type, const gchar *name, PurpleAccount *account,
- gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata);
+void purple_log_get_activity_score_async(PurpleLogChatType type, const gchar *name, PurpleAccount *account, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata);
/**
* Finishes asynchronously getting the activity score of a log
@@ -612,29 +617,33 @@ gint purple_log_get_activity_score_finis
gint purple_log_get_activity_score_finish(GAsyncResult *res, GError **error);
/**
- * Tests whether a log is deletable
+ * Tests whether a log is removable
*
- * A return value of @c FALSE indicates that purple_log_delete() will fail on this
+ * A return value of @c FALSE indicates that purple_log_remove() will fail on this
* log, unless something changes between the two calls. A return value of @c TRUE,
- * however, does not guarantee the log can be deleted.
+ * however, does not guarantee the log can be removed.
*
* @param log The log
*
- * @return %TRUE if the log is deletable, %FALSE otherwise
+ * @return %TRUE if the log is removable, %FALSE otherwise
*/
-gboolean purple_log_is_deletable(PurpleLog *log);
+gboolean purple_log_is_removable(PurpleLog *log, GCancellable *cancellable, GError **error);
+void purple_log_is_removable_async(PurpleLog *log, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata);
+
+gboolean purple_log_is_removable_finish(PurpleLog *log, GAsyncResult *res, GError **error);
+
/**
- * Deletes a log
+ * Removes a log
*
* @param log The log
*
- * @return %TRUE if the log was deleted, %FALSE otherwise
+ * @return %TRUE if the log was removed, %FALSE otherwise
*/
-gboolean purple_log_delete(PurpleLog *log);
+gboolean purple_log_remove(PurpleLog *log, GCancellable *cancellable, GError **error);
/**
- * Asychronously deletes a log
+ * Asychronously removes a log
*
* @param log The log
* @param io_priority The io priority of the request
@@ -644,21 +653,20 @@ gboolean purple_log_delete(PurpleLog *lo
*
* @since 2.8.0
*/
-void purple_log_delete_async(PurpleLog *log, gint io_priority, GCancellable *cancellable,
- GAsyncReadyCallback cb, gpointer userdata);
+void purple_log_remove_async(PurpleLog *log, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata);
/**
* Finishes asynchronously deleting a log
*
- * @param log The #PurpleLog that was to be deleted
+ * @param log The #PurpleLog that was to be removed
* @param res A #GAsyncResult
* @param error (out) (allow-none): a #GError location to store the error
*
- * @return %TRUE if the log was deleted, %FALSE otherwise
+ * @return %TRUE if the log was removed, %FALSE otherwise
*
* @since 2.8.0
*/
-gboolean purple_log_delete_finish(PurpleLog *log, GAsyncResult *res, GError **error);
+gboolean purple_log_remove_finish(PurpleLog *log, GAsyncResult *res, GError **error);
/**
* Returns the default logger directory Purple uses for a given account
@@ -671,7 +679,7 @@ gboolean purple_log_delete_finish(Purple
*
* @return The default logger directory for Purple
*/
-gchar *purple_log_get_log_dir(PurpleLogType type, const gchar *name, PurpleAccount *account);
+gchar *purple_log_get_log_dir(PurpleLogChatType type, const gchar *name, PurpleAccount *account);
/**
* Implements GCompareFunc for #PurpleLog<!-- -->s
@@ -724,7 +732,7 @@ void purple_log_set_free(PurpleLogSet *s
* @param log The log to write to
* @param ext (allow-none): The file extension to give to this log file
*/
-void purple_log_common_writer(PurpleLog *log, const gchar *ext);
+gboolean purple_log_common_writer(PurpleLog *log, const gchar *ext, GCancellable *cancellable, GError **error);
/**
* Asynchronously opens a new log in the standard log location
@@ -739,8 +747,7 @@ void purple_log_common_writer(PurpleLog
* @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);
+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
@@ -769,12 +776,11 @@ gboolean purple_log_common_writer_finish
* @param name The name of the log
* @param account The account of the log
* @param ext The file extension this log format uses
- * @param logger A reference to the logger struct for this log
+ * @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(PurpleLogType type, const gchar *name, PurpleAccount *account,
- const gchar *ext, PurpleLogLogger *logger);
+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
@@ -786,7 +792,7 @@ GList *purple_log_common_lister(PurpleLo
* @param name The name of the log
* @param account The account of the log
* @param ext The file extension this log format uses
- * @param logger A reference to the logger struct for this log
+ * @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
@@ -794,9 +800,7 @@ GList *purple_log_common_lister(PurpleLo
*
* @since 2.8.0
*/
-void purple_log_common_lister_async(PurpleLogType type, const gchar *name, PurpleAccount *account,
- const gchar *ext, PurpleLogLogger *logger, gint io_priority,
- GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata);
+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.
@@ -833,8 +837,7 @@ GList *purple_log_common_lister_finish(G
* @return The size of all the logs with the specified extension
* for the specified user
*/
-gint purple_log_common_total_sizer(PurpleLogType type, const gchar *name, PurpleAccount *account,
- const gchar *ext);
+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
@@ -854,9 +857,7 @@ gint purple_log_common_total_sizer(Purpl
*
* @since 2.8.0
*/
-void purple_log_common_total_sizer_async(PurpleLogType type, const gchar *name,
- PurpleAccount *account, const gchar *ext, gint io_priority, GCancellable *cancellable,
- GAsyncReadyCallback cb, gpointer userdata);
+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
@@ -883,7 +884,7 @@ gssize purple_log_common_total_sizer_fin
*
* @return An integer indicating the size of the log in bytes
*/
-gint purple_log_common_sizer(PurpleLog *log);
+gssize purple_log_common_sizer(PurpleLog *log, GCancellable *cancellable, GError **error);
/**
* Asychronously gets the size of a given #PurpleLog
@@ -899,8 +900,7 @@ gint purple_log_common_sizer(PurpleLog *
*
* @since 2.8.0
*/
-void purple_log_common_sizer_async(PurpleLog *log, gint io_priority, GCancellable *cancellable,
- GAsyncReadyCallback cb, gpointer userdata);
+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
@@ -916,30 +916,30 @@ gssize purple_log_common_sizer_finish(Pu
gssize purple_log_common_sizer_finish(PurpleLog *log, GAsyncResult *res, GError **error);
/**
- * Deletes a log
+ * 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 delete function.
+ * 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 delete
+ * @param log The #PurpleLog to remove
*
- * @return %TRUE if the log was deleted, %FALSE otherwise
+ * @return %TRUE if the log was removed, %FALSE otherwise
*/
-gboolean purple_log_common_deleter(PurpleLog *log);
+gboolean purple_log_common_remover(PurpleLog *log, GCancellable *cancellable, GError **error);
/**
- * Asynchronously deletes a log
+ * 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 delete function.
+ * 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 delete
+ * @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
@@ -947,37 +947,39 @@ gboolean purple_log_common_deleter(Purpl
*
* @since 2.8.0
*/
-void purple_log_common_deleter_async(PurpleLog *log, gint io_priority, GCancellable *cancellable,
- GAsyncReadyCallback cb, gpointer userdata);
+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 delete
+ * @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 deleted, %FALSE otherwise
+ * @return %TRUE if the log was removed, %FALSE otherwise
*
* @since 2.8.0
*/
-gboolean purple_log_common_deleter_finish(PurpleLog *log, GAsyncResult *res, GError **error);
+gboolean purple_log_common_remover_finish(PurpleLog *log, GAsyncResult *res, GError **error);
/**
- * Checks to see if a log is deletable
+ * 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_deletable function.
+ * 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 deletable, %FALSE otherwise
+ * @return %TRUE if the log is removable, %FALSE otherwise
*/
-gboolean purple_log_common_is_deletable(PurpleLog *log);
+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);
+
/*@}*/
/******************************************/
@@ -987,70 +989,41 @@ gboolean purple_log_common_is_deletable(
/*@{*/
/**
- * Creates a new logger
- *
- * @param id The logger's id
- * @param name The logger's name
- * @param functions The number of functions being passed. The following
- * functions are currently available (in order): @c create,
- * @c write, @c finalize, @c list, @c read, @c size,
- * @c total_size, @c list_syslog, @c get_log_sets,
- * @c remove, @c is_deletable.
- * For details on these functions, see PurpleLogLogger.
- * Functions may not be skipped. For example, passing
- * @c create and @c write is acceptable (for a total of
- * two functions). Passing @c create and @c finalize,
- * however, is not. To accomplish that, the caller must
- * pass @c create, @c %NULL (a placeholder for @c write),
- * and @c finalize (for a total of 3 functions).
- *
- * @return The new logger
- */
-PurpleLogLogger *purple_log_logger_new(const gchar *id, const gchar *name, gint functions, ...);
-
-/**
- * Frees a logger
- *
- * @param logger The logger to free
- */
-void purple_log_logger_free(PurpleLogLogger *logger);
-
-/**
* Adds a new logger
*
- * @param logger The new logger to add
+ * @param log_type The new logger to add
*/
-void purple_log_logger_add(PurpleLogLogger *logger);
+void purple_log_logger_add(GType log_type);
/**
* Removes a logger
*
- * @param logger The logger to remove
+ * @param log_type The logger to remove
*/
-void purple_log_logger_remove(PurpleLogLogger *logger);
+void purple_log_logger_remove(GType log_type);
/**
* Sets the current logger
*
- * @param logger The logger to set
+ * @param log_type The logger to set
*/
-void purple_log_logger_set(PurpleLogLogger *logger);
+void purple_log_logger_set(GType log_type);
/**
- * Returns the current logger
+ * Gets the current default logger's type
*
- * @return logger The current logger
+ * @return The current default logger type
*/
-PurpleLogLogger *purple_log_logger_get(void);
+GType purple_log_logger_get_default(void);
/**
- * Returns a list of all the available loggers
+ * Gets a list of all the available loggers
*
- * @return loggers All available loggers
+ * @return All available loggers
*
* @since 2.8.0
*/
-GSList *purple_log_logger_get_all(void);
+GArray *purple_log_logger_get_all(void);
/**
* Gets a #GList containing the IDs and names of the registered loggers.
@@ -1070,19 +1043,19 @@ GList *purple_log_logger_get_options(voi
/**
* Initializes the log subsystem
*/
-void purple_log_init(void);
+void purple_log_system_init(void);
/**
* Returns the log subsystem handle
*
* @return The log subsystem handle
*/
-void *purple_log_get_handle(void);
+void *purple_log_system_get_handle(void);
/**
* Uninitializes the log subsystem
*/
-void purple_log_uninit(void);
+void purple_log_system_uninit(void);
/*@}*/
============================================================
--- pidgin/gtklog.c 1a7b27749c5c448a40a40c92cbf832f0501b9171
+++ pidgin/gtklog.c 379ee451d8409fda74f354bbe91633f34da2f4f3
@@ -131,44 +131,6 @@ static PidginLogViewerEx *syslog_viewer
static GHashTable *log_viewers = NULL;
static PidginLogViewerEx *syslog_viewer = NULL;
-// To be used until PurpleLog changes to using a GDateTime
-GType purple_struct_tm_get_type(void);
-static gpointer purple_struct_tm_copy(gpointer);
-
-#define PURPLE_STRUCT_TM_GET_TYPE (purple_struct_tm_get_type())
-
-#if GLIB_CHECK_VERSION(2, 26, 0)
-
-typedef struct tm PurpleStructTM;
-G_DEFINE_BOXED_TYPE (PurpleStructTM, purple_struct_tm, purple_struct_tm_copy, g_free);
-
-#else
-
-GType
-purple_struct_tm_get_type(void)
-{
- static GType object_type = 0;
-
- if (G_UNLIKELY (!object_type))
- object_type = g_boxed_type_register_static(g_intern_static_string("PurpleStructTm"),
- purple_struct_tm_copy, g_free);
-
- return object_type;
-}
-
-#endif
-
-static gpointer
-purple_struct_tm_copy(gpointer original)
-{
- struct tm *copy;
-
- copy = g_new(struct tm, 1);
- memcpy(copy, original, sizeof(struct tm));
-
- return copy;
-}
-
static void
pidgin_log_data_free(_pidgin_log_data *data)
{
@@ -984,7 +946,7 @@ display_log_viewer_nonblocking(log_viewe
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
gtk_paned_add1(GTK_PANED(pane), sw);
- lv->treestore = gtk_tree_store_new(3, G_TYPE_STRING, G_TYPE_POINTER, PURPLE_STRUCT_TM_GET_TYPE);
+ lv->treestore = gtk_tree_store_new(3, G_TYPE_STRING, G_TYPE_POINTER, PURPLE_TYPE_STRUCT_TM);
lv->treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(lv->treestore));
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(lv->treeview), FALSE);
pidgin_set_accessible_label(lv->treeview, lv->label);
============================================================
--- libpurple/Makefile.am c1f7e9c3096c60434341bff05ce1d99f4b42527f
+++ libpurple/Makefile.am 1e30217909679956cd9e2c39368d08d00a98aa19
@@ -50,6 +50,7 @@ purple_coresources = \
desktopitem.c \
eventloop.c \
ft.c \
+ htmllog.c \
idle.c \
imgstore.c \
log.c \
@@ -90,6 +91,7 @@ purple_coresources = \
theme.c \
theme-loader.c \
theme-manager.c \
+ txtlog.c \
upnp.c \
util.c \
value.c \
@@ -118,6 +120,7 @@ purple_coreheaders = \
eventloop.h \
ft.h \
gaim-compat.h \
+ htmllog.h \
idle.h \
imgstore.h \
log.h \
@@ -154,6 +157,7 @@ purple_coreheaders = \
theme.h \
theme-loader.h \
theme-manager.h \
+ txtlog.h \
upnp.h \
util.h \
valgrind.h \
============================================================
--- libpurple/Makefile.mingw e15167af874d0b95fb51b36f35d9748cbf8320b2
+++ libpurple/Makefile.mingw dee33a1b0727bdc19f53839d9f495cba8504b0f0
@@ -45,6 +45,7 @@ C_SRC = \
dnssrv.c \
eventloop.c \
ft.c \
+ htmllog.c \
idle.c \
imgstore.c \
log.c \
@@ -78,6 +79,7 @@ C_SRC = \
theme-loader.c \
theme-manager.c \
theme.c \
+ txtlog.c \
upnp.c \
util.c \
value.c \
============================================================
--- /dev/null
+++ libpurple/htmllog.c a253d66d3d8720b4318defa9bc816e79ea5eafb3
@@ -0,0 +1,348 @@
+/**
+ * @file htmllog.c HTML 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 "htmllog.h"
+#include "log.h"
+#include "util.h"
+
+G_DEFINE_TYPE (PurpleHtmlLog, purple_html_log, PURPLE_TYPE_LOG)
+
+static gssize purple_html_log_create(PurpleLog *, GCancellable *, GError **);
+static gssize purple_html_log_write(PurpleLog *, PurpleMessageFlags, const gchar *, time_t, const gchar *, GCancellable *, GError **);
+static GList *purple_html_log_list(PurpleLog *, PurpleLogChatType, const gchar *, PurpleAccount *, GCancellable *, GError **);
+static gchar *purple_html_log_read(PurpleLog *, PurpleLogReadFlags *, GCancellable *, GError **);
+static gssize purple_html_log_total_size(PurpleLogChatType, const gchar *, PurpleAccount *, GCancellable *, GError **);
+static GList *purple_html_log_list_syslog(PurpleLog *, PurpleAccount *, GCancellable *, GError **);
+static void purple_html_log_finalize(GObject *);
+
+static void
+purple_html_log_class_init(PurpleHtmlLogClass *class)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS(class);
+ PurpleLogClass *log_class = PURPLE_LOG_CLASS(class);
+
+ log_class->logger_name = _("HTML");
+ log_class->logger_id = "html";
+
+ log_class->create_fn = purple_html_log_create;
+ 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;
+}
+
+static void
+purple_html_log_init(PurpleHtmlLog *html_log)
+{
+}
+
+PurpleLog *
+purple_html_log_new(PurpleLogChatType type, const gchar *name, PurpleAccount *account,
+ PurpleConversation *conv, time_t time, const struct tm *tm)
+{
+ return purple_log_new(PURPLE_TYPE_HTML_LOG, type, name, account, conv, time, tm);
+}
+
+static gssize
+purple_html_log_create(PurpleLog *log, GCancellable *cancellable, GError **error)
+{
+ return purple_log_common_writer(log, ".html", cancellable, error);
+}
+
+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;
+ gchar *date, *escaped_from;
+ gchar *image_corrected_msg, *msg_fixed, *line;
+ gssize written, size = 0;
+ gboolean write_header;
+
+ if (data == 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.
+ */
+ //Should we be doing this?
+ if (!purple_html_log_create(log, cancellable, error))
+ return -1;
+
+ data = purple_log_get_logger_data(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) {
+ g_set_error_literal(error,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ _("Unable to find log path"));
+
+ 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);
+
+ return -1;
+ }
+
+ out_stream = G_OUTPUT_STREAM(stream);
+
+ if (write_header) {
+ PurpleAccount *account = purple_log_get_account(log);
+ PurplePlugin *plugin;
+ const gchar *prpl;
+ const gchar *date_full;
+ gchar *header;
+ time_t log_time = purple_log_get_time(log);
+
+ plugin = purple_find_prpl(purple_account_get_protocol_id(account));
+ prpl = PURPLE_PLUGIN_PROTOCOL_INFO(plugin)->list_icon(account, NULL);
+ date_full = purple_date_format_full(localtime(&log_time));
+
+ if (purple_log_get_chat_type(log) == PURPLE_LOG_SYSTEM)
+ header = g_strdup_printf("System log for account %s (%s) connected at %s",
+ purple_account_get_username(account), prpl, date_full);
+ else
+ header = g_strdup_printf("Conversation with %s at %s on %s (%s)",
+ purple_log_get_name(log), date_full,
+ purple_account_get_username(account), prpl);
+
+ line = g_strdup_printf("<html><head>"
+ "<meta http-equiv=\"content-type\" "
+ "content=\"text/html; charset=UTF-8\">"
+ "<title>"
+ "%s"
+ "</title></head><body>"
+ "<h3>%s</h3>\n",
+ header, header);
+
+ g_free(header);
+
+ written = g_output_stream_write(out_stream, line,
+ strlen(line), cancellable, error);
+ g_free(line);
+
+ if (written < 0) {
+ g_object_unref(file);
+ g_object_unref(stream);
+
+ return -1;
+ }
+
+ size += written;
+ }
+
+ escaped_from = g_markup_escape_text(from, -1);
+ image_corrected_msg = _convert_image_tags(log, message);
+ purple_markup_html_to_xhtml(image_corrected_msg, &msg_fixed, NULL);
+
+ /* Yes, this breaks encapsulation. But it's a static function and
+ * this saves a needless strdup(). */
+ if (image_corrected_msg != message)
+ g_free(image_corrected_msg);
+
+ date = _log_get_timestamp(log, time);
+
+ if (purple_log_get_chat_type(log) == PURPLE_LOG_SYSTEM){
+ line = g_strdup_printf("---- %s @ %s ----<br/>\n", msg_fixed, date);
+ } else {
+ if (type & PURPLE_MESSAGE_SYSTEM)
+ line = g_strdup_printf("<font size=\"2\">(%s)</font><b> %s</b><br/>\n", date, msg_fixed);
+ else if (type & PURPLE_MESSAGE_RAW)
+ line = g_strdup_printf("<font size=\"2\">(%s)</font> %s<br/>\n",
+ date, msg_fixed);
+ else if (type & PURPLE_MESSAGE_ERROR)
+ line = g_strdup_printf("<font color=\"#FF0000\"><font "
+ "size=\"2\">(%s)</font><b> %s</b></font><br/>\n",
+ date, msg_fixed);
+ else if (type & PURPLE_MESSAGE_WHISPER)
+ line = g_strdup_printf("<font color=\"#6C2585\"><font "
+ "size=\"2\">(%s)</font><b> %s:</b></font> %s<br/>\n",
+ date, escaped_from, msg_fixed);
+ else if (type & PURPLE_MESSAGE_AUTO_RESP) {
+ if (type & PURPLE_MESSAGE_SEND)
+ line = g_strdup_printf(_("<font color=\"#16569E\"><font "
+ "size=\"2\">(%s)</font> <b>%s <AUTO-REPLY>:</b>"
+ "</font> %s<br/>\n"), date, escaped_from, msg_fixed);
+ else
+ line = g_strdup_printf(_("<font color=\"#A82F2F\"><font "
+ "size=\"2\">(%s)</font> <b>%s <AUTO-REPLY>:</b>"
+ "</font> %s<br/>\n"), date, escaped_from, msg_fixed);
+ } else if (type & PURPLE_MESSAGE_RECV) {
+ if (purple_message_meify(msg_fixed, -1))
+ line = g_strdup_printf("<font color=\"#062585\"><font "
+ "size=\"2\">(%s)</font> <b>***%s</b></font> %s<br/>\n",
+ date, escaped_from, msg_fixed);
+ else
+ line = g_strdup_printf("<font color=\"#A82F2F\"><font "
+ "size=\"2\">(%s)</font> <b>%s:</b></font> %s<br/>\n",
+ date, escaped_from, msg_fixed);
+ } else if (type & PURPLE_MESSAGE_SEND) {
+ if (purple_message_meify(msg_fixed, -1))
+ line = g_strdup_printf("<font color=\"#062585\"><font "
+ "size=\"2\">(%s)</font> <b>***%s</b></font> %s<br/>\n",
+ date, escaped_from, msg_fixed);
+ else
+ line = g_strdup_printf("<font color=\"#16569E\"><font "
+ "size=\"2\">(%s)</font> <b>%s:</b></font> %s<br/>\n",
+ date, escaped_from, msg_fixed);
+ } else {
+ line = g_strdup_printf("<font size=\"2\">(%s)</font>"
+ "<b> %s:</b></font> %s<br/>\n",
+ date, escaped_from, msg_fixed);
+ }
+ }
+
+ written = g_output_stream_write(out_stream, line, strlen(line),
+ cancellable, error);
+
+ if (written < 0)
+ size = -1;
+ else
+ size += written;
+
+ g_free(date);
+ g_free(msg_fixed);
+ g_free(escaped_from);
+ g_object_unref(file);
+ g_object_unref(stream);
+
+ return size;
+}
+
+static GList *
+purple_html_log_list(PurpleLog *log, PurpleLogChatType type, const gchar *sn, PurpleAccount *account, GCancellable *cancellable, GError **error)
+{
+ return purple_log_common_lister(type, sn, account, ".html", PURPLE_TYPE_HTML_LOG, cancellable, error);
+}
+
+static GList *
+purple_html_log_list_syslog(PurpleLog *log, PurpleAccount *account, GCancellable *cancellable, GError **error)
+{
+ return purple_log_common_lister(PURPLE_LOG_SYSTEM, ".system", account, ".html", PURPLE_TYPE_HTML_LOG, cancellable, error);
+}
+
+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) {
+ g_set_error_literal(error,
+ G_FILE_ERROR,
+ G_IO_ERROR_NOT_FOUND,
+ _("Unable to find log path"));
+
+ 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);
+
+ return NULL;
+ }
+
+ minus_header = strchr(read, '\n');
+
+ if (minus_header == NULL)
+ minus_header = read;
+ else {
+ minus_header = g_strdup(minus_header + 1);
+ g_free(read);
+ }
+
+ purple_str_strip_char(minus_header, '\r');
+
+ return minus_header;
+}
+
+static gssize
+purple_html_log_total_size(PurpleLogChatType type, const gchar *name, PurpleAccount *account, GCancellable *cancellable, GError **error)
+{
+ return purple_log_common_total_sizer(type, name, account, ".html", cancellable, error);
+}
+
+static void
+purple_html_log_finalize(GObject *object)
+{
+ PurpleLog *log = PURPLE_LOG(object);
+ PurpleLogCommonLoggerData *data = purple_log_get_logger_data(log);
+
+ if (data != NULL) {
+ if (data->file != NULL) {
+ fprintf(data->file, "</body></html>\n");
+ fclose(data->file);
+ }
+
+ g_free(data->path);
+ g_slice_free(PurpleLogCommonLoggerData, data);
+ }
+
+ G_OBJECT_CLASS(purple_html_log_parent_class)->finalize(object);
+}
+
+void
+purple_html_log_system_init(void)
+{
+ purple_prefs_add_string("/purple/logging/format", "html");
+}
+
+void *
+purple_html_log_system_get_handle(void)
+{
+ static gint handle;
+
+ return &handle;
+}
+
+void
+purple_html_log_system_uninit(void)
+{
+ purple_signals_unregister_by_instance(purple_html_log_system_get_handle());
+}
============================================================
--- /dev/null
+++ libpurple/htmllog.h 49ed99ca59a6f1f6ca3b030589a1a79fe25a2916
@@ -0,0 +1,71 @@
+/**
+ * @file htmllog.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_HTML_LOG_H_
+#define _PURPLE_HTML_LOG_H_
+
+#include <gio/gio.h>
+
+#include "log.h"
+
+G_BEGIN_DECLS
+
+#define PURPLE_TYPE_HTML_LOG (purple_html_log_get_type())
+#define PURPLE_HTML_LOG(o) (G_TYPE_CHECK_INSTANCE_CAST((o), PURPLE_TYPE_HTML_LOG, PurpleHtmlLog))
+#define PURPLE_HTML_LOG_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), PURPLE_TYPE_HTML_LOG, PurpleHtmlLogClass))
+#define PURPLE_IS_HTML_LOG(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), PURPLE_TYPE_HTML_LOG))
+#define PURPLE_IS_HTML_LOG_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), PURPLE_TYPE_HTML_LOG))
+#define PURPLE_HTML_LOG_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), PURPLE_TYPE_HTML_LOG, PurpleHtmlLogClass))
+
+typedef struct _PurpleHtmlLog PurpleHtmlLog;
+typedef struct _PurpleHtmlLogClass PurpleHtmlLogClass;
+
+struct _PurpleHtmlLog {
+ PurpleLog parent_instance;
+};
+
+struct _PurpleHtmlLogClass {
+ PurpleLogClass parent_class;
+
+ void (*_purple_reserved1)(void);
+ void (*_purple_reserved2)(void);
+ void (*_purple_reserved3)(void);
+ void (*_purple_reserved4)(void);
+};
+
+GType purple_html_log_get_type(void);
+
+PurpleLog *purple_html_log_new(PurpleLogChatType chat_type, const gchar *name, PurpleAccount *account,
+ PurpleConversation *conv, time_t time, const struct tm *tm);
+
+void purple_html_log_system_init(void);
+void *purple_html_log_system_get_handle(void);
+void purple_html_log_system_uninit(void);
+
+G_END_DECLS
+
+#endif /* _PURPLE_HTML_LOG_H_ */
============================================================
--- /dev/null
+++ libpurple/oldlog.c d6149b5e029a1fc0b246ba3b1a30ea9ee80ba73f
@@ -0,0 +1,480 @@
+/**
+ * @file oldlog.c Old 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
+ */
+
+
+static GList *old_logger_list(PurpleLogType, const gchar *, PurpleAccount *);
+static gint old_logger_total_size(PurpleLogType, const gchar *, PurpleAccount *);
+static gchar *old_logger_read(PurpleLog *, PurpleLogReadFlags *);
+static gint old_logger_size(PurpleLog *);
+static void old_logger_get_log_sets(PurpleLogSetCallback, GHashTable *);
+static void old_logger_finalize(PurpleLog *);
+
+
+/****************
+ * OLD LOGGER ***
+ ****************/
+
+/* The old logger doesn't write logs, only reads them. This is to include
+ * old logs in the log viewer transparently.
+ */
+
+typedef struct {
+ PurpleStringref *pathref;
+ gint offset;
+ gint length;
+} old_logger_data;
+
+static GList *
+old_logger_list(PurpleLogType type, const gchar *sn, PurpleAccount *account)
+{
+ old_logger_data *data;
+ PurpleStringref *pathref;
+ PurpleLog *log;
+ GList *list;
+ FILE *index, *file;
+ time_t log_last_modified, lasttime;
+ struct stat st;
+ struct tm tm;
+ gchar *logfile, *pathstr, *index_tmp, buf[BUF_LONG], month[4], convostart[32], *temp;
+ gint index_fd, logfound, lastoff, newlen, length, offset;
+ gulong idx_time;
+
+ logfile = g_strdup_printf("%s.log", purple_normalize(account, sn));
+ pathstr = g_build_filename(purple_user_dir(), "logs", logfile, NULL);
+ pathref = purple_stringref_new(pathstr);
+ g_free(logfile);
+
+ log = NULL;
+ list = NULL;
+ data = NULL;
+
+ logfound = 0;
+ lastoff = 0;
+ lasttime = 0;
+
+ if (g_stat(purple_stringref_value(pathref), &st)) {
+ purple_stringref_unref(pathref);
+ g_free(pathstr);
+
+ return NULL;
+ } else
+ log_last_modified = st.st_mtime;
+
+ /* Change the .log extension to .idx */
+ strcpy(pathstr + strlen(pathstr) - 3, "idx");
+
+ if (g_stat(pathstr, &st) == 0) {
+ if (st.st_mtime < log_last_modified) {
+ purple_debug_warning("log", "Index \"%s\" exists, but is older than the log.\n", pathstr);
+ } else {
+ /* The index file exists and is at least as new as the log, so open it. */
+ if (!(index = g_fopen(pathstr, "rb")))
+ {
+ purple_debug_error("log", "Failed to open index file \"%s\" for reading: %s\n",
+ pathstr, g_strerror(errno));
+
+ /* Fall through so that we'll parse the log file. */
+ } else {
+ purple_debug_info("log", "Using index: %s\n", pathstr);
+ g_free(pathstr);
+
+ while (fgets(buf, BUF_LONG, index)) {
+ if (sscanf(buf, "%d\t%d\t%lu", &lastoff, &newlen, &idx_time) == 3) {
+ log = purple_log_new(PURPLE_TYPE_OLD_LOG, PURPLE_LOG_IM, sn, account, NULL, -1, NULL);
+ log->time = (time_t) idx_time;
+
+ G_LOCK(old_logger);
+ log->logger = old_logger;
+ G_UNLOCK(old_logger);
+
+ /* IMPORTANT: Always set all members of old_logger_data */
+ data = g_slice_new(old_logger_data);
+
+ data->pathref = purple_stringref_ref(pathref);
+ data->offset = lastoff;
+ data->length = newlen;
+
+ log->logger_data = data;
+ list = g_list_prepend(list, log);
+ }
+ }
+
+ fclose(index);
+ purple_stringref_unref(pathref);
+
+ return list;
+ }
+ }
+ }
+
+ if (!(file = g_fopen(purple_stringref_value(pathref), "rb"))) {
+ purple_debug_error("log", "Failed to open log file \"%s\" for reading: %s\n",
+ purple_stringref_value(pathref), g_strerror(errno));
+ purple_stringref_unref(pathref);
+ g_free(pathstr);
+
+ return NULL;
+ }
+
+ index_tmp = g_strdup_printf("%s.XXXXXX", pathstr);
+
+ if ((index_fd = g_mkstemp(index_tmp)) == -1) {
+ purple_debug_error("log", "Failed to open index temp file: %s\n",
+ g_strerror(errno));
+
+ g_free(pathstr);
+ g_free(index_tmp);
+ index = NULL;
+ } else {
+ index = fdopen(index_fd, "wb");
+
+ if (index == NULL) {
+ purple_debug_error("log", "Failed to fdopen() index temp file: %s\n",
+ g_strerror(errno));
+ close(index_fd);
+
+ if (index_tmp != NULL) {
+ g_unlink(index_tmp);
+ g_free(index_tmp);
+ }
+
+ g_free(pathstr);
+ }
+ }
+
+ while (fgets(buf, BUF_LONG, file)) {
+ if (strstr(buf, "---- New C") != NULL) {
+ temp = strchr(buf, '@');
+
+ if (temp == NULL || strlen(temp) < 2)
+ continue;
+
+ temp++;
+ length = strcspn(temp, "-");
+ if (length > 31) length = 31;
+
+ offset = ftell(file);
+
+ if (logfound) {
+ newlen = offset - lastoff - length;
+ if(strstr(buf, "----</H3><BR>")) {
+ newlen -=
+ sizeof("<HR><BR><H3 Align=Center> ---- New Conversation @ ") +
+ sizeof("----</H3><BR>") - 2;
+ } else {
+ newlen -= sizeof("---- New Conversation @ ") + sizeof("----") - 2;
+ }
+
+ if(strchr(buf, '\r'))
+ newlen--;
+
+ if (newlen != 0) {
+ log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, -1, NULL);
+ log->time = lasttime;
+
+ G_LOCK(old_logger);
+ log->logger = old_logger;
+ G_UNLOCK(old_logger);
+
+ /* IMPORTANT: Always set all members of old_logger_data */
+ data = g_slice_new(old_logger_data);
+
+ data->pathref = purple_stringref_ref(pathref);
+ data->offset = lastoff;
+ data->length = newlen;
+
+ log->logger_data = data;
+ list = g_list_prepend(list, log);
+
+ /* XXX: There is apparently Is there a proper way to print a time_t? */
+ if (index != NULL)
+ fprintf(index, "%d\t%d\t%lu\n", data->offset, data->length,
+ (unsigned long)log->time);
+ }
+ }
+
+ logfound = 1;
+ lastoff = offset;
+
+ g_snprintf(convostart, length, "%s", temp);
+ memset(&tm, 0, sizeof(tm));
+ sscanf(convostart, "%*s %s %d %d:%d:%d %d", month, &tm.tm_mday,
+ &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &tm.tm_year);
+
+ /* Ugly hack, in case current locale is not English */
+ if (purple_strequal(month, "Jan")) {
+ tm.tm_mon= 0;
+ } else if (purple_strequal(month, "Feb")) {
+ tm.tm_mon = 1;
+ } else if (purple_strequal(month, "Mar")) {
+ tm.tm_mon = 2;
+ } else if (purple_strequal(month, "Apr")) {
+ tm.tm_mon = 3;
+ } else if (purple_strequal(month, "May")) {
+ tm.tm_mon = 4;
+ } else if (purple_strequal(month, "Jun")) {
+ tm.tm_mon = 5;
+ } else if (purple_strequal(month, "Jul")) {
+ tm.tm_mon = 6;
+ } else if (purple_strequal(month, "Aug")) {
+ tm.tm_mon = 7;
+ } else if (purple_strequal(month, "Sep")) {
+ tm.tm_mon = 8;
+ } else if (purple_strequal(month, "Oct")) {
+ tm.tm_mon = 9;
+ } else if (purple_strequal(month, "Nov")) {
+ tm.tm_mon = 10;
+ } else if (purple_strequal(month, "Dec")) {
+ tm.tm_mon = 11;
+ }
+ tm.tm_year -= 1900;
+ lasttime = mktime(&tm);
+ }
+ }
+
+ if (logfound) {
+ if ((newlen = ftell(file) - lastoff) != 0) {
+ log = purple_log_new(PURPLE_LOG_IM, sn, account, NULL, -1, NULL);
+ log->time = lasttime;
+
+ G_LOCK(old_logger);
+ log->logger = old_logger;
+ G_UNLOCK(old_logger);
+
+ /* IMPORTANT: Always set all members of old_logger_data */
+ data = g_slice_new(old_logger_data);
+
+ data->pathref = purple_stringref_ref(pathref);
+ data->offset = lastoff;
+ data->length = newlen;
+
+ log->logger_data = data;
+ list = g_list_prepend(list, log);
+
+ /* XXX: Is there a proper way to print a time_t? */
+ if (index != NULL)
+ fprintf(index, "%d\t%d\t%d\n", data->offset, data->length, (gint) log->time);
+ }
+ }
+
+ purple_stringref_unref(pathref);
+ fclose(file);
+
+ if (index != NULL) {
+ fclose(index);
+
+ if (index_tmp == NULL) {
+ g_free(pathstr);
+ g_return_val_if_reached(list);
+ }
+
+ if (g_rename(index_tmp, pathstr)) {
+ purple_debug_warning("log", "Failed to rename index temp file \"%s\" to \"%s\": %s\n",
+ index_tmp, pathstr, g_strerror(errno));
+ g_unlink(index_tmp);
+ } else
+ purple_debug_info("log", "Built index: %s\n", pathstr);
+
+ g_free(index_tmp);
+ g_free(pathstr);
+ }
+
+ return list;
+}
+
+static gint
+old_logger_total_size(PurpleLogType type, const gchar *name, PurpleAccount *account)
+{
+ gchar *logfile, *pathstr;
+ gint size;
+ struct stat st;
+
+ logfile = g_strdup_printf("%s.log", purple_normalize(account, name));
+ pathstr = g_build_filename(purple_user_dir(), "logs", logfile, NULL);
+
+ if (g_stat(pathstr, &st))
+ size = 0;
+ else
+ size = st.st_size;
+
+ g_free(logfile);
+ g_free(pathstr);
+
+ return size;
+}
+
+static gchar *
+old_logger_read(PurpleLog *log, PurpleLogReadFlags *flags)
+{
+ size_t result;
+ old_logger_data *data;
+ const gchar *path;
+ FILE *file;
+ gchar *read;
+
+ data = log->logger_data;
+ path = purple_stringref_value(data->pathref);
+ file = g_fopen(path, "rb");
+ read = g_malloc(data->length + 1);
+
+ fseek(file, data->offset, SEEK_SET);
+ result = fread(read, data->length, 1, file);
+
+ if (result != 1)
+ purple_debug_error("log", "Unable to read from log file: %s\n", path);
+
+ fclose(file);
+ read[data->length] = '\0';
+
+ if (flags != NULL)
+ *flags = 0;
+
+ if (strstr(read, "<BR>")) {
+ if (flags != NULL)
+ *flags |= PURPLE_LOG_READ_NO_NEWLINE;
+
+ return read;
+ }
+
+ purple_str_strip_char(read, '\r');
+
+ return process_txt_log(read, NULL);
+}
+
+static gint
+old_logger_size(PurpleLog *log)
+{
+ old_logger_data *data;
+
+ data = log->logger_data;
+
+ return data ? data->length : 0;
+}
+
+static void
+old_logger_get_log_sets(PurpleLogSetCallback cb, GHashTable *sets)
+{
+ PurpleBlistNode *gnode, *cnode, *bnode;
+ PurpleBuddy *buddy;
+ PurpleLogSet *set;
+ GDir *log_dir;
+ gchar *log_path, *name, *tmp, *ext;
+ size_t len;
+ gboolean found;
+
+ log_path = g_build_filename(purple_user_dir(), "logs", NULL);
+ log_dir = g_dir_open(log_path, 0, NULL);
+ g_free(log_path);
+
+ if (log_dir == NULL)
+ return;
+
+ /* Don't worry about the cast, name will be filled with a dynamically allocated data shortly. */
+ while ((name = (gchar *) g_dir_read_name(log_dir)) != NULL) {
+ found = FALSE;
+
+ /* Unescape the filename. */
+ name = g_strdup(purple_unescape_filename(name));
+
+ /* Get the (possibly new) length of name. */
+ len = strlen(name);
+
+ if (len < 5) {
+ g_free(name);
+ continue;
+ }
+
+ /* Make sure we're dealing with a log file. */
+ ext = &name[len - 4];
+ if (!purple_strequal(ext, ".log")) {
+ g_free(name);
+ continue;
+ }
+
+ /* IMPORTANT: Always set all members of PurpleLogSet */
+ set = g_slice_new(PurpleLogSet);
+
+ /* Chat for .chat at the end of the name to determine the type. */
+ *ext = '\0';
+ set->type = PURPLE_LOG_IM;
+
+ if (len > 9) {
+ tmp = &name[len - 9];
+ if (purple_strequal(tmp, ".chat")) {
+ set->type = PURPLE_LOG_CHAT;
+ *tmp = '\0';
+ }
+ }
+
+ set->name = set->normalized_name = name;
+
+ /* Search the buddy list to find the account and to determine if this is a buddy. */
+ for (gnode = purple_blist_get_root();
+ !found && gnode != NULL;
+ gnode = purple_blist_node_get_sibling_next(gnode)) {
+ if (!PURPLE_BLIST_NODE_IS_GROUP(gnode))
+ continue;
+
+ for (cnode = purple_blist_node_get_first_child(gnode);
+ !found && cnode != NULL;
+ cnode = purple_blist_node_get_sibling_next(cnode)) {
+ if (!PURPLE_BLIST_NODE_IS_CONTACT(cnode))
+ continue;
+
+ for (bnode = purple_blist_node_get_first_child(cnode);
+ !found && bnode != NULL;
+ bnode = purple_blist_node_get_sibling_next(bnode)) {
+ buddy = (PurpleBuddy *) bnode;
+
+ if (purple_strequal(purple_buddy_get_name(buddy), name)) {
+ set->account = purple_buddy_get_account(buddy);
+ set->buddy = TRUE;
+ found = TRUE;
+ }
+ }
+ }
+ }
+
+ if (!found) {
+ set->account = NULL;
+ set->buddy = FALSE;
+ }
+
+ cb(sets, set);
+ }
+
+ g_dir_close(log_dir);
+}
+
+static void
+old_logger_finalize(PurpleLog *log)
+{
+ old_logger_data *data = log->logger_data;
+
+ purple_stringref_unref(data->pathref);
+ g_slice_free(old_logger_data, data);
+}
+
============================================================
--- /dev/null
+++ libpurple/oldlog.h 83c5a5b2951acd1273c990d0bfd090fe94af2442
@@ -0,0 +1,71 @@
+/**
+ * @file oldlog.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_OLD_LOG_H_
+#define _PURPLE_OLD_LOG_H_
+
+#include <gio/gio.h>
+
+#include "log.h"
+
+G_BEGIN_DECLS
+
+#define PURPLE_TYPE_OLD_LOG (purple_old_log_get_type())
+#define PURPLE_OLD_LOG(o) (G_TYPE_CHECK_INSTANCE_CAST((o), PURPLE_TYPE_OLD_LOG, PurpleOldLog))
+#define PURPLE_OLD_LOG_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), PURPLE_TYPE_OLD_LOG, PurpleOldLogClass))
+#define PURPLE_IS_OLD_LOG(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), PURPLE_TYPE_OLD_LOG))
+#define PURPLE_IS_OLD_LOG_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), PURPLE_TYPE_OLD_LOG))
+#define PURPLE_OLD_LOG_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), PURPLE_TYPE_OLD_LOG, PurpleOldLogClass))
+
+typedef struct _PurpleOldLog PurpleOldLog;
+typedef struct _PurpleOldLogClass PurpleOldLogClass;
+
+struct _PurpleOldLog {
+ PurpleLog parent_instance;
+};
+
+struct _PurpleOldLogClass {
+ PurpleLogClass parent_class;
+
+ void (*_purple_reserved1)(void);
+ void (*_purple_reserved2)(void);
+ void (*_purple_reserved3)(void);
+ void (*_purple_reserved4)(void);
+};
+
+GType purple_old_log_get_type(void);
+
+PurpleLog *purple_old_log_new(PurpleLogChatType chat_type, const gchar *name, PurpleAccount *account,
+ PurpleConversation *conv, time_t time, const struct tm *tm);
+
+void purple_old_log_system_init(void);
+void *purple_old_log_system_get_handle(void);
+void purple_old_log_system_uninit(void);
+
+G_END_DECLS
+
+#endif /* _PURPLE_OLD_LOG_H_ */
============================================================
--- /dev/null
+++ libpurple/txtlog.c 10c77fb598b266e130a52a4fee474f0515ffbf82
@@ -0,0 +1,516 @@
+
+
+static gchar *process_txt_log(gchar *, gchar *);
+
+
+static gsize txt_logger_write(PurpleLog *, PurpleMessageFlags, const gchar *, time_t,
+ const gchar *);
+static void txt_logger_write_thread(GSimpleAsyncResult *, GObject *, GCancellable *);
+static void txt_logger_write_async(PurpleLog *, PurpleMessageFlags, const gchar *, time_t,
+ const gchar *, gint, GCancellable *, GAsyncReadyCallback, gpointer);
+static void txt_logger_finalize(PurpleLog *);
+static GList *txt_logger_list(PurpleLogType, const gchar *, PurpleAccount *);
+static void txt_logger_list_async(PurpleLogType, const gchar *, PurpleAccount *,
+ gint, GCancellable *, GAsyncReadyCallback, gpointer);
+static GList *txt_logger_list_syslog(PurpleAccount *);
+static void txt_logger_list_syslog_async(PurpleAccount *, gint, GCancellable *,
+ GAsyncReadyCallback, gpointer);
+static gchar *txt_logger_read(PurpleLog *, PurpleLogReadFlags *);
+static void txt_logger_read_thread(GSimpleAsyncResult *, GObject *, GCancellable *);
+static void txt_logger_read_async(PurpleLog *, PurpleLogReadFlags *, gint, GCancellable *,
+ GAsyncReadyCallback, gpointer);
+static gint txt_logger_total_size(PurpleLogType, const gchar *, PurpleAccount *);
+static void txt_logger_total_size_async(PurpleLogType, const gchar *, PurpleAccount *,
+ gint, GCancellable *, GAsyncReadyCallback, gpointer);
+
+
+
+
+
+
+
+
+
+
+
+
+static gchar *
+process_txt_log(gchar *txt, gchar *to_free)
+{
+ gchar *tmp;
+
+ /* The to_free argument allows us to save a
+ * g_strdup() in some cases. */
+
+ if (to_free == NULL)
+ to_free = txt;
+
+ /* g_markup_escape_text requires valid UTF-8 */
+ if (!g_utf8_validate(txt, -1, NULL))
+ {
+ tmp = purple_utf8_salvage(txt);
+ g_free(to_free);
+ to_free = txt = tmp;
+ }
+
+ tmp = g_markup_escape_text(txt, -1);
+ g_free(to_free);
+ txt = purple_markup_linkify(tmp);
+ g_free(tmp);
+
+ return txt;
+}
+
+
+
+
+
+
+/****************************
+ ** PLAIN TEXT LOGGER *******
+ ****************************/
+
+static gsize
+txt_logger_write(PurpleLog *log, PurpleMessageFlags type, const gchar *from, time_t time,
+ const gchar *message)
+{
+ PurplePlugin *plugin;
+ PurpleLogCommonLoggerData *data;
+ const gchar *prpl;
+ gchar *stripped, *date;
+ gsize written;
+
+ plugin = purple_find_prpl(purple_account_get_protocol_id(log->account));
+ data = log->logger_data;
+ stripped = NULL;
+ written = 0;
+
+ if (data == 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.
+ */
+ prpl = PURPLE_PLUGIN_PROTOCOL_INFO(plugin)->list_icon(log->account, NULL);
+ purple_log_common_writer(log, ".txt");
+
+ data = log->logger_data;
+
+ /* if we can't write to the file, give up before we hurt ourselves */
+ if(!data->file)
+ return 0;
+
+ if (log->type == PURPLE_LOG_SYSTEM)
+ written += fprintf(data->file, "System log for account %s (%s) connected at %s\n",
+ purple_account_get_username(log->account), prpl,
+ purple_date_format_full(localtime(&log->time)));
+ else
+ written += fprintf(data->file, "Conversation with %s at %s on %s (%s)\n",
+ log->name, purple_date_format_full(localtime(&log->time)),
+ purple_account_get_username(log->account), prpl);
+ }
+
+ /* if we can't write to the file, give up before we hurt ourselves */
+ if(!data->file)
+ return 0;
+
+ stripped = purple_markup_strip_html(message);
+ date = log_get_timestamp(log, time);
+
+ if(log->type == PURPLE_LOG_SYSTEM){
+ written += fprintf(data->file, "---- %s @ %s ----\n", stripped, date);
+ } else {
+ if (type & PURPLE_MESSAGE_SEND ||
+ type & PURPLE_MESSAGE_RECV) {
+ if (type & PURPLE_MESSAGE_AUTO_RESP) {
+ written += fprintf(data->file, _("(%s) %s <AUTO-REPLY>: %s\n"), date,
+ from, stripped);
+ } else {
+ if (purple_message_meify(stripped, -1))
+ written += fprintf(data->file, "(%s) ***%s %s\n", date, from, stripped);
+ else
+ written += fprintf(data->file, "(%s) %s: %s\n", date, from, stripped);
+ }
+ } else if (type & PURPLE_MESSAGE_SYSTEM ||
+ type & PURPLE_MESSAGE_ERROR ||
+ type & PURPLE_MESSAGE_RAW)
+ written += fprintf(data->file, "(%s) %s\n", date, stripped);
+ else if (type & PURPLE_MESSAGE_NO_LOG) {
+ /* This shouldn't happen */
+ g_free(stripped);
+
+ return written;
+ } else if (type & PURPLE_MESSAGE_WHISPER)
+ written += fprintf(data->file, "(%s) *%s* %s", date, from, stripped);
+ else
+ written += fprintf(data->file, "(%s) %s%s %s\n", date, from ? from : "",
+ from ? ":" : "", stripped);
+ }
+
+ g_free(date);
+ g_free(stripped);
+ fflush(data->file);
+
+ return written;
+}
+
+static void
+txt_logger_write_thread(GSimpleAsyncResult *simple, GObject *object, GCancellable *cancellable)
+{
+ _purple_log_logger_write_callback_data *callback_data =
+ g_simple_async_result_get_op_res_gpointer(simple);
+ PurpleLog *log = callback_data->log;
+ PurpleLogCommonLoggerData *data = log->logger_data;
+ PurpleLogType type = callback_data->type;
+ GError *err = NULL;
+ GFile *file;
+ GFileOutputStream *stream;
+ GOutputStream *out_stream;
+ const gchar *from = callback_data->from, *message = callback_data->message;
+ gchar *stripped = NULL, *date, *line;
+ gssize written, size = 0;
+ gboolean write_header;
+
+ if (type & PURPLE_MESSAGE_NO_LOG) {
+ g_simple_async_result_set_error(simple,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ _("Trying to log when flagged not to"));
+
+ return;
+ }
+
+ if (data == 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.
+ */
+ purple_log_common_writer(log, ".txt");
+ data = log->logger_data;
+ 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) {
+ g_simple_async_result_set_error(simple,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ _("Unable to find log path"));
+
+ return;
+ }
+
+ file = g_file_new_for_path(data->path);
+ stream = g_file_append_to(file, G_FILE_CREATE_NONE, cancellable, &err);
+
+ if (stream == NULL) {
+ g_simple_async_result_set_from_error(simple, err);
+
+ g_object_unref(file);
+ g_clear_error(&err);
+
+ return;
+ }
+
+ g_clear_error(&err);
+ out_stream = G_OUTPUT_STREAM(stream);
+
+ if (write_header) {
+ PurplePlugin *plugin;
+ const gchar *prpl;
+
+ plugin = purple_find_prpl(purple_account_get_protocol_id(log->account));
+ prpl = PURPLE_PLUGIN_PROTOCOL_INFO(plugin)->list_icon(log->account, NULL);
+
+ if (log->type == PURPLE_LOG_SYSTEM)
+ line = g_strdup_printf("System log for account %s (%s) connected at %s\n",
+ purple_account_get_username(log->account), prpl,
+ purple_date_format_full(localtime(&log->time)));
+ else
+ line = g_strdup_printf("Conversation with %s at %s on %s (%s)\n",
+ log->name, purple_date_format_full(localtime(&log->time)),
+ purple_account_get_username(log->account), prpl);
+
+ written = g_output_stream_write(out_stream, line,
+ strlen(line), cancellable, &err);
+ g_free(line);
+
+ if (written < 0) {
+ g_simple_async_result_set_from_error(simple, err);
+
+ g_object_unref(file);
+ g_object_unref(stream);
+ g_clear_error(&err);
+
+ return;
+ }
+
+ g_clear_error(&err);
+ size += written;
+ }
+
+ stripped = purple_markup_strip_html(message);
+ date = log_get_timestamp(log, callback_data->time);
+
+ if (log->type == PURPLE_LOG_SYSTEM)
+ line = g_strdup_printf("---- %s @ %s ----\n", stripped, date);
+ else {
+ if (type & PURPLE_MESSAGE_SEND ||
+ type & PURPLE_MESSAGE_RECV)
+ {
+ if (type & PURPLE_MESSAGE_AUTO_RESP)
+ line = g_strdup_printf(_("(%s) %s <AUTO-REPLY>: %s\n"), date, from, stripped);
+ else {
+ if (purple_message_meify(stripped, -1))
+ line = g_strdup_printf("(%s) ***%s %s\n", date, from, stripped);
+ else
+ line = g_strdup_printf("(%s) %s: %s\n", date, from, stripped);
+ }
+ } else if (type & PURPLE_MESSAGE_SYSTEM ||
+ type & PURPLE_MESSAGE_ERROR ||
+ type & PURPLE_MESSAGE_RAW)
+ line = g_strdup_printf("(%s) %s\n", date, stripped);
+ else if (type & PURPLE_MESSAGE_WHISPER)
+ line = g_strdup_printf("(%s) *%s* %s", date, from, stripped);
+ else
+ line = g_strdup_printf("(%s) %s%s %s\n", date, from ? from : "",
+ from ? ":" : "", stripped);
+ }
+
+ written = g_output_stream_write(out_stream, line, strlen(line),
+ cancellable, &err);
+
+ if (written < 0)
+ g_simple_async_result_set_from_error(simple, err);
+ else
+ g_simple_async_result_set_op_res_gssize(simple, size + written);
+
+ g_clear_error(&err);
+ g_free(line);
+ g_free(date);
+ g_free(stripped);
+ g_object_unref(file);
+ g_object_unref(stream);
+}
+
+static void
+txt_logger_write_async(PurpleLog *log, PurpleMessageFlags type, const gchar *from, time_t time,
+ const gchar *message, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb,
+ gpointer userdata)
+{
+ _purple_log_logger_write_callback_data *callback_data;
+ GSimpleAsyncResult *simple;
+
+ callback_data = g_new0(_purple_log_logger_write_callback_data, 1);
+ callback_data->log = log;
+ callback_data->type = type;
+ callback_data->from = g_strdup(from);
+ callback_data->time = time;
+ callback_data->message = g_strdup(message);
+
+ simple = g_simple_async_result_new(NULL, cb, userdata, purple_log_write_async);
+
+ g_simple_async_result_set_op_res_gpointer(simple, callback_data,
+ purple_log_logger_write_callback_data_free);
+ g_simple_async_result_run_in_thread(simple, txt_logger_write_thread,
+ io_priority, cancellable);
+
+ g_object_unref(simple);
+}
+
+static void
+txt_logger_finalize(PurpleLog *log)
+{
+ PurpleLogCommonLoggerData *data = log->logger_data;
+
+ if (data != NULL) {
+ if (data->file != NULL)
+ fclose(data->file);
+
+ g_free(data->path);
+ g_slice_free(PurpleLogCommonLoggerData, data);
+ }
+}
+
+static GList *
+txt_logger_list(PurpleLogType type, const gchar *sn, PurpleAccount *account)
+{
+ GList *list;
+
+ G_LOCK(txt_logger);
+ list = purple_log_common_lister(type, sn, account, ".txt", txt_logger);
+ G_UNLOCK(txt_logger);
+
+ return list;
+}
+
+static void
+txt_logger_list_async(PurpleLogType type, const gchar *sn, PurpleAccount *account,
+ gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
+{
+ G_LOCK(txt_logger);
+ purple_log_common_lister_async(type, sn, account, ".txt", txt_logger,
+ io_priority, cancellable, cb, userdata);
+ G_UNLOCK(txt_logger);
+}
+
+static GList *
+txt_logger_list_syslog(PurpleAccount *account)
+{
+ GList *list;
+
+ G_LOCK(txt_logger);
+ list = purple_log_common_lister(PURPLE_LOG_SYSTEM, ".system", account, ".txt", txt_logger);
+ G_UNLOCK(txt_logger);
+
+ return list;
+}
+
+static void
+txt_logger_list_syslog_async(PurpleAccount *account, gint io_priority, GCancellable *cancellable,
+ GAsyncReadyCallback cb, gpointer userdata)
+{
+ G_LOCK(txt_logger);
+ purple_log_common_lister_async(PURPLE_LOG_SYSTEM, ".system", account, ".txt", txt_logger,
+ io_priority, cancellable, cb, userdata);
+ G_UNLOCK(txt_logger);
+}
+
+static gchar *
+txt_logger_read(PurpleLog *log, PurpleLogReadFlags *flags)
+{
+ PurpleLogCommonLoggerData *data;
+ gchar *read, *minus_header;
+
+ data = log->logger_data;
+
+ if (flags != NULL)
+ *flags = 0;
+
+ if (!data || !data->path)
+ return g_strdup_printf("<font color=\"red\"><b>%s</b></font>",
+ _("Unable to find log path"));
+
+ if (g_file_get_contents(data->path, &read, NULL, NULL)) {
+ minus_header = strchr(read, '\n');
+
+ if (minus_header)
+ return process_txt_log(minus_header + 1, read);
+ else
+ return process_txt_log(read, NULL);
+ }
+
+ return g_strdup_printf("<font color=\"red\"><b>%s: %s</b></font>",
+ _("Could not read file"), data->path);
+}
+
+static void
+txt_logger_read_thread(GSimpleAsyncResult *simple, GObject *object, GCancellable *cancellable)
+{
+ _purple_log_logger_read_callback_data *callback_data =
+ g_simple_async_result_get_op_res_gpointer(simple);
+ PurpleLog *log = callback_data->log;
+ PurpleLogCommonLoggerData *data = log->logger_data;
+ PurpleLogReadFlags *flags = callback_data->flags;
+ GError *err = NULL;
+ GFile *file;
+ gchar *read, *minus_header;
+
+ if (flags != NULL)
+ *flags = 0;
+
+ if (data == NULL || data->path == NULL) {
+ g_simple_async_result_set_error(simple,
+ G_FILE_ERROR,
+ G_IO_ERROR_NOT_FOUND,
+ "<font color=\"red\"><b>%s</b></font>",
+ _("Unable to find log path"));
+
+ return;
+ }
+
+ file = g_file_new_for_path(data->path);
+
+ if (!g_file_load_contents(file, cancellable, &read, NULL, NULL, &err)) {
+ g_simple_async_result_set_error(simple,
+ err->domain,
+ err->code,
+ "<font color=\"red\"><b>%s</b></font>",
+ err->message);
+
+ g_clear_error(&err);
+
+ return;
+ }
+
+ g_clear_error(&err);
+
+ minus_header = strchr(read, '\n');
+
+ if (minus_header != NULL)
+ read = process_txt_log(minus_header + 1, read);
+ else
+ read = process_txt_log(read, NULL);
+
+ purple_str_strip_char(read, '\r');
+
+ g_simple_async_result_set_op_res_gpointer(simple, read, g_free);
+}
+
+static void
+txt_logger_read_async(PurpleLog *log, PurpleLogReadFlags *flags, gint io_priority,
+ GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
+{
+ _purple_log_logger_read_callback_data *callback_data;
+ GSimpleAsyncResult *simple;
+
+ callback_data = g_new0(_purple_log_logger_read_callback_data, 1);
+ callback_data->flags = flags;
+ callback_data->log = log;
+
+ simple = g_simple_async_result_new(NULL, cb, userdata, purple_log_read_async);
+
+ g_simple_async_result_set_op_res_gpointer(simple, callback_data, g_free);
+ g_simple_async_result_run_in_thread(simple, txt_logger_read_thread,
+ io_priority, cancellable);
+
+ g_object_unref(simple);
+}
+
+static gint
+txt_logger_total_size(PurpleLogType type, const gchar *name, PurpleAccount *account)
+{
+ return purple_log_common_total_sizer(type, name, account, ".txt");
+}
+
+static void
+txt_logger_total_size_async(PurpleLogType type, const gchar *name, PurpleAccount *account,
+ gint io_priority, GCancellable *cancellable, GAsyncReadyCallback cb, gpointer userdata)
+{
+ purple_log_common_total_sizer_async(type, name, account, ".txt",
+ io_priority, cancellable, cb, userdata);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
============================================================
--- /dev/null
+++ libpurple/txtlog.h 01bea99cc3956da3d332ca41cc98bb3e8e90f703
@@ -0,0 +1,71 @@
+/**
+ * @file txtlog.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_TXT_LOG_H_
+#define _PURPLE_TXT_LOG_H_
+
+#include <gio/gio.h>
+
+#include "log.h"
+
+G_BEGIN_DECLS
+
+#define PURPLE_TYPE_TXT_LOG (purple_txt_log_get_type())
+#define PURPLE_TXT_LOG(o) (G_TYPE_CHECK_INSTANCE_CAST((o), PURPLE_TYPE_TXT_LOG, PurpleTxtLog))
+#define PURPLE_TXT_LOG_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), PURPLE_TYPE_TXT_LOG, PurpleTxtLogClass))
+#define PURPLE_IS_TXT_LOG(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), PURPLE_TYPE_TXT_LOG))
+#define PURPLE_IS_TXT_LOG_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), PURPLE_TYPE_TXT_LOG))
+#define PURPLE_TXT_LOG_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), PURPLE_TYPE_TXT_LOG, PurpleTxtLogClass))
+
+typedef struct _PurpleTxtLog PurpleTxtLog;
+typedef struct _PurpleTxtLogClass PurpleTxtLogClass;
+
+struct _PurpleTxtLog {
+ PurpleLog parent_instance;
+};
+
+struct _PurpleTxtLogClass {
+ PurpleLogClass parent_class;
+
+ void (*_purple_reserved1)(void);
+ void (*_purple_reserved2)(void);
+ void (*_purple_reserved3)(void);
+ void (*_purple_reserved4)(void);
+};
+
+GType purple_txt_log_get_type(void);
+
+PurpleLog *purple_txt_log_new(PurpleLogChatType chat_type, const gchar *name, PurpleAccount *account,
+ PurpleConversation *conv, time_t time, const struct tm *tm);
+
+void purple_txt_log_system_init(void);
+void *purple_txt_log_system_get_handle(void);
+void purple_txt_log_system_uninit(void);
+
+G_END_DECLS
+
+#endif /* _PURPLE_TXT_LOG_H_ */
============================================================
--- /dev/null
+++ libpurple/xmllog.c c44388ba6b4d07929fe5e59ff5a574fa4c9d6d2d
@@ -0,0 +1,111 @@
+#if 0 /* Maybe some other time. */
+/****************
+ ** XML LOGGER **
+ ****************/
+
+static const gchar *
+str_from_msg_type (PurpleMessageFlags type)
+{
+ return "";
+}
+
+static void
+xml_logger_write(PurpleLog *log, PurpleMessageFlags type, const gchar *from, time_t time,
+ const gchar *message)
+{
+ gchar *xhtml = NULL;
+
+ if (!log->logger_data) {
+ /* 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.
+ */
+ struct tm *tm;
+ const gchar *tz;
+ const gchar *date;
+ gchar *dir = purple_log_get_log_dir(log->type, log->name, log->account);
+ gchar *name;
+ gchar *filename;
+
+ if (dir == NULL)
+ return;
+
+ 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);
+
+ name = g_strdup_printf("%s%s%s", date, tz, ext ? ext : "");
+
+ purple_build_dir (dir, S_IRUSR | S_IWUSR | S_IXUSR);
+
+ filename = g_build_filename(dir, name, NULL);
+ g_free(dir);
+ g_free(name);
+
+ log->logger_data = g_fopen(filename, "a");
+ if (!log->logger_data) {
+ purple_debug(PURPLE_DEBUG_ERROR, "log", "Could not create log file %s\n", filename);
+ g_free(filename);
+ return;
+ }
+ g_free(filename);
+ fprintf(log->logger_data, "<?xml version='1.0' encoding='UTF-8' ?>\n"
+ "<?xml-stylesheet href='file:///usr/src/web/htdocs/log-stylesheet.xsl' type='text/xml' ?>\n");
+
+ date = purple_utf8_strftime("%Y-%m-%d %H:%M:%S", localtime(&log->time));
+ fprintf(log->logger_data, "<conversation time='%s' screenname='%s' protocol='%s'>\n",
+ date, log->name, prpl);
+ }
+
+ /* if we can't write to the file, give up before we hurt ourselves */
+ if(!data->file)
+ return;
+
+ date = log_get_timestamp(log, time);
+
+ purple_markup_html_to_xhtml(message, &xhtml, NULL);
+ if (from)
+ fprintf(log->logger_data, "<message %s %s from='%s' time='%s'>%s</message>\n",
+ str_from_msg_type(type),
+ type & PURPLE_MESSAGE_SEND ? "direction='sent'" :
+ type & PURPLE_MESSAGE_RECV ? "direction='received'" : "",
+ from, date, xhtml);
+ else
+ fprintf(log->logger_data, "<message %s %s time='%s'>%s</message>\n",
+ str_from_msg_type(type),
+ type & PURPLE_MESSAGE_SEND ? "direction='sent'" :
+ type & PURPLE_MESSAGE_RECV ? "direction='received'" : "",
+ date, xhtml):
+ fflush(log->logger_data);
+ g_free(date);
+ g_free(xhtml);
+}
+
+ static void
+ xml_logger_finalize(PurpleLog *log)
+{
+ if (log->logger_data) {
+ fprintf(log->logger_data, "</conversation>\n");
+ fclose(log->logger_data);
+ log->logger_data = NULL;
+ }
+}
+
+static GList *
+xml_logger_list(PurpleLogType type, const gchar *sn, PurpleAccount *account)
+{
+ return purple_log_common_lister(type, sn, account, ".xml", &xml_logger);
+}
+
+static PurpleLogLogger xml_logger = {
+ N_("XML"), "xml",
+ NULL,
+ xml_logger_write,
+ xml_logger_finalize,
+ xml_logger_list,
+ NULL,
+ NULL,
+ NULL
+};
+#endif
+
============================================================
--- /dev/null
+++ libpurple/xmllog.h da39a3ee5e6b4b0d3255bfef95601890afd80709
More information about the Commits
mailing list