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