]> git.0d.be Git - empathy.git/blob - 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
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2003-2007 Imendio AB
4  * Copyright (C) 2007-2008 Collabora Ltd.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of the
9  * License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public
17  * License along with this program; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  *
21  * Authors: Xavier Claessens <xclaesse@gmail.com>
22  */
23
24 #include <config.h>
25
26 #include <string.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <glib/gstdio.h>
30
31 #include <telepathy-glib/util.h>
32
33 #include "empathy-log-manager.h"
34 #include "empathy-log-store-empathy.h"
35 #include "empathy-log-store.h"
36 #include "empathy-tp-chat.h"
37 #include "empathy-utils.h"
38
39 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
40 #include "empathy-debug.h"
41
42 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyLogManager)
43 typedef struct
44 {
45   GList *stores;
46 } EmpathyLogManagerPriv;
47
48 G_DEFINE_TYPE (EmpathyLogManager, empathy_log_manager, G_TYPE_OBJECT);
49
50 static EmpathyLogManager * manager_singleton = NULL;
51
52 static void
53 log_manager_finalize (GObject *object)
54 {
55   EmpathyLogManagerPriv *priv;
56
57   priv = GET_PRIV (object);
58
59   g_list_foreach (priv->stores, (GFunc) g_object_unref, NULL);
60   g_list_free (priv->stores);
61 }
62
63 static GObject *
64 log_manager_constructor (GType type,
65                          guint n_props,
66                          GObjectConstructParam *props)
67 {
68   GObject *retval;
69   EmpathyLogManagerPriv *priv;
70
71   if (manager_singleton)
72     {
73       retval = g_object_ref (manager_singleton);
74     }
75   else
76     {
77       retval = G_OBJECT_CLASS (empathy_log_manager_parent_class)->constructor
78           (type, n_props, props);
79
80       manager_singleton = EMPATHY_LOG_MANAGER (retval);
81       g_object_add_weak_pointer (retval, (gpointer *) &manager_singleton);
82
83       priv = GET_PRIV (manager_singleton);
84
85       priv->stores = g_list_append (priv->stores,
86           g_object_new (EMPATHY_TYPE_LOG_STORE_EMPATHY, NULL));
87     }
88
89   return retval;
90 }
91
92 static void
93 empathy_log_manager_class_init (EmpathyLogManagerClass *klass)
94 {
95   GObjectClass *object_class = G_OBJECT_CLASS (klass);
96
97   object_class->constructor = log_manager_constructor;
98   object_class->finalize = log_manager_finalize;
99
100   g_type_class_add_private (object_class, sizeof (EmpathyLogManagerPriv));
101 }
102
103 static void
104 empathy_log_manager_init (EmpathyLogManager *manager)
105 {
106   EmpathyLogManagerPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (manager,
107       EMPATHY_TYPE_LOG_MANAGER, EmpathyLogManagerPriv);
108
109   manager->priv = priv;
110 }
111
112 EmpathyLogManager *
113 empathy_log_manager_dup_singleton (void)
114 {
115   return g_object_new (EMPATHY_TYPE_LOG_MANAGER, NULL);
116 }
117
118 gboolean
119 empathy_log_manager_add_message (EmpathyLogManager *manager,
120                                  const gchar *chat_id,
121                                  gboolean chatroom,
122                                  EmpathyMessage *message,
123                                  GError **error)
124 {
125   EmpathyLogManagerPriv *priv;
126   GList *l;
127   gboolean out = FALSE;
128   gboolean found = FALSE;
129
130   /* TODO: When multiple log stores appear with add_message implementations
131    * make this customisable. */
132   const gchar *add_store = "Empathy";
133
134   g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), FALSE);
135   g_return_val_if_fail (chat_id != NULL, FALSE);
136   g_return_val_if_fail (EMPATHY_IS_MESSAGE (message), FALSE);
137
138   priv = GET_PRIV (manager);
139
140   for (l = priv->stores; l; l = g_list_next (l))
141     {
142       if (!tp_strdiff (empathy_log_store_get_name (
143               EMPATHY_LOG_STORE (l->data)), add_store))
144         {
145           out = empathy_log_store_add_message (EMPATHY_LOG_STORE (l->data),
146               chat_id, chatroom, message, error);
147           found = TRUE;
148           break;
149         }
150     }
151
152   if (!found)
153     DEBUG ("Failed to find chosen log store to write to.");
154
155   return out;
156 }
157
158 gboolean
159 empathy_log_manager_exists (EmpathyLogManager *manager,
160                             McAccount *account,
161                             const gchar *chat_id,
162                             gboolean chatroom)
163 {
164   GList *l;
165   EmpathyLogManagerPriv *priv;
166
167   g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), FALSE);
168   g_return_val_if_fail (MC_IS_ACCOUNT (account), FALSE);
169   g_return_val_if_fail (chat_id != NULL, FALSE);
170
171   priv = GET_PRIV (manager);
172
173   for (l = priv->stores; l; l = g_list_next (l))
174     {
175       if (empathy_log_store_exists (EMPATHY_LOG_STORE (l->data),
176             account, chat_id, chatroom))
177         return TRUE;
178     }
179
180   return FALSE;
181 }
182
183 GList *
184 empathy_log_manager_get_dates (EmpathyLogManager *manager,
185                                McAccount *account,
186                                const gchar *chat_id,
187                                gboolean chatroom)
188 {
189   GList *l, *out = NULL;
190   EmpathyLogManagerPriv *priv;
191
192   g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), NULL);
193   g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
194   g_return_val_if_fail (chat_id != NULL, NULL);
195
196   priv = GET_PRIV (manager);
197
198   for (l = priv->stores; l; l = g_list_next (l))
199     {
200       EmpathyLogStore *store = EMPATHY_LOG_STORE (l->data);
201       GList *new;
202
203       /* Insert dates of each store in the out list. Keep the out list sorted
204        * and avoid to insert dups. */
205       new = empathy_log_store_get_dates (store, account, chat_id, chatroom);
206       while (new)
207         {
208           if (g_list_find_custom (out, new->data, (GCompareFunc) strcmp))
209             g_free (new->data);
210           else
211             out = g_list_insert_sorted (out, new->data, (GCompareFunc) strcmp);
212
213           new = g_list_delete_link (new, new);
214         }
215     }
216
217   return out;
218 }
219
220 GList *
221 empathy_log_manager_get_messages_for_date (EmpathyLogManager *manager,
222                                            McAccount *account,
223                                            const gchar *chat_id,
224                                            gboolean chatroom,
225                                            const gchar *date)
226 {
227   GList *l, *out = NULL;
228   EmpathyLogManagerPriv *priv;
229
230   g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), NULL);
231   g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
232   g_return_val_if_fail (chat_id != NULL, NULL);
233
234   priv = GET_PRIV (manager);
235
236   for (l = priv->stores; l; l = g_list_next (l))
237     {
238       EmpathyLogStore *store = EMPATHY_LOG_STORE (l->data);
239
240       out = g_list_concat (out, empathy_log_store_get_messages_for_date (
241           store, account, chat_id, chatroom, date));
242     }
243
244   return out;
245 }
246
247 static gint
248 log_manager_message_date_cmp (gconstpointer a,
249                               gconstpointer b)
250 {
251         EmpathyMessage *one = (EmpathyMessage *) a;
252         EmpathyMessage *two = (EmpathyMessage *) b;
253         time_t one_time, two_time;
254
255         one_time = empathy_message_get_timestamp (one);
256         two_time = empathy_message_get_timestamp (two);
257
258         /* Return -1 of message1 is older than message2 */
259         return one_time < two_time ? -1 : one_time - two_time;
260 }
261
262 GList *
263 empathy_log_manager_get_filtered_messages (EmpathyLogManager *manager,
264                                            McAccount *account,
265                                            const gchar *chat_id,
266                                            gboolean chatroom,
267                                            guint num_messages,
268                                            EmpathyLogMessageFilter filter,
269                                            gpointer user_data)
270 {
271   EmpathyLogManagerPriv *priv;
272   GList *out = NULL;
273   GList *l;
274   guint i = 0;
275
276   g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), NULL);
277   g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
278   g_return_val_if_fail (chat_id != NULL, NULL);
279
280   priv = GET_PRIV (manager);
281
282   /* Get num_messages from each log store and keep only the
283    * newest ones in the out list. Keep that list sorted: Older first. */
284   for (l = priv->stores; l; l = g_list_next (l))
285     {
286       EmpathyLogStore *store = EMPATHY_LOG_STORE (l->data);
287       GList *new;
288
289       new = empathy_log_store_get_filtered_messages (store, account, chat_id,
290           chatroom, num_messages, filter, user_data);
291       while (new)
292         {
293           if (i < num_messages)
294             {
295               /* We have less message than needed so far. Keep this message */
296               out = g_list_insert_sorted (out, new->data,
297                   (GCompareFunc) log_manager_message_date_cmp);
298               i++;
299             }
300           else if (log_manager_message_date_cmp (new->data, out->data) > 0)
301             {
302               /* This message is newer than the oldest message we have in out
303                * list. Remove the head of out list and insert this message */
304               g_object_unref (out->data);
305               out = g_list_delete_link (out, out);
306               out = g_list_insert_sorted (out, new->data,
307                   (GCompareFunc) log_manager_message_date_cmp);
308             }
309           else
310             {
311               /* This message is older than the oldest message we have in out
312                * list. Drop it. */
313               g_object_unref (new->data);
314             }
315
316           new = g_list_delete_link (new, new);
317         }
318     }
319
320   return out;
321 }
322
323 GList *
324 empathy_log_manager_get_chats (EmpathyLogManager *manager,
325                                McAccount *account)
326 {
327   GList *l, *out = NULL;
328   EmpathyLogManagerPriv *priv;
329
330   g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), NULL);
331   g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
332
333   priv = GET_PRIV (manager);
334
335   for (l = priv->stores; l; l = g_list_next (l))
336     {
337       EmpathyLogStore *store = EMPATHY_LOG_STORE (l->data);
338
339       out = g_list_concat (out,
340           empathy_log_store_get_chats (store, account));
341     }
342
343   return out;
344 }
345
346 GList *
347 empathy_log_manager_search_new (EmpathyLogManager *manager,
348                                 const gchar *text)
349 {
350   GList *l, *out = NULL;
351   EmpathyLogManagerPriv *priv;
352
353   g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), NULL);
354   g_return_val_if_fail (!EMP_STR_EMPTY (text), NULL);
355
356   priv = GET_PRIV (manager);
357
358   for (l = priv->stores; l; l = g_list_next (l))
359     {
360       EmpathyLogStore *store = EMPATHY_LOG_STORE (l->data);
361
362       out = g_list_concat (out,
363           empathy_log_store_search_new (store, text));
364     }
365
366   return out;
367 }
368
369 void
370 empathy_log_manager_search_hit_free (EmpathyLogSearchHit *hit)
371 {
372   if (hit->account != NULL)
373     g_object_unref (hit->account);
374
375   g_free (hit->date);
376   g_free (hit->filename);
377   g_free (hit->chat_id);
378
379   g_slice_free (EmpathyLogSearchHit, hit);
380 }
381
382 void
383 empathy_log_manager_search_free (GList *hits)
384 {
385   GList *l;
386
387   for (l = hits; l; l = g_list_next (l))
388     {
389       empathy_log_manager_search_hit_free (l->data);
390     }
391
392   g_list_free (hits);
393 }
394
395 /* Format is just date, 20061201. */
396 gchar *
397 empathy_log_manager_get_date_readable (const gchar *date)
398 {
399   time_t t;
400
401   t = empathy_time_parse (date);
402
403   return empathy_time_to_string_local (t, "%a %d %b %Y");
404 }
405
406 static void
407 log_manager_chat_received_message_cb (EmpathyTpChat *tp_chat,
408                                       EmpathyMessage *message,
409                                       EmpathyLogManager *log_manager)
410 {
411   GError *error = NULL;
412   TpHandleType handle_type;
413   TpChannel *channel;
414
415   channel = empathy_tp_chat_get_channel (tp_chat);
416   tp_channel_get_handle (channel, &handle_type);
417
418   if (!empathy_log_manager_add_message (log_manager,
419         tp_channel_get_identifier (channel),
420         handle_type == TP_HANDLE_TYPE_ROOM,
421         message, &error))
422     {
423       DEBUG ("Failed to write message: %s",
424           error ? error->message : "No error message");
425
426       if (error != NULL)
427         g_error_free (error);
428     }
429 }
430
431 static void
432 log_manager_dispatcher_observe_cb (EmpathyDispatcher *dispatcher,
433                                    EmpathyDispatchOperation *operation,
434                                    EmpathyLogManager *log_manager)
435 {
436   GQuark channel_type;
437
438   channel_type = empathy_dispatch_operation_get_channel_type_id (operation);
439
440   if (channel_type == TP_IFACE_QUARK_CHANNEL_TYPE_TEXT)
441     {
442       EmpathyTpChat *tp_chat;
443
444       tp_chat = EMPATHY_TP_CHAT (
445           empathy_dispatch_operation_get_channel_wrapper (operation));
446
447       g_signal_connect (tp_chat, "message-received",
448           G_CALLBACK (log_manager_chat_received_message_cb), log_manager);
449     }
450 }
451
452
453 void
454 empathy_log_manager_observe (EmpathyLogManager *log_manager,
455                              EmpathyDispatcher *dispatcher)
456 {
457   g_signal_connect (dispatcher, "observe",
458       G_CALLBACK (log_manager_dispatcher_observe_cb), log_manager);
459 }