Mailing List Archive

svn commit: r494093 - in /spamassassin/trunk: INSTALL MANIFEST lib/Mail/SpamAssassin/Util/DependencyInfo.pm spamc/config.h.in spamc/configure spamc/configure.in spamc/libspamc.c spamc/libspamc.h spamc/spamc.c spamc/spamc.pod spamd/spamd.raw t/spamc_z.t
Author: jm
Date: Mon Jan 8 07:33:53 2007
New Revision: 494093

URL: http://svn.apache.org/viewvc?view=rev&rev=494093
Log:
add spamc '-z' switch, which compresses mails to be scanned using zlib compression; very useful for long-distance use of spamc over the internet. also add test script, INSTALL doc, and documentation. backport from r481882 on 'jm_spamc_hacks' branch

Added:
spamassassin/trunk/t/spamc_z.t
Modified:
spamassassin/trunk/INSTALL
spamassassin/trunk/MANIFEST
spamassassin/trunk/lib/Mail/SpamAssassin/Util/DependencyInfo.pm
spamassassin/trunk/spamc/config.h.in
spamassassin/trunk/spamc/configure
spamassassin/trunk/spamc/configure.in
spamassassin/trunk/spamc/libspamc.c
spamassassin/trunk/spamc/libspamc.h
spamassassin/trunk/spamc/spamc.c
spamassassin/trunk/spamc/spamc.pod
spamassassin/trunk/spamd/spamd.raw

Modified: spamassassin/trunk/INSTALL
URL: http://svn.apache.org/viewvc/spamassassin/trunk/INSTALL?view=diff&rev=494093&r1=494092&r2=494093
==============================================================================
--- spamassassin/trunk/INSTALL (original)
+++ spamassassin/trunk/INSTALL Mon Jan 8 07:33:53 2007
@@ -312,6 +312,14 @@
compatibile spamc.)


+ - Compress::Zlib (from CPAN)
+
+ If you wish to use the optional zlib compression for communication
+ between spamc and spamd (the -z option to spamc), useful for
+ long-distance use of spamc over the internet, you need to install
+ this module.
+
+
- Time::HiRes (from CPAN)

If this module is installed, the processing times are logged/reported

Modified: spamassassin/trunk/MANIFEST
URL: http://svn.apache.org/viewvc/spamassassin/trunk/MANIFEST?view=diff&rev=494093&r1=494092&r2=494093
==============================================================================
--- spamassassin/trunk/MANIFEST (original)
+++ spamassassin/trunk/MANIFEST Mon Jan 8 07:33:53 2007
@@ -347,6 +347,7 @@
t/spamc_l.t
t/spamc_optC.t
t/spamc_optL.t
+t/spamc_z.t
t/spamd.t
t/spamd_allow_user_rules.t
t/spamd_hup.t

Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Util/DependencyInfo.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/Util/DependencyInfo.pm?view=diff&rev=494093&r1=494092&r2=494093
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Util/DependencyInfo.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Util/DependencyInfo.pm Mon Jan 8 07:33:53 2007
@@ -122,6 +122,13 @@
compatibile spamc.)',
},
{
+ module => 'Compress::Zlib',
+ version => '0.00',
+ desc => 'If you wish to use the optional zlib compression for communication
+ between spamc and spamd (the -z option to spamc), you need to install
+ this module.',
+},
+{
module => 'Time::HiRes',
version => '0.00',
desc => 'If this module is installed, the processing times are logged/reported

Modified: spamassassin/trunk/spamc/config.h.in
URL: http://svn.apache.org/viewvc/spamassassin/trunk/spamc/config.h.in?view=diff&rev=494093&r1=494092&r2=494093
==============================================================================
--- spamassassin/trunk/spamc/config.h.in (original)
+++ spamassassin/trunk/spamc/config.h.in Mon Jan 8 07:33:53 2007
@@ -34,6 +34,9 @@
/* Define to 1 if you have the `socket' library (-lsocket). */
#undef HAVE_LIBSOCKET

+/* Define to 1 if you have the `z' library (-lz). */
+#undef HAVE_LIBZ
+
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H

@@ -108,6 +111,9 @@

/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the <zlib.h> header file. */
+#undef HAVE_ZLIB_H

/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT

Modified: spamassassin/trunk/spamc/configure
URL: http://svn.apache.org/viewvc/spamassassin/trunk/spamc/configure?view=diff&rev=494093&r1=494092&r2=494093
==============================================================================
--- spamassassin/trunk/spamc/configure (original)
+++ spamassassin/trunk/spamc/configure Mon Jan 8 07:33:53 2007
@@ -3035,7 +3035,8 @@



-for ac_header in pwd.h signal.h openssl/crypto.h
+
+for ac_header in pwd.h signal.h openssl/crypto.h zlib.h
do
as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
if eval "test \"\${$as_ac_Header+set}\" = set"; then
@@ -3957,6 +3958,79 @@
_ACEOF

LIBS="-lnsl $LIBS"
+
+fi
+
+
+echo "$as_me:$LINENO: checking for deflate in -lz" >&5
+echo $ECHO_N "checking for deflate in -lz... $ECHO_C" >&6
+if test "${ac_cv_lib_z_deflate+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lz $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char deflate ();
+int
+main ()
+{
+deflate ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_z_deflate=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_z_deflate=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_z_deflate" >&5
+echo "${ECHO_T}$ac_cv_lib_z_deflate" >&6
+if test $ac_cv_lib_z_deflate = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBZ 1
+_ACEOF
+
+ LIBS="-lz $LIBS"

fi


Modified: spamassassin/trunk/spamc/configure.in
URL: http://svn.apache.org/viewvc/spamassassin/trunk/spamc/configure.in?view=diff&rev=494093&r1=494092&r2=494093
==============================================================================
--- spamassassin/trunk/spamc/configure.in (original)
+++ spamassassin/trunk/spamc/configure.in Mon Jan 8 07:33:53 2007
@@ -29,7 +29,7 @@
AC_HEADER_STDC
AC_CHECK_HEADERS(sys/time.h syslog.h unistd.h errno.h sys/errno.h)
AC_CHECK_HEADERS(time.h sysexits.h sys/socket.h netdb.h netinet/in.h)
-AC_CHECK_HEADERS(pwd.h signal.h openssl/crypto.h)
+AC_CHECK_HEADERS(pwd.h signal.h openssl/crypto.h zlib.h)
dnl AC_CHECK_HEADERS(getopt.h)

AC_C_CONST
@@ -75,6 +75,7 @@
fi
AC_CHECK_LIB(inet, connect)
AC_CHECK_LIB(nsl, t_accept)
+AC_CHECK_LIB(z, deflate)
AC_CHECK_LIB(dl, dlopen)

AC_CHECK_FUNCS(socket strdup strtod strtol snprintf shutdown)

Modified: spamassassin/trunk/spamc/libspamc.c
URL: http://svn.apache.org/viewvc/spamassassin/trunk/spamc/libspamc.c?view=diff&rev=494093&r1=494092&r2=494093
==============================================================================
--- spamassassin/trunk/spamc/libspamc.c (original)
+++ spamassassin/trunk/spamc/libspamc.c Mon Jan 8 07:33:53 2007
@@ -57,6 +57,9 @@
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
+#ifdef HAVE_ZLIB_H
+#include <zlib.h>
+#endif

/* FIXME: Make this configurable */
#define MAX_CONNECT_RETRIES 3
@@ -990,6 +993,61 @@
return EX_OK;
}

+static int
+_zlib_compress (char *m_msg, int m_msg_len,
+ unsigned char **zlib_buf, int *zlib_bufsiz)
+{
+ int rc;
+ int len, totallen;
+
+#ifndef HAVE_LIBZ
+
+ UNUSED_VARIABLE(rc);
+ UNUSED_VARIABLE(len);
+ UNUSED_VARIABLE(totallen);
+ libspamc_log(flags, LOG_ERR, "spamc not built with zlib support");
+ return EX_SOFTWARE;
+
+#else
+
+ /* worst-case, according to http://www.zlib.org/zlib_tech.html ;
+ * same as input, plus 5 bytes per 16k, plus 6 bytes. this should
+ * be plenty */
+ *zlib_bufsiz = (int) (m_msg_len * 1.0005) + 1024;
+ *zlib_buf = (unsigned char *) malloc (*zlib_bufsiz);
+ if (*zlib_buf == NULL) {
+ return EX_OSERR;
+ }
+
+ z_stream strm;
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+ rc = deflateInit(&strm, 3);
+ if (rc != Z_OK) {
+ return EX_OSERR;
+ }
+
+ strm.avail_in = m_msg_len;
+ strm.next_in = (unsigned char *) m_msg;
+ strm.avail_out = *zlib_bufsiz;
+ strm.next_out = (unsigned char *) *zlib_buf;
+
+ totallen = 0;
+ do {
+ rc = deflate(&strm, Z_FINISH);
+ assert(rc != Z_STREAM_ERROR);
+ len = (size_t) (*zlib_bufsiz - strm.avail_out);
+ strm.next_out += len;
+ totallen += len;
+ } while (strm.avail_out == 0);
+
+ *zlib_bufsiz = totallen;
+ return EX_OK;
+
+#endif
+}
+
int message_filter(struct transport *tp, const char *username,
int flags, struct message *m)
{
@@ -1006,10 +1064,19 @@
SSL_CTX *ctx = NULL;
SSL *ssl = NULL;
SSL_METHOD *meth;
+ char zlib_on = 0;
+ unsigned char *zlib_buf = NULL;
+ int zlib_bufsiz = 0;
+ unsigned char *towrite_buf;
+ int towrite_len;

assert(tp != NULL);
assert(m != NULL);

+ if ((flags & SPAMC_USE_ZLIB) != 0) {
+ zlib_on = 1;
+ }
+
if (flags & SPAMC_USE_SSL) {
#ifdef SPAMC_SSL
SSLeay_add_ssl_algorithms();
@@ -1065,6 +1132,17 @@
strcat(buf, "\r\n");
len = strlen(buf);

+ towrite_buf = (unsigned char *) m->msg;
+ towrite_len = (int) m->msg_len;
+ if (zlib_on) {
+ if (_zlib_compress(m->msg, m->msg_len, &zlib_buf, &zlib_bufsiz) != EX_OK)
+ {
+ return EX_OSERR;
+ }
+ towrite_buf = zlib_buf;
+ towrite_len = zlib_bufsiz;
+ }
+
if (!(flags & SPAMC_PING)) {
if (username != NULL) {
if (strlen(username) + 8 >= (bufsiz - len)) {
@@ -1076,11 +1154,14 @@
strcat(buf + len, "\r\n");
len += strlen(buf + len);
}
+ if (zlib_on) {
+ len += snprintf(buf + len, 8192-len, "Compress: zlib\r\n");
+ }
if ((m->msg_len > SPAMC_MAX_MESSAGE_LEN) || ((len + 27) >= (bufsiz - len))) {
_use_msg_for_out(m);
return EX_DATAERR;
}
- len += sprintf(buf + len, "Content-length: %d\r\n\r\n", (int) m->msg_len);
+ len += snprintf(buf + len, 8192-len, "Content-length: %d\r\n\r\n", (int) towrite_len);
}

libspamc_timeout = m->timeout;
@@ -1107,12 +1188,12 @@
if (flags & SPAMC_USE_SSL) {
#ifdef SPAMC_SSL
SSL_write(ssl, buf, len);
- SSL_write(ssl, m->msg, m->msg_len);
+ SSL_write(ssl, towrite_buf, towrite_len);
#endif
}
else {
full_write(sock, 0, buf, len);
- full_write(sock, 0, m->msg, m->msg_len);
+ full_write(sock, 0, towrite_buf, towrite_len);
shutdown(sock, SHUT_WR);
}


Modified: spamassassin/trunk/spamc/libspamc.h
URL: http://svn.apache.org/viewvc/spamassassin/trunk/spamc/libspamc.h?view=diff&rev=494093&r1=494092&r2=494093
==============================================================================
--- spamassassin/trunk/spamc/libspamc.h (original)
+++ spamassassin/trunk/spamc/libspamc.h Mon Jan 8 07:33:53 2007
@@ -122,6 +122,9 @@
#define SPAMC_SSLV2 (1<<18)
#define SPAMC_SSLV3 (1<<17)

+/* Nov 30, 2006 jm: add -z, zlib support */
+#define SPAMC_USE_ZLIB (1<<16)
+
#define SPAMC_MESSAGE_CLASS_SPAM 1
#define SPAMC_MESSAGE_CLASS_HAM 2


Modified: spamassassin/trunk/spamc/spamc.c
URL: http://svn.apache.org/viewvc/spamassassin/trunk/spamc/spamc.c?view=diff&rev=494093&r1=494092&r2=494093
==============================================================================
--- spamassassin/trunk/spamc/spamc.c (original)
+++ spamassassin/trunk/spamc/spamc.c Mon Jan 8 07:33:53 2007
@@ -190,6 +190,7 @@
usg(" -h, --help Print this help message and exit.\n");
usg(" -V, --version Print spamc version and exit.\n");
usg(" -K Keepalive check of spamd.\n");
+ usg(" -z Compress mail message sent to spamd.\n");
usg(" -f (Now default, ignored.)\n");

usg("\n");
@@ -208,9 +209,9 @@
struct transport *ptrn)
{
#ifndef _WIN32
- const char *opts = "-BcrRd:e:fyp:t:s:u:L:C:xSHU:ElhVKF:";
+ const char *opts = "-BcrRd:e:fyp:t:s:u:L:C:xzSHU:ElhVKF:";
#else
- const char *opts = "-BcrRd:fyp:t:s:u:L:C:xSHElhVKF:";
+ const char *opts = "-BcrRd:fyp:t:s:u:L:C:xzSHElhVKF:";
#endif
int opt;
int ret = EX_OK;
@@ -239,6 +240,7 @@
{ "pipe-to", required_argument, 0, 'e' },
{ "help", no_argument, 0, 'h' },
{ "version", no_argument, 0, 'V' },
+ { "compress", no_argument, 0, 'z' },
{ 0, 0, 0, 0} /* last element _must_ be all zeroes */
};

@@ -432,6 +434,11 @@
{
print_version();
return(EX_TEMPFAIL);
+ }
+ case 'z':
+ {
+ flags |= SPAMC_USE_ZLIB;
+ break;
}
}
}

Modified: spamassassin/trunk/spamc/spamc.pod
URL: http://svn.apache.org/viewvc/spamassassin/trunk/spamc/spamc.pod?view=diff&rev=494093&r1=494092&r2=494093
==============================================================================
--- spamassassin/trunk/spamc/spamc.pod (original)
+++ spamassassin/trunk/spamc/spamc.pod Mon Jan 8 07:33:53 2007
@@ -212,6 +212,14 @@

Perform a keep-alive check of spamd, instead of a full message check.

+=item B<-z>
+
+Use gzip compression to compress the mail message sent to C<spamd>. This is
+useful for long-distance use of spamc over the internet. Note that this relies
+on C<zlib> being installed on the C<spamc> client side, and the
+C<Compress::Zlib> perl module on the server side; an error will be returned
+otherwise.
+
=back

=head1 CONFIGURATION FILE

Modified: spamassassin/trunk/spamd/spamd.raw
URL: http://svn.apache.org/viewvc/spamassassin/trunk/spamd/spamd.raw?view=diff&rev=494093&r1=494092&r2=494093
==============================================================================
--- spamassassin/trunk/spamd/spamd.raw (original)
+++ spamassassin/trunk/spamd/spamd.raw Mon Jan 8 07:33:53 2007
@@ -148,6 +148,8 @@
printf(" running on Perl %s\n", join(".", map { $_||=0; $_*1 } ($] =~ /(\d)\.(\d{3})(\d{3})?/)));
eval { require IO::Socket::SSL; };
printf(" with SSL support (%s %s)\n", "IO::Socket::SSL", $IO::Socket::SSL::VERSION) unless ($@);
+ eval { require Compress::Zlib; };
+ printf(" with zlib support (%s %s)\n", "Compress::Zlib", $Compress::Zlib::VERSION) unless ($@);
}

sub print_usage_and_exit {
@@ -1328,15 +1330,29 @@
}

sub parse_body {
- my ($client, $expected_length) = @_;
+ my ($client, $expected_length, $compress_zlib) = @_;

my @msglines;
- my $actual_length = 0;
+ my $actual_length;

- while (defined($_ = $client->getline())) {
- $actual_length += length($_);
- push(@msglines, $_);
- last if (defined $expected_length && $actual_length >= $expected_length);
+ if ($compress_zlib && !defined($expected_length)) {
+ service_unavailable_error("Compress requires Content-length header");
+ return;
+ }
+
+ if ($compress_zlib) {
+ $actual_length = zlib_inflate_read($client, $expected_length, \@msglines);
+ if ($actual_length < 0) { return; }
+ $expected_length = $actual_length;
+ }
+ else {
+ @msglines = ();
+ $actual_length = 0;
+ while (defined($_ = $client->getline())) {
+ $actual_length += length($_);
+ push(@msglines, $_);
+ last if (defined $expected_length && $actual_length >= $expected_length);
+ }
}

# Now parse *only* the message headers; the MIME tree won't be generated
@@ -1346,6 +1362,54 @@
return ($mail, $actual_length);
}

+sub zlib_inflate_read {
+ my ($client, $expected_length, $msglinesref) = @_;
+ my $out;
+ my $actual_length;
+
+ eval {
+ require Compress::Zlib;
+ my ($zlib, $status) = Compress::Zlib::inflateInit();
+ if (!$zlib) { die "inflateInit failed: $status"; }
+
+ my $red = 0;
+ my $buf;
+
+ # TODO: inflate in smaller buffers instead of at EOF
+ while (1) {
+ my $numbytes = $client->read($buf, (1024 * 64) + $red, $red);
+ if (!defined $numbytes) {
+ die "read of zlib data failed: $!";
+ return -1;
+ }
+ last if $numbytes == 0;
+ $red += $numbytes;
+ }
+
+ if ($red > $expected_length) {
+ warn "hmm, zlib read $red > expected_length $expected_length";
+ substr ($buf, $expected_length) = '';
+ }
+
+ ($out, $status) = $zlib->inflate($buf);
+ if ($status != Compress::Zlib::Z_STREAM_END()) {
+ die "failed to find end of zlib stream";
+ }
+ };
+
+ if ($@) {
+ service_unavailable_error("zlib: $@");
+ return -1;
+ }
+
+ $actual_length = length($out);
+
+ # TODO: split during inflate, too
+ # note that this preserves line endings
+ @{$msglinesref} = map { s/$/\n/gs; $_; } split(/\n/, $out);
+ return $actual_length;
+}
+
sub parse_msgids {
my ($mail) = @_;

@@ -1371,6 +1435,7 @@
my ( $method, $version, $start_time, $remote_hostname, $remote_hostaddr ) = @_;
local ($_);
my $expected_length;
+ my $compress_zlib;

# used to ensure we don't accidentally fork (bug 4370)
my $starting_self_pid = $$;
@@ -1384,6 +1449,7 @@
return 0 unless (parse_headers($hdrs, $client));

$expected_length = $hdrs->{expected_length};
+ $compress_zlib = $hdrs->{compress_zlib};
}

handle_setuid_to_user if ($setuid_to_user && $> == 0);
@@ -1402,7 +1468,13 @@
my $resp = "EX_OK";

# generate mail object from input
- my ($mail, $actual_length) = parse_body($client, $expected_length);
+ my ($mail, $actual_length) = parse_body($client, $expected_length,
+ $compress_zlib);
+ return 0 unless defined($mail); # error
+
+ if ($compress_zlib) {
+ $expected_length = $actual_length; # previously it was the gzipped length
+ }

# attempt to fetch the message ids
my ($msgid, $rmsgid) = parse_msgids($mail);
@@ -1571,13 +1643,13 @@
sub dotell {
my ($method, $version, $start_time, $remote_hostname, $remote_hostaddr) = @_;
local ($_);
- my $expected_length;

my $hdrs = {};

return 0 unless (parse_headers($hdrs, $client));

- $expected_length = $hdrs->{expected_length};
+ my $expected_length = $hdrs->{expected_length};
+ my $compress_zlib = $hdrs->{compress_zlib};

if (!$opt{tell}) {
service_unavailable_error("TELL commands have not been enabled.");
@@ -1610,7 +1682,13 @@
my $resp = "EX_OK";

# generate mail object from input
- my ($mail, $actual_length) = parse_body($client, $expected_length);
+ my ($mail, $actual_length) = parse_body($client, $expected_length,
+ $compress_zlib);
+ return 0 unless defined($mail); # error
+
+ if ($compress_zlib) {
+ $expected_length = $actual_length; # previously it was the gzipped length
+ }

if ( $mail->get_header("X-Spam-Checker-Version") ) {
my $new_mail = $spamtest->parse($spamtest->remove_spamassassin_markup($mail), 1);
@@ -1729,6 +1807,9 @@
elsif ($header eq 'Remove') {
return 0 unless &got_remove_header($hdrs, $header, $value);
}
+ elsif ($header eq 'Compress') {
+ return 0 unless &got_compress_header($hdrs, $header, $value);
+ }
}

# avoid too-many-headers DOS attack
@@ -1846,6 +1927,25 @@

if ($value =~ /remote/i) {
$hdrs->{remove_remote} = 1;
+ }
+
+ return 1;
+}
+
+sub got_compress_header {
+ my ($hdrs, $header, $value) = @_;
+
+ if ($value =~ /zlib/i) {
+ eval { require Compress::Zlib; };
+ if ($@) {
+ protocol_error("(compression not supported, Compress::Zlib not installed)");
+ return 0;
+ }
+ $hdrs->{compress_zlib} = 1;
+ }
+ else {
+ protocol_error("(compression type not supported)");
+ return 0;
}

return 1;

Added: spamassassin/trunk/t/spamc_z.t
URL: http://svn.apache.org/viewvc/spamassassin/trunk/t/spamc_z.t?view=auto&rev=494093
==============================================================================
--- spamassassin/trunk/t/spamc_z.t (added)
+++ spamassassin/trunk/t/spamc_z.t Mon Jan 8 07:33:53 2007
@@ -0,0 +1,31 @@
+#!/usr/bin/perl
+
+use constant HAVE_ZLIB => eval { require Compress::Zlib; };
+
+use lib '.'; use lib 't';
+use SATest; sa_t_init("spamc_z");
+use Test; plan tests => (($SKIP_SPAMD_TESTS || !HAVE_ZLIB) ? 0 : 9);
+
+exit if ($SKIP_SPAMD_TESTS || !HAVE_ZLIB);
+
+# ---------------------------------------------------------------------------
+
+%patterns = (
+
+q{ Return-Path: sb55sb55@yahoo.com}, 'firstline',
+q{ Subject: There yours for FREE!}, 'subj',
+q{ X-Spam-Status: Yes, score=}, 'status',
+q{ X-Spam-Flag: YES}, 'flag',
+q{ X-Spam-Level: **********}, 'stars',
+q{ TEST_ENDSNUMS}, 'endsinnums',
+q{ TEST_NOREALNAME}, 'noreal',
+q{ This must be the very last line}, 'lastline',
+
+
+);
+
+ok (sdrun ("-L",
+ "-z < data/spam/001",
+ \&patterns_run_cb));
+ok_all_patterns();
+