diff options
author | <robert.mcqueen@collabora.co.uk> | 2006-01-25 12:47:40 +0000 |
---|---|---|
committer | <robert.mcqueen@collabora.co.uk> | 2006-01-25 12:47:40 +0000 |
commit | 14014bcc4496e977f2679e7349d5cc0733896388 (patch) | |
tree | 08e6764e4e134e6e1406a1ee0ae9947cf8a7d8f2 | |
parent | f15d27cd9cf915fefa1abacf9f54b730a6b3af52 (diff) |
parse the roster replies from the server and emit the memberschanged signals on the publish/subscribe list channelsSVN_Push_3
-rw-r--r-- | src/gabble-connection.c | 125 | ||||
-rw-r--r-- | src/gabble-roster-channel.c | 71 | ||||
-rw-r--r-- | src/gabble-roster-channel.h | 11 |
3 files changed, 197 insertions, 10 deletions
diff --git a/src/gabble-connection.c b/src/gabble-connection.c index b8fb65a82..952cb5f7d 100644 --- a/src/gabble-connection.c +++ b/src/gabble-connection.c @@ -1047,6 +1047,12 @@ connection_presence_cb (LmMessageHandler *handler, return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS; } +#define IQ_DEBUG(n, s) \ +G_STMT_START { \ + char *iq_debug_tmp = lm_message_node_to_string (n); \ + g_debug ("%s: " s ":\n%s", G_STRFUNC, iq_debug_tmp); \ + g_free (iq_debug_tmp); \ +} G_STMT_END /** * connection_iq_roster_cb @@ -1063,9 +1069,7 @@ connection_iq_roster_cb (LmMessageHandler *handler, { GabbleConnection *conn = GABBLE_CONNECTION (user_data); GabbleConnectionPrivate *priv = GABBLE_CONNECTION_GET_PRIVATE (conn); - LmMessageNode *iq_node; - LmMessageNode *query_node; - char *tmp; + LmMessageNode *iq_node, *query_node; g_assert (connection == priv->conn); @@ -1076,9 +1080,113 @@ connection_iq_roster_cb (LmMessageHandler *handler, lm_message_node_get_attribute (query_node, "xmlns"))) return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS; - tmp = lm_message_node_to_string (iq_node); - g_debug ("%s: got roster iq:\n%s", G_STRFUNC, tmp); - g_free (tmp); + /* if this is a response, then it's from us asking for the roster */ + if (lm_message_get_sub_type (message) == LM_MESSAGE_SUB_TYPE_RESULT) + { + LmMessageNode *item_node; + GIntSet *empty, *pub_add, *pub_rem, + *sub_add, *sub_rem, *sub_rp; + + /* asymmetry is because we don't get locally pending subscription + * requests via <roster>, we get it via <presence> */ + empty = g_intset_new (); + pub_add = g_intset_new (); + pub_rem = g_intset_new (); + sub_add = g_intset_new (); + sub_rem = g_intset_new (); + sub_rp = g_intset_new (); + + /* iterate every sub-node, which we expect to be <item>s */ + for (item_node = query_node->children; + item_node; + item_node = item_node->next) + { + const char *jid, *subscription, *ask; + GabbleHandle handle; + + if (strcmp (item_node->name, "item")) + { + IQ_DEBUG (item_node, "query sub-node is not item, skipping"); + continue; + } + + jid = lm_message_node_get_attribute (item_node, "jid"); + if (!jid) + { + IQ_DEBUG (item_node, "item node has no jid, skipping"); + continue; + } + + subscription = lm_message_node_get_attribute (item_node, "subscription"); + if (!subscription) + { + IQ_DEBUG (item_node, "item node has no subscription, skipping"); + continue; + } + + handle = gabble_handle_for_contact (priv->handles, jid, FALSE); + ask = lm_message_node_get_attribute (item_node, "ask"); + + if (!strcmp (subscription, "both")) + { + g_intset_add (pub_add, handle); + g_intset_add (sub_add, handle); + } + else if (!strcmp (subscription, "from")) + { + g_intset_add (pub_add, handle); + if (!strcmp (ask, "subscribe")) + g_intset_add (sub_rp, handle); + else + g_intset_add (sub_rem, handle); + } + else if (!strcmp (subscription, "none")) + { + g_intset_add (pub_rem, handle); + if (!strcmp (ask, "subscribe")) + g_intset_add (sub_rp, handle); + else + g_intset_add (sub_rem, handle); + } + else if (!strcmp (subscription, "to")) + { + g_intset_add (pub_rem, handle); + g_intset_add (sub_add, handle); + } + else + { + IQ_DEBUG (item_node, "got unexpected subscription value"); + } + } + + if (g_intset_size (pub_add) > 0 || + g_intset_size (pub_rem) > 0) + { + g_debug ("%s: calling change members on publish channel", G_STRFUNC); + _gabble_roster_channel_change_members (priv->publish_channel, + "", pub_add, pub_rem, empty, empty); + } + + if (g_intset_size (sub_add) > 0 || + g_intset_size (sub_rem) > 0 || + g_intset_size (sub_rp) > 0) + { + g_debug ("%s: calling change members on subscribe channel", G_STRFUNC); + _gabble_roster_channel_change_members (priv->subscribe_channel, + "", sub_add, sub_rem, empty, sub_rp); + } + + g_intset_destroy (empty); + g_intset_destroy (pub_add); + g_intset_destroy (pub_rem); + g_intset_destroy (sub_add); + g_intset_destroy (sub_rem); + g_intset_destroy (sub_rp); + } + else + { + IQ_DEBUG (iq_node, "unhandled roster IQ"); + } return LM_HANDLER_RESULT_REMOVE_MESSAGE; } @@ -1100,14 +1208,11 @@ connection_iq_unknown_cb (LmMessageHandler *handler, GabbleConnection *conn = GABBLE_CONNECTION (user_data); GabbleConnectionPrivate *priv = GABBLE_CONNECTION_GET_PRIVATE (conn); LmMessageNode *iq_node; - char *iq_string; g_assert (connection == priv->conn); iq_node = lm_message_get_node (message); - iq_string = lm_message_node_to_string (iq_node); - g_debug ("%s: got unknown iq:\n%s", G_STRFUNC, iq_string); - g_free (iq_string); + IQ_DEBUG (iq_node, "got unknown iq"); /* TODO: return an IQ error for unknown get/set */ diff --git a/src/gabble-roster-channel.c b/src/gabble-roster-channel.c index 0fad34044..1fc9d33b9 100644 --- a/src/gabble-roster-channel.c +++ b/src/gabble-roster-channel.c @@ -306,6 +306,77 @@ gabble_roster_channel_finalize (GObject *object) } +/** + * _gabble_roster_channel_change_members: + * + * Request members to be added, removed or marked as local or remote pending. + * Changes member sets, references, and emits the MembersChanged signal. + */ +void +_gabble_roster_channel_change_members (GabbleRosterChannel *chan, + const char *message, + GIntSet *add, + GIntSet *remove, + GIntSet *local_pending, + GIntSet *remote_pending) +{ + GabbleRosterChannelPrivate *priv; + GArray *arr_add, *arr_remove, *arr_local, *arr_remote; + + g_assert (GABBLE_IS_ROSTER_CHANNEL (chan)); + g_assert (add != NULL); + g_assert (remove != NULL); + g_assert (local_pending != NULL); + g_assert (remote_pending != NULL); + + priv = GABBLE_ROSTER_CHANNEL_GET_PRIVATE (chan); + + /* members + add */ + handle_set_update (priv->members, add); + /* members - remove */ + handle_set_difference_update (priv->members, remove); + /* members - local_pending */ + handle_set_difference_update (priv->members, local_pending); + /* members - remote_pending */ + handle_set_difference_update (priv->members, remote_pending); + + /* local pending + local_pending */ + handle_set_update (priv->local_pending, local_pending); + /* local pending - add */ + handle_set_difference_update (priv->local_pending, add); + /* local pending - remove */ + handle_set_difference_update (priv->local_pending, remove); + /* local pending - remote_pending */ + handle_set_difference_update (priv->local_pending, remote_pending); + + /* remote pending + remote_pending */ + handle_set_update (priv->remote_pending, remote_pending); + /* remote pending - add */ + handle_set_difference_update (priv->remote_pending, add); + /* remote pending - remove */ + handle_set_difference_update (priv->remote_pending, remove); + /* remote pending - local_pending */ + handle_set_difference_update (priv->remote_pending, local_pending); + + /* translate arguments to arrays */ + arr_add = g_intset_to_array (add); + arr_remove = g_intset_to_array (remove); + arr_local = g_intset_to_array (local_pending); + arr_remote = g_intset_to_array (remote_pending); + + /* emit signal */ + g_signal_emit(chan, signals[MEMBERS_CHANGED], 0, + message, + arr_add, arr_remove, + arr_local, arr_remote); + + /* free arrays */ + g_array_free (arr_add, TRUE); + g_array_free (arr_remove, TRUE); + g_array_free (arr_local, TRUE); + g_array_free (arr_remote, TRUE); +} + /** * gabble_roster_channel_add_members diff --git a/src/gabble-roster-channel.h b/src/gabble-roster-channel.h index 2a2b7f0ed..4ccf3b041 100644 --- a/src/gabble-roster-channel.h +++ b/src/gabble-roster-channel.h @@ -23,6 +23,8 @@ #include <glib-object.h> +#include "gintset.h" + G_BEGIN_DECLS typedef struct _GabbleRosterChannel GabbleRosterChannel; @@ -53,6 +55,15 @@ GType gabble_roster_channel_get_type(void); (G_TYPE_INSTANCE_GET_CLASS ((obj), GABBLE_TYPE_ROSTER_CHANNEL, GabbleRosterChannelClass)) +void +_gabble_roster_channel_change_members (GabbleRosterChannel *chan, + const char *message, + GIntSet *add, + GIntSet *remove, + GIntSet *local_pending, + GIntSet *remote_pending); + + gboolean gabble_roster_channel_add_members (GabbleRosterChannel *obj, const GArray * contacts, const gchar * message, GError **error); gboolean gabble_roster_channel_close (GabbleRosterChannel *obj, GError **error); gboolean gabble_roster_channel_get_channel_type (GabbleRosterChannel *obj, gchar ** ret, GError **error); |