diff -urN OS.orig/Makefile-Base OS/Makefile-Base --- OS.orig/Makefile-Base Tue Apr 17 16:06:39 2007 +++ OS/Makefile-Base Sun May 27 17:26:48 2007 @@ -296,7 +296,8 @@ # if the corresponding #defines are not set, they wind up empty and # are thrown away by the linker. -OBJ_WITH_CONTENT_SCAN = malware.o mime.o regex.o spam.o spool_mbox.o +#OBJ_WITH_CONTENT_SCAN = malware.o mime.o regex.o spam.o spool_mbox.o +OBJ_WITH_CONTENT_SCAN = malware.o mime.o regex.o spam.o spool_mbox.o dspam.o OBJ_WITH_OLD_DEMIME = demime.o OBJ_EXPERIMENTAL = bmi_spam.o spf.o srs.o dk.o @@ -585,6 +586,7 @@ mime.o: $(HDRS) mime.c regex.o: $(HDRS) regex.c spam.o: $(HDRS) spam.c +dspam.o: $(HDRS) dspam.c spool_mbox.o: $(HDRS) spool_mbox.c diff -urN scripts.orig/MakeLinks scripts/MakeLinks --- scripts.orig/MakeLinks Tue Apr 17 16:06:39 2007 +++ scripts/MakeLinks Sun May 27 17:30:05 2007 @@ -265,6 +265,8 @@ ln -s ../src/mime.c mime.c ln -s ../src/mime.h mime.h ln -s ../src/malware.c malware.c +ln -s ../src/dspam.c dspam.c +ln -s ../src/dspam.h dspam.h # WITH_OLD_DEMIME ln -s ../src/demime.c demime.c diff -urN src.orig/acl.c src/acl.c --- src.orig/acl.c Tue Apr 17 16:06:39 2007 +++ src/acl.c Sun May 27 17:42:54 2007 @@ -72,6 +72,9 @@ #endif ACLC_DNSLISTS, ACLC_DOMAINS, +#ifdef WITH_CONTENT_SCAN + ACLC_DSPAM, +#endif ACLC_ENCRYPTED, ACLC_ENDPASS, ACLC_HOSTS, @@ -134,6 +137,9 @@ #endif US"dnslists", US"domains", +#ifdef WITH_CONTENT_SCAN + US"dspam", +#endif US"encrypted", US"endpass", US"hosts", @@ -258,6 +264,9 @@ #endif TRUE, /* dnslists */ FALSE, /* domains */ +#ifdef WITH_CONTENT_SCAN + TRUE, /* dspam */ +#endif FALSE, /* encrypted */ TRUE, /* endpass */ FALSE, /* hosts */ @@ -318,6 +327,9 @@ #endif FALSE, /* dnslists */ FALSE, /* domains */ +#ifdef WITH_CONTENT_SCAN + FALSE, /* dspam */ +#endif FALSE, /* encrypted */ TRUE, /* endpass */ FALSE, /* hosts */ @@ -454,6 +466,11 @@ (unsigned int) ~(1<domain, &arg, 0, &domainlist_anchor, addr->domain_cache, MCL_DOMAIN, TRUE, &deliver_domain_data); break; + +#ifdef WITH_CONTENT_SCAN + case ACLC_DSPAM: + { + /* Seperate the regular expression and any optional parameters. */ + uschar *ss = string_nextinlist(&arg, &sep, big_buffer, big_buffer_size); + /* Run the dspam backend. */ + rc = dspam(&ss); + /* Modify return code based upon the existance of options. */ + while ((ss = string_nextinlist(&arg, &sep, big_buffer, big_buffer_size)) + != NULL) { + if (strcmpic(ss, US"defer_ok") == 0 && rc == DEFER) + { + /* FAIL so that the message is passed to the next ACL */ + rc = FAIL; + } + } + } + break; +#endif /* The value in tls_cipher is the full cipher name, for example, TLSv1:DES-CBC3-SHA:168, whereas the values to test for are just the diff -urN src.orig/dspam.c src/dspam.c --- src.orig/dspam.c Fri Nov 24 18:44:10 2006 +++ src/dspam.c Fri Nov 24 19:02:19 2006 @@ -0,0 +1,562 @@ +/* $Cambridge: exim/exim-src/src/spam.c,v 1.11 2005/08/01 14:41:25 ph10 Exp $ */ + +/************************************************* +* Exim - an Internet mail transport agent * +*************************************************/ + +/* Copyright (c) Tom Kistner 2003-???? */ +/* License: GPL */ + +/* Code for calling dspam. Called from acl.c. */ + +#include "exim.h" +#include "transports/lmtp.h" +#ifdef WITH_CONTENT_SCAN +#include "dspam.h" + +uschar dspam_classification_buffer[16]; +uschar dspam_confidence_buffer[16]; +uschar dspam_factors_buffer[32600]; +uschar dspam_improbability_buffer[32]; +uschar dspam_probability_buffer[16]; +uschar dspam_probability_int_buffer[16]; +uschar dspam_processed_buffer[32]; +uschar dspam_result_buffer[16]; +uschar dspam_signature_buffer[32]; +uschar prev_dspam_user_name[128] = ""; +int dspam_ok = 0; +int dspam_rc = 0; + +int dspam(uschar **listptr) { + int sep = 0; + uschar *list = *listptr; + uschar *user_name; + uschar user_name_buffer[128]; + unsigned long mbox_size; + FILE *mbox_file = NULL; + int dspam_sock = 0; + FILE *dspam_file = NULL; + uschar dspam_buffer[32600]; + int j, offset; +#ifndef NO_POLL_H + int result; +#endif + double dspam_score; + int override = 0; + time_t start; + size_t read, wrote; + struct sockaddr_un server; +#ifndef NO_POLL_H + struct pollfd pollfd; +#endif + dspam_address_container * dspam_address_vector[32]; + int current_server = 0; + uschar ident[48]; + + /* find the username from the option list */ + if ((user_name = string_nextinlist(&list, &sep, + user_name_buffer, + sizeof(user_name_buffer))) == NULL) { + /* no username given, this means no scanning should be done */ + return FAIL; + }; + + /* if username is "0" or "false", do not scan */ + if ( (Ustrcmp(user_name,"0") == 0) || + (strcmpic(user_name,US"false") == 0) ) { + return FAIL; + }; + + /* if there is an additional option, check if it is "true" */ + if (strcmpic(list,US"true") == 0) { + /* in that case, always return true later */ + override = 1; + }; + + /* if we scanned for this username last time, just return */ + if ( dspam_ok && ( Ustrcmp(prev_dspam_user_name, user_name) == 0 ) ) { + if (override) + return OK; + else + return dspam_rc; + }; + + /* make sure the eml mbox file is spooled up */ + mbox_file = spool_mbox(&mbox_size); + + if (mbox_file == NULL) { + /* error while spooling */ + log_write(0, LOG_MAIN|LOG_PANIC, + "dspam acl condition: error while creating mbox spool file"); + goto RETURN_DEFER; + }; + + start = time(NULL); + /* socket does not start with '/' -> network socket */ + if (*dspam_address != '/') { + time_t now = time(NULL); + int num_servers = 0; + int start_server = 0; + uschar *address = NULL; + uschar *dspam_address_list_ptr = dspam_address; + uschar address_buffer[256]; + + /* Check how many dspam servers we have + and register their addresses */ + while ((address = string_nextinlist(&dspam_address_list_ptr, &sep, + address_buffer, + sizeof(address_buffer))) != NULL) { + + dspam_address_container *this_dspam = + (dspam_address_container *)store_get(sizeof(dspam_address_container)); + + /* grok dspam address, port and ident */ + if( sscanf(CS address, "%s %u %s", this_dspam->tcp_addr, &(this_dspam->tcp_port), this_dspam->ident) != 3 ) { + log_write(0, LOG_MAIN, + "dspam acl condition: warning - invalid dspam address: '%s'", address); + continue; + }; + + dspam_address_vector[num_servers] = this_dspam; + num_servers++; + if (num_servers > 31) + break; + }; + + /* check if we have at least one server */ + if (!num_servers) { + log_write(0, LOG_MAIN|LOG_PANIC, + "dspam acl condition: no useable dspam server addresses in dspam_address configuration option."); + goto RETURN_DEFER; + }; + + current_server = start_server = (int)now % num_servers; + + while (1) { + + debug_printf("trying server %s, port %u\n", + dspam_address_vector[current_server]->tcp_addr, + dspam_address_vector[current_server]->tcp_port); + + /* contact a dspam */ + if ( (dspam_sock = ip_socket(SOCK_STREAM, AF_INET)) < 0) { + log_write(0, LOG_MAIN|LOG_PANIC, + "dspam acl condition: error creating IP socket for dspam"); + goto RETURN_DEFER; + }; + + if (ip_connect( dspam_sock, + AF_INET, + dspam_address_vector[current_server]->tcp_addr, + dspam_address_vector[current_server]->tcp_port, + 5 ) > -1) { + /* connection OK */ + Ustrcpy(ident, dspam_address_vector[current_server]->ident); + break; + }; + + log_write(0, LOG_MAIN|LOG_PANIC, + "dspam acl condition: warning - dspam connection to %s, port %u failed: %s", + dspam_address_vector[current_server]->tcp_addr, + dspam_address_vector[current_server]->tcp_port, + strerror(errno)); + current_server++; + if (current_server >= num_servers) + current_server = 0; + if (current_server == start_server) { + log_write(0, LOG_MAIN|LOG_PANIC, "dspam acl condition: all dspam servers failed"); + goto RETURN_DEFER; + }; + }; + + } + else { + uschar socket_addr[512]; + + /* open the local socket */ + + /* grok dspam address and ident */ + if( sscanf(CS dspam_address, "%s %s", socket_addr, ident) != 2 ) { + log_write(0, LOG_MAIN, + "dspam acl condition: warning - invalid dspam address: '%s'", dspam_address); + goto RETURN_DEFER; + }; + + + if ((dspam_sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { + log_write(0, LOG_MAIN|LOG_PANIC, + "dspam acl condition: unable to acquire socket (%s)", + strerror(errno)); + goto RETURN_DEFER; + } + + server.sun_family = AF_UNIX; + Ustrcpy(server.sun_path, socket_addr); + + if (connect(dspam_sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) { + log_write(0, LOG_MAIN|LOG_PANIC, + "dspam acl condition: unable to connect to UNIX socket %s (%s)", + dspam_address, strerror(errno) ); + goto RETURN_DEFER; + } + + } + + /* now we are connected to dspam on dspam_sock */ + + dspam_file = fdopen(dspam_sock, "rb"); + + if (!lmtp_read_response(dspam_file, dspam_buffer, sizeof(dspam_buffer), '2', DSPAM_TIMEOUT - time(NULL) + start)) + goto RESPONSE_FAILED; + + /* send our request */ + + if (!lmtp_write_command(dspam_sock, "LHLO %s\r\n", primary_hostname)) + goto WRITE_FAILED; + if (!lmtp_read_response(dspam_file, dspam_buffer, sizeof(dspam_buffer), '2', DSPAM_TIMEOUT - time(NULL) + start)) + goto RESPONSE_FAILED; + + if (!lmtp_write_command(dspam_sock, "MAIL FROM: <%s> DSPAMPROCESSMODE=\"%s \"\r\n", + ident, "--client --stdout --deliver=innocent,spam --debug")) + goto WRITE_FAILED; + if (!lmtp_read_response(dspam_file, dspam_buffer, sizeof(dspam_buffer), '2', DSPAM_TIMEOUT - time(NULL) + start)) { + if (errno == 0 && dspam_buffer[0] == '4') errno = ERRNO_MAIL4XX; + goto RESPONSE_FAILED; + } + + if (!lmtp_write_command(dspam_sock, "RCPT TO: <%s>\r\n", user_name)) + goto WRITE_FAILED; + if (!lmtp_read_response(dspam_file, dspam_buffer, sizeof(dspam_buffer), '2', DSPAM_TIMEOUT - time(NULL) + start)) { + if (errno == 0 && dspam_buffer[0] == '4') errno = ERRNO_RCPT4XX; + goto RESPONSE_FAILED; + } + + if (!lmtp_write_command(dspam_sock, "DATA\r\n")) + goto WRITE_FAILED; + if (!lmtp_read_response(dspam_file, dspam_buffer, sizeof(dspam_buffer), '3', DSPAM_TIMEOUT - time(NULL) + start)) { + if (errno == 0 && dspam_buffer[0] == '4') errno = ERRNO_DATA4XX; + goto RESPONSE_FAILED; + } + + /* + * now send the file + */ + + Ustrcpy(big_buffer, "sending data block"); /* For error messages */ + debug_printf(" LMTP>> writing message and terminating \".\"\n"); + + /* + * Note: poll() is not supported in OSX 10.2. + */ + +#ifndef NO_POLL_H + pollfd.fd = dspam_sock; + pollfd.events = POLLOUT; +#endif +// (void)fcntl(dspam_sock, F_SETFL, O_NONBLOCK); + do { + read = fread(dspam_buffer,1,sizeof(dspam_buffer),mbox_file); + if (read > 0) { + offset = 0; +again: + +#ifndef NO_POLL_H + result = poll(&pollfd, 1, 1000); + if (result == -1 && errno == EINTR) + continue; + else if (result < 1) { + if (result == -1) + log_write(0, LOG_MAIN|LOG_PANIC, + "dspam acl condition: %s on dspam socket", strerror(errno)); + else { + if (time(NULL) - start < DSPAM_TIMEOUT) + goto again; + log_write(0, LOG_MAIN|LOG_PANIC, + "dspam acl condition: timed out writing dspam socket"); + } + goto RETURN_DEFER; + } +#endif + wrote = send(dspam_sock,dspam_buffer + offset,read - offset,0); + if (wrote == -1) + { + log_write(0, LOG_MAIN|LOG_PANIC, + "dspam acl condition: %s on dspam socket", strerror(errno)); + goto RETURN_DEFER; + } + if (offset + wrote != read) { + offset += wrote; + goto again; + } + } + } + while (!feof(mbox_file) && !ferror(mbox_file)); + + if (ferror(mbox_file)) { + log_write(0, LOG_MAIN|LOG_PANIC, + "dspam acl condition: error reading spool file: %s", strerror(errno)); + goto RETURN_DEFER; + } + + if (!lmtp_write_command(dspam_sock, ".\r\n")) + goto WRITE_FAILED; + + /* + read dspam response using what's left of the timeout. + */ + + { + char *rc; + int save_errno; + int done; + uschar *p; + int len; + uschar *last = NULL; + int last_size = 0; + + done = 0; + do { + dspam_buffer[0] = 0; /* In case nothing gets read */ + sigalrm_seen = FALSE; + alarm(DSPAM_TIMEOUT - time(NULL) + start); + rc = Ufgets(&dspam_buffer, sizeof(dspam_buffer) - 1, dspam_file); + save_errno = errno; + alarm(0); + errno = save_errno; + + if (rc == NULL) { + + /* Handle timeout; must do this first because it uses EINTR */ + + if (sigalrm_seen) { + errno = ETIMEDOUT; + debug_printf("LMTP timeout while reading data from socket\n"); + log_write(0, LOG_MAIN|LOG_PANIC, + "dspam acl condition: error reading data from LMTP socket: %s", strerror(errno)); + goto RETURN_DEFER; + + /* If some other interrupt arrived, just retry. We presume this to be rare, + but it can happen (e.g. the SIGUSR1 signal sent by exiwhat causes + read() to exit). */ + + } else if (errno == EINTR) { + debug_printf("EINTR while reading LMTP response\n"); + continue; + } + } + + debug_printf("read from LMTP socket: %s", rc); + if ((strcmpic(rc, US"\n") == 0) || (strcmpic(rc, US"\r\n") == 0) || (strcmpic(rc, US".\r\n") == 0)) { + done = 1; + } else { + + p = Ustrstr(rc, "X-Daemon-Classification: "); + if (p == rc) { + len = Ustrlen(rc) - 25 - 1; + if (len > sizeof(dspam_classification_buffer) - 1) len = sizeof(dspam_classification_buffer) - 1; + Ustrncpy(dspam_classification_buffer, rc + 25, len); + dspam_classification = dspam_classification_buffer; + last = dspam_classification; + last_size = sizeof(dspam_classification_buffer); + + } else { + + p = Ustrstr(rc, "X-DSPAM-Result: "); + if (p == rc) { + len = Ustrlen(rc) - 16 - 1; + if (len > sizeof(dspam_result_buffer) - 1) len = sizeof(dspam_result_buffer) - 1; + Ustrncpy(dspam_result_buffer, rc + 16, len); + dspam_result = dspam_result_buffer; + last = dspam_result; + last_size = sizeof(dspam_result_buffer); + + } else { + + p = Ustrstr(rc, "X-DSPAM-Processed: "); + if (p == rc) { + len = Ustrlen(rc) - 19 - 1; + if (len > sizeof(dspam_processed_buffer) - 1) len = sizeof(dspam_processed_buffer) - 1; + Ustrncpy(dspam_processed_buffer, rc + 19, len); + dspam_processed = dspam_processed_buffer; + last = dspam_processed; + last_size = sizeof(dspam_processed_buffer); + + } else { + + p = Ustrstr(rc, "X-DSPAM-Confidence: "); + if (p == rc) { + len = Ustrlen(rc) - 20 - 1; + if (len > sizeof(dspam_confidence_buffer) - 1) len = sizeof(dspam_confidence_buffer) - 1; + Ustrncpy(dspam_confidence_buffer, rc + 20, len); + dspam_confidence = dspam_confidence_buffer; + last = dspam_confidence; + last_size = sizeof(dspam_confidence_buffer); + + } else { + + p = Ustrstr(rc, "X-DSPAM-Improbability: "); + if (p == rc) { + len = Ustrlen(rc) - 23 - 1; + if (len > sizeof(dspam_improbability_buffer) - 1) len = sizeof(dspam_improbability_buffer) - 1; + Ustrncpy(dspam_improbability_buffer, rc + 23, len); + dspam_improbability = dspam_improbability_buffer; + last = dspam_improbability; + last_size = sizeof(dspam_improbability_buffer); + + } else { + + p = Ustrstr(rc, "X-DSPAM-Signature: "); + if (p == rc) { + len = Ustrlen(rc) - 19 - 1; + if (len > sizeof(dspam_signature_buffer) - 1) len = sizeof(dspam_signature_buffer) - 1; + Ustrncpy(dspam_signature_buffer, rc + 19, len); + dspam_signature = dspam_signature_buffer; + last = dspam_signature; + last_size = sizeof(dspam_signature_buffer); + + } else { + + p = Ustrstr(rc, "X-DSPAM-Factors: "); + if (p == rc) { + len = Ustrlen(rc) - 17 - 1; + if (len > sizeof(dspam_factors_buffer) - 1) len = sizeof(dspam_factors_buffer) - 1; + Ustrncpy(dspam_factors_buffer, rc + 17, len); + dspam_factors = dspam_factors_buffer; + last = dspam_factors; + last_size = sizeof(dspam_factors_buffer); + + } else { + + p = Ustrstr(rc, "X-DSPAM-Probability: "); + if (p == rc) { + len = Ustrlen(rc) - 21 - 1; + if (len > sizeof(dspam_probability_buffer) - 1) len = sizeof(dspam_probability_buffer) - 1; + Ustrncpy(dspam_probability_buffer, rc + 21, len); + dspam_probability = dspam_probability_buffer; + last = dspam_probability; + last_size = sizeof(dspam_probability_buffer); + + if (sscanf(CS dspam_probability, "%lf", &dspam_score) != 1) dspam_score = 0; + /* create "int" dspam probability */ + j = (int)((dspam_score + 0.00001)*1000); + (void)string_format(dspam_probability_int_buffer, sizeof(dspam_probability_int_buffer), "%d", j); + dspam_probability_int = dspam_probability_int_buffer; + + } else { + if (((rc[0] == 0x20) || (rc[0] == 0x09)) && (last != NULL)) { + if (Ustrlen(last) + 1 < last_size) { + len = Ustrlen(rc) - 1; + j = Ustrlen(last); + if (len > last_size - j - 2) len = last_size - j - 2; + Ustrncpy(last + j + 1, rc, len); + last[j] = 0x0a; + last[j + len + 1] = 0; + } else { + debug_printf("field buffer to small\n"); + } + } else { + last = NULL; + last_size = 0; + } + }}}}}}}} + } + + } while (!feof(dspam_file) && !ferror(dspam_file) && !done); + } + + if (ferror(dspam_file)) { + log_write(0, LOG_MAIN|LOG_PANIC, + "dspam acl condition: error reading response from LMTP socket: %s", strerror(errno)); + goto RETURN_DEFER; + } + + (void)lmtp_write_command(dspam_sock, "QUIT\r\n"); + (void)lmtp_read_response(dspam_file, dspam_buffer, sizeof(dspam_buffer), '2', DSPAM_TIMEOUT); + + /* remember user name and "been here" for it */ + Ustrcpy(prev_dspam_user_name, user_name); + dspam_ok = 1; + + if (mbox_file >= 0) (void)fclose(mbox_file); + if (dspam_file >= 0) (void)fclose(dspam_file); + if (dspam_sock >= 0) (void)close(dspam_sock); + + /* compare threshold against score */ + if ((dspam_classification && (strcmpic(dspam_classification,US"SPAM") == 0)) + || (dspam_result && (strcmpic(dspam_result,US"Spam") == 0))) { + /* spam */ + dspam_rc = OK; + } else { + /* not spam */ + dspam_rc = FAIL; + }; + + if (override) { + /* always return OK, no matter what the score */ + return OK; + } + else { + return dspam_rc; + }; + +/* Come here if any call to read_response, other than a response after the data +phase, failed. Analyse the error, and if isn't too bad, send a QUIT +command. Wait for the response with a short timeout, so we don't wind up this +process before the far end has had time to read the QUIT. */ + +RESPONSE_FAILED: +{ + int code; + int save_errno; + int more_errno; + uschar message_buffer[256]; + uschar *message; + + save_errno = errno; + + message = &message_buffer; +if (check_response(&save_errno, more_errno, dspam_buffer, &code, &message)) + { + (void) lmtp_write_command(dspam_sock, "QUIT\r\n"); + (void) lmtp_read_response(dspam_file, dspam_buffer, sizeof(dspam_buffer), '2', 2); + } + + log_write(0, LOG_MAIN|LOG_PANIC, "dspam acl condition: %s", message); + + goto RETURN_DEFER; +} + +/* Come here if there are errors during writing of a command or the message +itself. This error will be applied to all the addresses. */ + +WRITE_FAILED: + + if (errno == ERRNO_CHHEADER_FAIL) + log_write(0, LOG_MAIN|LOG_PANIC, + "Failed to expand headers_add or headers_remove: %s", + expand_string_message); + else if (errno == ERRNO_FILTER_FAIL) + log_write(0, LOG_MAIN|LOG_PANIC, + "Filter process failure"); + else if (errno == ERRNO_WRITEINCOMPLETE) + log_write(0, LOG_MAIN|LOG_PANIC, + "Failed repeatedly to write data"); + else if (errno == ERRNO_SMTPFORMAT) + log_write(0, LOG_MAIN|LOG_PANIC, + "overlong LMTP command generated"); + else + log_write(0, LOG_MAIN|LOG_PANIC, + "write failed: error %d: %s", errno, strerror(errno)); + + goto RETURN_DEFER; + +RETURN_DEFER: + + if (mbox_file > 0) (void)fclose(mbox_file); + if (dspam_file > 0) (void)fclose(dspam_file); + if (dspam_sock > 0) (void)close(dspam_sock); + + return DEFER; +} + +#endif diff -urN src.orig/dspam.h src/dspam.h --- src.orig/dspam.h Fri Nov 24 18:44:10 2006 +++ src/dspam.h Fri Nov 24 18:46:41 2006 @@ -0,0 +1,31 @@ +/* $Cambridge: exim/exim-src/src/spam.h,v 1.3 2005/04/27 10:00:18 ph10 Exp $ */ + +/************************************************* +* Exim - an Internet mail transport agent * +*************************************************/ + +/* Copyright (c) Tom Kistner 2003-???? */ +/* License: GPL */ + +/* spam defines */ + +#ifdef WITH_CONTENT_SCAN + +/* timeout for reading and writing spamd */ +#define DSPAM_TIMEOUT 120 + +/* maximum length of the spam bar */ +#define MAX_SPAM_BAR_CHARS 50 + +/* SHUT_WR seems to be undefined on Unixware ? */ +#ifndef SHUT_WR +#define SHUT_WR 1 +#endif + +typedef struct dspam_address_container { + uschar tcp_addr[24]; + unsigned int tcp_port; + uschar ident[48]; +} dspam_address_container; + +#endif diff -urN src.orig/expand.c src/expand.c --- src.orig/expand.c Tue Apr 17 16:06:39 2007 +++ src/expand.c Sun May 27 17:47:49 2007 @@ -418,6 +418,17 @@ { "dnslist_value", vtype_stringptr, &dnslist_value }, { "domain", vtype_stringptr, &deliver_domain }, { "domain_data", vtype_stringptr, &deliver_domain_data }, +#ifdef WITH_CONTENT_SCAN + { "dspam_classification", vtype_stringptr, &dspam_classification }, + { "dspam_confidence", vtype_stringptr, &dspam_confidence }, + { "dspam_factors", vtype_stringptr, &dspam_factors }, + { "dspam_improbability", vtype_stringptr, &dspam_improbability }, + { "dspam_probability", vtype_stringptr, &dspam_probability }, + { "dspam_probability_int",vtype_stringptr, &dspam_probability_int }, + { "dspam_processed", vtype_stringptr, &dspam_processed }, + { "dspam_result", vtype_stringptr, &dspam_result }, + { "dspam_signature", vtype_stringptr, &dspam_signature }, +#endif { "exim_gid", vtype_gid, &exim_gid }, { "exim_path", vtype_stringptr, &exim_path }, { "exim_uid", vtype_uid, &exim_uid }, diff -urN src.orig/functions.h src/functions.h --- src.orig/functions.h Tue Apr 17 16:06:39 2007 +++ src/functions.h Sun May 27 17:48:20 2007 @@ -92,6 +92,10 @@ extern dns_record *dns_next_rr(dns_answer *, dns_scan *, int); extern uschar *dns_text_type(int); +#ifdef WITH_CONTENT_SCAN +extern int dspam(uschar **); +#endif + extern void enq_end(uschar *); extern BOOL enq_start(uschar *); extern void exim_exit(int); diff -urN src.orig/globals.c src/globals.c --- src.orig/globals.c Tue Apr 17 16:06:39 2007 +++ src/globals.c Sun May 27 17:49:24 2007 @@ -530,6 +530,19 @@ BOOL drop_cr = FALSE; /* No longer used */ uschar *dsn_from = US DEFAULT_DSN_FROM; +#ifdef WITH_CONTENT_SCAN +uschar *dspam_address = US"127.0.0.1 24"; +uschar *dspam_classification = NULL; +uschar *dspam_confidence = NULL; +uschar *dspam_factors = NULL; +uschar *dspam_improbability = NULL; +uschar *dspam_probability = NULL; +uschar *dspam_probability_int = NULL; +uschar *dspam_processed = NULL; +uschar *dspam_result = NULL; +uschar *dspam_signature = NULL; +#endif + BOOL enable_dollar_recipients = FALSE; BOOL envelope_to_remove = TRUE; int errno_quota = ERRNO_QUOTA; diff -urN src.orig/globals.h src/globals.h --- src.orig/globals.h Tue Apr 17 16:06:39 2007 +++ src/globals.h Sun May 27 17:50:04 2007 @@ -312,6 +312,19 @@ extern uschar *dsn_from; /* From: string for DSNs */ +#ifdef WITH_CONTENT_SCAN +extern uschar *dspam_address; +extern uschar *dspam_classification; +extern uschar *dspam_confidence; +extern uschar *dspam_factors; +extern uschar *dspam_improbability; +extern uschar *dspam_probability; +extern uschar *dspam_probability_int; +extern uschar *dspam_processed; +extern uschar *dspam_result; +extern uschar *dspam_signature; +#endif + extern BOOL enable_dollar_recipients; /* Make $recipients available */ extern int envelope_to_remove; /* Remove envelope_to_headers */ extern int errno_quota; /* Quota errno in this OS */ diff -urN src.orig/readconf.c src/readconf.c --- src.orig/readconf.c Tue Apr 17 16:06:39 2007 +++ src/readconf.c Sun May 27 17:50:41 2007 @@ -210,6 +210,9 @@ { "drop_cr", opt_bool, &drop_cr }, /*********************************************************/ { "dsn_from", opt_stringptr, &dsn_from }, +#ifdef WITH_CONTENT_SCAN + { "dspam_address", opt_stringptr, &dspam_address }, +#endif { "envelope_to_remove", opt_bool, &envelope_to_remove }, { "errors_copy", opt_stringptr, &errors_copy }, { "errors_reply_to", opt_stringptr, &errors_reply_to }, diff -urN src.orig/spool_in.c src/spool_in.c --- src.orig/spool_in.c Tue Apr 17 16:06:40 2007 +++ src/spool_in.c Sun May 27 17:51:36 2007 @@ -289,6 +289,7 @@ #ifdef WITH_CONTENT_SCAN spam_score_int = NULL; +dspam_probability_int = NULL; #endif /* Generate the full name and open the file. If message_subdir is already @@ -535,6 +536,8 @@ #ifdef WITH_CONTENT_SCAN else if (Ustrncmp(p, "pam_score_int ", 14) == 0) spam_score_int = string_copy(big_buffer + 16); + else if (Ustrncmp(big_buffer, "-dspam_probability_int ", 23) == 0) + dspam_probability_int = string_copy(big_buffer + 23); #endif break; diff -urN src.orig/spool_mbox.c src/spool_mbox.c --- src.orig/spool_mbox.c Tue Apr 17 16:06:40 2007 +++ src/spool_mbox.c Sun May 27 17:52:26 2007 @@ -21,6 +21,7 @@ extern int malware_ok; extern int spam_ok; +extern int dspam_ok; int spool_mbox_ok = 0; uschar spooled_message_id[17]; @@ -176,6 +177,7 @@ #endif spam_ok = 0; + dspam_ok = 0; malware_ok = 0; if (spool_mbox_ok && !no_mbox_unspool) { diff -urN src.orig/spool_out.c src/spool_out.c --- src.orig/spool_out.c Tue Apr 17 16:06:40 2007 +++ src/spool_out.c Sun May 27 17:53:00 2007 @@ -218,6 +218,7 @@ if (local_scan_data != NULL) fprintf(f, "-local_scan %s\n", local_scan_data); #ifdef WITH_CONTENT_SCAN if (spam_score_int != NULL) fprintf(f,"-spam_score_int %s\n", spam_score_int); +if (dspam_probability_int != NULL) fprintf(f,"-dspam_probability_int %s\n", spam_score_int); #endif if (deliver_manual_thaw) fprintf(f, "-manual_thaw\n"); if (sender_set_untrusted) fprintf(f, "-sender_set_untrusted\n"); diff -urN src.orig/transports/lmtp.c src/transports/lmtp.c --- src.orig/transports/lmtp.c Tue Apr 17 16:06:40 2007 +++ src/transports/lmtp.c Sun May 27 17:54:27 2007 @@ -113,7 +113,8 @@ Returns: TRUE if a "QUIT" command should be sent, else FALSE */ -static BOOL check_response(int *errno_value, int more_errno, uschar *buffer, +//static +BOOL check_response(int *errno_value, int more_errno, uschar *buffer, int *yield, uschar **message) { *yield = '4'; /* Default setting is to give a temporary error */ @@ -211,7 +212,8 @@ Returns: TRUE if successful, FALSE if not, with errno set */ -static BOOL +//static BOOL +BOOL lmtp_write_command(int fd, char *format, ...) { int count, rc; @@ -256,7 +258,8 @@ Returns: TRUE if a valid, non-error response was received; else FALSE */ -static BOOL +//static BOOL +BOOL lmtp_read_response(FILE *f, uschar *buffer, int size, int okdigit, int timeout) { int count; diff -urN src.orig/transports/lmtp.h src/transports/lmtp.h --- src.orig/transports/lmtp.h Tue Apr 17 16:06:40 2007 +++ src/transports/lmtp.h Sun May 27 17:54:53 2007 @@ -30,5 +30,8 @@ extern BOOL lmtp_transport_entry(transport_instance *, address_item *); extern void lmtp_transport_init(transport_instance *); +extern BOOL lmtp_write_command(int fd, char *format, ...); +extern BOOL lmtp_read_response(FILE *f, uschar *buffer, int size, int okdigit, int timeout); +extern BOOL check_response(int *errno_value, int more_errno, uschar *buffer, int *yield, uschar **message); /* End of transports/lmtp.h */