1
0
mirror of https://github.com/weechat/weechat.git synced 2026-06-27 21:36:37 +02:00

irc: unmask smart filtered join if nick speaks in channel some minutes after the join, new option irc.look.smart_filter_join_unmask (task #12405)

The nick changes are tracked and will be unmasked with the join.
Events triggering the unmask of join are: a message (can be CTCP), a notice or
an update of topic.
This commit is contained in:
Sebastien Helleu
2013-02-17 13:27:36 +01:00
parent 6e3f6270d1
commit bc079b007d
29 changed files with 585 additions and 57 deletions
+260
View File
@@ -293,6 +293,7 @@ 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->join_smart_filtered = NULL;
new_channel->buffer = new_buffer;
new_channel->buffer_as_string = NULL;
@@ -720,6 +721,254 @@ irc_channel_nick_speaking_time_rename (struct t_irc_server *server,
}
}
/*
* Adds a nick in hashtable "join_smart_filtered" (creates the hashtable if
* needed).
*/
void
irc_channel_join_smart_filtered_add (struct t_irc_channel *channel,
const char *nick,
time_t join_time)
{
/* return if unmasking of smart filtered joins is disabled */
if (weechat_config_integer (irc_config_look_smart_filter_join_unmask) == 0)
return;
/* create hashtable if needed */
if (!channel->join_smart_filtered)
{
channel->join_smart_filtered = weechat_hashtable_new (64,
WEECHAT_HASHTABLE_STRING,
WEECHAT_HASHTABLE_TIME,
NULL,
NULL);
}
if (!channel->join_smart_filtered)
return;
weechat_hashtable_set (channel->join_smart_filtered, nick, &join_time);
}
/*
* Renames a nick in hashtable "join_smart_filtered".
*/
void
irc_channel_join_smart_filtered_rename (struct t_irc_channel *channel,
const char *old_nick,
const char *new_nick)
{
time_t *ptr_time, join_time;
/* return if hashtable does not exist in channel */
if (!channel->join_smart_filtered)
return;
/* search old_nick in hashtable */
ptr_time = weechat_hashtable_get (channel->join_smart_filtered, old_nick);
if (!ptr_time)
return;
/* remove old_nick, add new_nick with time of old_nick */
join_time = *ptr_time;
weechat_hashtable_remove (channel->join_smart_filtered, old_nick);
weechat_hashtable_set (channel->join_smart_filtered, new_nick, &join_time);
}
/*
* Removes a nick in hashtable "join_smart_filtered".
*/
void
irc_channel_join_smart_filtered_remove (struct t_irc_channel *channel,
const char *nick)
{
/* return if hashtable does not exist in channel */
if (!channel->join_smart_filtered)
return;
weechat_hashtable_remove (channel->join_smart_filtered, nick);
}
/*
* Unmasks a smart filtered join if nick is in hashtable "join_smart_filtered",
* then removes nick from hashtable.
*/
void
irc_channel_join_smart_filtered_unmask (struct t_irc_channel *channel,
const char *nick)
{
int i, unmask_delay, length_tags, nick_found, join, nick_changed;
int smart_filtered, remove_smart_filter;
time_t *ptr_time, date_min;
struct t_hdata *hdata_line, *hdata_line_data;
struct t_gui_line *own_lines;
struct t_gui_line *line;
struct t_gui_line_data *line_data;
const char **tags, *irc_nick1, *irc_nick2;
char *new_tags, *nick_to_search;
struct t_hashtable *hashtable;
/* return if hashtable does not exist in channel */
if (!channel->join_smart_filtered)
return;
/* return if unmasking of smart filtered joins is disabled */
unmask_delay = weechat_config_integer (irc_config_look_smart_filter_join_unmask);
if (unmask_delay == 0)
return;
/* check if nick is in hashtable "join_smart_filtered" */
ptr_time = weechat_hashtable_get (channel->join_smart_filtered, nick);
if (!ptr_time)
return;
/*
* the min date allowed to unmask a join (a join older than this date will
* not be unmasked)
*/
date_min = time (NULL) - (unmask_delay * 60);
/*
* if the join is too old (older than current time - unmask delay), just
* remove nick from hashtable and return
*/
if (*ptr_time < date_min)
{
weechat_hashtable_remove (channel->join_smart_filtered, nick);
return;
}
/* get hdata and pointers on last line in buffer */
own_lines = weechat_hdata_pointer (weechat_hdata_get ("buffer"),
channel->buffer, "own_lines");
if (!own_lines)
return;
line = weechat_hdata_pointer (weechat_hdata_get ("lines"),
own_lines, "last_line");
if (!line)
return;
hdata_line = weechat_hdata_get ("line");
hdata_line_data = weechat_hdata_get ("line_data");
/* the nick to search in messages (track nick changes) */
nick_to_search = strdup (nick);
if (!nick_to_search)
return;
/* loop on lines until we find the join */
while (line)
{
line_data = weechat_hdata_pointer (hdata_line, line, "data");
if (!line_data)
break;
/* exit loop if we reach the unmask delay */
if (weechat_hdata_time (hdata_line_data, line_data, "date_printed") < date_min)
break;
/* check tags in line */
length_tags = 0;
nick_found = 0;
join = 0;
nick_changed = 0;
irc_nick1 = NULL;
irc_nick2 = NULL;
smart_filtered = 0;
tags = weechat_hdata_pointer (hdata_line_data, line_data, "tags_array");
for (i = 0; tags[i]; i++)
{
if (strncmp (tags[i], "nick_", 5) == 0)
{
if (strcmp (tags[i] + 5, nick_to_search) == 0)
nick_found = 1;
}
else if (strcmp (tags[i], "irc_join") == 0)
join = 1;
else if (strcmp (tags[i], "irc_nick") == 0)
nick_changed = 1;
else if (strncmp (tags[i], "irc_nick1_", 10) == 0)
irc_nick1 = tags[i] + 10;
else if (strncmp (tags[i], "irc_nick2_", 10) == 0)
irc_nick2 = tags[i] + 10;
else if (strcmp (tags[i], "irc_smart_filter") == 0)
smart_filtered = 1;
length_tags += strlen (tags[i]) + 1;
}
/* check if we must remove tag "irc_smart_filter" in line */
remove_smart_filter = 0;
if (nick_changed && irc_nick1 && irc_nick2
&& (strcmp (irc_nick2, nick_to_search) == 0))
{
/* update the nick to search if the line is a message "nick" */
free (nick_to_search);
nick_to_search = strdup (irc_nick1);
if (!nick_to_search)
break;
remove_smart_filter = 1;
}
else if (nick_found && join && smart_filtered)
{
remove_smart_filter = 1;
}
if (remove_smart_filter)
{
/*
* unmask a "nick" or "join" message: remove the tag
* "irc_smart_filter"
*/
new_tags = malloc (length_tags);
if (new_tags)
{
/* build a string with all tags, except "irc_smart_filter" */
new_tags[0] = '\0';
for (i = 0; tags[i]; i++)
{
if (strcmp (tags[i], "irc_smart_filter") != 0)
{
if (new_tags[0])
strcat (new_tags, ",");
strcat (new_tags, tags[i]);
}
}
hashtable = weechat_hashtable_new (4,
WEECHAT_HASHTABLE_STRING,
WEECHAT_HASHTABLE_STRING,
NULL,
NULL);
if (hashtable)
{
/* update tags in line (remove tag "irc_smart_filter") */
weechat_hashtable_set (hashtable, "tags_array", new_tags);
weechat_hdata_update (hdata_line_data, line_data, hashtable);
weechat_hashtable_free (hashtable);
}
free (new_tags);
}
/*
* exit loop if the message was the join (if it's a nick change,
* then we loop until we find the join)
*/
if (join)
break;
}
/* continue with previous line in buffer */
line = weechat_hdata_move (hdata_line, line, -1);
}
if (nick_to_search)
free (nick_to_search);
weechat_hashtable_remove (channel->join_smart_filtered, nick);
}
/*
* Rejoins a channel (for example after kick).
*/
@@ -867,6 +1116,8 @@ irc_channel_free (struct t_irc_server *server, struct t_irc_channel *channel)
if (channel->nicks_speaking[1])
weechat_list_free (channel->nicks_speaking[1]);
irc_channel_nick_speaking_time_free_all (channel);
if (channel->join_smart_filtered)
weechat_hashtable_free (channel->join_smart_filtered);
if (channel->buffer_as_string)
free (channel->buffer_as_string);
@@ -925,6 +1176,7 @@ irc_channel_hdata_channel_cb (void *data, const char *hdata_name)
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, 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);
WEECHAT_HDATA_VAR(struct t_irc_channel, prev_channel, POINTER, 0, NULL, hdata_name);
@@ -1059,6 +1311,10 @@ irc_channel_add_to_infolist (struct t_infolist *infolist,
i++;
}
}
if (!weechat_infolist_new_var_string (ptr_item, "join_smart_filtered",
weechat_hashtable_get_string (channel->join_smart_filtered,
"keys_values")))
return 0;
return 1;
}
@@ -1098,6 +1354,10 @@ 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 (" join_smart_filtered. . . : 0x%lx (hashtable: '%s')",
channel->join_smart_filtered,
weechat_hashtable_get_string (channel->join_smart_filtered,
"keys_values"));
weechat_log_printf (" buffer . . . . . . . . . : 0x%lx", channel->buffer);
weechat_log_printf (" buffer_as_string . . . . : '%s'", channel->buffer_as_string);
weechat_log_printf (" prev_channel . . . . . . : 0x%lx", channel->prev_channel);
+11
View File
@@ -67,6 +67,7 @@ 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_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 */
struct t_irc_channel *prev_channel; /* link to previous channel */
@@ -118,6 +119,16 @@ extern void irc_channel_nick_speaking_time_rename (struct t_irc_server *server,
struct t_irc_channel *channel,
const char *old_nick,
const char *new_nick);
extern void irc_channel_join_smart_filtered_add (struct t_irc_channel *channel,
const char *nick,
time_t join_time);
extern void irc_channel_join_smart_filtered_rename (struct t_irc_channel *channel,
const char *old_nick,
const char *new_nick);
extern void irc_channel_join_smart_filtered_remove (struct t_irc_channel *channel,
const char *nick);
extern void irc_channel_join_smart_filtered_unmask (struct t_irc_channel *channel,
const char *nick);
extern void irc_channel_rejoin (struct t_irc_server *server,
struct t_irc_channel *channel);
extern int irc_channel_autorejoin_cb (void *data, int remaining_calls);
+11 -1
View File
@@ -94,6 +94,7 @@ struct t_config_option *irc_config_look_raw_messages;
struct t_config_option *irc_config_look_smart_filter;
struct t_config_option *irc_config_look_smart_filter_delay;
struct t_config_option *irc_config_look_smart_filter_join;
struct t_config_option *irc_config_look_smart_filter_join_unmask;
struct t_config_option *irc_config_look_smart_filter_quit;
struct t_config_option *irc_config_look_smart_filter_nick;
struct t_config_option *irc_config_look_topic_strip_colors;
@@ -2309,6 +2310,15 @@ irc_config_init ()
/* TRANSLATORS: please do not translate "join" */
N_("enable smart filter for \"join\" messages"),
NULL, 0, 0, "on", NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL);
irc_config_look_smart_filter_join_unmask = weechat_config_new_option (
irc_config_file, ptr_section,
"smart_filter_join_unmask", "integer",
N_("delay for unmasking a join message that was filtered with tag "
"\"irc_smart_filter\" (in minutes): if a nick jas joined max N "
"minutes ago and then says something on channel (message, notice or "
"update on topic), the join is unmasked, as well as nick changes "
"after this join (0 = disable: never unmask a join)"),
NULL, 0, 60*24*7, "30", NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL);
irc_config_look_smart_filter_quit = weechat_config_new_option (
irc_config_file, ptr_section,
"smart_filter_quit", "boolean",
@@ -2319,7 +2329,7 @@ irc_config_init ()
irc_config_file, ptr_section,
"smart_filter_nick", "boolean",
/* TRANSLATORS: please do not translate "nick" */
N_("enable smart filter for \"nick\" messages"),
N_("enable smart filter for \"nick\" messages (nick changes)"),
NULL, 0, 0, "on", NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL);
irc_config_look_topic_strip_colors = weechat_config_new_option (
irc_config_file, ptr_section,
+1
View File
@@ -129,6 +129,7 @@ extern struct t_config_option *irc_config_look_raw_messages;
extern struct t_config_option *irc_config_look_smart_filter;
extern struct t_config_option *irc_config_look_smart_filter_delay;
extern struct t_config_option *irc_config_look_smart_filter_join;
extern struct t_config_option *irc_config_look_smart_filter_join_unmask;
extern struct t_config_option *irc_config_look_smart_filter_quit;
extern struct t_config_option *irc_config_look_smart_filter_nick;
extern struct t_config_option *irc_config_look_topic_strip_colors;
+56 -8
View File
@@ -508,7 +508,7 @@ IRC_PROTOCOL_CALLBACK(join)
struct t_irc_nick *ptr_nick;
struct t_irc_channel_speaking *ptr_nick_speaking;
char *pos_channel;
int local_join, display_host;
int local_join, display_host, smart_filter;
IRC_PROTOCOL_MIN_ARGS(3);
IRC_PROTOCOL_CHECK_HOST;
@@ -578,16 +578,23 @@ IRC_PROTOCOL_CALLBACK(join)
display_host = (local_join) ?
weechat_config_boolean (irc_config_look_display_host_join_local) :
weechat_config_boolean (irc_config_look_display_host_join);
/*
* "smart" filter the join message is it's not a join from myself, if
* smart filtering is enabled, and if nick was not speaking in channel
*/
smart_filter = (!local_join
&& weechat_config_boolean (irc_config_look_smart_filter)
&& weechat_config_boolean (irc_config_look_smart_filter_join)
&& !ptr_nick_speaking);
/* display the join */
weechat_printf_date_tags (irc_msgbuffer_get_target_buffer (server, NULL,
command, NULL,
ptr_channel->buffer),
date,
irc_protocol_tags (command,
(local_join
|| !weechat_config_boolean (irc_config_look_smart_filter)
|| !weechat_config_boolean (irc_config_look_smart_filter_join)
|| ptr_nick_speaking) ?
NULL : "irc_smart_filter",
smart_filter ? "irc_smart_filter" : NULL,
nick),
_("%s%s%s%s%s%s%s%s%s%s has joined %s%s%s"),
weechat_prefix ("join"),
@@ -604,6 +611,14 @@ IRC_PROTOCOL_CALLBACK(join)
pos_channel,
IRC_COLOR_MESSAGE_JOIN);
/*
* if join is smart filtered, save the nick in hashtable, and if nick
* is speaking shortly after the join, it will be unmasked
* (option irc.look.smart_filter_join_unmask)
*/
if (smart_filter)
irc_channel_join_smart_filtered_add (ptr_channel, nick, time (NULL));
/* display message in private if private has flag "has_quit_server" */
if (!local_join)
irc_channel_display_nick_back_in_pv (server, ptr_nick, nick);
@@ -996,6 +1011,8 @@ IRC_PROTOCOL_CALLBACK(nick)
nick, new_nick);
irc_channel_nick_speaking_time_rename (server, ptr_channel,
nick, new_nick);
irc_channel_join_smart_filtered_rename (ptr_channel,
nick, new_nick);
}
if (old_color)
@@ -1078,6 +1095,14 @@ IRC_PROTOCOL_CALLBACK(notice)
{
/* notice for channel */
ptr_channel = irc_channel_search (server, pos_target);
/*
* unmask a smart filtered join if it is in hashtable
* "join_smart_filtered" of channel
*/
if (ptr_channel)
irc_channel_join_smart_filtered_unmask (ptr_channel, nick);
ptr_nick = irc_nick_search (server, ptr_channel, nick);
weechat_printf_date_tags ((ptr_channel) ? ptr_channel->buffer : server->buffer,
date,
@@ -1390,7 +1415,12 @@ IRC_PROTOCOL_CALLBACK(part)
}
}
else
{
/* part from another user */
irc_channel_join_smart_filtered_remove (ptr_channel,
ptr_nick->name);
irc_nick_free (server, ptr_channel, ptr_nick);
}
}
}
@@ -1506,6 +1536,12 @@ IRC_PROTOCOL_CALLBACK(privmsg)
ptr_channel = irc_channel_search (server, pos_target);
if (ptr_channel)
{
/*
* unmask a smart filtered join if it is in hashtable
* "join_smart_filtered" of channel
*/
irc_channel_join_smart_filtered_unmask (ptr_channel, nick);
/* CTCP to channel */
if ((pos_args[0] == '\01')
&& (pos_args[strlen (pos_args) - 1] == '\01'))
@@ -1673,10 +1709,10 @@ IRC_PROTOCOL_CALLBACK(quit)
if (ptr_nick
|| (irc_server_strcasecmp (server, ptr_channel->name, nick) == 0))
{
/* display quit message */
local_quit = (irc_server_strcasecmp (server, nick, server->nick) == 0);
if (!irc_ignore_check (server, ptr_channel->name, nick, host))
{
local_quit = (irc_server_strcasecmp (server, nick, server->nick) == 0);
/* display quit message */
ptr_nick_speaking = NULL;
if (ptr_channel->type == IRC_CHANNEL_TYPE_CHANNEL)
{
@@ -1749,6 +1785,11 @@ IRC_PROTOCOL_CALLBACK(quit)
IRC_COLOR_MESSAGE_QUIT);
}
}
if (!local_quit && ptr_nick)
{
irc_channel_join_smart_filtered_remove (ptr_channel,
ptr_nick->name);
}
if (ptr_nick)
irc_nick_free (server, ptr_channel, ptr_nick);
}
@@ -1855,6 +1896,13 @@ IRC_PROTOCOL_CALLBACK(topic)
ptr_nick = irc_nick_search (server, ptr_channel, nick);
ptr_buffer = (ptr_channel) ? ptr_channel->buffer : server->buffer;
/*
* unmask a smart filtered join if it is in hashtable
* "join_smart_filtered" of channel
*/
if (ptr_channel)
irc_channel_join_smart_filtered_unmask (ptr_channel, nick);
if (pos_topic && pos_topic[0])
{
topic_color = irc_color_decode (pos_topic,
+42 -14
View File
@@ -2688,14 +2688,11 @@ void
irc_server_check_join_manual_cb (void *data, struct t_hashtable *hashtable,
const void *key, const void *value)
{
struct t_irc_server *server;
/* make C compiler happy */
(void) data;
server = (struct t_irc_server *)data;
if (server)
{
if (*((time_t *)value) + (60 * 10) < time (NULL))
weechat_hashtable_remove (hashtable, key);
}
if (*((time_t *)value) + (60 * 10) < time (NULL))
weechat_hashtable_remove (hashtable, key);
}
/*
@@ -2707,13 +2704,33 @@ void
irc_server_check_join_noswitch_cb (void *data, struct t_hashtable *hashtable,
const void *key, const void *value)
{
struct t_irc_server *server;
/* make C compiler happy */
(void) data;
server = (struct t_irc_server *)data;
if (server)
if (*((time_t *)value) + (60 * 10) < time (NULL))
weechat_hashtable_remove (hashtable, key);
}
/*
* Callback called for each smart filtered join of a channel: deletes old
* entries in the hashtable.
*/
void
irc_server_check_join_smart_filtered_cb (void *data,
struct t_hashtable *hashtable,
const void *key, const void *value)
{
int unmask_delay;
/* make C compiler happy */
(void) data;
unmask_delay = weechat_config_integer (irc_config_look_smart_filter_join_unmask);
if ((unmask_delay == 0)
|| (*((time_t *)value) < time (NULL) - (unmask_delay * 60)))
{
if (*((time_t *)value) + (60 * 10) < time (NULL))
weechat_hashtable_remove (hashtable, key);
weechat_hashtable_remove (hashtable, key);
}
}
@@ -2725,6 +2742,7 @@ int
irc_server_timer_cb (void *data, int remaining_calls)
{
struct t_irc_server *ptr_server;
struct t_irc_channel *ptr_channel;
struct t_irc_redirect *ptr_redirect, *ptr_next_redirect;
time_t current_time;
static struct timeval tv;
@@ -2835,10 +2853,20 @@ irc_server_timer_cb (void *data, int remaining_calls)
{
weechat_hashtable_map (ptr_server->join_manual,
&irc_server_check_join_manual_cb,
ptr_server);
NULL);
weechat_hashtable_map (ptr_server->join_noswitch,
&irc_server_check_join_noswitch_cb,
ptr_server);
NULL);
for (ptr_channel = ptr_server->channels; ptr_channel;
ptr_channel = ptr_channel->next_channel)
{
if (ptr_channel->join_smart_filtered)
{
weechat_hashtable_map (ptr_channel->join_smart_filtered,
&irc_server_check_join_smart_filtered_cb,
NULL);
}
}
ptr_server->last_data_purge = current_time;
}
}
+36 -2
View File
@@ -284,8 +284,10 @@ irc_upgrade_read_cb (void *data,
int object_id,
struct t_infolist *infolist)
{
int flags, sock, size, i, index;
char *buf, option_name[64];
int flags, sock, size, i, index, nicks_count;
long number;
time_t join_time;
char *buf, option_name[64], **nicks, *nick_join, *pos, *error;
const char *buffer_name, *str, *nick;
struct t_irc_nick *ptr_nick;
struct t_irc_redirect *ptr_redirect;
@@ -482,6 +484,38 @@ irc_upgrade_read_cb (void *data,
option_name));
index++;
}
str = weechat_infolist_string (infolist, "join_smart_filtered");
if (str)
{
nicks = weechat_string_split (str, ",", 0, 0,
&nicks_count);
if (nicks)
{
for (i = 0; i < nicks_count; i++)
{
pos = strchr (nicks[i], ':');
if (pos)
{
nick_join = weechat_strndup (nicks[i],
pos - nicks[i]);
if (nick_join)
{
error = NULL;
number = strtol (pos + 1, &error, 10);
if (error && !error[0])
{
join_time = (time_t)number;
irc_channel_join_smart_filtered_add (irc_upgrade_current_channel,
nick_join,
join_time);
}
free (nick_join);
}
}
}
weechat_string_free_split (nicks);
}
}
}
}
break;