]> git.0d.be Git - empathy.git/blobdiff - libempathy/empathy-log-manager.c
empathy-tp-tube: remove initiator and type member variables as they are not used
[empathy.git] / libempathy / empathy-log-manager.c
index c9b5a304932c2c2265810ef666c3fb36bd1d364c..e2423ebf2c2b098fb45bb68ca264d253a5f39d0e 100644 (file)
 #include <stdlib.h>
 #include <glib/gstdio.h>
 
+#include <telepathy-glib/util.h>
+
 #include "empathy-log-manager.h"
-#include "empathy-log-source-empathy.h"
-#include "empathy-log-source.h"
+#include "empathy-log-store-empathy.h"
+#include "empathy-log-store.h"
+#include "empathy-tp-chat.h"
 #include "empathy-utils.h"
 
 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyLogManager)
 typedef struct
 {
-  GList *sources;
+  GList *stores;
 } EmpathyLogManagerPriv;
 
 G_DEFINE_TYPE (EmpathyLogManager, empathy_log_manager, G_TYPE_OBJECT);
 
 static EmpathyLogManager * manager_singleton = NULL;
 
-static void
-empathy_log_manager_init (EmpathyLogManager *manager)
-{
-  EmpathyLogManagerPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (manager,
-      EMPATHY_TYPE_LOG_MANAGER, EmpathyLogManagerPriv);
-  manager->priv = priv;
-}
-
 static void
 log_manager_finalize (GObject *object)
 {
   EmpathyLogManagerPriv *priv;
-  GList *l;
 
   priv = GET_PRIV (object);
 
-  for (l = priv->sources; l; l = l->next)
-    {
-      EmpathyLogSource *source = (EmpathyLogSource *) l->data;
-      g_object_unref (source);
-    }
-
-  g_list_free (priv->sources);
+  g_list_foreach (priv->stores, (GFunc) g_object_unref, NULL);
+  g_list_free (priv->stores);
 }
 
 static GObject *
@@ -77,6 +66,7 @@ log_manager_constructor (GType type,
                          GObjectConstructParam *props)
 {
   GObject *retval;
+  EmpathyLogManagerPriv *priv;
 
   if (manager_singleton)
     {
@@ -92,8 +82,8 @@ log_manager_constructor (GType type,
 
       priv = GET_PRIV (manager_singleton);
 
-      priv->sources = g_list_append (priv->sources,
-          empathy_log_source_empathy_get_source ());
+      priv->stores = g_list_append (priv->stores,
+          g_object_new (EMPATHY_TYPE_LOG_STORE_EMPATHY, NULL));
     }
 
   return retval;
@@ -104,6 +94,7 @@ empathy_log_manager_class_init (EmpathyLogManagerClass *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 (EmpathyLogManagerPriv));
@@ -115,16 +106,7 @@ empathy_log_manager_init (EmpathyLogManager *manager)
   EmpathyLogManagerPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (manager,
       EMPATHY_TYPE_LOG_MANAGER, EmpathyLogManagerPriv);
 
-  priv->sources = g_list_append (priv->sources,
-      g_object_new (EMPATHY_TYPE_LOG_SOURCE_EMPATHY, NULL));
-
-/*  priv->sources = g_list_append (priv->sources,
-      g_object_new (EMPATHY_LOG_SOURCE_PIDGIN, NULL));*/
-
   manager->priv = priv;
-
-  priv->sources = g_list_append (priv->sources,
-      empathy_log_source_empathy_get_source ());
 }
 
 EmpathyLogManager *
@@ -133,26 +115,44 @@ empathy_log_manager_dup_singleton (void)
   return g_object_new (EMPATHY_TYPE_LOG_MANAGER, NULL);
 }
 
-void
+gboolean
 empathy_log_manager_add_message (EmpathyLogManager *manager,
                                  const gchar *chat_id,
                                  gboolean chatroom,
-                                 EmpathyMessage *message)
+                                 EmpathyMessage *message,
+                                 GError **error)
 {
   EmpathyLogManagerPriv *priv;
   GList *l;
+  gboolean out = FALSE;
+  gboolean found = FALSE;
 
-  g_return_if_fail (EMPATHY_IS_LOG_MANAGER (manager));
-  g_return_if_fail (chat_id != NULL);
-  g_return_if_fail (EMPATHY_IS_MESSAGE (message));
+  /* TODO: When multiple log stores appear with add_message implementations
+   * make this customisable. */
+  const gchar *add_store = "Empathy";
+
+  g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), FALSE);
+  g_return_val_if_fail (chat_id != NULL, FALSE);
+  g_return_val_if_fail (EMPATHY_IS_MESSAGE (message), FALSE);
 
   priv = GET_PRIV (manager);
 
-  for (l = priv->sources; l; l = l->next)
+  for (l = priv->stores; l; l = g_list_next (l))
     {
-      empathy_log_source_add_message (EMPATHY_LOG_SOURCE (l->data),
-          chat_id, chatroom, message);
+      if (!tp_strdiff (empathy_log_store_get_name (
+              EMPATHY_LOG_STORE (l->data)), add_store))
+        {
+          out = empathy_log_store_add_message (EMPATHY_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
@@ -170,9 +170,9 @@ empathy_log_manager_exists (EmpathyLogManager *manager,
 
   priv = GET_PRIV (manager);
 
-  for (l = priv->sources; l; l = l->next)
+  for (l = priv->stores; l; l = g_list_next (l))
     {
-      if (empathy_log_source_exists (EMPATHY_LOG_SOURCE (l->data),
+      if (empathy_log_store_exists (EMPATHY_LOG_STORE (l->data),
             account, chat_id, chatroom))
         return TRUE;
     }
@@ -180,17 +180,6 @@ empathy_log_manager_exists (EmpathyLogManager *manager,
   return FALSE;
 }
 
-static void
-log_manager_get_dates_foreach (gpointer data,
-                               gpointer user_data)
-{
-  /* g_list_first is needed in case an older date was last inserted */
-  GList *orig = g_list_first (user_data);
-
-  if (g_list_find_custom (orig, data, (GCompareFunc) strcmp))
-    orig = g_list_insert_sorted (orig, g_strdup (data), (GCompareFunc) strcmp);
-}
-
 GList *
 empathy_log_manager_get_dates (EmpathyLogManager *manager,
                                McAccount *account,
@@ -206,23 +195,22 @@ empathy_log_manager_get_dates (EmpathyLogManager *manager,
 
   priv = GET_PRIV (manager);
 
-  for (l = priv->sources; l; l = l->next)
+  for (l = priv->stores; l; l = g_list_next (l))
     {
-      EmpathyLogSource *source = EMPATHY_LOG_SOURCE (l->data);
+      EmpathyLogStore *store = EMPATHY_LOG_STORE (l->data);
+      GList *new;
 
-      if (!out)
-        out = empathy_log_source_get_dates (source, account, chat_id, chatroom);
-      else
+      /* Insert dates of each store in the out list. Keep the out list sorted
+       * and avoid to insert dups. */
+      new = empathy_log_store_get_dates (store, account, chat_id, chatroom);
+      while (new)
         {
-          GList *new = empathy_log_source_get_dates (source, account, chat_id,
-              chatroom);
-          g_list_foreach (new, log_manager_get_dates_foreach, out);
-
-          g_list_foreach (new, (GFunc) g_free, NULL);
-          g_list_free (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);
 
-          /* Similar reason for using g_list_first here as before */
-          out = g_list_first (out);
+          new = g_list_delete_link (new, new);
         }
     }
 
@@ -245,46 +233,91 @@ empathy_log_manager_get_messages_for_date (EmpathyLogManager *manager,
 
   priv = GET_PRIV (manager);
 
-  for (l = priv->sources; l; l = l->next)
+  for (l = priv->stores; l; l = g_list_next (l))
     {
-      EmpathyLogSource *source = EMPATHY_LOG_SOURCE (l->data);
-
-      if (!out)
-        out = empathy_log_source_get_messages_for_date (source, account,
-            chat_id, chatroom, date);
-      else
-        out = g_list_concat (out, empathy_log_source_get_messages_for_date (
-              source, account, chat_id, chatroom, date));
+      EmpathyLogStore *store = EMPATHY_LOG_STORE (l->data);
+
+      out = g_list_concat (out, empathy_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)
+{
+       EmpathyMessage *one = (EmpathyMessage *) a;
+       EmpathyMessage *two = (EmpathyMessage *) b;
+       time_t one_time, two_time;
+
+       one_time = empathy_message_get_timestamp (one);
+       two_time = empathy_message_get_timestamp (two);
+
+        /* Return -1 of message1 is older than message2 */
+       return one_time < two_time ? -1 : one_time - two_time;
+}
+
 GList *
-empathy_log_manager_get_last_messages (EmpathyLogManager *manager,
-                                       McAccount *account,
-                                       const gchar *chat_id,
-                                       gboolean chatroom)
+empathy_log_manager_get_filtered_messages (EmpathyLogManager *manager,
+                                          McAccount *account,
+                                          const gchar *chat_id,
+                                          gboolean chatroom,
+                                          guint num_messages,
+                                          EmpathyLogMessageFilter filter,
+                                          gpointer user_data)
 {
-  GList *messages = NULL;
-  GList *dates;
+  EmpathyLogManagerPriv *priv;
+  GList *out = NULL;
   GList *l;
+  guint i = 0;
 
   g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), NULL);
   g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
   g_return_val_if_fail (chat_id != NULL, NULL);
 
-  dates = empathy_log_manager_get_dates (manager, account, chat_id, chatroom);
+  priv = GET_PRIV (manager);
 
-  l = g_list_last (dates);
-  if (l)
-    messages = empathy_log_manager_get_messages_for_date (manager, account,
-        chat_id, chatroom, l->data);
+  /* 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))
+    {
+      EmpathyLogStore *store = EMPATHY_LOG_STORE (l->data);
+      GList *new;
 
-  g_list_foreach (dates, (GFunc) g_free, NULL);
-  g_list_free (dates);
+      new = empathy_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 messages;
+  return out;
 }
 
 GList *
@@ -299,15 +332,12 @@ empathy_log_manager_get_chats (EmpathyLogManager *manager,
 
   priv = GET_PRIV (manager);
 
-  for (l = priv->sources; l; l = l->next)
+  for (l = priv->stores; l; l = g_list_next (l))
     {
-      EmpathyLogSource *source = EMPATHY_LOG_SOURCE (l->data);
+      EmpathyLogStore *store = EMPATHY_LOG_STORE (l->data);
 
-      if (!out)
-        out = empathy_log_source_get_chats (source, account);
-      else
-        out = g_list_concat (out,
-            empathy_log_source_get_chats (source, account));
+      out = g_list_concat (out,
+          empathy_log_store_get_chats (store, account));
     }
 
   return out;
@@ -325,15 +355,12 @@ empathy_log_manager_search_new (EmpathyLogManager *manager,
 
   priv = GET_PRIV (manager);
 
-  for (l = priv->sources; l; l = l->next)
+  for (l = priv->stores; l; l = g_list_next (l))
     {
-      EmpathyLogSource *source = EMPATHY_LOG_SOURCE (l->data);
+      EmpathyLogStore *store = EMPATHY_LOG_STORE (l->data);
 
-      if (!out)
-        out = empathy_log_source_search_new (source, text);
-      else
-        out = g_list_concat (out,
-            empathy_log_source_search_new (source, text));
+      out = g_list_concat (out,
+          empathy_log_store_search_new (store, text));
     }
 
   return out;
@@ -342,7 +369,7 @@ empathy_log_manager_search_new (EmpathyLogManager *manager,
 void
 empathy_log_manager_search_hit_free (EmpathyLogSearchHit *hit)
 {
-  if (hit->account)
+  if (hit->account != NULL)
     g_object_unref (hit->account);
 
   g_free (hit->date);
@@ -357,7 +384,7 @@ empathy_log_manager_search_free (GList *hits)
 {
   GList *l;
 
-  for (l = hits; l; l = l->next)
+  for (l = hits; l; l = g_list_next (l))
     {
       empathy_log_manager_search_hit_free (l->data);
     }
@@ -375,3 +402,58 @@ empathy_log_manager_get_date_readable (const gchar *date)
 
   return empathy_time_to_string_local (t, "%a %d %b %Y");
 }
+
+static void
+log_manager_chat_received_message_cb (EmpathyTpChat *tp_chat,
+                                      EmpathyMessage *message,
+                                      EmpathyLogManager *log_manager)
+{
+  GError *error = NULL;
+  TpHandleType handle_type;
+  TpChannel *channel;
+
+  channel = empathy_tp_chat_get_channel (tp_chat);
+  tp_channel_get_handle (channel, &handle_type);
+
+  if (!empathy_log_manager_add_message (log_manager,
+        tp_channel_get_identifier (channel),
+        handle_type == TP_HANDLE_TYPE_ROOM,
+        message, &error))
+    {
+      DEBUG ("Failed to write message: %s",
+          error ? error->message : "No error message");
+
+      if (error != NULL)
+        g_error_free (error);
+    }
+}
+
+static void
+log_manager_dispatcher_observe_cb (EmpathyDispatcher *dispatcher,
+                                   EmpathyDispatchOperation *operation,
+                                   EmpathyLogManager *log_manager)
+{
+  GQuark channel_type;
+
+  channel_type = empathy_dispatch_operation_get_channel_type_id (operation);
+
+  if (channel_type == TP_IFACE_QUARK_CHANNEL_TYPE_TEXT)
+    {
+      EmpathyTpChat *tp_chat;
+
+      tp_chat = EMPATHY_TP_CHAT (
+          empathy_dispatch_operation_get_channel_wrapper (operation));
+
+      g_signal_connect (tp_chat, "message-received",
+          G_CALLBACK (log_manager_chat_received_message_cb), log_manager);
+    }
+}
+
+
+void
+empathy_log_manager_observe (EmpathyLogManager *log_manager,
+                             EmpathyDispatcher *dispatcher)
+{
+  g_signal_connect (dispatcher, "observe",
+      G_CALLBACK (log_manager_dispatcher_observe_cb), log_manager);
+}