[tracker-miner-chatlog] Add Telepathy logger data migration



commit 7d1117e21fece3d7d59032570b01e026b4399183
Author: Carlos Garnacho <carlosg gnome org>
Date:   Thu Dec 24 01:27:45 2015 +0100

    Add Telepathy logger data migration
    
    This is meant to happen only once (which may take looooong).

 configure.ac        |   28 ++++
 src/Makefile.am     |    9 +
 src/logger-dumper.c |  410 +++++++++++++++++++++++++++++++++++++++++++++++++++
 src/logger-dumper.h |   36 +++++
 src/miner.c         |   71 +++++++++-
 src/observer.c      |   28 ++++
 6 files changed, 579 insertions(+), 3 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 5813a2b..0f4ec8d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -32,6 +32,30 @@ IT_PROG_INTLTOOL([0.40.0])
 # dependencies
 PKG_CHECK_MODULES(DEPS, [tracker-miner-1.0 telepathy-glib])
 
+# optional dependencies
+AC_ARG_ENABLE(migration,
+              AS_HELP_STRING([--enable-migration],
+                             [enable migration from telepathy-logger]),
+              [enable_migration=$enableval],
+              [enable_migration=yes])
+
+if test "x$enable_migration" != "xno" ; then
+   PKG_CHECK_MODULES(LOGGER,
+                    [telepathy-logger-0.2],
+                     [have_logger=yes],
+                     [have_logger=no])
+
+   AC_SUBST(LOGGER_CFLAGS)
+   AC_SUBST(LOGGER_LIBS)
+   AM_CONDITIONAL(HAVE_MIGRATION, test "$have_logger" = "yes")
+
+   if test "$have_logger" != "no" ; then
+      AC_DEFINE(HAVE_MIGRATION, [], [Define if we have telepathy-logger migration])
+   fi
+else
+   have_logger=no
+fi
+
 AC_CONFIG_FILES([
 Makefile
 data/Makefile
@@ -39,3 +63,7 @@ src/Makefile
 po/Makefile.in
 ])
 AC_OUTPUT
+
+echo "
+     Telepathy-logger migration: $have_logger
+"
diff --git a/src/Makefile.am b/src/Makefile.am
index d5d6e2d..ac80f1e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,6 +1,13 @@
 libexec_PROGRAMS = tracker-miner-chatlog
 
+if HAVE_MIGRATION
+migration_sources =            \
+       logger-dumper.c         \
+       logger-dumper.h
+endif
+
 tracker_miner_chatlog_SOURCES =        \
+       $(migration_sources)    \
        client-factory.c        \
        client-factory.h        \
        contact.c               \
@@ -28,7 +35,9 @@ tracker_miner_chatlog_SOURCES =       \
 tracker_miner_chatlog_CPPFLAGS =       \
     -DG_LOG_DOMAIN=\"Tmc\"     \
     -I$(top_srcdir)/src                \
+    $(LOGGER_CFLAGS)           \
     $(DEPS_CFLAGS)
 
 tracker_miner_chatlog_LDADD =  \
+    $(LOGGER_LIBS)             \
     $(DEPS_LIBS)
diff --git a/src/logger-dumper.c b/src/logger-dumper.c
new file mode 100644
index 0000000..f58ce34
--- /dev/null
+++ b/src/logger-dumper.c
@@ -0,0 +1,410 @@
+/*
+ * Copyright (C) 2015 Carlos Garnacho
+ *
+ * This library 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 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ *
+ * Author: Carlos Garnacho <carlosg gnome org>
+ */
+
+#include <telepathy-logger/telepathy-logger.h>
+
+#include "logger-dumper.h"
+#include "text-event.h"
+#include "contact.h"
+#include "room.h"
+#include "conversation.h"
+#include "entity-pool.h"
+
+typedef struct _TmcLoggerDumperPrivate TmcLoggerDumperPrivate;
+typedef struct _QueryOperation QueryOperation;
+
+struct _TmcLoggerDumper {
+       GObject parent_instance;
+};
+
+struct _QueryOperation {
+       TmcLoggerDumper *dumper;
+       TpAccount *account;
+       TplEntity *entity;
+       GList *dates;
+};
+
+struct _TmcLoggerDumperPrivate {
+       TplLogManager *log_manager;
+       GList *operations;
+       GList *accounts;
+
+       guint querying : 1;
+};
+
+enum {
+       TEXT_EVENT,
+       N_SIGNALS
+};
+
+static guint signals[N_SIGNALS] = { 0 };
+
+static gboolean tmc_logger_dumper_next_operation (TmcLoggerDumper *dumper);
+
+G_DEFINE_TYPE_WITH_PRIVATE (TmcLoggerDumper, tmc_logger_dumper, G_TYPE_OBJECT)
+
+static void
+tmc_logger_dumper_finalize (GObject *object)
+{
+       TmcLoggerDumper *dumper;
+       TmcLoggerDumperPrivate *priv;
+
+       dumper = TMC_LOGGER_DUMPER (object);
+       priv = tmc_logger_dumper_get_instance_private (dumper);
+
+       g_object_unref (priv->log_manager);
+
+       g_list_foreach (priv->accounts, (GFunc) g_object_unref, NULL);
+       g_list_free (priv->accounts);
+
+       G_OBJECT_CLASS (tmc_logger_dumper_parent_class)->finalize (object);
+}
+
+static void
+tmc_logger_dumper_class_init (TmcLoggerDumperClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+       object_class->finalize = tmc_logger_dumper_finalize;
+
+       signals[TEXT_EVENT] =
+               g_signal_new ("text-event",
+                             G_TYPE_FROM_CLASS (klass),
+                             G_SIGNAL_RUN_LAST,
+                             0, NULL, NULL,
+                             g_cclosure_marshal_VOID__OBJECT,
+                             G_TYPE_NONE, 1, TMC_TYPE_TEXT_EVENT);
+}
+
+static void
+tmc_logger_dumper_init (TmcLoggerDumper *dumper)
+{
+       TmcLoggerDumperPrivate *priv;
+
+       priv = tmc_logger_dumper_get_instance_private (dumper);
+       priv->log_manager = tpl_log_manager_dup_singleton ();
+}
+
+TmcLoggerDumper *
+tmc_logger_dumper_new (void)
+{
+       return g_object_new (TMC_TYPE_LOGGER_DUMPER, NULL);
+}
+
+static QueryOperation *
+query_operation_new (TmcLoggerDumper *dumper,
+                    TpAccount       *account,
+                    TplEntity       *entity)
+{
+       QueryOperation *op;
+
+       op = g_new0 (QueryOperation, 1);
+       op->dumper = dumper;
+       op->account = g_object_ref (account);
+       op->entity = g_object_ref (entity);
+
+       return op;
+}
+
+static void
+query_operation_free (QueryOperation *op)
+{
+       g_object_unref (op->account);
+       g_object_unref (op->entity);
+       g_list_foreach (op->dates, (GFunc) g_date_free, NULL);
+       g_list_free (op->dates);
+
+       g_free (op);
+}
+
+static TmcEntity *
+translate_contact (TplEntity *entity)
+{
+       TmcEntityPool *pool = tmc_entity_pool_contacts_get ();
+       TmcEntity *contact;
+
+       switch (tpl_entity_get_entity_type (entity)) {
+       case TPL_ENTITY_UNKNOWN:
+       case TPL_ENTITY_ROOM:
+               return NULL;
+       case TPL_ENTITY_SELF:
+               return tmc_contact_self_get ();
+       case TPL_ENTITY_CONTACT:
+               contact = tmc_entity_pool_lookup (pool, tpl_entity_get_alias (entity));
+
+               if (!contact) {
+                       contact = tmc_contact_new (tpl_entity_get_alias (entity),
+                                                  "irc");
+                       tmc_entity_pool_add (pool, contact);
+               }
+
+               return contact;
+       }
+}
+
+static TmcEntity *
+translate_channel (QueryOperation *op)
+{
+       TmcEntityPool *pool = tmc_entity_pool_channels_get ();
+       TmcEntity *channel;
+
+       channel = tmc_entity_pool_lookup (pool, tpl_entity_get_alias (op->entity));
+
+       if (!channel) {
+               switch (tpl_entity_get_entity_type (op->entity)) {
+               case TPL_ENTITY_UNKNOWN:
+               case TPL_ENTITY_SELF:
+                       return NULL;
+               case TPL_ENTITY_CONTACT:
+                       channel = tmc_conversation_new (TMC_CONTACT (translate_contact (op->entity)));
+                       break;
+               case TPL_ENTITY_ROOM:
+                       channel = tmc_room_new (tpl_entity_get_alias (op->entity),
+                                       "irc");
+                       break;
+               }
+
+               tmc_entity_pool_add (pool, channel);
+       }
+
+       return channel;
+}
+
+static void
+tmc_logger_dumper_emit_event (TmcLoggerDumper *dumper,
+                             TpAccount       *account,
+                             TplEntity       *entity,
+                             TplTextEvent    *event)
+{
+       TmcLoggerDumperPrivate *priv;
+       QueryOperation *op;
+       TmcTextEvent *text_event;
+       TmcEntity *from, *to, *channel;
+       GList *to_list = NULL;
+
+       priv = tmc_logger_dumper_get_instance_private (dumper);
+       op = priv->operations->data;
+
+       channel = translate_channel (op);
+       from = translate_contact (tpl_event_get_sender (TPL_EVENT (event)));
+       to = translate_contact (tpl_event_get_receiver (TPL_EVENT (event)));
+
+       if (to) {
+               to_list = g_list_prepend (to_list, to);
+       }
+
+       text_event = tmc_text_event_new (channel, from, to_list,
+                                        tpl_text_event_get_message (event),
+                                        tpl_event_get_timestamp (TPL_EVENT (event)));
+       g_signal_emit (dumper, signals[TEXT_EVENT], 0, text_event);
+       g_object_unref (text_event);
+}
+
+static void
+get_date_events_async_cb (GObject      *object,
+                         GAsyncResult *res,
+                         gpointer      user_data)
+{
+       TmcLoggerDumper *dumper = user_data;
+       TmcLoggerDumperPrivate *priv = tmc_logger_dumper_get_instance_private (dumper);
+       QueryOperation *op = priv->operations->data;
+       GError *error = NULL;
+       GList *events, *l;
+
+       if (!tpl_log_manager_get_events_for_date_finish (TPL_LOG_MANAGER (object),
+                                                        res, &events, &error)) {
+               g_warning ("Could not get events for date: %s",
+                          error->message);
+       } else {
+               for (l = events; l; l = l->next) {
+                       tmc_logger_dumper_emit_event (dumper, op->account,
+                                                     op->entity, l->data);
+                       g_object_unref (l->data);
+               }
+
+               g_list_free (events);
+       }
+
+       tmc_logger_dumper_next_operation (dumper);
+}
+
+static void
+get_entity_dates_async_cb (GObject      *object,
+                          GAsyncResult *res,
+                          gpointer      user_data)
+{
+       TmcLoggerDumper *dumper = user_data;
+       TmcLoggerDumperPrivate *priv = tmc_logger_dumper_get_instance_private (dumper);
+       GError *error = NULL;
+       QueryOperation *op;
+
+       op = priv->operations->data;
+
+       if (!tpl_log_manager_get_dates_finish (TPL_LOG_MANAGER (object),
+                                              res, &op->dates, &error)) {
+               g_warning ("Could not get dates for entity: %s",
+                          error->message);
+       }
+
+       tmc_logger_dumper_next_operation (dumper);
+}
+
+static void
+get_account_entities_async_cb (GObject      *object,
+                              GAsyncResult *res,
+                              gpointer      user_data)
+{
+       TmcLoggerDumper *dumper = user_data;
+       TmcLoggerDumperPrivate *priv;
+       GList *l, *entities = NULL;
+       GError *error = NULL;
+       TpAccount *account;
+
+       priv = tmc_logger_dumper_get_instance_private (dumper);
+       account = priv->accounts->data;
+       priv->accounts = g_list_remove (priv->accounts, account);
+
+       if (!tpl_log_manager_get_entities_finish (TPL_LOG_MANAGER (object),
+                                                 res, &entities, &error)) {
+               g_warning ("Could not get entities for account: %s",
+                          error->message);
+       } else {
+               for (l = entities; l; l = l->next) {
+                       TplEntity *entity = l->data;
+                       QueryOperation *op;
+
+                       op = query_operation_new (dumper, account, entity);
+                       priv->operations = g_list_prepend (priv->operations, op);
+                       g_object_unref (entity);
+               }
+
+               g_list_free (entities);
+       }
+
+       tmc_logger_dumper_next_operation (dumper);
+       g_object_unref (account);
+}
+
+static gboolean
+tmc_logger_dumper_query_date_events (TmcLoggerDumper *dumper)
+{
+       TmcLoggerDumperPrivate *priv = tmc_logger_dumper_get_instance_private (dumper);
+       QueryOperation *op;
+       GDate *date;
+       GList *elem;
+
+       if (!priv->operations)
+               return FALSE;
+
+       op = priv->operations->data;
+
+       if (!op->dates)
+               return FALSE;
+
+       elem = op->dates;
+       date = elem->data;
+       op->dates = op->dates->next;
+       g_list_free1 (elem);
+
+       tpl_log_manager_get_events_for_date_async (priv->log_manager,
+                                                  op->account, op->entity,
+                                                  TPL_EVENT_MASK_TEXT, date,
+                                                  get_date_events_async_cb,
+                                                  dumper);
+       g_date_free (date);
+
+       return TRUE;
+}
+
+static gboolean
+tmc_logger_dumper_query_next_entity (TmcLoggerDumper *dumper)
+{
+       TmcLoggerDumperPrivate *priv = tmc_logger_dumper_get_instance_private (dumper);
+       QueryOperation *op;
+
+       if (!priv->operations)
+               return FALSE;
+
+       op = priv->operations->data;
+       tpl_log_manager_get_dates_async (priv->log_manager,
+                                        op->account, op->entity,
+                                        TPL_EVENT_MASK_TEXT,
+                                        get_entity_dates_async_cb,
+                                        dumper);
+       return TRUE;
+}
+
+static gboolean
+tmc_logger_dumper_query_next_account (TmcLoggerDumper *dumper)
+{
+       TmcLoggerDumperPrivate *priv;
+
+       priv = tmc_logger_dumper_get_instance_private (dumper);
+       priv->querying = priv->accounts != NULL;
+
+       if (priv->accounts) {
+               tpl_log_manager_get_entities_async (priv->log_manager,
+                                                   priv->accounts->data,
+                                                   get_account_entities_async_cb,
+                                                   dumper);
+       }
+
+       return priv->querying;
+}
+
+static gboolean
+tmc_logger_dumper_next_operation (TmcLoggerDumper *dumper)
+{
+       TmcLoggerDumperPrivate *priv = tmc_logger_dumper_get_instance_private (dumper);
+       QueryOperation *op;
+
+       if (!priv->operations)
+               return tmc_logger_dumper_query_next_account (dumper);
+
+       op = priv->operations->data;
+
+       if (op->dates) {
+               return tmc_logger_dumper_query_date_events (dumper);
+       } else {
+               priv->operations = g_list_remove (priv->operations, op);
+               query_operation_free (op);
+
+               return tmc_logger_dumper_query_next_entity (dumper);
+       }
+}
+
+void
+tmc_logger_dumper_add_account (TmcLoggerDumper *dumper,
+                              TpAccount       *account)
+{
+       TmcLoggerDumperPrivate *priv;
+
+       priv = tmc_logger_dumper_get_instance_private (dumper);
+
+       if (g_list_find (priv->accounts, account))
+               return;
+
+       priv->accounts = g_list_prepend (priv->accounts,
+                                        g_object_ref (account));
+
+       if (!priv->querying)
+               tmc_logger_dumper_next_operation (dumper);
+}
diff --git a/src/logger-dumper.h b/src/logger-dumper.h
new file mode 100644
index 0000000..ff0a124
--- /dev/null
+++ b/src/logger-dumper.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2015 Carlos Garnacho
+ *
+ * This library 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 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ *
+ * Author: Carlos Garnacho <carlosg gnome org>
+ */
+
+#ifndef __TMC_LOGGER_DUMPER_H__
+#define __TMC_LOGGER_DUMPER_H__
+
+#include <glib-object.h>
+#include <telepathy-glib/telepathy-glib.h>
+
+#define TMC_TYPE_LOGGER_DUMPER (tmc_logger_dumper_get_type ())
+
+G_DECLARE_FINAL_TYPE (TmcLoggerDumper, tmc_logger_dumper, TMC, LOGGER_DUMPER, GObject)
+
+TmcLoggerDumper * tmc_logger_dumper_new         (void);
+void              tmc_logger_dumper_add_account (TmcLoggerDumper *dumper,
+                                                TpAccount       *account);
+
+#endif /* __TMC_LOGGER_DUMPER_H__ */
diff --git a/src/miner.c b/src/miner.c
index 33d6cfc..bd6ca96 100644
--- a/src/miner.c
+++ b/src/miner.c
@@ -19,6 +19,8 @@
  * Author: Carlos Garnacho <carlosg gnome org>
  */
 
+#include "config.h"
+
 #include "client-factory.h"
 #include "observer.h"
 #include "text-event.h"
@@ -27,7 +29,13 @@
 #include "conversation.h"
 #include "miner.h"
 
+#ifdef HAVE_MIGRATION
+#include "logger-dumper.h"
+#endif
+
 #define GRAPH_URN "urn:uuid:5f15c02c-bede-06c7-413f-7bae48712d3a"
+#define TRANSACTION_LIMIT 10000
+#define TP_MIGRATION_FILENAME "tracker-miner-chatlog.tp-migrated"
 
 typedef struct _TmcMinerPrivate TmcMinerPrivate;
 typedef struct _Transaction Transaction;
@@ -63,6 +71,10 @@ struct _TmcMinerPrivate {
        TmcClientFactory *client_factory;
        TmcObserver *observer;
 
+#ifdef HAVE_MIGRATION
+       TmcLoggerDumper *dumper;
+#endif
+
        GHashTable *room_urn_cache;
        GHashTable *contact_urn_cache;
 
@@ -105,6 +117,10 @@ tmc_miner_finalize (GObject *object)
        g_object_unref (priv->client_factory);
        g_object_unref (priv->dbus);
 
+#ifdef HAVE_MIGRATION
+       g_object_unref (priv->dumper);
+#endif
+
        G_OBJECT_CLASS (tmc_miner_parent_class)->finalize (object);
 }
 
@@ -596,10 +612,27 @@ idle_flush_cb (Transaction *transaction)
 {
        TmcMiner *miner = transaction->miner;
        TmcMinerPrivate *priv = tmc_miner_get_instance_private (miner);
+       gint i;
+
+       g_debug ("Starting transaction, %ld elements remaining", priv->events->len);
+
+       if (priv->events->len < TRANSACTION_LIMIT) {
+               /* Transfer events to the transaction */
+               transaction->events = priv->events;
+               priv->events = NULL;
+       } else {
+               /* Make a partial copy */
+               transaction->events =
+                       g_ptr_array_new_with_free_func (g_object_unref);
+
+               for (i = 0; i < TRANSACTION_LIMIT; i++) {
+                       g_ptr_array_add (transaction->events,
+                                        g_object_ref (g_ptr_array_index (priv->events, i)));
+               }
+
+               g_ptr_array_remove_range (priv->events, 0, TRANSACTION_LIMIT);
+       }
 
-       /* Transfer events to the transaction */
-       transaction->events = priv->events;
-       priv->events = NULL;
        priv->flushing = TRUE;
        priv->flush_idle_id = 0;
 
@@ -724,6 +757,18 @@ populate_contact_urn_cache (TmcMiner      *miner,
        return (*error) == NULL;
 }
 
+#ifdef HAVE_MIGRATION
+static void
+observer_account_added (TmcMiner    *miner,
+                       TpAccount   *account,
+                       TmcObserver *observer)
+{
+       TmcMinerPrivate *priv = tmc_miner_get_instance_private (miner);
+
+       tmc_logger_dumper_add_account (priv->dumper, account);
+}
+#endif
+
 static gboolean
 tmc_miner_initable_init (GInitable     *initable,
                          GCancellable  *cancellable,
@@ -732,6 +777,9 @@ tmc_miner_initable_init (GInitable     *initable,
        TmcMiner *miner = TMC_MINER (initable);
        TmcMinerPrivate *priv = tmc_miner_get_instance_private (miner);
        GInitableIface *parent_iface;
+#ifdef HAVE_MIGRATION
+       gchar *filename;
+#endif
 
        parent_iface = g_type_interface_peek_parent (G_INITABLE_GET_IFACE (initable));
 
@@ -748,6 +796,23 @@ tmc_miner_initable_init (GInitable     *initable,
        g_signal_connect_swapped (priv->observer, "text-event",
                                  G_CALLBACK (handle_text_event), miner);
 
+#ifdef HAVE_MIGRATION
+       filename = g_build_filename (g_get_user_cache_dir (), "tracker",
+                                    "tracker-miner-chatlog.tp-migration", NULL);
+
+       if (!g_file_test (filename, G_FILE_TEST_EXISTS)) {
+               priv->dumper = tmc_logger_dumper_new ();
+               g_signal_connect_swapped (priv->dumper, "text-event",
+                                         G_CALLBACK (handle_text_event), miner);
+               g_signal_connect_swapped (priv->observer, "account",
+                                         G_CALLBACK (observer_account_added), miner);
+
+               g_file_set_contents (filename, "", -1, NULL);
+       }
+
+       g_free (filename);
+#endif
+
        if (!tp_base_client_register (TP_BASE_CLIENT (priv->observer), error))
                return FALSE;
 
diff --git a/src/observer.c b/src/observer.c
index b1690d4..e8542f0 100644
--- a/src/observer.c
+++ b/src/observer.c
@@ -34,9 +34,11 @@ typedef struct _TmcObserverPrivate TmcObserverPrivate;
 struct _TmcObserverPrivate {
        GList *channels;
        GRegex *recipients_regex;
+       GList *accounts;
 };
 
 enum {
+       ACCOUNT,
        TEXT_EVENT,
        N_SIGNALS
 };
@@ -55,6 +57,9 @@ tmc_observer_finalize (GObject *object)
        g_list_free (priv->channels);
        g_regex_unref (priv->recipients_regex);
 
+       g_list_foreach (priv->accounts, (GFunc) g_object_unref, NULL);
+       g_list_free (priv->accounts);
+
        G_OBJECT_CLASS (tmc_observer_parent_class)->finalize (object);
 }
 
@@ -221,6 +226,20 @@ register_channel (TmcObserver *observer,
 }
 
 static void
+tmc_observer_manage_account (TmcObserver *observer,
+                            TpAccount   *account)
+{
+       TmcObserverPrivate *priv = tmc_observer_get_instance_private (observer);
+
+       if (g_list_find (priv->accounts, account))
+               return;
+
+       priv->accounts = g_list_prepend (priv->accounts,
+                                        g_object_ref (account));
+       g_signal_emit (observer, signals[ACCOUNT], 0, account);
+}
+
+static void
 tmc_observer_observe_channels (TpBaseClient               *client,
                               TpAccount                  *account,
                               TpConnection               *connection,
@@ -232,6 +251,8 @@ tmc_observer_observe_channels (TpBaseClient               *client,
        TmcObserver *self = TMC_OBSERVER (client);
        GList *l;
 
+       tmc_observer_manage_account (self, account);
+
        for (l = channels; l != NULL; l = l->next)
                register_channel (self, l->data);
 
@@ -257,6 +278,13 @@ tmc_observer_class_init (TmcObserverClass *klass)
                              0, NULL, NULL,
                              g_cclosure_marshal_VOID__OBJECT,
                              G_TYPE_NONE, 1, TMC_TYPE_TEXT_EVENT);
+       signals[ACCOUNT] =
+               g_signal_new ("account",
+                             G_TYPE_FROM_CLASS (klass),
+                             G_SIGNAL_RUN_LAST,
+                             0, NULL, NULL,
+                             g_cclosure_marshal_VOID__OBJECT,
+                             G_TYPE_NONE, 1, TP_TYPE_ACCOUNT);
 }
 
 static void


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]