summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog.adoc1
-rw-r--r--doc/en/weechat_dev.en.adoc1
-rw-r--r--doc/en/weechat_plugin_api.en.adoc14
-rw-r--r--doc/fr/weechat_dev.fr.adoc1
-rw-r--r--doc/fr/weechat_plugin_api.fr.adoc14
-rw-r--r--doc/it/weechat_plugin_api.it.adoc16
-rw-r--r--doc/ja/weechat_dev.ja.adoc2
-rw-r--r--doc/ja/weechat_plugin_api.ja.adoc16
-rw-r--r--doc/sr/weechat_dev.sr.adoc2
-rw-r--r--doc/sr/weechat_plugin_api.sr.adoc16
-rw-r--r--po/POTFILES.in4
-rw-r--r--po/srcfiles.cmake4
-rw-r--r--src/plugins/irc/CMakeLists.txt1
-rw-r--r--src/plugins/irc/Makefile.am2
-rw-r--r--src/plugins/irc/irc-protocol.c65
-rw-r--r--src/plugins/irc/irc-tag.c280
-rw-r--r--src/plugins/irc/irc-tag.h32
-rw-r--r--src/plugins/irc/irc.c5
-rw-r--r--tests/CMakeLists.txt1
-rw-r--r--tests/Makefile.am3
-rw-r--r--tests/unit/plugins/irc/test-irc-protocol.cpp34
-rw-r--r--tests/unit/plugins/irc/test-irc-tag.cpp147
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);
+}