hirc

IRC client
Log | Files | Refs

commit b14cddecd20b960054a4431ee91b0abff7ce4c85
parent 0c574f860ec243e36855f28096363780a6509388
Author: hhvn <dev@hhvn.uk>
Date:   Mon, 28 Mar 2022 18:12:07 +0100

/ignore

Diffstat:
Mhirc.1.footer | 3+++
Msrc/chan.c | 2+-
Msrc/commands.c | 98+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/config.c | 22+++++++++++++++++++++-
Msrc/handle.c | 1+
Msrc/hirc.h | 3+++
Msrc/hist.c | 33++++++++++++++++++++++++++-------
Msrc/main.c | 2+-
Msrc/serv.c | 2+-
Msrc/struct.h | 13+++++++++++++
Msrc/ui.c | 22+++++++++++++++-------
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;