diff options
author | Guillaume Desmottes <guillaume.desmottes@collabora.co.uk> | 2010-10-27 10:30:44 +0200 |
---|---|---|
committer | Guillaume Desmottes <guillaume.desmottes@collabora.co.uk> | 2010-10-27 16:36:16 +0200 |
commit | b68ed195e7cb46b92dae6de5061cd1f94e9ff732 (patch) | |
tree | c7b08b5c27166f2ccce326ad27730ddfaf7e9ba0 /src | |
parent | 3a72188a712b1cfd808d1522751fe30d1e1f1dc3 (diff) |
Implement Messages (#29377)
Diffstat (limited to 'src')
-rw-r--r-- | src/sip-text-channel.c | 357 | ||||
-rw-r--r-- | src/sip-text-channel.h | 3 |
2 files changed, 94 insertions, 266 deletions
diff --git a/src/sip-text-channel.c b/src/sip-text-channel.c index 60e8d6c..1472661 100644 --- a/src/sip-text-channel.c +++ b/src/sip-text-channel.c @@ -55,7 +55,6 @@ tpsip_text_channel_nua_r_message_cb (TpsipTextChannel *self, gpointer foo); static void channel_iface_init (gpointer, gpointer); -static void text_iface_init (gpointer, gpointer); static void destroyable_iface_init (gpointer, gpointer); G_DEFINE_TYPE_WITH_CODE (TpsipTextChannel, tpsip_text_channel, G_TYPE_OBJECT, @@ -63,7 +62,10 @@ G_DEFINE_TYPE_WITH_CODE (TpsipTextChannel, tpsip_text_channel, G_TYPE_OBJECT, 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_MESSAGES, + tp_message_mixin_messages_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_DESTROYABLE, destroyable_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_EXPORTABLE_CHANNEL, NULL); @@ -100,13 +102,6 @@ typedef struct _TpsipTextPendingMessage TpsipTextPendingMessage; struct _TpsipTextPendingMessage { - guint id; - time_t timestamp; - TpHandle sender; - TpChannelTextMessageType type; - guint flags; - gchar *text; - nua_handle_t *nh; }; @@ -119,9 +114,7 @@ struct _TpsipTextChannelPrivate TpHandle handle; TpHandle initiator; - guint recv_id; guint sent_id; - GQueue *pending_messages; GQueue *sending_messages; gboolean closed; @@ -138,11 +131,6 @@ struct _TpsipTextChannelPrivate static void tpsip_text_pending_free (TpsipTextPendingMessage *msg, TpHandleRepoIface *contact_handles) { - if (msg->sender) - tp_handle_unref (contact_handles, msg->sender); - - g_free (msg->text); - if (msg->nh) nua_handle_unref (msg->nh); @@ -156,10 +144,13 @@ tpsip_text_channel_init (TpsipTextChannel *obj) DEBUG("enter"); - priv->pending_messages = g_queue_new (); priv->sending_messages = g_queue_new (); } +static void tpsip_text_channel_send_message (GObject *object, + TpMessage *message, + TpMessageSendingFlags flags); + static void tpsip_text_channel_constructed (GObject *obj) { @@ -167,6 +158,13 @@ tpsip_text_channel_constructed (GObject *obj) TpBaseConnection *base_conn; TpHandleRepoIface *contact_handles; DBusGConnection *bus; + TpChannelTextMessageType types[] = { + TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL, + }; + const gchar * supported_content_types[] = { + "text/plain", + NULL + }; GObjectClass *parent_object_class = G_OBJECT_CLASS (tpsip_text_channel_parent_class); @@ -190,6 +188,14 @@ tpsip_text_channel_constructed (GObject *obj) G_CALLBACK (tpsip_text_channel_nua_r_message_cb), NULL); + tp_message_mixin_init (obj, G_STRUCT_OFFSET (TpsipTextChannel, message_mixin), + base_conn); + + tp_message_mixin_implement_sending (obj, tpsip_text_channel_send_message, + G_N_ELEMENTS (types), types, 0, + TP_DELIVERY_REPORTING_SUPPORT_FLAG_RECEIVE_FAILURES, + supported_content_types); + bus = tp_get_bus(); dbus_g_connection_register_g_object(bus, priv->object_path, obj); } @@ -298,6 +304,8 @@ tpsip_text_channel_class_init(TpsipTextChannelClass *klass) prop_interfaces; tp_dbus_properties_mixin_class_init (object_class, G_STRUCT_OFFSET (TpsipTextChannelClass, dbus_props_class)); + + tp_message_mixin_init_dbus_properties (object_class); } static void @@ -478,14 +486,6 @@ tpsip_text_channel_finalize(GObject *object) contact_handles = tp_base_connection_get_handles ( (TpBaseConnection *)priv->conn, TP_HANDLE_TYPE_CONTACT); - /* XXX: could have responded to the requests with e.g. 480, - * but generating network traffic upon abnormal channel termination - * does not sound like a good idea */ - DEBUG ("%u pending incoming messages", - g_queue_get_length (priv->pending_messages)); - zap_pending_messages (priv->pending_messages, contact_handles); - g_queue_free (priv->pending_messages); - DEBUG ("%u pending outgoing message requests", g_queue_get_length (priv->sending_messages)); zap_pending_messages (priv->sending_messages, contact_handles); @@ -493,13 +493,9 @@ tpsip_text_channel_finalize(GObject *object) g_free (priv->object_path); - G_OBJECT_CLASS (tpsip_text_channel_parent_class)->finalize (object); -} + tp_message_mixin_finalize (object); -static gint tpsip_pending_message_compare(gconstpointer msg, gconstpointer id) -{ - TpsipTextPendingMessage *message = (TpsipTextPendingMessage *)(msg); - return (message->id != GPOINTER_TO_UINT(id)); + G_OBJECT_CLASS (tpsip_text_channel_parent_class)->finalize (object); } static gint tpsip_acknowledged_messages_compare(gconstpointer msg, @@ -511,70 +507,6 @@ static gint tpsip_acknowledged_messages_compare(gconstpointer msg, } /** - * tpsip_text_channel_acknowledge_pending_messages - * - * Implements DBus method AcknowledgePendingMessages - * on interface org.freedesktop.Telepathy.Channel.Type.Text - */ -static void -tpsip_text_channel_acknowledge_pending_messages(TpSvcChannelTypeText *iface, - const GArray *ids, - DBusGMethodInvocation *context) -{ - TpsipTextChannel *chan = TPSIP_TEXT_CHANNEL (iface); - TpsipTextChannelPrivate *priv = TPSIP_TEXT_CHANNEL_GET_PRIVATE(chan); - TpHandleRepoIface *contact_repo; - GList **nodes; - TpsipTextPendingMessage *msg; - guint i; - - contact_repo = tp_base_connection_get_handles ( - (TpBaseConnection *)(priv->conn), TP_HANDLE_TYPE_CONTACT); - - 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 (priv->pending_messages, - GUINT_TO_POINTER (id), - tpsip_pending_message_compare); - - if (nodes[i] == NULL) - { - GError *error = NULL; - - DEBUG ("invalid message id %u", id); - - g_set_error (&error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, - "invalid message id %u", id); - - g_free(nodes); - dbus_g_method_return_error (context, error); - g_error_free (error); - return; - } - } - - for (i = 0; i < ids->len; i++) - { - msg = (TpsipTextPendingMessage *) nodes[i]->data; - - DEBUG("acknowledging message id %u", msg->id); - - g_queue_remove (priv->pending_messages, msg); - - tpsip_text_pending_free (msg, contact_repo); - } - - g_free(nodes); - - tp_svc_channel_type_text_return_from_acknowledge_pending_messages (context); -} - - -/** * tpsip_text_channel_close * * Implements DBus method Close @@ -593,24 +525,16 @@ tpsip_text_channel_close (TpSvcChannel *iface, } else { - if (g_queue_is_empty (priv->pending_messages)) + if (!tp_message_mixin_has_pending_messages ((GObject *) self, NULL)) { DEBUG ("actually closing, no pending messages"); priv->closed = TRUE; } else { - GList *cur; - DEBUG ("not really closing, there are pending messages left"); - for (cur = g_queue_peek_head_link (priv->pending_messages); - cur != NULL; - cur = cur->next) - { - TpsipTextPendingMessage *msg = cur->data; - msg->flags |= TP_CHANNEL_TEXT_MESSAGE_FLAG_RESCUED; - } + tp_message_mixin_set_rescued ((GObject *) self); if (priv->initiator != priv->handle) { @@ -647,8 +571,7 @@ tpsip_text_channel_destroy (TpSvcChannelInterfaceDestroyable *iface, contact_handles = tp_base_connection_get_handles ( (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT); - /* Make sure there are no pending messages for Close to get excited about */ - zap_pending_messages (priv->pending_messages, contact_handles); + tp_message_mixin_clear ((GObject *) iface); /* Close() and Destroy() have the same signature, so we can safely * chain to the other function now */ @@ -709,140 +632,64 @@ tpsip_text_channel_get_interfaces(TpSvcChannel *iface, tpsip_text_channel_interfaces); } - -/** - * tpsip_text_channel_get_message_types - * - * Implements DBus method GetMessageTypes - * on interface org.freedesktop.Telepathy.Channel.Type.Text - */ static void -tpsip_text_channel_get_message_types(TpSvcChannelTypeText *iface, - DBusGMethodInvocation *context) +tpsip_text_channel_send_message (GObject *object, + TpMessage *message, + TpMessageSendingFlags flags) { - GArray *ret = g_array_sized_new (FALSE, FALSE, sizeof (guint), 1); - guint normal[1] = { TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL }; + TpsipTextChannel *self = TPSIP_TEXT_CHANNEL(object); + TpsipTextChannelPrivate *priv = TPSIP_TEXT_CHANNEL_GET_PRIVATE (self); + TpsipTextPendingMessage *msg = NULL; + nua_handle_t *msg_nh = NULL; + GError *error = NULL; + const GHashTable *part; + guint n_parts; + const gchar *content_type; + const gchar *text; DEBUG("enter"); - g_array_append_val (ret, normal); - tp_svc_channel_type_text_return_from_get_message_types (context, ret); - g_array_free (ret, TRUE); -} - -static void -tpsip_pending_message_list_add (GPtrArray *list, TpsipTextPendingMessage *msg) -{ - GValue val = { 0 }; - GType message_type; - - message_type = TP_STRUCT_TYPE_PENDING_TEXT_MESSAGE; - g_value_init (&val, message_type); - g_value_take_boxed (&val, - dbus_g_type_specialized_construct (message_type)); - 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 (list, g_value_get_boxed (&val)); -} - -/** - * tpsip_text_channel_list_pending_messages - * - * Implements DBus method ListPendingMessages - * on interface org.freedesktop.Telepathy.Channel.Type.Text - */ -static void -tpsip_text_channel_list_pending_messages(TpSvcChannelTypeText *iface, - gboolean clear, - DBusGMethodInvocation *context) -{ - TpsipTextChannel *self = (TpsipTextChannel*) iface; - TpsipTextChannelPrivate *priv; - GPtrArray *messages; - GList *cur; - guint count; - g_assert (TPSIP_IS_TEXT_CHANNEL(self)); - priv = TPSIP_TEXT_CHANNEL_GET_PRIVATE (self); +#define INVALID_ARGUMENT(msg, ...) \ + G_STMT_START { \ + DEBUG (msg , ## __VA_ARGS__); \ + g_set_error (&error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, \ + msg , ## __VA_ARGS__); \ + goto fail; \ + } G_STMT_END - count = g_queue_get_length (priv->pending_messages); - messages = g_ptr_array_sized_new (count); + part = tp_message_peek (message, 0); - if (clear) + if (tp_asv_lookup (part, "message-type") != NULL) { - TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT); - while ((cur = g_queue_pop_head_link (priv->pending_messages)) != NULL) - { - TpsipTextPendingMessage * msg = (TpsipTextPendingMessage *) cur->data; - tpsip_pending_message_list_add (messages, msg); - tpsip_text_pending_free (msg, contact_repo); - } + if (tp_asv_get_uint32 (part, "message-type", NULL) != + TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL) + INVALID_ARGUMENT ("invalid message type"); } - else - { - for (cur = g_queue_peek_head_link(priv->pending_messages); - cur != NULL; - cur = cur->next) - tpsip_pending_message_list_add (messages, - (TpsipTextPendingMessage *) cur->data); - } - - tp_svc_channel_type_text_return_from_list_pending_messages (context, - messages); - g_boxed_free (TP_ARRAY_TYPE_PENDING_TEXT_MESSAGE_LIST, messages); -} + n_parts = tp_message_count_parts (message); + if (n_parts != 2) + INVALID_ARGUMENT ("message must contain exactly 1 part, not %u", + (n_parts - 1)); -/** - * tpsip_text_channel_send - * - * Implements DBus method Send - * on interface org.freedesktop.Telepathy.Channel.Type.Text - * - * @error: Used to return a pointer to a GError detailing any error - * that occured, DBus will throw the error only if this - * function returns false. - * - * Returns: TRUE if successful, FALSE if an error was thrown. - */ -static void -tpsip_text_channel_send(TpSvcChannelTypeText *iface, - guint type, - const gchar *text, - DBusGMethodInvocation *context) -{ - TpsipTextChannel *self = TPSIP_TEXT_CHANNEL(iface); - TpsipTextChannelPrivate *priv = TPSIP_TEXT_CHANNEL_GET_PRIVATE (self); - TpsipTextPendingMessage *msg = NULL; - nua_handle_t *msg_nh = NULL; + part = tp_message_peek (message, 1); + content_type = tp_asv_get_string (part, "content-type"); + text = tp_asv_get_string (part, "content"); - DEBUG("enter"); + if (content_type == NULL || tp_strdiff (content_type, "text/plain")) + INVALID_ARGUMENT ("message must be text/plain"); - if (priv->handle == 0) - { - GError invalid = { TP_ERRORS, TP_ERROR_NOT_AVAILABLE, - "Invalid recipient" }; + if (text == NULL) + INVALID_ARGUMENT ("content must be a UTF-8 string"); - WARNING ("invalid recipient handle %d", priv->handle); - dbus_g_method_return_error (context, &invalid); - return; - } + /* Okay, it's valid. Let's send it. */ msg_nh = tpsip_conn_create_request_handle (priv->conn, priv->handle); if (msg_nh == NULL) { - GError e = { TP_ERRORS, TP_ERROR_NOT_AVAILABLE, - "Request creation failed" }; - dbus_g_method_return_error (context, &e); - return; + g_set_error (&error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + "Request creation failed"); + goto fail; } tpsip_event_target_attach (msg_nh, (GObject *) self); @@ -854,15 +701,17 @@ tpsip_text_channel_send(TpSvcChannelTypeText *iface, msg = _tpsip_text_pending_new0 (); msg->nh = msg_nh; - msg->text = g_strdup(text); - msg->type = type; - msg->timestamp = time(NULL); + tp_message_mixin_sent (object, message, flags, "", NULL); g_queue_push_tail (priv->sending_messages, msg); - DEBUG("message queued for delivery with timestamp %u", (guint)msg->timestamp); + DEBUG ("message queued for delivery"); + return; - tp_svc_channel_type_text_return_from_send (context); +fail: + g_assert (error != NULL); + tp_message_mixin_sent (object, message, 0, NULL, error); + g_error_free (error); } static gboolean @@ -896,11 +745,10 @@ tpsip_text_channel_nua_r_message_cb (TpsipTextChannel *self, g_assert (msg != NULL); + /* FIXME: generate a delivery report */ if (ev->status >= 200 && ev->status < 300) { - DEBUG("message with timestamp %u delivered", (guint)msg->timestamp); - tp_svc_channel_type_text_emit_sent (self, - msg->timestamp, msg->type, msg->text); + DEBUG ("message delivered"); } else { @@ -939,9 +787,6 @@ tpsip_text_channel_nua_r_message_cb (TpsipTextChannel *self, default: send_error = TP_CHANNEL_TEXT_SEND_ERROR_UNKNOWN; } - - tp_svc_channel_type_text_emit_send_error (self, - send_error, msg->timestamp, msg->type, msg->text); } g_queue_remove(priv->sending_messages, msg); @@ -961,30 +806,24 @@ void tpsip_text_channel_receive(TpsipTextChannel *chan, gsize len) { TpsipTextChannelPrivate *priv = TPSIP_TEXT_CHANNEL_GET_PRIVATE (chan); - TpsipTextPendingMessage *msg; - TpHandleRepoIface *contact_repo; - - msg = _tpsip_text_pending_new0 (); + TpMessage *msg; + TpBaseConnection *base_conn; - msg->id = priv->recv_id++; - msg->timestamp = time(NULL); - msg->sender = sender; - msg->type = TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL; - msg->text = g_strndup (text, len); + base_conn = (TpBaseConnection *) priv->conn; + msg = tp_message_new (base_conn, 2, 2); - g_queue_push_tail(priv->pending_messages, msg); + DEBUG ("Received message from contact %u: %s", sender, text); - contact_repo = tp_base_connection_get_handles ( - (TpBaseConnection *)(priv->conn), TP_HANDLE_TYPE_CONTACT); + /* Header */ + tp_message_set_handle (msg, 0, "message-sender", TP_HANDLE_TYPE_CONTACT, + sender); + tp_message_set_uint64 (msg, 0, "message-received", time (NULL)); - tp_handle_ref (contact_repo, sender); + /* Body */ + tp_message_set_string (msg, 1, "content-type", "text/plain"); + tp_message_set_string (msg, 1, "content", text); - DEBUG("received message id %u, now %u pending", - msg->id, g_queue_get_length (priv->pending_messages)); - - tp_svc_channel_type_text_emit_received ((TpSvcChannelTypeText *)chan, - msg->id, msg->timestamp, msg->sender, msg->type, - 0 /* flags */, msg->text); + tp_message_mixin_take_received (G_OBJECT (chan), msg); } static void @@ -1012,17 +851,3 @@ channel_iface_init(gpointer g_iface, gpointer iface_data) IMPLEMENT(get_interfaces); #undef IMPLEMENT } - -static void -text_iface_init (gpointer g_iface, gpointer iface_data) -{ - TpSvcChannelTypeTextClass *klass = (TpSvcChannelTypeTextClass *)g_iface; - -#define IMPLEMENT(x) tp_svc_channel_type_text_implement_##x (klass,\ - tpsip_text_channel_##x) - IMPLEMENT(acknowledge_pending_messages); - IMPLEMENT(get_message_types); - IMPLEMENT(list_pending_messages); - IMPLEMENT(send); -#undef IMPLEMENT -} diff --git a/src/sip-text-channel.h b/src/sip-text-channel.h index efbe204..98db60d 100644 --- a/src/sip-text-channel.h +++ b/src/sip-text-channel.h @@ -24,6 +24,7 @@ #include <glib-object.h> #include <telepathy-glib/dbus-properties-mixin.h> #include <telepathy-glib/handle.h> +#include <telepathy-glib/message-mixin.h> #include <tpsip/sofia-decls.h> @@ -40,6 +41,8 @@ struct _TpsipTextChannelClass { struct _TpsipTextChannel { GObject parent; + + TpMessageMixin message_mixin; }; GType tpsip_text_channel_get_type(void); |