diff -N -r -u ./zmailer.orig/configure.in ./zmailer/configure.in
--- ./zmailer.orig/configure.in	2007-06-29 02:57:46.000000000 +0400
+++ ./zmailer/configure.in	2010-01-03 16:41:47.000000000 +0300
@@ -3067,7 +3067,7 @@
         proto/cf/SMTP+UUCP.cf           proto/cf/UTdefault.cf           
         proto/cf/SMTP.cf                proto/smtp-tls.conf             
         proto/db/aliases                proto/sm.conf                   
-        proto/post-install.sh
+        proto/post-install.sh           proto/zmailer_dspam.conf
 ],[])dnl
 dnl man-files
 AC_CONFIG_FILES([
diff -N -r -u ./zmailer.orig/proto/zmailer_dspam.conf.in ./zmailer/proto/zmailer_dspam.conf.in
--- ./zmailer.orig/proto/zmailer_dspam.conf.in	1970-01-01 03:00:00.000000000 +0300
+++ ./zmailer/proto/zmailer_dspam.conf.in	2010-01-03 16:44:58.000000000 +0300
@@ -0,0 +1,50 @@
+# Configuration for zmailer_dspam module
+
+# Turn the dspam check on or off
+# def: dspam_check off
+#
+dspam_check	on
+
+# transport setup: yes - UNIX socket, no - TCP transport 
+# def: socket_transport yes
+#
+socket_transport	no
+
+# socket location or TCP parms
+# def: unix_socket /tmp/dspam.sock
+# def: tcp_host 127.0.0.1
+# def: tcp_port 24
+#
+tcp_host	127.0.0.1
+
+# dspam clients require authentication
+# def: dspam_user nobody
+# def: dspam_pass secret@Relay1
+#
+dspam_user	nobody
+dspam_pass	secret@Relay1
+
+# dspamd answer timeout (sec)
+# def: dspam_timeout 30
+#
+dspam_timeout	10
+
+# dsapm will check maxfilesize 
+# def dsapm_maxfilesize 4M
+#
+dspam_maxfilesize 30M
+
+# checks the first bytes of a message if message size is more
+# def: dspam_checkfilesize 256K
+#
+dspam_checkfilesize   128K
+
+# switch dspam client to "classify" ONLY mode. "process" mode by def.
+# def: dspam_classify off
+#
+dspam_classify  off
+
+# don't add any header on skip messages
+# def: dspam_quiet off
+#
+dspam_quiet on
diff -N -r -u ./zmailer.orig/smtpserver/dspamcheck.c ./zmailer/smtpserver/dspamcheck.c
--- ./zmailer.orig/smtpserver/dspamcheck.c	1970-01-01 03:00:00.000000000 +0300
+++ ./zmailer/smtpserver/dspamcheck.c	2010-01-03 15:14:39.000000000 +0300
@@ -0,0 +1,947 @@
+/* DSPAM plugin for Zmailer MTA 
+
+  Submit messages over LMTP protocol to dspamd and add DSPAM headers into it 
+
+  Copyright (C) 2004-2009 kocmuk.ru
+  http://kocmuk.ru/2010/01/03/dspam-in-conjunction-with-zmailer/
+
+  Version 1.0.2
+  ---------------------------------------------------------------------------
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions
+  are met:
+
+    1. Redistributions of source code must retain the above copyright
+       notice, this list of conditions and the following disclaimer.
+    2. Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in
+       the documentation and/or other materials provided with the
+       distribution.
+    3. The name of the author may not be used to endorse or promote
+       products derived from this software without specific prior written
+       permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+  OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+-----------------------------------------------------------------------------
+*/
+
+#define MAXSTRSIZE          4096
+#define SCANINMEMORYSIZE    1048576
+#define DSPAM_CMD_LEN       256
+#define DSPAM_CONF "/usr/local/zmailer/zmailer_dspam.conf"
+
+/* def config */
+#define DSPAM_TIMEOUT       30
+#define DSPAM_PORT          24
+#define DSPAM_HOST	    "127.0.0.1"
+#define DSPAM_SOCKET	    "/tmp/dspam.sock"
+#define DSPAM_MAXFILESIZE   4194304 /* 4Mb */
+#define DSPAM_USER	    "nobody" 
+#define DSPAM_AUTH	    "secret@Relay1"
+#define DSPAM_CHECKFILESIZE 262144 /* 256K */
+
+/* Defines the bar score ranges. By default the following ratios are used:
+ * digital    Bar score
+ * 0          []
+ * 1-49       [X]
+ * 50-70      [XX]
+ * 71-89      [XXX]
+ * 90-94      [XXXX]
+ * 95-98      [XXXXX]
+ * 99-100     [XXXXXX]
+*/
+int BARSCORERANGES[] = {0,49,70,89,94,98,100,      -1};
+/*  Bar score here      ^^^^^^^^^^^^^^^^^^^^ */
+
+#define TRANSPORT_LOCALHOST 0x01    /* TCP to localhost only */
+#define TRANSPORT_TCP       0x02    /* standard TCP socket   */
+#define TRANSPORT_UNIX      0x03    /* UNIX domain socket    */
+#define TRANSPORT_MAX_HOSTS 1
+
+#ifndef offsetof
+# define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+typedef struct transport
+{
+    int            	type;
+    const char     	*socketpath;    	/* for UNIX domain socket */
+    const char     	*host;      		/* for TCP sockets        */
+    unsigned short 	port;           	/* for TCP sockets        */
+    struct in_addr 	hosts[TRANSPORT_MAX_HOSTS];
+    int            	nhosts;
+    int            	flags;
+} transport_t;
+
+typedef struct req
+{
+    transport_t     	*trans;
+    char            	duser[MAXSTRSIZE];
+    char            	dauth[MAXSTRSIZE];
+    int             	classify;
+    int			quiet;
+    int			dcheckfs;
+    int			timeout;
+    const char		*fname;
+    char		headers[MAXSTRSIZE];
+} req_t;
+
+typedef struct dspam_cfg {
+    int 		dspam_check;
+    int 		socket_transport;
+    char 		*unix_socket;
+    char 		*tcp_host;
+    int 		tcp_port;
+    char 		*dspam_user;
+    char 		*dspam_pass;
+    int 		dspam_maxfilesize;
+    int 		dspam_timeout;
+    int 		dspam_classify;
+    int 		dspam_quiet;
+    int 		dspam_checkfilesize;
+} dspam_cfg_t;
+
+static struct _verbs {
+    char 		*verb;
+    enum 		{badverb,boolean,integer,string} vtype;
+    size_t 		where;
+} verbs[] = {
+    {"dspam_check",    	boolean,offsetof(dspam_cfg_t,dspam_check)},
+    {"socket_transport",boolean,offsetof(dspam_cfg_t,socket_transport)},
+    {"unix_socket",     string, offsetof(dspam_cfg_t,unix_socket)},
+    {"tcp_host",        string, offsetof(dspam_cfg_t,tcp_host)},
+    {"tcp_port",        integer,offsetof(dspam_cfg_t,tcp_port)},
+    {"dspam_user",      string, offsetof(dspam_cfg_t,dspam_user)},
+    {"dspam_pass",      string, offsetof(dspam_cfg_t,dspam_pass)},
+    {"dspam_maxfilesize",integer,offsetof(dspam_cfg_t,dspam_maxfilesize)},
+    {"dspam_checkfilesize",integer,offsetof(dspam_cfg_t,dspam_checkfilesize)},
+    {"dspam_timeout",   integer,offsetof(dspam_cfg_t,dspam_timeout)},
+    {"dspam_classify",  boolean,offsetof(dspam_cfg_t,dspam_classify)},
+    {"dspam_quiet",     boolean,offsetof(dspam_cfg_t,dspam_quiet)},
+    {NULL,              badverb,0}
+};
+
+/* ----------------------------------------------------------------- */
+dspam_cfg_t * 	dspam_config(char *fn);
+void        	chomp (char *string);
+static int  	ds_lmtp(FILE *fd, char *buf, size_t buflen, const char *cmd, int wait, int timeout, int fds);
+static int  	getline(FILE *fd, char *buf, size_t buflen, int timeout, int fds);
+static int  	ds_stream(req_t *req);
+void    	dspam_level_calculate(char *msg);
+static int  	transport_connect(req_t *req);
+static void 	transport_init(transport_t *trans);
+static int  	transport_setup(transport_t *trans);
+static int  	dspamcheck(const char *ifname, FILE *ifd, long fsize);
+static int  	addheader_f(const char *ifname, FILE *ifd, const char *header);
+static int  	addheader_m(const char *ifname, FILE *ifd, const char *header);
+static long long getnum(char *p);
+static int 	select_fd (int fd, int maxtime, int writep);
+char 		*ifgets(char *s, int size, FILE *stream, int timeout, int fds);
+
+/* ----------------------------------------------------------------- */
+int
+dspamcheck(ifname, ifd, fsize)
+const char *ifname;
+FILE	*ifd;
+long 	fsize;
+{
+	int		rc;
+	transport_t     trans;
+	req_t           *req;
+	dspam_cfg_t 	*cfg;
+	char 		cfile[128];
+
+/* Read config  */
+	snprintf(cfile,sizeof(cfile),"%s",DSPAM_CONF);
+	if (!(cfg = dspam_config(cfile))) {
+		return 0;
+	}
+/*
+        type(NULL,0,NULL, "DSPAM error: cfg dspam_check=%d",cfg->dspam_check);
+        type(NULL,0,NULL, "DSPAM error: cfg socket_transport=%d",cfg->socket_transport);
+        type(NULL,0,NULL, "DSPAM error: cfg unix_socket=%s",cfg->unix_socket);
+        type(NULL,0,NULL, "DSPAM error: cfg tcp_host=%s",cfg->tcp_host);
+        type(NULL,0,NULL, "DSPAM error: cfg tcp_port=%d",cfg->tcp_port);
+        type(NULL,0,NULL, "DSPAM error: cfg dspam_user=%s",cfg->dspam_user);
+        type(NULL,0,NULL, "DSPAM error: cfg dspam_pass=%s",cfg->dspam_pass);
+        type(NULL,0,NULL, "DSPAM error: cfg dspam_maxfilesize=%d",cfg->dspam_maxfilesize);
+	type(NULL,0,NULL, "DSPAM error: cfg dspam_checkfilesize=%d",cfg->dspam_checkfilesize);
+        type(NULL,0,NULL, "DSPAM error: cfg dspam_timeout=%d",cfg->dspam_timeout);
+        type(NULL,0,NULL, "DSPAM error: cfg dspam_classify=%d",cfg->dspam_classify);
+	type(NULL,0,NULL, "DSPAM error: cfg dspam_quiet=%d",cfg->dspam_quiet);
+*/
+
+/* Configure: step 1*/
+	/* Exit if dspam_check is off */
+	if (!cfg->dspam_check) { 
+		if (cfg) free(cfg);
+		type(NULL,0,NULL, "DSPAM ok: dspam check is off. Skip check.");
+		return 1;
+	}
+	/*  Exit if msg size more then cfg.maxfilesize */
+	if (cfg->dspam_maxfilesize && cfg->dspam_maxfilesize < fsize) {
+		if (cfg) free(cfg);
+		type(NULL,0,NULL, "DSPAM ok: msg size(%d) more then maxfilesize(%d). Skip check.", fsize, cfg->dspam_maxfilesize);
+		return 1;
+	}
+
+	transport_init(&trans);
+
+/* Configure: step 2 */
+	if (cfg->socket_transport) {
+		trans.type = TRANSPORT_UNIX;
+		if (cfg->unix_socket)
+			trans.socketpath = cfg->unix_socket;
+	} else {
+		trans.type = TRANSPORT_TCP;
+		if (cfg->tcp_host)
+			trans.host = cfg->tcp_host;
+		if (cfg->tcp_port)
+			trans.port = cfg->tcp_port;
+	} 
+    	if( transport_setup(&trans) ) {
+		type(NULL,0,NULL, "DSPAM error: Can't transport_setup()");
+		if (cfg) free(cfg);
+        	return 0;
+    	}
+
+/* Make request */
+        if( (req = (req_t *)calloc(1, sizeof(req_t))) == NULL ) {
+		type(NULL,0,NULL, "DSPAM error: Can't calloc(): errno = %d",  errno);
+		if (cfg) free(cfg);
+                return 0;
+        }
+
+/* Configure: step 3 */
+	if (!cfg->dspam_user)
+		cfg->dspam_user = DSPAM_USER;
+	strncpy(req->duser, cfg->dspam_user, strlen(cfg->dspam_user));
+	if (!cfg->dspam_pass)
+		cfg->dspam_pass = DSPAM_AUTH;
+	strncpy(req->dauth, cfg->dspam_pass, strlen(cfg->dspam_pass));
+	if (!cfg->dspam_timeout)
+		cfg->dspam_timeout = DSPAM_TIMEOUT;
+	req->timeout = cfg->dspam_timeout;
+	if (!cfg->dspam_checkfilesize)
+		cfg->dspam_checkfilesize = DSPAM_CHECKFILESIZE;
+	req->dcheckfs = cfg->dspam_checkfilesize;
+
+	req->trans = &trans;
+	req->fname = ifname;
+	req->classify = cfg->dspam_classify;
+	req->quiet = cfg->dspam_quiet;
+/*
+        type(NULL,0,NULL, "DSPAM error: cfg dspam_check=%d",cfg->dspam_check);
+        type(NULL,0,NULL, "DSPAM error: cfg socket_transport=%d",cfg->socket_transport);
+        type(NULL,0,NULL, "DSPAM error: cfg unix_socket=%s",cfg->unix_socket);
+        type(NULL,0,NULL, "DSPAM error: cfg tcp_host=%s",cfg->tcp_host);
+        type(NULL,0,NULL, "DSPAM error: cfg tcp_port=%d",cfg->tcp_port);
+        type(NULL,0,NULL, "DSPAM error: cfg dspam_user=%s",cfg->dspam_user);
+        type(NULL,0,NULL, "DSPAM error: cfg dspam_pass=%s",cfg->dspam_pass);
+        type(NULL,0,NULL, "DSPAM error: cfg dspam_maxfilesize=%d",cfg->dspam_maxfilesize);
+        type(NULL,0,NULL, "DSPAM error: cfg dspam_checkfilesize=%d",cfg->dspam_checkfilesize);
+        type(NULL,0,NULL, "DSPAM error: cfg dspam_timeout=%d",cfg->dspam_timeout);
+        type(NULL,0,NULL, "DSPAM error: cfg dspam_classify=%d",cfg->dspam_classify);
+        type(NULL,0,NULL, "DSPAM error: cfg dspam_quiet=%d",cfg->dspam_quiet);
+*/
+/* Call DSPAM */
+	rc = ds_stream(req);
+    	if (rc < 0 ) {
+		if(req) free(req);
+		if (cfg) free(cfg);
+		return 0;
+    	} else if (rc == 0) {
+		if(req) free(req);
+		if (cfg) free(cfg);
+		type(NULL,0,NULL, "DSPAM ok: DSPAM Skip the message");
+		return 1;
+	} else {
+		/* Add header */        
+		if (fsize > SCANINMEMORYSIZE) 
+			rc = addheader_f(ifname, ifd, req->headers);
+		else 
+			rc = addheader_m(ifname, ifd, req->headers);
+
+		if(req) free(req);
+		if (cfg) free(cfg);
+		return rc; 
+	}
+}
+
+/* Call DSPAM via DLMTP ----------------------------------------------------------------- */
+static int
+ds_stream(req_t *req)
+{
+    char                buf[MAXSTRSIZE+2];
+    char                dspam_cmd[DSPAM_CMD_LEN];
+    int                 buf_len = sizeof(buf) - 2, len;
+    int                 fds = -1, fdis = -1, domsg = 0, fcut = 0;
+    FILE                *fd, *fdi;
+    long                fsize = 0, psize = 0;
+
+    if( (fds = transport_connect(req)) == -1 )
+        return -1;
+    if( (fd =  fdopen(fds, "w+")) == NULL ) {
+	type(NULL,0,NULL, "DSPAM error: ds_stream: Can't fdopen(): %s", strerror(errno));
+        close(fds);
+        return -1;
+    }
+    setvbuf(fd, (char *) NULL, _IONBF, 0);
+
+/* --- INIT --- */
+    if (ds_lmtp(fd, buf, buf_len, "", 220, req->timeout, fds) < 0) {
+	type(NULL,0,NULL, "DSPAM error: LMTP (INIT) error");
+        fclose(fd);
+        close(fds);
+        return -1;
+    }
+
+/* --- LHLO --- */
+    if (ds_lmtp(fd, buf, buf_len, "LHLO localhost.localdomain", 250, req->timeout, fds) < 0) {
+	type(NULL,0,NULL, "DSPAM error: LMTP (LHLO)  error");
+        fclose(fd);
+        close(fds);
+        return -1;
+    }
+
+/* --- MAIL FROM --- */
+    if (req->classify) {
+        snprintf(dspam_cmd, sizeof(dspam_cmd),
+                "MAIL FROM: <%s> DSPAMPROCESSMODE=\"--client --classify --stdout\"", req->dauth);
+    } else {
+        snprintf(dspam_cmd, sizeof(dspam_cmd),
+                "MAIL FROM: <%s> DSPAMPROCESSMODE=\"--client --process --deliver=innocent,spam --stdout\"", req->dauth);
+    }
+    if (ds_lmtp(fd, buf, buf_len, dspam_cmd, 250, req->timeout, fds) < 0) {
+	type(NULL,0,NULL, "DSPAM error: LMTP (MAIL FROM) error");
+        fclose(fd);
+        close(fds);
+        return -1;
+    }
+
+/* --- RCPT TO --- */
+    snprintf(dspam_cmd, sizeof(dspam_cmd), "RCPT TO: <%s>", req->duser);
+    if (ds_lmtp(fd, buf, buf_len, dspam_cmd, 250, req->timeout, fds) < 0) {
+	type(NULL,0,NULL, "DSPAM error: LMTP (RCPT TO) error");
+        fclose(fd);
+        close(fds);
+        return -1;
+    }
+
+/* --- DATA --- */
+    if (ds_lmtp(fd, buf, buf_len, "DATA", 354, req->timeout, fds) < 0) {
+	type(NULL,0,NULL, "DSPAM error: LMTP (DATA) error");
+        fclose(fd);
+        close(fds);
+        return -1;
+    }
+
+/* --- open file --- */
+    if( (fdi = fopen(req->fname, "r")) == NULL ) {
+	type(NULL,0,NULL, "DSPAM error: Can't open file(%s): %s", req->fname, strerror(errno));
+        fclose(fd);
+        close(fds);
+        return -1;
+    }
+
+    /* Check file size and set fcut flag */
+    fseek(fdi, 0L, SEEK_END);
+    fsize = ftell(fdi);
+    fseek(fdi, 0L, SEEK_SET);
+    if (fsize > (req->dcheckfs + 2*1024))
+        fcut = 1;
+
+    setvbuf(fd, (char *) NULL, _IONBF, 0);
+    fdis = fileno(fdi);
+
+/* --- put file to dspam --- */
+    while( (len = getline(fdi, buf, buf_len, req->timeout, fdis)) > 0 ) {
+
+        /* Skip Zmailer headers */
+	if (( strncmp(buf, "env-end\n", 8) == 0 ) && (!domsg) && (len == 8)) {
+            domsg = 1;
+            continue;
+        }
+        if (domsg) {
+            if (fcut) {
+                if (psize > req->dcheckfs)
+                        break;
+                psize = psize + len;
+            }
+            if( fputs(buf, fd) <= 0 ) {
+		type(NULL,0,NULL, "DSPAM error:  Can't fputs(): %s", strerror(errno));
+                fclose(fd);
+                close(fds);
+                fclose(fdi);
+                return -1;
+            }
+            fflush(fd);
+        }
+    }
+    fclose(fdi);
+
+/* --- put end (.) --- */
+    if( fputs(".\n", fd) <= 0 ) {
+	type(NULL,0,NULL, "DSPAM error:  LMTP (.) error");
+        fclose(fd);
+        close(fds);
+        return -1;
+    }
+    fflush(fd);
+
+/* --- READ answer --- */
+    if( (len = getline(fd, buf, buf_len, req->timeout, fds)) <= 0 ) {
+	type(NULL,0,NULL, "DSPAM error: Can't read(): %s", strerror(errno));
+        fclose(fd);
+        close(fds);
+        return -1;
+    }
+
+/* --- QUIT --- */
+    if( fputs("QUIT\n", fd) <= 0 ) {
+	type(NULL,0,NULL, "DSPAM error: LMTP (QUIT) error");
+        fclose(fd);
+        close(fds);
+        return -1;
+    }
+    fflush(fd);
+
+    fclose(fd);
+    close(fds);
+
+/* --- Check  answer --- */
+    buf[len] = '\0';
+    chomp(buf);
+
+    if( strcasecmp(buf, "X-DSPAM-Result:") >= 0 ) {
+	dspam_level_calculate(buf);
+	strncpy(req->headers, buf, sizeof(buf)-1);
+        return 1;
+    } else if (strcasecmp(buf, ".") == 0 ) {
+        if (req->quiet) {
+		return 0;
+        } else {
+		strcpy(req->headers, "X-DSPAM-Result: Skip\\n");
+		return 1;
+        }
+    } else {
+	type(NULL,0,NULL, "DSPAM error: abnormal reply: '%s'", buf);
+        return -1;
+    }
+}
+
+/* Add header via temp file ----------------------------------------------------------------- */
+int
+addheader_f(ifname, ifd, header)
+const char *ifname, *header;
+FILE *ifd;
+{
+	FILE	*ofd = NULL;
+	char	ofname[MAXSTRSIZE];
+	char	s[MAXSTRSIZE];
+	int	rc, found = 0;
+	char 	*p, *q;
+
+	sprintf(ofname, "%s.tmp", ifname);
+
+	if( (ofd = fopen(ofname, "w+")) == NULL ) {
+        	type(NULL,0,NULL, "DSPAM error: Can't open(%s) temporary: errno = %d", ofname, errno);
+		return 0;
+	}
+
+	rewind(ifd);
+	while (fgets(s, MAXSTRSIZE, ifd)) {
+		rc = fputs(s, ofd);
+		if ( rc == EOF ) {
+			type(NULL,0,NULL, "DSPAM error: Can't write to temporary(%s): errno = %d", ofname, errno);
+			fclose(ofd);
+			unlink(ofname);
+			return 0;
+		}
+	}
+
+	rewind(ifd);
+	rewind(ofd);
+	while (fgets(s, MAXSTRSIZE, ofd)) {
+		rc = fputs(s, ifd);
+                if ( rc == EOF ) {
+                        type(NULL,0,NULL, "DSPAM error: Can't write back to original(%s): errno = %d. CRITICAL!", 
+				ifname, errno);
+			type(NULL,0,NULL, "DSPAM error: Message will be rejected temporary");
+                        fclose(ofd);
+                        unlink(ofname);
+                        return -1;
+                }
+		if (found == 0 && strncmp("env-end\n", s, 8) == 0) {
+			type(NULL,0,NULL, "DSPAM header added: '%s'", header);
+			while ((p = strstr(header, "\\n")) != NULL ) {
+				*p = '\0';
+				fprintf(ifd, "%s\n", header);
+				q = p + 2;
+				if (*q == '\0')
+					break;	
+				header = q;	
+			}
+                	found = 1;
+		}
+	}
+	fflush(ifd);
+	fclose(ofd);
+	unlink(ofname);
+	return 1;
+}
+
+/* Add header via memory dump ----------------------------------------------------------------- */
+int
+addheader_m(ifname, ifd, header)
+const char *ifname, *header;
+FILE *ifd;
+{
+        char	*ofd;
+        char    *p = 0, *q = 0, *pp = 0;
+	long	fsize = 0, tsize = 0;
+
+	fseek(ifd, 0L, SEEK_END);
+	fsize = ftell(ifd);
+	fseek(ifd, 0L, SEEK_SET);
+
+        if( (ofd = (char *)calloc(sizeof(char), fsize+1)) == NULL ) {
+                type(NULL,0,NULL, "DSPAM error: Can't calloc() for tmp msg: errno = %d",  errno);
+		fseek(ifd, 0L, SEEK_END);
+                return 0;
+        }
+
+	if (fsize != fread(ofd, sizeof(char), fsize, ifd)) {
+		type(NULL,0,NULL, "DSPAM error: Can't write to temporary memory: errno = %d", errno);
+		if (ofd) free(ofd);
+		fseek(ifd, 0L, SEEK_END);
+		return 0;
+	}
+
+	pp = strstr(ofd, "env-end\n\0");
+	if (pp == NULL ) {
+		type(NULL,0,NULL, "DSPAM error: Can't find 'env-end' str in memory");
+		if (ofd) free(ofd);
+		fseek(ifd, 0L, SEEK_END);
+		return 0;
+	}
+
+	pp = pp + 8; /* sizeof("env-end\n\0") = 8 */
+	rewind(ifd);
+	tsize = pp - ofd; 
+
+	if (tsize != fwrite(ofd, sizeof(char), tsize, ifd)) {
+		type(NULL,0,NULL, "DSPAM error: Can't write back to original(%s) from memory: errno = %d. CRITICAL!",
+			ifname, errno);
+		type(NULL,0,NULL, "DSPAM error: Message will be rejected temporary");
+		if (ofd) free(ofd);
+		return -1;
+	} 
+
+	type(NULL,0,NULL, "DSPAM header added: '%s'", header);
+	while ((p = strstr(header, "\\n")) != NULL ) {
+		*p = '\0';
+		fprintf(ifd, "%s\n", header);
+		q = p + 2;
+		if (*q == '\0')
+			break;
+		header = q;
+	}
+
+	tsize = fsize - tsize;
+
+        if (tsize != fwrite(pp, sizeof(char), tsize, ifd)) {
+                type(NULL,0,NULL, "DSPAM error: Can't write back to original(%s) from memory: errno = %d. CRITICAL!",
+                        ifname, errno);
+                type(NULL,0,NULL, "DSPAM error: Message will be rejected temporary");
+                if (ofd) free(ofd);
+                return -1;
+        }
+
+        fflush(ifd);
+        if (ofd) free(ofd);
+        return 1;
+}
+
+/* DLMTP DSPAM dialog ----------------------------------------------------------------- */
+static int
+ds_lmtp(FILE *fd, char *buf, size_t buf_len, const char *cmd, int wait, int timeout, int fds)
+{
+    char    ecmd[MAXSTRSIZE];
+    char    rstr;
+    int     rc, len;
+
+    if( strlen(cmd) > 0 ) {
+        snprintf(ecmd, sizeof(ecmd), "%s\n", cmd);
+        if( fputs(ecmd, fd) <= 0 ) {
+	    type(NULL,0,NULL, "DSPAM error: ds_lmtp: Can't fputs(): %s", strerror(errno));
+            return -1;
+        }
+        fflush(fd);
+    }
+
+    while( (len = getline(fd, buf, buf_len, timeout, fds)) >=0 ) {
+        chomp(buf);
+        if ( sscanf(buf,"%03d%c",&rc, &rstr) <= 0 ) {
+	     type(NULL,0,NULL, "DSPAM error: ds_lmtp: abnormal answer: %s", buf);
+             return -1;
+        }
+        if ( rstr != ' ' )
+             continue;
+        if ( rc == wait )
+             return 1;
+	type(NULL,0,NULL, "DSPAM error: ds_lmtp: error: wait='%d', but rc='%d', str='%s'", wait, rc, buf);
+        return -1;
+    }
+    return -1;
+}
+
+/* calculate spam level and add X-Junk-Score scorebar ----------------------------- */
+void
+dspam_level_calculate (char *msg)
+{
+    float   conf=0.00, prob=0.00, tprob=0.00, out=0.00;
+    char    level[128]="", score[28]="", result[128]="";
+    char    *p;
+    int     i,rv=0;
+
+    if ((p = strstr(msg, "X-DSPAM-Result: "))) {
+        if ( sscanf(p,"X-DSPAM-Result: %s", result) != 1 ) {
+	    type(NULL,0,NULL, "DSPAM error: dspam_level_calculate: 'X-DSPAM-Result' parse error");
+            return;
+        } else {
+            if( strncasecmp(result, "Spam", 4) != 0 ) {
+       	        return;
+            }
+        }
+    } else {
+	type(NULL,0,NULL, "DSPAM error: dspam_level_calculate: 'X-DSPAM-Result' not found"); 
+        return;
+    }
+
+    if ((p = strstr(msg, "X-DSPAM-Confidence: "))) {
+        if ( sscanf(p,"X-DSPAM-Confidence: %f", &conf) != 1 ) {
+	    type(NULL,0,NULL, "DSPAM error: dspam_level_calculate: 'X-DSPAM-Confidence' parse error");
+            return;
+        }
+    } else {
+	type(NULL,0,NULL, "DSPAM error: dspam_level_calculate: 'X-DSPAM-Confidence' not found");
+        return;
+    }
+
+    if ((p = strstr(msg, "X-DSPAM-Probability: "))) {
+        if ( sscanf(p,"X-DSPAM-Probability: %f", &prob) != 1 ) {
+	    type(NULL,0,NULL, "DSPAM error: dspam_level_calculate: 'X-DSPAM-Probability' parse error");
+            return;
+        }
+    } else {
+	type(NULL,0,NULL, "DSPAM error: dspam_level_calculate: 'X-DSPAM-Probability' not found");
+        return;
+    }
+
+    tprob = (((prob - 0.5) * 2) * 100);
+    if (tprob <= 0) {
+	type(NULL,0,NULL, "DSPAM error: dspam_level_calculate: tprob=%f that <= 0", tprob);
+        return;
+    }
+    out = ((tprob + (conf*100)) / 2);
+    if (out > 0 && out < 101 ) {
+        if (out > 3 && out < 7) {
+            rv = 5;
+        } else {
+            rv = (abs((out / 10) + 0.49) * 10);
+            if (out > 93)
+                rv -= out > 97 ? 1:5;
+        }
+
+        for (i=0; BARSCORERANGES[i] >= 0; i++) {
+            if (i==0) {
+                if (rv<=BARSCORERANGES[i])
+                    break;
+            } else {
+                if (rv>BARSCORERANGES[i-1] && rv<=BARSCORERANGES[i]) {
+                    while(i--)
+                        strcat(score,"X");
+                    break;
+                }
+            }
+        }
+        sprintf(level, "X-Junk-Score: %d [%s]\\n", rv, score);
+        strcat(msg, level);
+    } else {
+	type(NULL,0,NULL, "DSPAM error: dspam_level_calculate: Outcome='%f' calculate error.", out);
+        return;
+    }
+
+return;
+}
+
+/* getline function ----------------------------------------------------------------- */
+static int
+getline(FILE *fd, char *buf, size_t buflen, int timeout, int fds)
+{
+  /* If the file isn't there or at the end, can't do anything */
+  if ( (NULL == fd) || feof(fd) || ferror(fd) ) {
+	type(NULL,0,NULL, "DSPAM error: getline: file isn't there or at the end, can't do anything: %s", strerror(errno));
+        return -1;
+  }
+
+  if (ifgets(buf, buflen, fd, timeout, fds))
+        return strlen(buf);
+  if (errno == ETIMEDOUT)
+	 type(NULL,0,NULL, "DSPAM error: getline: Socket timeout after %d seconds", timeout);
+  return (-1);
+}
+
+/* Make TCP or UNIX connect to dspamd ----------------------------------------------------------------- */
+static int
+transport_connect(req_t *req)
+{
+    struct sockaddr_in  srv_i;
+    struct sockaddr_un  srv_u;
+    transport_t         *trans = req->trans;
+    int                 fd = -1;
+
+    switch( trans->type ) {
+        case TRANSPORT_TCP:
+            if( (fd = socket(PF_INET, SOCK_STREAM, 0)) < 0 ) {
+		type(NULL,0,NULL, "DSPAM error: Can't tcp socket(): errno = %d", errno); 
+                return -1;
+            }
+
+            memset(&srv_i, 0, sizeof(srv_i));
+            srv_i.sin_family = AF_INET;
+            srv_i.sin_port = htons(trans->port);
+            srv_i.sin_addr = trans->hosts[0];
+
+            if( connect(fd, (struct sockaddr *) &srv_i, sizeof(srv_i)) < 0 ) {
+		type(NULL,0,NULL, "DSPAM error: Can't tcp connect(): errno = %d" , errno);
+                close(fd);
+                return -1;
+            }
+            break;
+
+        case TRANSPORT_UNIX:
+            if( (fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0 ) {
+		type(NULL,0,NULL, "DSPAM error: Can't unix socket(): errno = %d", errno);
+                return -1;
+            }
+            memset(&srv_u, 0, sizeof(srv_u));
+            srv_u.sun_family = AF_UNIX;
+            strncpy(srv_u.sun_path, trans->socketpath, sizeof(srv_u.sun_path) - 1);
+            if( connect(fd, (struct sockaddr *) &srv_u, sizeof(srv_u)) < 0 ) {
+		type(NULL,0,NULL, "DSPAM error: Can't unix connect(): errno = %d", errno);
+                close(fd);
+                return -1;
+            }
+            break;
+
+        default:
+            break;
+    }
+    return fd;
+}
+
+/* INIT transport ----------------------------------------------------------------- */
+static void
+transport_init(transport_t *trans)
+{
+    memset(trans, 0, sizeof(transport_t));
+    trans->port = DSPAM_PORT;
+    trans->host = DSPAM_HOST;
+    trans->socketpath = DSPAM_SOCKET;
+}
+
+/* SETUP transport ----------------------------------------------------------------- */
+static int
+transport_setup(transport_t *trans)
+{
+    switch( trans->type ) {
+        case TRANSPORT_TCP:
+            trans->hosts[0].s_addr = inet_addr(trans->host);
+            trans->nhosts = 1;
+            break;
+        case TRANSPORT_UNIX:
+            break;
+        default:
+	    type(NULL,0,NULL, "DSPAM error: unknown transport type: %d", trans->type);
+            return -1;
+            break;
+    }
+    return 0;
+}
+
+/* Make chomp ----------------------------------------------------------------- */
+void
+chomp (char *string)
+{
+  int len;
+  if (string == NULL)
+    return;
+  len = strlen (string);
+  if (len && string[len - 1] == 10)
+  {
+    string[len - 1] = 0;
+    len--;
+  }
+  if (len && string[len - 1] == 13)
+    string[len - 1] = 0;
+  return;
+}
+
+/* Read config, parse and make cfg structure ----------------------------------------------------------------- */
+dspam_cfg_t *
+dspam_config(char *fn)
+{
+        dspam_cfg_t *cfg;
+        FILE *fp;
+        char buf[256];
+        char fbuf[128];
+        int count=0;
+
+        if( (cfg = (dspam_cfg_t *)malloc(sizeof(dspam_cfg_t))) == NULL ) {
+		type(NULL,0,NULL, "DSPAM error: Can't malloc for config: errno = %d",  errno);
+		return 0;
+	}
+        memset(cfg,0,sizeof(dspam_cfg_t));
+        snprintf(fbuf,sizeof(fbuf),"%s",fn);
+
+/*	type(NULL,0,NULL, "DSPAM error: dspam_config fn=%s", fn); */
+
+        if ((fp=fopen(fn,"r")) == NULL) {
+		type(NULL,0,NULL, "DSPAM error: Can't open config file fn=%s", fn);
+                return cfg;
+        }
+
+        while (fgets(buf,sizeof(buf)-1,fp)) {
+                char *p;
+                int i;
+
+                count++;
+
+                if (buf[0] == '#') continue;
+                buf[sizeof(buf)-1]='\0';
+                p=buf+strlen(buf)-1;
+                while ((p >= buf) && ((*p == '\r') || (*p == '\n') ||
+                                     (*p == ' ') || (*p == '\t'))) *p--='\0';
+                if (buf[0] == '\0') continue;
+                for (p=buf;(*p != ' ') && (*p != '\t') && (*p != '\0');p++) ;
+                *p++='\0';
+                while ((*p == ' ') || (*p == '\t')) p++;
+                for (i=0;verbs[i].verb;i++) {
+                        if (strcasecmp(verbs[i].verb,buf) == 0) break;
+                }
+                switch (verbs[i].vtype) {
+                case boolean:
+                        if ((strcasecmp(p,"yes") == 0) ||
+                            (strcasecmp(p,"on") == 0)) {
+                                *((int*)((char*)cfg+verbs[i].where))=1;
+                        } else if ((strcasecmp(p,"no") == 0) ||
+                                   (strcasecmp(p,"off") == 0)) {
+                                *((int*)((char*)cfg+verbs[i].where))=0;
+                        } else {
+				type(NULL,0,NULL, "DSPAM error: Config parse error %s(%d): bad boolean '%s'",
+                                        fn,count,p);
+                        }
+                        break;
+                case string:
+                        *((char**)((char*)cfg+verbs[i].where))=
+                                                (char*)malloc(strlen(p)+1);
+                        strcpy(*((char**)((char*)cfg+verbs[i].where)),p);
+                        break;
+		case integer:
+                        *((int*)((char*)cfg+verbs[i].where))=(int)getnum(p);
+                        break;
+                case badverb:
+			type(NULL,0,NULL, "DSPAM error: Config parse error %s(%d): bad verb '%s'",
+                                        fn,count,buf);
+                        break;
+                }
+        }
+        fclose(fp);
+        return cfg;
+}
+
+/* Make long int from short format ----------------------------------------------------------------- */
+static long long getnum(char *p)
+{
+        long long factor;
+        char *q=p+strlen(p)-1;
+
+        switch (*q) {
+        case 'k':
+        case 'K':
+                factor=1024;
+                *q='\0';
+                break;
+        case 'm':
+        case 'M':
+                factor=1024*1024;
+                *q='\0';
+                break;
+        default:
+                factor=1;
+                break;
+        }
+        return factor*atol(p);
+}
+
+/* ----------------------------------------------------------------- */
+char *
+ifgets(char *s, int size, FILE *stream, int timeout, int fds)
+{
+  int res;
+
+  if (timeout) {
+      do {
+          res = select_fd (fds, timeout, 0);
+      } while (res == -1 && errno == EINTR);
+      if (res <= 0) {
+        if (res == 0) {
+                errno = ETIMEDOUT;
+                return NULL;
+        }
+      return NULL;
+      }
+  }
+  if(fgets(s, size, stream)) {
+        return s;
+  }
+  return NULL;
+}
+
+/* ----------------------------------------------------------------- */
+/* Wait for file descriptor FD to be readable, MAXTIME being the
+   timeout in seconds.  If WRITEP is non-zero, checks for FD being
+   writable instead.
+
+   Returns 1 if FD is accessible, 0 for timeout and -1 for error in
+   select().  */
+static int
+select_fd (int fd, int maxtime, int writep)
+{
+  fd_set fds, exceptfds;
+  struct timeval timeout;
+
+  FD_ZERO (&fds);
+  FD_SET (fd, &fds);
+  FD_ZERO (&exceptfds);
+  FD_SET (fd, &exceptfds);
+  timeout.tv_sec = maxtime;
+  timeout.tv_usec = 0;
+  /* HPUX reportedly warns here.  What is the correct incantation?  */
+  return select (fd + 1, writep ? NULL : &fds, writep ? &fds : NULL,
+                 &exceptfds, &timeout);
+}
+
diff -N -r -u ./zmailer.orig/smtpserver/smtpdata.c ./zmailer/smtpserver/smtpdata.c
--- ./zmailer.orig/smtpserver/smtpdata.c	2007-02-13 03:27:57.000000000 +0300
+++ ./zmailer/smtpserver/smtpdata.c	2009-12-28 18:00:42.000000000 +0300
@@ -29,6 +29,9 @@
 
 #include "smtpserver.h"
 
+/* DSPAM */
+#include "dspamcheck.c"
+
 #ifdef USE_TRANSLATION
 #include <libtrans.h>
 #endif				/* USE_TRANSLATION */
@@ -311,6 +314,28 @@
 	const char *sslines[20];
 	int sslinecnt = 0;
 
+	/* Lets see what the DSPAM will tell now ? */
+	int dsrc = dspamcheck(fname, SS->mfp, filsiz);
+	if (dsrc < 0) {
+            if (smtp_syslog)
+              zsyslog((LOG_INFO, 
+		"%s: DSPAM critical failed, rc=%d. For more information, see smtpserver log", taspid, dsrc));
+	    type(SS, 452, m430, NULL); /* insufficient system storage */
+	    if (lmtp_mode) for(i = 1; i < SS->ok_rcpt_count; ++i)
+	 	type(SS, 452, m430, NULL); /* insufficient system storage */
+	    typeflush(SS);
+	    reporterr(SS, tell, "dspamcheck critical failed");
+            mail_abort(SS->mfp);
+            policytest(&SS->policystate, POLICY_DATAABORT,
+                     	NULL, SS->rcpt_count, NULL);
+            MIBMtaEntry->ss.IncomingSMTP_DATA_bad += 1;
+            SS->mfp = NULL;
+            return 0;
+	} else if (dsrc == 0) {
+            if (smtp_syslog)
+              zsyslog((LOG_INFO,
+                "%s: DSPAM graceful failed, rc=%d. For more information, see smtpserver log", taspid, dsrc));
+	}
 
 	/* Lets see what the content-policy will tell now ? */
 
@@ -752,6 +777,30 @@
 	const char *sslines[20];
 	int sslinecnt = 0;
 
+        /* Lets see what the DSPAM will tell now ? */
+        int dsrc = dspamcheck(fname, SS->mfp, tell);
+        if (dsrc < 0) {
+            if (smtp_syslog)
+              zsyslog((LOG_INFO,
+                "%s: DSPAM critical failed, rc=%d. For more information, see smtpserver log", taspid, dsrc));
+	    type(SS, 452, m400, (char *) NULL);
+	    if (lmtp_mode && bdata_last) for(i = 1; i < SS->ok_rcpt_count; ++i)
+		type(SS, 452, m400, (char *) NULL);
+            typeflush(SS);
+            reporterr(SS, tell, "dspamcheck critical failed");
+	    clearerr(SS->mfp);
+            mail_abort(SS->mfp);
+            policytest(&SS->policystate, POLICY_DATAABORT,
+                        NULL, SS->rcpt_count, NULL);
+	    MIBMtaEntry->ss.IncomingSMTP_BDAT_bad += 1;
+            SS->mfp = NULL;
+            return 0;
+        } else if (dsrc == 0) {
+            if (smtp_syslog)
+              zsyslog((LOG_INFO,
+                "%s: DSPAM graceful failed, rc=%d. For more information, see smtpserver log", taspid, dsrc));
+        }
+
 	/* Lets see what the content-policy will tell now ? */
 
 	if (debug) typeflush(SS);

