From 669cf6e1895ef8048be2a49cec2d0fb8aab0c90b Mon Sep 17 00:00:00 2001
From: Bram Matthys
Date: Wed, 25 Feb 2004 20:49:00 +0000
Subject: [PATCH] - Fixed an issue where chanmode +f was often set by the
server again in a netjoin when there was no need to (nothing to synch). -
Added spamfilter::except which allows you to specify targets (eg: channels)
where spamfilter should not take action. Requested by Fury (#0001586). Ex:
set { spamfilter { except "#spamreport,#help"; }; };
---
Changes | 5 +++++
doc/example.conf | 18 +++++++++++++++---
doc/unreal32docs.html | 3 +++
include/dynconf.h | 3 +++
include/struct.h | 6 ++++++
src/modules/m_sjoin.c | 17 ++++++++++++++++-
src/modules/m_stats.c | 3 +++
src/s_conf.c | 32 ++++++++++++++++++++++++++++++--
src/s_kline.c | 20 ++++++++++++++++++++
9 files changed, 101 insertions(+), 6 deletions(-)
diff --git a/Changes b/Changes
index 516fd6c8e..c36d7fc23 100644
--- a/Changes
+++ b/Changes
@@ -2972,3 +2972,8 @@ seen. gmtime warning still there
- '0' tkltime in spamfilter now really means 'perm', not '*line for
0 seconds' or something. Reported by Certus.
- Fixed a bug in individual m_*.so loading, 39 new modules were affected.
+- Fixed an issue where chanmode +f was often set by the server again
+ in a netjoin when there was no need to (nothing to synch).
+- Added spamfilter::except which allows you to specify targets
+ (eg: channels) where spamfilter should not take action. Requested by Fury
+ (#0001586). Ex: set { spamfilter { except "#spamreport,#help"; }; };
diff --git a/doc/example.conf b/doc/example.conf
index ee8eff25f..87887127b 100644
--- a/doc/example.conf
+++ b/doc/example.conf
@@ -32,10 +32,15 @@
loadmodule "src/modules/commands.so";
/*
- * You can also include other configuration files. help.conf contains all the
- * /helpop text so you probably want this include:
+ * You can also include other configuration files.
+ * help.conf contains all the /helpop text. The badwords.*.conf
+ * files contain all the badword entries for mode +G...
+ * You probably want to include them:
*/
include "help.conf";
+include "badwords.channel.conf";
+include "badwords.message.conf";
+include "badwords.quit.conf";
/*
* NEW: me {}
@@ -743,7 +748,7 @@ set {
* Some admins might want to remove the 'kGs' to allow normal users to list
* klines, glines and shuns.
*/
- oper-only-stats "okGsMRUEelLCXzdD";
+ oper-only-stats "okfGsMRUEelLCXzdD";
/* Throttling: this example sets a limit of 3 connections per 60s (per host). */
throttle {
@@ -756,6 +761,13 @@ set {
nick-flood 3:60; /* 3 nickchanges per 60 seconds (the default) */
};
+ /* Spam filter */
+ spamfilter {
+ ban-time 1d; /* default duration of a *line ban set by spamfilter */
+ ban-reason "Spam/Advertising"; /* default reason */
+ virus-help-channel "#help"; /* channel to use for 'viruschan' action */
+ /* except "#help"; channel to exempt from filtering */
+ };
};
/*
diff --git a/doc/unreal32docs.html b/doc/unreal32docs.html
index 0dbd43cf1..1f208e746 100644
--- a/doc/unreal32docs.html
+++ b/doc/unreal32docs.html
@@ -2146,6 +2146,9 @@ set {
Reason to be used for *lines added by spamfilter
set::spamfilter::virus-help-channel <channel>
The channel to use for the 'viruschan' action in spamfilter
+ set::spamfilter::except <target(s)>
+ These targets are exempt from spam filtering (no action will be taken),
+ can be single target or comma seperated list.. Ex: except "#help,#spamreport"
5 – Additional Files
diff --git a/include/dynconf.h b/include/dynconf.h
index 72e62f3ec..7c8b9b29e 100644
--- a/include/dynconf.h
+++ b/include/dynconf.h
@@ -134,6 +134,8 @@ struct zConfiguration {
long spamfilter_ban_time;
char *spamfilter_ban_reason;
char *spamfilter_virus_help_channel;
+ SpamExcept *spamexcept;
+ char *spamexcept_line;
aNetwork network;
};
@@ -232,3 +234,4 @@ extern aConfiguration iConf;
#define SPAMFILTER_BAN_TIME iConf.spamfilter_ban_time
#define SPAMFILTER_BAN_REASON iConf.spamfilter_ban_reason
#define SPAMFILTER_VIRUSCHAN iConf.spamfilter_virus_help_channel
+#define SPAMFILTER_EXCEPT iConf.spamexcept_line
diff --git a/include/struct.h b/include/struct.h
index e76ff5393..c2717bbdf 100644
--- a/include/struct.h
+++ b/include/struct.h
@@ -77,6 +77,7 @@ typedef struct aloopStruct LoopStruct;
typedef struct ConfItem aConfItem;
typedef struct t_kline aTKline;
typedef struct _spamfilter Spamfilter;
+typedef struct _spamexcept SpamExcept;
/* New Config Stuff */
typedef struct _configentry ConfigEntry;
typedef struct _configfile ConfigFile;
@@ -775,6 +776,11 @@ struct t_kline {
TS expire_at, set_at;
};
+struct _spamexcept {
+ SpamExcept *prev, *next;
+ char name[1];
+};
+
typedef struct ircstatsx {
int clients; /* total */
int invisible; /* invisible */
diff --git a/src/modules/m_sjoin.c b/src/modules/m_sjoin.c
index 20b82c900..f785811a6 100644
--- a/src/modules/m_sjoin.c
+++ b/src/modules/m_sjoin.c
@@ -107,6 +107,21 @@ aParv *mp2parv(char *xmbuf, char *parmbuf)
return (&pparv);
}
+/* Checks if 2 ChanFloodProt modes (chmode +f) are different.
+ * This is a bit more complicated than 1 simple memcmp(a,b,..) because
+ * counters are also stored in this struct so we have to do
+ * it manually :( -- Syzop.
+ */
+static int compare_floodprot_modes(ChanFloodProt *a, ChanFloodProt *b)
+{
+ if (memcmp(a->l, b->l, sizeof(a->l)) ||
+ memcmp(a->a, b->a, sizeof(a->a)) ||
+ memcmp(a->r, b->r, sizeof(a->r)))
+ return 1;
+ else
+ return 0;
+}
+
/*
** m_sjoin
**
@@ -761,7 +776,7 @@ CMD_FUNC(m_sjoin)
char *x;
int i;
- if (memcmp(chptr->mode.floodprot, oldmode.floodprot, sizeof(ChanFloodProt)))
+ if (compare_floodprot_modes(chptr->mode.floodprot, oldmode.floodprot))
{
chptr->mode.floodprot->per = MAX(chptr->mode.floodprot->per, oldmode.floodprot->per);
for (i=0; i < NUMFLD; i++)
diff --git a/src/modules/m_stats.c b/src/modules/m_stats.c
index cead81901..425fc8798 100644
--- a/src/modules/m_stats.c
+++ b/src/modules/m_stats.c
@@ -1321,6 +1321,9 @@ int stats_set(aClient *sptr, char *para)
sptr->name, SPAMFILTER_BAN_REASON);
sendto_one(sptr, ":%s %i %s :spamfilter::virus-help-channel: %s", me.name, RPL_TEXT,
sptr->name, SPAMFILTER_VIRUSCHAN);
+ if (SPAMFILTER_EXCEPT)
+ sendto_one(sptr, ":%s %i %s :spamfilter::except: %s", me.name, RPL_TEXT,
+ sptr->name, SPAMFILTER_EXCEPT);
sendto_one(sptr, ":%s %i %s :hosts::global: %s", me.name, RPL_TEXT,
sptr->name, oper_host);
sendto_one(sptr, ":%s %i %s :hosts::admin: %s", me.name, RPL_TEXT,
diff --git a/src/s_conf.c b/src/s_conf.c
index 1424aa997..70e3ce0d2 100644
--- a/src/s_conf.c
+++ b/src/s_conf.c
@@ -1339,6 +1339,7 @@ void free_iConf(aConfiguration *i)
ircfree(i->network.x_stats_server);
ircfree(i->spamfilter_ban_reason);
ircfree(i->spamfilter_virus_help_channel);
+ ircfree(i->spamexcept_line);
}
int config_test();
@@ -1591,6 +1592,7 @@ void config_rehash()
OperStat *os_ptr;
ListStruct *next, *next2;
aTKline *tk, *tk_next;
+ SpamExcept *spamex_ptr;
USE_BAN_VERSION = 0;
/* clean out stuff that we don't use */
@@ -1892,6 +1894,12 @@ void config_rehash()
MyFree(os_ptr);
}
iConf.oper_only_stats_ext = NULL;
+ for (spamex_ptr = iConf.spamexcept; spamex_ptr; spamex_ptr = (SpamExcept *)next)
+ {
+ next = (ListStruct *)spamex_ptr->next;
+ MyFree(spamex_ptr);
+ }
+ iConf.spamexcept = NULL;
for (of_ptr = conf_offchans; of_ptr; of_ptr = (ConfigItem_offchans *)next)
{
next = (ListStruct *)of_ptr->next;
@@ -5543,7 +5551,7 @@ int _conf_set(ConfigFile *conf, ConfigEntry *ce)
{
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
{
- OperStat *os = MyMalloc(sizeof(OperStat));
+ OperStat *os = MyMallocEx(sizeof(OperStat));
ircstrdup(os->flag, cepp->ce_varname);
AddListItem(os, tempiConf.oper_only_stats_ext);
}
@@ -5726,6 +5734,23 @@ int _conf_set(ConfigFile *conf, ConfigEntry *ce)
ircstrdup(tempiConf.spamfilter_ban_reason, cepp->ce_vardata);
if (!strcmp(cepp->ce_varname, "virus-help-channel"))
ircstrdup(tempiConf.spamfilter_virus_help_channel, cepp->ce_vardata);
+ if (!strcmp(cepp->ce_varname, "except"))
+ {
+ char *name, *p;
+ SpamExcept *e;
+ ircstrdup(tempiConf.spamexcept_line, cepp->ce_vardata);
+ for (name = strtoken(&p, cepp->ce_vardata, ","); name; name = strtoken(&p, NULL, ","))
+ {
+ if (*name == ' ')
+ name++;
+ if (*name)
+ {
+ e = MyMallocEx(sizeof(SpamExcept) + strlen(name));
+ strcpy(e->name, name);
+ AddListItem(e, tempiConf.spamexcept);
+ }
+ }
+ }
}
}
else if (!strcmp(cep->ce_varname, "default-bantime"))
@@ -6344,7 +6369,10 @@ int _test_set(ConfigFile *conf, ConfigEntry *ce)
errors++;
continue;
}
- } else {
+ } else
+ if (!strcmp(cepp->ce_varname, "except"))
+ { } else
+ {
config_error("%s:%i: unknown directive set::spamfilter::%s",
cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum, cepp->ce_varname);
errors++;
diff --git a/src/s_kline.c b/src/s_kline.c
index 97454a192..b18a10cde 100644
--- a/src/s_kline.c
+++ b/src/s_kline.c
@@ -1319,6 +1319,21 @@ int place_host_ban(aClient *sptr, int action, char *reason, long duration)
return -1;
}
+/** Checks if 'target' is on the spamfilter exception list.
+ * RETURNS 1 if found in list, 0 if not.
+ */
+int target_is_spamexcept(char *target)
+{
+SpamExcept *e;
+
+ for (e = iConf.spamexcept; e; e = e->next)
+ {
+ if (!match(e->name, target))
+ return 1;
+ }
+ return 0;
+}
+
/** dospamfilter: executes the spamfilter onto the string.
* str: the text (eg msg text, notice text, part text, quit text, etc
* type: the spamfilter type (SPAMF_*)
@@ -1352,6 +1367,11 @@ char *str = (char *)StripControlCodes(str_in);
strlcpy(targetbuf+1, target, sizeof(targetbuf)-1); /* cut it off */
} else
targetbuf[0] = '\0';
+
+ /* Hold on.. perhaps it's on the exceptions list... */
+ if (target && target_is_spamexcept(target))
+ return 0; /* No problem! */
+
ircsprintf(buf, "[Spamfilter] %s!%s@%s matches filter '%s': [%s%s: '%s'] [%s]",
sptr->name, sptr->user->username, sptr->user->realhost,
tk->reason,