diff --git a/docs/help/in/ignore.in b/docs/help/in/ignore.in index 26c269a4..fbb23fe4 100644 --- a/docs/help/in/ignore.in +++ b/docs/help/in/ignore.in @@ -40,6 +40,19 @@ Some suggestions for ignoring annoying public aways: /IGNORE *afk* NICKS /IGNORE *away* NICKS +The special level "NO_ACT" can be used to ignore activity ("Act:") but not +actually ignore the message entirely. It is somewhat special because it is +allowed in addition to another ignore for the same target. + +Examples: + + /IGNORE #channel NO_ACT JOINS PARTS QUITS - hide joins, etc from activity + /IGNORE nick NO_ACT -MSGS - ignore activity from nick, except for /MSG + /IGNORE -regexp -pattern . -except nick NO_ACT HILIGHT + - combined with the ignore above show hilights from this nick (needs to be + an except as "PUBLIC HILIGHT" still matches public, the regexp is used to + have more than one ignore for "nick"). + For regular expressions, see `man 7 regex`. See also: UNIGNORE, SILENCE, ACCEPT diff --git a/src/core/ignore.c b/src/core/ignore.c index eda232c7..3c45967c 100644 --- a/src/core/ignore.c +++ b/src/core/ignore.c @@ -58,30 +58,6 @@ static int ignore_check_replies_rec(IGNORE_REC *rec, CHANNEL_REC *channel, return FALSE; } -#define ignore_match_channel(rec, channel) \ - ((rec)->channels == NULL || ((channel) != NULL && \ - strarray_find((rec)->channels, (channel)) != -1)) - -static int ignore_check_replies(CHANNEL_REC *chanrec, const char *text) -{ - GSList *tmp; - - if (text == NULL || chanrec == NULL) - return FALSE; - - /* check reply ignores */ - for (tmp = ignores; tmp != NULL; tmp = tmp->next) { - IGNORE_REC *rec = tmp->data; - - if (rec->mask != NULL && rec->replies && - ignore_match_channel(rec, chanrec->name) && - ignore_check_replies_rec(rec, chanrec, text)) - return TRUE; - } - - return FALSE; -} - static int ignore_match_pattern(IGNORE_REC *rec, const char *text) { if (rec->pattern == NULL) @@ -104,8 +80,15 @@ static int ignore_match_pattern(IGNORE_REC *rec, const char *text) stristr(text, rec->pattern) != NULL; } +/* MSGLEVEL_NO_ACT is special in ignores, when provided to ignore_check() it's + * used as a flag to indicate it should only look at ignore items with NO_ACT. + * However we also want to allow NO_ACT combined with levels, so mask it out and + * match levels if set. */ #define ignore_match_level(rec, level) \ - ((level & (rec)->level) != 0) + (((level & MSGLEVEL_NO_ACT) != 0) ? \ + ((~MSGLEVEL_NO_ACT & level) & (rec)->level) != 0 : \ + ((rec)->level & MSGLEVEL_NO_ACT ? 0 : \ + (level & (rec)->level) != 0)) #define ignore_match_nickmask(rec, nick, nickmask) \ ((rec)->mask == NULL || \ @@ -117,6 +100,31 @@ static int ignore_match_pattern(IGNORE_REC *rec, const char *text) ((rec)->servertag == NULL || \ g_ascii_strcasecmp((server)->tag, (rec)->servertag) == 0) +#define ignore_match_channel(rec, channel) \ + ((rec)->channels == NULL || ((channel) != NULL && \ + strarray_find((rec)->channels, (channel)) != -1)) + +static int ignore_check_replies(CHANNEL_REC *chanrec, const char *text, int level) +{ + GSList *tmp; + + if (text == NULL || chanrec == NULL) + return FALSE; + + /* check reply ignores */ + for (tmp = ignores; tmp != NULL; tmp = tmp->next) { + IGNORE_REC *rec = tmp->data; + + if (rec->mask != NULL && rec->replies && + ignore_match_level(rec, level) && + ignore_match_channel(rec, chanrec->name) && + ignore_check_replies_rec(rec, chanrec, text)) + return TRUE; + } + + return FALSE; +} + int ignore_check(SERVER_REC *server, const char *nick, const char *host, const char *channel, const char *text, int level) { @@ -176,11 +184,18 @@ int ignore_check(SERVER_REC *server, const char *nick, const char *host, if (best_match || (level & MSGLEVEL_PUBLIC) == 0) return best_match; - return ignore_check_replies(chanrec, text); + return ignore_check_replies(chanrec, text, level); } IGNORE_REC *ignore_find(const char *servertag, const char *mask, - char **channels) + char **channels) +{ + return ignore_find_noact(servertag, mask, channels, 0); +} + + +IGNORE_REC *ignore_find_noact(const char *servertag, const char *mask, + char **channels, int noact) { GSList *tmp; char **chan; @@ -202,6 +217,12 @@ IGNORE_REC *ignore_find(const char *servertag, const char *mask, continue; } + if (noact && (rec->level & MSGLEVEL_NO_ACT) == 0) + continue; + + if (!noact && (rec->level & MSGLEVEL_NO_ACT) != 0) + continue; + if ((rec->mask == NULL && mask != NULL) || (rec->mask != NULL && mask == NULL)) continue; diff --git a/src/core/ignore.h b/src/core/ignore.h index 4abfaca5..46025d4c 100644 --- a/src/core/ignore.h +++ b/src/core/ignore.h @@ -32,6 +32,7 @@ int ignore_check(SERVER_REC *server, const char *nick, const char *host, const char *channel, const char *text, int level); IGNORE_REC *ignore_find(const char *servertag, const char *mask, char **channels); +IGNORE_REC *ignore_find_noact(const char *servertag, const char *mask, char **channels, int noact); void ignore_add_rec(IGNORE_REC *rec); void ignore_update_rec(IGNORE_REC *rec); diff --git a/src/core/levels.c b/src/core/levels.c index b47079ba..7997ba98 100644 --- a/src/core/levels.c +++ b/src/core/levels.c @@ -136,19 +136,25 @@ char *bits2level(int bits) if (bits == 0) return g_strdup(""); - if (bits == MSGLEVEL_ALL) - return g_strdup("ALL"); str = g_string_new(NULL); - if (bits & MSGLEVEL_NEVER) + if (bits & MSGLEVEL_NEVER) { g_string_append(str, "NEVER "); + bits &= ~MSGLEVEL_NEVER; + } - if (bits & MSGLEVEL_NO_ACT) + if (bits & MSGLEVEL_NO_ACT) { g_string_append(str, "NO_ACT "); + bits &= ~MSGLEVEL_NO_ACT; + } - for (n = 0; levels[n] != NULL; n++) { - if (bits & (1L << n)) - g_string_append_printf(str, "%s ", levels[n]); + if (bits == MSGLEVEL_ALL) { + g_string_append(str, "ALL "); + } else { + for (n = 0; levels[n] != NULL; n++) { + if (bits & (1L << n)) + g_string_append_printf(str, "%s ", levels[n]); + } } if (str->len > 0) g_string_truncate(str, str->len-1); diff --git a/src/fe-common/core/fe-ignore.c b/src/fe-common/core/fe-ignore.c index 6d53bf1b..96242f9e 100644 --- a/src/fe-common/core/fe-ignore.c +++ b/src/fe-common/core/fe-ignore.c @@ -120,7 +120,7 @@ static void cmd_ignore(const char *data) char *patternarg, *chanarg, *mask, *levels, *timestr, *servertag; char **channels; void *free_arg; - int new_ignore, msecs; + int new_ignore, msecs, level; if (*data == '\0') { cmd_ignore_show(); @@ -140,6 +140,7 @@ static void cmd_ignore(const char *data) if (*mask == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS); if (*levels == '\0') levels = "ALL"; + level = level2bits(levels, NULL); msecs = 0; timestr = g_hash_table_lookup(optlist, "time"); @@ -156,7 +157,8 @@ static void cmd_ignore(const char *data) channels = (chanarg == NULL || *chanarg == '\0') ? NULL : g_strsplit(chanarg, ",", -1); - rec = patternarg != NULL ? NULL: ignore_find(servertag, mask, channels); + rec = patternarg != NULL ? NULL: ignore_find_noact(servertag, mask, channels, + (level & MSGLEVEL_NO_ACT)); new_ignore = rec == NULL; if (rec == NULL) { @@ -172,6 +174,12 @@ static void cmd_ignore(const char *data) rec->level = combine_level(rec->level, levels); + if (rec->level == MSGLEVEL_NO_ACT) { + /* If only NO_ACT was specified add all levels; it makes no + * sense on its own. */ + rec->level |= MSGLEVEL_ALL; + } + if (new_ignore && rec->level == 0) { /* tried to unignore levels from nonexisting ignore */ printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, @@ -228,7 +236,10 @@ static void cmd_unignore(const char *data) chans[0] = mask; mask = NULL; } - rec = ignore_find("*", mask, (char **) chans); + rec = ignore_find_noact("*", mask, (char **) chans, 0); + if (rec == NULL) { + rec = ignore_find_noact("*", mask, (char **) chans, 1); + } } if (rec != NULL) { diff --git a/src/fe-common/core/fe-messages.c b/src/fe-common/core/fe-messages.c index 367863c7..67c95745 100644 --- a/src/fe-common/core/fe-messages.c +++ b/src/fe-common/core/fe-messages.c @@ -190,7 +190,7 @@ static void sig_message_public(SERVER_REC *server, const char *msg, if (for_me) level |= MSGLEVEL_HILIGHT; - if (ignore_check(server, nick, address, target, msg, MSGLEVEL_NO_ACT)) + if (ignore_check(server, nick, address, target, msg, level | MSGLEVEL_NO_ACT)) level |= MSGLEVEL_NO_ACT; if (settings_get_bool("emphasis")) @@ -238,13 +238,17 @@ static void sig_message_private(SERVER_REC *server, const char *msg, { QUERY_REC *query; char *freemsg = NULL; + int level = MSGLEVEL_MSGS; query = query_find(server, nick); if (settings_get_bool("emphasis")) msg = freemsg = expand_emphasis((WI_ITEM_REC *) query, msg); - printformat(server, nick, MSGLEVEL_MSGS, + if (ignore_check(server, nick, address, NULL, msg, level | MSGLEVEL_NO_ACT)) + level |= MSGLEVEL_NO_ACT; + + printformat(server, nick, level, query == NULL ? TXT_MSG_PRIVATE : TXT_MSG_PRIVATE_QUERY, nick, address, msg); @@ -330,7 +334,7 @@ static void sig_message_join(SERVER_REC *server, const char *channel, { int level = MSGLEVEL_JOINS; - if (ignore_check(server, nick, address, channel, NULL, MSGLEVEL_NO_ACT)) + if (ignore_check(server, nick, address, channel, NULL, level | MSGLEVEL_NO_ACT)) level |= MSGLEVEL_NO_ACT; printformat(server, channel, level, @@ -343,7 +347,7 @@ static void sig_message_part(SERVER_REC *server, const char *channel, { int level = MSGLEVEL_PARTS; - if (ignore_check(server, nick, address, channel, NULL, MSGLEVEL_NO_ACT)) + if (ignore_check(server, nick, address, channel, NULL, level | MSGLEVEL_NO_ACT)) level |= MSGLEVEL_NO_ACT; printformat(server, channel, level, @@ -362,7 +366,7 @@ static void sig_message_quit(SERVER_REC *server, const char *nick, if (ignore_check(server, nick, address, NULL, reason, MSGLEVEL_QUITS)) return; - if (ignore_check(server, nick, address, NULL, reason, MSGLEVEL_NO_ACT)) + if (ignore_check(server, nick, address, NULL, reason, level | MSGLEVEL_NO_ACT)) level |= MSGLEVEL_NO_ACT; print_channel = NULL; @@ -432,7 +436,7 @@ static void sig_message_kick(SERVER_REC *server, const char *channel, { int level = MSGLEVEL_KICKS; - if (ignore_check(server, kicker, address, channel, reason, MSGLEVEL_NO_ACT)) + if (ignore_check(server, kicker, address, channel, reason, level | MSGLEVEL_NO_ACT)) level |= MSGLEVEL_NO_ACT; printformat(server, channel, level, @@ -453,7 +457,7 @@ static void print_nick_change_channel(SERVER_REC *server, const char *channel, level = MSGLEVEL_NICKS; if (ownnick) level |= MSGLEVEL_NO_ACT; - if (!(level & MSGLEVEL_NO_ACT) && ignore_check(server, oldnick, address, channel, newnick, MSGLEVEL_NO_ACT)) + if (!(level & MSGLEVEL_NO_ACT) && ignore_check(server, oldnick, address, channel, newnick, level | MSGLEVEL_NO_ACT)) level |= MSGLEVEL_NO_ACT; printformat(server, channel, level, @@ -532,7 +536,7 @@ static void sig_message_topic(SERVER_REC *server, const char *channel, { int level = MSGLEVEL_TOPICS; - if (ignore_check(server, nick, address, channel, topic, MSGLEVEL_NO_ACT)) + if (ignore_check(server, nick, address, channel, topic, level | MSGLEVEL_NO_ACT)) level |= MSGLEVEL_NO_ACT; printformat(server, channel, level, diff --git a/src/fe-common/core/hilight-text.c b/src/fe-common/core/hilight-text.c index 34c5c643..d4eeb1f3 100644 --- a/src/fe-common/core/hilight-text.c +++ b/src/fe-common/core/hilight-text.c @@ -336,6 +336,12 @@ static void sig_print_text(TEXT_DEST_REC *dest, const char *text, if (!nick_match || (dest->level & MSGLEVEL_HILIGHT)) { /* update the level / hilight info */ hilight_update_text_dest(dest, hilight); + /* Remove NO_ACT, this means explicitly defined hilights will bypass + * /IGNORE ... NO_ACT. + * (It's still possible to use /hilight -actcolor %n to hide + * hilight/beep). + */ + dest->level &= ~MSGLEVEL_NO_ACT; } if (nick_match) diff --git a/src/fe-common/irc/dcc/fe-dcc-chat-messages.c b/src/fe-common/irc/dcc/fe-dcc-chat-messages.c index 23ccc943..93e10943 100644 --- a/src/fe-common/irc/dcc/fe-dcc-chat-messages.c +++ b/src/fe-common/irc/dcc/fe-dcc-chat-messages.c @@ -25,6 +25,7 @@ #include "irc-servers.h" #include "irc-queries.h" #include "dcc-chat.h" +#include "ignore.h" #include "module-formats.h" #include "printtext.h" @@ -86,12 +87,17 @@ static void sig_message_dcc(CHAT_DCC_REC *dcc, const char *msg) TEXT_DEST_REC dest; QUERY_REC *query; char *tag; + int level = MSGLEVEL_DCCMSGS; tag = g_strconcat("=", dcc->id, NULL); query = query_find(NULL, tag); + if (ignore_check(SERVER(dcc->server), tag, dcc->addrstr, NULL, msg, + level | MSGLEVEL_NO_ACT)) + level |= MSGLEVEL_NO_ACT; + format_create_dest_tag(&dest, dcc->server, dcc->servertag, tag, - MSGLEVEL_DCCMSGS, NULL); + level, NULL); printformat_dest(&dest, query != NULL ? IRCTXT_DCC_MSG_QUERY : IRCTXT_DCC_MSG, dcc->id, msg); @@ -103,12 +109,17 @@ static void sig_message_dcc_action(CHAT_DCC_REC *dcc, const char *msg) TEXT_DEST_REC dest; QUERY_REC *query; char *tag; + int level = MSGLEVEL_DCCMSGS | MSGLEVEL_ACTIONS; tag = g_strconcat("=", dcc->id, NULL); query = query_find(NULL, tag); + if (ignore_check(SERVER(dcc->server), tag, dcc->addrstr, NULL, msg, + level | MSGLEVEL_NO_ACT)) + level |= MSGLEVEL_NO_ACT; + format_create_dest_tag(&dest, dcc->server, dcc->servertag, tag, - MSGLEVEL_DCCMSGS | MSGLEVEL_ACTIONS, NULL); + level, NULL); printformat_dest(&dest, query != NULL ? IRCTXT_ACTION_DCC_QUERY : IRCTXT_ACTION_DCC, dcc->id, msg); @@ -120,11 +131,16 @@ static void sig_message_dcc_ctcp(CHAT_DCC_REC *dcc, const char *cmd, { TEXT_DEST_REC dest; char *tag; + int level = MSGLEVEL_DCCMSGS | MSGLEVEL_CTCPS; tag = g_strconcat("=", dcc->id, NULL); + if (ignore_check(SERVER(dcc->server), tag, dcc->addrstr, NULL, cmd, + level | MSGLEVEL_NO_ACT)) + level |= MSGLEVEL_NO_ACT; + format_create_dest_tag(&dest, dcc->server, dcc->servertag, tag, - MSGLEVEL_DCC | MSGLEVEL_CTCPS, NULL); + level, NULL); printformat_dest(&dest, IRCTXT_DCC_CTCP, dcc->id, cmd, data); g_free(tag); diff --git a/src/fe-common/irc/fe-irc-messages.c b/src/fe-common/irc/fe-irc-messages.c index fb8d1e94..a8d52745 100644 --- a/src/fe-common/irc/fe-irc-messages.c +++ b/src/fe-common/irc/fe-irc-messages.c @@ -170,6 +170,10 @@ static void sig_message_irc_action(IRC_SERVER_REC *server, const char *msg, if (ignore_check(SERVER(server), nick, address, target, msg, level)) return; + if (ignore_check(SERVER(server), nick, address, target, msg, + level | MSGLEVEL_NO_ACT)) + level |= MSGLEVEL_NO_ACT; + if (ischannel(*target)) item = irc_channel_find(server, target); else @@ -214,6 +218,7 @@ static void sig_message_irc_notice(SERVER_REC *server, const char *msg, const char *target) { const char *oldtarget; + int level = MSGLEVEL_NOTICES; oldtarget = target; target = skip_target(IRC_SERVER(server), target); @@ -230,18 +235,23 @@ static void sig_message_irc_notice(SERVER_REC *server, const char *msg, if (ignore_check(server, nick, address, ischannel(*target) ? target : NULL, - msg, MSGLEVEL_NOTICES)) + msg, level)) return; + if (ignore_check(server, nick, address, + ischannel(*target) ? target : NULL, + msg, level | MSGLEVEL_NO_ACT)) + level |= MSGLEVEL_NO_ACT; + if (ischannel(*target)) { /* notice in some channel */ - printformat(server, target, MSGLEVEL_NOTICES, + printformat(server, target, level, IRCTXT_NOTICE_PUBLIC, nick, oldtarget, msg); } else { /* private notice */ privmsg_get_query(SERVER(server), nick, FALSE, MSGLEVEL_NOTICES); - printformat(server, nick, MSGLEVEL_NOTICES, + printformat(server, nick, level, IRCTXT_NOTICE_PRIVATE, nick, address, msg); } }