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