summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
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
commit14014bcc4496e977f2679e7349d5cc0733896388 (patch)
tree08e6764e4e134e6e1406a1ee0ae9947cf8a7d8f2
parentf15d27cd9cf915fefa1abacf9f54b730a6b3af52 (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.c125
-rw-r--r--src/gabble-roster-channel.c71
-rw-r--r--src/gabble-roster-channel.h11
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);