aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2011-08-20 17:43:21 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2011-08-20 17:46:45 +0300
commitdbb042cb96ec855120b11b27c4ea4a72a6920ed8 (patch)
tree8115aca3a885ecfa872cfa8d64b7087760c96762
parent65d790e09a96dd8319a9a3399ce85b40c7b57e77 (diff)
downloadmailfromd-dbb042cb96ec855120b11b27c4ea4a72a6920ed8.tar.gz
mailfromd-dbb042cb96ec855120b11b27c4ea4a72a6920ed8.tar.bz2
Implement dspam support.
* configure.ac: Check for dspam * mflib/.gitignore: Add dspam.h * mflib/Makefile.am: Build dspam.h Install dspam.mf * mflib/dspam.mf: New file. * src/Makefile.am (mailfromd_LDADD): Add DSPAM_LIBS (INCLUDES): Add DSPAM_CFLAGS * src/builtin/Makefile.am (BI_FILES): Add dspam.bi. (INCLUDES): Add DSPAM_CFLAGS * src/builtin/dspam.bi: New file. * src/main.c (mailfromd_show_defaults): Reflect dspam support.
-rw-r--r--configure.ac21
-rw-r--r--mflib/.gitignore1
-rw-r--r--mflib/Makefile.am4
-rw-r--r--mflib/dspam.mf54
-rw-r--r--src/Makefile.am6
-rw-r--r--src/builtin/.gitignore1
-rw-r--r--src/builtin/Makefile.am4
-rw-r--r--src/builtin/dspam.bi261
-rw-r--r--src/main.c7
9 files changed, 352 insertions, 7 deletions
diff --git a/configure.ac b/configure.ac
index 926d8f23..4a52ef05 100644
--- a/configure.ac
+++ b/configure.ac
@@ -46,6 +46,7 @@ AC_PROG_RANLIB
AC_PROG_YACC
AC_PROG_LEX
AC_PROG_LN_S
+PKG_PROG_PKG_CONFIG
# Debugging mode
MU_DEBUG_MODE
@@ -334,6 +335,7 @@ if test "$status_dbm" = "no"; then
AC_MSG_ERROR([Cannot find DBM library to link with.])
fi
+## Preprocessor
AC_ARG_WITH([preprocessor],
AC_HELP_STRING([--without-preprocessor],
[do not use external preprocessor]),
@@ -650,6 +652,23 @@ if test "$status_geoip" != "no"; then
fi
fi
+## Dspam
+status_dspam=maybe
+AC_SUBST(DSPAM_CFLAGS)
+AC_SUBST(DSPAM_LIBS)
+
+AC_ARG_WITH([dspam],
+ [status_dspam=$withval],
+ [status_dspam=no],
+ [status_dspam=maybe])
+
+if test $status_dspam != no; then
+ PKG_CHECK_MODULES([DSPAM], [dspam], [status_dspam=yes], [status_dspam=no])
+fi
+if test "$status_dspam" = "yes"; then
+ AC_DEFINE([WITH_DSPAM], [1], [Enable use of DSPAM library])
+fi
+
# Doc hints.
# Select a rendition level:
# DISTRIB for stable releases (at most one dot in the version number)
@@ -700,6 +719,7 @@ Readline (for mtasim)..................... $usereadline
Documentation rendition type.............. $rendition
Enable pmilter support.................... $enable_pmilter
Enable GeoIP support...................... $status_geoip
+Enable DSPAM support...................... $status_dspam
IPv6 support.............................. $status_ipv6
*******************************************************************
@@ -723,6 +743,7 @@ rendition=$RENDITION
syslog_async=$syslog_async
enable_pmilter=$enable_pmilter
status_geoip=$status_geoip
+status_dspam=$status_dspam
status_ipv6=$status_ipv6
])
diff --git a/mflib/.gitignore b/mflib/.gitignore
index 3e507dc9..9088ef1e 100644
--- a/mflib/.gitignore
+++ b/mflib/.gitignore
@@ -1,6 +1,7 @@
_register.h
callout.mf
dns.mf
+dspam.h
header_rename.mf
email.h
portprobe.mf
diff --git a/mflib/Makefile.am b/mflib/Makefile.am
index 457b03b3..c1d1c648 100644
--- a/mflib/Makefile.am
+++ b/mflib/Makefile.am
@@ -50,8 +50,8 @@ MF_FILES =\
verp.mf\
$(MF4_FILES:.mf4=.mf)
-noinst_HEADERS = email.h sieve.h syslog.h _register.h status.ex
-BUILT_SOURCES = email.h sieve.h syslog.h _register.h status.ex
+noinst_HEADERS = dspam.h email.h sieve.h syslog.h _register.h status.ex
+BUILT_SOURCES = dspam.h email.h sieve.h syslog.h _register.h status.ex
EXTRA_DIST=$(inc_DATA) pp-setup $(MF4_FILES) mfex.awk mfh.awk
diff --git a/mflib/dspam.mf b/mflib/dspam.mf
new file mode 100644
index 00000000..15a376d3
--- /dev/null
+++ b/mflib/dspam.mf
@@ -0,0 +1,54 @@
+/* Constants for dspam interface.
+ Copyright (C) 2011 Sergey Poznyakoff
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+module 'dspam'.
+
+#prefix _MF_
+
+# Operating Modes:
+const DSM_PROCESS 0 /* Process message */
+const DSM_CLASSIFY 1 /* Classify message only (do not write changes) */
+const _DSM_MASK 0x000f
+# Flags:
+const DSF_SIGNATURE 0x0010 /* Signature Mode (Use a signature) */
+const DSF_NOISE 0x0020 /* Use Bayesian Noise Reduction */
+const DSF_WHITELIST 0x0040 /* Use Automatic Whitelisting */
+
+# Tokenizers:
+const DSZ_WORD (0<<8) /* Use WORD tokenizer */
+const DSZ_CHAIN (1<<8) /* Use CHAIN tokenizer */
+const DSZ_SBPH (2<<8) /* Use SBPH tokenizer */
+const DSZ_OSB (3<<8) /* Use OSB tokenizer */
+const _DSZ_MASK 0x0f00
+
+# Training Modes:
+const DST_TEFT (0<<12) /* Train Everything */
+const DST_TOE (1<<12) /* Train-on-Error */
+const DST_TUM (2<<12) /* Train-until-Mature */
+const _DST_MASK 0xf000
+
+# Classifications:
+const DSR_ISSPAM 0 /* Message is spam (learn as spam) */
+const DSR_ISINNOCENT 1 /* Message is innocent (learn as innocent) */
+const DSR_NONE 2 /* No predetermined classification (classify message) */
+const _DSR_MASK 0x000f
+
+# Sources:
+const DSS_ERROR (0<<4) /* Misclassification by libdspam */
+const DSS_CORPUS (1<<4) /* Corpused message */
+const DSS_INOCULATION (2<<4) /* Message inoculation */
+const DSS_NONE (3<<4) /* No classification source (use only with DSR_NONE) */
+const _DSS_MASK 0x00f0 \ No newline at end of file
diff --git a/src/Makefile.am b/src/Makefile.am
index e301eb10..4400f8d4 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -52,7 +52,8 @@ mailfromd_LDADD = \
../gnu/libgnu.a\
$(MAILUTILS_LIBS)\
$(MILTER)\
- $(GEOIP_LIBS)
+ $(GEOIP_LIBS)\
+ $(DSPAM_LIBS)
noinst_HEADERS = \
bitmask.h\
@@ -122,7 +123,8 @@ INCLUDES = \
-I$(top_srcdir)/gnu\
-I../gnu\
-I$(top_srcdir)/src/builtin\
- $(MILTER_INCLUDES)
+ $(MILTER_INCLUDES)\
+ $(DSPAM_CFLAGS)
node-type.h: drivers.c
$(AM_V_GEN) $(AWK) -v MODE=types -f $(top_srcdir)/src/drv.awk drivers.c > node-type.h
diff --git a/src/builtin/.gitignore b/src/builtin/.gitignore
index 15202284..e72cf081 100644
--- a/src/builtin/.gitignore
+++ b/src/builtin/.gitignore
@@ -6,6 +6,7 @@ curhdr.c
db.c
debug.c
dns.c
+dspam.c
email.c
geoip.c
gethostname.c
diff --git a/src/builtin/Makefile.am b/src/builtin/Makefile.am
index fc025469..904cd02b 100644
--- a/src/builtin/Makefile.am
+++ b/src/builtin/Makefile.am
@@ -26,6 +26,7 @@ BI_FILES=\
db.bi\
debug.bi\
dns.bi\
+ dspam.bi\
email.bi\
geoip.bi\
gethostname.bi\
@@ -76,7 +77,8 @@ INCLUDES = \
-I../gnu\
$(MILTER_INCLUDES)\
-I$(top_srcdir)/src\
- -I$(top_srcdir)
+ -I$(top_srcdir)\
+ $(DSPAM_CFLAGS)
builtin.h: Makefile.am
diff --git a/src/builtin/dspam.bi b/src/builtin/dspam.bi
new file mode 100644
index 00000000..a07451c3
--- /dev/null
+++ b/src/builtin/dspam.bi
@@ -0,0 +1,261 @@
+/* This file is part of Mailfromd. -*- c -*-
+ Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Sergey Poznyakoff
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+MF_COND(WITH_DSPAM)
+
+#include "srvcfg.h"
+#undef HAVE_CONFIG_H
+#include <libdspam.h>
+#include "mflib/dspam.h"
+#include "msg.h"
+
+MF_VAR(dspam_home, STRING, SYM_PRECIOUS);
+MF_VAR(dspam_user, STRING, SYM_PRECIOUS);
+MF_VAR(dspam_group, STRING, SYM_PRECIOUS);
+#define DEFAULT_DSPAM_HOME_STR "dspam"
+#define DEFAULT_DSPAM_HOME_LEN (sizeof(DEFAULT_DSPAM_HOME_STR)-1)
+MF_VAR(dspam_probability, NUMBER);
+MF_VAR(dspam_confidence, NUMBER);
+MF_VAR(dspam_prec, NUMBER);
+#define DEFAULT_DSPAM_PREC 3
+
+static int _dspam_initialized;
+
+static void
+_dspam_shutdown()
+{
+ dspam_shutdown_driver(NULL);
+}
+
+struct transtab
+{
+ int trans_from;
+ int trans_to;
+};
+
+static struct transtab mode_trans[] = {
+ { _MF_DSM_PROCESS, DSM_PROCESS },
+ { _MF_DSM_CLASSIFY, DSM_CLASSIFY }
+};
+
+static struct transtab flag_trans[] = {
+ { _MF_DSF_SIGNATURE, DSF_SIGNATURE },
+ { _MF_DSF_NOISE, DSF_NOISE },
+ { _MF_DSF_WHITELIST, DSF_WHITELIST }
+};
+
+static struct transtab tokenizer_trans[] = {
+ { _MF_DSZ_WORD, DSZ_WORD },
+ { _MF_DSZ_CHAIN, DSZ_CHAIN },
+ { _MF_DSZ_SBPH, DSZ_SBPH },
+ { _MF_DSZ_OSB, DSZ_OSB }
+};
+
+static struct transtab tmod_trans[] = {
+ { _MF_DST_TEFT, DST_TEFT },
+ { _MF_DST_TOE, DST_TOE },
+ { _MF_DST_TUM, DST_TUM }
+};
+
+static struct transtab class_trans[] = {
+ { _MF_DSR_ISSPAM, DSR_ISSPAM },
+ { _MF_DSR_ISINNOCENT, DSR_ISINNOCENT },
+ { _MF_DSR_NONE, DSR_NONE }
+};
+
+static struct transtab source_trans[] = {
+ { _MF_DSS_ERROR, DSS_ERROR },
+ { _MF_DSS_CORPUS, DSS_CORPUS },
+ { _MF_DSS_INOCULATION, DSS_INOCULATION },
+ { _MF_DSS_NONE, DSS_NONE }
+};
+
+static int
+translate(struct transtab *tab, size_t count, int num, int *ret)
+{
+ for (; count; tab++, count--)
+ if (tab->trans_from == num) {
+ *ret = tab->trans_to;
+ return 0;
+ }
+ return -1;
+}
+
+static int
+translate_flags(struct transtab *tab, size_t count, int num)
+{
+ int f = 0;
+ for (; count; tab++, count--)
+ if (tab->trans_from & num)
+ f |= tab->trans_to;
+ return f;
+}
+
+static void
+stream_cleanup(void *ptr)
+{
+ mu_stream_t str = ptr;
+ mu_stream_unref(str);
+}
+
+static void
+ctx_cleanup(void *ptr)
+{
+ DSPAM_CTX *ctx = ptr;
+ dspam_destroy(ctx);
+}
+
+/* number dspam(number msg, number flags; number class_source) */
+MF_DSEXP
+MF_DEFUN(dspam, NUMBER, NUMBER nmsg, NUMBER mode_flags, OPTIONAL, NUMBER class_src)
+{
+ int rc, n;
+ DSPAM_CTX *ctx; /* DSPAM Context */
+ int mode;
+ int flags;
+ mu_message_t msg;
+ mu_stream_t msgstr, instr;
+ const char *msgbuf;
+ size_t msgsize;
+ unsigned prec;
+ mu_transport_t trans[2];
+
+ /* Prepare message buffer */
+ msg = bi_message_from_descr(env, nmsg);
+ rc = mu_message_size(msg, &msgsize);
+ MF_ASSERT(rc == 0,
+ mfe_failure,
+ "mu_message_size: %s", mu_strerror(rc));
+
+ rc = mu_memory_stream_create(&msgstr, MU_STREAM_RDWR);
+ MF_ASSERT(rc == 0,
+ mfe_failure,
+ "mu_static_memory_stream_create: %s",
+ mu_strerror(rc));
+ MF_DCL_CLEANUP(msgstr, stream_cleanup);
+
+ rc = mu_message_get_streamref(msg, &instr);
+ MF_ASSERT(rc == 0,
+ mfe_failure,
+ "mu_message_get_streamref: %s",
+ mu_strerror(rc));
+ MF_DCL_CLEANUP(instr, stream_cleanup);
+
+ rc = mu_stream_copy(msgstr, instr, msgsize, NULL);
+ MF_ASSERT(rc == 0,
+ mfe_failure,
+ "mu_stream_copy: %s",
+ mu_strerror(rc));
+
+ MF_CLEANUP(instr);
+
+ mu_stream_ioctl(msgstr, MU_IOCTL_TRANSPORT, MU_IOCTL_OP_GET, trans);
+ msgbuf = (const char*)trans[0];
+
+ /* Initialize dspam library and set up global variables, if
+ needed */
+ if (!_dspam_initialized) {
+ size_t off, len;
+ char *s;
+
+ dspam_init_driver(NULL);
+ atexit(_dspam_shutdown);
+ _dspam_initialized = 1;
+
+ if (MF_VAR_REF(dspam_home) == NULL) {
+ len = strlen(mailfromd_state_dir);
+ while (len > 0 && mailfromd_state_dir[len-1] == '/')
+ len--;
+ s = MF_ALLOC_HEAP(off,
+ len + DEFAULT_DSPAM_HOME_LEN + 2);
+ memcpy(s, mailfromd_state_dir, len);
+ s[len++] = '/';
+ strcpy(s + len, DEFAULT_DSPAM_HOME_STR);
+ MF_VAR_REF(dspam_home, off);
+ }
+
+ if (MF_VAR_REF(dspam_user) == NULL)
+ MF_VAR_SET_STRING(dspam_user, mf_server_user);
+
+ if (MF_VAR_REF(dspam_prec) == 0)
+ MF_VAR_REF(dspam_prec, DEFAULT_DSPAM_PREC);
+ }
+
+ /* Prepare DSPAM context */
+ MF_ASSERT(translate(mode_trans, MU_ARRAY_SIZE(mode_trans),
+ mode_flags & _MF__DSM_MASK, &mode) == 0,
+ mfe_failure,
+ "bad dspam mode");
+ flags = translate_flags(flag_trans, MU_ARRAY_SIZE(flag_trans),
+ mode_flags);
+
+ /* Initialize the DSPAM context */
+ ctx = dspam_init(MF_VAR_STRING(dspam_user),
+ MF_VAR_STRING(dspam_group),
+ MF_VAR_STRING(dspam_home), mode,
+ flags);
+ MF_ASSERT(ctx != NULL,
+ mfe_failure,
+ "dspam_init failed");
+ MF_DCL_CLEANUP(ctx, ctx_cleanup);
+
+ /* Use graham and robinson algorithms, graham's p-values */
+ /* FIXME: Get from args? */
+ ctx->algorithms = DSA_GRAHAM | DSA_BURTON | DSP_GRAHAM;
+
+ /* Use CHAIN tokenizer */
+ MF_ASSERT(translate(tokenizer_trans, MU_ARRAY_SIZE(tokenizer_trans),
+ mode_flags & _MF__DSZ_MASK, &ctx->tokenizer) == 0,
+ mfe_failure,
+ "bad dspam tokenizer");
+
+ /* Set up classification and source */
+ if (n = MF_OPTVAL(class_src)) {
+ MF_ASSERT(translate(class_trans, MU_ARRAY_SIZE(class_trans),
+ n & _MF__DSR_MASK,
+ &ctx->classification) == 0,
+ mfe_failure,
+ "bad dspam classification flag");
+ MF_ASSERT(translate(source_trans, MU_ARRAY_SIZE(source_trans),
+ n & _MF__DSS_MASK,
+ &ctx->source) == 0,
+ mfe_failure,
+ "bad dspam source flag");
+ }
+
+ /* Process the message */
+ MF_ASSERT(dspam_process(ctx, msgbuf) == 0,
+ mfe_failure,
+ "dspam_process failed");
+
+ rc = (unsigned) MF_VAR_REF(dspam_prec);
+ prec = 1;
+ while (rc--)
+ prec *= 10;
+ MF_VAR_REF(dspam_probability,
+ (unsigned long) (ctx->probability * prec));
+ MF_VAR_REF(dspam_confidence,
+ (unsigned long) (ctx->confidence * prec));
+ rc = ctx->result;
+ MF_CLEANUP(ctx);
+
+ /* FIXME: Any additional processing? */
+
+ MF_RETURN(rc);
+}
+END
+
+MF_INIT
diff --git a/src/main.c b/src/main.c
index cc0852df..637bad4f 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1030,10 +1030,13 @@ mailfromd_show_defaults()
#endif
printf("\n");
- printf("Optional features: ");
+ printf("Optional features: ");
#if defined WITH_GEOIP
- printf("GeoIP");
+ printf(" GeoIP");
#endif
+#if defined WITH_DSPAM
+ printf(" DSPAM");
+#endif
printf("\n");
db_format_enumerate(db_format_enumerator, NULL);

Return to:

Send suggestions and report system problems to the System administrator.