]> git.0d.be Git - empathy.git/blob - libempathy/empathy-message.c
Merge branch 'master' into tp-tube
[empathy.git] / libempathy / empathy-message.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2004-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: Mikael Hallendal <micke@imendio.com>
22  *          Xavier Claessens <xclaesse@gmail.com>
23  */
24
25 #include "config.h"
26
27 #include <string.h>
28
29 #include <telepathy-glib/util.h>
30
31 #include "empathy-message.h"
32 #include "empathy-utils.h"
33 #include "empathy-enum-types.h"
34
35 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyMessage)
36 typedef struct {
37         TpChannelTextMessageType  type;
38         EmpathyContact           *sender;
39         EmpathyContact           *receiver;
40         gchar                    *body;
41         time_t                    timestamp;
42         guint                     id;
43 } EmpathyMessagePriv;
44
45 static void empathy_message_finalize   (GObject            *object);
46 static void message_get_property      (GObject            *object,
47                                        guint               param_id,
48                                        GValue             *value,
49                                        GParamSpec         *pspec);
50 static void message_set_property      (GObject            *object,
51                                        guint               param_id,
52                                        const GValue       *value,
53                                        GParamSpec         *pspec);
54
55 G_DEFINE_TYPE (EmpathyMessage, empathy_message, G_TYPE_OBJECT);
56
57 enum {
58         PROP_0,
59         PROP_TYPE,
60         PROP_SENDER,
61         PROP_RECEIVER,
62         PROP_BODY,
63         PROP_TIMESTAMP,
64 };
65
66 static void
67 empathy_message_class_init (EmpathyMessageClass *class)
68 {
69         GObjectClass *object_class;
70
71         object_class = G_OBJECT_CLASS (class);
72         object_class->finalize     = empathy_message_finalize;
73         object_class->get_property = message_get_property;
74         object_class->set_property = message_set_property;
75
76         g_object_class_install_property (object_class,
77                                          PROP_TYPE,
78                                          g_param_spec_uint ("type",
79                                                             "Message Type",
80                                                             "The type of message",
81                                                             TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL,
82                                                             TP_CHANNEL_TEXT_MESSAGE_TYPE_AUTO_REPLY,
83                                                             TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL,
84                                                             G_PARAM_READWRITE));
85         g_object_class_install_property (object_class,
86                                          PROP_SENDER,
87                                          g_param_spec_object ("sender",
88                                                               "Message Sender",
89                                                               "The sender of the message",
90                                                               EMPATHY_TYPE_CONTACT,
91                                                               G_PARAM_READWRITE));
92         g_object_class_install_property (object_class,
93                                          PROP_RECEIVER,
94                                          g_param_spec_object ("receiver",
95                                                               "Message Receiver",
96                                                               "The receiver of the message",
97                                                               EMPATHY_TYPE_CONTACT,
98                                                               G_PARAM_READWRITE));
99         g_object_class_install_property (object_class,
100                                          PROP_BODY,
101                                          g_param_spec_string ("body",
102                                                               "Message Body",
103                                                               "The content of the message",
104                                                               NULL,
105                                                               G_PARAM_READWRITE));
106         g_object_class_install_property (object_class,
107                                          PROP_TIMESTAMP,
108                                          g_param_spec_long ("timestamp",
109                                                             "timestamp",
110                                                             "timestamp",
111                                                             -1,
112                                                             G_MAXLONG,
113                                                             -1,
114                                                             G_PARAM_READWRITE));
115
116
117         g_type_class_add_private (object_class, sizeof (EmpathyMessagePriv));
118
119 }
120
121 static void
122 empathy_message_init (EmpathyMessage *message)
123 {
124         EmpathyMessagePriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (message,
125                 EMPATHY_TYPE_MESSAGE, EmpathyMessagePriv);
126
127         message->priv = priv;
128         priv->timestamp = empathy_time_get_current ();
129 }
130
131 static void
132 empathy_message_finalize (GObject *object)
133 {
134         EmpathyMessagePriv *priv;
135
136         priv = GET_PRIV (object);
137
138         if (priv->sender) {
139                 g_object_unref (priv->sender);
140         }
141         if (priv->receiver) {
142                 g_object_unref (priv->receiver);
143         }
144
145         g_free (priv->body);
146
147         G_OBJECT_CLASS (empathy_message_parent_class)->finalize (object);
148 }
149
150 static void
151 message_get_property (GObject    *object,
152                       guint       param_id,
153                       GValue     *value,
154                       GParamSpec *pspec)
155 {
156         EmpathyMessagePriv *priv;
157
158         priv = GET_PRIV (object);
159
160         switch (param_id) {
161         case PROP_TYPE:
162                 g_value_set_uint (value, priv->type);
163                 break;
164         case PROP_SENDER:
165                 g_value_set_object (value, priv->sender);
166                 break;
167         case PROP_RECEIVER:
168                 g_value_set_object (value, priv->receiver);
169                 break;
170         case PROP_BODY:
171                 g_value_set_string (value, priv->body);
172                 break;
173         default:
174                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
175                 break;
176         };
177 }
178
179 static void
180 message_set_property (GObject      *object,
181                       guint         param_id,
182                       const GValue *value,
183                       GParamSpec   *pspec)
184 {
185         EmpathyMessagePriv *priv;
186
187         priv = GET_PRIV (object);
188
189         switch (param_id) {
190         case PROP_TYPE:
191                 empathy_message_set_tptype (EMPATHY_MESSAGE (object),
192                                             g_value_get_uint (value));
193                 break;
194         case PROP_SENDER:
195                 empathy_message_set_sender (EMPATHY_MESSAGE (object),
196                                            EMPATHY_CONTACT (g_value_get_object (value)));
197                 break;
198         case PROP_RECEIVER:
199                 empathy_message_set_receiver (EMPATHY_MESSAGE (object),
200                                              EMPATHY_CONTACT (g_value_get_object (value)));
201                 break;
202         case PROP_BODY:
203                 empathy_message_set_body (EMPATHY_MESSAGE (object),
204                                          g_value_get_string (value));
205                 break;
206         default:
207                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
208                 break;
209         };
210 }
211
212 EmpathyMessage *
213 empathy_message_new (const gchar *body)
214 {
215         return g_object_new (EMPATHY_TYPE_MESSAGE,
216                              "body", body,
217                              NULL);
218 }
219
220 TpChannelTextMessageType
221 empathy_message_get_tptype (EmpathyMessage *message)
222 {
223         EmpathyMessagePriv *priv;
224
225         g_return_val_if_fail (EMPATHY_IS_MESSAGE (message),
226                               TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL);
227
228         priv = GET_PRIV (message);
229
230         return priv->type;
231 }
232
233 void
234 empathy_message_set_tptype (EmpathyMessage           *message,
235                             TpChannelTextMessageType  type)
236 {
237         EmpathyMessagePriv *priv;
238
239         g_return_if_fail (EMPATHY_IS_MESSAGE (message));
240
241         priv = GET_PRIV (message);
242
243         priv->type = type;
244
245         g_object_notify (G_OBJECT (message), "type");
246 }
247
248 EmpathyContact *
249 empathy_message_get_sender (EmpathyMessage *message)
250 {
251         EmpathyMessagePriv *priv;
252
253         g_return_val_if_fail (EMPATHY_IS_MESSAGE (message), NULL);
254
255         priv = GET_PRIV (message);
256
257         return priv->sender;
258 }
259
260 void
261 empathy_message_set_sender (EmpathyMessage *message, EmpathyContact *contact)
262 {
263         EmpathyMessagePriv *priv;
264         EmpathyContact     *old_sender;
265
266         g_return_if_fail (EMPATHY_IS_MESSAGE (message));
267         g_return_if_fail (EMPATHY_IS_CONTACT (contact));
268
269         priv = GET_PRIV (message);
270
271         old_sender = priv->sender;
272         priv->sender = g_object_ref (contact);
273
274         if (old_sender) {
275                 g_object_unref (old_sender);
276         }
277
278         g_object_notify (G_OBJECT (message), "sender");
279 }
280
281 EmpathyContact *
282 empathy_message_get_receiver (EmpathyMessage *message)
283 {
284         EmpathyMessagePriv *priv;
285
286         g_return_val_if_fail (EMPATHY_IS_MESSAGE (message), NULL);
287
288         priv = GET_PRIV (message);
289
290         return priv->receiver;
291 }
292
293 void
294 empathy_message_set_receiver (EmpathyMessage *message, EmpathyContact *contact)
295 {
296         EmpathyMessagePriv *priv;
297         EmpathyContact     *old_receiver;
298
299         g_return_if_fail (EMPATHY_IS_MESSAGE (message));
300         g_return_if_fail (EMPATHY_IS_CONTACT (contact));
301
302         priv = GET_PRIV (message);
303
304         old_receiver = priv->receiver;
305         priv->receiver = g_object_ref (contact);
306
307         if (old_receiver) {
308                 g_object_unref (old_receiver);
309         }
310
311         g_object_notify (G_OBJECT (message), "receiver");
312 }
313
314 const gchar *
315 empathy_message_get_body (EmpathyMessage *message)
316 {
317         EmpathyMessagePriv *priv;
318
319         g_return_val_if_fail (EMPATHY_IS_MESSAGE (message), NULL);
320
321         priv = GET_PRIV (message);
322
323         return priv->body;
324 }
325
326 void
327 empathy_message_set_body (EmpathyMessage *message,
328                           const gchar    *body)
329 {
330         EmpathyMessagePriv       *priv = GET_PRIV (message);
331         TpChannelTextMessageType  type;
332
333         g_return_if_fail (EMPATHY_IS_MESSAGE (message));
334
335         g_free (priv->body);
336         priv->body = NULL;
337
338         type = TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL;
339         if (g_str_has_prefix (body, "/me")) {
340                 type = TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION;
341                 body += 4;
342         }
343         else if (g_str_has_prefix (body, "/say")) {
344                 body += 5;
345         }
346
347         if (body) {
348                 priv->body = g_strdup (body);
349         }
350
351         if (type != priv->type) {
352                 empathy_message_set_tptype (message, type);
353         }
354
355         g_object_notify (G_OBJECT (message), "body");
356 }
357
358 time_t
359 empathy_message_get_timestamp (EmpathyMessage *message)
360 {
361         EmpathyMessagePriv *priv;
362
363         g_return_val_if_fail (EMPATHY_IS_MESSAGE (message), -1);
364
365         priv = GET_PRIV (message);
366
367         return priv->timestamp;
368 }
369
370 void
371 empathy_message_set_timestamp (EmpathyMessage *message,
372                                time_t          timestamp)
373 {
374         EmpathyMessagePriv *priv;
375
376         g_return_if_fail (EMPATHY_IS_MESSAGE (message));
377         g_return_if_fail (timestamp >= -1);
378
379         priv = GET_PRIV (message);
380
381         if (timestamp <= 0) {
382                 priv->timestamp = empathy_time_get_current ();
383         } else {
384                 priv->timestamp = timestamp;
385         }
386
387         g_object_notify (G_OBJECT (message), "timestamp");
388 }
389
390 #define IS_SEPARATOR(ch) (ch == ' ' || ch == ',' || ch == '.' || ch == ':')
391 gboolean
392 empathy_message_should_highlight (EmpathyMessage *message)
393 {
394         EmpathyContact *contact;
395         const gchar   *msg, *to;
396         gchar         *cf_msg, *cf_to;
397         gchar         *ch;
398         gboolean       ret_val;
399
400         g_return_val_if_fail (EMPATHY_IS_MESSAGE (message), FALSE);
401
402         ret_val = FALSE;
403
404         msg = empathy_message_get_body (message);
405         if (!msg) {
406                 return FALSE;
407         }
408
409         contact = empathy_message_get_receiver (message);
410         if (!contact || !empathy_contact_is_user (contact)) {
411                 return FALSE;
412         }
413
414         to = empathy_contact_get_name (contact);
415         if (!to) {
416                 return FALSE;
417         }
418
419         cf_msg = g_utf8_casefold (msg, -1);
420         cf_to = g_utf8_casefold (to, -1);
421
422         ch = strstr (cf_msg, cf_to);
423         if (ch == NULL) {
424                 goto finished;
425         }
426         if (ch != cf_msg) {
427                 /* Not first in the message */
428                 if (!IS_SEPARATOR (*(ch - 1))) {
429                         goto finished;
430                 }
431         }
432
433         ch = ch + strlen (cf_to);
434         if (ch >= cf_msg + strlen (cf_msg)) {
435                 ret_val = TRUE;
436                 goto finished;
437         }
438
439         if (IS_SEPARATOR (*ch)) {
440                 ret_val = TRUE;
441                 goto finished;
442         }
443
444 finished:
445         g_free (cf_msg);
446         g_free (cf_to);
447
448         return ret_val;
449 }
450
451 TpChannelTextMessageType
452 empathy_message_type_from_str (const gchar *type_str)
453 {
454         if (strcmp (type_str, "normal") == 0) {
455                 return TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL;
456         }
457         if (strcmp (type_str, "action") == 0) {
458                 return TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION;
459         }
460         else if (strcmp (type_str, "notice") == 0) {
461                 return TP_CHANNEL_TEXT_MESSAGE_TYPE_NOTICE;
462         }
463         else if (strcmp (type_str, "auto-reply") == 0) {
464                 return TP_CHANNEL_TEXT_MESSAGE_TYPE_AUTO_REPLY;
465         }
466
467         return TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL;
468 }
469
470 const gchar *
471 empathy_message_type_to_str (TpChannelTextMessageType type)
472 {
473         switch (type) {
474         case TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION:
475                 return "action";
476         case TP_CHANNEL_TEXT_MESSAGE_TYPE_NOTICE:
477                 return "notice";
478         case TP_CHANNEL_TEXT_MESSAGE_TYPE_AUTO_REPLY:
479                 return "auto-reply";
480         default:
481                 return "normal";
482         }
483 }
484
485 guint
486 empathy_message_get_id (EmpathyMessage *message)
487 {
488         EmpathyMessagePriv *priv = GET_PRIV (message);
489
490         g_return_val_if_fail (EMPATHY_IS_MESSAGE (message), 0);
491
492         return priv->id;
493 }
494
495 void
496 empathy_message_set_id (EmpathyMessage *message, guint id)
497 {
498         EmpathyMessagePriv *priv = GET_PRIV (message);
499
500         priv->id = id;
501 }
502
503 gboolean
504 empathy_message_equal (EmpathyMessage *message1, EmpathyMessage *message2)
505 {
506         EmpathyMessagePriv *priv1;
507         EmpathyMessagePriv *priv2;
508
509         g_return_val_if_fail (EMPATHY_IS_MESSAGE (message1), FALSE);
510         g_return_val_if_fail (EMPATHY_IS_MESSAGE (message2), FALSE);
511
512         priv1 = GET_PRIV (message1);
513         priv2 = GET_PRIV (message2);
514
515         if (priv1->id == priv2->id && !tp_strdiff (priv1->body, priv2->body)) {
516                 return TRUE;
517         }
518
519         return FALSE;
520 }