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);
670 if (priv1->timestamp == priv2->timestamp &&
671 !tp_strdiff (priv1->body, priv2->body)) {
673 if (priv1->id == priv2->id && !tp_strdiff (priv1->body, priv2->body)) {
674 #endif /* ENABLE_TPL */
681 TpChannelTextMessageFlags
682 empathy_message_get_flags (EmpathyMessage *self)
684 EmpathyMessagePriv *priv = GET_PRIV (self);
686 g_return_val_if_fail (EMPATHY_IS_MESSAGE (self), 0);
692 empathy_message_set_flags (EmpathyMessage *self,
693 TpChannelTextMessageFlags flags)
695 EmpathyMessagePriv *priv;
697 g_return_if_fail (EMPATHY_IS_MESSAGE (self));
699 priv = GET_PRIV (self);
703 g_object_notify (G_OBJECT (self), "flags");