]> git.0d.be Git - empathy.git/blob - libempathy/empathy-log-manager.c
4125add7cea22adece8fafb20c6c941506fd1dec
[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   GList *l;
57
58   priv = GET_PRIV (object);
59
60   for (l = priv->stores; l; l = l->next)
61     {
62       EmpathyLogStore *store = (EmpathyLogStore *) l->data;
63       g_object_unref (store);
64     }
65
66   g_list_free (priv->stores);
67 }
68
69 static GObject *
70 log_manager_constructor (GType type,
71                          guint n_props,
72                          GObjectConstructParam *props)
73 {
74   GObject *retval;
75
76   if (manager_singleton)
77     {
78       retval = g_object_ref (manager_singleton);
79     }
80   else
81     {
82       retval = G_OBJECT_CLASS (empathy_log_manager_parent_class)->constructor
83           (type, n_props, props);
84
85       manager_singleton = EMPATHY_LOG_MANAGER (retval);
86       g_object_add_weak_pointer (retval, (gpointer *) &manager_singleton);
87
88       priv = GET_PRIV (manager_singleton);
89
90       priv->sources = g_list_append (priv->sources,
91           empathy_log_source_empathy_get_source ());
92     }
93
94   return retval;
95 }
96
97 static void
98 empathy_log_manager_class_init (EmpathyLogManagerClass *klass)
99 {
100   GObjectClass *object_class = G_OBJECT_CLASS (klass);
101
102   object_class->constructor = log_manager_constructor;
103   object_class->finalize = log_manager_finalize;
104
105   g_type_class_add_private (object_class, sizeof (EmpathyLogManagerPriv));
106 }
107
108 static void
109 empathy_log_manager_init (EmpathyLogManager *manager)
110 {
111   EmpathyLogManagerPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (manager,
112       EMPATHY_TYPE_LOG_MANAGER, EmpathyLogManagerPriv);
113
114   priv->stores = g_list_append (priv->stores,
115       g_object_new (EMPATHY_TYPE_LOG_STORE_EMPATHY, NULL));
116
117   manager->priv = priv;
118 }
119
120 EmpathyLogManager *
121 empathy_log_manager_dup_singleton (void)
122 {
123   return g_object_new (EMPATHY_TYPE_LOG_MANAGER, NULL);
124 }
125
126 gboolean
127 empathy_log_manager_add_message (EmpathyLogManager *manager,
128                                  const gchar *chat_id,
129                                  gboolean chatroom,
130                                  EmpathyMessage *message,
131                                  GError **error)
132 {
133   EmpathyLogManagerPriv *priv;
134   GList *l;
135   gboolean out = FALSE;
136   gboolean found = FALSE;
137
138   /* TODO: When multiple log stores appear with add_message implementations
139    * make this customisable. */
140   const gchar *add_store = "Empathy";
141
142   g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), FALSE);
143   g_return_val_if_fail (chat_id != NULL, FALSE);
144   g_return_val_if_fail (EMPATHY_IS_MESSAGE (message), FALSE);
145
146   priv = GET_PRIV (manager);
147
148   for (l = priv->stores; l; l = l->next)
149     {
150       if (!tp_strdiff (empathy_log_store_get_name (
151               EMPATHY_LOG_STORE (l->data)), add_store))
152         {
153           out = empathy_log_store_add_message (EMPATHY_LOG_STORE (l->data),
154               chat_id, chatroom, message, error);
155           found = TRUE;
156           break;
157         }
158     }
159
160   if (!found)
161     DEBUG ("Failed to find chosen log store to write to.");
162
163   return out;
164 }
165
166 gboolean
167 empathy_log_manager_exists (EmpathyLogManager *manager,
168                             McAccount *account,
169                             const gchar *chat_id,
170                             gboolean chatroom)
171 {
172   GList *l;
173   EmpathyLogManagerPriv *priv;
174
175   g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), FALSE);
176   g_return_val_if_fail (MC_IS_ACCOUNT (account), FALSE);
177   g_return_val_if_fail (chat_id != NULL, FALSE);
178
179   priv = GET_PRIV (manager);
180
181   for (l = priv->stores; l; l = l->next)
182     {
183       if (empathy_log_store_exists (EMPATHY_LOG_STORE (l->data),
184             account, chat_id, chatroom))
185         return TRUE;
186     }
187
188   return FALSE;
189 }
190
191 static void
192 log_manager_get_dates_foreach (gpointer data,
193                                gpointer user_data)
194 {
195   /* g_list_first is needed in case an older date was last inserted */
196   GList *orig = g_list_first (user_data);
197
198   if (g_list_find_custom (orig, data, (GCompareFunc) strcmp))
199     orig = g_list_insert_sorted (orig, g_strdup (data), (GCompareFunc) strcmp);
200 }
201
202 GList *
203 empathy_log_manager_get_dates (EmpathyLogManager *manager,
204                                McAccount *account,
205                                const gchar *chat_id,
206                                gboolean chatroom)
207 {
208   GList *l, *out = NULL;
209   EmpathyLogManagerPriv *priv;
210
211   g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), NULL);
212   g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
213   g_return_val_if_fail (chat_id != NULL, NULL);
214
215   priv = GET_PRIV (manager);
216
217   for (l = priv->stores; l; l = l->next)
218     {
219       EmpathyLogStore *store = EMPATHY_LOG_STORE (l->data);
220
221       if (!out)
222         out = empathy_log_store_get_dates (store, account, chat_id, chatroom);
223       else
224         {
225           GList *new = empathy_log_store_get_dates (store, account, chat_id,
226               chatroom);
227           g_list_foreach (new, log_manager_get_dates_foreach, out);
228
229           g_list_foreach (new, (GFunc) g_free, NULL);
230           g_list_free (new);
231
232           /* Similar reason for using g_list_first here as before */
233           out = g_list_first (out);
234         }
235     }
236
237   return out;
238 }
239
240 GList *
241 empathy_log_manager_get_messages_for_date (EmpathyLogManager *manager,
242                                            McAccount *account,
243                                            const gchar *chat_id,
244                                            gboolean chatroom,
245                                            const gchar *date)
246 {
247   GList *l, *out = NULL;
248   EmpathyLogManagerPriv *priv;
249
250   g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), NULL);
251   g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
252   g_return_val_if_fail (chat_id != NULL, NULL);
253
254   priv = GET_PRIV (manager);
255
256   for (l = priv->stores; l; l = l->next)
257     {
258       EmpathyLogStore *store = EMPATHY_LOG_STORE (l->data);
259
260       out = g_list_concat (out, empathy_log_store_get_messages_for_date (
261           store, account, chat_id, chatroom, date));
262     }
263
264   return out;
265 }
266
267 GList *
268 empathy_log_manager_get_last_messages (EmpathyLogManager *manager,
269                                        McAccount *account,
270                                        const gchar *chat_id,
271                                        gboolean chatroom)
272 {
273   GList *messages = NULL;
274   GList *dates;
275   GList *l;
276
277   g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), NULL);
278   g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
279   g_return_val_if_fail (chat_id != NULL, NULL);
280
281   dates = empathy_log_manager_get_dates (manager, account, chat_id, chatroom);
282
283   l = g_list_last (dates);
284   if (l)
285     messages = empathy_log_manager_get_messages_for_date (manager, account,
286         chat_id, chatroom, l->data);
287
288   g_list_foreach (dates, (GFunc) g_free, NULL);
289   g_list_free (dates);
290
291   return messages;
292 }
293
294 GList *
295 empathy_log_manager_get_chats (EmpathyLogManager *manager,
296                                McAccount *account)
297 {
298   GList *l, *out = NULL;
299   EmpathyLogManagerPriv *priv;
300
301   g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), NULL);
302   g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
303
304   priv = GET_PRIV (manager);
305
306   for (l = priv->stores; l; l = l->next)
307     {
308       EmpathyLogStore *store = EMPATHY_LOG_STORE (l->data);
309
310       out = g_list_concat (out,
311           empathy_log_store_get_chats (store, account));
312     }
313
314   return out;
315 }
316
317 GList *
318 empathy_log_manager_search_new (EmpathyLogManager *manager,
319                                 const gchar *text)
320 {
321   GList *l, *out = NULL;
322   EmpathyLogManagerPriv *priv;
323
324   g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), NULL);
325   g_return_val_if_fail (!EMP_STR_EMPTY (text), NULL);
326
327   priv = GET_PRIV (manager);
328
329   for (l = priv->stores; l; l = l->next)
330     {
331       EmpathyLogStore *store = EMPATHY_LOG_STORE (l->data);
332
333       out = g_list_concat (out,
334           empathy_log_store_search_new (store, text));
335     }
336
337   return out;
338 }
339
340 void
341 empathy_log_manager_search_hit_free (EmpathyLogSearchHit *hit)
342 {
343   if (hit->account)
344     g_object_unref (hit->account);
345
346   g_free (hit->date);
347   g_free (hit->filename);
348   g_free (hit->chat_id);
349
350   g_slice_free (EmpathyLogSearchHit, hit);
351 }
352
353 void
354 empathy_log_manager_search_free (GList *hits)
355 {
356   GList *l;
357
358   for (l = hits; l; l = l->next)
359     {
360       empathy_log_manager_search_hit_free (l->data);
361     }
362
363   g_list_free (hits);
364 }
365
366 /* Format is just date, 20061201. */
367 gchar *
368 empathy_log_manager_get_date_readable (const gchar *date)
369 {
370   time_t t;
371
372   t = empathy_time_parse (date);
373
374   return empathy_time_to_string_local (t, "%a %d %b %Y");
375 }
376
377 typedef struct
378 {
379   EmpathyLogManager *log_manager;
380   TpChannel *channel;
381 } MessageObserveData;
382
383 static void
384 message_observe_data_free (MessageObserveData *data)
385 {
386   g_slice_free (MessageObserveData, data);
387 }
388
389 static void
390 log_manager_chat_received_message_cb (EmpathyTpChat *tp_chat,
391                                       EmpathyMessage *message,
392                                       MessageObserveData *data)
393 {
394   GError *error = NULL;
395   TpHandleType handle_type;
396
397   tp_channel_get_handle (data->channel, &handle_type);
398
399   if (!empathy_log_manager_add_message (data->log_manager,
400         tp_channel_get_identifier (data->channel),
401         handle_type == TP_HANDLE_TYPE_ROOM,
402         message, &error))
403     {
404       DEBUG ("Failed to write message: %s",
405           error ? error->message : "No error message");
406
407       if (error)
408         g_error_free (error);
409     }
410 }
411
412 static void
413 log_manager_dispatcher_observe_cb (EmpathyDispatcher *dispatcher,
414                                    EmpathyDispatchOperation *operation,
415                                    EmpathyLogManager *log_manager)
416 {
417   GQuark channel_type;
418
419   channel_type = empathy_dispatch_operation_get_channel_type_id (operation);
420
421   if (channel_type == TP_IFACE_QUARK_CHANNEL_TYPE_TEXT)
422     {
423       EmpathyTpChat *tp_chat;
424       TpChannel *channel;
425       MessageObserveData *data;
426
427       tp_chat = EMPATHY_TP_CHAT (
428           empathy_dispatch_operation_get_channel_wrapper (operation));
429
430       channel = empathy_dispatch_operation_get_channel (operation);
431
432       data = g_slice_new0 (MessageObserveData);
433       data->log_manager = log_manager;
434       data->channel = channel;
435
436       g_signal_connect_data (tp_chat, "message-received",
437           G_CALLBACK (log_manager_chat_received_message_cb), data,
438           (GClosureNotify) message_observe_data_free, 0);
439     }
440 }
441
442
443 void
444 empathy_log_manager_observe (EmpathyLogManager *log_manager,
445                              EmpathyDispatcher *dispatcher)
446 {
447   g_signal_connect (dispatcher, "observe",
448       G_CALLBACK (log_manager_dispatcher_observe_cb), log_manager);
449 }