changeset 26884:af2b87aa82ee

Add ability to list roles/affiliations in a chat via slash-commands and modify roles/affiliations of multiple users at a time. Closes #5649. Slightly modified patch from Andrei Mozzhuhin. The multiple-user support is inefficient; all the changes can go in one stanza. We should also actually track roles/affiliations of members since ejabberd's MUC won't respond to the list query for a non-admin.
author Paul Aurich <paul@darkrain42.org>
date Sun, 03 May 2009 19:53:53 +0000
parents ea2306f2f886
children 1dfa009f6db5
files ChangeLog libpurple/protocols/jabber/chat.c libpurple/protocols/jabber/chat.h libpurple/protocols/jabber/jabber.c
diffstat 4 files changed, 170 insertions(+), 23 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Sun May 03 19:36:36 2009 +0000
+++ b/ChangeLog	Sun May 03 19:53:53 2009 +0000
@@ -31,6 +31,8 @@
 	* Support most recent version of User Avatar. (XEP-0084 v1.1)
 	* Updated Entity Capabilities support. (Tobias Markmann)
 	* Better support for receiving remote users' nicknames.
+	* /affiliate and /role will now list the room members with the specified
+	  affiliation/role if possible. (Andrei Mozzhuhin)
 
 	Yahoo:
 	* P2P file transfers. (Sulabh Mahajan)
--- a/libpurple/protocols/jabber/chat.c	Sun May 03 19:36:36 2009 +0000
+++ b/libpurple/protocols/jabber/chat.c	Sun May 03 19:53:53 2009 +0000
@@ -916,6 +916,68 @@
 	return TRUE;
 }
 
+static void
+jabber_chat_affiliation_list_cb(JabberStream *js, const char *from,
+                                JabberIqType type, const char *id,
+                                xmlnode *packet, gpointer data)
+{
+	JabberChat *chat;
+	xmlnode *query, *item;
+	int chat_id = GPOINTER_TO_INT(data);
+	GString *buf;
+
+	if(!(chat = jabber_chat_find_by_id(js, chat_id)))
+		return;
+
+	if (type == JABBER_IQ_ERROR)
+		return;
+
+	if(!(query = xmlnode_get_child(packet, "query")))
+		return;
+
+	buf = g_string_new(_("Affiliations:"));
+
+	item = xmlnode_get_child(query, "item");
+	if (item) {
+		for( ; item; item = xmlnode_get_next_twin(item)) {
+			const char *jid = xmlnode_get_attrib(item, "jid");
+			const char *affiliation = xmlnode_get_attrib(item, "affiliation");
+			if (jid && affiliation)
+				g_string_append_printf(buf, "\n%s %s", jid, affiliation);
+		}
+    } else {
+		buf = g_string_append_c(buf, '\n');
+		buf = g_string_append_len(buf, _("No users found"), -1);
+	}
+
+	purple_conv_chat_write(PURPLE_CONV_CHAT(chat->conv), "", buf->str,
+    	PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_NO_LOG, time(NULL));
+
+	g_string_free(buf, TRUE);
+}
+
+gboolean jabber_chat_affiliation_list(JabberChat *chat, const char *affiliation)
+{
+	JabberIq *iq;
+	char *room_jid;
+	xmlnode *query, *item;
+
+	iq = jabber_iq_new_query(chat->js, JABBER_IQ_GET,
+			"http://jabber.org/protocol/muc#admin");
+
+	room_jid = g_strdup_printf("%s@%s", chat->room, chat->server);
+	xmlnode_set_attrib(iq->node, "to", room_jid);
+
+	query = xmlnode_get_child(iq->node, "query");
+	item = xmlnode_new_child(query, "item");
+	xmlnode_set_attrib(item, "affiliation", affiliation);
+
+	jabber_iq_set_callback(iq, jabber_chat_affiliation_list_cb, GINT_TO_POINTER(chat->id));
+	jabber_iq_send(iq);
+
+	return TRUE;
+}
+
 gboolean jabber_chat_role_user(JabberChat *chat, const char *who, const char *role)
 {
 	char *to;
@@ -945,6 +1007,67 @@
 	return TRUE;
 }
 
+static void jabber_chat_role_list_cb(JabberStream *js, const char *from,
+                                     JabberIqType type, const char *id,
+                                     xmlnode *packet, gpointer data)
+{
+	JabberChat *chat;
+	xmlnode *query, *item;
+	int chat_id = GPOINTER_TO_INT(data);
+	GString *buf;
+
+	if(!(chat = jabber_chat_find_by_id(js, chat_id)))
+		return;
+
+	if (type == JABBER_IQ_ERROR)
+		return;
+
+	if(!(query = xmlnode_get_child(packet, "query")))
+		return;
+
+	buf = g_string_new(_("Roles:"));
+
+	item = xmlnode_get_child(query, "item");
+	if (item) {
+		for( ; item; item = xmlnode_get_next_twin(item)) {
+			const char *jid  = xmlnode_get_attrib(item, "jid");
+			const char *role = xmlnode_get_attrib(item, "role");
+			if (jid && role)
+				g_string_append_printf(buf, "\n%s %s", jid, role);
+	    }
+	} else {
+		buf = g_string_append_c(buf, '\n');
+		buf = g_string_append_len(buf, _("No users found"), -1);
+	}
+
+	purple_conv_chat_write(PURPLE_CONV_CHAT(chat->conv), "", buf->str,
+    	PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_NO_LOG, time(NULL));
+
+	g_string_free(buf, TRUE);
+}
+
+gboolean jabber_chat_role_list(JabberChat *chat, const char *role)
+{
+	JabberIq *iq;
+	char *room_jid;
+	xmlnode *query, *item;
+
+	iq = jabber_iq_new_query(chat->js, JABBER_IQ_GET,
+			"http://jabber.org/protocol/muc#admin");
+
+	room_jid = g_strdup_printf("%s@%s", chat->room, chat->server);
+	xmlnode_set_attrib(iq->node, "to", room_jid);
+
+	query = xmlnode_get_child(iq->node, "query");
+	item = xmlnode_new_child(query, "item");
+	xmlnode_set_attrib(item, "role", role);
+
+	jabber_iq_set_callback(iq, jabber_chat_role_list_cb, GINT_TO_POINTER(chat->id));
+	jabber_iq_send(iq);
+
+	return TRUE;
+}
+
 gboolean jabber_chat_kick_user(JabberChat *chat, const char *who, const char *why)
 {
 	JabberIq *iq;
--- a/libpurple/protocols/jabber/chat.h	Sun May 03 19:36:36 2009 +0000
+++ b/libpurple/protocols/jabber/chat.h	Sun May 03 19:53:53 2009 +0000
@@ -81,8 +81,10 @@
 		const char *why);
 gboolean jabber_chat_affiliate_user(JabberChat *chat, const char *who,
 		const char *affiliation);
+gboolean jabber_chat_affiliation_list(JabberChat *chat, const char *affiliation);
 gboolean jabber_chat_role_user(JabberChat *chat, const char *who,
 		const char *role);
+gboolean jabber_chat_role_list(JabberChat *chat, const char *role);
 gboolean jabber_chat_kick_user(JabberChat *chat, const char *who,
 		const char *why);
 
--- a/libpurple/protocols/jabber/jabber.c	Sun May 03 19:36:36 2009 +0000
+++ b/libpurple/protocols/jabber/jabber.c	Sun May 03 19:53:53 2009 +0000
@@ -2590,21 +2590,32 @@
 {
 	JabberChat *chat = jabber_chat_find_by_conv(conv);
 
-	if (!chat || !args || !args[0] || !args[1])
+	if (!chat || !args || !args[0])
 		return PURPLE_CMD_RET_FAILED;
 
-	if (strcmp(args[1], "owner") != 0 &&
-	    strcmp(args[1], "admin") != 0 &&
-	    strcmp(args[1], "member") != 0 &&
-	    strcmp(args[1], "outcast") != 0 &&
-	    strcmp(args[1], "none") != 0) {
-		*error = g_strdup_printf(_("Unknown affiliation: \"%s\""), args[1]);
+	if (strcmp(args[0], "owner") != 0 &&
+	    strcmp(args[0], "admin") != 0 &&
+	    strcmp(args[0], "member") != 0 &&
+	    strcmp(args[0], "outcast") != 0 &&
+	    strcmp(args[0], "none") != 0) {
+		*error = g_strdup_printf(_("Unknown affiliation: \"%s\""), args[0]);
 		return PURPLE_CMD_RET_FAILED;
 	}
 
-	if (!jabber_chat_affiliate_user(chat, args[0], args[1])) {
-		*error = g_strdup_printf(_("Unable to affiliate user %s as \"%s\""), args[0], args[1]);
-		return PURPLE_CMD_RET_FAILED;
+	if (args[1]) {
+		int i;
+		char **nicks = g_strsplit(args[1], " ", -1);
+
+		for (i = 0; nicks[i]; ++i)
+			if (!jabber_chat_affiliate_user(chat, nicks[i], args[0])) {
+				*error = g_strdup_printf(_("Unable to affiliate user %s as \"%s\""), nicks[i], args[0]);
+				g_strfreev(nicks);
+				return PURPLE_CMD_RET_FAILED;
+			}
+
+		g_strfreev(nicks);
+	} else {
+		jabber_chat_affiliation_list(chat, args[0]);
 	}
 
 	return PURPLE_CMD_RET_OK;
@@ -2615,23 +2626,32 @@
 {
 	JabberChat *chat = jabber_chat_find_by_conv(conv);
 
-	if (!chat || !args || !args[0] || !args[1])
+	if (!chat || !args || !args[0])
 		return PURPLE_CMD_RET_FAILED;
 
-	if (strcmp(args[1], "moderator") != 0 &&
-	    strcmp(args[1], "participant") != 0 &&
-	    strcmp(args[1], "visitor") != 0 &&
-	    strcmp(args[1], "none") != 0) {
-		*error = g_strdup_printf(_("Unknown role: \"%s\""), args[1]);
+	if (strcmp(args[0], "moderator") != 0 &&
+	    strcmp(args[0], "participant") != 0 &&
+	    strcmp(args[0], "visitor") != 0 &&
+	    strcmp(args[0], "none") != 0) {
+		*error = g_strdup_printf(_("Unknown role: \"%s\""), args[0]);
 		return PURPLE_CMD_RET_FAILED;
 	}
 
-	if (!jabber_chat_role_user(chat, args[0], args[1])) {
-		*error = g_strdup_printf(_("Unable to set role \"%s\" for user: %s"),
-		                         args[1], args[0]);
-		return PURPLE_CMD_RET_FAILED;
+	if (args[1]) {
+		int i;
+		char **nicks = g_strsplit(args[1], " ", -1);
+
+		for (i = 0; nicks[i]; i++)
+			if (!jabber_chat_role_user(chat, nicks[i], args[0])) {
+				*error = g_strdup_printf(_("Unable to set role \"%s\" for user: %s"),
+										 args[0], nicks[i]);
+				return PURPLE_CMD_RET_FAILED;
+			}
+
+		g_strfreev(nicks);
+	} else {
+		jabber_chat_role_list(chat, args[0]);
 	}
-
 	return PURPLE_CMD_RET_OK;
 }
 
@@ -3178,13 +3198,13 @@
 	                  PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY |
 	                  PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-jabber",
 	                  jabber_cmd_chat_affiliate,
-	                  _("affiliate &lt;user&gt; &lt;owner|admin|member|outcast|none&gt;: Set a user's affiliation with the room."),
+	                  _("affiliate &lt;owner|admin|member|outcast|none&gt; [nick1] [nick2] ...: Get the users with an affiliation or set users' affiliation with the room."),
 	                  NULL);
 	purple_cmd_register("role", "ws", PURPLE_CMD_P_PRPL,
 	                  PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY |
 	                  PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-jabber",
 	                  jabber_cmd_chat_role,
-	                  _("role &lt;user&gt; &lt;moderator|participant|visitor|none&gt;: Set a user's role in the room."),
+	                  _("role &lt;moderator|participant|visitor|none&gt; [nick1] [nick2] ...: Get the users with an role or set users' role with the room."),
 	                  NULL);
 	purple_cmd_register("invite", "ws", PURPLE_CMD_P_PRPL,
 	                  PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY |