diff options
author | Jonny Lamb <jonny.lamb@collabora.co.uk> | 2012-08-28 14:21:04 +0100 |
---|---|---|
committer | Jonny Lamb <jonny.lamb@collabora.co.uk> | 2012-08-28 14:21:04 +0100 |
commit | 9ad89f9a9a35467ce5649070b0207a91cbbd251b (patch) | |
tree | b4f1eae19b9a8d8c7b33949dfc0c73ab29633326 | |
parent | de9b0d133c83c6340b1797040a236367dadcf2dd (diff) | |
parent | f374056b8abf3a4179836faf1f397dfa1213c5ae (diff) | |
download | telepathy-salut-9ad89f9a9a35467ce5649070b0207a91cbbd251b.tar.gz |
Merge branch 'cheerio-tubes'
Conflicts:
src/tubes-channel.c
Signed-off-by: Jonny Lamb <jonny.lamb@collabora.co.uk>
-rw-r--r-- | src/Makefile.am | 6 | ||||
-rw-r--r-- | src/avahi-muc-manager.c | 1 | ||||
-rw-r--r-- | src/avahi-roomlist-manager.c | 1 | ||||
-rw-r--r-- | src/muc-channel.c | 808 | ||||
-rw-r--r-- | src/muc-channel.h | 20 | ||||
-rw-r--r-- | src/muc-manager.c | 589 | ||||
-rw-r--r-- | src/muc-manager.h | 6 | ||||
-rw-r--r-- | src/muc-tube-dbus.c | 47 | ||||
-rw-r--r-- | src/muc-tube-dbus.h | 60 | ||||
-rw-r--r-- | src/muc-tube-stream.c | 47 | ||||
-rw-r--r-- | src/muc-tube-stream.h | 60 | ||||
-rw-r--r-- | src/roomlist-manager.c | 1 | ||||
-rw-r--r-- | src/roomlist-manager.h | 1 | ||||
-rw-r--r-- | src/tube-dbus.c | 454 | ||||
-rw-r--r-- | src/tube-dbus.h | 11 | ||||
-rw-r--r-- | src/tube-iface.c | 17 | ||||
-rw-r--r-- | src/tube-stream.c | 544 | ||||
-rw-r--r-- | src/tube-stream.h | 11 | ||||
-rw-r--r-- | src/tubes-channel.c | 2598 | ||||
-rw-r--r-- | src/tubes-channel.h | 94 | ||||
-rw-r--r-- | src/tubes-manager.c | 503 | ||||
-rw-r--r-- | src/tubes-manager.h | 1 | ||||
-rw-r--r-- | tests/twisted/Makefile.am | 1 | ||||
-rw-r--r-- | tests/twisted/avahi/only-text-muc-when-needed.py | 318 | ||||
-rw-r--r-- | tests/twisted/avahi/tubes/request-muc-tubes.py | 148 | ||||
-rw-r--r-- | tests/twisted/avahi/tubes/two-muc-dbus-tubes.py | 139 | ||||
-rw-r--r-- | tests/twisted/avahi/tubes/two-muc-stream-tubes.py | 284 |
27 files changed, 2282 insertions, 4488 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 8a985abd..3fea9215 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -45,6 +45,10 @@ CORE_SOURCES = \ file-transfer-channel.c \ file-transfer-channel.h \ muc-channel.h \ + muc-tube-dbus.c \ + muc-tube-dbus.h \ + muc-tube-stream.c \ + muc-tube-stream.h \ presence-cache.c \ presence-cache.h \ tubes-manager.c \ @@ -72,8 +76,6 @@ CORE_SOURCES = \ tube-iface.c \ tube-stream.h \ tube-stream.c \ - tubes-channel.h \ - tubes-channel.c \ util.h \ util.c \ protocol.c \ diff --git a/src/avahi-muc-manager.c b/src/avahi-muc-manager.c index 46fea622..7418ab63 100644 --- a/src/avahi-muc-manager.c +++ b/src/avahi-muc-manager.c @@ -34,7 +34,6 @@ #include "muc-channel.h" #include "contact-manager.h" -#include "tubes-channel.h" #include "roomlist-channel.h" #include "avahi-muc-channel.h" diff --git a/src/avahi-roomlist-manager.c b/src/avahi-roomlist-manager.c index 1ac27f78..625be31d 100644 --- a/src/avahi-roomlist-manager.c +++ b/src/avahi-roomlist-manager.c @@ -33,7 +33,6 @@ #include <gibber/gibber-muc-connection.h> #include "contact-manager.h" -#include "tubes-channel.h" #include "roomlist-channel.h" #include <telepathy-glib/channel-factory-iface.h> diff --git a/src/muc-channel.c b/src/muc-channel.c index 38bf002f..c83ca1de 100644 --- a/src/muc-channel.c +++ b/src/muc-channel.c @@ -42,6 +42,7 @@ #include <telepathy-glib/errors.h> #include <telepathy-glib/util.h> +#include <gibber/gibber-bytestream-muc.h> #include <gibber/gibber-muc-connection.h> #include <gibber/gibber-transport.h> @@ -53,6 +54,7 @@ #include "text-helper.h" #include "tube-stream.h" +#include "tube-dbus.h" G_DEFINE_TYPE_WITH_CODE(SalutMucChannel, salut_muc_channel, TP_TYPE_BASE_CHANNEL, G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_GROUP, @@ -74,6 +76,7 @@ enum { READY, JOIN_ERROR, + NEW_TUBE, LAST_SIGNAL }; @@ -99,7 +102,10 @@ struct _SalutMucChannelPrivate guint timeout; /* (gchar *) -> (SalutContact *) */ GHashTable *senders; - SalutMucManager *muc_manager; + + gboolean autoclose; + + GHashTable *tubes; }; /* Callback functions */ @@ -122,6 +128,16 @@ static void salut_muc_channel_send (GObject *channel, TpMessageSendingFlags flags); static void salut_muc_channel_close (TpBaseChannel *base); +static void update_tube_info (SalutMucChannel *self); +static SalutTubeIface * create_new_tube (SalutMucChannel *self, + TpTubeType type, + TpHandle initiator, + const gchar *service, + GHashTable *parameters, + guint64 tube_id, + guint portnum, + WockyStanza *iq_req, + gboolean requested); static void salut_muc_channel_get_property (GObject *object, @@ -290,14 +306,6 @@ salut_muc_channel_constructed (GObject *obj) g_signal_connect (priv->muc_connection, "connected", G_CALLBACK (muc_connection_connected_cb), obj); - g_object_get (base_conn, - "muc-manager", &(priv->muc_manager), - NULL); - g_assert (priv->muc_manager != NULL); - - /* no need to keep a ref on the muc manager as it keeps a ref on us */ - g_object_unref (priv->muc_manager); - tp_group_mixin_init (obj, G_STRUCT_OFFSET(SalutMucChannel, group), contact_repo, base_conn->self_handle); @@ -306,6 +314,9 @@ salut_muc_channel_constructed (GObject *obj) TP_CHANNEL_GROUP_FLAG_CAN_ADD | TP_CHANNEL_GROUP_FLAG_MESSAGE_ADD, 0); + + priv->tubes = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, (GDestroyNotify) g_object_unref); } static void @@ -693,6 +704,17 @@ salut_muc_channel_class_init (SalutMucChannelClass *salut_muc_channel_class) g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); + signals[NEW_TUBE] = g_signal_new ( + "new-tube", + G_OBJECT_CLASS_TYPE (salut_muc_channel_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + /* this should be SALUT_TYPE_TUBE_IFACE but GObject + * wants a value type, not an interface. */ + G_TYPE_NONE, 1, TP_TYPE_BASE_CHANNEL); + tp_group_mixin_class_init (object_class, G_STRUCT_OFFSET(SalutMucChannelClass, group_class), salut_muc_channel_add_member, NULL); @@ -716,6 +738,8 @@ salut_muc_channel_dispose (GObject *object) priv->dispose_has_run = TRUE; + priv->connected = FALSE; + g_signal_handlers_disconnect_matched (priv->muc_connection, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self); @@ -737,6 +761,8 @@ salut_muc_channel_dispose (GObject *object) priv->senders = NULL; } + tp_clear_pointer (&priv->tubes, g_hash_table_unref); + /* release any references held by the object here */ if (G_OBJECT_CLASS (salut_muc_channel_parent_class)->dispose) G_OBJECT_CLASS (salut_muc_channel_parent_class)->dispose (object); @@ -915,6 +941,290 @@ salut_muc_channel_remove_members (SalutMucChannel *self, tp_intset_destroy (empty); } +/* tube_node is a MUC <message> */ +static gboolean +extract_tube_information (SalutMucChannel *self, + WockyNode *tube_node, + TpTubeType *type, + TpHandle *initiator_handle, + const gchar **service, + GHashTable **parameters, + guint *tube_id) +{ + TpBaseChannel *base = TP_BASE_CHANNEL (self); + TpBaseConnection *base_conn = tp_base_channel_get_connection (base); + TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( + base_conn, TP_HANDLE_TYPE_CONTACT); + + if (type != NULL) + { + const gchar *_type; + + _type = wocky_node_get_attribute (tube_node, "type"); + + + if (!tp_strdiff (_type, "stream")) + { + *type = TP_TUBE_TYPE_STREAM; + } + else if (!tp_strdiff (_type, "dbus")) + { + *type = TP_TUBE_TYPE_DBUS; + } + else + { + DEBUG ("Unknown tube type: %s", _type); + return FALSE; + } + } + + if (initiator_handle != NULL) + { + const gchar *initiator; + + initiator = wocky_node_get_attribute (tube_node, "initiator"); + + if (initiator != NULL) + { + *initiator_handle = tp_handle_ensure (contact_repo, initiator, NULL, + NULL); + + if (*initiator_handle == 0) + { + DEBUG ("invalid initiator ID %s", initiator); + return FALSE; + } + } + else + { + *initiator_handle = 0; + } + } + + if (service != NULL) + { + *service = wocky_node_get_attribute (tube_node, "service"); + } + + if (parameters != NULL) + { + WockyNode *node; + + node = wocky_node_get_child (tube_node, "parameters"); + *parameters = salut_wocky_node_extract_properties (node, + "parameter"); + } + + if (tube_id != NULL) + { + const gchar *str; + gchar *endptr; + long int tmp; + + str = wocky_node_get_attribute (tube_node, "id"); + if (str == NULL) + { + DEBUG ("no tube id in SI request"); + return FALSE; + } + + tmp = strtol (str, &endptr, 10); + if (!endptr || *endptr) + { + DEBUG ("tube id is not numeric: %s", str); + return FALSE; + } + *tube_id = (int) tmp; + } + + return TRUE; +} + +static void +muc_channel_handle_tubes (SalutMucChannel *self, + TpHandle contact, + WockyStanza *stanza) +{ + SalutMucChannelPrivate *priv = self->priv; + TpBaseChannel *base = TP_BASE_CHANNEL (self); + TpBaseConnection *base_conn = tp_base_channel_get_connection (base); + TpHandleRepoIface *contact_repo = + tp_base_connection_get_handles (base_conn, + TP_HANDLE_TYPE_CONTACT); + const gchar *sender; + WockyStanzaType stanza_type; + WockyStanzaSubType sub_type; + GHashTable *old_dbus_tubes; + GHashTableIter iter; + gpointer key, value; + GSList *l; + WockyNode *tubes_node; + + if (contact == TP_GROUP_MIXIN (self)->self_handle) + /* we don't need to inspect our own tubes */ + return; + + sender = tp_handle_inspect (contact_repo, contact); + + wocky_stanza_get_type_info (stanza, &stanza_type, &sub_type); + if (stanza_type != WOCKY_STANZA_TYPE_MESSAGE + || sub_type != WOCKY_STANZA_SUB_TYPE_GROUPCHAT) + return; + + tubes_node = wocky_node_get_child_ns ( + wocky_stanza_get_top_node (stanza), "tubes", + WOCKY_TELEPATHY_NS_TUBES); + g_assert (tubes_node != NULL); + + /* fill old_dbus_tubes with D-Bus tubes previously announced by the + * contact */ + old_dbus_tubes = g_hash_table_new (NULL, NULL); + g_hash_table_iter_init (&iter, priv->tubes); + while (g_hash_table_iter_next (&iter, &key, &value)) + { + guint tube_id = GPOINTER_TO_UINT (key); + SalutTubeIface *tube = value; + TpTubeType type; + + g_object_get (tube, + "type", &type, + NULL); + + if (type != TP_TUBE_TYPE_DBUS) + return; + + if (salut_tube_dbus_handle_in_names (SALUT_TUBE_DBUS (tube), + contact)) + { + g_hash_table_insert (old_dbus_tubes, GUINT_TO_POINTER (tube_id), tube); + } + } + + for (l = tubes_node->children; l != NULL; l = l->next) + { + WockyNode *tube_node = (WockyNode *) l->data; + const gchar *stream_id; + SalutTubeIface *tube; + guint tube_id; + TpTubeType type; + GibberBytestreamIface *bytestream; + + stream_id = wocky_node_get_attribute (tube_node, "stream-id"); + + if (!extract_tube_information (self, tube_node, NULL, + NULL, NULL, NULL, &tube_id)) + continue; + + tube = g_hash_table_lookup (priv->tubes, GUINT_TO_POINTER (tube_id)); + + if (tube == NULL) + { + /* a new tube */ + const gchar *service; + TpHandle initiator_handle; + GHashTable *parameters; + guint id; + + if (extract_tube_information (self, tube_node, &type, + &initiator_handle, &service, ¶meters, &id)) + { + switch (type) + { + case TP_TUBE_TYPE_DBUS: + { + if (initiator_handle == 0) + { + DEBUG ("D-Bus tube initiator missing"); + continue; + } + } + break; + case TP_TUBE_TYPE_STREAM: + initiator_handle = contact; + break; + default: + g_assert_not_reached (); + } + + tube = create_new_tube (self, type, initiator_handle, service, parameters, + id, 0, NULL, FALSE); + + g_signal_emit (self, signals[NEW_TUBE], 0, tube); + + g_hash_table_unref (parameters); + } + } + else + { + /* the contact is in the tube. + * remove it from old_dbus_tubes if needed. */ + g_hash_table_remove (old_dbus_tubes, GUINT_TO_POINTER (tube_id)); + } + + if (tube == NULL) + continue; + + g_object_get (tube, + "type", &type, + NULL); + + if (type == TP_TUBE_TYPE_DBUS + && !salut_tube_dbus_handle_in_names (SALUT_TUBE_DBUS (tube), + contact)) + { + /* contact just joined the tube */ + const gchar *new_name; + + new_name = wocky_node_get_attribute (tube_node, "dbus-name"); + + if (new_name == NULL) + { + DEBUG ("Contact %u isn't announcing his or her D-Bus name", contact); + continue; + } + + salut_tube_dbus_add_name (SALUT_TUBE_DBUS (tube), contact, new_name); + + g_object_get (tube, + "bytestream", &bytestream, + NULL); + g_assert (bytestream != NULL); + + if (GIBBER_IS_BYTESTREAM_MUC (bytestream)) + { + guint16 tmp = (guint16) atoi (stream_id); + + gibber_bytestream_muc_add_sender ( + GIBBER_BYTESTREAM_MUC (bytestream), sender, tmp); + } + + g_object_unref (bytestream); + } + } + + g_hash_table_iter_init (&iter, old_dbus_tubes); + while (g_hash_table_iter_next (&iter, NULL, &value)) + { + SalutTubeDBus *tube = SALUT_TUBE_DBUS (value); + GibberBytestreamIface *bytestream; + + salut_tube_dbus_remove_name (tube, contact); + + g_object_get (tube, + "bytestream", &bytestream, + NULL); + g_assert (bytestream != NULL); + + if (GIBBER_IS_BYTESTREAM_MUC (bytestream) && sender != NULL) + { + gibber_bytestream_muc_remove_sender ( + GIBBER_BYTESTREAM_MUC (bytestream), sender); + } + + g_object_unref (bytestream); + } +} + static void salut_muc_channel_received_stanza (GibberMucConnection *conn, const gchar *sender, @@ -951,6 +1261,16 @@ salut_muc_channel_received_stanza (GibberMucConnection *conn, return; } + /* are we actually hidden? */ + if (!tp_base_channel_is_registered (base_chan)) + { + DEBUG ("making MUC channel reappear!"); + tp_base_channel_reopened_with_requested (base_chan, FALSE, from_handle); + } + + /* let's not autoclose now */ + priv->autoclose = FALSE; + #ifdef ENABLE_OLPC if (salut_connection_olpc_observe_muc_stanza ( SALUT_CONNECTION (base_connection), @@ -963,43 +1283,7 @@ salut_muc_channel_received_stanza (GibberMucConnection *conn, WOCKY_TELEPATHY_NS_TUBES); if (tubes_node != NULL) { - SalutTubesChannel *tubes_chan; - GPtrArray *tubes; - guint i; - GHashTable *channels; - gboolean created; - - tubes_chan = salut_muc_manager_ensure_tubes_channel (priv->muc_manager, - tp_base_channel_get_target_handle (base_chan), from_handle, &created); - g_assert (tubes_chan != NULL); - - channels = g_hash_table_new_full (g_direct_hash, g_direct_equal, - NULL, NULL); - - if (created) - { - g_hash_table_insert (channels, tubes_chan, NULL); - } - - tubes = salut_tubes_channel_muc_message_received (tubes_chan, sender, - stanza); - - for (i = 0; i < tubes->len; i++) - { - SalutTubeIface *tube; - - tube = g_ptr_array_index (tubes, i); - g_hash_table_insert (channels, tube, NULL); - } - - if (g_hash_table_size (channels) > 0) - { - tp_channel_manager_emit_new_channels (priv->muc_manager, channels); - } - - g_object_unref (tubes_chan); - g_ptr_array_unref (tubes); - g_hash_table_unref (channels); + muc_channel_handle_tubes (self, from_handle, stanza); } if (!text_helper_parse_incoming_message (stanza, &from, &msgtype, @@ -1037,6 +1321,8 @@ salut_muc_channel_new_senders (GibberMucConnection *connection, DEBUG ("Got new senders. Adding myself as member"); salut_muc_channel_add_self_to_members (self); } + + update_tube_info (self); } static void @@ -1092,11 +1378,43 @@ salut_muc_channel_disconnected (GibberTransport *transport, gpointer user_data) tp_base_channel_destroyed (TP_BASE_CHANNEL (self)); } +gboolean +salut_muc_channel_can_be_closed (SalutMucChannel *self) +{ + if (self->priv->tubes == NULL) + return TRUE; + + return (g_hash_table_size (self->priv->tubes) == 0); +} + +gboolean +salut_muc_channel_get_autoclose (SalutMucChannel *self) +{ + return self->priv->autoclose; +} + +void +salut_muc_channel_set_autoclose (SalutMucChannel *self, + gboolean autoclose) +{ + self->priv->autoclose = autoclose; +} + static void salut_muc_channel_close (TpBaseChannel *base) { SalutMucChannel *self = SALUT_MUC_CHANNEL (base); + /* if we have some tubes around then don't close yet and just + * disappear from the bus, faking having closed, otherwise + * cheerio! */ + if (!salut_muc_channel_can_be_closed (self)) + { + self->priv->autoclose = TRUE; + tp_base_channel_disappear (base); + return; + } + salut_muc_channel_leave (self, TP_CHANNEL_GROUP_CHANGE_REASON_NONE, ""); tp_base_channel_destroyed (base); @@ -1146,3 +1464,401 @@ error: return; } +static void +publish_tube_in_node (SalutMucChannel *self, + WockyNode *node, + SalutTubeIface *tube) +{ + TpBaseChannel *base = TP_BASE_CHANNEL (tube); + TpBaseConnection *base_conn = tp_base_channel_get_connection (base); + TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( + base_conn, TP_HANDLE_TYPE_CONTACT); + WockyNode *parameters_node; + GHashTable *parameters; + TpTubeType type; + gchar *service, *id_str; + guint64 tube_id; + TpHandle initiator_handle; + + g_object_get (tube, + "type", &type, + "initiator-handle", &initiator_handle, + "service", &service, + "parameters", ¶meters, + "id", &tube_id, + NULL); + + id_str = g_strdup_printf ("%" G_GUINT64_FORMAT, tube_id); + + wocky_node_set_attribute (node, "service", service); + wocky_node_set_attribute (node, "id", id_str); + + g_free (id_str); + + switch (type) + { + case TP_TUBE_TYPE_DBUS: + { + gchar *name, *stream_id; + + g_object_get (G_OBJECT (tube), + "dbus-name", &name, + "stream-id", &stream_id, + NULL); + + wocky_node_set_attribute (node, "type", "dbus"); + wocky_node_set_attribute (node, "stream-id", stream_id); + wocky_node_set_attribute (node, "initiator", + tp_handle_inspect (contact_repo, initiator_handle)); + + if (name != NULL) + wocky_node_set_attribute (node, "dbus-name", name); + + g_free (name); + g_free (stream_id); + + } + break; + case TP_TUBE_TYPE_STREAM: + wocky_node_set_attribute (node, "type", "stream"); + break; + default: + g_assert_not_reached (); + } + + parameters_node = wocky_node_add_child (node, "parameters"); + salut_wocky_node_add_children_from_properties (parameters_node, + parameters, "parameter"); + + g_free (service); + g_hash_table_unref (parameters); +} + +static void +update_tube_info (SalutMucChannel *self) +{ + SalutMucChannelPrivate *priv = self->priv; + TpBaseChannel *base = TP_BASE_CHANNEL (self); + TpBaseConnection *base_conn = tp_base_channel_get_connection (base); + SalutConnection *conn = SALUT_CONNECTION (base_conn); + TpHandleRepoIface *room_repo = tp_base_connection_get_handles ( + base_conn, TP_HANDLE_TYPE_ROOM); + GHashTableIter iter; + gpointer value; + WockyStanza *msg; + WockyNode *msg_node; + WockyNode *node; + const gchar *jid; + GError *error = NULL; + + if (priv->tubes == NULL) + return; + + /* build the message */ + jid = tp_handle_inspect (room_repo, + tp_base_channel_get_target_handle (base)); + + msg = wocky_stanza_build (WOCKY_STANZA_TYPE_MESSAGE, + WOCKY_STANZA_SUB_TYPE_GROUPCHAT, + conn->name, jid, + WOCKY_NODE_START, "tubes", + WOCKY_NODE_XMLNS, WOCKY_TELEPATHY_NS_TUBES, + WOCKY_NODE_END, NULL); + msg_node = wocky_stanza_get_top_node (msg); + + node = wocky_node_get_child_ns (msg_node, "tubes", + WOCKY_TELEPATHY_NS_TUBES); + + g_hash_table_iter_init (&iter, priv->tubes); + while (g_hash_table_iter_next (&iter, NULL, &value)) + { + TpTubeChannelState state; + TpTubeType type; + TpHandle initiator; + WockyNode *tube_node; + + g_object_get (value, + "state", &state, + "type", &type, + "initiator-handle", &initiator, + NULL); + + if (state != TP_TUBE_CHANNEL_STATE_OPEN) + continue; + + if (type == TP_TUBE_TYPE_STREAM + && initiator != TP_GROUP_MIXIN (self)->self_handle) + /* We only announce stream tubes we initiated */ + return; + + tube_node = wocky_node_add_child (node, "tube"); + publish_tube_in_node (self, tube_node, value); + } + + /* Send it */ + if (!gibber_muc_connection_send (priv->muc_connection, msg, &error)) + { + g_warning ("%s: sending tubes info failed: %s", G_STRFUNC, + error->message); + g_error_free (error); + } + + g_object_unref (msg); +} + +static void +tube_opened_cb (SalutTubeIface *tube, + SalutMucChannel *self) +{ + if (SALUT_IS_TUBE_DBUS (tube)) + { + gchar *dbus_name; + + g_object_get (tube, + "dbus-name", &dbus_name, + NULL); + + salut_tube_dbus_add_name (SALUT_TUBE_DBUS (tube), + TP_GROUP_MIXIN (self)->self_handle, dbus_name); + + g_free (dbus_name); + } + + update_tube_info (self); +} + +static void +tube_offered_cb (SalutTubeIface *tube, + SalutMucChannel *self) +{ + update_tube_info (self); +} + +static void +tube_closed_cb (SalutTubeIface *tube, + SalutMucChannel *self) +{ + SalutMucChannelPrivate *priv = self->priv; + guint64 id; + + g_object_get (tube, + "id", &id, + NULL); + + update_tube_info (self); + + if (priv->tubes != NULL) + g_hash_table_remove (priv->tubes, GUINT_TO_POINTER (id)); +} + +static guint +generate_tube_id (SalutMucChannel *self) +{ + SalutMucChannelPrivate *priv = self->priv; + guint out; + + /* probably totally overkill */ + do + { + out = g_random_int_range (1, G_MAXINT32); + } + while (g_hash_table_lookup (priv->tubes, + GUINT_TO_POINTER (out)) != NULL); + + return out; +} + +static SalutTubeIface * +create_new_tube (SalutMucChannel *self, + TpTubeType type, + TpHandle initiator, + const gchar *service, + GHashTable *parameters, + guint64 tube_id, + guint portnum, + WockyStanza *iq_req, + gboolean requested) +{ + SalutMucChannelPrivate *priv = self->priv; + TpBaseChannel *base = TP_BASE_CHANNEL (self); + TpBaseConnection *base_conn = tp_base_channel_get_connection (base); + SalutConnection *conn = SALUT_CONNECTION (base_conn); + TpHandle self_handle = TP_GROUP_MIXIN (self)->self_handle; + TpHandle handle = tp_base_channel_get_target_handle (base); + SalutTubeIface *tube; + + switch (type) + { + case TP_TUBE_TYPE_DBUS: + tube = SALUT_TUBE_IFACE (salut_tube_dbus_new (conn, + handle, TP_HANDLE_TYPE_ROOM, self_handle, priv->muc_connection, + initiator, service, parameters, tube_id, requested)); + break; + case TP_TUBE_TYPE_STREAM: + tube = SALUT_TUBE_IFACE (salut_tube_stream_new (conn, + handle, TP_HANDLE_TYPE_ROOM, + self_handle, initiator, FALSE, service, + parameters, tube_id, portnum, iq_req, requested)); + break; + default: + g_return_val_if_reached (NULL); + } + + tp_base_channel_register ((TpBaseChannel *) tube); + + DEBUG ("create tube %" G_GUINT64_FORMAT, tube_id); + g_hash_table_insert (priv->tubes, GUINT_TO_POINTER (tube_id), tube); + + g_signal_connect (tube, "tube-opened", G_CALLBACK (tube_opened_cb), self); + g_signal_connect (tube, "tube-offered", G_CALLBACK (tube_offered_cb), self); + g_signal_connect (tube, "closed", G_CALLBACK (tube_closed_cb), self); + + return tube; +} + +SalutTubeIface * +salut_muc_channel_tube_request (SalutMucChannel *self, + GHashTable *request_properties) +{ + SalutTubeIface *tube; + const gchar *channel_type; + const gchar *service; + GHashTable *parameters = NULL; + guint64 tube_id; + TpTubeType type; + + tube_id = generate_tube_id (self); + + channel_type = tp_asv_get_string (request_properties, + TP_PROP_CHANNEL_CHANNEL_TYPE); + + if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_STREAM_TUBE)) + { + type = TP_TUBE_TYPE_STREAM; + service = tp_asv_get_string (request_properties, + TP_PROP_CHANNEL_TYPE_STREAM_TUBE_SERVICE); + + } + else if (! tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_DBUS_TUBE)) + { + type = TP_TUBE_TYPE_DBUS; + service = tp_asv_get_string (request_properties, + TP_PROP_CHANNEL_TYPE_DBUS_TUBE_SERVICE_NAME); + } + else + /* This assertion is safe: this function's caller only calls it in one of + * the above cases. + * FIXME: but it would be better to pass an enum member or something maybe. + */ + g_assert_not_reached (); + + /* requested tubes have an empty parameters dict */ + parameters = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, + (GDestroyNotify) tp_g_value_slice_free); + + /* if the service property is missing, the requestotron rejects the request + */ + g_assert (service != NULL); + + DEBUG ("Request a tube channel with type='%s' and service='%s'", + channel_type, service); + + tube = create_new_tube (self, type, TP_GROUP_MIXIN (self)->self_handle, + service, parameters, tube_id, 0, NULL, TRUE); + g_hash_table_unref (parameters); + + return tube; +} + +void +salut_muc_channel_foreach (SalutMucChannel *self, + TpExportableChannelFunc func, + gpointer user_data) +{ + SalutMucChannelPrivate *priv = self->priv; + GHashTableIter iter; + gpointer value; + + g_hash_table_iter_init (&iter, priv->tubes); + while (g_hash_table_iter_next (&iter, NULL, &value)) + { + func (TP_EXPORTABLE_CHANNEL (value), user_data); + } +} + +void +salut_muc_channel_bytestream_offered (SalutMucChannel *self, + GibberBytestreamIface *bytestream, + WockyStanza *msg) +{ + SalutMucChannelPrivate *priv = self->priv; + WockyNode *node = wocky_stanza_get_top_node (msg); + const gchar *stream_id, *tmp; + WockyNode *si_node, *stream_node; + guint64 tube_id; + SalutTubeIface *tube; + WockyStanzaType type; + WockyStanzaSubType sub_type; + + /* Caller is expected to have checked that we have a stream or muc-stream + * node with a stream ID and the TUBES profile + */ + wocky_stanza_get_type_info (msg, &type, &sub_type); + g_return_if_fail (type == WOCKY_STANZA_TYPE_IQ); + g_return_if_fail (sub_type == WOCKY_STANZA_SUB_TYPE_SET); + + si_node = wocky_node_get_child_ns (node, "si", + WOCKY_XMPP_NS_SI); + g_return_if_fail (si_node != NULL); + + stream_node = wocky_node_get_child_ns (si_node, + "muc-stream", WOCKY_TELEPATHY_NS_TUBES); + g_return_if_fail (stream_node != NULL); + + stream_id = wocky_node_get_attribute (si_node, "id"); + g_return_if_fail (stream_id != NULL); + + tmp = wocky_node_get_attribute (stream_node, "tube"); + if (tmp == NULL) + { + GError e = { WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, + "<muc-stream> has no tube attribute" }; + + DEBUG ("%s", e.message); + gibber_bytestream_iface_close (bytestream, &e); + return; + } + tube_id = g_ascii_strtoull (tmp, NULL, 10); + if (tube_id == 0 || tube_id > G_MAXUINT32) + { + GError e = { WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, + "<muc-stream> tube attribute is non-numeric or out of range" }; + + DEBUG ("tube id is non-numeric or out of range: %s", tmp); + gibber_bytestream_iface_close (bytestream, &e); + return; + } + + tube = g_hash_table_lookup (priv->tubes, GUINT_TO_POINTER (tube_id)); + if (tube == NULL) + { + GError e = { WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, + "<muc-stream> tube attribute points to a nonexistent " + "tube" }; + + DEBUG ("tube %" G_GUINT64_FORMAT " doesn't exist", tube_id); + gibber_bytestream_iface_close (bytestream, &e); + return; + } + + DEBUG ("received new bytestream request for existing tube: %" G_GUINT64_FORMAT, + tube_id); + + salut_tube_iface_add_bytestream (tube, bytestream); +} + +gboolean +salut_muc_channel_is_ready (SalutMucChannel *self) +{ + return self->priv->connected; +} diff --git a/src/muc-channel.h b/src/muc-channel.h index 3bb01f04..868e7af4 100644 --- a/src/muc-channel.h +++ b/src/muc-channel.h @@ -30,6 +30,7 @@ #include <gibber/gibber-muc-connection.h> #include "connection.h" +#include "tube-iface.h" G_BEGIN_DECLS @@ -89,6 +90,25 @@ gboolean salut_muc_channel_publish_service (SalutMucChannel *self); gboolean salut_muc_channel_add_member (GObject *iface, TpHandle handle, const gchar *message, GError **error); +SalutTubeIface * salut_muc_channel_tube_request (SalutMucChannel *self, + GHashTable *request_properties); + +void salut_muc_channel_foreach (SalutMucChannel *self, + TpExportableChannelFunc func, gpointer user_data); + +void salut_muc_channel_bytestream_offered (SalutMucChannel *self, + GibberBytestreamIface *bytestream, + WockyStanza *msg); + +void salut_muc_channel_set_autoclose (SalutMucChannel *chan, + gboolean autoclose); + +gboolean salut_muc_channel_get_autoclose (SalutMucChannel *chan); + +gboolean salut_muc_channel_can_be_closed (SalutMucChannel *chan); + +gboolean salut_muc_channel_is_ready (SalutMucChannel *self); + G_END_DECLS #endif /* #ifndef __SALUT_MUC_CHANNEL_H__*/ diff --git a/src/muc-manager.c b/src/muc-manager.c index 5f3f24d4..7dabb17a 100644 --- a/src/muc-manager.c +++ b/src/muc-manager.c @@ -36,7 +36,6 @@ #include "muc-channel.h" #include "contact-manager.h" -#include "tubes-channel.h" #include "roomlist-channel.h" #include "roomlist-manager.h" #include "discovery-client.h" @@ -84,8 +83,15 @@ struct _SalutMucManagerPrivate /* GUINT_TO_POINTER (room_handle) => (SalutMucChannel *) */ GHashTable *text_channels; - /* GUINT_TO_POINTER(room_handle) => (SalutTubesChannel *) */ - GHashTable *tubes_channels; + + /* tube ID => owned SalutTubeIface */ + GHashTable *tubes; + + /* borrowed TpExportableChannel => owned GSList of gpointer */ + GHashTable *queued_requests; + + /* borrowed SalutMucChannel => owned GSList of borrowed SalutTubeIface */ + GHashTable *text_needed_for_tube; gboolean dispose_has_run; }; @@ -93,6 +99,9 @@ struct _SalutMucManagerPrivate #define SALUT_MUC_MANAGER_GET_PRIVATE(obj) \ ((SalutMucManagerPrivate *) ((SalutMucManager *) obj)->priv) +#define TUBE_TEXT_QUARK (g_quark_from_static_string (\ + "salut-muc-manager-tube-text-channel")) + static void salut_muc_manager_init (SalutMucManager *obj) { @@ -106,8 +115,11 @@ salut_muc_manager_init (SalutMucManager *obj) /* allocate any data required by the object here */ priv->text_channels = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref); - priv->tubes_channels = g_hash_table_new_full (g_direct_hash, g_direct_equal, - NULL, g_object_unref); + + priv->queued_requests = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, (GDestroyNotify) g_slist_free); + priv->text_needed_for_tube = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, (GDestroyNotify) g_slist_free); } static void @@ -151,6 +163,23 @@ salut_muc_manager_set_property (GObject *object, } static void +cancel_queued_requests (gpointer k, + gpointer v, + gpointer d) +{ + SalutMucManager *self = SALUT_MUC_MANAGER (d); + GSList *requests_satisfied = v; + GSList *iter; + + for (iter = requests_satisfied; iter != NULL; iter = iter->next) + { + tp_channel_manager_emit_request_failed (self, + iter->data, TP_ERROR, TP_ERROR_DISCONNECTED, + "Unable to complete this channel request, we're disconnecting!"); + } +} + +static void salut_muc_manager_close_all (SalutMucManager *self) { SalutMucManagerPrivate *priv = SALUT_MUC_MANAGER_GET_PRIVATE (self); @@ -163,19 +192,14 @@ salut_muc_manager_close_all (SalutMucManager *self) priv->status_changed_id = 0; } - if (priv->text_channels) - { - GHashTable *tmp = priv->text_channels; - priv->text_channels = NULL; - g_hash_table_unref (tmp); - } + if (priv->queued_requests != NULL) + g_hash_table_foreach (priv->queued_requests, + cancel_queued_requests, self); - if (priv->tubes_channels != NULL) - { - GHashTable *tmp = priv->tubes_channels; - priv->tubes_channels = NULL; - g_hash_table_unref (tmp); - } + tp_clear_pointer (&priv->queued_requests, g_hash_table_unref); + tp_clear_pointer (&priv->text_needed_for_tube, g_hash_table_unref); + + tp_clear_pointer (&priv->text_channels, g_hash_table_unref); } static void @@ -269,7 +293,8 @@ salut_muc_manager_dispose (GObject *object) salut_muc_manager_close_all (self); g_assert (priv->text_channels == NULL); - g_assert (priv->tubes_channels == NULL); + g_assert (priv->queued_requests == NULL); + g_assert (priv->text_needed_for_tube == NULL); /* release any references held by the object here */ @@ -279,23 +304,6 @@ salut_muc_manager_dispose (GObject *object) /* Channel Manager interface */ -struct _ForeachData -{ - TpExportableChannelFunc foreach; - gpointer user_data; -}; - -static void -_foreach_slave (gpointer key, - gpointer value, - gpointer user_data) -{ - struct _ForeachData *data = (struct _ForeachData *) user_data; - TpExportableChannel *channel = TP_EXPORTABLE_CHANNEL (value); - - data->foreach (channel, data->user_data); -} - static void salut_muc_manager_foreach_channel (TpChannelManager *iface, TpExportableChannelFunc foreach, @@ -303,27 +311,20 @@ salut_muc_manager_foreach_channel (TpChannelManager *iface, { SalutMucManager *fac = SALUT_MUC_MANAGER (iface); SalutMucManagerPrivate *priv = SALUT_MUC_MANAGER_GET_PRIVATE (fac); - struct _ForeachData data; GHashTableIter iter; gpointer value; - data.user_data = user_data; - data.foreach = foreach; - - g_hash_table_foreach (priv->text_channels, _foreach_slave, &data); - - g_hash_table_iter_init (&iter, priv->tubes_channels); + g_hash_table_iter_init (&iter, priv->text_channels); while (g_hash_table_iter_next (&iter, NULL, &value)) { TpExportableChannel *chan = TP_EXPORTABLE_CHANNEL (value); - /* Add channels of type Channel.Type.Tubes */ + /* do the text channel */ foreach (chan, user_data); - /* Add channels of type Channel.Type.{Stream|DBus}Tube which live in the - * SalutTubesChannel object */ - salut_tubes_channel_foreach (SALUT_TUBES_CHANNEL (chan), foreach, - user_data); + /* now its tube channels */ + salut_muc_channel_foreach (SALUT_MUC_CHANNEL (chan), + foreach, user_data); } } @@ -342,10 +343,6 @@ static const gchar * const muc_channel_allowed_properties[] = { NULL }; -static const gchar * const * muc_tubes_channel_allowed_properties = - muc_channel_allowed_properties; - - static void salut_muc_manager_type_foreach_channel_class (GType type, TpChannelManagerTypeChannelClassFunc func, @@ -370,11 +367,6 @@ salut_muc_manager_type_foreach_channel_class (GType type, func (type, table, muc_channel_allowed_properties, user_data); - /* org.freedesktop.Telepathy.Channel.Type.Tubes */ - g_value_set_static_string (channel_type_value, TP_IFACE_CHANNEL_TYPE_TUBES); - func (type, table, muc_tubes_channel_allowed_properties, - user_data); - /* org.freedesktop.Telepathy.Channel.Type.StreamTube */ g_value_set_static_string (channel_type_value, TP_IFACE_CHANNEL_TYPE_STREAM_TUBE); @@ -390,6 +382,32 @@ salut_muc_manager_type_foreach_channel_class (GType type, g_hash_table_unref (table); } +static void +associate_channel_to_data (GHashTable *table, + gpointer channel, + gpointer data) +{ + GSList *list; + + if (data == NULL) + return; + + /* yes it might be more 'efficient' to use prepend, then reverse the + * list before use but that's just annoying. I doubt there'll ever + * be more than one item in the list anyway. */ + + /* get the old list */ + list = g_hash_table_lookup (table, channel); + + /* add the data to it */ + list = g_slist_append (list, data); + + /* steal it so it doesn't get freed */ + g_hash_table_steal (table, channel); + + /* throw it back in */ + g_hash_table_insert (table, channel, list); +} static void muc_channel_closed_cb (SalutMucChannel *chan, @@ -397,59 +415,65 @@ muc_channel_closed_cb (SalutMucChannel *chan, { SalutMucManager *self = SALUT_MUC_MANAGER (user_data); SalutMucManagerPrivate *priv = SALUT_MUC_MANAGER_GET_PRIVATE (self); + TpBaseChannel *base = TP_BASE_CHANNEL (chan); TpHandle handle; - tp_channel_manager_emit_channel_closed_for_object (self, - TP_EXPORTABLE_CHANNEL (chan)); + /* channel is actually reappearing, announce it */ + if (tp_base_channel_is_respawning (base)) + { + tp_channel_manager_emit_new_channel (self, + TP_EXPORTABLE_CHANNEL (chan), NULL); + return; + } + + if (tp_base_channel_is_registered (base)) + { + tp_channel_manager_emit_channel_closed_for_object (self, + TP_EXPORTABLE_CHANNEL (chan)); + } - if (priv->text_channels) + if (tp_base_channel_is_destroyed (base) + && priv->text_channels) { g_object_get (chan, "handle", &handle, NULL); DEBUG ("Removing channel with handle %u", handle); - if (priv->tubes_channels != NULL) - { - SalutTubesChannel *tubes; - - tubes = g_hash_table_lookup (priv->tubes_channels, - GUINT_TO_POINTER (handle)); - if (tubes != NULL) - salut_tubes_channel_close (tubes); - } - g_hash_table_remove (priv->text_channels, GUINT_TO_POINTER (handle)); } } -/** - * tubes_channel_closed_cb: - * - * Signal callback for when a tubes channel is closed. Removes the references - * that MucManager holds to them. - */ static void -tubes_channel_closed_cb (SalutTubesChannel *chan, - gpointer user_data) +muc_channel_tube_closed_cb (SalutTubeIface *tube, + SalutMucManager *mgr) { - SalutMucManager *fac = SALUT_MUC_MANAGER (user_data); - SalutMucManagerPrivate *priv = SALUT_MUC_MANAGER_GET_PRIVATE (fac); - TpHandle room_handle; + SalutMucChannel *channel; + + tp_channel_manager_emit_channel_closed_for_object (mgr, + TP_EXPORTABLE_CHANNEL (tube)); - tp_channel_manager_emit_channel_closed_for_object (fac, - TP_EXPORTABLE_CHANNEL (chan)); + channel = g_object_get_qdata (G_OBJECT (tube), TUBE_TEXT_QUARK); + g_assert (channel != NULL); - if (priv->tubes_channels != NULL) + if (salut_muc_channel_can_be_closed (channel) + && salut_muc_channel_get_autoclose (channel)) { - g_object_get (chan, "handle", &room_handle, NULL); + tp_base_channel_close (TP_BASE_CHANNEL (channel)); + } +} - DEBUG ("removing MUC tubes channel with handle %u", room_handle); +static void +muc_channel_new_tube_cb (SalutMucChannel *channel, + SalutTubeIface *tube, + SalutMucManager *mgr) +{ + tp_channel_manager_emit_new_channel (mgr, + TP_EXPORTABLE_CHANNEL (tube), NULL); - g_hash_table_remove (priv->tubes_channels, - GUINT_TO_POINTER (room_handle)); + g_signal_connect (tube, "closed", + G_CALLBACK (muc_channel_tube_closed_cb), mgr); - /* The channel will probably reopen soon due to an incoming tube message, - * but closing the corresponding text channel would be too astonishing */ - } + g_object_set_qdata (G_OBJECT (tube), TUBE_TEXT_QUARK, + channel); } static GibberMucConnection * @@ -464,13 +488,91 @@ _get_connection (SalutMucManager *mgr, protocol, parameters, error); } +static void +muc_channel_ready_cb (SalutMucChannel *chan, + SalutMucManager *mgr) +{ + SalutMucManagerPrivate *priv = SALUT_MUC_MANAGER_GET_PRIVATE (mgr); + GSList *tube_channels; + GSList *l; + + /* announce the text channel finally, but only if it is on the bus */ + if (tp_base_channel_is_registered (TP_BASE_CHANNEL (chan))) + { + GSList *satisfied = g_hash_table_lookup (priv->queued_requests, chan); + + tp_channel_manager_emit_new_channel (mgr, + TP_EXPORTABLE_CHANNEL (chan), satisfied); + } + g_hash_table_remove (priv->queued_requests, chan); + + /* announce tube channels now */ + tube_channels = g_hash_table_lookup (priv->text_needed_for_tube, chan); + + for (l = tube_channels; l != NULL; l = l->next) + { + SalutTubeIface *tube = SALUT_TUBE_IFACE (l->data); + GSList *requests_satisfied; + + requests_satisfied = g_hash_table_lookup (priv->queued_requests, tube); + + tp_channel_manager_emit_new_channel (mgr, + TP_EXPORTABLE_CHANNEL (tube), requests_satisfied); + + g_hash_table_remove (priv->queued_requests, tube); + } + + g_hash_table_remove (priv->text_needed_for_tube, chan); +} + +static void +muc_channel_join_error_cb (SalutMucChannel *chan, + GError *error, + SalutMucManager *mgr) +{ + SalutMucManagerPrivate *priv = SALUT_MUC_MANAGER_GET_PRIVATE (mgr); + GSList *requests_satisfied; + GSList *tube_channels; + GSList *l; + +#define FAIL_REQUESTS(requests) \ + { \ + GSList *_l; \ + for (_l = requests; _l != NULL; _l = _l->next) \ + { \ + tp_channel_manager_emit_request_failed (mgr, _l->data, \ + error->domain, error->code, error->message); \ + } \ + } + + /* first fail the text channel itself */ + requests_satisfied = g_hash_table_lookup (priv->queued_requests, chan); + FAIL_REQUESTS(requests_satisfied); + g_hash_table_remove (priv->queued_requests, chan); + + /* now fail all tube channel requests */ + tube_channels = g_hash_table_lookup (priv->text_needed_for_tube, chan); + + for (l = tube_channels; l != NULL; l = l->next) + { + TpExportableChannel *tube = TP_EXPORTABLE_CHANNEL (l->data); + + requests_satisfied = g_hash_table_lookup (priv->queued_requests, tube); + FAIL_REQUESTS (requests_satisfied); + g_hash_table_remove (priv->queued_requests, tube); + } + + g_hash_table_remove (priv->text_needed_for_tube, chan); +} + static SalutMucChannel * salut_muc_manager_new_muc_channel (SalutMucManager *mgr, TpHandle handle, GibberMucConnection *connection, TpHandle initiator, gboolean new_connection, - gboolean requested) + gboolean requested, + gboolean initially_register) { SalutMucManagerPrivate *priv = SALUT_MUC_MANAGER_GET_PRIVATE(mgr); TpBaseConnection *base_connection = TP_BASE_CONNECTION(priv->connection); @@ -495,55 +597,20 @@ salut_muc_manager_new_muc_channel (SalutMucManager *mgr, new_connection, requested); g_free (path); - tp_base_channel_register ((TpBaseChannel *) chan); + if (initially_register) + tp_base_channel_register ((TpBaseChannel *) chan); g_signal_connect (chan, "closed", G_CALLBACK (muc_channel_closed_cb), mgr); + g_signal_connect (chan, "new-tube", G_CALLBACK (muc_channel_new_tube_cb), mgr); g_hash_table_insert (priv->text_channels, GUINT_TO_POINTER (handle), chan); - return chan; -} - -/** - * new_tubes_channel: - * - * Creates the SalutTubesChannel object with the given parameters. - */ -static SalutTubesChannel * -new_tubes_channel (SalutMucManager *self, - TpHandle room, - SalutMucChannel *muc, - TpHandle initiator, - gboolean requested) -{ - SalutMucManagerPrivate *priv = SALUT_MUC_MANAGER_GET_PRIVATE (self); - TpBaseConnection *conn = (TpBaseConnection *) priv->connection; - SalutTubesChannel *chan; - char *object_path; - - g_assert (g_hash_table_lookup (priv->tubes_channels, - GUINT_TO_POINTER (room)) == NULL); - - object_path = g_strdup_printf ("%s/MucTubesChannel%u", - conn->object_path, room); - - DEBUG ("creating new tubes chan, object path %s", object_path); - - chan = g_object_new (SALUT_TYPE_TUBES_CHANNEL, - "connection", priv->connection, - "object-path", object_path, - "handle", room, - "handle-type", TP_HANDLE_TYPE_ROOM, - "muc", muc, - "initiator-handle", initiator, - "requested", requested, - NULL); - - g_signal_connect (chan, "closed", (GCallback) tubes_channel_closed_cb, self); - - g_hash_table_insert (priv->tubes_channels, GUINT_TO_POINTER (room), chan); + if (salut_muc_channel_is_ready (chan)) + muc_channel_ready_cb (chan, mgr); + else + g_signal_connect (chan, "ready", G_CALLBACK (muc_channel_ready_cb), mgr); - g_free (object_path); + g_signal_connect (chan, "join-error", G_CALLBACK (muc_channel_join_error_cb), mgr); return chan; } @@ -627,89 +694,37 @@ salut_muc_manager_request_new_muc_channel (SalutMucManager *mgr, text_chan = salut_muc_manager_new_muc_channel (mgr, handle, connection, base_connection->self_handle, params == NULL, - requested); + requested, announce); r = salut_muc_channel_invited (text_chan, base_connection->self_handle, NULL, NULL); /* Inviting ourselves to a connected channel should always * succeed */ g_assert (r); - if (request_token != NULL) - tokens = g_slist_prepend (tokens, request_token); - - if (announce) - { - tp_channel_manager_emit_new_channel (mgr, - TP_EXPORTABLE_CHANNEL (text_chan), tokens); - } - - g_slist_free (tokens); - - return text_chan; -} - -static SalutTubesChannel * -create_tubes_channel (SalutMucManager *self, - TpHandle handle, - TpHandle initiator, - gpointer request_token, - gboolean announce, - gboolean *text_created_out, - gboolean requested, - GError **error) -{ - SalutMucManagerPrivate *priv = SALUT_MUC_MANAGER_GET_PRIVATE (self); - SalutMucChannel *text_chan; - SalutTubesChannel *tubes_chan; - gboolean text_created = FALSE; - - text_chan = g_hash_table_lookup (priv->text_channels, - GUINT_TO_POINTER (handle)); - - if (text_chan == NULL) - { - DEBUG ("have to create the text channel before the tubes one"); - text_chan = salut_muc_manager_request_new_muc_channel (self, - handle, NULL, FALSE, error); - - if (text_chan == NULL) - return NULL; - - text_created = TRUE; - } - - tubes_chan = new_tubes_channel (self, handle, text_chan, initiator, - requested); - g_assert (tubes_chan != NULL); - + /* only signal the creation of the text channel if we're asked for + * it to happen. note that in the case of announce=FALSE, + * muc_channel_ready_cb will still get fired, but because it isn't + * registered on the bus, it will not be signalled then either. */ if (announce) { - GHashTable *channels; - GSList *tokens = NULL; - - if (request_token != NULL) - tokens = g_slist_prepend (tokens, request_token); - - /* announce channels */ - channels = g_hash_table_new_full (g_direct_hash, g_direct_equal, - NULL, NULL); + if (salut_muc_channel_is_ready (text_chan)) + { + if (request_token != NULL) + tokens = g_slist_prepend (tokens, request_token); - if (text_created) + tp_channel_manager_emit_new_channel (mgr, + TP_EXPORTABLE_CHANNEL (text_chan), tokens); + } + else { - g_hash_table_insert (channels, text_chan, NULL); + associate_channel_to_data (priv->queued_requests, + text_chan, request_token); } - - g_hash_table_insert (channels, tubes_chan, tokens); - tp_channel_manager_emit_new_channels (self, channels); - - g_hash_table_unref (channels); - g_slist_free (tokens); } - if (text_created_out != NULL) - *text_created_out = text_created; + g_slist_free (tokens); - return tubes_chan; + return text_chan; } static gboolean @@ -721,54 +736,52 @@ handle_tube_channel_request (SalutMucManager *self, GError **error) { SalutMucManagerPrivate *priv = SALUT_MUC_MANAGER_GET_PRIVATE (self); - TpBaseConnection *base_conn = (TpBaseConnection *) priv->connection; SalutMucChannel *text_chan; - SalutTubesChannel *tubes_chan; SalutTubeIface *new_channel; - GHashTable *channels; - GSList *request_tokens; - gboolean announce_text = FALSE, announce_tubes = FALSE; - tubes_chan = g_hash_table_lookup (priv->tubes_channels, + text_chan = g_hash_table_lookup (priv->text_channels, GUINT_TO_POINTER (handle)); - if (tubes_chan == NULL) + + if (text_chan == NULL) { - tubes_chan = create_tubes_channel (self, handle, - base_conn->self_handle, NULL, FALSE, &announce_text, - FALSE, error); - if (tubes_chan == NULL) + DEBUG ("have to create the text channel before the tube one"); + text_chan = salut_muc_manager_request_new_muc_channel (self, + handle, NULL, FALSE, error); + + if (text_chan == NULL) return FALSE; - announce_tubes = TRUE; } - g_assert (tubes_chan != NULL); - new_channel = salut_tubes_channel_tube_request (tubes_chan, request_token, - request_properties, require_new); + new_channel = salut_muc_channel_tube_request (text_chan, + request_properties); g_assert (new_channel != NULL); - /* announce channels */ - channels = g_hash_table_new_full (g_direct_hash, g_direct_equal, - NULL, NULL); + g_signal_connect (new_channel, "closed", + G_CALLBACK (muc_channel_tube_closed_cb), self); - if (announce_text) - { - text_chan = g_hash_table_lookup (priv->text_channels, - GINT_TO_POINTER (handle)); - g_assert (text_chan != NULL); - g_hash_table_insert (channels, text_chan, NULL); - } + g_object_set_qdata (G_OBJECT (new_channel), TUBE_TEXT_QUARK, + text_chan); - if (announce_tubes) + if (salut_muc_channel_is_ready (text_chan)) { - g_hash_table_insert (channels, tubes_chan, NULL); + GSList *request_tokens = g_slist_append (NULL, request_token); + + tp_channel_manager_emit_new_channel (self, + TP_EXPORTABLE_CHANNEL (new_channel), request_tokens); + + g_slist_free (request_tokens); } + else + { + associate_channel_to_data (priv->text_needed_for_tube, + text_chan, new_channel); - request_tokens = g_slist_prepend (NULL, request_token); - g_hash_table_insert (channels, new_channel, request_tokens); - tp_channel_manager_emit_new_channels (self, channels); + /* we need to do this so when the muc channel is ready, the tube + * can be announced and satisfy this request */ + associate_channel_to_data (priv->queued_requests, + new_channel, request_token); + } - g_hash_table_unref (channels); - g_slist_free (request_tokens); return TRUE; } @@ -841,12 +854,10 @@ salut_muc_manager_request (SalutMucManager *self, gboolean require_new) { SalutMucManagerPrivate *priv = SALUT_MUC_MANAGER_GET_PRIVATE (self); - TpBaseConnection *base_conn = (TpBaseConnection *) priv->connection; GError *error = NULL; TpHandle handle; const gchar *channel_type; SalutMucChannel *text_chan; - SalutTubesChannel *tubes_chan; if (tp_asv_get_uint32 (request_properties, TP_IFACE_CHANNEL ".TargetHandleType", NULL) != TP_HANDLE_TYPE_ROOM) @@ -856,7 +867,6 @@ salut_muc_manager_request (SalutMucManager *self, TP_IFACE_CHANNEL ".ChannelType"); if (tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_TEXT) && - tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_TUBES) && tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_STREAM_TUBE) && tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_DBUS_TUBE)) return FALSE; @@ -878,7 +888,8 @@ salut_muc_manager_request (SalutMucManager *self, if (text_chan != NULL) { - if (require_new) + if (require_new + && tp_base_channel_is_registered (TP_BASE_CHANNEL (text_chan))) { g_set_error (&error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "That channel has already been created (or requested)"); @@ -886,8 +897,28 @@ salut_muc_manager_request (SalutMucManager *self, } else { - tp_channel_manager_emit_request_already_satisfied (self, - request_token, TP_EXPORTABLE_CHANNEL (text_chan)); + if (tp_base_channel_is_registered (TP_BASE_CHANNEL (text_chan))) + { + tp_channel_manager_emit_request_already_satisfied (self, + request_token, TP_EXPORTABLE_CHANNEL (text_chan)); + } + else + { + tp_base_channel_register (TP_BASE_CHANNEL (text_chan)); + + if (salut_muc_channel_is_ready (text_chan)) + { + GSList *tokens = g_slist_append (NULL, request_token); + tp_channel_manager_emit_new_channel (self, + TP_EXPORTABLE_CHANNEL (text_chan), tokens); + g_slist_free (tokens); + } + else + { + associate_channel_to_data (priv->queued_requests, + text_chan, request_token); + } + } } } else @@ -898,41 +929,6 @@ salut_muc_manager_request (SalutMucManager *self, return TRUE; } - else if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_TUBES)) - { - if (tp_channel_manager_asv_has_unknown_properties (request_properties, - muc_tubes_channel_fixed_properties, - muc_tubes_channel_allowed_properties, - &error)) - goto error; - - tubes_chan = g_hash_table_lookup (priv->tubes_channels, - GUINT_TO_POINTER (handle)); - - if (tubes_chan != NULL) - { - if (require_new) - { - g_set_error (&error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, - "That channel has already been created (or requested)"); - goto error; - } - else - { - tp_channel_manager_emit_request_already_satisfied (self, - request_token, TP_EXPORTABLE_CHANNEL (tubes_chan)); - } - } - else - { - tubes_chan = create_tubes_channel (self, handle, - base_conn->self_handle, request_token, TRUE, NULL, TRUE, &error); - if (tubes_chan == NULL) - goto error; - } - - return TRUE; - } else if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_STREAM_TUBE)) { if (handle_stream_tube_channel_request (self, request_token, @@ -1104,7 +1100,7 @@ invite_stanza_callback (WockyPorter *porter, } /* Need to create a new one */ chan = salut_muc_manager_new_muc_channel (self, room_handle, - connection, inviter_handle, FALSE, FALSE); + connection, inviter_handle, FALSE, FALSE, TRUE); tp_channel_manager_emit_new_channel (self, TP_EXPORTABLE_CHANNEL (chan), NULL); @@ -1158,50 +1154,21 @@ salut_muc_manager_handle_si_stream_request (SalutMucManager *self, SalutMucManagerPrivate *priv = SALUT_MUC_MANAGER_GET_PRIVATE (self); TpHandleRepoIface *room_repo = tp_base_connection_get_handles ( (TpBaseConnection *) priv->connection, TP_HANDLE_TYPE_ROOM); - SalutTubesChannel *chan = NULL; + SalutMucChannel *chan = NULL; g_return_if_fail (tp_handle_is_valid (room_repo, room_handle, NULL)); - chan = g_hash_table_lookup (priv->tubes_channels, + chan = g_hash_table_lookup (priv->text_channels, GUINT_TO_POINTER (room_handle)); if (chan == NULL) { GError e = { WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "No tubes channel available for this MUC" }; + "No channel available for this MUC" }; - DEBUG ("tubes channel doesn't exist for muc %d", room_handle); + DEBUG ("MUC channel doesn't exist for muc %d", room_handle); gibber_bytestream_iface_close (bytestream, &e); return; } - salut_tubes_channel_bytestream_offered (chan, bytestream, msg); -} - -/* Caller is reponsible of announcing the channel if created */ -SalutTubesChannel * -salut_muc_manager_ensure_tubes_channel (SalutMucManager *self, - TpHandle handle, - TpHandle actor, - gboolean *created) -{ - SalutMucManagerPrivate *priv = SALUT_MUC_MANAGER_GET_PRIVATE (self); - SalutTubesChannel *tubes_chan; - - tubes_chan = g_hash_table_lookup (priv->tubes_channels, - GUINT_TO_POINTER (handle)); - if (tubes_chan != NULL) - { - g_object_ref (tubes_chan); - *created = FALSE; - return tubes_chan; - } - - - tubes_chan = create_tubes_channel (self, handle, actor, NULL, FALSE, NULL, - FALSE, NULL); - g_assert (tubes_chan != NULL); - g_object_ref (tubes_chan); - - *created = TRUE; - return tubes_chan; + salut_muc_channel_bytestream_offered (chan, bytestream, msg); } diff --git a/src/muc-manager.h b/src/muc-manager.h index 2e761a8d..a2cdd16f 100644 --- a/src/muc-manager.h +++ b/src/muc-manager.h @@ -26,7 +26,6 @@ #include <connection.h> #include "muc-channel.h" -#include "tubes-channel.h" #include "muc-channel.h" G_BEGIN_DECLS @@ -74,11 +73,6 @@ void salut_muc_manager_handle_si_stream_request (SalutMucManager *muc_manager, GibberBytestreamIface *bytestream, TpHandle room_handle, const gchar *stream_id, WockyStanza *msg); -SalutTubesChannel * salut_muc_manager_ensure_tubes_channel ( - SalutMucManager *muc_manager, TpHandle handle, TpHandle actor, - gboolean *created); - - G_END_DECLS #endif /* #ifndef __SALUT_MUC_MANAGER_H__*/ diff --git a/src/muc-tube-dbus.c b/src/muc-tube-dbus.c new file mode 100644 index 00000000..0fedeaf4 --- /dev/null +++ b/src/muc-tube-dbus.c @@ -0,0 +1,47 @@ +/* + * muc-tube-dbus.c - Source for SalutMucTubeDBus + * Copyright (C) 2012 Collabora Ltd. + * + * 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 "config.h" + +#include "muc-tube-dbus.h" + +G_DEFINE_TYPE (SalutMucTubeDBus, salut_muc_tube_dbus, + SALUT_TYPE_TUBE_DBUS) + +static const gchar *salut_muc_tube_dbus_interfaces[] = { + TP_IFACE_CHANNEL_INTERFACE_GROUP, + TP_IFACE_CHANNEL_INTERFACE_TUBE, + NULL +}; + +static void +salut_muc_tube_dbus_init (SalutMucTubeDBus *self) +{ +} + +static void +salut_muc_tube_dbus_class_init ( + SalutMucTubeDBusClass *salut_muc_tube_dbus_class) +{ + TpBaseChannelClass *base_class = TP_BASE_CHANNEL_CLASS ( + salut_muc_tube_dbus_class); + + base_class->interfaces = salut_muc_tube_dbus_interfaces; + base_class->target_handle_type = TP_HANDLE_TYPE_ROOM; +} diff --git a/src/muc-tube-dbus.h b/src/muc-tube-dbus.h new file mode 100644 index 00000000..cdaafab1 --- /dev/null +++ b/src/muc-tube-dbus.h @@ -0,0 +1,60 @@ +/* + * muc-tube-dbus.h - Header for SalutMucTubeDBus + * Copyright (C) 2012 Collabora Ltd. + * + * 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 + */ + +#ifndef __SALUT_MUC_TUBE_DBUS_H__ +#define __SALUT_MUC_TUBE_DBUS_H__ + +#include <glib-object.h> + +#include "tube-dbus.h" + +G_BEGIN_DECLS + +typedef struct _SalutMucTubeDBus SalutMucTubeDBus; +typedef struct _SalutMucTubeDBusClass SalutMucTubeDBusClass; + +struct _SalutMucTubeDBusClass { + SalutTubeDBusClass parent_class; +}; + +struct _SalutMucTubeDBus { + SalutTubeDBus parent; +}; + +GType salut_muc_tube_dbus_get_type (void); + +/* TYPE MACROS */ +#define SALUT_TYPE_MUC_TUBE_DBUS \ + (salut_muc_tube_dbus_get_type ()) +#define SALUT_MUC_TUBE_DBUS(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), SALUT_TYPE_MUC_TUBE_DBUS, SalutMucTubeDBus)) +#define SALUT_MUC_TUBE_DBUS_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), SALUT_TYPE_MUC_TUBE_DBUS,\ + SalutMucTubeDBusClass)) +#define SALUT_IS_MUC_TUBE_DBUS(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), SALUT_TYPE_MUC_TUBE_DBUS)) +#define SALUT_IS_MUC_TUBE_DBUS_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), SALUT_TYPE_MUC_TUBE_DBUS)) +#define SALUT_MUC_TUBE_DBUS_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), SALUT_TYPE_MUC_TUBE_DBUS,\ + SalutMucTubeDBusClass)) + +G_END_DECLS + +#endif /* #ifndef __SALUT_MUC_TUBE_DBUS_H__ */ diff --git a/src/muc-tube-stream.c b/src/muc-tube-stream.c new file mode 100644 index 00000000..0833d4df --- /dev/null +++ b/src/muc-tube-stream.c @@ -0,0 +1,47 @@ +/* + * muc-tube-stream.c - Source for SalutMucTubeStream + * Copyright (C) 2012 Collabora Ltd. + * + * 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 "config.h" + +#include "muc-tube-stream.h" + +G_DEFINE_TYPE (SalutMucTubeStream, salut_muc_tube_stream, + SALUT_TYPE_TUBE_STREAM) + +static const gchar *salut_muc_tube_stream_interfaces[] = { + TP_IFACE_CHANNEL_INTERFACE_GROUP, + TP_IFACE_CHANNEL_INTERFACE_TUBE, + NULL +}; + +static void +salut_muc_tube_stream_init (SalutMucTubeStream *self) +{ +} + +static void +salut_muc_tube_stream_class_init ( + SalutMucTubeStreamClass *salut_muc_tube_stream_class) +{ + TpBaseChannelClass *base_class = TP_BASE_CHANNEL_CLASS ( + salut_muc_tube_stream_class); + + base_class->interfaces = salut_muc_tube_stream_interfaces; + base_class->target_handle_type = TP_HANDLE_TYPE_ROOM; +} diff --git a/src/muc-tube-stream.h b/src/muc-tube-stream.h new file mode 100644 index 00000000..d673a108 --- /dev/null +++ b/src/muc-tube-stream.h @@ -0,0 +1,60 @@ +/* + * muc-tube-stream.h - Header for SalutMucTubeStream + * Copyright (C) 2012 Collabora Ltd. + * + * 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 + */ + +#ifndef __SALUT_MUC_TUBE_STREAM_H__ +#define __SALUT_MUC_TUBE_STREAM_H__ + +#include <glib-object.h> + +#include "tube-stream.h" + +G_BEGIN_DECLS + +typedef struct _SalutMucTubeStream SalutMucTubeStream; +typedef struct _SalutMucTubeStreamClass SalutMucTubeStreamClass; + +struct _SalutMucTubeStreamClass { + SalutTubeStreamClass parent_class; +}; + +struct _SalutMucTubeStream { + SalutTubeStream parent; +}; + +GType salut_muc_tube_stream_get_type (void); + +/* TYPE MACROS */ +#define SALUT_TYPE_MUC_TUBE_STREAM \ + (salut_muc_tube_stream_get_type ()) +#define SALUT_MUC_TUBE_STREAM(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), SALUT_TYPE_MUC_TUBE_STREAM, SalutMucTubeStream)) +#define SALUT_MUC_TUBE_STREAM_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), SALUT_TYPE_MUC_TUBE_STREAM,\ + SalutMucTubeStreamClass)) +#define SALUT_IS_MUC_TUBE_STREAM(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), SALUT_TYPE_MUC_TUBE_STREAM)) +#define SALUT_IS_MUC_TUBE_STREAM_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), SALUT_TYPE_MUC_TUBE_STREAM)) +#define SALUT_MUC_TUBE_STREAM_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), SALUT_TYPE_MUC_TUBE_STREAM,\ + SalutMucTubeStreamClass)) + +G_END_DECLS + +#endif /* #ifndef __SALUT_MUC_TUBE_STREAM_H__ */ diff --git a/src/roomlist-manager.c b/src/roomlist-manager.c index b121917e..dbde4310 100644 --- a/src/roomlist-manager.c +++ b/src/roomlist-manager.c @@ -36,7 +36,6 @@ #include "roomlist-channel.h" #include "contact-manager.h" #include "muc-manager.h" -#include "tubes-channel.h" #include "roomlist-channel.h" #include "discovery-client.h" diff --git a/src/roomlist-manager.h b/src/roomlist-manager.h index eb087439..162b48a6 100644 --- a/src/roomlist-manager.h +++ b/src/roomlist-manager.h @@ -25,7 +25,6 @@ #include <gibber/gibber-bytestream-iface.h> #include <connection.h> -#include "tubes-channel.h" #include "roomlist-channel.h" G_BEGIN_DECLS diff --git a/src/tube-dbus.c b/src/tube-dbus.c index cfa504bf..39686d2f 100644 --- a/src/tube-dbus.c +++ b/src/tube-dbus.c @@ -44,6 +44,7 @@ #define DEBUG_FLAG DEBUG_TUBES #include "debug.h" #include "connection.h" +#include "muc-tube-dbus.h" #include "tube-iface.h" #include "sha1/sha1-util.h" @@ -56,27 +57,17 @@ * arbitrary limit on the queue size set to 4MB. */ #define MAX_QUEUE_SIZE (4096*1024) -static void channel_iface_init (gpointer, gpointer); static void tube_iface_init (gpointer g_iface, gpointer iface_data); static void dbustube_iface_init (gpointer g_iface, gpointer iface_data); -G_DEFINE_TYPE_WITH_CODE (SalutTubeDBus, salut_tube_dbus, 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_DEFINE_TYPE_WITH_CODE (SalutTubeDBus, salut_tube_dbus, TP_TYPE_BASE_CHANNEL, G_IMPLEMENT_INTERFACE (SALUT_TYPE_TUBE_IFACE, tube_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_TYPE_DBUS_TUBE, dbustube_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_TUBE, - NULL); - G_IMPLEMENT_INTERFACE (TP_TYPE_EXPORTABLE_CHANNEL, NULL); - G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_IFACE, NULL)); + NULL)) static const gchar *salut_tube_dbus_interfaces[] = { - TP_IFACE_CHANNEL_INTERFACE_GROUP, - /* If more interfaces are added, either keep Group as the first, or change - * the implementations of salut_tube_dbus_get_interfaces () and - * salut_tube_dbus_get_property () too */ TP_IFACE_CHANNEL_INTERFACE_TUBE, NULL }; @@ -102,31 +93,18 @@ static guint signals[LAST_SIGNAL] = {0}; /* properties */ enum { - PROP_OBJECT_PATH = 1, - PROP_CHANNEL_TYPE, - PROP_CONNECTION, - PROP_INTERFACES, - PROP_TUBES_CHANNEL, - PROP_HANDLE, - PROP_HANDLE_TYPE, - PROP_SELF_HANDLE, + PROP_SELF_HANDLE = 1, PROP_MUC_CONNECTION, PROP_ID, PROP_BYTESTREAM, PROP_STREAM_ID, PROP_TYPE, - PROP_INITIATOR_HANDLE, PROP_SERVICE, PROP_PARAMETERS, PROP_STATE, PROP_DBUS_ADDRESS, PROP_DBUS_NAME, PROP_DBUS_NAMES, - PROP_CHANNEL_DESTROYED, - PROP_CHANNEL_PROPERTIES, - PROP_REQUESTED, - PROP_TARGET_ID, - PROP_INITIATOR_ID, PROP_SUPPORTED_ACCESS_CONTROLS, LAST_PROPERTY }; @@ -134,14 +112,9 @@ enum typedef struct _SalutTubeDBusPrivate SalutTubeDBusPrivate; struct _SalutTubeDBusPrivate { - SalutConnection *conn; - gchar *object_path; - SalutTubesChannel *tubes_channel; - TpHandle handle; - TpHandleType handle_type; TpHandle self_handle; GibberMucConnection *muc_connection; - guint id; + guint64 id; GibberBytestreamIface *bytestream; gchar *stream_id; TpHandle initiator; @@ -395,6 +368,7 @@ do_close (SalutTubeDBus *self) else { g_signal_emit (G_OBJECT (self), signals[CLOSED], 0); + tp_base_channel_destroyed (TP_BASE_CHANNEL (self)); } } @@ -546,6 +520,7 @@ bytestream_state_changed_cb (GibberBytestreamIface *bytestream, priv->closed = TRUE; g_signal_emit (G_OBJECT (self), signals[CLOSED], 0); + tp_base_channel_destroyed (TP_BASE_CHANNEL (self)); } else if (state == GIBBER_BYTESTREAM_STATE_OPEN) { @@ -635,7 +610,6 @@ salut_tube_dbus_finalize (GObject *object) SalutTubeDBus *self = SALUT_TUBE_DBUS (object); SalutTubeDBusPrivate *priv = SALUT_TUBE_DBUS_GET_PRIVATE (self); - g_free (priv->object_path); g_free (priv->stream_id); g_free (priv->service); g_hash_table_unref (priv->parameters); @@ -652,41 +626,9 @@ salut_tube_dbus_get_property (GObject *object, { SalutTubeDBus *self = SALUT_TUBE_DBUS (object); SalutTubeDBusPrivate *priv = SALUT_TUBE_DBUS_GET_PRIVATE (self); - TpBaseConnection *base_conn = (TpBaseConnection *) priv->conn; switch (property_id) { - case PROP_OBJECT_PATH: - g_value_set_string (value, priv->object_path); - break; - case PROP_CHANNEL_TYPE: - g_value_set_static_string (value, - TP_IFACE_CHANNEL_TYPE_DBUS_TUBE); - break; - case PROP_CONNECTION: - g_value_set_object (value, priv->conn); - break; - case PROP_INTERFACES: - if (priv->handle_type == TP_HANDLE_TYPE_CONTACT) - { - /* 1-1 tubes - omit the Group interface */ - g_value_set_boxed (value, salut_tube_dbus_interfaces + 1); - } - else - { - /* MUC tubes */ - g_value_set_boxed (value, salut_tube_dbus_interfaces); - } - break; - case PROP_TUBES_CHANNEL: - g_value_set_object (value, priv->tubes_channel); - break; - case PROP_HANDLE: - g_value_set_uint (value, priv->handle); - break; - case PROP_HANDLE_TYPE: - g_value_set_uint (value, priv->handle_type); - break; case PROP_SELF_HANDLE: g_value_set_uint (value, priv->self_handle); break; @@ -694,7 +636,7 @@ salut_tube_dbus_get_property (GObject *object, g_value_set_object (value, priv->muc_connection); break; case PROP_ID: - g_value_set_uint (value, priv->id); + g_value_set_uint64 (value, priv->id); break; case PROP_BYTESTREAM: g_value_set_object (value, priv->bytestream); @@ -705,9 +647,6 @@ salut_tube_dbus_get_property (GObject *object, case PROP_TYPE: g_value_set_uint (value, TP_TUBE_TYPE_DBUS); break; - case PROP_INITIATOR_HANDLE: - g_value_set_uint (value, priv->initiator); - break; case PROP_SERVICE: g_value_set_string (value, priv->service); break; @@ -726,72 +665,6 @@ salut_tube_dbus_get_property (GObject *object, case PROP_DBUS_NAMES: g_value_set_boxed (value, priv->dbus_names); break; - case PROP_CHANNEL_DESTROYED: - g_value_set_boolean (value, priv->closed); - break; - case PROP_CHANNEL_PROPERTIES: - { - GHashTable *properties; - - properties = tp_dbus_properties_mixin_make_properties_hash (object, - TP_IFACE_CHANNEL, "TargetHandle", - TP_IFACE_CHANNEL, "TargetHandleType", - TP_IFACE_CHANNEL, "ChannelType", - TP_IFACE_CHANNEL, "TargetID", - TP_IFACE_CHANNEL, "InitiatorHandle", - TP_IFACE_CHANNEL, "InitiatorID", - TP_IFACE_CHANNEL, "Requested", - TP_IFACE_CHANNEL, "Interfaces", - TP_IFACE_CHANNEL_TYPE_DBUS_TUBE, "ServiceName", - TP_IFACE_CHANNEL_TYPE_DBUS_TUBE, "SupportedAccessControls", - NULL); - - if (priv->initiator != priv->self_handle) - { - /* channel has not been requested so Parameters is immutable */ - GValue *prop_value = g_slice_new0 (GValue); - - /* FIXME: use tp_dbus_properties_mixin_add_properties once it's - * added in tp-glib */ - tp_dbus_properties_mixin_get (object, - TP_IFACE_CHANNEL_INTERFACE_TUBE, "Parameters", - prop_value, NULL); - g_assert (G_IS_VALUE (prop_value)); - - g_hash_table_insert (properties, - g_strdup_printf ("%s.%s", TP_IFACE_CHANNEL_INTERFACE_TUBE, - "Parameters"), prop_value); - } - - g_value_take_boxed (value, properties); - } - break; - case PROP_REQUESTED: - g_value_set_boolean (value, - (priv->initiator == priv->self_handle)); - break; - case PROP_INITIATOR_ID: - { - TpHandleRepoIface *repo = tp_base_connection_get_handles ( - base_conn, TP_HANDLE_TYPE_CONTACT); - - /* some channel can have o.f.T.Channel.InitiatorHandle == 0 but - * tubes always have an initiator */ - g_assert (priv->initiator != 0); - - g_value_set_string (value, - tp_handle_inspect (repo, priv->initiator)); - } - break; - case PROP_TARGET_ID: - { - TpHandleRepoIface *repo = tp_base_connection_get_handles ( - base_conn, priv->handle_type); - - g_value_set_string (value, - tp_handle_inspect (repo, priv->handle)); - } - break; case PROP_SUPPORTED_ACCESS_CONTROLS: g_value_set_boxed (value, priv->supported_access_controls); break; @@ -812,26 +685,6 @@ salut_tube_dbus_set_property (GObject *object, switch (property_id) { - case PROP_OBJECT_PATH: - g_free (priv->object_path); - priv->object_path = g_value_dup_string (value); - break; - case PROP_CHANNEL_TYPE: - /* this property is writable in the interface, but not actually - * meaningfully changeable on this channel, so we do nothing */ - break; - case PROP_CONNECTION: - priv->conn = g_value_get_object (value); - break; - case PROP_TUBES_CHANNEL: - priv->tubes_channel = g_value_get_object (value); - break; - case PROP_HANDLE: - priv->handle = g_value_get_uint (value); - break; - case PROP_HANDLE_TYPE: - priv->handle_type = g_value_get_uint (value); - break; case PROP_SELF_HANDLE: priv->self_handle = g_value_get_uint (value); break; @@ -840,7 +693,7 @@ salut_tube_dbus_set_property (GObject *object, g_object_ref (priv->muc_connection); break; case PROP_ID: - priv->id = g_value_get_uint (value); + priv->id = g_value_get_uint64 (value); break; case PROP_BYTESTREAM: if (priv->bytestream == NULL) @@ -860,9 +713,6 @@ salut_tube_dbus_set_property (GObject *object, G_CALLBACK (bytestream_state_changed_cb), self); } break; - case PROP_INITIATOR_HANDLE: - priv->initiator = g_value_get_uint (value); - break; case PROP_SERVICE: g_free (priv->service); priv->service = g_value_dup_string (value); @@ -886,7 +736,9 @@ salut_tube_dbus_constructor (GType type, GObject *obj; SalutTubeDBus *self; SalutTubeDBusPrivate *priv; - TpDBusDaemon *bus; + TpBaseChannel *base; + TpBaseChannelClass *cls; + SalutConnection *conn; TpBaseConnection *base_conn; TpHandleRepoIface *handles_repo; TpSocketAccessControl access_control; @@ -895,22 +747,18 @@ salut_tube_dbus_constructor (GType type, constructor (type, n_props, props); self = SALUT_TUBE_DBUS (obj); - priv = SALUT_TUBE_DBUS_GET_PRIVATE (self); - - base_conn = TP_BASE_CONNECTION (priv->conn); - handles_repo = tp_base_connection_get_handles (base_conn, priv->handle_type); + base = TP_BASE_CHANNEL (self); + cls = TP_BASE_CHANNEL_GET_CLASS (base); - /* Ref the initiator handle */ - g_assert (priv->conn != NULL); - g_assert (priv->initiator != 0); - - bus = tp_base_connection_get_dbus_daemon (base_conn); - tp_dbus_daemon_register_object (bus, priv->object_path, obj); + priv = SALUT_TUBE_DBUS_GET_PRIVATE (self); - DEBUG ("Registering at '%s'", priv->object_path); + conn = SALUT_CONNECTION (tp_base_channel_get_connection (base)); + base_conn = TP_BASE_CONNECTION (conn); + handles_repo = tp_base_connection_get_handles (base_conn, + cls->target_handle_type); g_assert (priv->self_handle != 0); - if (priv->handle_type == TP_HANDLE_TYPE_ROOM) + if (cls->target_handle_type == TP_HANDLE_TYPE_ROOM) { /* * We have to create an MUC bytestream that will be @@ -927,15 +775,16 @@ salut_tube_dbus_constructor (GType type, priv->dbus_names = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free); - priv->dbus_local_name = generate_dbus_unique_name (priv->conn->name); + priv->dbus_local_name = generate_dbus_unique_name (conn->name); DEBUG ("local name: %s", priv->dbus_local_name); - peer_id = tp_handle_inspect (handles_repo, priv->handle); + peer_id = tp_handle_inspect (handles_repo, + tp_base_channel_get_target_handle (base)); bytestream = g_object_new (GIBBER_TYPE_BYTESTREAM_MUC, "muc-connection", priv->muc_connection, "state", GIBBER_BYTESTREAM_STATE_LOCAL_PENDING, - "self-id", priv->conn->name, + "self-id", conn->name, "peer-id", peer_id, NULL); @@ -958,7 +807,13 @@ salut_tube_dbus_constructor (GType type, priv->reassembly_bytes_needed = 0; } - if (priv->initiator == priv->self_handle) + /* Tube needs to be offered if we initiated and requested it. Being + * the initiator is not enough as we could re-join a MUC containing + * an old tube we created when we were in this room some time + * ago. In that case, we have to accept it if we want to re-join the + * tube. */ + if (tp_base_channel_get_initiator (base) == priv->self_handle + && tp_base_channel_is_requested (base)) { priv->offered = FALSE; } @@ -984,19 +839,49 @@ salut_tube_dbus_constructor (GType type, } static void +salut_tube_dbus_fill_immutable_properties (TpBaseChannel *chan, + GHashTable *properties) +{ + TpBaseChannelClass *cls = TP_BASE_CHANNEL_CLASS ( + salut_tube_dbus_parent_class); + + cls->fill_immutable_properties (chan, properties); + + tp_dbus_properties_mixin_fill_properties_hash ( + G_OBJECT (chan), properties, + TP_IFACE_CHANNEL_TYPE_DBUS_TUBE, "ServiceName", + TP_IFACE_CHANNEL_TYPE_DBUS_TUBE, "SupportedAccessControls", + NULL); + + if (!tp_base_channel_is_requested (chan)) + { + tp_dbus_properties_mixin_fill_properties_hash ( + G_OBJECT (chan), properties, + TP_IFACE_CHANNEL_INTERFACE_TUBE, "Parameters", + NULL); + } +} + +static gchar * +salut_tube_dbus_get_object_path_suffix (TpBaseChannel *base) +{ + SalutTubeDBus *self = SALUT_TUBE_DBUS (base); + SalutTubeDBusPrivate *priv = SALUT_TUBE_DBUS_GET_PRIVATE (self); + + return g_strdup_printf ("DBusTubeChannel/%u/%" G_GUINT64_FORMAT, + tp_base_channel_get_target_handle (base), + priv->id); +} + +static void +salut_tube_dbus_close_dbus (TpBaseChannel *base) +{ + do_close ((SalutTubeDBus *) base); +} + +static void salut_tube_dbus_class_init (SalutTubeDBusClass *salut_tube_dbus_class) { - static TpDBusPropertiesMixinPropImpl channel_props[] = { - { "TargetHandleType", "handle-type", NULL }, - { "TargetHandle", "handle", NULL }, - { "ChannelType", "channel-type", NULL }, - { "TargetID", "target-id", NULL }, - { "Interfaces", "interfaces", NULL }, - { "Requested", "requested", NULL }, - { "InitiatorHandle", "initiator-handle", NULL }, - { "InitiatorID", "initiator-id", NULL }, - { NULL } - }; static TpDBusPropertiesMixinPropImpl dbus_tube_props[] = { { "ServiceName", "service", NULL }, { "DBusNames", "dbus-names", NULL }, @@ -1009,11 +894,6 @@ salut_tube_dbus_class_init (SalutTubeDBusClass *salut_tube_dbus_class) { NULL } }; static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = { - { TP_IFACE_CHANNEL, - tp_dbus_properties_mixin_getter_gobject_properties, - NULL, - channel_props, - }, { TP_IFACE_CHANNEL_TYPE_DBUS_TUBE, tp_dbus_properties_mixin_getter_gobject_properties, NULL, @@ -1027,38 +907,34 @@ salut_tube_dbus_class_init (SalutTubeDBusClass *salut_tube_dbus_class) { NULL } }; GObjectClass *object_class = G_OBJECT_CLASS (salut_tube_dbus_class); + TpBaseChannelClass *base_class = TP_BASE_CHANNEL_CLASS (salut_tube_dbus_class); GParamSpec *param_spec; object_class->get_property = salut_tube_dbus_get_property; object_class->set_property = salut_tube_dbus_set_property; object_class->constructor = salut_tube_dbus_constructor; + base_class->channel_type = TP_IFACE_CHANNEL_TYPE_DBUS_TUBE; + base_class->interfaces = salut_tube_dbus_interfaces; + base_class->target_handle_type = TP_HANDLE_TYPE_CONTACT; + base_class->close = salut_tube_dbus_close_dbus; + base_class->fill_immutable_properties = + salut_tube_dbus_fill_immutable_properties; + base_class->get_object_path_suffix = + salut_tube_dbus_get_object_path_suffix; + g_type_class_add_private (salut_tube_dbus_class, sizeof (SalutTubeDBusPrivate)); object_class->dispose = salut_tube_dbus_dispose; object_class->finalize = salut_tube_dbus_finalize; - g_object_class_override_property (object_class, PROP_OBJECT_PATH, - "object-path"); - g_object_class_override_property (object_class, PROP_CHANNEL_TYPE, - "channel-type"); - g_object_class_override_property (object_class, PROP_CONNECTION, - "connection"); - g_object_class_override_property (object_class, PROP_TUBES_CHANNEL, - "tubes-channel"); - g_object_class_override_property (object_class, PROP_HANDLE, - "handle"); - g_object_class_override_property (object_class, PROP_HANDLE_TYPE, - "handle-type"); g_object_class_override_property (object_class, PROP_SELF_HANDLE, "self-handle"); g_object_class_override_property (object_class, PROP_ID, "id"); g_object_class_override_property (object_class, PROP_TYPE, "type"); - g_object_class_override_property (object_class, PROP_INITIATOR_HANDLE, - "initiator-handle"); g_object_class_override_property (object_class, PROP_SERVICE, "service"); g_object_class_override_property (object_class, PROP_PARAMETERS, @@ -1066,11 +942,6 @@ salut_tube_dbus_class_init (SalutTubeDBusClass *salut_tube_dbus_class) g_object_class_override_property (object_class, PROP_STATE, "state"); - g_object_class_override_property (object_class, PROP_CHANNEL_DESTROYED, - "channel-destroyed"); - g_object_class_override_property (object_class, PROP_CHANNEL_PROPERTIES, - "channel-properties"); - param_spec = g_param_spec_object ( "muc-connection", "GibberMucConnection object", @@ -1123,31 +994,6 @@ salut_tube_dbus_class_init (SalutTubeDBusClass *salut_tube_dbus_class) G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_DBUS_NAMES, param_spec); - param_spec = g_param_spec_boxed ("interfaces", "Extra D-Bus interfaces", - "Additional Channel.Interface.* interfaces", - G_TYPE_STRV, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_INTERFACES, param_spec); - - param_spec = g_param_spec_string ("target-id", "Target JID", - "The string obtained by inspecting the target handle", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_TARGET_ID, param_spec); - - param_spec = g_param_spec_string ("initiator-id", "Initiator's bare JID", - "The string obtained by inspecting the initiator-handle", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_INITIATOR_ID, - param_spec); - - param_spec = g_param_spec_boolean ("requested", "Requested?", - "True if this channel was requested by the local user", - FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_REQUESTED, param_spec); - param_spec = g_param_spec_boxed ( "supported-access-controls", "Supported access-controls", @@ -1194,6 +1040,8 @@ salut_tube_dbus_offer (SalutTubeDBus *self, GError **error) { SalutTubeDBusPrivate *priv = SALUT_TUBE_DBUS_GET_PRIVATE (self); + TpBaseChannel *base = TP_BASE_CHANNEL (self); + TpBaseChannelClass *cls = TP_BASE_CHANNEL_GET_CLASS (base); if (priv->offered) { @@ -1202,7 +1050,7 @@ salut_tube_dbus_offer (SalutTubeDBus *self, return FALSE; } - if (priv->handle_type == TP_HANDLE_TYPE_CONTACT) + if (cls->target_handle_type == TP_HANDLE_TYPE_CONTACT) { /* TODO: we don't implement 1-1 D-Bus tube atm */ ; @@ -1229,6 +1077,8 @@ message_received (SalutTubeDBus *tube, const char *data, size_t len) { + TpBaseChannel *base = TP_BASE_CHANNEL (tube); + TpBaseChannelClass *cls = TP_BASE_CHANNEL_GET_CLASS (base); SalutTubeDBusPrivate *priv = SALUT_TUBE_DBUS_GET_PRIVATE (tube); DBusMessage *msg; DBusError error = {0,}; @@ -1245,7 +1095,7 @@ message_received (SalutTubeDBus *tube, return; } - if (priv->handle_type == TP_HANDLE_TYPE_ROOM) + if (cls->target_handle_type == TP_HANDLE_TYPE_ROOM) { const gchar *destination; const gchar *sender_name; @@ -1331,8 +1181,11 @@ data_received_cb (GibberBytestreamIface *stream, { SalutTubeDBus *tube = SALUT_TUBE_DBUS (user_data); SalutTubeDBusPrivate *priv = SALUT_TUBE_DBUS_GET_PRIVATE (tube); + TpBaseChannel *base = TP_BASE_CHANNEL (tube); + TpBaseChannelClass *cls = TP_BASE_CHANNEL_GET_CLASS (base); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT); + tp_base_channel_get_connection (base), + TP_HANDLE_TYPE_CONTACT); TpHandle sender; sender = tp_handle_lookup (contact_repo, from, NULL, NULL); @@ -1342,7 +1195,7 @@ data_received_cb (GibberBytestreamIface *stream, return; } - if (priv->handle_type == TP_HANDLE_TYPE_CONTACT) + if (cls->target_handle_type == TP_HANDLE_TYPE_CONTACT) { GString *buf = priv->reassembly_buffer; @@ -1447,7 +1300,6 @@ data_received_cb (GibberBytestreamIface *stream, SalutTubeDBus * salut_tube_dbus_new (SalutConnection *conn, - SalutTubesChannel *tubes_channel, TpHandle handle, TpHandleType handle_type, TpHandle self_handle, @@ -1455,26 +1307,25 @@ salut_tube_dbus_new (SalutConnection *conn, TpHandle initiator, const gchar *service, GHashTable *parameters, - guint id) + guint64 id, + gboolean requested) { SalutTubeDBus *tube; - gchar *object_path; + GType gtype = SALUT_TYPE_TUBE_DBUS; - object_path = g_strdup_printf ("%s/DBusTubeChannel_%u_%u", - conn->parent.object_path, handle, id); + if (handle_type == TP_HANDLE_TYPE_ROOM) + gtype = SALUT_TYPE_MUC_TUBE_DBUS; - tube = g_object_new (SALUT_TYPE_TUBE_DBUS, + tube = g_object_new (gtype, "connection", conn, - "object-path", object_path, - "tubes-channel", tubes_channel, "handle", handle, - "handle-type", handle_type, "self-handle", self_handle, "muc-connection", muc_connection, "initiator-handle", initiator, "service", service, "parameters", parameters, "id", id, + "requested", requested, NULL); return tube; @@ -1491,6 +1342,8 @@ salut_tube_dbus_accept (SalutTubeIface *tube, { SalutTubeDBus *self = SALUT_TUBE_DBUS (tube); SalutTubeDBusPrivate *priv = SALUT_TUBE_DBUS_GET_PRIVATE (self); + TpBaseChannel *base = TP_BASE_CHANNEL (self); + TpBaseChannelClass *cls = TP_BASE_CHANNEL_GET_CLASS (base); GibberBytestreamState state; g_assert (priv->bytestream != NULL); @@ -1502,7 +1355,7 @@ salut_tube_dbus_accept (SalutTubeIface *tube, if (state != GIBBER_BYTESTREAM_STATE_LOCAL_PENDING) return TRUE; - if (priv->handle_type == TP_HANDLE_TYPE_CONTACT) + if (cls->target_handle_type == TP_HANDLE_TYPE_CONTACT) { /* TODO: SI reply */ } @@ -1551,12 +1404,15 @@ salut_tube_dbus_add_name (SalutTubeDBus *self, const gchar *name) { SalutTubeDBusPrivate *priv = SALUT_TUBE_DBUS_GET_PRIVATE (self); + TpBaseChannel *base = TP_BASE_CHANNEL (self); + TpBaseChannelClass *cls = TP_BASE_CHANNEL_GET_CLASS (base); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT); + tp_base_channel_get_connection (base), + TP_HANDLE_TYPE_CONTACT); GHashTable *added; GArray *removed; - g_assert (priv->handle_type == TP_HANDLE_TYPE_ROOM); + g_assert (cls->target_handle_type == TP_HANDLE_TYPE_ROOM); if (g_hash_table_lookup (priv->dbus_names, GUINT_TO_POINTER (handle)) != NULL) @@ -1606,11 +1462,13 @@ salut_tube_dbus_remove_name (SalutTubeDBus *self, TpHandle handle) { SalutTubeDBusPrivate *priv = SALUT_TUBE_DBUS_GET_PRIVATE (self); + TpBaseChannel *base = TP_BASE_CHANNEL (self); + TpBaseChannelClass *cls = TP_BASE_CHANNEL_GET_CLASS (base); const gchar *name; GHashTable *added; GArray *removed; - g_assert (priv->handle_type == TP_HANDLE_TYPE_ROOM); + g_assert (cls->target_handle_type == TP_HANDLE_TYPE_ROOM); name = g_hash_table_lookup (priv->dbus_names, GUINT_TO_POINTER (handle)); if (name == NULL) @@ -1637,8 +1495,10 @@ salut_tube_dbus_handle_in_names (SalutTubeDBus *self, TpHandle handle) { SalutTubeDBusPrivate *priv = SALUT_TUBE_DBUS_GET_PRIVATE (self); + TpBaseChannel *base = TP_BASE_CHANNEL (self); + TpBaseChannelClass *cls = TP_BASE_CHANNEL_GET_CLASS (base); - g_assert (priv->handle_type == TP_HANDLE_TYPE_ROOM); + g_assert (cls->target_handle_type == TP_HANDLE_TYPE_ROOM); return (g_hash_table_lookup (priv->dbus_names, GUINT_TO_POINTER (handle)) != NULL); @@ -1650,77 +1510,6 @@ salut_tube_dbus_channel_get_allowed_properties (void) return salut_tube_dbus_channel_allowed_properties; } -/** - * salut_tube_dbus_close_async: - * - * Implements D-Bus method Close - * on interface org.freedesktop.Telepathy.Channel - */ -static void -salut_tube_dbus_close_async (TpSvcChannel *iface, - DBusGMethodInvocation *context) -{ - salut_tube_dbus_close (SALUT_TUBE_IFACE (iface), FALSE); - tp_svc_channel_return_from_close (context); -} - -/** - * salut_tube_dbus_get_channel_type - * - * Implements D-Bus method GetChannelType - * on interface org.freedesktop.Telepathy.Channel - */ -static void -salut_tube_dbus_get_channel_type (TpSvcChannel *iface, - DBusGMethodInvocation *context) -{ - tp_svc_channel_return_from_get_channel_type (context, - TP_IFACE_CHANNEL_TYPE_DBUS_TUBE); -} - -/** - * salut_tube_dbus_get_handle - * - * Implements D-Bus method GetHandle - * on interface org.freedesktop.Telepathy.Channel - */ -static void -salut_tube_dbus_get_handle (TpSvcChannel *iface, - DBusGMethodInvocation *context) -{ - SalutTubeDBus *self = SALUT_TUBE_DBUS (iface); - SalutTubeDBusPrivate *priv = SALUT_TUBE_DBUS_GET_PRIVATE (self); - - tp_svc_channel_return_from_get_handle (context, priv->handle_type, - priv->handle); -} - -/** - * salut_tube_dbus_get_interfaces - * - * Implements D-Bus method GetInterfaces - * on interface org.freedesktop.Telepathy.Channel - */ -static void -salut_tube_dbus_get_interfaces (TpSvcChannel *iface, - DBusGMethodInvocation *context) -{ - SalutTubeDBus *self = SALUT_TUBE_DBUS (iface); - SalutTubeDBusPrivate *priv = SALUT_TUBE_DBUS_GET_PRIVATE (self); - - if (priv->handle_type == TP_HANDLE_TYPE_CONTACT) - { - /* omit the Group interface */ - tp_svc_channel_return_from_get_interfaces (context, - salut_tube_dbus_interfaces + 1); - } - else - { - tp_svc_channel_return_from_get_interfaces (context, - salut_tube_dbus_interfaces); - } -} - static gboolean salut_tube_dbus_check_access_control (SalutTubeDBus *self, guint access_control, @@ -1817,21 +1606,6 @@ salut_tube_dbus_accept_async (TpSvcChannelTypeDBusTube *self, } static void -channel_iface_init (gpointer g_iface, - gpointer iface_data) -{ - TpSvcChannelClass *klass = (TpSvcChannelClass *) g_iface; - -#define IMPLEMENT(x, suffix) tp_svc_channel_implement_##x (\ - klass, salut_tube_dbus_##x##suffix) - IMPLEMENT(close,_async); - IMPLEMENT(get_channel_type,); - IMPLEMENT(get_handle,); - IMPLEMENT(get_interfaces,); -#undef IMPLEMENT -} - -static void tube_iface_init (gpointer g_iface, gpointer iface_data) { diff --git a/src/tube-dbus.h b/src/tube-dbus.h index e8a64eb1..71b43bb6 100644 --- a/src/tube-dbus.h +++ b/src/tube-dbus.h @@ -22,11 +22,11 @@ #include <glib-object.h> +#include <telepathy-glib/base-channel.h> #include <telepathy-glib/enums.h> #include <telepathy-glib/interfaces.h> #include "connection.h" -#include "tubes-channel.h" #include <gibber/gibber-muc-connection.h> #include <gibber/gibber-bytestream-iface.h> @@ -36,13 +36,13 @@ typedef struct _SalutTubeDBus SalutTubeDBus; typedef struct _SalutTubeDBusClass SalutTubeDBusClass; struct _SalutTubeDBusClass { - GObjectClass parent_class; + TpBaseChannelClass parent_class; TpDBusPropertiesMixinClass dbus_props_class; }; struct _SalutTubeDBus { - GObject parent; + TpBaseChannel parent; gpointer priv; }; @@ -66,10 +66,11 @@ GType salut_tube_dbus_get_type (void); SalutTubeDBusClass)) SalutTubeDBus * -salut_tube_dbus_new (SalutConnection *conn, SalutTubesChannel *tubes_channel, +salut_tube_dbus_new (SalutConnection *conn, TpHandle handle, TpHandleType handle_type, TpHandle self_handle, GibberMucConnection *muc_connection, TpHandle initiator, - const gchar *service, GHashTable *parameters, guint id); + const gchar *service, GHashTable *parameters, guint64 id, + gboolean requested); gboolean salut_tube_dbus_add_name (SalutTubeDBus *self, TpHandle handle, const gchar *name); diff --git a/src/tube-iface.c b/src/tube-iface.c index 18d39877..56ad5e0c 100644 --- a/src/tube-iface.c +++ b/src/tube-iface.c @@ -22,7 +22,6 @@ #include <telepathy-glib/gtypes.h> #include "connection.h" -#include "tubes-channel.h" #include <glib.h> @@ -96,23 +95,11 @@ salut_tube_iface_base_init (gpointer klass) "connection", "SalutConnection object", "Salut connection object that owns this D-Bus tube object.", - SALUT_TYPE_CONNECTION, + TP_TYPE_BASE_CONNECTION, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_interface_install_property (klass, param_spec); - param_spec = g_param_spec_object ( - "tubes-channel", - "SalutTubesChannel object", - "Salut tubes object that implements the old interface.", - SALUT_TYPE_TUBES_CHANNEL, - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_READWRITE | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB); - g_object_interface_install_property (klass, param_spec); - param_spec = g_param_spec_uint ( "handle", "Handle", @@ -143,7 +130,7 @@ salut_tube_iface_base_init (gpointer klass) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_interface_install_property (klass, param_spec); - param_spec = g_param_spec_uint ( + param_spec = g_param_spec_uint64 ( "id", "id", "The unique identifier of this tube", diff --git a/src/tube-stream.c b/src/tube-stream.c index acb3a8e9..ee501fe6 100644 --- a/src/tube-stream.c +++ b/src/tube-stream.c @@ -67,32 +67,23 @@ #include "debug.h" #include "signals-marshal.h" #include "connection.h" +#include "muc-tube-stream.h" #include "tube-iface.h" #include "si-bytestream-manager.h" #include "contact-manager.h" -#include "tubes-channel.h" static void tube_iface_init (gpointer g_iface, gpointer iface_data); -static void channel_iface_init (gpointer g_iface, gpointer iface_data); static void streamtube_iface_init (gpointer g_iface, gpointer iface_data); -G_DEFINE_TYPE_WITH_CODE (SalutTubeStream, salut_tube_stream, 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_DEFINE_TYPE_WITH_CODE (SalutTubeStream, salut_tube_stream, + TP_TYPE_BASE_CHANNEL, G_IMPLEMENT_INTERFACE (SALUT_TYPE_TUBE_IFACE, tube_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_TYPE_STREAM_TUBE, streamtube_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_TUBE, - NULL); - G_IMPLEMENT_INTERFACE (TP_TYPE_EXPORTABLE_CHANNEL, NULL); - G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_IFACE, NULL)); + NULL)); static const gchar *salut_tube_stream_interfaces[] = { - TP_IFACE_CHANNEL_INTERFACE_GROUP, - /* If more interfaces are added, either keep Tube as the first, or change - * the implementations of salut_tube_stream_get_interfaces () and - * salut_tube_stream_get_property () too */ TP_IFACE_CHANNEL_INTERFACE_TUBE, NULL }; @@ -131,15 +122,9 @@ static guint signals[LAST_SIGNAL] = {0}; /* properties */ enum { - PROP_CONNECTION = 1, - PROP_TUBES_CHANNEL, - PROP_INTERFACES, - PROP_HANDLE, - PROP_HANDLE_TYPE, - PROP_SELF_HANDLE, + PROP_SELF_HANDLE = 1, PROP_ID, PROP_TYPE, - PROP_INITIATOR_HANDLE, PROP_SERVICE, PROP_PARAMETERS, PROP_STATE, @@ -150,13 +135,6 @@ enum PROP_ACCESS_CONTROL_PARAM, PROP_PORT, PROP_IQ_REQ, - PROP_CHANNEL_DESTROYED, - PROP_CHANNEL_PROPERTIES, - PROP_OBJECT_PATH, - PROP_CHANNEL_TYPE, - PROP_TARGET_ID, - PROP_REQUESTED, - PROP_INITIATOR_ID, PROP_SUPPORTED_SOCKET_TYPES, LAST_PROPERTY }; @@ -164,15 +142,10 @@ enum typedef struct _SalutTubeStreamPrivate SalutTubeStreamPrivate; struct _SalutTubeStreamPrivate { - SalutConnection *conn; - SalutTubesChannel *tubes_channel; - TpHandle handle; - TpHandleType handle_type; TpHandle self_handle; - guint id; + guint64 id; guint port; WockyStanza *iq_req; - gchar *object_path; /* Bytestreams for MUC tubes (using stream initiation) or 1-1 tubes (using * direct TCP connections). One tube can have several bytestreams. The @@ -200,7 +173,6 @@ struct _SalutTubeStreamPrivate GHashTable *transport_to_id; guint last_connection_id; - TpHandle initiator; gchar *service; GHashTable *parameters; TpTubeChannelState state; @@ -219,8 +191,6 @@ struct _SalutTubeStreamPrivate /* listen for connections from the remote CM */ GibberListener *contact_listener; - gboolean closed; - gboolean offer_needed; gboolean dispose_has_run; @@ -499,10 +469,11 @@ extra_bytestream_negotiate_cb (GibberBytestreamIface *bytestream, static gchar * generate_stream_id (SalutTubeStream *self) { - SalutTubeStreamPrivate *priv = SALUT_TUBE_STREAM_GET_PRIVATE (self); + TpBaseChannel *base = TP_BASE_CHANNEL (self); + TpBaseChannelClass *cls = TP_BASE_CHANNEL_GET_CLASS (base); gchar *stream_id; - if (priv->handle_type == TP_HANDLE_TYPE_CONTACT) + if (cls->target_handle_type == TP_HANDLE_TYPE_CONTACT) { stream_id = g_strdup_printf ("%lu-%u", (unsigned long) time (NULL), g_random_int ()); @@ -522,10 +493,13 @@ start_stream_initiation (SalutTubeStream *self, GError **error) { SalutTubeStreamPrivate *priv = SALUT_TUBE_STREAM_GET_PRIVATE (self); + TpBaseChannel *base = TP_BASE_CHANNEL (self); + TpBaseChannelClass *cls = TP_BASE_CHANNEL_GET_CLASS (base); + TpHandle initiator = tp_base_channel_get_initiator (base); WockyNode *node, *si_node; WockyStanza *msg; WockyNode *msg_node; - TpHandleRepoIface *contact_repo; + TpHandleRepoIface *contact_repo, *room_repo; const gchar *jid; gchar *stream_id, *id_str; gboolean result; @@ -533,32 +507,34 @@ start_stream_initiation (SalutTubeStream *self, SalutContact *contact; SalutContactManager *contact_mgr; SalutSiBytestreamManager *si_bytestream_mgr; - TpHandleRepoIface *room_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_ROOM); + TpBaseConnection *base_conn = tp_base_channel_get_connection (base); + SalutConnection *conn = SALUT_CONNECTION (base_conn); - contact_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT); + contact_repo = tp_base_connection_get_handles (base_conn, + TP_HANDLE_TYPE_CONTACT); + room_repo = tp_base_connection_get_handles (base_conn, + TP_HANDLE_TYPE_ROOM); - jid = tp_handle_inspect (contact_repo, priv->initiator); + jid = tp_handle_inspect (contact_repo, initiator); stream_id = generate_stream_id (self); - msg = salut_si_bytestream_manager_make_stream_init_iq (priv->conn->name, jid, + msg = salut_si_bytestream_manager_make_stream_init_iq (conn->name, jid, stream_id, WOCKY_TELEPATHY_NS_TUBES); msg_node = wocky_stanza_get_top_node (msg); si_node = wocky_node_get_child_ns (msg_node, "si", WOCKY_XMPP_NS_SI); g_assert (si_node != NULL); - id_str = g_strdup_printf ("%u", priv->id); + id_str = g_strdup_printf ("%" G_GUINT64_FORMAT, priv->id); - g_assert (priv->handle_type == TP_HANDLE_TYPE_ROOM); + g_assert (cls->target_handle_type == TP_HANDLE_TYPE_ROOM); /* FIXME: this needs standardizing */ node = wocky_node_add_child_ns (si_node, "muc-stream", WOCKY_TELEPATHY_NS_TUBES); wocky_node_set_attribute (node, "muc", tp_handle_inspect ( - room_repo, priv->handle)); + room_repo, tp_base_channel_get_target_handle (base))); wocky_node_set_attribute (node, "tube", id_str); @@ -566,19 +542,19 @@ start_stream_initiation (SalutTubeStream *self, data->self = self; data->transport = g_object_ref (transport); - g_object_get (priv->conn, + g_object_get (conn, "si-bytestream-manager", &si_bytestream_mgr, "contact-manager", &contact_mgr, NULL); g_assert (si_bytestream_mgr != NULL); g_assert (contact_mgr != NULL); - contact = salut_contact_manager_get_contact (contact_mgr, priv->initiator); + contact = salut_contact_manager_get_contact (contact_mgr, initiator); if (contact == NULL) { result = FALSE; g_set_error (error, TP_ERROR, TP_ERROR_NETWORK_ERROR, - "can't find contact with handle %d", priv->initiator); + "can't find contact with handle %d", initiator); g_object_unref (transport); g_slice_free (struct _extra_bytestream_negotiate_cb_data, data); } @@ -623,22 +599,25 @@ start_stream_direct (SalutTubeStream *self, GError **error) { SalutTubeStreamPrivate *priv = SALUT_TUBE_STREAM_GET_PRIVATE (self); + TpBaseChannel *base = TP_BASE_CHANNEL (self); + TpBaseChannelClass *cls = TP_BASE_CHANNEL_GET_CLASS (base); + TpHandle initiator = tp_base_channel_get_initiator (base); SalutContact *contact; SalutContactManager *contact_mgr; GibberBytestreamIface *bytestream; - g_assert (priv->handle_type == TP_HANDLE_TYPE_CONTACT); + g_assert (cls->target_handle_type == TP_HANDLE_TYPE_CONTACT); - g_object_get (priv->conn, + g_object_get (tp_base_channel_get_connection (base), "contact-manager", &contact_mgr, NULL); g_assert (contact_mgr != NULL); - contact = salut_contact_manager_get_contact (contact_mgr, priv->initiator); + contact = salut_contact_manager_get_contact (contact_mgr, initiator); if (contact == NULL) { g_set_error (error, TP_ERROR, TP_ERROR_NETWORK_ERROR, - "can't find contact with handle %d", priv->initiator); + "can't find contact with handle %d", initiator); g_object_unref (contact_mgr); @@ -713,7 +692,8 @@ local_new_connection_cb (GibberListener *listener, gpointer user_data) { SalutTubeStream *self = SALUT_TUBE_STREAM (user_data); - SalutTubeStreamPrivate *priv = SALUT_TUBE_STREAM_GET_PRIVATE (self); + TpBaseChannel *base = TP_BASE_CHANNEL (self); + TpBaseChannelClass *cls = TP_BASE_CHANNEL_GET_CLASS (base); /* Block the transport while there is no open bytestream to transfer * its data. */ @@ -725,7 +705,7 @@ local_new_connection_cb (GibberListener *listener, * Streams in P2P tubes are established directly with a TCP connection. We * use SalutDirectBytestreamManager. */ - if (priv->handle_type == TP_HANDLE_TYPE_CONTACT) + if (cls->target_handle_type == TP_HANDLE_TYPE_CONTACT) { if (!start_stream_direct (self, transport, NULL)) { @@ -774,9 +754,10 @@ new_connection_to_socket (SalutTubeStream *self, GibberBytestreamIface *bytestream) { SalutTubeStreamPrivate *priv = SALUT_TUBE_STREAM_GET_PRIVATE (self); + TpBaseChannel *base = TP_BASE_CHANNEL (self); GibberTransport *transport; - g_assert (priv->initiator == priv->self_handle); + g_assert (tp_base_channel_is_requested (base)); #ifdef GIBBER_TYPE_UNIX_TRANSPORT if (priv->address_type == TP_SOCKET_ADDRESS_TYPE_UNIX) @@ -837,10 +818,11 @@ tube_stream_open (SalutTubeStream *self, GError **error) { SalutTubeStreamPrivate *priv = SALUT_TUBE_STREAM_GET_PRIVATE (self); + TpBaseChannel *base = TP_BASE_CHANNEL (self); DEBUG ("called"); - if (priv->initiator == priv->self_handle) + if (tp_base_channel_is_requested (base)) /* Nothing to do if we are the initiator of this tube. * We'll connect to the socket each time request a new bytestream. */ return TRUE; @@ -970,7 +952,6 @@ salut_tube_stream_init (SalutTubeStream *self) priv->address = NULL; priv->access_control = TP_SOCKET_ACCESS_CONTROL_LOCALHOST; priv->access_control_param = NULL; - priv->closed = FALSE; priv->offer_needed = FALSE; priv->dispose_has_run = FALSE; @@ -1010,13 +991,14 @@ salut_tube_stream_dispose (GObject *object) { SalutTubeStream *self = SALUT_TUBE_STREAM (object); SalutTubeStreamPrivate *priv = SALUT_TUBE_STREAM_GET_PRIVATE (self); + TpBaseChannel *base = TP_BASE_CHANNEL (self); if (priv->dispose_has_run) return; salut_tube_iface_close (SALUT_TUBE_IFACE (self), FALSE); - if (priv->initiator != priv->self_handle && + if (tp_base_channel_is_requested (base) && priv->address_type == TP_SOCKET_ADDRESS_TYPE_UNIX && priv->address != NULL) { @@ -1077,7 +1059,6 @@ salut_tube_stream_finalize (GObject *object) SalutTubeStream *self = SALUT_TUBE_STREAM (object); SalutTubeStreamPrivate *priv = SALUT_TUBE_STREAM_GET_PRIVATE (self); - g_free (priv->object_path); g_free (priv->service); if (priv->parameters != NULL) { @@ -1108,52 +1089,18 @@ salut_tube_stream_get_property (GObject *object, { SalutTubeStream *self = SALUT_TUBE_STREAM (object); SalutTubeStreamPrivate *priv = SALUT_TUBE_STREAM_GET_PRIVATE (self); - TpBaseConnection *base_conn = (TpBaseConnection *) priv->conn; switch (property_id) { - case PROP_TUBES_CHANNEL: - g_value_set_object (value, priv->tubes_channel); - break; - case PROP_CONNECTION: - g_value_set_object (value, priv->conn); - break; - case PROP_OBJECT_PATH: - g_value_set_string (value, priv->object_path); - break; - case PROP_INTERFACES: - if (priv->handle_type == TP_HANDLE_TYPE_ROOM) - { - /* MUC tubes */ - g_value_set_boxed (value, salut_tube_stream_interfaces); - } - else - { - /* 1-1 tubes - omit the Group interface */ - g_value_set_boxed (value, salut_tube_stream_interfaces + 1); - } - break; - case PROP_CHANNEL_TYPE: - g_value_set_static_string (value, TP_IFACE_CHANNEL_TYPE_STREAM_TUBE); - break; - case PROP_HANDLE: - g_value_set_uint (value, priv->handle); - break; - case PROP_HANDLE_TYPE: - g_value_set_uint (value, priv->handle_type); - break; case PROP_SELF_HANDLE: g_value_set_uint (value, priv->self_handle); break; case PROP_ID: - g_value_set_uint (value, priv->id); + g_value_set_uint64 (value, priv->id); break; case PROP_TYPE: g_value_set_uint (value, TP_TUBE_TYPE_STREAM); break; - case PROP_INITIATOR_HANDLE: - g_value_set_uint (value, priv->initiator); - break; case PROP_SERVICE: g_value_set_string (value, priv->service); break; @@ -1184,72 +1131,6 @@ salut_tube_stream_get_property (GObject *object, case PROP_IQ_REQ: g_value_set_pointer (value, priv->iq_req); break; - case PROP_CHANNEL_DESTROYED: - g_value_set_boolean (value, priv->closed); - break; - case PROP_CHANNEL_PROPERTIES: - { - GHashTable *properties; - - properties = tp_dbus_properties_mixin_make_properties_hash (object, - TP_IFACE_CHANNEL, "TargetHandle", - TP_IFACE_CHANNEL, "TargetHandleType", - TP_IFACE_CHANNEL, "ChannelType", - TP_IFACE_CHANNEL, "TargetID", - TP_IFACE_CHANNEL, "InitiatorHandle", - TP_IFACE_CHANNEL, "InitiatorID", - TP_IFACE_CHANNEL, "Requested", - TP_IFACE_CHANNEL, "Interfaces", - TP_IFACE_CHANNEL_TYPE_STREAM_TUBE, "Service", - TP_IFACE_CHANNEL_TYPE_STREAM_TUBE, "SupportedSocketTypes", - NULL); - - if (priv->initiator != priv->self_handle) - { - /* channel has not been requested so Parameters is immutable */ - GValue *prop_value = g_slice_new0 (GValue); - - /* FIXME: use tp_dbus_properties_mixin_add_properties once it's - * added in tp-glib */ - tp_dbus_properties_mixin_get (object, - TP_IFACE_CHANNEL_INTERFACE_TUBE, "Parameters", - prop_value, NULL); - g_assert (G_IS_VALUE (prop_value)); - - g_hash_table_insert (properties, - g_strdup_printf ("%s.%s", TP_IFACE_CHANNEL_INTERFACE_TUBE, - "Parameters"), prop_value); - } - - g_value_take_boxed (value, properties); - } - break; - case PROP_REQUESTED: - g_value_set_boolean (value, - (priv->initiator == priv->self_handle)); - break; - case PROP_INITIATOR_ID: - { - TpHandleRepoIface *repo = tp_base_connection_get_handles ( - base_conn, TP_HANDLE_TYPE_CONTACT); - - /* some channel can have o.f.T.Channel.InitiatorHandle == 0 but - * tubes always have an initiator */ - g_assert (priv->initiator != 0); - - g_value_set_string (value, - tp_handle_inspect (repo, priv->initiator)); - } - break; - case PROP_TARGET_ID: - { - TpHandleRepoIface *repo = tp_base_connection_get_handles ( - base_conn, priv->handle_type); - - g_value_set_string (value, - tp_handle_inspect (repo, priv->handle)); - } - break; case PROP_SUPPORTED_SOCKET_TYPES: g_value_take_boxed (value, salut_tube_stream_get_supported_socket_types ()); @@ -1271,34 +1152,11 @@ salut_tube_stream_set_property (GObject *object, switch (property_id) { - case PROP_TUBES_CHANNEL: - priv->tubes_channel = g_value_get_object (value); - break; - case PROP_CONNECTION: - priv->conn = g_value_get_object (value); - break; - case PROP_OBJECT_PATH: - g_free (priv->object_path); - priv->object_path = g_value_dup_string (value); - break; - case PROP_CHANNEL_TYPE: - /* this property is writable in the interface, but not actually - * meaningfully changeable on this channel, so we do nothing */ - break; - case PROP_HANDLE: - priv->handle = g_value_get_uint (value); - break; - case PROP_HANDLE_TYPE: - priv->handle_type = g_value_get_uint (value); - break; case PROP_SELF_HANDLE: priv->self_handle = g_value_get_uint (value); break; case PROP_ID: - priv->id = g_value_get_uint (value); - break; - case PROP_INITIATOR_HANDLE: - priv->initiator = g_value_get_uint (value); + priv->id = g_value_get_uint64 (value); break; case PROP_SERVICE: g_free (priv->service); @@ -1358,19 +1216,16 @@ salut_tube_stream_constructor (GType type, { GObject *obj; SalutTubeStreamPrivate *priv; - TpDBusDaemon *bus; - TpBaseConnection *base_conn; + TpBaseChannel *base; obj = G_OBJECT_CLASS (salut_tube_stream_parent_class)-> constructor (type, n_props, props); priv = SALUT_TUBE_STREAM_GET_PRIVATE (SALUT_TUBE_STREAM (obj)); - /* Ref the initiator handle */ - base_conn = TP_BASE_CONNECTION (priv->conn); - g_assert (priv->initiator != 0); + base = TP_BASE_CHANNEL (obj); - if (priv->initiator == priv->self_handle) + if (tp_base_channel_get_initiator (base) == priv->self_handle) { /* We initiated this tube */ priv->state = TP_TUBE_CHANNEL_STATE_NOT_OFFERED; @@ -1382,28 +1237,55 @@ salut_tube_stream_constructor (GType type, priv->state = TP_TUBE_CHANNEL_STATE_LOCAL_PENDING; } - bus = tp_base_connection_get_dbus_daemon (base_conn); - tp_dbus_daemon_register_object (bus, priv->object_path, obj); - - DEBUG ("Registering at '%s'", priv->object_path); + DEBUG ("Registering at '%s'", tp_base_channel_get_object_path (base)); return obj; } static void +salut_tube_stream_fill_immutable_properties (TpBaseChannel *chan, + GHashTable *properties) +{ + TpBaseChannelClass *cls = TP_BASE_CHANNEL_CLASS ( + salut_tube_stream_parent_class); + + cls->fill_immutable_properties (chan, properties); + + tp_dbus_properties_mixin_fill_properties_hash ( + G_OBJECT (chan), properties, + TP_IFACE_CHANNEL_TYPE_STREAM_TUBE, "Service", + TP_IFACE_CHANNEL_TYPE_STREAM_TUBE, "SupportedSocketTypes", + NULL); + + if (!tp_base_channel_is_requested (chan)) + { + tp_dbus_properties_mixin_fill_properties_hash ( + G_OBJECT (chan), properties, + TP_IFACE_CHANNEL_INTERFACE_TUBE, "Parameters", + NULL); + } +} + +static gchar * +salut_tube_stream_get_object_path_suffix (TpBaseChannel *base) +{ + SalutTubeStream *self = SALUT_TUBE_STREAM (base); + SalutTubeStreamPrivate *priv = SALUT_TUBE_STREAM_GET_PRIVATE (self); + + return g_strdup_printf ("StreamTubeChannel/%u/%" G_GUINT64_FORMAT, + tp_base_channel_get_target_handle (base), + priv->id); +} + +static void +salut_tube_stream_close_dbus (TpBaseChannel *base) +{ + salut_tube_iface_close ((SalutTubeIface *) base, FALSE); +} + +static void salut_tube_stream_class_init (SalutTubeStreamClass *salut_tube_stream_class) { - static TpDBusPropertiesMixinPropImpl channel_props[] = { - { "TargetHandleType", "handle-type", NULL }, - { "TargetHandle", "handle", NULL }, - { "ChannelType", "channel-type", NULL }, - { "TargetID", "target-id", NULL }, - { "Interfaces", "interfaces", NULL }, - { "Requested", "requested", NULL }, - { "InitiatorHandle", "initiator-handle", NULL }, - { "InitiatorID", "initiator-id", NULL }, - { NULL } - }; static TpDBusPropertiesMixinPropImpl stream_tube_props[] = { { "Service", "service", NULL }, { "SupportedSocketTypes", "supported-socket-types", NULL }, @@ -1415,11 +1297,6 @@ salut_tube_stream_class_init (SalutTubeStreamClass *salut_tube_stream_class) { NULL } }; static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = { - { TP_IFACE_CHANNEL, - tp_dbus_properties_mixin_getter_gobject_properties, - NULL, - channel_props, - }, { TP_IFACE_CHANNEL_TYPE_STREAM_TUBE, tp_dbus_properties_mixin_getter_gobject_properties, NULL, @@ -1434,34 +1311,34 @@ salut_tube_stream_class_init (SalutTubeStreamClass *salut_tube_stream_class) }; GObjectClass *object_class = G_OBJECT_CLASS (salut_tube_stream_class); + TpBaseChannelClass *base_class = TP_BASE_CHANNEL_CLASS (salut_tube_stream_class); GParamSpec *param_spec; object_class->get_property = salut_tube_stream_get_property; object_class->set_property = salut_tube_stream_set_property; object_class->constructor = salut_tube_stream_constructor; + base_class->channel_type = TP_IFACE_CHANNEL_TYPE_STREAM_TUBE; + base_class->interfaces = salut_tube_stream_interfaces; + base_class->target_handle_type = TP_HANDLE_TYPE_CONTACT; + base_class->close = salut_tube_stream_close_dbus; + base_class->fill_immutable_properties = + salut_tube_stream_fill_immutable_properties; + base_class->get_object_path_suffix = + salut_tube_stream_get_object_path_suffix; + g_type_class_add_private (salut_tube_stream_class, sizeof (SalutTubeStreamPrivate)); object_class->dispose = salut_tube_stream_dispose; object_class->finalize = salut_tube_stream_finalize; - g_object_class_override_property (object_class, PROP_CONNECTION, - "connection"); - g_object_class_override_property (object_class, PROP_TUBES_CHANNEL, - "tubes-channel"); - g_object_class_override_property (object_class, PROP_HANDLE, - "handle"); - g_object_class_override_property (object_class, PROP_HANDLE_TYPE, - "handle-type"); g_object_class_override_property (object_class, PROP_SELF_HANDLE, "self-handle"); g_object_class_override_property (object_class, PROP_ID, "id"); g_object_class_override_property (object_class, PROP_TYPE, "type"); - g_object_class_override_property (object_class, PROP_INITIATOR_HANDLE, - "initiator-handle"); g_object_class_override_property (object_class, PROP_SERVICE, "service"); g_object_class_override_property (object_class, PROP_PARAMETERS, @@ -1469,23 +1346,6 @@ salut_tube_stream_class_init (SalutTubeStreamClass *salut_tube_stream_class) g_object_class_override_property (object_class, PROP_STATE, "state"); - g_object_class_override_property (object_class, PROP_OBJECT_PATH, - "object-path"); - g_object_class_override_property (object_class, PROP_CHANNEL_TYPE, - "channel-type"); - - g_object_class_override_property (object_class, PROP_CHANNEL_DESTROYED, - "channel-destroyed"); - g_object_class_override_property (object_class, PROP_CHANNEL_PROPERTIES, - "channel-properties"); - - param_spec = g_param_spec_boxed ("interfaces", "Extra D-Bus interfaces", - "Additional Channel.Interface.* interfaces", - G_TYPE_STRV, - G_PARAM_READABLE | - G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NAME); - g_object_class_install_property (object_class, PROP_INTERFACES, param_spec); - param_spec = g_param_spec_uint ( "address-type", "address type", @@ -1525,13 +1385,6 @@ salut_tube_stream_class_init (SalutTubeStreamClass *salut_tube_stream_class) g_object_class_install_property (object_class, PROP_ACCESS_CONTROL_PARAM, param_spec); - param_spec = g_param_spec_string ("target-id", "Target JID", - "The string obtained by inspecting the target handle", - NULL, - G_PARAM_READABLE | - G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NAME); - g_object_class_install_property (object_class, PROP_TARGET_ID, param_spec); - param_spec = g_param_spec_uint ( "port", "port on the initiator's CM", @@ -1565,19 +1418,6 @@ salut_tube_stream_class_init (SalutTubeStreamClass *salut_tube_stream_class) G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_OFFERED, param_spec); - param_spec = g_param_spec_string ("initiator-id", "Initiator's bare JID", - "The string obtained by inspecting the initiator-handle", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_INITIATOR_ID, - param_spec); - - param_spec = g_param_spec_boolean ("requested", "Requested?", - "True if this channel was requested by the local user", - FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_REQUESTED, param_spec); - param_spec = g_param_spec_boxed ( "supported-socket-types", "Supported socket types", @@ -1671,7 +1511,6 @@ data_received_cb (GibberBytestreamIface *bytestream, SalutTubeStream * salut_tube_stream_new (SalutConnection *conn, - SalutTubesChannel *tubes_channel, TpHandle handle, TpHandleType handle_type, TpHandle self_handle, @@ -1679,22 +1518,20 @@ salut_tube_stream_new (SalutConnection *conn, gboolean offered, const gchar *service, GHashTable *parameters, - guint id, + guint64 id, guint portnum, - WockyStanza *iq_req) + WockyStanza *iq_req, + gboolean requested) { SalutTubeStream *obj; - char *object_path; + GType gtype = SALUT_TYPE_TUBE_STREAM; - object_path = g_strdup_printf ("%s/StreamTubeChannel_%u_%u", - conn->parent.object_path, handle, id); + if (handle_type == TP_HANDLE_TYPE_ROOM) + gtype = SALUT_TYPE_MUC_TUBE_STREAM; - obj = g_object_new (SALUT_TYPE_TUBE_STREAM, + obj = g_object_new (gtype, "connection", conn, - "tubes-channel", tubes_channel, - "object-path", object_path, "handle", handle, - "handle-type", handle_type, "self-handle", self_handle, "initiator-handle", initiator, "offered", offered, @@ -1703,10 +1540,9 @@ salut_tube_stream_new (SalutConnection *conn, "id", id, "port", portnum, "iq-req", iq_req, + "requested", requested, NULL); - g_free (object_path); - return obj; } @@ -1721,6 +1557,10 @@ salut_tube_stream_accept (SalutTubeIface *tube, { SalutTubeStream *self = SALUT_TUBE_STREAM (tube); SalutTubeStreamPrivate *priv = SALUT_TUBE_STREAM_GET_PRIVATE (self); + TpBaseChannel *base = TP_BASE_CHANNEL (self); + TpBaseChannelClass *cls = TP_BASE_CHANNEL_GET_CLASS (base); + TpBaseConnection *base_conn = tp_base_channel_get_connection (base); + SalutConnection *conn = SALUT_CONNECTION (base_conn); WockyStanza *reply; if (priv->state != TP_TUBE_CHANNEL_STATE_LOCAL_PENDING) @@ -1732,10 +1572,10 @@ salut_tube_stream_accept (SalutTubeIface *tube, return FALSE; } - if (priv->handle_type == TP_HANDLE_TYPE_CONTACT) + if (cls->target_handle_type == TP_HANDLE_TYPE_CONTACT) { reply = wocky_stanza_build_iq_result (priv->iq_req, NULL); - wocky_porter_send (priv->conn->porter, reply); + wocky_porter_send (conn->porter, reply); g_object_unref (priv->iq_req); priv->iq_req = NULL; @@ -1798,29 +1638,34 @@ contact_new_connection_cb (GibberListener *listener, gpointer user_data) { SalutTubeStream *self = SALUT_TUBE_STREAM (user_data); - SalutTubeStreamPrivate *priv = SALUT_TUBE_STREAM_GET_PRIVATE (self); + TpBaseChannel *base = TP_BASE_CHANNEL (self); + TpBaseChannelClass *cls = TP_BASE_CHANNEL_GET_CLASS (base); + TpBaseConnection *base_conn = tp_base_channel_get_connection (base); + SalutConnection *conn = SALUT_CONNECTION (base_conn); GibberBytestreamIface *bytestream; SalutContactManager *contact_mgr; SalutContact *contact; - g_assert (priv->handle_type == TP_HANDLE_TYPE_CONTACT); + g_assert (cls->target_handle_type == TP_HANDLE_TYPE_CONTACT); - g_object_get (priv->conn, + g_object_get (conn, "contact-manager", &contact_mgr, NULL); g_assert (contact_mgr != NULL); - contact = salut_contact_manager_get_contact (contact_mgr, priv->handle); + contact = salut_contact_manager_get_contact (contact_mgr, + tp_base_channel_get_target_handle (base)); if (contact == NULL) { - DEBUG ("can't find contact with handle %d", priv->handle); + DEBUG ("can't find contact with handle %d", + tp_base_channel_get_target_handle (base)); g_object_unref (contact_mgr); return; } bytestream = g_object_new (GIBBER_TYPE_BYTESTREAM_DIRECT, "state", GIBBER_BYTESTREAM_STATE_LOCAL_PENDING, - "self-id", priv->conn->name, + "self-id", conn->name, "peer-id", contact->name, NULL); @@ -1889,34 +1734,37 @@ salut_tube_stream_close (SalutTubeIface *tube, gboolean closed_remotely) { SalutTubeStream *self = SALUT_TUBE_STREAM (tube); SalutTubeStreamPrivate *priv = SALUT_TUBE_STREAM_GET_PRIVATE (self); + TpBaseChannel *base = TP_BASE_CHANNEL (self); + TpBaseChannelClass *cls = TP_BASE_CHANNEL_GET_CLASS (base); + TpBaseConnection *base_conn = tp_base_channel_get_connection (base); + SalutConnection *conn = SALUT_CONNECTION (base_conn); - if (priv->closed) + if (tp_base_channel_is_destroyed (base)) return; - priv->closed = TRUE; g_hash_table_foreach_remove (priv->bytestream_to_transport, close_each_extra_bytestream, self); /* do not send the close stanza if the tube was closed due to the remote * contact */ - if (!closed_remotely && priv->handle_type == TP_HANDLE_TYPE_CONTACT) + if (!closed_remotely && cls->target_handle_type == TP_HANDLE_TYPE_CONTACT) { WockyStanza *stanza; const gchar *jid_from; TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT); + base_conn, TP_HANDLE_TYPE_CONTACT); gchar *tube_id_str; SalutContactManager *contact_mgr; SalutContact *contact; jid_from = tp_handle_inspect (contact_repo, priv->self_handle); - tube_id_str = g_strdup_printf ("%u", priv->id); + tube_id_str = g_strdup_printf ("%" G_GUINT64_FORMAT, priv->id); - g_object_get (priv->conn, "contact-manager", &contact_mgr, NULL); + g_object_get (conn, "contact-manager", &contact_mgr, NULL); g_assert (contact_mgr != NULL); contact = salut_contact_manager_get_contact (contact_mgr, - priv->handle); + tp_base_channel_get_target_handle (base)); stanza = wocky_stanza_build_to_contact (WOCKY_STANZA_TYPE_IQ, WOCKY_STANZA_SUB_TYPE_SET, @@ -1926,7 +1774,7 @@ salut_tube_stream_close (SalutTubeIface *tube, gboolean closed_remotely) '@', "id", tube_id_str, ')', NULL); - wocky_porter_send_iq_async (priv->conn->porter, stanza, + wocky_porter_send_iq_async (conn->porter, stanza, NULL, iq_close_reply_cb, tube); g_free (tube_id_str); @@ -1936,19 +1784,26 @@ salut_tube_stream_close (SalutTubeIface *tube, gboolean closed_remotely) g_object_unref (contact_mgr); } - if (priv->handle_type == TP_HANDLE_TYPE_CONTACT) + if (cls->target_handle_type == TP_HANDLE_TYPE_CONTACT) { - if (priv->initiator == priv->self_handle) + if (priv->contact_listener != NULL) { - if (priv->contact_listener != NULL) - { - g_object_unref (priv->contact_listener); - priv->contact_listener = NULL; - } + g_object_unref (priv->contact_listener); + priv->contact_listener = NULL; } } + /* Take a ref to ourselves as when we emit tube-closed + * SalutTubesChannel will drop our last ref but we still need to + * declare ourselves as destroyed. this is rubbish, but will + * disappear when we finally remove the Tubes channel type. */ + g_object_ref (self); + g_signal_emit (G_OBJECT (self), signals[CLOSED], 0); + + tp_base_channel_destroyed (base); + + g_object_unref (self); } static void @@ -1969,9 +1824,11 @@ salut_tube_stream_add_bytestream (SalutTubeIface *tube, { SalutTubeStream *self = SALUT_TUBE_STREAM (tube); SalutTubeStreamPrivate *priv = SALUT_TUBE_STREAM_GET_PRIVATE (self); + TpBaseChannel *base = TP_BASE_CHANNEL (self); + TpBaseConnection *base_conn = tp_base_channel_get_connection (base); GibberTransport *transport; - if (priv->initiator != priv->self_handle) + if (!tp_base_channel_is_requested (base)) { DEBUG ("I'm not the initiator of this tube, can't accept " "an extra bytestream"); @@ -1987,7 +1844,7 @@ salut_tube_stream_add_bytestream (SalutTubeIface *tube, TpHandle contact; gchar *peer_id; TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT); + base_conn, TP_HANDLE_TYPE_CONTACT); if (priv->state == TP_TUBE_CHANNEL_STATE_REMOTE_PENDING) { @@ -2314,7 +2171,7 @@ salut_tube_stream_accept_async (TpSvcChannelTypeStreamTube *iface, #if 0 /* TODO: add a property "muc" and set it at initialization */ - if (priv->handle_type == TP_HANDLE_TYPE_ROOM) + if (cls->target_handle_type == TP_HANDLE_TYPE_ROOM) salut_muc_channel_send_presence (self->muc, NULL); #endif @@ -2322,77 +2179,6 @@ salut_tube_stream_accept_async (TpSvcChannelTypeStreamTube *iface, priv->address); } -/** - * salut_tube_stream_close_async: - * - * Implements D-Bus method Close - * on interface org.freedesktop.Telepathy.Channel - */ -static void -salut_tube_stream_close_async (TpSvcChannel *iface, - DBusGMethodInvocation *context) -{ - salut_tube_stream_close (SALUT_TUBE_IFACE (iface), FALSE); - tp_svc_channel_return_from_close (context); -} - -/** - * salut_tube_stream_get_channel_type - * - * Implements D-Bus method GetChannelType - * on interface org.freedesktop.Telepathy.Channel - */ -static void -salut_tube_stream_get_channel_type (TpSvcChannel *iface, - DBusGMethodInvocation *context) -{ - tp_svc_channel_return_from_get_channel_type (context, - TP_IFACE_CHANNEL_TYPE_STREAM_TUBE); -} - -/** - * salut_tube_stream_get_handle - * - * Implements D-Bus method GetHandle - * on interface org.freedesktop.Telepathy.Channel - */ -static void -salut_tube_stream_get_handle (TpSvcChannel *iface, - DBusGMethodInvocation *context) -{ - SalutTubeStream *self = SALUT_TUBE_STREAM (iface); - SalutTubeStreamPrivate *priv = SALUT_TUBE_STREAM_GET_PRIVATE (self); - - tp_svc_channel_return_from_get_handle (context, priv->handle_type, - priv->handle); -} - -/** - * salut_tube_stream_get_interfaces - * - * Implements D-Bus method GetInterfaces - * on interface org.freedesktop.Telepathy.Channel - */ -static void -salut_tube_stream_get_interfaces (TpSvcChannel *iface, - DBusGMethodInvocation *context) -{ - SalutTubeStream *self = SALUT_TUBE_STREAM (iface); - SalutTubeStreamPrivate *priv = SALUT_TUBE_STREAM_GET_PRIVATE (self); - - if (priv->handle_type == TP_HANDLE_TYPE_CONTACT) - { - /* omit the Group interface */ - tp_svc_channel_return_from_get_interfaces (context, - salut_tube_stream_interfaces + 1); - } - else - { - tp_svc_channel_return_from_get_interfaces (context, - salut_tube_stream_interfaces); - } -} - static void destroy_socket_control_list (gpointer data) { @@ -2442,13 +2228,14 @@ salut_tube_stream_offer (SalutTubeStream *self, GError **error) { SalutTubeStreamPrivate *priv = SALUT_TUBE_STREAM_GET_PRIVATE (self); + TpBaseChannel *base = TP_BASE_CHANNEL (self); + TpBaseChannelClass *cls = TP_BASE_CHANNEL_GET_CLASS (base); g_assert (priv->state == TP_TUBE_CHANNEL_STATE_NOT_OFFERED); - if (priv->handle_type == TP_HANDLE_TYPE_CONTACT) + if (cls->target_handle_type == TP_HANDLE_TYPE_CONTACT) { priv->state = TP_TUBE_CHANNEL_STATE_REMOTE_PENDING; - salut_tubes_channel_send_iq_offer (priv->tubes_channel); tp_svc_channel_interface_tube_emit_tube_channel_state_changed ( self, TP_TUBE_CHANNEL_STATE_REMOTE_PENDING); @@ -2499,18 +2286,3 @@ streamtube_iface_init (gpointer g_iface, IMPLEMENT(accept,_async); #undef IMPLEMENT } - -static void -channel_iface_init (gpointer g_iface, - gpointer iface_data) -{ - TpSvcChannelClass *klass = (TpSvcChannelClass *) g_iface; - -#define IMPLEMENT(x, suffix) tp_svc_channel_implement_##x (\ - klass, salut_tube_stream_##x##suffix) - IMPLEMENT(close,_async); - IMPLEMENT(get_channel_type,); - IMPLEMENT(get_handle,); - IMPLEMENT(get_interfaces,); -#undef IMPLEMENT -} diff --git a/src/tube-stream.h b/src/tube-stream.h index fb908590..0594d20f 100644 --- a/src/tube-stream.h +++ b/src/tube-stream.h @@ -22,12 +22,12 @@ #include <glib-object.h> +#include <telepathy-glib/base-channel.h> #include <telepathy-glib/enums.h> #include <telepathy-glib/interfaces.h> #include "extensions/extensions.h" #include "connection.h" -#include "tubes-channel.h" G_BEGIN_DECLS @@ -35,13 +35,13 @@ typedef struct _SalutTubeStream SalutTubeStream; typedef struct _SalutTubeStreamClass SalutTubeStreamClass; struct _SalutTubeStreamClass { - GObjectClass parent_class; + TpBaseChannelClass parent_class; TpDBusPropertiesMixinClass dbus_props_class; }; struct _SalutTubeStream { - GObject parent; + TpBaseChannel parent; gpointer priv; }; @@ -65,12 +65,11 @@ GType salut_tube_stream_get_type (void); SalutTubeStreamClass)) SalutTubeStream *salut_tube_stream_new (SalutConnection *conn, - SalutTubesChannel *tubes_channel, TpHandle handle, TpHandleType handle_type, TpHandle self_handle, TpHandle initiator, gboolean offered, const gchar *service, - GHashTable *parameters, guint id, guint portnum, - WockyStanza *iq_req); + GHashTable *parameters, guint64 id, guint portnum, + WockyStanza *iq_req, gboolean requested); gboolean salut_tube_stream_check_params (TpSocketAddressType address_type, const GValue *address, TpSocketAccessControl access_control, diff --git a/src/tubes-channel.c b/src/tubes-channel.c deleted file mode 100644 index 289eb3b3..00000000 --- a/src/tubes-channel.c +++ /dev/null @@ -1,2598 +0,0 @@ -/* - * tubes-channel.c - Source for SalutTubesChannel - * Copyright (C) 2007 Collabora Ltd. - * - * 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 tubesplied 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 "tubes-channel.h" - -#include <stdio.h> -#include <stdlib.h> - -#include <glib.h> - -#ifdef G_OS_UNIX -#include <sys/socket.h> -#include <netdb.h> -#endif - -#include <errno.h> -#include <string.h> - -#include <dbus/dbus-glib.h> -#include <telepathy-glib/channel-iface.h> -#include <telepathy-glib/channel-manager.h> -#include <telepathy-glib/interfaces.h> -#include <telepathy-glib/dbus.h> -#include <telepathy-glib/exportable-channel.h> -#include <telepathy-glib/gtypes.h> -#include <telepathy-glib/svc-channel.h> -#include <telepathy-glib/svc-generic.h> - -#include <gibber/gibber-muc-connection.h> -#include <gibber/gibber-bytestream-muc.h> - -#define DEBUG_FLAG DEBUG_TUBES -#include "debug.h" -#include "extensions/extensions.h" -#include "util.h" -#include "connection.h" -#include "contact.h" -#include "muc-channel.h" -#include "muc-manager.h" -#include "tubes-manager.h" -#include "tube-iface.h" -#include "tube-dbus.h" -#include "tube-stream.h" - -#define SALUT_CHANNEL_TUBE_TYPE \ - (dbus_g_type_get_struct ("GValueArray", \ - G_TYPE_UINT, \ - G_TYPE_UINT, \ - G_TYPE_UINT, \ - G_TYPE_STRING, \ - dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE), \ - G_TYPE_UINT, \ - G_TYPE_INVALID)) - -#define DBUS_NAME_PAIR_TYPE \ - (dbus_g_type_get_struct ("GValueArray", \ - G_TYPE_UINT, G_TYPE_STRING, G_TYPE_INVALID)) - -static void channel_iface_init (gpointer g_iface, gpointer iface_data); -static void tubes_iface_init (gpointer g_iface, gpointer iface_data); - -G_DEFINE_TYPE_WITH_CODE (SalutTubesChannel, salut_tubes_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_EXPORTABLE_CHANNEL, NULL); - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_TYPE_TUBES, tubes_iface_init); - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_GROUP, - tp_external_group_mixin_iface_init); - G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_IFACE, NULL); -); - -/* Channel state */ -typedef enum -{ - CHANNEL_NOT_CONNECTED = 0, - CHANNEL_CONNECTING, - CHANNEL_CONNECTED, - CHANNEL_CLOSING, -} ChannelState; - -/* properties */ -static const char *salut_tubes_channel_interfaces[] = { - TP_IFACE_CHANNEL_INTERFACE_GROUP, - /* If more interfaces are added, either keep Group as the first, or change - * the implementations of salut_tubes_channel_get_interfaces () and - * salut_tubes_channel_get_property () too */ - NULL -}; - -enum -{ - PROP_OBJECT_PATH = 1, - PROP_CHANNEL_TYPE, - PROP_HANDLE_TYPE, - PROP_HANDLE, - PROP_CONNECTION, - PROP_MUC, - PROP_INTERFACES, - PROP_TARGET_ID, - PROP_REQUESTED, - PROP_INITIATOR_ID, - PROP_INITIATOR_HANDLE, - PROP_CHANNEL_DESTROYED, - PROP_CHANNEL_PROPERTIES, - - /* only for 1-1 tubes */ - PROP_CONTACT, - - LAST_PROPERTY -}; - -/* private structure */ -typedef struct _SalutTubesChannelPrivate SalutTubesChannelPrivate; - -struct _SalutTubesChannelPrivate -{ - SalutConnection *conn; - gchar *object_path; - TpHandle handle; - TpHandleType handle_type; - TpHandle self_handle; - TpHandle initiator; - gboolean requested; - /* Used for MUC tubes channel only */ - GibberMucConnection *muc_connection; - - /* Used for 1-1 tubes channel */ - SalutContact *contact; - ChannelState state; - - /* guint tube_id -> SalutTubeDBus tube */ - GHashTable *tubes; - - gboolean closed; - gboolean dispose_has_run; -}; - -#define SALUT_TUBES_CHANNEL_GET_PRIVATE(obj) \ - ((SalutTubesChannelPrivate *) ((SalutTubesChannel *) obj)->priv) - -static gboolean update_tubes_info (SalutTubesChannel *self); -static void muc_connection_lost_senders_cb (GibberMucConnection *conn, - GArray *senders, gpointer user_data); -static void muc_connection_new_senders_cb (GibberMucConnection *conn, - GArray *senders, gpointer user_data); -static gboolean extract_tube_information (SalutTubesChannel *self, - WockyNode *tube_node, TpTubeType *type, TpHandle *initiator_handle, - const gchar **service, GHashTable **parameters, guint *tube_id); -static SalutTubeIface * create_new_tube (SalutTubesChannel *self, - TpTubeType type, TpHandle initiator, gboolean offered, - const gchar *service, GHashTable *parameters, guint tube_id, guint portnum, - WockyStanza *iq_req); - -static void -salut_tubes_channel_init (SalutTubesChannel *self) -{ - SalutTubesChannelPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self, - SALUT_TYPE_TUBES_CHANNEL, SalutTubesChannelPrivate); - - self->priv = priv; - - priv->tubes = g_hash_table_new_full (g_direct_hash, g_direct_equal, - NULL, (GDestroyNotify) g_object_unref); - - priv->contact = NULL; - priv->state = CHANNEL_NOT_CONNECTED; - - priv->dispose_has_run = FALSE; - priv->closed = FALSE; -} - -static GObject * -salut_tubes_channel_constructor (GType type, - guint n_props, - GObjectConstructParam *props) -{ - GObject *obj; - SalutTubesChannel *self; - SalutTubesChannelPrivate *priv; - TpDBusDaemon *bus; - TpBaseConnection *base_conn; - - obj = G_OBJECT_CLASS (salut_tubes_channel_parent_class)-> - constructor (type, n_props, props); - - self = SALUT_TUBES_CHANNEL (obj); - priv = SALUT_TUBES_CHANNEL_GET_PRIVATE (self); - - base_conn = TP_BASE_CONNECTION (priv->conn); - - switch (priv->handle_type) - { - case TP_HANDLE_TYPE_CONTACT: - g_assert (self->muc == NULL); - priv->self_handle = ((TpBaseConnection *) - (priv->conn))->self_handle; - break; - - case TP_HANDLE_TYPE_ROOM: - g_assert (self->muc != NULL); - priv->self_handle = self->muc->group.self_handle; - tp_external_group_mixin_init (obj, (GObject *) self->muc); - g_object_get (self->muc, - "muc-connection", &(priv->muc_connection), - NULL); - g_assert (priv->muc_connection != NULL); - - g_signal_connect (priv->muc_connection, "new-senders", - G_CALLBACK (muc_connection_new_senders_cb), self); - g_signal_connect (priv->muc_connection, "lost-senders", - G_CALLBACK (muc_connection_lost_senders_cb), self); - - break; - default: - g_assert_not_reached (); - } - - /* Connect to the bus */ - bus = tp_base_connection_get_dbus_daemon (base_conn); - tp_dbus_daemon_register_object (bus, priv->object_path, obj); - - DEBUG ("Registering at '%s'", priv->object_path); - - return obj; -} - -static void -salut_tubes_channel_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - SalutTubesChannel *chan = SALUT_TUBES_CHANNEL (object); - SalutTubesChannelPrivate *priv = SALUT_TUBES_CHANNEL_GET_PRIVATE (chan); - - switch (property_id) - { - case PROP_OBJECT_PATH: - g_value_set_string (value, priv->object_path); - break; - case PROP_CHANNEL_TYPE: - g_value_set_static_string (value, TP_IFACE_CHANNEL_TYPE_TUBES); - break; - case PROP_HANDLE_TYPE: - g_value_set_uint (value, priv->handle_type); - break; - case PROP_HANDLE: - g_value_set_uint (value, priv->handle); - break; - case PROP_CONNECTION: - g_value_set_object (value, priv->conn); - break; - case PROP_MUC: - g_value_set_object (value, chan->muc); - break; - case PROP_CONTACT: - g_value_set_object (value, priv->contact); - break; - case PROP_INTERFACES: - if (chan->muc) - g_value_set_static_boxed (value, salut_tubes_channel_interfaces); - else - g_value_set_static_boxed (value, salut_tubes_channel_interfaces + 1); - break; - case PROP_TARGET_ID: - { - TpHandleRepoIface *repo = tp_base_connection_get_handles ( - (TpBaseConnection *) priv->conn, priv->handle_type); - - g_value_set_string (value, tp_handle_inspect (repo, priv->handle)); - } - break; - case PROP_INITIATOR_HANDLE: - g_assert (priv->initiator != 0); - g_value_set_uint (value, priv->initiator); - break; - case PROP_INITIATOR_ID: - { - TpHandleRepoIface *repo = tp_base_connection_get_handles ( - (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT); - - g_assert (priv->initiator != 0); - g_value_set_string (value, tp_handle_inspect (repo, priv->initiator)); - } - break; - case PROP_REQUESTED: - g_value_set_boolean (value, priv->requested); - break; - case PROP_CHANNEL_DESTROYED: - g_value_set_boolean (value, priv->closed); - break; - case PROP_CHANNEL_PROPERTIES: - g_value_take_boxed (value, - tp_dbus_properties_mixin_make_properties_hash (object, - TP_IFACE_CHANNEL, "TargetHandle", - TP_IFACE_CHANNEL, "TargetHandleType", - TP_IFACE_CHANNEL, "ChannelType", - TP_IFACE_CHANNEL, "TargetID", - TP_IFACE_CHANNEL, "InitiatorHandle", - TP_IFACE_CHANNEL, "InitiatorID", - TP_IFACE_CHANNEL, "Requested", - TP_IFACE_CHANNEL, "Interfaces", - NULL)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -salut_tubes_channel_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - SalutTubesChannel *chan = SALUT_TUBES_CHANNEL (object); - SalutTubesChannelPrivate *priv = SALUT_TUBES_CHANNEL_GET_PRIVATE (chan); - const gchar *value_str; - - switch (property_id) - { - case PROP_OBJECT_PATH: - g_free (priv->object_path); - priv->object_path = g_value_dup_string (value); - break; - case PROP_CHANNEL_TYPE: - /* this property is writable in the interface (in - * telepathy-glib > 0.7.0), but not actually - * meaningfully changeable on this channel, so we do nothing */ - value_str = g_value_get_string (value); - g_assert (value_str == NULL || !tp_strdiff (value_str, - TP_IFACE_CHANNEL_TYPE_TUBES)); - break; - case PROP_HANDLE_TYPE: - priv->handle_type = g_value_get_uint (value); - break; - case PROP_HANDLE: - priv->handle = g_value_get_uint (value); - break; - case PROP_CONNECTION: - priv->conn = g_value_get_object (value); - break; - case PROP_MUC: - chan->muc = g_value_get_object (value); - break; - case PROP_CONTACT: - priv->contact = g_value_get_object (value); - /* contact is set only for 1-1 tubes */ - if (priv->contact != NULL) - g_object_ref (priv->contact); - break; - case PROP_INITIATOR_HANDLE: - priv->initiator = g_value_get_uint (value); - g_assert (priv->initiator != 0); - break; - case PROP_REQUESTED: - priv->requested = g_value_get_boolean (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -setup_connection (SalutTubesChannel *self) -{ - SalutTubesChannelPrivate *priv = SALUT_TUBES_CHANNEL_GET_PRIVATE (self); - - DEBUG ("setting up the tubes channel"); - - if (priv->state == CHANNEL_CONNECTING) - return; - - priv->state = CHANNEL_CONNECTED; - DEBUG ("priv->state = CHANNEL_CONNECTED"); - salut_tubes_channel_send_iq_offer (self); -} - -static void -d_bus_names_changed_added (SalutTubesChannel *self, - guint tube_id, - TpHandle contact, - const gchar *new_name) -{ - GPtrArray *added = g_ptr_array_sized_new (1); - GArray *removed = g_array_new (FALSE, FALSE, sizeof (guint)); - GValue tmp = {0,}; - guint i; - - g_value_init (&tmp, DBUS_NAME_PAIR_TYPE); - g_value_take_boxed (&tmp, - dbus_g_type_specialized_construct (DBUS_NAME_PAIR_TYPE)); - dbus_g_type_struct_set (&tmp, - 0, contact, - 1, new_name, - G_MAXUINT); - g_ptr_array_add (added, g_value_get_boxed (&tmp)); - - tp_svc_channel_type_tubes_emit_d_bus_names_changed (self, - tube_id, added, removed); - - for (i = 0; i < added->len; i++) - g_boxed_free (DBUS_NAME_PAIR_TYPE, added->pdata[i]); - g_ptr_array_unref (added); - g_array_unref (removed); -} - -static void -d_bus_names_changed_removed (SalutTubesChannel *self, - guint tube_id, - TpHandle contact) -{ - SalutTubesChannelPrivate *priv = SALUT_TUBES_CHANNEL_GET_PRIVATE (self); - GPtrArray *added; - GArray *removed; - - if (priv->handle_type == TP_HANDLE_TYPE_CONTACT) - return; - - added = g_ptr_array_new (); - removed = g_array_new (FALSE, FALSE, sizeof (guint)); - - g_array_append_val (removed, contact); - - tp_svc_channel_type_tubes_emit_d_bus_names_changed (self, - tube_id, added, removed); - - g_ptr_array_unref (added); - g_array_unref (removed); -} - -static void -add_name_in_dbus_names (SalutTubesChannel *self, - guint tube_id, - TpHandle handle, - const gchar *dbus_name) -{ - SalutTubesChannelPrivate *priv = SALUT_TUBES_CHANNEL_GET_PRIVATE (self); - SalutTubeDBus *tube; - - if (priv->handle_type == TP_HANDLE_TYPE_CONTACT) - return; - - tube = g_hash_table_lookup (priv->tubes, GUINT_TO_POINTER (tube_id)); - if (tube == NULL) - return; - - if (salut_tube_dbus_add_name (tube, handle, dbus_name)) - { - /* Emit the DBusNamesChanged signal */ - d_bus_names_changed_added (self, tube_id, handle, dbus_name); - } -} - -static void -add_yourself_in_dbus_names (SalutTubesChannel *self, - guint tube_id) -{ - SalutTubesChannelPrivate *priv = SALUT_TUBES_CHANNEL_GET_PRIVATE (self); - SalutTubeDBus *tube; - gchar *dbus_name; - - if (priv->handle_type == TP_HANDLE_TYPE_CONTACT) - return; - - tube = g_hash_table_lookup (priv->tubes, GUINT_TO_POINTER (tube_id)); - if (tube == NULL) - return; - - g_object_get (tube, - "dbus-name", &dbus_name, - NULL); - - add_name_in_dbus_names (self, tube_id, priv->self_handle, dbus_name); - - g_free (dbus_name); -} - -/** - * salut_tubes_channel_get_available_tube_types - * - * Implements D-Bus method GetAvailableTubeTypes - * on org.freedesktop.Telepathy.Channel.Type.Tubes - */ -static void -salut_tubes_channel_get_available_tube_types (TpSvcChannelTypeTubes *iface, - DBusGMethodInvocation *context) -{ - SalutTubesChannel *self = SALUT_TUBES_CHANNEL (iface); - GArray *ret; - TpTubeType type; - - g_assert (SALUT_IS_TUBES_CHANNEL (self)); - - ret = g_array_sized_new (FALSE, FALSE, sizeof (TpTubeType), 1); - type = TP_TUBE_TYPE_DBUS; - g_array_append_val (ret, type); - type = TP_TUBE_TYPE_STREAM; - g_array_append_val (ret, type); - - tp_svc_channel_type_tubes_return_from_get_available_tube_types (context, - ret); - - g_array_unref (ret); -} - -struct _add_in_old_dbus_tubes_data -{ - GHashTable *old_dbus_tubes; - TpHandle contact; -}; - -static void -add_in_old_dbus_tubes (gpointer key, - gpointer value, - gpointer user_data) -{ - guint tube_id = GPOINTER_TO_UINT (key); - SalutTubeIface *tube = SALUT_TUBE_IFACE (value); - struct _add_in_old_dbus_tubes_data *data = - (struct _add_in_old_dbus_tubes_data *) user_data; - TpTubeType type; - - g_object_get (tube, "type", &type, NULL); - - if (type != TP_TUBE_TYPE_DBUS) - return; - - if (salut_tube_dbus_handle_in_names (SALUT_TUBE_DBUS (tube), - data->contact)) - { - /* contact was in this tube */ - g_hash_table_insert (data->old_dbus_tubes, GUINT_TO_POINTER (tube_id), - tube); - } -} - -struct -emit_d_bus_names_changed_foreach_data -{ - SalutTubesChannel *self; - TpHandle contact; -}; - -static void -emit_d_bus_names_changed_foreach (gpointer key, - gpointer value, - gpointer user_data) -{ - guint tube_id = GPOINTER_TO_UINT (key); - SalutTubeDBus *tube = SALUT_TUBE_DBUS (value); - struct emit_d_bus_names_changed_foreach_data *data = - (struct emit_d_bus_names_changed_foreach_data *) user_data; - SalutTubesChannelPrivate *priv = SALUT_TUBES_CHANNEL_GET_PRIVATE ( - data->self); - - if (salut_tube_dbus_remove_name (tube, data->contact)) - { - /* Emit the DBusNamesChanged signal */ - d_bus_names_changed_removed (data->self, tube_id, data->contact); - } - - /* Remove the contact as sender in the muc bytestream */ - if (priv->handle_type == TP_HANDLE_TYPE_ROOM) - { - GibberBytestreamIface *bytestream; - - g_object_get (tube, "bytestream", &bytestream, NULL); - g_assert (bytestream != NULL); - - if (GIBBER_IS_BYTESTREAM_MUC (bytestream)) - { - TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT); - const gchar *sender; - - sender = tp_handle_inspect (contact_repo, data->contact); - if (sender != NULL) - gibber_bytestream_muc_remove_sender ( - GIBBER_BYTESTREAM_MUC (bytestream), sender); - } - - g_object_unref (bytestream); - } -} - -/* MUC message */ -/* Return an array containing all the SalutTubeIface * channels that have been - * created due to this message. These channels have not been announced yet - * so it's the responsability of the caller to announce them. */ -GPtrArray * -salut_tubes_channel_muc_message_received (SalutTubesChannel *self, - const gchar *sender, - WockyStanza *stanza) -{ - SalutTubesChannelPrivate *priv = SALUT_TUBES_CHANNEL_GET_PRIVATE (self); - TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT); - TpHandle contact; - WockyNode *top_node = wocky_stanza_get_top_node (stanza); - WockyNode *tubes_node; - GSList *l; - GHashTable *old_dbus_tubes; - struct _add_in_old_dbus_tubes_data add_data; - struct emit_d_bus_names_changed_foreach_data emit_data; - WockyStanzaType stanza_type; - WockyStanzaSubType sub_type; - GPtrArray *result = g_ptr_array_new (); - - contact = tp_handle_lookup (contact_repo, sender, NULL, NULL); - g_assert (contact != 0); - - if (contact == priv->self_handle) - /* We don't need to inspect our own tubes */ - return result; - - wocky_stanza_get_type_info (stanza, &stanza_type, &sub_type); - if (stanza_type != WOCKY_STANZA_TYPE_MESSAGE - || sub_type != WOCKY_STANZA_SUB_TYPE_GROUPCHAT) - return result; - - tubes_node = wocky_node_get_child_ns (top_node, "tubes", - WOCKY_TELEPATHY_NS_TUBES); - g_assert (tubes_node != NULL); - - /* Fill old_dbus_tubes with D-BUS tubes previoulsy announced by - * the contact */ - old_dbus_tubes = g_hash_table_new (g_direct_hash, g_direct_equal); - add_data.old_dbus_tubes = old_dbus_tubes; - add_data.contact = contact; - g_hash_table_foreach (priv->tubes, add_in_old_dbus_tubes, &add_data); - - for (l = tubes_node->children; l != NULL; l = l->next) - { - WockyNode *tube_node = (WockyNode *) l->data; - const gchar *stream_id; - SalutTubeIface *tube = NULL; - guint tube_id; - TpTubeType type; - - stream_id = wocky_node_get_attribute (tube_node, "stream-id"); - - if (!extract_tube_information (self, tube_node, NULL, - NULL, NULL, NULL, &tube_id)) - { - DEBUG ("can't find a tube ID; never mind then."); - continue; - } - - tube = g_hash_table_lookup (priv->tubes, GUINT_TO_POINTER (tube_id)); - - if (tube == NULL) - { - /* We don't know yet this tube */ - const gchar *service; - TpHandle initiator_handle; - GHashTable *parameters; - guint id; - - if (extract_tube_information (self, tube_node, &type, - &initiator_handle, &service, ¶meters, &id)) - { - switch (type) - { - case TP_TUBE_TYPE_DBUS: - { - if (initiator_handle == 0) - { - DEBUG ("D-Bus tube initiator missing"); - /* skip to the next child of <tubes> */ - continue; - } - } - break; - case TP_TUBE_TYPE_STREAM: - { - initiator_handle = contact; - } - break; - default: - { - g_assert_not_reached (); - } - } - - tube = create_new_tube (self, type, initiator_handle, FALSE, - service, parameters, id, 0, NULL); - g_ptr_array_add (result, tube); - - /* the tube has reffed its initiator, no need to keep a ref */ - g_hash_table_unref (parameters); - } - } - else - { - /* The contact is in the tube. - * Remove it from old_dbus_tubes if needed */ - g_hash_table_remove (old_dbus_tubes, GUINT_TO_POINTER (tube_id)); - } - - if (tube == NULL) - continue; - - g_object_get (tube, "type", &type, NULL); - - if (type == TP_TUBE_TYPE_DBUS) - { - /* Update mapping of handle -> D-Bus name. */ - if (!salut_tube_dbus_handle_in_names (SALUT_TUBE_DBUS (tube), - contact)) - { - /* Contact just joined the tube */ - const gchar *new_name; - - new_name = wocky_node_get_attribute (tube_node, - "dbus-name"); - - if (!new_name) - { - DEBUG ("Contact %u isn't announcing their D-Bus name", - contact); - continue; - } - - add_name_in_dbus_names (self, tube_id, contact, new_name); - - /* associate the contact with his stream id */ - if (priv->handle_type == TP_HANDLE_TYPE_ROOM) - { - GibberBytestreamIface *bytestream; - - g_object_get (tube, "bytestream", &bytestream, NULL); - g_assert (bytestream != NULL); - - if (GIBBER_IS_BYTESTREAM_MUC (bytestream)) - { - guint16 tmp = (guint16) atoi (stream_id); - - gibber_bytestream_muc_add_sender ( - GIBBER_BYTESTREAM_MUC (bytestream), sender, tmp); - } - - g_object_unref (bytestream); - } - } - } - } - - /* Tubes remaining in old_dbus_tubes was left by the contact */ - emit_data.contact = contact; - emit_data.self = self; - g_hash_table_foreach (old_dbus_tubes, emit_d_bus_names_changed_foreach, - &emit_data); - - g_hash_table_unref (old_dbus_tubes); - - return result; -} - -/* 1-1 message */ - -/* Return a newly created SalutTubeIface channel if it has been created - * due to this message. This channel has not been announced yet - * so it's the responsability of the caller to announce it. */ -SalutTubeIface * -salut_tubes_channel_message_received (SalutTubesChannel *self, - const gchar *service, - TpTubeType tube_type, - TpHandle initiator_handle, - GHashTable *parameters, - guint tube_id, - guint portnum, - WockyStanza *iq_req) -{ - SalutTubesChannelPrivate *priv = SALUT_TUBES_CHANNEL_GET_PRIVATE (self); - SalutTubeIface *tube; - - /* do we already know this tube? */ - tube = g_hash_table_lookup (priv->tubes, GUINT_TO_POINTER (tube_id)); - if (tube == NULL) - { - tube = create_new_tube (self, tube_type, initiator_handle, FALSE, - service, parameters, tube_id, portnum, iq_req); - return tube; - } - - return NULL; -} - -void -salut_tubes_channel_message_close_received (SalutTubesChannel *self, - TpHandle initiator_handle, - guint tube_id) -{ - SalutTubesChannelPrivate *priv = SALUT_TUBES_CHANNEL_GET_PRIVATE (self); - - SalutTubeIface *tube; - - tube = g_hash_table_lookup (priv->tubes, GUINT_TO_POINTER (tube_id)); - - if (tube) - { - DEBUG ("received a tube close message"); - salut_tube_iface_close (tube, TRUE); - } - else - { - DEBUG ("received a tube close message on a non existent tube"); - } -} - -static gint -generate_tube_id (void) -{ - return g_random_int_range (0, G_MAXINT); -} - -SalutTubeIface * -salut_tubes_channel_tube_request (SalutTubesChannel *self, - gpointer request_token, - GHashTable *request_properties, - gboolean require_new) -{ - SalutTubesChannelPrivate *priv = SALUT_TUBES_CHANNEL_GET_PRIVATE (self); - SalutTubeIface *tube; - const gchar *channel_type; - const gchar *service; - guint tube_id; - TpTubeType type; - GHashTable *parameters; - - tube_id = generate_tube_id (); - - channel_type = tp_asv_get_string (request_properties, - TP_IFACE_CHANNEL ".ChannelType"); - - if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_STREAM_TUBE)) - { - type = TP_TUBE_TYPE_STREAM; - service = tp_asv_get_string (request_properties, - TP_IFACE_CHANNEL_TYPE_STREAM_TUBE ".Service"); - - } - else if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_DBUS_TUBE)) - { - type = TP_TUBE_TYPE_DBUS; - service = tp_asv_get_string (request_properties, - TP_IFACE_CHANNEL_TYPE_DBUS_TUBE ".ServiceName"); - } - else - g_assert_not_reached (); - - /* if the service property is missing, the requestotron rejects the request - */ - g_assert (service != NULL); - - DEBUG ("Request a tube channel with type='%s' and service='%s'", - channel_type, service); - - /* requested tubes have an empty parameters dict */ - parameters = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, - (GDestroyNotify) tp_g_value_slice_free); - - tube = create_new_tube (self, type, priv->self_handle, FALSE, service, - parameters, tube_id, 0, NULL); - - g_hash_table_unref (parameters); - return tube; -} - -static void -muc_connection_new_senders_cb (GibberMucConnection *conn, - GArray *senders, - gpointer user_data) -{ - SalutTubesChannel *self = SALUT_TUBES_CHANNEL (user_data); - - update_tubes_info (self); -} - -static void -muc_connection_lost_senders_cb (GibberMucConnection *conn, - GArray *senders, - gpointer user_data) -{ - SalutTubesChannel *self = SALUT_TUBES_CHANNEL (user_data); - SalutTubesChannelPrivate *priv = SALUT_TUBES_CHANNEL_GET_PRIVATE (self); - TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT); - guint i; - - for (i = 0; i < senders->len; i++) - { - gchar *sender; - TpHandle contact; - GHashTable *old_dbus_tubes; - struct _add_in_old_dbus_tubes_data add_data; - struct emit_d_bus_names_changed_foreach_data emit_data; - - sender = g_array_index (senders, gchar *, i); - - contact = tp_handle_lookup (contact_repo, sender, NULL, NULL); - if (contact == 0) - { - DEBUG ("unknown sender: %s", sender); - return; - } - - old_dbus_tubes = g_hash_table_new (g_direct_hash, g_direct_equal); - add_data.old_dbus_tubes = old_dbus_tubes; - add_data.contact = contact; - g_hash_table_foreach (priv->tubes, add_in_old_dbus_tubes, &add_data); - - /* contact left the muc so he left all its tubes */ - emit_data.contact = contact; - emit_data.self = self; - g_hash_table_foreach (old_dbus_tubes, emit_d_bus_names_changed_foreach, - &emit_data); - - g_hash_table_unref (old_dbus_tubes); - } -} - -static void -copy_tube_in_ptr_array (gpointer key, - gpointer value, - gpointer user_data) -{ - SalutTubeIface *tube = (SalutTubeIface *) value; - guint tube_id = GPOINTER_TO_UINT(key); - TpHandle initiator; - gchar *service; - GHashTable *parameters; - TpTubeChannelState state; - TpTubeType type; - GPtrArray *array = (GPtrArray *) user_data; - GValue entry = {0,}; - - g_object_get (tube, - "type", &type, - "initiator-handle", &initiator, - "service", &service, - "parameters", ¶meters, - "state", &state, - NULL); - - g_value_init (&entry, SALUT_CHANNEL_TUBE_TYPE); - g_value_take_boxed (&entry, - dbus_g_type_specialized_construct (SALUT_CHANNEL_TUBE_TYPE)); - dbus_g_type_struct_set (&entry, - 0, tube_id, - 1, initiator, - 2, type, - 3, service, - 4, parameters, - 5, state, - G_MAXUINT); - - g_ptr_array_add (array, g_value_get_boxed (&entry)); - g_free (service); - g_hash_table_unref (parameters); -} - -static GPtrArray * -make_tubes_ptr_array (SalutTubesChannel *self, - GHashTable *tubes) -{ - GPtrArray *ret; - - ret = g_ptr_array_sized_new (g_hash_table_size (tubes)); - - g_hash_table_foreach (tubes, copy_tube_in_ptr_array, ret); - - return ret; -} - -/** - * salut_tubes_channel_list_tubes - * - * Implements D-Bus method ListTubes - * on org.freedesktop.Telepathy.Channel.Type.Tubes - */ -static void -salut_tubes_channel_list_tubes (TpSvcChannelTypeTubes *iface, - DBusGMethodInvocation *context) -{ - SalutTubesChannel *self = SALUT_TUBES_CHANNEL (iface); - SalutTubesChannelPrivate *priv; - GPtrArray *ret; - guint i; - - g_assert (SALUT_IS_TUBES_CHANNEL (self)); - - priv = SALUT_TUBES_CHANNEL_GET_PRIVATE (self); - - ret = make_tubes_ptr_array (self, priv->tubes); - tp_svc_channel_type_tubes_return_from_list_tubes (context, ret); - - for (i = 0; i < ret->len; i++) - g_boxed_free (SALUT_CHANNEL_TUBE_TYPE, ret->pdata[i]); - - g_ptr_array_unref (ret); -} - -static void -tube_closed_cb (SalutTubeIface *tube, - gpointer user_data) -{ - SalutTubesChannel *self = SALUT_TUBES_CHANNEL (user_data); - SalutTubesChannelPrivate *priv = SALUT_TUBES_CHANNEL_GET_PRIVATE (self); - guint tube_id; - TpChannelManager *mgr; - - if (priv->closed) - return; - - g_object_get (tube, "id", &tube_id, NULL); - if (!g_hash_table_remove (priv->tubes, GUINT_TO_POINTER (tube_id))) - { - DEBUG ("Can't find tube having this id: %d", tube_id); - } - - DEBUG ("tube %d removed", tube_id); - - if (priv->handle_type == TP_HANDLE_TYPE_ROOM && SALUT_IS_TUBE_DBUS (tube)) - { - /* Emit the DBusNamesChanged signal */ - d_bus_names_changed_removed (self, tube_id, priv->self_handle); - } - - update_tubes_info (self); - - tp_svc_channel_type_tubes_emit_tube_closed (self, tube_id); - tp_svc_channel_emit_closed (tube); - - if (priv->handle_type == TP_HANDLE_TYPE_CONTACT) - { - g_object_get (priv->conn, "tubes-manager", &mgr, NULL); - } - else - { - g_object_get (priv->conn, "muc-manager", &mgr, NULL); - } - - tp_channel_manager_emit_channel_closed_for_object (mgr, - TP_EXPORTABLE_CHANNEL (tube)); - - g_object_unref (mgr); -} - -static void -tube_opened_cb (SalutTubeIface *tube, - gpointer user_data) -{ - SalutTubesChannel *self = SALUT_TUBES_CHANNEL (user_data); - guint tube_id; - TpTubeType type; - - g_object_get (tube, - "id", &tube_id, - "type", &type, - NULL); - - if (type == TP_TUBE_TYPE_DBUS) - { - add_yourself_in_dbus_names (self, tube_id); - } - - update_tubes_info (self); - - tp_svc_channel_type_tubes_emit_tube_state_changed (self, tube_id, - TP_TUBE_STATE_OPEN); -} - -static void -tube_offered_cb (SalutTubeIface *tube, - gpointer user_data) -{ - SalutTubesChannel *self = SALUT_TUBES_CHANNEL (user_data); - guint tube_id; - TpHandle initiator; - TpTubeType type; - gchar *service; - GHashTable *parameters; - TpTubeState state; - - g_object_get (tube, - "id", &tube_id, - "initiator-handle", &initiator, - "type", &type, - "service", &service, - "parameters", ¶meters, - "state", &state, - NULL); - - /* tube has been offered and so can be announced using the old API */ - tp_svc_channel_type_tubes_emit_new_tube (self, - tube_id, - initiator, - type, - service, - parameters, - state); - - update_tubes_info (self); - - g_free (service); - g_hash_table_unref (parameters); -} - -static SalutTubeIface * -create_new_tube (SalutTubesChannel *self, - TpTubeType type, - TpHandle initiator, - gboolean offered, - const gchar *service, - GHashTable *parameters, - guint tube_id, - guint portnum, - WockyStanza *iq_req) -{ - SalutTubesChannelPrivate *priv = SALUT_TUBES_CHANNEL_GET_PRIVATE (self); - SalutTubeIface *tube; - TpTubeChannelState state; - GibberMucConnection *muc_connection = NULL; - - if (self->muc != NULL) - g_object_get (self->muc, "muc-connection", &muc_connection, NULL); - - switch (type) - { - case TP_TUBE_TYPE_DBUS: - tube = SALUT_TUBE_IFACE (salut_tube_dbus_new (priv->conn, self, - priv->handle, priv->handle_type, priv->self_handle, muc_connection, - initiator, service, parameters, tube_id)); - break; - case TP_TUBE_TYPE_STREAM: - tube = SALUT_TUBE_IFACE (salut_tube_stream_new (priv->conn, self, - priv->handle, priv->handle_type, - priv->self_handle, initiator, offered, service, parameters, - tube_id, portnum, iq_req)); - break; - default: - g_assert_not_reached (); - } - - DEBUG ("create tube %u", tube_id); - g_hash_table_insert (priv->tubes, GUINT_TO_POINTER (tube_id), tube); - - g_object_get (tube, "state", &state, NULL); - - /* The old API doesn't know the "not offered" state, so we have to wait that - * the tube is offered before announcing it. */ - if (state != TP_TUBE_CHANNEL_STATE_NOT_OFFERED) - { - tp_svc_channel_type_tubes_emit_new_tube (self, - tube_id, - initiator, - type, - service, - parameters, - state); - } - - g_signal_connect (tube, "tube-opened", G_CALLBACK (tube_opened_cb), self); - g_signal_connect (tube, "tube-closed", G_CALLBACK (tube_closed_cb), self); - g_signal_connect (tube, "tube-offered", G_CALLBACK (tube_offered_cb), self); - - if (muc_connection != NULL) - g_object_unref (muc_connection); - - return tube; -} - -/* tube_node is a MUC <message> */ -static gboolean -extract_tube_information (SalutTubesChannel *self, - WockyNode *tube_node, - TpTubeType *type, - TpHandle *initiator_handle, - const gchar **service, - GHashTable **parameters, - guint *tube_id) -{ - SalutTubesChannelPrivate *priv = SALUT_TUBES_CHANNEL_GET_PRIVATE (self); - TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT); - - if (type != NULL) - { - const gchar *_type; - - _type = wocky_node_get_attribute (tube_node, "type"); - - - if (!tp_strdiff (_type, "stream")) - { - *type = TP_TUBE_TYPE_STREAM; - } - else if (!tp_strdiff (_type, "dbus")) - { - *type = TP_TUBE_TYPE_DBUS; - } - else - { - DEBUG ("Unknown tube type: %s", _type); - return FALSE; - } - } - - if (initiator_handle != NULL) - { - const gchar *initiator; - - initiator = wocky_node_get_attribute (tube_node, "initiator"); - - if (initiator != NULL) - { - *initiator_handle = tp_handle_ensure (contact_repo, initiator, NULL, - NULL); - - if (*initiator_handle == 0) - { - DEBUG ("invalid initiator ID %s", initiator); - return FALSE; - } - } - else - { - *initiator_handle = 0; - } - } - - if (service != NULL) - { - *service = wocky_node_get_attribute (tube_node, "service"); - } - - if (parameters != NULL) - { - WockyNode *node; - - node = wocky_node_get_child (tube_node, "parameters"); - *parameters = salut_wocky_node_extract_properties (node, - "parameter"); - } - - if (tube_id != NULL) - { - const gchar *str; - gchar *endptr; - long int tmp; - - str = wocky_node_get_attribute (tube_node, "id"); - if (str == NULL) - { - DEBUG ("no tube id in SI request"); - return FALSE; - } - - tmp = strtol (str, &endptr, 10); - if (!endptr || *endptr) - { - DEBUG ("tube id is not numeric: %s", str); - return FALSE; - } - *tube_id = (int) tmp; - } - - return TRUE; -} - -static void -publish_tube_in_node (SalutTubesChannel *self, - WockyNode *node, - SalutTubeIface *tube) -{ - SalutTubesChannelPrivate *priv = SALUT_TUBES_CHANNEL_GET_PRIVATE (self); - WockyNode *parameters_node; - GHashTable *parameters; - TpTubeType type; - gchar *service, *id_str; - guint tube_id; - TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT); - TpHandle initiator_handle; - - g_object_get (G_OBJECT (tube), - "type", &type, - "initiator-handle", &initiator_handle, - "service", &service, - "parameters", ¶meters, - "id", &tube_id, - NULL); - - id_str = g_strdup_printf ("%u", tube_id); - - wocky_node_set_attribute (node, "service", service); - wocky_node_set_attribute (node, "id", id_str); - - g_free (id_str); - - switch (type) - { - case TP_TUBE_TYPE_DBUS: - { - gchar *name, *stream_id; - - g_object_get (G_OBJECT (tube), - "dbus-name", &name, - "stream-id", &stream_id, - NULL); - - wocky_node_set_attribute (node, "type", "dbus"); - wocky_node_set_attribute (node, "stream-id", stream_id); - wocky_node_set_attribute (node, "initiator", - tp_handle_inspect (contact_repo, initiator_handle)); - - if (name != NULL) - wocky_node_set_attribute (node, "dbus-name", name); - - g_free (name); - g_free (stream_id); - - } - break; - case TP_TUBE_TYPE_STREAM: - wocky_node_set_attribute (node, "type", "stream"); - break; - default: - g_assert_not_reached (); - } - - parameters_node = wocky_node_add_child (node, "parameters"); - salut_wocky_node_add_children_from_properties (parameters_node, - parameters, "parameter"); - - g_free (service); - g_hash_table_unref (parameters); -} - -struct _i_hate_g_hash_table_foreach -{ - SalutTubesChannel *self; - WockyNode *tubes_node; -}; - -static void -publish_tubes_in_node (gpointer key, - gpointer value, - gpointer user_data) -{ - SalutTubeIface *tube = (SalutTubeIface *) value; - struct _i_hate_g_hash_table_foreach *data = - (struct _i_hate_g_hash_table_foreach *) user_data; - SalutTubesChannelPrivate *priv = SALUT_TUBES_CHANNEL_GET_PRIVATE ( - data->self); - TpTubeChannelState state; - WockyNode *tube_node; - TpTubeType type; - TpHandle initiator; - - if (tube == NULL) - return; - - g_object_get (tube, - "state", &state, - "type", &type, - "initiator-handle", &initiator, - NULL); - - if (state != TP_TUBE_CHANNEL_STATE_OPEN) - return; - - if (type == TP_TUBE_TYPE_STREAM && initiator != priv->self_handle) - /* We only announce stream tubes we initiated */ - return; - - tube_node = wocky_node_add_child (data->tubes_node, "tube"); - publish_tube_in_node (data->self, tube_node, tube); -} - -static gboolean -update_tubes_info (SalutTubesChannel *self) -{ - SalutTubesChannelPrivate *priv = SALUT_TUBES_CHANNEL_GET_PRIVATE (self); - TpBaseConnection *conn = (TpBaseConnection *) priv->conn; - TpHandleRepoIface *room_repo = tp_base_connection_get_handles ( - conn, TP_HANDLE_TYPE_ROOM); - WockyStanza *msg; - WockyNode *msg_node; - WockyNode *node; - const gchar *jid; - struct _i_hate_g_hash_table_foreach data; - GError *error = NULL; - - if (priv->handle_type != TP_HANDLE_TYPE_ROOM) - return FALSE; - - /* build the message */ - jid = tp_handle_inspect (room_repo, priv->handle); - - msg = wocky_stanza_build (WOCKY_STANZA_TYPE_MESSAGE, - WOCKY_STANZA_SUB_TYPE_GROUPCHAT, - priv->conn->name, jid, - WOCKY_NODE_START, "tubes", - WOCKY_NODE_XMLNS, WOCKY_TELEPATHY_NS_TUBES, - WOCKY_NODE_END, NULL); - msg_node = wocky_stanza_get_top_node (msg); - - node = wocky_node_get_child_ns (msg_node, "tubes", - WOCKY_TELEPATHY_NS_TUBES); - - data.self = self; - data.tubes_node = node; - - g_hash_table_foreach (priv->tubes, publish_tubes_in_node, &data); - - /* Send it */ - if (!gibber_muc_connection_send (priv->muc_connection, msg, &error)) - { - g_warning ("%s: sending tubes info failed: %s", G_STRFUNC, - error->message); - g_error_free (error); - g_object_unref (msg); - return FALSE; - } - - g_object_unref (msg); - return TRUE; -} - -/** - * salut_tubes_channel_offer_d_bus_tube - * - * Implements D-Bus method OfferDBusTube - * on org.freedesktop.Telepathy.Channel.Type.Tubes - */ -static void -salut_tubes_channel_offer_d_bus_tube (TpSvcChannelTypeTubes *iface, - const gchar *service, - GHashTable *parameters, - DBusGMethodInvocation *context) -{ - SalutTubesChannel *self = SALUT_TUBES_CHANNEL (iface); - SalutTubesChannelPrivate *priv; - guint tube_id; - SalutTubeIface *tube; - GError *err = NULL; - - g_assert (SALUT_IS_TUBES_CHANNEL (self)); - - priv = SALUT_TUBES_CHANNEL_GET_PRIVATE (self); - - if (priv->handle_type == TP_HANDLE_TYPE_ROOM - && !tp_handle_set_is_member (TP_GROUP_MIXIN (self->muc)->members, - priv->self_handle)) - { - GError error = { TP_ERROR, TP_ERROR_NOT_AVAILABLE, - "Tube channel isn't connected" }; - - dbus_g_method_return_error (context, &error); - return; - } - - tube_id = generate_tube_id (); - - tube = create_new_tube (self, TP_TUBE_TYPE_DBUS, priv->self_handle, - TRUE, service, parameters, tube_id, 0, NULL); - - if (!salut_tube_dbus_offer (SALUT_TUBE_DBUS (tube), &err)) - { - salut_tube_iface_close (tube, TRUE); - dbus_g_method_return_error (context, err); - - g_error_free (err); - return; - } - - tp_svc_channel_type_tubes_return_from_offer_d_bus_tube (context, tube_id); -} - -/** - * salut_tubes_channel_accept_d_bus_tube - * - * Implements D-Bus method AcceptDBusTube - * on org.freedesktop.Telepathy.Channel.Type.Tubes - */ -static void -salut_tubes_channel_accept_d_bus_tube (TpSvcChannelTypeTubes *iface, - guint id, - DBusGMethodInvocation *context) -{ - SalutTubesChannel *self = SALUT_TUBES_CHANNEL (iface); - SalutTubesChannelPrivate *priv; - SalutTubeIface *tube; - TpTubeChannelState state; - TpTubeType type; - gchar *addr; - - g_assert (SALUT_IS_TUBES_CHANNEL (self)); - - priv = SALUT_TUBES_CHANNEL_GET_PRIVATE (self); - - tube = g_hash_table_lookup (priv->tubes, GUINT_TO_POINTER (id)); - if (tube == NULL) - { - GError error = { TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Unknown tube" }; - - dbus_g_method_return_error (context, &error); - - return; - } - - g_object_get (tube, - "type", &type, - "state", &state, - NULL); - - if (type != TP_TUBE_TYPE_DBUS) - { - GError error = { TP_ERROR, TP_ERROR_INVALID_ARGUMENT, - "Tube is not a D-Bus tube" }; - - dbus_g_method_return_error (context, &error); - return; - } - - if (state != TP_TUBE_CHANNEL_STATE_LOCAL_PENDING) - { - GError error = { TP_ERROR, TP_ERROR_INVALID_ARGUMENT, - "Tube is not in the local pending state" }; - - dbus_g_method_return_error (context, &error); - - return; - } - - salut_tube_iface_accept (tube, NULL); - - g_object_get (tube, - "dbus-address", &addr, - NULL); - - add_yourself_in_dbus_names (self, id); - - tp_svc_channel_type_tubes_return_from_accept_d_bus_tube (context, addr); - g_free (addr); -} - -/** - * salut_tubes_channel_close_tube - * - * Implements D-Bus method CloseTube - * on org.freedesktop.Telepathy.Channel.Type.Tubes - */ -static void -salut_tubes_channel_close_tube (TpSvcChannelTypeTubes *iface, - guint id, - DBusGMethodInvocation *context) -{ - SalutTubesChannel *self = SALUT_TUBES_CHANNEL (iface); - SalutTubesChannelPrivate *priv; - SalutTubeIface *tube; - - g_assert (SALUT_IS_TUBES_CHANNEL (self)); - - priv = SALUT_TUBES_CHANNEL_GET_PRIVATE (self); - - tube = g_hash_table_lookup (priv->tubes, GUINT_TO_POINTER (id)); - if (tube == NULL) - { - GError error = { TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Unknown tube" }; - - dbus_g_method_return_error (context, &error); - return; - } - - salut_tube_iface_close (tube, FALSE); - - tp_svc_channel_type_tubes_return_from_close_tube (context); -} - -/** - * salut_tubes_channel_get_d_bus_tube_address - * - * Implements D-Bus method GetDBusTubeAddress - * on org.freedesktop.Telepathy.Channel.Type.Tubes - */ -static void -salut_tubes_channel_get_d_bus_tube_address (TpSvcChannelTypeTubes *iface, - guint id, - DBusGMethodInvocation *context) -{ - SalutTubesChannel *self = SALUT_TUBES_CHANNEL (iface); - SalutTubesChannelPrivate *priv; - SalutTubeIface *tube; - gchar *addr; - TpTubeType type; - TpTubeChannelState state; - - g_assert (SALUT_IS_TUBES_CHANNEL (self)); - - priv = SALUT_TUBES_CHANNEL_GET_PRIVATE (self); - - tube = g_hash_table_lookup (priv->tubes, GUINT_TO_POINTER (id)); - - if (tube == NULL) - { - GError error = { TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Unknown tube" }; - - dbus_g_method_return_error (context, &error); - return; - } - - g_object_get (tube, - "type", &type, - "state", &state, - NULL); - - if (type != TP_TUBE_TYPE_DBUS) - { - GError error = { TP_ERROR, TP_ERROR_INVALID_ARGUMENT, - "Tube is not a D-Bus tube" }; - - dbus_g_method_return_error (context, &error); - return; - } - - if (state != TP_TUBE_CHANNEL_STATE_OPEN) - { - GError error = { TP_ERROR, TP_ERROR_NOT_AVAILABLE, - "Tube is not open" }; - - dbus_g_method_return_error (context, &error); - return; - } - - g_object_get (tube, "dbus-address", &addr, NULL); - tp_svc_channel_type_tubes_return_from_get_d_bus_tube_address (context, - addr); - g_free (addr); -} - -static void -get_d_bus_names_foreach (gpointer key, - gpointer value, - gpointer user_data) -{ - GPtrArray *ret = user_data; - GValue tmp = {0,}; - - g_value_init (&tmp, DBUS_NAME_PAIR_TYPE); - g_value_take_boxed (&tmp, - dbus_g_type_specialized_construct (DBUS_NAME_PAIR_TYPE)); - dbus_g_type_struct_set (&tmp, - 0, key, - 1, value, - G_MAXUINT); - g_ptr_array_add (ret, g_value_get_boxed (&tmp)); -} - -/** - * salut_tubes_channel_get_d_bus_names - * - * Implements D-Bus method GetDBusNames - * on org.freedesktop.Telepathy.Channel.Type.Tubes - */ -static void -salut_tubes_channel_get_d_bus_names (TpSvcChannelTypeTubes *iface, - guint id, - DBusGMethodInvocation *context) -{ - SalutTubesChannel *self = SALUT_TUBES_CHANNEL (iface); - SalutTubesChannelPrivate *priv = SALUT_TUBES_CHANNEL_GET_PRIVATE (self); - SalutTubeIface *tube; - GHashTable *names; - GPtrArray *ret; - TpTubeType type; - TpTubeChannelState state; - guint i; - - g_assert (SALUT_IS_TUBES_CHANNEL (self)); - - tube = g_hash_table_lookup (priv->tubes, GUINT_TO_POINTER (id)); - - if (tube == NULL) - { - GError error = { TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Unknown tube" }; - - dbus_g_method_return_error (context, &error); - return; - } - - g_object_get (tube, - "type", &type, - "state", &state, - NULL); - - if (type != TP_TUBE_TYPE_DBUS) - { - GError error = { TP_ERROR, TP_ERROR_INVALID_ARGUMENT, - "Tube is not a D-Bus tube" }; - - dbus_g_method_return_error (context, &error); - return; - } - - if (state != TP_TUBE_CHANNEL_STATE_OPEN) - { - GError error = { TP_ERROR, TP_ERROR_NOT_AVAILABLE, - "Tube is not open" }; - - dbus_g_method_return_error (context, &error); - return; - } - - g_object_get (tube, "dbus-names", &names, NULL); - g_assert (names); - - ret = g_ptr_array_sized_new (g_hash_table_size (names)); - g_hash_table_foreach (names, get_d_bus_names_foreach, ret); - - tp_svc_channel_type_tubes_return_from_get_d_bus_names (context, ret); - - for (i = 0; i < ret->len; i++) - g_boxed_free (DBUS_NAME_PAIR_TYPE, ret->pdata[i]); - g_hash_table_unref (names); - g_ptr_array_unref (ret); -} - -static void -stream_tube_new_connection_cb (SalutTubeIface *tube, - guint contact, - gpointer user_data) -{ - SalutTubesChannel *self = SALUT_TUBES_CHANNEL (user_data); - guint tube_id; - TpTubeType type; - - g_object_get (tube, - "id", &tube_id, - "type", &type, - NULL); - - g_assert (type == TP_TUBE_TYPE_STREAM); - - tp_svc_channel_type_tubes_emit_stream_tube_new_connection (self, - tube_id, contact); -} - -static void -iq_reply_cb (GObject *source_object, - GAsyncResult *result, - gpointer user_data) -{ - WockyPorter *porter = WOCKY_PORTER (source_object); - SalutTubeIface *tube = (SalutTubeIface *) user_data; - WockyStanzaSubType sub_type; - WockyStanza *reply_stanza; - GError *error = NULL; - - reply_stanza = wocky_porter_send_iq_finish (porter, result, &error); - - if (reply_stanza == NULL) - { - DEBUG ("Failed to send IQ: %s", error->message); - salut_tube_iface_close (tube, TRUE); - g_clear_error (&error); - return; - } - - wocky_stanza_get_type_info (reply_stanza, NULL, &sub_type); - if (sub_type != WOCKY_STANZA_SUB_TYPE_RESULT) - { - DEBUG ("The contact has declined our tube offer"); - salut_tube_iface_close (tube, TRUE); - return; - } - - salut_tube_iface_accepted (tube); - - DEBUG ("The contact has accepted our tube offer"); -} - -static void -send_channel_iq_tube (gpointer key, - gpointer value, - gpointer user_data) -{ - SalutTubesChannel *self = (SalutTubesChannel *) user_data; - SalutTubesChannelPrivate *priv = SALUT_TUBES_CHANNEL_GET_PRIVATE (self); - - SalutTubeIface *tube = (SalutTubeIface *) value; - guint tube_id = GPOINTER_TO_UINT (key); - TpHandle initiator; - gchar *service; - GHashTable *parameters; - TpTubeChannelState state; - TpTubeType type; - - g_object_get (tube, - "type", &type, - "initiator-handle", &initiator, - "service", &service, - "parameters", ¶meters, - "state", &state, - NULL); - - if (state != TP_TUBE_CHANNEL_STATE_NOT_OFFERED && - salut_tube_iface_offer_needed (tube)) - { - WockyNode *parameters_node; - const char *tube_type_str; - WockyStanza *stanza; - WockyNode *top_node; - const gchar *jid_from; - TpHandleRepoIface *contact_repo; - gchar *tube_id_str; - int port; - gchar *port_str; - - DEBUG ("Listening for connections from the remote contact " - "and sending the tube offer stanza"); - - /* listen for future connections from the remote CM before sending the - * iq */ - port = salut_tube_iface_listen (tube); - g_assert (port > 0); - - contact_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT); - - jid_from = tp_handle_inspect (contact_repo, priv->self_handle); - - switch (type) - { - case TP_TUBE_TYPE_DBUS: - tube_type_str = "dbus"; - break; - - case TP_TUBE_TYPE_STREAM: - tube_type_str = "stream"; - break; - default: - g_assert_not_reached (); - } - - port_str = g_strdup_printf ("%d", port); - tube_id_str = g_strdup_printf ("%d", tube_id); - - stanza = wocky_stanza_build_to_contact (WOCKY_STANZA_TYPE_IQ, - WOCKY_STANZA_SUB_TYPE_SET, - jid_from, WOCKY_CONTACT (priv->contact), - WOCKY_NODE_START, "tube", - WOCKY_NODE_XMLNS, WOCKY_TELEPATHY_NS_TUBES, - WOCKY_NODE_ATTRIBUTE, "type", tube_type_str, - WOCKY_NODE_ATTRIBUTE, "service", service, - WOCKY_NODE_ATTRIBUTE, "id", tube_id_str, - WOCKY_NODE_START, "transport", - WOCKY_NODE_ATTRIBUTE, "port", port_str, - WOCKY_NODE_END, - WOCKY_NODE_END, - NULL); - top_node = wocky_stanza_get_top_node (stanza); - - parameters_node = wocky_node_add_child ( - wocky_node_get_child (top_node, "tube"), "parameters"); - salut_wocky_node_add_children_from_properties (parameters_node, - parameters, "parameter"); - - wocky_porter_send_iq_async (priv->conn->porter, stanza, - NULL, iq_reply_cb, tube); - - g_object_unref (stanza); - g_free (tube_id_str); - g_free (port_str); - } - - g_free (service); - g_hash_table_unref (parameters); -} - -/** - * Send iq offer(s) for all tubes in this channel to the remote contact in iq - * stanza(s). If the XmppConnection is not established, try to establish it, - * and the offer will be sent later asynchronously. - * - * Iq stanzas are sent only when the tube has not been offered yet. It asks - * each tube whether it is really needed with salut_tube_iface_offer_needed() - * - * This is called when the client offer the tube, either via the old - * Channel.Type.Tubes interface, or the new Channel.Type.{Stream,DBus}Tube - * interface. This is also called when the XmppConnection is established in - * case a tube was offered while the XmppConnection was not established. - */ -void -salut_tubes_channel_send_iq_offer (SalutTubesChannel *self) -{ - SalutTubesChannelPrivate *priv = SALUT_TUBES_CHANNEL_GET_PRIVATE (self); - - if (priv->state != CHANNEL_CONNECTED) - { - /* TODO: do not connect if nothing to send... */ - setup_connection (self); - return; - } - - g_hash_table_foreach (priv->tubes, send_channel_iq_tube, self); -} - - -/** - * salut_tubes_channel_offer_stream_tube - * - * Implements D-Bus method OfferStreamTube - * on org.freedesktop.Telepathy.Channel.Type.Tubes - */ -static void -salut_tubes_channel_offer_stream_tube (TpSvcChannelTypeTubes *iface, - const gchar *service, - GHashTable *parameters, - guint address_type, - const GValue *address, - guint access_control, - const GValue *access_control_param, - DBusGMethodInvocation *context) -{ - SalutTubesChannel *self = SALUT_TUBES_CHANNEL (iface); - SalutTubesChannelPrivate *priv; - guint tube_id; - SalutTubeIface *tube; - GError *error = NULL; - - priv = SALUT_TUBES_CHANNEL_GET_PRIVATE (self); - - if (priv->handle_type == TP_HANDLE_TYPE_ROOM - && !tp_handle_set_is_member (TP_GROUP_MIXIN (self->muc)->members, - priv->self_handle)) - { - GError err = { TP_ERROR, TP_ERROR_NOT_AVAILABLE, - "Tube channel isn't connected" }; - - dbus_g_method_return_error (context, &err); - return; - } - - if (!salut_tube_stream_check_params (address_type, address, - access_control, access_control_param, &error)) - { - dbus_g_method_return_error (context, error); - g_error_free (error); - return; - } - - tube_id = generate_tube_id (); - - tube = create_new_tube (self, TP_TUBE_TYPE_STREAM, priv->self_handle, - TRUE, service, parameters, tube_id, 0, NULL); - - g_object_set (tube, - "address-type", address_type, - "address", address, - "access-control", access_control, - "access-control-param", access_control_param, - NULL); - - if (!salut_tube_stream_offer (SALUT_TUBE_STREAM (tube), &error)) - { - salut_tube_iface_close (tube, TRUE); - - dbus_g_method_return_error (context, error); - return; - } - - g_signal_connect (tube, "tube-new-connection", - G_CALLBACK (stream_tube_new_connection_cb), self); - - tp_svc_channel_type_tubes_return_from_offer_stream_tube (context, - tube_id); -} - -/** - * salut_tubes_channel_accept_stream_tube - * - * Implements D-Bus method AcceptStreamTube - * on org.freedesktop.Telepathy.Channel.Type.Tubes - */ -static void -salut_tubes_channel_accept_stream_tube (TpSvcChannelTypeTubes *iface, - guint id, - guint address_type, - guint access_control, - const GValue *access_control_param, - DBusGMethodInvocation *context) -{ - SalutTubesChannel *self = SALUT_TUBES_CHANNEL (iface); - SalutTubesChannelPrivate *priv; - SalutTubeIface *tube; - TpTubeChannelState state; - TpTubeType type; - GValue *address; - GError *error = NULL; - - g_assert (SALUT_IS_TUBES_CHANNEL (self)); - - priv = SALUT_TUBES_CHANNEL_GET_PRIVATE (self); - - tube = g_hash_table_lookup (priv->tubes, GUINT_TO_POINTER (id)); - if (tube == NULL) - { - GError err = { TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Unknown tube" }; - - dbus_g_method_return_error (context, &err); - return; - } - - if (address_type != TP_SOCKET_ADDRESS_TYPE_UNIX && - address_type != TP_SOCKET_ADDRESS_TYPE_IPV4 && - address_type != TP_SOCKET_ADDRESS_TYPE_IPV6) - { - GError *err = NULL; - - err = g_error_new (TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, - "Address type %d not implemented", address_type); - - dbus_g_method_return_error (context, err); - - g_error_free (err); - return; - } - - if (access_control != TP_SOCKET_ACCESS_CONTROL_LOCALHOST) - { - GError *err = NULL; - - err = g_error_new (TP_ERROR, TP_ERROR_INVALID_ARGUMENT, - "Unix sockets only support localhost control access"); - - dbus_g_method_return_error (context, err); - - g_error_free (err); - return; - } - - g_object_get (tube, - "type", &type, - "state", &state, - NULL); - - if (type != TP_TUBE_TYPE_STREAM) - { - GError err = { TP_ERROR, TP_ERROR_INVALID_ARGUMENT, - "Tube is not a stream tube" }; - - dbus_g_method_return_error (context, &err); - return; - } - - if (state != TP_TUBE_CHANNEL_STATE_LOCAL_PENDING) - { - GError err = { TP_ERROR, TP_ERROR_INVALID_ARGUMENT, - "Tube is not in the local pending state" }; - - dbus_g_method_return_error (context, &err); - return; - } - - g_object_set (tube, - "address-type", address_type, - "access-control", access_control, - "access-control-param", access_control_param, - NULL); - - if (!salut_tube_iface_accept (tube, &error)) - { - dbus_g_method_return_error (context, error); - return; - } - - g_object_get (tube, "address", &address, NULL); - - tp_svc_channel_type_tubes_return_from_accept_stream_tube (context, - address); -} - -/** - * salut_tubes_channel_get_stream_tube_socket_address - * - * Implements D-Bus method GetStreamTubeSocketAddress - * on org.freedesktop.Telepathy.Channel.Type.Tubes - */ -static void -salut_tubes_channel_get_stream_tube_socket_address (TpSvcChannelTypeTubes *iface, - guint id, - DBusGMethodInvocation *context) -{ - SalutTubesChannel *self = SALUT_TUBES_CHANNEL (iface); - SalutTubesChannelPrivate *priv = SALUT_TUBES_CHANNEL_GET_PRIVATE (self); - SalutTubeIface *tube; - TpTubeType type; - TpTubeChannelState state; - GValue *address; - TpSocketAddressType address_type; - - tube = g_hash_table_lookup (priv->tubes, GUINT_TO_POINTER (id)); - if (tube == NULL) - { - GError error = { TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Unknown tube" }; - - dbus_g_method_return_error (context, &error); - return; - } - - g_object_get (tube, - "type", &type, - "state", &state, - NULL); - - if (type != TP_TUBE_TYPE_STREAM) - { - GError error = { TP_ERROR, TP_ERROR_INVALID_ARGUMENT, - "Tube is not a Stream tube" }; - - dbus_g_method_return_error (context, &error); - return; - } - - if (state != TP_TUBE_CHANNEL_STATE_OPEN) - { - GError error = { TP_ERROR, TP_ERROR_NOT_AVAILABLE, - "Tube is not open" }; - - dbus_g_method_return_error (context, &error); - return; - } - - g_object_get (tube, - "address", &address, - "address-type", &address_type, - NULL); - - tp_svc_channel_type_tubes_return_from_get_stream_tube_socket_address ( - context, address_type, address); -} - -/** - * salut_tubes_channel_get_available_stream_tube_types - * - * Implements D-Bus method GetAvailableStreamTubeTypes - * on org.freedesktop.Telepathy.Channel.Type.Tubes - */ -static void -salut_tubes_channel_get_available_stream_tube_types ( - TpSvcChannelTypeTubes *iface, - DBusGMethodInvocation *context) -{ - GHashTable *ret; - - ret = salut_tube_stream_get_supported_socket_types (); - - tp_svc_channel_type_tubes_return_from_get_available_stream_tube_types ( - context, ret); - - g_hash_table_unref (ret); -} - -static void salut_tubes_channel_dispose (GObject *object); -static void salut_tubes_channel_finalize (GObject *object); - -static void -salut_tubes_channel_class_init ( - SalutTubesChannelClass *salut_tubes_channel_class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (salut_tubes_channel_class); - GParamSpec *param_spec; - static TpDBusPropertiesMixinPropImpl channel_props[] = { - { "TargetHandleType", "handle-type", NULL }, - { "TargetHandle", "handle", NULL }, - { "TargetID", "target-id", NULL }, - { "ChannelType", "channel-type", NULL }, - { "Interfaces", "interfaces", NULL }, - { "Requested", "requested", NULL }, - { "InitiatorHandle", "initiator-handle", NULL }, - { "InitiatorID", "initiator-id", NULL }, - { NULL } - }; - static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = { - { TP_IFACE_CHANNEL, - tp_dbus_properties_mixin_getter_gobject_properties, - NULL, - channel_props, - }, - { NULL } - }; - - g_type_class_add_private (salut_tubes_channel_class, - sizeof (SalutTubesChannelPrivate)); - - object_class->constructor = salut_tubes_channel_constructor; - - object_class->dispose = salut_tubes_channel_dispose; - object_class->finalize = salut_tubes_channel_finalize; - - object_class->get_property = salut_tubes_channel_get_property; - object_class->set_property = salut_tubes_channel_set_property; - - g_object_class_override_property (object_class, PROP_OBJECT_PATH, - "object-path"); - g_object_class_override_property (object_class, PROP_CHANNEL_TYPE, - "channel-type"); - g_object_class_override_property (object_class, PROP_HANDLE_TYPE, - "handle-type"); - g_object_class_override_property (object_class, PROP_HANDLE, "handle"); - - g_object_class_override_property (object_class, PROP_CHANNEL_DESTROYED, - "channel-destroyed"); - g_object_class_override_property (object_class, PROP_CHANNEL_PROPERTIES, - "channel-properties"); - - param_spec = g_param_spec_string ("target-id", "Target JID", - "The string obtained by inspecting this channel's handle", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_TARGET_ID, param_spec); - - param_spec = g_param_spec_boolean ("requested", "Requested?", - "True if this channel was requested by the local user", - FALSE, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_REQUESTED, param_spec); - - param_spec = g_param_spec_uint ("initiator-handle", "Initiator's handle", - "The contact which caused the Tubes channel to appear", - 0, G_MAXUINT32, 0, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_INITIATOR_HANDLE, - param_spec); - - param_spec = g_param_spec_string ("initiator-id", "Initiator JID", - "The string obtained by inspecting this channel's initiator-handle", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_INITIATOR_ID, - param_spec); - - param_spec = g_param_spec_object ( - "connection", - "SalutConnection object", - "Salut Connection that owns the connection for this tubes channel", - SALUT_TYPE_CONNECTION, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_CONNECTION, param_spec); - - param_spec = g_param_spec_object ( - "muc", - "SalutMucChannel object", - "Salut text MUC channel corresponding to this Tubes channel object, " - "if the handle type is ROOM.", - SALUT_TYPE_MUC_CHANNEL, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_MUC, param_spec); - - param_spec = g_param_spec_object ( - "contact", - "SalutContact object", - "Salut Contact to which this channel is dedicated in case of 1-1 tube", - SALUT_TYPE_CONTACT, - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_READWRITE | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB); - g_object_class_install_property (object_class, PROP_CONTACT, param_spec); - - param_spec = g_param_spec_boxed ("interfaces", "Extra D-Bus interfaces", - "Additional Channel.Interface.* interfaces", - G_TYPE_STRV, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_INTERFACES, param_spec); - - salut_tubes_channel_class->dbus_props_class.interfaces = prop_interfaces; - tp_dbus_properties_mixin_class_init (object_class, - G_STRUCT_OFFSET (SalutTubesChannelClass, dbus_props_class)); - - tp_external_group_mixin_init_dbus_properties (object_class); -} - -void -salut_tubes_channel_dispose (GObject *object) -{ - SalutTubesChannel *self = SALUT_TUBES_CHANNEL (object); - SalutTubesChannelPrivate *priv = SALUT_TUBES_CHANNEL_GET_PRIVATE (self); - - if (priv->dispose_has_run) - return; - - if (priv->muc_connection != NULL) - { - g_signal_handlers_disconnect_matched (priv->muc_connection, - G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self); - - g_object_unref (priv->muc_connection); - priv->muc_connection = NULL; - } - - if (priv->contact != NULL) - { - g_object_unref (priv->contact); - priv->contact = NULL; - } - - priv->dispose_has_run = TRUE; - - if (self->muc != NULL) - tp_external_group_mixin_finalize (object); - - salut_tubes_channel_close (self); - - if (G_OBJECT_CLASS (salut_tubes_channel_parent_class)->dispose) - G_OBJECT_CLASS (salut_tubes_channel_parent_class)->dispose (object); -} - -static void -salut_tubes_channel_finalize (GObject *object) -{ - SalutTubesChannel *self = SALUT_TUBES_CHANNEL (object); - SalutTubesChannelPrivate *priv = SALUT_TUBES_CHANNEL_GET_PRIVATE (self); - - g_free (priv->object_path); - - G_OBJECT_CLASS (salut_tubes_channel_parent_class)->finalize (object); -} - -static void -emit_tube_closed_signal (gpointer key, - gpointer value, - gpointer user_data) -{ - guint id = GPOINTER_TO_UINT (key); - SalutTubesChannel *self = (SalutTubesChannel *) user_data; - - tp_svc_channel_type_tubes_emit_tube_closed (self, id); -} - -void -salut_tubes_channel_foreach (SalutTubesChannel *self, - TpExportableChannelFunc foreach, - gpointer user_data) -{ - SalutTubesChannelPrivate *priv = SALUT_TUBES_CHANNEL_GET_PRIVATE (self); - GHashTableIter iter; - gpointer value; - - g_hash_table_iter_init (&iter, priv->tubes); - while (g_hash_table_iter_next (&iter, NULL, &value)) - { - foreach (TP_EXPORTABLE_CHANNEL (value), user_data); - } -} - -void -salut_tubes_channel_close (SalutTubesChannel *self) -{ - SalutTubesChannelPrivate *priv; - - g_assert (SALUT_IS_TUBES_CHANNEL (self)); - - priv = SALUT_TUBES_CHANNEL_GET_PRIVATE (self); - - if (priv->closed) - { - return; - } - - priv->closed = TRUE; - - g_hash_table_foreach (priv->tubes, emit_tube_closed_signal, self); - g_hash_table_unref (priv->tubes); - - priv->tubes = NULL; - - tp_svc_channel_emit_closed (self); -} - -/** - * salut_tubes_channel_close_async: - * - * Implements D-Bus method Close - * on interface org.freedesktop.Telepathy.Channel - */ -static void -salut_tubes_channel_close_async (TpSvcChannel *iface, - DBusGMethodInvocation *context) -{ - SalutTubesChannel *self = SALUT_TUBES_CHANNEL (iface); - - g_assert (SALUT_IS_TUBES_CHANNEL (self)); - - salut_tubes_channel_close (self); - tp_svc_channel_return_from_close (context); -} - -/** - * salut_tubes_channel_get_channel_type - * - * Tubesplements DBus method GetChannelType - * on interface org.freedesktop.Telepathy.Channel - */ -static void -salut_tubes_channel_get_channel_type (TpSvcChannel *iface, - DBusGMethodInvocation *context) -{ - tp_svc_channel_return_from_get_channel_type (context, - TP_IFACE_CHANNEL_TYPE_TUBES); -} - - -/** - * salut_tubes_channel_get_handle - * - * Tubesplements DBus method GetHandle - * on interface org.freedesktop.Telepathy.Channel - */ -static void -salut_tubes_channel_get_handle (TpSvcChannel *iface, - DBusGMethodInvocation *context) -{ - SalutTubesChannel *self = SALUT_TUBES_CHANNEL (iface); - SalutTubesChannelPrivate *priv; - - g_assert (SALUT_IS_TUBES_CHANNEL (self)); - priv = SALUT_TUBES_CHANNEL_GET_PRIVATE (self); - - tp_svc_channel_return_from_get_handle (context, priv->handle_type, - priv->handle); -} - - -/** - * salut_tubes_channel_get_interfaces - * - * Tubesplements DBus method GetInterfaces - * on interface org.freedesktop.Telepathy.Channel - */ -static void -salut_tubes_channel_get_interfaces (TpSvcChannel *iface, - DBusGMethodInvocation *context) -{ - SalutTubesChannel *self = SALUT_TUBES_CHANNEL (iface); - - if (self->muc) - { - tp_svc_channel_return_from_get_interfaces (context, - salut_tubes_channel_interfaces); - } - else - { - /* only show the NULL */ - tp_svc_channel_return_from_get_interfaces (context, - salut_tubes_channel_interfaces + 1); - } -} - -/* Called when we receive a SI request, - * via salut_muc_manager_handle_si_stream_request - */ -void -salut_tubes_channel_bytestream_offered (SalutTubesChannel *self, - GibberBytestreamIface *bytestream, - WockyStanza *msg) -{ - SalutTubesChannelPrivate *priv = SALUT_TUBES_CHANNEL_GET_PRIVATE (self); - WockyNode *node = wocky_stanza_get_top_node (msg); - const gchar *stream_id, *tmp; - gchar *endptr; - WockyNode *si_node, *stream_node; - guint tube_id; - unsigned long tube_id_tmp; - SalutTubeIface *tube; - WockyStanzaType type; - WockyStanzaSubType sub_type; - - /* Caller is expected to have checked that we have a stream or muc-stream - * node with a stream ID and the TUBES profile - */ - wocky_stanza_get_type_info (msg, &type, &sub_type); - g_return_if_fail (type == WOCKY_STANZA_TYPE_IQ); - g_return_if_fail (sub_type == WOCKY_STANZA_SUB_TYPE_SET); - - si_node = wocky_node_get_child_ns (node, "si", - WOCKY_XMPP_NS_SI); - g_return_if_fail (si_node != NULL); - - if (priv->handle_type == TP_HANDLE_TYPE_CONTACT) - stream_node = wocky_node_get_child_ns (si_node, - "stream", WOCKY_TELEPATHY_NS_TUBES); - else - stream_node = wocky_node_get_child_ns (si_node, - "muc-stream", WOCKY_TELEPATHY_NS_TUBES); - g_return_if_fail (stream_node != NULL); - - stream_id = wocky_node_get_attribute (si_node, "id"); - g_return_if_fail (stream_id != NULL); - - tmp = wocky_node_get_attribute (stream_node, "tube"); - if (tmp == NULL) - { - GError e = { WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "<stream> or <muc-stream> has no tube attribute" }; - - DEBUG ("%s", e.message); - gibber_bytestream_iface_close (bytestream, &e); - return; - } - tube_id_tmp = strtoul (tmp, &endptr, 10); - if (!endptr || *endptr || tube_id_tmp > G_MAXUINT32) - { - GError e = { WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "<stream> or <muc-stream> tube attribute not numeric or > 2**32" }; - - DEBUG ("tube id is not numeric or > 2**32: %s", tmp); - gibber_bytestream_iface_close (bytestream, &e); - return; - } - tube_id = (guint) tube_id_tmp; - - tube = g_hash_table_lookup (priv->tubes, GUINT_TO_POINTER (tube_id)); - if (tube == NULL) - { - GError e = { WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "<stream> or <muc-stream> tube attribute points to a nonexistent " - "tube" }; - - DEBUG ("tube %u doesn't exist", tube_id); - gibber_bytestream_iface_close (bytestream, &e); - return; - } - - DEBUG ("received new bytestream request for existing tube: %u", tube_id); - - salut_tube_iface_add_bytestream (tube, bytestream); -} - -static void -tubes_iface_init (gpointer g_iface, - gpointer iface_data) -{ - TpSvcChannelTypeTubesClass *klass = (TpSvcChannelTypeTubesClass *) g_iface; - -#define IMPLEMENT(x) tp_svc_channel_type_tubes_implement_##x (\ - klass, salut_tubes_channel_##x) - IMPLEMENT(get_available_tube_types); - IMPLEMENT(list_tubes); - IMPLEMENT(close_tube); - IMPLEMENT(offer_d_bus_tube); - IMPLEMENT(accept_d_bus_tube); - IMPLEMENT(get_d_bus_tube_address); - IMPLEMENT(get_d_bus_names); - IMPLEMENT(offer_stream_tube); - IMPLEMENT(accept_stream_tube); - IMPLEMENT(get_stream_tube_socket_address); - IMPLEMENT(get_available_stream_tube_types); -#undef IMPLEMENT -} - -static void -channel_iface_init (gpointer g_iface, - gpointer iface_data) -{ - TpSvcChannelClass *klass = (TpSvcChannelClass *) g_iface; - -#define IMPLEMENT(x, suffix) tp_svc_channel_implement_##x (\ - klass, salut_tubes_channel_##x##suffix) - IMPLEMENT(close,_async); - IMPLEMENT(get_channel_type,); - IMPLEMENT(get_handle,); - IMPLEMENT(get_interfaces,); -#undef IMPLEMENT -} diff --git a/src/tubes-channel.h b/src/tubes-channel.h deleted file mode 100644 index c92fcb74..00000000 --- a/src/tubes-channel.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * tubes-channel.h - Header for SalutTubesChannel - * Copyright (C) 2007 Collabora Ltd. - * - * 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 tubesplied 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 - */ - -#ifndef __SALUT_TUBES_CHANNEL_H__ -#define __SALUT_TUBES_CHANNEL_H__ - -#include <glib-object.h> -#include <wocky/wocky.h> -#include <gibber/gibber-bytestream-iface.h> - -#include "muc-channel.h" -#include "tube-iface.h" - -G_BEGIN_DECLS - -typedef struct _SalutTubesChannel SalutTubesChannel; -typedef struct _SalutTubesChannelClass SalutTubesChannelClass; - -struct _SalutTubesChannelClass { - GObjectClass parent_class; - TpDBusPropertiesMixinClass dbus_props_class; -}; - -struct _SalutTubesChannel { - GObject parent; - - SalutMucChannel *muc; - - gpointer priv; -}; - -GType salut_tubes_channel_get_type (void); - -/* TYPE MACROS */ -#define SALUT_TYPE_TUBES_CHANNEL \ - (salut_tubes_channel_get_type ()) -#define SALUT_TUBES_CHANNEL(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), SALUT_TYPE_TUBES_CHANNEL, \ - SalutTubesChannel)) -#define SALUT_TUBES_CHANNEL_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), SALUT_TYPE_TUBES_CHANNEL, \ - SalutTubesChannelClass)) -#define SALUT_IS_TUBES_CHANNEL(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), SALUT_TYPE_TUBES_CHANNEL)) -#define SALUT_IS_TUBES_CHANNEL_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), SALUT_TYPE_TUBES_CHANNEL)) -#define SALUT_TUBES_CHANNEL_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), SALUT_TYPE_TUBES_CHANNEL, \ - SalutTubesChannelClass)) - -void salut_tubes_channel_foreach (SalutTubesChannel *self, - TpExportableChannelFunc foreach, gpointer user_data); - -void salut_tubes_channel_close (SalutTubesChannel *channel); - -void salut_tubes_channel_bytestream_offered (SalutTubesChannel *chanel, - GibberBytestreamIface *bytestream, WockyStanza *msg); - -GPtrArray * salut_tubes_channel_muc_message_received ( - SalutTubesChannel *channel, const gchar *sender, WockyStanza *stanza); - -SalutTubeIface * salut_tubes_channel_message_received (SalutTubesChannel *self, - const gchar *service, TpTubeType tube_type, TpHandle initiator_handle, - GHashTable *parameters, guint tube_id, guint portnum, - WockyStanza *iq_req); - -void salut_tubes_channel_message_close_received (SalutTubesChannel *self, - TpHandle initiator_handle, guint tube_id); - -SalutTubeIface *salut_tubes_channel_tube_request (SalutTubesChannel *self, - gpointer request_token, GHashTable *request_properties, - gboolean require_new); - -void salut_tubes_channel_send_iq_offer (SalutTubesChannel *self); - -G_END_DECLS - -#endif /* #ifndef __SALUT_TUBES_CHANNEL_H__*/ diff --git a/src/tubes-manager.c b/src/tubes-manager.c index 3fc6bfc7..a94d1623 100644 --- a/src/tubes-manager.c +++ b/src/tubes-manager.c @@ -43,27 +43,29 @@ #include "extensions/extensions.h" #include "connection.h" #include "capabilities.h" -#include "tubes-channel.h" #include "muc-manager.h" #include "muc-channel.h" #include "self.h" #include "util.h" #include "tube-iface.h" +#include "tube-dbus.h" #include "tube-stream.h" -static SalutTubesChannel *new_tubes_channel (SalutTubesManager *fac, - TpHandle handle, TpHandle initiator, gpointer request_token, - gboolean requested, GError **error); - -static void tubes_channel_closed_cb (SalutTubesChannel *chan, - gpointer user_data); - static void salut_tubes_manager_iface_init (gpointer g_iface, gpointer iface_data); static void gabble_caps_channel_manager_iface_init ( GabbleCapsChannelManagerIface *); +static SalutTubeIface * create_new_tube (SalutTubesManager *self, + TpTubeType type, + TpHandle handle, + const gchar *service, + GHashTable *parameters, + guint64 tube_id, + guint portnum, + WockyStanza *iq_req); + G_DEFINE_TYPE_WITH_CODE (SalutTubesManager, salut_tubes_manager, G_TYPE_OBJECT, @@ -89,7 +91,8 @@ struct _SalutTubesManagerPrivate guint iq_tube_handler_id; SalutContactManager *contact_manager; - GHashTable *tubes_channels; + /* guint tube ID => (owned) (SalutTubeIface *) */ + GHashTable *tubes; gboolean dispose_has_run; }; @@ -105,8 +108,8 @@ salut_tubes_manager_init (SalutTubesManager *self) self->priv = priv; - priv->tubes_channels = g_hash_table_new_full (g_direct_hash, g_direct_equal, - NULL, g_object_unref); + priv->tubes = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, (GDestroyNotify) g_object_unref); priv->conn = NULL; priv->dispose_has_run = FALSE; @@ -122,7 +125,7 @@ extract_tube_information (TpHandleRepoIface *contact_repo, TpHandle *initiator_handle, const gchar **service, GHashTable **parameters, - guint *tube_id, + guint64 *tube_id, guint *portnum, GError **error) { @@ -188,8 +191,7 @@ extract_tube_information (TpHandleRepoIface *contact_repo, if (tube_id != NULL) { const gchar *str; - gchar *endptr; - long int tmp; + guint64 tmp; str = wocky_node_get_attribute (node, "id"); if (str == NULL) @@ -199,14 +201,14 @@ extract_tube_information (TpHandleRepoIface *contact_repo, return FALSE; } - tmp = strtol (str, &endptr, 10); - if (!endptr || *endptr) + tmp = g_ascii_strtoull (str, NULL, 10); + if (tmp == 0 || tmp > G_MAXUINT32) { g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, - "tube id is not numeric: %s", str); + "tube id is non-numeric or out of range: %s", str); return FALSE; } - *tube_id = (int) tmp; + *tube_id = tmp; } /* next fields are not in the close stanza */ @@ -295,12 +297,12 @@ iq_tube_request_cb (WockyPorter *porter, TpTubeType tube_type; TpHandle initiator_handle; GHashTable *parameters; - guint tube_id; + guint64 tube_id; guint portnum = 0; gboolean close_; GError *error = NULL; - SalutTubesChannel *chan; + SalutTubeIface *chan; /* after this point, the message is for us, so in all cases we either handle * it or send an error reply */ @@ -323,72 +325,33 @@ iq_tube_request_cb (WockyPorter *porter, return TRUE; } - DEBUG ("received a tube request, tube id %d", tube_id); + DEBUG ("received a tube request, tube id %" G_GUINT64_FORMAT, tube_id); + + chan = g_hash_table_lookup (priv->tubes, + GUINT_TO_POINTER (tube_id)); - chan = g_hash_table_lookup (priv->tubes_channels, - GUINT_TO_POINTER (initiator_handle)); if (close_) { if (chan != NULL) { - salut_tubes_channel_message_close_received (chan, initiator_handle, - tube_id); + DEBUG ("received a tube close message"); + salut_tube_iface_close (chan, TRUE); } } else { - SalutTubeIface *tube; - GHashTable *channels; - gboolean tubes_channel_created = FALSE; - if (chan == NULL) { - GError *e = NULL; - - chan = new_tubes_channel (self, initiator_handle, initiator_handle, - NULL, FALSE, &e); - - if (chan == NULL) - { - DEBUG ("couldn't make new tubes channel: %s", e->message); - g_error_free (e); - g_hash_table_unref (parameters); - return TRUE; - } - - tubes_channel_created = TRUE; + /* create new tube here */ + chan = create_new_tube (self, tube_type, + initiator_handle, service, parameters, tube_id, portnum, stanza); } - tube = salut_tubes_channel_message_received (chan, service, tube_type, - initiator_handle, parameters, tube_id, portnum, stanza); - - if (tube == NULL) - { - if (tubes_channel_created) - { - /* Destroy the tubes channel we just created as it's now - * useless */ - g_hash_table_remove (priv->tubes_channels, GUINT_TO_POINTER ( - initiator_handle)); - } - - g_hash_table_unref (parameters); - return TRUE; - } - - /* announce tubes and tube channels */ - channels = g_hash_table_new_full (g_direct_hash, g_direct_equal, - NULL, NULL); - - if (tubes_channel_created) - g_hash_table_insert (channels, chan, NULL); - - g_hash_table_insert (channels, tube, NULL); - - tp_channel_manager_emit_new_channels (self, channels); + /* announce tube channel */ + tp_channel_manager_emit_new_channel (self, + TP_EXPORTABLE_CHANNEL (chan), NULL); g_hash_table_unref (parameters); - g_hash_table_unref (channels); } return TRUE; @@ -408,14 +371,7 @@ salut_tubes_manager_close_all (SalutTubesManager *self) priv->status_changed_id = 0; } - if (priv->tubes_channels != NULL) - { - GHashTable *tmp; - - tmp = priv->tubes_channels; - priv->tubes_channels = NULL; - g_hash_table_unref (tmp); - } + tp_clear_pointer (&priv->tubes, g_hash_table_unref); } static void @@ -581,93 +537,6 @@ salut_tubes_manager_class_init ( } -/** - * tubes_channel_closed_cb: - * - * Signal callback for when a Tubes channel is closed. Removes the references - * that TubesManager holds to them. - */ -static void -tubes_channel_closed_cb (SalutTubesChannel *chan, - gpointer user_data) -{ - SalutTubesManager *conn = SALUT_TUBES_MANAGER (user_data); - SalutTubesManagerPrivate *priv = - SALUT_TUBES_MANAGER_GET_PRIVATE (conn); - TpHandle contact_handle; - - if (priv->tubes_channels == NULL) - return; - - g_object_get (chan, "handle", &contact_handle, NULL); - - DEBUG ("removing tubes channel with handle %d", contact_handle); - - g_hash_table_remove (priv->tubes_channels, GUINT_TO_POINTER (contact_handle)); -} - -/** - * new_tubes_channel - * - * Creates the SalutTubes object associated with the given parameters - */ -static SalutTubesChannel * -new_tubes_channel (SalutTubesManager *fac, - TpHandle handle, - TpHandle initiator, - gpointer request_token, - gboolean requested, - GError **error) -{ - SalutTubesManagerPrivate *priv; - TpBaseConnection *conn; - SalutTubesChannel *chan; - char *object_path; - SalutContact *contact; - - g_assert (SALUT_IS_TUBES_MANAGER (fac)); - - priv = SALUT_TUBES_MANAGER_GET_PRIVATE (fac); - conn = (TpBaseConnection *) priv->conn; - - contact = salut_contact_manager_get_contact (priv->contact_manager, handle); - - if (contact == NULL) - { - TpBaseConnection *base_conn = TP_BASE_CONNECTION (priv->conn); - TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( - base_conn, TP_HANDLE_TYPE_CONTACT); - - g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, - "%s is not online", tp_handle_inspect (contact_repo, handle)); - return NULL; - } - - object_path = g_strdup_printf ("%s/TubesChannel%u", conn->object_path, - handle); - - chan = g_object_new (SALUT_TYPE_TUBES_CHANNEL, - "connection", priv->conn, - "object-path", object_path, - "handle", handle, - "handle-type", TP_HANDLE_TYPE_CONTACT, - "contact", contact, - "initiator-handle", initiator, - "requested", requested, - NULL); - - DEBUG ("object path %s", object_path); - - g_signal_connect (chan, "closed", G_CALLBACK (tubes_channel_closed_cb), fac); - - g_hash_table_insert (priv->tubes_channels, GUINT_TO_POINTER (handle), chan); - - g_object_unref (contact); - g_free (object_path); - - return chan; -} - static void salut_tubes_manager_foreach_channel (TpChannelManager *manager, TpExportableChannelFunc foreach, @@ -679,19 +548,11 @@ salut_tubes_manager_foreach_channel (TpChannelManager *manager, GHashTableIter iter; gpointer value; - g_hash_table_iter_init (&iter, priv->tubes_channels); + g_hash_table_iter_init (&iter, priv->tubes); while (g_hash_table_iter_next (&iter, NULL, &value)) - { - TpExportableChannel *chan = TP_EXPORTABLE_CHANNEL (value); - - /* Add channels of type Channel.Type.Tubes */ - foreach (chan, user_data); - - /* Add channels of type Channel.Type.{Stream|DBus}Tube which live in the - * SalutTubesChannel object */ - salut_tubes_channel_foreach (SALUT_TUBES_CHANNEL (chan), foreach, - user_data); - } + { + foreach (TP_EXPORTABLE_CHANNEL (value), user_data); + } } static const gchar * const tubes_channel_fixed_properties[] = { @@ -700,11 +561,6 @@ static const gchar * const tubes_channel_fixed_properties[] = { NULL }; -static const gchar * const old_tubes_channel_allowed_properties[] = { - TP_IFACE_CHANNEL ".TargetHandle", - NULL -}; - static const gchar * const stream_tube_channel_allowed_properties[] = { TP_IFACE_CHANNEL ".TargetHandle", TP_IFACE_CHANNEL ".TargetID", @@ -730,24 +586,6 @@ salut_tubes_manager_type_foreach_channel_class (GType type, GHashTable *table; GValue *value; - /* 1-1 Channel.Type.Tubes */ - 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_static_string (value, TP_IFACE_CHANNEL_TYPE_TUBES); - g_hash_table_insert (table, TP_IFACE_CHANNEL ".ChannelType", - value); - - value = tp_g_value_slice_new (G_TYPE_UINT); - g_value_set_uint (value, TP_HANDLE_TYPE_CONTACT); - g_hash_table_insert (table, TP_IFACE_CHANNEL ".TargetHandleType", - value); - - func (type, table, old_tubes_channel_allowed_properties, user_data); - - g_hash_table_unref (table); - /* 1-1 Channel.Type.StreamTube */ table = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) tp_g_value_slice_free); @@ -789,6 +627,179 @@ salut_tubes_manager_type_foreach_channel_class (GType type, #endif } +static SalutTubeIface * +salut_tubes_manager_lookup (SalutTubesManager *self, + const gchar *type, + TpHandle handle, + const gchar *service) +{ + SalutTubesManagerPrivate *priv = + SALUT_TUBES_MANAGER_GET_PRIVATE (self); + GHashTableIter iter; + gpointer value; + + g_hash_table_iter_init (&iter, priv->tubes); + while (g_hash_table_iter_next (&iter, NULL, &value)) + { + SalutTubeIface *tube = value; + gboolean match = FALSE; + + gchar *channel_type, *channel_service; + TpHandle channel_handle; + + g_object_get (tube, + "channel-type", &channel_type, + "handle", &channel_handle, + "service", &channel_service, + NULL); + + if (!tp_strdiff (type, channel_type) + && handle == channel_handle + && !tp_strdiff (service, channel_service)) + match = TRUE; + + g_free (channel_type); + g_free (channel_service); + + if (match) + return tube; + } + + return NULL; +} + +static void +channel_closed_cb (SalutTubeIface *tube, + SalutTubesManager *self) +{ + SalutTubesManagerPrivate *priv = + SALUT_TUBES_MANAGER_GET_PRIVATE (self); + guint id; + + g_object_get (tube, + "id", &id, + NULL); + + tp_channel_manager_emit_channel_closed_for_object (self, + TP_EXPORTABLE_CHANNEL (tube)); + + if (priv->tubes != NULL) + g_hash_table_remove (priv->tubes, GUINT_TO_POINTER (id)); +} + +static guint64 +generate_tube_id (SalutTubesManager *self) +{ + SalutTubesManagerPrivate *priv = + SALUT_TUBES_MANAGER_GET_PRIVATE (self); + guint64 out; + + /* probably totally overkill */ + do + { + out = g_random_int_range (1, G_MAXINT32); + } + while (g_hash_table_lookup (priv->tubes, + GUINT_TO_POINTER (out)) != NULL); + + return out; +} + +static SalutTubeIface * +create_new_tube (SalutTubesManager *self, + TpTubeType type, + TpHandle handle, + const gchar *service, + GHashTable *parameters, + guint64 tube_id, + guint portnum, + WockyStanza *iq_req) +{ + SalutTubesManagerPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self, + SALUT_TYPE_TUBES_MANAGER, SalutTubesManagerPrivate); + TpBaseConnection *base_conn = TP_BASE_CONNECTION (priv->conn); + SalutTubeIface *tube; + + if (type == TP_TUBE_TYPE_STREAM) + { + tube = SALUT_TUBE_IFACE (salut_tube_stream_new (priv->conn, + handle, TP_HANDLE_TYPE_CONTACT, + base_conn->self_handle, base_conn->self_handle, FALSE, service, + parameters, tube_id, portnum, iq_req, TRUE)); + } + else if (type == TP_TUBE_TYPE_DBUS) + { + tube = SALUT_TUBE_IFACE (salut_tube_dbus_new (priv->conn, + handle, TP_HANDLE_TYPE_CONTACT, base_conn->self_handle, NULL, + base_conn->self_handle, service, parameters, tube_id, TRUE)); + } + else + { + g_return_val_if_reached (NULL); + } + + tp_base_channel_register ((TpBaseChannel *) tube); + + g_signal_connect (tube, "closed", + G_CALLBACK (channel_closed_cb), self); + + g_hash_table_insert (priv->tubes, GUINT_TO_POINTER (tube_id), + tube); + + return tube; +} + +/* Returns: (transfer none): new tube channel. the channel manager + * holds the ref to this channel, so don't unref it! */ +static SalutTubeIface * +new_channel_from_request (SalutTubesManager *self, + GHashTable *request) +{ + SalutTubeIface *tube; + + TpTubeType type; + const gchar *ctype, *service; + TpHandle handle; + guint64 tube_id; + GHashTable *parameters; + + ctype = tp_asv_get_string (request, TP_PROP_CHANNEL_CHANNEL_TYPE); + handle = tp_asv_get_uint32 (request, TP_PROP_CHANNEL_TARGET_HANDLE, NULL); + + tube_id = generate_tube_id (self); + + /* requested tubes have an empty parameters dict */ + parameters = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, + (GDestroyNotify) tp_g_value_slice_free); + + + if (!tp_strdiff (ctype, TP_IFACE_CHANNEL_TYPE_STREAM_TUBE)) + { + service = tp_asv_get_string (request, + TP_PROP_CHANNEL_TYPE_STREAM_TUBE_SERVICE); + + type = TP_TUBE_TYPE_STREAM; + } + else if (!tp_strdiff (ctype, TP_IFACE_CHANNEL_TYPE_DBUS_TUBE)) + { + service = tp_asv_get_string (request, + TP_PROP_CHANNEL_TYPE_DBUS_TUBE_SERVICE_NAME); + + type = TP_TUBE_TYPE_DBUS; + } + else + { + g_return_val_if_reached (NULL); + } + + tube = create_new_tube (self, type, handle, service, + parameters, tube_id, 0, NULL); + + g_hash_table_unref (parameters); + + return tube; +} + static gboolean salut_tubes_manager_requestotron (SalutTubesManager *self, gpointer request_token, @@ -803,8 +814,9 @@ salut_tubes_manager_requestotron (SalutTubesManager *self, TpHandle handle; GError *error = NULL; const gchar *channel_type; - SalutTubesChannel *tubes_channel; const gchar *service = NULL; + SalutTubeIface *new_channel; + GSList *tokens = NULL; if (tp_asv_get_uint32 (request_properties, TP_IFACE_CHANNEL ".TargetHandleType", NULL) != TP_HANDLE_TYPE_CONTACT) @@ -813,21 +825,13 @@ salut_tubes_manager_requestotron (SalutTubesManager *self, channel_type = tp_asv_get_string (request_properties, TP_IFACE_CHANNEL ".ChannelType"); - if (tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_TUBES) && + if ( /* Temporarily disabled since the implementation is incomplete. */ /* tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_DBUS_TUBE) && */ tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_STREAM_TUBE)) return FALSE; - if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_TUBES)) - { - if (tp_channel_manager_asv_has_unknown_properties (request_properties, - tubes_channel_fixed_properties, - old_tubes_channel_allowed_properties, - &error)) - goto error; - } - else if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_STREAM_TUBE)) + if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_STREAM_TUBE)) { if (tp_channel_manager_asv_has_unknown_properties (request_properties, tubes_channel_fixed_properties, @@ -894,74 +898,38 @@ salut_tubes_manager_requestotron (SalutTubesManager *self, goto error; } - tubes_channel = g_hash_table_lookup (priv->tubes_channels, - GUINT_TO_POINTER (handle)); + new_channel = salut_tubes_manager_lookup (self, channel_type, + handle, service); - if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_TUBES)) + if (new_channel == NULL) { - if (tubes_channel == NULL) - { - GSList *tokens = NULL; - - tubes_channel = new_tubes_channel (self, handle, - base_conn->self_handle, request_token, TRUE, &error); - - if (tubes_channel == NULL) - goto error; - - tokens = g_slist_prepend (tokens, request_token); + new_channel = new_channel_from_request (self, + request_properties); + g_assert (new_channel != NULL); - tp_channel_manager_emit_new_channel (self, - TP_EXPORTABLE_CHANNEL (tubes_channel), tokens); + if (request_token != NULL) + tokens = g_slist_prepend (NULL, request_token); - g_slist_free (tokens); - return TRUE; - } + tp_channel_manager_emit_new_channel (self, + TP_EXPORTABLE_CHANNEL (new_channel), tokens); + g_slist_free (tokens); + } + else + { if (require_new) { g_set_error (&error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, - "A tube channel with contact #%u already exists", handle); - DEBUG ("A tube channel with contact #%u already exists", handle); + "A channel to #%u (service: %s) is already open", + handle, service); goto error; } tp_channel_manager_emit_request_already_satisfied (self, - request_token, TP_EXPORTABLE_CHANNEL (tubes_channel)); - return TRUE; + request_token, TP_EXPORTABLE_CHANNEL (new_channel)); } - else - { - SalutTubeIface *new_channel; - GSList *tokens = NULL; - GHashTable *channels; - - if (tubes_channel == NULL) - { - tubes_channel = new_tubes_channel (self, handle, - base_conn->self_handle, NULL, FALSE, &error); - if (tubes_channel == NULL) - goto error; - } - - new_channel = salut_tubes_channel_tube_request (tubes_channel, - request_token, request_properties, require_new); - g_assert (new_channel != NULL); - - if (request_token != NULL) - tokens = g_slist_prepend (NULL, request_token); - channels = g_hash_table_new_full (g_direct_hash, g_direct_equal, - NULL, NULL); - g_hash_table_insert (channels, tubes_channel, NULL); - g_hash_table_insert (channels, new_channel, tokens); - - tp_channel_manager_emit_new_channels (self, channels); - - g_hash_table_unref (channels); - g_slist_free (tokens); - return TRUE; - } + return TRUE; error: tp_channel_manager_emit_request_failed (self, request_token, @@ -1215,8 +1183,7 @@ gabble_private_tubes_factory_add_cap (GabbleCapsChannelManager *manager, TP_IFACE_CHANNEL ".ChannelType"); /* this channel is not for this factory */ - if (tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_TUBES) && - tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_STREAM_TUBE) && + if (tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_STREAM_TUBE) && tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_DBUS_TUBE)) return; diff --git a/src/tubes-manager.h b/src/tubes-manager.h index 1697d9e0..449f6134 100644 --- a/src/tubes-manager.h +++ b/src/tubes-manager.h @@ -25,7 +25,6 @@ #include <telepathy-glib/base-connection.h> #include "connection.h" #include "contact-manager.h" -#include "tubes-channel.h" G_BEGIN_DECLS diff --git a/tests/twisted/Makefile.am b/tests/twisted/Makefile.am index 9dc553c7..1a37388d 100644 --- a/tests/twisted/Makefile.am +++ b/tests/twisted/Makefile.am @@ -13,6 +13,7 @@ TWISTED_AVAHI_TESTS = \ avahi/muc-invite.py \ avahi/caps-file-transfer.py \ avahi/close-local-pending-room.py \ + avahi/only-text-muc-when-needed.py \ avahi/tubes/disabled-1-1-tubes.py \ avahi/file-transfer/send-file-and-cancel-immediately.py \ avahi/file-transfer/send-file-and-disconnect.py \ diff --git a/tests/twisted/avahi/only-text-muc-when-needed.py b/tests/twisted/avahi/only-text-muc-when-needed.py new file mode 100644 index 00000000..40bb1ab5 --- /dev/null +++ b/tests/twisted/avahi/only-text-muc-when-needed.py @@ -0,0 +1,318 @@ +""" +Test support for creating MUC text channels when necessary, not all +the time. + +This test is a copy of gabble's. It's not quite as good as gabble's as +that one really tests that the XMPP MUC is left but that's harder. Oh +well. +""" + +import dbus + +from servicetest import call_async, EventPattern, assertEquals, \ + sync_dbus, wrap_channel +from saluttest import exec_test +import constants as cs +import ns + +def request_stream_tube(q, bus, conn, method, jid): + call_async(q, conn.Requests, method, + { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAM_TUBE, + cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, + cs.TARGET_ID: jid, + cs.STREAM_TUBE_SERVICE: 'the.service', + }) + +def stream_tube(q, bus, conn, method, jid): + request_stream_tube(q, bus, conn, method, jid) + e, _ = q.expect_many(EventPattern('dbus-return', method=method), + EventPattern('dbus-signal', signal='NewChannels')) + + # sigh + if method == 'EnsureChannel': + path = e.value[1] + else: + path = e.value[0] + + tube_chan = wrap_channel(bus.get_object(conn.bus_name, path), 'StreamTube') + + return (tube_chan,) + e.value + +def request_text_channel(q, bus, conn, method, jid): + call_async(q, conn.Requests, method, + { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, + cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, + cs.TARGET_ID: jid, + }) + +def text_channel(q, bus, conn, method, jid, presence=True): + request_text_channel(q, bus, conn, method, jid) + e, _ = q.expect_many(EventPattern('dbus-return', method=method), + EventPattern('dbus-signal', signal='NewChannels')) + + # sigh + if method == 'EnsureChannel': + path = e.value[1] + else: + path = e.value[0] + + text_chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text') + + return (text_chan,) + e.value + +def expect_close(q, path): + q.expect_many(EventPattern('dbus-signal', signal='ChannelClosed', + args=[path]), + EventPattern('dbus-signal', signal='Closed', + path=path)) + +def connect(q, bus, conn): + conn.Connect() + q.expect('dbus-signal', signal='StatusChanged', + args=[cs.CONN_STATUS_CONNECTED, cs.CSR_NONE_SPECIFIED]) + +def stream_tube_predicate(e): + channels = e.args[0] + _, props = channels[0] + return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_TUBE + +def assert_on_bus(q, chan): + call_async(q, chan.Properties, 'GetAll', cs.CHANNEL) + e = q.expect('dbus-return', method='GetAll') + props = e.value[0] + assert 'ChannelType' in props + +def assert_not_on_bus(q, chan): + call_async(q, chan.Properties, 'GetAll', cs.CHANNEL) + q.expect('dbus-error', method='GetAll', + name='org.freedesktop.DBus.Error.UnknownMethod') + +# tests start here + +def tube_no_text(q, bus, conn): + jid = 'test-muc' + + connect(q, bus, conn) + + # create a stream tube. + # this will need a MUC channel to be opened, but we want to make + # sure it doesn't get signalled. + request_stream_tube(q, bus, conn, 'CreateChannel', jid) + + ret, new_sig = q.expect_many( + EventPattern('dbus-return', method='CreateChannel'), + EventPattern('dbus-signal', signal='NewChannels', + predicate=stream_tube_predicate)) + + forbidden = [EventPattern('dbus-signal', signal='NewChannels')] + q.forbid_events(forbidden) + + tube_path, tube_props = ret.value + assertEquals(cs.CHANNEL_TYPE_STREAM_TUBE, tube_props[cs.CHANNEL_TYPE]) + + channels = new_sig.args[0] + assertEquals(1, len(channels)) + path, props = channels[0] + + assertEquals(tube_path, path) + assertEquals(tube_props, props) + + sync_dbus(bus, q, conn) + + q.unforbid_events(forbidden) + +def tube_then_text(q, bus, conn): + jid = 'test-muc' + + connect(q, bus, conn) + + # first let's get a stream tube + tube_chan, _, _ = stream_tube(q, bus, conn, 'CreateChannel', jid) + + # now let's try and ensure the text channel which should happen + # immediately + request_text_channel(q, bus, conn, 'EnsureChannel', jid) + + ret = q.expect('dbus-return', method='EnsureChannel') + + yours, text_path, text_props = ret.value + assertEquals(True, yours) + assertEquals(cs.CHANNEL_TYPE_TEXT, text_props[cs.CHANNEL_TYPE]) + + new_sig = q.expect('dbus-signal', signal='NewChannels') + + channels = new_sig.args[0] + assertEquals(1, len(channels)) + path, props = channels[0] + + assertEquals(text_path, path) + assertEquals(text_props, props) + +def tube_remains_text_closes(q, bus, conn): + jid = 'test-muc' + + connect(q, bus, conn) + + text_chan, text_path, _ = text_channel(q, bus, conn, 'CreateChannel', jid) + tube_chan, tube_path, _ = stream_tube(q, bus, conn, 'CreateChannel', jid) + + # now let's try and close the text channel + # this should happen sucessfully but the tube channel + # should stick around + forbidden = [EventPattern('dbus-signal', signal='ChannelClosed', + args=[tube_path])] + q.forbid_events(forbidden) + + assert_on_bus(q, tube_chan) + assert_on_bus(q, text_chan) + + text_chan.Close() + expect_close(q, text_path) + + sync_dbus(bus, q, conn) + + assert_on_bus(q, tube_chan) + assert_not_on_bus(q, text_chan) + + q.unforbid_events(forbidden) + +def normally_close_text(q, bus, conn): + jid = 'test-muc' + + connect(q, bus, conn) + + text_chan, text_path, _ = text_channel(q, bus, conn, 'CreateChannel', jid) + + text_chan.Close() + expect_close(q, text_path) + + assert_not_on_bus(q, text_chan) + +def text_can_automatically_close(q, bus, conn): + jid = 'test-muc' + + connect(q, bus, conn) + + tube_chan, tube_path, _ = stream_tube(q, bus, conn, 'CreateChannel', jid) + + sync_dbus(bus, q, conn) + + tube_chan.Close() + expect_close(q, tube_path) + + assert_not_on_bus(q, tube_chan) + +def text_remains_after_tube(q, bus, conn): + jid = 'test-muc' + + connect(q, bus, conn) + + tube_chan, tube_path, _ = stream_tube(q, bus, conn, 'CreateChannel', jid) + text_chan, text_path, _ = text_channel(q, bus, conn, 'CreateChannel', jid) + + sync_dbus(bus, q, conn) + + tube_chan.Close() + expect_close(q, tube_path) + + assert_not_on_bus(q, tube_chan) + assert_on_bus(q, text_chan) + + call_async(q, text_chan.Properties, 'GetAll', cs.CHANNEL_TYPE_TEXT) + q.expect('dbus-return', method='GetAll') + + text_chan.Close() + expect_close(q, text_path) + + assert_not_on_bus(q, tube_chan) + assert_not_on_bus(q, text_chan) + +def recreate_text(q, bus, conn): + jid = 'test-muc' + + connect(q, bus, conn) + + tube_chan, _, _ = stream_tube(q, bus, conn, 'CreateChannel', jid) + text_chan, text_path, text_props = text_channel(q, bus, conn, + 'CreateChannel', jid) + + text_chan.Close() + expect_close(q, text_path) + + assert_on_bus(q, tube_chan) + assert_not_on_bus(q, text_chan) + + # now let's try and create the same text channel and hope we get + # back the same channel + + request_text_channel(q, bus, conn, 'CreateChannel', jid) + + ret = q.expect('dbus-return', method='CreateChannel') + + path, props = ret.value + assertEquals(cs.CHANNEL_TYPE_TEXT, props[cs.CHANNEL_TYPE]) + + new_sig = q.expect('dbus-signal', signal='NewChannels') + + channels = new_sig.args[0] + assertEquals(1, len(channels)) + + assertEquals(path, channels[0][0]) + assertEquals(props, channels[0][1]) + + # the channel should be identical given it's the same MucChannel + assertEquals(text_path, path) + assertEquals(text_props, props) + + assert_on_bus(q, tube_chan) + assert_on_bus(q, text_chan) + +def test_channels(q, bus, conn): + jid = 'test-muc' + + connect(q, bus, conn) + + tube_chan, _, _ = stream_tube(q, bus, conn, 'CreateChannel', jid) + text_chan, text_path, _ = text_channel(q, bus, conn,'CreateChannel', jid) + + text_chan.Close() + expect_close(q, text_path) + + # the following are basically the same as assert_[not_]on_bus() + # but they look pretty. + + # methods on the text channel should fail + call_async(q, text_chan.Properties, 'GetAll', cs.CHANNEL_TYPE_TEXT) + q.expect('dbus-error', method='GetAll') + + # but methods on the tube should pass + call_async(q, tube_chan.Properties, 'GetAll', cs.CHANNEL_TYPE_STREAM_TUBE) + q.expect('dbus-return', method='GetAll') + +if __name__ == '__main__': + # request tube, assert no text appears + exec_test(tube_no_text) + + # request tube, request text (no presence), assert both appear + exec_test(tube_then_text) + + # request tube & text, close text, assert tube doesn't close + exec_test(tube_remains_text_closes) + + # request text, close text, assert unavailable presence + exec_test(normally_close_text) + + # request tube, close tube, assert unavailable presence + exec_test(text_can_automatically_close) + + # request tube & text, close tube, assert text doesn't close + exec_test(text_remains_after_tube) + + # request tube & text, close text, request text (no presence), + # assert appears as normal + exec_test(recreate_text) + + # request tube & text, close text, assert GetAll on text fails but + # works on tube + exec_test(test_channels) + diff --git a/tests/twisted/avahi/tubes/request-muc-tubes.py b/tests/twisted/avahi/tubes/request-muc-tubes.py index 999e85bb..8608fa0a 100644 --- a/tests/twisted/avahi/tubes/request-muc-tubes.py +++ b/tests/twisted/avahi/tubes/request-muc-tubes.py @@ -9,7 +9,7 @@ import avahitest from twisted.words.xish import domish from saluttest import exec_test, wait_for_contact_list -from servicetest import call_async, EventPattern, make_channel_proxy +from servicetest import call_async, EventPattern, wrap_channel, pretty from constants import * def test(q, bus, conn): @@ -23,68 +23,20 @@ def test(q, bus, conn): # announced so they won't interfere with the muc ones announces. wait_for_contact_list(q, conn) - # check if we can request roomlist channels - properties = conn.GetAll(CONN_IFACE_REQUESTS, dbus_interface=PROPERTIES_IFACE) - assert ({CHANNEL_TYPE: CHANNEL_TYPE_TUBES, + # check if we can request tube channels + properties = conn.Properties.GetAll(CONN_IFACE_REQUESTS) + assert ({CHANNEL_TYPE: CHANNEL_TYPE_STREAM_TUBE, TARGET_HANDLE_TYPE: HT_ROOM}, - [TARGET_HANDLE, TARGET_ID], + [TARGET_HANDLE, TARGET_ID, STREAM_TUBE_SERVICE], ) in properties.get('RequestableChannelClasses'),\ properties['RequestableChannelClasses'] - # request a muc tubes channel using the old API - handle = conn.RequestHandles(HT_ROOM, ['my-first-room'])[0] - call_async(q, conn, 'RequestChannel', CHANNEL_TYPE_TUBES, HT_ROOM, handle, True) - - ret, old_sig, new_sig = q.expect_many( - EventPattern('dbus-return', method='RequestChannel'), - EventPattern('dbus-signal', signal='NewChannel'), - EventPattern('dbus-signal', signal='NewChannels'), - ) - - path1 = ret.value[0] - chan = make_channel_proxy(conn, path1, "Channel") - - # text and tubes channels are announced - channels = new_sig.args[0] - assert len(channels) == 2 - got_text, got_tubes = False, False - - for path, props in channels: - if props[CHANNEL_TYPE] == CHANNEL_TYPE_TEXT: - got_text = True - assert props[REQUESTED] == False - elif props[CHANNEL_TYPE] == CHANNEL_TYPE_TUBES: - got_tubes = True - assert props[REQUESTED] == True - else: - assert False - - assert props[TARGET_HANDLE_TYPE] == HT_ROOM - assert props[TARGET_HANDLE] == handle - assert props[TARGET_ID] == 'my-first-room' - assert props[INITIATOR_HANDLE] == conn.GetSelfHandle() - assert props[INITIATOR_ID] == self_name - - # Exercise basic Channel Properties from spec 0.17.7 - channel_props = chan.GetAll(CHANNEL, dbus_interface=PROPERTIES_IFACE) - assert channel_props.get('TargetHandle') == handle,\ - channel_props.get('TargetHandle') - assert channel_props['TargetID'] == 'my-first-room', channel_props - assert channel_props.get('TargetHandleType') == HT_ROOM,\ - channel_props.get('TargetHandleType') - assert channel_props.get('ChannelType') == \ - CHANNEL_TYPE_TUBES, channel_props.get('ChannelType') - assert channel_props['Requested'] == True - assert channel_props['InitiatorID'] == self_name - assert channel_props['InitiatorHandle'] == conn.GetSelfHandle() - - requestotron = dbus.Interface(conn, CONN_IFACE_REQUESTS) - # create muc channel using new API - call_async(q, requestotron, 'CreateChannel', - { CHANNEL_TYPE: CHANNEL_TYPE_TUBES, + call_async(q, conn.Requests, 'CreateChannel', + { CHANNEL_TYPE: CHANNEL_TYPE_STREAM_TUBE, TARGET_HANDLE_TYPE: HT_ROOM, TARGET_ID: 'my-second-room', + STREAM_TUBE_SERVICE: 'loldongs', }) ret, old_sig, new_sig = q.expect_many( @@ -92,61 +44,55 @@ def test(q, bus, conn): EventPattern('dbus-signal', signal='NewChannel'), EventPattern('dbus-signal', signal='NewChannels'), ) - path2 = ret.value[0] - chan = make_channel_proxy(conn, path2, "Channel") + tube_path = ret.value[0] + chan = wrap_channel(bus.get_object(conn.bus_name, tube_path), + 'StreamTube') handle = conn.RequestHandles(HT_ROOM, ['my-second-room'])[0] - tubes_props = ret.value[1] - assert tubes_props[CHANNEL_TYPE] == CHANNEL_TYPE_TUBES - assert tubes_props[TARGET_HANDLE_TYPE] == HT_ROOM - assert tubes_props[TARGET_HANDLE] == handle - assert tubes_props[TARGET_ID] == 'my-second-room' - assert tubes_props[REQUESTED] == True - assert tubes_props[INITIATOR_HANDLE] == conn.GetSelfHandle() - assert tubes_props[INITIATOR_ID] == self_name + tube_props = ret.value[1] + assert tube_props[CHANNEL_TYPE] == CHANNEL_TYPE_STREAM_TUBE + assert tube_props[TARGET_HANDLE_TYPE] == HT_ROOM + assert tube_props[TARGET_HANDLE] == handle + assert tube_props[TARGET_ID] == 'my-second-room' + assert tube_props[REQUESTED] == True + assert tube_props[INITIATOR_HANDLE] == conn.GetSelfHandle() + assert tube_props[INITIATOR_ID] == self_name - # text and tubes channels are announced + # text and tube channels are announced channels = new_sig.args[0] - assert len(channels) == 2 - got_text, got_tubes = False, False - - for path, props in channels: - if props[CHANNEL_TYPE] == CHANNEL_TYPE_TEXT: - got_text = True - assert props[REQUESTED] == False - elif props[CHANNEL_TYPE] == CHANNEL_TYPE_TUBES: - got_tubes = True - assert props == tubes_props - assert path == path2 - else: - assert False - - assert props[TARGET_HANDLE_TYPE] == HT_ROOM - assert props[TARGET_HANDLE] == handle - assert props[TARGET_ID] == 'my-second-room' - assert props[INITIATOR_HANDLE] == conn.GetSelfHandle() - assert props[INITIATOR_ID] == self_name - - # ensure roomlist channel - yours, ensured_path, ensured_props = requestotron.EnsureChannel( - { CHANNEL_TYPE: CHANNEL_TYPE_TUBES, - TARGET_HANDLE_TYPE: HT_ROOM, - TARGET_HANDLE: handle, - }) - - assert not yours - assert ensured_path == path2, (ensured_path, path2) + assert len(channels) == 1 + + path, props = channels[0] + assert props[CHANNEL_TYPE] == CHANNEL_TYPE_STREAM_TUBE + assert path == tube_path + assert props == tube_props + assert props[TARGET_HANDLE_TYPE] == HT_ROOM + assert props[TARGET_HANDLE] == handle + assert props[TARGET_ID] == 'my-second-room' + assert props[INITIATOR_HANDLE] == conn.GetSelfHandle() + assert props[INITIATOR_ID] == self_name + + # ensure the same channel + +# TODO: the muc channel doesn't bother to look at existing tubes +# before creating a new one. once that's fixed, uncomment this. +# yours, ensured_path, _ = conn.Requests.EnsureChannel( +# { CHANNEL_TYPE: CHANNEL_TYPE_STREAM_TUBE, +# TARGET_HANDLE_TYPE: HT_ROOM, +# TARGET_HANDLE: handle, +# STREAM_TUBE_SERVICE: 'loldongs', +# }) + +# assert not yours +# assert ensured_path == tube_path, (ensured_path, tube_path) conn.Disconnect() q.expect_many( EventPattern('dbus-signal', signal='Closed', - path=path1), - EventPattern('dbus-signal', signal='Closed', - path=path2), - EventPattern('dbus-signal', signal='ChannelClosed', args=[path1]), - EventPattern('dbus-signal', signal='ChannelClosed', args=[path2]), + path=tube_path), + EventPattern('dbus-signal', signal='ChannelClosed', args=[tube_path]), EventPattern('dbus-signal', signal='StatusChanged', args=[2, 1]), ) diff --git a/tests/twisted/avahi/tubes/two-muc-dbus-tubes.py b/tests/twisted/avahi/tubes/two-muc-dbus-tubes.py index a87a4cbe..c34a8e2e 100644 --- a/tests/twisted/avahi/tubes/two-muc-dbus-tubes.py +++ b/tests/twisted/avahi/tubes/two-muc-dbus-tubes.py @@ -2,7 +2,7 @@ from saluttest import exec_test import dbus from dbus.service import method, signal, Object -from servicetest import make_channel_proxy, call_async, EventPattern, Event +from servicetest import wrap_channel, call_async, EventPattern, Event import constants as cs import tubetestutil as t @@ -17,8 +17,7 @@ sample_parameters = dbus.Dictionary({ muc_name = "test-two-muc-stream-tubes" def check_dbus_names(tube, members): - names = tube.Get(cs.CHANNEL_TYPE_DBUS_TUBE, 'DBusNames', - dbus_interface=cs.PROPERTIES_IFACE) + names = tube.Properties.Get(cs.CHANNEL_TYPE_DBUS_TUBE, 'DBusNames') assert set(names.keys()) == set(members), names.keys() SERVICE = "org.freedesktop.Telepathy.Tube.Test" @@ -72,49 +71,31 @@ def test(q, bus, conn): e = q.expect('dbus-signal', signal='NewChannels') channels = e.args[0] - assert len(channels) == 2 + assert len(channels) == 1 # get the list of all channels to check that newly announced ones are in it all_channels = conn.Get(cs.CONN_IFACE_REQUESTS, 'Channels', dbus_interface=cs.PROPERTIES_IFACE, byte_arrays=True) - got_tubes, got_tube = False, False - for path, props in channels: - if props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_TUBES: - got_tubes = True - assert props[cs.REQUESTED] == False - assert props[cs.INTERFACES] == [cs.CHANNEL_IFACE_GROUP] - elif props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_DBUS_TUBE: - got_tube = True - assert props[cs.REQUESTED] == True - assert props[cs.INTERFACES] == [cs.CHANNEL_IFACE_GROUP, - cs.CHANNEL_IFACE_TUBE] - assert props[cs.DBUS_TUBE_SERVICE_NAME] == 'com.example.TestCase' - assert props[cs.DBUS_TUBE_SUPPORTED_ACCESS_CONTROLS] == [ - cs.SOCKET_ACCESS_CONTROL_CREDENTIALS, cs.SOCKET_ACCESS_CONTROL_LOCALHOST] - - contact1_tube = bus.get_object(conn.bus_name, path) - contact1_dbus_tube = make_channel_proxy(conn, path, - "Channel.Type.DBusTube") - contact1_tube_channel = make_channel_proxy(conn, path, "Channel") - tube1_path = path - else: - assert False - - assert props[cs.INITIATOR_HANDLE] == conn1_self_handle - assert props[cs.INITIATOR_ID] == contact1_name - assert props[cs.TARGET_ID] == muc_name - - assert (path, props) in all_channels, (path, props) - - assert got_tubes - assert got_tube - - state = contact1_dbus_tube.Get(cs.CHANNEL_IFACE_TUBE, 'State', - dbus_interface=cs.PROPERTIES_IFACE) + path, props = channels[0] + + assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_DBUS_TUBE + assert props[cs.REQUESTED] == True + assert props[cs.INTERFACES] == [cs.CHANNEL_IFACE_GROUP, + cs.CHANNEL_IFACE_TUBE] + assert props[cs.DBUS_TUBE_SERVICE_NAME] == 'com.example.TestCase' + assert props[cs.DBUS_TUBE_SUPPORTED_ACCESS_CONTROLS] == [ + cs.SOCKET_ACCESS_CONTROL_CREDENTIALS, cs.SOCKET_ACCESS_CONTROL_LOCALHOST] + + contact1_tube = wrap_channel(bus.get_object(conn.bus_name, path), 'DBusTube') + tube1_path = path + + assert (path, props) in all_channels, (path, props) + + state = contact1_tube.Properties.Get(cs.CHANNEL_IFACE_TUBE, 'State') assert state == cs.TUBE_CHANNEL_STATE_NOT_OFFERED - call_async(q, contact1_dbus_tube, 'Offer', sample_parameters, + call_async(q, contact1_tube.DBusTube, 'Offer', sample_parameters, cs.SOCKET_ACCESS_CONTROL_CREDENTIALS) _, e = q.expect_many( @@ -124,11 +105,10 @@ def test(q, bus, conn): tube_addr1 = e.value[0] - state = contact1_dbus_tube.Get(cs.CHANNEL_IFACE_TUBE, 'State', - dbus_interface=cs.PROPERTIES_IFACE) + state = contact1_tube.Properties.Get(cs.CHANNEL_IFACE_TUBE, 'State') assert state == cs.TUBE_CHANNEL_STATE_OPEN - check_dbus_names(contact1_dbus_tube, [conn1_self_handle]) + check_dbus_names(contact1_tube, [conn1_self_handle]) t.invite_to_muc(q, group1, conn2, contact2_handle_on_conn1, contact1_handle_on_conn2) @@ -138,44 +118,27 @@ def test(q, bus, conn): EventPattern('dbus-signal', signal='DBusNamesChanged', interface=cs.CHANNEL_TYPE_DBUS_TUBE)) channels = e.args[0] - assert len(channels) == 2 + assert len(channels) == 1 # get the list of all channels to check that newly announced ones are in it all_channels = conn2.Get(cs.CONN_IFACE_REQUESTS, 'Channels', dbus_interface=cs.PROPERTIES_IFACE, byte_arrays=True) - got_tubes, got_tube = False, False - for path, props in channels: - if props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_TUBES: - got_tubes = True - assert props[cs.REQUESTED] == False - assert props[cs.INTERFACES] == [cs.CHANNEL_IFACE_GROUP] - elif props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_DBUS_TUBE: - got_tube = True - assert props[cs.REQUESTED] == False - assert props[cs.INTERFACES] == [cs.CHANNEL_IFACE_GROUP, - cs.CHANNEL_IFACE_TUBE] - assert props[cs.TUBE_PARAMETERS] == sample_parameters - assert props[cs.DBUS_TUBE_SERVICE_NAME] == 'com.example.TestCase' - assert props[cs.DBUS_TUBE_SUPPORTED_ACCESS_CONTROLS] == [ - cs.SOCKET_ACCESS_CONTROL_CREDENTIALS, cs.SOCKET_ACCESS_CONTROL_LOCALHOST] - - contact2_tube = bus.get_object(conn.bus_name, path) - contact2_dbus_tube = make_channel_proxy(conn, path, - "Channel.Type.DBusTube") - contact2_tube_channel = make_channel_proxy(conn, path, "Channel") - tube2_path = path - else: - assert False - - assert props[cs.INITIATOR_HANDLE] == contact1_handle_on_conn2 - assert props[cs.INITIATOR_ID] == contact1_name - assert props[cs.TARGET_ID] == muc_name - - assert (path, props) in all_channels, (path, props) - - assert got_tubes - assert got_tube + path, props = channels[0] + + assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_DBUS_TUBE + assert props[cs.REQUESTED] == False + assert props[cs.INTERFACES] == [cs.CHANNEL_IFACE_GROUP, + cs.CHANNEL_IFACE_TUBE] + assert props[cs.TUBE_PARAMETERS] == sample_parameters + assert props[cs.DBUS_TUBE_SERVICE_NAME] == 'com.example.TestCase' + assert props[cs.DBUS_TUBE_SUPPORTED_ACCESS_CONTROLS] == [ + cs.SOCKET_ACCESS_CONTROL_CREDENTIALS, cs.SOCKET_ACCESS_CONTROL_LOCALHOST] + + contact2_tube = wrap_channel(bus.get_object(conn.bus_name, path), 'DBusTube') + tube2_path = path + + assert (path, props) in all_channels, (path, props) # second connection: check DBusNamesChanged signal assert dbus_names_e.path == tube2_path @@ -183,18 +146,16 @@ def test(q, bus, conn): assert added.keys() == [contact1_handle_on_conn2] assert removed == [] - state = contact2_tube.Get(cs.CHANNEL_IFACE_TUBE, 'State', - dbus_interface=cs.PROPERTIES_IFACE) + state = contact2_tube.Properties.Get(cs.CHANNEL_IFACE_TUBE, 'State') assert state == cs.TUBE_CHANNEL_STATE_LOCAL_PENDING # first connection: contact2 is not in the tube yet - check_dbus_names(contact1_dbus_tube, [conn1_self_handle]) + check_dbus_names(contact1_tube, [conn1_self_handle]) # second connection: accept the tube (new API) - tube_addr2 = unix_socket_adr = contact2_dbus_tube.Accept(cs.SOCKET_ACCESS_CONTROL_CREDENTIALS) + tube_addr2 = unix_socket_adr = contact2_tube.DBusTube.Accept(cs.SOCKET_ACCESS_CONTROL_CREDENTIALS) - state = contact2_tube.Get(cs.CHANNEL_IFACE_TUBE, 'State', - dbus_interface=cs.PROPERTIES_IFACE) + state = contact2_tube.Properties.Get(cs.CHANNEL_IFACE_TUBE, 'State') assert state == cs.TUBE_CHANNEL_STATE_OPEN e, dbus_names_e = q.expect_many( @@ -207,10 +168,10 @@ def test(q, bus, conn): assert added.keys() == [contact2_handle_on_conn1] assert removed == [] - check_dbus_names(contact1_dbus_tube, [conn1_self_handle, contact2_handle_on_conn1]) - check_dbus_names(contact2_dbus_tube, [conn2_self_handle, contact1_handle_on_conn2]) + check_dbus_names(contact1_tube, [conn1_self_handle, contact2_handle_on_conn1]) + check_dbus_names(contact2_tube, [conn2_self_handle, contact1_handle_on_conn2]) - tube2_names = contact2_dbus_tube.Get(cs.CHANNEL_TYPE_DBUS_TUBE, 'DBusNames', + tube2_names = contact2_tube.Get(cs.CHANNEL_TYPE_DBUS_TUBE, 'DBusNames', dbus_interface=cs.PROPERTIES_IFACE) tube_conn1 = dbus.connection.Connection(tube_addr1) @@ -244,11 +205,10 @@ def test(q, bus, conn): q.expect('tube-dbus-call', method='MyMethod', args=[42]) q.expect('tube-dbus-return', method='MyMethod', value=[420]) - call_async(q, contact1_tube_channel, 'Close') - _, _, _, _, dbus_names_e = q.expect_many( + call_async(q, contact1_tube, 'Close') + _, _, _, dbus_names_e = q.expect_many( EventPattern('dbus-return', method='Close'), EventPattern('dbus-signal', signal='Closed'), - EventPattern('dbus-signal', signal='TubeClosed'), EventPattern('dbus-signal', signal='ChannelClosed'), EventPattern('dbus-signal', signal='DBusNamesChanged', interface=cs.CHANNEL_TYPE_DBUS_TUBE, path=tube2_path)) @@ -258,13 +218,12 @@ def test(q, bus, conn): assert added == {} assert removed == [contact1_handle_on_conn2] - check_dbus_names(contact2_dbus_tube, [conn2_self_handle]) + check_dbus_names(contact2_tube, [conn2_self_handle]) - call_async(q, contact2_tube_channel, 'Close') + call_async(q, contact2_tube, 'Close') q.expect_many( EventPattern('dbus-return', method='Close'), EventPattern('dbus-signal', signal='Closed'), - EventPattern('dbus-signal', signal='TubeClosed'), EventPattern('dbus-signal', signal='ChannelClosed')) conn.Disconnect() diff --git a/tests/twisted/avahi/tubes/two-muc-stream-tubes.py b/tests/twisted/avahi/tubes/two-muc-stream-tubes.py index b4d7a084..82696335 100644 --- a/tests/twisted/avahi/tubes/two-muc-stream-tubes.py +++ b/tests/twisted/avahi/tubes/two-muc-stream-tubes.py @@ -5,7 +5,7 @@ import errno import string import tempfile -from servicetest import make_channel_proxy, Event, call_async, EventPattern +from servicetest import wrap_channel, Event, call_async, EventPattern from twisted.internet.protocol import Factory, Protocol, ClientCreator from twisted.internet import reactor @@ -22,7 +22,6 @@ sample_parameters = dbus.Dictionary({ test_string = "This string travels on a tube !" muc_name = "test-two-muc-stream-tubes" -muc2_name = "test-two-muc-stream-tubes-2" SERVER_WELCOME_MSG = "Welcome!" @@ -56,191 +55,58 @@ def test(q, bus, conn): # create the server factory = Factory() factory.protocol = TrivialServer - server_socket_address = tempfile.mkstemp()[1] - try: - os.remove(server_socket_address) - except OSError, e: - if e.errno != errno.ENOENT: - raise - l = reactor.listenUNIX(server_socket_address, factory) + + def listen_for_connections(): + server_socket_address = tempfile.mkstemp()[1] + try: + os.remove(server_socket_address) + except OSError, e: + if e.errno != errno.ENOENT: + raise + reactor.listenUNIX(server_socket_address, factory) + return server_socket_address + + server_socket_address = listen_for_connections() contact1_name, conn2, contact2_name, contact2_handle_on_conn1,\ contact1_handle_on_conn2 = t.connect_two_accounts(q, bus, conn) conn1_self_handle = conn.GetSelfHandle() - # first connection: join muc - muc_handle1, group1 = t.join_muc(q, conn, muc_name) - - t.invite_to_muc(q, group1, conn2, contact2_handle_on_conn1, contact1_handle_on_conn2) - - # first connection: offer a muc stream tube (old API) - tubes1_path = conn.RequestChannel(CHANNEL_TYPE_TUBES, HT_ROOM, muc_handle1, - True) - contact1_tubes_channel = make_channel_proxy(conn, tubes1_path, - "Channel.Type.Tubes") - - q.expect('dbus-signal', signal='NewChannel', - args=[tubes1_path, CHANNEL_TYPE_TUBES, HT_ROOM, muc_handle1, True]) - - conn1_tube_id = contact1_tubes_channel.OfferStreamTube("http", - sample_parameters, SOCKET_ADDRESS_TYPE_UNIX, - dbus.ByteArray(server_socket_address), - SOCKET_ACCESS_CONTROL_LOCALHOST, "") - - e = q.expect('dbus-signal', signal='NewTube', path=tubes1_path) - tube = e.args - assert tube[1] == conn1_self_handle # initiator - assert tube[2] == 1 # type = stream tube - assert tube[3] == 'http' # service - assert tube[4] == sample_parameters # paramaters - assert tube[5] == TUBE_CHANNEL_STATE_OPEN - - contact2_channeltype = None - while contact2_channeltype == None: - e = q.expect('dbus-signal', signal='NewChannel') - if (e.args[1] == CHANNEL_TYPE_TUBES) and \ - (e.path.endswith("testsuite2") == True): - tubes2_path = e.args[0] - contact2_channeltype = e.args[1] - - contact2_tubes_channel = make_channel_proxy(conn2, tubes2_path, - "Channel.Type.Tubes") - - contact2_tubes = contact2_tubes_channel.ListTubes() - assert len(contact2_tubes) == 1 - contact2_tube = contact2_tubes[0] - assert contact2_tube[0] is not None # tube id - conn2_tube_id = contact2_tube[0] - assert contact2_tube[1] is not None # initiator - assert contact2_tube[2] == 1 # type = stream tube - assert contact2_tube[3] == 'http' # service = http - assert contact2_tube[4] is not None # parameters - assert contact2_tube[5] == 0, contact2_tube[5] # status = local pending - - # second connection: accept the tube (old API) - unix_socket_adr = contact2_tubes_channel.AcceptStreamTube( - contact2_tube[0], 0, 0, '', byte_arrays=True) - - e = q.expect('dbus-signal', signal='TubeStateChanged', path=tubes2_path) - id, state = e.args - assert id == conn2_tube_id - assert state == TUBE_CHANNEL_STATE_OPEN - - client = ClientCreator(reactor, ClientGreeter) - client.connectUNIX(unix_socket_adr).addCallback(client_connected_cb) - - # server got the connection - _, e = q.expect_many( - EventPattern('server-connected'), - EventPattern('client-connected')) - - client_transport = e.transport - - sig, e = q.expect_many( - EventPattern('dbus-signal', signal='StreamTubeNewConnection', - path=tubes1_path), - EventPattern('client-data-received')) - - id, handle = sig.args - assert id == conn1_tube_id - assert handle == contact2_handle_on_conn1 - - # client receives server's welcome message - assert e.data == SERVER_WELCOME_MSG - - client_transport.write(test_string) - - server_received, client_received = q.expect_many( - EventPattern('server-data-received'), - EventPattern('client-data-received')) - - assert server_received.data == test_string - assert client_received.data == string.swapcase(test_string) - - # contact1 closes the tube - contact1_tubes_channel.CloseTube(conn1_tube_id) - q.expect('dbus-signal', signal='TubeClosed', args=[conn1_tube_id]) - - # contact2 closes the tube - contact2_tubes_channel.CloseTube(conn2_tube_id) - q.expect('dbus-signal', signal='TubeClosed', args=[conn2_tube_id]) - - # Now contact1 will create a new muc stream tube to another room using the - # new API - - # Can we request muc stream tubes? - properties = conn.GetAll(CONN_IFACE_REQUESTS, - dbus_interface=PROPERTIES_IFACE) - - assert ({CHANNEL_TYPE: CHANNEL_TYPE_STREAM_TUBE, - TARGET_HANDLE_TYPE: HT_ROOM}, - [TARGET_HANDLE, TARGET_ID, STREAM_TUBE_SERVICE] - ) in properties.get('RequestableChannelClasses'),\ - properties['RequestableChannelClasses'] - # request a stream tube channel (new API) - requestotron = dbus.Interface(conn, CONN_IFACE_REQUESTS) - - requestotron.CreateChannel({ + conn.Requests.CreateChannel({ CHANNEL_TYPE: CHANNEL_TYPE_STREAM_TUBE, TARGET_HANDLE_TYPE: HT_ROOM, - TARGET_ID: muc2_name, + TARGET_ID: muc_name, STREAM_TUBE_SERVICE: 'test'}) e = q.expect('dbus-signal', signal='NewChannels') channels = e.args[0] - assert len(channels) == 3 + assert len(channels) == 1 # get the list of all channels to check that newly announced ones are in it - all_channels = conn.Get(CONN_IFACE_REQUESTS, 'Channels', dbus_interface=PROPERTIES_IFACE, + all_channels = conn.Properties.Get(CONN_IFACE_REQUESTS, 'Channels', byte_arrays=True) - got_text, got_tubes, got_tube = False, False, False - for path, props in channels: - if props[CHANNEL_TYPE] == CHANNEL_TYPE_TEXT: - got_text = True - assert props[REQUESTED] == False - group1 = make_channel_proxy(conn, path, "Channel.Interface.Group") - txt_path = path - elif props[CHANNEL_TYPE] == CHANNEL_TYPE_TUBES: - got_tubes = True - assert props[REQUESTED] == False - assert props[INTERFACES] == [CHANNEL_IFACE_GROUP] - elif props[CHANNEL_TYPE] == CHANNEL_TYPE_STREAM_TUBE: - got_tube = True - assert props[REQUESTED] == True - assert props[INTERFACES] == [CHANNEL_IFACE_GROUP, - CHANNEL_IFACE_TUBE] - assert props[STREAM_TUBE_SERVICE] == 'test' - - contact1_tube = bus.get_object(conn.bus_name, path) - contact1_stream_tube = make_channel_proxy(conn, path, - "Channel.Type.StreamTube") - contact1_tube_channel = make_channel_proxy(conn, path, "Channel") - tube1_path = path - else: - assert False - - assert props[INITIATOR_HANDLE] == conn1_self_handle - assert props[INITIATOR_ID] == contact1_name - assert props[TARGET_ID] == muc2_name - - assert (path, props) in all_channels, (path, props) - - assert got_text - assert got_tubes - assert got_tube - - state = contact1_stream_tube.Get(CHANNEL_IFACE_TUBE, 'State', - dbus_interface=PROPERTIES_IFACE) - assert state == TUBE_CHANNEL_STATE_NOT_OFFERED + path, props = channels[0] + assert props[CHANNEL_TYPE] == CHANNEL_TYPE_STREAM_TUBE + assert props[REQUESTED] == True + assert props[INTERFACES] == [CHANNEL_IFACE_GROUP, + CHANNEL_IFACE_TUBE] + assert props[STREAM_TUBE_SERVICE] == 'test' + assert props[INITIATOR_HANDLE] == conn1_self_handle + assert props[INITIATOR_ID] == contact1_name + assert props[TARGET_ID] == muc_name + + assert (path, props) in all_channels, (path, props) - # added as member - q.expect('dbus-signal', signal='MembersChanged', path=txt_path, - args=['', [conn1_self_handle], [], [], [], conn1_self_handle, 0]) + contact1_tube = wrap_channel(bus.get_object(conn.bus_name, path), 'StreamTube') + tube1_path = path - call_async(q, contact1_stream_tube, 'Offer', + state = contact1_tube.Properties.Get(CHANNEL_IFACE_TUBE, 'State') + assert state == TUBE_CHANNEL_STATE_NOT_OFFERED + + call_async(q, contact1_tube.StreamTube, 'Offer', SOCKET_ADDRESS_TYPE_UNIX, dbus.ByteArray(server_socket_address), SOCKET_ACCESS_CONTROL_LOCALHOST, sample_parameters) @@ -249,63 +115,50 @@ def test(q, bus, conn): args=[TUBE_CHANNEL_STATE_OPEN]), EventPattern('dbus-return', method='Offer')) - state = contact1_stream_tube.Get(CHANNEL_IFACE_TUBE, 'State', - dbus_interface=PROPERTIES_IFACE) + state = contact1_tube.Properties.Get(CHANNEL_IFACE_TUBE, 'State') assert state == TUBE_CHANNEL_STATE_OPEN - t.invite_to_muc(q, group1, conn2, contact2_handle_on_conn1, contact1_handle_on_conn2) + # now let's get the text channel so we can invite contact2 using + # the utility t.invite_to_muc + _, path, _ = conn.Requests.EnsureChannel({ + CHANNEL_TYPE: CHANNEL_TYPE_TEXT, + TARGET_HANDLE_TYPE: HT_ROOM, + TARGET_ID: muc_name}) + text1 = wrap_channel(bus.get_object(conn.bus_name, path), 'Text') + + t.invite_to_muc(q, text1.Group, conn2, contact2_handle_on_conn1, contact1_handle_on_conn2) # tubes channel is created e = q.expect('dbus-signal', signal='NewChannels') channels = e.args[0] - assert len(channels) == 2 + assert len(channels) == 1 # get the list of all channels to check that newly announced ones are in it - all_channels = conn2.Get(CONN_IFACE_REQUESTS, 'Channels', dbus_interface=PROPERTIES_IFACE, + all_channels = conn2.Properties.Get(CONN_IFACE_REQUESTS, 'Channels', byte_arrays=True) - got_tubes, got_tube = False, False - for path, props in channels: - if props[CHANNEL_TYPE] == CHANNEL_TYPE_TUBES: - got_tubes = True - assert props[REQUESTED] == False - assert props[INTERFACES] == [CHANNEL_IFACE_GROUP] - elif props[CHANNEL_TYPE] == CHANNEL_TYPE_STREAM_TUBE: - got_tube = True - assert props[REQUESTED] == False - assert props[INTERFACES] == [CHANNEL_IFACE_GROUP, - CHANNEL_IFACE_TUBE] - assert props[STREAM_TUBE_SERVICE] == 'test' - assert props[TUBE_PARAMETERS] == sample_parameters - - contact2_tube = bus.get_object(conn.bus_name, path) - contact2_stream_tube = make_channel_proxy(conn, path, - "Channel.Type.StreamTube") - contact2_tube_channel = make_channel_proxy(conn, path, "Channel") - tube2_path = path - else: - assert False - - assert props[INITIATOR_HANDLE] == contact1_handle_on_conn2 - assert props[INITIATOR_ID] == contact1_name - assert props[TARGET_ID] == muc2_name - - assert (path, props) in all_channels, (path, props) - - assert got_tubes - assert got_tube - - state = contact2_tube.Get(CHANNEL_IFACE_TUBE, 'State', - dbus_interface=PROPERTIES_IFACE) + path, props = channels[0] + assert props[REQUESTED] == False + assert props[INTERFACES] == [CHANNEL_IFACE_GROUP, + CHANNEL_IFACE_TUBE] + assert props[STREAM_TUBE_SERVICE] == 'test' + assert props[TUBE_PARAMETERS] == sample_parameters + + assert (path, props) in all_channels, (path, props) + + contact2_tube = wrap_channel(bus.get_object(conn.bus_name, path), + 'StreamTube') + tube2_path = path + + state = contact2_tube.Properties.Get(CHANNEL_IFACE_TUBE, 'State') assert state == TUBE_CHANNEL_STATE_LOCAL_PENDING # second connection: accept the tube (new API) - unix_socket_adr = contact2_stream_tube.Accept( + unix_socket_adr = contact2_tube.StreamTube.Accept( SOCKET_ADDRESS_TYPE_UNIX, SOCKET_ACCESS_CONTROL_LOCALHOST, '', byte_arrays=True) - state = contact2_tube.Get(CHANNEL_IFACE_TUBE, 'State', - dbus_interface=PROPERTIES_IFACE) + state = contact2_tube.Properties.Get(CHANNEL_IFACE_TUBE, 'State') assert state == TUBE_CHANNEL_STATE_OPEN e = q.expect('dbus-signal', signal='TubeChannelStateChanged', @@ -345,13 +198,12 @@ def test(q, bus, conn): assert server_received.data == test_string assert client_received.data == string.swapcase(test_string) - call_async(q, contact1_tube_channel, 'Close') - _, e1, e2, _, _, _ = q.expect_many( + call_async(q, contact1_tube, 'Close') + _, e1, e2, _, _ = q.expect_many( EventPattern('dbus-return', method='Close'), EventPattern('dbus-signal', signal='ConnectionClosed', path=tube1_path), EventPattern('dbus-signal', signal='ConnectionClosed', path=tube2_path), EventPattern('dbus-signal', signal='Closed'), - EventPattern('dbus-signal', signal='TubeClosed'), EventPattern('dbus-signal', signal='ChannelClosed')) conn_id, error, dbus_msg = e1.args @@ -362,18 +214,20 @@ def test(q, bus, conn): assert conn_id == contact2_tube_conn_id assert error == CONNECTION_LOST - call_async(q, contact2_tube_channel, 'Close') + call_async(q, contact2_tube, 'Close') q.expect_many( EventPattern('dbus-return', method='Close'), EventPattern('dbus-signal', signal='Closed'), - EventPattern('dbus-signal', signal='TubeClosed'), EventPattern('dbus-signal', signal='ChannelClosed')) conn.Disconnect() conn2.Disconnect() # cleanup - os.remove(server_socket_address) + try: + os.remove(server_socket_address) + except OSError: + pass # idgaf if __name__ == '__main__': # increase timer because Clique takes some time to join an existing muc |