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