/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* Copyright (C) 2004-2007 Imendio AB
- * Copyright (C) 2007 Collabora Ltd.
+ * Copyright (C) 2007-2008 Collabora Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
*
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
*
* Authors: Mikael Hallendal <micke@imendio.com>
* Xavier Claessens <xclaesse@gmail.com>
#include "config.h"
-#include "empathy-message.h"
-
-#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_MESSAGE, EmpathyMessagePriv))
+#include <string.h>
-typedef struct _EmpathyMessagePriv EmpathyMessagePriv;
+#include <telepathy-glib/util.h>
+#include <telepathy-glib/account.h>
+#include <telepathy-glib/account-manager.h>
-struct _EmpathyMessagePriv {
- EmpathyMessageType type;
- EmpathyContact *sender;
- EmpathyContact *receiver;
- gchar *body;
- EmpathyTime timestamp;
+#include <telepathy-logger/entity.h>
+#include <telepathy-logger/entry.h>
+#include <telepathy-logger/entry-text.h>
-};
+#include "empathy-message.h"
+#include "empathy-utils.h"
+#include "empathy-enum-types.h"
+
+#define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyMessage)
+typedef struct {
+ TpChannelTextMessageType type;
+ EmpathyContact *sender;
+ EmpathyContact *receiver;
+ gchar *body;
+ time_t timestamp;
+ gboolean is_backlog;
+ guint id;
+ gboolean incoming;
+ TpChannelTextMessageFlags flags;
+} EmpathyMessagePriv;
-static void empathy_message_class_init (EmpathyMessageClass *class);
-static void empathy_message_init (EmpathyMessage *message);
static void empathy_message_finalize (GObject *object);
static void message_get_property (GObject *object,
guint param_id,
const GValue *value,
GParamSpec *pspec);
+G_DEFINE_TYPE (EmpathyMessage, empathy_message, G_TYPE_OBJECT);
+
enum {
PROP_0,
PROP_TYPE,
PROP_RECEIVER,
PROP_BODY,
PROP_TIMESTAMP,
+ PROP_IS_BACKLOG,
+ PROP_INCOMING,
+ PROP_FLAGS,
};
-static gpointer parent_class = NULL;
-
-GType
-empathy_message_get_gtype (void)
-{
- static GType type = 0;
-
- if (!type) {
- static const GTypeInfo info = {
- sizeof (EmpathyMessageClass),
- NULL, /* base_init */
- NULL, /* base_finalize */
- (GClassInitFunc) empathy_message_class_init,
- NULL, /* class_finalize */
- NULL, /* class_data */
- sizeof (EmpathyMessage),
- 0, /* n_preallocs */
- (GInstanceInitFunc) empathy_message_init
- };
-
- type = g_type_register_static (G_TYPE_OBJECT,
- "EmpathyMessage",
- &info, 0);
- }
-
- return type;
-}
-
static void
empathy_message_class_init (EmpathyMessageClass *class)
{
GObjectClass *object_class;
object_class = G_OBJECT_CLASS (class);
- parent_class = g_type_class_peek_parent (class);
-
object_class->finalize = empathy_message_finalize;
object_class->get_property = message_get_property;
object_class->set_property = message_set_property;
g_object_class_install_property (object_class,
PROP_TYPE,
- g_param_spec_int ("type",
- "Message Type",
- "The type of message",
- EMPATHY_MESSAGE_TYPE_NORMAL,
- EMPATHY_MESSAGE_TYPE_LAST,
- EMPATHY_MESSAGE_TYPE_NORMAL,
- G_PARAM_READWRITE));
+ g_param_spec_uint ("type",
+ "Message Type",
+ "The type of message",
+ TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL,
+ TP_CHANNEL_TEXT_MESSAGE_TYPE_AUTO_REPLY,
+ TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL,
+ G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_SENDER,
g_param_spec_object ("sender",
G_MAXLONG,
-1,
G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_IS_BACKLOG,
+ g_param_spec_boolean ("is-backlog",
+ "History message",
+ "If the message belongs to history",
+ FALSE,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_INCOMING,
+ g_param_spec_boolean ("incoming",
+ "Incoming",
+ "If this is an incoming (as opposed to sent) message",
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (object_class,
+ PROP_FLAGS,
+ g_param_spec_uint ("flags",
+ "Flags",
+ "The TpChannelTextMessageFlags of this message",
+ 0, G_MAXUINT, 0,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
g_type_class_add_private (object_class, sizeof (EmpathyMessagePriv));
}
static void
empathy_message_init (EmpathyMessage *message)
{
- EmpathyMessagePriv *priv;
-
- priv = GET_PRIV (message);
+ EmpathyMessagePriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (message,
+ EMPATHY_TYPE_MESSAGE, EmpathyMessagePriv);
+ message->priv = priv;
priv->timestamp = empathy_time_get_current ();
}
g_free (priv->body);
- (G_OBJECT_CLASS (parent_class)->finalize) (object);
+ G_OBJECT_CLASS (empathy_message_parent_class)->finalize (object);
}
static void
switch (param_id) {
case PROP_TYPE:
- g_value_set_int (value, priv->type);
+ g_value_set_uint (value, priv->type);
break;
case PROP_SENDER:
g_value_set_object (value, priv->sender);
case PROP_BODY:
g_value_set_string (value, priv->body);
break;
+ case PROP_INCOMING:
+ g_value_set_boolean (value, priv->incoming);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
switch (param_id) {
case PROP_TYPE:
- empathy_message_set_type (EMPATHY_MESSAGE (object),
- g_value_get_int (value));
+ empathy_message_set_tptype (EMPATHY_MESSAGE (object),
+ g_value_get_uint (value));
break;
case PROP_SENDER:
empathy_message_set_sender (EMPATHY_MESSAGE (object),
empathy_message_set_body (EMPATHY_MESSAGE (object),
g_value_get_string (value));
break;
+ case PROP_INCOMING:
+ priv->incoming = g_value_get_boolean (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
NULL);
}
-EmpathyMessageType
-empathy_message_get_type (EmpathyMessage *message)
+EmpathyMessage *
+empathy_message_from_tpl_log_entry (TplEntry *logentry)
+{
+ EmpathyMessage *retval = NULL;
+ TpAccountManager *acc_man = NULL;
+ TpAccount *account = NULL;
+ TplEntity *receiver = NULL;
+ TplEntity *sender = NULL;
+ gchar *body= NULL;
+ EmpathyContact *contact;
+
+ g_return_val_if_fail (TPL_IS_ENTRY (logentry), NULL);
+
+ acc_man = tp_account_manager_dup ();
+ /* FIXME Currently Empathy shows in the log viewer only valid accounts, so it
+ * won't be selected any non-existing (ie removed) account.
+ * When #610455 will be fixed, calling tp_account_manager_ensure_account ()
+ * might add a not existing account to the AM. tp_account_new () probably
+ * will be the best way to handle it.
+ * Note: When creating an EmpathyContact from a TplEntity instance, the
+ * TpAccount is passed *only* to let EmpathyContact be able to retrieve the
+ * avatar (contact_get_avatar_filename () need a TpAccount).
+ * If the way EmpathyContact stores the avatar is changes, it might not be
+ * needed anymore any TpAccount passing and the following call will be
+ * useless */
+ account = tp_account_manager_ensure_account (acc_man,
+ tpl_entry_get_account_path (logentry));
+ g_object_unref (acc_man);
+
+ /* TODO Currently only TplLogEntryText exists as subclass of TplEntry, in
+ * future more TplEntry will exist and EmpathyMessage should probably
+ * be enhanced to support other types of log entries (ie TplLogEntryCall).
+ *
+ * For now we just check (simply) that we are dealing with the only supported type,
+ * then there will be a if/then/else or switch handling all the supported
+ * cases.
+ */
+ if (!TPL_IS_ENTRY_TEXT (logentry))
+ return NULL;
+
+ body = g_strdup (tpl_entry_text_get_message (
+ TPL_ENTRY_TEXT (logentry)));
+ receiver = tpl_entry_get_receiver (logentry);
+ sender = tpl_entry_get_sender (logentry);
+
+ retval = empathy_message_new (body);
+ if (receiver != NULL) {
+ contact = empathy_contact_from_tpl_contact (account, receiver);
+ empathy_message_set_receiver (retval, contact);
+ g_object_unref (contact);
+ }
+
+ if (sender != NULL) {
+ contact = empathy_contact_from_tpl_contact (account, sender);
+ empathy_message_set_sender (retval, contact);
+ g_object_unref (contact);
+ }
+
+ empathy_message_set_timestamp (retval,
+ tpl_entry_get_timestamp (logentry));
+ empathy_message_set_id (retval,
+ tpl_entry_text_get_pending_msg_id (TPL_ENTRY_TEXT (logentry)));
+ empathy_message_set_is_backlog (retval, TRUE);
+
+ g_free (body);
+
+ return retval;
+}
+
+TpChannelTextMessageType
+empathy_message_get_tptype (EmpathyMessage *message)
{
EmpathyMessagePriv *priv;
g_return_val_if_fail (EMPATHY_IS_MESSAGE (message),
- EMPATHY_MESSAGE_TYPE_NORMAL);
+ TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL);
priv = GET_PRIV (message);
}
void
-empathy_message_set_type (EmpathyMessage *message,
- EmpathyMessageType type)
+empathy_message_set_tptype (EmpathyMessage *message,
+ TpChannelTextMessageType type)
{
EmpathyMessagePriv *priv;
void
empathy_message_set_body (EmpathyMessage *message,
- const gchar *body)
+ const gchar *body)
{
- EmpathyMessagePriv *priv;
- EmpathyMessageType type;
+ EmpathyMessagePriv *priv = GET_PRIV (message);
g_return_if_fail (EMPATHY_IS_MESSAGE (message));
- priv = GET_PRIV (message);
-
g_free (priv->body);
- priv->body = NULL;
-
- type = EMPATHY_MESSAGE_TYPE_NORMAL;
- if (g_str_has_prefix (body, "/me")) {
- type = EMPATHY_MESSAGE_TYPE_ACTION;
- body += 4;
- }
- else if (g_str_has_prefix (body, "/say")) {
- body += 5;
- }
if (body) {
priv->body = g_strdup (body);
- }
-
- if (type != priv->type) {
- empathy_message_set_type (message, type);
+ } else {
+ priv->body = NULL;
}
g_object_notify (G_OBJECT (message), "body");
}
-EmpathyTime
+time_t
empathy_message_get_timestamp (EmpathyMessage *message)
{
EmpathyMessagePriv *priv;
void
empathy_message_set_timestamp (EmpathyMessage *message,
- EmpathyTime timestamp)
+ time_t timestamp)
{
EmpathyMessagePriv *priv;
g_object_notify (G_OBJECT (message), "timestamp");
}
+gboolean
+empathy_message_is_backlog (EmpathyMessage *message)
+{
+ EmpathyMessagePriv *priv;
+
+ g_return_val_if_fail (EMPATHY_IS_MESSAGE (message), FALSE);
+
+ priv = GET_PRIV (message);
+
+ return priv->is_backlog;
+}
+
+void
+empathy_message_set_is_backlog (EmpathyMessage *message,
+ gboolean is_backlog)
+{
+ EmpathyMessagePriv *priv;
+
+ g_return_if_fail (EMPATHY_IS_MESSAGE (message));
+
+ priv = GET_PRIV (message);
+
+ priv->is_backlog = is_backlog;
+
+ g_object_notify (G_OBJECT (message), "is-backlog");
+}
+
+#define IS_SEPARATOR(ch) (ch == ' ' || ch == ',' || ch == '.' || ch == ':')
+gboolean
+empathy_message_should_highlight (EmpathyMessage *message)
+{
+ EmpathyContact *contact;
+ const gchar *msg, *to;
+ gchar *cf_msg, *cf_to;
+ gchar *ch;
+ gboolean ret_val;
+ TpChannelTextMessageFlags flags;
+
+ g_return_val_if_fail (EMPATHY_IS_MESSAGE (message), FALSE);
+
+ ret_val = FALSE;
+
+ msg = empathy_message_get_body (message);
+ if (!msg) {
+ return FALSE;
+ }
+
+ contact = empathy_message_get_receiver (message);
+ if (!contact || !empathy_contact_is_user (contact)) {
+ return FALSE;
+ }
+
+ to = empathy_contact_get_alias (contact);
+ if (!to) {
+ return FALSE;
+ }
+
+ flags = empathy_message_get_flags (message);
+ if (flags & TP_CHANNEL_TEXT_MESSAGE_FLAG_SCROLLBACK) {
+ /* FIXME: Ideally we shouldn't highlight scrollback messages only if they
+ * have already been received by the user before (and so are in the logs) */
+ return FALSE;
+ }
+
+ cf_msg = g_utf8_casefold (msg, -1);
+ cf_to = g_utf8_casefold (to, -1);
+
+ ch = strstr (cf_msg, cf_to);
+ if (ch == NULL) {
+ goto finished;
+ }
+ if (ch != cf_msg) {
+ /* Not first in the message */
+ if (!IS_SEPARATOR (*(ch - 1))) {
+ goto finished;
+ }
+ }
+
+ ch = ch + strlen (cf_to);
+ if (ch >= cf_msg + strlen (cf_msg)) {
+ ret_val = TRUE;
+ goto finished;
+ }
+
+ if (IS_SEPARATOR (*ch)) {
+ ret_val = TRUE;
+ goto finished;
+ }
+
+finished:
+ g_free (cf_msg);
+ g_free (cf_to);
+
+ return ret_val;
+}
+
+TpChannelTextMessageType
+empathy_message_type_from_str (const gchar *type_str)
+{
+ if (strcmp (type_str, "normal") == 0) {
+ return TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL;
+ }
+ if (strcmp (type_str, "action") == 0) {
+ return TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION;
+ }
+ else if (strcmp (type_str, "notice") == 0) {
+ return TP_CHANNEL_TEXT_MESSAGE_TYPE_NOTICE;
+ }
+ else if (strcmp (type_str, "auto-reply") == 0) {
+ return TP_CHANNEL_TEXT_MESSAGE_TYPE_AUTO_REPLY;
+ }
+
+ return TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL;
+}
+
+const gchar *
+empathy_message_type_to_str (TpChannelTextMessageType type)
+{
+ switch (type) {
+ case TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION:
+ return "action";
+ case TP_CHANNEL_TEXT_MESSAGE_TYPE_NOTICE:
+ return "notice";
+ case TP_CHANNEL_TEXT_MESSAGE_TYPE_AUTO_REPLY:
+ return "auto-reply";
+ case TP_CHANNEL_TEXT_MESSAGE_TYPE_DELIVERY_REPORT:
+ return "delivery-report";
+ case TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL:
+ default:
+ return "normal";
+ }
+}
+
+guint
+empathy_message_get_id (EmpathyMessage *message)
+{
+ EmpathyMessagePriv *priv = GET_PRIV (message);
+
+ g_return_val_if_fail (EMPATHY_IS_MESSAGE (message), 0);
+
+ return priv->id;
+}
+
+void
+empathy_message_set_id (EmpathyMessage *message, guint id)
+{
+ EmpathyMessagePriv *priv = GET_PRIV (message);
+
+ priv->id = id;
+}
+
+void
+empathy_message_set_incoming (EmpathyMessage *message, gboolean incoming)
+{
+ EmpathyMessagePriv *priv;
+
+ g_return_if_fail (EMPATHY_IS_MESSAGE (message));
+
+ priv = GET_PRIV (message);
+
+ priv->incoming = incoming;
+
+ g_object_notify (G_OBJECT (message), "incoming");
+}
+
+gboolean
+empathy_message_is_incoming (EmpathyMessage *message)
+{
+ EmpathyMessagePriv *priv = GET_PRIV (message);
+
+ g_return_val_if_fail (EMPATHY_IS_MESSAGE (message), FALSE);
+
+ return priv->incoming;
+}
+
+gboolean
+empathy_message_equal (EmpathyMessage *message1, EmpathyMessage *message2)
+{
+ EmpathyMessagePriv *priv1;
+ EmpathyMessagePriv *priv2;
+
+ g_return_val_if_fail (EMPATHY_IS_MESSAGE (message1), FALSE);
+ g_return_val_if_fail (EMPATHY_IS_MESSAGE (message2), FALSE);
+
+ priv1 = GET_PRIV (message1);
+ priv2 = GET_PRIV (message2);
+
+ if (priv1->timestamp == priv2->timestamp &&
+ !tp_strdiff (priv1->body, priv2->body)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+TpChannelTextMessageFlags
+empathy_message_get_flags (EmpathyMessage *self)
+{
+ EmpathyMessagePriv *priv = GET_PRIV (self);
+
+ g_return_val_if_fail (EMPATHY_IS_MESSAGE (self), 0);
+
+ return priv->flags;
+}
+
+void
+empathy_message_set_flags (EmpathyMessage *self,
+ TpChannelTextMessageFlags flags)
+{
+ EmpathyMessagePriv *priv;
+
+ g_return_if_fail (EMPATHY_IS_MESSAGE (self));
+
+ priv = GET_PRIV (self);
+
+ priv->flags = flags;
+
+ g_object_notify (G_OBJECT (self), "flags");
+}