summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimmo Saan <simmo.saan@gmail.com>2018-03-24 17:01:50 +0100
committerSébastien Helleu <flashcode@flashtux.org>2018-03-24 17:01:50 +0100
commitd77e1ea49950f1f537194368cc4d003bb8667d41 (patch)
tree62c4cddaa9af9f59417e3d262b05b10e012d13f8
parentb2f971d4b046ae49b01f926f5617a0542c21d5d3 (diff)
downloadweechat-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.adoc1
-rw-r--r--src/plugins/irc/CMakeLists.txt1
-rw-r--r--src/plugins/irc/Makefile.am2
-rw-r--r--src/plugins/irc/irc-channel.c18
-rw-r--r--src/plugins/irc/irc-channel.h3
-rw-r--r--src/plugins/irc/irc-command.c32
-rw-r--r--src/plugins/irc/irc-completion.c46
-rw-r--r--src/plugins/irc/irc-info.c216
-rw-r--r--src/plugins/irc/irc-mode.c23
-rw-r--r--src/plugins/irc/irc-mode.h1
-rw-r--r--src/plugins/irc/irc-modelist.c495
-rw-r--r--src/plugins/irc/irc-modelist.h90
-rw-r--r--src/plugins/irc/irc-protocol.c178
-rw-r--r--src/plugins/irc/irc-upgrade.c72
-rw-r--r--src/plugins/irc/irc-upgrade.h2
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 ();