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