Tue, 22 Nov 2022 22:06:24 -0600
Unescape tag values in IRCv3
Testing Done:
Ran the unittests (after uncommenting them of course...)
Reviewed at https://reviews.imfreedom.org/r/2078/
| libpurple/protocols/ircv3/purpleircv3parser.c | file | annotate | diff | comparison | revisions | |
| libpurple/protocols/ircv3/tests/test_ircv3_parser.c | file | annotate | diff | comparison | revisions |
--- 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