]> git.0d.be Git - empathy.git/blob - libempathy/empathy-log-manager.c
Make it possible to set element properties from a config file
[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., 51 Franklin St, Fifth Floor,
19  * Boston, MA  02110-1301  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                             EmpathyAccount *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 (chat_id != NULL, FALSE);
169
170   priv = GET_PRIV (manager);
171
172   for (l = priv->stores; l; l = g_list_next (l))
173     {
174       if (empathy_log_store_exists (EMPATHY_LOG_STORE (l->data),
175             account, chat_id, chatroom))
176         return TRUE;
177     }
178
179   return FALSE;
180 }
181
182 GList *
183 empathy_log_manager_get_dates (EmpathyLogManager *manager,
184                                EmpathyAccount *account,
185                                const gchar *chat_id,
186                                gboolean chatroom)
187 {
188   GList *l, *out = NULL;
189   EmpathyLogManagerPriv *priv;
190
191   g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), NULL);
192   g_return_val_if_fail (chat_id != NULL, NULL);
193
194   priv = GET_PRIV (manager);
195
196   for (l = priv->stores; l; l = g_list_next (l))
197     {
198       EmpathyLogStore *store = EMPATHY_LOG_STORE (l->data);
199       GList *new;
200
201       /* Insert dates of each store in the out list. Keep the out list sorted
202        * and avoid to insert dups. */
203       new = empathy_log_store_get_dates (store, account, chat_id, chatroom);
204       while (new)
205         {
206           if (g_list_find_custom (out, new->data, (GCompareFunc) strcmp))
207             g_free (new->data);
208           else
209             out = g_list_insert_sorted (out, new->data, (GCompareFunc) strcmp);
210
211           new = g_list_delete_link (new, new);
212         }
213     }
214
215   return out;
216 }
217
218 GList *
219 empathy_log_manager_get_messages_for_date (EmpathyLogManager *manager,
220                                            EmpathyAccount *account,
221                                            const gchar *chat_id,
222                                            gboolean chatroom,
223                                            const gchar *date)
224 {
225   GList *l, *out = NULL;
226   EmpathyLogManagerPriv *priv;
227
228   g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), NULL);
229   g_return_val_if_fail (chat_id != NULL, NULL);
230
231   priv = GET_PRIV (manager);
232
233   for (l = priv->stores; l; l = g_list_next (l))
234     {
235       EmpathyLogStore *store = EMPATHY_LOG_STORE (l->data);
236
237       out = g_list_concat (out, empathy_log_store_get_messages_for_date (
238           store, account, chat_id, chatroom, date));
239     }
240
241   return out;
242 }
243
244 static gint
245 log_manager_message_date_cmp (gconstpointer a,
246                               gconstpointer b)
247 {
248         EmpathyMessage *one = (EmpathyMessage *) a;
249         EmpathyMessage *two = (EmpathyMessage *) b;
250         time_t one_time, two_time;
251
252         one_time = empathy_message_get_timestamp (one);
253         two_time = empathy_message_get_timestamp (two);
254
255         /* Return -1 of message1 is older than message2 */
256         return one_time < two_time ? -1 : one_time - two_time;
257 }
258
259 GList *
260 empathy_log_manager_get_filtered_messages (EmpathyLogManager *manager,
261                                            EmpathyAccount *account,
262                                            const gchar *chat_id,
263                                            gboolean chatroom,
264                                            guint num_messages,
265                                            EmpathyLogMessageFilter filter,
266                                            gpointer user_data)
267 {
268   EmpathyLogManagerPriv *priv;
269   GList *out = NULL;
270   GList *l;
271   guint i = 0;
272
273   g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), NULL);
274   g_return_val_if_fail (chat_id != NULL, NULL);
275
276   priv = GET_PRIV (manager);
277
278   /* Get num_messages from each log store and keep only the
279    * newest ones in the out list. Keep that list sorted: Older first. */
280   for (l = priv->stores; l; l = g_list_next (l))
281     {
282       EmpathyLogStore *store = EMPATHY_LOG_STORE (l->data);
283       GList *new;
284
285       new = empathy_log_store_get_filtered_messages (store, account, chat_id,
286           chatroom, num_messages, filter, user_data);
287       while (new)
288         {
289           if (i < num_messages)
290             {
291               /* We have less message than needed so far. Keep this message */
292               out = g_list_insert_sorted (out, new->data,
293                   (GCompareFunc) log_manager_message_date_cmp);
294               i++;
295             }
296           else if (log_manager_message_date_cmp (new->data, out->data) > 0)
297             {
298               /* This message is newer than the oldest message we have in out
299                * list. Remove the head of out list and insert this message */
300               g_object_unref (out->data);
301               out = g_list_delete_link (out, out);
302               out = g_list_insert_sorted (out, new->data,
303                   (GCompareFunc) log_manager_message_date_cmp);
304             }
305           else
306             {
307               /* This message is older than the oldest message we have in out
308                * list. Drop it. */
309               g_object_unref (new->data);
310             }
311
312           new = g_list_delete_link (new, new);
313         }
314     }
315
316   return out;
317 }
318
319 GList *
320 empathy_log_manager_get_chats (EmpathyLogManager *manager,
321                                EmpathyAccount *account)
322 {
323   GList *l, *out = NULL;
324   EmpathyLogManagerPriv *priv;
325
326   g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), NULL);
327
328   priv = GET_PRIV (manager);
329
330   for (l = priv->stores; l; l = g_list_next (l))
331     {
332       EmpathyLogStore *store = EMPATHY_LOG_STORE (l->data);
333
334       out = g_list_concat (out,
335           empathy_log_store_get_chats (store, account));
336     }
337
338   return out;
339 }
340
341 GList *
342 empathy_log_manager_search_new (EmpathyLogManager *manager,
343                                 const gchar *text)
344 {
345   GList *l, *out = NULL;
346   EmpathyLogManagerPriv *priv;
347
348   g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), NULL);
349   g_return_val_if_fail (!EMP_STR_EMPTY (text), NULL);
350
351   priv = GET_PRIV (manager);
352
353   for (l = priv->stores; l; l = g_list_next (l))
354     {
355       EmpathyLogStore *store = EMPATHY_LOG_STORE (l->data);
356
357       out = g_list_concat (out,
358           empathy_log_store_search_new (store, text));
359     }
360
361   return out;
362 }
363
364 void
365 empathy_log_manager_search_hit_free (EmpathyLogSearchHit *hit)
366 {
367   if (hit->account != NULL)
368     g_object_unref (hit->account);
369
370   g_free (hit->date);
371   g_free (hit->filename);
372   g_free (hit->chat_id);
373
374   g_slice_free (EmpathyLogSearchHit, hit);
375 }
376
377 void
378 empathy_log_manager_search_free (GList *hits)
379 {
380   GList *l;
381
382   for (l = hits; l; l = g_list_next (l))
383     {
384       empathy_log_manager_search_hit_free (l->data);
385     }
386
387   g_list_free (hits);
388 }
389
390 /* Format is just date, 20061201. */
391 gchar *
392 empathy_log_manager_get_date_readable (const gchar *date)
393 {
394   time_t t;
395
396   t = empathy_time_parse (date);
397
398   return empathy_time_to_string_local (t, "%a %d %b %Y");
399 }
400
401 static void
402 log_manager_chat_received_message_cb (EmpathyTpChat *tp_chat,
403                                       EmpathyMessage *message,
404                                       EmpathyLogManager *log_manager)
405 {
406   GError *error = NULL;
407   TpHandleType handle_type;
408   TpChannel *channel;
409
410   channel = empathy_tp_chat_get_channel (tp_chat);
411   tp_channel_get_handle (channel, &handle_type);
412
413   if (!empathy_log_manager_add_message (log_manager,
414         tp_channel_get_identifier (channel),
415         handle_type == TP_HANDLE_TYPE_ROOM,
416         message, &error))
417     {
418       DEBUG ("Failed to write message: %s",
419           error ? error->message : "No error message");
420
421       if (error != NULL)
422         g_error_free (error);
423     }
424 }
425
426 static void
427 log_manager_dispatcher_observe_cb (EmpathyDispatcher *dispatcher,
428                                    EmpathyDispatchOperation *operation,
429                                    EmpathyLogManager *log_manager)
430 {
431   GQuark channel_type;
432
433   channel_type = empathy_dispatch_operation_get_channel_type_id (operation);
434
435   if (channel_type == TP_IFACE_QUARK_CHANNEL_TYPE_TEXT)
436     {
437       EmpathyTpChat *tp_chat;
438
439       tp_chat = EMPATHY_TP_CHAT (
440           empathy_dispatch_operation_get_channel_wrapper (operation));
441
442       g_signal_connect (tp_chat, "message-received",
443           G_CALLBACK (log_manager_chat_received_message_cb), log_manager);
444     }
445 }
446
447
448 void
449 empathy_log_manager_observe (EmpathyLogManager *log_manager,
450                              EmpathyDispatcher *dispatcher)
451 {
452   g_signal_connect (dispatcher, "observe",
453       G_CALLBACK (log_manager_dispatcher_observe_cb), log_manager);
454 }