]> git.0d.be Git - empathy.git/blob - libempathy/empathy-message.c
9841cbb618f24e3e7246be3eddf7d101aca0895c
[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 <glib/gi18n-lib.h>
30
31 #include <telepathy-glib/util.h>
32 #include <telepathy-glib/account.h>
33 #include <telepathy-glib/account-manager.h>
34
35 #include <telepathy-logger/entity.h>
36 #include <telepathy-logger/event.h>
37 #include <telepathy-logger/text-event.h>
38 #ifdef HAVE_CALL_LOGS
39 # include <telepathy-logger/call-event.h>
40 #endif
41
42 #define DEBUG_FLAG EMPATHY_DEBUG_CHAT
43 #include "empathy-debug.h"
44
45 #include "empathy-client-factory.h"
46 #include "empathy-message.h"
47 #include "empathy-utils.h"
48 #include "empathy-enum-types.h"
49
50 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyMessage)
51 typedef struct {
52         TpMessage *tp_message;
53         TpChannelTextMessageType  type;
54         EmpathyContact           *sender;
55         EmpathyContact           *receiver;
56         gchar                    *token;
57         gchar                    *supersedes;
58         gchar                    *body;
59         gint64                    timestamp;
60         gint64                    original_timestamp;
61         gboolean                  is_backlog;
62         guint                     id;
63         gboolean                  incoming;
64         TpChannelTextMessageFlags flags;
65 } EmpathyMessagePriv;
66
67 static void empathy_message_finalize   (GObject            *object);
68 static void message_get_property      (GObject            *object,
69                                        guint               param_id,
70                                        GValue             *value,
71                                        GParamSpec         *pspec);
72 static void message_set_property      (GObject            *object,
73                                        guint               param_id,
74                                        const GValue       *value,
75                                        GParamSpec         *pspec);
76
77 G_DEFINE_TYPE (EmpathyMessage, empathy_message, G_TYPE_OBJECT);
78
79 enum {
80         PROP_0,
81         PROP_TYPE,
82         PROP_SENDER,
83         PROP_RECEIVER,
84         PROP_TOKEN,
85         PROP_SUPERSEDES,
86         PROP_BODY,
87         PROP_TIMESTAMP,
88         PROP_ORIGINAL_TIMESTAMP,
89         PROP_IS_BACKLOG,
90         PROP_INCOMING,
91         PROP_FLAGS,
92         PROP_TP_MESSAGE,
93 };
94
95 static void
96 empathy_message_class_init (EmpathyMessageClass *class)
97 {
98         GObjectClass *object_class;
99
100         object_class = G_OBJECT_CLASS (class);
101         object_class->finalize     = empathy_message_finalize;
102         object_class->get_property = message_get_property;
103         object_class->set_property = message_set_property;
104
105         g_object_class_install_property (object_class,
106                                          PROP_TYPE,
107                                          g_param_spec_uint ("type",
108                                                             "Message Type",
109                                                             "The type of message",
110                                                             TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL,
111                                                             TP_CHANNEL_TEXT_MESSAGE_TYPE_AUTO_REPLY,
112                                                             TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL,
113                                                             G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
114                                                             G_PARAM_CONSTRUCT_ONLY));
115         g_object_class_install_property (object_class,
116                                          PROP_SENDER,
117                                          g_param_spec_object ("sender",
118                                                               "Message Sender",
119                                                               "The sender of the message",
120                                                               EMPATHY_TYPE_CONTACT,
121                                                               G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
122         g_object_class_install_property (object_class,
123                                          PROP_RECEIVER,
124                                          g_param_spec_object ("receiver",
125                                                               "Message Receiver",
126                                                               "The receiver of the message",
127                                                               EMPATHY_TYPE_CONTACT,
128                                                               G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
129         g_object_class_install_property (object_class,
130                                          PROP_TOKEN,
131                                          g_param_spec_string ("token",
132                                                               "Message Token",
133                                                               "The message-token",
134                                                               NULL,
135                                                               G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY));
136         g_object_class_install_property (object_class,
137                                          PROP_SUPERSEDES,
138                                          g_param_spec_string ("supersedes",
139                                                               "Supersedes Token",
140                                                               "The message-token this message supersedes",
141                                                               NULL,
142                                                               G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY));
143         g_object_class_install_property (object_class,
144                                          PROP_BODY,
145                                          g_param_spec_string ("body",
146                                                               "Message Body",
147                                                               "The content of the message",
148                                                               NULL,
149                                                               G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
150                                                               G_PARAM_CONSTRUCT_ONLY));
151         g_object_class_install_property (object_class,
152                                          PROP_TIMESTAMP,
153                                          g_param_spec_int64 ("timestamp",
154                                                             "timestamp",
155                                                             "timestamp",
156                                                             G_MININT64, G_MAXINT64, 0,
157                                                             G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
158                                                             G_PARAM_CONSTRUCT_ONLY));
159         g_object_class_install_property (object_class,
160                                          PROP_ORIGINAL_TIMESTAMP,
161                                          g_param_spec_int64 ("original-timestamp",
162                                                              "Original Timestamp",
163                                                              "Timestamp of the original message",
164                                                              G_MININT64, G_MAXINT64, 0,
165                                                              G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY));
166         g_object_class_install_property (object_class,
167                                          PROP_IS_BACKLOG,
168                                          g_param_spec_boolean ("is-backlog",
169                                                                "History message",
170                                                                "If the message belongs to history",
171                                                                FALSE,
172                                                                G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
173                                                                G_PARAM_CONSTRUCT_ONLY));
174
175
176         g_object_class_install_property (object_class,
177                                          PROP_INCOMING,
178                                          g_param_spec_boolean ("incoming",
179                                                                "Incoming",
180                                                                "If this is an incoming (as opposed to sent) message",
181                                                                FALSE,
182                                                                G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
183                                                                G_PARAM_CONSTRUCT_ONLY));
184
185         g_object_class_install_property (object_class,
186                                          PROP_FLAGS,
187                                          g_param_spec_uint ("flags",
188                                                                "Flags",
189                                                                "The TpChannelTextMessageFlags of this message",
190                                                                0, G_MAXUINT, 0,
191                                                                G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
192                                                                G_PARAM_CONSTRUCT_ONLY));
193
194         g_object_class_install_property (object_class,
195                                          PROP_TP_MESSAGE,
196                                          g_param_spec_object ("tp-message",
197                                                                "TpMessage",
198                                                                "The TpMessage of this message",
199                                                                TP_TYPE_MESSAGE,
200                                                                G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
201                                                                G_PARAM_CONSTRUCT_ONLY));
202
203         g_type_class_add_private (object_class, sizeof (EmpathyMessagePriv));
204
205 }
206
207 static void
208 empathy_message_init (EmpathyMessage *message)
209 {
210         EmpathyMessagePriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (message,
211                 EMPATHY_TYPE_MESSAGE, EmpathyMessagePriv);
212
213         message->priv = priv;
214         priv->timestamp = empathy_time_get_current ();
215 }
216
217 static void
218 empathy_message_finalize (GObject *object)
219 {
220         EmpathyMessagePriv *priv;
221
222         priv = GET_PRIV (object);
223
224         if (priv->sender) {
225                 g_object_unref (priv->sender);
226         }
227         if (priv->receiver) {
228                 g_object_unref (priv->receiver);
229         }
230
231         if (priv->tp_message) {
232                 g_object_unref (priv->tp_message);
233         }
234
235         g_free (priv->token);
236         g_free (priv->supersedes);
237         g_free (priv->body);
238
239         G_OBJECT_CLASS (empathy_message_parent_class)->finalize (object);
240 }
241
242 static void
243 message_get_property (GObject    *object,
244                       guint       param_id,
245                       GValue     *value,
246                       GParamSpec *pspec)
247 {
248         EmpathyMessagePriv *priv;
249
250         priv = GET_PRIV (object);
251
252         switch (param_id) {
253         case PROP_TYPE:
254                 g_value_set_uint (value, priv->type);
255                 break;
256         case PROP_SENDER:
257                 g_value_set_object (value, priv->sender);
258                 break;
259         case PROP_RECEIVER:
260                 g_value_set_object (value, priv->receiver);
261                 break;
262         case PROP_TOKEN:
263                 g_value_set_string (value, priv->token);
264                 break;
265         case PROP_SUPERSEDES:
266                 g_value_set_string (value, priv->supersedes);
267                 break;
268         case PROP_BODY:
269                 g_value_set_string (value, priv->body);
270                 break;
271         case PROP_TIMESTAMP:
272                 g_value_set_int64 (value, priv->timestamp);
273                 break;
274         case PROP_ORIGINAL_TIMESTAMP:
275                 g_value_set_int64 (value, priv->original_timestamp);
276                 break;
277         case PROP_IS_BACKLOG:
278                 g_value_set_boolean (value, priv->is_backlog);
279                 break;
280         case PROP_INCOMING:
281                 g_value_set_boolean (value, priv->incoming);
282                 break;
283         case PROP_FLAGS:
284                 g_value_set_uint (value, priv->flags);
285                 break;
286         case PROP_TP_MESSAGE:
287                 g_value_set_object (value, priv->tp_message);
288                 break;
289         default:
290                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
291                 break;
292         };
293 }
294
295 static void
296 message_set_property (GObject      *object,
297                       guint         param_id,
298                       const GValue *value,
299                       GParamSpec   *pspec)
300 {
301         EmpathyMessagePriv *priv;
302
303         priv = GET_PRIV (object);
304
305         switch (param_id) {
306         case PROP_TYPE:
307                 priv->type = g_value_get_uint (value);
308                 break;
309         case PROP_SENDER:
310                 empathy_message_set_sender (EMPATHY_MESSAGE (object),
311                                            EMPATHY_CONTACT (g_value_get_object (value)));
312                 break;
313         case PROP_RECEIVER:
314                 empathy_message_set_receiver (EMPATHY_MESSAGE (object),
315                                              EMPATHY_CONTACT (g_value_get_object (value)));
316                 break;
317         case PROP_TOKEN:
318                 g_assert (priv->token == NULL); /* construct only */
319                 priv->token = g_value_dup_string (value);
320                 break;
321         case PROP_SUPERSEDES:
322                 g_assert (priv->supersedes == NULL); /* construct only */
323                 priv->supersedes = g_value_dup_string (value);
324                 break;
325         case PROP_BODY:
326                 g_assert (priv->body == NULL); /* construct only */
327                 priv->body = g_value_dup_string (value);
328                 break;
329         case PROP_TIMESTAMP:
330                 priv->timestamp = g_value_get_int64 (value);
331                 if (priv->timestamp <= 0)
332                         priv->timestamp = empathy_time_get_current ();
333                 break;
334         case PROP_ORIGINAL_TIMESTAMP:
335                 priv->original_timestamp = g_value_get_int64 (value);
336                 break;
337         case PROP_IS_BACKLOG:
338                 priv->is_backlog = g_value_get_boolean (value);
339                 break;
340         case PROP_INCOMING:
341                 priv->incoming = g_value_get_boolean (value);
342                 break;
343         case PROP_FLAGS:
344                 priv->flags = g_value_get_uint (value);
345                 break;
346         case PROP_TP_MESSAGE:
347                 priv->tp_message = g_value_dup_object (value);
348                 break;
349         default:
350                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
351                 break;
352         };
353 }
354
355 EmpathyMessage *
356 empathy_message_from_tpl_log_event (TplEvent *logevent)
357 {
358         EmpathyMessage *retval = NULL;
359         EmpathyClientFactory *factory;
360         TpAccount *account = NULL;
361         TplEntity *receiver = NULL;
362         TplEntity *sender = NULL;
363         gchar *body = NULL;
364         const gchar *token = NULL, *supersedes = NULL;
365         EmpathyContact *contact;
366         TpChannelTextMessageType type = TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL;
367         gint64 timestamp, original_timestamp = 0;
368
369         g_return_val_if_fail (TPL_IS_EVENT (logevent), NULL);
370
371         factory = empathy_client_factory_dup ();
372         /* FIXME Currently Empathy shows in the log viewer only valid accounts, so it
373          * won't be selected any non-existing (ie removed) account.
374          * When #610455 will be fixed, calling tp_account_manager_ensure_account ()
375          * might add a not existing account to the AM. tp_account_new () probably
376          * will be the best way to handle it.
377          * Note: When creating an EmpathyContact from a TplEntity instance, the
378          * TpAccount is passed *only* to let EmpathyContact be able to retrieve the
379          * avatar (contact_get_avatar_filename () need a TpAccount).
380          * If the way EmpathyContact stores the avatar is changes, it might not be
381          * needed anymore any TpAccount passing and the following call will be
382          * useless */
383         account = tp_simple_client_factory_ensure_account (
384                         TP_SIMPLE_CLIENT_FACTORY (factory),
385                         tpl_event_get_account_path (logevent), NULL, NULL);
386         g_object_unref (factory);
387
388         if (TPL_IS_TEXT_EVENT (logevent)) {
389                 TplTextEvent *textevent = TPL_TEXT_EVENT (logevent);
390
391                 supersedes = tpl_text_event_get_supersedes_token (textevent);
392
393                 /* tp-logger is kind of messy in that instead of having
394                  * timestamp and original-timestamp like Telepathy it has
395                  * timestamp (which is the original) and edited-timestamp,
396                  * (which is when the message was edited) */
397                 if (tp_str_empty (supersedes)) {
398                         /* not an edited message */
399                         timestamp = tpl_event_get_timestamp (logevent);
400                 } else {
401                         /* this is an edited event */
402                         original_timestamp = tpl_event_get_timestamp (logevent);
403                         timestamp = tpl_text_event_get_edit_timestamp (textevent);
404                 }
405
406                 body = g_strdup (tpl_text_event_get_message (textevent));
407
408                 type = tpl_text_event_get_message_type (TPL_TEXT_EVENT (logevent));
409                 token = tpl_text_event_get_message_token (textevent);
410         }
411 #ifdef HAVE_CALL_LOGS
412         else if (TPL_IS_CALL_EVENT (logevent)) {
413                 TplCallEvent *call = TPL_CALL_EVENT (logevent);
414
415                 timestamp = tpl_event_get_timestamp (logevent);
416
417                 if (tpl_call_event_get_end_reason (call) == TPL_CALL_END_REASON_NO_ANSWER)
418                         body = g_strdup_printf (_("Missed call from %s"),
419                                 tpl_entity_get_alias (tpl_event_get_sender (logevent)));
420                 else if (tpl_entity_get_entity_type (tpl_event_get_sender (logevent)) == TPL_ENTITY_SELF)
421                         /* Translators: this is an outgoing call, e.g. 'Called Alice' */
422                         body = g_strdup_printf (_("Called %s"),
423                                 tpl_entity_get_alias (tpl_event_get_receiver (logevent)));
424                 else
425                         body = g_strdup_printf (_("Call from %s"),
426                                 tpl_entity_get_alias (tpl_event_get_sender (logevent)));
427         }
428 #endif
429         else {
430                 /* Unknown event type */
431                 return NULL;
432         }
433
434         receiver = tpl_event_get_receiver (logevent);
435         sender = tpl_event_get_sender (logevent);
436
437         retval = g_object_new (EMPATHY_TYPE_MESSAGE,
438                 "type", type,
439                 "token", token,
440                 "supersedes", supersedes,
441                 "body", body,
442                 "is-backlog", TRUE,
443                 "timestamp", timestamp,
444                 "original-timestamp", original_timestamp,
445                 NULL);
446
447         if (receiver != NULL) {
448                 contact = empathy_contact_from_tpl_contact (account, receiver);
449                 empathy_message_set_receiver (retval, contact);
450                 g_object_unref (contact);
451         }
452
453         if (sender != NULL) {
454                 contact = empathy_contact_from_tpl_contact (account, sender);
455                 empathy_message_set_sender (retval, contact);
456                 g_object_unref (contact);
457         }
458
459         g_free (body);
460
461         return retval;
462 }
463
464 TpMessage *
465 empathy_message_get_tp_message (EmpathyMessage *message)
466 {
467         EmpathyMessagePriv *priv;
468
469         g_return_val_if_fail (EMPATHY_IS_MESSAGE (message), NULL);
470
471         priv = GET_PRIV (message);
472
473         return priv->tp_message;
474 }
475
476 TpChannelTextMessageType
477 empathy_message_get_tptype (EmpathyMessage *message)
478 {
479         EmpathyMessagePriv *priv;
480
481         g_return_val_if_fail (EMPATHY_IS_MESSAGE (message),
482                               TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL);
483
484         priv = GET_PRIV (message);
485
486         return priv->type;
487 }
488
489 EmpathyContact *
490 empathy_message_get_sender (EmpathyMessage *message)
491 {
492         EmpathyMessagePriv *priv;
493
494         g_return_val_if_fail (EMPATHY_IS_MESSAGE (message), NULL);
495
496         priv = GET_PRIV (message);
497
498         return priv->sender;
499 }
500
501 void
502 empathy_message_set_sender (EmpathyMessage *message, EmpathyContact *contact)
503 {
504         EmpathyMessagePriv *priv;
505         EmpathyContact     *old_sender;
506
507         g_return_if_fail (EMPATHY_IS_MESSAGE (message));
508         g_return_if_fail (EMPATHY_IS_CONTACT (contact));
509
510         priv = GET_PRIV (message);
511
512         old_sender = priv->sender;
513         priv->sender = g_object_ref (contact);
514
515         if (old_sender) {
516                 g_object_unref (old_sender);
517         }
518
519         g_object_notify (G_OBJECT (message), "sender");
520 }
521
522 EmpathyContact *
523 empathy_message_get_receiver (EmpathyMessage *message)
524 {
525         EmpathyMessagePriv *priv;
526
527         g_return_val_if_fail (EMPATHY_IS_MESSAGE (message), NULL);
528
529         priv = GET_PRIV (message);
530
531         return priv->receiver;
532 }
533
534 void
535 empathy_message_set_receiver (EmpathyMessage *message, EmpathyContact *contact)
536 {
537         EmpathyMessagePriv *priv;
538         EmpathyContact     *old_receiver;
539
540         g_return_if_fail (EMPATHY_IS_MESSAGE (message));
541         g_return_if_fail (EMPATHY_IS_CONTACT (contact));
542
543         priv = GET_PRIV (message);
544
545         old_receiver = priv->receiver;
546         priv->receiver = g_object_ref (contact);
547
548         if (old_receiver) {
549                 g_object_unref (old_receiver);
550         }
551
552         g_object_notify (G_OBJECT (message), "receiver");
553 }
554
555 const gchar *
556 empathy_message_get_token (EmpathyMessage *message)
557 {
558         EmpathyMessagePriv *priv;
559
560         g_return_val_if_fail (EMPATHY_IS_MESSAGE (message), NULL);
561
562         priv = GET_PRIV (message);
563
564         return priv->token;
565 }
566
567 const gchar *
568 empathy_message_get_supersedes (EmpathyMessage *message)
569 {
570         EmpathyMessagePriv *priv;
571
572         g_return_val_if_fail (EMPATHY_IS_MESSAGE (message), NULL);
573
574         priv = GET_PRIV (message);
575
576         return priv->supersedes;
577 }
578
579 gboolean
580 empathy_message_is_edit (EmpathyMessage *message)
581 {
582         EmpathyMessagePriv *priv;
583
584         g_return_val_if_fail (EMPATHY_IS_MESSAGE (message), FALSE);
585
586         priv = GET_PRIV (message);
587
588         return !tp_str_empty (priv->supersedes);
589 }
590
591 const gchar *
592 empathy_message_get_body (EmpathyMessage *message)
593 {
594         EmpathyMessagePriv *priv;
595
596         g_return_val_if_fail (EMPATHY_IS_MESSAGE (message), NULL);
597
598         priv = GET_PRIV (message);
599
600         return priv->body;
601 }
602
603 gint64
604 empathy_message_get_timestamp (EmpathyMessage *message)
605 {
606         EmpathyMessagePriv *priv;
607
608         g_return_val_if_fail (EMPATHY_IS_MESSAGE (message), -1);
609
610         priv = GET_PRIV (message);
611
612         return priv->timestamp;
613 }
614
615 gint64
616 empathy_message_get_original_timestamp (EmpathyMessage *message)
617 {
618         EmpathyMessagePriv *priv;
619
620         g_return_val_if_fail (EMPATHY_IS_MESSAGE (message), -1);
621
622         priv = GET_PRIV (message);
623
624         return priv->original_timestamp;
625 }
626
627 gboolean
628 empathy_message_is_backlog (EmpathyMessage *message)
629 {
630         EmpathyMessagePriv *priv;
631
632         g_return_val_if_fail (EMPATHY_IS_MESSAGE (message), FALSE);
633
634         priv = GET_PRIV (message);
635
636         return priv->is_backlog;
637 }
638
639 static GRegex *
640 get_highlight_regex_for (const gchar *name)
641 {
642         GRegex *regex;
643         gchar *name_esc, *pattern;
644         GError *error = NULL;
645
646         name_esc = g_regex_escape_string (name, -1);
647         pattern = g_strdup_printf ("\\b%s\\b", name_esc);
648         regex = g_regex_new (pattern, G_REGEX_CASELESS | G_REGEX_OPTIMIZE, 0,
649                 &error);
650
651         if (regex == NULL) {
652                 DEBUG ("couldn't compile regex /%s/: %s", pattern,
653                         error->message);
654
655                 g_error_free (error);
656         }
657
658         g_free (pattern);
659         g_free (name_esc);
660
661         return regex;
662 }
663
664 gboolean
665 empathy_message_should_highlight (EmpathyMessage *message)
666 {
667         EmpathyContact *contact;
668         const gchar   *msg, *to;
669         gboolean       ret_val = FALSE;
670         TpChannelTextMessageFlags flags;
671         GRegex *regex;
672
673         g_return_val_if_fail (EMPATHY_IS_MESSAGE (message), FALSE);
674
675         msg = empathy_message_get_body (message);
676         if (!msg) {
677                 return FALSE;
678         }
679
680         contact = empathy_message_get_receiver (message);
681         if (!contact || !empathy_contact_is_user (contact)) {
682                 return FALSE;
683         }
684
685         to = empathy_contact_get_alias (contact);
686         if (!to) {
687                 return FALSE;
688         }
689
690         flags = empathy_message_get_flags (message);
691         if (flags & TP_CHANNEL_TEXT_MESSAGE_FLAG_SCROLLBACK) {
692                 /* FIXME: Ideally we shouldn't highlight scrollback messages only if they
693                  * have already been received by the user before (and so are in the logs) */
694                 return FALSE;
695         }
696
697         regex = get_highlight_regex_for (to);
698         if (regex != NULL) {
699                 ret_val = g_regex_match (regex, msg, 0, NULL);
700                 g_regex_unref (regex);
701         }
702
703         return ret_val;
704 }
705
706 TpChannelTextMessageType
707 empathy_message_type_from_str (const gchar *type_str)
708 {
709         if (strcmp (type_str, "normal") == 0) {
710                 return TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL;
711         }
712         if (strcmp (type_str, "action") == 0) {
713                 return TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION;
714         }
715         else if (strcmp (type_str, "notice") == 0) {
716                 return TP_CHANNEL_TEXT_MESSAGE_TYPE_NOTICE;
717         }
718         else if (strcmp (type_str, "auto-reply") == 0) {
719                 return TP_CHANNEL_TEXT_MESSAGE_TYPE_AUTO_REPLY;
720         }
721
722         return TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL;
723 }
724
725 const gchar *
726 empathy_message_type_to_str (TpChannelTextMessageType type)
727 {
728         switch (type) {
729         case TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION:
730                 return "action";
731         case TP_CHANNEL_TEXT_MESSAGE_TYPE_NOTICE:
732                 return "notice";
733         case TP_CHANNEL_TEXT_MESSAGE_TYPE_AUTO_REPLY:
734                 return "auto-reply";
735         case TP_CHANNEL_TEXT_MESSAGE_TYPE_DELIVERY_REPORT:
736                 return "delivery-report";
737         case TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL:
738         default:
739                 return "normal";
740         }
741 }
742
743 gboolean
744 empathy_message_is_incoming (EmpathyMessage *message)
745 {
746         EmpathyMessagePriv *priv = GET_PRIV (message);
747
748         g_return_val_if_fail (EMPATHY_IS_MESSAGE (message), FALSE);
749
750         return priv->incoming;
751 }
752
753 gboolean
754 empathy_message_equal (EmpathyMessage *message1, EmpathyMessage *message2)
755 {
756         EmpathyMessagePriv *priv1;
757         EmpathyMessagePriv *priv2;
758
759         g_return_val_if_fail (EMPATHY_IS_MESSAGE (message1), FALSE);
760         g_return_val_if_fail (EMPATHY_IS_MESSAGE (message2), FALSE);
761
762         priv1 = GET_PRIV (message1);
763         priv2 = GET_PRIV (message2);
764
765         if (priv1->timestamp == priv2->timestamp &&
766                         !tp_strdiff (priv1->body, priv2->body)) {
767                 return TRUE;
768         }
769
770         return FALSE;
771 }
772
773 TpChannelTextMessageFlags
774 empathy_message_get_flags (EmpathyMessage *self)
775 {
776         EmpathyMessagePriv *priv = GET_PRIV (self);
777
778         g_return_val_if_fail (EMPATHY_IS_MESSAGE (self), 0);
779
780         return priv->flags;
781 }
782
783 EmpathyMessage *
784 empathy_message_new_from_tp_message (TpMessage *tp_msg,
785                                      gboolean incoming)
786 {
787         EmpathyMessage *message;
788         gchar *body;
789         TpChannelTextMessageFlags flags;
790         gint64 timestamp;
791         gint64 original_timestamp;
792         const GHashTable *part = tp_message_peek (tp_msg, 0);
793         gboolean is_backlog;
794
795         g_return_val_if_fail (TP_IS_MESSAGE (tp_msg), NULL);
796
797         body = tp_message_to_text (tp_msg, &flags);
798
799         timestamp = tp_message_get_sent_timestamp (tp_msg);
800         if (timestamp == 0)
801                 timestamp = tp_message_get_received_timestamp (tp_msg);
802
803         original_timestamp = tp_asv_get_int64 (part,
804                 "original-message-received", NULL);
805
806         is_backlog = (flags & TP_CHANNEL_TEXT_MESSAGE_FLAG_SCROLLBACK) ==
807                 TP_CHANNEL_TEXT_MESSAGE_FLAG_SCROLLBACK;
808
809         message = g_object_new (EMPATHY_TYPE_MESSAGE,
810                 "body", body,
811                 "token", tp_message_get_token (tp_msg),
812                 "supersedes", tp_message_get_supersedes (tp_msg),
813                 "type", tp_message_get_message_type (tp_msg),
814                 "timestamp", timestamp,
815                 "original-timestamp", original_timestamp,
816                 "flags", flags,
817                 "is-backlog", is_backlog,
818                 "incoming", incoming,
819                 "tp-message", tp_msg,
820                 NULL);
821
822         g_free (body);
823         return message;
824 }