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