summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author <ole.andre.ravnaas@collabora.co.uk>2006-06-14 13:57:15 +0000
committer <ole.andre.ravnaas@collabora.co.uk>2006-06-14 13:57:15 +0000
commit4c798393990876a037a9025daab2408f0ffc292c (patch)
tree9cb70b59fdd7aeb60495ef43a8161156f5a18a24
parent4c16541bf7b864c3255f354b82cd03cb8e5536df (diff)
MUC: set property permissions correctly based on changes in presence and what the server supports.
-rw-r--r--src/gabble-muc-channel.c374
1 files changed, 271 insertions, 103 deletions
diff --git a/src/gabble-muc-channel.c b/src/gabble-muc-channel.c
index c6380db5c..19a0242d9 100644
--- a/src/gabble-muc-channel.c
+++ b/src/gabble-muc-channel.c
@@ -275,13 +275,14 @@ gabble_muc_channel_constructor (GType type, guint n_props,
return obj;
}
-static void properties_disco_cb (GabbleDisco *disco,
- GabbleDiscoRequest *request,
- const gchar *jid,
- const gchar *node,
- LmMessageNode *query_result,
- GError *error,
- gpointer user_data)
+static void
+properties_disco_cb (GabbleDisco *disco,
+ GabbleDiscoRequest *request,
+ const gchar *jid,
+ const gchar *node,
+ LmMessageNode *query_result,
+ GError *error,
+ gpointer user_data)
{
GabbleMucChannel *chan = user_data;
GabbleMucChannelPrivate *priv;
@@ -300,8 +301,6 @@ static void properties_disco_cb (GabbleDisco *disco,
return;
}
- HANDLER_DEBUG (query_result, "disco query result");
-
changed_props_val = changed_props_flags = NULL;
@@ -492,71 +491,6 @@ static void properties_disco_cb (GabbleDisco *disco,
}
}
-
- /*
- * Update write capabilities based on room configuration
- * and own role and affiliation.
- */
-
- /* Subject */
- /* FIXME: this might be allowed for participants/moderators only,
- * so for now just rely on the server making that call. */
- if (priv->self_role >= ROLE_VISITOR)
- {
- gabble_properties_mixin_change_flags (G_OBJECT (chan),
- ROOM_PROP_SUBJECT, TP_PROPERTY_FLAG_WRITE, 0,
- &changed_props_flags);
- }
-
- /* Room definition */
- if (priv->self_affil == AFFILIATION_OWNER)
- {
- gabble_properties_mixin_change_flags (G_OBJECT (chan),
- ROOM_PROP_ANONYMOUS, TP_PROPERTY_FLAG_WRITE, 0,
- &changed_props_flags);
-
- gabble_properties_mixin_change_flags (G_OBJECT (chan),
- ROOM_PROP_INVITE_ONLY, TP_PROPERTY_FLAG_WRITE, 0,
- &changed_props_flags);
-
- gabble_properties_mixin_change_flags (G_OBJECT (chan),
- ROOM_PROP_MODERATED, TP_PROPERTY_FLAG_WRITE, 0,
- &changed_props_flags);
-
- gabble_properties_mixin_change_flags (G_OBJECT (chan),
- ROOM_PROP_NAME, TP_PROPERTY_FLAG_WRITE, 0,
- &changed_props_flags);
-
- if (gabble_properties_mixin_is_readable (G_OBJECT (chan),
- ROOM_PROP_DESCRIPTION))
- {
- gabble_properties_mixin_change_flags (G_OBJECT (chan),
- ROOM_PROP_DESCRIPTION, TP_PROPERTY_FLAG_WRITE, 0,
- &changed_props_flags);
- }
-
- gabble_properties_mixin_change_flags (G_OBJECT (chan),
- ROOM_PROP_PASSWORD, TP_PROPERTY_FLAG_WRITE, 0,
- &changed_props_flags);
-
- gabble_properties_mixin_change_flags (G_OBJECT (chan),
- ROOM_PROP_PASSWORD_REQUIRED, TP_PROPERTY_FLAG_WRITE, 0,
- &changed_props_flags);
-
- gabble_properties_mixin_change_flags (G_OBJECT (chan),
- ROOM_PROP_PERSISTENT, TP_PROPERTY_FLAG_WRITE, 0,
- &changed_props_flags);
-
- gabble_properties_mixin_change_flags (G_OBJECT (chan),
- ROOM_PROP_PRIVATE, TP_PROPERTY_FLAG_WRITE, 0,
- &changed_props_flags);
-
- gabble_properties_mixin_change_flags (G_OBJECT (chan),
- ROOM_PROP_SUBJECT, TP_PROPERTY_FLAG_WRITE, 0,
- &changed_props_flags);
- }
-
-
/*
* Emit signals.
*/
@@ -574,11 +508,12 @@ room_properties_update (GabbleMucChannel *chan)
priv = GABBLE_MUC_CHANNEL_GET_PRIVATE (chan);
- if (gabble_disco_request (priv->conn->disco, GABBLE_DISCO_TYPE_INFO, priv->jid, NULL,
- properties_disco_cb, chan, G_OBJECT (chan), &error) == NULL)
+ if (gabble_disco_request (priv->conn->disco, GABBLE_DISCO_TYPE_INFO,
+ priv->jid, NULL, properties_disco_cb, chan, G_OBJECT (chan),
+ &error) == NULL)
{
g_warning ("%s: disco query failed: '%s'", G_STRFUNC, error->message);
- return;
+ g_error_free (error);
}
}
@@ -1289,6 +1224,238 @@ room_created_submit_reply_cb (GabbleConnection *conn, LmMessage *sent_msg,
return LM_HANDLER_RESULT_REMOVE_MESSAGE;
}
+static LmMessageNode *
+config_form_get_form_node (LmMessage *msg)
+{
+ LmMessageNode *node;
+
+ /* find the query node */
+ node = lm_message_node_get_child (msg->node, "query");
+ if (node == NULL)
+ return NULL;
+
+ /* then the form node */
+ for (node = node->children; node; node = node->next)
+ {
+ if (strcmp (node->name, "x") == 0)
+ {
+ if (strcmp (lm_message_node_get_attribute (node, "xmlns"),
+ "jabber:x:data") != 0)
+ {
+ continue;
+ }
+
+ if (strcmp (lm_message_node_get_attribute (node, "type"),
+ "form") != 0)
+ {
+ continue;
+ }
+
+ return node;
+ }
+ }
+
+ return NULL;
+}
+
+static LmHandlerResult
+perms_config_form_reply_cb (GabbleConnection *conn, LmMessage *sent_msg,
+ LmMessage *reply_msg, GObject *object,
+ gpointer user_data)
+{
+ GabbleMucChannel *chan = GABBLE_MUC_CHANNEL (object);
+ GabbleMucChannelPrivate *priv = GABBLE_MUC_CHANNEL_GET_PRIVATE (chan);
+ LmMessageNode *form_node, *node;
+
+ if (lm_message_get_sub_type (reply_msg) != LM_MESSAGE_SUB_TYPE_RESULT)
+ {
+ g_warning ("%s: request for config form denied, property permissions "
+ "will be inaccurate", G_STRFUNC);
+ goto OUT;
+ }
+
+ /* just in case our affiliation has changed in the meantime */
+ if (priv->self_affil != AFFILIATION_OWNER)
+ goto OUT;
+
+ form_node = config_form_get_form_node (reply_msg);
+ if (form_node == NULL)
+ {
+ g_warning ("%s: form node node found, property permissions will be "
+ "inaccurate", G_STRFUNC);
+ goto OUT;
+ }
+
+ for (node = form_node->children; node; node = node->next)
+ {
+ const gchar *var;
+
+ if (strcmp (node->name, "field") != 0)
+ continue;
+
+ var = lm_message_node_get_attribute (node, "var");
+ if (var == NULL)
+ continue;
+
+ if (strcmp (var, "muc#roomconfig_roomdesc") == 0 ||
+ strcmp (var, "muc#owner_roomdesc") == 0)
+ {
+ if (gabble_properties_mixin_is_readable (G_OBJECT (chan),
+ ROOM_PROP_DESCRIPTION))
+ {
+ gabble_properties_mixin_change_flags (G_OBJECT (chan),
+ ROOM_PROP_DESCRIPTION, TP_PROPERTY_FLAG_WRITE, 0,
+ NULL);
+
+ goto OUT;
+ }
+ }
+ }
+
+OUT:
+ return LM_HANDLER_RESULT_REMOVE_MESSAGE;
+}
+
+static void
+update_permissions (GabbleMucChannel *chan)
+{
+ GabbleMucChannelPrivate *priv = GABBLE_MUC_CHANNEL_GET_PRIVATE (chan);
+ TpChannelGroupFlags grp_flags_add, grp_flags_rem;
+ TpPropertyFlags prop_flags_add, prop_flags_rem;
+ GArray *changed_props_val, *changed_props_flags;
+
+ /*
+ * Update group flags.
+ */
+ grp_flags_add = TP_CHANNEL_GROUP_FLAG_CAN_ADD |
+ TP_CHANNEL_GROUP_FLAG_MESSAGE_ADD;
+ grp_flags_rem = 0;
+
+ if (priv->self_role == ROLE_MODERATOR)
+ {
+ grp_flags_add |= TP_CHANNEL_GROUP_FLAG_CAN_REMOVE |
+ TP_CHANNEL_GROUP_FLAG_MESSAGE_REMOVE;
+ }
+ else
+ {
+ grp_flags_rem |= TP_CHANNEL_GROUP_FLAG_CAN_REMOVE |
+ TP_CHANNEL_GROUP_FLAG_MESSAGE_REMOVE;
+ }
+
+ gabble_group_mixin_change_flags (G_OBJECT (chan), grp_flags_add,
+ grp_flags_rem);
+
+
+ /*
+ * Update write capabilities based on room configuration
+ * and own role and affiliation.
+ */
+
+ changed_props_val = changed_props_flags = NULL;
+
+ /*
+ * Subject
+ *
+ * FIXME: this might be allowed for participants/moderators only,
+ * so for now just rely on the server making that call.
+ */
+
+ if (priv->self_role >= ROLE_VISITOR)
+ {
+ prop_flags_add = TP_PROPERTY_FLAG_WRITE;
+ prop_flags_rem = 0;
+ }
+ else
+ {
+ prop_flags_add = 0;
+ prop_flags_rem = TP_PROPERTY_FLAG_WRITE;
+ }
+
+ gabble_properties_mixin_change_flags (G_OBJECT (chan),
+ ROOM_PROP_SUBJECT, prop_flags_add, prop_flags_rem,
+ &changed_props_flags);
+
+ /* Room definition */
+ if (priv->self_affil == AFFILIATION_OWNER)
+ {
+ prop_flags_add = TP_PROPERTY_FLAG_WRITE;
+ prop_flags_rem = 0;
+ }
+ else
+ {
+ prop_flags_add = 0;
+ prop_flags_rem = TP_PROPERTY_FLAG_WRITE;
+ }
+
+ gabble_properties_mixin_change_flags (G_OBJECT (chan),
+ ROOM_PROP_ANONYMOUS, prop_flags_add, prop_flags_rem,
+ &changed_props_flags);
+
+ gabble_properties_mixin_change_flags (G_OBJECT (chan),
+ ROOM_PROP_INVITE_ONLY, prop_flags_add, prop_flags_rem,
+ &changed_props_flags);
+
+ gabble_properties_mixin_change_flags (G_OBJECT (chan),
+ ROOM_PROP_MODERATED, prop_flags_add, prop_flags_rem,
+ &changed_props_flags);
+
+ gabble_properties_mixin_change_flags (G_OBJECT (chan),
+ ROOM_PROP_NAME, prop_flags_add, prop_flags_rem,
+ &changed_props_flags);
+
+ gabble_properties_mixin_change_flags (G_OBJECT (chan),
+ ROOM_PROP_PASSWORD, prop_flags_add, prop_flags_rem,
+ &changed_props_flags);
+
+ gabble_properties_mixin_change_flags (G_OBJECT (chan),
+ ROOM_PROP_PASSWORD_REQUIRED, prop_flags_add, prop_flags_rem,
+ &changed_props_flags);
+
+ gabble_properties_mixin_change_flags (G_OBJECT (chan),
+ ROOM_PROP_PERSISTENT, prop_flags_add, prop_flags_rem,
+ &changed_props_flags);
+
+ gabble_properties_mixin_change_flags (G_OBJECT (chan),
+ ROOM_PROP_PRIVATE, prop_flags_add, prop_flags_rem,
+ &changed_props_flags);
+
+ gabble_properties_mixin_change_flags (G_OBJECT (chan),
+ ROOM_PROP_SUBJECT, prop_flags_add, prop_flags_rem,
+ &changed_props_flags);
+
+ /*
+ * Emit signals.
+ */
+ gabble_properties_mixin_emit_changed (G_OBJECT (chan), &changed_props_val);
+ gabble_properties_mixin_emit_flags (G_OBJECT (chan), &changed_props_flags);
+
+ if (priv->self_affil == AFFILIATION_OWNER)
+ {
+ LmMessage *msg;
+ LmMessageNode *node;
+ GError *error;
+ gboolean success;
+
+ msg = lm_message_new_with_sub_type (priv->jid,
+ LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_GET);
+ node = lm_message_node_add_child (msg->node, "query", NULL);
+ lm_message_node_set_attribute (node, "xmlns", NS_MUC_OWNER);
+
+ success = _gabble_connection_send_with_reply (priv->conn, msg,
+ perms_config_form_reply_cb, G_OBJECT (chan), NULL,
+ &error);
+
+ lm_message_unref (msg);
+
+ if (!success)
+ {
+ g_warning ("%s: failed to request config form: %s",
+ G_STRFUNC, error->message);
+ g_error_free (error);
+ }
+ }
+}
+
/**
* _gabble_muc_channel_member_presence_updated
*/
@@ -1364,29 +1531,19 @@ _gabble_muc_channel_member_presence_updated (GabbleMucChannel *chan,
if (handle == mixin->self_handle)
{
- TpChannelGroupFlags flags_add, flags_rem;
-
- priv->self_role = get_role_from_string (role);
- priv->self_affil = get_affiliation_from_string (affil);
+ GabbleMucRole new_role;
+ GabbleMucAffiliation new_affil;
- /* update flags */
- flags_add = TP_CHANNEL_GROUP_FLAG_CAN_ADD |
- TP_CHANNEL_GROUP_FLAG_MESSAGE_ADD;
- flags_rem = 0;
+ new_role = get_role_from_string (role);
+ new_affil = get_affiliation_from_string (affil);
- if (priv->self_role == ROLE_MODERATOR)
+ if (new_role != priv->self_role || new_affil != priv->self_affil)
{
- flags_add |= TP_CHANNEL_GROUP_FLAG_CAN_REMOVE |
- TP_CHANNEL_GROUP_FLAG_MESSAGE_REMOVE;
- }
- else
- {
- flags_rem |= TP_CHANNEL_GROUP_FLAG_CAN_REMOVE |
- TP_CHANNEL_GROUP_FLAG_MESSAGE_REMOVE;
- }
+ priv->self_role = new_role;
+ priv->self_affil = new_affil;
- gabble_group_mixin_change_flags (G_OBJECT (chan), flags_add,
- flags_rem);
+ update_permissions (chan);
+ }
if (status_code && strcmp (status_code, "201") == 0)
{
@@ -1413,6 +1570,8 @@ _gabble_muc_channel_member_presence_updated (GabbleMucChannel *chan,
g_error_free (error);
close_channel (chan, NULL, TRUE);
+
+ goto OUT;
}
}
@@ -1442,6 +1601,7 @@ _gabble_muc_channel_member_presence_updated (GabbleMucChannel *chan,
}
}
+OUT:
g_intset_destroy (empty);
g_intset_destroy (set);
}
@@ -2358,7 +2518,7 @@ request_config_form_reply_cb (GabbleConnection *conn, LmMessage *sent_msg,
GabblePropertiesContext *ctx = priv->properties_ctx;
GError *error = NULL;
LmMessage *msg = NULL;
- LmMessageNode *submit_node, *query_node, *form_node, *node;
+ LmMessageNode *submit_node, *form_node, *node;
guint i, props_left;
if (lm_message_get_sub_type (reply_msg) != LM_MESSAGE_SUB_TYPE_RESULT)
@@ -2369,6 +2529,10 @@ request_config_form_reply_cb (GabbleConnection *conn, LmMessage *sent_msg,
goto OUT;
}
+ form_node = config_form_get_form_node (reply_msg);
+ if (form_node == NULL)
+ goto PARSE_ERROR;
+
/* initialize */
msg = lm_message_new_with_sub_type (priv->jid, LM_MESSAGE_TYPE_IQ,
LM_MESSAGE_SUB_TYPE_SET);
@@ -2393,13 +2557,17 @@ request_config_form_reply_cb (GabbleConnection *conn, LmMessage *sent_msg,
{
if (strcmp (node->name, "x") == 0)
{
- const gchar *type = lm_message_node_get_attribute (node, "type");
-
- if (!_lm_message_node_has_namespace (node, NS_DATA))
- continue;
+ if (strcmp (lm_message_node_get_attribute (node, "xmlns"),
+ "jabber:x:data") != 0)
+ {
+ continue;
+ }
- if (g_strdiff (type, "form"))
- continue;
+ if (strcmp (lm_message_node_get_attribute (node, "type"),
+ "form") != 0)
+ {
+ continue;
+ }
form_node = node;
break;