--- src/EDITME	2007-01-22 16:29:54.000000000 +0000
+++ src/EDITME	2009-07-24 13:46:01.000000000 +0000
@@ -1133,4 +1133,9 @@
 
 # ENABLE_DISABLE_FSYNC=yes
 
+CFLAGS= -I/usr/local/ap-mailfilter3/include
+EXTRALIBS_EXIM=-L/usr/local/ap-mailfilter3/lib -lspamtest
+LOCAL_SCAN_SOURCE=Local/kas_exim.c
+LOCAL_SCAN_HAS_OPTIONS=yes
+
 # End of EDITME for Exim 4.
--- /dev/null	2009-07-24 13:44:23.000000000 +0000
+++ Local/kas_exim.c	2009-07-24 13:42:28.000000000 +0000
@@ -0,0 +1,871 @@
+
+#include "local_scan.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <syslog.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include "spamtest.h"
+#include "msgstore.h"
+
+//#define SPAMTEST_USE_SYSLOG
+
+/* Default values for configuration options */
+#define KAS_CONNECT_TIMEOUT             60000
+#define KAS_DEFAULT_DOMAIN              ""
+#define KAS_LOG_LEVEL                   0
+#define KAS_ON_ERROR                    "tempfail"
+#define KAS_DATA_TIMEOUT                60000
+#define KAS_CONNECT_TO                  "tcp:127.0.0.1:2277"
+#define KAS_FILTERING_SIZE_LIMIT        512
+
+/* Result variables for configuration options */
+static uschar *result_default_domain;
+static uschar *result_connect_to;
+static uschar *result_on_error_str;
+static int result_on_error;
+
+/* Configuration options */
+//old
+static int st_connect_timeout = 0;
+static int debug_level = 0;
+static int st_rw_timeout = 0;
+static int filtering_size_limit=0;
+static uschar *st_mail_domain;
+static uschar *st_on_error;
+static uschar *st_address;
+//new
+static int kas_connect_timeout = 0;
+static int kas_log_level = 0;
+static int kas_data_timeout = 0;
+static int kas_filtering_size_limit = 0;
+static uschar *kas_default_domain;
+static uschar *kas_on_error;
+static uschar *kas_connect_to;
+
+optionlist local_scan_options[] = 
+{/* The entries must appear in alphabetical order */
+    { "connect_timeout", opt_int, &st_connect_timeout },
+    { "kas_connect_timeout", opt_int, &kas_connect_timeout },
+    { "kas_connect_to", opt_stringptr, &kas_connect_to },
+    { "kas_data_timeout", opt_int, &kas_data_timeout },
+    { "kas_default_domain", opt_stringptr, &kas_default_domain },
+    { "kas_filtering_size_limit", opt_int, &kas_filtering_size_limit },
+    { "kas_log_level",opt_int,&kas_log_level},
+    { "kas_on_error",opt_stringptr,&kas_on_error},
+    { "local_mail_domain", opt_stringptr, &st_mail_domain },
+    { "log_level",opt_int,&debug_level},
+    { "on_spamtest_error",opt_stringptr,&st_on_error},
+    { "rw_timeout", opt_int, &st_rw_timeout },
+    { "spamtest_address", opt_stringptr, &st_address },
+    { "spamtest_filtering_size_limit", opt_int, &filtering_size_limit },
+};
+
+int local_scan_options_count = sizeof(local_scan_options)/sizeof(optionlist);
+
+
+int check_results(spamtest_session_t *s,spamtest_status_t *status,int *res,int fd,uschar **return_text);
+int proceed_accept(spamtest_status_t *status,int fd);
+void logger(const int log_level,const char *fmt,...);
+void prepare_config_parameters();
+void free_conf();
+
+
+int local_scan(int fd, uschar **return_text)
+{
+    int myfd;
+    char buf[4096];
+    int cnt = 0;
+    int totalcnt = 0;
+    int i;
+    header_line * tmp;
+    spamtest_session_t s;
+    int errorcode = STS_ERR_NO_ERR;
+    spamtest_status_t *status = NULL;
+    int rcpt_sent = 0;
+    int res = 0;
+    int rest = 0;
+    char *ctmp;
+
+    /* Initialize spamtest session */
+    
+    prepare_config_parameters();
+
+    if(filtering_size_limit > 0)
+	{
+	    struct stat sb;
+	    fstat(fd,&sb);
+	    if(sb.st_size > filtering_size_limit * 1024)
+		{
+		    logger(LOG_DEBUG," Message larger than filtering_size_limit, accepting");
+                    free_conf();
+		    return LOCAL_SCAN_ACCEPT;
+		}
+	}
+    
+    bzero(&s,sizeof(s));
+    s.access_address = result_connect_to;
+    s.rw_timeout = st_rw_timeout;
+    s.connect_timeout = st_connect_timeout;
+    s.mail_domain = result_default_domain;
+
+    if ( s.access_address == NULL || s.access_address[0] == '\0' )
+    {
+	logger(LOG_ERR," Spamtest access address not defined, cannot process mail by spam filtering");
+        free_conf();
+	return LOCAL_SCAN_ACCEPT;
+    }
+    
+    logger(LOG_DEBUG," Spam test session: %s %s %d %d",s.access_address,s.mail_domain,s.connect_timeout,s.rw_timeout);
+
+    if ( (errorcode = sts_init(&s)) < 0 )
+    {
+	logger(LOG_ERR," Unable to connect to %s (%s)",s.access_address,sts_strerror(errorcode));
+        free_conf();
+	return result_on_error;
+    };
+    
+    if ( ! s.should_store_message )
+    {
+	/* SMTP mode, blackholing message because filter will send message */
+	logger(LOG_ERR," Filter in SMTP mode, Incorrect situation.");
+	//recipients_count = 0;
+	sts_close(&s);
+        free_conf();
+	return result_on_error;
+    }
+
+    if ( sender_address != NULL && sender_address[0] != '\0' )
+    {
+	if ( (errorcode = sts_set_sender(&s,sender_address)) != STS_ERR_NO_ERR )
+	{
+	    logger(LOG_ERR," Unable to pass sender address %s(%d)",sender_address,errorcode);
+            free_conf();
+	    return result_on_error;
+	}
+    }
+    
+    if ( sender_host_address != NULL && sender_host_address[0] != '\0' )
+    {
+	if ( ( errorcode = sts_set_relay(&s,sender_host_address) ) != STS_ERR_NO_ERR )
+	{
+	    logger(LOG_ERR," Unable to pass relay IP");
+	    if(errorcode == STS_ERR_OUT_OF_MEMORY){
+                free_conf();
+		return result_on_error;
+            }
+	}
+    }
+
+    rcpt_sent = 0;
+    for ( i = 0;i<recipients_count;i++)
+    {
+	if ( recipients_list[i].address != NULL && recipients_list[i].address[0] != '\0' )
+	{
+	    if ( ( errorcode = sts_add_recipient(&s,recipients_list[i].address) ) != STS_ERR_NO_ERR )
+	    {
+		logger(LOG_ERR," Unable to pass recipient '%s' to filter",recipients_list[i].address);
+	    }
+	    else
+	    {
+		rcpt_sent++;
+	    }
+	}
+    }
+    if ( rcpt_sent == 0 )
+    {
+	logger(LOG_DEBUG," Recipients not sent to filter. Continue.");
+    }
+
+    tmp = header_list;
+    while ( tmp != NULL )
+    {
+	if(tmp->type != '*')
+	    {
+		logger(LOG_DEBUG,"Iterating a , %c %d %s|%d",tmp->type,tmp->slen,tmp->text,tmp->text[tmp->slen-1]);
+		if ( ( status = sts_send_body(&s,tmp->text,tmp->slen,STS_REINIT_TIMEOUT) ) == NULL )
+		    {
+			/* failure. finish proceed */
+			logger(LOG_ERR," NULL status after sending header %s",tmp->text);
+			sts_close(&s);
+		    }
+		else
+		    { /* check status and finish if need */
+			logger(LOG_DEBUG," header %s sent to filter",tmp->text);
+			if ( check_results(&s,status,&res,fd,return_text) > 0 ){
+                            free_conf();
+			    return res;
+                        }
+		    }
+	    }
+	if(tmp==header_last)
+	    break;
+	tmp = tmp->next;
+    }
+
+    logger(LOG_DEBUG," Headers sent");
+
+    if ( ( status = sts_send_body(&s,"\n",1,STS_REINIT_TIMEOUT) ) == NULL )
+    {
+        /* failure. finish proceed */
+        logger(LOG_ERR," NULL status after sending empty string(end of headers)");
+        sts_close(&s);
+    }
+    else
+    { /* check status and finish if need */
+        logger(LOG_DEBUG," empty string (end of headers) sent to filter");
+	if ( check_results(&s,status,&res,fd,return_text) > 0 ){
+            free_conf();
+	    return res;
+        }
+    }
+
+    logger(LOG_DEBUG," Enter sent");
+
+    i = 0;
+    ctmp = buf;
+    while ( (cnt = read(fd,ctmp,buf + sizeof(buf) - ctmp)) > 0 )
+    {
+	logger(LOG_DEBUG,"sending %d bytes to filter",cnt);
+	status = sts_send_body(&s,buf,cnt,STS_REINIT_TIMEOUT);
+	logger(LOG_DEBUG,"send");
+	if ( status == NULL )
+	{
+	    // failure. finish proceed 
+	    logger(LOG_ERR," NULL status after sending part of body");
+	    sts_close(&s);
+	}
+	else
+	{ // check status and finish if need 
+	    logger(LOG_DEBUG," part of body sent to filter");
+	    if ( check_results(&s,status,&res,fd,return_text) > 0 ){
+                free_conf();
+		return res;
+            }
+	}
+    };
+
+    logger(LOG_DEBUG," Total sent %d bytes of message",totalcnt);
+
+    status = sts_body_end(&s,STS_FLUSH_DATA);
+    logger(LOG_DEBUG," Body sent");
+
+
+    if ( check_results(&s,status,&res,fd,return_text) > 0 ){
+        free_conf();
+	return res;
+    }
+    else
+	sts_close(&s);
+
+    logger(LOG_DEBUG," EOF");
+
+    free_conf();
+    return LOCAL_SCAN_ACCEPT;
+    
+}
+
+
+int check_results(spamtest_session_t *s,spamtest_status_t *status,int *res,int fd,uschar **return_text)
+{
+    logger(LOG_DEBUG," Check results started.");
+    switch ( status->status )
+    {
+    case STS_SMTP_ACCEPT:
+    case STS_BLACKHOLE:
+	logger(LOG_DEBUG," SMTP_ACCEPT or BLACK_HOLE.");
+        recipients_count = 0;
+        sts_close(s);
+	*res = LOCAL_SCAN_ACCEPT;
+	return 1;
+    case STS_REJECT:
+	logger(LOG_DEBUG," REJECT");
+        *return_text=(uschar *)status->reason;
+        sts_close(s);
+        *res = LOCAL_SCAN_REJECT;
+	return 1;
+    case STS_FILTER_ERROR:
+	logger(LOG_DEBUG," FILTER_ERROR");
+        sts_close(s);
+        *res =  result_on_error;
+	return 1;
+    case STS_ACCEPT:
+	logger(LOG_DEBUG," ACCEPT");
+	if ( proceed_accept(status,fd) != 0 )
+    	    *res = result_on_error;
+	else
+    	    *res = LOCAL_SCAN_ACCEPT;
+    	sts_close(s);
+	return 1;
+    case STS_CONTINUE:
+	logger(LOG_DEBUG," CONTINUE");
+	return 0;
+    }
+
+}
+
+extern int recipients_list_max;
+int proceed_accept(spamtest_status_t *status,int fd)
+{
+    spamtest_status_t *st;
+    message_status_t *mst;
+    int i;
+    int rcptn;
+    int good_rcpt_cnt = 0,k;
+    int found = 0;
+
+    logger(LOG_DEBUG," accept_message started.");
+
+    st = glue_actions(status);
+
+    if (st==NULL) {
+      logger(LOG_ERR," glue_actions return NULL" );
+      return -1;    
+    }
+
+    mst = &st->ms_array[0] ;
+
+    rcptn = rcptlist_count(mst->rcpts);
+    for( k=0; k<rcptn; k++)
+	if(strlen(rcptlist_getn(mst->rcpts, k))>0)
+	    good_rcpt_cnt++;
+    if(good_rcpt_cnt <1)
+	{
+	    logger(LOG_INFO," Empty recipient list");
+	    recipients_count = 0;
+	    return 0;
+	}
+
+    if ( (mst != NULL) && (mst->action == STS_ACTION_CHANGE) ) 
+      {
+	logger(LOG_DEBUG," spamtest status returned STS_ACTION_CHANGE for message.");
+	
+	// cleanup old rcpts list
+	recipients_count = 0;
+	recipients_list = NULL;
+	recipients_list_max = 0;
+	for (i = 0; i<rcptlist_count(mst->rcpts);i++) 
+	  {
+	    char *rcpt = rcptlist_getn(mst->rcpts,i);
+	    if(rcpt)
+	      {
+		logger(LOG_DEBUG,"Adding recipient: %s",rcpt);
+		receive_add_recipient(string_copy(US rcpt),-1);
+	      }
+	  }
+	
+	logger(LOG_DEBUG," new recipients_count=%d",recipients_count);
+
+	if ( sender_address[0] != '\0' )
+	{
+	    if (strcasecmp(mst->mailfrom,sender_address) != 0 )
+	    { /* changing sender address */
+		logger(LOG_DEBUG," senders different");
+		sender_address = string_copy( US mst->mailfrom );
+	    }
+	    else
+	    {
+		logger(LOG_DEBUG," senders equivalented");
+	    }
+	}
+	logger(LOG_DEBUG," Actions count = %d",mst->action_count);
+	for (i=0;i<mst->action_count;i++)
+	{
+	    header_line * tmp;
+	    header_line * matched;
+	    header_line * last;
+	    int deleted_count = 0;
+	    int matched_count = 0;
+	    int hdrlen = strlen(mst->act_array[i].header);
+
+	    switch ( mst->act_array[i].type )
+	    {
+		case STS_HEADER_DEL:
+		    logger(LOG_DEBUG," Delete header %s",mst->act_array[i].header);
+		    tmp = header_list;
+		    while ( tmp != NULL )
+		    {
+			if ( (tmp->type != '*') &&
+			     (tmp->slen > 0) && 
+			     (strncasecmp(tmp->text,
+				mst->act_array[i].header,
+				hdrlen < tmp->slen ? hdrlen:tmp->slen) == 0 ) 
+			    )
+			{
+			    deleted_count++;
+			    tmp->type = '*';
+			}
+			tmp = tmp->next;
+		    }
+		    logger(LOG_DEBUG," deleted %d headers",deleted_count);
+		    break;
+		case STS_HEADER_ADD:
+		    logger(LOG_DEBUG," Add value to header %s %s",mst->act_array[i].header,mst->act_array[i].value);
+		    tmp = header_list;
+		    matched = NULL;
+		    while ( tmp != NULL )
+		    {
+			logger(LOG_DEBUG,"Iterating, %c %d %s",tmp->type,tmp->slen,tmp->text);
+			if ( (tmp->slen > 0) && 
+			     (strncasecmp(tmp->text,
+				mst->act_array[i].header,
+				hdrlen < tmp->slen ? hdrlen:tmp->slen) == 0 ) 
+			    )
+			{
+			    if ( matched != NULL )
+			    {
+				if ( (tmp->type != '*') || ( matched->type == '*' ) )
+				    matched = tmp;
+			    }
+			    else
+			    {
+				matched = tmp;
+			    }
+			}
+			tmp = tmp->next;
+			if(matched)
+			    break;
+		    }
+		    if ( matched != NULL )
+		    { /* adding value to exits header */
+			logger(LOG_DEBUG,"Found matched header, %c %d %s",matched->type,matched->slen,matched->text);
+			if ( matched->type == '*' )
+			{
+			    matched->text = string_sprintf("%s: %s\n",mst->act_array[i].header,mst->act_array[i].value);
+			    matched->slen = strlen(matched->text);
+			    matched->type = ' ';
+			    matched->type = header_checkname(matched,0);
+			}
+			else
+			{
+			    logger(LOG_DEBUG,"Appending value to existing header value");
+			    matched->text = string_sprintf("%s %s\n",matched->text,mst->act_array[i].value);
+			    matched->slen += (strlen(mst->act_array[i].value) + 2);
+			}
+		    }
+		    else
+		    { /* add new header in case when this header not found */
+			logger(LOG_DEBUG," We must add value to header %s but this header not found.",mst->act_array[i].header);
+			header_add(' ',"%s: %s\n",mst->act_array[i].header,mst->act_array[i].value);
+		    }
+		    logger(LOG_DEBUG," Add header %s %s",mst->act_array[i].header,mst->act_array[i].value);
+		    break;
+
+
+		case STS_HEADER_PREPEND:
+		    logger(LOG_DEBUG," Prepend value to header %s %s",mst->act_array[i].header,mst->act_array[i].value);
+		    tmp = header_list;
+		    matched = NULL;
+		    while ( tmp != NULL )
+		    {
+			logger(LOG_DEBUG,"Iterating, %c %d %s",tmp->type,tmp->slen,tmp->text);
+			if ( (tmp->slen > 0) && 
+			     (strncasecmp(tmp->text,
+				mst->act_array[i].header,
+				hdrlen < tmp->slen ? hdrlen:tmp->slen) == 0 ) 
+			    )
+			{
+			    if ( matched != NULL )
+			    {
+				if ( (tmp->type != '*') || ( matched->type == '*' ) )
+				    matched = tmp;
+			    }
+			    else
+			    {
+				matched = tmp;
+			    }
+			}
+			tmp = tmp->next;
+			if(matched)
+			    break;
+		    }
+		    if ( matched != NULL )
+		    { /* adding value to exits header */
+			logger(LOG_DEBUG,"Found matched header, %c %d %s",matched->type,matched->slen,matched->text);
+			if ( matched->type == '*' )
+			{
+			    matched->text = string_sprintf("%s: %s\n",mst->act_array[i].header,mst->act_array[i].value);
+			    matched->slen = strlen(matched->text);
+			    matched->type = ' ';
+			    matched->type = header_checkname(matched,0);
+			}
+			else
+			{
+			    int l = strlen(mst->act_array[i].header);
+			    char *p = matched->text+l+2;
+			    matched->text[l]=0;
+			    matched->text = string_sprintf("%s: %s %s",matched->text,
+							   mst->act_array[i].value,p);
+			    matched->slen += (strlen(mst->act_array[i].value) + 1);
+			    logger(LOG_DEBUG,"Prepending value %s to existing header value %s|",
+				   mst->act_array[i].value, matched->text);
+			    
+			}
+		    }
+		    else
+		    { /* add new header in case when this header not found */
+			logger(LOG_DEBUG," We must add value to header %s but this header not found.",mst->act_array[i].header);
+			header_add(' ',"%s: %s\n",mst->act_array[i].header,mst->act_array[i].value);
+		    }
+		    logger(LOG_DEBUG," Prepend header %s %s",mst->act_array[i].header,mst->act_array[i].value);
+		    break;
+
+		case STS_HEADER_CHG:
+		    logger(LOG_DEBUG," Change header %s %s",mst->act_array[i].header,mst->act_array[i].value);
+		    tmp = header_list;
+		    matched = NULL;
+		    matched_count = 0;
+		    while ( tmp != NULL )
+		    {
+			int hdrlen = strlen(mst->act_array[i].header);
+			if ( (tmp->type != '*') &&
+			     (tmp->slen > 0) && 
+			     (strncasecmp(tmp->text,
+				mst->act_array[i].header,
+				hdrlen < tmp->slen ? hdrlen:tmp->slen) == 0 ) 
+			    )
+			{
+			    matched = tmp;
+			    matched_count++;
+			}
+			tmp = tmp->next;
+		    }
+		    if ( matched != NULL )
+		    {
+			matched->text = string_sprintf("%s: %s\n",mst->act_array[i].header,mst->act_array[i].value);
+			matched->slen += (strlen(mst->act_array[i].value) + strlen(mst->act_array[i].header) + 3);
+			if ( matched_count > 1 )
+			{
+			    tmp = header_list;
+			    while ( (tmp != NULL) && matched_count > 1 )
+			    {
+				if ( (tmp->type != '*') &&
+			    	     (tmp->slen > 0) && 
+			    	     (strncasecmp(tmp->text,
+					mst->act_array[i].header,
+					hdrlen < tmp->slen ? hdrlen:tmp->slen) == 0 ) &&
+				     (tmp != matched)
+				   )
+				{
+				    tmp->type = '*';
+				    matched_count--;
+				}
+				tmp = tmp->next;
+			    }
+			}
+			
+		    }
+		    else
+		    {
+			logger(LOG_DEBUG," We must change value for header %s but this header not found.Adding new",mst->act_array[i].header);
+			header_add(' ',"%s: %s\n",mst->act_array[i].header,mst->act_array[i].value);
+		    }
+		    break;
+		case STS_HEADER_NEW:
+		    logger(LOG_DEBUG," New header %s: %s",mst->act_array[i].header,mst->act_array[i].value);
+
+		    tmp = header_list;
+		    matched = NULL;
+		    while ( tmp != NULL )
+		    {
+			if ( (tmp->type != '*') &&
+			     (tmp->slen > 0) && 
+			     (strncasecmp(tmp->text,
+				mst->act_array[i].header,
+				hdrlen < tmp->slen ? hdrlen:tmp->slen) == 0 ) 
+			    )
+			{
+			    matched = tmp;
+			}
+			tmp = tmp->next;
+		    }
+		    if ( matched != NULL &&  matched != header_last )
+			{
+			if(matched == header_last)
+			    {
+				logger(LOG_DEBUG,"Header %s is last in message, adding below",
+				       mst->act_array[i].header);
+				header_add(' ',"%s: %s\n",mst->act_array[i].header,mst->act_array[i].value);
+			    }
+			else
+			    { /* adding value after last header with this name */
+				logger(LOG_DEBUG,"Some headers %s found",mst->act_array[i].header);
+				tmp = header_last;
+				header_add(' ',"%s: %s\n",mst->act_array[i].header,mst->act_array[i].value);
+				tmp->next->next = matched->next;
+				matched->next = tmp->next;
+				tmp->next = NULL;
+				header_last = tmp;
+			    }
+			}
+		    else
+		    { /* add new header at the end of headers list */
+			logger(LOG_DEBUG,"Headers %s not found",mst->act_array[i].header);
+			header_add(' ',"%s: %s\n",mst->act_array[i].header,mst->act_array[i].value);
+		    }
+		    
+		    break;
+		default:
+		    logger(LOG_INFO," Invalid action type %d",mst->act_array[i].type);
+	    }
+	}
+    }
+    else if ( (mst != NULL) && (mst->action == STS_ACTION_BOUNCE) ) 
+    { /* bounce message */
+	header_line *tmp;
+	message_t *bounced_mess;
+	
+	logger(LOG_DEBUG," bouncing message.");
+
+	/* preparing bounced message */
+	bounced_mess = message_init();
+	if ( bounced_mess == NULL )
+	{
+	    logger(LOG_ERR," Unable to allocate memory for bounced message");
+	    return -1;
+	}
+	logger(LOG_DEBUG," new message allocated.");
+
+	/* copying data from filter to prepared message (for automatically creating headers list ) */
+	for (i=0;i<msgtext_count_chunks(mst->bouncemsg);i++ )
+	{
+	    if ( message_put_body(bounced_mess,msgtext_get_chunk(mst->bouncemsg,i),msgtext_chunk_len(mst->bouncemsg,i)) == -1 )
+	    {
+		logger(LOG_ERR," unable to copy data from filter to bounced message");
+		message_free(bounced_mess);
+		return -1;
+	    }
+	    else
+	    {
+		logger(LOG_DEBUG," message_put_body - ok.");
+	    }
+	}
+
+	/* deleting exim old headers */
+	tmp = header_list;
+	while ( tmp != NULL )
+	{
+	    tmp->type = '*';
+	    tmp = tmp->next;
+	};
+	logger(LOG_DEBUG," headers deleted.");
+
+	/* adding new headers */
+	for ( i = 0;i < bounced_mess->headers->used; i++ )
+	{
+	    header_add(' ',"%s: %s",bounced_mess->headers->array[i].header.hptr,bounced_mess->headers->array[i].value.hptr);
+	    logger(LOG_DEBUG," added header: %s: %s",bounced_mess->headers->array[i].header.hptr,bounced_mess->headers->array[i].value.hptr);
+	}
+	
+	/* replacing rcpts */
+	recipients_count = 0;
+	recipients_list = NULL;
+	recipients_list_max = 0;
+
+	if ( rcptlist_count(bounced_mess->recipients) > 0 )
+	  {
+	    for (i = 0; i<rcptlist_count(bounced_mess->recipients);i++) 
+	    {
+		char *rcpt = rcptlist_getn(bounced_mess->recipients,i);
+		if ( rcpt == NULL )
+		{
+		    logger(LOG_ERR," unable to get recipient %d",i);
+		    message_free(bounced_mess);
+		    return -1;
+		}
+		logger(LOG_DEBUG," rcpt = %s",rcpt);
+		receive_add_recipient(string_copy(US rcpt),-1);
+	    }
+	}
+	else
+	{
+	    if ( sender_address[0] != '\0' )
+	      receive_add_recipient(string_copy(US sender_address),-1);
+	    else
+	    {
+		logger(LOG_ERR," Unable to get sender address to bounce, failed");
+		return -1;
+	    }
+	}
+	/* cleaning sender ( must be empty string ) */
+	logger(LOG_DEBUG," sender address emptied");
+	sender_address = "";
+	
+	/* writing new message body */
+	lseek(fd,SPOOL_DATA_START_OFFSET,SEEK_SET);
+
+	if ( get_message_bodychunks_count(bounced_mess) > 0 )
+	{
+	    for (i=0;i<get_message_bodychunks_count(bounced_mess);i++ )
+	    {
+		if ( write(fd,get_message_bodychunk_ptr(bounced_mess,i),get_message_bodychunk_len(bounced_mess,i)) == -1 )
+		{
+		    logger(LOG_ERR," unable to write bounced message body.");
+		    message_free(bounced_mess);
+		    return -1;
+		}
+		else
+		{
+		    logger(LOG_DEBUG," written part of body to file");
+		}
+	    }
+	}
+	else
+	{
+		char *autogenmsg = "Autogenerated message for bouncing\n\n\n";
+		if ( write(fd,autogenmsg,strlen(autogenmsg)) == -1 )
+		{
+		    logger(LOG_ERR," unable to write bounced message body.");
+		    message_free(bounced_mess);
+		    return -1;
+		}
+		else
+		{
+		    logger(LOG_DEBUG," written autogenerated message to file");
+		}
+	}
+	
+	message_free(bounced_mess);
+	logger(LOG_DEBUG," bouncing finished");
+	
+
+    }
+    else
+    {
+	if ( mst != NULL )
+	    logger(LOG_ERR," Invalid action %d",mst->action);
+	else
+	    logger(LOG_ERR," mst is NULL");
+    }
+
+    logger(LOG_DEBUG," Message accepted.");
+    return 0;
+
+}
+
+
+void logger(const int log_level,const char *fmt,...)
+{
+    va_list params;
+    char buf[512];
+    /* LOG_ERR == 3 is minimum level for us */
+    if (log_level <= (debug_level+3))
+    {
+	va_start(params,fmt);
+	vsnprintf(buf,(size_t)512,fmt,params);
+	debug_printf("-ls- %s\n",buf);
+#ifdef SPAMTEST_USE_SYSLOG
+	va_start(params,fmt);
+	vsyslog(log_level>LOG_DEBUG?LOG_DEBUG:log_level,fmt,params);
+#else
+	log_write(0,LOG_MAIN,"spamtest: %s",buf);
+#endif
+	va_end(params);
+    }
+}
+
+void prepare_config_parameters()
+{
+    int len;
+        /*
+         * Firstly we are looking for new parameter,
+         * then - for old parameter, else - we use
+         * default value.
+         */
+    if (kas_log_level != 0)
+            debug_level = kas_log_level;
+    if (debug_level == 0)
+            debug_level = KAS_LOG_LEVEL;
+
+    if (kas_connect_timeout != 0)
+            st_connect_timeout = kas_connect_timeout*1000;
+    if (st_connect_timeout == 0)
+            st_connect_timeout = KAS_CONNECT_TIMEOUT;
+
+    if (kas_data_timeout != 0)
+            st_rw_timeout = kas_data_timeout*1000;
+    if (st_rw_timeout == 0)
+            st_rw_timeout = KAS_DATA_TIMEOUT;
+    
+    if (kas_filtering_size_limit != 0)
+            filtering_size_limit = kas_filtering_size_limit;
+    if (filtering_size_limit == 0)
+            filtering_size_limit = KAS_FILTERING_SIZE_LIMIT;
+    
+    
+    if (kas_default_domain != NULL){
+            len = strlen(kas_default_domain);
+            result_default_domain = malloc(len+1);
+            strncpy(result_default_domain,kas_default_domain,len);
+            result_default_domain[len]='\0';
+    }
+    else if (st_mail_domain != NULL){
+            len = strlen(st_mail_domain);
+            result_default_domain = malloc(len+1);
+            strncpy(result_default_domain,st_mail_domain,len);
+            result_default_domain[len]='\0';
+    }
+    else{
+            len = strlen(KAS_DEFAULT_DOMAIN);
+            result_default_domain = malloc(len+1);
+            strncpy(result_default_domain,KAS_DEFAULT_DOMAIN,len);
+            result_default_domain[len]='\0';
+    }
+
+    if (kas_connect_to != NULL){
+            len = strlen(kas_connect_to);
+            result_connect_to = malloc(len+1);
+            strncpy(result_connect_to,kas_connect_to,len);
+            result_connect_to[len]='\0';
+    }
+    else if (st_address != NULL){
+            len = strlen(st_address);
+            result_connect_to = malloc(len+1);
+            strncpy(result_connect_to,st_address,len);
+            result_connect_to[len]='\0';
+    }/* one parameter have no default,
+      * because else we can't disable kas-exim in config file*/
+
+    if (kas_on_error != NULL){
+            len = strlen(kas_on_error);
+            result_on_error_str = malloc(len+1);
+            strncpy(result_on_error_str,kas_on_error,len);
+            result_on_error_str[len]='\0';
+    }
+    else if (st_on_error != NULL){
+            len = strlen(st_on_error);
+            result_on_error_str = malloc(len+1);
+            strncpy(result_on_error_str,st_on_error,len);
+            result_on_error_str[len]='\0';
+    }
+    else{
+            len = strlen(KAS_ON_ERROR);
+            result_on_error_str = malloc(len+1);
+            strncpy(result_on_error_str,KAS_ON_ERROR,len);
+            result_on_error_str[len]='\0';
+    }
+
+    if ( strcasecmp(result_on_error_str,"accept") == 0 ){
+	result_on_error = LOCAL_SCAN_ACCEPT;
+    }
+    else if ( strcasecmp(result_on_error_str,"reject") == 0 ){
+	result_on_error = LOCAL_SCAN_REJECT;
+    }
+    else if ( strcasecmp(result_on_error_str,"tempfail") == 0 ){
+	result_on_error = LOCAL_SCAN_TEMPREJECT;
+    }
+    else{
+	logger(LOG_ERR,"Invalid value for parameter on_spamtest_error. Will use 'accept'");
+	result_on_error = LOCAL_SCAN_ACCEPT;
+    }
+}
+
+void free_conf(){
+        free(result_default_domain);
+        free(result_connect_to);
+        free(result_on_error_str);
+}
+
