1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2004-2007 Imendio AB
4 * Copyright (C) 2007-2008 Collabora Ltd.
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.
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.
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
21 * Authors: Mikael Hallendal <micke@imendio.com>
22 * Xavier Claessens <xclaesse@gmail.com>
29 #include <telepathy-glib/util.h>
31 #include <telepathy-glib/account.h>
32 #include <telepathy-glib/account-manager.h>
34 #include <telepathy-logger/contact.h>
35 #include <telepathy-logger/log-entry.h>
36 #include <telepathy-logger/log-entry-text.h>
37 #endif /* ENABLE_TPL */
39 #include "empathy-message.h"
40 #include "empathy-utils.h"
41 #include "empathy-enum-types.h"
43 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyMessage)
45 TpChannelTextMessageType type
;
46 EmpathyContact
*sender
;
47 EmpathyContact
*receiver
;
53 TpChannelTextMessageFlags flags
;
56 static void empathy_message_finalize (GObject
*object
);
57 static void message_get_property (GObject
*object
,
61 static void message_set_property (GObject
*object
,
66 G_DEFINE_TYPE (EmpathyMessage
, empathy_message
, G_TYPE_OBJECT
);
81 empathy_message_class_init (EmpathyMessageClass
*class)
83 GObjectClass
*object_class
;
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
;
90 g_object_class_install_property (object_class
,
92 g_param_spec_uint ("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
,
99 g_object_class_install_property (object_class
,
101 g_param_spec_object ("sender",
103 "The sender of the message",
104 EMPATHY_TYPE_CONTACT
,
106 g_object_class_install_property (object_class
,
108 g_param_spec_object ("receiver",
110 "The receiver of the message",
111 EMPATHY_TYPE_CONTACT
,
113 g_object_class_install_property (object_class
,
115 g_param_spec_string ("body",
117 "The content of the message",
120 g_object_class_install_property (object_class
,
122 g_param_spec_long ("timestamp",
129 g_object_class_install_property (object_class
,
131 g_param_spec_boolean ("is-backlog",
133 "If the message belongs to history",
138 g_object_class_install_property (object_class
,
140 g_param_spec_boolean ("incoming",
142 "If this is an incoming (as opposed to sent) message",
144 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
));
146 g_object_class_install_property (object_class
,
148 g_param_spec_uint ("flags",
150 "The TpChannelTextMessageFlags of this message",
152 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
));
154 g_type_class_add_private (object_class
, sizeof (EmpathyMessagePriv
));
159 empathy_message_init (EmpathyMessage
*message
)
161 EmpathyMessagePriv
*priv
= G_TYPE_INSTANCE_GET_PRIVATE (message
,
162 EMPATHY_TYPE_MESSAGE
, EmpathyMessagePriv
);
164 message
->priv
= priv
;
165 priv
->timestamp
= empathy_time_get_current ();
169 empathy_message_finalize (GObject
*object
)
171 EmpathyMessagePriv
*priv
;
173 priv
= GET_PRIV (object
);
176 g_object_unref (priv
->sender
);
178 if (priv
->receiver
) {
179 g_object_unref (priv
->receiver
);
184 G_OBJECT_CLASS (empathy_message_parent_class
)->finalize (object
);
188 message_get_property (GObject
*object
,
193 EmpathyMessagePriv
*priv
;
195 priv
= GET_PRIV (object
);
199 g_value_set_uint (value
, priv
->type
);
202 g_value_set_object (value
, priv
->sender
);
205 g_value_set_object (value
, priv
->receiver
);
208 g_value_set_string (value
, priv
->body
);
211 g_value_set_boolean (value
, priv
->incoming
);
214 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, param_id
, pspec
);
220 message_set_property (GObject
*object
,
225 EmpathyMessagePriv
*priv
;
227 priv
= GET_PRIV (object
);
231 empathy_message_set_tptype (EMPATHY_MESSAGE (object
),
232 g_value_get_uint (value
));
235 empathy_message_set_sender (EMPATHY_MESSAGE (object
),
236 EMPATHY_CONTACT (g_value_get_object (value
)));
239 empathy_message_set_receiver (EMPATHY_MESSAGE (object
),
240 EMPATHY_CONTACT (g_value_get_object (value
)));
243 empathy_message_set_body (EMPATHY_MESSAGE (object
),
244 g_value_get_string (value
));
247 priv
->incoming
= g_value_get_boolean (value
);
250 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, param_id
, pspec
);
256 empathy_message_new (const gchar
*body
)
258 return g_object_new (EMPATHY_TYPE_MESSAGE
,
265 empathy_message_from_tpl_log_entry (TplLogEntry
*logentry
)
267 EmpathyMessage
*retval
= NULL
;
268 TpAccountManager
*acc_man
= NULL
;
269 TpAccount
*account
= NULL
;
270 TplContact
*receiver
= NULL
;
271 TplContact
*sender
= NULL
;
274 g_return_val_if_fail (TPL_IS_LOG_ENTRY (logentry
), NULL
);
276 acc_man
= tp_account_manager_dup ();
277 /* FIXME Currently Empathy shows in the log viewer only valid accounts, so it
278 * won't be selected any non-existing (ie removed) account.
279 * When #610455 will be fixed, calling tp_account_manager_ensure_account ()
280 * might add a not existing account to the AM. tp_account_new () probably
281 * will be the best way to handle it.
282 * Note: When creating an EmpathyContact from a TplContact instance, the
283 * TpAccount is passed *only* to let EmpathyContact be able to retrieve the
284 * avatar (contact_get_avatar_filename () need a TpAccount).
285 * If the way EmpathyContact stores the avatar is changes, it might not be
286 * needed anymore any TpAccount passing and the following call will be
288 account
= tp_account_manager_ensure_account (acc_man
,
289 tpl_log_entry_get_account_path (logentry
));
290 g_object_unref (acc_man
);
292 /* TODO Currently only TplLogEntryText exists as subclass of TplLogEntry, in
293 * future more TplLogEntry will exist and EmpathyMessage should probably
294 * be enhanced to support other types of log entries (ie TplLogEntryCall).
296 * For now we just check (simply) that we are dealing with the only supported type,
297 * then there will be a if/then/else or switch handling all the supported
300 if (!TPL_IS_LOG_ENTRY_TEXT (logentry
))
303 body
= g_strdup (tpl_log_entry_text_get_message (
304 TPL_LOG_ENTRY_TEXT (logentry
)));
305 receiver
= tpl_log_entry_text_get_receiver (TPL_LOG_ENTRY_TEXT (logentry
));
306 sender
= tpl_log_entry_text_get_sender (TPL_LOG_ENTRY_TEXT (logentry
));
308 retval
= empathy_message_new (body
);
309 if (receiver
!= NULL
)
310 empathy_message_set_receiver (retval
,
311 empathy_contact_from_tpl_contact (account
, receiver
));
313 empathy_message_set_sender (retval
,
314 empathy_contact_from_tpl_contact (account
, sender
));
316 empathy_message_set_timestamp (retval
,
317 tpl_log_entry_get_timestamp (logentry
));
318 empathy_message_set_id (retval
,
319 tpl_log_entry_text_get_log_id (TPL_LOG_ENTRY_TEXT (logentry
)));
320 empathy_message_set_is_backlog (retval
, FALSE
);
326 #endif /* ENABLE_TPL */
328 TpChannelTextMessageType
329 empathy_message_get_tptype (EmpathyMessage
*message
)
331 EmpathyMessagePriv
*priv
;
333 g_return_val_if_fail (EMPATHY_IS_MESSAGE (message
),
334 TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL
);
336 priv
= GET_PRIV (message
);
342 empathy_message_set_tptype (EmpathyMessage
*message
,
343 TpChannelTextMessageType type
)
345 EmpathyMessagePriv
*priv
;
347 g_return_if_fail (EMPATHY_IS_MESSAGE (message
));
349 priv
= GET_PRIV (message
);
353 g_object_notify (G_OBJECT (message
), "type");
357 empathy_message_get_sender (EmpathyMessage
*message
)
359 EmpathyMessagePriv
*priv
;
361 g_return_val_if_fail (EMPATHY_IS_MESSAGE (message
), NULL
);
363 priv
= GET_PRIV (message
);
369 empathy_message_set_sender (EmpathyMessage
*message
, EmpathyContact
*contact
)
371 EmpathyMessagePriv
*priv
;
372 EmpathyContact
*old_sender
;
374 g_return_if_fail (EMPATHY_IS_MESSAGE (message
));
375 g_return_if_fail (EMPATHY_IS_CONTACT (contact
));
377 priv
= GET_PRIV (message
);
379 old_sender
= priv
->sender
;
380 priv
->sender
= g_object_ref (contact
);
383 g_object_unref (old_sender
);
386 g_object_notify (G_OBJECT (message
), "sender");
390 empathy_message_get_receiver (EmpathyMessage
*message
)
392 EmpathyMessagePriv
*priv
;
394 g_return_val_if_fail (EMPATHY_IS_MESSAGE (message
), NULL
);
396 priv
= GET_PRIV (message
);
398 return priv
->receiver
;
402 empathy_message_set_receiver (EmpathyMessage
*message
, EmpathyContact
*contact
)
404 EmpathyMessagePriv
*priv
;
405 EmpathyContact
*old_receiver
;
407 g_return_if_fail (EMPATHY_IS_MESSAGE (message
));
408 g_return_if_fail (EMPATHY_IS_CONTACT (contact
));
410 priv
= GET_PRIV (message
);
412 old_receiver
= priv
->receiver
;
413 priv
->receiver
= g_object_ref (contact
);
416 g_object_unref (old_receiver
);
419 g_object_notify (G_OBJECT (message
), "receiver");
423 empathy_message_get_body (EmpathyMessage
*message
)
425 EmpathyMessagePriv
*priv
;
427 g_return_val_if_fail (EMPATHY_IS_MESSAGE (message
), NULL
);
429 priv
= GET_PRIV (message
);
435 empathy_message_set_body (EmpathyMessage
*message
,
438 EmpathyMessagePriv
*priv
= GET_PRIV (message
);
440 g_return_if_fail (EMPATHY_IS_MESSAGE (message
));
445 priv
->body
= g_strdup (body
);
450 g_object_notify (G_OBJECT (message
), "body");
454 empathy_message_get_timestamp (EmpathyMessage
*message
)
456 EmpathyMessagePriv
*priv
;
458 g_return_val_if_fail (EMPATHY_IS_MESSAGE (message
), -1);
460 priv
= GET_PRIV (message
);
462 return priv
->timestamp
;
466 empathy_message_set_timestamp (EmpathyMessage
*message
,
469 EmpathyMessagePriv
*priv
;
471 g_return_if_fail (EMPATHY_IS_MESSAGE (message
));
472 g_return_if_fail (timestamp
>= -1);
474 priv
= GET_PRIV (message
);
476 if (timestamp
<= 0) {
477 priv
->timestamp
= empathy_time_get_current ();
479 priv
->timestamp
= timestamp
;
482 g_object_notify (G_OBJECT (message
), "timestamp");
486 empathy_message_is_backlog (EmpathyMessage
*message
)
488 EmpathyMessagePriv
*priv
;
490 g_return_val_if_fail (EMPATHY_IS_MESSAGE (message
), FALSE
);
492 priv
= GET_PRIV (message
);
494 return priv
->is_backlog
;
498 empathy_message_set_is_backlog (EmpathyMessage
*message
,
501 EmpathyMessagePriv
*priv
;
503 g_return_if_fail (EMPATHY_IS_MESSAGE (message
));
505 priv
= GET_PRIV (message
);
507 priv
->is_backlog
= is_backlog
;
509 g_object_notify (G_OBJECT (message
), "is-backlog");
512 #define IS_SEPARATOR(ch) (ch == ' ' || ch == ',' || ch == '.' || ch == ':')
514 empathy_message_should_highlight (EmpathyMessage
*message
)
516 EmpathyContact
*contact
;
517 const gchar
*msg
, *to
;
518 gchar
*cf_msg
, *cf_to
;
521 TpChannelTextMessageFlags flags
;
523 g_return_val_if_fail (EMPATHY_IS_MESSAGE (message
), FALSE
);
527 msg
= empathy_message_get_body (message
);
532 contact
= empathy_message_get_receiver (message
);
533 if (!contact
|| !empathy_contact_is_user (contact
)) {
537 to
= empathy_contact_get_name (contact
);
542 flags
= empathy_message_get_flags (message
);
543 if (flags
& TP_CHANNEL_TEXT_MESSAGE_FLAG_SCROLLBACK
) {
544 /* FIXME: Ideally we shouldn't highlight scrollback messages only if they
545 * have already been received by the user before (and so are in the logs) */
549 cf_msg
= g_utf8_casefold (msg
, -1);
550 cf_to
= g_utf8_casefold (to
, -1);
552 ch
= strstr (cf_msg
, cf_to
);
557 /* Not first in the message */
558 if (!IS_SEPARATOR (*(ch
- 1))) {
563 ch
= ch
+ strlen (cf_to
);
564 if (ch
>= cf_msg
+ strlen (cf_msg
)) {
569 if (IS_SEPARATOR (*ch
)) {
581 TpChannelTextMessageType
582 empathy_message_type_from_str (const gchar
*type_str
)
584 if (strcmp (type_str
, "normal") == 0) {
585 return TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL
;
587 if (strcmp (type_str
, "action") == 0) {
588 return TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION
;
590 else if (strcmp (type_str
, "notice") == 0) {
591 return TP_CHANNEL_TEXT_MESSAGE_TYPE_NOTICE
;
593 else if (strcmp (type_str
, "auto-reply") == 0) {
594 return TP_CHANNEL_TEXT_MESSAGE_TYPE_AUTO_REPLY
;
597 return TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL
;
601 empathy_message_type_to_str (TpChannelTextMessageType type
)
604 case TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION
:
606 case TP_CHANNEL_TEXT_MESSAGE_TYPE_NOTICE
:
608 case TP_CHANNEL_TEXT_MESSAGE_TYPE_AUTO_REPLY
:
616 empathy_message_get_id (EmpathyMessage
*message
)
618 EmpathyMessagePriv
*priv
= GET_PRIV (message
);
620 g_return_val_if_fail (EMPATHY_IS_MESSAGE (message
), 0);
626 empathy_message_set_id (EmpathyMessage
*message
, guint id
)
628 EmpathyMessagePriv
*priv
= GET_PRIV (message
);
634 empathy_message_set_incoming (EmpathyMessage
*message
, gboolean incoming
)
636 EmpathyMessagePriv
*priv
;
638 g_return_if_fail (EMPATHY_IS_MESSAGE (message
));
640 priv
= GET_PRIV (message
);
642 priv
->incoming
= incoming
;
644 g_object_notify (G_OBJECT (message
), "incoming");
648 empathy_message_is_incoming (EmpathyMessage
*message
)
650 EmpathyMessagePriv
*priv
= GET_PRIV (message
);
652 g_return_val_if_fail (EMPATHY_IS_MESSAGE (message
), FALSE
);
654 return priv
->incoming
;
658 empathy_message_equal (EmpathyMessage
*message1
, EmpathyMessage
*message2
)
660 EmpathyMessagePriv
*priv1
;
661 EmpathyMessagePriv
*priv2
;
663 g_return_val_if_fail (EMPATHY_IS_MESSAGE (message1
), FALSE
);
664 g_return_val_if_fail (EMPATHY_IS_MESSAGE (message2
), FALSE
);
666 priv1
= GET_PRIV (message1
);
667 priv2
= GET_PRIV (message2
);
669 if (priv1
->timestamp
== priv2
->timestamp
&&
670 !tp_strdiff (priv1
->body
, priv2
->body
)) {
677 TpChannelTextMessageFlags
678 empathy_message_get_flags (EmpathyMessage
*self
)
680 EmpathyMessagePriv
*priv
= GET_PRIV (self
);
682 g_return_val_if_fail (EMPATHY_IS_MESSAGE (self
), 0);
688 empathy_message_set_flags (EmpathyMessage
*self
,
689 TpChannelTextMessageFlags flags
)
691 EmpathyMessagePriv
*priv
;
693 g_return_if_fail (EMPATHY_IS_MESSAGE (self
));
695 priv
= GET_PRIV (self
);
699 g_object_notify (G_OBJECT (self
), "flags");