qulogic/pidgin

Parents b24f582761a4
Children f7a4bc500915
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?
--- a/ChangeLog Wed May 23 03:25:01 2012 +0000
+++ b/ChangeLog Wed May 23 05:01:14 2012 +0000
@@ -39,6 +39,7 @@
to the core (and UIs) as incoming messages (Thijs Alkemade).
(#14529)
* Support file transfers up to ~9 EiB.
+ * Invalid user moods can no longer be sent to the server.
Plugins:
* The Voice/Video Settings plugin supports using the sndio GStreamer
--- a/libpurple/protocols/jabber/jabber.c Wed May 23 03:25:01 2012 +0000
+++ b/libpurple/protocols/jabber/jabber.c Wed May 23 05:01:14 2012 +0000
@@ -3575,16 +3575,32 @@
JabberStream *js = purple_connection_get_protocol_data(purple_account_get_connection(account));
if (js->pep) {
- /* if no argument was given, unset mood */
+ gboolean ret;
+
if (!args || !args[0]) {
- jabber_mood_set(js, NULL, NULL);
- } else if (!args[1]) {
- jabber_mood_set(js, args[0], NULL);
+ /* No arguments; unset mood */
+ ret = jabber_mood_set(js, NULL, NULL);
} else {
- jabber_mood_set(js, args[0], args[1]);
+ /* At least one argument. Relying on the list of arguments
+ * being NULL-terminated.
+ */
+ ret = jabber_mood_set(js, args[0], args[1]);
+ if (!ret) {
+ /* Let's try again */
+ char *tmp = g_strjoin(" ", args[0], args[1], NULL);
+ ret = jabber_mood_set(js, "undefined", tmp);
+ g_free(tmp);
+ }
}
- return PURPLE_CMD_RET_OK;
+ if (ret) {
+ return PURPLE_CMD_RET_OK;
+ } else {
+ purple_conversation_write(conv, NULL,
+ _("Failed to specify mood"),
+ PURPLE_MESSAGE_ERROR, time(NULL));
+ return PURPLE_CMD_RET_FAILED;
+ }
} else {
/* account does not support PEP, can't set a mood */
purple_conversation_write(conv, NULL,
@@ -3713,7 +3729,7 @@
PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_IM |
PURPLE_CMD_FLAG_PRPL_ONLY | PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS,
"prpl-jabber", jabber_cmd_mood,
- _("mood: Set current user mood"), NULL);
+ _("mood &lt;mood&gt; [text]: Set current user mood"), NULL);
commands = g_slist_prepend(commands, GUINT_TO_POINTER(id));
g_hash_table_insert(jabber_cmds, plugin, commands);
--- 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)
--- a/libpurple/protocols/jabber/usermood.h Wed May 23 03:25:01 2012 +0000
+++ b/libpurple/protocols/jabber/usermood.h Wed May 23 05:01:14 2012 +0000
@@ -30,9 +30,20 @@
void jabber_mood_init(void);
-void jabber_mood_set(JabberStream *js,
- const char *mood, /* must be one of the valid strings defined in the XEP */
- const char *text /* might be NULL */);
+/**
+ * Sets / unsets the mood for the specified account. The mood passed in
+ * must either be NULL, "", or one of the moods returned by
+ * jabber_get_moods().
+ *
+ * @param js The JabberStream object.
+ * @param mood The mood to set, NULL, or ""
+ * @param text Optional text that goes along with a mood. Only used when
+ * setting a mood (not when unsetting a mood).
+ *
+ * @return FALSE if an invalid mood was specified, or TRUE otherwise.
+ */
+gboolean
+jabber_mood_set(JabberStream *js, const char *mood, const char *text);
PurpleMood *jabber_get_moods(PurpleAccount *account);