diff options
-rw-r--r-- | ChangeLog.adoc | 1 | ||||
-rw-r--r-- | doc/en/weechat_dev.en.adoc | 1 | ||||
-rw-r--r-- | doc/en/weechat_plugin_api.en.adoc | 14 | ||||
-rw-r--r-- | doc/fr/weechat_dev.fr.adoc | 1 | ||||
-rw-r--r-- | doc/fr/weechat_plugin_api.fr.adoc | 14 | ||||
-rw-r--r-- | doc/it/weechat_plugin_api.it.adoc | 16 | ||||
-rw-r--r-- | doc/ja/weechat_dev.ja.adoc | 2 | ||||
-rw-r--r-- | doc/ja/weechat_plugin_api.ja.adoc | 16 | ||||
-rw-r--r-- | doc/sr/weechat_dev.sr.adoc | 2 | ||||
-rw-r--r-- | doc/sr/weechat_plugin_api.sr.adoc | 16 | ||||
-rw-r--r-- | po/POTFILES.in | 4 | ||||
-rw-r--r-- | po/srcfiles.cmake | 4 | ||||
-rw-r--r-- | src/plugins/irc/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/plugins/irc/Makefile.am | 2 | ||||
-rw-r--r-- | src/plugins/irc/irc-protocol.c | 65 | ||||
-rw-r--r-- | src/plugins/irc/irc-tag.c | 280 | ||||
-rw-r--r-- | src/plugins/irc/irc-tag.h | 32 | ||||
-rw-r--r-- | src/plugins/irc/irc.c | 5 | ||||
-rw-r--r-- | tests/CMakeLists.txt | 1 | ||||
-rw-r--r-- | tests/Makefile.am | 3 | ||||
-rw-r--r-- | tests/unit/plugins/irc/test-irc-protocol.cpp | 34 | ||||
-rw-r--r-- | tests/unit/plugins/irc/test-irc-tag.cpp | 147 |
22 files changed, 564 insertions, 97 deletions
diff --git a/ChangeLog.adoc b/ChangeLog.adoc index 86c4e2f37..257879c06 100644 --- a/ChangeLog.adoc +++ b/ChangeLog.adoc @@ -31,6 +31,7 @@ New features:: Bug fixes:: * api: fix function string_match with joker in the string if multiple words matched in input string + * irc: escape/unescape IRC message tags values (issue #1654) * irc: set notify level to "private" for received WALLOPS Documentation:: diff --git a/doc/en/weechat_dev.en.adoc b/doc/en/weechat_dev.en.adoc index 34b7e7358..2c889bcc1 100644 --- a/doc/en/weechat_dev.en.adoc +++ b/doc/en/weechat_dev.en.adoc @@ -294,6 +294,7 @@ WeeChat "core" is located in following directories: | irc-redirect.c | Redirection of IRC command output. | irc-sasl.c | SASL authentication with IRC server. | irc-server.c | I/O communication with IRC server. +| irc-tag.c | Functions to manipulate IRC message tags. | irc-upgrade.c | Save/restore of IRC data when upgrading WeeChat. | javascript/ | JavaScript plugin. | weechat-js.cpp | Main JavaScript functions (load/unload scripts, execute JavaScript code). diff --git a/doc/en/weechat_plugin_api.en.adoc b/doc/en/weechat_plugin_api.en.adoc index dde1f532c..3ce99dbcc 100644 --- a/doc/en/weechat_plugin_api.en.adoc +++ b/doc/en/weechat_plugin_api.en.adoc @@ -11837,6 +11837,20 @@ List of modifiers defined by WeeChat and plugins that can be used: Message displayed after `/msg` sent to nickserv. | Message with hidden password. +| [[hook_modifier_irc_tag_escape_value]] irc_tag_escape_value + + _(WeeChat ≥ 3.3)_ | + - | + Any string. | + String with IRC tag value escaped, + see: https://ircv3.net/specs/extensions/message-tags#escaping-values. + +| [[hook_modifier_irc_tag_unescape_value]] irc_tag_unescape_value + + _(WeeChat ≥ 3.3)_ | + - | + Any string. | + String with IRC tag value unescaped, + see: https://ircv3.net/specs/extensions/message-tags#escaping-values. + | [[hook_modifier_color_decode_ansi]] color_decode_ansi + _(WeeChat ≥ 1.0)_ | "1" to keep colors, "0" to remove colors | diff --git a/doc/fr/weechat_dev.fr.adoc b/doc/fr/weechat_dev.fr.adoc index cdd807ee3..64b897298 100644 --- a/doc/fr/weechat_dev.fr.adoc +++ b/doc/fr/weechat_dev.fr.adoc @@ -296,6 +296,7 @@ Le cœur de WeeChat est situé dans les répertoires suivants : | irc-redirect.c | Redirection de la sortie des commandes IRC. | irc-sasl.c | Authentification SASL avec le serveur IRC. | irc-server.c | Communication avec le serveur IRC. +| irc-tag.c | Fonctions pour manipuler les étiquettes de message IRC. | irc-upgrade.c | Sauvegarde/restauration des données IRC lors de la mise à jour de WeeChat. | javascript/ | Extension JavaScript. | weechat-js.cpp | Fonctions principales pour JavaScript (chargement/déchargement des scripts, exécution de code JavaScript). diff --git a/doc/fr/weechat_plugin_api.fr.adoc b/doc/fr/weechat_plugin_api.fr.adoc index 7d4c0d92d..5bfe0b2b6 100644 --- a/doc/fr/weechat_plugin_api.fr.adoc +++ b/doc/fr/weechat_plugin_api.fr.adoc @@ -12083,6 +12083,20 @@ utilisés : Message affiché après `msg` envoyé à nickserv. | Message avec le mot de passe caché. +| [[hook_modifier_irc_tag_escape_value]] irc_tag_escape_value + + _(WeeChat ≥ 3.3)_ | + - | + Toute chaîne. | + Chaîne avec la valeur de l'étiquette IRC échappée, + voir : https://ircv3.net/specs/extensions/message-tags#escaping-values. + +| [[hook_modifier_irc_tag_unescape_value]] irc_tag_unescape_value + + _(WeeChat ≥ 3.3)_ | + - | + Toute chaîne. | + Chaîne avec la valeur de l'étiquette IRC sans échappements, + voir : https://ircv3.net/specs/extensions/message-tags#escaping-values. + | [[hook_modifier_color_decode_ansi]] color_decode_ansi + _(WeeChat ≥ 1.0)_ | "1" pour garder les couleurs, "0" pour les supprimer | diff --git a/doc/it/weechat_plugin_api.it.adoc b/doc/it/weechat_plugin_api.it.adoc index 667c09c38..5618bd8a2 100644 --- a/doc/it/weechat_plugin_api.it.adoc +++ b/doc/it/weechat_plugin_api.it.adoc @@ -12304,6 +12304,22 @@ List of modifiers defined by WeeChat and plugins that can be used: Message with hidden password. // TRANSLATION MISSING +| [[hook_modifier_irc_tag_escape_value]] irc_tag_escape_value + + _(WeeChat ≥ 3.3)_ | + - | + Any string. | + String with IRC tag value escaped, + see: https://ircv3.net/specs/extensions/message-tags#escaping-values. + +// TRANSLATION MISSING +| [[hook_modifier_irc_tag_unescape_value]] irc_tag_unescape_value + + _(WeeChat ≥ 3.3)_ | + - | + Any string. | + String with IRC tag value unescaped, + see: https://ircv3.net/specs/extensions/message-tags#escaping-values. + +// TRANSLATION MISSING | [[hook_modifier_color_decode_ansi]] color_decode_ansi + _(WeeChat ≥ 1.0)_ | "1" per mantenere i colori, "0" per rimuovere i colori | diff --git a/doc/ja/weechat_dev.ja.adoc b/doc/ja/weechat_dev.ja.adoc index 1f0bb8c10..4350df4b1 100644 --- a/doc/ja/weechat_dev.ja.adoc +++ b/doc/ja/weechat_dev.ja.adoc @@ -305,6 +305,8 @@ WeeChat "core" は以下のディレクトリに配置されています: | irc-redirect.c | IRC コマンド出力のリダイレクト | irc-sasl.c | IRC サーバに対する SASL 認証 | irc-server.c | IRC サーバとの入出力通信 +// TRANSLATION MISSING +| irc-tag.c | Functions to manipulate IRC message tags. | irc-upgrade.c | WeeChat をアップグレードする際の IRC データの保存およびロード | javascript/ | JavaScript プラグイン | weechat-js.cpp | JavaScript の主要関数 (スクリプトのロード/アンロード、JavaScript コードの実行) diff --git a/doc/ja/weechat_plugin_api.ja.adoc b/doc/ja/weechat_plugin_api.ja.adoc index ea645d493..21bd45ec8 100644 --- a/doc/ja/weechat_plugin_api.ja.adoc +++ b/doc/ja/weechat_plugin_api.ja.adoc @@ -11859,6 +11859,22 @@ WeeChat とプラグインが定義する修飾子のリスト: `/msg` をサーバに送信した後に表示されるメッセージ | パスワードを隠したメッセージ +// TRANSLATION MISSING +| [[hook_modifier_irc_tag_escape_value]] irc_tag_escape_value + + _(WeeChat ≥ 3.3)_ | + - | + Any string. | + String with IRC tag value escaped, + see: https://ircv3.net/specs/extensions/message-tags#escaping-values. + +// TRANSLATION MISSING +| [[hook_modifier_irc_tag_unescape_value]] irc_tag_unescape_value + + _(WeeChat ≥ 3.3)_ | + - | + Any string. | + String with IRC tag value unescaped, + see: https://ircv3.net/specs/extensions/message-tags#escaping-values. + | [[hook_modifier_color_decode_ansi]] color_decode_ansi + _(WeeChat バージョン 1.0 以上で利用可)_ | 色を保持する場合は "1"、削除する場合は "0" | diff --git a/doc/sr/weechat_dev.sr.adoc b/doc/sr/weechat_dev.sr.adoc index 988968ea5..456351149 100644 --- a/doc/sr/weechat_dev.sr.adoc +++ b/doc/sr/weechat_dev.sr.adoc @@ -290,6 +290,8 @@ WeeChat „језгро” се налази у следећим директо | irc-redirect.c | Преусмеравање излаза IRC команде. | irc-sasl.c | SASL аутентификација са IRC сервером. | irc-server.c | У/И комуникација са IRC сервером. +// TRANSLATION MISSING +| irc-tag.c | Functions to manipulate IRC message tags. | irc-upgrade.c | Чување/обнављање IRC података када се ажурира програм WeeChat. | javascript/ | JavaScript додатак. | weechat-js.cpp | Главне JavaScript функције (учитавање/уклањање скрипти, извршавање JavaScript кода). diff --git a/doc/sr/weechat_plugin_api.sr.adoc b/doc/sr/weechat_plugin_api.sr.adoc index 06fb60e93..829141662 100644 --- a/doc/sr/weechat_plugin_api.sr.adoc +++ b/doc/sr/weechat_plugin_api.sr.adoc @@ -11405,6 +11405,22 @@ char *weechat_hook_modifier_exec (const char *modifier, Порука која се приказује након што се `/msg` пошаље nickserv боту. | Порука са скривеном лозинком. +// TRANSLATION MISSING +| [[hook_modifier_irc_tag_escape_value]] irc_tag_escape_value + + _(WeeChat ≥ 3.3)_ | + - | + Any string. | + String with IRC tag value escaped, + see: https://ircv3.net/specs/extensions/message-tags#escaping-values. + +// TRANSLATION MISSING +| [[hook_modifier_irc_tag_unescape_value]] irc_tag_unescape_value + + _(WeeChat ≥ 3.3)_ | + - | + Any string. | + String with IRC tag value unescaped, + see: https://ircv3.net/specs/extensions/message-tags#escaping-values. + | [[hook_modifier_color_decode_ansi]] color_decode_ansi + _(WeeChat ≥ 1.0)_ | "1" да се боје задрже, "0" да се боје уклоне | diff --git a/po/POTFILES.in b/po/POTFILES.in index 393f196b1..e69d1443c 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -257,6 +257,10 @@ ./src/plugins/irc/irc-sasl.h ./src/plugins/irc/irc-server.c ./src/plugins/irc/irc-server.h +./src/plugins/irc/irc-tag.c +./src/plugins/irc/irc-tag.h +./src/plugins/irc/irc-upgrade.c +./src/plugins/irc/irc-upgrade.h ./src/plugins/javascript/weechat-js-api.cpp ./src/plugins/javascript/weechat-js-api.h ./src/plugins/javascript/weechat-js-v8.cpp diff --git a/po/srcfiles.cmake b/po/srcfiles.cmake index 33e675694..af5a5f45c 100644 --- a/po/srcfiles.cmake +++ b/po/srcfiles.cmake @@ -258,6 +258,10 @@ SET(WEECHAT_SOURCES ./src/plugins/irc/irc-sasl.h ./src/plugins/irc/irc-server.c ./src/plugins/irc/irc-server.h +./src/plugins/irc/irc-tag.c +./src/plugins/irc/irc-tag.h +./src/plugins/irc/irc-upgrade.c +./src/plugins/irc/irc-upgrade.h ./src/plugins/javascript/weechat-js-api.cpp ./src/plugins/javascript/weechat-js-api.h ./src/plugins/javascript/weechat-js-v8.cpp diff --git a/src/plugins/irc/CMakeLists.txt b/src/plugins/irc/CMakeLists.txt index da5647691..c638605e7 100644 --- a/src/plugins/irc/CMakeLists.txt +++ b/src/plugins/irc/CMakeLists.txt @@ -42,6 +42,7 @@ add_library(irc MODULE irc-redirect.c irc-redirect.h irc-sasl.c irc-sasl.h irc-server.c irc-server.h + irc-tag.c irc-tag.h irc-upgrade.c irc-upgrade.h ) set_target_properties(irc PROPERTIES PREFIX "") diff --git a/src/plugins/irc/Makefile.am b/src/plugins/irc/Makefile.am index b12570f8a..fa5833350 100644 --- a/src/plugins/irc/Makefile.am +++ b/src/plugins/irc/Makefile.am @@ -71,6 +71,8 @@ irc_la_SOURCES = irc.c \ irc-sasl.h \ irc-server.c \ irc-server.h \ + irc-tag.c \ + irc-tag.h \ irc-upgrade.c \ irc-upgrade.h diff --git a/src/plugins/irc/irc-protocol.c b/src/plugins/irc/irc-protocol.c index 356fc1347..2890496a7 100644 --- a/src/plugins/irc/irc-protocol.c +++ b/src/plugins/irc/irc-protocol.c @@ -53,9 +53,10 @@ #include "irc-modelist.h" #include "irc-msgbuffer.h" #include "irc-nick.h" +#include "irc-notify.h" #include "irc-sasl.h" #include "irc-server.h" -#include "irc-notify.h" +#include "irc-tag.h" /* @@ -200,66 +201,6 @@ irc_protocol_nick_address (struct t_irc_server *server, } /* - * Returns hashtable with tags for an IRC message. - * - * Example: - * if tags == "aaa=bbb;ccc;example.com/ddd=eee", - * hashtable will have following keys/values: - * "aaa" => "bbb" - * "ccc" => NULL - * "example.com/ddd" => "eee" - */ - -struct t_hashtable * -irc_protocol_get_message_tags (const char *tags) -{ - struct t_hashtable *hashtable; - char **items, *pos, *key; - int num_items, i; - - if (!tags || !tags[0]) - return NULL; - - hashtable = weechat_hashtable_new (32, - WEECHAT_HASHTABLE_STRING, - WEECHAT_HASHTABLE_STRING, - NULL, NULL); - if (!hashtable) - return NULL; - - items = weechat_string_split (tags, ";", NULL, - WEECHAT_STRING_SPLIT_STRIP_LEFT - | WEECHAT_STRING_SPLIT_STRIP_RIGHT - | WEECHAT_STRING_SPLIT_COLLAPSE_SEPS, - 0, &num_items); - if (items) - { - for (i = 0; i < num_items; i++) - { - pos = strchr (items[i], '='); - if (pos) - { - /* format: "tag=value" */ - key = weechat_strndup (items[i], pos - items[i]); - if (key) - { - weechat_hashtable_set (hashtable, key, pos + 1); - free (key); - } - } - else - { - /* format: "tag" */ - weechat_hashtable_set (hashtable, items[i], NULL); - } - } - weechat_string_free_split (items); - } - - return hashtable; -} - -/* * Parses date/time received in a "time" tag. * * Returns value of time (timestamp), 0 if error. @@ -6883,7 +6824,7 @@ irc_protocol_recv_command (struct t_irc_server *server, pos_space - (irc_message + 1)); if (tags) { - hash_tags = irc_protocol_get_message_tags (tags); + hash_tags = irc_tag_parse (tags); if (hash_tags) { date = irc_protocol_parse_time ( diff --git a/src/plugins/irc/irc-tag.c b/src/plugins/irc/irc-tag.c new file mode 100644 index 000000000..a0534e0ad --- /dev/null +++ b/src/plugins/irc/irc-tag.c @@ -0,0 +1,280 @@ +/* + * irc-tag.c - functions for IRC message tags + * + * Copyright (C) 2021 Sébastien Helleu <flashcode@flashtux.org> + * + * This file is part of WeeChat, the extensible chat client. + * + * WeeChat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * WeeChat is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WeeChat. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> + +#include "../weechat-plugin.h" +#include "irc.h" +#include "irc-tag.h" + + +/* + * Escapes a tag value, the following sequences are replaced: + * + * character | escaped value + * ---------------+------------------------- + * ; (semicolon) | \: (backslash and colon) + * SPACE | \s + * \ | \\ + * CR | \r + * LF | \n + * all others | the character itself + * + * See: https://ircv3.net/specs/extensions/message-tags#escaping-values + * + * Note: result must be freed after use. + */ + +char * +irc_tag_escape_value (const char *string) +{ + char **out, *result; + unsigned char *ptr_string; + int length; + + if (!string) + return NULL; + + length = strlen (string); + out = weechat_string_dyn_alloc (length + (length / 2) + 1); + if (!out) + return NULL; + + ptr_string = (unsigned char *)string; + while (ptr_string && ptr_string[0]) + { + switch (ptr_string[0]) + { + case ';': + weechat_string_dyn_concat (out, "\\:", -1); + ptr_string++; + break; + case ' ': + weechat_string_dyn_concat (out, "\\s", -1); + ptr_string++; + break; + case '\\': + weechat_string_dyn_concat (out, "\\\\", -1); + ptr_string++; + break; + case '\r': + weechat_string_dyn_concat (out, "\\r", -1); + ptr_string++; + break; + case '\n': + weechat_string_dyn_concat (out, "\\n", -1); + ptr_string++; + break; + default: + length = weechat_utf8_char_size ((char *)ptr_string); + if (length == 0) + length = 1; + weechat_string_dyn_concat (out, + (const char *)ptr_string, + length); + ptr_string += length; + break; + } + } + + result = *out; + weechat_string_dyn_free (out, 0); + + return result; +} + +/* + * Unescapes a tag value. + * + * See: https://ircv3.net/specs/extensions/message-tags#escaping-values + * + * Note: result must be freed after use. + */ + +char * +irc_tag_unescape_value (const char *string) +{ + char **out, *result; + unsigned char *ptr_string; + int length; + + if (!string) + return NULL; + + length = strlen (string); + out = weechat_string_dyn_alloc (length + (length / 2) + 1); + if (!out) + return NULL; + + ptr_string = (unsigned char *)string; + while (ptr_string && ptr_string[0]) + { + switch (ptr_string[0]) + { + case '\\': + ptr_string++; + switch (ptr_string[0]) + { + case ':': + weechat_string_dyn_concat (out, ";", -1); + ptr_string++; + break; + case 's': + weechat_string_dyn_concat (out, " ", -1); + ptr_string++; + break; + case '\\': + weechat_string_dyn_concat (out, "\\", -1); + ptr_string++; + break; + case 'r': + weechat_string_dyn_concat (out, "\r", -1); + ptr_string++; + break; + case 'n': + weechat_string_dyn_concat (out, "\n", -1); + ptr_string++; + break; + default: + if (ptr_string[0]) + { + length = weechat_utf8_char_size ((char *)ptr_string); + if (length == 0) + length = 1; + weechat_string_dyn_concat (out, + (const char *)ptr_string, + length); + ptr_string += length; + } + break; + } + break; + default: + length = weechat_utf8_char_size ((char *)ptr_string); + if (length == 0) + length = 1; + weechat_string_dyn_concat (out, + (const char *)ptr_string, + length); + ptr_string += length; + break; + } + } + + result = *out; + weechat_string_dyn_free (out, 0); + + return result; +} + +/* + * Callback for modifiers "irc_tag_escape_value" and "irc_tag_unescape_value". + * + * These modifiers can be used by other plugins to escape/unescape IRC message + * tags. + */ + +char * +irc_tag_modifier_cb (const void *pointer, void *data, + const char *modifier, const char *modifier_data, + const char *string) +{ + /* make C compiler happy */ + (void) pointer; + (void) data; + (void) modifier_data; + + if (strcmp (modifier, "irc_tag_escape_value") == 0) + return irc_tag_escape_value (string); + + if (strcmp (modifier, "irc_tag_unescape_value") == 0) + return irc_tag_unescape_value (string); + + /* unknown modifier */ + return NULL; +} + +/* + * Parses tags received in an IRC message. + * Returns a hashtable with tags and their unescaped values. + * + * Example: + * if tags == "aaa=bbb;ccc;example.com/ddd=eee", + * hashtable will have following keys/values: + * "aaa" => "bbb" + * "ccc" => NULL + * "example.com/ddd" => "eee" + */ + +struct t_hashtable * +irc_tag_parse (const char *tags) +{ + struct t_hashtable *hashtable; + char **items, *pos, *key, *unescaped; + int num_items, i; + + if (!tags || !tags[0]) + return NULL; + + hashtable = weechat_hashtable_new (32, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING, + NULL, NULL); + if (!hashtable) + return NULL; + + items = weechat_string_split (tags, ";", NULL, + WEECHAT_STRING_SPLIT_STRIP_LEFT + | WEECHAT_STRING_SPLIT_STRIP_RIGHT + | WEECHAT_STRING_SPLIT_COLLAPSE_SEPS, + 0, &num_items); + if (items) + { + for (i = 0; i < num_items; i++) + { + pos = strchr (items[i], '='); + if (pos) + { + /* format: "tag=value" */ + key = weechat_strndup (items[i], pos - items[i]); + if (key) + { + unescaped = irc_tag_unescape_value (pos + 1); + weechat_hashtable_set (hashtable, key, unescaped); + if (unescaped) + free (unescaped); + free (key); + } + } + else + { + /* format: "tag" */ + weechat_hashtable_set (hashtable, items[i], NULL); + } + } + weechat_string_free_split (items); + } + + return hashtable; +} diff --git a/src/plugins/irc/irc-tag.h b/src/plugins/irc/irc-tag.h new file mode 100644 index 000000000..2e70668af --- /dev/null +++ b/src/plugins/irc/irc-tag.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2021 Sébastien Helleu <flashcode@flashtux.org> + * + * This file is part of WeeChat, the extensible chat client. + * + * WeeChat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * WeeChat is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WeeChat. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef WEECHAT_PLUGIN_IRC_TAG_H +#define WEECHAT_PLUGIN_IRC_TAG_H + +extern char *irc_tag_escape_value (const char *string); +extern char *irc_tag_unescape_value (const char *string); +extern char *irc_tag_modifier_cb (const void *pointer, + void *data, + const char *modifier, + const char *modifier_data, + const char *string); +extern struct t_hashtable *irc_tag_parse (const char *tags); + +#endif /* WEECHAT_PLUGIN_IRC_TAG_H */ diff --git a/src/plugins/irc/irc.c b/src/plugins/irc/irc.c index e1043aa29..9c1a1a3db 100644 --- a/src/plugins/irc/irc.c +++ b/src/plugins/irc/irc.c @@ -42,6 +42,7 @@ #include "irc-raw.h" #include "irc-redirect.h" #include "irc-server.h" +#include "irc-tag.h" #include "irc-upgrade.h" @@ -213,6 +214,10 @@ weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[]) &irc_color_modifier_cb, NULL, NULL); weechat_hook_modifier ("irc_color_decode_ansi", &irc_color_modifier_cb, NULL, NULL); + weechat_hook_modifier ("irc_tag_escape_value", + &irc_tag_modifier_cb, NULL, NULL); + weechat_hook_modifier ("irc_tag_unescape_value", + &irc_tag_modifier_cb, NULL, NULL); /* hook completions */ irc_completion_init (); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 319462acd..00cba0348 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -62,6 +62,7 @@ if(ENABLE_IRC) unit/plugins/irc/test-irc-nick.cpp unit/plugins/irc/test-irc-protocol.cpp unit/plugins/irc/test-irc-server.cpp + unit/plugins/irc/test-irc-tag.cpp ) endif() diff --git a/tests/Makefile.am b/tests/Makefile.am index 8b2292db7..9ea082f5d 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -76,7 +76,8 @@ tests_irc = unit/plugins/irc/test-irc-channel.cpp \ unit/plugins/irc/test-irc-mode.cpp \ unit/plugins/irc/test-irc-nick.cpp \ unit/plugins/irc/test-irc-protocol.cpp \ - unit/plugins/irc/test-irc-server.cpp + unit/plugins/irc/test-irc-server.cpp \ + unit/plugins/irc/test-irc-tag.cpp endif if PLUGIN_RELAY diff --git a/tests/unit/plugins/irc/test-irc-protocol.cpp b/tests/unit/plugins/irc/test-irc-protocol.cpp index eff9e3346..04eaf6b4b 100644 --- a/tests/unit/plugins/irc/test-irc-protocol.cpp +++ b/tests/unit/plugins/irc/test-irc-protocol.cpp @@ -42,7 +42,6 @@ extern const char *irc_protocol_nick_address (struct t_irc_server *server, struct t_irc_nick *nick, const char *nickname, const char *address); -extern struct t_hashtable *irc_protocol_get_message_tags (const char *tags); extern char *irc_protocol_cap_to_enable (const char *capabilities, int sasl_requested); } @@ -171,39 +170,6 @@ TEST(IrcProtocol, Tags) /* * Tests functions: - * irc_protocol_get_message_tags - */ - -TEST(IrcProtocol, GetMessageTags) -{ - struct t_hashtable *hashtable; - - POINTERS_EQUAL(NULL, irc_protocol_get_message_tags (NULL)); - POINTERS_EQUAL(NULL, irc_protocol_get_message_tags ("")); - - hashtable = irc_protocol_get_message_tags ("abc"); - CHECK(hashtable); - LONGS_EQUAL(1, hashtable->items_count); - POINTERS_EQUAL(NULL, (const char *)hashtable_get (hashtable, "abc")); - hashtable_free (hashtable); - - hashtable = irc_protocol_get_message_tags ("abc=def"); - CHECK(hashtable); - LONGS_EQUAL(1, hashtable->items_count); - STRCMP_EQUAL("def", (const char *)hashtable_get (hashtable, "abc")); - hashtable_free (hashtable); - - hashtable = irc_protocol_get_message_tags ("aaa=bbb;ccc;example.com/ddd=eee"); - CHECK(hashtable); - LONGS_EQUAL(3, hashtable->items_count); - STRCMP_EQUAL("bbb", (const char *)hashtable_get (hashtable, "aaa")); - POINTERS_EQUAL(NULL, (const char *)hashtable_get (hashtable, "ccc")); - STRCMP_EQUAL("eee", (const char *)hashtable_get (hashtable, "example.com/ddd")); - hashtable_free (hashtable); -} - -/* - * Tests functions: * irc_protocol_parse_time */ diff --git a/tests/unit/plugins/irc/test-irc-tag.cpp b/tests/unit/plugins/irc/test-irc-tag.cpp new file mode 100644 index 000000000..50796ac37 --- /dev/null +++ b/tests/unit/plugins/irc/test-irc-tag.cpp @@ -0,0 +1,147 @@ +/* + * test-irc-tag.cpp - test IRC message tags functions + * + * Copyright (C) 2021 Sébastien Helleu <flashcode@flashtux.org> + * + * This file is part of WeeChat, the extensible chat client. + * + * WeeChat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * WeeChat is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WeeChat. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "CppUTest/TestHarness.h" + +extern "C" +{ +#include <stdio.h> +#include "src/core/wee-hashtable.h" +#include "src/core/wee-hook.h" +#include "src/plugins/irc/irc-tag.h" +} + +#define WEE_CHECK_ESCAPE_VALUE(__result, __string) \ + escaped = irc_tag_escape_value (__string); \ + STRCMP_EQUAL(__result, escaped); \ + free (escaped); + +#define WEE_CHECK_UNESCAPE_VALUE(__result, __string) \ + unescaped = irc_tag_unescape_value (__string); \ + STRCMP_EQUAL(__result, unescaped); \ + free (unescaped); + +TEST_GROUP(IrcTag) +{ +}; + +/* + * Tests functions: + * irc_tag_escape_value + */ + +TEST(IrcTag, EscapeValue) +{ + char *escaped; + + /* NULL/empty string */ + POINTERS_EQUAL(NULL, irc_tag_escape_value (NULL)); + WEE_CHECK_ESCAPE_VALUE("", ""); + + WEE_CHECK_ESCAPE_VALUE("test", "test"); + WEE_CHECK_ESCAPE_VALUE("test\\:abc", "test;abc"); + WEE_CHECK_ESCAPE_VALUE("test\\sabc", "test abc"); + WEE_CHECK_ESCAPE_VALUE("test_\\\\_abc", "test_\\_abc"); + WEE_CHECK_ESCAPE_VALUE("test_\\r_abc", "test_\r_abc"); + WEE_CHECK_ESCAPE_VALUE("test_\\n_abc", "test_\n_abc"); + WEE_CHECK_ESCAPE_VALUE("test_\xf0\xa4\xad\xa2_abc", + "test_\xf0\xa4\xad\xa2_abc"); + WEE_CHECK_ESCAPE_VALUE("\\:\\s\\\\\\r\\n", "; \\\r\n"); +} + +/* + * Tests functions: + * irc_tag_unescape_value + */ + +TEST(IrcTag, UnescapeValue) +{ + char *unescaped; + + /* NULL/empty string */ + POINTERS_EQUAL(NULL, irc_tag_unescape_value (NULL)); + WEE_CHECK_UNESCAPE_VALUE("", ""); + + WEE_CHECK_UNESCAPE_VALUE("test", "test"); + WEE_CHECK_UNESCAPE_VALUE("test", "test\\"); + WEE_CHECK_UNESCAPE_VALUE("test;abc", "test\\:abc"); + WEE_CHECK_UNESCAPE_VALUE("test abc", "test\\sabc"); + WEE_CHECK_UNESCAPE_VALUE("test_\\_abc", "test_\\\\_abc"); + WEE_CHECK_UNESCAPE_VALUE("test_\r_abc", "test_\\r_abc"); + WEE_CHECK_UNESCAPE_VALUE("test_\n_abc", "test_\\n_abc"); + WEE_CHECK_UNESCAPE_VALUE("test_a_abc", "test_\\a_abc"); + WEE_CHECK_UNESCAPE_VALUE("test_\xf0\xa4\xad\xa2_abc", + "test_\\\xf0\xa4\xad\xa2_abc"); + WEE_CHECK_UNESCAPE_VALUE("; \\\r\n", "\\:\\s\\\\\\r\\n"); +} + +/* + * Tests functions: + * irc_tag_modifier_cb + */ + +TEST(IrcTag, ModifierCallback) +{ + char *result; + + /* modifier "irc_tag_escape_value" */ + result = hook_modifier_exec (NULL, "irc_tag_escape_value", NULL, "test"); + STRCMP_EQUAL("test", result); + free (result); + + /* modifier "irc_tag_unescape_value" */ + result = hook_modifier_exec (NULL, "irc_tag_unescape_value", NULL, "test"); + STRCMP_EQUAL("test", result); + free (result); +} + +/* + * Tests functions: + * irc_tag_parse + */ + +TEST(IrcTag, Parse) +{ + struct t_hashtable *hashtable; + + POINTERS_EQUAL(NULL, irc_tag_parse (NULL)); + POINTERS_EQUAL(NULL, irc_tag_parse ("")); + + hashtable = irc_tag_parse ("abc"); + CHECK(hashtable); + LONGS_EQUAL(1, hashtable->items_count); + POINTERS_EQUAL(NULL, (const char *)hashtable_get (hashtable, "abc")); + hashtable_free (hashtable); + + hashtable = irc_tag_parse ("abc=def"); + CHECK(hashtable); + LONGS_EQUAL(1, hashtable->items_count); + STRCMP_EQUAL("def", (const char *)hashtable_get (hashtable, "abc")); + hashtable_free (hashtable); + + hashtable = irc_tag_parse ("aaa=bbb;ccc;example.com/ddd=eee"); + CHECK(hashtable); + LONGS_EQUAL(3, hashtable->items_count); + STRCMP_EQUAL("bbb", (const char *)hashtable_get (hashtable, "aaa")); + POINTERS_EQUAL(NULL, (const char *)hashtable_get (hashtable, "ccc")); + STRCMP_EQUAL("eee", (const char *)hashtable_get (hashtable, "example.com/ddd")); + hashtable_free (hashtable); +} |