diff options
author | Sébastien Helleu <flashcode@flashtux.org> | 2023-07-14 14:27:23 +0200 |
---|---|---|
committer | Sébastien Helleu <flashcode@flashtux.org> | 2023-08-12 13:05:49 +0200 |
commit | 2f1de098bd3a44eaf0cfccb2c126250bb50f11b9 (patch) | |
tree | 03c6e6e5cf4b233d51b92f3542ed90636c98a202 /src | |
parent | d25a4213fecf8abccfecda4229fe85bfcf4a51b7 (diff) | |
download | weechat-2f1de098bd3a44eaf0cfccb2c126250bb50f11b9.zip |
irc: add buffer for /list reply (closes #1972)
New options:
- irc.color.list_buffer_line_selected
- irc.color.list_buffer_line_selected_bg
- irc.look.list_buffer_sort
- irc.look.list_buffer_scroll_horizontal
- irc.look.new_list_position
- irc.look.list_buffer_topic_strip_colors
Diffstat (limited to 'src')
-rw-r--r-- | src/plugins/fset/fset-buffer.c | 2 | ||||
-rw-r--r-- | src/plugins/irc/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/plugins/irc/irc-buffer.c | 180 | ||||
-rw-r--r-- | src/plugins/irc/irc-buffer.h | 3 | ||||
-rw-r--r-- | src/plugins/irc/irc-channel.c | 91 | ||||
-rw-r--r-- | src/plugins/irc/irc-command.c | 190 | ||||
-rw-r--r-- | src/plugins/irc/irc-config.c | 83 | ||||
-rw-r--r-- | src/plugins/irc/irc-config.h | 6 | ||||
-rw-r--r-- | src/plugins/irc/irc-info.c | 7 | ||||
-rw-r--r-- | src/plugins/irc/irc-input.c | 7 | ||||
-rw-r--r-- | src/plugins/irc/irc-list.c | 1309 | ||||
-rw-r--r-- | src/plugins/irc/irc-list.h | 81 | ||||
-rw-r--r-- | src/plugins/irc/irc-server.c | 12 | ||||
-rw-r--r-- | src/plugins/irc/irc-server.h | 1 | ||||
-rw-r--r-- | src/plugins/irc/irc-upgrade.c | 10 | ||||
-rw-r--r-- | src/plugins/irc/irc.c | 9 |
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 */ + ¶ms, + &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 (); |