You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@spamassassin.apache.org by ms...@apache.org on 2004/01/08 02:13:56 UTC

svn commit: rev 6099 - in incubator/spamassassin/trunk: . spamd

Author: mss
Date: Mon Jan  5 18:36:44 2004
New Revision: 6099

Added:
   incubator/spamassassin/trunk/spamd/README.Win
   incubator/spamassassin/trunk/spamd/binaries.mk.win
   incubator/spamassassin/trunk/spamd/config.h.win
   incubator/spamassassin/trunk/spamd/getopt.c
   incubator/spamassassin/trunk/spamd/getopt.h
Modified:
   incubator/spamassassin/trunk/Makefile.PL
   incubator/spamassassin/trunk/spamd/libspamc.c
   incubator/spamassassin/trunk/spamd/libspamc.h
   incubator/spamassassin/trunk/spamd/spamc.c
   incubator/spamassassin/trunk/spamd/utils.c
   incubator/spamassassin/trunk/spamd/utils.h
Log:
Added a modified version of Sidney's Native Windows Patch(tm). build/configure is now enabled.


Modified: incubator/spamassassin/trunk/Makefile.PL
==============================================================================
--- incubator/spamassassin/trunk/Makefile.PL	(original)
+++ incubator/spamassassin/trunk/Makefile.PL	Mon Jan  5 18:36:44 2004
@@ -1,3 +1,4 @@
+#!/usr/bin/perl
 require 5.6.1;
 
 use strict;
@@ -6,7 +7,7 @@
 
 use ExtUtils::MakeMaker 5.45;
 
-use constant RUNNING_ON_WINDOWS => ($^O =~ /^(?:mswin|dos|os2)/oi);
+use constant RUNNING_ON_WINDOWS => ($^O =~ /^(mswin|dos|os2)/oi);
 
 
 my @ATT_KEYS = (
@@ -149,11 +150,6 @@
 my @datafiles = map { s,^rules/,,; $_ } (<rules/*.cf>);
 my $datafiles = join(' ', (grep { /^[0-6][0-9]_/ } @datafiles), qw(user_prefs.template triplets.txt languages));
 
-# Only build spamd and spamc on non-Windows platforms
-my @SPAMD_EXE_FILES = ();
-if (!RUNNING_ON_WINDOWS) {
-  @SPAMD_EXE_FILES = ('spamd/spamc$(EXE_EXT)', 'spamd/spamd');
-}
 
 # See lib/ExtUtils/MakeMaker.pm for details of how to influence
 # the contents of the Makefile that is written.
@@ -163,7 +159,8 @@
 
     'EXE_FILES'	=> [
         'spamassassin', 'sa-learn',
-        @SPAMD_EXE_FILES
+        'spamd/spamc$(EXE_EXT)',
+        'spamd/spamd',
     ],
 
     'MAN1PODS' => {
@@ -206,6 +203,7 @@
         'spamassassin', 'sa-learn',
         'spamd/spamd', 'spamd/spamc$(EXE_EXT)',
         'spamd/libspamc.so', 'spamd/libsslspamc.so',
+        'spamd/*.o', 'spamd/*.obj',
         'spamd/binaries.mk', 'spamd/config.h', 'spamd/config.status',
         'spamd/config.cache', 'spamd/config.log', 'spamd/autom4te.cache',
         'qmail/qmail-spamc',
@@ -295,6 +293,15 @@
 }
 
 
+# Windows platforms need some adjustments
+if (RUNNING_ON_WINDOWS) {
+  # Don't build spamd
+  delete $makefile{EXE_FILES}['spamd/spamd'];
+  # And require Net::DNS v0.44
+  #$makefile{PREREQ_PM}{Net::DNS} = 0.44;
+}
+
+
 $makefile{'macro'}{'ENABLE_SSL'} = yesno($opt{'enable_ssl'});
 
 if (!defined $opt{'contact_address'}) {
@@ -337,6 +344,8 @@
 use vars qw(
   $MY_GLOBALS_ARE_SANE
 
+  $RUNNING_ON_WINDOWS
+
   @REPOSITORIES
 
   $MACRO_RE
@@ -378,6 +387,9 @@
   # To assign or own macros we'll follow the first assignment string we find;
   # normally " = ".
   $EQ = undef;
+
+  # Inherit our Windows-Flag.
+  $RUNNING_ON_WINDOWS = ::RUNNING_ON_WINDOWS;
 }
 
 # Unset $SELF to avoid any leaking memory.
@@ -432,8 +444,10 @@
 # If it is omitted, the value set in the current EU::MM instance is used.
 sub macro_def {
   my($name, $val) = (@_, undef);
+  my $MUST_NOT_HAPPEN = "THIS MUST NOT HAPPEN. PLEASE REPORT A BUG VIA <http://bugzilla.spamassassin.org>";
+  die $MUST_NOT_HAPPEN  unless defined $name;
+  die $MUST_NOT_HAPPEN  unless defined $EQ;
   $val = $SELF->{$name} unless defined $val;
-  die unless defined $EQ;
 
   return $name . $EQ . $val;
 }
@@ -705,6 +719,33 @@
   _set_macro_PERL_yesno('TAINT');
 }
 
+# This routine sets the value for PREPROCESS.
+#
+# There are no parameters.
+#
+# If PREPROCESS wasn't set at the command line, it chooses our default
+# perl-called preprocessor.
+sub _set_macro_PREPROCESS {
+
+  return if get_macro('PREPROCESS');
+  set_macro('PREPROCESS', join(' ', macro_ref('PERL'), qq{build/preprocessor}));
+}
+
+# This routine sets the value for CONFIGURE (spamc only).
+#
+# There are no parameters.
+#
+# If CONFIGURE wasn't set at the command line, it chooses our default
+# perl-wrapped configure.
+sub _set_macro_CONFIGURE {
+
+  return if get_macro('CONFIGURE');
+  set_macro('CONFIGURE', join(' ', macro_ref('PERL'), qq{build/configure}));
+}
+
+
+
+
 
 # Override the libscan routine so it skips SVN/CVS stuff and some common
 # patch/backup extensions.
@@ -748,8 +789,6 @@
 }
 
 
-
-
 # Now override the constants routine to add our own macros.
 sub MY::constants {
   my $self = shift;
@@ -800,6 +839,7 @@
       }
     }
   }
+  push(@code, qq{});
 
   # Add some additional target dirs
   {
@@ -814,6 +854,7 @@
 
     # ... and add it to the Makefile.
     push(@code, qq{});
+    push(@code, qq{# Where to install config files});
     push(@code, macro_def('SYSCONFDIR'));
     foreach my $r (@REPOSITORIES) {
       push(@code, macro_def($r . 'SYSCONFDIR'));
@@ -841,46 +882,56 @@
 
     # Add it to the Makefile.
     push(@code, qq{});
+    push(@code, qq{# Some details about our Perl});
     foreach my $m (qw(BIN VERSION WARN TAINT)) {
       push(@code, macro_def('PERL_' . $m));
     }
   }
 
-  clean_MY_globals($self);
-  return join("\n", @code);
-}
+  # Set the preprocessor and configure scripts
+  {
+    _set_macro_PREPROCESS;
+    _set_macro_CONFIGURE;
 
-sub MY::postamble {
-  my $self = shift;
-  my @code = ();
-  init_MY_globals($self);
+    # Add it to the Makefile.
+    push(@code, qq{});
+    push(@code, macro_def('PREPROCESS'));
+    push(@code, macro_def('CONFIGURE'));
+  }
 
-  my($repository);
-  $repository = uc($SELF->{INSTALLDIRS}) || 'SITE';
+  # Set some additional helper/shortcut macros.
+  {
+    my($repository);
+    $repository = uc($SELF->{INSTALLDIRS}) || 'SITE';
 
-  foreach my $macro (qw(PREFIX SYSCONFDIR)) {
-    push(@code, macro_def('I_' . $macro,
+    foreach my $macro (qw(PREFIX SYSCONFDIR)) {
+      push(@code, macro_def('I_' . $macro,
                     macro_ref($repository . $macro)));
-  }
-  foreach my $macro (qw(DATA CONF LIB)) {
-    push(@code, macro_def('I_' . $macro . 'DIR',
+    }
+    foreach my $macro (qw(DATA CONF LIB)) {
+      push(@code, macro_def('I_' . $macro . 'DIR',
                     macro_ref('INSTALL' . repository($repository) . $macro)));
 
-    if ($mm_has_destdir) {
-      push(@code, macro_def('B_' . $macro . 'DIR',
-                    macro_ref('DESTINSTALL' . repository($repository) . $macro)));
-    } else {
-      push(@code, macro_def('B_' . $macro . 'DIR',
-                    macro_ref('I_' . $macro . 'DIR')));
+      if ($mm_has_destdir) {
+        push(@code, macro_def('B_' . $macro . 'DIR',
+                      macro_ref('DESTINSTALL' . repository($repository) . $macro)));
+      } else {
+        push(@code, macro_def('B_' . $macro . 'DIR',
+                      macro_ref('I_' . $macro . 'DIR')));
+      }
     }
   }
 
-  my $code = join("\n", @code);
-  @code = (); # free mem
+  clean_MY_globals($self);
+  return join("\n", @code);
+}
 
-  $code .= <<'  EOD';
+sub MY::postamble {
+  my $self = shift;
+  my $code = "";
+  init_MY_globals($self);
 
-PREPROCESS    = $(PERL) build/preprocessor
+  $code .= <<'  EOD';
 
 FIXVARS		= -Mvars \
 		  -DVERSION="$(VERSION)" \
@@ -904,29 +955,25 @@
 sa-learn: sa-learn.raw
 	$(PREPROCESS) $(FIXBYTES) $(FIXVARS) $(FIXBANG) -m$(PERM_RWX) -i$? -o$@
 
+
+spamd/binaries.mk:
+	$(CONFIGURE) --srcdir="spamd" --prefix="$(I_PREFIX)" --sysconfdir="$(I_SYSCONFDIR)" --datadir="$(I_DATADIR)" --enable-ssl="$(ENABLE_SSL)"
+
 spamd/spamd: spamd/spamd.raw
 	$(PREPROCESS) $(FIXBYTES) $(FIXVARS) $(FIXBANG) -m$(PERM_RWX) -i$? -o$@
 
 spamd/libspamc.so: spamd/binaries.mk $(SPAMC_SOURCES)
 	$(MAKE) -f spamd/binaries.mk $@
 
-spamd/libspamc.dll: spamd/binaries.mk $(SPAMC_SOURCES)
-	$(MAKE) -f spamd/binaries.mk $@
-
 spamd/spamc$(EXE_EXT): spamd/binaries.mk $(SPAMC_SOURCES)
 	$(MAKE) -f spamd/binaries.mk $@
 
 spamd/libsslspamc.so: spamd/binaries.mk $(SPAMC_SOURCES)
 	$(MAKE) -f spamd/binaries.mk $@
 
-spamd/libsslspamc.dll: spamd/binaries.mk $(SPAMC_SOURCES)
-	$(MAKE) -f spamd/binaries.mk $@
-
 qmail/qmail-spamc: spamd/binaries.mk $(SPAMC_SOURCES)
 	$(MAKE) -f spamd/binaries.mk $@
 
-spamd/binaries.mk: spamd/configure
-	cd spamd; ./configure --prefix="$(I_PREFIX)" --sysconfdir="$(I_SYSCONFDIR)" --datadir="$(I_DATADIR)" --enable-ssl="$(ENABLE_SSL)"
 
 conf__install:
 	-$(MKPATH) $(B_CONFDIR)

Added: incubator/spamassassin/trunk/spamd/README.Win
==============================================================================
--- (empty file)
+++ incubator/spamassassin/trunk/spamd/README.Win	Mon Jan  5 18:36:44 2004
@@ -0,0 +1,97 @@
+Building Spamd/Spamc under Windows
+----------------------------------
+
+Spamd currently does not run under Windows, but spamc does.
+
+Spamd does work when built and run in the Cygwin unix emulation
+environment, and a pure Windows spamc can be used with it. You can
+also run a pure Windows spamc that communicates with spamd running on
+any network accessible computer. The unix sockets option is not
+supported under Windows, so only TCP/IP can be used. As of this
+writing SSL has not been tested with the Windows spamc.
+
+Building spamc for Windows requires a lot more than running it. If all
+you want to do is run spamc without the full SpamAssassin on your
+Windows machine, it is easier if you can get a binary executable from
+someone else who has built it.
+
+System Requirements
+-------------------
+
+This has only been tested with Microsoft Visual C++ 6.0. There is a
+good chance it will just work with later versions of VC++, but some
+installation files would have to be changed to use with any other
+compiler.
+
+In addition to VC++ you also have to have installed a Windows version
+of Perl and the modules that are listed as required in the general
+SpamAssassin documentation. So far the only Windows version of perl
+this has been tested with is ActivePerl.
+
+To run the spamc executable once it is built you do not need to have
+VC++ or perl installed.
+
+Spamc requires spamd to be running on some system that it can talk to
+using tcp/ip over a network or on the same machine. The test cases in
+the build process will only work if spamd has been installed under
+Cygwin on the same computer.
+
+Building
+--------
+
+To build such a combined setup, first install SpamAssassin under
+Cygwin by unpacking the source files into some directory, for example,
+/usr/local/src/spamassassin, then in a Cygwin bash shell
+
+ cd /usr/local/src/spamassassin
+ perl Makefile.PL
+ make
+ make test
+ make install
+
+This assumes that you have already installed perl and all necessary
+perl modules as described elsewhere in the SpamAssassin install
+documentation.
+
+Now that you have a working SpamAssassin under Cygwin you can use that
+to test the spamc that you will build under Windows. To set that up,
+first create a Windows environment variable in the System control
+panel. The variable is named
+
+ SPAMD_SCRIPT
+
+and set it to
+
+SPAMD_SCRIPT=start \cygwin\bin\perl -w -T /bin/spamd -x -s stderr --syslog-socket none
+
+where "\cygwin\bin\perl" is the path of the Cygwin perl executable
+file in the Windows directory system, and "/bin/spamd" is the path of
+the spamd executable that you installed under Cygwin. Be sure to
+substitute the correct path names for your installation if they are
+different from this example.
+
+Now you are ready to build SpamAssassin under Windows. Unpack the
+SpamAssassin source tree into a different directory than you used for
+building the Cygwin version, for example C:\spamassassin\. Then in a
+Windows command shell do the following.
+
+First, make sure that the environment is set up for running VC++. In
+VC++ 6.0 there is a batch file created during installation that sets
+the environment. In a typical installation that would be found at
+
+"\Program Files\Microsoft Visual Studio\VC98\Bin\VCVARS32.BAT"
+
+Also make sure that the SPAMD_SCRIPT environment variable is set in
+your command shell as described above.
+
+Then use the commands
+
+ cd \spamasassin
+ perl Makefile.PL
+ nmake
+ nmake test
+ nmake install
+
+That's it. You should now have two working versions of SpamAssassin,
+one under Cygwin and one under Windows.
+

Added: incubator/spamassassin/trunk/spamd/binaries.mk.win
==============================================================================
--- (empty file)
+++ incubator/spamassassin/trunk/spamd/binaries.mk.win	Mon Jan  5 18:36:44 2004
@@ -0,0 +1,17 @@
+CC = @@CC@@
+CFLAGS = @@CFLAGS@@
+SSLCFLAGS = @@SSLCFLAGS@@
+
+LIBS = @@LIBS@@
+SSLLIBS = @@SSLLIBS@@
+
+SPAMC_FILES = @@SPAMC_FILES@@
+LIBSPAMC_FILES = @@LIBSPAMC_FILES@@
+
+
+all: spamd/spamc.exe
+
+spamd/spamc.exe: $(SPAMC_FILES) $(LIBSPAMC_FILES)
+	cd spamd
+	$(CC) $(SSLCFLAGS) $(CFLAGS) $(SPAMC_FILES) $(LIBSPAMC_FILES) $(LIBS) $(SSLLIBS)
+

Added: incubator/spamassassin/trunk/spamd/config.h.win
==============================================================================
--- (empty file)
+++ incubator/spamassassin/trunk/spamd/config.h.win	Mon Jan  5 18:36:44 2004
@@ -0,0 +1,169 @@
+/* config.h.  Generated by configure.  */
+/* config.h.in.  Generated from configure.in by autoheader.  */
+
+/* #undef CCDLFLAGS */
+
+/* #undef LDDLFLAGS */
+
+#define HAVE_SHUT_RD 1
+
+#define HAVE_H_ERRNO 1
+
+#define HAVE_OPTARG 1
+
+/* #undef in_addr_t */
+
+#define HAVE_INADDR_NONE 1
+
+#ifndef _WIN32
+#define HAVE_EX__MAX 1
+#endif
+
+/* Define to 1 if you have the <errno.h> header file. */
+#define HAVE_ERRNO_H 1
+
+/* Define to 1 if you have the <getopt.h> header file. */
+#define HAVE_GETOPT_H 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `crypto' library (-lcrypto). */
+/* #undef HAVE_LIBCRYPTO */
+
+/* Define to 1 if you have the `dl' library (-ldl). */
+/* #undef HAVE_LIBDL */
+
+/* Define to 1 if you have the `inet' library (-linet). */
+/* #undef HAVE_LIBINET */
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+/* #undef HAVE_LIBNSL */
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+/* #undef HAVE_LIBSOCKET */
+
+/* Define to 1 if you have the `ssl' library (-lssl). */
+/* #undef HAVE_LIBSSL */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#define HAVE_NETDB_H 1
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#define HAVE_NETINET_IN_H 1
+
+/* Define to 1 if you have the <openssl/crypto.h> header file. */
+/* #undef HAVE_OPENSSL_CRYPTO_H */
+
+#ifndef _WIN32
+/* Define to 1 if you have the <pwd.h> header file. */
+#define HAVE_PWD_H 1
+#endif
+
+/* Define to 1 if you have the `shutdown' function. */
+#define HAVE_SHUTDOWN 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the `snprintf' function. */
+#define HAVE_SNPRINTF 1
+
+/* Define to 1 if you have the `socket' function. */
+#define HAVE_SOCKET 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `strdup' function. */
+#define HAVE_STRDUP 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strtod' function. */
+#define HAVE_STRTOD 1
+
+/* Define to 1 if you have the `strtol' function. */
+#define HAVE_STRTOL 1
+
+#ifndef _WIN32
+/* Define to 1 if you have the <sysexits.h> header file. */
+#define HAVE_SYSEXITS_H 1
+
+/* Define to 1 if you have the <syslog.h> header file. */
+#define HAVE_SYSLOG_H 1
+
+/* Define to 1 if you have the <sys/errno.h> header file. */
+#define HAVE_SYS_ERRNO_H 1
+#endif
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+#ifndef _WIN32
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+#endif
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <time.h> header file. */
+#define HAVE_TIME_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION ""
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef gid_t */
+
+/* Define to `unsigned long' if <sys/types.h> does not define. */
+/* #undef in_addr_t */
+
+/* Define to `long' if <sys/types.h> does not define. */
+/* #undef off_t */
+/* #define off_t long */
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef pid_t */
+#define pid_t int
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef uid_t */

Added: incubator/spamassassin/trunk/spamd/getopt.c
==============================================================================
--- (empty file)
+++ incubator/spamassassin/trunk/spamd/getopt.c	Mon Jan  5 18:36:44 2004
@@ -0,0 +1,231 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-2004 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ *    not be used to endorse or promote products derived from this
+ *    software without prior written permission. For written
+ *    permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    nor may "Apache" appear in their name, without prior written
+ *    permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+
+#ifdef WIN32
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#define OPTERRCOLON (1)
+#define OPTERRNF (2)
+#define OPTERRARG (3)
+
+char *optarg;
+int optreset = 0;
+int optind = 1;
+int opterr = 1;
+int optopt;
+
+static int
+optiserr(int argc, char * const *argv, int oint, const char *optstr,
+         int optchr, int err)
+{
+    if(opterr)
+    {
+        fprintf(stderr, "Error in argument %d, char %d: ", oint, optchr+1);
+        switch(err)
+        {
+        case OPTERRCOLON:
+            fprintf(stderr, ": in flags\n");
+            break;
+        case OPTERRNF:
+            fprintf(stderr, "option not found %c\n", argv[oint][optchr]);
+            break;
+        case OPTERRARG:
+            fprintf(stderr, "no argument for option %c\n", argv[oint][optchr]);
+            break;
+        default:
+            fprintf(stderr, "unknown\n");
+            break;
+        }
+    }
+    optopt = argv[oint][optchr];
+    return('?');
+}
+    
+   
+
+int
+getopt(int argc, char* const *argv, const char *optstr)
+{
+    static int optchr = 0;
+    static int dash = 0; /* have already seen the - */
+
+    char *cp;
+
+    if (optreset)
+        optreset = optchr = dash = 0;
+    if(optind >= argc)
+        return(EOF);
+    if(!dash && (argv[optind][0] !=  '-'))
+        return(EOF);
+    if(!dash && (argv[optind][0] ==  '-') && !argv[optind][1])
+    {
+        /*
+         * use to specify stdin. Need to let pgm process this and
+         * the following args
+         */
+        return(EOF);
+    }
+    if((argv[optind][0] == '-') && (argv[optind][1] == '-'))
+    {
+        /* -- indicates end of args */
+        optind++;
+        return(EOF);
+    }
+    if(!dash)
+    {
+        assert((argv[optind][0] == '-') && argv[optind][1]);
+        dash = 1;
+        optchr = 1;
+    }
+
+    /* Check if the guy tries to do a -: kind of flag */
+    assert(dash);
+    if(argv[optind][optchr] == ':')
+    {
+        dash = 0;
+        optind++;
+        return(optiserr(argc, argv, optind-1, optstr, optchr, OPTERRCOLON));
+    }
+    if(!(cp = strchr(optstr, argv[optind][optchr])))
+    {
+        int errind = optind;
+        int errchr = optchr;
+
+        if(!argv[optind][optchr+1])
+        {
+            dash = 0;
+            optind++;
+        }
+        else
+            optchr++;
+        return(optiserr(argc, argv, errind, optstr, errchr, OPTERRNF));
+    }
+    if(cp[1] == ':')
+    {
+        dash = 0;
+        optind++;
+        if(optind == argc)
+            return(optiserr(argc, argv, optind-1, optstr, optchr, OPTERRARG));
+        optarg = argv[optind++];
+        return(*cp);
+    }
+    else
+    {
+        if(!argv[optind][optchr+1])
+        {
+            dash = 0;
+            optind++;
+        }
+        else
+            optchr++;
+        return(*cp);
+    }
+    assert(0);
+    return(0);
+}
+
+#ifdef TESTGETOPT
+int
+ main (int argc, char **argv)
+ {
+      int c;
+      extern char *optarg;
+      extern int optind;
+      int aflg = 0;
+      int bflg = 0;
+      int errflg = 0;
+      char *ofile = NULL;
+
+      while ((c = getopt(argc, argv, "abo:")) != EOF)
+           switch (c) {
+           case 'a':
+                if (bflg)
+                     errflg++;
+                else
+                     aflg++;
+                break;
+           case 'b':
+                if (aflg)
+                     errflg++;
+                else
+                     bflg++;
+                break;
+           case 'o':
+                ofile = optarg;
+                (void)printf("ofile = %s\n", ofile);
+                break;
+           case '?':
+                errflg++;
+           }
+      if (errflg) {
+           (void)fprintf(stderr,
+                "usage: cmd [-a|-b] [-o <filename>] files...\n");
+           exit (2);
+      }
+      for ( ; optind < argc; optind++)
+           (void)printf("%s\n", argv[optind]);
+      return 0;
+ }
+
+#endif /* TESTGETOPT */
+
+#endif /* WIN32 */

Added: incubator/spamassassin/trunk/spamd/getopt.h
==============================================================================
--- (empty file)
+++ incubator/spamassassin/trunk/spamd/getopt.h	Mon Jan  5 18:36:44 2004
@@ -0,0 +1,73 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-2004 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ *    not be used to endorse or promote products derived from this
+ *    software without prior written permission. For written
+ *    permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    nor may "Apache" appear in their name, without prior written
+ *    permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+
+#ifndef GETOPT_H
+#define GETOPT_H
+
+#ifdef WIN32
+
+extern char *optarg;
+extern int optreset;
+extern int optind;
+extern int opterr;
+extern int optopt;
+int getopt(int argc, char* const *argv, const char *optstr);
+
+#endif /* WIN32 */
+
+#endif /* GETOPT_H */

Modified: incubator/spamassassin/trunk/spamd/libspamc.c
==============================================================================
--- incubator/spamassassin/trunk/spamd/libspamc.c	(original)
+++ incubator/spamassassin/trunk/spamd/libspamc.c	Mon Jan  5 18:36:44 2004
@@ -10,18 +10,26 @@
 #include "libspamc.h"
 #include "utils.h"
 
-#include <unistd.h>
 #include <stdlib.h>
 #include <assert.h>
 #include <stdio.h>
 #include <string.h>
+#ifdef _WIN32
+/* simple macro that works for single strings without %m */
+#define syslog(x, y) fprintf(stderr, #y "\n")
+#define strcasecmp stricmp
+#define sleep Sleep
+#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>
@@ -173,11 +181,20 @@
 	}
 
 #ifdef DO_CONNECT_DEBUG_SYSLOGS
+#ifndef _WIN32
 	syslog (DEBUG_LEVEL, "dbg: create socket(%s)", typename);
+#else
+	fprintf (stderr, "dbg: create socket(%s)\n", typename);
+#endif
 #endif
 
-	if ( (*psock = socket(type, SOCK_STREAM, proto)) < 0 )
-	{
+	if ( (*psock = socket(type, SOCK_STREAM, proto))
+#ifndef _WIN32
+         < 0
+#else
+         == INVALID_SOCKET
+#endif
+         ) {
 	int	origerr;
 
 		/*--------------------------------------------------------
@@ -185,9 +202,13 @@
 		 * this is pretty much fatal. Translate the error reason
 		 * into something the user can understand.
 		 */
+#ifndef _WIN32
 		origerr = errno;    /* take a copy before syslog() */
-
 		syslog (LOG_ERR, "socket(%s) to spamd failed: %m", typename);
+#else
+      origerr = WSAGetLastError();
+      printf ("socket(%s) to spamd failed: %d\n", typename, origerr);
+#endif
 
 		switch (origerr)
 		{
@@ -221,15 +242,26 @@
 		if ( type == PF_INET
 		 &&  setsockopt(*psock, 0, TCP_NODELAY, &one, sizeof one) != 0 )
 		{
-			switch(errno)
+          int origerrno;
+#ifndef _WIN32
+          origerr = errno;
+#else
+          origerrno = WSAGetLastError();
+#endif
+			switch(origerr)
 			{
 			  case EBADF:
 			  case ENOTSOCK:
 			  case ENOPROTOOPT:
 			  case EFAULT:
+#ifndef _WIN32
 				syslog(LOG_ERR,
 				   "setsockopt(TCP_NODELAY) failed: %m");
-				close (*psock);
+#else
+				fprintf(stderr,
+				   "setsockopt(TCP_NODELAY) failed: %d\n", origerr));
+#endif
+				closesocket (*psock);
 				return EX_SOFTWARE;
 
 			  default:
@@ -253,6 +285,7 @@
 static int
 try_to_connect_unix (struct transport *tp, int *sockptr)
 {
+#ifndef _WIN32
 int mysock, status, origerr;
 struct sockaddr_un addrbuf;
 int ret;
@@ -295,10 +328,12 @@
 
 	syslog(LOG_ERR, "connect(AF_UNIX) to spamd %s failed: %m",
 		addrbuf.sun_path);
-
-	close(mysock);
+	closesocket(mysock);
 
 	return translate_connect_errno(origerr);
+#else
+    return EX_OSERR;
+#endif
 }
 
 /*
@@ -323,7 +358,13 @@
 #ifdef DO_CONNECT_DEBUG_SYSLOGS
 	for (numloops = 0; numloops < tp->nhosts; numloops++)
 	{
-		syslog(LOG_ERR, "dbg: %d/%d: %s",
+#ifndef _WIN32
+		syslog(LOG_ERR,
+			"dbg: %d/%d: %s",
+#else
+		fprintf(stderr,
+			"dbg: %d/%d: %s\n",
+#endif
 			numloops+1, tp->nhosts, inet_ntoa(tp->hosts[numloops]));
 	}
 #endif
@@ -352,8 +393,13 @@
 		ipaddr = inet_ntoa(addrbuf.sin_addr);
 
 #ifdef DO_CONNECT_DEBUG_SYSLOGS
-		syslog (DEBUG_LEVEL,
+#ifndef _WIN32
+		syslog(DEBUG_LEVEL,
 			"dbg: connect(AF_INET) to spamd at %s (try #%d of %d)",
+#else
+		fprintf(stderr,
+			"dbg: connect(AF_INET) to spamd at %s (try #%d of %d\)\n",
+#endif
 			ipaddr,
 			numloops+1,
 			MAX_CONNECT_RETRIES);
@@ -363,20 +409,33 @@
 
 		if (status != 0)
 		{
+#ifndef _WIN32
+          origerr = errno;
 			syslog (LOG_ERR,
 			"connect(AF_INET) to spamd at %s failed, retrying (#%d of %d): %m",
 				ipaddr, numloops+1, MAX_CONNECT_RETRIES);
-
-			close(mysock);
+#else
+          origerr = WSAGetLastError();
+          fprintf (stderr,
+                  "connect(AF_INET) to spamd at %s failed, retrying (#%d of %d): %d\n",
+                  ipaddr, numloops+1, MAX_CONNECT_RETRIES, origerr);
+#endif
+          closesocket(mysock);
 
 			sleep(CONNECT_RETRY_SLEEP);
 		}
 		else
 		{
 #ifdef DO_CONNECT_DEBUG_SYSLOGS
+#ifndef _WIN32
 			syslog(DEBUG_LEVEL,
 				"dbg: connect(AF_INET) to spamd at %s done",
 				ipaddr);
+#else
+			fprintf(stderr,
+				"dbg: connect(AF_INET) to spamd at %s done\n",
+				ipaddr);
+#endif
 #endif
 			*sockptr = mysock;
 
@@ -384,7 +443,13 @@
 		}
 	}
 
-	syslog (LOG_ERR, "connection attempt to spamd aborted after %d retries",
+#ifndef _WIN32
+	syslog (LOG_ERR,
+		"connection attempt to spamd aborted after %d retries",
+#else
+	fprintf(stderr,
+		"connection attempt to spamd aborted after %d retries\n",
+#endif
 		MAX_CONNECT_RETRIES);
 
 	return translate_connect_errno(origerr);
@@ -411,7 +476,7 @@
 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);
+    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;
@@ -434,7 +499,7 @@
     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);
+    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;
@@ -506,7 +571,12 @@
         return message_read_bsmtp(fd, m);
 
       default:
-        syslog(LOG_ERR, "message_read: Unknown mode %d\n", flags&SPAMC_MODE_MASK);
+#ifndef _WIN32
+        syslog(LOG_ERR, "message_read: Unknown mode %d",
+#else
+        fprintf(stderr, "message_read: Unknown mode %d\n",
+#endif
+			flags&SPAMC_MODE_MASK);
         return EX_USAGE;
     }
 }
@@ -519,10 +589,14 @@
 
     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);
+	    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);
+#ifndef _WIN32
+	    syslog(LOG_ERR, "oops! SPAMC_CHECK_ONLY is_spam: %d", m->is_spam);
+#else
+	    fprintf(stderr, "oops! SPAMC_CHECK_ONLY is_spam: %d\n", m->is_spam);
+#endif
 	    return -1;
 	}
     }
@@ -530,17 +604,17 @@
     /* 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");
+        syslog(LOG_ERR, "Cannot write this message, it's MESSAGE_NONE!");
         return -1;
 
       case MESSAGE_ERROR:
-        return full_write(fd, m->raw, m->raw_len);
+        return full_write(fd, 1, m->raw, m->raw_len);
 
       case MESSAGE_RAW:
-        return full_write(fd, m->out, m->out_len);
+        return full_write(fd, 1, m->out, m->out_len);
 
       case MESSAGE_BSMTP:
-        total=full_write(fd, m->pre, m->pre_len);
+        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 &&
@@ -557,12 +631,16 @@
                     buffer[j++]=m->out[i++];
                 }
             }
-            total+=full_write(fd, buffer, j);
+            total+=full_write(fd, 1, buffer, j);
         }
-        return total+full_write(fd, m->post, m->post_len);
+        return total+full_write(fd, 1, m->post, m->post_len);
 
       default:
-        syslog(LOG_ERR, "Unknown message type %d\n", m->type);
+#ifndef _WIN32
+        syslog(LOG_ERR, "Unknown message type %d", m->type);
+#else
+        fprintf(stderr, "Unknown message type %d\n", m->type);
+#endif
         return -1;
     }
 }
@@ -574,9 +652,13 @@
     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)) {
+    while((bytes=full_read(in_fd, 1, buf, 8192, 8192))>0){
+        if (bytes!=full_write(out_fd, 1, buf, bytes)) {
+#ifndef _WIN32
             syslog(LOG_ERR, "oops! message_dump of %d returned different", bytes);
+#else
+            fprintf(stderr, "oops! message_dump of %d returned different\n", bytes);
+#endif
         }
     }
 }
@@ -596,7 +678,7 @@
 	if(flags&SPAMC_USE_SSL) {
 	  bytesread = ssl_timeout_read (ssl, buf+len, 1);
 	} else {
-	  bytesread = fd_timeout_read (sock, buf+len, 1);
+	  bytesread = fd_timeout_read (sock, 0, buf+len, 1);
 	}
 
         if(buf[len]=='\n') {
@@ -614,7 +696,11 @@
         }
     }
 
+#ifndef _WIN32
     syslog(LOG_ERR, "spamd responded with line of %d bytes, dying", len);
+#else
+    fprintf(stderr, "spamd responded with line of %d bytes, dying\n", len);
+#endif
     failureval = EX_TOOBIG;
 
 failure:
@@ -693,30 +779,48 @@
 	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;
 
 	if(flags&SPAMC_CHECK_ONLY) {
-	    m->out_len=snprintf (m->out, m->max_len+EXPANSION_ALLOWANCE,
+	    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,
+	    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) {
 	if (m->content_length < 0) {
+#ifndef _WIN32
 	    syslog(LOG_ERR, "spamd responded with bad Content-length '%s'", buf);
+#else
+	    fprintf(stderr, "spamd responded with bad Content-length '%s'\n", buf);
+#endif
 	    return EX_PROTOCOL;
 	}
 	return EX_OK;
     }
 
+#ifndef _WIN32
     syslog(LOG_ERR, "spamd responded with bad header '%s'", buf);
+#else
+    fprintf(stderr, "spamd responded with bad header '%s'\n", buf);
+#endif
     return EX_PROTOCOL;
 }
 
@@ -733,7 +837,7 @@
     int response;
     int failureval;
     SSL_CTX* ctx;
-    SSL* ssl;
+    SSL* ssl = NULL;
     SSL_METHOD *meth;
 
     if (flags&SPAMC_USE_SSL) {
@@ -760,25 +864,35 @@
 
     /* Build spamd protocol header */
     if(flags & SPAMC_CHECK_ONLY) 
-      len=snprintf(buf, bufsiz, "CHECK %s\r\n", PROTOCOL_VERSION);
+	  strcpy(buf, "CHECK ");
     else if(flags & SPAMC_REPORT_IFSPAM)
-      len=snprintf(buf, bufsiz, "REPORT_IFSPAM %s\r\n", PROTOCOL_VERSION);
+      strcpy(buf, "REPORT_IFSPAM ");
     else if(flags & SPAMC_REPORT) 
-      len=snprintf(buf, bufsiz, "REPORT %s\r\n", PROTOCOL_VERSION);
+      strcpy(buf, "REPORT ");
     else if(flags & SPAMC_SYMBOLS) 
-      len=snprintf(buf, bufsiz, "SYMBOLS %s\r\n", PROTOCOL_VERSION);
+      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; }
 
-    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; }
-    }
-    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; }
+    strcat(buf, PROTOCOL_VERSION);
+    strcat(buf, "\r\n");
+    len = strlen(buf);
+
+    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 += sprintf(buf+len, "Content-length: %d\r\n\r\n", m->msg_len);
 
     libspamc_timeout = m->timeout;
 
@@ -790,7 +904,7 @@
     if ( rc != EX_OK )
     {
         free(m->out); m->out=m->msg; m->out_len=m->msg_len;
-        return i;
+        return EX_OSERR;
     }
 
     if(flags&SPAMC_USE_SSL) {
@@ -808,8 +922,8 @@
       SSL_write(ssl, m->msg, m->msg_len);
 #endif
     } else {
-      full_write(sock, buf, len);
-      full_write(sock, m->msg, m->msg_len);
+      full_write(sock, 0, buf, len);
+      full_write(sock, 0, m->msg, m->msg_len);
       shutdown(sock, SHUT_WR);
     }
 
@@ -818,14 +932,22 @@
     if (failureval != EX_OK) { goto failure; }
 
     if(sscanf(buf, "SPAMD/%18s %d %*s", versbuf, &response)!=2) {
+#ifndef _WIN32
 	syslog(LOG_ERR, "spamd responded with bad string '%s'", buf);
+#else
+	fprintf(stderr, "spamd responded with bad string '%s'\n", buf);
+#endif
 	failureval = EX_PROTOCOL; goto failure;
     }
 
     versbuf[19] = '\0';
     version = _locale_safe_string_to_float (versbuf, 20);
     if (version < 1.0) {
+#ifndef _WIN32
 	syslog(LOG_ERR, "spamd responded with bad version string '%s'", versbuf);
+#else
+	fprintf(stderr, "spamd responded with bad version string '%s'\n", versbuf);
+#endif
 	failureval = EX_PROTOCOL; goto failure;
     }
 
@@ -848,7 +970,7 @@
     len = 0;		/* overwrite those headers */
 
     if (flags&SPAMC_CHECK_ONLY) {
-	close(sock); sock = -1;
+	closesocket(sock); sock = -1;
 	if (m->is_spam == EX_TOOBIG) {
 	      /* We should have gotten headers back... Damnit. */
 	      failureval = EX_PROTOCOL; goto failure;
@@ -874,7 +996,7 @@
 		     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,
+	  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);
 	}
@@ -886,12 +1008,16 @@
 	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) {
+#ifndef _WIN32
         syslog(LOG_ERR, "failed sanity check, %d bytes claimed, %d bytes seen",
+#else
+        fprintf(stderr, "failed sanity check, %d bytes claimed, %d bytes seen\n",
+#endif
 				m->content_length, m->out_len);
 	failureval = EX_PROTOCOL; goto failure;
     }
@@ -901,7 +1027,7 @@
 failure:
     free(m->out); m->out=m->msg; m->out_len=m->msg_len;
     if (sock != -1) {
-      close(sock);
+      closesocket(sock);
     }
     libspamc_timeout = 0;
 
@@ -936,7 +1062,7 @@
 
 FAIL:
    if(flags&SPAMC_CHECK_ONLY){
-       full_write(out_fd, "0/0\n", 4);
+       full_write(out_fd, 1, "0/0\n", 4);
        message_cleanup(&m);
        return EX_NOTSPAM;
    } else {
@@ -1032,14 +1158,26 @@
 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
+
 	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;
@@ -1050,7 +1188,11 @@
 		{
 		int	origherr = h_errno;  /* take a copy before syslog() */
 
+#ifndef _WIN32
 			syslog (LOG_ERR, "gethostbyname(%s) failed: h_errno=%d",
+#else
+			fprintf (stderr, "gethostbyname(%s) failed: h_errno=%d\n",
+#endif
 				tp->hostname, origherr);
 			switch (origherr)
 			{
@@ -1094,7 +1236,11 @@
 		for (addrp = hp->h_addr_list; *addrp; addrp++)
 		{
 			if (tp->nhosts >= TRANSPORT_MAX_HOSTS-1) {
+#ifndef _WIN32
 				syslog (LOG_ERR, "hit limit of %d hosts, ignoring remainder", TRANSPORT_MAX_HOSTS-1);
+#else
+				fprintf (stderr, "hit limit of %d hosts, ignoring remainder\n", TRANSPORT_MAX_HOSTS-1);
+#endif
 				break;
 			}
 
@@ -1148,13 +1294,14 @@
   char inputstr[99], cmpbuf1[99], cmpbuf2[99];
   float output;
 
-  snprintf (inputstr, 99, "%f", input);
+  /* 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);
+  sprintf (cmpbuf1, "%f", input);
+  sprintf (cmpbuf2, "%f", output);
   if (!strcmp (cmpbuf1, cmpbuf2)) { return; }
 
   printf ("FAIL: input=%f != output=%f\n", input, output);

Modified: incubator/spamassassin/trunk/spamd/libspamc.h
==============================================================================
--- incubator/spamassassin/trunk/spamd/libspamc.h	(original)
+++ incubator/spamassassin/trunk/spamd/libspamc.h	Mon Jan  5 18:36:44 2004
@@ -9,11 +9,38 @@
 #ifndef LIBSPAMC_H
 #define LIBSPAMC_H 1
 
+#include <stdio.h>
 #include <sys/types.h>
+#ifdef _WIN32
+#include <winsock.h>
+#else
+#include <netdb.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
-#include <netdb.h>
-#include <stdio.h>
+#endif
+
+#ifdef _WIN32
+#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
+
+#endif
 
 #define EX_NOTSPAM		  0
 #define EX_ISSPAM		  1

Modified: incubator/spamassassin/trunk/spamd/spamc.c
==============================================================================
--- incubator/spamassassin/trunk/spamd/spamc.c	(original)
+++ incubator/spamassassin/trunk/spamd/spamc.c	Mon Jan  5 18:36:44 2004
@@ -9,17 +9,21 @@
 #include "libspamc.h"
 #include "utils.h"
 
-#include <unistd.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
+#ifdef _WIN32
+#define syslog(x, y) fprintf(stderr, #y "\n")
+#else
 #include <syslog.h>
+#include <unistd.h>
+#include <netdb.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <netinet/tcp.h>
-#include <netdb.h>
 #include <arpa/inet.h>
+#endif
 
 #ifdef HAVE_SYSEXITS_H
 #include <sysexits.h>
@@ -48,13 +52,19 @@
      || (defined(__sgi))  /* IRIX */ \
      || (defined(__osf__)) /* Digital UNIX */ \
      || (defined(hpux) || defined(__hpux)) /* HPUX */ \
-     || (defined(_WIN32) || defined(__CYGWIN__)) /* CygWin, Win32 */
+     || (defined(__CYGWIN__)) /* CygWin, Win32 */
 
 extern int optind;
 extern char *optarg;
 
 #endif
 
+#ifdef _WIN32
+#include "getopt.h"
+char* __progname = "spamc";
+#endif
+
+
 /* safe fallback defaults to on now - CRH */
 int flags = SPAMC_RAW_MODE | SPAMC_SAFE_FALLBACK;
 
@@ -93,7 +103,13 @@
 {
   int opt, i, j;
 
-  while(-1 != (opt = getopt(argc,argv,"-BcrRd:e:fhyp:t:s:u:xSHU:")))
+  while(-1 != (opt = getopt(argc,argv,
+#ifndef _WIN32
+                            "-BcrRd:e:fhyp:t:s:u:xSHU:"
+#else
+                            "-BcrRd:fhyp:t:s:u:xSH"
+#endif
+)))
   {
     switch(opt)
     {
@@ -102,12 +118,14 @@
         flags |= SPAMC_RANDOMIZE_HOSTS;
         break;
       }
+#ifndef _WIN32
     case 'U':
       {
         ptrn->type       = TRANSPORT_UNIX;
         ptrn->socketpath = optarg;
         break;
       }
+#endif
     case 'B':
       {
         flags = (flags & ~SPAMC_MODE_MASK) | SPAMC_BSMTP_MODE;
@@ -139,6 +157,7 @@
 	ptrn->hostname = optarg;	/* fix the ptr to point to this string */
 	break;
       }
+#ifndef _WIN32
     case 'e':
       {
         if((exec_argv=malloc(sizeof(*exec_argv)*(argc-optind+2)))==NULL)
@@ -149,6 +168,7 @@
         exec_argv[i]=NULL;
         return EX_OK;
       }
+#endif
     case 'p':
       {
 	ptrn->port = atoi(optarg);
@@ -210,6 +230,7 @@
         *fd=STDOUT_FILENO;
         return;
     }
+#ifndef _WIN32
     if(pipe(fds)){
         syslog(LOG_ERR, "pipe creation failed: %m");
         exit(EX_OSERR);
@@ -237,6 +258,9 @@
     close(fds[0]); /* no point in leaving extra fds lying around */
     execv(exec_argv[0], exec_argv);
     syslog(LOG_ERR, "exec failed: %m");
+#else
+    fprintf(stderr, "exec failed: %d\n", errno);
+#endif
     exit(EX_OSERR);
 }
 
@@ -256,8 +280,10 @@
   do_libspamc_unit_tests();
 #endif
 
+#ifndef _WIN32
   openlog ("spamc", LOG_CONS|LOG_PID, LOG_MAIL);
   signal (SIGPIPE, SIG_IGN);
+#endif
 
   read_args(argc,argv, &max_size, &username, &trans);
 
@@ -274,6 +300,7 @@
    * to our own buffer - then this won't arise as a problem.
    */
  
+#ifndef _WIN32
   if(NULL == username)
   {
   static char   userbuf[256];
@@ -289,6 +316,7 @@
     userbuf[sizeof userbuf - 1] = '\0';
     username = userbuf;
   }
+#endif
 
   if ((flags & SPAMC_RANDOMIZE_HOSTS) != 0) {
     /* we don't need strong randomness; this is just so we pick
@@ -304,57 +332,59 @@
    * we connect to the spam daemon. Mainly this involves lookup up the
    * hostname and getting the IP addresses to connect to.
    */
-  if ( (ret = transport_setup(&trans, flags)) != EX_OK )
-    goto FAIL;
-
-
+  if ( (ret = transport_setup(&trans, flags)) == EX_OK ) {
     out_fd=-1;
     m.type    = MESSAGE_NONE;
     m.max_len = max_size;
     m.timeout = timeout;
 
     ret=message_read(STDIN_FILENO, flags, &m);
-    if(ret!=EX_OK) goto FAIL;
+    if(ret==EX_OK) {
     ret=message_filter(&trans, username, flags, &m);
-    if(ret!=EX_OK) goto FAIL;
+      if(ret==EX_OK) {
     get_output_fd(&out_fd);
 
-    if(message_write(out_fd, &m)<0) {
-      goto FAIL;
-    }
+        if(message_write(out_fd, &m)>=0) {
 
     result = m.is_spam;
     if ((flags&SPAMC_CHECK_ONLY) && result != EX_TOOBIG) {
       message_cleanup (&m);
-      return result;
+            ret = result;
     } else {
       message_cleanup (&m);
+          }
+#ifdef _WIN32
+          WSACleanup();
+#endif
       return ret;
     }
+      }
+    }
+  }
 
-FAIL:
+ FAIL:
     get_output_fd(&out_fd);
 
     result = m.is_spam;
     if((flags&SPAMC_CHECK_ONLY) && result != EX_TOOBIG) {
 	/* probably, the write to stdout failed; we can still report exit code */
 	message_cleanup (&m);
-	return result;
-
+      ret = result;      
     } else if(flags&SPAMC_CHECK_ONLY || flags&SPAMC_REPORT || flags&SPAMC_REPORT_IFSPAM) {
-        full_write(out_fd, "0/0\n", 4);
+      full_write(out_fd, 1, "0/0\n", 4);
 	message_cleanup (&m);
-        return EX_NOTSPAM;
-
+      ret = EX_NOTSPAM;      
     } else {
         message_dump(STDIN_FILENO, out_fd, &m);
 	message_cleanup (&m);
         if (ret == EX_TOOBIG) {
-          return 0;
+        ret = 0;
         } else if (flags & SPAMC_SAFE_FALLBACK) {
-	  return EX_OK;
-	} else {
-	  return ret;
+        ret = EX_OK;
 	}
     }
+#ifdef _WIN32
+    WSACleanup();
+#endif
+    return ret;
 }

Modified: incubator/spamassassin/trunk/spamd/utils.c
==============================================================================
--- incubator/spamassassin/trunk/spamd/utils.c	(original)
+++ incubator/spamassassin/trunk/spamd/utils.c	Mon Jan  5 18:36:44 2004
@@ -6,12 +6,15 @@
  * "License".
  */
 
+#ifndef _WIN32
 #include <unistd.h>
+#include <sys/uio.h>
+#else
+typedef int ssize_t;
+#endif
 #include <errno.h>
 #include <signal.h>
 #include <sys/types.h>
-#include <sys/uio.h>
-#include <unistd.h>
 #include <stdio.h>
 #include "utils.h"
 
@@ -25,7 +28,7 @@
 /* Apr 24, 2003 sjf: made full_read and full_write void* params */
 
 /* -------------------------------------------------------------------------- */
-
+#ifndef _WIN32
 typedef void    sigfunc(int);   /* for signal handlers */
 
 sigfunc* sig_catch(int sig, void (*f)(int))
@@ -41,23 +44,38 @@
 static void catch_alrm(int x) {
   UNUSED_VARIABLE(x);
 }
+#endif
 
 ssize_t
-fd_timeout_read (int fd, void *buf, size_t nbytes)
+fd_timeout_read (int fd, char fdflag, void *buf, size_t nbytes)
 {
   ssize_t nred;
+  int origerr;
+#ifndef _WIN32
   sigfunc* sig;
 
   sig = sig_catch(SIGALRM, catch_alrm);
   if (libspamc_timeout > 0) {
     alarm(libspamc_timeout);
   }
+#endif
 
   do {
+    if (fdflag) {
     nred = read (fd, buf, nbytes);
-  } while(nred < 0 && errno == EAGAIN);
+      origerr = errno;
+    } else {
+      nred = recv (fd, buf, nbytes, 0);
+#ifndef _WIN32
+      origerr = errno;
+#else
+      origerr = WSAGetLastError();
+#endif
+    }
+  } while(nred < 0 && origerr == EWOULDBLOCK);
 
-  if(nred < 0 && errno == EINTR)
+#ifndef _WIN32
+  if(nred < 0 && origerr == EINTR)
     errno = ETIMEDOUT;
 
   if (libspamc_timeout > 0) {
@@ -66,6 +84,7 @@
 
   /* restore old signal handler */
   sig_catch(SIGALRM, sig);
+#endif
 
   return nred;
 }
@@ -74,7 +93,6 @@
 ssl_timeout_read (SSL *ssl, void *buf, int nbytes)
 {
   int nred;
-  sigfunc* sig;
 
 #ifndef SPAMC_SSL
   UNUSED_VARIABLE(ssl);
@@ -82,10 +100,14 @@
   UNUSED_VARIABLE(nbytes);
 #endif
 
+#ifndef _WIN32
+  sigfunc* sig;
+
   sig = sig_catch(SIGALRM, catch_alrm);
   if (libspamc_timeout > 0) {
     alarm(libspamc_timeout);
   }
+#endif
 
   do {
 #ifdef SPAMC_SSL
@@ -93,8 +115,9 @@
 #else
     nred = 0;			/* never used */
 #endif
-  } while(nred < 0 && errno == EAGAIN);
+  } while(nred < 0 && errno == EWOULDBLOCK);
 
+#ifndef _WIN32
   if(nred < 0 && errno == EINTR)
     errno = ETIMEDOUT;
 
@@ -104,6 +127,7 @@
 
   /* restore old signal handler */
   sig_catch(SIGALRM, sig);
+#endif
 
   return nred;
 }
@@ -111,14 +135,14 @@
 /* -------------------------------------------------------------------------- */
 
 int
-full_read (int fd, void *vbuf, int min, int len)
+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);
+    thistime = fd_timeout_read (fd, fdflag, buf+total, len-total);
 
     if (thistime < 0) {
       return -1;
@@ -156,17 +180,27 @@
 }
 
 int
-full_write (int fd, const void *vbuf, int len)
+full_write (int fd, char fdflag, const void *vbuf, int len)
 {
   const unsigned char *buf = (const unsigned 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 == errno || EAGAIN == errno) continue;
+      if(EINTR == origerr || EWOULDBLOCK == origerr) continue;
       return thistime;        /* always an error for writes */
     }
     total += thistime;

Modified: incubator/spamassassin/trunk/spamd/utils.h
==============================================================================
--- incubator/spamassassin/trunk/spamd/utils.h	(original)
+++ incubator/spamassassin/trunk/spamd/utils.h	Mon Jan  5 18:36:44 2004
@@ -15,13 +15,65 @@
 typedef int	SSL_CTX;
 typedef int	SSL_METHOD;
 #endif
+#ifdef _WIN32
+#include <winsock.h>
+typedef int ssize_t;
+//
+// BSD-compatible socket error codes for Win32
+//
 
-ssize_t fd_timeout_read (int fd, void *, size_t );  
+#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, 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(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, const void *buf, int len);
+int full_write(int fd, char fdflag, const void *buf, int len);
 
 #endif