summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/tubes-manager.c274
1 files changed, 184 insertions, 90 deletions
diff --git a/src/tubes-manager.c b/src/tubes-manager.c
index 3fc6bfc7..1b1b6e03 100644
--- a/src/tubes-manager.c
+++ b/src/tubes-manager.c
@@ -49,6 +49,7 @@
#include "self.h"
#include "util.h"
#include "tube-iface.h"
+#include "tube-dbus.h"
#include "tube-stream.h"
@@ -91,6 +92,9 @@ struct _SalutTubesManagerPrivate
GHashTable *tubes_channels;
+ /* guint tube ID => (owned) (SalutTubeIface *) */
+ GHashTable *tubes;
+
gboolean dispose_has_run;
};
@@ -108,6 +112,9 @@ salut_tubes_manager_init (SalutTubesManager *self)
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;
}
@@ -408,14 +415,8 @@ 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_channels, g_hash_table_unref);
+ tp_clear_pointer (&priv->tubes, g_hash_table_unref);
}
static void
@@ -692,6 +693,12 @@ salut_tubes_manager_foreach_channel (TpChannelManager *manager,
salut_tubes_channel_foreach (SALUT_TUBES_CHANNEL (chan), foreach,
user_data);
}
+
+ g_hash_table_iter_init (&iter, priv->tubes);
+ while (g_hash_table_iter_next (&iter, NULL, &value))
+ {
+ foreach (TP_EXPORTABLE_CHANNEL (value), user_data);
+ }
}
static const gchar * const tubes_channel_fixed_properties[] = {
@@ -730,24 +737,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 +778,149 @@ 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 = FALSE;
+
+ 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 guint
+generate_tube_id (SalutTubesManager *self)
+{
+ SalutTubesManagerPrivate *priv =
+ SALUT_TUBES_MANAGER_GET_PRIVATE (self);
+ guint out;
+
+ /* probably totally overkill */
+ do
+ {
+ out = g_random_int_range (0, G_MAXINT);
+ }
+ while (g_hash_table_lookup (priv->tubes,
+ GUINT_TO_POINTER (out)) != NULL);
+
+ return out;
+}
+
+static SalutTubeIface *
+new_channel_from_request (SalutTubesManager *self,
+ GHashTable *request)
+{
+ SalutTubesManagerPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+ SALUT_TYPE_TUBES_MANAGER, SalutTubesManagerPrivate);
+ TpBaseConnection *base_conn = TP_BASE_CONNECTION (priv->conn);
+ SalutTubeIface *tube;
+
+ const gchar *ctype, *service;
+ TpHandle handle;
+ TpHandleType handle_type;
+ guint 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);
+ handle_type = tp_asv_get_uint32 (request,
+ TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, 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);
+
+ tube = SALUT_TUBE_IFACE (salut_tube_stream_new (priv->conn, NULL,
+ handle, handle_type,
+ base_conn->self_handle, base_conn->self_handle, FALSE, service,
+ parameters, tube_id, 0, NULL, TRUE));
+
+ tube = SALUT_TUBE_IFACE (NULL);
+ }
+ 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);
+
+ tube = SALUT_TUBE_IFACE (salut_tube_dbus_new (priv->conn, NULL,
+ handle, handle_type, 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);
+
+ g_hash_table_unref (parameters);
+
+ return tube;
+}
+
static gboolean
salut_tubes_manager_requestotron (SalutTubesManager *self,
gpointer request_token,
@@ -803,8 +935,10 @@ 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;
+ GHashTable *channels;
if (tp_asv_get_uint32 (request_properties,
TP_IFACE_CHANNEL ".TargetHandleType", NULL) != TP_HANDLE_TYPE_CONTACT)
@@ -813,21 +947,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 +1020,42 @@ 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;
+ new_channel = new_channel_from_request (self,
+ request_properties);
+ g_assert (new_channel != NULL);
- tokens = g_slist_prepend (tokens, request_token);
+ channels = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+ NULL, 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;
- }
+ 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);
+ }
+ 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,