[Telepathy-commits] [telepathy-glib/master] Implement some more of the Message mixin
Simon McVittie
simon.mcvittie at collabora.co.uk
Thu Dec 18 10:41:27 PST 2008
20080414171827-53eee-a5a8fbc5ebf84872043d0047c7c717e7e9ebd670.gz
---
examples/cm/echo-message-parts/chan.c | 102 +++------
examples/cm/echo-message-parts/chan.h | 5 +-
telepathy-glib/message-mixin.c | 375 ++++++++++++++++++++++++++++-----
telepathy-glib/message-mixin.h | 53 +++--
4 files changed, 386 insertions(+), 149 deletions(-)
diff --git a/examples/cm/echo-message-parts/chan.c b/examples/cm/echo-message-parts/chan.c
index 90e7fbd..a415bdb 100644
--- a/examples/cm/echo-message-parts/chan.c
+++ b/examples/cm/echo-message-parts/chan.c
@@ -16,11 +16,11 @@
#include <telepathy-glib/base-connection.h>
#include <telepathy-glib/channel-iface.h>
#include <telepathy-glib/dbus.h>
+#include <telepathy-glib/gtypes.h>
#include <telepathy-glib/interfaces.h>
#include <telepathy-glib/svc-channel.h>
#include <telepathy-glib/svc-generic.h>
-static void text_iface_init (gpointer iface, gpointer data);
static void channel_iface_init (gpointer iface, gpointer data);
G_DEFINE_TYPE_WITH_CODE (ExampleEcho2Channel,
@@ -29,7 +29,10 @@ G_DEFINE_TYPE_WITH_CODE (ExampleEcho2Channel,
G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES,
tp_dbus_properties_mixin_iface_init);
G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL, channel_iface_init);
- G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_TYPE_TEXT, text_iface_init);
+ G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_TYPE_TEXT,
+ tp_message_mixin_text_iface_init);
+ G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_MESSAGE_PARTS,
+ tp_message_mixin_message_parts_iface_init);
G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_IFACE, NULL);
G_IMPLEMENT_INTERFACE (TP_TYPE_EXPORTABLE_CHANNEL, NULL))
@@ -74,6 +77,31 @@ example_echo_2_channel_init (ExampleEcho2Channel *self)
ExampleEcho2ChannelPrivate);
}
+static gboolean
+send_message (GObject *object,
+ TpMessageMixinOutgoingMessage *message)
+{
+ ExampleEcho2Channel *self = EXAMPLE_ECHO_2_CHANNEL (object);
+ TpHandleRepoIface *contact_repo = tp_base_connection_get_handles
+ (self->priv->conn, TP_HANDLE_TYPE_CONTACT);
+ time_t timestamp = time (NULL);
+ TpChannelTextMessageType message_type = message->message_type;
+ GPtrArray *parts = g_boxed_copy (dbus_g_type_get_collection ("GPtrArray",
+ TP_HASH_TYPE_MESSAGE_PART), message->parts);
+
+ tp_handle_ref (contact_repo, self->priv->handle);
+
+ /* This consumes the data, so we mustn't free it */
+ tp_message_mixin_take_received (object, timestamp, self->priv->handle,
+ message_type, parts);
+
+ /* "OK, we've sent the message" (after calling this, message must not be
+ * dereferenced) */
+ tp_message_mixin_sent (object, message, "");
+
+ return TRUE;
+}
+
static GObject *
constructor (GType type,
guint n_props,
@@ -95,14 +123,10 @@ constructor (GType type,
bus = tp_get_bus ();
dbus_g_connection_register_g_object (bus, self->priv->object_path, object);
- tp_text_mixin_init (object, G_STRUCT_OFFSET (ExampleEcho2Channel, text),
+ tp_message_mixin_init (object, G_STRUCT_OFFSET (ExampleEcho2Channel, text),
contact_repo);
- tp_text_mixin_set_message_types (object,
- TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL,
- TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION,
- TP_CHANNEL_TEXT_MESSAGE_TYPE_NOTICE,
- G_MAXUINT);
+ tp_message_mixin_implement_sending (object, send_message);
return object;
}
@@ -255,7 +279,7 @@ finalize (GObject *object)
g_free (self->priv->object_path);
- tp_text_mixin_finalize (object);
+ tp_message_mixin_finalize (object);
((GObjectClass *) example_echo_2_channel_parent_class)->finalize (object);
}
@@ -344,7 +368,7 @@ example_echo_2_channel_class_init (ExampleEcho2ChannelClass *klass)
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
g_object_class_install_property (object_class, PROP_REQUESTED, param_spec);
- tp_text_mixin_class_init (object_class,
+ tp_message_mixin_class_init (object_class,
G_STRUCT_OFFSET (ExampleEcho2ChannelClass, text_class));
klass->dbus_properties_class.interfaces = prop_interfaces;
@@ -445,64 +469,6 @@ channel_iface_init (gpointer iface,
#undef IMPLEMENT
}
-static void
-text_send (TpSvcChannelTypeText *iface,
- guint type,
- const gchar *text,
- DBusGMethodInvocation *context)
-{
- ExampleEcho2Channel *self = EXAMPLE_ECHO_2_CHANNEL (iface);
- time_t timestamp = time (NULL);
- gchar *echo;
- guint echo_type = type;
-
- /* Tell the client that the message was sent successfully. If it's possible
- * to tell whether a message has been delivered, you should delay emitting
- * this signal until it's actually been successful, and emit SendError
- * instead if there was an error; if you can't tell, emit Sent immediately,
- * like this */
- tp_svc_channel_type_text_emit_sent ((GObject *) self, timestamp, type, text);
-
- /* Pretend that the remote contact has replied. Normally,
- * you'd call tp_text_mixin_receive in response to network events */
-
- switch (type)
- {
- case TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL:
- echo = g_strdup_printf ("You said: %s", text);
- break;
- case TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION:
- echo = g_strdup_printf ("notices that the user %s", text);
- break;
- case TP_CHANNEL_TEXT_MESSAGE_TYPE_NOTICE:
- echo = g_strdup_printf ("You sent a notice: %s", text);
- break;
- default:
- echo = g_strdup_printf ("You sent some weird message type, %u: \"%s\"",
- type, text);
- echo_type = TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL;
- }
-
- tp_text_mixin_receive ((GObject *) self, echo_type, self->priv->handle,
- timestamp, echo);
-
- g_free (echo);
-
- tp_svc_channel_type_text_return_from_send (context);
-}
-
-static void
-text_iface_init (gpointer iface,
- gpointer data)
-{
- TpSvcChannelTypeTextClass *klass = iface;
-
- tp_text_mixin_iface_init (iface, data);
-#define IMPLEMENT(x) tp_svc_channel_type_text_implement_##x (klass, text_##x)
- IMPLEMENT (send);
-#undef IMPLEMENT
-}
-
/* FIXME: enable this when Destroyable is supported */
#if 0
static void
diff --git a/examples/cm/echo-message-parts/chan.h b/examples/cm/echo-message-parts/chan.h
index 1117d58..f79d3c5 100644
--- a/examples/cm/echo-message-parts/chan.h
+++ b/examples/cm/echo-message-parts/chan.h
@@ -14,7 +14,7 @@
#include <glib-object.h>
#include <telepathy-glib/base-connection.h>
-#include <telepathy-glib/text-mixin.h>
+#include <telepathy-glib/message-mixin.h>
G_BEGIN_DECLS
@@ -43,12 +43,13 @@ GType example_echo_2_channel_get_type (void);
struct _ExampleEcho2ChannelClass {
GObjectClass parent_class;
TpTextMixinClass text_class;
+ TpMessageMixinClass text_class;
TpDBusPropertiesMixinClass dbus_properties_class;
};
struct _ExampleEcho2Channel {
GObject parent;
- TpTextMixin text;
+ TpMessageMixin text;
ExampleEcho2ChannelPrivate *priv;
};
diff --git a/telepathy-glib/message-mixin.c b/telepathy-glib/message-mixin.c
index 75199d4..61e5b01 100644
--- a/telepathy-glib/message-mixin.c
+++ b/telepathy-glib/message-mixin.c
@@ -47,6 +47,7 @@
#include <dbus/dbus-glib.h>
#include <string.h>
+#include <telepathy-glib/dbus.h>
#include <telepathy-glib/enums.h>
#include <telepathy-glib/errors.h>
#include <telepathy-glib/gtypes.h>
@@ -75,15 +76,32 @@
struct _TpMessageMixinPrivate
{
+ TpMessageMixinSendImpl send_message;
+
TpHandleRepoIface *contact_repo;
guint recv_id;
- gboolean message_lost;
GQueue *pending;
GArray *msg_types;
};
+#define TP_MESSAGE_MIXIN_CLASS_OFFSET_QUARK \
+ (tp_message_mixin_class_get_offset_quark ())
+#define TP_MESSAGE_MIXIN_CLASS_OFFSET(o) \
+ (GPOINTER_TO_UINT (g_type_get_qdata (G_OBJECT_CLASS_TYPE (o), \
+ TP_MESSAGE_MIXIN_CLASS_OFFSET_QUARK)))
+#define TP_MESSAGE_MIXIN_CLASS(o) \
+ ((TpMessageMixinClass *) tp_mixin_offset_cast (o, \
+ TP_MESSAGE_MIXIN_CLASS_OFFSET (o)))
+
+#define TP_MESSAGE_MIXIN_OFFSET_QUARK (tp_message_mixin_get_offset_quark ())
+#define TP_MESSAGE_MIXIN_OFFSET(o) \
+ (GPOINTER_TO_UINT (g_type_get_qdata (G_OBJECT_TYPE (o), \
+ TP_MESSAGE_MIXIN_OFFSET_QUARK)))
+#define TP_MESSAGE_MIXIN(o) \
+ ((TpMessageMixin *) tp_mixin_offset_cast (o, TP_MESSAGE_MIXIN_OFFSET (o)))
+
/**
* tp_message_mixin_class_get_offset_quark:
*
@@ -91,7 +109,7 @@ struct _TpMessageMixinPrivate
*
* Returns: the quark used for storing mixin offset on a GObjectClass
*/
-GQuark
+static GQuark
tp_message_mixin_class_get_offset_quark (void)
{
static GQuark offset_quark = 0;
@@ -110,7 +128,7 @@ tp_message_mixin_class_get_offset_quark (void)
*
* Returns: the quark used for storing mixin offset on a GObject
*/
-GQuark
+static GQuark
tp_message_mixin_get_offset_quark (void)
{
static GQuark offset_quark = 0;
@@ -154,20 +172,14 @@ 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. */
+ TpHandle sender;
+ time_t timestamp;
+ TpChannelTextMessageType message_type;
+ GPtrArray *content;
+ TpChannelTextMessageFlags old_flags;
+ gchar *old_text;
} PendingItem;
@@ -205,39 +217,84 @@ pending_item_free (PendingItem *pending,
}
-#if 0
-static PendingItem *
-pending_item_new (void)
+static inline const gchar *
+value_force_string (const GValue *value)
{
- PendingItem *pending = g_slice_new0 (PendingItem);
+ if (value == NULL || !G_VALUE_HOLDS_STRING (value))
+ return NULL;
- pending->content = g_ptr_array_sized_new (1);
- return pending;
+ return g_value_get_string (value);
+}
+
+
+static inline void
+nullify_hash (GHashTable **hash)
+{
+ if (*hash != NULL)
+ return;
+
+ g_hash_table_destroy (*hash);
+ *hash = NULL;
+}
+
+
+static void
+subtract_from_hash (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ g_hash_table_remove (user_data, key);
}
-#endif
static TpChannelTextMessageFlags
-pending_item_get_text (PendingItem *item,
- GString *buffer)
+parts_to_text (const GPtrArray *parts,
+ 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++)
+ /* Lazily created hash tables, used as a sets: keys are borrowed
+ * "alternative" string values from @parts, value == key. */
+ /* Alternative IDs for which we have already extracted an alternative */
+ GHashTable *alternatives_used = NULL;
+ /* Alternative IDs for which we expect to extract text, but have not yet;
+ * cleared if the flag Channel_Text_Message_Flag_Non_Text_Content is set.
+ * At the end, if this contains any item not in alternatives_used,
+ * Channel_Text_Message_Flag_Non_Text_Content must be set. */
+ GHashTable *alternatives_needed = NULL;
+
+ for (i = 0; i < parts->len; i++)
{
- GHashTable *part = g_ptr_array_index (item->content, i);
+ GHashTable *part = g_ptr_array_index (parts, i);
+ const gchar *type = value_force_string (g_hash_table_lookup (part,
+ "type"));
+ const gchar *alternative = value_force_string (g_hash_table_lookup (part,
+ "alternative"));
- if (!tp_strdiff (g_hash_table_lookup (part, "type"), "text/plain"))
+ if (!tp_strdiff (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 */
+
+ if (alternative != NULL && alternative[0] != '\0')
+ {
+ if (alternatives_used == NULL)
+ {
+ /* We can't have seen an alternative for this part yet.
+ * However, we need to create the hash table now */
+ alternatives_used = g_hash_table_new (g_str_hash,
+ g_str_equal);
+ }
+ else if (g_hash_table_lookup (alternatives_used,
+ alternative) != NULL)
+ {
+ /* we've seen a "better" alternative for this part already.
+ * Skip it */
+ continue;
+ }
+
+ g_hash_table_insert (alternatives_used, (gpointer) alternative,
+ (gpointer) alternative);
+ }
value = g_hash_table_lookup (part, "content");
@@ -251,9 +308,51 @@ pending_item_get_text (PendingItem *item,
g_value_get_boolean (value))
flags |= TP_CHANNEL_TEXT_MESSAGE_FLAG_TRUNCATED;
}
+ else
+ {
+ flags |= TP_CHANNEL_TEXT_MESSAGE_FLAG_NON_TEXT_CONTENT;
+ nullify_hash (&alternatives_needed);
+ }
}
+ else if ((flags & TP_CHANNEL_TEXT_MESSAGE_FLAG_NON_TEXT_CONTENT) != 0)
+ {
+ if (alternative == NULL || alternative[0] == '\0')
+ {
+ /* This part can't possibly have a text alternative
+ * (attached image or something, perhaps) */
+ flags |= TP_CHANNEL_TEXT_MESSAGE_FLAG_NON_TEXT_CONTENT;
+ nullify_hash (&alternatives_needed);
+ }
+ else
+ {
+ /* This part might have a text alternative later */
+ if (alternatives_needed == NULL)
+ alternatives_needed = g_hash_table_new (g_str_hash,
+ g_str_equal);
+
+ g_hash_table_insert (alternatives_needed, (gpointer) alternative,
+ (gpointer) alternative);
+ }
+ }
+ }
+
+ if ((flags & TP_CHANNEL_TEXT_MESSAGE_FLAG_NON_TEXT_CONTENT) == 0 &&
+ alternatives_needed != NULL)
+ {
+ if (alternatives_used != NULL)
+ g_hash_table_foreach (alternatives_used, subtract_from_hash,
+ alternatives_needed);
+
+ if (g_hash_table_size (alternatives_needed) > 0)
+ flags |= TP_CHANNEL_TEXT_MESSAGE_FLAG_NON_TEXT_CONTENT;
}
+ if (alternatives_needed != NULL)
+ g_hash_table_destroy (alternatives_needed);
+
+ if (alternatives_used != NULL)
+ g_hash_table_destroy (alternatives_used);
+
return flags;
}
@@ -295,8 +394,6 @@ tp_message_mixin_init (GObject *obj,
mixin->priv->recv_id = 0;
mixin->priv->msg_types = g_array_sized_new (FALSE, FALSE, sizeof (guint),
NUM_TP_CHANNEL_TEXT_MESSAGE_TYPES);
-
- mixin->priv->message_lost = FALSE;
}
static void
@@ -407,14 +504,8 @@ tp_message_mixin_list_pending_messages_async (TpSvcChannelTypeText *iface,
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);
+ flags = parts_to_text (msg->content, text);
g_value_init (&val, pending_type);
g_value_take_boxed (&val,
@@ -443,14 +534,11 @@ tp_message_mixin_list_pending_messages_async (TpSvcChannelTypeText *iface,
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 */
+ /* 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);
- }
+ g_queue_delete_link (mixin->priv->pending, cur);
+ pending_item_free (msg, mixin->priv->contact_repo);
cur = next;
}
@@ -481,22 +569,176 @@ static void
tp_message_mixin_get_message_types_async (TpSvcChannelTypeText *iface,
DBusGMethodInvocation *context)
{
- GError e = { TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, "Not implemented" };
+ TpMessageMixin *mixin = TP_MESSAGE_MIXIN (iface);
- dbus_g_method_return_error (context, &e);
+ tp_svc_channel_type_text_return_from_get_message_types (context,
+ mixin->priv->msg_types);
}
+
+/**
+ * tp_message_mixin_take_received:
+ * @object: a channel with this mixin
+ * @timestamp: the time the message was received (if 0, time (NULL) will be
+ * used)
+ * @sender: an owned reference to the handle of the sender, which is stolen
+ * by the message mixin
+ * @message_type: the type of message
+ * @content: the content of the message, which is stolen by the message mixin
+ *
+ * Receive a message into the pending messages queue, where it will stay
+ * until acknowledged, and emit the ReceivedMessage signal. Also emit the
+ * Received signal if appropriate.
+ *
+ * Note that the sender and content arguments are *not* copied, and the caller
+ * loses ownership of them (this is to avoid lengthy and unnecessary copying
+ * of the content).
+ */
+void
+tp_message_mixin_take_received (GObject *object,
+ time_t timestamp,
+ TpHandle sender,
+ TpChannelTextMessageType message_type,
+ GPtrArray *content)
+{
+ TpMessageMixin *mixin = TP_MESSAGE_MIXIN (object);
+ PendingItem *pending = g_slice_new0 (PendingItem);
+ GString *text;
+
+ if (timestamp == 0)
+ timestamp = time (NULL);
+
+ /* FIXME: we don't check for overflow, so in highly pathological cases we
+ * might end up with multiple messages with the same ID */
+ pending->id = mixin->priv->recv_id++;
+ pending->sender = sender;
+ pending->timestamp = timestamp;
+ pending->message_type = message_type;
+ pending->content = content;
+ text = g_string_new ("");
+ pending->old_flags = parts_to_text (content, text);
+ pending->old_text = g_string_free (text, FALSE);
+
+ /* Queue it */
+
+ g_queue_push_tail (mixin->priv->pending, pending);
+
+ /* Signal it to clients */
+
+ tp_svc_channel_type_text_emit_received (object,
+ pending->id, timestamp, sender, message_type, pending->old_flags,
+ pending->old_text);
+
+ tp_svc_channel_interface_message_parts_emit_message_received (object,
+ pending->id, timestamp, sender, message_type, content);
+}
+
+
+#if 0
+void
+tp_message_mixin_take_delivery_report (GObject *object,
+ GHashTable *report)
+{
+}
+#endif
+
+
+struct _TpMessageMixinOutgoingMessagePrivate {
+ DBusGMethodInvocation *context;
+ gboolean message_parts:1;
+};
+
+
+void
+tp_message_mixin_sent (GObject *object,
+ TpMessageMixinOutgoingMessage *message,
+ const gchar *token)
+{
+ TpMessageMixin *mixin = TP_MESSAGE_MIXIN (object);
+ time_t now = time (NULL);
+ GString *string;
+
+ g_return_if_fail (mixin != NULL);
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (message != NULL);
+ g_return_if_fail (message != NULL);
+ g_return_if_fail (message->parts != NULL);
+ g_return_if_fail (message->priv != NULL);
+ g_return_if_fail (message->priv->context != NULL);
+
+ if (token == NULL)
+ token = "";
+
+ /* emit Sent and MessageSent */
+
+ tp_svc_channel_interface_message_parts_emit_message_sent (object,
+ message->message_type, message->parts, token);
+ string = g_string_new ("");
+ parts_to_text (message->parts, string);
+ tp_svc_channel_type_text_emit_sent (object, now, message->message_type,
+ g_string_free (string, FALSE));
+
+ /* return successfully */
+
+ if (message->priv->message_parts)
+ {
+ tp_svc_channel_interface_message_parts_return_from_send_message (
+ message->priv->context, token);
+ }
+ else
+ {
+ tp_svc_channel_type_text_return_from_send (
+ message->priv->context);
+ }
+
+ message->priv->context = NULL;
+}
+
+
static void
tp_message_mixin_send_async (TpSvcChannelTypeText *iface,
guint message_type,
const gchar *text,
DBusGMethodInvocation *context)
{
- GError e = { TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, "Not implemented" };
+ TpMessageMixin *mixin = TP_MESSAGE_MIXIN (iface);
+ GPtrArray *parts;
+ GHashTable *table;
+ GValue *value;
+ TpMessageMixinOutgoingMessage *message;
- dbus_g_method_return_error (context, &e);
+ if (mixin->priv->send_message == NULL)
+ {
+ tp_dbus_g_method_return_not_implemented (context);
+ return;
+ }
+
+ parts = g_ptr_array_sized_new (1);
+ table = g_hash_table_new_full (g_str_hash, g_str_equal,
+ NULL, (GDestroyNotify) tp_g_value_slice_free);
+
+ value = tp_g_value_slice_new (G_TYPE_STRING);
+ g_value_set_string (value, text);
+ g_hash_table_insert (table, "content", value);
+
+ value = tp_g_value_slice_new (G_TYPE_STRING);
+ g_value_set_static_string (value, "text/plain");
+ g_hash_table_insert (table, "type", value);
+
+ g_ptr_array_add (parts, table);
+
+ message = g_slice_new0 (TpMessageMixinOutgoingMessage);
+ message->flags = 0;
+ message->message_type = message_type;
+ message->parts = parts;
+ message->priv = g_slice_new0 (TpMessageMixinOutgoingMessagePrivate);
+ message->priv->context = context;
+ message->priv->message_parts = FALSE;
+
+ mixin->priv->send_message ((GObject *) iface, message);
}
+
static void
tp_message_mixin_send_message_async (TpSvcChannelInterfaceMessageParts *iface,
guint message_type,
@@ -504,11 +746,30 @@ tp_message_mixin_send_message_async (TpSvcChannelInterfaceMessageParts *iface,
guint flags,
DBusGMethodInvocation *context)
{
- GError e = { TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, "Not implemented" };
+ TpMessageMixin *mixin = TP_MESSAGE_MIXIN (iface);
+ TpMessageMixinOutgoingMessage *message;
- dbus_g_method_return_error (context, &e);
+ if (mixin->priv->send_message == NULL)
+ {
+ tp_dbus_g_method_return_not_implemented (context);
+ return;
+ }
+
+ message = g_slice_new0 (TpMessageMixinOutgoingMessage);
+ message->flags = flags;
+ message->message_type = message_type;
+ /* FIXME: fix codegen so we get a GType-generator for
+ * TP_ARRAY_TYPE_MESSAGE_PART */
+ message->parts = g_boxed_copy (dbus_g_type_get_collection ("GPtrArray",
+ TP_HASH_TYPE_MESSAGE_PART), parts);
+ message->priv = g_slice_new0 (TpMessageMixinOutgoingMessagePrivate);
+ message->priv->context = context;
+ message->priv->message_parts = TRUE;
+
+ mixin->priv->send_message ((GObject *) iface, message);
}
+
/**
* tp_message_mixin_iface_init:
* @g_iface: A pointer to the #TpSvcChannelTypeTextClass in an object class
diff --git a/telepathy-glib/message-mixin.h b/telepathy-glib/message-mixin.h
index 81bd7e9..11b01e7 100644
--- a/telepathy-glib/message-mixin.h
+++ b/telepathy-glib/message-mixin.h
@@ -42,35 +42,44 @@ struct _TpMessageMixin {
TpMessageMixinPrivate *priv;
};
-#define TP_MESSAGE_MIXIN_CLASS_OFFSET_QUARK \
- (tp_message_mixin_class_get_offset_quark ())
-#define TP_MESSAGE_MIXIN_CLASS_OFFSET(o) \
- (GPOINTER_TO_UINT (g_type_get_qdata (G_OBJECT_CLASS_TYPE (o), \
- TP_MESSAGE_MIXIN_CLASS_OFFSET_QUARK)))
-#define TP_MESSAGE_MIXIN_CLASS(o) \
- ((TpMessageMixinClass *) tp_mixin_offset_cast (o, \
- TP_MESSAGE_MIXIN_CLASS_OFFSET (o)))
-
-#define TP_MESSAGE_MIXIN_OFFSET_QUARK (tp_message_mixin_get_offset_quark ())
-#define TP_MESSAGE_MIXIN_OFFSET(o) \
- (GPOINTER_TO_UINT (g_type_get_qdata (G_OBJECT_TYPE (o), \
- TP_MESSAGE_MIXIN_OFFSET_QUARK)))
-#define TP_MESSAGE_MIXIN(o) \
- ((TpMessageMixin *) tp_mixin_offset_cast (o, TP_MESSAGE_MIXIN_OFFSET (o)))
-
-GQuark tp_message_mixin_class_get_offset_quark (void);
-GQuark tp_message_mixin_get_offset_quark (void);
-void tp_message_mixin_class_init (GObjectClass *obj_cls, gsize offset);
+/* Receiving */
+void tp_message_mixin_take_received (GObject *object,
+ time_t timestamp, TpHandle sender, TpChannelTextMessageType message_type,
+ GPtrArray *content);
-void tp_message_mixin_init (GObject *obj, gsize offset,
- TpHandleRepoIface *contact_repo);
-void tp_message_mixin_finalize (GObject *obj);
+/* Sending */
+typedef struct _TpMessageMixinOutgoingMessagePrivate
+ TpMessageMixinOutgoingMessagePrivate;
+
+typedef struct _TpMessageMixinOutgoingMessage {
+ guint flags;
+ guint message_type;
+ GPtrArray *parts;
+ TpMessageMixinOutgoingMessagePrivate *priv;
+} TpMessageMixinOutgoingMessage;
+
+typedef gboolean (*TpMessageMixinSendImpl) (GObject *object,
+ TpMessageMixinOutgoingMessage *message);
+
+void tp_message_mixin_sent (GObject *object,
+ TpMessageMixinOutgoingMessage *message, const gchar *token);
+
+
+/* Initialization */
void tp_message_mixin_text_iface_init (gpointer g_iface, gpointer iface_data);
void tp_message_mixin_message_parts_iface_init (gpointer g_iface,
gpointer iface_data);
+void tp_message_mixin_class_init (GObjectClass *obj_cls, gsize offset);
+
+void tp_message_mixin_init (GObject *obj, gsize offset,
+ TpHandleRepoIface *contact_repo);
+void tp_message_mixin_implement_sending (GObject *object,
+ TpMessageMixinSendImpl send);
+void tp_message_mixin_finalize (GObject *obj);
+
G_END_DECLS
#endif
--
1.5.6.5
More information about the Telepathy-commits
mailing list