2004-09-23 [christoph] 0.9.12cvs103
authorChristoph Hohmann <reboot@gmx.ch>
Thu, 23 Sep 2004 12:07:44 +0000 (12:07 +0000)
committerChristoph Hohmann <reboot@gmx.ch>
Thu, 23 Sep 2004 12:07:44 +0000 (12:07 +0000)
* src/plugins/spamassassin/libspamc.[ch]
* src/plugins/spamassassin/utils.[ch]
update libspamc to SpamAssassin 3.0.0

ChangeLog.claws
PATCHSETS
configure.ac
src/plugins/spamassassin/libspamc.c
src/plugins/spamassassin/libspamc.h
src/plugins/spamassassin/utils.c
src/plugins/spamassassin/utils.h

index c9098e2..ebb838e 100644 (file)
@@ -1,3 +1,9 @@
+2004-09-23 [christoph] 0.9.12cvs103
+
+       * src/plugins/spamassassin/libspamc.[ch]
+       * src/plugins/spamassassin/utils.[ch]
+               update libspamc to SpamAssassin 3.0.0
+
 2004-09-17 [paul]      0.9.12cvs102
 
        * ChangeLog
index de11d9c..88b2559 100644 (file)
--- a/PATCHSETS
+++ b/PATCHSETS
@@ -85,3 +85,4 @@
 ( cvs diff -u -r 1.259 -r 1.260 src/folder.c; ) > 0.9.12cvs100.patchset
 ( cvs diff -u -r 1.143 -r 1.144 src/main.c; ) > 0.9.12cvs101.patchset
 ( cvs diff -u -r 1.442 -r 1.443 ChangeLog; cvs diff -u -r 1.437 -r 1.438 ChangeLog.jp; cvs diff -u -r 1.176 -r 1.177 src/inc.c; ) > 0.9.12cvs102.patchset
+( cvs diff -u -r 1.6 -r 1.7 src/plugins/spamassassin/libspamc.c; cvs diff -u -r 1.5 -r 1.6 src/plugins/spamassassin/libspamc.h; cvs diff -u -r 1.4 -r 1.5 src/plugins/spamassassin/utils.c; cvs diff -u -r 1.4 -r 1.5 src/plugins/spamassassin/utils.h; ) > 0.9.12cvs103.patchset
index fd30ff6..a1d1460 100644 (file)
@@ -11,7 +11,7 @@ MINOR_VERSION=9
 MICRO_VERSION=12
 INTERFACE_AGE=0
 BINARY_AGE=0
-EXTRA_VERSION=102
+EXTRA_VERSION=103
 EXTRA_RELEASE=
 
 if test \( $EXTRA_VERSION -eq 0 \) -o \( "x$EXTRA_RELEASE" != "x" \); then
index 84d21da..4d47987 100644 (file)
@@ -1,27 +1,45 @@
-/*
- * This code is copyright 2001 by Craig Hughes
- * Portions copyright 2002 by Brad Jorsch
- * It is licensed under the same license as Perl itself.  The text of this
- * license is included in the SpamAssassin distribution in the file named
- * "License".
+/* <@LICENSE>
+ * Copyright 2004 Apache Software Foundation
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * </@LICENSE>
  */
 
 #include "config.h"
 #include "libspamc.h"
 #include "utils.h"
 
-#include <unistd.h>
 #include <stdlib.h>
 #include <assert.h>
 #include <stdio.h>
 #include <string.h>
+#ifdef _WIN32
+#define snprintf _snprintf
+#define vsnprintf _vsnprintf
+#define strcasecmp stricmp
+#define sleep Sleep
+#include <io.h>
+#else
 #include <syslog.h>
+#include <unistd.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <sys/un.h>
 #include <netinet/tcp.h>
 #include <arpa/inet.h>
+#define closesocket(x) close(x)
+#endif
 
 #ifdef HAVE_SYSEXITS_H
 #include <sysexits.h>
 /* KAM 12-4-01 */
 /* SJF 2003/04/25 - now test for macros directly */
 #ifndef SHUT_RD
-#  define SHUT_RD 0    /* no more receptions */
+#  define SHUT_RD 0            /* no more receptions */
 #endif
 #ifndef SHUT_WR
-#  define SHUT_WR 1    /* no more transmissions */
+#  define SHUT_WR 1            /* no more transmissions */
 #endif
 #ifndef SHUT_RDWR
-#  define SHUT_RDWR 2  /* no more receptions or transmissions */
+#  define SHUT_RDWR 2          /* no more receptions or transmissions */
 #endif
 
 #ifndef HAVE_H_ERRNO
@@ -72,13 +90,13 @@ extern char *optarg;
 
 #ifndef HAVE_EX__MAX
 /* jm: very conservative figure, should be well out of range on almost all NIXes */
-#define EX__MAX 200 
+#define EX__MAX 200
 #endif
 
 #undef DO_CONNECT_DEBUG_SYSLOGS
 /* or #define DO_CONNECT_DEBUG_SYSLOGS 1 */
 
-static const int ESC_PASSTHROUGHRAW = EX__MAX+666;
+static const int ESC_PASSTHROUGHRAW = EX__MAX + 666;
 
 /* set EXPANSION_ALLOWANCE to something more than might be
    added to a message in X-headers and the report template */
@@ -91,14 +109,15 @@ static const int EXPANSION_ALLOWANCE = 16384;
  */
 
 /* Set the protocol version that this spamc speaks */
-static const char *PROTOCOL_VERSION="SPAMC/1.3";
+static const char *PROTOCOL_VERSION = "SPAMC/1.3";
 
 /* "private" part of struct message.
  * we use this instead of the struct message directly, so that we
  * can add new members without affecting the ABI.
  */
-struct libspamc_private_message {
-  int flags;   /* copied from "flags" arg to message_read() */
+struct libspamc_private_message
+{
+    int flags;                 /* copied from "flags" arg to message_read() */
 };
 
 int libspamc_timeout = 0;
@@ -112,32 +131,30 @@ int libspamc_timeout = 0;
  *
  *     This should ONLY be called when there is an error.
  */
-static int
-translate_connect_errno(int err)
+static int _translate_connect_errno(int err)
 {
-       switch (err)
-       {
-         case EBADF:
-         case EFAULT:
-         case ENOTSOCK:
-         case EISCONN:
-         case EADDRINUSE:
-         case EINPROGRESS:
-         case EALREADY:
-         case EAFNOSUPPORT:
-               return EX_SOFTWARE;
+    switch (err) {
+    case EBADF:
+    case EFAULT:
+    case ENOTSOCK:
+    case EISCONN:
+    case EADDRINUSE:
+    case EINPROGRESS:
+    case EALREADY:
+    case EAFNOSUPPORT:
+       return EX_SOFTWARE;
 
-         case ECONNREFUSED:
-         case ETIMEDOUT:
-         case ENETUNREACH:
-               return EX_UNAVAILABLE;
+    case ECONNREFUSED:
+    case ETIMEDOUT:
+    case ENETUNREACH:
+       return EX_UNAVAILABLE;
 
-         case EACCES:
-               return EX_NOPERM;
+    case EACCES:
+       return EX_NOPERM;
 
-         default:
-               return EX_SOFTWARE;
-       }
+    default:
+       return EX_SOFTWARE;
+    }
 }
 
 /*
@@ -150,64 +167,70 @@ translate_connect_errno(int err)
  *
  *     Upon failure we return one of the other EX_??? error codes.
  */
-static int opensocket(int type, int *psock)
+static int _opensocket(int flags, int type, int *psock)
 {
-const char *typename;
-int        proto = 0;
+    const char *typename;
+    int proto = 0;
 
-       assert(psock != 0);
+    assert(psock != 0);
 
        /*----------------------------------------------------------------
         * Create a few induction variables that are implied by the socket
         * type given by the user. The typename is strictly used for debug
         * reporting.
         */
-       if ( type == PF_UNIX )
-       {
-               typename = "PF_UNIX";
-       }
-       else
-       {
-               typename = "PF_INET";
-               proto    = IPPROTO_TCP;
-       }
+    if (type == PF_UNIX) {
+       typename = "PF_UNIX";
+    }
+    else {
+       typename = "PF_INET";
+       proto = IPPROTO_TCP;
+    }
 
 #ifdef DO_CONNECT_DEBUG_SYSLOGS
-       syslog (DEBUG_LEVEL, "dbg: create socket(%s)", typename);
+    libspamc_log(flags, DEBUG_LEVEL, "dbg: create socket(%s)", typename);
 #endif
 
-       if ( (*psock = socket(type, SOCK_STREAM, proto)) < 0 )
-       {
-       int     origerr;
+    if ((*psock = socket(type, SOCK_STREAM, proto))
+#ifndef _WIN32
+       < 0
+#else
+       == INVALID_SOCKET
+#endif
+       ) {
+       int origerr;
 
                /*--------------------------------------------------------
                 * At this point we had a failure creating the socket, and
                 * this is pretty much fatal. Translate the error reason
                 * into something the user can understand.
                 */
-               origerr = errno;    /* take a copy before syslog() */
-
-               syslog (LOG_ERR, "socket(%s) to spamd failed: %m", typename);
+#ifndef _WIN32
+       origerr = errno;        /* take a copy before syslog() */
+       libspamc_log(flags, LOG_ERR, "socket(%s) to spamd failed: %s", typename, strerror(origerr));
+#else
+       origerr = WSAGetLastError();
+       libspamc_log(flags, LOG_ERR, "socket(%s) to spamd failed: %d", typename, origerr);
+#endif
 
-               switch (origerr)
-               {
-                 case EPROTONOSUPPORT:
-                 case EINVAL:
-                       return EX_SOFTWARE;
+       switch (origerr) {
+       case EPROTONOSUPPORT:
+       case EINVAL:
+           return EX_SOFTWARE;
 
-                 case EACCES:
-                       return EX_NOPERM;
+       case EACCES:
+           return EX_NOPERM;
 
-                 case ENFILE:
-                 case EMFILE:
-                 case ENOBUFS:
-                 case ENOMEM:
-                       return EX_OSERR;
+       case ENFILE:
+       case EMFILE:
+       case ENOBUFS:
+       case ENOMEM:
+           return EX_OSERR;
 
-                 default:
-                       return EX_SOFTWARE;
-               }
+       default:
+           return EX_SOFTWARE;
        }
+    }
 
 
        /*----------------------------------------------------------------
@@ -215,31 +238,39 @@ int           proto = 0;
         * suggest this is probably not set
         */
 #ifdef USE_TCP_NODELAY
-       {
-               int one = 1;
-
-               if ( type == PF_INET
-                &&  setsockopt(*psock, 0, TCP_NODELAY, &one, sizeof one) != 0 )
-               {
-                       switch(errno)
-                       {
-                         case EBADF:
-                         case ENOTSOCK:
-                         case ENOPROTOOPT:
-                         case EFAULT:
-                               syslog(LOG_ERR,
-                                  "setsockopt(TCP_NODELAY) failed: %m");
-                               close (*psock);
-                               return EX_SOFTWARE;
-
-                         default:
-                               break;            /* ignored */
-                       }
-               }
+    {
+       int one = 1;
+
+       if (type == PF_INET
+           && setsockopt(*psock, 0, TCP_NODELAY, &one, sizeof one) != 0) {
+           int origerrno;
+#ifndef _WIN32
+           origerr = errno;
+#else
+           origerrno = WSAGetLastError();
+#endif
+           switch (origerr) {
+           case EBADF:
+           case ENOTSOCK:
+           case ENOPROTOOPT:
+           case EFAULT:
+               libspamc_log(flags, LOG_ERR,
+#ifndef _WIN32
+                      "setsockopt(TCP_NODELAY) failed: %s", strerror(origerr));
+#else
+                      "setsockopt(TCP_NODELAY) failed: %d", origerr);
+#endif
+               closesocket(*psock);
+               return EX_SOFTWARE;
+
+           default:
+               break;          /* ignored */
+           }
        }
+    }
 #endif /* USE_TCP_NODELAY */
 
-       return EX_OK;   /* all is well */
+    return EX_OK;              /* all is well */
 }
 
 /*
@@ -250,55 +281,58 @@ int           proto = 0;
  *     file descriptor in *sockptr. Return is EX_OK if we did it,
  *     and some other error code otherwise.
  */
-static int
-try_to_connect_unix (struct transport *tp, int *sockptr)
+static int _try_to_connect_unix(struct transport *tp, int *sockptr)
 {
-int mysock, status, origerr;
-struct sockaddr_un addrbuf;
-int ret;
+#ifndef _WIN32
+    int mysock, status, origerr;
+    struct sockaddr_un addrbuf;
+    int ret;
 
-       assert(tp             != 0);
-       assert(sockptr        != 0);
-       assert(tp->socketpath != 0);
+    assert(tp != 0);
+    assert(sockptr != 0);
+    assert(tp->socketpath != 0);
 
        /*----------------------------------------------------------------
         * If the socket itself can't be created, this is a fatal error.
         */
-       if ( (ret = opensocket(PF_UNIX, &mysock)) != EX_OK )
-               return ret;
+    if ((ret = _opensocket(tp->flags, PF_UNIX, &mysock)) != EX_OK)
+       return ret;
 
-       /* set up the UNIX domain socket */
-       memset(&addrbuf, 0, sizeof addrbuf);
-       addrbuf.sun_family = AF_UNIX;
-       strncpy(addrbuf.sun_path, tp->socketpath, sizeof addrbuf.sun_path - 1);
-       addrbuf.sun_path[sizeof addrbuf.sun_path - 1] = '\0';
+    /* set up the UNIX domain socket */
+    memset(&addrbuf, 0, sizeof addrbuf);
+    addrbuf.sun_family = AF_UNIX;
+    strncpy(addrbuf.sun_path, tp->socketpath, sizeof addrbuf.sun_path - 1);
+    addrbuf.sun_path[sizeof addrbuf.sun_path - 1] = '\0';
 
 #ifdef DO_CONNECT_DEBUG_SYSLOGS
-       syslog (DEBUG_LEVEL, "dbg: connect(AF_UNIX) to spamd at %s",
-               addrbuf.sun_path);
+    libspamc_log(tp->flags, DEBUG_LEVEL, "dbg: connect(AF_UNIX) to spamd at %s",
+          addrbuf.sun_path);
 #endif
 
-       status = connect(mysock, (struct sockaddr *) &addrbuf, sizeof(addrbuf));
+    status = connect(mysock, (struct sockaddr *) &addrbuf, sizeof(addrbuf));
 
-       origerr = errno;
+    origerr = errno;
 
-       if ( status >= 0 )
-       {
+    if (status >= 0) {
 #ifdef DO_CONNECT_DEBUG_SYSLOGS
-               syslog(DEBUG_LEVEL, "dbg: connect(AF_UNIX) ok");
+       libspamc_log(tp->flags, DEBUG_LEVEL, "dbg: connect(AF_UNIX) ok");
 #endif
 
-               *sockptr = mysock;
-
-               return EX_OK;
-       }
+       *sockptr = mysock;
 
-       syslog(LOG_ERR, "connect(AF_UNIX) to spamd %s failed: %m",
-               addrbuf.sun_path);
+       return EX_OK;
+    }
 
-       close(mysock);
+    libspamc_log(tp->flags, LOG_ERR, "connect(AF_UNIX) to spamd %s failed: %s",
+          addrbuf.sun_path, strerror(origerr));
+    closesocket(mysock);
 
-       return translate_connect_errno(origerr);
+    return _translate_connect_errno(origerr);
+#else
+    (void) tp; /* not used. suppress compiler warning */
+    (void) sockptr; /* not used. suppress compiler warning */
+    return EX_OSERR;
+#endif
 }
 
 /*
@@ -309,545 +343,346 @@ int ret;
  *     list of IP addresses has already been randomized (if requested)
  *     and limited to just one if fallback has been enabled.
  */
-static int
-try_to_connect_tcp (const struct transport *tp, int *sockptr)
+static int _try_to_connect_tcp(const struct transport *tp, int *sockptr)
 {
-int    numloops;
-int    origerr = 0;
-int    ret;
+    int numloops;
+    int origerr = 0;
+    int ret;
 
-       assert(tp        != 0);
-       assert(sockptr   != 0);
-       assert(tp->nhosts > 0);
+    assert(tp != 0);
+    assert(sockptr != 0);
+    assert(tp->nhosts > 0);
 
 #ifdef DO_CONNECT_DEBUG_SYSLOGS
-       for (numloops = 0; numloops < tp->nhosts; numloops++)
-       {
-               syslog(LOG_ERR, "dbg: %d/%d: %s",
-                       numloops+1, tp->nhosts, inet_ntoa(tp->hosts[numloops]));
-       }
+    for (numloops = 0; numloops < tp->nhosts; numloops++) {
+       libspamc_log(tp->flags, LOG_ERR, "dbg: %d/%d: %s",
+               numloops + 1, tp->nhosts, inet_ntoa(tp->hosts[numloops]));
+    }
 #endif
 
-       for (numloops = 0; numloops < MAX_CONNECT_RETRIES; numloops++)
-       {
+    for (numloops = 0; numloops < MAX_CONNECT_RETRIES; numloops++) {
        struct sockaddr_in addrbuf;
-       const int          hostix = numloops % tp->nhosts;
-       int                status, mysock;
-       const char       * ipaddr;
+       const int hostix = numloops % tp->nhosts;
+       int status, mysock;
+       const char *ipaddr;
 
                /*--------------------------------------------------------
                 * We always start by creating the socket, as we get only
                 * one attempt to connect() on each one. If this fails,
                 * we're done.
                 */
-               if ( (ret = opensocket(PF_INET, &mysock)) != EX_OK )
-                       return ret;
+       if ((ret = _opensocket(tp->flags, PF_INET, &mysock)) != EX_OK)
+           return ret;
 
-               memset(&addrbuf, 0, sizeof(addrbuf));
+       memset(&addrbuf, 0, sizeof(addrbuf));
 
-               addrbuf.sin_family = AF_INET;
-               addrbuf.sin_port   = htons(tp->port);
-               addrbuf.sin_addr   = tp->hosts[hostix];
+       addrbuf.sin_family = AF_INET;
+       addrbuf.sin_port = htons(tp->port);
+       addrbuf.sin_addr = tp->hosts[hostix];
 
-               ipaddr = inet_ntoa(addrbuf.sin_addr);
+       ipaddr = inet_ntoa(addrbuf.sin_addr);
 
 #ifdef DO_CONNECT_DEBUG_SYSLOGS
-               syslog (DEBUG_LEVEL,
-                       "dbg: connect(AF_INET) to spamd at %s (try #%d of %d)",
-                       ipaddr,
-                       numloops+1,
-                       MAX_CONNECT_RETRIES);
+       libspamc_log(tp->flags, DEBUG_LEVEL,
+              "dbg: connect(AF_INET) to spamd at %s (try #%d of %d)",
+               ipaddr, numloops + 1, MAX_CONNECT_RETRIES);
 #endif
 
-               status = connect(mysock, (struct sockaddr *)&addrbuf, sizeof(addrbuf));
+       status =
+           connect(mysock, (struct sockaddr *) &addrbuf, sizeof(addrbuf));
 
-               if (status != 0)
-               {
-                       syslog (LOG_ERR,
-                       "connect(AF_INET) to spamd at %s failed, retrying (#%d of %d): %m",
-                               ipaddr, numloops+1, MAX_CONNECT_RETRIES);
-
-                       close(mysock);
-
-                       sleep(CONNECT_RETRY_SLEEP);
-               }
-               else
-               {
-#ifdef DO_CONNECT_DEBUG_SYSLOGS
-                       syslog(DEBUG_LEVEL,
-                               "dbg: connect(AF_INET) to spamd at %s done",
-                               ipaddr);
+       if (status != 0) {
+#ifndef _WIN32
+           origerr = errno;
+           libspamc_log(tp->flags, LOG_ERR,
+                  "connect(AF_INET) to spamd at %s failed, retrying (#%d of %d): %s",
+                  ipaddr, numloops + 1, MAX_CONNECT_RETRIES, strerror(origerr));
+#else
+           origerr = WSAGetLastError();
+           libspamc_log(tp->flags, LOG_ERR,
+                  "connect(AF_INET) to spamd at %s failed, retrying (#%d of %d): %d",
+                  ipaddr, numloops + 1, MAX_CONNECT_RETRIES, origerr);
 #endif
-                       *sockptr = mysock;
+           closesocket(mysock);
 
-                       return EX_OK;
-               }
+           sleep(CONNECT_RETRY_SLEEP);
        }
-
-       syslog (LOG_ERR, "connection attempt to spamd aborted after %d retries",
-               MAX_CONNECT_RETRIES);
-
-       return translate_connect_errno(origerr);
-}
-
-#if 0
-static int
-try_to_connect (const struct sockaddr *argaddr, struct hostent *hent,
-                int hent_port, int *sockptr)
-{
-#ifdef USE_TCP_NODELAY
-  int value;
-#endif
-  int mysock = -1;
-  int status = -1;
-  int origerr;
-  int numloops;
-  int hostnum = 0;
-  struct sockaddr_in addrbuf, *addr;
-  struct in_addr inaddrlist[256];
-
+       else {
 #ifdef DO_CONNECT_DEBUG_SYSLOGS
-  int dbgiter; char dbgbuf[2048]; int dbgbuflen = 0;
-#endif
-
-  /* NOTE: do not call syslog() (unless you are about to return) before
-   * we take a copy of the h_addr_list.
-   */
-
-  /* only one set of connection targets can be used.  assert this */
-  if (argaddr == NULL && hent == NULL) {
-      syslog (LOG_ERR, "oops! both NULL in try_to_connect");
-      return EX_SOFTWARE;
-  } else if (argaddr != NULL && hent != NULL) {
-      syslog (LOG_ERR, "oops! both non-NULL in try_to_connect");
-      return EX_SOFTWARE;
-  }
-
-  /* take a copy of the h_addr_list part of the struct hostent */
-  if (hent != NULL) {
-    memset (inaddrlist, 0, sizeof(inaddrlist));
-
-    for (hostnum=0; hent->h_addr_list[hostnum] != 0; hostnum++) {
-
-#ifdef DO_CONNECT_DEBUG_SYSLOGS
-      dbgbuflen += snprintf (dbgbuf+dbgbuflen, 2047-dbgbuflen,
-                 "[%d %lx: %d.%d.%d.%d]",
-                 hostnum, hent->h_addr_list[hostnum],
-                 hent->h_addr_list[hostnum][0],
-                 hent->h_addr_list[hostnum][1],
-                 hent->h_addr_list[hostnum][2],
-                 hent->h_addr_list[hostnum][3]);
-#endif
-
-      if (hostnum > 255) {
-       syslog (LOG_ERR, "too many address in hostent (%d), ignoring others",
-                           hostnum);
-       break;
-      }
-
-      if (hent->h_addr_list[hostnum] == NULL) {
-       /* shouldn't happen */
-       syslog (LOG_ERR, "hent->h_addr_list[hostnum] == NULL! foo!");
-       return EX_SOFTWARE;
-      }
-
-#ifdef DO_CONNECT_DEBUG_SYSLOGS
-      dbgbuflen += snprintf (dbgbuf+dbgbuflen, 2047-dbgbuflen,
-                 "[%d: %d.%d.%d.%d] ", sizeof (struct in_addr),
-                 hent->h_addr_list[hostnum][0],
-                 hent->h_addr_list[hostnum][1],
-                 hent->h_addr_list[hostnum][2],
-                 hent->h_addr_list[hostnum][3]);
-#endif
-
-      memcpy ((void *) &(inaddrlist[hostnum]),
-               (void *) hent->h_addr_list[hostnum],
-               sizeof (struct in_addr));
-    }
-
-#ifdef DO_CONNECT_DEBUG_SYSLOGS
-      syslog (LOG_DEBUG, "dbg: %d %s", hostnum, dbgbuf); dbgbuflen = 0;
-#endif
-  }
-
-
-#ifdef DO_CONNECT_DEBUG_SYSLOGS
-    for (dbgiter = 0; dbgiter < hostnum; dbgiter++) {
-      syslog (LOG_DEBUG, "dbg: host addr %d/%d = %lx at %lx", dbgiter, hostnum,
-                 inaddrlist[dbgiter].s_addr, &(inaddrlist[dbgiter]));
-    }
-#endif
-
-  hent = NULL; /* cannot use hent after this point, syslog() may overwrite it */
-
-#ifdef DO_CONNECT_DEBUG_SYSLOGS
-  syslog (LOG_DEBUG, "dbg: socket");
-#endif
-
-  if(-1 == (mysock = socket(PF_INET,SOCK_STREAM,0)))
-  {
-    origerr = errno;    /* take a copy before syslog() */
-    syslog (LOG_ERR, "socket() to spamd failed: %m");
-    switch(origerr)
-    {
-    case EPROTONOSUPPORT:
-    case EINVAL:
-      return EX_SOFTWARE;
-    case EACCES:
-      return EX_NOPERM;
-    case ENFILE:
-    case EMFILE:
-    case ENOBUFS:
-    case ENOMEM:
-      return EX_OSERR;
-    default:
-      return EX_SOFTWARE;
-    }
-  }
-
-#ifdef USE_TCP_NODELAY
-  /* TODO: should this be up above the connect()? */
-  value = 1;           /* make this explicit! */
-  if(-1 == setsockopt(mysock,0,TCP_NODELAY,&value,sizeof(value)))
-  {
-    switch(errno)
-    {
-    case EBADF:
-    case ENOTSOCK:
-    case ENOPROTOOPT:
-    case EFAULT:
-      syslog (LOG_ERR, "setsockopt() to spamd failed: %m");
-      close (mysock);
-      return EX_SOFTWARE;
-
-    default:
-      break;           /* ignored */
-    }
-  }
-#endif
-
-  for (numloops=0; numloops < MAX_CONNECT_RETRIES; numloops++) {
-  
-#ifdef DO_CONNECT_DEBUG_SYSLOGS
-      syslog (LOG_DEBUG, "dbg: connect() to spamd %d", numloops);
-#endif
-
-    if (argaddr != NULL) {
-      addr = (struct sockaddr_in *) argaddr;     /* use the one provided */
-  
-#ifdef DO_CONNECT_DEBUG_SYSLOGS
-       syslog (LOG_DEBUG, "dbg: using argaddr");
-#endif
-
-    } else {
-      /* cycle through the addrs in hent */
-      memset(&addrbuf, 0, sizeof(addrbuf));
-      addrbuf.sin_family=AF_INET;
-      addrbuf.sin_port=htons(hent_port);
-
-      if (sizeof(addrbuf.sin_addr) != sizeof(struct in_addr)) {        /* shouldn't happen */
-       syslog (LOG_ERR,        
-               "foo! sizeof(sockaddr.sin_addr) != sizeof(struct in_addr)");
-       return EX_SOFTWARE;
-      }
-
-#ifdef DO_CONNECT_DEBUG_SYSLOGS
-       syslog (LOG_DEBUG, "dbg: cpy addr %d/%d at %lx",
-               numloops%hostnum, hostnum, &(inaddrlist[numloops % hostnum]));
-#endif
-
-      memcpy (&addrbuf.sin_addr, &(inaddrlist[numloops % hostnum]),
-                        sizeof(addrbuf.sin_addr));
-      addr = &addrbuf;
-
-#ifdef DO_CONNECT_DEBUG_SYSLOGS
-       syslog (LOG_DEBUG, "dbg: conn addr %d/%d = %lx",
-           numloops%hostnum, hostnum, addrbuf.sin_addr.s_addr);
+           libspamc_log(tp->flags, DEBUG_LEVEL,
+                  "dbg: connect(AF_INET) to spamd at %s done", ipaddr);
 #endif
+           *sockptr = mysock;
 
+           return EX_OK;
+       }
     }
 
-#ifdef DO_CONNECT_DEBUG_SYSLOGS
-    syslog (LOG_DEBUG, "dbg: connect() to spamd at %s",
-               inet_ntoa(((struct sockaddr_in *)addr)->sin_addr));
-#endif
-    status = connect(mysock,(const struct sockaddr *) addr, sizeof(*addr));
-
-#ifdef DO_CONNECT_DEBUG_SYSLOGS
-      syslog (LOG_DEBUG, "dbg: connect() to spamd at %s done",
-         inet_ntoa(((struct sockaddr_in *)addr)->sin_addr));
-#endif
-
-    if (status < 0)
-    {
-      origerr = errno;        /* take a copy before syslog() */
-      syslog (LOG_ERR, "connect() to spamd at %s failed, retrying (%d/%d): %m",
-                        inet_ntoa(((struct sockaddr_in *)addr)->sin_addr),
-                        numloops+1, MAX_CONNECT_RETRIES);
-      sleep(CONNECT_RETRY_SLEEP);
+    libspamc_log(tp->flags, LOG_ERR, "connection attempt to spamd aborted after %d retries",
+           MAX_CONNECT_RETRIES);
 
-    } else {
-      *sockptr = mysock;
-      return EX_OK;
-    }
-  }
-  /* failed, even with a few retries */
-  close (mysock);
-  syslog (LOG_ERR, "connection attempt to spamd aborted after %d retries",
-       MAX_CONNECT_RETRIES);
-  switch(origerr)
-  {
-   case EBADF:
-   case EFAULT:
-   case ENOTSOCK:
-   case EISCONN:
-   case EADDRINUSE:
-   case EINPROGRESS:
-   case EALREADY:
-   case EAFNOSUPPORT:
-     return EX_SOFTWARE;
-   case ECONNREFUSED:
-   case ETIMEDOUT:
-   case ENETUNREACH:
-     return EX_UNAVAILABLE;
-   case EACCES:
-     return EX_NOPERM;
-   default:
-     return EX_SOFTWARE;
-  }
+    return _translate_connect_errno(origerr);
 }
-#endif
 
 /* Aug 14, 2002 bj: Reworked things. Now we have message_read, message_write,
  * message_dump, lookup_host, message_filter, and message_process, and a bunch
  * of helper functions.
  */
 
-static void clear_message(struct message *m){
-    m->type=MESSAGE_NONE;
-    m->raw=NULL; m->raw_len=0;
-    m->pre=NULL; m->pre_len=0;
-    m->msg=NULL; m->msg_len=0;
-    m->post=NULL; m->post_len=0;
-    m->is_spam=EX_TOOBIG;
-    m->score=0.0; m->threshold=0.0;
-    m->out=NULL; m->out_len=0;
-    m->content_length=-1;
+static void _clear_message(struct message *m)
+{
+    m->type = MESSAGE_NONE;
+    m->raw = NULL;
+    m->raw_len = 0;
+    m->pre = NULL;
+    m->pre_len = 0;
+    m->msg = NULL;
+    m->msg_len = 0;
+    m->post = NULL;
+    m->post_len = 0;
+    m->is_spam = EX_TOOBIG;
+    m->score = 0.0;
+    m->threshold = 0.0;
+    m->out = NULL;
+    m->out_len = 0;
+    m->content_length = -1;
 }
 
-static int
-message_read_raw(int fd, struct message *m){
-    clear_message(m);
-    if((m->raw=malloc(m->max_len+1))==NULL) return EX_OSERR;
-    m->raw_len=full_read(fd, m->raw, m->max_len+1, m->max_len+1);
-    if(m->raw_len<=0){
-        free(m->raw); m->raw=NULL; m->raw_len=0;
-        return EX_IOERR;
+static int _message_read_raw(int fd, struct message *m)
+{
+    _clear_message(m);
+    if ((m->raw = malloc(m->max_len + 1)) == NULL)
+       return EX_OSERR;
+    m->raw_len = full_read(fd, 1, m->raw, m->max_len + 1, m->max_len + 1);
+    if (m->raw_len <= 0) {
+       free(m->raw);
+       m->raw = NULL;
+       m->raw_len = 0;
+       return EX_IOERR;
     }
-    m->type=MESSAGE_ERROR;
-    if(m->raw_len>m->max_len) return EX_TOOBIG;
-    m->type=MESSAGE_RAW;
-    m->msg=m->raw;
-    m->msg_len=m->raw_len;
-    m->out=m->msg;
-    m->out_len=m->msg_len;
+    m->type = MESSAGE_ERROR;
+    if (m->raw_len > m->max_len)
+       return EX_TOOBIG;
+    m->type = MESSAGE_RAW;
+    m->msg = m->raw;
+    m->msg_len = m->raw_len;
+    m->out = m->msg;
+    m->out_len = m->msg_len;
     return EX_OK;
 }
 
-static int message_read_bsmtp(int fd, struct message *m){
-    off_t i, j;
+static int _message_read_bsmtp(int fd, struct message *m)
+{
+    unsigned int i, j;
     char prev;
 
-    clear_message(m);
-    if((m->raw=malloc(m->max_len+1))==NULL) return EX_OSERR;
+    _clear_message(m);
+    if ((m->raw = malloc(m->max_len + 1)) == NULL)
+       return EX_OSERR;
 
     /* Find the DATA line */
-    m->raw_len=full_read(fd, m->raw, m->max_len+1, m->max_len+1);
-    if(m->raw_len<=0){
-        free(m->raw); m->raw=NULL; m->raw_len=0;
-        return EX_IOERR;
+    m->raw_len = full_read(fd, 1, m->raw, m->max_len + 1, m->max_len + 1);
+    if (m->raw_len <= 0) {
+       free(m->raw);
+       m->raw = NULL;
+       m->raw_len = 0;
+       return EX_IOERR;
     }
-    m->type=MESSAGE_ERROR;
-    if(m->raw_len>m->max_len) return EX_TOOBIG;
-    m->pre=m->raw;
-    for(i=0; i<m->raw_len-6; i++){
-        if((m->raw[i]=='\n') &&
-           (m->raw[i+1]=='D' || m->raw[i+1]=='d') &&
-           (m->raw[i+2]=='A' || m->raw[i+2]=='a') &&
-           (m->raw[i+3]=='T' || m->raw[i+3]=='t') &&
-           (m->raw[i+4]=='A' || m->raw[i+4]=='a') &&
-           ((m->raw[i+5]=='\r' && m->raw[i+6]=='\n') || m->raw[i+5]=='\n')){
-            /* Found it! */
-            i+=6;
-            if(m->raw[i-1]=='\r') i++;
-            m->pre_len=i;
-            m->msg=m->raw+i;
-            m->msg_len=m->raw_len-i;
-            break;
-        }
+    m->type = MESSAGE_ERROR;
+    if (m->raw_len > m->max_len)
+       return EX_TOOBIG;
+    m->pre = m->raw;
+    for (i = 0; i < m->raw_len - 6; i++) {
+       if ((m->raw[i] == '\n') &&
+           (m->raw[i + 1] == 'D' || m->raw[i + 1] == 'd') &&
+           (m->raw[i + 2] == 'A' || m->raw[i + 2] == 'a') &&
+           (m->raw[i + 3] == 'T' || m->raw[i + 3] == 't') &&
+           (m->raw[i + 4] == 'A' || m->raw[i + 4] == 'a') &&
+           ((m->raw[i + 5] == '\r' && m->raw[i + 6] == '\n')
+            || m->raw[i + 5] == '\n')) {
+           /* Found it! */
+           i += 6;
+           if (m->raw[i - 1] == '\r')
+               i++;
+           m->pre_len = i;
+           m->msg = m->raw + i;
+           m->msg_len = m->raw_len - i;
+           break;
+       }
     }
-    if(m->msg==NULL) return EX_DATAERR;
+    if (m->msg == NULL)
+       return EX_DATAERR;
 
     /* Find the end-of-DATA line */
-    prev='\n';
-    for(i=j=0; i<m->msg_len; i++){
-        if(prev=='\n' && m->msg[i]=='.'){
-            /* Dot at the beginning of a line */
-            if((m->msg[i+1]=='\r' && m->msg[i+2]=='\n') || m->msg[i+1]=='\n'){
-                /* Lone dot! That's all, folks */
-                m->post=m->msg+i;
-                m->post_len=m->msg_len-i;
-                m->msg_len=j;
-                break;
-            } else if(m->msg[i+1]=='.'){
-                /* Escaping dot, eliminate. */
-                prev='.';
-                continue;
-            } /* Else an ordinary dot, drop down to ordinary char handler */
-        }
-        prev=m->msg[i];
-        m->msg[j++]=m->msg[i];
+    prev = '\n';
+    for (i = j = 0; i < m->msg_len; i++) {
+       if (prev == '\n' && m->msg[i] == '.') {
+           /* Dot at the beginning of a line */
+           if ((m->msg[i + 1] == '\r' && m->msg[i + 2] == '\n')
+               || m->msg[i + 1] == '\n') {
+               /* Lone dot! That's all, folks */
+               m->post = m->msg + i;
+               m->post_len = m->msg_len - i;
+               m->msg_len = j;
+               break;
+           }
+           else if (m->msg[i + 1] == '.') {
+               /* Escaping dot, eliminate. */
+               prev = '.';
+               continue;
+           }                   /* Else an ordinary dot, drop down to ordinary char handler */
+       }
+       prev = m->msg[i];
+       m->msg[j++] = m->msg[i];
     }
 
-    m->type=MESSAGE_BSMTP;
-    m->out=m->msg;
-    m->out_len=m->msg_len;
+    m->type = MESSAGE_BSMTP;
+    m->out = m->msg;
+    m->out_len = m->msg_len;
     return EX_OK;
 }
 
-int message_read(int fd, int flags, struct message *m){
+int message_read(int fd, int flags, struct message *m)
+{
     libspamc_timeout = 0;
 
     /* create the "private" part of the struct message */
-    m->priv = malloc (sizeof (struct libspamc_private_message));
+    m->priv = malloc(sizeof(struct libspamc_private_message));
     if (m->priv == NULL) {
-        syslog(LOG_ERR, "message_read: malloc failed");
-        return EX_OSERR;
+       libspamc_log(flags, LOG_ERR, "message_read: malloc failed");
+       return EX_OSERR;
     }
     m->priv->flags = flags;
 
-    switch(flags&SPAMC_MODE_MASK){
-      case SPAMC_RAW_MODE:
-        return message_read_raw(fd, m);
+    switch (flags & SPAMC_MODE_MASK) {
+    case SPAMC_RAW_MODE:
+       return _message_read_raw(fd, m);
 
-      case SPAMC_BSMTP_MODE:
-        return message_read_bsmtp(fd, m);
+    case SPAMC_BSMTP_MODE:
+       return _message_read_bsmtp(fd, m);
 
-      default:
-        syslog(LOG_ERR, "message_read: Unknown mode %d\n", flags&SPAMC_MODE_MASK);
-        return EX_USAGE;
+    default:
+       libspamc_log(flags, LOG_ERR, "message_read: Unknown mode %d",
+               flags & SPAMC_MODE_MASK);
+       return EX_USAGE;
     }
 }
 
-long message_write(int fd, struct message *m){
-    long total=0;
+long message_write(int fd, struct message *m)
+{
+    long total = 0;
     off_t i, j;
     off_t jlimit;
     char buffer[1024];
 
-    if (m->priv->flags&SPAMC_CHECK_ONLY) {
-       if(m->is_spam==EX_ISSPAM || m->is_spam==EX_NOTSPAM){
-           return full_write(fd, m->out, m->out_len);
+    if (m->priv->flags & SPAMC_CHECK_ONLY) {
+       if (m->is_spam == EX_ISSPAM || m->is_spam == EX_NOTSPAM) {
+           return full_write(fd, 1, m->out, m->out_len);
 
-       } else {
-           syslog(LOG_ERR, "oops! SPAMC_CHECK_ONLY is_spam: %d\n", m->is_spam);
+       }
+       else {
+           libspamc_log(m->priv->flags, LOG_ERR, "oops! SPAMC_CHECK_ONLY is_spam: %d",
+                        m->is_spam);
            return -1;
        }
     }
 
     /* else we're not in CHECK_ONLY mode */
-    switch(m->type){
-      case MESSAGE_NONE:
-        syslog(LOG_ERR, "Cannot write this message, it's MESSAGE_NONE!\n");
-        return -1;
-
-      case MESSAGE_ERROR:
-        return full_write(fd, m->raw, m->raw_len);
-
-      case MESSAGE_RAW:
-        return full_write(fd, m->out, m->out_len);
-
-      case MESSAGE_BSMTP:
-        total=full_write(fd, m->pre, m->pre_len);
-        for(i=0; i<m->out_len; ){
-           jlimit = (off_t) (sizeof(buffer)/sizeof(*buffer)-4);
-            for(j=0; i < (off_t) m->out_len &&
-                                j < jlimit;)
-            {
-                if(i+1<m->out_len && m->out[i]=='\n' && m->out[i+1]=='.'){
+    switch (m->type) {
+    case MESSAGE_NONE:
+       libspamc_log(m->priv->flags, LOG_ERR, "Cannot write this message, it's MESSAGE_NONE!");
+       return -1;
+
+    case MESSAGE_ERROR:
+       return full_write(fd, 1, m->raw, m->raw_len);
+
+    case MESSAGE_RAW:
+       return full_write(fd, 1, m->out, m->out_len);
+
+    case MESSAGE_BSMTP:
+       total = full_write(fd, 1, m->pre, m->pre_len);
+       for (i = 0; i < m->out_len;) {
+           jlimit = (off_t) (sizeof(buffer) / sizeof(*buffer) - 4);
+           for (j = 0; i < (off_t) m->out_len && j < jlimit;) {
+               if (i + 1 < m->out_len && m->out[i] == '\n'
+                   && m->out[i + 1] == '.') {
                    if (j > jlimit - 4) {
-                       break;          /* avoid overflow */
+                       break;  /* avoid overflow */
                    }
-                    buffer[j++]=m->out[i++];
-                    buffer[j++]=m->out[i++];
-                    buffer[j++]='.';
-                } else {
-                    buffer[j++]=m->out[i++];
-                }
-            }
-            total+=full_write(fd, buffer, j);
-        }
-        return total+full_write(fd, m->post, m->post_len);
-
-      default:
-        syslog(LOG_ERR, "Unknown message type %d\n", m->type);
-        return -1;
+                   buffer[j++] = m->out[i++];
+                   buffer[j++] = m->out[i++];
+                   buffer[j++] = '.';
+               }
+               else {
+                   buffer[j++] = m->out[i++];
+               }
+           }
+           total += full_write(fd, 1, buffer, j);
+       }
+       return total + full_write(fd, 1, m->post, m->post_len);
+
+    default:
+       libspamc_log(m->priv->flags, LOG_ERR, "Unknown message type %d", m->type);
+       return -1;
     }
 }
 
-void message_dump(int in_fd, int out_fd, struct message *m){
+void message_dump(int in_fd, int out_fd, struct message *m)
+{
     char buf[8196];
     int bytes;
-    
-    if(m!=NULL && m->type!=MESSAGE_NONE) {
-        message_write(out_fd, m);
+
+    if (m != NULL && m->type != MESSAGE_NONE) {
+       message_write(out_fd, m);
     }
-    while((bytes=full_read(in_fd, buf, 8192, 8192))>0){
-        if (bytes!=full_write(out_fd, buf, bytes)) {
-            syslog(LOG_ERR, "oops! message_dump of %d returned different", bytes);
-        }
+    while ((bytes = full_read(in_fd, 1, buf, 8192, 8192)) > 0) {
+       if (bytes != full_write(out_fd, 1, buf, bytes)) {
+           libspamc_log(m->priv->flags, LOG_ERR, "oops! message_dump of %d returned different",
+                  bytes);
+       }
     }
 }
 
 static int
-_spamc_read_full_line (struct message *m, int flags, SSL *ssl, int sock,
-               char *buf, int *lenp, int bufsiz)
+_spamc_read_full_line(struct message *m, int flags, SSL * ssl, int sock,
+                     char *buf, size_t *lenp, size_t bufsiz)
 {
     int failureval;
     int bytesread = 0;
-    int len;
+    size_t len;
 
     UNUSED_VARIABLE(m);
 
+    *lenp = 0;
     /* Now, read from spamd */
-    for(len=0; len<bufsiz-1; len++) {
-       if(flags&SPAMC_USE_SSL) {
-         bytesread = ssl_timeout_read (ssl, buf+len, 1);
-       } else {
-         bytesread = fd_timeout_read (sock, buf+len, 1);
+    for (len = 0; len < bufsiz - 1; len++) {
+       if (flags & SPAMC_USE_SSL) {
+           bytesread = ssl_timeout_read(ssl, buf + len, 1);
+       }
+       else {
+           bytesread = fd_timeout_read(sock, 0, buf + len, 1);
+       }
+
+       if (bytesread <= 0) {
+           failureval = EX_IOERR;
+           goto failure;
        }
 
-        if(buf[len]=='\n') {
-            buf[len]='\0';
-           if (len > 0 && buf[len-1] == '\r') {
+       if (buf[len] == '\n') {
+           buf[len] = '\0';
+           if (len > 0 && buf[len - 1] == '\r') {
                len--;
-               buf[len]='\0';
+               buf[len] = '\0';
            }
            *lenp = len;
            return EX_OK;
        }
-
-        if(bytesread<=0){
-           failureval = EX_IOERR; goto failure;
-        }
     }
 
-    syslog(LOG_ERR, "spamd responded with line of %d bytes, dying", len);
+    libspamc_log(flags, LOG_ERR, "spamd responded with line of %d bytes, dying", len);
     failureval = EX_TOOBIG;
 
-failure:
+  failure:
     return failureval;
 }
 
@@ -855,58 +690,67 @@ failure:
  * May  7 2003 jm: using %f is bad where LC_NUMERIC is "," in the locale.
  * work around using our own locale-independent float-parser code.
  */
-static float
-_locale_safe_string_to_float (char *buf, int siz)
+static float _locale_safe_string_to_float(char *buf, int siz)
 {
-  int is_neg;
-  char *cp, *dot;
-  int divider;
-  float ret, postdot;
-
-  buf[siz-1] = '\0';   /* ensure termination */
-
-  /* ok, let's illustrate using "100.033" as an example... */
-  
-  is_neg = 0;
-  if (*buf == '-') { is_neg = 1; }
-
-  ret = (float) (strtol (buf, &dot, 10));
-  if (dot == NULL) { return 0.0; }
-  if (dot != NULL && *dot != '.') { return ret; }
-
-  /* ex: ret == 100.0 */
-
-  cp = (dot + 1);
-  postdot = (float) (strtol (cp, NULL, 10));
-  if (postdot == 0.0) { return ret; }
-
-  /* ex: postdot == 33.0, cp="033" */
-
-  /* now count the number of decimal places and figure out what power of 10 to use */
-  divider = 1;
-  while (*cp != '\0') {
-    divider *= 10; cp++;
-  }
-
-  /* ex:
-   * cp="033", divider=1
-   * cp="33", divider=10
-   * cp="3", divider=100
-   * cp="", divider=1000
-   */
-
-  if (is_neg) {
-    ret -= (postdot / ((float) divider));
-  } else {
-    ret += (postdot / ((float) divider));
-  }
-  /* ex: ret == 100.033, tada! ... hopefully */
-
-  return ret;
+    int is_neg;
+    char *cp, *dot;
+    int divider;
+    float ret, postdot;
+
+    buf[siz - 1] = '\0';       /* ensure termination */
+
+    /* ok, let's illustrate using "100.033" as an example... */
+
+    is_neg = 0;
+    if (*buf == '-') {
+       is_neg = 1;
+    }
+
+    ret = (float) (strtol(buf, &dot, 10));
+    if (dot == NULL) {
+       return 0.0;
+    }
+    if (dot != NULL && *dot != '.') {
+       return ret;
+    }
+
+    /* ex: ret == 100.0 */
+
+    cp = (dot + 1);
+    postdot = (float) (strtol(cp, NULL, 10));
+    if (postdot == 0.0) {
+       return ret;
+    }
+
+    /* ex: postdot == 33.0, cp="033" */
+
+    /* now count the number of decimal places and figure out what power of 10 to use */
+    divider = 1;
+    while (*cp != '\0') {
+       divider *= 10;
+       cp++;
+    }
+
+    /* ex:
+     * cp="033", divider=1
+     * cp="33", divider=10
+     * cp="3", divider=100
+     * cp="", divider=1000
+     */
+
+    if (is_neg) {
+       ret -= (postdot / ((float) divider));
+    }
+    else {
+       ret += (postdot / ((float) divider));
+    }
+    /* ex: ret == 100.033, tada! ... hopefully */
+
+    return ret;
 }
 
 static int
-_handle_spamd_header (struct message *m, int flags, char *buf, int len)
+_handle_spamd_header(struct message *m, int flags, char *buf, int len)
 {
     char is_spam[6];
     char s_str[21], t_str[21];
@@ -918,278 +762,352 @@ _handle_spamd_header (struct message *m, int flags, char *buf, int len)
      * May  7 2003 jm: using %f is bad where LC_NUMERIC is "," in the locale.
      * work around using our own locale-independent float-parser code.
      */
-    if (sscanf(buf, "Spam: %5s ; %20s / %20s", is_spam, s_str, t_str) == 3)
-    {
-       m->score = _locale_safe_string_to_float (s_str, 20);
-       m->threshold = _locale_safe_string_to_float (t_str, 20);
+    if (sscanf(buf, "Spam: %5s ; %20s / %20s", is_spam, s_str, t_str) == 3) {
+       m->score = _locale_safe_string_to_float(s_str, 20);
+       m->threshold = _locale_safe_string_to_float(t_str, 20);
+
+       /* set bounds on these to ensure no buffer overflow in the sprintf */
+       if (m->score > 1e10)
+           m->score = 1e10;
+       else if (m->score < -1e10)
+           m->score = -1e10;
+       if (m->threshold > 1e10)
+           m->threshold = 1e10;
+       else if (m->threshold < -1e10)
+           m->threshold = -1e10;
 
        /* Format is "Spam: x; y / x" */
-       m->is_spam=strcasecmp("true", is_spam) == 0 ? EX_ISSPAM: EX_NOTSPAM;
+       m->is_spam =
+           strcasecmp("true", is_spam) == 0 ? EX_ISSPAM : EX_NOTSPAM;
 
-       if(flags&SPAMC_CHECK_ONLY) {
-           m->out_len=snprintf (m->out, m->max_len+EXPANSION_ALLOWANCE,
-                       "%.1f/%.1f\n", m->score, m->threshold);
+       if (flags & SPAMC_CHECK_ONLY) {
+           m->out_len = sprintf(m->out,
+                                "%.1f/%.1f\n", m->score, m->threshold);
        }
        else if ((flags & SPAMC_REPORT_IFSPAM && m->is_spam == EX_ISSPAM)
-               || (flags & SPAMC_REPORT))
-       {
-           m->out_len=snprintf (m->out, m->max_len+EXPANSION_ALLOWANCE,
-                       "%.1f/%.1f\n", m->score, m->threshold);
+                || (flags & SPAMC_REPORT)) {
+           m->out_len = sprintf(m->out,
+                                "%.1f/%.1f\n", m->score, m->threshold);
        }
        return EX_OK;
 
-    } else if(sscanf(buf, "Content-length: %d", &m->content_length) == 1) {
+    }
+    else if (sscanf(buf, "Content-length: %d", &m->content_length) == 1) {
        if (m->content_length < 0) {
-           syslog(LOG_ERR, "spamd responded with bad Content-length '%s'", buf);
+           libspamc_log(flags, LOG_ERR, "spamd responded with bad Content-length '%s'",
+                  buf);
            return EX_PROTOCOL;
        }
        return EX_OK;
     }
 
-    syslog(LOG_ERR, "spamd responded with bad header '%s'", buf);
+    libspamc_log(flags, LOG_ERR, "spamd responded with bad header '%s'", buf);
     return EX_PROTOCOL;
 }
 
 int message_filter(struct transport *tp, const char *username,
-                int flags, struct message *m)
+                  int flags, struct message *m)
 {
     char buf[8192];
-    int bufsiz = (sizeof(buf) / sizeof(*buf)) - 4; /* bit of breathing room */
-    int len, i;
+    size_t bufsiz = (sizeof(buf) / sizeof(*buf)) - 4; /* bit of breathing room */
+    size_t len;
     int sock = -1;
     int rc;
     char versbuf[20];
     float version;
     int response;
     int failureval;
-    SSL_CTX* ctx;
-    SSL* ssl;
+    SSL_CTX *ctx = NULL;
+    SSL *ssl = NULL;
     SSL_METHOD *meth;
 
-    if (flags&SPAMC_USE_SSL) {
+    if (flags & SPAMC_USE_SSL) {
 #ifdef SPAMC_SSL
-      SSLeay_add_ssl_algorithms();
-      meth = SSLv2_client_method();
-      SSL_load_error_strings();
-      ctx = SSL_CTX_new(meth);
+       SSLeay_add_ssl_algorithms();
+       meth = SSLv2_client_method();
+       SSL_load_error_strings();
+       ctx = SSL_CTX_new(meth);
 #else
-      UNUSED_VARIABLE(ssl);
-      UNUSED_VARIABLE(meth);
-      UNUSED_VARIABLE(ctx);
-      syslog(LOG_ERR, "spamc not built with SSL support");
-      return EX_SOFTWARE;
+       UNUSED_VARIABLE(ssl);
+       UNUSED_VARIABLE(meth);
+       UNUSED_VARIABLE(ctx);
+       libspamc_log(flags, LOG_ERR, "spamc not built with SSL support");
+       return EX_SOFTWARE;
 #endif
-    }    
+    }
 
-    m->is_spam=EX_TOOBIG;
-    if((m->out=malloc(m->max_len+EXPANSION_ALLOWANCE+1))==NULL){
-        failureval = EX_OSERR; goto failure;
+    m->is_spam = EX_TOOBIG;
+    if ((m->out = malloc(m->max_len + EXPANSION_ALLOWANCE + 1)) == NULL) {
+       failureval = EX_OSERR;
+       goto failure;
     }
-    m->out_len=0;
+    m->out_len = 0;
 
 
     /* Build spamd protocol header */
-    if(flags & SPAMC_CHECK_ONLY) 
-      len=snprintf(buf, bufsiz, "CHECK %s\r\n", PROTOCOL_VERSION);
-    else if(flags & SPAMC_REPORT_IFSPAM)
-      len=snprintf(buf, bufsiz, "REPORT_IFSPAM %s\r\n", PROTOCOL_VERSION);
-    else if(flags & SPAMC_REPORT) 
-      len=snprintf(buf, bufsiz, "REPORT %s\r\n", PROTOCOL_VERSION);
-    else if(flags & SPAMC_SYMBOLS) 
-      len=snprintf(buf, bufsiz, "SYMBOLS %s\r\n", PROTOCOL_VERSION);
+    if (flags & SPAMC_CHECK_ONLY)
+       strcpy(buf, "CHECK ");
+    else if (flags & SPAMC_REPORT_IFSPAM)
+       strcpy(buf, "REPORT_IFSPAM ");
+    else if (flags & SPAMC_REPORT)
+       strcpy(buf, "REPORT ");
+    else if (flags & SPAMC_SYMBOLS)
+       strcpy(buf, "SYMBOLS ");
     else
-      len=snprintf(buf, bufsiz, "PROCESS %s\r\n", PROTOCOL_VERSION);
+       strcpy(buf, "PROCESS ");
+
+    len = strlen(buf);
+    if (len + strlen(PROTOCOL_VERSION) + 2 >= bufsiz) {
+       free(m->out);
+       m->out = m->msg;
+       m->out_len = m->msg_len;
+       return EX_OSERR;
+    }
+
+    strcat(buf, PROTOCOL_VERSION);
+    strcat(buf, "\r\n");
+    len = strlen(buf);
 
-    if(len<0 || len >= bufsiz){ free(m->out); m->out=m->msg; m->out_len=m->msg_len; return EX_OSERR; }
-    if(username!=NULL){
-        len+=i=snprintf(buf+len, bufsiz-len, "User: %s\r\n", username);
-        if(i<0 || len >= bufsiz){ free(m->out); m->out=m->msg; m->out_len=m->msg_len; return EX_OSERR; }
+    if (username != NULL) {
+       if (strlen(username) + 8 >= (bufsiz - len)) {
+           free(m->out);
+           m->out = m->msg;
+           m->out_len = m->msg_len;
+           return EX_OSERR;
+       }
+       strcpy(buf + len, "User: ");
+       strcat(buf + len, username);
+       strcat(buf + len, "\r\n");
+       len += strlen(buf + len);
+    }
+    if ((m->msg_len > 9999999) || ((len + 27) >= (bufsiz - len))) {
+       free(m->out);
+       m->out = m->msg;
+       m->out_len = m->msg_len;
+       return EX_OSERR;
     }
-    len+=i=snprintf(buf+len, bufsiz-len, "Content-length: %d\r\n", m->msg_len);
-    if(i<0 || len >= bufsiz){ free(m->out); m->out=m->msg; m->out_len=m->msg_len; return EX_OSERR; }
-    len+=i=snprintf(buf+len, bufsiz-len, "\r\n");
-    if(i<0 || len >= bufsiz){ free(m->out); m->out=m->msg; m->out_len=m->msg_len; return EX_OSERR; }
+    len += sprintf(buf + len, "Content-length: %d\r\n\r\n", m->msg_len);
 
     libspamc_timeout = m->timeout;
 
-    if ( tp->socketpath )
-        rc = try_to_connect_unix(tp, &sock);
+    if (tp->socketpath)
+       rc = _try_to_connect_unix(tp, &sock);
     else
-        rc = try_to_connect_tcp(tp, &sock);
+       rc = _try_to_connect_tcp(tp, &sock);
 
-    if ( rc != EX_OK )
-    {
-        free(m->out); m->out=m->msg; m->out_len=m->msg_len;
-        return i;
+    if (rc != EX_OK) {
+       free(m->out);
+       m->out = m->msg;
+       m->out_len = m->msg_len;
+       return rc;      /* use the error code try_to_connect_*() gave us. */
     }
 
-    if(flags&SPAMC_USE_SSL) {
+    if (flags & SPAMC_USE_SSL) {
 #ifdef SPAMC_SSL
-      ssl = SSL_new(ctx);
-      SSL_set_fd(ssl, sock);
-      SSL_connect(ssl);
-#endif    
+       ssl = SSL_new(ctx);
+       SSL_set_fd(ssl, sock);
+       SSL_connect(ssl);
+#endif
     }
 
     /* Send to spamd */
-    if(flags&SPAMC_USE_SSL) {
+    if (flags & SPAMC_USE_SSL) {
 #ifdef SPAMC_SSL
-      SSL_write(ssl, buf, len);
-      SSL_write(ssl, m->msg, m->msg_len);
+       SSL_write(ssl, buf, len);
+       SSL_write(ssl, m->msg, m->msg_len);
 #endif
-    } else {
-      full_write(sock, buf, len);
-      full_write(sock, m->msg, m->msg_len);
-      shutdown(sock, SHUT_WR);
+    }
+    else {
+       full_write(sock, 0, buf, len);
+       full_write(sock, 0, m->msg, m->msg_len);
+       shutdown(sock, SHUT_WR);
     }
 
     /* ok, now read and parse it.  SPAMD/1.2 line first... */
-    failureval = _spamc_read_full_line (m, flags, ssl, sock, buf, &len, bufsiz);
-    if (failureval != EX_OK) { goto failure; }
+    failureval =
+       _spamc_read_full_line(m, flags, ssl, sock, buf, &len, bufsiz);
+    if (failureval != EX_OK) {
+       goto failure;
+    }
 
-    if(sscanf(buf, "SPAMD/%18s %d %*s", versbuf, &response)!=2) {
-       syslog(LOG_ERR, "spamd responded with bad string '%s'", buf);
-       failureval = EX_PROTOCOL; goto failure;
+    if (sscanf(buf, "SPAMD/%18s %d %*s", versbuf, &response) != 2) {
+       libspamc_log(flags, LOG_ERR, "spamd responded with bad string '%s'", buf);
+       failureval = EX_PROTOCOL;
+       goto failure;
     }
 
     versbuf[19] = '\0';
-    version = _locale_safe_string_to_float (versbuf, 20);
+    version = _locale_safe_string_to_float(versbuf, 20);
     if (version < 1.0) {
-       syslog(LOG_ERR, "spamd responded with bad version string '%s'", versbuf);
-       failureval = EX_PROTOCOL; goto failure;
+       libspamc_log(flags, LOG_ERR, "spamd responded with bad version string '%s'",
+              versbuf);
+       failureval = EX_PROTOCOL;
+       goto failure;
     }
 
     m->score = 0;
     m->threshold = 0;
     m->is_spam = EX_TOOBIG;
     while (1) {
-       failureval = _spamc_read_full_line (m, flags, ssl, sock, buf, &len, bufsiz);
-       if (failureval != EX_OK) { goto failure; }
+       failureval =
+           _spamc_read_full_line(m, flags, ssl, sock, buf, &len, bufsiz);
+       if (failureval != EX_OK) {
+           goto failure;
+       }
 
        if (len == 0 && buf[0] == '\0') {
-           break;      /* end of headers */
+           break;              /* end of headers */
        }
 
        if (_handle_spamd_header(m, flags, buf, len) < 0) {
-           failureval = EX_PROTOCOL; goto failure;
+           failureval = EX_PROTOCOL;
+           goto failure;
        }
     }
 
-    len = 0;           /* overwrite those headers */
+    len = 0;                   /* overwrite those headers */
 
-    if (flags&SPAMC_CHECK_ONLY) {
-       close(sock); sock = -1;
+    if (flags & SPAMC_CHECK_ONLY) {
+       closesocket(sock);
+       sock = -1;
        if (m->is_spam == EX_TOOBIG) {
-             /* We should have gotten headers back... Damnit. */
-             failureval = EX_PROTOCOL; goto failure;
+           /* We should have gotten headers back... Damnit. */
+           failureval = EX_PROTOCOL;
+           goto failure;
        }
        return EX_OK;
     }
     else {
        if (m->content_length < 0) {
            /* should have got a length too. */
-           failureval = EX_PROTOCOL; goto failure;
+           failureval = EX_PROTOCOL;
+           goto failure;
        }
 
        /* have we already got something in the buffer (e.g. REPORT and
-         * REPORT_IFSPAM both create a line from the "Spam:" hdr)?  If
+        * REPORT_IFSPAM both create a line from the "Spam:" hdr)?  If
         * so, add the size of that so our sanity check passes.
         */
        if (m->out_len > 0) {
            m->content_length += m->out_len;
        }
 
-       if (flags&SPAMC_USE_SSL) {
-         len = full_read_ssl (ssl, (unsigned char *) m->out+m->out_len,
-                    m->max_len+EXPANSION_ALLOWANCE+1-m->out_len,
-                    m->max_len+EXPANSION_ALLOWANCE+1-m->out_len);
-       } else{
-         len = full_read (sock, m->out+m->out_len,
-                    m->max_len+EXPANSION_ALLOWANCE+1-m->out_len,
-                    m->max_len+EXPANSION_ALLOWANCE+1-m->out_len);
+       if (flags & SPAMC_USE_SSL) {
+           len = full_read_ssl(ssl, (unsigned char *) m->out + m->out_len,
+                               m->max_len + EXPANSION_ALLOWANCE + 1 -
+                               m->out_len,
+                               m->max_len + EXPANSION_ALLOWANCE + 1 -
+                               m->out_len);
+       }
+       else {
+           len = full_read(sock, 0, m->out + m->out_len,
+                           m->max_len + EXPANSION_ALLOWANCE + 1 - m->out_len,
+                           m->max_len + EXPANSION_ALLOWANCE + 1 -
+                           m->out_len);
        }
 
 
-       if(len+m->out_len>m->max_len+EXPANSION_ALLOWANCE){
-           failureval = EX_TOOBIG; goto failure;
+       if (len + m->out_len > m->max_len + EXPANSION_ALLOWANCE) {
+           failureval = EX_TOOBIG;
+           goto failure;
        }
-       m->out_len+=len;
+       m->out_len += len;
 
        shutdown(sock, SHUT_RD);
-       close(sock); sock = -1;
+       closesocket(sock);
+       sock = -1;
     }
     libspamc_timeout = 0;
 
-    if(m->out_len!=m->content_length) {
-        syslog(LOG_ERR, "failed sanity check, %d bytes claimed, %d bytes seen",
-                               m->content_length, m->out_len);
-       failureval = EX_PROTOCOL; goto failure;
+    if (m->out_len != m->content_length) {
+       libspamc_log(flags, LOG_ERR,
+              "failed sanity check, %d bytes claimed, %d bytes seen",
+              m->content_length, m->out_len);
+       failureval = EX_PROTOCOL;
+       goto failure;
     }
 
     return EX_OK;
 
-failure:
-    free(m->out); m->out=m->msg; m->out_len=m->msg_len;
+  failure:
+    free(m->out);
+    m->out = m->msg;
+    m->out_len = m->msg_len;
     if (sock != -1) {
-      close(sock);
+       closesocket(sock);
     }
     libspamc_timeout = 0;
 
-    if(flags&SPAMC_USE_SSL) {
+    if (flags & SPAMC_USE_SSL) {
 #ifdef SPAMC_SSL
-      SSL_free(ssl);
-      SSL_CTX_free(ctx);
+       SSL_free(ssl);
+       SSL_CTX_free(ctx);
 #endif
     }
     return failureval;
 }
 
 
-int message_process(struct transport *trans, char *username, int max_size, int in_fd, int out_fd, const int flags){
+int message_process(struct transport *trans, char *username, int max_size,
+                   int in_fd, int out_fd, const int flags)
+{
     int ret;
     struct message m;
 
-    m.type=MESSAGE_NONE;
-
-    m.max_len=max_size;
-    ret=message_read(in_fd, flags, &m);
-    if(ret!=EX_OK) goto FAIL;
-    ret=message_filter(trans, username, flags, &m);
-    if(ret!=EX_OK) goto FAIL;
-    if(message_write(out_fd, &m)<0) goto FAIL;
-    if(m.is_spam!=EX_TOOBIG) {
-       message_cleanup(&m);
-       return m.is_spam;
+    m.type = MESSAGE_NONE;
+
+    m.max_len = max_size;
+    ret = message_read(in_fd, flags, &m);
+    if (ret != EX_OK)
+       goto FAIL;
+    ret = message_filter(trans, username, flags, &m);
+    if (ret != EX_OK)
+       goto FAIL;
+    if (message_write(out_fd, &m) < 0)
+       goto FAIL;
+    if (m.is_spam != EX_TOOBIG) {
+       message_cleanup(&m);
+       return m.is_spam;
     }
     message_cleanup(&m);
     return ret;
 
-FAIL:
-   if(flags&SPAMC_CHECK_ONLY){
-       full_write(out_fd, "0/0\n", 4);
-       message_cleanup(&m);
-       return EX_NOTSPAM;
-   } else {
-       message_dump(in_fd, out_fd, &m);
-       message_cleanup(&m);
-       return ret;
+  FAIL:
+    if (flags & SPAMC_CHECK_ONLY) {
+       full_write(out_fd, 1, "0/0\n", 4);
+       message_cleanup(&m);
+       return EX_NOTSPAM;
+    }
+    else {
+       message_dump(in_fd, out_fd, &m);
+       message_cleanup(&m);
+       return ret;
     }
 }
 
-void message_cleanup(struct message *m) {
-   if (m->out != NULL && m->out != m->raw) free(m->out);
-   if (m->raw != NULL) free(m->raw);
-   if (m->priv != NULL) free(m->priv);
-   clear_message(m);
+void message_cleanup(struct message *m)
+{
+    if (m->out != NULL && m->pre != NULL && m->out != m->pre+m->pre_len)
+       free(m->out);
+    if (m->raw != NULL)
+       free(m->raw);
+    if (m->priv != NULL)
+       free(m->priv);
+    _clear_message(m);
 }
 
 /* Aug 14, 2002 bj: Obsolete! */
-int process_message(struct transport *tp, char *username, int max_size, int in_fd, int out_fd, const int my_check_only, const int my_safe_fallback){
+int process_message(struct transport *tp, char *username, int max_size,
+                   int in_fd, int out_fd, const int my_check_only,
+                   const int my_safe_fallback)
+{
     int flags;
 
-    flags=SPAMC_RAW_MODE;
-    if(my_check_only) flags|=SPAMC_CHECK_ONLY;
-    if(my_safe_fallback) flags|=SPAMC_SAFE_FALLBACK;
+    flags = SPAMC_RAW_MODE;
+    if (my_check_only)
+       flags |= SPAMC_CHECK_ONLY;
+    if (my_safe_fallback)
+       flags |= SPAMC_SAFE_FALLBACK;
 
     return message_process(tp, username, max_size, in_fd, out_fd, flags);
 }
@@ -1202,12 +1120,13 @@ int process_message(struct transport *tp, char *username, int max_size, int in_f
  */
 void transport_init(struct transport *tp)
 {
-       assert(tp != 0);
+    assert(tp != 0);
 
-       memset(tp, 0, sizeof *tp);
+    memset(tp, 0, sizeof *tp);
 
-       tp->type = TRANSPORT_LOCALHOST;
-       tp->port = 783;
+    tp->type = TRANSPORT_LOCALHOST;
+    tp->port = 783;
+    tp->flags = 0;
 }
 
 /*
@@ -1220,26 +1139,26 @@ void transport_init(struct transport *tp)
  *     do anything unless 
  */
 
-static void randomize_hosts(struct transport *tp)
+static void _randomize_hosts(struct transport *tp)
 {
-int     rnum;
+    int rnum;
 
-       assert(tp != 0);
+    assert(tp != 0);
 
-       if ( tp->nhosts <= 1 ) return;
+    if (tp->nhosts <= 1)
+       return;
 
-       rnum = rand() % tp->nhosts;
+    rnum = rand() % tp->nhosts;
 
-       while ( rnum-- > 0 )
-       {
-       struct in_addr  tmp = tp->hosts[0];
-       int             i;
+    while (rnum-- > 0) {
+       struct in_addr tmp = tp->hosts[0];
+       int i;
 
-               for (i = 1; i < tp->nhosts; i++ )
-                       tp->hosts[i-1] = tp->hosts[i];
+       for (i = 1; i < tp->nhosts; i++)
+           tp->hosts[i - 1] = tp->hosts[i];
 
-               tp->hosts[i-1] = tmp;
-       }
+       tp->hosts[i - 1] = tmp;
+    }
 }
 
 /*
@@ -1259,59 +1178,68 @@ int     rnum;
  */
 int transport_setup(struct transport *tp, int flags)
 {
-struct hostent *hp = 0;
-char           **addrp;
-
-       assert(tp != 0);
-
-       switch ( tp->type )
-       {
-         case TRANSPORT_UNIX:
-               assert(tp->socketpath != 0);
-               return EX_OK;
-
-         case TRANSPORT_LOCALHOST:
-               tp->hosts[0].s_addr = inet_addr("127.0.0.1");
-               tp->nhosts          = 1;
-               return EX_OK;
-
-         case TRANSPORT_TCP:
-               if (NULL == (hp = gethostbyname(tp->hostname)))
-               {
-               int     origherr = h_errno;  /* take a copy before syslog() */
-
-                       syslog (LOG_ERR, "gethostbyname(%s) failed: h_errno=%d",
-                               tp->hostname, origherr);
-                       switch (origherr)
-                       {
-                         case HOST_NOT_FOUND:
-                         case NO_ADDRESS:
-                         case NO_RECOVERY:
-                               return EX_NOHOST;
-                         case TRY_AGAIN:
-                               return EX_TEMPFAIL;
-                         default:
-                               return EX_OSERR;
-                       }
-               }
+    struct hostent *hp = 0;
+    char **addrp;
+
+#ifdef _WIN32
+    // Start Winsock up
+    WSADATA wsaData;
+    int nCode;
+    if ((nCode = WSAStartup(MAKEWORD(1, 1), &wsaData)) != 0) {
+       printf("WSAStartup() returned error code %d\n", nCode);
+       return EX_OSERR;
+    }
+
+#endif
+
+    tp->flags = flags;
+
+    assert(tp != 0);
+
+    switch (tp->type) {
+#ifndef _WIN32
+    case TRANSPORT_UNIX:
+       assert(tp->socketpath != 0);
+       return EX_OK;
+#endif
+    case TRANSPORT_LOCALHOST:
+       tp->hosts[0].s_addr = inet_addr("127.0.0.1");
+       tp->nhosts = 1;
+       return EX_OK;
+
+    case TRANSPORT_TCP:
+       if (NULL == (hp = gethostbyname(tp->hostname))) {
+           int origherr = h_errno;     /* take a copy before syslog() */
+
+           libspamc_log(flags, LOG_ERR, "gethostbyname(%s) failed: h_errno=%d",
+                   tp->hostname, origherr);
+           switch (origherr) {
+           case HOST_NOT_FOUND:
+           case NO_ADDRESS:
+           case NO_RECOVERY:
+               return EX_NOHOST;
+           case TRY_AGAIN:
+               return EX_TEMPFAIL;
+           default:
+               return EX_OSERR;
+           }
+       }
 
                /*--------------------------------------------------------
                 * If we have no hosts at all, or if they are some other
                 * kind of address family besides IPv4, then we really
                 * just have no hosts at all.
                 */
-               if ( hp->h_addr_list[0] == 0 )
-               {
-                       /* no hosts in this list */
-                       return EX_NOHOST;
-               }
+       if (hp->h_addr_list[0] == 0) {
+           /* no hosts in this list */
+           return EX_NOHOST;
+       }
 
-               if ( hp->h_length   != sizeof tp->hosts[0]
-                 || hp->h_addrtype != AF_INET )
-               {
-                       /* FAIL - bad size/protocol/family? */
-                       return EX_NOHOST;
-               }
+       if (hp->h_length != sizeof tp->hosts[0]
+           || hp->h_addrtype != AF_INET) {
+           /* FAIL - bad size/protocol/family? */
+           return EX_NOHOST;
+       }
 
                /*--------------------------------------------------------
                 * Copy all the IP addresses into our private structure.
@@ -1319,20 +1247,19 @@ char           **addrp;
                 * means we won't ever walk all over the list with other
                 * calls.
                 */
-               tp->nhosts = 0;
+       tp->nhosts = 0;
 
-               for (addrp = hp->h_addr_list; *addrp; addrp++)
-               {
-                       if (tp->nhosts >= TRANSPORT_MAX_HOSTS-1) {
-                               syslog (LOG_ERR, "hit limit of %d hosts, ignoring remainder", TRANSPORT_MAX_HOSTS-1);
-                               break;
-                       }
+       for (addrp = hp->h_addr_list; *addrp; addrp++) {
+           if (tp->nhosts >= TRANSPORT_MAX_HOSTS - 1) {
+               libspamc_log(flags, LOG_ERR, "hit limit of %d hosts, ignoring remainder",
+                      TRANSPORT_MAX_HOSTS - 1);
+               break;
+           }
 
-                       memcpy(&tp->hosts[tp->nhosts], *addrp,
-                               sizeof tp->hosts[0]);
+           memcpy(&tp->hosts[tp->nhosts], *addrp, sizeof tp->hosts[0]);
 
-                       tp->nhosts++;
-               }
+           tp->nhosts++;
+       }
 
                /*--------------------------------------------------------
                 * QUASI-LOAD-BALANCING
@@ -1342,25 +1269,61 @@ char           **addrp;
                 * This may later be truncated to a single item. This is
                 * meaningful only if we have more than one host.
                 */
-               if ( (flags & SPAMC_RANDOMIZE_HOSTS)  &&  tp->nhosts > 1 )
-               {
-                       randomize_hosts(tp);
-               }
+       if ((flags & SPAMC_RANDOMIZE_HOSTS) && tp->nhosts > 1) {
+           _randomize_hosts(tp);
+       }
 
                /*--------------------------------------------------------
                 * If the user wants no fallback, simply truncate the host
                 * list to just one - this pretends that this is the extent
                 * of our connection list - then it's not a special case.
                 */
-               if ( !(flags & SPAMC_SAFE_FALLBACK)  &&  tp->nhosts > 1 )
-               {
-                       /* truncating list */
-                       tp->nhosts = 1;
-               }
+       if (!(flags & SPAMC_SAFE_FALLBACK) && tp->nhosts > 1) {
+           /* truncating list */
+           tp->nhosts = 1;
        }
-       return EX_OK;
+    }
+    return EX_OK;
 }
 
+/* --------------------------------------------------------------------------- */
+
+#define LOG_BUFSIZ      1023
+
+void
+libspamc_log (int flags, int level, char *msg, ...)
+{
+    va_list ap;
+    char buf[LOG_BUFSIZ+1];
+    int len = 0;
+
+    va_start(ap, msg);
+
+    if ((flags & SPAMC_LOG_TO_STDERR) != 0) {
+        // create a log-line buffer
+        len = snprintf(buf, LOG_BUFSIZ, "spamc: ");
+        len += vsnprintf(buf+len, LOG_BUFSIZ-len, msg, ap);
+
+        // avoid buffer overflow
+        if (len > (LOG_BUFSIZ-2)) { len = (LOG_BUFSIZ-3); }
+
+        len += snprintf(buf+len, LOG_BUFSIZ-len, "\n");
+        buf[LOG_BUFSIZ] = '\0';     /* ensure termination */
+        (void) write (2, buf, len);
+
+    } else {
+        vsnprintf(buf, LOG_BUFSIZ, msg, ap);
+        buf[LOG_BUFSIZ] = '\0';     /* ensure termination */
+#ifndef _WIN32
+        syslog (level, "%s", buf);
+#else
+        (void) level;  /* not used. suppress compiler warning */
+        fprintf (stderr, "%s\n", buf);
+#endif
+    }
+
+    va_end(ap);
+}
 
 /* --------------------------------------------------------------------------- */
 
@@ -1373,52 +1336,57 @@ char           **addrp;
  */
 #ifdef LIBSPAMC_UNIT_TESTS
 
-static void
-_test_locale_safe_string_to_float_val (float input) {
-  char inputstr[99], cmpbuf1[99], cmpbuf2[99];
-  float output;
-
-  snprintf (inputstr, 99, "%f", input);
-  output = _locale_safe_string_to_float (inputstr, 99);
-  if (input == output) { return; }
+static void _test_locale_safe_string_to_float_val(float input)
+{
+    char inputstr[99], cmpbuf1[99], cmpbuf2[99];
+    float output;
+
+    /* sprintf instead of snprintf is safe here because it is only a controlled test */
+    sprintf(inputstr, "%f", input);
+    output = _locale_safe_string_to_float(inputstr, 99);
+    if (input == output) {
+       return;
+    }
 
-  /* could be a rounding error.  print as string and compare those */
-  snprintf (cmpbuf1, 98, "%f", input);
-  snprintf (cmpbuf2, 98, "%f", output);
-  if (!strcmp (cmpbuf1, cmpbuf2)) { return; }
+    /* could be a rounding error.  print as string and compare those */
+    sprintf(cmpbuf1, "%f", input);
+    sprintf(cmpbuf2, "%f", output);
+    if (!strcmp(cmpbuf1, cmpbuf2)) {
+       return;
+    }
 
-  printf ("FAIL: input=%f != output=%f\n", input, output);
+    printf("FAIL: input=%f != output=%f\n", input, output);
 }
 
-static void
-unit_test_locale_safe_string_to_float (void) {
-  float statictestset[] = {    /* will try both +ve and -ve */
+static void unit_test_locale_safe_string_to_float(void)
+{
+    float statictestset[] = {  /* will try both +ve and -ve */
        0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001,
        9.1, 9.91, 9.991, 9.9991, 9.99991, 9.999991,
-       0.0             /* end of set constant */
-  };
-  float num;
-  int i;
-
-  printf ("starting unit_test_locale_safe_string_to_float\n");
-  /* tests of precision */
-  for (i = 0; statictestset[i] != 0.0; i++) {
-    _test_locale_safe_string_to_float_val (statictestset[i]);
-    _test_locale_safe_string_to_float_val (-statictestset[i]);
-    _test_locale_safe_string_to_float_val (1-statictestset[i]);
-    _test_locale_safe_string_to_float_val (1+statictestset[i]);
-  }
-  /* now exhaustive, in steps of 0.01 */
-  for (num = -1000.0; num < 1000.0; num += 0.01) {
-    _test_locale_safe_string_to_float_val (num);
-  }
-  printf ("finished unit_test_locale_safe_string_to_float\n");
+       0.0                     /* end of set constant */
+    };
+    float num;
+    int i;
+
+    printf("starting unit_test_locale_safe_string_to_float\n");
+    /* tests of precision */
+    for (i = 0; statictestset[i] != 0.0; i++) {
+       _test_locale_safe_string_to_float_val(statictestset[i]);
+       _test_locale_safe_string_to_float_val(-statictestset[i]);
+       _test_locale_safe_string_to_float_val(1 - statictestset[i]);
+       _test_locale_safe_string_to_float_val(1 + statictestset[i]);
+    }
+    /* now exhaustive, in steps of 0.01 */
+    for (num = -1000.0; num < 1000.0; num += 0.01) {
+       _test_locale_safe_string_to_float_val(num);
+    }
+    printf("finished unit_test_locale_safe_string_to_float\n");
 }
 
-void
-do_libspamc_unit_tests (void) {
-  unit_test_locale_safe_string_to_float();
-  exit (0);
+void do_libspamc_unit_tests(void)
+{
+    unit_test_locale_safe_string_to_float();
+    exit(0);
 }
 
 #endif /* LIBSPAMC_UNIT_TESTS */
index cf00e8a..dd44ddc 100644 (file)
@@ -1,19 +1,75 @@
-/*
- * This code is copyright 2001 by Craig Hughes
- * Conversion to a thread-safe shared library copyright 2002 Liam Widdowson
- * Portions copyright 2002 by Brad Jorsch
- * It is licensed under the same license as Perl itself.  The text of this
- * license is included in the SpamAssassin distribution in the file named
- * "License".
+/* <@LICENSE>
+ * Copyright 2004 Apache Software Foundation
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * </@LICENSE>
  */
 #ifndef LIBSPAMC_H
 #define LIBSPAMC_H 1
 
+#include <stdio.h>
+#include <stdarg.h>
 #include <sys/types.h>
+#ifdef _WIN32
+#ifdef _MSC_VER
+/* ignore MSVC++ warnings that are annoying and hard to remove:
+ 4115 named type definition in parentheses
+ 4127 conditional expression is constant
+ 4514 unreferenced inline function removed
+ */
+#pragma warning( disable : 4115 4127 4514 )
+#endif
+#include <winsock.h>
+#else
+#include <netdb.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
-#include <netdb.h>
-#include <stdio.h>
+#endif
+
+#ifdef _WIN32
+/* FIXME: This stuff has to go somewhere else */
+
+#define EX_OK           0
+#define EX_USAGE        64
+#define EX_DATAERR      65
+#define EX_NOINPUT      66
+#define EX_NOUSER       67
+#define EX_NOHOST       68
+#define EX_UNAVAILABLE  69
+#define EX_SOFTWARE     70
+#define EX_OSERR        71
+#define EX_OSFILE       72
+#define EX_CANTCREAT    73
+#define EX_IOERR        74
+#define EX_TEMPFAIL     75
+#define EX_PROTOCOL     76
+#define EX_NOPERM       77
+#define EX_CONFIG       78
+
+#define STDIN_FILENO 0
+#define STDOUT_FILENO 1
+
+/* FIXME: This doesn't belong here either */
+#define LOG_EMERG       0       /* system is unusable */
+#define LOG_ALERT       1       /* action must be taken immediately */
+#define LOG_CRIT        2       /* critical conditions */
+#define LOG_ERR         3       /* error conditions */
+#define LOG_WARNING     4       /* warning conditions */
+#define LOG_NOTICE      5       /* normal but significant condition */
+#define LOG_INFO        6       /* informational */
+#define LOG_DEBUG       7       /* debug-level messages */
+
+#endif
 
 #define EX_NOTSPAM               0
 #define EX_ISSPAM                1
 /* 2003/04/16 SJF: randomize hostname order (quasi load balancing) */
 #define SPAMC_RANDOMIZE_HOSTS (1<<23)
 
+/* log to stderr */
+#define SPAMC_LOG_TO_STDERR  (1<<22)
 
 /* Aug 14, 2002 bj: A struct for storing a message-in-progress */
-typedef enum {
+typedef enum
+{
     MESSAGE_NONE,
     MESSAGE_ERROR,
     MESSAGE_RAW,
@@ -50,26 +109,32 @@ typedef enum {
 
 struct libspamc_private_message;
 
-struct message {
+struct message
+{
     /* Set before passing the struct on! */
-    int max_len;  /* messages larger than this will return EX_TOOBIG */
-    int timeout;  /* timeout for read() system calls */
+    unsigned int max_len; /* messages larger than this will return EX_TOOBIG */
+    int timeout;               /* timeout for read() system calls */
 
     /* Filled in by message_read */
     message_type_t type;
-    char *raw; int raw_len;   /* Raw message buffer */
-    char *pre; int pre_len;   /* Pre-message data (e.g. SMTP commands) */
-    char *msg; int msg_len;   /* The message */
-    char *post; int post_len; /* Post-message data (e.g. SMTP commands) */
+    char *raw;
+    unsigned int raw_len;              /* Raw message buffer */
+    char *pre;
+    int pre_len;               /* Pre-message data (e.g. SMTP commands) */
+    char *msg;
+    unsigned int msg_len;              /* The message */
+    char *post;
+    int post_len;              /* Post-message data (e.g. SMTP commands) */
     int content_length;
 
     /* Filled in by filter_message */
-    int is_spam;              /* EX_ISSPAM if the message is spam, EX_NOTSPAM
-                                 if not */
-    float score, threshold;   /* score and threshold */
-    char *out; int out_len;   /* Output from spamd. Either the filtered
-                                 message, or the check-only response. Or else,
-                                 a pointer to msg above. */
+    int is_spam;               /* EX_ISSPAM if the message is spam, EX_NOTSPAM
+                                  if not */
+    float score, threshold;    /* score and threshold */
+    char *out;
+    int out_len;               /* Output from spamd. Either the filtered
+                                  message, or the check-only response. Or else,
+                                  a pointer to msg above. */
 
     /* these members added in SpamAssassin version 2.60: */
     struct libspamc_private_message *priv;
@@ -99,25 +164,27 @@ struct message {
  * code just loops over that same address.
  */
 #define TRANSPORT_LOCALHOST 0x01       /* TCP to localhost only */
-#define        TRANSPORT_TCP       0x02        /* standard TCP socket   */
-#define TRANSPORT_UNIX     0x03        /* UNIX domain socket    */
+#define        TRANSPORT_TCP       0x02        /* standard TCP socket   */
+#define TRANSPORT_UNIX     0x03        /* UNIX domain socket    */
 
-#define TRANSPORT_MAX_HOSTS 256                /* max hosts we can failover between */
+#define TRANSPORT_MAX_HOSTS 256        /* max hosts we can failover between */
 
-struct transport {
-       int             type;
+struct transport
+{
+    int type;
 
-       const char      *socketpath;    /* for UNIX dommain socket      */
-       const char      *hostname;      /* for TCP sockets              */
+    const char *socketpath;    /* for UNIX dommain socket      */
+    const char *hostname;      /* for TCP sockets              */
 
-       unsigned short  port;           /* for TCP sockets              */
+    unsigned short port;       /* for TCP sockets              */
 
-       struct in_addr  hosts[TRANSPORT_MAX_HOSTS];
-       int             nhosts;
+    struct in_addr hosts[TRANSPORT_MAX_HOSTS];
+    int nhosts;
+    int flags;
 };
 
 extern void transport_init(struct transport *tp);
-extern int  transport_setup(struct transport *tp, int flags);
+extern int transport_setup(struct transport *tp, int flags);
 
 /* Aug 14, 2002 bj: New interface functions */
 
@@ -138,7 +205,7 @@ long message_write(int out_fd, struct message *m);
  * no failover is done.
  */
 int message_filter(struct transport *tp, const char *username,
-               int flags, struct message *m);
+                  int flags, struct message *m);
 
 /* Dump the message. If there is any data in the message (typically, m->type
  * will be MESSAGE_ERROR) it will be message_writed. Then, fd_in will be piped
@@ -149,16 +216,18 @@ void message_dump(int in_fd, int out_fd, struct message *m);
 /* Do a message_read->message_filter->message_write sequence, handling errors
  * appropriately with dump_message or appropriate CHECK_ONLY output. Returns
  * EX_OK or EX_ISSPAM/EX_NOTSPAM on success, some error EX on error. */
-int message_process(struct transport *trans, char *username, int max_size, int in_fd, int out_fd, const int flags);
+int message_process(struct transport *trans, char *username, int max_size,
+                   int in_fd, int out_fd, const int flags);
 
 /* Cleanup the resources we allocated for storing the message. Call after
  * you're done processing. */
 void message_cleanup(struct message *m);
 
 /* Aug 14, 2002 bj: This is now legacy, don't use it. */
-int process_message(struct transport *tp, char *username, 
-                    int max_size, int in_fd, int out_fd,
-                    const int check_only, const int safe_fallback);
+int process_message(struct transport *tp, char *username,
+                   int max_size, int in_fd, int out_fd,
+                   const int check_only, const int safe_fallback);
 
-#endif
+void libspamc_log(int flags, int level, char *msg, ...);
 
+#endif
index b67ca67..f42c961 100644 (file)
@@ -1,17 +1,40 @@
-/*
- * This code is copyright 2001 by Craig Hughes
- * Portions copyright 2002 by Brad Jorsch
- * It is licensed under the same license as Perl itself.  The text of this
- * license is included in the SpamAssassin distribution in the file named
- * "License".
+/* <@LICENSE>
+ * Copyright 2004 Apache Software Foundation
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * </@LICENSE>
  */
 
+#ifndef _WIN32
 #include <unistd.h>
+#include <sys/uio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#else
+
+#ifdef _MSC_VER
+/* ignore MSVC++ warnings that are annoying and hard to remove:
+ 4115 named type definition in parentheses
+ 4127 conditional expression is constant
+ 4514 unreferenced inline function removed
+ */
+#pragma warning( disable : 4115 4127 4514 )
+#endif
+
+#include <io.h>
+#endif
 #include <errno.h>
 #include <signal.h>
-#include <sys/types.h>
-#include <sys/uio.h>
-#include <unistd.h>
 #include <stdio.h>
 #include "utils.h"
 
 /* Apr 24, 2003 sjf: made full_read and full_write void* params */
 
 /* -------------------------------------------------------------------------- */
+#ifndef _WIN32
+typedef void sigfunc(int);     /* for signal handlers */
 
-typedef void    sigfunc(int);   /* for signal handlers */
-
-sigfunc* sig_catch(int sig, void (*f)(int))
+sigfunc *sig_catch(int sig, void (*f) (int))
 {
-  struct sigaction act, oact;
-  act.sa_handler = f;
-  act.sa_flags = 0;
-  sigemptyset(&act.sa_mask);
-  sigaction(sig, &act, &oact);
-  return oact.sa_handler;
+    struct sigaction act, oact;
+    act.sa_handler = f;
+    act.sa_flags = 0;
+    sigemptyset(&act.sa_mask);
+    sigaction(sig, &act, &oact);
+    return oact.sa_handler;
 }
 
-static void catch_alrm(int x) {
-  UNUSED_VARIABLE(x);
+static void catch_alrm(int x)
+{
+    UNUSED_VARIABLE(x);
 }
+#endif
 
-ssize_t
-fd_timeout_read (int fd, void *buf, size_t nbytes)
+int fd_timeout_read(int fd, char fdflag, void *buf, size_t nbytes)
 {
-  ssize_t nred;
-  sigfunc* sig;
-
-  sig = sig_catch(SIGALRM, catch_alrm);
-  if (libspamc_timeout > 0) {
-    alarm(libspamc_timeout);
-  }
+    int nred;
+    int origerr;
+#ifndef _WIN32
+    sigfunc *sig;
+
+    sig = sig_catch(SIGALRM, catch_alrm);
+    if (libspamc_timeout > 0) {
+       alarm(libspamc_timeout);
+    }
+#endif
 
-  do {
-    nred = read (fd, buf, nbytes);
-  } while(nred < 0 && errno == EAGAIN);
+    do {
+       if (fdflag) {
+           nred = (int)read(fd, buf, nbytes);
+           origerr = errno;
+       }
+       else {
+           nred = (int)recv(fd, buf, nbytes, 0);
+#ifndef _WIN32
+           origerr = errno;
+#else
+           origerr = WSAGetLastError();
+#endif
+       }
+    } while (nred < 0 && origerr == EWOULDBLOCK);
 
-  if(nred < 0 && errno == EINTR)
-    errno = ETIMEDOUT;
+#ifndef _WIN32
+    if (nred < 0 && origerr == EINTR)
+       errno = ETIMEDOUT;
 
-  if (libspamc_timeout > 0) {
-    alarm(0);
-  }
+    if (libspamc_timeout > 0) {
+       alarm(0);
+    }
 
-  /* restore old signal handler */
-  sig_catch(SIGALRM, sig);
+    /* restore old signal handler */
+    sig_catch(SIGALRM, sig);
+#endif
 
-  return nred;
+    return nred;
 }
 
-int
-ssl_timeout_read (SSL *ssl, void *buf, int nbytes)
+int ssl_timeout_read(SSL * ssl, void *buf, int nbytes)
 {
-  int nred;
-  sigfunc* sig;
+    int nred;
+
+#ifndef _WIN32
+    sigfunc *sig;
 
-#ifndef SPAMC_SSL
-  UNUSED_VARIABLE(ssl);
-  UNUSED_VARIABLE(buf);
-  UNUSED_VARIABLE(nbytes);
+    sig = sig_catch(SIGALRM, catch_alrm);
+    if (libspamc_timeout > 0) {
+       alarm(libspamc_timeout);
+    }
 #endif
 
-  sig = sig_catch(SIGALRM, catch_alrm);
-  if (libspamc_timeout > 0) {
-    alarm(libspamc_timeout);
-  }
+    do {
 
-  do {
 #ifdef SPAMC_SSL
-    nred = SSL_read (ssl, buf, nbytes);
+       nred = SSL_read(ssl, buf, nbytes);
 #else
-    nred = 0;                  /* never used */
+       UNUSED_VARIABLE(ssl);
+       UNUSED_VARIABLE(buf);
+       UNUSED_VARIABLE(nbytes);
+       nred = 0;               /* never used */
 #endif
-  } while(nred < 0 && errno == EAGAIN);
 
-  if(nred < 0 && errno == EINTR)
-    errno = ETIMEDOUT;
+    } while (nred < 0 && errno == EWOULDBLOCK);
+
+#ifndef _WIN32
+    if (nred < 0 && errno == EINTR)
+       errno = ETIMEDOUT;
 
-  if (libspamc_timeout > 0) {
-    alarm(0);
-  }
+    if (libspamc_timeout > 0) {
+       alarm(0);
+    }
 
-  /* restore old signal handler */
-  sig_catch(SIGALRM, sig);
+    /* restore old signal handler */
+    sig_catch(SIGALRM, sig);
+#endif
 
-  return nred;
+    return nred;
 }
 
 /* -------------------------------------------------------------------------- */
 
-int
-full_read (int fd, void *vbuf, int min, int len)
+int full_read(int fd, char fdflag, void *vbuf, int min, int len)
 {
-  unsigned char *buf = (unsigned char *)vbuf;
-  int total;
-  int thistime;
-
-  for (total = 0; total < min; ) {
-    thistime = fd_timeout_read (fd, buf+total, len-total);
-
-    if (thistime < 0) {
-      return -1;
-    } else if (thistime == 0) {
-      /* EOF, but we didn't read the minimum.  return what we've read
-       * so far and next read (if there is one) will return 0. */
-      return total;
+    unsigned char *buf = (unsigned char *) vbuf;
+    int total;
+    int thistime;
+
+    for (total = 0; total < min;) {
+       thistime = fd_timeout_read(fd, fdflag, buf + total, len - total);
+
+       if (thistime < 0) {
+           if (total >= min) {
+               /* error, but we read *some*.  return what we've read
+                * so far and next read (if there is one) will return -1. */
+               return total;
+           } else {
+               return -1;
+           }
+       }
+       else if (thistime == 0) {
+           /* EOF, but we didn't read the minimum.  return what we've read
+            * so far and next read (if there is one) will return 0. */
+           return total;
+       }
+
+       total += thistime;
     }
-
-    total += thistime;
-  }
-  return total;
+    return total;
 }
 
-int
-full_read_ssl (SSL *ssl, unsigned char *buf, int min, int len)
+int full_read_ssl(SSL * ssl, unsigned char *buf, int min, int len)
 {
-  int total;
-  int thistime;
-
-  for (total = 0; total < min; ) {
-    thistime = ssl_timeout_read (ssl, buf+total, len-total);
-
-    if (thistime < 0) {
-      return -1;
-    } else if (thistime == 0) {
-      /* EOF, but we didn't read the minimum.  return what we've read
-       * so far and next read (if there is one) will return 0. */
-      return total;
+    int total;
+    int thistime;
+
+    for (total = 0; total < min;) {
+       thistime = ssl_timeout_read(ssl, buf + total, len - total);
+
+       if (thistime < 0) {
+           if (total >= min) {
+               /* error, but we read *some*.  return what we've read
+                * so far and next read (if there is one) will return -1. */
+               return total;
+           } else {
+               return -1;
+           }
+       }
+       else if (thistime == 0) {
+           /* EOF, but we didn't read the minimum.  return what we've read
+            * so far and next read (if there is one) will return 0. */
+           return total;
+       }
+
+       total += thistime;
     }
-
-    total += thistime;
-  }
-  return total;
+    return total;
 }
 
-int
-full_write (int fd, const void *vbuf, int len)
+int full_write(int fd, char fdflag, const void *vbuf, int len)
 {
-  const unsigned char *buf = (const unsigned char *)vbuf;
-  int total;
-  int thistime;
-
-  for (total = 0; total < len; ) {
-    thistime = write (fd, buf+total, len-total);
-
-    if (thistime < 0) {
-      if(EINTR == errno || EAGAIN == errno) continue;
-      return thistime;        /* always an error for writes */
+    const char *buf = (const char *) vbuf;
+    int total;
+    int thistime;
+    int origerr;
+
+    for (total = 0; total < len;) {
+       if (fdflag) {
+           thistime = write(fd, buf + total, len - total);
+           origerr = errno;
+       }
+       else {
+           thistime = send(fd, buf + total, len - total, 0);
+#ifndef _WIN32
+           origerr = errno;
+#else
+           origerr = WSAGetLastError();
+#endif
+       }
+       if (thistime < 0) {
+           if (EINTR == origerr || EWOULDBLOCK == origerr)
+               continue;
+           return thistime;    /* always an error for writes */
+       }
+       total += thistime;
     }
-    total += thistime;
-  }
-  return total;
+    return total;
 }
index 4df7c53..3a28754 100644 (file)
@@ -1,9 +1,26 @@
+/* <@LICENSE>
+ * Copyright 2004 Apache Software Foundation
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * </@LICENSE>
+ */
+
 #ifndef UTILS_H
 #define UTILS_H
 
 #define UNUSED_VARIABLE(v)     ((void)(v))
 
-extern int libspamc_timeout;  /* default timeout in seconds */
+extern int libspamc_timeout;   /* default timeout in seconds */
 
 #ifdef SPAMC_SSL
 #include <openssl/crypto.h>
@@ -11,17 +28,69 @@ extern int libspamc_timeout;  /* default timeout in seconds */
 #include <openssl/ssl.h>
 #include <openssl/err.h>
 #else
-typedef int    SSL;    /* fake type to avoid conditional compilation */
-typedef int    SSL_CTX;
-typedef int    SSL_METHOD;
+typedef int SSL;               /* fake type to avoid conditional compilation */
+typedef int SSL_CTX;
+typedef int SSL_METHOD;
+#endif
+
+#ifdef _WIN32
+#include <winsock.h>
+//
+// BSD-compatible socket error codes for Win32
+//
+
+#define EWOULDBLOCK             WSAEWOULDBLOCK
+#define EINPROGRESS             WSAEINPROGRESS
+#define EALREADY                WSAEALREADY
+#define ENOTSOCK                WSAENOTSOCK
+#define EDESTADDRREQ            WSAEDESTADDRREQ
+#define EMSGSIZE                WSAEMSGSIZE
+#define EPROTOTYPE              WSAEPROTOTYPE
+#define ENOPROTOOPT             WSAENOPROTOOPT
+#define EPROTONOSUPPORT         WSAEPROTONOSUPPORT
+#define ESOCKTNOSUPPORT         WSAESOCKTNOSUPPORT
+#define EOPNOTSUPP              WSAEOPNOTSUPP
+#define EPFNOSUPPORT            WSAEPFNOSUPPORT
+#define EAFNOSUPPORT            WSAEAFNOSUPPORT
+#define EADDRINUSE              WSAEADDRINUSE
+#define EADDRNOTAVAIL           WSAEADDRNOTAVAIL
+#define ENETDOWN                WSAENETDOWN
+#define ENETUNREACH             WSAENETUNREACH
+#define ENETRESET               WSAENETRESET
+#define ECONNABORTED            WSAECONNABORTED
+#define ECONNRESET              WSAECONNRESET
+#define ENOBUFS                 WSAENOBUFS
+#define EISCONN                 WSAEISCONN
+#define ENOTCONN                WSAENOTCONN
+#define ESHUTDOWN               WSAESHUTDOWN
+#define ETOOMANYREFS            WSAETOOMANYREFS
+#define ETIMEDOUT               WSAETIMEDOUT
+#define ECONNREFUSED            WSAECONNREFUSED
+#define ELOOP                   WSAELOOP
+// #define ENAMETOOLONG            WSAENAMETOOLONG
+#define EHOSTDOWN               WSAEHOSTDOWN
+#define EHOSTUNREACH            WSAEHOSTUNREACH
+// #define ENOTEMPTY               WSAENOTEMPTY
+#define EPROCLIM                WSAEPROCLIM
+#define EUSERS                  WSAEUSERS
+#define EDQUOT                  WSAEDQUOT
+#define ESTALE                  WSAESTALE
+#define EREMOTE                 WSAEREMOTE
+
+// NOTE: these are not errno constants in UNIX!
+#define HOST_NOT_FOUND          WSAHOST_NOT_FOUND
+#define TRY_AGAIN               WSATRY_AGAIN
+#define NO_RECOVERY             WSANO_RECOVERY
+#define NO_DATA                 WSANO_DATA
+
 #endif
 
-ssize_t fd_timeout_read (int fd, void *, size_t );  
-int ssl_timeout_read (SSL *ssl, void *, int );  
+int fd_timeout_read(int fd, char fdflag, void *, size_t);
+int ssl_timeout_read(SSL * ssl, void *, int);
 
 /* these are fd-only, no SSL support */
-int full_read(int fd, void *buf, int min, int len);
-int full_read_ssl(SSL *ssl, unsigned char *buf, int min, int len);
-int full_write(int fd, const void *buf, int len);
+int full_read(int fd, char fdflag, void *buf, int min, int len);
+int full_read_ssl(SSL * ssl, unsigned char *buf, int min, int len);
+int full_write(int fd, char fdflag, const void *buf, int len);
 
 #endif