diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/muc-channel.c | 6 | ||||
-rw-r--r-- | src/muc-channel.h | 2 | ||||
-rw-r--r-- | src/muc-manager.c | 162 |
3 files changed, 165 insertions, 5 deletions
diff --git a/src/muc-channel.c b/src/muc-channel.c index 1b0c5886..2abc5907 100644 --- a/src/muc-channel.c +++ b/src/muc-channel.c @@ -1812,3 +1812,9 @@ salut_muc_channel_bytestream_offered (SalutMucChannel *self, 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 8c888d18..f5992768 100644 --- a/src/muc-channel.h +++ b/src/muc-channel.h @@ -100,6 +100,8 @@ void salut_muc_channel_bytestream_offered (SalutMucChannel *self, GibberBytestreamIface *bytestream, WockyStanza *msg); +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 36d77ef0..ca28004b 100644 --- a/src/muc-manager.c +++ b/src/muc-manager.c @@ -87,6 +87,12 @@ struct _SalutMucManagerPrivate /* 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; }; @@ -106,6 +112,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->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 @@ -149,6 +160,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); @@ -161,6 +189,13 @@ salut_muc_manager_close_all (SalutMucManager *self) priv->status_changed_id = 0; } + if (priv->queued_requests != NULL) + g_hash_table_foreach (priv->queued_requests, + cancel_queued_requests, self); + + 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); } @@ -255,6 +290,8 @@ salut_muc_manager_dispose (GObject *object) salut_muc_manager_close_all (self); g_assert (priv->text_channels == NULL); + g_assert (priv->queued_requests == NULL); + g_assert (priv->text_needed_for_tube == NULL); /* release any references held by the object here */ @@ -342,6 +379,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, @@ -395,6 +458,80 @@ _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 *satisfied; + GSList *tube_channels; + GSList *l; + + /* announce the text channel finally */ + 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, @@ -433,6 +570,13 @@ salut_muc_manager_new_muc_channel (SalutMucManager *mgr, g_hash_table_insert (priv->text_channels, GUINT_TO_POINTER (handle), 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_signal_connect (chan, "join-error", G_CALLBACK (muc_channel_join_error_cb), mgr); + return chan; } @@ -522,13 +666,21 @@ salut_muc_manager_request_new_muc_channel (SalutMucManager *mgr, * 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); + if (salut_muc_channel_is_ready (text_chan)) + { + if (request_token != NULL) + tokens = g_slist_prepend (tokens, request_token); + + tp_channel_manager_emit_new_channel (mgr, + TP_EXPORTABLE_CHANNEL (text_chan), tokens); + } + else + { + associate_channel_to_data (priv->queued_requests, + text_chan, request_token); + } } g_slist_free (tokens); |