[Telepathy-commits] [telepathy-glib/master] Populate some more of TpMessageMixin

Simon McVittie simon.mcvittie at collabora.co.uk
Thu Dec 18 10:41:26 PST 2008


20080409150333-53eee-770fe12e89b003f5390aa6c1fd50cedeaa9c6606.gz
---
 telepathy-glib/message-mixin.c |  239 ++++++++++++++++++++++++++++++++++++++--
 1 files changed, 228 insertions(+), 11 deletions(-)

diff --git a/telepathy-glib/message-mixin.c b/telepathy-glib/message-mixin.c
index f9e1087..75199d4 100644
--- a/telepathy-glib/message-mixin.c
+++ b/telepathy-glib/message-mixin.c
@@ -75,7 +75,7 @@
 
 struct _TpMessageMixinPrivate
 {
-  TpHandleRepoIface *contacts_repo;
+  TpHandleRepoIface *contact_repo;
   guint recv_id;
   gboolean message_lost;
 
@@ -154,11 +154,115 @@ tp_message_mixin_class_init (GObjectClass *obj_cls,
 }
 
 
+typedef enum {
+    PENDING_TEXT_MESSAGE,       /* A message with text/plain content */
+    PENDING_NON_TEXT_MESSAGE,   /* A message with no text/plain content */
+    PENDING_DELIVERY_REPORT     /* A delivery report */
+} PendingType;
+
+
+typedef struct {
+    guint32 id;
+    PendingType pending_type;
+    TpHandle sender;                        /* 0 for delivery reports */
+    time_t timestamp;                       /* 0 for delivery reports */
+    TpChannelTextMessageType message_type;  /* 0 for delivery reports */
+    GPtrArray *content;                     /* has exactly one item for d.r. */
+} PendingItem;
+
+
+static gint
+pending_item_id_equals_data (gconstpointer item,
+                             gconstpointer data)
+{
+  const PendingItem *self = item;
+  guint id = GPOINTER_TO_UINT (data);
+
+  return (self->id != id);
+}
+
+
+static void
+pending_item_free (PendingItem *pending,
+                   TpHandleRepoIface *contact_repo)
+{
+  guint i;
+
+  if (pending->sender != 0)
+    tp_handle_unref (contact_repo, pending->sender);
+
+  if (pending->content != NULL)
+    {
+      for (i = 0; i < pending->content->len; i++)
+        {
+          g_hash_table_destroy (g_ptr_array_index (pending->content, i));
+        }
+
+      g_ptr_array_free (pending->content, TRUE);
+    }
+
+  g_slice_free (PendingItem, pending);
+}
+
+
+#if 0
+static PendingItem *
+pending_item_new (void)
+{
+  PendingItem *pending = g_slice_new0 (PendingItem);
+
+  pending->content = g_ptr_array_sized_new (1);
+  return pending;
+}
+#endif
+
+
+static TpChannelTextMessageFlags
+pending_item_get_text (PendingItem *item,
+                       GString *buffer)
+{
+  guint i;
+  TpChannelTextMessageFlags flags = 0;
+
+  g_return_val_if_fail (item->pending_type != PENDING_TEXT_MESSAGE, 0);
+  g_return_val_if_fail (item->content != NULL, 0);
+
+  for (i = 0; i < item->content->len; i++)
+    {
+      GHashTable *part = g_ptr_array_index (item->content, i);
+
+      if (!tp_strdiff (g_hash_table_lookup (part, "type"), "text/plain"))
+        {
+          GValue *value;
+          /* FIXME: strictly, we should skip all but the first in any set of
+           * alternatives... in practice, this is only likely to affect XMPP,
+           * where this will result in getting *all* the languages for a
+           * multilingual message, rather than just one of them */
+
+          value = g_hash_table_lookup (part, "content");
+
+          if (value != NULL && G_VALUE_HOLDS_STRING (value))
+            {
+              g_string_append (buffer, g_value_get_string (value));
+
+              value = g_hash_table_lookup (part, "truncated");
+
+              if (value != NULL && G_VALUE_HOLDS_BOOLEAN (value) &&
+                  g_value_get_boolean (value))
+                flags |= TP_CHANNEL_TEXT_MESSAGE_FLAG_TRUNCATED;
+            }
+        }
+    }
+
+  return flags;
+}
+
+
 /**
  * tp_message_mixin_init:
  * @obj: An instance of the implementation that uses this mixin
  * @offset: The byte offset of the TpMessageMixin within the object structure
- * @contacts_repo: The connection's %TP_HANDLE_TYPE_CONTACT repository
+ * @contact_repo: The connection's %TP_HANDLE_TYPE_CONTACT repository
  *
  * Initialize the mixin. Should be called from the implementation's
  * instance init function like so:
@@ -172,7 +276,7 @@ tp_message_mixin_class_init (GObjectClass *obj_cls,
 void
 tp_message_mixin_init (GObject *obj,
                        gsize offset,
-                       TpHandleRepoIface *contacts_repo)
+                       TpHandleRepoIface *contact_repo)
 {
   TpMessageMixin *mixin;
 
@@ -187,7 +291,7 @@ tp_message_mixin_init (GObject *obj,
   mixin->priv = g_slice_new0 (TpMessageMixinPrivate);
 
   mixin->priv->pending = g_queue_new ();
-  mixin->priv->contacts_repo = contacts_repo;
+  mixin->priv->contact_repo = contact_repo;
   mixin->priv->recv_id = 0;
   mixin->priv->msg_types = g_array_sized_new (FALSE, FALSE, sizeof (guint),
       NUM_TP_CHANNEL_TEXT_MESSAGE_TYPES);
@@ -199,11 +303,11 @@ static void
 tp_message_mixin_clear (GObject *obj)
 {
   TpMessageMixin *mixin = TP_MESSAGE_MIXIN (obj);
-  gpointer msg;
+  PendingItem *item;
 
-  while ((msg = g_queue_pop_head (mixin->priv->pending)) != NULL)
+  while ((item = g_queue_pop_head (mixin->priv->pending)) != NULL)
     {
-      /* FIXME */
+      pending_item_free (item, mixin->priv->contact_repo);
     }
 }
 
@@ -233,9 +337,50 @@ tp_message_mixin_acknowledge_pending_messages_async (
     const GArray *ids,
     DBusGMethodInvocation *context)
 {
-  GError e = { TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, "Not implemented" };
+  TpMessageMixin *mixin = TP_MESSAGE_MIXIN (iface);
+  GList **nodes;
+  PendingItem *item;
+  guint i;
 
-  dbus_g_method_return_error (context, &e);
+  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->priv->pending,
+          GUINT_TO_POINTER (id), pending_item_id_equals_data);
+
+      if (nodes[i] == NULL)
+        {
+          GError *error = g_error_new (TP_ERRORS, TP_ERROR_INVALID_ARGUMENT,
+              "invalid message id %u", id);
+
+          DEBUG ("%s", error->message);
+          dbus_g_method_return_error (context, error);
+          g_error_free (error);
+
+          g_free (nodes);
+          return;
+        }
+    }
+
+  for (i = 0; i < ids->len; i++)
+    {
+      item = nodes[i]->data;
+
+      DEBUG ("acknowledging message id %u", item->id);
+
+      g_queue_remove (mixin->priv->pending, item);
+
+      /* FIXME: need a hook here to send acknowledgements out on the network
+       * if the protocol requires it */
+
+      pending_item_free (item, mixin->priv->contact_repo);
+    }
+
+  g_free (nodes);
+  tp_svc_channel_type_text_return_from_acknowledge_pending_messages (context);
 }
 
 static void
@@ -243,9 +388,81 @@ tp_message_mixin_list_pending_messages_async (TpSvcChannelTypeText *iface,
                                               gboolean clear,
                                               DBusGMethodInvocation *context)
 {
-  GError e = { TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, "Not implemented" };
+  TpMessageMixin *mixin = TP_MESSAGE_MIXIN (iface);
+  GType pending_type = TP_STRUCT_TYPE_PENDING_TEXT_MESSAGE;
+  guint count;
+  GPtrArray *messages;
+  GList *cur;
+  guint i;
+
+  count = g_queue_get_length (mixin->priv->pending);
+  messages = g_ptr_array_sized_new (count);
+
+  for (cur = g_queue_peek_head_link (mixin->priv->pending);
+       cur != NULL;
+       cur = cur->next)
+    {
+      PendingItem *msg = cur->data;
+      GValue val = { 0, };
+      guint flags;
+      GString *text;
+
+      if (msg->pending_type != PENDING_TEXT_MESSAGE)
+        {
+          /* No text/plain part */
+          continue;
+        }
+
+      text = g_string_new ("");
+      flags = pending_item_get_text (msg, text);
+
+      g_value_init (&val, pending_type);
+      g_value_take_boxed (&val,
+          dbus_g_type_specialized_construct (pending_type));
+      dbus_g_type_struct_set (&val,
+          0, msg->id,
+          1, msg->timestamp,
+          2, msg->sender,
+          3, msg->message_type,
+          4, flags,
+          5, text,
+          G_MAXUINT);
+
+      g_string_free (text, TRUE);
+
+      g_ptr_array_add (messages, g_value_get_boxed (&val));
+    }
 
-  dbus_g_method_return_error (context, &e);
+  if (clear)
+    {
+      DEBUG ("WARNING: ListPendingMessages(clear=TRUE) is deprecated");
+      cur = g_queue_peek_head_link (mixin->priv->pending);
+
+      while (cur != NULL)
+        {
+          PendingItem *msg = cur->data;
+          GList *next = cur->next;
+
+          if (msg->pending_type == PENDING_TEXT_MESSAGE)
+            {
+              /* FIXME: need a hook here to send acknowledgements out on the
+               * network if the protocol requires it */
+
+              g_queue_delete_link (mixin->priv->pending, cur);
+              pending_item_free (msg, mixin->priv->contact_repo);
+            }
+
+          cur = next;
+        }
+    }
+
+  tp_svc_channel_type_text_return_from_list_pending_messages (context,
+      messages);
+
+  for (i = 0; i < messages->len; i++)
+    g_value_array_free (g_ptr_array_index (messages, i));
+
+  g_ptr_array_free (messages, TRUE);
 }
 
 static void
-- 
1.5.6.5




More information about the Telepathy-commits mailing list