Hi,
I attach a proposed patch for the spamc client which I have tested - it
seems to be working well. It's based off the latest SVN I got from:
http://svn.apache.org/repos/asf/spamassassin/trunk
It adds the option -T to allow the spam threshold value to be
overridden, which changes when spamc will return 0/1 to indicate spam,
but does *not* change any of SpamAssassin's message rewriting.
The reason I think this change is a good idea is that I (and perhaps
others) find myself wanting to be able to define a "grey area" of
e-mails, where they are rewritten as spam but not completely discarded.
This can be done by setting the threshold override higher than the
normal SpamAssassin threshold.
For example, if you want the grey area to be between 3.0 and 8.0, you'd
set the normal SpamAssassin threshold to 3.0, then call spamc with the
threshold override of 8.0. Scores under 3.0 would be OK; spamc returns
0 and the message is not rewritten. Scores between 3.0 and 8.0 would be
"grey area" - spamc still returns 0 (so a shell script will not discard
it), but the message *is* rewritten. It will be delivered to the user's
mailbox as a rewritten message. Remaining scores would cause the
message to be rewritten *and* spamc would return 1, allowing a shell
script to discard it.
What do you think? Can it be merged into the SpamAssassin trunk?
--
Best regards,
Jeremy Morton (Jez)
Index: spamc/libspamc.h
===================================================================
--- spamc/libspamc.h (revision 1432542)
+++ spamc/libspamc.h (working copy)
@@ -139,6 +139,9 @@
* */
#define SPAMC_UNAVAIL_TEMPFAIL (1<<13)
+/* Jan 13, 2013 jez: allow overriding of 'is spam' threshold */
+#define SPAMC_THRESHOLD_OVERRIDE (1<<12)
+
#define SPAMC_MESSAGE_CLASS_SPAM 1
#define SPAMC_MESSAGE_CLASS_HAM 2
Index: spamc/spamc.c
===================================================================
--- spamc/spamc.c (revision 1432542)
+++ spamc/spamc.c (working copy)
@@ -100,6 +100,7 @@
static int timeout = 600;
static int connect_timeout = 0; /* Sep 8, 2008 mrgus: separate connect
timeout */
+static float threshold_override = 0.0;
void
@@ -154,6 +155,10 @@
usg(" -t, --timeout timeout\n"
" Timeout in seconds for communications to\n"
" spamd. [default: 600]\n");
+ usg(" -T, --threshold-override score\n"
+ " Score above or equal to which message will be\n"
+ " considered spam, causing the return value
to\n");
+ " be 1 (message rewriting is not affected).\n");
usg(" -n, --connect-timeout timeout\n"
" Timeout in seconds when opening a connection
to\n"
" spamd. [default: 600]\n");
@@ -235,9 +240,9 @@
struct transport *ptrn)
{
#ifndef _WIN32
- const char *opts = "-BcrR46d:e:fyp:n:t:s:u:L:C:xXzSHU:ElhVKF:0:1:2";
+ const char *opts = "-BcrR46d:e:fyp:n:t:T:s:u:L:C:xXzSHU:ElhVKF:0:1:2";
#else
- const char *opts = "-BcrR46d:fyp:n:t:s:u:L:C:xXzSHElhVKF:0:1:2";
+ const char *opts = "-BcrR46d:fyp:n:t:T:s:u:L:C:xXzSHElhVKF:0:1:2";
#endif
int opt;
int ret = EX_OK;
@@ -251,6 +256,7 @@
{ "socket", required_argument, 0, 'U' },
{ "config", required_argument, 0, 'F' },
{ "timeout", required_argument, 0, 't' },
+ { "threshold-override", required_argument, 0, 'T' },
{ "connect-timeout", required_argument, 0, 'n'},
{ "connect-retries", required_argument, 0, 0 },
{ "retry-sleep", required_argument, 0, 1 },
@@ -389,6 +395,12 @@
}
break;
}
+ case 'T':
+ {
+ threshold_override = atof(spamc_optarg);
+ flags |= SPAMC_THRESHOLD_OVERRIDE;
+ break;
+ }
case 'n':
{
connect_timeout = atoi(spamc_optarg);
@@ -726,6 +738,25 @@
/**
+ * Determines whether the message score is over or equal to the overridden
threshold.
+ */
+int
+is_spam(int is_spam, float message_score)
+{
+ if (is_spam == EX_NOHOST) {
+ return EX_NOHOST;
+ }
+
+ if (flags & SPAMC_THRESHOLD_OVERRIDE) {
+ return message_score >= threshold_override;
+ }
+ else {
+ return is_spam;
+ }
+}
+
+
+/**
* Determines the username of the uid spamc is running under.
*
* If the program's caller didn't identify the user to run as, use the
@@ -999,7 +1030,7 @@
goto finish;
}
else if (message_write(out_fd, &m) >= 0) {
- result = m.is_spam;
+ result = is_spam(m.is_spam, m.score);
if ((flags & SPAMC_CHECK_ONLY) && result != EX_TOOBIG) {
message_cleanup(&m);
ret = result;
@@ -1018,7 +1049,7 @@
free(username);
/* FAIL: */
- result = m.is_spam;
+ result = is_spam(m.is_spam, m.score);
if (ret != EX_OK) {
result = ret;
}