diff --git a/ChangeLog.adoc b/ChangeLog.adoc index b7a6728ee..31cd3384e 100644 --- a/ChangeLog.adoc +++ b/ChangeLog.adoc @@ -22,6 +22,7 @@ New features:: * core: search in message tags when tags are displayed with `/debug tags` * core: add support of date and tags in messages displayed in buffers with free content, add function printf_y_date_tags (issue #1746) + * irc: add server option "autojoin_record" * irc: add IRC message tags in messages displayed (issue #1680) * relay: add `zstd` (https://facebook.github.io/zstd/[Zstandard]) compression in weechat protocol, remove option `compression` from `init` command, rename option relay.network.compression_level to relay.network.compression * trigger: add variables `${tg_tag_irc_xxx}` containing IRC message tags (issue #1680) diff --git a/doc/de/weechat_faq.de.adoc b/doc/de/weechat_faq.de.adoc index 184eed02e..4152fce93 100644 --- a/doc/de/weechat_faq.de.adoc +++ b/doc/de/weechat_faq.de.adoc @@ -887,6 +887,24 @@ um sich vor dem Betreten von Channels bei "nickserv" zu identifizieren: [[edit_autojoin]] === Wie kann ich Channels zur autojoin Option entfernen/hinzufügen? +// TRANSLATION MISSING +With WeeChat ≥ 3.5, you can automatically record the channels you manually +join and part in the "autojoin" server option. + +// TRANSLATION MISSING +For all servers: + +---- +/set irc.server_default.autojoin_record on +---- + +// TRANSLATION MISSING +For a single server: + +---- +/set irc.server.libera.autojoin_record on +---- + Um die Liste der autojoin Channels zu editieren, kann der Befehl `/set` genutzt werden. In folgendem Beispiel wird der "libera"-Server angepasst: diff --git a/doc/en/weechat_dev.en.adoc b/doc/en/weechat_dev.en.adoc index 29d8c61ec..cb8ae635c 100644 --- a/doc/en/weechat_dev.en.adoc +++ b/doc/en/weechat_dev.en.adoc @@ -284,6 +284,7 @@ WeeChat "core" is located in following directories: |       irc-ignore.c | IRC Ignore. |       irc-info.c | IRC info/infolists/hdata. |       irc-input.c | Input of commands/text. +|       irc-join.c | Functions for list of channels to join. |       irc-message.c | Functions to manipulate IRC messages. |       irc-mode.c | Functions about channel/nick modes. |       irc-modelist.c | IRC channel mode lists (+b, +e, +I, ...). @@ -431,6 +432,7 @@ WeeChat "core" is located in following directories: |             test-irc-color.cpp | Tests: IRC colors. |             test-irc-config.cpp | Tests: IRC configuration. |             test-irc-ignore.cpp | Tests: IRC ignores. +|             test-irc-join.cpp | Tests: IRC join functions. |             test-irc-message.cpp | Tests: IRC messages. |             test-irc-mode.cpp | Tests: IRC modes. |             test-irc-nick.cpp | Tests: IRC nicks. diff --git a/doc/en/weechat_faq.en.adoc b/doc/en/weechat_faq.en.adoc index 596aa017f..e1d692c4f 100644 --- a/doc/en/weechat_faq.en.adoc +++ b/doc/en/weechat_faq.en.adoc @@ -829,6 +829,21 @@ join of channels): [[edit_autojoin]] === How can I add/remove channels from autojoin option? +With WeeChat ≥ 3.5, you can automatically record the channels you manually +join and part in the "autojoin" server option. + +For all servers: + +---- +/set irc.server_default.autojoin_record on +---- + +For a single server: + +---- +/set irc.server.libera.autojoin_record on +---- + You can use the `/set` command to edit the list of autojoin channels, for example for the "libera" server: diff --git a/doc/es/weechat_faq.es.adoc b/doc/es/weechat_faq.es.adoc index c187dd807..dc120e453 100644 --- a/doc/es/weechat_faq.es.adoc +++ b/doc/es/weechat_faq.es.adoc @@ -832,6 +832,24 @@ unirse a los canales): [[edit_autojoin]] === ¿Cómo puedo añadir/eliminar canales de la opción autojoin? +// TRANSLATION MISSING +With WeeChat ≥ 3.5, you can automatically record the channels you manually +join and part in the "autojoin" server option. + +// TRANSLATION MISSING +For all servers: + +---- +/set irc.server_default.autojoin_record on +---- + +// TRANSLATION MISSING +For a single server: + +---- +/set irc.server.libera.autojoin_record on +---- + Puede utilizar el comando `/set` para editar la lista de canales con autojoin, por ejemplo, para el servidor "libera": diff --git a/doc/fr/weechat_dev.fr.adoc b/doc/fr/weechat_dev.fr.adoc index 94df1c836..4545c1c3b 100644 --- a/doc/fr/weechat_dev.fr.adoc +++ b/doc/fr/weechat_dev.fr.adoc @@ -286,6 +286,7 @@ Le cœur de WeeChat est situé dans les répertoires suivants : |       irc-ignore.c | Ignore IRC. |       irc-info.c | Info/infolists/hdata pour IRC. |       irc-input.c | Entrée de commandes/texte. +|       irc-join.c | Fonctions pour les listes de canaux à rejoindre. |       irc-message.c | Fonctions pour manipuler les messages IRC. |       irc-mode.c | Fonctions pour les modes de canal/pseudo. |       irc-modelist.c | Listes de modes de canaux IRC (+b, +e, +I, ...). @@ -433,6 +434,7 @@ Le cœur de WeeChat est situé dans les répertoires suivants : |             test-irc-color.cpp | Tests : couleurs IRC. |             test-irc-config.cpp | Tests : configuration IRC. |             test-irc-ignore.cpp | Tests : ignores IRC. +|             test-irc-join.cpp | Tests : fonctions de join IRC. |             test-irc-message.cpp | Tests : messages IRC. |             test-irc-mode.cpp | Tests : modes IRC. |             test-irc-nick.cpp | Tests : pseudos IRC. diff --git a/doc/fr/weechat_faq.fr.adoc b/doc/fr/weechat_faq.fr.adoc index de1dcc956..eaec3d3b6 100644 --- a/doc/fr/weechat_faq.fr.adoc +++ b/doc/fr/weechat_faq.fr.adoc @@ -855,6 +855,21 @@ commande et le join des canaux) : [[edit_autojoin]] === Comment puis-je ajouter/supprimer des canaux de l'option autojoin ? +Avec WeeChat ≥ 3.5, vous pouvez automatiquement enregistrer les canaux que +vous rejoignez et quittez manuellement dans l'option "autojoin" du serveur. + +Pour tous les serveurs : + +---- +/set irc.server_default.autojoin_record on +---- + +Pour un seul serveur : + +---- +/set irc.server.libera.autojoin_record on +---- + Vous pouvez utiliser la commande `/set` pour éditer la liste des canaux de l'autojoin, par exemple pour le serveur libera : diff --git a/doc/it/weechat_faq.it.adoc b/doc/it/weechat_faq.it.adoc index 967039f32..059cedef7 100644 --- a/doc/it/weechat_faq.it.adoc +++ b/doc/it/weechat_faq.it.adoc @@ -899,6 +899,24 @@ comando e l'ingresso nei canali): [[edit_autojoin]] === How can I add/remove channels from autojoin option? +// TRANSLATION MISSING +With WeeChat ≥ 3.5, you can automatically record the channels you manually +join and part in the "autojoin" server option. + +// TRANSLATION MISSING +For all servers: + +---- +/set irc.server_default.autojoin_record on +---- + +// TRANSLATION MISSING +For a single server: + +---- +/set irc.server.libera.autojoin_record on +---- + // TRANSLATION MISSING You can use the `/set` command to edit the list of autojoin channels, for example for the "libera" server: diff --git a/doc/ja/weechat_dev.ja.adoc b/doc/ja/weechat_dev.ja.adoc index e247e9479..d549bbb35 100644 --- a/doc/ja/weechat_dev.ja.adoc +++ b/doc/ja/weechat_dev.ja.adoc @@ -295,6 +295,8 @@ WeeChat "core" は以下のディレクトリに配置されています: |       irc-ignore.c | IRC 無視 |       irc-info.c | IRC の情報/インフォリスト/hdata |       irc-input.c | コマンドおよびテキストの入力 +// TRANSLATION MISSING +|       irc-join.c | Functions for list of channels to join. |       irc-message.c | IRC メッセージを操作する関数 |       irc-mode.c | チャンネルおよびニックネームのモードを操作する関数 |       irc-modelist.c | IRC チャンネルモードリスト (+b、+e、+I、...). @@ -463,6 +465,8 @@ WeeChat "core" は以下のディレクトリに配置されています: // TRANSLATION MISSING |             test-irc-ignore.cpp | Tests: IRC ignores. // TRANSLATION MISSING +|             test-irc-join.cpp | Tests: IRC join functions. +// TRANSLATION MISSING |             test-irc-message.cpp | Tests: IRC messages. // TRANSLATION MISSING |             test-irc-mode.cpp | Tests: IRC modes. diff --git a/doc/ja/weechat_faq.ja.adoc b/doc/ja/weechat_faq.ja.adoc index f058dbc13..7b8281724 100644 --- a/doc/ja/weechat_faq.ja.adoc +++ b/doc/ja/weechat_faq.ja.adoc @@ -834,6 +834,24 @@ SASL を利用する方が良いです。例えば: [[edit_autojoin]] === どうすれば自動参加オプションにチャンネルを追加/削除できますか。 +// TRANSLATION MISSING +With WeeChat ≥ 3.5, you can automatically record the channels you manually +join and part in the "autojoin" server option. + +// TRANSLATION MISSING +For all servers: + +---- +/set irc.server_default.autojoin_record on +---- + +// TRANSLATION MISSING +For a single server: + +---- +/set irc.server.libera.autojoin_record on +---- + `/set` コマンドを使って、自動参加チャンネルのリストを編集してください。"libera" サーバに対してこれを実行するには以下のようにします: diff --git a/doc/pl/weechat_faq.pl.adoc b/doc/pl/weechat_faq.pl.adoc index 36f4df8fb..5e9e0c376 100644 --- a/doc/pl/weechat_faq.pl.adoc +++ b/doc/pl/weechat_faq.pl.adoc @@ -833,6 +833,24 @@ na kanały): [[edit_autojoin]] === Jak mogę dodać/usunąć kanaly z opcji automatycznego wejścia? +// TRANSLATION MISSING +With WeeChat ≥ 3.5, you can automatically record the channels you manually +join and part in the "autojoin" server option. + +// TRANSLATION MISSING +For all servers: + +---- +/set irc.server_default.autojoin_record on +---- + +// TRANSLATION MISSING +For a single server: + +---- +/set irc.server.libera.autojoin_record on +---- + Możesz użyć komendy `/set` do edytowania tej listy, na przykład dla serwera "libera": diff --git a/doc/sr/weechat_dev.sr.adoc b/doc/sr/weechat_dev.sr.adoc index 4b3a4bb5e..b28bc31f9 100644 --- a/doc/sr/weechat_dev.sr.adoc +++ b/doc/sr/weechat_dev.sr.adoc @@ -284,6 +284,8 @@ WeeChat „језгро” се налази у следећим директо |       irc-ignore.c | IRC Ignore. |       irc-info.c | IRC info/infolists/hdata. |       irc-input.c | Унос команди/текста. +// TRANSLATION MISSING +|       irc-join.c | Functions for list of channels to join. |       irc-message.c | Функције за манипулисање IRC порукама. |       irc-mode.c | Функције у вези режима канала/надимка. |       irc-modelist.c | Листе режима IRC канала (+b, +e, +I, ...). @@ -431,6 +433,8 @@ WeeChat „језгро” се налази у следећим директо |             test-irc-color.cpp | Тестови: IRC боје. |             test-irc-config.cpp | Тестови: IRC конфигурација. |             test-irc-ignore.cpp | Тестови: IRC игнорисања. +// TRANSLATION MISSING +|             test-irc-join.cpp | Tests: IRC join functions. |             test-irc-message.cpp | Тестови: IRC поруке. |             test-irc-mode.cpp | Тестови: IRC режими. |             test-irc-nick.cpp | Тестови: IRC надимци. diff --git a/doc/sr/weechat_faq.sr.adoc b/doc/sr/weechat_faq.sr.adoc index 9f64390d4..d73cdce73 100644 --- a/doc/sr/weechat_faq.sr.adoc +++ b/doc/sr/weechat_faq.sr.adoc @@ -726,6 +726,24 @@ oauth је једноставно лозинка која има вреднос [[edit_autojoin]] === Како да додам/уклоним канале из autojoin опције? +// TRANSLATION MISSING +With WeeChat ≥ 3.5, you can automatically record the channels you manually +join and part in the "autojoin" server option. + +// TRANSLATION MISSING +For all servers: + +---- +/set irc.server_default.autojoin_record on +---- + +// TRANSLATION MISSING +For a single server: + +---- +/set irc.server.libera.autojoin_record on +---- + Можете да употребите команду `/set` и да уредите листу autojoin канала, на пример за „libera” сервер: ---- diff --git a/po/POTFILES.in b/po/POTFILES.in index 13a54a381..bad208762 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -242,6 +242,8 @@ ./src/plugins/irc/irc-info.h ./src/plugins/irc/irc-input.c ./src/plugins/irc/irc-input.h +./src/plugins/irc/irc-join.c +./src/plugins/irc/irc-join.h ./src/plugins/irc/irc-message.c ./src/plugins/irc/irc-message.h ./src/plugins/irc/irc-mode.c diff --git a/po/srcfiles.cmake b/po/srcfiles.cmake index cef9d9bab..38974cb5a 100644 --- a/po/srcfiles.cmake +++ b/po/srcfiles.cmake @@ -243,6 +243,8 @@ SET(WEECHAT_SOURCES ./src/plugins/irc/irc-info.h ./src/plugins/irc/irc-input.c ./src/plugins/irc/irc-input.h +./src/plugins/irc/irc-join.c +./src/plugins/irc/irc-join.h ./src/plugins/irc/irc-message.c ./src/plugins/irc/irc-message.h ./src/plugins/irc/irc-mode.c diff --git a/src/plugins/irc/CMakeLists.txt b/src/plugins/irc/CMakeLists.txt index 6f01ddb3e..4745df994 100644 --- a/src/plugins/irc/CMakeLists.txt +++ b/src/plugins/irc/CMakeLists.txt @@ -31,6 +31,7 @@ add_library(irc MODULE irc-ignore.c irc-ignore.h irc-info.c irc-info.h irc-input.c irc-input.h + irc-join.c irc-join.h irc-message.c irc-message.h irc-mode.c irc-mode.h irc-modelist.c irc-modelist.h diff --git a/src/plugins/irc/Makefile.am b/src/plugins/irc/Makefile.am index 5dd255886..aeac8566d 100644 --- a/src/plugins/irc/Makefile.am +++ b/src/plugins/irc/Makefile.am @@ -49,6 +49,8 @@ irc_la_SOURCES = irc.c \ irc-info.h \ irc-input.c \ irc-input.h \ + irc-join.c \ + irc-join.h \ irc-message.c \ irc-message.h \ irc-mode.c \ diff --git a/src/plugins/irc/irc-command.c b/src/plugins/irc/irc-command.c index bc61059fb..27219e5bd 100644 --- a/src/plugins/irc/irc-command.c +++ b/src/plugins/irc/irc-command.c @@ -41,6 +41,7 @@ #include "irc-config.h" #include "irc-ignore.h" #include "irc-input.h" +#include "irc-join.h" #include "irc-message.h" #include "irc-mode.h" #include "irc-modelist.h" @@ -2632,8 +2633,8 @@ irc_command_join_server (struct t_irc_server *server, const char *arguments, int manual_join, int noswitch) { char *new_args, **channels, **keys, *pos_space, *pos_keys, *pos_channel; - char *channel_name; - int i, num_channels, num_keys, length; + char *channel_name, *ptr_key; + int i, num_channels, num_keys, length, record; time_t time_now; struct t_irc_channel *ptr_channel; @@ -2646,6 +2647,8 @@ irc_command_join_server (struct t_irc_server *server, const char *arguments, return; } + record = IRC_SERVER_OPTION_BOOLEAN(server, IRC_SERVER_OPTION_AUTOJOIN_RECORD); + /* split channels and keys */ channels = NULL; num_channels = 0; @@ -2733,8 +2736,10 @@ irc_command_join_server (struct t_irc_server *server, const char *arguments, free (channel_name); } } + ptr_key = NULL; if (keys && (i < num_keys)) { + ptr_key = keys[i]; ptr_channel = irc_channel_search (server, pos_channel); if (ptr_channel) { @@ -2749,16 +2754,24 @@ irc_command_join_server (struct t_irc_server *server, const char *arguments, } } if (manual_join - && weechat_config_boolean (irc_config_look_buffer_open_before_join) && !irc_channel_search (server, pos_channel) && (strcmp (pos_channel, "0") != 0)) { - /* - * open the channel buffer immediately (do not wait for the - * JOIN sent by server) - */ - irc_channel_create_buffer ( - server, IRC_CHANNEL_TYPE_CHANNEL, pos_channel, 1, 1); + if (weechat_config_boolean (irc_config_look_buffer_open_before_join)) + { + /* + * open the channel buffer immediately (do not wait + * for the JOIN sent by server) + */ + irc_channel_create_buffer ( + server, IRC_CHANNEL_TYPE_CHANNEL, pos_channel, + 1, 1); + } + if (record) + { + irc_join_add_channel_to_autojoin (server, pos_channel, + ptr_key); + } } } if (pos_space) @@ -4070,7 +4083,8 @@ irc_command_part_channel (struct t_irc_server *server, const char *channel_name, IRC_COMMAND_CALLBACK(part) { - char *channel_name, *pos_args; + char *channel_name, *pos_args, **channels; + int i, num_channels; IRC_BUFFER_GET_SERVER_CHANNEL(buffer); IRC_COMMAND_CHECK_SERVER("part", 1, 1); @@ -4129,6 +4143,23 @@ IRC_COMMAND_CALLBACK(part) irc_command_part_channel (ptr_server, channel_name, pos_args); + if (IRC_SERVER_OPTION_BOOLEAN(ptr_server, IRC_SERVER_OPTION_AUTOJOIN_RECORD)) + { + channels = weechat_string_split (channel_name, ",", NULL, + WEECHAT_STRING_SPLIT_STRIP_LEFT + | WEECHAT_STRING_SPLIT_STRIP_RIGHT + | WEECHAT_STRING_SPLIT_COLLAPSE_SEPS, + 0, &num_channels); + if (channels) + { + for (i = 0; i < num_channels; i++) + { + irc_join_remove_channel_from_autojoin (ptr_server, channels[i]); + } + weechat_string_free_split (channels); + } + } + return WEECHAT_RC_OK; } @@ -5104,6 +5135,18 @@ irc_command_display_server (struct t_irc_server *server, int with_detail) weechat_printf (NULL, " autojoin . . . . . . : %s'%s'", IRC_COLOR_CHAT_VALUE, weechat_config_string (server->options[IRC_SERVER_OPTION_AUTOJOIN])); + + /* autojoin_record */ + if (weechat_config_option_is_null (server->options[IRC_SERVER_OPTION_AUTOJOIN_RECORD])) + weechat_printf (NULL, " autojoin_record. . . : (%s)", + (IRC_SERVER_OPTION_BOOLEAN(server, IRC_SERVER_OPTION_AUTOJOIN_RECORD)) ? + _("on") : _("off")); + else + weechat_printf (NULL, " autojoin_record. . . : %s%s", + IRC_COLOR_CHAT_VALUE, + (weechat_config_boolean (server->options[IRC_SERVER_OPTION_AUTOJOIN_RECORD])) ? + _("on") : _("off")); + /* autorejoin */ if (weechat_config_option_is_null (server->options[IRC_SERVER_OPTION_AUTOREJOIN])) weechat_printf (NULL, " autorejoin . . . . . : (%s)", diff --git a/src/plugins/irc/irc-config.c b/src/plugins/irc/irc-config.c index 08805a136..632c71170 100644 --- a/src/plugins/irc/irc-config.c +++ b/src/plugins/irc/irc-config.c @@ -2217,6 +2217,24 @@ irc_config_server_new_option (struct t_config_file *config_file, callback_change_data, NULL, NULL, NULL); break; + case IRC_SERVER_OPTION_AUTOJOIN_RECORD: + new_option = weechat_config_new_option ( + config_file, section, + option_name, "boolean", + N_("set automatically the \"autojoin\" option according to " + "the channels you manually join and part with commands " + "/join and /part"), + NULL, 0, 0, + default_value, value, + null_value_allowed, + callback_check_value, + callback_check_value_pointer, + callback_check_value_data, + callback_change, + callback_change_pointer, + callback_change_data, + NULL, NULL, NULL); + break; case IRC_SERVER_OPTION_AUTOREJOIN: new_option = weechat_config_new_option ( config_file, section, diff --git a/src/plugins/irc/irc-join.c b/src/plugins/irc/irc-join.c new file mode 100644 index 000000000..62908fa0e --- /dev/null +++ b/src/plugins/irc/irc-join.c @@ -0,0 +1,377 @@ +/* + * irc-join.c - functions for list of channels to join + * + * Copyright (C) 2022 Sébastien Helleu + * + * 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 . + */ + +#include +#include +#include +#include + +#include "../weechat-plugin.h" +#include "irc.h" +#include "irc-join.h" +#include "irc-config.h" +#include "irc-server.h" + + +/* + * Compares two join channels. + */ + +int +irc_join_compare_cb (void *data, struct t_arraylist *arraylist, + void *pointer1, void *pointer2) +{ + struct t_irc_server *server; + struct t_irc_join_channel *channel1, *channel2; + int rc; + + /* make C compiler happy */ + (void) arraylist; + + server = (struct t_irc_server *)data; + + channel1 = (struct t_irc_join_channel *)pointer1; + channel2 = (struct t_irc_join_channel *)pointer2; + + /* + * if channel is the same, always consider it's the same, even if the key + * is different + */ + rc = irc_server_strcasecmp (server, channel1->name, channel2->name); + if (rc == 0) + return 0; + + /* channels with a key are first in list */ + if (channel1->key && !channel2->key) + return -1; + if (!channel1->key && channel2->key) + return 1; + + return 1; +} + +/* + * Frees a join channel. + */ + +void +irc_join_free_cb (void *data, struct t_arraylist *arraylist, void *pointer) +{ + struct t_irc_join_channel *channel; + + /* make C compiler happy */ + (void) data; + (void) arraylist; + + channel = (struct t_irc_join_channel *)pointer; + + if (channel->name) + free (channel->name); + if (channel->key) + free (channel->key); + free (channel); +} + +/* + * Splits join string and returns an array list with a list of + * channels/keys. + * + * The format of channels/keys is the one specified by RFC 1459 for the JOIN + * command (channels with key first in list), for example: + * + * #channel1,#channel2,#channel3 key1,key2 + */ + +struct t_arraylist * +irc_join_split (struct t_irc_server *server, const char *join) +{ + struct t_arraylist *arraylist; + char **items, **channels, **keys; + int count_items, count_channels, count_keys, i; + const char *ptr_channels, *ptr_keys; + struct t_irc_join_channel *new_channel; + + arraylist = NULL; + items = NULL; + count_items = 0; + ptr_channels = NULL; + ptr_keys = NULL; + channels = NULL; + count_channels = 0; + keys = NULL; + count_keys = 0; + + items = weechat_string_split ((join) ? join : "", + " ", NULL, + WEECHAT_STRING_SPLIT_STRIP_LEFT | + WEECHAT_STRING_SPLIT_STRIP_RIGHT | + WEECHAT_STRING_SPLIT_COLLAPSE_SEPS, + 0, &count_items); + + if (count_items >= 1) + ptr_channels = items[0]; + if (count_items >= 2) + ptr_keys = items[1]; + + if (ptr_channels) + { + channels = weechat_string_split (ptr_channels, ",", NULL, + WEECHAT_STRING_SPLIT_COLLAPSE_SEPS, + 0, &count_channels); + } + + if (ptr_keys) + { + keys = weechat_string_split (ptr_keys, ",", NULL, + WEECHAT_STRING_SPLIT_COLLAPSE_SEPS, + 0, &count_keys); + } + + arraylist = weechat_arraylist_new ( + 16, 1, 0, + &irc_join_compare_cb, server, + &irc_join_free_cb, NULL); + if (!arraylist) + goto end; + + for (i = 0; i < count_channels; i++) + { + new_channel = (struct t_irc_join_channel *)malloc (sizeof (*new_channel)); + new_channel->name = strdup (channels[i]); + new_channel->key = (i < count_keys) ? strdup (keys[i]) : NULL; + weechat_arraylist_add (arraylist, new_channel); + } + +end: + if (items) + weechat_string_free_split (items); + if (channels) + weechat_string_free_split (channels); + if (keys) + weechat_string_free_split (keys); + + return arraylist; +} + +/* + * Builds string with a list of channels/keys. + * + * Note: result must be freed after use. + */ + +char * +irc_join_build_string (struct t_arraylist *arraylist) +{ + struct t_irc_join_channel *channel; + char **channels, **keys, *result; + int size, i; + + if (!arraylist) + return strdup (""); + + channels = NULL; + keys = NULL; + result = NULL; + + channels = weechat_string_dyn_alloc (1024); + if (!channels) + goto end; + keys = weechat_string_dyn_alloc (1024); + if (!keys) + goto end; + + size = weechat_arraylist_size (arraylist); + for (i = 0; i < size; i++) + { + channel = (struct t_irc_join_channel *)weechat_arraylist_get ( + arraylist, i); + if (*channels[0]) + weechat_string_dyn_concat (channels, ",", -1); + weechat_string_dyn_concat (channels, channel->name, -1); + if (channel->key) + { + if (*keys[0]) + weechat_string_dyn_concat (keys, ",", -1); + weechat_string_dyn_concat (keys, channel->key, -1); + } + } + + if (*keys[0]) + { + weechat_string_dyn_concat (channels, " ", -1); + weechat_string_dyn_concat (channels, *keys, -1); + } + +end: + if (channels) + { + result = *channels; + weechat_string_dyn_free (channels, 0); + } + if (keys) + weechat_string_dyn_free (keys, 1); + + return (result) ? result : strdup (""); +} + +/* + * Adds a channel with optional key to the join string. + * + * Channels with a key are first in list, so for example: + * + * join = "#abc,#def,#ghi key_abc,key_def" + * channel_name = "#xyz" + * key = "key_xyz" + * + * => returned value: "#abc,#def,#xyz,#ghi key_abc,key_def,key_xyz" + * + * Note: result must be freed after use. + */ + +char * +irc_join_add_channel (struct t_irc_server *server, + const char *join, + const char *channel_name, const char *key) +{ + struct t_arraylist *arraylist; + struct t_irc_join_channel *channel; + char *new_join; + + if (!channel_name) + return NULL; + + arraylist = irc_join_split (server, join); + if (!arraylist) + return NULL; + + channel = (struct t_irc_join_channel *)malloc (sizeof (*channel)); + channel->name = strdup (channel_name); + channel->key = (key && key[0]) ? strdup (key) : NULL; + weechat_arraylist_add (arraylist, channel); + + new_join = irc_join_build_string (arraylist); + + weechat_arraylist_free (arraylist); + + return new_join; +} + +/* + * Adds a channel with optional key to the autojoin option of a server. + */ + +void +irc_join_add_channel_to_autojoin (struct t_irc_server *server, + const char *channel_name, const char *key) +{ + char *new_autojoin; + + if (!channel_name) + return; + + new_autojoin = irc_join_add_channel ( + server, + IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_AUTOJOIN), + channel_name, + key); + if (new_autojoin) + { + weechat_config_option_set ( + server->options[IRC_SERVER_OPTION_AUTOJOIN], + new_autojoin, + 1); + free (new_autojoin); + } +} + +/* + * Removes a channel from a join string. + * + * Channels with a key are first in list, so for example: + * + * join = "#abc,#def,#ghi key_abc,key_def" + * channel_name = "#def" + * + * => returned value: "#abc,#ghi key_abc" + * + * Note: result must be freed after use. + */ + +char * +irc_join_remove_channel (struct t_irc_server *server, + const char *join, const char *channel_name) +{ + struct t_arraylist *arraylist; + struct t_irc_join_channel *channel; + char *new_join; + int i; + + if (!channel_name) + return NULL; + + arraylist = irc_join_split (server, join); + if (!arraylist) + return NULL; + + i = 0; + while (i < weechat_arraylist_size (arraylist)) + { + channel = (struct t_irc_join_channel *)weechat_arraylist_get ( + arraylist, i); + if (irc_server_strcasecmp (server, channel->name, channel_name) == 0) + weechat_arraylist_remove (arraylist, i); + else + i++; + } + + new_join = irc_join_build_string (arraylist); + + weechat_arraylist_free (arraylist); + + return new_join; +} + +/* + * Removes a channel from server autojoin option. + */ + +void +irc_join_remove_channel_from_autojoin (struct t_irc_server *server, + const char *channel_name) +{ + char *new_autojoin; + + if (!channel_name) + return; + + new_autojoin = irc_join_remove_channel ( + server, + IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_AUTOJOIN), + channel_name); + if (new_autojoin) + { + weechat_config_option_set ( + server->options[IRC_SERVER_OPTION_AUTOJOIN], + new_autojoin, + 1); + free (new_autojoin); + } +} diff --git a/src/plugins/irc/irc-join.h b/src/plugins/irc/irc-join.h new file mode 100644 index 000000000..ca2a049d6 --- /dev/null +++ b/src/plugins/irc/irc-join.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2022 Sébastien Helleu + * + * 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 . + */ + +#ifndef WEECHAT_PLUGIN_IRC_JOIN_H +#define WEECHAT_PLUGIN_IRC_JOIN_H + +struct t_irc_server; + +struct t_irc_join_channel +{ + char *name; /* channel name */ + char *key; /* channel key */ +}; + +extern struct t_arraylist *irc_join_split (struct t_irc_server *server, + const char *join); +extern char *irc_join_build_string (struct t_arraylist *arraylist); +extern char *irc_join_add_channel (struct t_irc_server *server, + const char *join, const char *channel_name, + const char *key); +void irc_join_add_channel_to_autojoin (struct t_irc_server *server, + const char *channel_name, + const char *key); +extern char *irc_join_remove_channel (struct t_irc_server *server, + const char *join, + const char *channel_name); +void irc_join_remove_channel_from_autojoin (struct t_irc_server *server, + const char *channel_name); + +#endif /* WEECHAT_PLUGIN_IRC_JOIN_H */ diff --git a/src/plugins/irc/irc-server.c b/src/plugins/irc/irc-server.c index a2c17afe2..2b3923e19 100644 --- a/src/plugins/irc/irc-server.c +++ b/src/plugins/irc/irc-server.c @@ -107,6 +107,7 @@ char *irc_server_options[IRC_SERVER_NUM_OPTIONS][2] = { "command", "" }, { "command_delay", "0" }, { "autojoin", "" }, + { "autojoin_record", "off" }, { "autorejoin", "off" }, { "autorejoin_delay", "30" }, { "connection_timeout", "60" }, @@ -6289,6 +6290,9 @@ irc_server_add_to_infolist (struct t_infolist *infolist, if (!weechat_infolist_new_var_string (ptr_item, "autojoin", IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_AUTOJOIN))) return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "autojoin_record", + IRC_SERVER_OPTION_BOOLEAN(server, IRC_SERVER_OPTION_AUTOJOIN_RECORD))) + return 0; if (!weechat_infolist_new_var_integer (ptr_item, "autorejoin", IRC_SERVER_OPTION_BOOLEAN(server, IRC_SERVER_OPTION_AUTOREJOIN))) return 0; @@ -6648,6 +6652,15 @@ irc_server_print_log () else weechat_log_printf (" autojoin. . . . . . . . . : '%s'", weechat_config_string (ptr_server->options[IRC_SERVER_OPTION_AUTOJOIN])); + /* autojoin_record */ + if (weechat_config_option_is_null (ptr_server->options[IRC_SERVER_OPTION_AUTOJOIN_RECORD])) + weechat_log_printf (" autojoin_record . . . . . : null (%s)", + (IRC_SERVER_OPTION_BOOLEAN(ptr_server, IRC_SERVER_OPTION_AUTOJOIN_RECORD)) ? + "on" : "off"); + else + weechat_log_printf (" autojoin_record . . . . . : %s", + (weechat_config_boolean (ptr_server->options[IRC_SERVER_OPTION_AUTOJOIN_RECORD])) ? + "on" : "off"); /* autorejoin */ if (weechat_config_option_is_null (ptr_server->options[IRC_SERVER_OPTION_AUTOREJOIN])) weechat_log_printf (" autorejoin. . . . . . . . : null (%s)", diff --git a/src/plugins/irc/irc-server.h b/src/plugins/irc/irc-server.h index 52b19bdab..f73f5af76 100644 --- a/src/plugins/irc/irc-server.h +++ b/src/plugins/irc/irc-server.h @@ -79,6 +79,7 @@ enum t_irc_server_option IRC_SERVER_OPTION_COMMAND, /* command to run once connected */ IRC_SERVER_OPTION_COMMAND_DELAY, /* delay after execution of command */ IRC_SERVER_OPTION_AUTOJOIN, /* channels to automatically join */ + IRC_SERVER_OPTION_AUTOJOIN_RECORD, /* auto set autojoin option */ IRC_SERVER_OPTION_AUTOREJOIN, /* auto rejoin channels when kicked */ IRC_SERVER_OPTION_AUTOREJOIN_DELAY, /* delay before auto rejoin */ IRC_SERVER_OPTION_CONNECTION_TIMEOUT, /* timeout for connection */ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index a90149e0e..997f85f9d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -60,6 +60,7 @@ if(ENABLE_IRC) unit/plugins/irc/test-irc-color.cpp unit/plugins/irc/test-irc-config.cpp unit/plugins/irc/test-irc-ignore.cpp + unit/plugins/irc/test-irc-join.cpp unit/plugins/irc/test-irc-message.cpp unit/plugins/irc/test-irc-mode.cpp unit/plugins/irc/test-irc-nick.cpp diff --git a/tests/Makefile.am b/tests/Makefile.am index 9d4f7650a..0e48ef45b 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -75,6 +75,7 @@ tests_irc = unit/plugins/irc/test-irc-buffer.cpp \ unit/plugins/irc/test-irc-color.cpp \ unit/plugins/irc/test-irc-config.cpp \ unit/plugins/irc/test-irc-ignore.cpp \ + unit/plugins/irc/test-irc-join.cpp \ unit/plugins/irc/test-irc-message.cpp \ unit/plugins/irc/test-irc-mode.cpp \ unit/plugins/irc/test-irc-nick.cpp \ diff --git a/tests/unit/plugins/irc/test-irc-join.cpp b/tests/unit/plugins/irc/test-irc-join.cpp new file mode 100644 index 000000000..11f30ad55 --- /dev/null +++ b/tests/unit/plugins/irc/test-irc-join.cpp @@ -0,0 +1,360 @@ +/* + * test-irc-join.cpp - test IRC join functions + * + * Copyright (C) 2022 Sébastien Helleu + * + * 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 . + */ + +#include "CppUTest/TestHarness.h" + +extern "C" +{ +#include "tests/tests.h" +#include "src/core/wee-arraylist.h" +#include "src/core/wee-config-file.h" +#include "src/plugins/irc/irc-join.h" +#include "src/plugins/irc/irc-server.h" +} + +#define WEE_CHECK_ADD_CHANNEL(__result, __join, __channel, __key) \ + str = irc_join_add_channel (NULL, __join, __channel, __key); \ + if (__result == NULL) \ + { \ + POINTERS_EQUAL(NULL, str); \ + } \ + else \ + { \ + STRCMP_EQUAL(__result, str); \ + } \ + if (str) \ + free (str); + +#define WEE_CHECK_REMOVE_CHANNEL(__result, __join, __channel) \ + str = irc_join_remove_channel (NULL, __join, __channel); \ + if (__result == NULL) \ + { \ + POINTERS_EQUAL(NULL, str); \ + } \ + else \ + { \ + STRCMP_EQUAL(__result, str); \ + } \ + if (str) \ + free (str); + +TEST_GROUP(IrcJoin) +{ +}; + +/* + * Tests functions: + * irc_join_compare_cb + * irc_join_free_cb + * irc_join_split + * irc_join_build_string + */ + +TEST(IrcJoin, SplitBuildString) +{ + struct t_arraylist *arraylist; + struct t_irc_join_channel **channels; + struct t_irc_server *server; + char *autojoin; + + arraylist = irc_join_split (NULL, NULL); + CHECK(arraylist); + LONGS_EQUAL(0, arraylist->size); + autojoin = irc_join_build_string (arraylist); + STRCMP_EQUAL("", autojoin); + free (autojoin); + arraylist_free (arraylist); + + autojoin = irc_join_build_string (NULL); + STRCMP_EQUAL("", autojoin); + free (autojoin); + + arraylist = irc_join_split (NULL, ""); + CHECK(arraylist); + LONGS_EQUAL(0, arraylist->size); + autojoin = irc_join_build_string (arraylist); + STRCMP_EQUAL("", autojoin); + free (autojoin); + arraylist_free (arraylist); + + /* 1 channel, 2 keys (the second is ignored) */ + arraylist = irc_join_split (NULL, "#xyz key_xyz,key_abc"); + CHECK(arraylist); + LONGS_EQUAL(1, arraylist->size); + channels = (struct t_irc_join_channel **)arraylist->data; + CHECK(channels[0]); + STRCMP_EQUAL("#xyz", channels[0]->name); + STRCMP_EQUAL("key_xyz", channels[0]->key); + autojoin = irc_join_build_string (arraylist); + STRCMP_EQUAL("#xyz key_xyz", autojoin); + free (autojoin); + arraylist_free (arraylist); + + /* 1 channel */ + arraylist = irc_join_split (NULL, "#xyz"); + CHECK(arraylist); + LONGS_EQUAL(1, arraylist->size); + channels = (struct t_irc_join_channel **)arraylist->data; + CHECK(channels[0]); + STRCMP_EQUAL("#xyz", channels[0]->name); + POINTERS_EQUAL(NULL, channels[0]->key); + autojoin = irc_join_build_string (arraylist); + STRCMP_EQUAL("#xyz", autojoin); + free (autojoin); + arraylist_free (arraylist); + + /* 2 channels */ + arraylist = irc_join_split (NULL, "#xyz,#abc"); + CHECK(arraylist); + LONGS_EQUAL(2, arraylist->size); + channels = (struct t_irc_join_channel **)arraylist->data; + CHECK(channels[0]); + STRCMP_EQUAL("#xyz", channels[0]->name); + POINTERS_EQUAL(NULL, channels[0]->key); + STRCMP_EQUAL("#abc", channels[1]->name); + POINTERS_EQUAL(NULL, channels[1]->key); + autojoin = irc_join_build_string (arraylist); + STRCMP_EQUAL("#xyz,#abc", autojoin); + free (autojoin); + arraylist_free (arraylist); + + /* 2 channels, 2 keys */ + arraylist = irc_join_split (NULL, "#xyz,#abc key_xyz,key_abc"); + CHECK(arraylist); + LONGS_EQUAL(2, arraylist->size); + channels = (struct t_irc_join_channel **)arraylist->data; + CHECK(channels[0]); + STRCMP_EQUAL("#xyz", channels[0]->name); + STRCMP_EQUAL("key_xyz", channels[0]->key); + STRCMP_EQUAL("#abc", channels[1]->name); + STRCMP_EQUAL("key_abc", channels[1]->key); + autojoin = irc_join_build_string (arraylist); + STRCMP_EQUAL("#xyz,#abc key_xyz,key_abc", autojoin); + free (autojoin); + arraylist_free (arraylist); + + /* 3 channels, 2 keys */ + arraylist = irc_join_split (NULL, "#xyz,#abc,#def key_xyz,key_abc"); + CHECK(arraylist); + LONGS_EQUAL(3, arraylist->size); + channels = (struct t_irc_join_channel **)arraylist->data; + CHECK(channels[0]); + STRCMP_EQUAL("#xyz", channels[0]->name); + STRCMP_EQUAL("key_xyz", channels[0]->key); + STRCMP_EQUAL("#abc", channels[1]->name); + STRCMP_EQUAL("key_abc", channels[1]->key); + STRCMP_EQUAL("#def", channels[2]->name); + POINTERS_EQUAL(NULL, channels[2]->key); + autojoin = irc_join_build_string (arraylist); + STRCMP_EQUAL("#xyz,#abc,#def key_xyz,key_abc", autojoin); + free (autojoin); + arraylist_free (arraylist); + + /* duplicated channel */ + arraylist = irc_join_split (NULL, "#xyz,#XYZ"); + CHECK(arraylist); + LONGS_EQUAL(1, arraylist->size); + channels = (struct t_irc_join_channel **)arraylist->data; + CHECK(channels[0]); + STRCMP_EQUAL("#XYZ", channels[0]->name); + POINTERS_EQUAL(NULL, channels[0]->key); + autojoin = irc_join_build_string (arraylist); + STRCMP_EQUAL("#XYZ", autojoin); + free (autojoin); + arraylist_free (arraylist); + + /* server with casemapping RFC1459 */ + server = irc_server_alloc ("my_ircd"); + CHECK(server); + server->casemapping = IRC_SERVER_CASEMAPPING_RFC1459; + arraylist = irc_join_split (server, "#chan[a]^,#CHAN{A}~"); + CHECK(arraylist); + LONGS_EQUAL(1, arraylist->size); + channels = (struct t_irc_join_channel **)arraylist->data; + CHECK(channels[0]); + STRCMP_EQUAL("#CHAN{A}~", channels[0]->name); + POINTERS_EQUAL(NULL, channels[0]->key); + autojoin = irc_join_build_string (arraylist); + STRCMP_EQUAL("#CHAN{A}~", autojoin); + free (autojoin); + arraylist_free (arraylist); + irc_server_free (server); + + /* server with casemapping STRICT_RFC1459 */ + server = irc_server_alloc ("my_ircd"); + CHECK(server); + server->casemapping = IRC_SERVER_CASEMAPPING_STRICT_RFC1459; + arraylist = irc_join_split (server, "#chan[a]^,#CHAN{A}~"); + CHECK(arraylist); + LONGS_EQUAL(2, arraylist->size); + channels = (struct t_irc_join_channel **)arraylist->data; + CHECK(channels[0]); + STRCMP_EQUAL("#chan[a]^", channels[0]->name); + POINTERS_EQUAL(NULL, channels[0]->key); + STRCMP_EQUAL("#CHAN{A}~", channels[1]->name); + POINTERS_EQUAL(NULL, channels[1]->key); + autojoin = irc_join_build_string (arraylist); + STRCMP_EQUAL("#chan[a]^,#CHAN{A}~", autojoin); + free (autojoin); + arraylist_free (arraylist); + irc_server_free (server); +} + +/* + * Tests functions: + * irc_join_add_channel + */ + +TEST(IrcJoin, AddChannel) +{ + char *str; + + WEE_CHECK_ADD_CHANNEL(NULL, NULL, NULL, NULL); + WEE_CHECK_ADD_CHANNEL(NULL, "", NULL, NULL); + WEE_CHECK_ADD_CHANNEL("", "", "", NULL); + WEE_CHECK_ADD_CHANNEL("", NULL, "", NULL); + + WEE_CHECK_ADD_CHANNEL("#abc", NULL, "#abc", NULL); + WEE_CHECK_ADD_CHANNEL("#abc", "", "#abc", NULL); + WEE_CHECK_ADD_CHANNEL("#abc key_abc", NULL, "#abc", "key_abc"); + WEE_CHECK_ADD_CHANNEL("#ABC key_ABC", NULL, "#ABC", "key_ABC"); + + WEE_CHECK_ADD_CHANNEL("#xyz,#abc", "#xyz", "#abc", NULL); + WEE_CHECK_ADD_CHANNEL("#abc,#xyz key_abc", "#xyz", "#abc", "key_abc"); + + WEE_CHECK_ADD_CHANNEL("#abc,#xyz,#def key_abc", "#xyz,#def", "#abc", "key_abc"); +} + +/* + * Tests functions: + * irc_join_remove_channel + */ + +TEST(IrcJoin, RemoveChannel) +{ + char *str; + + WEE_CHECK_REMOVE_CHANNEL(NULL, NULL, NULL); + WEE_CHECK_REMOVE_CHANNEL(NULL, "", NULL); + WEE_CHECK_REMOVE_CHANNEL("", "", ""); + WEE_CHECK_REMOVE_CHANNEL("", NULL, ""); + + WEE_CHECK_REMOVE_CHANNEL("", NULL, "#abc"); + WEE_CHECK_REMOVE_CHANNEL("", "", "#abc"); + + WEE_CHECK_REMOVE_CHANNEL("#xyz", "#xyz", "#abc"); + WEE_CHECK_REMOVE_CHANNEL("", "#xyz", "#xyz"); + WEE_CHECK_REMOVE_CHANNEL("", "#xyz", "#XYZ"); + WEE_CHECK_REMOVE_CHANNEL("#xyz", "#abc,#xyz key_abc", "#abc"); + WEE_CHECK_REMOVE_CHANNEL("#abc key_abc", "#abc,#xyz key_abc", "#xyz"); + WEE_CHECK_REMOVE_CHANNEL("#abc key_abc", "#abc,#xyz key_abc", "#XYZ"); + + WEE_CHECK_REMOVE_CHANNEL("#def,#ghi key_def", + "#abc,#def,#ghi key_abc,key_def", "#abc"); + WEE_CHECK_REMOVE_CHANNEL("#def,#ghi key_def", + "#abc,#def,#ghi key_abc,key_def", "#ABC"); + + WEE_CHECK_REMOVE_CHANNEL("#abc,#ghi key_abc", + "#abc,#def,#ghi key_abc,key_def", "#def"); + + WEE_CHECK_REMOVE_CHANNEL("#abc,#def key_abc,key_def", + "#abc,#def,#ghi key_abc,key_def", "#ghi"); +} + +/* + * Tests functions: + * irc_join_add_channel_to_autojoin + * irc_join_remove_channel_from_autojoin + */ + +TEST(IrcJoin, AddRemoveChannelAutojoin) +{ + struct t_irc_server *server; + + server = irc_server_alloc ("my_ircd"); + + irc_join_remove_channel_from_autojoin (server, "#xyz"); + STRCMP_EQUAL( + "", + CONFIG_STRING(server->options[IRC_SERVER_OPTION_AUTOJOIN])); + + irc_join_add_channel_to_autojoin (server, "#xyz", NULL); + STRCMP_EQUAL( + "#xyz", + CONFIG_STRING(server->options[IRC_SERVER_OPTION_AUTOJOIN])); + + irc_join_add_channel_to_autojoin (server, NULL, NULL); + STRCMP_EQUAL( + "#xyz", + CONFIG_STRING(server->options[IRC_SERVER_OPTION_AUTOJOIN])); + + irc_join_add_channel_to_autojoin (server, "#abc", "key_abc"); + STRCMP_EQUAL( + "#abc,#xyz key_abc", + CONFIG_STRING(server->options[IRC_SERVER_OPTION_AUTOJOIN])); + + irc_join_add_channel_to_autojoin (server, "#def", "key_def"); + STRCMP_EQUAL( + "#abc,#def,#xyz key_abc,key_def", + CONFIG_STRING(server->options[IRC_SERVER_OPTION_AUTOJOIN])); + + irc_join_add_channel_to_autojoin (server, "#ghi", NULL); + STRCMP_EQUAL( + "#abc,#def,#xyz,#ghi key_abc,key_def", + CONFIG_STRING(server->options[IRC_SERVER_OPTION_AUTOJOIN])); + + irc_join_add_channel_to_autojoin (server, "#jkl", ""); + STRCMP_EQUAL( + "#abc,#def,#xyz,#ghi,#jkl key_abc,key_def", + CONFIG_STRING(server->options[IRC_SERVER_OPTION_AUTOJOIN])); + + irc_join_remove_channel_from_autojoin (server, "#def"); + STRCMP_EQUAL( + "#abc,#xyz,#ghi,#jkl key_abc", + CONFIG_STRING(server->options[IRC_SERVER_OPTION_AUTOJOIN])); + + irc_join_remove_channel_from_autojoin (server, "#ghi"); + STRCMP_EQUAL( + "#abc,#xyz,#jkl key_abc", + CONFIG_STRING(server->options[IRC_SERVER_OPTION_AUTOJOIN])); + + irc_join_remove_channel_from_autojoin (server, "#abc"); + STRCMP_EQUAL( + "#xyz,#jkl", + CONFIG_STRING(server->options[IRC_SERVER_OPTION_AUTOJOIN])); + + irc_join_remove_channel_from_autojoin (server, "#jkl"); + STRCMP_EQUAL( + "#xyz", + CONFIG_STRING(server->options[IRC_SERVER_OPTION_AUTOJOIN])); + + irc_join_remove_channel_from_autojoin (server, "#xyz"); + STRCMP_EQUAL( + "", + CONFIG_STRING(server->options[IRC_SERVER_OPTION_AUTOJOIN])); + + irc_join_remove_channel_from_autojoin (server, NULL); + STRCMP_EQUAL( + "", + CONFIG_STRING(server->options[IRC_SERVER_OPTION_AUTOJOIN])); + + irc_server_free (server); +}