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 "empathy-message.h"
32 #include "empathy-utils.h"
33 #include "empathy-enum-types.h"
35 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyMessage)
37 TpChannelTextMessageType type;
38 EmpathyContact *sender;
39 EmpathyContact *receiver;
47 static void empathy_message_finalize (GObject *object);
48 static void message_get_property (GObject *object,
52 static void message_set_property (GObject *object,
57 G_DEFINE_TYPE (EmpathyMessage, empathy_message, G_TYPE_OBJECT);
71 empathy_message_class_init (EmpathyMessageClass *class)
73 GObjectClass *object_class;
75 object_class = G_OBJECT_CLASS (class);
76 object_class->finalize = empathy_message_finalize;
77 object_class->get_property = message_get_property;
78 object_class->set_property = message_set_property;
80 g_object_class_install_property (object_class,
82 g_param_spec_uint ("type",
84 "The type of message",
85 TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL,
86 TP_CHANNEL_TEXT_MESSAGE_TYPE_AUTO_REPLY,
87 TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL,
89 g_object_class_install_property (object_class,
91 g_param_spec_object ("sender",
93 "The sender of the message",
96 g_object_class_install_property (object_class,
98 g_param_spec_object ("receiver",
100 "The receiver of the message",
101 EMPATHY_TYPE_CONTACT,
103 g_object_class_install_property (object_class,
105 g_param_spec_string ("body",
107 "The content of the message",
110 g_object_class_install_property (object_class,
112 g_param_spec_long ("timestamp",
119 g_object_class_install_property (object_class,
121 g_param_spec_boolean ("is-backlog",
123 "If the message belongs to history",
128 g_object_class_install_property (object_class,
130 g_param_spec_boolean ("incoming",
132 "If this is an incoming (as opposed to sent) message",
134 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
136 g_type_class_add_private (object_class, sizeof (EmpathyMessagePriv));
141 empathy_message_init (EmpathyMessage *message)
143 EmpathyMessagePriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (message,
144 EMPATHY_TYPE_MESSAGE, EmpathyMessagePriv);
146 message->priv = priv;
147 priv->timestamp = empathy_time_get_current ();
151 empathy_message_finalize (GObject *object)
153 EmpathyMessagePriv *priv;
155 priv = GET_PRIV (object);
158 g_object_unref (priv->sender);
160 if (priv->receiver) {
161 g_object_unref (priv->receiver);
166 G_OBJECT_CLASS (empathy_message_parent_class)->finalize (object);
170 message_get_property (GObject *object,
175 EmpathyMessagePriv *priv;
177 priv = GET_PRIV (object);
181 g_value_set_uint (value, priv->type);
184 g_value_set_object (value, priv->sender);
187 g_value_set_object (value, priv->receiver);
190 g_value_set_string (value, priv->body);
193 g_value_set_boolean (value, priv->incoming);
196 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
202 message_set_property (GObject *object,
207 EmpathyMessagePriv *priv;
209 priv = GET_PRIV (object);
213 empathy_message_set_tptype (EMPATHY_MESSAGE (object),
214 g_value_get_uint (value));
217 empathy_message_set_sender (EMPATHY_MESSAGE (object),
218 EMPATHY_CONTACT (g_value_get_object (value)));
221 empathy_message_set_receiver (EMPATHY_MESSAGE (object),
222 EMPATHY_CONTACT (g_value_get_object (value)));
225 empathy_message_set_body (EMPATHY_MESSAGE (object),
226 g_value_get_string (value));
229 priv->incoming = g_value_get_boolean (value);
232 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
238 has_prefix_case (const gchar *s,
241 return g_ascii_strncasecmp (s, prefix, strlen (prefix)) == 0;
245 * Constructs an EmpathyMessage based on user input, which may include "/me"
248 * Returns: an #EmpathyMessage if @message could be parsed, or %NULL if
249 * @message was an unknown command.
252 empathy_message_new_from_entry (const gchar *message)
254 TpChannelTextMessageType t = TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL;
256 g_return_val_if_fail (message != NULL, NULL);
258 if (message[0] == '/') {
259 if (g_ascii_strcasecmp (message, "/me") == 0) {
261 t = TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION;
262 } else if (has_prefix_case (message, "/me ")) {
263 message += strlen ("/me ");
264 t = TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION;
265 } else if (has_prefix_case (message, "/say ")) {
266 message += strlen ("/say ");
268 /* Also allow messages with two slashes before the
269 * first space, so it is possible to send a /unix/path.
270 * This heuristic is kind of crap.
272 gboolean second_slash = FALSE;
273 const gchar *m = message + 1;
275 while (!second_slash && *m != '\0' && *m != ' ') {
287 return g_object_new (EMPATHY_TYPE_MESSAGE,
294 empathy_message_new (const gchar *body)
296 return g_object_new (EMPATHY_TYPE_MESSAGE,
301 TpChannelTextMessageType
302 empathy_message_get_tptype (EmpathyMessage *message)
304 EmpathyMessagePriv *priv;
306 g_return_val_if_fail (EMPATHY_IS_MESSAGE (message),
307 TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL);
309 priv = GET_PRIV (message);
315 empathy_message_set_tptype (EmpathyMessage *message,
316 TpChannelTextMessageType type)
318 EmpathyMessagePriv *priv;
320 g_return_if_fail (EMPATHY_IS_MESSAGE (message));
322 priv = GET_PRIV (message);
326 g_object_notify (G_OBJECT (message), "type");
330 empathy_message_get_sender (EmpathyMessage *message)
332 EmpathyMessagePriv *priv;
334 g_return_val_if_fail (EMPATHY_IS_MESSAGE (message), NULL);
336 priv = GET_PRIV (message);
342 empathy_message_set_sender (EmpathyMessage *message, EmpathyContact *contact)
344 EmpathyMessagePriv *priv;
345 EmpathyContact *old_sender;
347 g_return_if_fail (EMPATHY_IS_MESSAGE (message));
348 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
350 priv = GET_PRIV (message);
352 old_sender = priv->sender;
353 priv->sender = g_object_ref (contact);
356 g_object_unref (old_sender);
359 g_object_notify (G_OBJECT (message), "sender");
363 empathy_message_get_receiver (EmpathyMessage *message)
365 EmpathyMessagePriv *priv;
367 g_return_val_if_fail (EMPATHY_IS_MESSAGE (message), NULL);
369 priv = GET_PRIV (message);
371 return priv->receiver;
375 empathy_message_set_receiver (EmpathyMessage *message, EmpathyContact *contact)
377 EmpathyMessagePriv *priv;
378 EmpathyContact *old_receiver;
380 g_return_if_fail (EMPATHY_IS_MESSAGE (message));
381 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
383 priv = GET_PRIV (message);
385 old_receiver = priv->receiver;
386 priv->receiver = g_object_ref (contact);
389 g_object_unref (old_receiver);
392 g_object_notify (G_OBJECT (message), "receiver");
396 empathy_message_get_body (EmpathyMessage *message)
398 EmpathyMessagePriv *priv;
400 g_return_val_if_fail (EMPATHY_IS_MESSAGE (message), NULL);
402 priv = GET_PRIV (message);
408 empathy_message_set_body (EmpathyMessage *message,
411 EmpathyMessagePriv *priv = GET_PRIV (message);
413 g_return_if_fail (EMPATHY_IS_MESSAGE (message));
418 priv->body = g_strdup (body);
423 g_object_notify (G_OBJECT (message), "body");
427 empathy_message_get_timestamp (EmpathyMessage *message)
429 EmpathyMessagePriv *priv;
431 g_return_val_if_fail (EMPATHY_IS_MESSAGE (message), -1);
433 priv = GET_PRIV (message);
435 return priv->timestamp;
439 empathy_message_set_timestamp (EmpathyMessage *message,
442 EmpathyMessagePriv *priv;
444 g_return_if_fail (EMPATHY_IS_MESSAGE (message));
445 g_return_if_fail (timestamp >= -1);
447 priv = GET_PRIV (message);
449 if (timestamp <= 0) {
450 priv->timestamp = empathy_time_get_current ();
452 priv->timestamp = timestamp;
455 g_object_notify (G_OBJECT (message), "timestamp");
459 empathy_message_is_backlog (EmpathyMessage *message)
461 EmpathyMessagePriv *priv;
463 g_return_val_if_fail (EMPATHY_IS_MESSAGE (message), FALSE);
465 priv = GET_PRIV (message);
467 return priv->is_backlog;
471 empathy_message_set_is_backlog (EmpathyMessage *message,
474 EmpathyMessagePriv *priv;
476 g_return_if_fail (EMPATHY_IS_MESSAGE (message));
478 priv = GET_PRIV (message);
480 priv->is_backlog = is_backlog;
482 g_object_notify (G_OBJECT (message), "is-backlog");
485 #define IS_SEPARATOR(ch) (ch == ' ' || ch == ',' || ch == '.' || ch == ':')
487 empathy_message_should_highlight (EmpathyMessage *message)
489 EmpathyContact *contact;
490 const gchar *msg, *to;
491 gchar *cf_msg, *cf_to;
495 g_return_val_if_fail (EMPATHY_IS_MESSAGE (message), FALSE);
499 msg = empathy_message_get_body (message);
504 contact = empathy_message_get_receiver (message);
505 if (!contact || !empathy_contact_is_user (contact)) {
509 to = empathy_contact_get_name (contact);
514 cf_msg = g_utf8_casefold (msg, -1);
515 cf_to = g_utf8_casefold (to, -1);
517 ch = strstr (cf_msg, cf_to);
522 /* Not first in the message */
523 if (!IS_SEPARATOR (*(ch - 1))) {
528 ch = ch + strlen (cf_to);
529 if (ch >= cf_msg + strlen (cf_msg)) {
534 if (IS_SEPARATOR (*ch)) {
546 TpChannelTextMessageType
547 empathy_message_type_from_str (const gchar *type_str)
549 if (strcmp (type_str, "normal") == 0) {
550 return TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL;
552 if (strcmp (type_str, "action") == 0) {
553 return TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION;
555 else if (strcmp (type_str, "notice") == 0) {
556 return TP_CHANNEL_TEXT_MESSAGE_TYPE_NOTICE;
558 else if (strcmp (type_str, "auto-reply") == 0) {
559 return TP_CHANNEL_TEXT_MESSAGE_TYPE_AUTO_REPLY;
562 return TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL;
566 empathy_message_type_to_str (TpChannelTextMessageType type)
569 case TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION:
571 case TP_CHANNEL_TEXT_MESSAGE_TYPE_NOTICE:
573 case TP_CHANNEL_TEXT_MESSAGE_TYPE_AUTO_REPLY:
581 empathy_message_get_id (EmpathyMessage *message)
583 EmpathyMessagePriv *priv = GET_PRIV (message);
585 g_return_val_if_fail (EMPATHY_IS_MESSAGE (message), 0);
591 empathy_message_set_id (EmpathyMessage *message, guint id)
593 EmpathyMessagePriv *priv = GET_PRIV (message);
599 empathy_message_set_incoming (EmpathyMessage *message, gboolean incoming)
601 EmpathyMessagePriv *priv;
603 g_return_if_fail (EMPATHY_IS_MESSAGE (message));
605 priv = GET_PRIV (message);
607 priv->incoming = incoming;
609 g_object_notify (G_OBJECT (message), "incoming");
613 empathy_message_is_incoming (EmpathyMessage *message)
615 EmpathyMessagePriv *priv = GET_PRIV (message);
617 g_return_val_if_fail (EMPATHY_IS_MESSAGE (message), FALSE);
619 return priv->incoming;
623 empathy_message_equal (EmpathyMessage *message1, EmpathyMessage *message2)
625 EmpathyMessagePriv *priv1;
626 EmpathyMessagePriv *priv2;
628 g_return_val_if_fail (EMPATHY_IS_MESSAGE (message1), FALSE);
629 g_return_val_if_fail (EMPATHY_IS_MESSAGE (message2), FALSE);
631 priv1 = GET_PRIV (message1);
632 priv2 = GET_PRIV (message2);
634 if (priv1->id == priv2->id && !tp_strdiff (priv1->body, priv2->body)) {