summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/plugins/fset/fset-buffer.c2
-rw-r--r--src/plugins/irc/CMakeLists.txt1
-rw-r--r--src/plugins/irc/irc-buffer.c180
-rw-r--r--src/plugins/irc/irc-buffer.h3
-rw-r--r--src/plugins/irc/irc-channel.c91
-rw-r--r--src/plugins/irc/irc-command.c190
-rw-r--r--src/plugins/irc/irc-config.c83
-rw-r--r--src/plugins/irc/irc-config.h6
-rw-r--r--src/plugins/irc/irc-info.c7
-rw-r--r--src/plugins/irc/irc-input.c7
-rw-r--r--src/plugins/irc/irc-list.c1309
-rw-r--r--src/plugins/irc/irc-list.h81
-rw-r--r--src/plugins/irc/irc-server.c12
-rw-r--r--src/plugins/irc/irc-server.h1
-rw-r--r--src/plugins/irc/irc-upgrade.c10
-rw-r--r--src/plugins/irc/irc.c9
16 files changed, 1872 insertions, 120 deletions
diff --git a/src/plugins/fset/fset-buffer.c b/src/plugins/fset/fset-buffer.c
index 0822d24ed..9e378d0aa 100644
--- a/src/plugins/fset/fset-buffer.c
+++ b/src/plugins/fset/fset-buffer.c
@@ -1433,7 +1433,7 @@ fset_buffer_input_cb (const void *pointer, void *data,
return WEECHAT_RC_OK;
}
- /* execute action on an option */
+ /* execute action */
for (i = 0; actions[i][0]; i++)
{
if (strcmp (input_data, actions[i][0]) == 0)
diff --git a/src/plugins/irc/CMakeLists.txt b/src/plugins/irc/CMakeLists.txt
index bdc290e58..6452ac59b 100644
--- a/src/plugins/irc/CMakeLists.txt
+++ b/src/plugins/irc/CMakeLists.txt
@@ -32,6 +32,7 @@ add_library(irc MODULE
irc-ignore.c irc-ignore.h
irc-info.c irc-info.h
irc-input.c irc-input.h
+ irc-list.c irc-list.h
irc-join.c irc-join.h
irc-message.c irc-message.h
irc-mode.c irc-mode.h
diff --git a/src/plugins/irc/irc-buffer.c b/src/plugins/irc/irc-buffer.c
index a2332a3d5..63c107871 100644
--- a/src/plugins/irc/irc-buffer.c
+++ b/src/plugins/irc/irc-buffer.c
@@ -31,6 +31,7 @@
#include "irc-command.h"
#include "irc-config.h"
#include "irc-join.h"
+#include "irc-list.h"
#include "irc-raw.h"
#include "irc-server.h"
@@ -67,6 +68,13 @@ irc_buffer_get_server_and_channel (struct t_gui_buffer *buffer,
return;
}
+ if (ptr_server->list->buffer == buffer)
+ {
+ if (server)
+ *server = ptr_server;
+ return;
+ }
+
for (ptr_channel = ptr_server->channels; ptr_channel;
ptr_channel = ptr_channel->next_channel)
{
@@ -204,41 +212,52 @@ irc_buffer_close_cb (const void *pointer, void *data,
}
irc_channel_free (ptr_server, ptr_channel);
}
- else
+ else if (ptr_server && (ptr_server->buffer == buffer))
{
- if (ptr_server)
+ if (!ptr_server->disconnected)
{
- if (!ptr_server->disconnected)
- {
- /* send QUIT to server, then disconnect */
- irc_command_quit_server (ptr_server, NULL);
- irc_server_disconnect (ptr_server, 0, 0);
- }
+ /* send QUIT to server, then disconnect */
+ irc_command_quit_server (ptr_server, NULL);
+ irc_server_disconnect (ptr_server, 0, 0);
+ }
- /* disable reconnection */
- ptr_server->reconnect_delay = 0;
- ptr_server->reconnect_start = 0;
+ /* disable reconnection */
+ ptr_server->reconnect_delay = 0;
+ ptr_server->reconnect_start = 0;
- /* consider auto-join has never been done */
- ptr_server->autojoin_done = 0;
+ /* consider auto-join has never been done */
+ ptr_server->autojoin_done = 0;
- /* close server channels/privates */
- ptr_channel = ptr_server->channels;
- while (ptr_channel)
- {
- next_channel = ptr_channel->next_channel;
- if (ptr_channel->buffer != buffer)
- weechat_buffer_close (ptr_channel->buffer);
- ptr_channel = next_channel;
- }
+ /* close server channels/privates */
+ ptr_channel = ptr_server->channels;
+ while (ptr_channel)
+ {
+ next_channel = ptr_channel->next_channel;
+ if (ptr_channel->buffer != buffer)
+ weechat_buffer_close (ptr_channel->buffer);
+ ptr_channel = next_channel;
+ }
- /*
- * close remaining channels/privates
- * (which are not yet in server->channels)
- */
- irc_buffer_close_server_channels (ptr_server);
+ /*
+ * close remaining channels/privates
+ * (which are not yet in server->channels)
+ */
+ irc_buffer_close_server_channels (ptr_server);
- ptr_server->buffer = NULL;
+ ptr_server->buffer = NULL;
+ }
+ else if (ptr_server && (ptr_server->list->buffer == buffer))
+ {
+ ptr_server->list->buffer = NULL;
+ if (ptr_server->list->channels)
+ {
+ weechat_arraylist_free (ptr_server->list->channels);
+ ptr_server->list->channels = NULL;
+ }
+ if (ptr_server->list->filter_channels)
+ {
+ weechat_arraylist_free (ptr_server->list->filter_channels);
+ ptr_server->list->filter_channels = NULL;
}
}
}
@@ -357,3 +376,108 @@ irc_buffer_search_private_lowest_number (struct t_irc_server *server)
}
return ptr_buffer;
}
+
+/*
+ * Moves new channel/pv or list buffer near server.
+ *
+ * Parameters:
+ * list_buffer: 1 if it is a /list buffer, 0 otherwise
+ * channel_type: -1, IRC_CHANNEL_TYPE_CHANNEL or IRC_CHANNEL_TYPE_PRIVATE
+ */
+
+void
+irc_buffer_move_near_server (struct t_irc_server *server,
+ int list_buffer, int channel_type,
+ struct t_gui_buffer *buffer)
+{
+ int number, number_channel, number_last_channel, number_last_private;
+ int number_found;
+ char str_number[32];
+ const char *ptr_type, *ptr_server_name;
+ struct t_hdata *hdata_buffer;
+ struct t_gui_buffer *ptr_buffer;
+
+ number = weechat_buffer_get_integer (buffer, "number");
+ number_last_channel = 0;
+ number_last_private = 0;
+ number_found = 0;
+
+ hdata_buffer = weechat_hdata_get ("buffer");
+ ptr_buffer = weechat_hdata_get_list (hdata_buffer, "gui_buffers");
+ while (ptr_buffer)
+ {
+ if ((ptr_buffer != buffer)
+ && (weechat_buffer_get_pointer (ptr_buffer,
+ "plugin") == weechat_irc_plugin))
+ {
+ ptr_type = weechat_buffer_get_string (ptr_buffer,
+ "localvar_type");
+ ptr_server_name = weechat_buffer_get_string (ptr_buffer,
+ "localvar_server");
+ number_channel = weechat_buffer_get_integer (ptr_buffer,
+ "number");
+ if (ptr_type && ptr_type[0]
+ && ptr_server_name && ptr_server_name[0]
+ && (strcmp (ptr_server_name, server->name) == 0))
+ {
+ if (strcmp (ptr_type, "channel") == 0)
+ {
+ if (number_channel > number_last_channel)
+ number_last_channel = number_channel;
+ }
+ else if (strcmp (ptr_type, "private") == 0)
+ {
+ if (number_channel > number_last_private)
+ number_last_private = number_channel;
+ }
+ }
+ }
+ /* move to next buffer */
+ ptr_buffer = weechat_hdata_move (hdata_buffer, ptr_buffer, 1);
+ }
+
+ if (list_buffer)
+ {
+ if ((number_last_private > 0)
+ && (number_last_private > number_last_channel))
+ {
+ number_found = number_last_private + 1;
+ }
+ else if ((number_last_channel > 0)
+ && (number_last_channel > number_last_private))
+ {
+ number_found = number_last_channel + 1;
+ }
+ }
+ else
+ {
+ /* use last channel/pv number + 1 */
+ switch (channel_type)
+ {
+ case IRC_CHANNEL_TYPE_CHANNEL:
+ if (number_last_channel > 0)
+ number_found = number_last_channel + 1;
+ break;
+ case IRC_CHANNEL_TYPE_PRIVATE:
+ if (number_last_private > 0)
+ number_found = number_last_private + 1;
+ else if (number_last_channel > 0)
+ number_found = number_last_channel + 1;
+ break;
+ }
+ }
+
+ if ((number_found == 0)
+ && (weechat_config_enum (irc_config_look_server_buffer) ==
+ IRC_CONFIG_LOOK_SERVER_BUFFER_INDEPENDENT))
+ {
+ number_found = weechat_buffer_get_integer (server->buffer, "number") + 1;
+ }
+
+ /* switch to number found */
+ if ((number_found >= 1) && (number_found != number))
+ {
+ snprintf (str_number, sizeof (str_number), "%d", number_found);
+ weechat_buffer_set (buffer, "number", str_number);
+ }
+}
diff --git a/src/plugins/irc/irc-buffer.h b/src/plugins/irc/irc-buffer.h
index 4282709c2..5e8ca6c11 100644
--- a/src/plugins/irc/irc-buffer.h
+++ b/src/plugins/irc/irc-buffer.h
@@ -54,5 +54,8 @@ extern int irc_buffer_nickcmp_cb (const void *pointer, void *data,
const char *nick1, const char *nick2);
extern struct t_gui_buffer *irc_buffer_search_server_lowest_number ();
extern struct t_gui_buffer *irc_buffer_search_private_lowest_number (struct t_irc_server *server);
+extern void irc_buffer_move_near_server (struct t_irc_server *server,
+ int list_buffer, int channel_type,
+ struct t_gui_buffer *buffer);
#endif /* WEECHAT_PLUGIN_IRC_BUFFER_H */
diff --git a/src/plugins/irc/irc-channel.c b/src/plugins/irc/irc-channel.c
index b0bed60d7..ccb264d94 100644
--- a/src/plugins/irc/irc-channel.c
+++ b/src/plugins/irc/irc-channel.c
@@ -76,90 +76,6 @@ irc_channel_valid (struct t_irc_server *server, struct t_irc_channel *channel)
}
/*
- * Moves new channel/pv buffer near server.
- */
-
-void
-irc_channel_move_near_server (struct t_irc_server *server, int channel_type,
- struct t_gui_buffer *buffer)
-{
- int number, number_channel, number_last_channel, number_last_private;
- int number_found;
- char str_number[32];
- const char *ptr_type, *ptr_server_name;
- struct t_hdata *hdata_buffer;
- struct t_gui_buffer *ptr_buffer;
-
- number = weechat_buffer_get_integer (buffer, "number");
- number_last_channel = 0;
- number_last_private = 0;
- number_found = 0;
-
- hdata_buffer = weechat_hdata_get ("buffer");
- ptr_buffer = weechat_hdata_get_list (hdata_buffer, "gui_buffers");
- while (ptr_buffer)
- {
- if ((ptr_buffer != buffer)
- && (weechat_buffer_get_pointer (ptr_buffer,
- "plugin") == weechat_irc_plugin))
- {
- ptr_type = weechat_buffer_get_string (ptr_buffer,
- "localvar_type");
- ptr_server_name = weechat_buffer_get_string (ptr_buffer,
- "localvar_server");
- number_channel = weechat_buffer_get_integer (ptr_buffer,
- "number");
- if (ptr_type && ptr_type[0]
- && ptr_server_name && ptr_server_name[0]
- && (strcmp (ptr_server_name, server->name) == 0))
- {
- if (strcmp (ptr_type, "channel") == 0)
- {
- if (number_channel > number_last_channel)
- number_last_channel = number_channel;
- }
- else if (strcmp (ptr_type, "private") == 0)
- {
- if (number_channel > number_last_private)
- number_last_private = number_channel;
- }
- }
- }
- /* move to next buffer */
- ptr_buffer = weechat_hdata_move (hdata_buffer, ptr_buffer, 1);
- }
-
- /* use last channel/pv number + 1 */
- switch (channel_type)
- {
- case IRC_CHANNEL_TYPE_CHANNEL:
- if (number_last_channel > 0)
- number_found = number_last_channel + 1;
- break;
- case IRC_CHANNEL_TYPE_PRIVATE:
- if (number_last_private > 0)
- number_found = number_last_private + 1;
- else if (number_last_channel > 0)
- number_found = number_last_channel + 1;
- break;
- }
-
- if ((number_found == 0)
- && (weechat_config_enum (irc_config_look_server_buffer) ==
- IRC_CONFIG_LOOK_SERVER_BUFFER_INDEPENDENT))
- {
- number_found = weechat_buffer_get_integer (server->buffer, "number") + 1;
- }
-
- /* switch to number found */
- if ((number_found >= 1) && (number_found != number))
- {
- snprintf (str_number, sizeof (str_number), "%d", number_found);
- weechat_buffer_set (buffer, "number", str_number);
- }
-}
-
-/*
* Searches for a channel by name.
*
* Returns pointer to channel found, NULL if not found.
@@ -374,8 +290,11 @@ irc_channel_create_buffer (struct t_irc_server *server,
break;
case IRC_CONFIG_LOOK_BUFFER_POSITION_NEAR_SERVER:
/* move buffer after last channel/pv of server */
- irc_channel_move_near_server (server, channel_type,
- ptr_buffer);
+ irc_buffer_move_near_server (
+ server,
+ 0, /* list_buffer */
+ channel_type,
+ ptr_buffer);
break;
}
if (ptr_buffer_for_merge)
diff --git a/src/plugins/irc/irc-command.c b/src/plugins/irc/irc-command.c
index 7e7058bc7..57f8e4541 100644
--- a/src/plugins/irc/irc-command.c
+++ b/src/plugins/irc/irc-command.c
@@ -43,6 +43,7 @@
#include "irc-ignore.h"
#include "irc-input.h"
#include "irc-join.h"
+#include "irc-list.h"
#include "irc-message.h"
#include "irc-mode.h"
#include "irc-modelist.h"
@@ -3370,14 +3371,37 @@ IRC_COMMAND_CALLBACK(links)
}
/*
+ * Gets an integer argument given to the /list command.
+ */
+
+int
+irc_command_list_get_int_arg (int argc, char **argv, int arg_number,
+ int default_value)
+{
+ long value;
+ char *error;
+
+ value = default_value;
+ if (argc > arg_number)
+ {
+ error = NULL;
+ value = strtol (argv[arg_number], &error, 10);
+ if (!error || error[0])
+ value = default_value;
+ }
+ return (int)value;
+}
+
+/*
* Callback for command "/list": lists channels and their topics.
*/
IRC_COMMAND_CALLBACK(list)
{
+ struct t_hashtable *hashtable;
char buf[512], *ptr_channel_name, *ptr_server_name, *ptr_regex;
regex_t *new_regexp;
- int i, ret;
+ int i, ret, value;
IRC_BUFFER_GET_SERVER(buffer);
@@ -3390,6 +3414,69 @@ IRC_COMMAND_CALLBACK(list)
ptr_regex = NULL;
new_regexp = NULL;
+ if ((argc > 0) && (weechat_strcmp (argv[1], "-up") == 0))
+ {
+ if (ptr_server && ptr_server->list->buffer)
+ {
+ irc_list_move_line_relative (
+ ptr_server,
+ -1 * irc_command_list_get_int_arg (argc, argv, 2, 1));
+ }
+ return WEECHAT_RC_OK;
+ }
+ if ((argc > 0) && (weechat_strcmp (argv[1], "-down") == 0))
+ {
+ if (ptr_server && ptr_server->list->buffer)
+ {
+ irc_list_move_line_relative (
+ ptr_server,
+ irc_command_list_get_int_arg (argc, argv, 2, 1));
+ }
+ return WEECHAT_RC_OK;
+ }
+ if ((argc > 0) && (weechat_strcmp (argv[1], "-go") == 0))
+ {
+ if (ptr_server && ptr_server->list->buffer)
+ {
+ if (argc < 3)
+ WEECHAT_COMMAND_ERROR;
+ value = (weechat_strcmp (argv[2], "end") == 0) ?
+ -1 : irc_command_list_get_int_arg (argc, argv, 2, -2);
+ if (value < -1)
+ WEECHAT_COMMAND_ERROR;
+ irc_list_move_line_absolute (ptr_server, value);
+ }
+ return WEECHAT_RC_OK;
+ }
+ if ((argc > 0) && (weechat_strcmp (argv[1], "-left") == 0))
+ {
+ if (ptr_server && ptr_server->list->buffer)
+ {
+ value = irc_command_list_get_int_arg (
+ argc, argv, 2,
+ weechat_config_integer (irc_config_look_list_buffer_scroll_horizontal));
+ irc_list_scroll_horizontal (ptr_server, -1 * value);
+ }
+ return WEECHAT_RC_OK;
+ }
+ if ((argc > 0) && (weechat_strcmp (argv[1], "-right") == 0))
+ {
+ if (ptr_server && ptr_server->list->buffer)
+ {
+ value = irc_command_list_get_int_arg (
+ argc, argv, 2,
+ weechat_config_integer (irc_config_look_list_buffer_scroll_horizontal));
+ irc_list_scroll_horizontal (ptr_server, value);
+ }
+ return WEECHAT_RC_OK;
+ }
+ if ((argc > 0) && (weechat_strcmp (argv[1], "-join") == 0))
+ {
+ if (ptr_server && ptr_server->list->buffer)
+ irc_list_join_channel (ptr_server);
+ return WEECHAT_RC_OK;
+ }
+
for (i = 1; i < argc; i++)
{
if (weechat_strcmp (argv[i], "-server") == 0)
@@ -3458,6 +3545,39 @@ IRC_COMMAND_CALLBACK(list)
ptr_server->cmd_list_regexp = NULL;
}
+ if (ptr_server->list && !ptr_server->cmd_list_regexp)
+ {
+ hashtable = weechat_hashtable_new (32,
+ WEECHAT_HASHTABLE_STRING,
+ WEECHAT_HASHTABLE_STRING,
+ NULL,
+ NULL);
+ if (hashtable)
+ {
+ weechat_hashtable_set (hashtable, "server", ptr_server->name);
+ weechat_hashtable_set (hashtable, "pattern", "list");
+ snprintf (buf, sizeof (buf), "server_%s", ptr_server->name);
+ weechat_hashtable_set (hashtable, "signal", buf);
+ weechat_hook_hsignal_send ("irc_redirect_command", hashtable);
+ weechat_hashtable_free (hashtable);
+ }
+
+ irc_list_reset (ptr_server);
+
+ if (ptr_server->list->buffer)
+ weechat_buffer_clear (ptr_server->list->buffer);
+ else
+ ptr_server->list->buffer = irc_list_create_buffer (ptr_server);
+ if (ptr_server->list->buffer)
+ {
+ weechat_printf_y (ptr_server->list->buffer, 1,
+ "%s",
+ _("Receiving list of channels, please wait..."));
+ irc_list_buffer_set_title (ptr_server);
+ weechat_buffer_set (ptr_server->list->buffer, "display", "1");
+ }
+ }
+
irc_server_sendf (ptr_server, IRC_SERVER_SEND_OUTQ_PRIO_HIGH, NULL,
"LIST%s%s%s%s",
(ptr_channel_name) ? " " : "",
@@ -7155,24 +7275,84 @@ irc_command_init ()
"list",
N_("list channels and their topics"),
N_("[-server <server>] [-re <regex>] [<channel>[,<channel>...]] "
- "[<target>]"),
+ "[<target>]"
+ " || -up|-down [<number>]"
+ " || -left|-right [<percent>]"
+ " || -go <line>|end"
+ " || -join"),
N_(" server: send to this server (internal name)\n"
" regex: POSIX extended regular expression used to filter results "
"(case insensitive, can start by \"(?-i)\" to become case "
"sensitive)\n"
"channel: channel to list\n"
" target: server name\n"
+ " -up: move the selected line up by \"number\" lines\n"
+ " -down: move the selected line down by \"number\" lines\n"
+ " -left: scroll the list buffer by \"percent\" of width "
+ "on the left\n"
+ " -right: scroll the list buffer by \"percent\" of width "
+ "on the right\n"
+ " -go: select a line by number, first line number is 0 "
+ "(\"end\" to select the last line)\n"
+ " -join: join the channel on the selected line\n"
+ "\n"
+ "Keys and input on /list buffer:\n"
+ " up move one line up\n"
+ " down move one line down\n"
+ " pgup move one page up\n"
+ " pgdn move one page down\n"
+ " alt-home << move to first line\n"
+ " alt-end >> move to last line\n"
+ " F11 < scroll horizontally on the left\n"
+ " F12 > scroll horizontally on the right\n"
+ " * show all channels (no filter)\n"
+ " xxx show only channels with \"xxx\" in name or topic (case insensitive)\n"
+ " n:xxx show only channels with \"xxx\" in name (case insensitive)\n"
+ " u:n show only channels with at least \"n\" users\n"
+ " u:>n show only channels with more than \"n\" users\n"
+ " u:<n show only channels with less than \"n\" users\n"
+ " t:xxx show only channels with \"xxx\" in topic (case insensitive)\n"
+ " c:xxx show only channels matching the evaluated "
+ "condition \"xxx\", using following variables: name, name2, users, "
+ "topic\n"
+ " ctrl-j j join channel on selected line\n"
+ " s:x,y sort channels by fields x,y (see below)\n"
+ " s: reset sort to its default value (see below)\n"
+ " $ refresh list\n"
+ " q close buffer\n"
+ "\n"
+ "Sort keys on /list buffer:\n"
+ " name channel name (eg: \"##test\")\n"
+ " name2 channel name without prefix (eg: \"test\")\n"
+ " users number of users on channel\n"
+ " topic channel topic\n"
"\n"
"Examples:\n"
- " list all channels on server (can be very slow on large networks):\n"
+ " list all channels on server and display them in a dedicated buffer "
+ "(can be slow on large networks):\n"
" /list\n"
" list channel #weechat:\n"
" /list #weechat\n"
" list all channels beginning with \"#weechat\" (can be very slow "
"on large networks):\n"
- " /list -re #weechat.*"),
+ " /list -re #weechat.*\n"
+ " on /list buffer:\n"
+ " channels with \"weechat\" in name:\n"
+ " n:weechat\n"
+ " channels with at least 100 users:\n"
+ " u:100\n"
+ " channels with \"freebsd\" (case insensitive) in topic and more than 10 users:\n"
+ " c:${topic} =- freebsd && ${users} > 10\n"
+ " sort channels by users (big channels first), then name2 (name without prefix):\n"
+ " s:-users,name2"),
"-server %(irc_servers)"
- " || -re",
+ " || -re"
+ " || -up 1|2|3|4|5"
+ " || -down 1|2|3|4|5"
+ " || -left 10|20|30|40|50|60|70|80|90|100"
+ " || -right 10|20|30|40|50|60|70|80|90|100"
+ " || -go 0|end"
+ " || -join",
&irc_command_list, NULL, NULL);
weechat_hook_command (
"lusers",
diff --git a/src/plugins/irc/irc-config.c b/src/plugins/irc/irc-config.c
index 36c564f94..3a90efdfa 100644
--- a/src/plugins/irc/irc-config.c
+++ b/src/plugins/irc/irc-config.c
@@ -33,6 +33,7 @@
#include "irc-channel.h"
#include "irc-ctcp.h"
#include "irc-ignore.h"
+#include "irc-list.h"
#include "irc-mode.h"
#include "irc-msgbuffer.h"
#include "irc-nick.h"
@@ -91,8 +92,12 @@ struct t_config_option *irc_config_look_item_display_server = NULL;
struct t_config_option *irc_config_look_item_nick_modes = NULL;
struct t_config_option *irc_config_look_item_nick_prefix = NULL;
struct t_config_option *irc_config_look_join_auto_add_chantype = NULL;
+struct t_config_option *irc_config_look_list_buffer_scroll_horizontal = NULL;
+struct t_config_option *irc_config_look_list_buffer_sort = NULL;
+struct t_config_option *irc_config_look_list_buffer_topic_strip_colors = NULL;
struct t_config_option *irc_config_look_msgbuffer_fallback = NULL;
struct t_config_option *irc_config_look_new_channel_position = NULL;
+struct t_config_option *irc_config_look_new_list_position = NULL;
struct t_config_option *irc_config_look_new_pv_position = NULL;
struct t_config_option *irc_config_look_nick_completion_smart = NULL;
struct t_config_option *irc_config_look_nick_mode = NULL;
@@ -133,6 +138,8 @@ struct t_config_option *irc_config_color_item_nick_modes = NULL;
struct t_config_option *irc_config_color_item_tls_version_deprecated = NULL;
struct t_config_option *irc_config_color_item_tls_version_insecure = NULL;
struct t_config_option *irc_config_color_item_tls_version_ok = NULL;
+struct t_config_option *irc_config_color_list_buffer_line_selected = NULL;
+struct t_config_option *irc_config_color_list_buffer_line_selected_bg = NULL;
struct t_config_option *irc_config_color_message_account = NULL;
struct t_config_option *irc_config_color_message_chghost = NULL;
struct t_config_option *irc_config_color_message_join = NULL;
@@ -736,6 +743,29 @@ irc_config_change_color_item_tls_version (const void *pointer, void *data,
}
/*
+ * Callback for changes on options "irc.color.list_buffer_*".
+ */
+
+void
+irc_config_change_color_list_buffer (const void *pointer, void *data,
+ struct t_config_option *option)
+{
+ struct t_irc_server *ptr_server;
+
+ /* make C compiler happy */
+ (void) pointer;
+ (void) data;
+ (void) option;
+
+ for (ptr_server = irc_servers; ptr_server;
+ ptr_server = ptr_server->next_server)
+ {
+ if (ptr_server->list->buffer)
+ irc_list_buffer_refresh (ptr_server, 0);
+ }
+}
+
+/*
* Callback for changes on option "irc.color.mirc_remap".
*/
@@ -3230,6 +3260,34 @@ irc_config_init ()
"will in fact send: \"/join #weechat\""),
NULL, 0, 0, "off", NULL, 0,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+ irc_config_look_list_buffer_scroll_horizontal = weechat_config_new_option (
+ irc_config_file, irc_config_section_look,
+ "list_buffer_scroll_horizontal", "integer",
+ N_("left/right scroll in /list buffer (percent of width)"),
+ NULL, 1, 100, "10", NULL, 0,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL);
+ irc_config_look_list_buffer_sort = weechat_config_new_option (
+ irc_config_file, irc_config_section_look,
+ "list_buffer_sort", "string",
+ N_("comma-separated list of fields to sort channels (see /help list "
+ "for a list of fields); char \"-\" can be used before field to "
+ "reverse order, char \"~\" can be used to do a case insensitive "
+ "comparison; example: \"-count,~name\" for biggest channels "
+ "first then case insensitive sort on name"),
+ NULL, 0, 0, "~name2", NULL, 0,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL);
+ irc_config_look_list_buffer_topic_strip_colors = weechat_config_new_option (
+ irc_config_file, irc_config_section_look,
+ "list_buffer_topic_strip_colors", "boolean",
+ N_("strip channel topic colors in /list buffer"),
+ NULL, 0, 0, "on", NULL, 0,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL);
irc_config_look_msgbuffer_fallback = weechat_config_new_option (
irc_config_file, irc_config_section_look,
"msgbuffer_fallback", "enum",
@@ -3246,6 +3304,15 @@ irc_config_init ()
"of server)"),
"none|next|near_server", 0, 0, "none", NULL, 0,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+ irc_config_look_new_list_position = weechat_config_new_option (
+ irc_config_file, irc_config_section_look,
+ "new_list_position", "enum",
+ N_("force position of new /list buffer in list of buffers "
+ "(none = default position (should be last buffer), "
+ "next = current buffer + 1, near_server = after last channel/pv "
+ "of server)"),
+ "none|next|near_server", 0, 0, "none", NULL, 0,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
irc_config_look_new_pv_position = weechat_config_new_option (
irc_config_file, irc_config_section_look,
"new_pv_position", "enum",
@@ -3564,6 +3631,22 @@ irc_config_init ()
NULL, NULL, NULL,
&irc_config_change_color_item_tls_version, NULL, NULL,
NULL, NULL, NULL);
+ irc_config_color_list_buffer_line_selected = weechat_config_new_option (
+ irc_config_file, irc_config_section_color,
+ "list_buffer_line_selected", "color",
+ N_("color for selected line on /list buffer"),
+ NULL, -1, 0, "white", NULL, 0,
+ NULL, NULL, NULL,
+ &irc_config_change_color_list_buffer, NULL, NULL,
+ NULL, NULL, NULL);
+ irc_config_color_list_buffer_line_selected_bg = weechat_config_new_option (
+ irc_config_file, irc_config_section_color,
+ "list_buffer_line_selected_bg", "color",
+ N_("background color for selected line on /list buffer"),
+ NULL, -1, 0, "24", NULL, 0,
+ NULL, NULL, NULL,
+ &irc_config_change_color_list_buffer, NULL, NULL,
+ NULL, NULL, NULL);
irc_config_color_message_account = weechat_config_new_option (
irc_config_file, irc_config_section_color,
"message_account", "color",
diff --git a/src/plugins/irc/irc-config.h b/src/plugins/irc/irc-config.h
index 3a9e8b899..c5d078bdc 100644
--- a/src/plugins/irc/irc-config.h
+++ b/src/plugins/irc/irc-config.h
@@ -127,8 +127,12 @@ extern struct t_config_option *irc_config_look_item_display_server;
extern struct t_config_option *irc_config_look_item_nick_modes;
extern struct t_config_option *irc_config_look_item_nick_prefix;
extern struct t_config_option *irc_config_look_join_auto_add_chantype;
+extern struct t_config_option *irc_config_look_list_buffer_scroll_horizontal;
+extern struct t_config_option *irc_config_look_list_buffer_sort;
+extern struct t_config_option *irc_config_look_list_buffer_topic_strip_colors;
extern struct t_config_option *irc_config_look_msgbuffer_fallback;
extern struct t_config_option *irc_config_look_new_channel_position;
+extern struct t_config_option *irc_config_look_new_list_position;
extern struct t_config_option *irc_config_look_new_pv_position;
extern struct t_config_option *irc_config_look_nick_completion_smart;
extern struct t_config_option *irc_config_look_nick_mode;
@@ -167,6 +171,8 @@ extern struct t_config_option *irc_config_color_item_nick_modes;
extern struct t_config_option *irc_config_color_item_tls_version_deprecated;
extern struct t_config_option *irc_config_color_item_tls_version_insecure;
extern struct t_config_option *irc_config_color_item_tls_version_ok;
+extern struct t_config_option *irc_config_color_list_buffer_line_selected;
+extern struct t_config_option *irc_config_color_list_buffer_line_selected_bg;
extern struct t_config_option *irc_config_color_message_account;
extern struct t_config_option *irc_config_color_message_chghost;
extern struct t_config_option *irc_config_color_message_join;
diff --git a/src/plugins/irc/irc-info.c b/src/plugins/irc/irc-info.c
index 98da456f8..a95d95f1f 100644
--- a/src/plugins/irc/irc-info.c
+++ b/src/plugins/irc/irc-info.c
@@ -30,6 +30,7 @@
#include "irc-color.h"
#include "irc-config.h"
#include "irc-ignore.h"
+#include "irc-list.h"
#include "irc-message.h"
#include "irc-modelist.h"
#include "irc-nick.h"
@@ -1384,4 +1385,10 @@ irc_info_init ()
weechat_hook_hdata (
"irc_batch", N_("irc batch"),
&irc_batch_hdata_batch_cb, NULL, NULL);
+ weechat_hook_hdata (
+ "irc_list_channel", N_("irc channel on /list buffer"),
+ &irc_list_hdata_list_channel_cb, NULL, NULL);
+ weechat_hook_hdata (
+ "irc_list", N_("irc data for /list buffer"),
+ &irc_list_hdata_list_cb, NULL, NULL);
}
diff --git a/src/plugins/irc/irc-input.c b/src/plugins/irc/irc-input.c
index d0cae36c1..fa44d5938 100644
--- a/src/plugins/irc/irc-input.c
+++ b/src/plugins/irc/irc-input.c
@@ -32,6 +32,7 @@
#include "irc-nick.h"
#include "irc-color.h"
#include "irc-config.h"
+#include "irc-list.h"
#include "irc-msgbuffer.h"
#include "irc-protocol.h"
#include "irc-raw.h"
@@ -365,6 +366,12 @@ irc_input_data (struct t_gui_buffer *buffer, const char *input_data, int flags,
else
irc_raw_filter_options (input_data);
}
+ else if (weechat_strcmp (
+ weechat_buffer_get_string (buffer,
+ "localvar_type"), "irc_list") == 0)
+ {
+ irc_list_buffer_input_data (buffer, input_data);
+ }
else
{
/*
diff --git a/src/plugins/irc/irc-list.c b/src/plugins/irc/irc-list.c
new file mode 100644
index 000000000..e4383b449
--- /dev/null
+++ b/src/plugins/irc/irc-list.c
@@ -0,0 +1,1309 @@
+/*
+ * irc-list.c - functions for IRC list buffer
+ *
+ * Copyright (C) 2023 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 <time.h>
+
+#include "../weechat-plugin.h"
+#include "irc.h"
+#include "irc-list.h"
+#include "irc-buffer.h"
+#include "irc-color.h"
+#include "irc-config.h"
+#include "irc-input.h"
+#include "irc-message.h"
+#include "irc-server.h"
+
+
+struct t_hdata *irc_list_hdata_list_channel = NULL;
+struct t_hashtable *irc_list_filter_hashtable_pointers = NULL;
+struct t_hashtable *irc_list_filter_hashtable_extra_vars = NULL;
+struct t_hashtable *irc_list_filter_hashtable_options = NULL;
+
+
+/*
+ * Compares two channels in list.
+ */
+
+int
+irc_list_compare_cb (void *data, struct t_arraylist *arraylist,
+ void *pointer1, void *pointer2)
+{
+ struct t_irc_server *ptr_server;
+ const char *ptr_field;
+ int i, reverse, case_sensitive, rc;
+
+ /* make C compiler happy */
+ (void) arraylist;
+
+ ptr_server = data;
+ if (!ptr_server)
+ return 1;
+
+ for (i = 0; i < ptr_server->list->sort_fields_count; i++)
+ {
+ reverse = 1;
+ case_sensitive = 1;
+ ptr_field = ptr_server->list->sort_fields[i];
+ while ((ptr_field[0] == '-') || (ptr_field[0] == '~'))
+ {
+ if (ptr_field[0] == '-')
+ reverse *= -1;
+ else if (ptr_field[0] == '~')
+ case_sensitive ^= 1;
+ ptr_field++;
+ }
+ rc = weechat_hdata_compare (irc_list_hdata_list_channel,
+ pointer1, pointer2,
+ ptr_field,
+ case_sensitive);
+ rc *= reverse;
+ if (rc != 0)
+ return rc;
+ }
+
+ return 1;
+}
+
+/*
+ * Frees a channel in list.
+ */
+
+void
+irc_list_free_cb (void *data, struct t_arraylist *arraylist, void *pointer)
+{
+ struct t_irc_list_channel *ptr_channel;
+
+ /* make C compiler happy */
+ (void) data;
+ (void) arraylist;
+
+ ptr_channel = (struct t_irc_list_channel *)pointer;
+ if (ptr_channel)
+ {
+ if (ptr_channel->name)
+ free (ptr_channel->name);
+ if (ptr_channel->name2)
+ free (ptr_channel->name2);
+ if (ptr_channel->topic)
+ free (ptr_channel->topic);
+ free (ptr_channel);
+ }
+}
+
+/*
+ * Sets filter for list of channels.
+ */
+
+void
+irc_list_set_filter (struct t_irc_server *server, const char *filter)
+{
+ if (server->list->filter)
+ {
+ free (server->list->filter);
+ server->list->filter = NULL;
+ }
+
+ server->list->filter = (filter && (strcmp (filter, "*") != 0)) ?
+ strdup (filter) : NULL;
+}
+
+/*
+ * Sets sort for list of channels.
+ *
+ */
+
+void
+irc_list_set_sort (struct t_irc_server *server, const char *sort)
+{
+ if (server->list->sort)
+ {
+ free (server->list->sort);
+ server->list->sort = NULL;
+ }
+ if (server->list->sort_fields)
+ {
+ weechat_string_free_split (server->list->sort_fields);
+ server->list->sort_fields = NULL;
+ }
+ server->list->sort_fields_count = 0;
+
+ server->list->sort = strdup (
+ (sort && sort[0]) ?
+ sort : weechat_config_string (irc_config_look_list_buffer_sort));
+
+ if (server->list->sort)
+ {
+ server->list->sort_fields = weechat_string_split (
+ server->list->sort,
+ ",",
+ NULL,
+ WEECHAT_STRING_SPLIT_STRIP_LEFT
+ | WEECHAT_STRING_SPLIT_STRIP_RIGHT
+ | WEECHAT_STRING_SPLIT_COLLAPSE_SEPS,
+ 0,
+ &server->list->sort_fields_count);
+ }
+}
+
+/*
+ * Adds the properties of an irc list channel in a hashtable
+ * (keys and values must be strings).
+ */
+
+void
+irc_list_add_channel_in_hashtable (struct t_hashtable *hashtable,
+ struct t_irc_list_channel *channel)
+{
+ char str_number[32];
+
+ weechat_hashtable_set (hashtable, "name", channel->name);
+ weechat_hashtable_set (hashtable, "name2", channel->name2);
+ snprintf (str_number, sizeof (str_number), "%d", channel->users);
+ weechat_hashtable_set (hashtable, "users", str_number);
+ weechat_hashtable_set (hashtable, "topic", channel->topic);
+}
+
+/*
+ * Checks if a string matches a mask.
+ *
+ * If mask has no "*" inside, it just checks if "mask" is inside the "string".
+ * If mask has at least one "*" inside, the function weechat_string_match is
+ * used.
+ *
+ * Returns:
+ * 1: string matches mask
+ * 0: string does not match mask
+ */
+
+int
+irc_list_string_match (const char *string, const char *mask)
+{
+ if (strchr (mask, '*'))
+ return weechat_string_match (string, mask, 0);
+ else
+ return (weechat_strcasestr (string, mask)) ? 1 : 0;
+}
+
+/*
+ * Checks if a channel matches filter.
+ *
+ * Return:
+ * 1: channel matches filter
+ * 0: channel does NOT match filter
+ */
+
+int
+irc_list_channel_match_filter (struct t_irc_server *server,
+ struct t_irc_list_channel *channel)
+{
+ char *error, *result;
+ long number;
+ int match;
+
+ /* no filter? then any channel is matching */
+ if (!server->list->filter)
+ return 1;
+
+ if (strncmp (server->list->filter, "c:", 2) == 0)
+ {
+ /* filter by evaluated condition */
+ weechat_hashtable_set (irc_list_filter_hashtable_pointers,
+ "irc_list_channel", channel);
+ irc_list_add_channel_in_hashtable (irc_list_filter_hashtable_extra_vars,
+ channel);
+ result = weechat_string_eval_expression (
+ server->list->filter + 2,
+ irc_list_filter_hashtable_pointers,
+ irc_list_filter_hashtable_extra_vars,
+ irc_list_filter_hashtable_options);
+ match = (result && (strcmp (result, "1") == 0)) ? 1 : 0;
+ if (result)
+ free (result);
+ return match;
+ }
+
+ if (strncmp (server->list->filter, "n:", 2) == 0)
+ {
+ /* filter by channel name */
+ if (channel->name
+ && irc_list_string_match (channel->name, server->list->filter + 2))
+ {
+ return 1;
+ }
+ }
+ else if (strncmp (server->list->filter, "t:", 2) == 0)
+ {
+ /* filter by topic */
+ if (channel->topic
+ && irc_list_string_match (channel->topic, server->list->filter + 2))
+ {
+ return 1;
+ }
+ }
+ else if (strncmp (server->list->filter, "u:>", 3) == 0)
+ {
+ /* filter by users (> N)*/
+ number = strtol (server->list->filter + 3, &error, 10);
+ if (error && !error[0] && channel->users > (int)number)
+ return 1;
+ }
+ else if (strncmp (server->list->filter, "u:<", 3) == 0)
+ {
+ /* filter by users (< N)*/
+ number = strtol (server->list->filter + 3, &error, 10);
+ if (error && !error[0] && channel->users < (int)number)
+ return 1;
+ }
+ else if (strncmp (server->list->filter, "u:", 2) == 0)
+ {
+ /* filter by users */
+ number = strtol (server->list->filter + 2, &error, 10);
+ if (error && !error[0] && channel->users >= (int)number)
+ return 1;
+ }
+ else
+ {
+ if (channel->name
+ && irc_list_string_match (channel->name, server->list->filter))
+ {
+ return 1;
+ }
+ if (channel->topic
+ && irc_list_string_match (channel->topic, server->list->filter))
+ {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Filters channels: apply filter and use sort to build the list
+ * "filter_channels" that are pointers to t_irc_list_channel structs
+ * stored in main list "channels".
+ */
+
+void
+irc_list_filter_channels (struct t_irc_server *server)
+{
+ struct t_irc_list_channel *ptr_channel;
+ int i, list_size;
+
+ if (server->list->filter_channels)
+ {
+ weechat_arraylist_clear (server->list->filter_channels);
+ }
+ else
+ {
+ server->list->filter_channels = weechat_arraylist_new (
+ 16, 1, 0,
+ &irc_list_compare_cb, server,
+ NULL, NULL);
+ }
+
+ if (!server->list->sort)
+ {
+ irc_list_set_sort (
+ server,
+ weechat_config_string (irc_config_look_list_buffer_sort));
+ }
+
+ list_size = weechat_arraylist_size (server->list->channels);
+ for (i = 0; i < list_size; i++)
+ {
+ ptr_channel = (struct t_irc_list_channel *)weechat_arraylist_get (
+ server->list->channels, i);
+ if (!ptr_channel)
+ continue;
+ if (irc_list_channel_match_filter (server, ptr_channel))
+ weechat_arraylist_add (server->list->filter_channels, ptr_channel);
+ }
+}
+
+/*
+ * Parses output of redirected /list (string with raw IRC messages separated
+ * by newlines) and returns an arraylist of parsed channels, or NULL if no
+ * valid message (322) was found in output.
+ *
+ * Returns:
+ * 1: OK
+ * 0: error
+ */
+
+int
+irc_list_parse_messages (struct t_irc_server *server, const char *output)
+{
+ struct t_irc_list_channel *channel;
+ char **irc_msgs, *command, **params, *error;
+ const char *ptr_name;
+ int i, count_irc_msgs, num_params, length, keep_colors;
+ long number;
+
+ if (server->list->channels)
+ {
+ weechat_arraylist_free (server->list->channels);
+ server->list->channels = NULL;
+ }
+
+ irc_msgs = weechat_string_split (output, "\n", NULL, 0, 0, &count_irc_msgs);
+ if (!irc_msgs)
+ return 0;
+
+ server->list->channels = weechat_arraylist_new (
+ 16, 0, 1,
+ NULL, NULL,
+ &irc_list_free_cb, NULL);
+ if (!server->list->channels)
+ {
+ weechat_string_free_split (irc_msgs);
+ return 0;
+ }
+
+ server->list->name_max_length = 0;
+
+ keep_colors = (weechat_config_boolean (
+ irc_config_look_list_buffer_topic_strip_colors)) ?
+ 0 : 1;
+
+ for (i = 0; i < count_irc_msgs; i++)
+ {
+ irc_message_parse (server, irc_msgs[i],
+ NULL, /* tags */
+ NULL, /* message_without_tags */
+ NULL, /* nick */
+ NULL, /* user */
+ NULL, /* host */
+ &command,
+ NULL, /* channel */
+ NULL, /* arguments */
+ NULL, /* text */
+ &params,
+ &num_params,
+ NULL, /* pos_command */
+ NULL, /* pos_arguments */
+ NULL, /* pos_channel */
+ NULL); /* pos_text */
+ if (command
+ && (strcmp (command, "322") == 0)
+ && params
+ && (num_params >= 3))
+ {
+ channel = malloc (sizeof (*channel));
+ if (channel)
+ {
+ channel->name = strdup (params[1]);
+ ptr_name = params[1] + 1;
+ while (ptr_name[0] && (ptr_name[0] == params[1][0]))
+ {
+ ptr_name++;
+ }
+ channel->name2 = strdup (ptr_name);
+ number = strtol (params[2], &error, 10);
+ channel->users = (error && !error[0]) ? number : 0;
+ channel->topic = (num_params > 3) ?
+ irc_color_decode (params[3], keep_colors) : NULL;
+ length = weechat_utf8_strlen_screen (channel->name);
+ if (length > server->list->name_max_length)
+ server->list->name_max_length = length;
+ weechat_arraylist_add (server->list->channels, channel);
+ }
+ }
+ if (command)
+ free (command);
+ if (params)
+ weechat_string_free_split (params);
+ }
+
+ weechat_string_free_split (irc_msgs);
+
+ irc_list_filter_channels (server);
+
+ return 1;
+}
+
+/*
+ * Sets title of list buffer.
+ */
+
+void
+irc_list_buffer_set_title (struct t_irc_server *server)
+{
+ int num_channels, num_channels_total;
+ char str_title[8192];
+
+ if (!server || !server->list->buffer)
+ return;
+
+ num_channels = (server->list->filter_channels) ?
+ weechat_arraylist_size (server->list->filter_channels) : 0;
+ num_channels_total = (server->list->channels) ?
+ weechat_arraylist_size (server->list->channels) : 0;
+
+ snprintf (str_title, sizeof (str_title),
+ _("%d channels (total: %d) | Filter: %s | Sort: %s | "
+ "Key(input): "
+ "ctrl+j=join channel, "
+ "($)=refresh, "
+ "(q)=close buffer"),
+ num_channels,
+ num_channels_total,
+ (server->list->filter) ? server->list->filter : "*",
+ (server->list->sort) ? server->list->sort : "");
+
+ weechat_buffer_set (server->list->buffer, "title", str_title);
+}
+
+/*
+ * Displays a line.
+ */
+
+void
+irc_list_display_line (struct t_irc_server *server, int line)
+{
+ struct t_irc_list_channel *ptr_channel;
+ const char *ptr_color;
+ char str_spaces[1024], color[256];
+ int num_spaces;
+
+ ptr_channel = (struct t_irc_list_channel *)weechat_arraylist_get (
+ server->list->filter_channels, line);
+
+ /* line color */
+ if (line == server->list->selected_line)
+ {
+ snprintf (color, sizeof (color),
+ "%s,%s",
+ weechat_config_string (irc_config_color_list_buffer_line_selected),
+ weechat_config_string (irc_config_color_list_buffer_line_selected_bg));
+ ptr_color = weechat_color (color);
+ }
+ else
+ {
+ ptr_color = NULL;
+ }
+
+ /* channel name */
+ str_spaces[0] = '\0';
+ num_spaces = server->list->name_max_length
+ - weechat_utf8_strlen_screen (ptr_channel->name);
+ if (num_spaces > 0)
+ {
+ if (num_spaces >= (int)sizeof (str_spaces))
+ num_spaces = sizeof (str_spaces) - 1;
+ memset (str_spaces, ' ', num_spaces);
+ str_spaces[num_spaces] = '\0';
+ }
+
+ /* display the line */
+ weechat_printf_y (
+ server->list->buffer,
+ line,
+ "%s%s%s %7d %s",
+ (ptr_color) ? ptr_color : "",
+ ptr_channel->name,
+ str_spaces,
+ ptr_channel->users,
+ ptr_channel->topic);
+}
+
+/*
+ * Updates list of channels in list buffer.
+ */
+
+void
+irc_list_buffer_refresh (struct t_irc_server *server, int clear)
+{
+ int num_channels, i;
+
+ if (!server || !server->list->buffer)
+ return;
+
+ num_channels = weechat_arraylist_size (server->list->filter_channels);
+
+ if (clear)
+ {
+ weechat_buffer_clear (server->list->buffer);
+ server->list->selected_line = 0;
+ }
+
+ for (i = 0; i < num_channels; i++)
+ {
+ irc_list_display_line (server, i);
+ }
+
+ irc_list_buffer_set_title (server);
+}
+
+/*
+ * Sets current selected line.
+ */
+
+void
+irc_list_set_current_line (struct t_irc_server *server, int line)
+{
+ int old_line;
+
+ if ((line >= 0) && (line < weechat_arraylist_size (server->list->filter_channels)))
+ {
+ old_line = server->list->selected_line;
+ server->list->selected_line = line;
+
+ if (old_line != server->list->selected_line)
+ irc_list_display_line (server, old_line);
+ irc_list_display_line (server, server->list->selected_line);
+
+ irc_list_buffer_set_title (server);
+ }
+}
+
+/*
+ * Gets info about a window.
+ */
+
+void
+irc_list_get_window_info (struct t_gui_window *window,
+ int *start_line_y, int *chat_height)
+{
+ struct t_hdata *hdata_window, *hdata_window_scroll, *hdata_line;
+ struct t_hdata *hdata_line_data;
+ void *window_scroll, *start_line, *line_data;
+
+ hdata_window = weechat_hdata_get ("window");
+ hdata_window_scroll = weechat_hdata_get ("window_scroll");
+ hdata_line = weechat_hdata_get ("line");
+ hdata_line_data = weechat_hdata_get ("line_data");
+ *start_line_y = 0;
+ window_scroll = weechat_hdata_pointer (hdata_window, window, "scroll");
+ if (window_scroll)
+ {
+ start_line = weechat_hdata_pointer (hdata_window_scroll, window_scroll,
+ "start_line");
+ if (start_line)
+ {
+ line_data = weechat_hdata_pointer (hdata_line, start_line, "data");
+ if (line_data)
+ {
+ *start_line_y = weechat_hdata_integer (hdata_line_data,
+ line_data, "y");
+ }
+ }
+ }
+ *chat_height = weechat_hdata_integer (hdata_window, window,
+ "win_chat_height");
+}
+
+/*
+ * Checks if current line is outside window and adjusts scroll if needed.
+ */
+
+void
+irc_list_check_line_outside_window (struct t_irc_server *server)
+{
+ struct t_gui_window *window;
+ int start_line_y, chat_height;
+ int selected_y;
+ char str_command[256];
+
+ window = weechat_window_search_with_buffer (server->list->buffer);
+ if (!window)
+ return;
+
+ irc_list_get_window_info (window, &start_line_y, &chat_height);
+
+ selected_y = server->list->selected_line;
+
+ if ((start_line_y > selected_y)
+ || (start_line_y < selected_y - chat_height + 1))
+ {
+ snprintf (str_command, sizeof (str_command),
+ "/window scroll -window %d %s%d",
+ weechat_window_get_integer (window, "number"),
+ (start_line_y > selected_y) ? "-" : "+",
+ (start_line_y > selected_y) ?
+ start_line_y - selected_y :
+ selected_y - start_line_y - chat_height + 1);
+ weechat_command (server->list->buffer, str_command);
+ }
+}
+
+/*
+ * Callback for signal "window_scrolled".
+ */
+
+int
+irc_list_window_scrolled_cb (const void *pointer, void *data,
+ const char *signal, const char *type_data,
+ void *signal_data)
+{
+ struct t_gui_buffer *ptr_buffer;
+ struct t_irc_server *ptr_server;
+ int start_line_y, chat_height, line, num_channels;
+
+ /* make C compiler happy */
+ (void) pointer;
+ (void) data;
+ (void) signal;
+ (void) type_data;
+
+ /* search the /list buffer */
+ ptr_buffer = weechat_window_get_pointer (signal_data, "buffer");
+ for (ptr_server = irc_servers; ptr_server;
+ ptr_server = ptr_server->next_server)
+ {
+ if (ptr_server->list->buffer == ptr_buffer)
+ break;
+ }
+ if (!ptr_server)
+ return WEECHAT_RC_OK;
+
+ irc_list_get_window_info (signal_data, &start_line_y, &chat_height);
+
+ line = ptr_server->list->selected_line;
+ while (line < start_line_y)
+ {
+ line += chat_height;
+ }
+ while (line >= start_line_y + chat_height)
+ {
+ line -= chat_height;
+ }
+ if (line < start_line_y)
+ line = start_line_y + 1;
+
+ num_channels = weechat_arraylist_size (ptr_server->list->filter_channels);
+ if ((num_channels > 0) && (line >= num_channels))
+ line = num_channels - 1;
+
+ irc_list_set_current_line (ptr_server, line);
+
+ return WEECHAT_RC_OK;
+}
+
+/*
+ * Moves N lines up/down in buffer
+ * (negative lines = move up, positive lines = move down).
+ */
+
+void
+irc_list_move_line_relative (struct t_irc_server *server, int num_lines)
+{
+ int num_channels, line;
+
+ num_channels = weechat_arraylist_size (server->list->filter_channels);
+ if (num_channels == 0)
+ return;
+
+ line = server->list->selected_line + num_lines;
+ if (line < 0)
+ line = 0;
+ if ((num_channels > 0) && (line >= num_channels))
+ line = num_channels - 1;
+ if (line != server->list->selected_line)
+ {
+ irc_list_set_current_line (server, line);
+ irc_list_check_line_outside_window (server);
+ }
+}
+
+/*
+ * Moves to line N (0 = first line, -1 = last line).
+ */
+
+void
+irc_list_move_line_absolute (struct t_irc_server *server, int line_number)
+{
+ int num_channels, line;
+
+ num_channels = weechat_arraylist_size (server->list->filter_channels);
+ if (num_channels == 0)
+ return;
+
+ line = line_number;
+ if (line < 0)
+ line = (num_channels > 0) ? num_channels - 1 : 0;
+ if ((num_channels > 0) && (line >= num_channels))
+ line = num_channels - 1;
+ if (line != server->list->selected_line)
+ {
+ irc_list_set_current_line (server, line);
+ irc_list_check_line_outside_window (server);
+ }
+}
+
+/*
+ * Scrolls horizontally with percent
+ * (negative: scroll to the left, positive: scroll to the right).
+ */
+
+void
+irc_list_scroll_horizontal (struct t_irc_server *server, int percent)
+{
+ struct t_gui_window *ptr_window;
+ char str_command[512];
+
+ if (percent < -100)
+ percent = -100;
+ else if (percent > 100)
+ percent = 100;
+
+ ptr_window = weechat_window_search_with_buffer (server->list->buffer);
+ if (!ptr_window)
+ return;
+
+ snprintf (str_command, sizeof (str_command),
+ "/window scroll_horiz -window %d %d%%",
+ weechat_window_get_integer (ptr_window, "number"),
+ percent);
+ weechat_command (server->list->buffer, str_command);
+}
+
+/*
+ * Joins channel on current selected line.
+ */
+
+void
+irc_list_join_channel (struct t_irc_server *server)
+{
+ struct t_irc_list_channel *ptr_channel;
+ int num_channels;
+ char str_command[1024];
+
+ num_channels = weechat_arraylist_size (server->list->filter_channels);
+
+ if ((num_channels == 0) || (server->list->selected_line >= num_channels))
+ return;
+
+ ptr_channel = (struct t_irc_list_channel *)weechat_arraylist_get (
+ server->list->filter_channels,
+ server->list->selected_line);
+ if (!ptr_channel)
+ return;
+
+ snprintf (str_command, sizeof (str_command),
+ "/join %s", ptr_channel->name);
+
+ weechat_command (server->list->buffer, str_command);
+}
+
+/*
+ * Callback for input data in list buffer.
+ */
+
+int
+irc_list_buffer_input_data (struct t_gui_buffer *buffer, const char *input_data)
+{
+ struct t_irc_server *ptr_server;
+ const char *ptr_server_name, *ptr_input;
+ int i;
+ char *actions[][2] = {
+ { "<<", "/list -go 0" },
+ { ">>", "/list -go end" },
+ { "<", "/list -left" },
+ { ">", "/list -right" },
+ { NULL, NULL },
+ };
+
+ /* close buffer */
+ if (strcmp (input_data, "q") == 0)
+ {
+ weechat_buffer_close (buffer);
+ return WEECHAT_RC_OK;
+ }
+
+ ptr_server_name = weechat_buffer_get_string (buffer, "localvar_server");
+ if (!ptr_server_name)
+ return WEECHAT_RC_OK;
+
+ ptr_server = irc_server_search (ptr_server_name);
+ if (!ptr_server)
+ return WEECHAT_RC_OK;
+
+ /* refresh buffer */
+ if (strcmp (input_data, "$") == 0)
+ {
+ weechat_command (ptr_server->list->buffer, "/list");
+ return WEECHAT_RC_OK;
+ }
+
+ /* join channel */
+ if (strcmp (input_data, "j") == 0)
+ {
+ irc_list_join_channel (ptr_server);
+ return WEECHAT_RC_OK;
+ }
+
+ /* change sort of channels */
+ if (strncmp (input_data, "s:", 2) == 0)
+ {
+ irc_list_set_sort (ptr_server, input_data + 2);
+ irc_list_filter_channels (ptr_server);
+ irc_list_buffer_refresh (ptr_server, 1);
+ weechat_buffer_set (buffer, "display", "1");
+ return WEECHAT_RC_OK;
+ }
+
+ /* execute action */
+ for (i = 0; actions[i][0]; i++)
+ {
+ if (strcmp (input_data, actions[i][0]) == 0)
+ {
+ weechat_command (buffer, actions[i][1]);
+ return WEECHAT_RC_OK;
+ }
+ }
+
+ /* filter channels with given text */
+ ptr_input = input_data;
+ while (ptr_input[0] == ' ')
+ {
+ ptr_input++;
+ }
+ if (ptr_input[0])
+ {
+ irc_list_set_filter (ptr_server, ptr_input);
+ irc_list_filter_channels (ptr_server);
+ irc_list_buffer_refresh (ptr_server, 1);
+ weechat_buffer_set (buffer, "display", "1");
+ }
+
+ return WEECHAT_RC_OK;
+}
+
+/*
+ * Sets keys on list buffer.
+ */
+
+void
+irc_list_buffer_set_keys (struct t_gui_buffer *buffer)
+{
+ char *keys[][2] = {
+ { "up", "/list -up" },
+ { "down", "/list -down" },
+ { "meta-home", "/list -go 0" },
+ { "meta-end", "/list -go end" },
+ { "f11", "/list -left" },
+ { "f12", "/list -right" },
+ { "ctrl-j", "/list -join" },
+ { NULL, NULL },
+ };
+ char str_key[64];
+ int i;
+
+ for (i = 0; keys[i][0]; i++)
+ {
+ snprintf (str_key, sizeof (str_key), "key_bind_%s", keys[i][0]);
+ weechat_buffer_set (buffer, str_key, keys[i][1]);
+ }
+}
+
+/*
+ * Creates buffer with list of channels for a server.
+ *
+ * Returns pointer to newly created buffer, NULL if error.
+ */
+
+struct t_gui_buffer *
+irc_list_create_buffer (struct t_irc_server *server)
+{
+ struct t_hashtable *buffer_props;
+ struct t_gui_buffer *buffer;
+ char buffer_name[1024], str_number[32];
+ int buffer_position, current_buffer_number;
+
+ buffer_props = weechat_hashtable_new (
+ 32,
+ WEECHAT_HASHTABLE_STRING,
+ WEECHAT_HASHTABLE_STRING,
+ NULL, NULL);
+ if (buffer_props)
+ {
+ weechat_hashtable_set (buffer_props, "type", "free");
+ weechat_hashtable_set (buffer_props, "localvar_set_type", "irc_list");
+ weechat_hashtable_set (buffer_props, "localvar_set_server", server->name);
+ weechat_hashtable_set (buffer_props, "localvar_set_channel", server->name);
+ weechat_hashtable_set (buffer_props, "localvar_set_no_log", "1");
+ /* disable all highlights on this buffer */
+ weechat_hashtable_set (buffer_props, "highlight_words", "-");
+ }
+
+ current_buffer_number = weechat_buffer_get_integer (
+ weechat_current_buffer (), "number");
+
+ snprintf (buffer_name, sizeof (buffer_name), "list_%s", server->name);
+
+ buffer = weechat_buffer_new_props (
+ buffer_name,
+ buffer_props,
+ &irc_input_data_cb, NULL, NULL,
+ &irc_buffer_close_cb, NULL, NULL);
+
+ if (buffer_props)
+ weechat_hashtable_free (buffer_props);
+
+ irc_list_buffer_set_keys (buffer);
+
+ if (weechat_buffer_get_integer (buffer, "layout_number") < 1)
+ {
+ buffer_position = weechat_config_enum (irc_config_look_new_list_position);
+ switch (buffer_position)
+ {
+ case IRC_CONFIG_LOOK_BUFFER_POSITION_NONE:
+ /* do nothing */
+ break;
+ case IRC_CONFIG_LOOK_BUFFER_POSITION_NEXT:
+ /* move buffer to current number + 1 */
+ snprintf (str_number, sizeof (str_number),
+ "%d", current_buffer_number + 1);
+ weechat_buffer_set (buffer, "number", str_number);
+ break;
+ case IRC_CONFIG_LOOK_BUFFER_POSITION_NEAR_SERVER:
+ /* move buffer after last channel/pv of server */
+ irc_buffer_move_near_server (
+ server,
+ 1, /* list_buffer */
+ -1, /* channel_type */
+ buffer);
+ break;
+ }
+ }
+
+ return buffer;
+}
+
+/*
+ * Callback for redirected /list command.
+ */
+
+int
+irc_list_hsignal_redirect_list_cb (const void *pointer,
+ void *data,
+ const char *signal,
+ struct t_hashtable *hashtable)
+{
+ struct t_irc_server *ptr_server;
+ const char *ptr_error, *ptr_server_name, *ptr_output;
+
+ /* make C compiler happy */
+ (void) pointer;
+ (void) data;
+ (void) signal;
+
+ ptr_error = weechat_hashtable_get (hashtable, "error");
+ if (ptr_error && ptr_error[0])
+ {
+ weechat_printf (
+ NULL,
+ _("%s%s: error in redirection of /list: %s"),
+ weechat_prefix ("error"), IRC_PLUGIN_NAME, ptr_error);
+ return WEECHAT_RC_OK;
+ }
+
+ ptr_server_name = weechat_hashtable_get (hashtable, "server");
+ if (!ptr_server_name)
+ return WEECHAT_RC_OK;
+
+ ptr_server = irc_server_search (ptr_server_name);
+ if (!ptr_server || !ptr_server->buffer)
+ return WEECHAT_RC_OK;
+
+ ptr_output = weechat_hashtable_get (hashtable, "output");
+ if (!ptr_output)
+ return WEECHAT_RC_OK;
+
+ if (!irc_list_hdata_list_channel)
+ {
+ irc_list_hdata_list_channel = weechat_hdata_get ("irc_list_channel");
+ if (!irc_list_hdata_list_channel)
+ return WEECHAT_RC_OK;
+ }
+
+ irc_list_parse_messages (ptr_server, ptr_output);
+ if (!ptr_server->list->channels)
+ return WEECHAT_RC_OK;
+
+ irc_list_buffer_refresh (ptr_server, 1);
+
+ return WEECHAT_RC_OK;
+}
+
+/*
+ * Resets lists used by list buffer.
+ */
+
+void
+irc_list_reset (struct t_irc_server *server)
+{
+ if (!server)
+ return;
+
+ if (server->list->channels)
+ weechat_arraylist_clear (server->list->channels);
+ if (server->list->filter_channels)
+ weechat_arraylist_clear (server->list->filter_channels);
+ server->list->name_max_length = 0;
+ if (!server->list->sort)
+ {
+ irc_list_set_sort (
+ server,
+ weechat_config_string (irc_config_look_list_buffer_sort));
+ }
+ server->list->selected_line = 0;
+}
+
+/*
+ * Frees a list structure in a server.
+ */
+
+struct t_irc_list *
+irc_list_alloc ()
+{
+ struct t_irc_list *list;
+
+ list = malloc (sizeof (*list));
+ if (!list)
+ return NULL;
+
+ list->buffer = NULL;
+ list->channels = NULL;
+ list->filter_channels = NULL;
+ list->name_max_length = 0;
+ list->filter = NULL;
+ list->sort = NULL;
+ list->sort_fields = NULL;
+ list->sort_fields_count = 0;
+ list->selected_line = 0;
+
+ return list;
+}
+
+/*
+ * Frees a list structure in a server.
+ */
+
+void
+irc_list_free (struct t_irc_server *server)
+{
+ if (!server || !server->list)
+ return;
+
+ if (server->list->buffer)
+ weechat_buffer_close (server->list->buffer);
+ if (server->list->channels)
+ weechat_arraylist_free (server->list->channels);
+ if (server->list->filter_channels)
+ weechat_arraylist_free (server->list->filter_channels);
+ if (server->list->filter)
+ free (server->list->filter);
+ if (server->list->sort)
+ free (server->list->sort);
+ if (server->list->sort_fields)
+ weechat_string_free_split (server->list->sort_fields);
+
+ free (server->list);
+ server->list = NULL;
+}
+
+/*
+ * Returns hdata for irc_list_channel.
+ */
+
+struct t_hdata *
+irc_list_hdata_list_channel_cb (const void *pointer, void *data,
+ const char *hdata_name)
+{
+ struct t_hdata *hdata;
+
+ /* make C compiler happy */
+ (void) pointer;
+ (void) data;
+
+ hdata = weechat_hdata_new (hdata_name, NULL, NULL, 0, 0, NULL, NULL);
+ if (hdata)
+ {
+ WEECHAT_HDATA_VAR(struct t_irc_list_channel, name, STRING, 0, NULL, NULL);
+ WEECHAT_HDATA_VAR(struct t_irc_list_channel, name2, STRING, 0, NULL, NULL);
+ WEECHAT_HDATA_VAR(struct t_irc_list_channel, users, INTEGER, 0, NULL, NULL);
+ WEECHAT_HDATA_VAR(struct t_irc_list_channel, topic, STRING, 0, NULL, NULL);
+ }
+ return hdata;
+}
+
+/*
+ * Returns hdata for irc_list.
+ */
+
+struct t_hdata *
+irc_list_hdata_list_cb (const void *pointer, void *data, const char *hdata_name)
+{
+ struct t_hdata *hdata;
+
+ /* make C compiler happy */
+ (void) pointer;
+ (void) data;
+
+ hdata = weechat_hdata_new (hdata_name, NULL, NULL, 0, 0, NULL, NULL);
+ if (hdata)
+ {
+ WEECHAT_HDATA_VAR(struct t_irc_list, buffer, POINTER, 0, NULL, "buffer");
+ WEECHAT_HDATA_VAR(struct t_irc_list, channels, POINTER, 0, NULL, NULL);
+ WEECHAT_HDATA_VAR(struct t_irc_list, filter_channels, POINTER, 0, NULL, NULL);
+ WEECHAT_HDATA_VAR(struct t_irc_list, name_max_length, INTEGER, 0, NULL, NULL);
+ WEECHAT_HDATA_VAR(struct t_irc_list, filter, STRING, 0, NULL, NULL);
+ WEECHAT_HDATA_VAR(struct t_irc_list, sort, STRING, 0, NULL, NULL);
+ WEECHAT_HDATA_VAR(struct t_irc_list, sort_fields, POINTER, 0, NULL, NULL);
+ WEECHAT_HDATA_VAR(struct t_irc_list, sort_fields_count, INTEGER, 0, NULL, NULL);
+ WEECHAT_HDATA_VAR(struct t_irc_list, selected_line, INTEGER, 0, NULL, NULL);
+ }
+ return hdata;
+}
+
+/*
+ * Callback called when a mouse action occurs in irc list buffer.
+ */
+
+int
+irc_list_mouse_hsignal_cb (const void *pointer, void *data, const char *signal,
+ struct t_hashtable *hashtable)
+{
+ const char *ptr_key, *ptr_chat_line_y, *ptr_buffer_pointer;
+ struct t_gui_buffer *ptr_buffer;
+ unsigned long value;
+ char str_command[1024];
+ int rc;
+
+ /* make C compiler happy */
+ (void) pointer;
+ (void) data;
+ (void) signal;
+
+ ptr_key = weechat_hashtable_get (hashtable, "_key");
+ ptr_buffer_pointer = weechat_hashtable_get (hashtable, "_buffer");
+ ptr_chat_line_y = weechat_hashtable_get (hashtable, "_chat_line_y");
+
+ if (!ptr_key || !ptr_buffer_pointer || !ptr_chat_line_y)
+ return WEECHAT_RC_OK;
+
+ rc = sscanf (ptr_buffer_pointer, "%lx", &value);
+ if ((rc == EOF) || (rc == 0))
+ return WEECHAT_RC_OK;
+ ptr_buffer = (struct t_gui_buffer *)value;
+ if (!ptr_buffer)
+ return WEECHAT_RC_OK;
+
+ snprintf (str_command, sizeof (str_command),
+ "/list -go %s",
+ ptr_chat_line_y);
+ weechat_command (ptr_buffer, str_command);
+
+ if (weechat_string_match (ptr_key, "button2*", 1))
+ weechat_command (ptr_buffer, "/list -join");
+
+ return WEECHAT_RC_OK;
+}
+
+/*
+ * Initializes irc list.
+ */
+
+void
+irc_list_init ()
+{
+ struct t_hashtable *keys;
+
+ irc_list_filter_hashtable_pointers = weechat_hashtable_new (
+ 8,
+ WEECHAT_HASHTABLE_STRING,
+ WEECHAT_HASHTABLE_POINTER,
+ NULL, NULL);
+ irc_list_filter_hashtable_extra_vars = weechat_hashtable_new (
+ 32,
+ WEECHAT_HASHTABLE_STRING,
+ WEECHAT_HASHTABLE_STRING,
+ NULL, NULL);
+ irc_list_filter_hashtable_options = weechat_hashtable_new (
+ 8,
+ WEECHAT_HASHTABLE_STRING,
+ WEECHAT_HASHTABLE_STRING,
+ NULL, NULL);
+ if (irc_list_filter_hashtable_options)
+ {
+ weechat_hashtable_set (irc_list_filter_hashtable_options,
+ "type", "condition");
+ }
+
+ weechat_hook_hsignal (IRC_LIST_MOUSE_HSIGNAL,
+ &irc_list_mouse_hsignal_cb, NULL, NULL);
+
+ keys = weechat_hashtable_new (32,
+ WEECHAT_HASHTABLE_STRING,
+ WEECHAT_HASHTABLE_STRING,
+ NULL, NULL);
+ if (keys)
+ {
+ weechat_hashtable_set (
+ keys,
+ "@chat(" IRC_PLUGIN_NAME ".list_*):button1",
+ "/window ${_window_number};/list -go ${_chat_line_y}");
+ weechat_hashtable_set (
+ keys,
+ "@chat(" IRC_PLUGIN_NAME ".list_*):button2*",
+ "hsignal:" IRC_LIST_MOUSE_HSIGNAL);
+ weechat_hashtable_set (
+ keys,
+ "@chat(" IRC_PLUGIN_NAME ".list_*):wheelup",
+ "/list -up 5");
+ weechat_hashtable_set (
+ keys,
+ "@chat(" IRC_PLUGIN_NAME ".list_*):wheeldown",
+ "/list -down 5");
+ weechat_hashtable_set (keys, "__quiet", "1");
+ weechat_key_bind ("mouse", keys);
+ weechat_hashtable_free (keys);
+ }
+}
+
+/*
+ * Ends irc list.
+ */
+
+void
+irc_list_end ()
+{
+ if (irc_list_filter_hashtable_pointers)
+ {
+ weechat_hashtable_free (irc_list_filter_hashtable_pointers);
+ irc_list_filter_hashtable_pointers = NULL;
+ }
+ if (irc_list_filter_hashtable_extra_vars)
+ {
+ weechat_hashtable_free (irc_list_filter_hashtable_extra_vars);
+ irc_list_filter_hashtable_extra_vars = NULL;
+ }
+ if (irc_list_filter_hashtable_options)
+ {
+ weechat_hashtable_free (irc_list_filter_hashtable_options);
+ irc_list_filter_hashtable_options = NULL;
+ }
+}
diff --git a/src/plugins/irc/irc-list.h b/src/plugins/irc/irc-list.h
new file mode 100644
index 000000000..d9bc6413d
--- /dev/null
+++ b/src/plugins/irc/irc-list.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2023 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_LIST_H
+#define WEECHAT_PLUGIN_IRC_LIST_H
+
+#include <regex.h>
+
+#define IRC_LIST_MOUSE_HSIGNAL "irc_list_mouse"
+
+struct t_irc_server;
+
+struct t_irc_list_channel
+{
+ char *name; /* channel name */
+ char *name2; /* channel name without prefix ('#') */
+ int users; /* number of users in the channel */
+ char *topic; /* channel topic */
+};
+
+struct t_irc_list
+{
+ struct t_gui_buffer *buffer; /* buffer for /list */
+ struct t_arraylist *channels; /* channels received in /list reply */
+ struct t_arraylist *filter_channels; /* filtered channels */
+ int name_max_length; /* max length for channel name */
+ char *filter; /* filter for channels */
+ char *sort; /* sort for channels */
+ char **sort_fields; /* sort fields */
+ int sort_fields_count; /* number of sort fields */
+ int selected_line; /* selected line */
+};
+
+extern void irc_list_buffer_set_title (struct t_irc_server *server);
+extern void irc_list_buffer_refresh (struct t_irc_server *server, int clear);
+extern int irc_list_window_scrolled_cb (const void *pointer, void *data,
+ const char *signal,
+ const char *type_data,
+ void *signal_data);
+extern void irc_list_move_line_relative (struct t_irc_server *server,
+ int num_lines);
+extern void irc_list_move_line_absolute (struct t_irc_server *server,
+ int line_number);
+extern void irc_list_scroll_horizontal (struct t_irc_server *server,
+ int percent);
+extern void irc_list_join_channel (struct t_irc_server *server);
+extern int irc_list_buffer_input_data (struct t_gui_buffer *buffer,
+ const char *input_data);
+extern struct t_gui_buffer *irc_list_create_buffer (struct t_irc_server *server);
+extern int irc_list_hsignal_redirect_list_cb (const void *pointer,
+ void *data,
+ const char *signal,
+ struct t_hashtable *hashtable);
+extern void irc_list_reset (struct t_irc_server *server);
+extern struct t_irc_list *irc_list_alloc ();
+extern void irc_list_free (struct t_irc_server *server);
+extern struct t_hdata *irc_list_hdata_list_channel_cb (const void *pointer,
+ void *data,
+ const char *hdata_name);
+extern struct t_hdata *irc_list_hdata_list_cb (const void *pointer, void *data,
+ const char *hdata_name);
+extern void irc_list_init ();
+extern void irc_list_end ();
+
+#endif /* WEECHAT_PLUGIN_IRC_LIST_H */
diff --git a/src/plugins/irc/irc-server.c b/src/plugins/irc/irc-server.c
index e76627007..5f468d0eb 100644
--- a/src/plugins/irc/irc-server.c
+++ b/src/plugins/irc/irc-server.c
@@ -59,6 +59,7 @@
#include "irc-command.h"
#include "irc-config.h"
#include "irc-input.h"
+#include "irc-list.h"
#include "irc-message.h"
#include "irc-nick.h"
#include "irc-notify.h"
@@ -1740,6 +1741,7 @@ irc_server_alloc (const char *name)
weechat_config_integer (irc_config_network_lag_check);
new_server->lag_last_refresh = 0;
new_server->cmd_list_regexp = NULL;
+ new_server->list = irc_list_alloc (new_server);
new_server->last_user_message = 0;
new_server->last_away_check = 0;
new_server->last_data_purge = 0;
@@ -2325,6 +2327,8 @@ irc_server_free_data (struct t_irc_server *server)
regfree (server->cmd_list_regexp);
free (server->cmd_list_regexp);
}
+ if (server->list)
+ irc_list_free (server);
if (server->buffer_as_string)
free (server->buffer_as_string);
}
@@ -6474,6 +6478,7 @@ irc_server_hdata_server_cb (const void *pointer, void *data,
WEECHAT_HDATA_VAR(struct t_irc_server, lag_next_check, TIME, 0, NULL, NULL);
WEECHAT_HDATA_VAR(struct t_irc_server, lag_last_refresh, TIME, 0, NULL, NULL);
WEECHAT_HDATA_VAR(struct t_irc_server, cmd_list_regexp, POINTER, 0, NULL, NULL);
+ WEECHAT_HDATA_VAR(struct t_irc_server, list, POINTER, 0, NULL, "irc_list");
WEECHAT_HDATA_VAR(struct t_irc_server, last_user_message, TIME, 0, NULL, NULL);
WEECHAT_HDATA_VAR(struct t_irc_server, last_away_check, TIME, 0, NULL, NULL);
WEECHAT_HDATA_VAR(struct t_irc_server, last_data_purge, TIME, 0, NULL, NULL);
@@ -7255,6 +7260,13 @@ irc_server_print_log ()
weechat_log_printf (" lag_next_check. . . . . . : %lld", (long long)ptr_server->lag_next_check);
weechat_log_printf (" lag_last_refresh. . . . . : %lld", (long long)ptr_server->lag_last_refresh);
weechat_log_printf (" cmd_list_regexp . . . . . : 0x%lx", ptr_server->cmd_list_regexp);
+ weechat_log_printf (" list. . . . . . . . . . . : 0x%lx", ptr_server->list);
+ if (ptr_server->list)
+ {
+ weechat_log_printf (" buffer. . . . . . . . . : 0x%lx", ptr_server->list->buffer);
+ weechat_log_printf (" channels. . . . . . . . : 0x%lx", ptr_server->list->channels);
+ weechat_log_printf (" filter_channels . . . . : 0x%lx", ptr_server->list->filter_channels);
+ }
weechat_log_printf (" last_user_message . . . . : %lld", (long long)ptr_server->last_user_message);
weechat_log_printf (" last_away_check . . . . . : %lld", (long long)ptr_server->last_away_check);
weechat_log_printf (" last_data_purge . . . . . : %lld", (long long)ptr_server->last_data_purge);
diff --git a/src/plugins/irc/irc-server.h b/src/plugins/irc/irc-server.h
index 8f9323d15..f26a4437e 100644
--- a/src/plugins/irc/irc-server.h
+++ b/src/plugins/irc/irc-server.h
@@ -280,6 +280,7 @@ struct t_irc_server
time_t lag_next_check; /* time for next check */
time_t lag_last_refresh; /* last refresh of lag item */
regex_t *cmd_list_regexp; /* compiled Regular Expression for /list */
+ struct t_irc_list *list; /* /list buffer management */
time_t last_user_message; /* time of last user message (anti flood)*/
time_t last_away_check; /* time of last away check on server */
time_t last_data_purge; /* time of last purge (some hashtables) */
diff --git a/src/plugins/irc/irc-upgrade.c b/src/plugins/irc/irc-upgrade.c
index 0ca19852d..53f074526 100644
--- a/src/plugins/irc/irc-upgrade.c
+++ b/src/plugins/irc/irc-upgrade.c
@@ -30,6 +30,7 @@
#include "irc-channel.h"
#include "irc-config.h"
#include "irc-input.h"
+#include "irc-list.h"
#include "irc-modelist.h"
#include "irc-nick.h"
#include "irc-notify.h"
@@ -323,6 +324,15 @@ irc_upgrade_set_buffer_callbacks ()
ptr_server);
}
}
+ if (type && (strcmp (type, "irc_list") == 0))
+ {
+ ptr_server = irc_server_search (
+ weechat_buffer_get_string (ptr_buffer,
+ "localvar_server"));
+ if (ptr_server)
+ ptr_server->list->buffer = ptr_buffer;
+ irc_list_buffer_refresh (ptr_server, 1);
+ }
if (strcmp (weechat_infolist_string (infolist, "name"),
IRC_RAW_BUFFER_NAME) == 0)
{
diff --git a/src/plugins/irc/irc.c b/src/plugins/irc/irc.c
index bd03193c5..a978530c4 100644
--- a/src/plugins/irc/irc.c
+++ b/src/plugins/irc/irc.c
@@ -37,6 +37,7 @@
#include "irc-ignore.h"
#include "irc-info.h"
#include "irc-input.h"
+#include "irc-list.h"
#include "irc-nick.h"
#include "irc-notify.h"
#include "irc-protocol.h"
@@ -197,6 +198,8 @@ weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[])
irc_config_read ();
+ irc_list_init ();
+
irc_raw_init ();
irc_command_init ();
@@ -223,12 +226,16 @@ weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[])
&irc_input_send_cb, NULL, NULL);
weechat_hook_signal ("typing_self_*",
&irc_typing_signal_typing_self_cb, NULL, NULL);
+ weechat_hook_signal ("window_scrolled",
+ &irc_list_window_scrolled_cb, NULL, NULL);
/* hook hsignals for redirection */
weechat_hook_hsignal ("irc_redirect_pattern",
&irc_redirect_pattern_hsignal_cb, NULL, NULL);
weechat_hook_hsignal ("irc_redirect_command",
&irc_redirect_command_hsignal_cb, NULL, NULL);
+ weechat_hook_hsignal ("irc_redirection_server_*_list",
+ &irc_list_hsignal_redirect_list_cb, NULL, NULL);
/* modifiers */
weechat_hook_modifier ("irc_color_decode",
@@ -322,6 +329,8 @@ weechat_plugin_end (struct t_weechat_plugin *plugin)
irc_ignore_free_all ();
+ irc_list_end ();
+
irc_raw_end ();
irc_server_free_all ();