diff options
author | Simmo Saan <simmo.saan@gmail.com> | 2018-03-24 17:01:50 +0100 |
---|---|---|
committer | Sébastien Helleu <flashcode@flashtux.org> | 2018-03-24 17:01:50 +0100 |
commit | d77e1ea49950f1f537194368cc4d003bb8667d41 (patch) | |
tree | 62c4cddaa9af9f59417e3d262b05b10e012d13f8 | |
parent | b2f971d4b046ae49b01f926f5617a0542c21d5d3 (diff) | |
download | weechat-d77e1ea49950f1f537194368cc4d003bb8667d41.zip |
irc: add indexed ban list, add completion for /unban and /unquiet (closes #597, task #11374, task #10876)
-rw-r--r-- | doc/en/weechat_dev.en.adoc | 1 | ||||
-rw-r--r-- | src/plugins/irc/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/plugins/irc/Makefile.am | 2 | ||||
-rw-r--r-- | src/plugins/irc/irc-channel.c | 18 | ||||
-rw-r--r-- | src/plugins/irc/irc-channel.h | 3 | ||||
-rw-r--r-- | src/plugins/irc/irc-command.c | 32 | ||||
-rw-r--r-- | src/plugins/irc/irc-completion.c | 46 | ||||
-rw-r--r-- | src/plugins/irc/irc-info.c | 216 | ||||
-rw-r--r-- | src/plugins/irc/irc-mode.c | 23 | ||||
-rw-r--r-- | src/plugins/irc/irc-mode.h | 1 | ||||
-rw-r--r-- | src/plugins/irc/irc-modelist.c | 495 | ||||
-rw-r--r-- | src/plugins/irc/irc-modelist.h | 90 | ||||
-rw-r--r-- | src/plugins/irc/irc-protocol.c | 178 | ||||
-rw-r--r-- | src/plugins/irc/irc-upgrade.c | 72 | ||||
-rw-r--r-- | src/plugins/irc/irc-upgrade.h | 2 |
15 files changed, 1160 insertions, 20 deletions
diff --git a/doc/en/weechat_dev.en.adoc b/doc/en/weechat_dev.en.adoc index 3fe02b9ac..e6a815fc3 100644 --- a/doc/en/weechat_dev.en.adoc +++ b/doc/en/weechat_dev.en.adoc @@ -253,6 +253,7 @@ WeeChat "core" is located in following directories: | irc-input.c | Input of commands/text. | irc-message.c | Functions to manipulate IRC messages. | irc-mode.c | Functions about channel/nick modes. +| irc-modelist.c | IRC channel mode lists (+b, +e, +I) | irc-msgbuffer.c | Target buffer for IRC messages. | irc-nick.c | IRC nicks. | irc-notify.c | IRC notify lists. diff --git a/src/plugins/irc/CMakeLists.txt b/src/plugins/irc/CMakeLists.txt index 4badf8e7d..f205adbc5 100644 --- a/src/plugins/irc/CMakeLists.txt +++ b/src/plugins/irc/CMakeLists.txt @@ -33,6 +33,7 @@ irc-info.c irc-info.h irc-input.c irc-input.h irc-message.c irc-message.h irc-mode.c irc-mode.h +irc-modelist.c irc-modelist.h irc-msgbuffer.c irc-msgbuffer.h irc-nick.c irc-nick.h irc-notify.c irc-notify.h diff --git a/src/plugins/irc/Makefile.am b/src/plugins/irc/Makefile.am index af56b2c10..966dc6813 100644 --- a/src/plugins/irc/Makefile.am +++ b/src/plugins/irc/Makefile.am @@ -53,6 +53,8 @@ irc_la_SOURCES = irc.c \ irc-message.h \ irc-mode.c \ irc-mode.h \ + irc-modelist.c \ + irc-modelist.h \ irc-msgbuffer.c \ irc-msgbuffer.h \ irc-nick.c \ diff --git a/src/plugins/irc/irc-channel.c b/src/plugins/irc/irc-channel.c index 4b6158ee6..e93b1d373 100644 --- a/src/plugins/irc/irc-channel.c +++ b/src/plugins/irc/irc-channel.c @@ -33,6 +33,7 @@ #include "irc-color.h" #include "irc-command.h" #include "irc-config.h" +#include "irc-modelist.h" #include "irc-nick.h" #include "irc-server.h" #include "irc-input.h" @@ -426,6 +427,7 @@ irc_channel_new (struct t_irc_server *server, int channel_type, { struct t_irc_channel *new_channel; struct t_gui_buffer *ptr_buffer; + const char *chanmodes; /* create buffer for channel (or use existing one) */ ptr_buffer = irc_channel_create_buffer (server, channel_type, @@ -479,6 +481,12 @@ irc_channel_new (struct t_irc_server *server, int channel_type, new_channel->nicks_speaking[1] = NULL; new_channel->nicks_speaking_time = NULL; new_channel->last_nick_speaking_time = NULL; + new_channel->modelists = NULL; + new_channel->last_modelist = NULL; + for (chanmodes = irc_server_get_chanmodes (server); chanmodes[0] && chanmodes[0] != ','; chanmodes++) + { + irc_modelist_new (new_channel, chanmodes[0]); + } new_channel->join_smart_filtered = NULL; new_channel->buffer = ptr_buffer; new_channel->buffer_as_string = NULL; @@ -1387,6 +1395,7 @@ irc_channel_free (struct t_irc_server *server, struct t_irc_channel *channel) /* free linked lists */ irc_nick_free_all (server, channel); + irc_modelist_free_all (channel); /* free channel data */ if (channel->name) @@ -1472,6 +1481,8 @@ irc_channel_hdata_channel_cb (const void *pointer, void *data, WEECHAT_HDATA_VAR(struct t_irc_channel, nicks_speaking, POINTER, 0, NULL, NULL); WEECHAT_HDATA_VAR(struct t_irc_channel, nicks_speaking_time, POINTER, 0, NULL, "irc_channel_speaking"); WEECHAT_HDATA_VAR(struct t_irc_channel, last_nick_speaking_time, POINTER, 0, NULL, "irc_channel_speaking"); + WEECHAT_HDATA_VAR(struct t_irc_channel, modelists, POINTER, 0, NULL, "irc_modelist"); + WEECHAT_HDATA_VAR(struct t_irc_channel, last_modelist, POINTER, 0, NULL, "irc_modelist"); WEECHAT_HDATA_VAR(struct t_irc_channel, join_smart_filtered, HASHTABLE, 0, NULL, NULL); WEECHAT_HDATA_VAR(struct t_irc_channel, buffer, POINTER, 0, NULL, "buffer"); WEECHAT_HDATA_VAR(struct t_irc_channel, buffer_as_string, STRING, 0, NULL, NULL); @@ -1629,6 +1640,7 @@ irc_channel_print_log (struct t_irc_channel *channel) struct t_irc_channel_speaking *ptr_nick_speaking; int i, index; struct t_irc_nick *ptr_nick; + struct t_irc_modelist *ptr_modelist; weechat_log_printf (""); weechat_log_printf (" => channel %s (addr:0x%lx):", channel->name, channel); @@ -1656,6 +1668,8 @@ irc_channel_print_log (struct t_irc_channel *channel) weechat_log_printf (" nicks_speaking[1]. . . . : 0x%lx", channel->nicks_speaking[1]); weechat_log_printf (" nicks_speaking_time. . . : 0x%lx", channel->nicks_speaking_time); weechat_log_printf (" last_nick_speaking_time. : 0x%lx", channel->last_nick_speaking_time); + weechat_log_printf (" modelists. . . . . . . . : 0x%lx", channel->modelists); + weechat_log_printf (" last_modelist. . . . . . : 0x%lx", channel->last_modelist); weechat_log_printf (" join_smart_filtered. . . : 0x%lx (hashtable: '%s')", channel->join_smart_filtered, weechat_hashtable_get_string (channel->join_smart_filtered, @@ -1695,4 +1709,8 @@ irc_channel_print_log (struct t_irc_channel *channel) { irc_nick_print_log (ptr_nick); } + for (ptr_modelist = channel->modelists; ptr_modelist; ptr_modelist = ptr_modelist->next_modelist) + { + irc_modelist_print_log (ptr_modelist); + } } diff --git a/src/plugins/irc/irc-channel.h b/src/plugins/irc/irc-channel.h index 6326edf61..7434acff4 100644 --- a/src/plugins/irc/irc-channel.h +++ b/src/plugins/irc/irc-channel.h @@ -32,6 +32,7 @@ #define IRC_CHANNEL_NICKS_SPEAKING_LIMIT 128 struct t_irc_server; +struct t_irc_modelist; struct t_irc_channel_speaking { @@ -71,6 +72,8 @@ struct t_irc_channel struct t_irc_channel_speaking *nicks_speaking_time; /* for smart filter */ /* of join/part/quit messages */ struct t_irc_channel_speaking *last_nick_speaking_time; + struct t_irc_modelist *modelists; /* modelists in the channel */ + struct t_irc_modelist *last_modelist; /* last modelist in the channel */ struct t_hashtable *join_smart_filtered; /* smart filtered joins */ struct t_gui_buffer *buffer; /* buffer allocated for channel */ char *buffer_as_string; /* used to return buffer info */ diff --git a/src/plugins/irc/irc-command.c b/src/plugins/irc/irc-command.c index 7fb56d37c..0b9a81a1e 100644 --- a/src/plugins/irc/irc-command.c +++ b/src/plugins/irc/irc-command.c @@ -42,6 +42,7 @@ #include "irc-input.h" #include "irc-message.h" #include "irc-mode.h" +#include "irc-modelist.h" #include "irc-msgbuffer.h" #include "irc-nick.h" #include "irc-notify.h" @@ -238,6 +239,10 @@ irc_command_mode_masks (struct t_irc_server *server, char modes[128+1], masks[1024], *mask; struct t_irc_channel *ptr_channel; struct t_irc_nick *ptr_nick; + struct t_irc_modelist *ptr_modelist; + struct t_irc_modelist_item *ptr_item; + long number; + char *error; if (irc_mode_get_chanmode_type (server, mode[0]) != 'A') { @@ -265,15 +270,30 @@ irc_command_mode_masks (struct t_irc_server *server, masks[0] = '\0'; ptr_channel = irc_channel_search (server, channel_name); + ptr_modelist = irc_modelist_search (ptr_channel, mode[0]); for (; argv[pos_masks]; pos_masks++) { mask = NULL; - /* use default_ban_mask for nick arguments */ if (ptr_channel) { - if (!strchr (argv[pos_masks], '!') + /* use modelist item for number arguments */ + if (set[0] == '-' && ptr_modelist) + { + error = NULL; + number = strtol (argv[pos_masks], &error, 10); + if (error && !error[0]) + { + ptr_item = irc_modelist_item_number (ptr_modelist, number - 1); + if (ptr_item) + mask = strdup (ptr_item->mask); + } + } + + /* use default_ban_mask for nick arguments */ + if (!mask + && !strchr (argv[pos_masks], '!') && !strchr (argv[pos_masks], '@')) { ptr_nick = irc_nick_search (server, ptr_channel, @@ -6957,15 +6977,15 @@ irc_command_init () N_("unban nicks or hosts"), N_("[<channel>] <nick> [<nick>...]"), N_("channel: channel name\n" - " nick: nick or host"), - NULL, &irc_command_unban, NULL, NULL); + " nick: nick, host or ban number"), + "%(irc_modelist:b)", &irc_command_unban, NULL, NULL); weechat_hook_command ( "unquiet", N_("unquiet nicks or hosts"), N_("[<channel>] <nick> [<nick>...]"), N_("channel: channel name\n" - " nick: nick or host"), - "%(irc_channel_nicks_hosts)", &irc_command_unquiet, NULL, NULL); + " nick: nick, host or quiet number"), + "%(irc_modelist:q)", &irc_command_unquiet, NULL, NULL); weechat_hook_command ( "userhost", N_("return a list of information about nicks"), diff --git a/src/plugins/irc/irc-completion.c b/src/plugins/irc/irc-completion.c index b9d53633e..e3b2f834d 100644 --- a/src/plugins/irc/irc-completion.c +++ b/src/plugins/irc/irc-completion.c @@ -31,6 +31,7 @@ #include "irc-completion.h" #include "irc-config.h" #include "irc-ignore.h" +#include "irc-modelist.h" #include "irc-nick.h" #include "irc-notify.h" #include "irc-server.h" @@ -421,6 +422,47 @@ irc_completion_channel_nicks_hosts_cb (const void *pointer, void *data, } /* + * Adds modelist masks current channel to completion list. + */ + +int +irc_completion_modelist_cb (const void *pointer, void *data, + const char *completion_item, + struct t_gui_buffer *buffer, + struct t_gui_completion *completion) +{ + char *pos; + struct t_irc_modelist *ptr_modelist; + struct t_irc_modelist_item *ptr_item; + + IRC_BUFFER_GET_SERVER_CHANNEL(buffer); + + /* make C compiler happy */ + (void) pointer; + (void) data; + + pos = strchr (completion_item, ':'); + if (pos) + pos++; + + if (pos && pos[0] && ptr_channel) + { + ptr_modelist = irc_modelist_search (ptr_channel, pos[0]); + if (ptr_modelist) + { + for (ptr_item = ptr_modelist->items; ptr_item; ptr_item = ptr_item->next_item) + { + weechat_hook_completion_list_add (completion, + ptr_item->mask, + 0, WEECHAT_LIST_POS_END); + } + } + } + + return WEECHAT_RC_OK; +} + +/* * Adds topic of current channel to completion list. */ @@ -758,6 +800,10 @@ irc_completion_init () weechat_hook_completion ("irc_channel_nicks_hosts", N_("nicks and hostnames of current IRC channel"), &irc_completion_channel_nicks_hosts_cb, NULL, NULL); + weechat_hook_completion ("irc_modelist", + N_("modelist masks of current IRC channel; " + "required argument: modelist mode"), + &irc_completion_modelist_cb, NULL, NULL); weechat_hook_completion ("irc_channel_topic", N_("topic of current IRC channel"), &irc_completion_channel_topic_cb, NULL, NULL); diff --git a/src/plugins/irc/irc-info.c b/src/plugins/irc/irc-info.c index 825d6740c..9f7b6eb42 100644 --- a/src/plugins/irc/irc-info.c +++ b/src/plugins/irc/irc-info.c @@ -30,6 +30,7 @@ #include "irc-config.h" #include "irc-ignore.h" #include "irc-message.h" +#include "irc-modelist.h" #include "irc-nick.h" #include "irc-notify.h" #include "irc-protocol.h" @@ -574,6 +575,203 @@ irc_info_infolist_irc_channel_cb (const void *pointer, void *data, } /* + * Returns IRC infolist "irc_modelist". + */ + +struct t_infolist * +irc_info_infolist_irc_modelist_cb (const void *pointer, void *data, + const char *infolist_name, + void *obj_pointer, const char *arguments) +{ + struct t_infolist *ptr_infolist; + struct t_irc_server *ptr_server; + struct t_irc_channel *ptr_channel; + struct t_irc_modelist *ptr_modelist; + char **argv; + int argc; + + /* make C compiler happy */ + (void) pointer; + (void) data; + (void) infolist_name; + + if (!arguments || !arguments[0]) + return NULL; + + ptr_server = NULL; + ptr_channel = NULL; + argv = weechat_string_split (arguments, ",", 0, 0, &argc); + if (!argv) + return NULL; + + if (argc >= 2) + { + ptr_server = irc_server_search (argv[0]); + if (!ptr_server) + { + weechat_string_free_split (argv); + return NULL; + } + ptr_channel = irc_channel_search (ptr_server, argv[1]); + if (!ptr_channel) + { + weechat_string_free_split (argv); + return NULL; + } + if (!obj_pointer && (argc >= 3)) + { + obj_pointer = irc_modelist_search (ptr_channel, argv[2][0]); + + if (!obj_pointer) + { + weechat_string_free_split (argv); + return NULL; + } + } + } + weechat_string_free_split (argv); + + if (!ptr_server || !ptr_channel) + return NULL; + + if (obj_pointer && !irc_modelist_valid (ptr_channel, obj_pointer)) + return NULL; + + ptr_infolist = weechat_infolist_new (); + if (!ptr_infolist) + return NULL; + + if (obj_pointer) + { + /* build list with only one modelist */ + if (!irc_modelist_add_to_infolist (ptr_infolist, obj_pointer)) + { + weechat_infolist_free (ptr_infolist); + return NULL; + } + return ptr_infolist; + } + else + { + /* build list with all modelists of channel */ + for (ptr_modelist = ptr_channel->modelists; ptr_modelist; + ptr_modelist = ptr_modelist->next_modelist) + { + if (!irc_modelist_add_to_infolist (ptr_infolist, ptr_modelist)) + { + weechat_infolist_free (ptr_infolist); + return NULL; + } + } + return ptr_infolist; + } + + return NULL; +} + +/* + * Returns IRC infolist "irc_modelist_item". + */ + +struct t_infolist * +irc_info_infolist_irc_modelist_item_cb (const void *pointer, void *data, + const char *infolist_name, + void *obj_pointer, const char *arguments) +{ + struct t_infolist *ptr_infolist; + struct t_irc_server *ptr_server; + struct t_irc_channel *ptr_channel; + struct t_irc_modelist *ptr_modelist; + struct t_irc_modelist_item *ptr_item; + char **argv; + int argc; + + /* make C compiler happy */ + (void) pointer; + (void) data; + (void) infolist_name; + + if (!arguments || !arguments[0]) + return NULL; + + ptr_server = NULL; + ptr_channel = NULL; + argv = weechat_string_split (arguments, ",", 0, 0, &argc); + if (!argv) + return NULL; + + if (argc >= 3) + { + ptr_server = irc_server_search (argv[0]); + if (!ptr_server) + { + weechat_string_free_split (argv); + return NULL; + } + ptr_channel = irc_channel_search (ptr_server, argv[1]); + if (!ptr_channel) + { + weechat_string_free_split (argv); + return NULL; + } + ptr_modelist = irc_modelist_search (ptr_channel, argv[2][0]); + if (!ptr_modelist) + { + weechat_string_free_split (argv); + return NULL; + } + if (!obj_pointer && (argc >= 4)) + { + obj_pointer = irc_modelist_item_number (ptr_modelist, atoi(argv[3])); + + if (!obj_pointer) + { + weechat_string_free_split (argv); + return NULL; + } + } + } + weechat_string_free_split (argv); + + if (!ptr_server || !ptr_channel || !ptr_modelist) + return NULL; + + if (obj_pointer && !irc_modelist_item_valid (ptr_modelist, obj_pointer)) + return NULL; + + ptr_infolist = weechat_infolist_new (); + if (!ptr_infolist) + return NULL; + + if (obj_pointer) + { + /* build list with only one modelist item */ + if (!irc_modelist_item_add_to_infolist (ptr_infolist, obj_pointer)) + { + weechat_infolist_free (ptr_infolist); + return NULL; + } + return ptr_infolist; + } + else + { + /* build list with all modelist items of modelist */ + for (ptr_item = ptr_modelist->items; ptr_item; + ptr_item = ptr_item->next_item) + { + if (!irc_modelist_item_add_to_infolist (ptr_infolist, ptr_item)) + { + weechat_infolist_free (ptr_infolist); + return NULL; + } + } + return ptr_infolist; + } + + return NULL; +} + +/* * Returns IRC infolist "irc_nick". */ @@ -920,6 +1118,18 @@ irc_info_init () N_("server,channel (channel is optional)"), &irc_info_infolist_irc_channel_cb, NULL, NULL); weechat_hook_infolist ( + "irc_modelist", + N_("list of channel mode lists for an IRC channel"), + N_("mode list pointer (optional)"), + N_("server,channel,type (type is optional)"), + &irc_info_infolist_irc_modelist_cb, NULL, NULL); + weechat_hook_infolist ( + "irc_modelist_item", + N_("list of channel mode list items for a channel mode list"), + N_("mode list item pointer (optional)"), + N_("server,channel,type,number (number is optional)"), + &irc_info_infolist_irc_modelist_item_cb, NULL, NULL); + weechat_hook_infolist ( "irc_nick", N_("list of nicks for an IRC channel"), N_("nick pointer (optional)"), @@ -949,6 +1159,12 @@ irc_info_init () "irc_nick", N_("irc nick"), &irc_nick_hdata_nick_cb, NULL, NULL); weechat_hook_hdata ( + "irc_modelist", N_("irc modelist"), + &irc_modelist_hdata_modelist_cb, NULL, NULL); + weechat_hook_hdata ( + "irc_modelist_item", N_("irc modelist item"), + &irc_modelist_hdata_item_cb, NULL, NULL); + weechat_hook_hdata ( "irc_channel", N_("irc channel"), &irc_channel_hdata_channel_cb, NULL, NULL); weechat_hook_hdata ( diff --git a/src/plugins/irc/irc-mode.c b/src/plugins/irc/irc-mode.c index b96e47f35..307527dcf 100644 --- a/src/plugins/irc/irc-mode.c +++ b/src/plugins/irc/irc-mode.c @@ -22,6 +22,7 @@ #include <stdlib.h> #include <stdio.h> #include <string.h> +#include <time.h> #include "../weechat-plugin.h" #include "irc.h" @@ -30,6 +31,7 @@ #include "irc-server.h" #include "irc-channel.h" #include "irc-nick.h" +#include "irc-modelist.h" /* @@ -317,12 +319,14 @@ irc_mode_smart_filtered (struct t_irc_server *server, char mode) int irc_mode_channel_set (struct t_irc_server *server, struct t_irc_channel *channel, + const char *host, const char *modes) { char *pos_args, *str_modes, set_flag, **argv, *pos, *ptr_arg, chanmode_type; int argc, current_arg, update_channel_modes, channel_modes_updated; int smart_filter; struct t_irc_nick *ptr_nick; + struct t_irc_modelist *ptr_modelist; if (!server || !channel || !modes) return 0; @@ -464,6 +468,25 @@ irc_mode_channel_set (struct t_irc_server *server, } } } + else if (chanmode_type == 'A') + { + /* modelist modes */ + ptr_modelist = irc_modelist_search (channel, pos[0]); + if (ptr_modelist) + { + if (set_flag == '+') + { + irc_modelist_item_new (ptr_modelist, ptr_arg, + host, time (NULL)); + } + else if (set_flag == '-') + { + irc_modelist_item_free (ptr_modelist, + irc_modelist_item_search (ptr_modelist, ptr_arg)); + } + } + } + if (update_channel_modes) { irc_mode_channel_update (server, channel, set_flag, diff --git a/src/plugins/irc/irc-mode.h b/src/plugins/irc/irc-mode.h index 3b29d0268..857a8a8fc 100644 --- a/src/plugins/irc/irc-mode.h +++ b/src/plugins/irc/irc-mode.h @@ -27,6 +27,7 @@ extern char irc_mode_get_chanmode_type (struct t_irc_server *server, char chanmode); extern int irc_mode_channel_set (struct t_irc_server *server, struct t_irc_channel *channel, + const char *host, const char *modes); extern void irc_mode_user_set (struct t_irc_server *server, const char *modes, int reset_modes); diff --git a/src/plugins/irc/irc-modelist.c b/src/plugins/irc/irc-modelist.c new file mode 100644 index 000000000..e9226c784 --- /dev/null +++ b/src/plugins/irc/irc-modelist.c @@ -0,0 +1,495 @@ +/* + * irc-modelist.c - channel mode list management for IRC plugin + * + * Copyright (C) 2015 Simmo Saan <simmo.saan@gmail.com> + * + * This file is part of WeeChat, the extensible chat client. + * + * WeeChat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * WeeChat is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WeeChat. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <stddef.h> +#include <unistd.h> +#include <stdio.h> +#include <string.h> +#include <time.h> + +#include "../weechat-plugin.h" +#include "irc.h" +#include "irc-channel.h" +#include "irc-modelist.h" + + +/* + * Checks if a modelist item pointer is valid for a modelist. + * + * Returns: + * 1: item exists for modelist + * 0: item does not exist for modelist + */ + +int +irc_modelist_item_valid (struct t_irc_modelist *modelist, struct t_irc_modelist_item *item) +{ + struct t_irc_modelist_item *ptr_item; + + if (!modelist || !item) + return 0; + + for (ptr_item = modelist->items; ptr_item; + ptr_item = ptr_item->next_item) + { + if (ptr_item == item) + return 1; + } + + /* item not found */ + return 0; +} + +/* + * Creates a new item in a modelist. + * + * Returns pointer to new item, NULL if error. + */ + +struct t_irc_modelist_item * +irc_modelist_item_new (struct t_irc_modelist *modelist, + const char *mask, const char *setter, time_t datetime) +{ + struct t_irc_modelist_item *new_item; + + /* alloc memory for new item */ + if ((new_item = malloc (sizeof (*new_item))) == NULL) + { + weechat_printf (NULL, + _("%s%s: cannot allocate new modelist item"), + weechat_prefix ("error"), IRC_PLUGIN_NAME); + return NULL; + } + + /* initialize new item */ + new_item->number = (modelist->last_item) ? modelist->last_item->number + 1 : 0; + new_item->mask = strdup (mask); + new_item->setter = (setter) ? strdup (setter) : NULL; + new_item->datetime = datetime; + + /* add new item to modelist */ + new_item->prev_item = modelist->last_item; + new_item->next_item = NULL; + if (modelist->items) + (modelist->last_item)->next_item = new_item; + else + modelist->items = new_item; + modelist->last_item = new_item; + + if (modelist->state == IRC_MODELIST_STATE_EMPTY || + modelist->state == IRC_MODELIST_STATE_RECEIVED) + modelist->state = IRC_MODELIST_STATE_MODIFIED; + + /* all is OK, return address of new item */ + return new_item; +} + +/* + * Frees an item and remove it from modelist. + */ + +void +irc_modelist_item_free (struct t_irc_modelist *modelist, struct t_irc_modelist_item *item) +{ + struct t_irc_modelist_item *new_items; + + if (!modelist || !item) + return; + + /* remove channel from channels list */ + if (modelist->last_item == item) + modelist->last_item = item->prev_item; + if (item->prev_item) + { + (item->prev_item)->next_item = item->next_item; + new_items = modelist->items; + } + else + new_items = item->next_item; + + if (item->next_item) + (item->next_item)->prev_item = item->prev_item; + + /* free item data */ + if (item->mask) + free (item->mask); + if (item->setter) + free (item->setter); + free (item); + + modelist->items = new_items; + + if (modelist->state == IRC_MODELIST_STATE_RECEIVED) + modelist->state = IRC_MODELIST_STATE_MODIFIED; +} + +/* + * Frees all items for a modelist. + */ + +void +irc_modelist_item_free_all (struct t_irc_modelist *modelist) +{ + while (modelist->items) + { + irc_modelist_item_free (modelist, modelist->items); + } + modelist->state = IRC_MODELIST_STATE_EMPTY; +} + +/* + * Searches for an item by mask. + * + * Returns pointer to item found, NULL if not found. + */ + +struct t_irc_modelist_item * +irc_modelist_item_search (struct t_irc_modelist *modelist, const char *mask) +{ + struct t_irc_modelist_item *ptr_item; + + if (!modelist || !mask) + return NULL; + + for (ptr_item = modelist->items; ptr_item; + ptr_item = ptr_item->next_item) + { + if (strcmp (ptr_item->mask, mask) == 0) + return ptr_item; + } + return NULL; +} + +/* + * Searches for an item by number. + * + * Returns pointer to item found, NULL if not found. + */ + +struct t_irc_modelist_item * +irc_modelist_item_number (struct t_irc_modelist *modelist, int number) +{ + struct t_irc_modelist_item *ptr_item; + + if (!modelist) + return NULL; + + for (ptr_item = modelist->items; ptr_item; + ptr_item = ptr_item->next_item) + { + if (ptr_item->number == number) + return ptr_item; + } + return NULL; +} + +/* + * Checks if a modelist pointer is valid for a channel. + * + * Returns: + * 1: modelist exists for channel + * 0: modelist does not exist for channel + */ + +int +irc_modelist_valid (struct t_irc_channel *channel, struct t_irc_modelist *modelist) +{ + struct t_irc_modelist *ptr_modelist; + + if (!channel || !modelist) + return 0; + + for (ptr_modelist = channel->modelists; ptr_modelist; + ptr_modelist = ptr_modelist->next_modelist) + { + if (ptr_modelist == modelist) + return 1; + } + + /* modelist not found */ + return 0; +} + +/* + * Creates a new modelist in a channel. + * + * Returns pointer to new modelist, NULL if error. + */ + +struct t_irc_modelist * +irc_modelist_new (struct t_irc_channel *channel, char type) +{ + struct t_irc_modelist *new_modelist; + + /* alloc memory for new modelist */ + if ((new_modelist = malloc (sizeof (*new_modelist))) == NULL) + { + weechat_printf (NULL, + _("%s%s: cannot allocate new modelist"), + weechat_prefix ("error"), IRC_PLUGIN_NAME); + return NULL; + } + + /* initialize new modelist */ + new_modelist->type = type; + new_modelist->state = IRC_MODELIST_STATE_EMPTY; + new_modelist->items = NULL; + new_modelist->last_item = NULL; + + /* add new modelist to channel */ + new_modelist->prev_modelist = channel->last_modelist; + new_modelist->next_modelist = NULL; + if (channel->modelists) + (channel->last_modelist)->next_modelist = new_modelist; + else + channel->modelists = new_modelist; + channel->last_modelist = new_modelist; + + /* all is OK, return address of new modelist */ + return new_modelist; +} + +/* + * Frees a modelist and remove it from channel. + */ + +void +irc_modelist_free (struct t_irc_channel *channel, struct t_irc_modelist *modelist) +{ + struct t_irc_modelist *new_modelists; + + if (!channel || !modelist) + return; + + /* remove modelist from channel modelists */ + if (channel->last_modelist == modelist) + channel->last_modelist = modelist->prev_modelist; + if (modelist->prev_modelist) + { + (modelist->prev_modelist)->next_modelist = modelist->next_modelist; + new_modelists = channel->modelists; + } + else + new_modelists = modelist->next_modelist; + + if (modelist->next_modelist) + (modelist->next_modelist)->prev_modelist = modelist->prev_modelist; + + /* free linked lists */ + irc_modelist_item_free_all (modelist); + + free (modelist); + + channel->modelists = new_modelists; +} + +/* + * Frees all modelists for a channel. + */ + +void +irc_modelist_free_all (struct t_irc_channel *channel) +{ + while (channel->modelists) + { + irc_modelist_free (channel, channel->modelists); + } +} + +/* + * Searches for a modelist by type. + * + * Returns pointer to modelist found, NULL if not found. + */ + +struct t_irc_modelist * +irc_modelist_search (struct t_irc_channel *channel, char type) +{ + struct t_irc_modelist *ptr_modelist; + + if (!channel) + return NULL; + + for (ptr_modelist = channel->modelists; ptr_modelist; + ptr_modelist = ptr_modelist->next_modelist) + { + if (ptr_modelist->type == type) + return ptr_modelist; + } + return NULL; +} + +/* + * Returns hdata for modelist item. + */ + +struct t_hdata * +irc_modelist_hdata_item_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, "prev_item", "next_item", + 0, 0, NULL, NULL); + if (hdata) + { + WEECHAT_HDATA_VAR(struct t_irc_modelist_item, number, INTEGER, 0, NULL, NULL); + WEECHAT_HDATA_VAR(struct t_irc_modelist_item, mask, STRING, 0, NULL, NULL); + WEECHAT_HDATA_VAR(struct t_irc_modelist_item, setter, STRING, 0, NULL, NULL); + WEECHAT_HDATA_VAR(struct t_irc_modelist_item, datetime, TIME, 0, NULL, NULL); + WEECHAT_HDATA_VAR(struct t_irc_modelist_item, prev_item, POINTER, 0, NULL, hdata_name); + WEECHAT_HDATA_VAR(struct t_irc_modelist_item, next_item, POINTER, 0, NULL, hdata_name); + } + return hdata; +} + +/* + * Returns hdata for modelist. + */ + +struct t_hdata * +irc_modelist_hdata_modelist_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, "prev_modelist", "next_modelist", + 0, 0, NULL, NULL); + if (hdata) + { + WEECHAT_HDATA_VAR(struct t_irc_modelist, type, CHAR, 0, NULL, NULL); + WEECHAT_HDATA_VAR(struct t_irc_modelist, state, INTEGER, 0, NULL, NULL); + WEECHAT_HDATA_VAR(struct t_irc_modelist, items, POINTER, 0, NULL, "irc_modelist_item"); + WEECHAT_HDATA_VAR(struct t_irc_modelist, last_item, POINTER, 0, NULL, "irc_modelist_item"); + WEECHAT_HDATA_VAR(struct t_irc_modelist, prev_modelist, POINTER, 0, NULL, hdata_name); + WEECHAT_HDATA_VAR(struct t_irc_modelist, next_modelist, POINTER, 0, NULL, hdata_name); + } + return hdata; +} + +/* + * Adds a modelist item in an infolist. + * + * Returns: + * 1: OK + * 0: error + */ + +int +irc_modelist_item_add_to_infolist (struct t_infolist *infolist, + struct t_irc_modelist_item *item) +{ + struct t_infolist_item *ptr_item; + + if (!infolist || !item) + return 0; + + ptr_item = weechat_infolist_new_item (infolist); + if (!ptr_item) + return 0; + + if (!weechat_infolist_new_var_integer (ptr_item, "number", item->number)) + return 0; + if (!weechat_infolist_new_var_string (ptr_item, "mask", item->mask)) + return 0; + if (!weechat_infolist_new_var_string (ptr_item, "setter", item->setter)) + return 0; + if (!weechat_infolist_new_var_time (ptr_item, "datetime", item->datetime)) + return 0; + + return 1; +} + +/* + * Adds a modelist in an infolist. + * + * Returns: + * 1: OK + * 0: error + */ + +int +irc_modelist_add_to_infolist (struct t_infolist *infolist, + struct t_irc_modelist *modelist) +{ + struct t_infolist_item *ptr_item; + char str_type[2]; + + if (!infolist || !modelist) + return 0; + + ptr_item = weechat_infolist_new_item (infolist); + if (!ptr_item) + return 0; + + str_type[0] = modelist->type; + str_type[1] = '\0'; + + if (!weechat_infolist_new_var_string (ptr_item, "type", str_type)) + return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "state", modelist->state)) + return 0; + + return 1; +} + +/* + * Prints modelist item infos in WeeChat log file (usually for crash dump). + */ + +void +irc_modelist_item_print_log (struct t_irc_modelist_item *item) +{ + weechat_log_printf (""); + weechat_log_printf (" => modelist item %d (addr:0x%lx):", item, item->number); + weechat_log_printf (" mask . . . . . . . . . . : '%s'", item->mask); + weechat_log_printf (" setter . . . . . . . . . : '%s'", item->setter); + weechat_log_printf (" datetime . . . . . . . . : '%s'", item->datetime); + weechat_log_printf (" prev_item . . . . . . . : 0x%lx", item->prev_item); + weechat_log_printf (" next_item . . . . . . . : 0x%lx", item->next_item); +} + +/* + * Prints modelist infos in WeeChat log file (usually for crash dump). + */ + +void +irc_modelist_print_log (struct t_irc_modelist *modelist) +{ + struct t_irc_modelist_item *ptr_item; + + weechat_log_printf (""); + weechat_log_printf (" => modelist %c (addr:0x%lx):", modelist->type, modelist); + weechat_log_printf (" state. . . . . . . . . . : %d", modelist->state); + weechat_log_printf (" prev_modelist . . . . . : 0x%lx", modelist->prev_modelist); + weechat_log_printf (" next_modelist . . . . . : 0x%lx", modelist->next_modelist); + for (ptr_item = modelist->items; ptr_item; ptr_item = ptr_item->next_item) + { + irc_modelist_item_print_log (ptr_item); + } +} diff --git a/src/plugins/irc/irc-modelist.h b/src/plugins/irc/irc-modelist.h new file mode 100644 index 000000000..1e709dd5a --- /dev/null +++ b/src/plugins/irc/irc-modelist.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2015 Simmo Saan <simmo.saan@gmail.com> + * + * This file is part of WeeChat, the extensible chat client. + * + * WeeChat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * WeeChat is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WeeChat. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef WEECHAT_IRC_MODELIST_H +#define WEECHAT_IRC_MODELIST_H 1 + +/* modelist states */ +#define IRC_MODELIST_STATE_EMPTY 0 +#define IRC_MODELIST_STATE_RECEIVING 1 +#define IRC_MODELIST_STATE_RECEIVED 2 +#define IRC_MODELIST_STATE_MODIFIED 3 + +struct t_irc_server; + +struct t_irc_modelist_item +{ + int number; /* item number */ + char *mask; /* modelist mask */ + char *setter; /* hostmask of setter */ + time_t datetime; /* datetime of setting (optional)*/ + + struct t_irc_modelist_item *prev_item; /* pointer to previous item */ + struct t_irc_modelist_item *next_item; /* pointer to next item */ +}; + +struct t_irc_modelist +{ + char type; /* mode list channel A type */ + int state; /* state */ + + struct t_irc_modelist_item *items; /* items in modelist */ + struct t_irc_modelist_item *last_item; /* last item in modelist */ + + struct t_irc_modelist *prev_modelist; /* pointer to previous modelist */ + struct t_irc_modelist *next_modelist; /* pointer to next modelist */ +}; + +extern int irc_modelist_item_valid (struct t_irc_modelist *modelist, + struct t_irc_modelist_item *item); +extern struct t_irc_modelist_item *irc_modelist_item_new (struct t_irc_modelist *modelist, + const char *mask, + const char *setter, + time_t datetime); +extern void irc_modelist_item_free (struct t_irc_modelist *modelist, + struct t_irc_modelist_item *item); +extern void irc_modelist_item_free_all (struct t_irc_modelist *modelist); +extern struct t_irc_modelist_item *irc_modelist_item_search (struct t_irc_modelist *modelist, + const char *mask); +extern struct t_irc_modelist_item *irc_modelist_item_number (struct t_irc_modelist *modelist, + int number); + +extern int irc_modelist_valid (struct t_irc_channel *channel, + struct t_irc_modelist *modelist); +extern struct t_irc_modelist *irc_modelist_new (struct t_irc_channel *channel, + char type); +extern void irc_modelist_free (struct t_irc_channel *channel, + struct t_irc_modelist *modelist); +extern void irc_modelist_free_all (struct t_irc_channel *channel); +extern struct t_irc_modelist *irc_modelist_search (struct t_irc_channel *channel, + char type); + +extern struct t_hdata *irc_modelist_hdata_item_cb (const void *pointer, void *data, + const char *hdata_name); +extern struct t_hdata *irc_modelist_hdata_modelist_cb (const void *pointer, + void *data, + const char *hdata_name); +extern int irc_modelist_item_add_to_infolist (struct t_infolist *infolist, + struct t_irc_modelist_item *item); +extern int irc_modelist_add_to_infolist (struct t_infolist *infolist, + struct t_irc_modelist *modelist); +extern void irc_modelist_item_print_log (struct t_irc_modelist_item *item); +extern void irc_modelist_print_log (struct t_irc_modelist *modelist); + +#endif /* WEECHAT_IRC_MODELIST_H */ diff --git a/src/plugins/irc/irc-protocol.c b/src/plugins/irc/irc-protocol.c index 8aa118f1b..177d945e0 100644 --- a/src/plugins/irc/irc-protocol.c +++ b/src/plugins/irc/irc-protocol.c @@ -50,6 +50,7 @@ #include "irc-ignore.h" #include "irc-message.h" #include "irc-mode.h" +#include "irc-modelist.h" #include "irc-msgbuffer.h" #include "irc-nick.h" #include "irc-sasl.h" @@ -947,6 +948,7 @@ IRC_PROTOCOL_CALLBACK(kick) int rejoin; struct t_irc_channel *ptr_channel; struct t_irc_nick *ptr_nick, *ptr_nick_kicked; + struct t_irc_modelist *ptr_modelist; IRC_PROTOCOL_MIN_ARGS(4); IRC_PROTOCOL_CHECK_HOST; @@ -1006,6 +1008,10 @@ IRC_PROTOCOL_CALLBACK(kick) */ irc_nick_free_all (server, ptr_channel); + for (ptr_modelist = ptr_channel->modelists; ptr_modelist; + ptr_modelist = ptr_modelist->next_modelist) + ptr_modelist->state = IRC_MODELIST_STATE_MODIFIED; + /* read option "autorejoin" in server */ rejoin = IRC_SERVER_OPTION_BOOLEAN(server, IRC_SERVER_OPTION_AUTOREJOIN); @@ -1066,6 +1072,7 @@ IRC_PROTOCOL_CALLBACK(kill) char *pos_comment; struct t_irc_channel *ptr_channel; struct t_irc_nick *ptr_nick, *ptr_nick_killed; + struct t_irc_modelist *ptr_modelist; IRC_PROTOCOL_MIN_ARGS(3); IRC_PROTOCOL_CHECK_HOST; @@ -1120,6 +1127,10 @@ IRC_PROTOCOL_CALLBACK(kill) */ irc_nick_free_all (server, ptr_channel); + for (ptr_modelist = ptr_channel->modelists; ptr_modelist; + ptr_modelist = ptr_modelist->next_modelist) + ptr_modelist->state = IRC_MODELIST_STATE_MODIFIED; + irc_bar_item_update_channel (); } else @@ -1162,7 +1173,7 @@ IRC_PROTOCOL_CALLBACK(mode) ptr_channel = irc_channel_search (server, argv[2]); if (ptr_channel) { - smart_filter = irc_mode_channel_set (server, ptr_channel, + smart_filter = irc_mode_channel_set (server, ptr_channel, host, pos_modes); } local_mode = (irc_server_strcasecmp (server, nick, server->nick) == 0); @@ -1661,6 +1672,7 @@ IRC_PROTOCOL_CALLBACK(part) struct t_irc_channel *ptr_channel; struct t_irc_nick *ptr_nick; struct t_irc_channel_speaking *ptr_nick_speaking; + struct t_irc_modelist *ptr_modelist; IRC_PROTOCOL_MIN_ARGS(3); IRC_PROTOCOL_CHECK_HOST; @@ -1757,6 +1769,10 @@ IRC_PROTOCOL_CALLBACK(part) { irc_nick_free_all (server, ptr_channel); + for (ptr_modelist = ptr_channel->modelists; ptr_modelist; + ptr_modelist = ptr_modelist->next_modelist) + ptr_modelist->state = IRC_MODELIST_STATE_MODIFIED; + /* cycling ? => rejoin channel immediately */ if (ptr_channel->cycle) { @@ -3294,7 +3310,7 @@ IRC_PROTOCOL_CALLBACK(324) irc_channel_set_modes (ptr_channel, ptr_modes); if (argc > 4) { - (void) irc_mode_channel_set (server, ptr_channel, + (void) irc_mode_channel_set (server, ptr_channel, host, ptr_channel->modes); } } @@ -3878,14 +3894,35 @@ IRC_PROTOCOL_CALLBACK(346) { struct t_irc_channel *ptr_channel; struct t_gui_buffer *ptr_buffer; + struct t_irc_modelist *ptr_modelist; time_t datetime; const char *nick_address; + char str_number[64]; IRC_PROTOCOL_MIN_ARGS(5); ptr_channel = irc_channel_search (server, argv[3]); ptr_buffer = (ptr_channel && ptr_channel->nicks) ? ptr_channel->buffer : server->buffer; + ptr_modelist = irc_modelist_search (ptr_channel, 'I'); + + if (ptr_modelist) { + /* start receiving new list */ + if (ptr_modelist->state != IRC_MODELIST_STATE_RECEIVING) + { + irc_modelist_item_free_all (ptr_modelist); + ptr_modelist->state = IRC_MODELIST_STATE_RECEIVING; + } + + sprintf (str_number, "%s[%s%d%s] ", + IRC_COLOR_CHAT_DELIMITERS, + IRC_COLOR_RESET, + ((ptr_modelist->last_item) ? ptr_modelist->last_item->number + 1 : 0) + 1, + IRC_COLOR_CHAT_DELIMITERS); + } + else + str_number[0] = '\0'; + if (argc >= 6) { nick_address = irc_protocol_nick_address ( @@ -3894,18 +3931,21 @@ IRC_PROTOCOL_CALLBACK(346) if (argc >= 7) { datetime = (time_t)(atol (argv[6])); + if (ptr_modelist) + irc_modelist_item_new (ptr_modelist, argv[4], argv[5], datetime); weechat_printf_date_tags ( irc_msgbuffer_get_target_buffer ( server, NULL, command, "invitelist", ptr_buffer), date, irc_protocol_tags (command, "irc_numeric", NULL, NULL), /* TRANSLATORS: "%s" after "on" is a date */ - _("%s%s[%s%s%s] %s%s%s invited by %s on %s"), + _("%s%s[%s%s%s] %s%s%s%s invited by %s on %s"), weechat_prefix ("network"), IRC_COLOR_CHAT_DELIMITERS, IRC_COLOR_CHAT_CHANNEL, argv[3], IRC_COLOR_CHAT_DELIMITERS, + str_number, IRC_COLOR_CHAT_HOST, argv[4], IRC_COLOR_RESET, @@ -3914,17 +3954,20 @@ IRC_PROTOCOL_CALLBACK(346) } else { + if (ptr_modelist) + irc_modelist_item_new (ptr_modelist, argv[4], argv[5], 0); weechat_printf_date_tags ( irc_msgbuffer_get_target_buffer ( server, NULL, command, "invitelist", ptr_buffer), date, irc_protocol_tags (command, "irc_numeric", NULL, NULL), - _("%s%s[%s%s%s] %s%s%s invited by %s"), + _("%s%s[%s%s%s] %s%s%s%s invited by %s"), weechat_prefix ("network"), IRC_COLOR_CHAT_DELIMITERS, IRC_COLOR_CHAT_CHANNEL, argv[3], IRC_COLOR_CHAT_DELIMITERS, + str_number, IRC_COLOR_CHAT_HOST, argv[4], IRC_COLOR_RESET, @@ -3933,17 +3976,20 @@ IRC_PROTOCOL_CALLBACK(346) } else { + if (ptr_modelist) + irc_modelist_item_new (ptr_modelist, argv[4], NULL, 0); weechat_printf_date_tags ( irc_msgbuffer_get_target_buffer ( server, NULL, command, "invitelist", ptr_buffer), date, irc_protocol_tags (command, "irc_numeric", NULL, NULL), - _("%s%s[%s%s%s] %s%s%s invited"), + _("%s%s[%s%s%s] %s%s%s%s invited"), weechat_prefix ("network"), IRC_COLOR_CHAT_DELIMITERS, IRC_COLOR_CHAT_CHANNEL, argv[3], IRC_COLOR_CHAT_DELIMITERS, + str_number, IRC_COLOR_CHAT_HOST, argv[4], IRC_COLOR_RESET); @@ -3964,6 +4010,7 @@ IRC_PROTOCOL_CALLBACK(347) char *pos_args; struct t_irc_channel *ptr_channel; struct t_gui_buffer *ptr_buffer; + struct t_irc_modelist *ptr_modelist; IRC_PROTOCOL_MIN_ARGS(4); @@ -3973,6 +4020,9 @@ IRC_PROTOCOL_CALLBACK(347) ptr_channel = irc_channel_search (server, argv[3]); ptr_buffer = (ptr_channel && ptr_channel->nicks) ? ptr_channel->buffer : server->buffer; + ptr_modelist = irc_modelist_search (ptr_channel, 'I'); + if (ptr_modelist) + ptr_modelist->state = IRC_MODELIST_STATE_RECEIVED; weechat_printf_date_tags ( irc_msgbuffer_get_target_buffer ( server, NULL, command, "invitelist", ptr_buffer), @@ -4003,14 +4053,35 @@ IRC_PROTOCOL_CALLBACK(348) { struct t_irc_channel *ptr_channel; struct t_gui_buffer *ptr_buffer; + struct t_irc_modelist *ptr_modelist; time_t datetime; const char *nick_address; + char str_number[64]; IRC_PROTOCOL_MIN_ARGS(5); ptr_channel = irc_channel_search (server, argv[3]); ptr_buffer = (ptr_channel && ptr_channel->nicks) ? ptr_channel->buffer : server->buffer; + ptr_modelist = irc_modelist_search (ptr_channel, 'e'); + + if (ptr_modelist) { + /* start receiving new list */ + if (ptr_modelist->state != IRC_MODELIST_STATE_RECEIVING) + { + irc_modelist_item_free_all (ptr_modelist); + ptr_modelist->state = IRC_MODELIST_STATE_RECEIVING; + } + + sprintf (str_number, "%s[%s%d%s] ", + IRC_COLOR_CHAT_DELIMITERS, + IRC_COLOR_RESET, + ((ptr_modelist->last_item) ? ptr_modelist->last_item->number + 1 : 0) + 1, + IRC_COLOR_CHAT_DELIMITERS); + } + else + str_number[0] = '\0'; + if (argc >= 6) { nick_address = irc_protocol_nick_address ( @@ -4019,18 +4090,21 @@ IRC_PROTOCOL_CALLBACK(348) if (argc >= 7) { datetime = (time_t)(atol (argv[6])); + if (ptr_modelist) + irc_modelist_item_new (ptr_modelist, argv[4], argv[5], datetime); weechat_printf_date_tags ( irc_msgbuffer_get_target_buffer ( server, NULL, command, "exceptionlist", ptr_buffer), date, irc_protocol_tags (command, "irc_numeric", NULL, NULL), /* TRANSLATORS: "%s" after "on" is a date */ - _("%s%s[%s%s%s]%s exception %s%s%s by %s on %s"), + _("%s%s[%s%s%s] %s%sexception %s%s%s by %s on %s"), weechat_prefix ("network"), IRC_COLOR_CHAT_DELIMITERS, IRC_COLOR_CHAT_CHANNEL, argv[3], IRC_COLOR_CHAT_DELIMITERS, + str_number, IRC_COLOR_RESET, IRC_COLOR_CHAT_HOST, argv[4], @@ -4040,17 +4114,20 @@ IRC_PROTOCOL_CALLBACK(348) } else { + if (ptr_modelist) + irc_modelist_item_new (ptr_modelist, argv[4], argv[5], 0); weechat_printf_date_tags ( irc_msgbuffer_get_target_buffer ( server, NULL, command, "exceptionlist", ptr_buffer), date, irc_protocol_tags (command, "irc_numeric", NULL, NULL), - _("%s%s[%s%s%s]%s exception %s%s%s by %s"), + _("%s%s[%s%s%s] %s%sexception %s%s%s by %s"), weechat_prefix ("network"), IRC_COLOR_CHAT_DELIMITERS, IRC_COLOR_CHAT_CHANNEL, argv[3], IRC_COLOR_CHAT_DELIMITERS, + str_number, IRC_COLOR_RESET, IRC_COLOR_CHAT_HOST, argv[4], @@ -4060,17 +4137,20 @@ IRC_PROTOCOL_CALLBACK(348) } else { + if (ptr_modelist) + irc_modelist_item_new (ptr_modelist, argv[4], NULL, 0); weechat_printf_date_tags ( irc_msgbuffer_get_target_buffer ( server, NULL, command, "exceptionlist", ptr_buffer), date, irc_protocol_tags (command, "irc_numeric", NULL, NULL), - _("%s%s[%s%s%s]%s exception %s%s"), + _("%s%s[%s%s%s] %s%sexception %s%s"), weechat_prefix ("network"), IRC_COLOR_CHAT_DELIMITERS, IRC_COLOR_CHAT_CHANNEL, argv[3], IRC_COLOR_CHAT_DELIMITERS, + str_number, IRC_COLOR_RESET, IRC_COLOR_CHAT_HOST, argv[4]); @@ -4091,6 +4171,7 @@ IRC_PROTOCOL_CALLBACK(349) char *pos_args; struct t_irc_channel *ptr_channel; struct t_gui_buffer *ptr_buffer; + struct t_irc_modelist *ptr_modelist; IRC_PROTOCOL_MIN_ARGS(4); @@ -4100,6 +4181,9 @@ IRC_PROTOCOL_CALLBACK(349) ptr_channel = irc_channel_search (server, argv[3]); ptr_buffer = (ptr_channel && ptr_channel->nicks) ? ptr_channel->buffer : server->buffer; + ptr_modelist = irc_modelist_search (ptr_channel, 'e'); + if (ptr_modelist) + ptr_modelist->state = IRC_MODELIST_STATE_RECEIVED; weechat_printf_date_tags ( irc_msgbuffer_get_target_buffer ( server, NULL, command, "exceptionlist", ptr_buffer), @@ -4761,14 +4845,34 @@ IRC_PROTOCOL_CALLBACK(367) { struct t_irc_channel *ptr_channel; struct t_gui_buffer *ptr_buffer; + struct t_irc_modelist *ptr_modelist; time_t datetime; const char *nick_address; + char str_number[64]; IRC_PROTOCOL_MIN_ARGS(5); ptr_channel = irc_channel_search (server, argv[3]); ptr_buffer = (ptr_channel && ptr_channel->nicks) ? ptr_channel->buffer : server->buffer; + ptr_modelist = irc_modelist_search (ptr_channel, 'b'); + + if (ptr_modelist) { + /* start receiving new list */ + if (ptr_modelist->state != IRC_MODELIST_STATE_RECEIVING) + { + irc_modelist_item_free_all (ptr_modelist); + ptr_modelist->state = IRC_MODELIST_STATE_RECEIVING; + } + + sprintf (str_number, "%s[%s%d%s] ", + IRC_COLOR_CHAT_DELIMITERS, + IRC_COLOR_RESET, + ((ptr_modelist->last_item) ? ptr_modelist->last_item->number + 1 : 0) + 1, + IRC_COLOR_CHAT_DELIMITERS); + } + else + str_number[0] = '\0'; if (argc >= 6) { @@ -4778,18 +4882,21 @@ IRC_PROTOCOL_CALLBACK(367) if (argc >= 7) { datetime = (time_t)(atol (argv[6])); + if (ptr_modelist) + irc_modelist_item_new (ptr_modelist, argv[4], argv[5], datetime); weechat_printf_date_tags ( irc_msgbuffer_get_target_buffer ( server, NULL, command, "banlist", ptr_buffer), date, irc_protocol_tags (command, "irc_numeric", NULL, NULL), /* TRANSLATORS: "%s" after "on" is a date */ - _("%s%s[%s%s%s] %s%s%s banned by %s on %s"), + _("%s%s[%s%s%s] %s%s%s%s banned by %s on %s"), weechat_prefix ("network"), IRC_COLOR_CHAT_DELIMITERS, IRC_COLOR_CHAT_CHANNEL, argv[3], IRC_COLOR_CHAT_DELIMITERS, + str_number, IRC_COLOR_CHAT_HOST, argv[4], IRC_COLOR_RESET, @@ -4798,17 +4905,20 @@ IRC_PROTOCOL_CALLBACK(367) } else { + if (ptr_modelist) + irc_modelist_item_new (ptr_modelist, argv[4], argv[5], 0); weechat_printf_date_tags ( irc_msgbuffer_get_target_buffer ( server, NULL, command, "banlist", ptr_buffer), date, irc_protocol_tags (command, "irc_numeric", NULL, NULL), - _("%s%s[%s%s%s] %s%s%s banned by %s"), + _("%s%s[%s%s%s] %s%s%s%s banned by %s"), weechat_prefix ("network"), IRC_COLOR_CHAT_DELIMITERS, IRC_COLOR_CHAT_CHANNEL, argv[3], IRC_COLOR_CHAT_DELIMITERS, + str_number, IRC_COLOR_CHAT_HOST, argv[4], IRC_COLOR_RESET, @@ -4817,17 +4927,20 @@ IRC_PROTOCOL_CALLBACK(367) } else { + if (ptr_modelist) + irc_modelist_item_new (ptr_modelist, argv[4], NULL, 0); weechat_printf_date_tags ( irc_msgbuffer_get_target_buffer ( server, NULL, command, "banlist", ptr_buffer), date, irc_protocol_tags (command, "irc_numeric", NULL, NULL), - _("%s%s[%s%s%s] %s%s%s banned"), + _("%s%s[%s%s%s] %s%s%s%s banned"), weechat_prefix ("network"), IRC_COLOR_CHAT_DELIMITERS, IRC_COLOR_CHAT_CHANNEL, argv[3], IRC_COLOR_CHAT_DELIMITERS, + str_number, IRC_COLOR_CHAT_HOST, argv[4], IRC_COLOR_RESET); @@ -4848,6 +4961,7 @@ IRC_PROTOCOL_CALLBACK(368) char *pos_args; struct t_irc_channel *ptr_channel; struct t_gui_buffer *ptr_buffer; + struct t_irc_modelist *ptr_modelist; IRC_PROTOCOL_MIN_ARGS(4); @@ -4857,6 +4971,9 @@ IRC_PROTOCOL_CALLBACK(368) ptr_channel = irc_channel_search (server, argv[3]); ptr_buffer = (ptr_channel && ptr_channel->nicks) ? ptr_channel->buffer : server->buffer; + ptr_modelist = irc_modelist_search (ptr_channel, 'b'); + if (ptr_modelist) + ptr_modelist->state = IRC_MODELIST_STATE_RECEIVED; weechat_printf_date_tags ( irc_msgbuffer_get_target_buffer ( server, NULL, command, "banlist", ptr_buffer), @@ -5188,14 +5305,34 @@ IRC_PROTOCOL_CALLBACK(728) { struct t_irc_channel *ptr_channel; struct t_gui_buffer *ptr_buffer; + struct t_irc_modelist *ptr_modelist; time_t datetime; const char *nick_address; + char str_number[64]; IRC_PROTOCOL_MIN_ARGS(6); ptr_channel = irc_channel_search (server, argv[3]); ptr_buffer = (ptr_channel && ptr_channel->nicks) ? ptr_channel->buffer : server->buffer; + ptr_modelist = irc_modelist_search (ptr_channel, argv[4][0]); + + if (ptr_modelist) { + /* start receiving new list */ + if (ptr_modelist->state != IRC_MODELIST_STATE_RECEIVING) + { + irc_modelist_item_free_all (ptr_modelist); + ptr_modelist->state = IRC_MODELIST_STATE_RECEIVING; + } + + sprintf (str_number, "%s[%s%d%s] ", + IRC_COLOR_CHAT_DELIMITERS, + IRC_COLOR_RESET, + ((ptr_modelist->last_item) ? ptr_modelist->last_item->number + 1 : 0) + 1, + IRC_COLOR_CHAT_DELIMITERS); + } + else + str_number[0] = '\0'; if (argc >= 7) { @@ -5205,18 +5342,21 @@ IRC_PROTOCOL_CALLBACK(728) if (argc >= 8) { datetime = (time_t)(atol (argv[7])); + if (ptr_modelist) + irc_modelist_item_new (ptr_modelist, argv[5], argv[6], datetime); weechat_printf_date_tags ( irc_msgbuffer_get_target_buffer ( server, NULL, command, "quietlist", ptr_buffer), date, irc_protocol_tags (command, "irc_numeric", NULL, NULL), /* TRANSLATORS: "%s" after "on" is a date */ - _("%s%s[%s%s%s] %s%s%s quieted by %s on %s"), + _("%s%s[%s%s%s] %s%s%s%s quieted by %s on %s"), weechat_prefix ("network"), IRC_COLOR_CHAT_DELIMITERS, IRC_COLOR_CHAT_CHANNEL, argv[3], IRC_COLOR_CHAT_DELIMITERS, + str_number, IRC_COLOR_CHAT_HOST, argv[5], IRC_COLOR_RESET, @@ -5225,17 +5365,20 @@ IRC_PROTOCOL_CALLBACK(728) } else { + if (ptr_modelist) + irc_modelist_item_new (ptr_modelist, argv[5], argv[6], 0); weechat_printf_date_tags ( irc_msgbuffer_get_target_buffer ( server, NULL, command, "quietlist", ptr_buffer), date, irc_protocol_tags (command, "irc_numeric", NULL, NULL), - _("%s%s[%s%s%s] %s%s%s quieted by %s"), + _("%s%s[%s%s%s] %s%s%s%s quieted by %s"), weechat_prefix ("network"), IRC_COLOR_CHAT_DELIMITERS, IRC_COLOR_CHAT_CHANNEL, argv[3], IRC_COLOR_CHAT_DELIMITERS, + str_number, IRC_COLOR_CHAT_HOST, argv[5], IRC_COLOR_RESET, @@ -5244,17 +5387,20 @@ IRC_PROTOCOL_CALLBACK(728) } else { + if (ptr_modelist) + irc_modelist_item_new (ptr_modelist, argv[5], NULL, 0); weechat_printf_date_tags ( irc_msgbuffer_get_target_buffer ( server, NULL, command, "quietlist", ptr_buffer), date, irc_protocol_tags (command, "irc_numeric", NULL, NULL), - _("%s%s[%s%s%s] %s%s%s quieted"), + _("%s%s[%s%s%s] %s%s%s%s quieted"), weechat_prefix ("network"), IRC_COLOR_CHAT_DELIMITERS, IRC_COLOR_CHAT_CHANNEL, argv[3], IRC_COLOR_CHAT_DELIMITERS, + str_number, IRC_COLOR_CHAT_HOST, argv[5], IRC_COLOR_RESET); @@ -5275,6 +5421,7 @@ IRC_PROTOCOL_CALLBACK(729) char *pos_args; struct t_irc_channel *ptr_channel; struct t_gui_buffer *ptr_buffer; + struct t_irc_modelist *ptr_modelist; IRC_PROTOCOL_MIN_ARGS(5); @@ -5284,6 +5431,9 @@ IRC_PROTOCOL_CALLBACK(729) ptr_channel = irc_channel_search (server, argv[3]); ptr_buffer = (ptr_channel && ptr_channel->nicks) ? ptr_channel->buffer : server->buffer; + ptr_modelist = irc_modelist_search (ptr_channel, argv[4][0]); + if (ptr_modelist) + ptr_modelist->state = IRC_MODELIST_STATE_RECEIVED; weechat_printf_date_tags ( irc_msgbuffer_get_target_buffer ( server, NULL, command, "quietlist", ptr_buffer), diff --git a/src/plugins/irc/irc-upgrade.c b/src/plugins/irc/irc-upgrade.c index 0c0c919e3..b8dcb0696 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-modelist.h" #include "irc-nick.h" #include "irc-notify.h" #include "irc-raw.h" @@ -39,6 +40,7 @@ struct t_irc_server *irc_upgrade_current_server = NULL; struct t_irc_channel *irc_upgrade_current_channel = NULL; +struct t_irc_modelist *irc_upgrade_current_modelist = NULL; /* @@ -59,6 +61,8 @@ irc_upgrade_save_all_data (struct t_upgrade_file *upgrade_file) struct t_irc_redirect *ptr_redirect; struct t_irc_redirect_pattern *ptr_redirect_pattern; struct t_irc_notify *ptr_notify; + struct t_irc_modelist *ptr_modelist; + struct t_irc_modelist_item *ptr_item; struct t_irc_raw_message *ptr_raw_message; int rc; @@ -120,6 +124,46 @@ irc_upgrade_save_all_data (struct t_upgrade_file *upgrade_file) if (!rc) return 0; } + + for (ptr_modelist = ptr_channel->modelists; ptr_modelist; + ptr_modelist = ptr_modelist->next_modelist) + { + /* save modelist */ + infolist = weechat_infolist_new (); + if (!infolist) + return 0; + if (!irc_modelist_add_to_infolist (infolist, ptr_modelist)) + { + weechat_infolist_free (infolist); + return 0; + } + rc = weechat_upgrade_write_object (upgrade_file, + IRC_UPGRADE_TYPE_MODELIST, + infolist); + weechat_infolist_free (infolist); + if (!rc) + return 0; + + for (ptr_item = ptr_modelist->items; ptr_item; + ptr_item = ptr_item->next_item) + { + /* save modelist item */ + infolist = weechat_infolist_new (); + if (!infolist) + return 0; + if (!irc_modelist_item_add_to_infolist (infolist, ptr_item)) + { + weechat_infolist_free (infolist); + return 0; + } + rc = weechat_upgrade_write_object (upgrade_file, + IRC_UPGRADE_TYPE_MODELIST_ITEM, + infolist); + weechat_infolist_free (infolist); + if (!rc) + return 0; + } + } } /* save server redirects */ @@ -304,6 +348,7 @@ irc_upgrade_read_cb (const void *pointer, void *data, struct t_irc_nick *ptr_nick; struct t_irc_redirect *ptr_redirect; struct t_irc_notify *ptr_notify; + struct t_irc_modelist_item *ptr_item; struct t_gui_buffer *ptr_buffer; /* make C compiler happy */ @@ -657,6 +702,33 @@ irc_upgrade_read_cb (const void *pointer, void *data, } } break; + case IRC_UPGRADE_TYPE_MODELIST: + if (irc_upgrade_current_server && irc_upgrade_current_channel) + { + /* modelists are already created by the channel */ + irc_upgrade_current_modelist = irc_modelist_search ( + irc_upgrade_current_channel, + weechat_infolist_string (infolist, "type")[0]); + if (irc_upgrade_current_modelist) + { + irc_upgrade_current_modelist->state = weechat_infolist_integer (infolist, "state"); + } + } + break; + case IRC_UPGRADE_TYPE_MODELIST_ITEM: + if (irc_upgrade_current_server && irc_upgrade_current_channel && irc_upgrade_current_modelist) + { + ptr_item = irc_modelist_item_new ( + irc_upgrade_current_modelist, + weechat_infolist_string (infolist, "mask"), + weechat_infolist_string (infolist, "setter"), + weechat_infolist_time (infolist, "datetime")); + if (ptr_item) + { + ptr_item->number = weechat_infolist_integer (infolist, "number"); + } + } + break; case IRC_UPGRADE_TYPE_REDIRECT: if (irc_upgrade_current_server) { diff --git a/src/plugins/irc/irc-upgrade.h b/src/plugins/irc/irc-upgrade.h index e13682928..acfc39120 100644 --- a/src/plugins/irc/irc-upgrade.h +++ b/src/plugins/irc/irc-upgrade.h @@ -33,6 +33,8 @@ enum t_irc_upgrade_type IRC_UPGRADE_TYPE_REDIRECT_PATTERN, IRC_UPGRADE_TYPE_REDIRECT, IRC_UPGRADE_TYPE_NOTIFY, + IRC_UPGRADE_TYPE_MODELIST, + IRC_UPGRADE_TYPE_MODELIST_ITEM }; extern int irc_upgrade_save (); |