pidgin/pidgin

Unescape tag values in IRCv3

17 months ago, Gary Kramlich
f35eb5adb2e0
Parents 0472e404b129
Children 0c3de459b1cc
Unescape tag values in IRCv3

Testing Done:
Ran the unittests (after uncommenting them of course...)

Reviewed at https://reviews.imfreedom.org/r/2078/
--- a/libpurple/protocols/ircv3/purpleircv3parser.c Sat Nov 19 16:49:14 2022 -0600
+++ b/libpurple/protocols/ircv3/purpleircv3parser.c Tue Nov 22 22:06:24 2022 -0600
@@ -36,6 +36,45 @@
/******************************************************************************
* Helpers
*****************************************************************************/
+static char *
+purple_ircv3_parser_unescape_tag_value(const char *value) {
+ GString *unescaped = g_string_new("");
+ gboolean escaping = FALSE;
+
+ /* Walk the string and replace escaped values according to
+ * https://ircv3.net/specs/extensions/message-tags.html#escaping-values
+ */
+ for(int i = 0; value[i] != '\0'; i++) {
+ if(escaping) {
+ /* Set the replacement to the current character which will fall
+ * through for everything, including '\\'
+ */
+ char replacement = value[i];
+
+ if(value[i] == ':') {
+ replacement = ';';
+ } else if(value[i] == 's') {
+ replacement = ' ';
+ } else if(value[i] == 'r') {
+ replacement = '\r';
+ } else if(value[i] == 'n') {
+ replacement = '\n';
+ }
+
+ g_string_append_c(unescaped, replacement);
+ escaping = FALSE;
+ } else {
+ if(value[i] == '\\') {
+ escaping = TRUE;
+ } else {
+ g_string_append_c(unescaped, value[i]);
+ }
+ }
+ }
+
+ return g_string_free(unescaped, FALSE);
+}
+
static GHashTable *
purple_ircv3_parser_parse_tags(PurpleIRCv3Parser *parser,
const gchar *tags_string, GError **error)
@@ -76,16 +115,20 @@
}
while(g_match_info_matches(info)) {
- gchar *key = NULL;
- gchar *value = NULL;
+ char *key = NULL;
+ char *value = NULL;
+ char *unescaped = NULL;
key = g_match_info_fetch_named(info, "key");
value = g_match_info_fetch_named(info, "value");
+ unescaped = purple_ircv3_parser_unescape_tag_value(value);
+ g_free(value);
+
/* the hash table is created with destroy notifies for both key and
* value, so there's no need to free the allocated memory right now.
*/
- g_hash_table_insert(tags, key, value);
+ g_hash_table_insert(tags, key, unescaped);
g_match_info_next(info, &local_error);
if(local_error != NULL) {
--- a/libpurple/protocols/ircv3/tests/test_ircv3_parser.c Sat Nov 19 16:49:14 2022 -0600
+++ b/libpurple/protocols/ircv3/tests/test_ircv3_parser.c Tue Nov 22 22:06:24 2022 -0600
@@ -255,8 +255,6 @@
static void
test_purple_ircv3_parser_with_escaped_tags(void) {
-#if 0
-/* Escaped tags aren't implemented yet. */
TestPurpleIRCv3ParserData data = {
.command = "foo",
};
@@ -268,7 +266,6 @@
test_purple_ircv3_parser("@a=b\\\\and\\nk;c=72\\s45;d=gh\\:764 foo",
&data);
-#endif
}
static void
@@ -452,8 +449,6 @@
static void
test_purple_ircv3_slashes_are_fun(void) {
-#if 0
-/* Escaped tags aren't implemented yet. */
TestPurpleIRCv3ParserData data = {
.command = "COMMAND",
};
@@ -462,7 +457,6 @@
g_hash_table_insert(data.tags, "foo", "\\\\;\\s \r\n");
test_purple_ircv3_parser("@foo=\\\\\\\\\\:\\\\s\\s\\r\\n COMMAND", &data);
-#endif
}
static void
@@ -508,8 +502,6 @@
static void
test_purple_ircv3_tag_escape_char_at_a_time(void) {
-#if 0
-/* Escaped tags aren't implemented yet. */
TestPurpleIRCv3ParserData data = {
.command = "COMMAND",
};
@@ -518,12 +510,10 @@
g_hash_table_insert(data.tags, "tag1", "value\\ntest");
test_purple_ircv3_parser("@tag1=value\\\\ntest COMMAND", &data);
-#endif
}
static void
test_purple_ircv3_tag_drop_unnecessary_escapes(void) {
-#if 0
TestPurpleIRCv3ParserData data = {
.command = "COMMAND",
};
@@ -532,13 +522,10 @@
g_hash_table_insert(data.tags, "tag1", "value1");
test_purple_ircv3_parser("@tag1=value\\1 COMMAND", &data);
-#endif
}
static void
test_purple_ircv3_tag_drop_trailing_slash(void) {
-#if 0
-/* Escaped tags aren't implemented yet. */
TestPurpleIRCv3ParserData data = {
.command = "COMMAND",
};
@@ -547,7 +534,6 @@
g_hash_table_insert(data.tags, "tag1", "value1");
test_purple_ircv3_parser("@tag1=value1\\ COMMAND", &data);
-#endif
}
static void