diff libpurple/protocols/jabber/usermood.c @ 32777:3b1070cb4f29

jabber: Validate user moods, and make the /mood cmd behave flexibly. A user in Pidgin running "/mood ?" or "/mood -" would result in invalid XML being sent to the server (similar to #14342, except '<-/>' or '<?/>'). Prevent this by ensuring the user is specifying something from the list. The /mood command will also now try to treat its entire arguments as a single string, and set that as the mood -- I figure this is what a user would expect?
author Paul Aurich <paul@darkrain42.org>
date Wed, 23 May 2012 05:01:14 +0000
parents 2ec94166be43
children
line wrap: on
line diff
--- a/libpurple/protocols/jabber/usermood.c	Wed May 23 03:25:01 2012 +0000
+++ b/libpurple/protocols/jabber/usermood.c	Wed May 23 05:01:14 2012 +0000
@@ -115,10 +115,26 @@
 	{"undefined", N_("Undefined"), NULL},
 	{"weak", N_("Weak"), NULL},
 	{"worried", N_("Worried"), NULL},
-	/* Mark the last record. */
+	/* Mar last record. */
 	{NULL, NULL, NULL}
 };
 
+static const PurpleMood*
+find_mood_by_name(const gchar *name)
+{
+	int i;
+
+	g_return_val_if_fail(name && *name, NULL);
+
+	for (i = 0; moods[i].mood != NULL; ++i) {
+		if (g_str_equal(name, moods[i].mood)) {
+			return &moods[i];
+		}
+	}
+
+	return NULL;
+}
+
 static void jabber_mood_cb(JabberStream *js, const char *from, xmlnode *items) {
 	/* it doesn't make sense to have more than one item here, so let's just pick the first one */
 	xmlnode *item = xmlnode_get_child(items, "item");
@@ -139,15 +155,13 @@
 				if (!moodtext) /* only pick the first one */
 					moodtext = xmlnode_get_data(moodinfo);
 			} else {
-				int i;
-				for (i = 0; moods[i].mood; ++i) {
-					/* verify that the mood is known (valid) */
-					if (!strcmp(moodinfo->name, moods[i].mood)) {
-						newmood = moods[i].mood;
-						break;
-					}
-				}
+				const PurpleMood *target_mood;
+
+				/* verify that the mood is known (valid) */
+				target_mood = find_mood_by_name(moodinfo->name);
+				newmood = target_mood ? target_mood->mood : NULL;
 			}
+
 			if (newmood != NULL && moodtext != NULL)
 			   break;
 		}
@@ -170,26 +184,41 @@
 	jabber_pep_register_handler("http://jabber.org/protocol/mood", jabber_mood_cb);
 }
 
-void jabber_mood_set(JabberStream *js, const char *mood, const char *text) {
+gboolean
+jabber_mood_set(JabberStream *js, const char *mood, const char *text)
+{
+	const PurpleMood *target_mood = NULL;
 	xmlnode *publish, *moodnode;
 
+	if (mood && *mood) {
+		target_mood = find_mood_by_name(mood);
+		/* Mood specified, but is invalid --
+		 * fail so that the command can handle this.
+		 */
+		if (!target_mood)
+			return FALSE;
+	}
+
 	publish = xmlnode_new("publish");
 	xmlnode_set_attrib(publish,"node","http://jabber.org/protocol/mood");
 	moodnode = xmlnode_new_child(xmlnode_new_child(publish, "item"), "mood");
 	xmlnode_set_namespace(moodnode, "http://jabber.org/protocol/mood");
-	if (mood && *mood) {
-		/* if mood is NULL, set an empty mood node, meaning: unset mood */
+
+	if (target_mood) {
+		/* If target_mood is not NULL, then
+		 * target_mood->mood == mood, and is a valid element name.
+		 */
 	    xmlnode_new_child(moodnode, mood);
-	}
 
-	if (text && *text) {
-		xmlnode *textnode = xmlnode_new_child(moodnode, "text");
-		xmlnode_insert_data(textnode, text, -1);
+		/* Only set text when setting a mood */
+		if (text && *text) {
+			xmlnode *textnode = xmlnode_new_child(moodnode, "text");
+			xmlnode_insert_data(textnode, text, -1);
+		}
 	}
 
 	jabber_pep_publish(js, publish);
-	/* publish is freed by jabber_pep_publish -> jabber_iq_send -> jabber_iq_free
-	   (yay for well-defined memory management rules) */
+	return TRUE;
 }
 
 PurpleMood *jabber_get_moods(PurpleAccount *account)