summaryrefslogtreecommitdiff
path: root/telepathy-logger
diff options
context:
space:
mode:
authorCosimo Alfarano <cosimo.alfarano@collabora.co.uk>2010-01-13 14:58:08 +0000
committerCosimo Alfarano <cosimo.alfarano@collabora.co.uk>2010-01-13 14:58:08 +0000
commitc5a57433eb4c2ade0fc110d98093eea2bb42de3e (patch)
treececda8ac7bdc2bab944c8e16cbcab5e610dfc89c /telepathy-logger
parent4ed7270537dce069ee0f73d24a575043828f1622 (diff)
downloadtelepathy-logger-c5a57433eb4c2ade0fc110d98093eea2bb42de3e.tar.gz
Async API infrastructure
* moved code from libtelepathy-logger/ to telepathy-logger/ * used /usr/bin/indent filter with GNU style for source formatting * added log-manager's async APIs infrastructure using GIO * addes some async method using the async infrastructure * added gconf infrastructure in the telepathy-logger/conf module
Diffstat (limited to 'telepathy-logger')
-rw-r--r--telepathy-logger/Makefile.am57
-rw-r--r--telepathy-logger/channel-text.c708
-rw-r--r--telepathy-logger/channel-text.h90
-rw-r--r--telepathy-logger/channel.c334
-rw-r--r--telepathy-logger/channel.h99
-rw-r--r--telepathy-logger/conf.c93
-rw-r--r--telepathy-logger/contact.c216
-rw-r--r--telepathy-logger/contact.h100
-rw-r--r--telepathy-logger/datetime.c186
-rw-r--r--telepathy-logger/datetime.h42
-rw-r--r--telepathy-logger/debug.h2
-rw-r--r--telepathy-logger/libtelepathy-logger.pc.in11
-rw-r--r--telepathy-logger/log-entry-text.c292
-rw-r--r--telepathy-logger/log-entry-text.h144
-rw-r--r--telepathy-logger/log-entry.c131
-rw-r--r--telepathy-logger/log-entry.h74
-rw-r--r--telepathy-logger/log-manager-priv.h34
-rw-r--r--telepathy-logger/log-manager.c833
-rw-r--r--telepathy-logger/log-manager.h198
-rw-r--r--telepathy-logger/log-store-empathy.c1097
-rw-r--r--telepathy-logger/log-store-empathy.h65
-rw-r--r--telepathy-logger/log-store.c197
-rw-r--r--telepathy-logger/log-store.h115
-rw-r--r--telepathy-logger/observer.c411
-rw-r--r--telepathy-logger/observer.h70
-rw-r--r--telepathy-logger/telepathy-logger.schemas32
-rw-r--r--telepathy-logger/utils.c40
-rw-r--r--telepathy-logger/utils.h54
28 files changed, 5725 insertions, 0 deletions
diff --git a/telepathy-logger/Makefile.am b/telepathy-logger/Makefile.am
new file mode 100644
index 0000000..34ce6dd
--- /dev/null
+++ b/telepathy-logger/Makefile.am
@@ -0,0 +1,57 @@
+include $(top_srcdir)/tools/shave.mk
+include $(top_srcdir)/tools/flymake.mk
+
+AM_CPPFLAGS = \
+ $(ERROR_CFLAGS) \
+ -DG_LOG_DOMAIN=\"telepathy-logger\" \
+ $(LIBTPL_CFLAGS) \
+ $(DISABLE_DEPRECATED) \
+ $(WARN_CFLAGS)
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = libtelepathy-logger.pc
+
+lib_LTLIBRARIES = libtelepathy-logger.la
+
+LIBTPLdir = $(includedir)/telepathy-logger
+LIBTPL_HEADERS = \
+ observer.h \
+ channel.h \
+ contact.h \
+ log-entry.h \
+ log-entry-text.h \
+ log-manager.h \
+ log-manager-priv.h \
+ log-store-empathy.h \
+ log-store.h \
+ channel-text.h \
+ datetime.h \
+ utils.h
+
+
+libtelepathy_logger_la_SOURCES = \
+ observer.c \
+ channel.c \
+ channel-text.c \
+ log-entry.c \
+ log-entry-text.c \
+ contact.c \
+ log-manager.c \
+ log-store.c \
+ log-store-empathy.c \
+ utils.c \
+ datetime.c
+
+schemadir = @GCONF_SCHEMA_FILE_DIR@
+schema_DATA = telepathy-logger.schemas
+
+install-data-local:
+ GCONF_CONFIG_SOURCE=$(GCONF_SCHEMA_CONFIG_SOURCE) $(GCONFTOOL) \
+ --makefile-install-rule $(srcdir)/$(schema_DATA)
+
+check_c_sources = \
+ $(libtelepathy_logger_la_SOURCES) \
+include $(top_srcdir)/tools/check-coding-style.mk
+check-local: check-coding-style
+
+CLEANFILES = $(BUILT_SOURCES)
diff --git a/telepathy-logger/channel-text.c b/telepathy-logger/channel-text.c
new file mode 100644
index 0000000..ca8e679
--- /dev/null
+++ b/telepathy-logger/channel-text.c
@@ -0,0 +1,708 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2009 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Cosimo Alfarano <cosimo.alfarano@collabora.co.uk>
+ */
+
+/*
+ * This object acts as a Text Channel context, handling a automaton to
+ * set up all the needed information before connect to Text iface
+ * signals.
+ */
+
+#include "channel-text.h"
+
+#include <telepathy-glib/contact.h>
+#include <telepathy-glib/enums.h>
+
+#include <telepathy-logger/contact.h>
+#include <telepathy-logger/channel.h>
+#include <telepathy-logger/observer.h>
+#include <telepathy-logger/log-entry.h>
+#include <telepathy-logger/log-entry-text.h>
+#include <telepathy-logger/log-manager-priv.h>
+
+#define TP_CONTACT_FEATURES_LEN 2
+#define TP_CONTACT_MYSELF 0
+#define TP_CONTACT_REMOTE 1
+
+typedef void (*TplPendingProc) (TplTextChannel * self);
+
+static TpContactFeature features[TP_CONTACT_FEATURES_LEN] = {
+ TP_CONTACT_FEATURE_ALIAS,
+ TP_CONTACT_FEATURE_PRESENCE
+};
+
+/* Signal's Callbacks */
+
+static void
+_channel_on_closed_cb (TpChannel * proxy,
+ gpointer user_data, GObject * weak_object)
+{
+ TplTextChannel *tpl_text = TPL_TEXT_CHANNEL (user_data);
+ TplChannel *tpl_chan = tpl_text_channel_get_tpl_channel (tpl_text);
+ gchar *chan_path;
+
+ chan_path = g_strdup (tpl_channel_get_channel_path (tpl_chan));
+
+ if (!tpl_channel_unregister_from_observer (tpl_chan))
+ g_warning ("Channel %s couldn't be unregistered correctly (BUG?)\n",
+ chan_path);
+
+ g_free (chan_path);
+}
+
+static void
+_channel_on_lost_message_cb (TpChannel * proxy,
+ gpointer user_data, GObject * weak_object)
+{
+ g_debug ("lost message signal catched. nothing logged\n");
+ // TODO log that the system lost a message
+}
+
+static void
+_channel_on_send_error_cb (TpChannel * proxy,
+ guint arg_Error,
+ guint arg_Timestamp,
+ guint arg_Type,
+ const gchar * arg_Text,
+ gpointer user_data, GObject * weak_object)
+{
+ g_error ("unlogged event: "
+ "TP was unable to send the message: %s.\n", arg_Text);
+ // TODO log that the system was unable to send the message
+}
+
+
+static void
+_channel_on_sent_signal_cb (TpChannel * proxy,
+ guint arg_Timestamp,
+ guint arg_Type,
+ const gchar * arg_Text,
+ gpointer user_data, GObject * weak_object)
+{
+ GError *error = NULL;
+ TplTextChannel *tpl_text = TPL_TEXT_CHANNEL (user_data);
+ TpContact *remote, *me;
+ TplContact *tpl_contact_sender;
+ TplContact *tpl_contact_receiver;
+ TplLogEntryText *tlog;
+ TplLogEntry *log;
+ TplLogManager *logmanager;
+ gchar *chat_id;
+
+ g_assert (TPL_IS_TEXT_CHANNEL (tpl_text));
+ g_return_if_fail (TPL_IS_TEXT_CHANNEL (tpl_text));
+
+ /* Initialize data for TplContact */
+ me = tpl_text_channel_get_my_contact (tpl_text);
+ remote = tpl_text_channel_get_remote_contact (tpl_text);
+
+ if (!tpl_text_channel_is_chatroom (tpl_text) && remote == NULL)
+ {
+ g_error ("Sending message: Remote TplContact NULL on 1-1 Chat\n");
+ }
+
+ tpl_contact_sender = tpl_contact_from_tp_contact (me);
+ tpl_contact_set_contact_type (tpl_contact_sender, TPL_CONTACT_USER);
+ tpl_contact_receiver = tpl_contact_from_tp_contact (remote);
+ tpl_contact_set_contact_type (tpl_contact_receiver, TPL_CONTACT_USER);
+
+ g_message ("%s (%s): %s\n",
+ tpl_contact_get_identifier (tpl_contact_sender),
+ tpl_contact_get_alias (tpl_contact_sender), arg_Text);
+
+ /* Initialize TplLogEntryText */
+ log = tpl_log_entry_new ();
+ tlog = tpl_log_entry_text_new ();
+
+ tpl_log_entry_text_set_tpl_text_channel (tlog, tpl_text);
+ tpl_log_entry_text_set_sender (tlog, tpl_contact_sender);
+ tpl_log_entry_text_set_receiver (tlog, tpl_contact_receiver);
+ tpl_log_entry_text_set_message (tlog, arg_Text);
+ tpl_log_entry_text_set_message_type (tlog, arg_Type);
+ tpl_log_entry_text_set_signal_type (tlog, TPL_LOG_ENTRY_TEXT_SIGNAL_SENT);
+ tpl_log_entry_text_set_message_id (tlog, 123);
+
+ tpl_log_entry_set_entry (log, tlog);
+ tpl_log_entry_set_timestamp (log, (time_t) arg_Timestamp);
+
+ /* Initialized LogStore and send the log entry */
+
+ if (!tpl_text_channel_is_chatroom (tpl_text))
+ chat_id = g_strdup (tpl_contact_get_identifier (tpl_contact_receiver));
+ else
+ chat_id = g_strdup (tpl_text_channel_get_chatroom_id (tpl_text));
+
+ tpl_log_entry_text_set_chat_id (tlog, chat_id);
+
+ logmanager = tpl_log_manager_dup_singleton ();
+
+ tpl_log_manager_add_message (logmanager, chat_id,
+ tpl_text_channel_is_chatroom (tpl_text),
+ log, &error);
+
+ if (error != NULL)
+ {
+ g_error ("LogStore: %s", error->message);
+ g_clear_error (&error);
+ g_error_free (error);
+ }
+
+ g_object_unref (tpl_contact_receiver);
+ g_object_unref (tpl_contact_sender);
+ g_object_unref (logmanager);
+ g_object_unref (log);
+ g_free (chat_id);
+}
+
+static void
+_channel_on_received_signal_with_contact_cb (TpConnection * connection,
+ guint n_contacts,
+ TpContact * const *contacts,
+ guint n_failed,
+ const TpHandle * failed,
+ const GError * error,
+ gpointer user_data,
+ GObject * weak_object)
+{
+ TplLogEntry *log = TPL_LOG_ENTRY (user_data);
+ TplLogEntryText *tlog = TPL_LOG_ENTRY_TEXT (tpl_log_entry_get_entry (log));
+ TplTextChannel *tpl_text = tpl_log_entry_text_get_tpl_text_channel (tlog);
+ GError *e = NULL;
+ TplLogManager *logmanager;
+ TplContact *tpl_contact_sender;
+ TpContact *remote;
+ gchar *chat_id;
+
+ g_return_if_fail (TPL_IS_LOG_ENTRY (log));
+ g_return_if_fail (TPL_IS_LOG_ENTRY_TEXT (tlog));
+
+ if (error != NULL)
+ {
+ g_error ("Unrecoverable error retrieving remote contact "
+ "information: %s\n", error->message);
+ g_error ("Not able to log the received message: %s\n",
+ tpl_log_entry_text_get_message (tlog));
+ return;
+ }
+
+ if (n_failed > 0)
+ {
+ g_error ("%d invalid handle(s) passed to "
+ "tp_connection_get_contacts_by_handle()\n", n_failed);
+ g_error ("Not able to log the received message: %s\n",
+ tpl_log_entry_text_get_message (tlog));
+ return;
+ }
+
+ remote = contacts[0];
+ tpl_text_channel_set_remote_contact (tpl_text, remote);
+ tpl_contact_sender = tpl_contact_from_tp_contact (remote);
+
+ tpl_contact_set_contact_type (tpl_contact_sender, TPL_CONTACT_USER);
+ tpl_log_entry_text_set_sender (tlog, tpl_contact_sender);
+
+ g_message ("%s (%s): %s\n",
+ tpl_contact_get_identifier (tpl_contact_sender),
+ tpl_contact_get_alias (tpl_contact_sender),
+ tpl_log_entry_text_get_message (tlog));
+
+ /* Initialize LogStore and store the message */
+
+ if (!tpl_text_channel_is_chatroom (tpl_text))
+ chat_id = g_strdup (tpl_contact_get_identifier (tpl_contact_sender));
+ else
+ chat_id = g_strdup (tpl_text_channel_get_chatroom_id (tpl_text));
+
+ tpl_log_entry_text_set_chat_id (tlog, chat_id);
+
+ logmanager = tpl_log_manager_dup_singleton ();
+ tpl_log_manager_add_message (logmanager,
+ tpl_log_entry_text_get_chat_id (tlog),
+ tpl_text_channel_is_chatroom (tpl_text),
+ log, &e);
+ if (e != NULL)
+ {
+ g_error ("LogStore: %s", e->message);
+ g_clear_error (&e);
+ g_error_free (e);
+ }
+
+ g_object_unref (tpl_contact_sender);
+ g_object_unref (logmanager);
+ g_free (chat_id);
+}
+
+static void
+_channel_on_received_signal_cb (TpChannel * proxy,
+ guint arg_ID,
+ guint arg_Timestamp,
+ guint arg_Sender,
+ guint arg_Type,
+ guint arg_Flags,
+ const gchar * arg_Text,
+ gpointer user_data, GObject * weak_object)
+{
+ TpHandle remote_handle = (TpHandle) arg_Sender;
+ TplTextChannel *tpl_text = TPL_TEXT_CHANNEL (user_data);
+ TplChannel *tpl_chan = tpl_text_channel_get_tpl_channel (tpl_text);
+ TpContact *me;
+ TplContact *tpl_contact_receiver;
+ TplLogEntry *log;
+ TplLogEntryText *tlog;
+
+ g_message ("ID: %d\n", arg_ID);
+
+ // TODO use the Message iface to check the delivery
+ // notification and handle it correctly
+ if (arg_Flags & TP_CHANNEL_TEXT_MESSAGE_FLAG_NON_TEXT_CONTENT)
+ {
+ g_debug ("Non text content flag set."
+ "Probably a delivery notification for a sent message."
+ "Ignoring\n");
+ return;
+ }
+
+ /* Initialize TplLogEntryText (part 1) */
+ log = tpl_log_entry_new ();
+ tlog = tpl_log_entry_text_new ();
+ tpl_log_entry_set_entry (log, tlog);
+
+ tpl_log_entry_text_set_tpl_text_channel (tlog, tpl_text);
+ tpl_log_entry_text_set_message (tlog, arg_Text);
+ tpl_log_entry_text_set_message_type (tlog, arg_Type);
+ tpl_log_entry_text_set_signal_type (tlog,
+ TPL_LOG_ENTRY_TEXT_SIGNAL_RECEIVED);
+ tpl_log_entry_text_set_message_id (tlog, 123); //TODO set a real Id
+
+ me = tpl_text_channel_get_my_contact (tpl_text);
+ tpl_contact_receiver = tpl_contact_from_tp_contact (me);
+ tpl_contact_set_contact_type (tpl_contact_receiver, TPL_CONTACT_USER);
+ tpl_log_entry_text_set_receiver (tlog, tpl_contact_receiver);
+
+ tpl_log_entry_set_timestamp (log, (time_t) arg_Timestamp);
+
+ tp_connection_get_contacts_by_handle (tpl_channel_get_connection (tpl_chan),
+ 1, &remote_handle,
+ TP_CONTACT_FEATURES_LEN, features,
+ _channel_on_received_signal_with_contact_cb,
+ log, g_object_unref, NULL);
+
+ g_object_unref (tpl_contact_receiver);
+}
+
+/* End of Signal's Callbacks */
+
+
+/* Context related operations */
+
+static void
+context_continue (TplTextChannel * ctx)
+{
+ if (g_queue_is_empty (ctx->chain))
+ {
+ // TODO do some sanity checks
+ }
+ else
+ {
+ TplPendingProc next = g_queue_pop_head (ctx->chain);
+ next (ctx);
+ }
+}
+
+/* Context TplPendingProc and related CB */
+
+/* Connect signals to TplTextChannel instance */
+static void
+_tpl_text_channel_pendingproc_connect_signals (TplTextChannel * self)
+{
+ GError *error = NULL;
+ TpChannel *channel = NULL;
+
+ channel = tpl_channel_get_channel (tpl_text_channel_get_tpl_channel (self));
+
+ tp_cli_channel_type_text_connect_to_received (channel,
+ _channel_on_received_signal_cb,
+ self, NULL, NULL, &error);
+ if (error != NULL)
+ {
+ g_error ("received signal connect: %s\n", error->message);
+ g_clear_error (&error);
+ g_error_free (error);
+ error = NULL;
+ }
+
+ tp_cli_channel_type_text_connect_to_sent (channel,
+ _channel_on_sent_signal_cb, self,
+ NULL, NULL, &error);
+ if (error != NULL)
+ {
+ g_error ("sent signal connect: %s\n", error->message);
+ g_clear_error (&error);
+ g_error_free (error);
+ error = NULL;
+ }
+
+ tp_cli_channel_type_text_connect_to_send_error (channel,
+ _channel_on_send_error_cb,
+ self, NULL, NULL, &error);
+ if (error != NULL)
+ {
+ g_error ("send error signal connect: %s\n", error->message);
+ g_clear_error (&error);
+ g_error_free (error);
+ error = NULL;
+ }
+
+ tp_cli_channel_type_text_connect_to_lost_message (channel,
+ _channel_on_lost_message_cb,
+ self, NULL, NULL, &error);
+ if (error != NULL)
+ {
+ g_error ("lost message signal connect: %s\n", error->message);
+ g_clear_error (&error);
+ g_error_free (error);
+ error = NULL;
+ }
+
+ tp_cli_channel_connect_to_closed (channel, _channel_on_closed_cb,
+ self, NULL, NULL, &error);
+ if (error != NULL)
+ {
+ g_error ("channel closed signal connect: %s\n", error->message);
+ g_clear_error (&error);
+ g_error_free (error);
+ error = NULL;
+ }
+
+ // TODO connect to TpContacts' notify::presence-type
+ context_continue (self);
+}
+
+static void
+_tpl_text_channel_get_chatroom_cb (TpConnection * proxy,
+ const gchar ** out_Identifiers,
+ const GError * error,
+ gpointer user_data, GObject * weak_object)
+{
+ TplTextChannel *tpl_text = TPL_TEXT_CHANNEL (user_data);
+
+ if (error != NULL)
+ {
+ g_error ("retrieving chatroom identifier: %s\n", error->message);
+ }
+
+ tpl_text_channel_set_chatroom_id (tpl_text, *out_Identifiers);
+
+ context_continue (tpl_text);
+}
+
+static void
+_tpl_text_channel_pendingproc_get_chatroom_id (TplTextChannel * ctx)
+{
+ TplChannel *tpl_chan = tpl_text_channel_get_tpl_channel (ctx);
+ TpConnection *connection = tpl_channel_get_connection (tpl_chan);
+ TpHandle room_handle;
+ GArray *handles;
+
+ handles = g_array_new (FALSE, FALSE, sizeof (TpHandle));
+ room_handle = tp_channel_get_handle (tpl_channel_get_channel (tpl_chan),
+ NULL);
+ g_array_append_val (handles, room_handle);
+
+ tpl_text_channel_set_chatroom (ctx, TRUE);
+ tp_cli_connection_call_inspect_handles (connection,
+ -1, TP_HANDLE_TYPE_ROOM, handles,
+ _tpl_text_channel_get_chatroom_cb,
+ ctx, NULL, NULL);
+
+ g_array_unref (handles);
+}
+
+
+/* retrieve contacts (me and remote buddy/chatroom) and set TplTextChannel
+ * members */
+
+
+// used by _get_my_contact and _get_remote_contact
+static void
+_tpl_text_channel_get_contact_cb (TpConnection * connection,
+ guint n_contacts,
+ TpContact * const *contacts,
+ guint n_failed,
+ const TpHandle * failed,
+ const GError * error,
+ gpointer user_data, GObject * weak_object)
+{
+ TplTextChannel *tpl_text = TPL_TEXT_CHANNEL (user_data);
+
+ g_assert_cmpuint (n_failed, ==, 0);
+ g_assert_cmpuint (n_contacts, ==, 1);
+ g_assert_cmpuint (tpl_text->selector, <=, TP_CONTACT_REMOTE);
+
+ if (n_failed > 0)
+ {
+ g_error ("error resolving self handle for connection %s.\n"
+ "Aborting channel %s observation\n",
+ tpl_channel_get_connection_path
+ (tpl_text_channel_get_tpl_channel (tpl_text)),
+ tpl_channel_get_channel_path (tpl_text_channel_get_tpl_channel
+ (tpl_text)));
+ tpl_channel_unregister_from_observer (tpl_text_channel_get_tpl_channel
+ (tpl_text));
+ return;
+ }
+
+ switch (tpl_text->selector)
+ {
+ case TP_CONTACT_MYSELF:
+ tpl_text_channel_set_my_contact (tpl_text, *contacts);
+ break;
+ case TP_CONTACT_REMOTE:
+ tpl_text_channel_set_remote_contact (tpl_text, *contacts);
+ break;
+ default:
+ g_error ("retrieving TpContacts: passing invalid value "
+ "for selector: %d\n"
+ "Aborting channel %s observation\n",
+ tpl_text->selector,
+ tpl_channel_get_channel_path (tpl_text_channel_get_tpl_channel
+ (tpl_text)));
+ tpl_channel_unregister_from_observer (tpl_text_channel_get_tpl_channel
+ (tpl_text));
+ return;
+ }
+
+ context_continue (tpl_text);
+}
+
+
+static void
+_tpl_text_channel_pendingproc_get_remote_contact (TplTextChannel * ctx)
+{
+ TplChannel *tpl_chan = tpl_text_channel_get_tpl_channel (ctx);
+ TpHandleType remote_handle_type;
+ TpHandle remote_handle;
+
+ remote_handle = tp_channel_get_handle (tpl_channel_get_channel (tpl_chan),
+ &remote_handle_type);
+
+ ctx->selector = TP_CONTACT_REMOTE;
+ tp_connection_get_contacts_by_handle (tpl_channel_get_connection (tpl_chan),
+ 1, &remote_handle,
+ TP_CONTACT_FEATURES_LEN, features,
+ _tpl_text_channel_get_contact_cb,
+ ctx, NULL, NULL);
+}
+
+static void
+_tpl_text_channel_pendingproc_get_my_contact (TplTextChannel * ctx)
+{
+ TplChannel *tpl_chan = tpl_text_channel_get_tpl_channel (ctx);
+ TpHandle my_handle =
+ tp_connection_get_self_handle (tpl_channel_get_connection (tpl_chan));
+
+ ctx->selector = TP_CONTACT_MYSELF;
+ tp_connection_get_contacts_by_handle (tpl_channel_get_connection (tpl_chan),
+ 1, &my_handle,
+ TP_CONTACT_FEATURES_LEN, features,
+ _tpl_text_channel_get_contact_cb,
+ ctx, NULL, NULL);
+}
+
+/* end of async Callbacks */
+
+
+G_DEFINE_TYPE (TplTextChannel, tpl_text_channel, G_TYPE_OBJECT)
+ static void tpl_text_channel_dispose (GObject * obj)
+{
+ TplTextChannel *self = TPL_TEXT_CHANNEL (obj);
+
+ g_debug ("TplTextChannel: disposing\n");
+
+ tpl_object_unref_if_not_null (self->tpl_channel);
+ self->tpl_channel = NULL;
+ tpl_object_unref_if_not_null (self->my_contact);
+ self->my_contact = NULL;
+ tpl_object_unref_if_not_null (self->remote_contact);
+ self->remote_contact = NULL;
+ g_queue_free (self->chain);
+ self->chain = NULL;
+
+ G_OBJECT_CLASS (tpl_text_channel_parent_class)->dispose (obj);
+
+ g_debug ("TplTextChannel: disposed\n");
+}
+
+static void
+tpl_text_channel_finalize (GObject * obj)
+{
+ TplTextChannel *self = TPL_TEXT_CHANNEL (obj);
+
+ g_debug ("TplTextChannel: finalizing\n");
+
+ g_free ((gchar *) self->chatroom_id);
+ G_OBJECT_CLASS (tpl_text_channel_parent_class)->finalize (obj);
+
+ g_debug ("TplTextChannel: finalized\n");
+}
+
+static void
+tpl_text_channel_class_init (TplTextChannelClass * klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = tpl_text_channel_dispose;
+ object_class->finalize = tpl_text_channel_finalize;
+}
+
+
+static void
+tpl_text_channel_init (TplTextChannel * self)
+{
+ /* Init TplTextChannel's members to zero/NULL */
+#undef TPL_SET_NULL
+ tpl_text_channel_set_tpl_channel (self, NULL);
+ tpl_text_channel_set_my_contact (self, NULL);
+ tpl_text_channel_set_remote_contact (self, NULL);
+ tpl_text_channel_set_chatroom_id (self, NULL);
+ tpl_text_channel_set_chatroom (self, FALSE);
+}
+
+TplTextChannel *
+tpl_text_channel_new (TplChannel * tpl_channel)
+{
+ TplTextChannel *ret = g_object_new (TPL_TYPE_TEXT_CHANNEL, NULL);
+ tpl_text_channel_set_tpl_channel (ret, tpl_channel);
+
+ // here some post instance-initialization, the object needs
+ // to set some type's members and probably access (futurely) some
+ // props
+ TpHandleType remote_handle_type;
+ tp_channel_get_handle (tpl_channel_get_channel (tpl_channel),
+ &remote_handle_type);
+
+ ret->chain = g_queue_new ();
+ g_queue_push_tail (ret->chain,
+ _tpl_text_channel_pendingproc_get_my_contact);
+
+ switch (remote_handle_type)
+ {
+ case TP_HANDLE_TYPE_CONTACT:
+ g_queue_push_tail (ret->chain,
+ _tpl_text_channel_pendingproc_get_remote_contact);
+ break;
+ case TP_HANDLE_TYPE_ROOM:
+ g_queue_push_tail (ret->chain,
+ _tpl_text_channel_pendingproc_get_chatroom_id);
+ break;
+
+ /* follows unhandled TpHandleType */
+ case TP_HANDLE_TYPE_NONE:
+ g_warning ("remote handle: TP_HANDLE_TYPE_NONE: "
+ "un-handled. It's probably OK.\n");
+ break;
+ case TP_HANDLE_TYPE_LIST:
+ g_warning ("remote handle: TP_HANDLE_TYPE_LIST: \n"
+ "un-handled. It's probably OK.\n");
+ break;
+ case TP_HANDLE_TYPE_GROUP:
+ g_warning ("remote handle: TP_HANDLE_TYPE_GROUP: "
+ "un-handled. It's probably OK.\n");
+ break;
+ default:
+ g_error ("remote handle type unknown %d.\n", remote_handle_type);
+ break;
+ }
+
+ g_queue_push_tail (ret->chain,
+ _tpl_text_channel_pendingproc_connect_signals);
+
+ // start the chain consuming
+ context_continue (ret);
+ return ret;
+}
+
+
+TplChannel *
+tpl_text_channel_get_tpl_channel (TplTextChannel * self)
+{
+ return self->tpl_channel;
+}
+
+TpContact *
+tpl_text_channel_get_remote_contact (TplTextChannel * self)
+{
+ return self->remote_contact;
+}
+
+TpContact *
+tpl_text_channel_get_my_contact (TplTextChannel * self)
+{
+ return self->my_contact;
+}
+
+gboolean
+tpl_text_channel_is_chatroom (TplTextChannel * self)
+{
+ return self->chatroom;
+}
+
+const gchar *
+tpl_text_channel_get_chatroom_id (TplTextChannel * self)
+{
+ return self->chatroom_id;
+}
+
+void
+tpl_text_channel_set_tpl_channel (TplTextChannel * self, TplChannel * data)
+{
+ tpl_object_unref_if_not_null (self->tpl_channel);
+ self->tpl_channel = data;
+ tpl_object_ref_if_not_null (data);
+}
+
+void
+tpl_text_channel_set_remote_contact (TplTextChannel * self, TpContact * data)
+{
+ tpl_object_unref_if_not_null (self->remote_contact);
+ self->remote_contact = data;
+ tpl_object_ref_if_not_null (data);
+}
+
+void
+tpl_text_channel_set_my_contact (TplTextChannel * self, TpContact * data)
+{
+ tpl_object_unref_if_not_null (self->my_contact);
+ self->my_contact = data;
+ tpl_object_ref_if_not_null (data);
+}
+
+void
+tpl_text_channel_set_chatroom (TplTextChannel * self, gboolean data)
+{
+ self->chatroom = data;
+}
+
+void
+tpl_text_channel_set_chatroom_id (TplTextChannel * self, const gchar * data)
+{
+ g_free ((gchar *) self->chatroom_id);
+ self->chatroom_id = g_strdup (data);
+}
diff --git a/telepathy-logger/channel-text.h b/telepathy-logger/channel-text.h
new file mode 100644
index 0000000..069f077
--- /dev/null
+++ b/telepathy-logger/channel-text.h
@@ -0,0 +1,90 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2009 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Cosimo Alfarano <cosimo.alfarano@collabora.co.uk>
+ */
+
+#ifndef __TPL_TEXT_CHANNEL_H__
+#define __TPL_TEXT_CHANNEL_H__
+
+/*
+ * http://telepathy.freedesktop.org/doc/telepathy-glib/telepathy-glib-channel-text.html#tp-cli-channel-type-text-connect-to-received
+ */
+
+#include <glib-object.h>
+#include <telepathy-glib/account.h>
+#include <telepathy-glib/channel.h>
+#include <telepathy-glib/connection.h>
+#include <telepathy-glib/contact.h>
+#include <telepathy-glib/svc-client.h>
+
+#include <telepathy-logger/channel.h>
+#include <telepathy-logger/observer.h>
+#include <telepathy-logger/utils.h>
+
+G_BEGIN_DECLS
+#define TPL_TYPE_TEXT_CHANNEL (tpl_text_channel_get_type ())
+#define TPL_TEXT_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TPL_TYPE_TEXT_CHANNEL, TplTextChannel))
+#define TPL_TEXT_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TPL_TYPE_TEXT_CHANNEL, TplTextChannelClass))
+#define TPL_IS_TEXT_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TPL_TYPE_TEXT_CHANNEL))
+#define TPL_IS_TEXT_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TPL_TYPE_TEXT_CHANNEL))
+#define TPL_TEXT_CHANNEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TPL_TYPE_TEXT_CHANNEL, TplTextChannelClass))
+ typedef struct
+{
+ GObject parent;
+
+ /* private */
+ TplChannel *tpl_channel;
+ gboolean chatroom;
+ TpContact *my_contact;
+ TpContact *remote_contact; // only set if chatroom==FALSE
+ const gchar *chatroom_id; // only set if chatroom==TRUE
+
+ GQueue *chain; // queue of TplPendingProc
+
+ // only used as metadata in CB data passing
+ guint selector;
+} TplTextChannel;
+
+typedef struct
+{
+ GObjectClass parent_class;
+} TplTextChannelClass;
+
+GType tpl_text_channel_get_type (void);
+
+TplTextChannel *tpl_text_channel_new (TplChannel * tpl_channel);
+
+TplChannel *tpl_text_channel_get_tpl_channel (TplTextChannel * self);
+TpContact *tpl_text_channel_get_remote_contact (TplTextChannel * self);
+TpContact *tpl_text_channel_get_my_contact (TplTextChannel * self);
+gboolean tpl_text_channel_is_chatroom (TplTextChannel * self);
+const gchar *tpl_text_channel_get_chatroom_id (TplTextChannel * self);
+
+void tpl_text_channel_set_tpl_channel (TplTextChannel * self,
+ TplChannel * tpl_chan);
+void tpl_text_channel_set_remote_contact (TplTextChannel * self,
+ TpContact * data);
+void tpl_text_channel_set_my_contact (TplTextChannel * self,
+ TpContact * data);
+void tpl_text_channel_set_chatroom (TplTextChannel * self, gboolean data);
+void tpl_text_channel_set_chatroom_id (TplTextChannel * self,
+ const gchar * data);
+
+G_END_DECLS
+#endif // __TPL_TEXT_CHANNEL_H__
diff --git a/telepathy-logger/channel.c b/telepathy-logger/channel.c
new file mode 100644
index 0000000..7a75449
--- /dev/null
+++ b/telepathy-logger/channel.c
@@ -0,0 +1,334 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2009 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Cosimo Alfarano <cosimo.alfarano@collabora.co.uk>
+ */
+
+#include "channel.h"
+
+#include <glib.h>
+
+#include <telepathy-logger/channel-text.h>
+#include <telepathy-logger/observer.h>
+
+G_DEFINE_TYPE (TplChannel, tpl_channel, G_TYPE_OBJECT)
+ static void tpl_channel_dispose (GObject * obj)
+{
+ TplChannel *self = TPL_CHANNEL (obj);
+
+ g_debug ("TplChannel dispose start\n");
+
+ tpl_object_unref_if_not_null (self->channel);
+ self->channel = NULL;
+
+ if (self->channel_properties != NULL)
+ g_hash_table_unref (self->channel_properties);
+ self->channel_properties = NULL;
+
+ tpl_object_unref_if_not_null (self->account);
+ self->account = NULL;
+
+ tpl_object_unref_if_not_null (self->connection);
+ self->connection = NULL;
+
+ tpl_object_unref_if_not_null (self->observer);
+ self->observer = NULL;
+
+ G_OBJECT_CLASS (tpl_channel_parent_class)->dispose (obj);
+ g_debug ("TplChannel dispose end\n");
+}
+
+static void
+tpl_channel_finalize (GObject * obj)
+{
+ TplChannel *self = TPL_CHANNEL (obj);
+ g_free ((gchar *) self->channel_path);
+ g_free ((gchar *) self->channel_type);
+ g_free ((gchar *) self->account_path);
+ g_free ((gchar *) self->connection_path);
+
+ G_OBJECT_CLASS (tpl_channel_parent_class)->finalize (obj);
+
+ g_debug ("TplChannel instance finalized\n");
+}
+
+static void
+tpl_channel_class_init (TplChannelClass * klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = tpl_channel_dispose;
+ object_class->finalize = tpl_channel_finalize;
+}
+
+
+static void
+tpl_channel_init (TplChannel * self)
+{
+ /* Init TplChannel's members to zero/NULL */
+/* TODO remove the comment
+#define TPL_SET_NULL(x) tpl_channel_set_##x(self, NULL)
+ TPL_SET_NULL(channel);
+ TPL_SET_NULL(channel_path);
+ TPL_SET_NULL(channel_type);
+ TPL_SET_NULL(channel_properties);
+ TPL_SET_NULL(account);
+ TPL_SET_NULL(account_path);
+ TPL_SET_NULL(connection);
+ TPL_SET_NULL(connection_path);
+ TPL_SET_NULL(observer);
+#undef TPL_SET_NULL
+*/
+}
+
+
+TplChannel *
+tpl_channel_new (TpSvcClientObserver * observer)
+{
+ g_return_val_if_fail (TP_IS_SVC_CLIENT_OBSERVER (observer), NULL);
+
+ TplChannel *ret = g_object_new (TPL_TYPE_CHANNEL, NULL);
+ tpl_channel_set_observer (ret, observer);
+ return ret;
+}
+
+TpSvcClientObserver *
+tpl_channel_get_observer (TplChannel * self)
+{
+ g_return_val_if_fail (TPL_IS_CHANNEL (self), NULL);
+ return self->observer;
+}
+
+TpAccount *
+tpl_channel_get_account (TplChannel * self)
+{
+ g_return_val_if_fail (TPL_IS_CHANNEL (self), NULL);
+ return self->account;
+}
+
+const gchar *
+tpl_channel_get_account_path (TplChannel * self)
+{
+ g_return_val_if_fail (TPL_IS_CHANNEL (self), NULL);
+ return self->account_path;
+}
+
+TpConnection *
+tpl_channel_get_connection (TplChannel * self)
+{
+ g_return_val_if_fail (TPL_IS_CHANNEL (self), NULL);
+ return self->connection;
+}
+
+const gchar *
+tpl_channel_get_connection_path (TplChannel * self)
+{
+ g_return_val_if_fail (TPL_IS_CHANNEL (self), NULL);
+ return self->connection_path;
+}
+
+TpChannel *
+tpl_channel_get_channel (TplChannel * self)
+{
+ g_return_val_if_fail (TPL_IS_CHANNEL (self), NULL);
+ return self->channel;
+}
+
+const gchar *
+tpl_channel_get_channel_path (TplChannel * self)
+{
+ g_return_val_if_fail (TPL_IS_CHANNEL (self), NULL);
+ return self->channel_path;
+}
+
+const gchar *
+tpl_channel_get_channel_type (TplChannel * self)
+{
+ g_return_val_if_fail (TPL_IS_CHANNEL (self), NULL);
+ return self->channel_type;
+}
+
+GHashTable *
+tpl_channel_get_channel_properties (TplChannel * self)
+{
+ g_return_val_if_fail (TPL_IS_CHANNEL (self), NULL);
+ return self->channel_properties;
+}
+
+
+
+void
+tpl_channel_set_observer (TplChannel * self, TpSvcClientObserver * data)
+{
+ g_return_if_fail (TPL_IS_CHANNEL (self));
+ g_return_if_fail (TP_IS_SVC_CLIENT_OBSERVER (data) || data == NULL);
+
+ tpl_object_unref_if_not_null (self->observer);
+ self->observer = data;
+ tpl_object_ref_if_not_null (data);
+}
+
+void
+tpl_channel_set_account (TplChannel * self, TpAccount * data)
+{
+ g_return_if_fail (TPL_IS_CHANNEL (self));
+ g_return_if_fail (TP_IS_ACCOUNT (data) || data == NULL);
+
+ tpl_object_unref_if_not_null (self->account);
+ self->account = data;
+ tpl_object_ref_if_not_null (data);
+}
+
+void
+tpl_channel_set_account_path (TplChannel * self, const gchar * data)
+{
+ g_return_if_fail (TPL_IS_CHANNEL (self));
+ // TODO check validity of data
+
+ g_free ((gchar *) self->account_path);
+ self->account_path = g_strdup (data);
+}
+
+void
+tpl_channel_set_connection (TplChannel * self, TpConnection * data)
+{
+ g_return_if_fail (TPL_IS_CHANNEL (self));
+ g_return_if_fail (TP_IS_CONNECTION (data) || data == NULL);
+
+ tpl_object_unref_if_not_null (self->connection);
+ self->connection = data;
+ tpl_object_ref_if_not_null (data);
+}
+
+void
+tpl_channel_set_connection_path (TplChannel * self, const gchar * data)
+{
+ g_return_if_fail (TPL_IS_CHANNEL (self));
+ // TODO check validity of data
+
+ g_free ((gchar *) self->connection_path);
+ self->connection_path = g_strdup (data);
+}
+
+void
+tpl_channel_set_channel (TplChannel * self, TpChannel * data)
+{
+ g_return_if_fail (TPL_IS_CHANNEL (self));
+ g_return_if_fail (TP_IS_CHANNEL (data) || data == NULL);
+
+ tpl_object_unref_if_not_null (self->channel);
+ self->channel = data;
+ tpl_object_ref_if_not_null (data);
+}
+
+void
+tpl_channel_set_channel_path (TplChannel * self, const gchar * data)
+{
+ g_return_if_fail (TPL_IS_CHANNEL (self));
+ // TODO check validity of data
+
+ g_free ((gchar *) self->channel_path);
+ self->channel_path = g_strdup (data);
+}
+
+void
+tpl_channel_set_channel_type (TplChannel * self, const gchar * data)
+{
+ g_return_if_fail (TPL_IS_CHANNEL (self));
+ // TODO check validity of data
+
+ g_free ((gchar *) self->channel_type);
+ self->channel_type = g_strdup (data);
+}
+
+void
+tpl_channel_set_channel_properties (TplChannel * self, GHashTable * data)
+{
+ g_return_if_fail (TPL_IS_CHANNEL (self));
+ // TODO check validity of data
+
+ if (self->channel_properties != NULL)
+ g_hash_table_unref (self->channel_properties);
+ self->channel_properties = data;
+ if (data != NULL)
+ g_hash_table_ref (data);
+}
+
+
+gboolean
+tpl_channel_register_to_observer (TplChannel * self)
+{
+ TplObserver *obs = TPL_OBSERVER (tpl_channel_get_observer (self));
+ GHashTable *glob_map = tpl_observer_get_channel_map (obs);
+ gchar *key;
+
+ g_return_val_if_fail (TPL_IS_CHANNEL (self), FALSE);
+ g_return_val_if_fail (glob_map != NULL, FALSE);
+
+ key = g_strdup (tpl_channel_get_channel_path (self));
+
+ if (g_hash_table_lookup (glob_map, key) != NULL)
+ {
+ g_error ("Channel path found, replacing %s\n", key);
+ g_hash_table_remove (glob_map, key);
+ }
+ else
+ {
+ g_debug ("Channel path not found, registering %s\n", key);
+ }
+
+ // Instantiate and delegate channel handling to the right object
+ if (0 == g_strcmp0 (TP_IFACE_CHAN_TEXT,
+ tpl_channel_get_channel_type (self)))
+ {
+ // when removed, automatically frees the Key and unrefs
+ // its Value
+ TplTextChannel *chan_text = tpl_text_channel_new (self);
+ g_hash_table_insert (glob_map, key, chan_text);
+ }
+ else
+ {
+ g_warning ("%s: channel type not handled by this logger",
+ tpl_channel_get_channel_type (self));
+ }
+
+ g_object_unref (self);
+
+ return TRUE;
+}
+
+gboolean
+tpl_channel_unregister_from_observer (TplChannel * self)
+{
+ TplObserver *obs = TPL_OBSERVER (tpl_channel_get_observer (self));
+ GHashTable *glob_map = tpl_observer_get_channel_map (obs);
+ const gchar *key;
+
+ g_assert (TPL_IS_CHANNEL (self));
+ g_assert (glob_map != NULL);
+ g_return_val_if_fail (TPL_IS_CHANNEL (self), FALSE);
+ g_return_val_if_fail (glob_map != NULL, FALSE);
+
+ key = tpl_channel_get_channel_path (self);
+ g_debug ("Unregistering channel path %s\n", key);
+
+ // this will destroy the associated value object: at this point
+ // the hash table reference should be the only one for the
+ // value's object
+ return g_hash_table_remove (glob_map, key);
+}
diff --git a/telepathy-logger/channel.h b/telepathy-logger/channel.h
new file mode 100644
index 0000000..9b47ade
--- /dev/null
+++ b/telepathy-logger/channel.h
@@ -0,0 +1,99 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2009 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Cosimo Alfarano <cosimo.alfarano@collabora.co.uk>
+ */
+
+#ifndef __TPL_CHANNEL_H__
+#define __TPL_CHANNEL_H__
+
+#include <glib.h>
+#include <glib-object.h>
+#include <telepathy-glib/account.h>
+#include <telepathy-glib/connection.h>
+#include <telepathy-glib/channel.h>
+#include <telepathy-glib/svc-client.h>
+
+#include <telepathy-logger/observer.h>
+#include <telepathy-logger/utils.h>
+
+G_BEGIN_DECLS
+#define TPL_TYPE_CHANNEL (tpl_channel_get_type ())
+#define TPL_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TPL_TYPE_CHANNEL, TplChannel))
+#define TPL_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TPL_TYPE_CHANNEL, TplChannelClass))
+#define TPL_IS_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TPL_TYPE_CHANNEL))
+#define TPL_IS_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TPL_TYPE_CHANNEL))
+#define TPL_CHANNEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TPL_TYPE_CHANNEL, TplChannelClass))
+// TODO test the following macros
+//#define TPL_CHANNEL_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE((obj), TPL_TYPE_CHANNEL, TplChannelClass))
+ typedef struct
+{
+ GObject parent;
+
+ /* private */
+ TpChannel *channel;
+ const gchar *channel_path;
+ const gchar *channel_type;
+ GHashTable *channel_properties;
+
+ TpAccount *account;
+ const gchar *account_path;
+ TpConnection *connection;
+ const gchar *connection_path;
+
+ TpSvcClientObserver *observer;
+} TplChannel;
+
+typedef struct
+{
+ GObjectClass parent_class;
+} TplChannelClass;
+
+
+GType tpl_channel_get_type (void);
+
+TplChannel *tpl_channel_new (TpSvcClientObserver * observer);
+void tpl_channel_free (TplChannel * tpl_chan);
+
+TpSvcClientObserver *tpl_channel_get_observer (TplChannel * self);
+TpAccount *tpl_channel_get_account (TplChannel * self);
+const gchar *tpl_channel_get_account_path (TplChannel * self);
+TpConnection *tpl_channel_get_connection (TplChannel * self);
+const gchar *tpl_channel_get_connection_path (TplChannel * self);
+TpChannel *tpl_channel_get_channel (TplChannel * self);
+const gchar *tpl_channel_get_channel_path (TplChannel * self);
+const gchar *tpl_channel_get_channel_type (TplChannel * self);
+GHashTable *tpl_channel_get_channel_properties (TplChannel * self);
+
+
+void tpl_channel_set_observer (TplChannel * self, TpSvcClientObserver * data);
+void tpl_channel_set_account (TplChannel * self, TpAccount * data);
+void tpl_channel_set_account_path (TplChannel * self, const gchar * data);
+void tpl_channel_set_connection (TplChannel * self, TpConnection * data);
+void tpl_channel_set_connection_path (TplChannel * self, const gchar * data);
+void tpl_channel_set_channel (TplChannel * self, TpChannel * data);
+void tpl_channel_set_channel_path (TplChannel * self, const gchar * data);
+void tpl_channel_set_channel_type (TplChannel * self, const gchar * data);
+void tpl_channel_set_channel_properties (TplChannel * self,
+ GHashTable * data);
+
+gboolean tpl_channel_register_to_observer (TplChannel * self);
+gboolean tpl_channel_unregister_from_observer (TplChannel * self);
+
+G_END_DECLS
+#endif // __TPL_CHANNEL_H__
diff --git a/telepathy-logger/conf.c b/telepathy-logger/conf.c
new file mode 100644
index 0000000..a38dc0d
--- /dev/null
+++ b/telepathy-logger/conf.c
@@ -0,0 +1,93 @@
+ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+ /*
+ * Copyright (C) 2009 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Cosimo Alfarano <cosimo.alfarano@collabora.co.uk>
+ */
+
+#include "conf.h"
+
+#include <glib.h>
+
+#define DEBUG(...)
+
+G_DEFINE_TYPE (TplConf, tpl_conf, G_TYPE_OBJECT)
+ static void tpl_conf_finalize (GObject * obj)
+{
+
+ G_OBJECT_CLASS (tpl_conf_parent_class)->finalize (obj);
+}
+
+static void
+tpl_conf_dispose (GObject * obj)
+{
+ TplConf *self = TPL_CONF (obj);
+
+ tpl_object_unref_if_not_null (tpl_conf_get_entry (self));
+ self->entry.generic = NULL;
+
+ G_OBJECT_CLASS (tpl_conf_parent_class)->dispose (obj);
+}
+
+
+static void
+tpl_conf_class_init (TplConfClass * klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = tpl_conf_finalize;
+ object_class->dispose = tpl_conf_dispose;
+}
+
+static void
+tpl_conf_init (TplConf * self)
+{
+ self->client = gconf_client_get_default ();
+}
+
+
+TplConf *
+tpl_conf_new (void)
+{
+ return g_object_new (TPL_TYPE_CONF, NULL);
+}
+
+#define GCONF_KEY_DISABLING_GLOBAL "/apps/telepathy-logger/disabling/global";
+#define GCONF_KEY_DISABLING_ACCOUNT_LIST "/apps/telepathy-logger/disabling/accounts/blocklist"
+gboolean *
+tpl_conf_is_enabled_globally (TplConf * self)
+{
+ GConfValue *val =
+ gconf_client_get (self->client, GCONF_KEY_DISABLING_GLOBAL, &error);
+ return !gconf_value_get_bool (val);
+}
+
+void
+tpl_conf_enable_globally (TplConf * self)
+{
+ GConfValue *val = gconf_value_new (GCONF_VALUE_BOOL);
+ gconf_value_set_bool (val, FALSE); // not disabling
+ gconf_client_set (self->client, GCONF_KEY_DISABLING_GLOBAL, val);
+}
+
+
+void
+tpl_conf_enable_globally (TplConf * self)
+{
+ GConfValue *val = gconf_value_new (GCONF_VALUE_BOOL);
+ gconf_value_set_bool (val, TRUE); // disabling
+ gconf_client_set (self->client, GCONF_KEY_DISABLING_GLOBAL, val);
+}
diff --git a/telepathy-logger/contact.c b/telepathy-logger/contact.c
new file mode 100644
index 0000000..e79e34d
--- /dev/null
+++ b/telepathy-logger/contact.c
@@ -0,0 +1,216 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2009 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Cosimo Alfarano <cosimo.alfarano@collabora.co.uk>
+ */
+
+#include "contact.h"
+
+#include <telepathy-glib/account.h>
+
+#include <telepathy-logger/utils.h>
+
+G_DEFINE_TYPE (TplContact, tpl_contact, G_TYPE_OBJECT)
+ static void tpl_contact_finalize (GObject * obj);
+ static void tpl_contact_dispose (GObject * obj);
+
+ static void tpl_contact_class_init (TplContactClass * klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = tpl_contact_finalize;
+ object_class->dispose = tpl_contact_dispose;
+}
+
+static void
+tpl_contact_init (TplContact * self)
+{
+}
+
+static void
+tpl_contact_finalize (GObject * obj)
+{
+ TplContact *self = TPL_CONTACT (obj);
+
+ g_free (self->alias);
+ self->alias = NULL;
+ g_free (self->identifier);
+ self->identifier = NULL;
+ g_free (self->presence_status);
+ self->presence_status = NULL;
+ g_free (self->presence_message);
+ self->presence_message = NULL;
+
+ G_OBJECT_CLASS (tpl_contact_parent_class)->finalize (obj);
+}
+
+static void
+tpl_contact_dispose (GObject * obj)
+{
+ TplContact *self = TPL_CONTACT (obj);
+
+ tpl_object_unref_if_not_null (self->contact);
+ self->contact = NULL;
+
+ G_OBJECT_CLASS (tpl_contact_parent_class)->dispose (obj);
+}
+
+
+
+TplContact *
+tpl_contact_from_tp_contact (TpContact * contact)
+{
+ TplContact *ret;
+
+ ret = tpl_contact_new ();
+ tpl_contact_set_contact (ret, contact);
+ tpl_contact_set_identifier (ret,
+ (gchar *) tp_contact_get_identifier (contact));
+ tpl_contact_set_alias (ret, (gchar *) tp_contact_get_alias (contact));
+ tpl_contact_set_presence_status (ret,
+ (gchar *)
+ tp_contact_get_presence_status (contact));
+ tpl_contact_set_presence_message (ret,
+ (gchar *)
+ tp_contact_get_presence_message
+ (contact));
+
+ return ret;
+}
+
+TplContact *
+tpl_contact_new (void)
+{
+ return g_object_new (TPL_TYPE_CONTACT, NULL);
+}
+
+TpContact *
+tpl_contact_get_contact (TplContact * self)
+{
+ g_return_val_if_fail (TPL_IS_CONTACT (self), NULL);
+ return self->contact;
+}
+
+gchar *
+tpl_contact_get_alias (TplContact * self)
+{
+ g_return_val_if_fail (TPL_IS_CONTACT (self), NULL);
+ return self->alias;
+}
+
+gchar *
+tpl_contact_get_identifier (TplContact * self)
+{
+ g_return_val_if_fail (TPL_IS_CONTACT (self), NULL);
+ return self->identifier;
+}
+
+gchar *
+tpl_contact_get_presence_status (TplContact * self)
+{
+ g_return_val_if_fail (TPL_IS_CONTACT (self), NULL);
+ return self->presence_status;
+}
+
+gchar *
+tpl_contact_get_presence_message (TplContact * self)
+{
+ g_return_val_if_fail (TPL_IS_CONTACT (self), NULL);
+ return self->presence_message;
+}
+
+TplContactType
+tpl_contact_get_contact_type (TplContact * self)
+{
+ g_return_val_if_fail (TPL_IS_CONTACT (self), TPL_CONTACT_UNKNOWN);
+ return self->contact_type;
+}
+
+TpAccount *
+tpl_contact_get_account (TplContact * self)
+{
+ g_return_val_if_fail (TPL_IS_CONTACT (self), NULL);
+ return self->account;
+}
+
+
+void
+tpl_contact_set_contact (TplContact * self, TpContact * data)
+{
+ g_return_if_fail (TPL_IS_CONTACT (self));
+ g_return_if_fail (TP_IS_CONTACT (data) || data == NULL);
+
+ tpl_object_unref_if_not_null (self->contact);
+ self->contact = data;
+ tpl_object_ref_if_not_null (data);
+}
+
+void
+tpl_contact_set_account (TplContact * self, TpAccount * data)
+{
+ g_return_if_fail (TPL_IS_CONTACT (self));
+ g_return_if_fail (TP_IS_ACCOUNT (data) || data == NULL);
+
+ tpl_object_unref_if_not_null (self->account);
+ self->account = data;
+ tpl_object_ref_if_not_null (data);
+}
+
+void
+tpl_contact_set_alias (TplContact * self, gchar * data)
+{
+ g_return_if_fail (TPL_IS_CONTACT (self));
+
+ g_free (self->alias);
+ self->alias = g_strdup (data);
+}
+
+void
+tpl_contact_set_identifier (TplContact * self, gchar * data)
+{
+ g_return_if_fail (TPL_IS_CONTACT (self));
+
+ g_free (self->identifier);
+ self->identifier = g_strdup (data);
+}
+
+void
+tpl_contact_set_presence_status (TplContact * self, gchar * data)
+{
+ g_return_if_fail (TPL_IS_CONTACT (self));
+
+ g_free (self->presence_status);
+ self->presence_status = g_strdup (data);
+}
+
+void
+tpl_contact_set_presence_message (TplContact * self, gchar * data)
+{
+ g_return_if_fail (TPL_IS_CONTACT (self));
+
+ g_free (self->presence_message);
+ self->presence_message = g_strdup (data);
+}
+
+
+void
+tpl_contact_set_contact_type (TplContact * self, TplContactType data)
+{
+ g_return_if_fail (TPL_IS_CONTACT (self));
+
+ self->contact_type = data;
+}
diff --git a/telepathy-logger/contact.h b/telepathy-logger/contact.h
new file mode 100644
index 0000000..6fca0ae
--- /dev/null
+++ b/telepathy-logger/contact.h
@@ -0,0 +1,100 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2009 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Cosimo Alfarano <cosimo.alfarano@collabora.co.uk>
+ */
+
+#ifndef __TPL_CONTACT_H__
+#define __TPL_CONTACT_H__
+
+#include <glib-object.h>
+#include <telepathy-glib/contact.h>
+#include <telepathy-glib/account.h>
+
+G_BEGIN_DECLS
+#define TPL_TYPE_CONTACT (tpl_contact_get_type ())
+#define TPL_CONTACT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TPL_TYPE_CONTACT, TplContact))
+#define TPL_CONTACT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TPL_TYPE_CONTACT, TplContactClass))
+#define TPL_IS_CONTACT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TPL_TYPE_CONTACT))
+#define TPL_IS_CONTACT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TPL_TYPE_CONTACT))
+#define TPL_CONTACT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TPL_TYPE_CONTACT, TplContactClass))
+ typedef enum
+{
+ TPL_CONTACT_UNKNOWN,
+ TPL_CONTACT_USER,
+ TPL_CONTACT_GROUP
+} TplContactType;
+
+typedef struct
+{
+ GObject parent;
+
+ /* Private */
+ TpContact *contact;
+ TplContactType contact_type;
+ gchar *alias;
+ gchar *identifier;
+ gchar *presence_status;
+ gchar *presence_message;
+
+ TpAccount *account;
+} TplContact;
+
+
+typedef struct
+{
+ GObjectClass parent_class;
+} TplContactClass;
+
+
+GType tpl_contact_get_type (void);
+
+TplContact *tpl_contact_from_tp_contact (TpContact * contact);
+
+TplContact *tpl_contact_new (void);
+
+TpContact *tpl_contact_get_contact (TplContact * self);
+
+gchar *tpl_contact_get_alias (TplContact * self);
+
+gchar *tpl_contact_get_identifier (TplContact * self);
+
+gchar *tpl_contact_get_presence_status (TplContact * self);
+
+gchar *tpl_contact_get_presence_message (TplContact * self);
+
+TplContactType tpl_contact_get_contact_type (TplContact * self);
+
+TpAccount *tpl_contact_get_account (TplContact * self);
+
+void tpl_contact_set_contact (TplContact * self, TpContact * data);
+
+void tpl_contact_set_account (TplContact * self, TpAccount * data);
+
+void tpl_contact_set_alias (TplContact * self, gchar * data);
+
+void tpl_contact_set_identifier (TplContact * self, gchar * data);
+
+void tpl_contact_set_presence_status (TplContact * self, gchar * data);
+
+void tpl_contact_set_presence_message (TplContact * self, gchar * data);
+
+void tpl_contact_set_contact_type (TplContact * self, TplContactType data);
+
+G_END_DECLS
+#endif // __TPL_CONTACT_H__
diff --git a/telepathy-logger/datetime.c b/telepathy-logger/datetime.c
new file mode 100644
index 0000000..41f32b3
--- /dev/null
+++ b/telepathy-logger/datetime.c
@@ -0,0 +1,186 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2003-2007 Imendio AB
+ *
+ * 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 St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ *
+ * Authors: Richard Hult <richard@imendio.com>
+ */
+
+#include "datetime.h"
+
+#include <glib/gi18n.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+
+/* Note: TplTime is always in UTC. */
+
+time_t
+tpl_time_get_current (void)
+{
+ return time (NULL);
+}
+
+time_t
+tpl_time_get_local_time (struct tm * tm)
+{
+ const gchar *tz;
+ time_t t;
+
+ tz = g_getenv ("TZ");
+ g_setenv ("TZ", "", TRUE);
+
+ tzset ();
+
+ t = mktime (tm);
+
+ if (tz)
+ {
+ g_setenv ("TZ", tz, TRUE);
+ }
+ else
+ {
+ g_unsetenv ("TZ");
+ }
+
+ tzset ();
+
+ return t;
+}
+
+/* The format is: "20021209T23:51:30" and is in UTC. 0 is returned on
+ * failure. The alternative format "20021209" is also accepted.
+ */
+time_t
+tpl_time_parse (const gchar * str)
+{
+ struct tm tm;
+ gint year, month;
+ gint n_parsed;
+
+ memset (&tm, 0, sizeof (struct tm));
+
+ n_parsed = sscanf (str, "%4d%2d%2dT%2d:%2d:%2d",
+ &year, &month, &tm.tm_mday, &tm.tm_hour,
+ &tm.tm_min, &tm.tm_sec);
+ if (n_parsed != 3 && n_parsed != 6)
+ {
+ return 0;
+ }
+
+ tm.tm_year = year - 1900;
+ tm.tm_mon = month - 1;
+ tm.tm_isdst = -1;
+
+ return tpl_time_get_local_time (&tm);
+}
+
+/* Converts the UTC timestamp to a string, also in UTC. Returns NULL on failure. */
+gchar *
+tpl_time_to_string_utc (time_t t, const gchar * format)
+{
+ gchar stamp[128];
+ struct tm *tm;
+
+ g_return_val_if_fail (format != NULL, NULL);
+
+ tm = gmtime (&t);
+ if (strftime (stamp, sizeof (stamp), format, tm) == 0)
+ {
+ return NULL;
+ }
+
+ return g_strdup (stamp);
+}
+
+/* Converts the UTC timestamp to a string, in local time. Returns NULL on failure. */
+gchar *
+tpl_time_to_string_local (time_t t, const gchar * format)
+{
+ gchar stamp[128];
+ struct tm *tm;
+
+ g_return_val_if_fail (format != NULL, NULL);
+
+ tm = localtime (&t);
+ if (strftime (stamp, sizeof (stamp), format, tm) == 0)
+ {
+ return NULL;
+ }
+
+ return g_strdup (stamp);
+}
+
+gchar *
+tpl_time_to_string_relative (time_t then)
+{
+ time_t now;
+ gint seconds;
+
+ now = time (NULL);
+ seconds = now - then;
+
+ if (seconds > 0)
+ {
+ if (seconds < 60)
+ {
+ return g_strdup_printf (ngettext ("%d second ago",
+ "%d seconds ago", seconds),
+ seconds);
+ }
+ else if (seconds < (60 * 60))
+ {
+ seconds /= 60;
+ return g_strdup_printf (ngettext ("%d minute ago",
+ "%d minutes ago", seconds),
+ seconds);
+ }
+ else if (seconds < (60 * 60 * 24))
+ {
+ seconds /= 60 * 60;
+ return g_strdup_printf (ngettext ("%d hour ago",
+ "%d hours ago", seconds),
+ seconds);
+ }
+ else if (seconds < (60 * 60 * 24 * 7))
+ {
+ seconds /= 60 * 60 * 24;
+ return g_strdup_printf (ngettext ("%d day ago",
+ "%d days ago", seconds), seconds);
+ }
+ else if (seconds < (60 * 60 * 24 * 30))
+ {
+ seconds /= 60 * 60 * 24 * 7;
+ return g_strdup_printf (ngettext ("%d week ago",
+ "%d weeks ago", seconds),
+ seconds);
+ }
+ else
+ {
+ seconds /= 60 * 60 * 24 * 30;
+ return g_strdup_printf (ngettext ("%d month ago",
+ "%d months ago", seconds),
+ seconds);
+ }
+ }
+ else
+ {
+ return g_strdup (_("in the future"));
+ }
+}
diff --git a/telepathy-logger/datetime.h b/telepathy-logger/datetime.h
new file mode 100644
index 0000000..2e4ae2a
--- /dev/null
+++ b/telepathy-logger/datetime.h
@@ -0,0 +1,42 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2004 Imendio AB
+ *
+ * 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 St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifndef __TPL_TIME_H__
+#define __TPL_TIME_H__
+
+#ifndef __USE_XOPEN
+#define __USE_XOPEN
+#endif
+#include <time.h>
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+#define TPL_TIME_FORMAT_DISPLAY_SHORT "%H:%M"
+#define TPL_TIME_FORMAT_DISPLAY_LONG "%a %d %b %Y"
+ time_t tpl_time_get_current (void);
+time_t tpl_time_get_local_time (struct tm *tm);
+time_t tpl_time_parse (const gchar * str);
+gchar *tpl_time_to_string_utc (time_t t, const gchar * format);
+gchar *tpl_time_to_string_local (time_t t, const gchar * format);
+gchar *tpl_time_to_string_relative (time_t t);
+
+G_END_DECLS
+#endif /* __TPL_TIME_H__ */
diff --git a/telepathy-logger/debug.h b/telepathy-logger/debug.h
new file mode 100644
index 0000000..cb90ec5
--- /dev/null
+++ b/telepathy-logger/debug.h
@@ -0,0 +1,2 @@
+
+#define DEBUG(...)
diff --git a/telepathy-logger/libtelepathy-logger.pc.in b/telepathy-logger/libtelepathy-logger.pc.in
new file mode 100644
index 0000000..c11a59f
--- /dev/null
+++ b/telepathy-logger/libtelepathy-logger.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@/telepathy-logger
+
+Name: something
+Description: Telepathy Logger library
+Requires: telepathy-glib libxml-2.0
+Version: @VERSION@
+Libs: -L${libdir} -llibtelepathy-logger
+Cflags: -I${includedir}
diff --git a/telepathy-logger/log-entry-text.c b/telepathy-logger/log-entry-text.c
new file mode 100644
index 0000000..0332f9d
--- /dev/null
+++ b/telepathy-logger/log-entry-text.c
@@ -0,0 +1,292 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2009 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Cosimo Alfarano <cosimo.alfarano@collabora.co.uk>
+ */
+
+#include "log-entry-text.h"
+
+#include <telepathy-logger/channel.h>
+#include <telepathy-logger/contact.h>
+#include <telepathy-logger/utils.h>
+
+G_DEFINE_TYPE (TplLogEntryText, tpl_log_entry_text, G_TYPE_OBJECT)
+ static void tpl_log_entry_text_finalize (GObject * obj);
+ static void tpl_log_entry_text_dispose (GObject * obj);
+
+ static void tpl_log_entry_text_class_init (TplLogEntryTextClass * klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = tpl_log_entry_text_finalize;
+ object_class->dispose = tpl_log_entry_text_dispose;
+}
+
+static void
+tpl_log_entry_text_init (TplLogEntryText * self)
+{
+#define TPL_SET_NULL(x) tpl_log_entry_text_set_##x(self, NULL)
+ TPL_SET_NULL (tpl_text_channel);
+ TPL_SET_NULL (sender);
+ TPL_SET_NULL (receiver);
+ TPL_SET_NULL (message);
+ TPL_SET_NULL (chat_id);
+#undef TPL_SET_NULL
+}
+
+static void
+tpl_log_entry_text_dispose (GObject * obj)
+{
+ TplLogEntryText *self = TPL_LOG_ENTRY_TEXT (obj);
+ g_debug ("TplLogEntryText: disposing\n");
+
+ tpl_object_unref_if_not_null (self->tpl_text);
+ self->tpl_text = NULL;
+ tpl_object_unref_if_not_null (self->sender);
+ self->sender = NULL;
+ tpl_object_unref_if_not_null (self->receiver);
+ self->receiver = NULL;
+
+ G_OBJECT_CLASS (tpl_log_entry_text_parent_class)->finalize (obj);
+
+ g_debug ("TplLogEntryText: disposed\n");
+}
+
+static void
+tpl_log_entry_text_finalize (GObject * obj)
+{
+ TplLogEntryText *self = TPL_LOG_ENTRY_TEXT (obj);
+
+ g_debug ("TplLogEntryText: finalizing\n");
+
+ g_free ((gchar *) self->message);
+ self->message = NULL;
+ g_free ((gchar *) self->chat_id);
+ self->chat_id = NULL;
+
+ G_OBJECT_CLASS (tpl_log_entry_text_parent_class)->dispose (obj);
+
+ g_debug ("TplLogEntryText: finalized\n");
+}
+
+
+TplLogEntryText *
+tpl_log_entry_text_new (void)
+{
+ return g_object_new (TPL_TYPE_LOG_ENTRY_TEXT, NULL);
+}
+
+
+
+TpChannelTextMessageType
+tpl_log_entry_text_message_type_from_str (const gchar * type_str)
+{
+ if (g_strcmp0 (type_str, "normal") == 0)
+ {
+ return TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL;
+ }
+ else if (g_strcmp0 (type_str, "action") == 0)
+ {
+ return TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION;
+ }
+ else if (g_strcmp0 (type_str, "notice") == 0)
+ {
+ return TP_CHANNEL_TEXT_MESSAGE_TYPE_NOTICE;
+ }
+ else if (g_strcmp0 (type_str, "auto-reply") == 0)
+ {
+ return TP_CHANNEL_TEXT_MESSAGE_TYPE_AUTO_REPLY;
+ }
+
+ return TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL;
+}
+
+
+const gchar *
+tpl_log_entry_text_message_type_to_str (TpChannelTextMessageType msg_type)
+{
+ switch (msg_type)
+ {
+ case TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION:
+ return "action";
+ case TP_CHANNEL_TEXT_MESSAGE_TYPE_NOTICE:
+ return "notice";
+ case TP_CHANNEL_TEXT_MESSAGE_TYPE_AUTO_REPLY:
+ return "auto-reply";
+ default:
+ return "normal";
+ }
+}
+
+
+TplChannel *
+tpl_log_entry_text_get_tpl_channel (TplLogEntryText * self)
+{
+ g_return_val_if_fail (TPL_IS_LOG_ENTRY_TEXT (self), NULL);
+
+ return
+ tpl_text_channel_get_tpl_channel (tpl_log_entry_text_get_tpl_text_channel
+ (self));
+}
+
+TplTextChannel *
+tpl_log_entry_text_get_tpl_text_channel (TplLogEntryText * self)
+{
+ g_return_val_if_fail (TPL_IS_LOG_ENTRY_TEXT (self), NULL);
+ return self->tpl_text;
+}
+
+TplContact *
+tpl_log_entry_text_get_sender (TplLogEntryText * self)
+{
+ g_return_val_if_fail (TPL_IS_LOG_ENTRY_TEXT (self), NULL);
+ return self->sender;
+}
+
+TplContact *
+tpl_log_entry_text_get_receiver (TplLogEntryText * self)
+{
+ g_return_val_if_fail (TPL_IS_LOG_ENTRY_TEXT (self), NULL);
+ return self->receiver;
+}
+
+const gchar *
+tpl_log_entry_text_get_message (TplLogEntryText * self)
+{
+ g_return_val_if_fail (TPL_IS_LOG_ENTRY_TEXT (self), NULL);
+ return self->message;
+}
+
+TpChannelTextMessageType
+tpl_log_entry_text_get_message_type (TplLogEntryText * self)
+{
+ return self->message_type;
+}
+
+TplLogEntryTextSignalType
+tpl_log_entry_text_get_signal_type (TplLogEntryText * self)
+{
+ return self->signal_type;
+}
+
+TplLogEntryTextDirection
+tpl_log_entry_text_get_direction (TplLogEntryText * self)
+{
+ return self->direction;
+}
+
+guint
+tpl_log_entry_text_get_message_id (TplLogEntryText * self)
+{
+ g_return_val_if_fail (TPL_IS_LOG_ENTRY_TEXT (self), 0);
+ return self->message_id;
+}
+
+const gchar *
+tpl_log_entry_text_get_chat_id (TplLogEntryText * self)
+{
+ g_return_val_if_fail (TPL_IS_LOG_ENTRY_TEXT (self), NULL);
+ return self->chat_id;
+}
+
+
+void
+tpl_log_entry_text_set_tpl_text_channel (TplLogEntryText * self,
+ TplTextChannel * data)
+{
+ g_return_if_fail (TPL_IS_LOG_ENTRY_TEXT (self));
+ g_return_if_fail (TPL_IS_TEXT_CHANNEL (data) || data == NULL);
+
+ tpl_object_unref_if_not_null (self->tpl_text);
+ self->tpl_text = data;
+ tpl_object_ref_if_not_null (data);
+}
+
+void
+tpl_log_entry_text_set_sender (TplLogEntryText * self, TplContact * data)
+{
+ g_return_if_fail (TPL_IS_LOG_ENTRY_TEXT (self));
+ g_return_if_fail (TPL_IS_CONTACT (data) || data == NULL);
+
+ tpl_object_unref_if_not_null (self->sender);
+ self->sender = data;
+ tpl_object_ref_if_not_null (data);
+}
+
+void
+tpl_log_entry_text_set_receiver (TplLogEntryText * self, TplContact * data)
+{
+ g_return_if_fail (TPL_IS_LOG_ENTRY_TEXT (self));
+ g_return_if_fail (TPL_IS_CONTACT (data) || data == NULL);
+
+ tpl_object_unref_if_not_null (self->receiver);
+ self->receiver = data;
+ tpl_object_ref_if_not_null (data);
+}
+
+void
+tpl_log_entry_text_set_message (TplLogEntryText * self, const gchar * data)
+{
+ g_return_if_fail (TPL_IS_LOG_ENTRY_TEXT (self));
+
+ g_free ((gchar *) self->message);
+ self->message = g_strdup (data);
+}
+
+void
+tpl_log_entry_text_set_message_type (TplLogEntryText * self,
+ TpChannelTextMessageType data)
+{
+ g_return_if_fail (TPL_IS_LOG_ENTRY_TEXT (self));
+
+ self->message_type = data;
+}
+
+void
+tpl_log_entry_text_set_signal_type (TplLogEntryText * self,
+ TplLogEntryTextSignalType data)
+{
+ g_return_if_fail (TPL_IS_LOG_ENTRY_TEXT (self));
+
+ self->signal_type = data;
+}
+
+void
+tpl_log_entry_text_set_direction (TplLogEntryText * self,
+ TplLogEntryTextDirection data)
+{
+ g_return_if_fail (TPL_IS_LOG_ENTRY_TEXT (self));
+
+ self->direction = data;
+}
+
+void
+tpl_log_entry_text_set_message_id (TplLogEntryText * self, guint data)
+{
+ g_return_if_fail (TPL_IS_LOG_ENTRY_TEXT (self));
+
+ self->message_id = data;
+}
+
+void
+tpl_log_entry_text_set_chat_id (TplLogEntryText * self, const gchar * data)
+{
+ g_return_if_fail (TPL_IS_LOG_ENTRY_TEXT (self));
+
+ g_free ((gchar *) self->chat_id);
+ self->chat_id = g_strdup (data);
+}
diff --git a/telepathy-logger/log-entry-text.h b/telepathy-logger/log-entry-text.h
new file mode 100644
index 0000000..7d6c32d
--- /dev/null
+++ b/telepathy-logger/log-entry-text.h
@@ -0,0 +1,144 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2009 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Cosimo Alfarano <cosimo.alfarano@collabora.co.uk>
+ */
+
+#ifndef __TPL_LOG_ENTRY_TEXT_H__
+#define __TPL_LOG_ENTRY_TEXT_H__
+
+#include <glib-object.h>
+#include <telepathy-glib/enums.h>
+
+#include <telepathy-logger/channel-text.h>
+#include <telepathy-logger/contact.h>
+
+G_BEGIN_DECLS
+#define TPL_TYPE_LOG_ENTRY_TEXT (tpl_log_entry_text_get_type ())
+#define TPL_LOG_ENTRY_TEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TPL_TYPE_LOG_ENTRY_TEXT, TplLogEntryText))
+#define TPL_LOG_ENTRY_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TPL_TYPE_LOG_ENTRY_TEXT, TplLogEntryTextClass))
+#define TPL_IS_LOG_ENTRY_TEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TPL_TYPE_LOG_ENTRY_TEXT))
+#define TPL_IS_LOG_ENTRY_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TPL_TYPE_LOG_ENTRY_TEXT))
+#define TPL_LOG_ENTRY_TEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TPL_TYPE_LOG_ENTRY_TEXT, TplLogEntryTextClass))
+/* Valid for org.freedesktop.Telepathy.Channel.Type.Text */
+ typedef enum
+{
+ TPL_LOG_ENTRY_TEXT_SIGNAL_SENT,
+ TPL_LOG_ENTRY_TEXT_SIGNAL_RECEIVED,
+ TPL_LOG_ENTRY_TEXT_SIGNAL_SEND_ERROR,
+ TPL_LOG_ENTRY_TEXT_SIGNAL_LOST_MESSAGE,
+ TPL_LOG_ENTRY_TEXT_SIGNAL_CHAT_STATUS_CHANGED,
+ TPL_LOG_ENTRY_TEXT_SIGNAL_CHANNEL_CLOSED
+} TplLogEntryTextSignalType;
+
+/* wether the log entry is referring to something outgoing on incoming */
+typedef enum
+{
+ TPL_LOG_ENTRY_TEXT_CHANNEL_IN,
+ TPL_LOG_ENTRY_TEXT_CHANNEL_OUT
+} TplLogEntryTextDirection;
+
+typedef struct
+{
+ GObject parent;
+
+ /* Private */
+
+ // tpl_channel has informations about channel/account/connection
+ TplTextChannel *tpl_text;
+ // what kind of signal produced this log entry
+ TplLogEntryTextSignalType signal_type;
+ TpChannelTextMessageType message_type;
+ // is the this entry produced by something incoming or outgoing
+ TplLogEntryTextDirection direction;
+
+ // message and receiver may be NULL depending on the signal. ie.
+ // status changed signals set only the sender
+ TplContact *sender;
+ TplContact *receiver;
+ const gchar *message;
+ guint message_id;
+ const gchar *chat_id;
+ gboolean chatroom;
+} TplLogEntryText;
+
+typedef struct
+{
+ GObjectClass parent_class;
+} TplLogEntryTextClass;
+
+GType tpl_log_entry_text_get_type (void);
+
+TplLogEntryText *tpl_log_entry_text_new (void);
+
+TpChannelTextMessageType tpl_log_entry_text_message_type_from_str (const gchar
+ *
+ type_str);
+
+const gchar *tpl_log_entry_text_message_type_to_str (TpChannelTextMessageType
+ msg_type);
+
+TplChannel *tpl_log_entry_text_get_tpl_channel (TplLogEntryText * self);
+
+TplTextChannel *tpl_log_entry_text_get_tpl_text_channel (TplLogEntryText *
+ self);
+
+TplContact *tpl_log_entry_text_get_sender (TplLogEntryText * self);
+
+TplContact *tpl_log_entry_text_get_receiver (TplLogEntryText * self);
+
+const gchar *tpl_log_entry_text_get_message (TplLogEntryText * self);
+
+TpChannelTextMessageType
+tpl_log_entry_text_get_message_type (TplLogEntryText * self);
+
+TplLogEntryTextSignalType
+tpl_log_entry_text_get_signal_type (TplLogEntryText * self);
+
+TplLogEntryTextDirection
+tpl_log_entry_text_get_direction (TplLogEntryText * self);
+
+guint tpl_log_entry_text_get_message_id (TplLogEntryText * self);
+
+const gchar *tpl_log_entry_text_get_chat_id (TplLogEntryText * self);
+
+gboolean tpl_log_entry_text_is_chatroom (TplLogEntryText * self);
+
+void
+tpl_log_entry_text_set_tpl_text_channel (TplLogEntryText * self,
+ TplTextChannel * data);
+
+void tpl_log_entry_text_set_sender (TplLogEntryText * self,
+ TplContact * data);
+void tpl_log_entry_text_set_receiver (TplLogEntryText * self,
+ TplContact * data);
+void tpl_log_entry_text_set_message (TplLogEntryText * self,
+ const gchar * data);
+void tpl_log_entry_text_set_message_type (TplLogEntryText * self,
+ TpChannelTextMessageType data);
+void tpl_log_entry_text_set_signal_type (TplLogEntryText * self,
+ TplLogEntryTextSignalType data);
+void tpl_log_entry_text_set_direction (TplLogEntryText * self,
+ TplLogEntryTextDirection data);
+void tpl_log_entry_text_set_message_id (TplLogEntryText * self, guint data);
+void tpl_log_entry_text_set_chat_id (TplLogEntryText * self,
+ const gchar * data);
+void tpl_log_entry_text_set_chatroom (TplLogEntryText * self, gboolean data);
+
+G_END_DECLS
+#endif // __TPL_LOG_ENTRY_TEXT_H__
diff --git a/telepathy-logger/log-entry.c b/telepathy-logger/log-entry.c
new file mode 100644
index 0000000..cddddb0
--- /dev/null
+++ b/telepathy-logger/log-entry.c
@@ -0,0 +1,131 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2009 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Cosimo Alfarano <cosimo.alfarano@collabora.co.uk>
+ */
+
+#include "log-entry.h"
+
+#include <glib.h>
+
+#include <telepathy-logger/debug.h>
+
+G_DEFINE_TYPE (TplLogEntry, tpl_log_entry, G_TYPE_OBJECT)
+ static void tpl_log_entry_finalize (GObject * obj)
+{
+ G_OBJECT_CLASS (tpl_log_entry_parent_class)->finalize (obj);
+}
+
+static void
+tpl_log_entry_dispose (GObject * obj)
+{
+ TplLogEntry *self = TPL_LOG_ENTRY (obj);
+
+ DEBUG ("TplLogEntry: disposing\n");
+
+ tpl_object_unref_if_not_null (tpl_log_entry_get_entry (self));
+ self->entry.generic = NULL;
+
+ G_OBJECT_CLASS (tpl_log_entry_parent_class)->dispose (obj);
+
+ DEBUG ("TplLogEntry: disposed\n");
+}
+
+
+static void
+tpl_log_entry_class_init (TplLogEntryClass * klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = tpl_log_entry_finalize;
+ object_class->dispose = tpl_log_entry_dispose;
+}
+
+static void
+tpl_log_entry_init (TplLogEntry * self)
+{
+}
+
+
+void
+tpl_log_entry_set_entry (TplLogEntry * self, void *entry)
+{
+ g_return_if_fail (TPL_IS_LOG_ENTRY (self));
+ g_return_if_fail (self->entry.generic == NULL);
+
+ if (TPL_IS_LOG_ENTRY_TEXT (entry))
+ {
+ self->type = TPL_LOG_ENTRY_TEXT;
+ self->entry.text = entry;
+ }
+ else
+ {
+ g_error ("TplLogEntry does handle only Text channels\n");
+ }
+}
+
+TplLogEntryType
+tpl_log_entry_get_entry_type (TplLogEntry * self)
+{
+ g_return_val_if_fail (TPL_IS_LOG_ENTRY (self), TPL_LOG_ENTRY_ERROR);
+
+ return self->type;
+}
+
+void *
+tpl_log_entry_get_entry (TplLogEntry * self)
+{
+ g_return_val_if_fail (TPL_IS_LOG_ENTRY (self), NULL);
+
+ switch (self->type)
+ {
+ case TPL_LOG_ENTRY_TEXT:
+ if (!TPL_IS_LOG_ENTRY_TEXT (self->entry.text))
+ {
+ g_error ("TplLogEntry->entry->text not a TplLogEntryText instance");
+ return NULL;
+ }
+ return self->entry.text;
+ break;
+ default:
+ g_warning ("TplLogEntry type not handled\n");
+ return NULL;
+ break;
+ }
+}
+
+TplLogEntry *
+tpl_log_entry_new (void)
+{
+ return g_object_new (TPL_TYPE_LOG_ENTRY, NULL);
+}
+
+
+time_t
+tpl_log_entry_get_timestamp (TplLogEntry * self)
+{
+ g_return_val_if_fail (TPL_IS_LOG_ENTRY (self), -1);
+ return self->timestamp;
+}
+
+void
+tpl_log_entry_set_timestamp (TplLogEntry * self, time_t data)
+{
+ g_return_if_fail (TPL_IS_LOG_ENTRY (self));
+
+ self->timestamp = data;
+}
diff --git a/telepathy-logger/log-entry.h b/telepathy-logger/log-entry.h
new file mode 100644
index 0000000..dbb073e
--- /dev/null
+++ b/telepathy-logger/log-entry.h
@@ -0,0 +1,74 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2009 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Cosimo Alfarano <cosimo.alfarano@collabora.co.uk>
+ */
+
+#ifndef __TPL_LOG_ENTRY_H__
+#define __TPL_LOG_ENTRY_H__
+
+#include <glib-object.h>
+
+#include <telepathy-logger/log-entry-text.h>
+
+G_BEGIN_DECLS
+#define TPL_TYPE_LOG_ENTRY (tpl_log_entry_get_type ())
+#define TPL_LOG_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TPL_TYPE_LOG_ENTRY, TplLogEntry))
+#define TPL_LOG_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TPL_TYPE_LOG_ENTRY, TplLogEntryClass))
+#define TPL_IS_LOG_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TPL_TYPE_LOG_ENTRY))
+#define TPL_IS_LOG_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TPL_TYPE_LOG_ENTRY))
+#define TPL_LOG_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TPL_TYPE_LOG_ENTRY, TplLogEntryClass))
+ typedef enum
+{
+ TPL_LOG_ENTRY_ERROR,
+ TPL_LOG_ENTRY_TEXT
+} TplLogEntryType;
+
+typedef struct
+{
+ GObject parent;
+
+ /* Private */
+ TplLogEntryType type;
+ union
+ {
+ TplLogEntryText *text;
+ void *generic;
+ } entry;
+ time_t timestamp;
+} TplLogEntry;
+
+typedef struct
+{
+ GObjectClass parent_class;
+} TplLogEntryClass;
+
+GType tpl_log_entry_get_type (void);
+
+TplLogEntry *tpl_log_entry_new (void);
+
+TplLogEntryType tpl_log_entry_get_entry_type (TplLogEntry * data);
+void *tpl_log_entry_get_entry (TplLogEntry * data);
+time_t tpl_log_entry_get_timestamp (TplLogEntry * self);
+
+// sets entry type and its object
+void tpl_log_entry_set_entry (TplLogEntry * self, void *entry);
+void tpl_log_entry_set_timestamp (TplLogEntry * self, time_t data);
+
+G_END_DECLS
+#endif // __TPL_LOG_ENTRY_H__
diff --git a/telepathy-logger/log-manager-priv.h b/telepathy-logger/log-manager-priv.h
new file mode 100644
index 0000000..2bfcaea
--- /dev/null
+++ b/telepathy-logger/log-manager-priv.h
@@ -0,0 +1,34 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2003-2007 Imendio AB
+ * Copyright (C) 2007-2008 Collabora Ltd.
+ *
+ * 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 St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ *
+ * Authors: Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#ifndef __TPL_LOG_MANAGER_PRIV_H__
+#define __TPL_LOG_MANAGER_PRIV_H__
+
+#include <telepathy-logger/log-manager.h>
+
+gboolean tpl_log_manager_add_message (TplLogManager * manager,
+ const gchar * chat_id,
+ gboolean chatroom,
+ TplLogEntry * message, GError ** error);
+
+#endif /* __TPL_LOG_MANAGER_PRIV_H__ */
diff --git a/telepathy-logger/log-manager.c b/telepathy-logger/log-manager.c
new file mode 100644
index 0000000..f9f1a75
--- /dev/null
+++ b/telepathy-logger/log-manager.c
@@ -0,0 +1,833 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2003-2007 Imendio AB
+ * Copyright (C) 2007-2008 Collabora Ltd.
+ *
+ * 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 St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ *
+ * Authors: Xavier Claessens <xclaesse@gmail.com>
+ * Cosimo Alfarano <cosimo.alfarano@collabora.co.uk>
+ */
+
+#include "log-manager.h" // RO
+#include "log-manager-priv.h" // W
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <gio/gio.h>
+#include <glib/gstdio.h>
+#include <telepathy-glib/interfaces.h>
+#include <telepathy-glib/util.h>
+
+#include <telepathy-logger/log-entry.h>
+#include <telepathy-logger/log-store.h>
+#include <telepathy-logger/log-store-empathy.h>
+#include <telepathy-logger/datetime.h>
+#include <telepathy-logger/utils.h>
+
+//#define DEBUG_FLAG EMPATHY_DEBUG_OTHER
+//#include <empathy-debug.h>
+
+#define DEBUG g_debug
+
+#define GET_PRIV(obj) TPL_GET_PRIV (obj, TplLogManager)
+typedef struct
+{
+ GList *stores;
+} TplLogManagerPriv;
+
+G_DEFINE_TYPE (TplLogManager, tpl_log_manager, G_TYPE_OBJECT);
+
+static TplLogManager *manager_singleton = NULL;
+
+static void
+log_manager_finalize (GObject * object)
+{
+ TplLogManagerPriv *priv;
+
+ priv = GET_PRIV (object);
+
+ g_list_foreach (priv->stores, (GFunc) g_object_unref, NULL);
+ g_list_free (priv->stores);
+}
+
+/*
+ * - Singleton LogManager constructor -
+ * Initialises LogStores with LogStoreEmpathy instance
+ */
+static GObject *
+log_manager_constructor (GType type,
+ guint n_props, GObjectConstructParam * props)
+{
+ GObject *retval;
+ TplLogManagerPriv *priv;
+
+ if (manager_singleton)
+ {
+ retval = g_object_ref (manager_singleton);
+ }
+ else
+ {
+ retval = G_OBJECT_CLASS (tpl_log_manager_parent_class)->constructor
+ (type, n_props, props);
+
+ manager_singleton = TPL_LOG_MANAGER (retval);
+ g_object_add_weak_pointer (retval, (gpointer *) & manager_singleton);
+
+ priv = GET_PRIV (manager_singleton);
+
+ priv->stores = g_list_append (priv->stores,
+ g_object_new (TPL_TYPE_LOG_STORE_EMPATHY,
+ NULL));
+ }
+
+ return retval;
+}
+
+static void
+tpl_log_manager_class_init (TplLogManagerClass * klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->constructor = log_manager_constructor;
+ object_class->finalize = log_manager_finalize;
+
+ g_type_class_add_private (object_class, sizeof (TplLogManagerPriv));
+}
+
+static void
+tpl_log_manager_init (TplLogManager * manager)
+{
+ TplLogManagerPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (manager,
+ TPL_TYPE_LOG_MANAGER,
+ TplLogManagerPriv);
+
+ manager->priv = priv;
+}
+
+TplLogManager *
+tpl_log_manager_dup_singleton (void)
+{
+ return g_object_new (TPL_TYPE_LOG_MANAGER, NULL);
+}
+
+
+gboolean
+tpl_log_manager_add_message (TplLogManager * manager,
+ const gchar * chat_id,
+ gboolean chatroom,
+ TplLogEntry * message, GError ** error)
+{
+ TplLogManagerPriv *priv;
+ GList *l;
+ gboolean out = FALSE;
+ gboolean found = FALSE;
+
+ /* TODO: When multiple log stores appear with add_message implementations
+ * make this customisable. */
+ const gchar *add_store = "TpLogger";
+
+ g_return_val_if_fail (TPL_IS_LOG_MANAGER (manager), FALSE);
+ g_return_val_if_fail (!TPL_STR_EMPTY (chat_id), FALSE);
+ g_return_val_if_fail (TPL_IS_LOG_ENTRY (message), FALSE);
+
+ priv = GET_PRIV (manager);
+
+ for (l = priv->stores; l; l = g_list_next (l))
+ {
+ if (!tp_strdiff
+ (tpl_log_store_get_name (TPL_LOG_STORE (l->data)), add_store))
+ {
+ out = tpl_log_store_add_message (TPL_LOG_STORE (l->data),
+ chat_id, chatroom, message, error);
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (!found)
+ DEBUG ("Failed to find chosen log store to write to.");
+
+ return out;
+}
+
+
+
+gboolean
+tpl_log_manager_exists (TplLogManager * manager,
+ TpAccount * account,
+ const gchar * chat_id, gboolean chatroom)
+{
+ GList *l;
+ TplLogManagerPriv *priv;
+
+ g_return_val_if_fail (TPL_IS_LOG_MANAGER (manager), FALSE);
+ g_return_val_if_fail (chat_id != NULL, FALSE);
+
+ priv = GET_PRIV (manager);
+
+ for (l = priv->stores; l; l = g_list_next (l))
+ {
+ if (tpl_log_store_exists (TPL_LOG_STORE (l->data),
+ account, chat_id, chatroom))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+// returns a list of gchar dates
+GList *
+tpl_log_manager_get_dates (TplLogManager * manager,
+ TpAccount * account,
+ const gchar * chat_id, gboolean chatroom)
+{
+ GList *l, *out = NULL;
+ TplLogManagerPriv *priv;
+
+ g_return_val_if_fail (TPL_IS_LOG_MANAGER (manager), NULL);
+ g_return_val_if_fail (chat_id != NULL, NULL);
+
+ priv = GET_PRIV (manager);
+
+ for (l = priv->stores; l; l = g_list_next (l))
+ {
+ TplLogStore *store = TPL_LOG_STORE (l->data);
+ GList *new;
+
+ /* Insert dates of each store in the out list. Keep the out list sorted
+ * and avoid to insert dups. */
+ new = tpl_log_store_get_dates (store, account, chat_id, chatroom);
+ while (new)
+ {
+ if (g_list_find_custom (out, new->data, (GCompareFunc) strcmp))
+ g_free (new->data);
+ else
+ out =
+ g_list_insert_sorted (out, new->data, (GCompareFunc) strcmp);
+
+ new = g_list_delete_link (new, new);
+ }
+ }
+
+ return out;
+}
+
+GList *
+tpl_log_manager_get_messages_for_date (TplLogManager * manager,
+ TpAccount * account,
+ const gchar * chat_id,
+ gboolean chatroom, const gchar * date)
+{
+ GList *l, *out = NULL;
+ TplLogManagerPriv *priv;
+
+ g_return_val_if_fail (TPL_IS_LOG_MANAGER (manager), NULL);
+ g_return_val_if_fail (chat_id != NULL, NULL);
+
+ priv = GET_PRIV (manager);
+
+ for (l = priv->stores; l; l = g_list_next (l))
+ {
+ TplLogStore *store = TPL_LOG_STORE (l->data);
+
+ out =
+ g_list_concat (out,
+ tpl_log_store_get_messages_for_date (store, account,
+ chat_id, chatroom,
+ date));
+ }
+
+ return out;
+}
+
+static gint
+log_manager_message_date_cmp (gconstpointer a, gconstpointer b)
+{
+ TplLogEntry *one = (TplLogEntry *) a;
+ TplLogEntry *two = (TplLogEntry *) b;
+ time_t one_time, two_time;
+
+ one_time = tpl_log_entry_get_timestamp (one);
+ two_time = tpl_log_entry_get_timestamp (two);
+
+ /* Return -1 of message1 is older than message2 */
+ return one_time < two_time ? -1 : one_time - two_time;
+}
+
+GList *
+tpl_log_manager_get_filtered_messages (TplLogManager * manager,
+ TpAccount * account,
+ const gchar * chat_id,
+ gboolean chatroom,
+ guint num_messages,
+ TplLogMessageFilter filter,
+ gpointer user_data)
+{
+ TplLogManagerPriv *priv;
+ GList *out = NULL;
+ GList *l;
+ guint i = 0;
+
+ g_return_val_if_fail (TPL_IS_LOG_MANAGER (manager), NULL);
+ g_return_val_if_fail (chat_id != NULL, NULL);
+
+ priv = GET_PRIV (manager);
+
+ /* Get num_messages from each log store and keep only the
+ * newest ones in the out list. Keep that list sorted: Older first. */
+ for (l = priv->stores; l; l = g_list_next (l))
+ {
+ TplLogStore *store = TPL_LOG_STORE (l->data);
+ GList *new;
+
+ new = tpl_log_store_get_filtered_messages (store, account, chat_id,
+ chatroom, num_messages,
+ filter, user_data);
+ while (new)
+ {
+ if (i < num_messages)
+ {
+ /* We have less message than needed so far. Keep this message */
+ out = g_list_insert_sorted (out, new->data,
+ (GCompareFunc)
+ log_manager_message_date_cmp);
+ i++;
+ }
+ else if (log_manager_message_date_cmp (new->data, out->data) > 0)
+ {
+ /* This message is newer than the oldest message we have in out
+ * list. Remove the head of out list and insert this message */
+ g_object_unref (out->data);
+ out = g_list_delete_link (out, out);
+ out = g_list_insert_sorted (out, new->data,
+ (GCompareFunc)
+ log_manager_message_date_cmp);
+ }
+ else
+ {
+ /* This message is older than the oldest message we have in out
+ * list. Drop it. */
+ g_object_unref (new->data);
+ }
+
+ new = g_list_delete_link (new, new);
+ }
+ }
+
+ return out;
+}
+
+GList *
+tpl_log_manager_get_chats (TplLogManager * manager, TpAccount * account)
+{
+ GList *l, *out = NULL;
+ TplLogManagerPriv *priv;
+
+ g_return_val_if_fail (TPL_IS_LOG_MANAGER (manager), NULL);
+ g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL);
+
+ priv = GET_PRIV (manager);
+
+ for (l = priv->stores; l; l = g_list_next (l))
+ {
+ TplLogStore *store = TPL_LOG_STORE (l->data);
+
+ out = g_list_concat (out, tpl_log_store_get_chats (store, account));
+ }
+
+ return out;
+}
+
+GList *
+tpl_log_manager_search_in_identifier_chats_new (TplLogManager * manager,
+ TpAccount * account,
+ gchar const *identifier,
+ const gchar * text)
+{
+ GList *l, *out = NULL;
+ TplLogManagerPriv *priv;
+
+ g_return_val_if_fail (TPL_IS_LOG_MANAGER (manager), NULL);
+ g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL);
+ g_return_val_if_fail (!TPL_STR_EMPTY (identifier), NULL);
+ g_return_val_if_fail (!TPL_STR_EMPTY (text), NULL);
+
+ priv = GET_PRIV (manager);
+
+ for (l = priv->stores; l; l = g_list_next (l))
+ {
+ TplLogStore *store = TPL_LOG_STORE (l->data);
+
+ out = g_list_concat (out,
+ tpl_log_store_search_in_identifier_chats_new
+ (store, account, identifier, text));
+ }
+
+ return out;
+}
+
+GList *
+tpl_log_manager_search_new (TplLogManager * manager, const gchar * text)
+{
+ GList *l, *out = NULL;
+ TplLogManagerPriv *priv;
+
+ g_return_val_if_fail (TPL_IS_LOG_MANAGER (manager), NULL);
+ g_return_val_if_fail (!TPL_STR_EMPTY (text), NULL);
+
+ priv = GET_PRIV (manager);
+
+ for (l = priv->stores; l; l = g_list_next (l))
+ {
+ TplLogStore *store = TPL_LOG_STORE (l->data);
+
+ out = g_list_concat (out, tpl_log_store_search_new (store, text));
+ }
+
+ return out;
+}
+
+void
+tpl_log_manager_search_hit_free (TplLogSearchHit * hit)
+{
+ if (hit->account != NULL)
+ g_object_unref (hit->account);
+
+ g_free (hit->date);
+ g_free (hit->filename);
+ g_free (hit->chat_id);
+
+ g_slice_free (TplLogSearchHit, hit);
+}
+
+void
+tpl_log_manager_search_free (GList * hits)
+{
+ GList *l;
+
+ for (l = hits; l; l = g_list_next (l))
+ {
+ tpl_log_manager_search_hit_free (l->data);
+ }
+
+ g_list_free (hits);
+}
+
+/* Format is just date, 20061201. */
+gchar *
+tpl_log_manager_get_date_readable (const gchar * date)
+{
+ time_t t;
+
+ t = tpl_time_parse (date);
+
+ return tpl_time_to_string_local (t, "%a %d %b %Y");
+}
+
+/* Async */
+
+TplLogManagerAsyncData *
+tpl_log_manager_async_data_new (void)
+{
+ return g_slice_new (TplLogManagerAsyncData);
+}
+
+void
+tpl_log_manager_async_data_free (TplLogManagerAsyncData * data)
+{
+ g_return_if_fail (TPL_IS_LOG_MANAGER (data->manager));
+ g_return_if_fail (data->request && data->request_free);
+
+ g_object_unref (data->manager);
+ data->request_free (data->request);
+ g_free (data);
+}
+
+
+
+TplLogManagerChatInfo *
+tpl_log_manager_chat_info_new (void)
+{
+ return g_slice_new0 (TplLogManagerChatInfo);
+}
+
+void
+tpl_log_manager_chat_info_free (TplLogManagerChatInfo * data)
+{
+ tpl_object_unref_if_not_null (data->account);
+ if (data->chat_id)
+ g_free (data->chat_id);
+ if (data->date)
+ g_free (data->date);
+ g_free (data);
+}
+
+
+
+static gpointer
+_tpl_log_manager_async_operation_finish (TplLogManager * manager,
+ GAsyncResult * result,
+ TplLogManagerAsyncData * async_data)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
+ g_print ("FINISH CALLED\n");
+ return g_simple_async_result_get_op_res_gpointer (simple);
+}
+
+static void
+_tpl_log_manager_async_operation_cb (GObject * source_object,
+ GAsyncResult * result,
+ gpointer user_data)
+{
+ TplLogManager *manager = TPL_LOG_MANAGER (source_object);
+ TplLogManagerAsyncData *async_data = (TplLogManagerAsyncData *) user_data;
+ gpointer retval;
+
+ g_message ("GSimple CB called: calling _finish to retrieve the result\n");
+ retval =
+ _tpl_log_manager_async_operation_finish (manager, result, async_data);
+
+ if (async_data->cb)
+ {
+ async_data->cb (async_data->manager, retval, NULL,
+ async_data->user_data);
+ }
+
+ //tpl_log_manager_async_data_free(async_data);
+}
+
+/* wrapper around GIO's GSimpleAsync* */
+static void
+_tpl_log_manager_call_async_operation (TplLogManager * manager,
+ GSimpleAsyncThreadFunc
+ operation_thread_func,
+ TplLogManagerAsyncData * async_data,
+ TplLogManagerAsyncCallback callback)
+{
+ GSimpleAsyncResult *simple;
+
+ g_message ("called async\n");
+ simple = g_simple_async_result_new (G_OBJECT (manager),
+ _tpl_log_manager_async_operation_cb,
+ async_data,
+ _tpl_log_manager_async_operation_finish);
+
+ g_simple_async_result_run_in_thread (simple, operation_thread_func, 0,
+ NULL);
+}
+
+/* end of Async common function */
+
+gboolean
+tpl_log_manager_add_message_async (TplLogManager * manager,
+ const gchar * chat_id,
+ gboolean chatroom,
+ TplLogEntry * message, GError ** error)
+
+
+/* Start of get_dates async implementation */
+static void
+_get_dates_async_thread (GSimpleAsyncResult * simple, GObject * object,
+ GCancellable * cancellable)
+{
+ TplLogManagerAsyncData *async_data;
+ TplLogManagerChatInfo *chat_info;
+ GList *lst = NULL;
+
+ async_data = g_async_result_get_user_data (G_ASYNC_RESULT (simple));
+ chat_info = async_data->request;
+
+ // use the sync method
+ lst = tpl_log_manager_get_dates (async_data->manager,
+ chat_info->account, chat_info->chat_id,
+ chat_info->is_chatroom);
+
+ g_simple_async_result_set_op_res_gpointer (simple, lst, NULL); // TODO add destructor
+ g_message ("THREAD!: GASYNC RESULT: SET GLIST PTR\n");
+}
+
+
+void
+tpl_log_manager_get_dates_async (TplLogManager * manager,
+ TpAccount * account,
+ const gchar * chat_id,
+ gboolean is_chatroom,
+ TplLogManagerAsyncCallback callback,
+ gpointer user_data, GDestroyNotify destroy)
+{
+ TplLogManagerChatInfo *chat_info = tpl_log_manager_chat_info_new ();
+ TplLogManagerAsyncData *async_data = tpl_log_manager_async_data_new ();
+
+ tpl_call_with_err_if_fail (TPL_IS_LOG_MANAGER (manager), manager,
+ TPL_LOG_MANAGER, FAILED,
+ "manager argument passed is not a TplManager instance",
+ callback, user_data);
+ tpl_call_with_err_if_fail (TP_IS_ACCOUNT (account), manager,
+ TPL_LOG_MANAGER, FAILED,
+ "account argument is not a TpAccount instance",
+ callback, user_data);
+ tpl_call_with_err_if_fail (!TPL_STR_EMPTY (chat_id), manager,
+ TPL_LOG_MANAGER, FAILED,
+ "chat_id argument passed cannot be empty string or NULL ptr",
+ callback, user_data);
+
+
+
+ // TODO add check against manager, chat_info
+ // TODO add check against date!=NULL and call cb in case of error
+
+ chat_info->account = account;
+ g_object_ref (account);
+ chat_info->chat_id = g_strdup (chat_id);
+ chat_info->is_chatroom = is_chatroom;
+
+ async_data->manager = manager;
+ g_object_ref (manager);
+ async_data->request = (gpointer) chat_info;
+ async_data->request_free =
+ (TplLogManagerFreeFunc) tpl_log_manager_chat_info_free;
+ async_data->cb = callback;
+ async_data->user_data = user_data;
+
+ _tpl_log_manager_call_async_operation (manager, _get_dates_async_thread,
+ async_data, callback);
+}
+
+/* End of get_dates async implementation */
+
+/* Start of get_messages_for_date async implementation */
+static void
+_get_messages_for_date_async_thread (GSimpleAsyncResult * simple,
+ GObject * object,
+ GCancellable * cancellable)
+{
+ TplLogManagerAsyncData *async_data;
+ TplLogManagerChatInfo *chat_info;
+ GList *lst;
+
+ async_data = g_async_result_get_user_data (G_ASYNC_RESULT (simple));
+ chat_info = async_data->request;
+
+ // use the sync method
+ lst = tpl_log_manager_get_messages_for_date (async_data->manager,
+ chat_info->account,
+ chat_info->chat_id,
+ chat_info->is_chatroom,
+ chat_info->date);
+
+ g_simple_async_result_set_op_res_gpointer (simple, lst, NULL); // TODO add destructor
+ g_message ("THREAD!: GASYNC RESULT: SET GLIST PTR\n");
+}
+
+
+void
+tpl_log_manager_get_messages_for_date_async (TplLogManager * manager,
+ TpAccount * account,
+ const gchar * chat_id,
+ gboolean is_chatroom,
+ const gchar * date,
+ TplLogManagerAsyncCallback
+ callback, gpointer user_data,
+ GDestroyNotify destroy)
+{
+ TplLogManagerChatInfo *chat_info = tpl_log_manager_chat_info_new ();
+ TplLogManagerAsyncData *async_data = tpl_log_manager_async_data_new ();
+
+ // TODO add check against manager, chat_info
+ // TODO add check against date!=NULL and call cb in case of error
+ tpl_call_with_err_if_fail (TPL_IS_LOG_MANAGER (manager), manager,
+ TPL_LOG_MANAGER, FAILED,
+ "manager argument passed is not a TplManager instance",
+ callback, user_data);
+ tpl_call_with_err_if_fail (TP_IS_ACCOUNT (account), manager,
+ TPL_LOG_MANAGER, FAILED,
+ "account argument is not a TpAccount instance",
+ callback, user_data);
+ tpl_call_with_err_if_fail (!TPL_STR_EMPTY (chat_id), manager,
+ TPL_LOG_MANAGER, FAILED,
+ "chat_id argument passed cannot be empty string or NULL ptr",
+ callback, user_data);
+ tpl_call_with_err_if_fail (!TPL_STR_EMPTY (date), manager,
+ TPL_LOG_MANAGER, FAILED,
+ "date argument passed cannot be empty string or NULL ptr",
+ callback, user_data);
+
+
+
+ chat_info->account = account;
+ g_object_ref (account);
+ chat_info->chat_id = g_strdup (chat_id);
+ chat_info->is_chatroom = is_chatroom;
+ chat_info->date = g_strdup(date);
+
+ async_data->manager = manager;
+ g_object_ref (manager);
+ async_data->request = (gpointer) chat_info;
+ async_data->request_free =
+ (TplLogManagerFreeFunc) tpl_log_manager_chat_info_free;
+ async_data->cb = callback;
+ async_data->user_data = user_data;
+
+ _tpl_log_manager_call_async_operation (manager,
+ _get_messages_for_date_async_thread,
+ async_data, callback);
+}
+
+/* End of get_messages_for_date async implementation */
+
+/* Start of get_filtered_messages async implementation */
+static void
+_get_filtered_messages_thread (GSimpleAsyncResult * simple, GObject * object,
+ GCancellable * cancellable)
+{
+ TplLogManagerAsyncData *async_data;
+ TplLogManagerChatInfo *chat_info;
+ GList *lst;
+
+ async_data = g_async_result_get_user_data (G_ASYNC_RESULT (simple));
+ chat_info = async_data->request;
+
+ // use the sync method
+ lst = tpl_log_manager_get_filtered_messages (async_data->manager,
+ chat_info->account,
+ chat_info->chat_id,
+ chat_info->is_chatroom,
+ chat_info->num_messages,
+ chat_info->filter,
+ chat_info->user_data);
+
+ g_simple_async_result_set_op_res_gpointer (simple, lst, NULL); // TODO add destructor
+ g_message ("THREAD!: GASYNC RESULT: SET GLIST PTR\n");
+}
+
+
+void
+tpl_log_manager_get_filtered_messages_async (TplLogManager * manager,
+ TpAccount * account,
+ const gchar * chat_id,
+ gboolean is_chatroom,
+ guint num_messages,
+ TplLogMessageFilter filter,
+ gpointer filter_user_data,
+ TplLogManagerAsyncCallback
+ callback, gpointer user_data,
+ GDestroyNotify destroy)
+{
+ TplLogManagerChatInfo *chat_info = tpl_log_manager_chat_info_new ();
+ TplLogManagerAsyncData *async_data = tpl_log_manager_async_data_new ();
+
+ tpl_call_with_err_if_fail (TPL_IS_LOG_MANAGER (manager), manager,
+ TPL_LOG_MANAGER, FAILED,
+ "manager argument passed is not a TplManager instance",
+ callback, user_data);
+ tpl_call_with_err_if_fail (TP_IS_ACCOUNT (account), manager,
+ TPL_LOG_MANAGER, FAILED,
+ "account argument is not a TpAccount instance",
+ callback, user_data);
+ tpl_call_with_err_if_fail (!TPL_STR_EMPTY (chat_id), manager,
+ TPL_LOG_MANAGER, FAILED,
+ "chat_id argument passed cannot be empty string or NULL ptr",
+ callback, user_data);
+ tpl_call_with_err_if_fail ((num_messages > 0), manager,
+ TPL_LOG_MANAGER, FAILED,
+ "num_message argument passed needs to be greater than 0",
+ callback, user_data);
+ tpl_call_with_err_if_fail (filter != NULL, manager,
+ TPL_LOG_MANAGER, FAILED,
+ "filter function should be not NULL",
+ callback, user_data);
+
+ chat_info->account = account;
+ g_object_ref (account);
+ chat_info->chat_id = g_strdup (chat_id);
+ chat_info->is_chatroom = is_chatroom;
+ chat_info->num_messages = num_messages;
+ chat_info->filter = filter;
+ chat_info->user_data = filter_user_data;
+
+ async_data->manager = manager;
+ g_object_ref (manager);
+ async_data->request = (gpointer) chat_info;
+ async_data->request_free =
+ (TplLogManagerFreeFunc) tpl_log_manager_chat_info_free;
+ async_data->cb = callback;
+ async_data->user_data = user_data;
+
+ _tpl_log_manager_call_async_operation (manager,
+ _get_filtered_messages_thread,
+ async_data, callback);
+}
+
+/* End of get_filtered_messages async implementation */
+
+
+/* Start of get_chats async implementation */
+static void
+_get_chats_thread (GSimpleAsyncResult * simple, GObject * object,
+ GCancellable * cancellable)
+{
+ TplLogManagerAsyncData *async_data;
+ TplLogManagerChatInfo *chat_info;
+ GList *lst;
+
+ async_data = g_async_result_get_user_data (G_ASYNC_RESULT (simple));
+ chat_info = async_data->request;
+
+ // use the sync method
+ lst = tpl_log_manager_get_chats (async_data->manager, chat_info->account);
+
+ g_simple_async_result_set_op_res_gpointer (simple, lst, NULL); // TODO add destructor
+}
+
+
+void
+tpl_log_manager_get_chats_async (TplLogManager * manager,
+ TpAccount * account,
+ TplLogManagerAsyncCallback callback,
+ gpointer user_data, GDestroyNotify destroy)
+{
+ TplLogManagerChatInfo *chat_info = tpl_log_manager_chat_info_new ();
+ TplLogManagerAsyncData *async_data = tpl_log_manager_async_data_new ();
+
+ tpl_call_with_err_if_fail (TPL_IS_LOG_MANAGER (manager), manager,
+ TPL_LOG_MANAGER, FAILED,
+ "manager argument is not a TplManager instance",
+ callback, user_data);
+ tpl_call_with_err_if_fail (TP_IS_ACCOUNT (account), manager,
+ TPL_LOG_MANAGER, FAILED,
+ "account argument is not a TpAccount instance",
+ callback, user_data);
+
+ chat_info->account = account;
+ g_object_ref (account);
+
+ async_data->manager = manager;
+ g_object_ref (manager);
+ async_data->request = (gpointer) chat_info;
+ async_data->request_free =
+ (TplLogManagerFreeFunc) tpl_log_manager_chat_info_free;
+ async_data->cb = callback;
+ async_data->user_data = user_data;
+
+ _tpl_log_manager_call_async_operation (manager,
+ _get_chats_thread,
+ async_data, callback);
+}
+
+/* End of get_filtered_messages async implementation */
diff --git a/telepathy-logger/log-manager.h b/telepathy-logger/log-manager.h
new file mode 100644
index 0000000..8bcdf7f
--- /dev/null
+++ b/telepathy-logger/log-manager.h
@@ -0,0 +1,198 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2003-2007 Imendio AB
+ * Copyright (C) 2007-2008 Collabora Ltd.
+ *
+ * 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 St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ *
+ * Authors: Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#ifndef __TPL_LOG_MANAGER_H__
+#define __TPL_LOG_MANAGER_H__
+
+#include <gio/gio.h>
+#include <glib-object.h>
+#include <telepathy-glib/account.h>
+
+#include <telepathy-logger/log-entry.h>
+
+G_BEGIN_DECLS
+#define TPL_TYPE_LOG_MANAGER (tpl_log_manager_get_type ())
+#define TPL_LOG_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TPL_TYPE_LOG_MANAGER, TplLogManager))
+#define TPL_LOG_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), TPL_TYPE_LOG_MANAGER, TplLogManagerClass))
+#define TPL_IS_LOG_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TPL_TYPE_LOG_MANAGER))
+#define TPL_IS_LOG_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), TPL_TYPE_LOG_MANAGER))
+#define TPL_LOG_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), TPL_TYPE_LOG_MANAGER, TplLogManagerClass))
+
+#define TPL_LOG_MANAGER_ERROR g_quark_from_static_string ("tpl-log-manager-error-quark")
+ typedef enum
+{
+ TPL_LOG_MANAGER_ERROR_FAILED
+} TplLogManagerError;
+
+
+
+typedef struct
+{
+ GObject parent;
+
+ gpointer priv;
+} TplLogManager;
+
+typedef struct
+{
+ GObjectClass parent_class;
+} TplLogManagerClass;
+
+typedef struct
+{
+ TpAccount *account;
+ gchar *chat_id;
+ gboolean is_chatroom;
+ gchar *filename;
+ gchar *date;
+} TplLogSearchHit;
+
+typedef gboolean (*TplLogMessageFilter) (TplLogEntry * message,
+ gpointer user_data);
+
+GType tpl_log_manager_get_type (void);
+
+TplLogManager *tpl_log_manager_dup_singleton (void);
+
+gboolean tpl_log_manager_exists (TplLogManager * manager,
+ TpAccount * account, const gchar * chat_id,
+ gboolean chatroom);
+
+GList *tpl_log_manager_get_dates (TplLogManager * manager,
+ TpAccount * account, const gchar * chat_id,
+ gboolean chatroom);
+
+
+GList *tpl_log_manager_get_messages_for_date (TplLogManager * manager,
+ TpAccount * account,
+ const gchar * chat_id,
+ gboolean chatroom,
+ const gchar * date);
+
+GList *tpl_log_manager_get_filtered_messages (TplLogManager * manager,
+ TpAccount * account,
+ const gchar * chat_id,
+ gboolean chatroom,
+ guint num_messages,
+ TplLogMessageFilter filter,
+ gpointer user_data);
+
+GList *tpl_log_manager_get_chats (TplLogManager * manager,
+ TpAccount * account);
+
+GList *tpl_log_manager_search_in_identifier_chats_new (TplLogManager *
+ manager,
+ TpAccount * account,
+ gchar const
+ *identifier,
+ const gchar * text);
+
+GList *tpl_log_manager_search_new (TplLogManager * manager,
+ const gchar * text);
+
+void tpl_log_manager_search_free (GList * hits);
+
+gchar *tpl_log_manager_get_date_readable (const gchar * date);
+
+void tpl_log_manager_search_hit_free (TplLogSearchHit * hit);
+
+
+/* Async */
+typedef void (*TplLogManagerAsyncCallback) (TplLogManager * manager,
+ gpointer result, GError * error,
+ gpointer user_data);
+
+typedef void (*TplLogManagerFreeFunc) (gpointer * data);
+
+typedef struct
+{
+ TplLogManager *manager;
+ gpointer request;
+ TplLogManagerFreeFunc request_free;
+ TplLogManagerAsyncCallback cb;
+ gpointer user_data;
+} TplLogManagerAsyncData;
+
+TplLogManagerAsyncData *tpl_log_manager_async_data_new (void);
+
+void tpl_log_manager_async_data_free (TplLogManagerAsyncData * data);
+
+
+typedef struct
+{
+ TpAccount *account;
+ gchar *chat_id;
+ gboolean is_chatroom;
+ gchar *date;
+ guint num_messages;
+ TplLogMessageFilter filter;
+ gpointer user_data;
+} TplLogManagerChatInfo;
+
+TplLogManagerChatInfo *tpl_log_manager_chat_info_new (void);
+
+void tpl_log_manager_chat_info_free (TplLogManagerChatInfo * data);
+
+void tpl_log_manager_get_dates_async (TplLogManager * manager,
+ TpAccount * account,
+ const gchar * chat_id,
+ gboolean is_chatroom,
+ TplLogManagerAsyncCallback callback,
+ gpointer user_data,
+ GDestroyNotify destroy);
+
+
+void tpl_log_manager_get_messages_for_date_async (TplLogManager * manager,
+ TpAccount * account,
+ const gchar * chat_id,
+ gboolean is_chatroom,
+ const gchar * date,
+ TplLogManagerAsyncCallback
+ callback,
+ gpointer user_data,
+ GDestroyNotify destroy);
+
+void tpl_log_manager_get_filtered_messages_async (TplLogManager * manager,
+ TpAccount * account,
+ const gchar * chat_id,
+ gboolean is_chatroom,
+ guint num_messages,
+ TplLogMessageFilter filter,
+ gpointer filter_user_data,
+ TplLogManagerAsyncCallback
+ callback,
+ gpointer user_data,
+ GDestroyNotify destroy);
+
+void
+tpl_log_manager_get_chats_async (TplLogManager * manager,
+ TpAccount * account,
+ TplLogManagerAsyncCallback callback,
+ gpointer user_data, GDestroyNotify destroy);
+
+
+/* End of Async */
+
+
+G_END_DECLS
+#endif /* __TPL_LOG_MANAGER_H__ */
diff --git a/telepathy-logger/log-store-empathy.c b/telepathy-logger/log-store-empathy.c
new file mode 100644
index 0000000..eb35aec
--- /dev/null
+++ b/telepathy-logger/log-store-empathy.c
@@ -0,0 +1,1097 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2003-2007 Imendio AB
+ * Copyright (C) 2007-2008 Collabora Ltd.
+ *
+ * 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 St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ *
+ * Authors: Xavier Claessens <xclaesse@gmail.com>
+ * Jonny Lamb <jonny.lamb@collabora.co.uk>
+ */
+
+#include "log-store-empathy.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <glib/gstdio.h>
+
+#include <glib-object.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <telepathy-glib/account.h>
+#include <telepathy-glib/account-manager.h>
+#include <telepathy-glib/defs.h>
+#include <telepathy-glib/util.h>
+
+#include <telepathy-logger/contact.h>
+#include <telepathy-logger/log-manager.h>
+#include <telepathy-logger/log-store.h>
+#include <telepathy-logger/log-entry-text.h>
+#include <telepathy-logger/datetime.h>
+
+#define DEBUG g_debug
+
+#define LOG_DIR_CREATE_MODE (S_IRUSR | S_IWUSR | S_IXUSR)
+#define LOG_FILE_CREATE_MODE (S_IRUSR | S_IWUSR)
+#define LOG_DIR_CHATROOMS "chatrooms"
+#define LOG_FILENAME_SUFFIX ".log"
+#define LOG_TIME_FORMAT_FULL "%Y%m%dT%H:%M:%S"
+#define LOG_TIME_FORMAT "%Y%m%d"
+#define LOG_HEADER \
+ "<?xml version='1.0' encoding='utf-8'?>\n" \
+ "<?xml-stylesheet type=\"text/xsl\" href=\"empathy-log.xsl\"?>\n" \
+ "<log>\n"
+
+#define LOG_FOOTER \
+ "</log>\n"
+
+
+#define GET_PRIV(obj) TPL_GET_PRIV (obj, TplLogStoreEmpathy)
+typedef struct
+{
+ gchar *basedir;
+ gchar *name;
+ TpAccountManager *account_manager;
+} TplLogStoreEmpathyPriv;
+
+static void log_store_iface_init (gpointer g_iface, gpointer iface_data);
+
+G_DEFINE_TYPE_WITH_CODE (TplLogStoreEmpathy, tpl_log_store_empathy,
+ G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (TPL_TYPE_LOG_STORE,
+ log_store_iface_init));
+
+static void
+log_store_empathy_dispose (GObject * object)
+{
+ TplLogStoreEmpathy *self = TPL_LOG_STORE_EMPATHY (object);
+ TplLogStoreEmpathyPriv *priv = GET_PRIV (self);
+
+ // FIXME See TP-bug #25569, when dispose a non prepared TP_AM, it
+ // might segfault.
+ // To avoid it, a *klduge*, a reference in the TplObserver to
+ // the TplLogManager is kept, so that until TplObserver is instanced,
+ // there will always be a TpLogManager reference and it won't be
+ // diposed, not executing the follwoing unref (which caused the bug)
+ if (priv->account_manager != NULL)
+ {
+ g_object_unref (priv->account_manager);
+ priv->account_manager = NULL;
+ }
+}
+
+
+static void
+log_store_empathy_finalize (GObject * object)
+{
+ TplLogStoreEmpathy *self = TPL_LOG_STORE_EMPATHY (object);
+ TplLogStoreEmpathyPriv *priv = GET_PRIV (self);
+
+ g_free (priv->basedir);
+ g_free (priv->name);
+}
+
+static void
+tpl_log_store_empathy_class_init (TplLogStoreEmpathyClass * klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = log_store_empathy_finalize;
+ object_class->dispose = log_store_empathy_dispose;
+
+ g_type_class_add_private (object_class, sizeof (TplLogStoreEmpathyPriv));
+}
+
+static void
+tpl_log_store_empathy_init (TplLogStoreEmpathy * self)
+{
+ TplLogStoreEmpathyPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+ TPL_TYPE_LOG_STORE_EMPATHY,
+ TplLogStoreEmpathyPriv);
+
+ self->priv = priv;
+
+ priv->basedir = g_build_path (G_DIR_SEPARATOR_S, g_get_user_data_dir (),
+ "TpLogger", "logs", NULL);
+
+ // TODO update to a more meaningful name when more than one LogStore
+ // implementation will exist, like TpXMLLogger and TPSQLiteLogger
+ priv->name = g_strdup ("TpLogger");
+ priv->account_manager = tp_account_manager_dup ();
+}
+
+static gchar *
+log_store_account_to_dirname (TpAccount * account)
+{
+ const gchar *name;
+
+ g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL);
+
+ name = tp_proxy_get_object_path (account);
+ if (g_str_has_prefix (name, TP_ACCOUNT_OBJECT_PATH_BASE))
+ name += strlen (TP_ACCOUNT_OBJECT_PATH_BASE);
+
+ return g_strdelimit (g_strdup (name), "/", '_');
+}
+
+
+static gchar *
+log_store_empathy_get_dir (TplLogStore * self,
+ TpAccount * account,
+ const gchar * chat_id, gboolean chatroom)
+{
+ gchar *basedir;
+ gchar *escaped;
+ TplLogStoreEmpathyPriv *priv;
+
+ g_return_val_if_fail (TPL_IS_LOG_STORE (self), NULL);
+ g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL);
+ // chat_id may be NULL, in order to obtain the account part of the
+ // path.
+
+ priv = GET_PRIV (self);
+
+ escaped = log_store_account_to_dirname (account);
+
+ if (chatroom)
+ basedir = g_build_path (G_DIR_SEPARATOR_S, priv->basedir, escaped,
+ LOG_DIR_CHATROOMS, chat_id, NULL);
+ else
+ basedir = g_build_path (G_DIR_SEPARATOR_S, priv->basedir,
+ escaped, chat_id, NULL);
+
+ g_free (escaped);
+
+ return basedir;
+}
+
+static gchar *
+log_store_empathy_get_timestamp_filename (void)
+{
+ time_t t;
+ gchar *time_str;
+ gchar *filename;
+
+ t = tpl_time_get_current ();
+ time_str = tpl_time_to_string_local (t, LOG_TIME_FORMAT);
+ filename = g_strconcat (time_str, LOG_FILENAME_SUFFIX, NULL);
+
+ g_free (time_str);
+
+ return filename;
+}
+
+static gchar *
+log_store_empathy_get_timestamp_from_message (TplLogEntry * message)
+{
+ time_t t;
+
+ t = tpl_log_entry_get_timestamp (message);
+
+ /* We keep the timestamps in the messages as UTC. */
+ return tpl_time_to_string_utc (t, LOG_TIME_FORMAT_FULL);
+}
+
+static gchar *
+log_store_empathy_get_filename (TplLogStore * self,
+ TpAccount * account,
+ const gchar * chat_id, gboolean chatroom)
+{
+ gchar *basedir;
+ gchar *timestamp;
+ gchar *filename;
+
+ basedir = log_store_empathy_get_dir (self, account, chat_id, chatroom);
+ timestamp = log_store_empathy_get_timestamp_filename ();
+ filename = g_build_filename (basedir, timestamp, NULL);
+
+ g_free (basedir);
+ g_free (timestamp);
+
+ return filename;
+}
+
+static gboolean
+_log_store_empathy_write_to_store (TplLogStore * self,
+ TpAccount * account,
+ const gchar * chat_id,
+ gboolean chatroom,
+ const gchar * entry, GError ** error)
+{
+ FILE *file;
+ gchar *filename;
+ gchar *basedir;
+
+ filename =
+ log_store_empathy_get_filename (self, account, chat_id, chatroom);
+ basedir = g_path_get_dirname (filename);
+ if (!g_file_test (basedir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))
+ {
+ DEBUG ("Creating directory:'%s'", basedir);
+ g_mkdir_with_parents (basedir, LOG_DIR_CREATE_MODE);
+ }
+ g_free (basedir);
+
+ DEBUG ("Adding log to file: '%s': %s", filename, entry);
+
+ if (!g_file_test (filename, G_FILE_TEST_EXISTS))
+ {
+ file = g_fopen (filename, "w+");
+ if (file != NULL)
+ g_fprintf (file, LOG_HEADER);
+
+ g_chmod (filename, LOG_FILE_CREATE_MODE);
+ }
+ else
+ {
+ file = g_fopen (filename, "r+");
+ if (file != NULL)
+ fseek (file, -strlen (LOG_FOOTER), SEEK_END);
+ }
+
+ g_fprintf (file, entry);
+
+ fclose (file);
+ g_free (filename);
+ return TRUE;
+}
+
+/* currently unused */
+static gboolean
+_log_store_empathy_add_message_text_status_changed (TplLogStore * self,
+ const gchar * chat_id,
+ gboolean chatroom,
+ TplLogEntry * message,
+ GError ** error)
+{
+ TpAccount *account;
+ TplContact *sender;
+ const gchar *str;
+ gchar *timestamp;
+ gchar *contact_name;
+ gchar *contact_id;
+ gchar *contact_status;
+ gchar *contact_presence;
+ gchar *entry;
+ gboolean ret = FALSE;
+ TplLogEntryText *tmessage;
+
+ tmessage = tpl_log_entry_get_entry (message);
+ sender = tpl_log_entry_text_get_sender (tmessage);
+ account =
+ tpl_channel_get_account (tpl_log_entry_text_get_tpl_channel (tmessage));
+
+ timestamp = log_store_empathy_get_timestamp_from_message (message);
+
+ str = tpl_contact_get_alias (sender);
+ contact_name = g_markup_escape_text (str, -1);
+
+ str = tpl_contact_get_identifier (sender);
+ contact_id = g_markup_escape_text (str, -1);
+
+ str = tpl_contact_get_presence_status (sender);
+ contact_presence = g_markup_escape_text (str, -1);
+
+ str = tpl_contact_get_presence_message (sender);
+ contact_status = g_markup_escape_text (str, -1);
+
+ entry =
+ g_strdup_printf ("<statusUpdate time='%s' id='%s' name='%s' isuser='%s'"
+ "presence='%s' status='%s'/>\n" LOG_FOOTER, timestamp,
+ contact_id, contact_name,
+ tpl_contact_get_contact_type (sender) ==
+ TPL_CONTACT_USER ? "true" : "false", contact_presence,
+ contact_status);
+
+
+ ret = _log_store_empathy_write_to_store (self,
+ account, chat_id, chatroom, entry,
+ error);
+
+ g_free (contact_id);
+ g_free (contact_name);
+ g_free (contact_presence);
+ g_free (contact_status);
+ g_free (timestamp);
+ g_free (entry);
+
+ return ret;
+}
+
+
+static gboolean
+_log_store_empathy_add_message_text_chat (TplLogStore * self,
+ const gchar * chat_id,
+ gboolean chatroom,
+ TplLogEntry * message,
+ GError ** error)
+{
+ gboolean ret;
+ TpAccount *account;
+ TplContact *sender;
+ const gchar *body_str;
+ const gchar *str;
+ //EmpathyAvatar *avatar;
+ //gchar *avatar_token = NULL;
+ gchar *body;
+ gchar *timestamp;
+ gchar *contact_name;
+ gchar *contact_id;
+ gchar *entry;
+ TpChannelTextMessageType msg_type;
+ TplLogEntryText *tmessage;
+
+ tmessage = tpl_log_entry_get_entry (message);
+
+ sender = tpl_log_entry_text_get_sender (tmessage);
+ account =
+ tpl_channel_get_account (tpl_log_entry_text_get_tpl_channel (tmessage));
+ body_str = tpl_log_entry_text_get_message (tmessage);
+ msg_type = tpl_log_entry_text_get_message_type (tmessage);
+
+ if (TPL_STR_EMPTY (body_str))
+ return FALSE;
+
+ body = g_markup_escape_text (body_str, -1);
+ timestamp = log_store_empathy_get_timestamp_from_message (message);
+
+ str = tpl_contact_get_alias (sender);
+ contact_name = g_markup_escape_text (str, -1);
+
+ str = tpl_contact_get_identifier (sender);
+
+ contact_id = g_markup_escape_text (str, -1);
+/*
+ avatar = empathy_contact_get_avatar (sender);
+ if (avatar != NULL)
+ avatar_token = g_markup_escape_text (avatar->token, -1);
+*/
+ entry = g_strdup_printf ("<message time='%s' cm_id='%d' id='%s' name='%s' "
+ "token='%s' isuser='%s' type='%s'>"
+ "%s</message>\n" LOG_FOOTER, timestamp,
+ tpl_log_entry_text_get_message_id (tmessage),
+ contact_id, contact_name,
+ //avatar_token ? avatar_token : "", // instead force to "" as
+ //follow
+ "",
+ tpl_contact_get_contact_type (sender) ==
+ TPL_CONTACT_USER ? "true" : "false",
+ tpl_log_entry_text_message_type_to_str (msg_type),
+ body);
+
+ ret = _log_store_empathy_write_to_store (self,
+ account, chat_id, chatroom, entry,
+ error);
+
+ g_free (contact_id);
+ g_free (contact_name);
+ g_free (timestamp);
+ g_free (body);
+ g_free (entry);
+ //g_free (avatar_token);
+
+ return ret;
+}
+
+
+static gboolean
+_log_store_empathy_add_message_text (TplLogStore * self,
+ const gchar * chat_id,
+ gboolean chatroom,
+ TplLogEntry * message, GError ** error)
+{
+ TplLogEntryTextSignalType signal_type;
+ TplLogEntryText *tmessage;
+
+ g_return_val_if_fail (TPL_IS_LOG_STORE (self), FALSE);
+ g_return_val_if_fail (chat_id != NULL, FALSE);
+ g_return_val_if_fail (TPL_IS_LOG_ENTRY (message), FALSE);
+
+ tmessage = tpl_log_entry_get_entry (message);
+ signal_type = tpl_log_entry_text_get_signal_type (tmessage);
+
+ switch (signal_type)
+ {
+ case TPL_LOG_ENTRY_TEXT_SIGNAL_SENT:
+ case TPL_LOG_ENTRY_TEXT_SIGNAL_RECEIVED:
+ return _log_store_empathy_add_message_text_chat (self,
+ chat_id, chatroom,
+ message, error);
+ break;
+ case TPL_LOG_ENTRY_TEXT_SIGNAL_CHAT_STATUS_CHANGED:
+ return _log_store_empathy_add_message_text_status_changed (self,
+ chat_id,
+ chatroom,
+ message,
+ error);
+ break;
+ case TPL_LOG_ENTRY_TEXT_SIGNAL_SEND_ERROR:
+ g_warning ("SEND_ERROR log entry not currently handled");
+ return FALSE;
+ case TPL_LOG_ENTRY_TEXT_SIGNAL_LOST_MESSAGE:
+ g_warning ("LOST_MESSAGE log entry not currently handled");
+ return FALSE;
+ default:
+ g_warning ("LogEntry's signal type unknown");
+ return FALSE;
+ }
+}
+
+
+/* First of two phases selection: understand the type LogEntry */
+static gboolean
+log_store_empathy_add_message (TplLogStore * self,
+ const gchar * chat_id,
+ gboolean chatroom,
+ TplLogEntry * message, GError ** error)
+{
+ g_return_val_if_fail (TPL_IS_LOG_ENTRY (message), FALSE);
+
+ switch (tpl_log_entry_get_entry_type (message))
+ {
+ case TPL_LOG_ENTRY_TEXT:
+ return _log_store_empathy_add_message_text (self, chat_id, chatroom,
+ message, error);
+ default:
+ return FALSE;
+ }
+}
+
+
+static gboolean
+log_store_empathy_exists (TplLogStore * self,
+ TpAccount * account,
+ const gchar * chat_id, gboolean chatroom)
+{
+ gchar *dir;
+ gboolean exists;
+
+ g_return_val_if_fail (TPL_IS_LOG_ENTRY (self), FALSE);
+ g_return_val_if_fail (TP_IS_ACCOUNT (account), FALSE);
+ g_return_val_if_fail (!TPL_STR_EMPTY (chat_id), FALSE);
+
+ dir = log_store_empathy_get_dir (self, account, chat_id, chatroom);
+ exists = g_file_test (dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR);
+ g_free (dir);
+
+ return exists;
+}
+
+static GList *
+log_store_empathy_get_dates (TplLogStore * self,
+ TpAccount * account,
+ const gchar * chat_id, gboolean chatroom)
+{
+ GList *dates = NULL;
+ gchar *date;
+ gchar *directory;
+ GDir *dir;
+ const gchar *filename;
+ const gchar *p;
+
+ g_return_val_if_fail (TPL_IS_LOG_STORE (self), NULL);
+ g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL);
+ g_return_val_if_fail (!TPL_STR_EMPTY (chat_id), NULL);
+
+ directory = log_store_empathy_get_dir (self, account, chat_id, chatroom);
+ dir = g_dir_open (directory, 0, NULL);
+ if (!dir)
+ {
+ DEBUG ("Could not open directory:'%s'", directory);
+ g_free (directory);
+ return NULL;
+ }
+
+ DEBUG ("Collating a list of dates in:'%s'", directory);
+
+ while ((filename = g_dir_read_name (dir)) != NULL)
+ {
+ if (!g_str_has_suffix (filename, LOG_FILENAME_SUFFIX))
+ continue;
+
+ p = strstr (filename, LOG_FILENAME_SUFFIX);
+ date = g_strndup (filename, p - filename);
+
+ if (!date)
+ continue;
+
+ if (!g_regex_match_simple ("\\d{8}", date, 0, 0))
+ continue;
+
+ dates = g_list_insert_sorted (dates, date, (GCompareFunc) strcmp);
+ }
+
+ g_free (directory);
+ g_dir_close (dir);
+
+ DEBUG ("Parsed %d dates", g_list_length (dates));
+
+ return dates;
+}
+
+static gchar *
+log_store_empathy_get_filename_for_date (TplLogStore * self,
+ TpAccount * account,
+ const gchar * chat_id,
+ gboolean chatroom,
+ const gchar * date)
+{
+ gchar *basedir;
+ gchar *timestamp;
+ gchar *filename;
+
+
+ g_return_val_if_fail (TPL_IS_LOG_STORE (self), NULL);
+ g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL);
+ g_return_val_if_fail (!TPL_STR_EMPTY (chat_id), NULL);
+ g_return_val_if_fail (!TPL_STR_EMPTY (date), NULL);
+
+ basedir = log_store_empathy_get_dir (self, account, chat_id, chatroom);
+ timestamp = g_strconcat (date, LOG_FILENAME_SUFFIX, NULL);
+ filename = g_build_filename (basedir, timestamp, NULL);
+
+ g_free (basedir);
+ g_free (timestamp);
+
+ return filename;
+}
+
+static TplLogSearchHit *
+log_store_empathy_search_hit_new (TplLogStore * self, const gchar * filename)
+{
+ TplLogStoreEmpathyPriv *priv = GET_PRIV (self);
+ TplLogSearchHit *hit;
+ gchar *account_name;
+ const gchar *end;
+ gchar **strv;
+ guint len;
+ GList *accounts, *l;
+
+ g_return_val_if_fail (TPL_IS_LOG_STORE (self), NULL);
+ g_return_val_if_fail (!TPL_STR_EMPTY (filename), NULL);
+ g_return_val_if_fail (g_str_has_suffix (filename, LOG_FILENAME_SUFFIX),
+ NULL);
+
+ strv = g_strsplit (filename, G_DIR_SEPARATOR_S, -1);
+ len = g_strv_length (strv);
+
+ hit = g_slice_new0 (TplLogSearchHit);
+
+ end = strstr (strv[len - 1], LOG_FILENAME_SUFFIX);
+ hit->date = g_strndup (strv[len - 1], end - strv[len - 1]);
+ hit->chat_id = g_strdup (strv[len - 2]);
+ hit->is_chatroom = (strcmp (strv[len - 3], LOG_DIR_CHATROOMS) == 0);
+
+ if (hit->is_chatroom)
+ account_name = strv[len - 4];
+ else
+ account_name = strv[len - 3];
+
+ /* FIXME: This assumes the account manager is prepared, but the
+ * synchronous API forces this. See bug #599189. */
+ accounts = tp_account_manager_get_valid_accounts (priv->account_manager);
+
+ for (l = accounts; l != NULL; l = g_list_next (l))
+ {
+ TpAccount *account = TP_ACCOUNT (l->data);
+ gchar *name;
+
+ name = log_store_account_to_dirname (account);
+ if (!tp_strdiff (name, account_name))
+ {
+ g_assert (hit->account == NULL);
+ hit->account = account;
+ g_object_ref (account);
+ }
+ g_free (name);
+ }
+ g_list_free (accounts);
+
+ hit->filename = g_strdup (filename);
+
+ g_strfreev (strv);
+
+ return hit;
+}
+
+static GList *
+log_store_empathy_get_messages_for_file (TplLogStore * self,
+ TpAccount * account,
+ const gchar * filename)
+{
+ GList *messages = NULL;
+ xmlParserCtxtPtr ctxt;
+ xmlDocPtr doc;
+ xmlNodePtr log_node;
+ xmlNodePtr node;
+
+ g_return_val_if_fail (TPL_IS_LOG_STORE (self), NULL);
+ g_return_val_if_fail (!TPL_STR_EMPTY (filename), NULL);
+
+ DEBUG ("Attempting to parse filename:'%s'...", filename);
+
+ if (!g_file_test (filename, G_FILE_TEST_EXISTS))
+ {
+ DEBUG ("Filename:'%s' does not exist", filename);
+ return NULL;
+ }
+
+ /* Create parser. */
+ ctxt = xmlNewParserCtxt ();
+
+ /* Parse and validate the file. */
+ doc = xmlCtxtReadFile (ctxt, filename, NULL, 0);
+ if (!doc)
+ {
+ g_warning ("Failed to parse file:'%s'", filename);
+ xmlFreeParserCtxt (ctxt);
+ return NULL;
+ }
+
+ /* The root node, presets. */
+ log_node = xmlDocGetRootElement (doc);
+ if (!log_node)
+ {
+ xmlFreeDoc (doc);
+ xmlFreeParserCtxt (ctxt);
+ return NULL;
+ }
+
+ /* Now get the messages. */
+ for (node = log_node->children; node; node = node->next)
+ {
+ TplLogEntry *message;
+ TplLogEntryText *tmessage;
+ TplContact *sender;
+ gchar *time_;
+ time_t t;
+ gchar *sender_id;
+ gchar *sender_name;
+ //gchar *sender_avatar_token;
+ gchar *body;
+ gchar *is_user_str;
+ gboolean is_user = FALSE;
+ gchar *msg_type_str;
+ gchar *cm_id_str;
+ guint cm_id;
+ TpChannelTextMessageType msg_type = TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL;
+
+ if (strcmp ((const gchar *) node->name, "message") != 0)
+ continue;
+
+ body = (gchar *) xmlNodeGetContent (node);
+ time_ = (gchar *) xmlGetProp (node, (const xmlChar *) "time");
+ sender_id = (gchar *) xmlGetProp (node, (const xmlChar *) "id");
+ sender_name = (gchar *) xmlGetProp (node, (const xmlChar *) "name");
+ /*
+ sender_avatar_token = (gchar *) xmlGetProp (node,
+ (const xmlChar *) "token");
+ */
+ is_user_str = (gchar *) xmlGetProp (node, (const xmlChar *) "isuser");
+ msg_type_str = (gchar *) xmlGetProp (node, (const xmlChar *) "type");
+ cm_id_str = (gchar *) xmlGetProp (node, (const xmlChar *) "cm_id");
+
+ if (is_user_str)
+ is_user = strcmp (is_user_str, "true") == 0;
+
+ if (msg_type_str)
+ msg_type = tpl_log_entry_text_message_type_from_str (msg_type_str);
+
+ if (cm_id_str)
+ cm_id = atoi (cm_id_str);
+
+ t = tpl_time_parse (time_);
+
+ sender = tpl_contact_new ();
+ tpl_contact_set_account (sender, account);
+ tpl_contact_set_identifier (sender, sender_id);
+ tpl_contact_set_alias (sender, sender_name);
+
+ /* TODO remove avatar code
+ if (!TPL_STR_EMPTY (sender_avatar_token))
+ empathy_contact_load_avatar_cache (sender,
+ sender_avatar_token);
+ */
+
+ tmessage = tpl_log_entry_text_new ();
+ tpl_log_entry_text_set_message (tmessage, body);
+ tpl_log_entry_text_set_sender (tmessage, sender);
+ tpl_log_entry_text_set_message_type (tmessage, msg_type);
+ //TODO uderstand if useful
+ //tpl_log_entry_text_set_is_backlog (message, TRUE);
+
+ message = tpl_log_entry_new ();
+ tpl_log_entry_set_timestamp (message, t);
+ tpl_log_entry_set_entry (message, tmessage);
+
+ if (cm_id_str)
+ tpl_log_entry_text_set_message_id (tmessage, cm_id);
+
+ messages = g_list_append (messages, message);
+
+ g_object_unref (sender);
+ xmlFree (time_);
+ xmlFree (sender_id);
+ xmlFree (sender_name);
+ xmlFree (body);
+ xmlFree (is_user_str);
+ xmlFree (msg_type_str);
+ xmlFree (cm_id_str);
+ //xmlFree (sender_avatar_token);
+ }
+
+ DEBUG ("Parsed %d messages", g_list_length (messages));
+
+ xmlFreeDoc (doc);
+ xmlFreeParserCtxt (ctxt);
+
+ return messages;
+}
+
+static GList *
+log_store_empathy_get_all_files (TplLogStore * self, const gchar * dir)
+{
+ GDir *gdir;
+ GList *files = NULL;
+ const gchar *name;
+ const gchar *basedir;
+ TplLogStoreEmpathyPriv *priv;
+
+ priv = GET_PRIV (self);
+
+ g_return_val_if_fail (TPL_IS_LOG_STORE (self), NULL);
+ // dir can be NULL, and basedir will be searched instead
+
+ basedir = dir ? dir : priv->basedir;
+
+ gdir = g_dir_open (basedir, 0, NULL);
+ if (!gdir)
+ return NULL;
+
+ while ((name = g_dir_read_name (gdir)) != NULL)
+ {
+ gchar *filename;
+
+ filename = g_build_filename (basedir, name, NULL);
+ if (g_str_has_suffix (filename, LOG_FILENAME_SUFFIX))
+ {
+ files = g_list_prepend (files, filename);
+ continue;
+ }
+
+ if (g_file_test (filename, G_FILE_TEST_IS_DIR))
+ {
+ /* Recursively get all log files */
+ files = g_list_concat (files,
+ log_store_empathy_get_all_files (self,
+ filename));
+ }
+
+ g_free (filename);
+ }
+
+ g_dir_close (gdir);
+
+ return files;
+}
+
+
+static GList *
+_log_store_empathy_search_in_files (TplLogStore * self,
+ const gchar * text, GList * files)
+{
+ GList *l;
+ GList *hits = NULL;
+ gchar *text_casefold;
+
+ g_return_val_if_fail (TPL_IS_LOG_STORE (self), NULL);
+ g_return_val_if_fail (!TPL_STR_EMPTY (text), NULL);
+
+ text_casefold = g_utf8_casefold (text, -1);
+
+ for (l = files; l; l = g_list_next (l))
+ {
+ gchar *filename;
+ GMappedFile *file;
+ gsize length;
+ gchar *contents;
+ gchar *contents_casefold;
+
+ filename = l->data;
+
+ file = g_mapped_file_new (filename, FALSE, NULL);
+ if (!file)
+ continue;
+
+ length = g_mapped_file_get_length (file);
+ contents = g_mapped_file_get_contents (file);
+ contents_casefold = g_utf8_casefold (contents, length);
+
+ g_mapped_file_unref (file);
+
+ if (strstr (contents_casefold, text_casefold))
+ {
+ TplLogSearchHit *hit;
+
+ hit = log_store_empathy_search_hit_new (self, filename);
+
+ if (hit)
+ {
+ hits = g_list_prepend (hits, hit);
+ DEBUG ("Found text:'%s' in file:'%s' on date:'%s'",
+ text, hit->filename, hit->date);
+ }
+ }
+
+ g_free (contents_casefold);
+ g_free (filename);
+ }
+
+ g_list_free (files);
+ g_free (text_casefold);
+
+ return hits;
+}
+
+
+static GList *
+log_store_empathy_search_in_identifier_chats_new (TplLogStore * self,
+ TpAccount * account,
+ gchar const *identifier,
+ const gchar * text)
+{
+ GList *files;
+ gchar *dir, *account_dir;
+ TplLogStoreEmpathyPriv *priv = GET_PRIV (self);
+
+ g_return_val_if_fail (TPL_IS_LOG_STORE (self), NULL);
+ g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL);
+ g_return_val_if_fail (!TPL_STR_EMPTY (identifier), NULL);
+ g_return_val_if_fail (!TPL_STR_EMPTY (text), NULL);
+
+ account_dir = log_store_account_to_dirname (account);
+ dir =
+ g_build_path (G_DIR_SEPARATOR_S, priv->basedir, account_dir,
+ G_DIR_SEPARATOR_S, identifier, NULL);
+
+ files = log_store_empathy_get_all_files (self, dir);
+ DEBUG ("Found %d log files in total", g_list_length (files));
+
+ return _log_store_empathy_search_in_files (self, text, files);
+}
+
+
+
+static GList *
+log_store_empathy_search_new (TplLogStore * self, const gchar * text)
+{
+ GList *files;
+
+ g_return_val_if_fail (TPL_IS_LOG_STORE (self), NULL);
+ g_return_val_if_fail (!TPL_STR_EMPTY (text), NULL);
+
+ files = log_store_empathy_get_all_files (self, NULL);
+ DEBUG ("Found %d log files in total", g_list_length (files));
+
+ return _log_store_empathy_search_in_files (self, text, files);
+}
+
+/*
+static gboolean
+log_store_empathy_is_logfile (gchar const *filename) {
+ gchar **path;
+ guint len;
+ g_return_val_if_fail(!TPL_STR_EMPTY(filename), FALSE);
+
+
+ path = g_strsplit (filename, G_DIR_SEPARATOR_S, -1);
+ len = g_strv_length (path);
+
+ return g_regex_match_simple (
+ TPL_LOG_STORE_EMPATHY_LOGFILE_REGEX, path[len-1], 0, 0);
+}
+*/
+
+static GList *
+log_store_empathy_get_chats_for_dir (TplLogStore * self,
+ const gchar * dir, gboolean is_chatroom)
+{
+ GDir *gdir;
+ GList *hits = NULL;
+ const gchar *name;
+ GError *error = NULL;
+
+ gdir = g_dir_open (dir, 0, &error);
+ if (!gdir)
+ {
+ DEBUG ("Failed to open directory: %s, error: %s", dir, error->message);
+ g_error_free (error);
+ return NULL;
+ }
+
+ while ((name = g_dir_read_name (gdir)) != NULL)
+ {
+ TplLogSearchHit *hit;
+
+ if (!is_chatroom && strcmp (name, LOG_DIR_CHATROOMS) == 0)
+ {
+ gchar *filename = g_build_filename (dir, name, NULL);
+ hits =
+ g_list_concat (hits,
+ log_store_empathy_get_chats_for_dir (self,
+ filename,
+ TRUE));
+ g_free (filename);
+ continue;
+ }
+ hit = g_slice_new0 (TplLogSearchHit);
+ hit->chat_id = g_strdup (name);
+ hit->is_chatroom = is_chatroom;
+
+ hits = g_list_prepend (hits, hit);
+ }
+
+ g_dir_close (gdir);
+
+ return hits;
+}
+
+
+static GList *
+log_store_empathy_get_messages_for_date (TplLogStore * self,
+ TpAccount * account,
+ const gchar * chat_id,
+ gboolean chatroom,
+ const gchar * date)
+{
+ gchar *filename;
+ GList *messages;
+
+ g_return_val_if_fail (TPL_IS_LOG_STORE (self), NULL);
+ g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL);
+ g_return_val_if_fail (!TPL_STR_EMPTY (chat_id), NULL);
+
+ filename = log_store_empathy_get_filename_for_date (self, account,
+ chat_id, chatroom,
+ date);
+ messages =
+ log_store_empathy_get_messages_for_file (self, account, filename);
+ g_free (filename);
+
+ return messages;
+}
+
+static GList *
+log_store_empathy_get_chats (TplLogStore * self, TpAccount * account)
+{
+ gchar *dir;
+ GList *hits;
+ TplLogStoreEmpathyPriv *priv;
+
+ priv = GET_PRIV (self);
+
+ dir = log_store_empathy_get_dir (self, account, NULL, FALSE);
+
+ hits = log_store_empathy_get_chats_for_dir (self, dir, FALSE);
+
+ g_free (dir);
+
+ for (guint i = 0; i < g_list_length (hits); ++i)
+ {
+ TplLogSearchHit *hit;
+ hit = g_list_nth_data (hits, i);
+ }
+
+
+ return hits;
+}
+
+static const gchar *
+log_store_empathy_get_name (TplLogStore * self)
+{
+ TplLogStoreEmpathyPriv *priv = GET_PRIV (self);
+
+ return priv->name;
+}
+
+static GList *
+log_store_empathy_get_filtered_messages (TplLogStore * self,
+ TpAccount * account,
+ const gchar * chat_id,
+ gboolean chatroom,
+ guint num_messages,
+ TplLogMessageFilter filter,
+ gpointer user_data)
+{
+ GList *dates, *l, *messages = NULL;
+ guint i = 0;
+
+ dates = log_store_empathy_get_dates (self, account, chat_id, chatroom);
+
+ for (l = g_list_last (dates); l && i < num_messages;
+ l = g_list_previous (l))
+ {
+ GList *new_messages, *n, *next;
+
+ /* FIXME: We should really restrict the message parsing to get only
+ * the newest num_messages. */
+ new_messages = log_store_empathy_get_messages_for_date (self, account,
+ chat_id,
+ chatroom,
+ l->data);
+
+ n = new_messages;
+ while (n != NULL)
+ {
+ next = g_list_next (n);
+ if (!filter (n->data, user_data))
+ {
+ g_object_unref (n->data);
+ new_messages = g_list_delete_link (new_messages, n);
+ }
+ else
+ {
+ i++;
+ }
+ n = next;
+ }
+ messages = g_list_concat (messages, new_messages);
+ }
+
+ g_list_foreach (dates, (GFunc) g_free, NULL);
+ g_list_free (dates);
+
+ return messages;
+}
+
+static void
+log_store_iface_init (gpointer g_iface, gpointer iface_data)
+{
+ TplLogStoreInterface *iface = (TplLogStoreInterface *) g_iface;
+
+ iface->get_name = log_store_empathy_get_name;
+ iface->exists = log_store_empathy_exists;
+ iface->add_message = log_store_empathy_add_message;
+ iface->get_dates = log_store_empathy_get_dates;
+ iface->get_messages_for_date = log_store_empathy_get_messages_for_date;
+ iface->get_chats = log_store_empathy_get_chats;
+ iface->search_in_identifier_chats_new =
+ log_store_empathy_search_in_identifier_chats_new;
+ iface->search_new = log_store_empathy_search_new;
+ iface->ack_message = NULL;
+ iface->get_filtered_messages = log_store_empathy_get_filtered_messages;
+}
diff --git a/telepathy-logger/log-store-empathy.h b/telepathy-logger/log-store-empathy.h
new file mode 100644
index 0000000..d099371
--- /dev/null
+++ b/telepathy-logger/log-store-empathy.h
@@ -0,0 +1,65 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2003-2007 Imendio AB
+ * Copyright (C) 2007-2008 Collabora Ltd.
+ *
+ * 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 St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ *
+ * Authors: Xavier Claessens <xclaesse@gmail.com>
+ * Jonny Lamb <jonny.lamb@collabora.co.uk>
+ */
+
+#ifndef __TPL_LOG_STORE_EMPATHY_H__
+#define __TPL_LOG_STORE_EMPATHY_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+#define TPL_LOG_STORE_EMPATHY_LOGFILE_REGEX "\\d{8}.log"
+#define TPL_TYPE_LOG_STORE_EMPATHY \
+ (tpl_log_store_empathy_get_type ())
+#define TPL_LOG_STORE_EMPATHY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), TPL_TYPE_LOG_STORE_EMPATHY, \
+ TplLogStoreEmpathy))
+#define TPL_LOG_STORE_EMPATHY_CLASS(vtable) \
+ (G_TYPE_CHECK_CLASS_CAST ((vtable), TPL_TYPE_LOG_STORE_EMPATHY, \
+ TplLogStoreEmpathyClass))
+#define TPL_IS_LOG_STORE_EMPATHY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TPL_TYPE_LOG_STORE_EMPATHY))
+#define TPL_IS_LOG_STORE_EMPATHY_CLASS(vtable) \
+ (G_TYPE_CHECK_CLASS_TYPE ((vtable), TPL_TYPE_LOG_STORE_EMPATHY))
+#define TPL_LOG_STORE_EMPATHY_GET_CLASS(inst) \
+ (G_TYPE_INSTANCE_GET_CLASS ((inst), TPL_TYPE_LOG_STORE_EMPATHY, \
+ TplLogStoreEmpathyClass))
+typedef struct _TplLogStoreEmpathy TplLogStoreEmpathy;
+typedef struct _TplLogStoreEmpathyClass TplLogStoreEmpathyClass;
+
+struct _TplLogStoreEmpathy
+{
+ GObject parent;
+ gpointer priv;
+};
+
+struct _TplLogStoreEmpathyClass
+{
+ GObjectClass parent;
+};
+
+GType tpl_log_store_empathy_get_type (void);
+
+G_END_DECLS
+#endif /* __TPL_LOG_STORE_EMPATHY_H__ */
diff --git a/telepathy-logger/log-store.c b/telepathy-logger/log-store.c
new file mode 100644
index 0000000..03f98a3
--- /dev/null
+++ b/telepathy-logger/log-store.c
@@ -0,0 +1,197 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2008 Collabora Ltd.
+ *
+ * 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 St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ *
+ * Authors: Jonny Lamb <jonny.lamb@collabora.co.uk>
+ */
+
+#include "log-store.h"
+
+GType
+tpl_log_store_get_type (void)
+{
+ static GType type = 0;
+ if (type == 0)
+ {
+ static const GTypeInfo info = {
+ sizeof (TplLogStoreInterface),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ NULL, /* class_init */
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ 0,
+ 0, /* n_preallocs */
+ NULL /* instance_init */
+ };
+ type = g_type_register_static (G_TYPE_INTERFACE, "TplLogStore",
+ &info, 0);
+ }
+ return type;
+}
+
+const gchar *
+tpl_log_store_get_name (TplLogStore * self)
+{
+ if (!TPL_LOG_STORE_GET_INTERFACE (self)->get_name)
+ return NULL;
+
+ return TPL_LOG_STORE_GET_INTERFACE (self)->get_name (self);
+}
+
+gboolean
+tpl_log_store_exists (TplLogStore * self,
+ TpAccount * account,
+ const gchar * chat_id, gboolean chatroom)
+{
+ if (!TPL_LOG_STORE_GET_INTERFACE (self)->exists)
+ return FALSE;
+
+ return TPL_LOG_STORE_GET_INTERFACE (self)->exists (self, account, chat_id,
+ chatroom);
+}
+
+
+
+gboolean
+tpl_log_store_add_message (TplLogStore * self,
+ const gchar * chat_id,
+ gboolean chatroom,
+ TplLogEntry * message, GError ** error)
+{
+ if (!TPL_LOG_STORE_GET_INTERFACE (self)->add_message)
+ {
+ g_warning ("LogStore: add_message not implemented");
+ return FALSE;
+ }
+
+ return TPL_LOG_STORE_GET_INTERFACE (self)->add_message (self, chat_id,
+ chatroom, message,
+ error);
+}
+
+GList *
+tpl_log_store_get_dates (TplLogStore * self,
+ TpAccount * account,
+ const gchar * chat_id, gboolean chatroom)
+{
+ if (!TPL_LOG_STORE_GET_INTERFACE (self)->get_dates)
+ return NULL;
+
+ return TPL_LOG_STORE_GET_INTERFACE (self)->get_dates (self, account,
+ chat_id, chatroom);
+}
+
+GList *
+tpl_log_store_get_messages_for_date (TplLogStore * self,
+ TpAccount * account,
+ const gchar * chat_id,
+ gboolean chatroom, const gchar * date)
+{
+ if (!TPL_LOG_STORE_GET_INTERFACE (self)->get_messages_for_date)
+ return NULL;
+
+ return TPL_LOG_STORE_GET_INTERFACE (self)->get_messages_for_date (self,
+ account,
+ chat_id,
+ chatroom,
+ date);
+}
+
+GList *
+tpl_log_store_get_last_messages (TplLogStore * self,
+ TpAccount * account,
+ const gchar * chat_id, gboolean chatroom)
+{
+ if (!TPL_LOG_STORE_GET_INTERFACE (self)->get_last_messages)
+ return NULL;
+
+ return TPL_LOG_STORE_GET_INTERFACE (self)->get_last_messages (self, account,
+ chat_id,
+ chatroom);
+}
+
+GList *
+tpl_log_store_get_chats (TplLogStore * self, TpAccount * account)
+{
+ if (!TPL_LOG_STORE_GET_INTERFACE (self)->get_chats)
+ return NULL;
+
+ return TPL_LOG_STORE_GET_INTERFACE (self)->get_chats (self, account);
+}
+
+
+
+GList *
+tpl_log_store_search_in_identifier_chats_new (TplLogStore * self,
+ TpAccount * account,
+ gchar const *identifier,
+ const gchar * text)
+{
+ if (!TPL_LOG_STORE_GET_INTERFACE (self)->search_new)
+ return NULL;
+
+ return
+ TPL_LOG_STORE_GET_INTERFACE (self)->search_in_identifier_chats_new (self,
+ account,
+ identifier,
+ text);
+}
+
+
+GList *
+tpl_log_store_search_new (TplLogStore * self, const gchar * text)
+{
+ if (!TPL_LOG_STORE_GET_INTERFACE (self)->search_new)
+ return NULL;
+
+ return TPL_LOG_STORE_GET_INTERFACE (self)->search_new (self, text);
+}
+
+void
+tpl_log_store_ack_message (TplLogStore * self,
+ const gchar * chat_id,
+ gboolean chatroom, TplLogEntry * message)
+{
+ if (!TPL_LOG_STORE_GET_INTERFACE (self)->ack_message)
+ return;
+
+ TPL_LOG_STORE_GET_INTERFACE (self)->ack_message (self, chat_id, chatroom,
+ message);
+}
+
+GList *
+tpl_log_store_get_filtered_messages (TplLogStore * self,
+ TpAccount * account,
+ const gchar * chat_id,
+ gboolean chatroom,
+ guint num_messages,
+ TplLogMessageFilter filter,
+ gpointer user_data)
+{
+ if (!TPL_LOG_STORE_GET_INTERFACE (self)->get_filtered_messages)
+ return NULL;
+
+ return TPL_LOG_STORE_GET_INTERFACE (self)->get_filtered_messages (self,
+ account,
+ chat_id,
+ chatroom,
+ num_messages,
+ filter,
+ user_data);
+}
diff --git a/telepathy-logger/log-store.h b/telepathy-logger/log-store.h
new file mode 100644
index 0000000..f24f45c
--- /dev/null
+++ b/telepathy-logger/log-store.h
@@ -0,0 +1,115 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2008 Collabora Ltd.
+ *
+ * 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 St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ *
+ * Authors: Jonny Lamb <jonny.lamb@collabora.co.uk>
+ */
+
+#ifndef __TPL_LOG_STORE_H__
+#define __TPL_LOG_STORE_H__
+
+#include <glib-object.h>
+#include <telepathy-glib/account.h>
+
+#include <telepathy-logger/log-manager.h>
+#include <telepathy-logger/log-entry-text.h>
+
+G_BEGIN_DECLS
+#define TPL_TYPE_LOG_STORE (tpl_log_store_get_type ())
+#define TPL_LOG_STORE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), TPL_TYPE_LOG_STORE, \
+ TplLogStore))
+#define TPL_IS_LOG_STORE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TPL_TYPE_LOG_STORE))
+#define TPL_LOG_STORE_GET_INTERFACE(inst) \
+ (G_TYPE_INSTANCE_GET_INTERFACE ((inst), TPL_TYPE_LOG_STORE, \
+ TplLogStoreInterface))
+typedef struct _TplLogStore TplLogStore; /* dummy object */
+typedef struct _TplLogStoreInterface TplLogStoreInterface;
+
+struct _TplLogStoreInterface
+{
+ GTypeInterface parent;
+
+ const gchar *(*get_name) (TplLogStore * self);
+ gboolean (*exists) (TplLogStore * self, TpAccount * account,
+ const gchar * chat_id, gboolean chatroom);
+ gboolean (*add_message) (TplLogStore * self, const gchar * chat_id,
+ gboolean chatroom, TplLogEntry * message,
+ GError ** error);
+ GList *(*get_dates) (TplLogStore * self, TpAccount * account,
+ const gchar * chat_id, gboolean chatroom);
+ GList *(*get_messages_for_date) (TplLogStore * self, TpAccount * account,
+ const gchar * chat_id, gboolean chatroom,
+ const gchar * date);
+ GList *(*get_last_messages) (TplLogStore * self, TpAccount * account,
+ const gchar * chat_id, gboolean chatroom);
+ GList *(*get_chats) (TplLogStore * self, TpAccount * account);
+ GList *(*search_new) (TplLogStore * self, const gchar * text);
+ GList *(*search_in_identifier_chats_new) (TplLogStore * self,
+ TpAccount * account,
+ gchar const *identifier,
+ const gchar * text);
+ void (*ack_message) (TplLogStore * self, const gchar * chat_id,
+ gboolean chatroom, TplLogEntry * message);
+ GList *(*get_filtered_messages) (TplLogStore * self, TpAccount * account,
+ const gchar * chat_id, gboolean chatroom,
+ guint num_messages,
+ TplLogMessageFilter filter,
+ gpointer user_data);
+};
+
+GType tpl_log_store_get_type (void);
+
+const gchar *tpl_log_store_get_name (TplLogStore * self);
+gboolean tpl_log_store_exists (TplLogStore * self,
+ TpAccount * account, const gchar * chat_id,
+ gboolean chatroom);
+gboolean tpl_log_store_add_message (TplLogStore * self, const gchar * chat_id,
+ gboolean chatroom, TplLogEntry * message,
+ GError ** error);
+GList *tpl_log_store_get_dates (TplLogStore * self, TpAccount * account,
+ const gchar * chat_id, gboolean chatroom);
+GList *tpl_log_store_get_messages_for_date (TplLogStore * self,
+ TpAccount * account,
+ const gchar * chat_id,
+ gboolean chatroom,
+ const gchar * date);
+GList *tpl_log_store_get_last_messages (TplLogStore * self,
+ TpAccount * account,
+ const gchar * chat_id,
+ gboolean chatroom);
+GList *tpl_log_store_get_chats (TplLogStore * self, TpAccount * account);
+GList *tpl_log_store_search_in_identifier_chats_new (TplLogStore * self,
+ TpAccount * account,
+ gchar const *identifier,
+ const gchar * text);
+GList *tpl_log_store_search_new (TplLogStore * self, const gchar * text);
+void tpl_log_store_ack_message (TplLogStore * self,
+ const gchar * chat_id, gboolean chatroom,
+ TplLogEntry * message);
+GList *tpl_log_store_get_filtered_messages (TplLogStore * self,
+ TpAccount * account,
+ const gchar * chat_id,
+ gboolean chatroom,
+ guint num_messages,
+ TplLogMessageFilter filter,
+ gpointer user_data);
+
+G_END_DECLS
+#endif /* __TPL_LOG_STORE_H__ */
diff --git a/telepathy-logger/observer.c b/telepathy-logger/observer.c
new file mode 100644
index 0000000..03457d1
--- /dev/null
+++ b/telepathy-logger/observer.c
@@ -0,0 +1,411 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2009 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Cosimo Alfarano <cosimo.alfarano@collabora.co.uk>
+ */
+
+#include "observer.h"
+
+#include <glib.h>
+#include <telepathy-glib/interfaces.h>
+#include <telepathy-glib/channel.h>
+#include <telepathy-glib/gtypes.h>
+#include <telepathy-glib/dbus.h>
+#include <telepathy-glib/svc-generic.h>
+#include <telepathy-glib/svc-client.h>
+
+#include <telepathy-logger/channel.h>
+#include <telepathy-logger/channel-text.h>
+#include <telepathy-logger/log-manager.h>
+
+// TODO move to a member of TplObserver
+static TplLogManager *logmanager = NULL;
+
+static void tpl_observer_finalize (GObject * obj);
+static void tpl_observer_dispose (GObject * obj);
+
+static void observer_iface_init (gpointer, gpointer);
+
+G_DEFINE_TYPE_WITH_CODE (TplObserver, tpl_observer, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES,
+ tp_dbus_properties_mixin_iface_init);
+ G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CLIENT,
+ NULL);
+ G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CLIENT_OBSERVER,
+ observer_iface_init);
+ );
+
+static TplObserver *observer_singleton = NULL;
+static const char *client_interfaces[] = {
+ TP_IFACE_CLIENT_OBSERVER,
+ NULL
+};
+
+enum
+{
+ PROP_0,
+ PROP_INTERFACES,
+ PROP_CHANNEL_FILTER
+};
+
+
+static void
+_observe_channel_when_ready_cb (TpChannel * channel,
+ const GError * error, gpointer user_data)
+{
+ TplChannel *tpl_chan = TPL_CHANNEL (user_data);
+
+ if (error != NULL)
+ {
+ g_error ("%s\n", error->message);
+ g_error ("giving up observing channel '%s'", tpl_chan->channel_path);
+ g_object_unref (tpl_chan);
+ return;
+ }
+
+ tpl_channel_set_channel_type (tpl_chan,
+ tp_channel_get_channel_type
+ (tpl_chan->channel));
+
+ tpl_channel_register_to_observer (tpl_chan);
+}
+
+
+static void
+_get_ready_tp_channel (TpConnection * connection,
+ const GError * error, gpointer user_data)
+{
+ TplChannel *tpl_chan = TPL_CHANNEL (user_data);
+
+ tp_channel_call_when_ready (tpl_channel_get_channel (tpl_chan),
+ _observe_channel_when_ready_cb, tpl_chan);
+}
+
+static void
+tpl_observer_observe_channels (TpSvcClientObserver * self,
+ const char *account,
+ const char *connection,
+ const GPtrArray * channels,
+ const char *dispatch_op,
+ const GPtrArray * requests_satisfied,
+ GHashTable * observer_info,
+ DBusGMethodInvocation * context)
+{
+ TpAccount *tp_acc;
+ TpConnection *tp_conn;
+ TpDBusDaemon *tp_bus_daemon;
+ GError *error = NULL;
+
+ tp_bus_daemon = tp_dbus_daemon_dup (&error);
+ if (tp_bus_daemon == NULL)
+ {
+ g_error ("%s\n", error->message);
+ g_clear_error (&error);
+ g_error_free (error);
+ return;
+ }
+
+ tp_acc = tp_account_new (tp_bus_daemon, account, &error);
+ if (tp_acc == NULL)
+ {
+ g_error ("%s\n", error->message);
+ g_clear_error (&error);
+ g_error_free (error);
+ g_object_unref (tp_bus_daemon);
+ return;
+ }
+
+
+ tp_conn = tp_connection_new (tp_bus_daemon, NULL, connection, &error);
+ if (tp_conn == NULL)
+ {
+ g_error ("%s\n", error->message);
+ g_clear_error (&error);
+ g_error_free (error);
+ g_object_unref (tp_bus_daemon);
+ g_object_unref (tp_acc);
+ return;
+ }
+
+ /* channels is of type a(oa{sv}) */
+ for (guint i = 0; i < channels->len; i++)
+ {
+ GValueArray *channel = g_ptr_array_index (channels, i);
+ TpChannel *tp_chan;
+ TplChannel *tpl_chan;
+
+ gchar *path = g_value_get_boxed (g_value_array_get_nth (channel, 0));
+ // propertyNameStr/value hash
+ GHashTable *map =
+ g_value_get_boxed (g_value_array_get_nth (channel, 1));
+
+ tp_chan = tp_channel_new (tp_conn, path, NULL,
+ TP_UNKNOWN_HANDLE_TYPE, 0, &error);
+ if (tp_conn == NULL)
+ {
+ // log and skip to next channel
+ g_error ("%s", error->message);
+ g_clear_error (&error);
+ g_error_free (error);
+ error = NULL;
+ continue;
+ }
+
+ tpl_chan = tpl_channel_new (self);
+ tpl_channel_set_account (tpl_chan, tp_acc);
+ tpl_channel_set_account_path (tpl_chan, account);
+ tpl_channel_set_connection (tpl_chan, tp_conn);
+ tpl_channel_set_connection_path (tpl_chan, connection);
+ tpl_channel_set_channel (tpl_chan, tp_chan);
+ tpl_channel_set_channel_path (tpl_chan, path);
+ tpl_channel_set_channel_properties (tpl_chan, map);
+
+ tp_connection_call_when_ready (tp_conn,
+ _get_ready_tp_channel, tpl_chan);
+
+ }
+
+ g_object_unref (tp_acc);
+ g_object_unref (tp_conn);
+ g_object_unref (tp_bus_daemon);
+
+ tp_svc_client_observer_return_from_observe_channels (context);
+}
+
+static void
+tpl_observer_get_property (GObject * self,
+ guint property_id,
+ GValue * value, GParamSpec * pspec)
+{
+ switch (property_id)
+ {
+ GPtrArray *array;
+ GHashTable *map;
+ case PROP_INTERFACES:
+ g_value_set_boxed (value, client_interfaces);
+ break;
+
+ case PROP_CHANNEL_FILTER:
+
+ /* create an empty filter - which means all channels */
+ array = g_ptr_array_new ();
+ map = g_hash_table_new (NULL, NULL);
+
+ g_ptr_array_add (array, map);
+ g_value_set_boxed (value, array);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (self, property_id, pspec);
+ break;
+ }
+}
+
+/* Singleton Constructor */
+static GObject *
+tpl_observer_constructor (GType type, guint n_props,
+ GObjectConstructParam * props)
+{
+ GObject *retval;
+
+ if (observer_singleton)
+ {
+ retval = g_object_ref (observer_singleton);
+ }
+ else
+ {
+ retval = G_OBJECT_CLASS (tpl_observer_parent_class)->constructor
+ (type, n_props, props);
+
+ observer_singleton = TPL_OBSERVER (retval);
+ g_object_add_weak_pointer (retval, (gpointer *) & observer_singleton);
+ }
+
+ return retval;
+}
+
+
+static void
+tpl_observer_class_init (TplObserverClass * klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->constructor = tpl_observer_constructor;
+ object_class->finalize = tpl_observer_finalize;
+ object_class->dispose = tpl_observer_dispose;
+
+ /* D-Bus properties are exposed as GObject properties through the
+ * TpDBusPropertiesMixin */
+ /* properties on the Client interface */
+ static TpDBusPropertiesMixinPropImpl client_props[] = {
+ {"Interfaces", "interfaces", NULL},
+ {NULL}
+ };
+
+ /* properties on the Client.Observer interface */
+ static TpDBusPropertiesMixinPropImpl client_observer_props[] = {
+ {"ObserverChannelFilter", "channel-filter", NULL},
+ {NULL}
+ };
+
+ /* complete list of interfaces with properties */
+ static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = {
+ {TP_IFACE_CLIENT,
+ tp_dbus_properties_mixin_getter_gobject_properties,
+ NULL,
+ client_props},
+ {TP_IFACE_CLIENT_OBSERVER,
+ tp_dbus_properties_mixin_getter_gobject_properties,
+ NULL,
+ client_observer_props},
+ {NULL}
+ };
+ object_class->get_property = tpl_observer_get_property;
+
+ g_object_class_install_property (object_class, PROP_INTERFACES,
+ g_param_spec_boxed ("interfaces",
+ "Interfaces",
+ "Available D-Bus Interfaces",
+ G_TYPE_STRV,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (object_class, PROP_CHANNEL_FILTER,
+ g_param_spec_boxed ("channel-filter",
+ "Channel Filter",
+ "Filter for channels we observe",
+ TP_ARRAY_TYPE_CHANNEL_CLASS_LIST,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /* call our mixin class init */
+ klass->dbus_props_class.interfaces = prop_interfaces;
+ tp_dbus_properties_mixin_class_init (object_class,
+ G_STRUCT_OFFSET (TplObserverClass,
+ dbus_props_class));
+}
+
+
+static gboolean
+tpl_str_are_eq (gconstpointer data, gconstpointer data2)
+{
+ return g_strcmp0 (data, data2) ? FALSE : TRUE;
+}
+
+
+static void
+tpl_observer_init (TplObserver * self)
+{
+ DBusGConnection *bus;
+ TpDBusDaemon *tp_bus;
+ GError *error = NULL;
+
+ self->channel_map = g_hash_table_new_full (g_str_hash, tpl_str_are_eq,
+ g_free, g_object_unref);
+ logmanager = tpl_log_manager_dup_singleton ();
+
+ bus = tp_get_bus ();
+ tp_bus = tp_dbus_daemon_new (bus);
+
+ if (tp_dbus_daemon_request_name (tp_bus, TPL_OBSERVER_WELL_KNOWN_BUS_NAME,
+ TRUE, &error))
+ {
+ g_debug ("%s DBus well known name registered\n",
+ TPL_OBSERVER_WELL_KNOWN_BUS_NAME);
+ }
+ else
+ {
+ g_error ("Well Known name request error: %s\n", error->message);
+ g_clear_error (&error);
+ g_error_free (error);
+ }
+
+ dbus_g_connection_register_g_object (bus,
+ TPL_OBSERVER_OBJECT_PATH,
+ G_OBJECT (self));
+}
+
+static void
+observer_iface_init (gpointer g_iface, gpointer iface_data)
+{
+ TpSvcClientObserverClass *klass = (TpSvcClientObserverClass *) g_iface;
+
+ tp_svc_client_observer_implement_observe_channels (klass,
+ tpl_observer_observe_channels);
+}
+
+static void
+tpl_observer_dispose (GObject * obj)
+{
+ TplObserver *self = TPL_OBSERVER (obj);
+
+ g_debug ("TplObserver: disposing\n");
+
+ if (self->channel_map != NULL)
+ {
+ g_object_unref (self->channel_map);
+ self->channel_map = NULL;
+ }
+ if (logmanager != NULL)
+ {
+ g_object_unref (logmanager);
+ logmanager = NULL;
+ }
+
+ G_OBJECT_CLASS (tpl_observer_parent_class)->dispose (obj);
+
+ g_debug ("TplObserver: disposed\n");
+}
+
+static void
+tpl_observer_finalize (GObject * obj)
+{
+ //TplObserver *self = TPL_OBSERVER(obj);
+
+ g_debug ("TplObserver: finalizing\n");
+
+ G_OBJECT_CLASS (tpl_observer_parent_class)->finalize (obj);
+
+ g_debug ("TplObserver: finalized\n");
+}
+
+TplObserver *
+tpl_observer_new (void)
+{
+ return g_object_new (TYPE_TPL_OBSERVER, NULL);
+}
+
+
+GHashTable *
+tpl_observer_get_channel_map (TplObserver * self)
+{
+ g_return_val_if_fail (TPL_IS_OBSERVER (self), NULL);
+
+ return self->channel_map;
+}
+
+void
+tpl_observer_set_channel_map (TplObserver * self, GHashTable * data)
+{
+ g_return_if_fail (TPL_IS_OBSERVER (self));
+ //TODO check data validity
+
+ tpl_object_unref_if_not_null (self->channel_map);
+ self->channel_map = data;
+ tpl_object_ref_if_not_null (data);
+}
diff --git a/telepathy-logger/observer.h b/telepathy-logger/observer.h
new file mode 100644
index 0000000..798c674
--- /dev/null
+++ b/telepathy-logger/observer.h
@@ -0,0 +1,70 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2009 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Cosimo Alfarano <cosimo.alfarano@collabora.co.uk>
+ */
+
+#ifndef __TPL_OBSERVER_H__
+#define __TPL_OBSERVER_H__
+
+#include <glib-object.h>
+#include <telepathy-glib/dbus-properties-mixin.h>
+
+#define TP_IFACE_CHAN_TEXT "org.freedesktop.Telepathy.Channel.Type.Text"
+#define TPL_OBSERVER_WELL_KNOWN_BUS_NAME \
+ "org.freedesktop.Telepathy.Client.TelepathyLogger"
+#define TPL_OBSERVER_OBJECT_PATH \
+ "/org/freedesktop/Telepathy/Client/TelepathyLogger"
+
+
+G_BEGIN_DECLS
+#define TYPE_TPL_OBSERVER (tpl_observer_get_type ())
+#define TPL_OBSERVER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_TPL_OBSERVER, TplObserver))
+#define TPL_OBSERVER_CLASS(obj) (G_TYPE_CHECK_CLASS_CAST ((obj), TYPE_TPL_OBSERVER, TplObserverClass))
+#define TPL_IS_OBSERVER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_TPL_OBSERVER))
+#define TPL_IS_OBSERVER_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((obj), TYPE_TPL_OBSERVER))
+#define TPL_OBSERVER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_TPL_OBSERVER, TplObserverClass))
+typedef struct _TplObserver TplObserver;
+struct _TplObserver
+{
+ GObject parent;
+
+ /* private */
+
+ // mapping channel_path_str->Tpl<Interface>Channel instances
+ GHashTable *channel_map;
+};
+
+typedef struct _TplObserverClass TplObserverClass;
+struct _TplObserverClass
+{
+ GObjectClass parent_class;
+ TpDBusPropertiesMixinClass dbus_props_class;
+};
+
+GType tpl_observer_get_type (void);
+
+TplObserver *tpl_observer_new (void);
+
+void tpl_headless_logger_init (void);
+
+GHashTable *tpl_observer_get_channel_map (TplObserver * self);
+void tpl_observer_set_channel_map (TplObserver * self, GHashTable * data);
+
+G_END_DECLS
+#endif // __TPL_OBSERVER_H__
diff --git a/telepathy-logger/telepathy-logger.schemas b/telepathy-logger/telepathy-logger.schemas
new file mode 100644
index 0000000..511dc94
--- /dev/null
+++ b/telepathy-logger/telepathy-logger.schemas
@@ -0,0 +1,32 @@
+<gconfschemafile>
+ <schemalist>
+
+ <schema>
+ <key>/schemas/apps/telepathy-logger/disabling/global</key>
+ <applyto>/apps/telepathy-logger/disabling/global</applyto>
+ <owner>telepathy-logger</owner>
+ <type>bool</type>
+ <default>TRUE</default>
+ <locale name="C">
+ <short>Globally enable or to disable logging</short>
+ <long>Globally enable or disable the telepathy logging system.
+Setting it to "false" will completely disable any logging</long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/telepathy-logger/disabling/accounts/blocklist</key>
+ <applyto>/apps/telepathy-logger/disabling/accounts/blocklist</applyto>
+ <owner>telepathy-logger</owner>
+ <type>list</type>
+ <list_type>string</list_type>
+ <default>true</default>
+ <locale name="C">
+ <short>A list of accounts for which logging is disabled</short>
+ <long>Disables logging for the named accounts, when logging is
+globally enabled. Globally disabling logging will ignore this key.</long>
+ </locale>
+ </schema>
+
+</schemalist>
+</gconfschemafile>
diff --git a/telepathy-logger/utils.c b/telepathy-logger/utils.c
new file mode 100644
index 0000000..1f51efc
--- /dev/null
+++ b/telepathy-logger/utils.c
@@ -0,0 +1,40 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2009 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Cosimo Alfarano <cosimo.alfarano@collabora.co.uk>
+ */
+
+#include "utils.h"
+
+void
+tpl_object_unref_if_not_null (void *data)
+{
+ if (data && G_IS_OBJECT (data))
+ {
+ g_object_unref (data);
+ }
+}
+
+void
+tpl_object_ref_if_not_null (void *data)
+{
+ if (data && G_IS_OBJECT (data))
+ {
+ g_object_ref (data);
+ }
+}
diff --git a/telepathy-logger/utils.h b/telepathy-logger/utils.h
new file mode 100644
index 0000000..acf4740
--- /dev/null
+++ b/telepathy-logger/utils.h
@@ -0,0 +1,54 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2009 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Cosimo Alfarano <cosimo.alfarano@collabora.co.uk>
+ */
+
+#ifndef __TPL_UTILS_H__
+#define __TPL_UTILS_H__
+
+#include <glib-object.h>
+
+#define TPL_GET_PRIV(obj,type) ((type##Priv *) ((type *) obj)->priv)
+#define TPL_STR_EMPTY(x) ((x) == NULL || (x)[0] == '\0')
+
+/*
+#define tpl_object_ref_if_not_null(obj) if (obj && G_IS_OBJECT(obj)) \
+ g_object_ref(obj);
+#define tpl_object_unref_if_not_null(obj) if (obj && G_IS_OBJECT(obj)) \
+ g_object_unref(obj);
+*/
+void tpl_object_unref_if_not_null (void *data);
+void tpl_object_ref_if_not_null (void *data);
+
+#define tpl_call_with_err_if_fail(guard, obj, PREFIX, POSTFIX, msg, func, user_data) \
+ if (!(guard)) \
+ { \
+ if (func != NULL) \
+ { \
+ GError *e; \
+ e = g_error_new ( PREFIX ## _ERROR, \
+ PREFIX ## _ERROR_ ## POSTFIX, \
+ msg); \
+ func (obj, FALSE, e, user_data); \
+ g_error_free (e); \
+ } \
+ return; \
+ }
+
+#endif // __TPL_UTILS_H__