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