telepathygabble/src/text-mixin.c
changeset 10 59927b2d3b75
parent 0 d0f3a028347a
--- a/telepathygabble/src/text-mixin.c	Tue Feb 02 01:10:06 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,819 +0,0 @@
-/*
- * text-mixin.c - Source for GabbleTextMixin
- * Copyright (C) 2006 Collabora Ltd.
- * 
- *   @author Ole Andre Vadla Ravnaas <ole.andre.ravnaas@collabora.co.uk>
- *   @author Robert McQueen <robert.mcqueen@collabora.co.uk>
- *   @author Senko Rasic <senko@senko.net>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-
-#include "loudmouth/loudmouth.h"
-#include <dbus/dbus-glib.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
-#include "telepathy-constants.h"
-#include "telepathy-errors.h"
-
-
-#include "debug.h"
-#include "gabble-connection.h"
-#include "namespaces.h"
-#include "roster.h"
-#include "util.h"
-
-#include "text-mixin.h"
-#include "text-mixin-signals-marshal.h"
-
-#include "gabble_enums.h"
-
-#define _GNU_SOURCE /* Needed for strptime (_XOPEN_SOURCE can also be used). */
-#define DEBUG_FLAG GABBLE_DEBUG_IM
-#define TP_TYPE_PENDING_MESSAGE_STRUCT (dbus_g_type_get_struct ("GValueArray", \
-      G_TYPE_UINT, \
-      G_TYPE_UINT, \
-      G_TYPE_UINT, \
-      G_TYPE_UINT, \
-      G_TYPE_UINT, \
-      G_TYPE_STRING, \
-      G_TYPE_INVALID))
-
-/* allocator */
-
-#ifdef DEBUG_FLAG
-//#define DEBUG(format, ...)
-#define DEBUGGING 0
-#define NODE_DEBUG(n, s)
-#endif /* DEBUG_FLAG */
-
-
-#ifdef EMULATOR
-#include "libgabble_wsd_solution.h"
-
-	GET_STATIC_VAR_FROM_TLS(offset_quark1,gabble_txt_mixin,GQuark)
-	#define offset_quark1 (*GET_WSD_VAR_NAME(offset_quark1,gabble_txt_mixin, s)())	
-	
-	GET_STATIC_VAR_FROM_TLS(offset_quark,gabble_txt_mixin,GQuark)
-	#define offset_quark (*GET_WSD_VAR_NAME(offset_quark,gabble_txt_mixin, s)())	
-	
-	GET_STATIC_VAR_FROM_TLS(alloc1,gabble_txt_mixin,GabbleAllocator)
-	#define alloc1 (*GET_WSD_VAR_NAME(alloc1,gabble_txt_mixin, s)())		
-	
-#endif
-
-/*
-Moved to gabble_enums.h
-typedef struct _GabbleAllocator GabbleAllocator;
-struct _GabbleAllocator
-{
-  gulong size;
-  guint limit;
-  guint count;
-};*/
-
-
-
-#define ga_new0(alloc, type) \
-    ((type *) gabble_allocator_alloc0 (alloc))
-
-static void
-gabble_allocator_init (GabbleAllocator *alloc, gulong size, guint limit)
-{
-  g_assert (alloc != NULL);
-  g_assert (size > 0);
-  g_assert (limit > 0);
-
-  alloc->size = size;
-  alloc->limit = limit;
-}
-
-static gpointer gabble_allocator_alloc0 (GabbleAllocator *alloc)
-{
-  gpointer ret;
-
-  g_assert (alloc != NULL);
-  g_assert (alloc->count <= alloc->limit);
-
-  if (alloc->count == alloc->limit)
-    {
-      ret = NULL;
-    }
-  else
-    {
-      ret = g_malloc0 (alloc->size);
-      alloc->count++;
-    }
-
-  return ret;
-}
-
-static void gabble_allocator_free (GabbleAllocator *alloc, gpointer thing)
-{
-  g_assert (alloc != NULL);
-  g_assert (thing != NULL);
-
-  g_free (thing);
-  alloc->count--;
-}
-
-/* pending message */
-#define MAX_PENDING_MESSAGES 256
-#define MAX_MESSAGE_SIZE 1024 - 1
-
-typedef struct _GabblePendingMessage GabblePendingMessage;
-struct _GabblePendingMessage
-{
-  guint id;
-  time_t timestamp;
-  GabbleHandle sender;
-  TpChannelTextMessageType type;
-  char *text;
-  guint flags;
-};
-
-/**
- * gabble_text_mixin_class_get_offset_quark:
- *
- * Returns: the quark used for storing mixin offset on a GObjectClass
- */
-GQuark
-gabble_text_mixin_class_get_offset_quark ()
-{
-#ifndef EMULATOR  
-  static GQuark offset_quark1 = 0;
-#endif
-  
-  if (!offset_quark1)
-    offset_quark1 = g_quark_from_static_string("TextMixinClassOffsetQuark");
-  return offset_quark1;
-}
-
-/**
- * gabble_text_mixin_get_offset_quark:
- *
- * Returns: the quark used for storing mixin offset on a GObject
- */
-GQuark
-gabble_text_mixin_get_offset_quark ()
-{
-#ifndef EMULATOR  
-  static GQuark offset_quark = 0;
-#endif
-  
-  if (!offset_quark)
-    offset_quark = g_quark_from_static_string("TextMixinOffsetQuark");
-  return offset_quark;
-}
-
-
-/* GabbleTextMixin */
-void
-gabble_text_mixin_class_init (GObjectClass *obj_cls, glong offset)
-{
-  GabbleTextMixinClass *mixin_cls;
-
-  g_assert (G_IS_OBJECT_CLASS (obj_cls));
-
-  g_type_set_qdata (G_OBJECT_CLASS_TYPE (obj_cls),
-      GABBLE_TEXT_MIXIN_CLASS_OFFSET_QUARK,
-      GINT_TO_POINTER (offset));
-
-  mixin_cls = GABBLE_TEXT_MIXIN_CLASS (obj_cls);
-
-  mixin_cls->lost_message_signal_id = g_signal_new ("lost-message",
-                G_OBJECT_CLASS_TYPE (obj_cls),
-                G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
-                0,
-                NULL, NULL,
-                g_cclosure_marshal_VOID__VOID,
-                G_TYPE_NONE, 0);
-
-  mixin_cls->received_signal_id = g_signal_new ("received",
-                G_OBJECT_CLASS_TYPE (obj_cls),
-                G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
-                0,
-                NULL, NULL,
-                text_mixin_marshal_VOID__UINT_UINT_UINT_UINT_UINT_STRING,
-                G_TYPE_NONE, 6, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING);
-
-  mixin_cls->send_error_signal_id = g_signal_new ("send-error",
-                G_OBJECT_CLASS_TYPE (obj_cls),
-                G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
-                0,
-                NULL, NULL,
-                text_mixin_marshal_VOID__UINT_UINT_UINT_STRING,
-                G_TYPE_NONE, 4, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING);
-
-  mixin_cls->sent_signal_id = g_signal_new ("sent",
-                G_OBJECT_CLASS_TYPE (obj_cls),
-                G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
-                0,
-                NULL, NULL,
-                text_mixin_marshal_VOID__UINT_UINT_STRING,
-                G_TYPE_NONE, 3, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING);
-}
-
-void
-gabble_text_mixin_init (GObject *obj,
-                        glong offset,
-                        GabbleHandleRepo *handle_repo,
-                        gboolean send_nick)
-{
-  GabbleTextMixin *mixin;
-
-  g_assert (G_IS_OBJECT (obj));
-
-  g_type_set_qdata (G_OBJECT_TYPE (obj),
-                    GABBLE_TEXT_MIXIN_OFFSET_QUARK,
-                    GINT_TO_POINTER (offset));
-
-  mixin = GABBLE_TEXT_MIXIN (obj);
-
-  mixin->pending = g_queue_new ();
-  mixin->handle_repo = handle_repo;
-  mixin->recv_id = 0;
-  mixin->msg_types = g_array_sized_new (FALSE, FALSE, sizeof (guint), 4);
-
-  mixin->message_lost = FALSE;
-}
-
-void
-gabble_text_mixin_set_message_types (GObject *obj,
-                                     ...)
-{
-  GabbleTextMixin *mixin = GABBLE_TEXT_MIXIN (obj);
-  va_list args;
-  guint type;
-
-  va_start (args, obj);
-
-  while ((type = va_arg (args, guint)) != G_MAXUINT)
-    g_array_append_val (mixin->msg_types, type);
-
-  va_end (args);
-}
-
-static void _gabble_pending_free (GabblePendingMessage *msg);
-static GabbleAllocator * _gabble_pending_get_alloc ();
-
-void
-gabble_text_mixin_finalize (GObject *obj)
-{
-  GabbleTextMixin *mixin = GABBLE_TEXT_MIXIN (obj);
-  GabblePendingMessage *msg;
-
-  /* free any data held directly by the object here */
-
-  msg = g_queue_pop_head(mixin->pending);
-  while (msg)
-    {
-      gabble_handle_unref (mixin->handle_repo, TP_HANDLE_TYPE_CONTACT, msg->sender);
-      _gabble_pending_free (msg);
-      msg = g_queue_pop_head(mixin->pending);
-    }
-
-  g_queue_free (mixin->pending);
-
-  g_array_free (mixin->msg_types, TRUE);
-}
-
-/**
- * _gabble_pending_get_alloc
- *
- * Returns a GabbleAllocator for creating up to 256 pending messages, but no
- * more.
- */
-static GabbleAllocator *
-_gabble_pending_get_alloc ()
-{
-
-#ifndef EMULATOR
-  static GabbleAllocator alloc1 = { 0, };
-#endif
-
-  if (0 == alloc1.size)
-    gabble_allocator_init (&alloc1, sizeof(GabblePendingMessage), MAX_PENDING_MESSAGES);
-
-  return &alloc1;
-}
-
-#define _gabble_pending_new0() \
-  (ga_new0 (_gabble_pending_get_alloc (), GabblePendingMessage))
-
-/**
- * _gabble_pending_free
- *
- * Free up a GabblePendingMessage struct.
- */
-static void _gabble_pending_free (GabblePendingMessage *msg)
-{
-  g_free (msg->text);
-  gabble_allocator_free (_gabble_pending_get_alloc (), msg);
-}
-
-/**
- * _gabble_text_mixin_receive
- *
- */
-gboolean gabble_text_mixin_receive (GObject *obj,
-                                     TpChannelTextMessageType type,
-                                     GabbleHandle sender,
-                                     time_t timestamp,
-                                     const char *text)
-{
-  GabbleTextMixin *mixin = GABBLE_TEXT_MIXIN (obj);
-  GabbleTextMixinClass *mixin_cls = GABBLE_TEXT_MIXIN_CLASS (G_OBJECT_GET_CLASS (obj));
-
-  gchar *end;
-  GabblePendingMessage *msg;
-  gsize len;
-
-  msg = _gabble_pending_new0 ();
-
-  if (msg == NULL)
-    {
-      gabble_debug (DEBUG_FLAG, "no more pending messages available, giving up");
-
-      if (!mixin->message_lost)
-        {
-          g_signal_emit (obj, mixin_cls->lost_message_signal_id, 0);
-          mixin->message_lost = TRUE;
-        }
-
-      return FALSE;
-    }
-
-  len = strlen (text);
-
-  if (len > MAX_MESSAGE_SIZE)
-    {
-      gabble_debug (DEBUG_FLAG, "message exceeds maximum size, truncating");
-
-      msg->flags |= TP_CHANNEL_TEXT_MESSAGE_FLAG_TRUNCATED;
-
-      end = g_utf8_find_prev_char (text, text+MAX_MESSAGE_SIZE);
-      if (end)
-        len = end-text;
-      else
-        len = 0;
-    }
-
-  msg->text = g_try_malloc (len + 1);
-
-  if (msg->text == NULL)
-    {
-      gabble_debug (DEBUG_FLAG, "unable to allocate message, giving up");
-
-      if (!mixin->message_lost)
-        {
-          g_signal_emit (obj, mixin_cls->lost_message_signal_id, 0);
-          mixin->message_lost = TRUE;
-        }
-
-      _gabble_pending_free (msg);
-
-      return FALSE;
-    }
-
-  g_strlcpy (msg->text, text, len + 1);
-
-  msg->id = mixin->recv_id++;
-  msg->timestamp = timestamp;
-  msg->sender = sender;
-  msg->type = type;
-
-  gabble_handle_ref (mixin->handle_repo, TP_HANDLE_TYPE_CONTACT, msg->sender);
-  g_queue_push_tail (mixin->pending, msg);
-
-  g_signal_emit (obj, mixin_cls->received_signal_id, 0,
-                 msg->id,
-                 msg->timestamp,
-                 msg->sender,
-                 msg->type,
-                 msg->flags,
-                 msg->text);
-
-  gabble_debug (DEBUG_FLAG, "queued message %u", msg->id);
-
-  mixin->message_lost = FALSE;
-
-  return TRUE;
-}
-
-static gint
-compare_pending_message (gconstpointer haystack,
-                         gconstpointer needle)
-{
-  GabblePendingMessage *msg = (GabblePendingMessage *) haystack;
-  guint id = GPOINTER_TO_INT (needle);
-
-  return (msg->id != id);
-}
-
-/**
- * gabble_text_mixin_acknowledge_pending_messages
- *
- * Implements D-Bus method AcknowledgePendingMessages
- * on interface org.freedesktop.Telepathy.Channel.Type.Text
- *
- * @error: Used to return a pointer to a GError detailing any error
- *         that occurred, D-Bus will throw the error only if this
- *         function returns false.
- *
- * Returns: TRUE if successful, FALSE if an error was thrown.
- */
-gboolean gabble_text_mixin_acknowledge_pending_messages (GObject *obj, const GArray * ids, GError **error)
-{
-  GabbleTextMixin *mixin = GABBLE_TEXT_MIXIN (obj);
-  GList **nodes;
-  GabblePendingMessage *msg;
-  guint i;
-
-  nodes = g_new(GList *, ids->len);
-
-  for (i = 0; i < ids->len; i++)
-    {
-      guint id = g_array_index(ids, guint, i);
-
-      nodes[i] = g_queue_find_custom (mixin->pending,
-                                      GINT_TO_POINTER (id),
-                                      compare_pending_message);
-
-      if (nodes[i] == NULL)
-        {
-          gabble_debug (DEBUG_FLAG, "invalid message id %u", id);
-
-          g_set_error (error, TELEPATHY_ERRORS, InvalidArgument,
-              "invalid message id %u", id);
-
-          g_free(nodes);
-          return FALSE;
-        }
-    }
-
-  for (i = 0; i < ids->len; i++)
-    {
-      msg = (GabblePendingMessage *) nodes[i]->data;
-
-      gabble_debug (DEBUG_FLAG, "acknowleding message id %u", msg->id);
-
-      g_queue_remove (mixin->pending, msg);
-
-      gabble_handle_unref (mixin->handle_repo, TP_HANDLE_TYPE_CONTACT, msg->sender);
-      _gabble_pending_free (msg);
-    }
-
-  g_free(nodes);
-  return TRUE;
-}
-
-/**
- * gabble_text_mixin_list_pending_messages
- *
- * Implements D-Bus method ListPendingMessages
- * on interface org.freedesktop.Telepathy.Channel.Type.Text
- *
- * @error: Used to return a pointer to a GError detailing any error
- *         that occurred, D-Bus will throw the error only if this
- *         function returns false.
- *
- * Returns: TRUE if successful, FALSE if an error was thrown.
- */
-gboolean gabble_text_mixin_list_pending_messages (GObject *obj, gboolean clear, GPtrArray ** ret, GError **error)
-{
-  GabbleTextMixin *mixin = GABBLE_TEXT_MIXIN (obj);
-  guint count;
-  GPtrArray *messages;
-  GList *cur;
-
-  count = g_queue_get_length (mixin->pending);
-  messages = g_ptr_array_sized_new (count);
-
-  for (cur = (clear ? g_queue_pop_head_link(mixin->pending)
-                    : g_queue_peek_head_link(mixin->pending));
-       cur != NULL;
-       cur = (clear ? g_queue_pop_head_link(mixin->pending)
-                    : cur->next))
-    {
-      GabblePendingMessage *msg = (GabblePendingMessage *) cur->data;
-      GValue val = { 0, };
-
-      g_value_init (&val, TP_TYPE_PENDING_MESSAGE_STRUCT);
-      g_value_take_boxed (&val,
-          dbus_g_type_specialized_construct (TP_TYPE_PENDING_MESSAGE_STRUCT));
-      dbus_g_type_struct_set (&val,
-          0, msg->id,
-          1, msg->timestamp,
-          2, msg->sender,
-          3, msg->type,
-          4, msg->flags,
-          5, msg->text,
-          G_MAXUINT);
-
-      g_ptr_array_add (messages, g_value_get_boxed (&val));
-    }
-
-  *ret = messages;
-
-  return TRUE;
-}
-
-/**
- * gabble_text_mixin_send
- *
- * Implements D-Bus method Send
- * on interface org.freedesktop.Telepathy.Channel.Type.Text
- *
- * @error: Used to return a pointer to a GError detailing any error
- *         that occurred, D-Bus will throw the error only if this
- *         function returns false.
- *
- * Returns: TRUE if successful, FALSE if an error was thrown.
- */
-gboolean gabble_text_mixin_send (GObject *obj, guint type, guint subtype,
-                                 const char *recipient, const gchar *text,
-                                 GabbleConnection *conn, gboolean emit_signal,
-                                 GError **error)
-{
-  GabbleTextMixin *mixin = GABBLE_TEXT_MIXIN (obj);
-  LmMessage *msg;
-  gboolean result;
-  time_t timestamp;
-
-  if (type > TP_CHANNEL_TEXT_MESSAGE_TYPE_NOTICE)
-    {
-      gabble_debug (DEBUG_FLAG, "invalid message type %u", type);
-
-      g_set_error (error, TELEPATHY_ERRORS, InvalidArgument,
-          "invalid message type: %u", type);
-
-      return FALSE;
-    }
-
-  if (!subtype)
-    {
-      switch (type)
-        {
-        case TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL:
-        case TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION:
-          subtype = LM_MESSAGE_SUB_TYPE_CHAT;
-          break;
-        case TP_CHANNEL_TEXT_MESSAGE_TYPE_NOTICE:
-          subtype = LM_MESSAGE_SUB_TYPE_NORMAL;
-          break;
-        }
-    }
-
-  msg = lm_message_new_with_sub_type (recipient, LM_MESSAGE_TYPE_MESSAGE, subtype);
-
-  if (mixin->send_nick)
-    {
-      lm_message_node_add_own_nick (msg->node, conn);
-      mixin->send_nick = FALSE;
-    }
-
-  if (type == TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION)
-    {
-      gchar *tmp;
-      tmp = g_strconcat ("/me ", text, NULL);
-      lm_message_node_add_child (msg->node, "body", tmp);
-      g_free (tmp);
-    }
-  else
-    {
-      lm_message_node_add_child (msg->node, "body", text);
-    }
-
-  result = _gabble_connection_send (conn, msg, error);
-  lm_message_unref (msg);
-
-  if (!result)
-    return FALSE;
-
-  if (emit_signal)
-    {
-      timestamp = time (NULL);
-
-      gabble_text_mixin_emit_sent (obj, timestamp, type, text);
-    }
-
-  return TRUE;
-}
-
-void
-gabble_text_mixin_emit_sent (GObject *obj,
-                             time_t timestamp,
-                             guint type,
-                             const char *text)
-{
-  GabbleTextMixinClass *mixin_cls = GABBLE_TEXT_MIXIN_CLASS (G_OBJECT_GET_CLASS
-      (obj));
-
-  g_signal_emit (obj, mixin_cls->sent_signal_id, 0,
-                 timestamp,
-                 type,
-                 text);
-}
-
-gboolean
-gabble_text_mixin_get_message_types (GObject *obj, GArray **ret, GError **error)
-{
-  GabbleTextMixin *mixin = GABBLE_TEXT_MIXIN (obj);
-  guint i;
-
-  *ret = g_array_sized_new (FALSE, FALSE, sizeof (guint),
-                            mixin->msg_types->len);
-
-  for (i = 0; i < mixin->msg_types->len; i++)
-    {
-      g_array_append_val (*ret, g_array_index (mixin->msg_types, guint, i));
-    }
-
-  return TRUE;
-}
-
-
-void
-gabble_text_mixin_clear (GObject *obj)
-{
-  GabbleTextMixin *mixin = GABBLE_TEXT_MIXIN (obj);
-  GabblePendingMessage *msg;
-
-  msg = g_queue_pop_head(mixin->pending);
-  while (msg)
-    {
-      gabble_handle_unref (mixin->handle_repo, TP_HANDLE_TYPE_CONTACT, msg->sender);
-      _gabble_pending_free (msg);
-      msg = g_queue_pop_head(mixin->pending);
-    }
-}
-
-gboolean
-gabble_text_mixin_parse_incoming_message (LmMessage *message,
-                        const gchar **from,
-                        time_t *stamp,
-                        TpChannelTextMessageType *msgtype,
-                        const gchar **body,
-                        const gchar **body_offset,
-                        GabbleTextMixinSendError *send_error)
-{
-  const gchar *type;
-  LmMessageNode *node;
-
-  *send_error = CHANNEL_TEXT_SEND_NO_ERROR;
-
-  if (lm_message_get_sub_type (message) == LM_MESSAGE_SUB_TYPE_ERROR)
-    {
-      LmMessageNode *error_node;
-
-      error_node = lm_message_node_get_child (message->node, "error");
-      if (error_node)
-        {
-          GabbleXmppError err = gabble_xmpp_error_from_node (error_node);
-          gabble_debug (DEBUG_FLAG, "got xmpp error: %s: %s", gabble_xmpp_error_string (err),
-                 gabble_xmpp_error_description (err));
-
-          /* these are based on descriptions of errors, and some testing */
-          switch (err)
-            {
-              case XMPP_ERROR_SERVICE_UNAVAILABLE:
-              case XMPP_ERROR_RECIPIENT_UNAVAILABLE:
-                *send_error = CHANNEL_TEXT_SEND_ERROR_OFFLINE;
-                break;
-
-              case XMPP_ERROR_ITEM_NOT_FOUND:
-              case XMPP_ERROR_JID_MALFORMED:
-              case XMPP_ERROR_REMOTE_SERVER_TIMEOUT:
-                *send_error = CHANNEL_TEXT_SEND_ERROR_INVALID_CONTACT;
-                break;
-
-              case XMPP_ERROR_FORBIDDEN:
-                *send_error = CHANNEL_TEXT_SEND_ERROR_PERMISSION_DENIED;
-                break;
-
-              case XMPP_ERROR_RESOURCE_CONSTRAINT:
-                *send_error = CHANNEL_TEXT_SEND_ERROR_TOO_LONG;
-                break;
-
-              case XMPP_ERROR_FEATURE_NOT_IMPLEMENTED:
-                *send_error = CHANNEL_TEXT_SEND_ERROR_NOT_IMPLEMENTED;
-                break;
-
-              default:
-                *send_error = CHANNEL_TEXT_SEND_ERROR_UNKNOWN;
-            }
-        }
-      else
-        {
-          *send_error = CHANNEL_TEXT_SEND_ERROR_UNKNOWN;
-        }
-    }
-
-  *from = lm_message_node_get_attribute (message->node, "from");
-  if (*from == NULL)
-    {
-      NODE_DEBUG (message->node, "got a message without a from field");
-      return FALSE;
-    }
-
-  type = lm_message_node_get_attribute (message->node, "type");
-
-  /*
-   * Parse timestamp of delayed messages. For non-delayed, it's
-   * 0 and the channel code should set the current timestamp.
-   */
-  *stamp = 0;
-
-  node = lm_message_node_get_child_with_namespace (message->node, "x",
-      NS_X_DELAY);
-  if (node != NULL)
-    {
-      const gchar *stamp_str, *p;
-      struct tm stamp_tm = { 0, };
-
-      stamp_str = lm_message_node_get_attribute (node, "stamp");
-      if (stamp_str != NULL)
-        {
-          p = strptime (stamp_str, "%Y%m%dT%T", &stamp_tm);
-          if (p == NULL || *p != '\0')
-            {
-              g_warning ("%s: malformed date string '%s' for jabber:x:delay",
-                         G_STRFUNC, stamp_str);
-            }
-          else
-            {
-              *stamp = 0; // bsr timegm (&stamp_tm);
-            }
-        }
-    }
-
-  /*
-   * Parse body if it exists.
-   */
-  node = lm_message_node_get_child (message->node, "body");
-
-  if (node)
-    {
-      *body = lm_message_node_get_value (node);
-    }
-  else
-    {
-      *body = NULL;
-    }
-
-  /* Messages starting with /me are ACTION messages, and the /me should be
-   * removed. type="chat" messages are NORMAL.  everything else is
-   * something that doesn't necessarily expect a reply or ongoing
-   * conversation ("normal") or has been auto-sent, so we make it NOTICE in
-   * all other cases. */
-
-  *msgtype = TP_CHANNEL_TEXT_MESSAGE_TYPE_NOTICE;
-  *body_offset = *body;
-
-  if (*body)
-    {
-      if (0 == strncmp (*body, "/me ", 4))
-        {
-          *msgtype = TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION;
-          *body_offset = *body + 4;
-        }
-      else if (type != NULL && (0 == strcmp (type, "chat") ||
-                                0 == strcmp (type, "groupchat")))
-        {
-          *msgtype = TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL;
-          *body_offset = *body;
-        }
-    }
-
-  return TRUE;
-}
-
-void
-_gabble_text_mixin_send_error_signal (GObject *obj,
-                                      GabbleTextMixinSendError error,
-                                      time_t timestamp,
-                                      TpChannelTextMessageType type,
-                                      const gchar *text)
-{
-  GabbleTextMixinClass *mixin_cls = GABBLE_TEXT_MIXIN_CLASS (G_OBJECT_GET_CLASS (obj));
-
-  g_signal_emit (obj, mixin_cls->send_error_signal_id, 0, error, timestamp, type, text, 0);
-}
-