Split ignore fields to avoid over-eager * matching
Split ignore fields and match each separately to avoid an early * eagerly matching across several fields. For example, "* JOIN * *" should not match messages which happen to contain the word "JOIN" followed by two other words. Ignore capacity is reduced to 64 to keep the size of the array the same. I don't think it's an issue.master
parent
519fcc436f
commit
4b883177dc
15
chat.h
15
chat.h
|
@ -353,13 +353,16 @@ void urlOpenCount(uint id, uint count);
|
||||||
void urlOpenMatch(uint id, const char *str);
|
void urlOpenMatch(uint id, const char *str);
|
||||||
void urlCopyMatch(uint id, const char *str);
|
void urlCopyMatch(uint id, const char *str);
|
||||||
|
|
||||||
enum { IgnoreCap = 256 };
|
enum { IgnoreCap = 64 };
|
||||||
extern struct Ignore {
|
extern struct Ignore {
|
||||||
size_t len;
|
char *mask;
|
||||||
char *patterns[IgnoreCap];
|
char *cmd;
|
||||||
} ignore;
|
char *chan;
|
||||||
const char *ignoreAdd(const char *pattern);
|
char *mesg;
|
||||||
bool ignoreRemove(const char *pattern);
|
} 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);
|
enum Heat ignoreCheck(enum Heat heat, uint id, const struct Message *msg);
|
||||||
|
|
||||||
extern bool logEnable;
|
extern bool logEnable;
|
||||||
|
|
26
command.c
26
command.c
|
@ -388,16 +388,19 @@ static void commandCopy(uint id, char *params) {
|
||||||
|
|
||||||
static void commandIgnore(uint id, char *params) {
|
static void commandIgnore(uint id, char *params) {
|
||||||
if (params) {
|
if (params) {
|
||||||
const char *pattern = ignoreAdd(params);
|
struct Ignore ignore = ignoreAdd(params);
|
||||||
uiFormat(
|
uiFormat(
|
||||||
id, Cold, NULL, "Ignoring \3%02d%s\3",
|
id, Cold, NULL, "Ignoring \3%02d%s %s %s %s",
|
||||||
Brown, pattern
|
Brown, ignore.mask,
|
||||||
|
(ignore.cmd ?: ""), (ignore.chan ?: ""), (ignore.mesg ?: "")
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
for (size_t i = 0; i < ignore.len; ++i) {
|
for (size_t i = 0; i < IgnoreCap && ignores[i].mask; ++i) {
|
||||||
uiFormat(
|
uiFormat(
|
||||||
Network, Warm, NULL, "Ignoring \3%02d%s\3",
|
Network, Warm, NULL, "Ignoring \3%02d%s %s %s %s",
|
||||||
Brown, ignore.patterns[i]
|
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) {
|
static void commandUnignore(uint id, char *params) {
|
||||||
if (!params) return;
|
if (!params) return;
|
||||||
if (ignoreRemove(params)) {
|
struct Ignore ignore = ignoreParse(params);
|
||||||
|
bool found = ignoreRemove(ignore);
|
||||||
uiFormat(
|
uiFormat(
|
||||||
id, Cold, NULL, "No longer ignoring \3%02d%s\3",
|
id, Cold, NULL, "%s ignoring \3%02d%s %s %s %s",
|
||||||
Brown, params
|
(found ? "No longer" : "Not"), Brown, ignore.mask,
|
||||||
|
(ignore.cmd ?: ""), (ignore.chan ?: ""), (ignore.mesg ?: "")
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
uiFormat(id, Cold, NULL, "Not ignoring \3%02d%s\3", Brown, params);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void commandExec(uint id, char *params) {
|
static void commandExec(uint id, char *params) {
|
||||||
|
|
93
ignore.c
93
ignore.c
|
@ -35,55 +35,70 @@
|
||||||
|
|
||||||
#include "chat.h"
|
#include "chat.h"
|
||||||
|
|
||||||
struct Ignore ignore;
|
struct Ignore ignores[IgnoreCap];
|
||||||
|
static size_t len;
|
||||||
|
|
||||||
const char *ignoreAdd(const char *pattern) {
|
struct Ignore ignoreParse(char *pattern) {
|
||||||
if (ignore.len == IgnoreCap) errx(EX_CONFIG, "ignore limit exceeded");
|
struct Ignore ignore = {0};
|
||||||
uint ex = 0, sp = 0;
|
ignore.mask = strsep(&pattern, " ");
|
||||||
for (const char *ch = pattern; *ch; ++ch) {
|
ignore.cmd = strsep(&pattern, " ");
|
||||||
if (*ch == '!') ex++;
|
ignore.chan = strsep(&pattern, " ");
|
||||||
if (*ch == ' ') sp++;
|
ignore.mesg = pattern;
|
||||||
}
|
return ignore;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
bool found = false;
|
||||||
for (size_t i = 0; i < ignore.len; ++i) {
|
for (size_t i = len - 1; i < len; --i) {
|
||||||
if (strcasecmp(ignore.patterns[i], pattern)) continue;
|
if (!ignores[i].cmd != !ignore.cmd) continue;
|
||||||
free(ignore.patterns[i]);
|
if (!ignores[i].chan != !ignore.chan) continue;
|
||||||
ignore.patterns[i] = ignore.patterns[--ignore.len];
|
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;
|
found = true;
|
||||||
}
|
}
|
||||||
return found;
|
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) {
|
enum Heat ignoreCheck(enum Heat heat, uint id, const struct Message *msg) {
|
||||||
if (!ignore.len) return heat;
|
if (!len) return heat;
|
||||||
char match[512];
|
char mask[512];
|
||||||
snprintf(
|
snprintf(mask, sizeof(mask), "%s!%s@%s", msg->nick, msg->user, msg->host);
|
||||||
match, sizeof(match), "%s!%s@%s %s %s %s",
|
for (size_t i = 0; i < len; ++i) {
|
||||||
msg->nick, msg->user, msg->host,
|
if (ignoreTest(ignores[i], mask, id, msg)) return Ice;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
return heat;
|
return heat;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue