commit b14cddecd20b960054a4431ee91b0abff7ce4c85
parent 0c574f860ec243e36855f28096363780a6509388
Author: hhvn <dev@hhvn.uk>
Date: Mon, 28 Mar 2022 18:12:07 +0100
/ignore
Diffstat:
11 files changed, 183 insertions(+), 18 deletions(-)
diff --git a/hirc.1.footer b/hirc.1.footer
@@ -23,6 +23,9 @@ Bind alt-1 so that it selects buffer 1.
.Dl /alias /unalias /alias -delete
Alias '/unalias' to '/alias -delete',
so that '/unalias /command` is translated to `/alias -delete /command`
+
+.Dl /server hlircnet /ignore -E -server ^:[^ ]* (JOIN|PART|QUIT).*
+Ignore join, part and quit messages on server 'hlircnet'.
.Sh SEE ALSO
.Xr irssi 1
.Sh AUTHOR
diff --git a/src/chan.c b/src/chan.c
@@ -61,7 +61,7 @@ chan_create(struct Server *server, char *name, int priv) {
channel->server = server;
channel->history = emalloc(sizeof(struct HistInfo));
channel->history->activity = Activity_ignore;
- channel->history->unread = 0;
+ channel->history->unread = channel->history->ignored = 0;
channel->history->server = server;
channel->history->channel = channel;
if (server)
diff --git a/src/commands.c b/src/commands.c
@@ -112,6 +112,7 @@ COMMAND(command_scroll);
COMMAND(command_source);
COMMAND(command_dump);
COMMAND(command_close);
+COMMAND(command_ignore);
static char *command_optarg;
enum {
@@ -364,6 +365,21 @@ struct Command commands[] = {
{"close", command_close, 0, {
"usage: /close [id]",
"Forget about selected buffer, or a buffer by id.", NULL}},
+ {"ignore", command_ignore, 0, {
+ "usage: /ignore [[-server] regex]",
+ " /ignore -delete id",
+ " /ignore -hide|-show",
+ "Hide future messages matching regex.",
+ "Regexes should match a raw IRC message.",
+ "Display all rules if no argument given.",
+ " -show show ignored messages",
+ " -hide hide ignored messages",
+ " -delete delete rule with specified ID",
+ " -E use extended POSIX regex",
+ " -i case insensitive match",
+ " -server only ignore for the current server",
+ " or server provided by /server.",
+ "See also: regex.extended, regex.icase", NULL}},
{NULL, NULL},
};
@@ -1819,6 +1835,88 @@ command_close) {
}
}
+COMMAND(
+command_ignore) {
+ struct Ignore *ign, *p;
+ char errbuf[BUFSIZ];
+ int ret, raw = 0, i, regopt = 0, serv = 0;
+ enum { opt_show, opt_hide, opt_extended, opt_icase, opt_server };
+ static struct CommandOpts opts[] = {
+ {"E", CMD_NARG, opt_extended},
+ {"i", CMD_NARG, opt_icase},
+ {"show", CMD_NARG, opt_show},
+ {"hide", CMD_NARG, opt_hide},
+ {"server", CMD_NARG, opt_server},
+ {NULL, 0, 0},
+ };
+
+ if (!str) {
+ hist_format(selected.history, Activity_none, HIST_UI, "SELF_IGNORES_START :Ignoring:");
+ for (p = ignores, i = 1; p; p = p->next, i++)
+ if (!serv || !p->server || strcmp(server->name, p->server) == 0)
+ hist_format(selected.history, Activity_none, HIST_UI, "SELF_IGNORES_LIST %d %s :%s",
+ i, p->server ? p->server : "ANY", p->text);
+ hist_format(selected.history, Activity_none, HIST_UI, "SELF_IGNORES_END :End of ignore list");
+ return;
+ }
+
+ while ((ret = command_getopt(&str, opts)) != opt_done) {
+ switch (ret) {
+ case opt_error:
+ return;
+ case opt_show: case opt_hide:
+ if (*str) {
+ command_toomany("ignore");
+ } else {
+ selected.showign = ret == opt_show;
+ windows[Win_main].refresh = 1;
+ }
+ return;
+ case opt_extended:
+ regopt |= REG_EXTENDED;
+ break;
+ case opt_icase:
+ regopt |= REG_ICASE;
+ break;
+ case opt_server:
+ serv = 1;
+ break;
+ }
+ }
+
+ if (config_getl("regex.extended"))
+ regopt |= REG_EXTENDED;
+ if (config_getl("regex.icase"))
+ regopt |= REG_ICASE;
+
+ if (!*str) {
+ command_toofew("ignore");
+ return;
+ }
+
+ ign = emalloc(sizeof(struct Ignore));
+ ign->next = NULL;
+ if ((ret = regcomp(&ign->regex, str, regopt)) != 0) {
+ regerror(ret, &ign->regex, errbuf, sizeof(errbuf));
+ ui_error("%s: %s", errbuf, str);
+ free(ign);
+ return;
+ }
+ ign->text = strdup(str);
+ ign->regopt = regopt;
+ ign->server = serv ? strdup(server->name) : NULL;
+
+ hist_format(selected.history, Activity_none, HIST_UI, "SELF_IGNORES_ADDED %s :%s", serv ? server->name : "ANY", str);
+
+ if (!ignores) {
+ ignores = ign;
+ } else {
+ for (p = ignores; p && p->next; p = p->next);
+ ign->prev = p;
+ p->next = ign;
+ }
+}
+
static void
modelset(char *cmd, struct Server *server, struct Channel *channel,
int remove, char mode, char *args) {
diff --git a/src/config.c b/src/config.c
@@ -331,10 +331,30 @@ struct Config config[] = {
.description = {
"Format of log restore footer.", NULL}},
{"format.ui.unread", 1, Val_string,
- .str = "%{c:93}---%{=}%{c:93}%{b}${1}%{b} unread ---",
+ .str = "%{c:93}---%{=}%{c:93}%{b}${1}%{b} unread (%{b}${2}%{b} ignored) ---",
.strhandle = config_redraws,
.description = {
"Format of unread message indicator.", NULL}},
+ {"format.ui.ignores.start", 1, Val_string,
+ .str = "Ignoring:",
+ .strhandle = config_redraws,
+ .description = {
+ "Format of ignore list header.", NULL}},
+ {"format.ui.ignores", 1, Val_string,
+ .str = " %{pad:-3,${1}} ${2}: ${3}",
+ .strhandle = config_redraws,
+ .description = {
+ "Format of ignore list messages.", NULL}},
+ {"format.ui.ignores.end", 1, Val_string,
+ .str = "",
+ .strhandle = config_redraws,
+ .description = {
+ "Format of ignore list footer.", NULL}},
+ {"format.ui.ignores.added", 1, Val_string,
+ .str = "Ignore added: ${2} (server: ${1})",
+ .strhandle = config_redraws,
+ .description = {
+ "Format of new ignores.", NULL}},
{"format.ui.grep.start", 1, Val_string,
.str = "%{b}%{c:94}Results of ${1}:",
.strhandle = config_redraws,
diff --git a/src/handle.c b/src/handle.c
@@ -50,6 +50,7 @@ HANDLER(handle_ERR_NOSUCHNICK);
HANDLER(handle_ERR_NICKNAMEINUSE);
HANDLER(handle_RPL_AWAY);
+struct Ignore *ignores = NULL;
struct Handler handlers[] = {
{ "ERROR", handle_ERROR },
{ "PING", handle_PING },
diff --git a/src/hirc.h b/src/hirc.h
@@ -197,6 +197,9 @@ void config_read(char *filename);
extern struct Server *servers;
extern struct HistInfo *main_buf;
+/* handle.c */
+extern struct Ignore *ignores;
+
/* ui.c */
extern struct Selected selected;
extern struct Keybind *keybinds;
diff --git a/src/hist.c b/src/hist.c
@@ -20,6 +20,7 @@
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
+#include <regex.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
@@ -119,8 +120,12 @@ hist_add(struct HistInfo *histinfo,
time_t timestamp, enum HistOpt options) {
struct Nick *from = NULL;
struct History *new, *p;
+ struct Ignore *ign;
int i;
+ if (!histinfo)
+ return NULL;
+
if (options & HIST_MAIN) {
if (options & HIST_TMP && histinfo == main_buf) {
hist_add(main_buf, msg, activity, timestamp, HIST_SHOW);
@@ -133,6 +138,15 @@ hist_add(struct HistInfo *histinfo,
}
}
+ for (ign = ignores; ign; ign = ign->next) {
+ if (!ign->server || (histinfo->server && strcmp_n(ign->server, histinfo->server->name))) {
+ if (regexec(&ign->regex, msg, 0, NULL, 0) == 0) {
+ options |= HIST_IGN;
+ break;
+ }
+ }
+ }
+
if (options & HIST_SELF && histinfo->server) {
if (histinfo->channel && histinfo->channel->nicks)
from = nick_get(&histinfo->channel->nicks, histinfo->server->self->nick);
@@ -142,13 +156,6 @@ hist_add(struct HistInfo *histinfo,
new = hist_create(histinfo, from, msg, activity, timestamp, options);
- if (histinfo && options & HIST_SHOW && activity > histinfo->activity && histinfo != selected.history) {
- histinfo->activity = activity;
- windows[Win_buflist].refresh = 1;
- }
- if (histinfo && options & HIST_SHOW && histinfo != selected.history)
- histinfo->unread++;
-
if (!histinfo->history) {
histinfo->history = new;
goto ui;
@@ -165,6 +172,18 @@ hist_add(struct HistInfo *histinfo,
histinfo->history = new;
ui:
+ if (histinfo && options & HIST_SHOW && activity > histinfo->activity && histinfo != selected.history) {
+ histinfo->activity = activity;
+ windows[Win_buflist].refresh = 1;
+ }
+
+ if (histinfo && options & HIST_SHOW && histinfo != selected.history) {
+ if (options & HIST_IGN)
+ histinfo->ignored++;
+ else
+ histinfo->unread++;
+ }
+
if (options & HIST_LOG) {
if (histinfo->server)
hist_log(new);
diff --git a/src/main.c b/src/main.c
@@ -406,7 +406,7 @@ main(int argc, char *argv[]) {
main_buf = emalloc(sizeof(struct HistInfo));
main_buf->activity = Activity_ignore;
- main_buf->unread = 0;
+ main_buf->unread = main_buf->ignored = 0;
main_buf->server = NULL;
main_buf->channel = NULL;
main_buf->history = NULL;
diff --git a/src/serv.c b/src/serv.c
@@ -89,7 +89,7 @@ serv_create(char *name, char *host, char *port, char *nick,
server->self->self = 1;
server->history = emalloc(sizeof(struct HistInfo));
server->history->activity = Activity_ignore;
- server->history->unread = 0;
+ server->history->unread = server->history->ignored = 0;
server->history->server = server;
server->history->channel = NULL;
server->history->history = NULL;
diff --git a/src/struct.h b/src/struct.h
@@ -56,6 +56,7 @@ enum HistOpt {
HIST_ERR = 64, /* generated by ui_error and friends */
HIST_SERR = 128,/* generated by 400-599 numerics (which should be errors) */
HIST_RLOG = 256,/* messages read from log, useful for clearing the log */
+ HIST_IGN = 512,/* added to ignored messages */
HIST_DFL = HIST_SHOW|HIST_LOG,
HIST_UI = HIST_SHOW|HIST_TMP|HIST_MAIN,
HIST_ALL = 0xFFFF
@@ -79,6 +80,7 @@ struct History {
struct HistInfo {
enum Activity activity;
int unread;
+ int ignored;
struct Server *server;
struct Channel *channel;
struct History *history;
@@ -268,6 +270,7 @@ struct Selected {
struct Server *server;
struct HistInfo *history;
char *name;
+ int showign;
int hasnicks;
};
@@ -287,4 +290,14 @@ struct Alias {
struct Alias *next;
};
+#include <regex.h>
+struct Ignore {
+ struct Ignore *prev;
+ char *text;
+ regex_t regex;
+ int regopt;
+ char *server;
+ struct Ignore *next;
+};
+
#endif /* H_STRUCT */
diff --git a/src/ui.c b/src/ui.c
@@ -97,6 +97,10 @@ struct {
{"SELF_AUTOCMDS_END", "format.ui.autocmds.end"},
{"SELF_LOG_RESTORE", "format.ui.logrestore"},
{"SELF_UNREAD", "format.ui.unread"},
+ {"SELF_IGNORES_START", "format.ui.ignores.start"},
+ {"SELF_IGNORES_LIST", "format.ui.ignores"},
+ {"SELF_IGNORES_ADDED", "format.ui.ignores.added"},
+ {"SELF_IGNORES_END", "format.ui.ignores.end"},
/* Real commands/numerics from server */
{"PRIVMSG", "format.privmsg"},
{"NOTICE", "format.notice"},
@@ -1339,7 +1343,7 @@ ui_draw_main(void) {
werase(windows[Win_main].window);
for (i=0, p = selected.history->history, hp = NULL; p; p = p->next) {
- if (!(p->options & HIST_SHOW))
+ if (!(p->options & HIST_SHOW) || ((p->options & HIST_IGN) && !selected.showign))
continue;
if (windows[Win_main].scroll > 0 && !hp && !p->next)
hp = p;
@@ -1358,7 +1362,7 @@ ui_draw_main(void) {
hp = selected.history->history;
for (y = windows[Win_main].h; hp && y > 0; hp = hp->next) {
- if (!(hp->options & HIST_SHOW) || !hp->format)
+ if (!(hp->options & HIST_SHOW) || !hp->format || ((hp->options & HIST_IGN) && !selected.showign))
continue;
if (ui_strlenc(&windows[Win_main], hp->format, &lines) <= 0)
continue;
@@ -1382,7 +1386,7 @@ ui_draw_main(void) {
void
ui_select(struct Server *server, struct Channel *channel) {
struct History *hp, *ind;
- int i;
+ int i, total;
if (selected.history)
hist_purgeopt(selected.history, HIST_TMP);
@@ -1392,19 +1396,23 @@ ui_select(struct Server *server, struct Channel *channel) {
selected.history = channel ? channel->history : server ? server->history : main_buf;
selected.name = channel ? channel->name : server ? server->name : "hirc";
selected.hasnicks = channel ? !channel->priv && !channel->old : 0;
+ selected.showign = 0;
- if (selected.history->unread) {
+ if (selected.history->unread || selected.history->ignored) {
for (i = 0, hp = selected.history->history; hp && hp->next; hp = hp->next, i++);
if (i == (HIST_MAX-1)) {
pfree(&hp->next);
hp->next = NULL;
}
- for (i = 0, hp = selected.history->history; hp && hp->next && i < selected.history->unread; hp = hp->next)
+ total = selected.history->unread + selected.history->ignored;
+
+ for (i = 0, hp = selected.history->history; hp && hp->next && i < total; hp = hp->next)
if (hp->options & HIST_SHOW)
i++;
if (hp) {
- ind = hist_format(NULL, Activity_none, HIST_SHOW|HIST_TMP, "SELF_UNREAD %d :unread", selected.history->unread);
+ ind = hist_format(NULL, Activity_none, HIST_SHOW|HIST_TMP, "SELF_UNREAD %d %d :unread, ignored",
+ selected.history->unread, selected.history->ignored);
ind->origin = selected.history;
ind->next = hp;
ind->prev = hp->prev;
@@ -1416,7 +1424,7 @@ ui_select(struct Server *server, struct Channel *channel) {
selected.history->activity = Activity_none;
- selected.history->unread = 0;
+ selected.history->unread = selected.history->ignored = 0;
if (!selected.hasnicks)
windows[Win_nicklist].location = HIDDEN;