diff --git a/chat.h b/chat.h index c7af680..b06d383 100644 --- a/chat.h +++ b/chat.h @@ -353,13 +353,16 @@ void urlOpenCount(uint id, uint count); void urlOpenMatch(uint id, const char *str); void urlCopyMatch(uint id, const char *str); -enum { IgnoreCap = 256 }; +enum { IgnoreCap = 64 }; extern struct Ignore { - size_t len; - char *patterns[IgnoreCap]; -} ignore; -const char *ignoreAdd(const char *pattern); -bool ignoreRemove(const char *pattern); + char *mask; + char *cmd; + char *chan; + char *mesg; +} ignores[IgnoreCap]; +struct Ignore ignoreParse(char *pattern); +struct Ignore ignoreAdd(const char *pattern); +bool ignoreRemove(struct Ignore ignore); enum Heat ignoreCheck(enum Heat heat, uint id, const struct Message *msg); extern bool logEnable; diff --git a/command.c b/command.c index 43870f1..c71bebc 100644 --- a/command.c +++ b/command.c @@ -388,16 +388,19 @@ static void commandCopy(uint id, char *params) { static void commandIgnore(uint id, char *params) { if (params) { - const char *pattern = ignoreAdd(params); + struct Ignore ignore = ignoreAdd(params); uiFormat( - id, Cold, NULL, "Ignoring \3%02d%s\3", - Brown, pattern + id, Cold, NULL, "Ignoring \3%02d%s %s %s %s", + Brown, ignore.mask, + (ignore.cmd ?: ""), (ignore.chan ?: ""), (ignore.mesg ?: "") ); } else { - for (size_t i = 0; i < ignore.len; ++i) { + for (size_t i = 0; i < IgnoreCap && ignores[i].mask; ++i) { uiFormat( - Network, Warm, NULL, "Ignoring \3%02d%s\3", - Brown, ignore.patterns[i] + Network, Warm, NULL, "Ignoring \3%02d%s %s %s %s", + Brown, ignores[i].mask, + (ignores[i].cmd ?: ""), (ignores[i].chan ?: ""), + (ignores[i].mesg ?: "") ); } } @@ -405,14 +408,13 @@ static void commandIgnore(uint id, char *params) { static void commandUnignore(uint id, char *params) { if (!params) return; - if (ignoreRemove(params)) { - uiFormat( - id, Cold, NULL, "No longer ignoring \3%02d%s\3", - Brown, params - ); - } else { - uiFormat(id, Cold, NULL, "Not ignoring \3%02d%s\3", Brown, params); - } + struct Ignore ignore = ignoreParse(params); + bool found = ignoreRemove(ignore); + uiFormat( + id, Cold, NULL, "%s ignoring \3%02d%s %s %s %s", + (found ? "No longer" : "Not"), Brown, ignore.mask, + (ignore.cmd ?: ""), (ignore.chan ?: ""), (ignore.mesg ?: "") + ); } static void commandExec(uint id, char *params) { diff --git a/ignore.c b/ignore.c index f8e4d59..5a9d296 100644 --- a/ignore.c +++ b/ignore.c @@ -35,55 +35,70 @@ #include "chat.h" -struct Ignore ignore; +struct Ignore ignores[IgnoreCap]; +static size_t len; -const char *ignoreAdd(const char *pattern) { - if (ignore.len == IgnoreCap) errx(EX_CONFIG, "ignore limit exceeded"); - uint ex = 0, sp = 0; - for (const char *ch = pattern; *ch; ++ch) { - if (*ch == '!') ex++; - if (*ch == ' ') sp++; - } - char **dest = &ignore.patterns[ignore.len++]; - int n = 0; - if (!ex && !sp) { - n = asprintf(dest, "%s!*@* * * *", pattern); - } else if (sp < 1) { - n = asprintf(dest, "%s * * *", pattern); - } else if (sp < 2) { - n = asprintf(dest, "%s * *", pattern); - } else if (sp < 3) { - n = asprintf(dest, "%s *", pattern); - } else { - *dest = strdup(pattern); - } - if (n < 0) err(EX_OSERR, "asprintf"); - if (!*dest) err(EX_OSERR, "strdup"); - return *dest; +struct Ignore ignoreParse(char *pattern) { + struct Ignore ignore = {0}; + ignore.mask = strsep(&pattern, " "); + ignore.cmd = strsep(&pattern, " "); + ignore.chan = strsep(&pattern, " "); + ignore.mesg = pattern; + return ignore; } -bool ignoreRemove(const char *pattern) { +struct Ignore ignoreAdd(const char *pattern) { + if (len == IgnoreCap) errx(EX_CONFIG, "ignore limit exceeded"); + char *own; + if (!strchr(pattern, '!') && !strchr(pattern, ' ')) { + int n = asprintf(&own, "%s!*@*", pattern); + if (n < 0) err(EX_OSERR, "asprintf"); + } else { + own = strdup(pattern); + if (!own) err(EX_OSERR, "strdup"); + } + struct Ignore ignore = ignoreParse(own); + ignores[len++] = ignore; + return ignore; +} + +bool ignoreRemove(struct Ignore ignore) { bool found = false; - for (size_t i = 0; i < ignore.len; ++i) { - if (strcasecmp(ignore.patterns[i], pattern)) continue; - free(ignore.patterns[i]); - ignore.patterns[i] = ignore.patterns[--ignore.len]; + for (size_t i = len - 1; i < len; --i) { + if (!ignores[i].cmd != !ignore.cmd) continue; + if (!ignores[i].chan != !ignore.chan) continue; + if (!ignores[i].mesg != !ignore.mesg) continue; + if (strcasecmp(ignores[i].mask, ignore.mask)) continue; + if (ignore.cmd && strcasecmp(ignores[i].cmd, ignore.cmd)) continue; + if (ignore.chan && strcasecmp(ignores[i].chan, ignore.chan)) continue; + if (ignore.mesg && strcasecmp(ignores[i].mesg, ignore.mesg)) continue; + free(ignores[i].mask); + ignores[i] = ignores[--len]; + ignores[len] = (struct Ignore) {0}; found = true; } return found; } +static bool ignoreTest( + struct Ignore ignore, const char *mask, uint id, const struct Message *msg +) { + if (fnmatch(ignore.mask, mask, FNM_CASEFOLD)) return false; + if (!ignore.cmd) return true; + if (fnmatch(ignore.cmd, msg->cmd, FNM_CASEFOLD)) return false; + if (!ignore.chan) return true; + if (fnmatch(ignore.chan, idNames[id], FNM_CASEFOLD)) return false; + if (!ignore.mesg) return true; + if (!msg->params[1]) return false; + return !fnmatch(ignore.mesg, msg->params[1], FNM_CASEFOLD); +} + enum Heat ignoreCheck(enum Heat heat, uint id, const struct Message *msg) { - if (!ignore.len) return heat; - char match[512]; - snprintf( - match, sizeof(match), "%s!%s@%s %s %s %s", - msg->nick, msg->user, msg->host, - msg->cmd, idNames[id], (msg->params[1] ?: "") - ); - for (size_t i = 0; i < ignore.len; ++i) { - if (fnmatch(ignore.patterns[i], match, FNM_CASEFOLD)) continue; - return Ice; + if (!len) return heat; + char mask[512]; + snprintf(mask, sizeof(mask), "%s!%s@%s", msg->nick, msg->user, msg->host); + for (size_t i = 0; i < len; ++i) { + if (ignoreTest(ignores[i], mask, id, msg)) return Ice; } return heat; }