ports/164191: [maintainer update] Update japanese/p5-Mail-SpamAssassin

Masaki TAGAWA masaki at club.kyutech.ac.jp
Mon Jan 16 03:50:11 UTC 2012


>Number:         164191
>Category:       ports
>Synopsis:       [maintainer update] Update japanese/p5-Mail-SpamAssassin
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-ports-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          maintainer-update
>Submitter-Id:   current-users
>Arrival-Date:   Mon Jan 16 03:50:10 UTC 2012
>Closed-Date:
>Last-Modified:
>Originator:     Masaki TAGAWA
>Release:        FreeBSD 8.2-RELEASE-p5 amd64
>Organization:
Kyushu Institute of Technology
>Environment:
System: FreeBSD sakura.mochipon.com 8.2-RELEASE-p5 FreeBSD 8.2-RELEASE-p5 #2: Thu Jan  5 19:32:16 JST 2012     root at sakura.mochipon.com:/usr/obj/usr/src/sys/SAKURA-VPS  amd64
>Description:
	- Update japanese/p5-Mail-SpamAssassin to move it to be a proper slave
		- Follow mail/p5-Mail-SpamAssassin 3.3.2_6
>How-To-Repeat:
	
>Fix:

	

--- patch.txt begins here ---
diff -ruN /usr/ports/japanese/p5-Mail-SpamAssassin/Makefile ja-p5-Mail-SpamAssassin/Makefile
--- /usr/ports/japanese/p5-Mail-SpamAssassin/Makefile	2012-01-15 01:19:12.000000000 +0900
+++ ja-p5-Mail-SpamAssassin/Makefile	2012-01-16 09:56:02.610919593 +0900
@@ -7,12 +7,12 @@
 
 PORTNAME=	Mail-SpamAssassin
 PORTVERSION=	3.3.2
-PORTREVISION=	1
+PORTREVISION=	2
 CATEGORIES=	japanese mail perl5
 MASTER_SITES=	${MASTER_SITE_APACHE:S/$/:apache/} ${MASTER_SITE_PERL_CPAN:S/$/:cpan/} \
 		${PATCH_SITES}
 MASTER_SITE_SUBDIR=	spamassassin/source/:apache Mail/:cpan
-PKGNAMEPREFIX=	ja-p5-
+PKGNAMEPREFIX?=	ja-p5-
 DISTFILES=	${DISTNAME}${EXTRACT_SUFX}:apache,cpan \
 		${TOKENIZER_PRE}:JA ${DOCJA}:JA
 DIST_SUBDIR=	ja-spamassassin
@@ -23,37 +23,35 @@
 PATCHLEVEL=	1
 PATCH_DIST_STRIP=	-p1
 
-MAINTAINER=	ports at FreeBSD.org
+MAINTAINER=	masaki at club.kyutech.ac.jp
 COMMENT=	SpamAssassin with Japanese tokenizer
 
 RUN_DEPENDS=	p5-NetAddr-IP>=4.00.7:${PORTSDIR}/net-mgmt/p5-NetAddr-IP \
 		p5-Net-DNS>=0.63:${PORTSDIR}/dns/p5-Net-DNS \
 		p5-HTML-Parser>=3.46:${PORTSDIR}/www/p5-HTML-Parser \
 		p5-libwww>=0:${PORTSDIR}/www/p5-libwww \
-		p5-Encode-Detect>=0:${PORTSDIR}/converters/p5-Encode-Detect \
-		p5-Mail-Tools>=0:${PORTSDIR}/mail/p5-Mail-Tools \
+		${SITE_PERL}/${PERL_ARCH}/Encode/Detect.pm:${PORTSDIR}/converters/p5-Encode-Detect \
+		${SITE_PERL}/Mail/Internet.pm:${PORTSDIR}/mail/p5-Mail-Tools \
 		ja-p5-MeCab>=0.98:${PORTSDIR}/japanese/p5-MeCab
 BUILD_DEPENDS=	p5-NetAddr-IP>=4.00.7:${PORTSDIR}/net-mgmt/p5-NetAddr-IP \
 		p5-Net-DNS>=0.63:${PORTSDIR}/dns/p5-Net-DNS \
 		p5-HTML-Parser>=3.46:${PORTSDIR}/www/p5-HTML-Parser \
 		p5-libwww>=0:${PORTSDIR}/www/p5-libwww \
-		p5-Encode-Detect>=0:${PORTSDIR}/converters/p5-Encode-Detect \
-		p5-Mail-Tools>=0:${PORTSDIR}/mail/p5-Mail-Tools
+		${SITE_PERL}/${PERL_ARCH}/Encode/Detect.pm:${PORTSDIR}/converters/p5-Encode-Detect \
+		${SITE_PERL}/Mail/Internet.pm:${PORTSDIR}/mail/p5-Mail-Tools
 
 CONFLICTS=	p5-Mail-SpamAssassin-[0-9]*
 
 PERL_CONFIGURE=	yes
 USE_PERL5_RUN=	5.8.8+
 USE_LDCONFIG=	yes
+DBDIR?=     /var/db
+CONTACT_ADDRESS?=   The administrator of that system
+USERS?=     spamd
+GROUPS?=    spamd
 CONFIGURE_ARGS=	SYSCONFDIR="${PREFIX}/etc" \
 	       	CONTACT_ADDRESS="${CONTACT_ADDRESS}" \
-		LOCALSTATEDIR="/var/db/spamassassin"
-
-USERS=		spamd
-GROUPS=		spamd
-
-# You can override it if you like
-CONTACT_ADDRESS?=	The administrator of that system
+		LOCALSTATEDIR="${DBDIR}/spamassassin"
 
 OPTIONS=	AS_ROOT "Run spamd as root (recommended)" on \
 		SPAMC "Build spamd/spamc (not for amavisd)" on \
@@ -68,6 +66,9 @@
 		RELAY_COUNTRY "Relay country support" off \
 		DCC "Add DCC support (see LICENSE)" off
 
+SUB_FILES=  pkg-install
+SUB_LIST=   USER=${USERS} GROUP=${GROUPS} INSTALL="${INSTALL}"
+
 .if !defined(WITHOUT_SSL)
 USE_OPENSSL=	yes
 .endif
@@ -139,7 +140,11 @@
 RUN_DEPENDS+=	${SITE_PERL}/${PERL_ARCH}/Digest/SHA.pm:${PORTSDIR}/security/p5-Digest-SHA
 . endif
 RUN_DEPENDS+=	p5-Mail-DKIM>=0.37:${PORTSDIR}/mail/p5-Mail-DKIM
+. if ${PERL_LEVEL} < 501400
+RUN_DEPENDS+=	p5-Crypt-OpenSSL-RSA>=0.24:${PORTSDIR}/security/p5-Crypt-OpenSSL-RSA
+. else
 RUN_DEPENDS+=	p5-Crypt-OpenSSL-RSA>=0.26_1:${PORTSDIR}/security/p5-Crypt-OpenSSL-RSA
+. endif
 .endif
 
 .if defined(WITH_SACOMPILE)
@@ -154,79 +159,7 @@
 RUN_DEPENDS+=	dcc-dccd>=1.3.111:${PORTSDIR}/mail/dcc-dccd
 .endif
 
-MAN3=		Mail::SpamAssassin.3 \
-		Mail::SpamAssassin::AICache.3 \
-		Mail::SpamAssassin::ArchiveIterator.3 \
-		Mail::SpamAssassin::AsyncLoop.3 \
-		Mail::SpamAssassin::AutoWhitelist.3 \
-		Mail::SpamAssassin::Bayes.3 \
-		Mail::SpamAssassin::BayesStore.3 \
-		Mail::SpamAssassin::BayesStore::BDB.3 \
-		Mail::SpamAssassin::BayesStore::MySQL.3 \
-		Mail::SpamAssassin::BayesStore::PgSQL.3 \
-		Mail::SpamAssassin::BayesStore::SQL.3 \
-		Mail::SpamAssassin::Client.3 \
-		Mail::SpamAssassin::Conf.3 \
-		Mail::SpamAssassin::Conf::LDAP.3 \
-		Mail::SpamAssassin::Conf::Parser.3 \
-		Mail::SpamAssassin::Conf::SQL.3 \
-		Mail::SpamAssassin::DnsResolver.3 \
-		Mail::SpamAssassin::Logger.3 \
-		Mail::SpamAssassin::Logger::File.3 \
-		Mail::SpamAssassin::Logger::Stderr.3 \
-		Mail::SpamAssassin::Logger::Syslog.3 \
-		Mail::SpamAssassin::Message.3 \
-		Mail::SpamAssassin::Message::Metadata.3 \
-		Mail::SpamAssassin::Message::Node.3 \
-		Mail::SpamAssassin::PerMsgLearner.3 \
-		Mail::SpamAssassin::PerMsgStatus.3 \
-		Mail::SpamAssassin::PersistentAddrList.3 \
-		Mail::SpamAssassin::Plugin.3 \
-		Mail::SpamAssassin::Plugin::ASN.3 \
-		Mail::SpamAssassin::Plugin::AWL.3 \
-		Mail::SpamAssassin::Plugin::AccessDB.3 \
-		Mail::SpamAssassin::Plugin::AntiVirus.3 \
-		Mail::SpamAssassin::Plugin::AutoLearnThreshold.3 \
-		Mail::SpamAssassin::Plugin::Bayes.3 \
-		Mail::SpamAssassin::Plugin::BodyRuleBaseExtractor.3 \
-		Mail::SpamAssassin::Plugin::Check.3 \
-		Mail::SpamAssassin::Plugin::DCC.3 \
-		Mail::SpamAssassin::Plugin::DKIM.3 \
-		Mail::SpamAssassin::Plugin::Hashcash.3 \
-		Mail::SpamAssassin::Plugin::MIMEHeader.3 \
-		Mail::SpamAssassin::Plugin::OneLineBodyRuleType.3 \
-		Mail::SpamAssassin::Plugin::PhishTag.3 \
-		Mail::SpamAssassin::Plugin::Pyzor.3 \
-		Mail::SpamAssassin::Plugin::Razor2.3 \
-		Mail::SpamAssassin::Plugin::RelayCountry.3 \
-		Mail::SpamAssassin::Plugin::ReplaceTags.3 \
-		Mail::SpamAssassin::Plugin::Reuse.3 \
-		Mail::SpamAssassin::Plugin::Rule2XSBody.3 \
-		Mail::SpamAssassin::Plugin::SPF.3 \
-		Mail::SpamAssassin::Plugin::Shortcircuit.3 \
-		Mail::SpamAssassin::Plugin::SpamCop.3 \
-		Mail::SpamAssassin::Plugin::Test.3 \
-		Mail::SpamAssassin::Plugin::TextCat.3 \
-		Mail::SpamAssassin::Plugin::Tokenizer.3 \
-		Mail::SpamAssassin::Plugin::Tokenizer::MeCab.3 \
-		Mail::SpamAssassin::Plugin::Tokenizer::SimpleJA.3 \
-		Mail::SpamAssassin::Plugin::URIDNSBL.3 \
-		Mail::SpamAssassin::Plugin::URIDetail.3 \
-		Mail::SpamAssassin::Plugin::VBounce.3 \
-		Mail::SpamAssassin::Plugin::WhiteListSubject.3 \
-		Mail::SpamAssassin::PluginHandler.3 \
-		Mail::SpamAssassin::SQLBasedAddrList.3 \
-		Mail::SpamAssassin::SubProcBackChannel.3 \
-		Mail::SpamAssassin::Timeout.3 \
-		Mail::SpamAssassin::Util.3 \
-		Mail::SpamAssassin::Util::Charset.3 \
-		Mail::SpamAssassin::Util::DependencyInfo.3 \
-		Mail::SpamAssassin::Util::Progress.3 \
-		Mail::SpamAssassin::Util::RegistrarBoundaries.3 \
-		spamassassin-run.3
-
-MAN1=		spamd.1 spamassassin.1 spamc.1 sa-learn.1 sa-update.1 \
-		spamassassin-run.1 sa-compile.1 sa-awl.1
+.include "${FILESDIR}/manpages"
 
 DOCSDIR=	${PREFIX}/share/doc/${PKGNAMEPREFIX}${PORTNAME}
 DATADIR=	${PREFIX}/share/spamassassin
@@ -278,16 +211,10 @@
 .if defined(WITH_DCC)
 	${REINPLACE_CMD} -e '/DCC/s/^#loadplugin/loadplugin/' ${WRKSRC}/rules/v310.pre
 .endif
-.if !defined(WITH_AWL)
-	${REINPLACE_CMD} -e '/AWL/s/^loadplugin/#loadplugin/' ${WRKSRC}/rules/v310.pre
-.endif
 .if defined(WITH_SACOMPILE)
 	${REINPLACE_CMD} -e '/Rule2XSBody/s/^# loadplugin/loadplugin/' ${WRKSRC}/rules/v320.pre
 .endif
 
-pre-install:
-	@${MKDIR}  ${DATADIR}
-
 post-build:
 	@(cd ${BUILD_WRKSRC}; ${SETENV} ${MAKE_ENV} ${MAKE} ${MAKE_FLAGS} ${MAKEFILE} ${MAKE_ARGS} spamc/libspamc.so)
 .if !defined(WITHOUT_SSL)
@@ -295,7 +222,7 @@
 .endif
 
 pre-su-install:
-	@USER=${USERS} GROUP=${GROUPS} ${SH} ${PKGINSTALL} ${PKGNAME} PRE-INSTALL
+	@${MKDIR} ${DATADIR}
 	@${INSTALL_PROGRAM} ${WRKSRC}/spamc/libspamc.so ${PREFIX}/lib/libspamc.so.0
 	@${LN} -sf libspamc.so.0 ${PREFIX}/lib/libspamc.so
 .if !defined(WITHOUT_SSL)
@@ -320,11 +247,10 @@
 	@[ -f ${PREFIX}/etc/mail/spamassassin/v320.pre ] || \
 		${CP} ${PREFIX}/etc/mail/spamassassin/v320.pre.sample \
 			${PREFIX}/etc/mail/spamassassin/v320.pre
-	@PKG_PREFIX=${PREFIX} BATCH=${BATCH} SU_CMD="${SU_CMD}" USER=${USERS} GROUP=${GROUPS} ${SH} ${PKGDIR}/pkg-install ${PKGNAME} POST-INSTALL
 	@[ -f ${PREFIX}/etc/mail/spamassassin/v330.pre ] || \
 		${CP} ${PREFIX}/etc/mail/spamassassin/v330.pre.sample \
 			${PREFIX}/etc/mail/spamassassin/v330.pre
-
+	@${SH} ${PKGINSTALL} ${PKGNAME} POST-INSTALL
 	@${CP} ${DISTDIR}/${DIST_SUBDIR}/${TOKENIZER_PRE} ${PREFIX}/etc/mail/spamassassin/${TOKENIZER_PRE}.sample
 	@[ -f ${PREFIX}/etc/mail/spamassassin/${TOKENIZER_PRE} ] || \
 		${CP} ${PREFIX}/etc/mail/spamassassin/${TOKENIZER_PRE}.sample \
diff -ruN /usr/ports/japanese/p5-Mail-SpamAssassin/files/manpages ja-p5-Mail-SpamAssassin/files/manpages
--- /usr/ports/japanese/p5-Mail-SpamAssassin/files/manpages	1970-01-01 09:00:00.000000000 +0900
+++ ja-p5-Mail-SpamAssassin/files/manpages	2012-01-16 09:28:59.696265468 +0900
@@ -0,0 +1,71 @@
+# $FreeBSD: ports/mail/p5-Mail-SpamAssassin/files/manpages,v 1.1 2011/12/31 14:17:03 scheidell Exp $
+MAN3=		Mail::SpamAssassin.3 \
+		Mail::SpamAssassin::AICache.3 \
+		Mail::SpamAssassin::ArchiveIterator.3 \
+		Mail::SpamAssassin::AsyncLoop.3 \
+		Mail::SpamAssassin::AutoWhitelist.3 \
+		Mail::SpamAssassin::Bayes.3 \
+		Mail::SpamAssassin::BayesStore.3 \
+		Mail::SpamAssassin::BayesStore::BDB.3 \
+		Mail::SpamAssassin::BayesStore::MySQL.3 \
+		Mail::SpamAssassin::BayesStore::PgSQL.3 \
+		Mail::SpamAssassin::BayesStore::SQL.3 \
+		Mail::SpamAssassin::Client.3 \
+		Mail::SpamAssassin::Conf.3 \
+		Mail::SpamAssassin::Conf::LDAP.3 \
+		Mail::SpamAssassin::Conf::Parser.3 \
+		Mail::SpamAssassin::Conf::SQL.3 \
+		Mail::SpamAssassin::DnsResolver.3 \
+		Mail::SpamAssassin::Logger.3 \
+		Mail::SpamAssassin::Logger::File.3 \
+		Mail::SpamAssassin::Logger::Stderr.3 \
+		Mail::SpamAssassin::Logger::Syslog.3 \
+		Mail::SpamAssassin::Message.3 \
+		Mail::SpamAssassin::Message::Metadata.3 \
+		Mail::SpamAssassin::Message::Node.3 \
+		Mail::SpamAssassin::PerMsgLearner.3 \
+		Mail::SpamAssassin::PerMsgStatus.3 \
+		Mail::SpamAssassin::PersistentAddrList.3 \
+		Mail::SpamAssassin::Plugin.3 \
+		Mail::SpamAssassin::Plugin::ASN.3 \
+		Mail::SpamAssassin::Plugin::AWL.3 \
+		Mail::SpamAssassin::Plugin::AccessDB.3 \
+		Mail::SpamAssassin::Plugin::AntiVirus.3 \
+		Mail::SpamAssassin::Plugin::AutoLearnThreshold.3 \
+		Mail::SpamAssassin::Plugin::Bayes.3 \
+		Mail::SpamAssassin::Plugin::BodyRuleBaseExtractor.3 \
+		Mail::SpamAssassin::Plugin::Check.3 \
+		Mail::SpamAssassin::Plugin::DCC.3 \
+		Mail::SpamAssassin::Plugin::DKIM.3 \
+		Mail::SpamAssassin::Plugin::Hashcash.3 \
+		Mail::SpamAssassin::Plugin::MIMEHeader.3 \
+		Mail::SpamAssassin::Plugin::OneLineBodyRuleType.3 \
+		Mail::SpamAssassin::Plugin::PhishTag.3 \
+		Mail::SpamAssassin::Plugin::Pyzor.3 \
+		Mail::SpamAssassin::Plugin::Razor2.3 \
+		Mail::SpamAssassin::Plugin::RelayCountry.3 \
+		Mail::SpamAssassin::Plugin::ReplaceTags.3 \
+		Mail::SpamAssassin::Plugin::Reuse.3 \
+		Mail::SpamAssassin::Plugin::Rule2XSBody.3 \
+		Mail::SpamAssassin::Plugin::SPF.3 \
+		Mail::SpamAssassin::Plugin::Shortcircuit.3 \
+		Mail::SpamAssassin::Plugin::SpamCop.3 \
+		Mail::SpamAssassin::Plugin::Test.3 \
+		Mail::SpamAssassin::Plugin::TextCat.3 \
+		Mail::SpamAssassin::Plugin::URIDNSBL.3 \
+		Mail::SpamAssassin::Plugin::URIDetail.3 \
+		Mail::SpamAssassin::Plugin::VBounce.3 \
+		Mail::SpamAssassin::Plugin::WhiteListSubject.3 \
+		Mail::SpamAssassin::PluginHandler.3 \
+		Mail::SpamAssassin::SQLBasedAddrList.3 \
+		Mail::SpamAssassin::SubProcBackChannel.3 \
+		Mail::SpamAssassin::Timeout.3 \
+		Mail::SpamAssassin::Util.3 \
+		Mail::SpamAssassin::Util::DependencyInfo.3 \
+		Mail::SpamAssassin::Util::Progress.3 \
+		Mail::SpamAssassin::Util::RegistrarBoundaries.3 \
+		spamassassin-run.3
+
+MAN1=		spamd.1 spamassassin.1 spamc.1 sa-learn.1 sa-update.1 \
+		spamassassin-run.1 sa-compile.1 sa-awl.1
+
diff -ruN /usr/ports/japanese/p5-Mail-SpamAssassin/files/patch-bug6624 ja-p5-Mail-SpamAssassin/files/patch-bug6624
--- /usr/ports/japanese/p5-Mail-SpamAssassin/files/patch-bug6624	1970-01-01 09:00:00.000000000 +0900
+++ ja-p5-Mail-SpamAssassin/files/patch-bug6624	2012-01-16 09:28:59.696265468 +0900
@@ -0,0 +1,88 @@
+--- lib/Mail/SpamAssassin/BayesStore/MySQL.pm	(revision 1138970)
++++ lib/Mail/SpamAssassin/BayesStore/MySQL.pm	(working copy)
+@@ -840,14 +840,28 @@
+       return 0;
+     }
+ 
++    # With ON DUPLICATE KEY UPDATE, the affected-rows value per row is 1 if
++    # the row is inserted as a new row and 2 if an existing row is updated.
++    #
++    # Due to a MySQL server bug a value of 3 can be seen.
++    # See: http://bugs.mysql.com/bug.php?id=46675
++    #   When executing the INSERT ... ON DUPLICATE KEY UPDATE statement
++    #   and checking the rows return count:
++    #   mysql_client_found_rows = 0: The second INSERT returns a row count
++    #                                of 2 in all MySQL versions.
++    #   mysql_client_found_rows = 1: The second INSERT returns this row count:
++    #     Before MySQL 5.1.20: 2
++    #     MySQL 5.1.20: undef on Mac OS X, 139775481 on Linux (garbage?)
++    #     MySQL 5.1.21 and up: 3
++    #
+     my $num_rows = $rc;
+ 
+     $sth->finish();
+ 
+-    if ($num_rows == 1 || $num_rows == 2) {
++    if ($num_rows == 1 || $num_rows == 2 || $num_rows == 3) {
+       my $token_count_update = '';
+       
+-      $token_count_update = "token_count = token_count + 1," if ($num_rows == 1);
++      $token_count_update = "token_count = token_count + 1," if $num_rows == 1;
+       $sql = "UPDATE bayes_vars SET
+                      $token_count_update
+                      newest_token_age = GREATEST(newest_token_age, ?),
+@@ -872,7 +886,11 @@
+     }
+     else {
+       # $num_rows was not what we expected
+-      dbg("bayes: _put_token: Updated an unexpected number of rows.");
++      my $token_displ = $token;
++      $token_displ =~ s/(.)/sprintf('%02x',ord($1))/egs;
++      dbg("bayes: _put_token: Updated an unexpected number of rows: %s, ".
++          "id: %s, token (hex): %s",
++          $num_rows, $self->{_userid}, $token_displ);
+       $self->{_dbh}->rollback();
+       return 0;
+     }
+@@ -987,8 +1005,24 @@
+       else {
+ 	my $num_rows = $rc;
+ 
+-	$need_atime_update_p = 1 if ($num_rows == 1 || $num_rows == 2);
+-	$new_tokens++ if ($num_rows == 1);
++        # With ON DUPLICATE KEY UPDATE, the affected-rows value per row is 1 if
++        # the row is inserted as a new row and 2 if an existing row is updated.
++        # But see MySQL bug (as above): http://bugs.mysql.com/bug.php?id=46675
++
++        if ($num_rows == 1) {
++          $new_tokens++;
++          $need_atime_update_p = 1;
++        } elsif ($num_rows == 2 || $num_rows == 3) {
++          $need_atime_update_p = 1;
++        } else {
++          # $num_rows was not what we expected
++          my $token_displ = $token;
++          $token_displ =~ s/(.)/sprintf('%02x',ord($1))/egs;
++          dbg("bayes: _put_tokens: Updated an unexpected number of rows: %s, ".
++              "id: %s, token (hex): %s",
++              $num_rows, $self->{_userid}, $token_displ);
++          $error_p = 1;
++        }
+       }
+     }
+ 
+@@ -1026,10 +1060,10 @@
+       }
+     }
+     else {
+-      # $num_rows was not what we expected
+-      dbg("bayes: _put_tokens: Updated an unexpected number of rows.");
+-      $self->{_dbh}->rollback();
+-      return 0;
++      info("bayes: _put_tokens: no atime updates needed?  Num of tokens: %d",
++           scalar keys %{$tokens});
++#     $self->{_dbh}->rollback();
++#     return 0;
+     }
+   }
+ 
diff -ruN /usr/ports/japanese/p5-Mail-SpamAssassin/files/patch-bug6655 ja-p5-Mail-SpamAssassin/files/patch-bug6655
--- /usr/ports/japanese/p5-Mail-SpamAssassin/files/patch-bug6655	1970-01-01 09:00:00.000000000 +0900
+++ ja-p5-Mail-SpamAssassin/files/patch-bug6655	2012-01-16 09:28:59.696265468 +0900
@@ -0,0 +1,50 @@
+$FreeBSD: ports/mail/p5-Mail-SpamAssassin/files/patch-bug6655,v 1.1 2011/08/30 12:43:25 crees Exp $
+
+https://issues.apache.org/SpamAssassin/show_bug.cgi?id=6655
+
+--- lib/Mail/SpamAssassin/Util.pm	2011-06-06 19:59:17.000000000 -0400
++++ lib/Mail/SpamAssassin/Util.pm	2011-08-26 17:12:19.000000000 -0400
+@@ -1025,6 +1024,8 @@
+     return;
+   }
+ 
++  opendir(my $dh, $tmpdir) || die "Could not open $tmpdir: $!";
++  closedir $dh;
+   my ($reportfile, $tmpfile);
+   my $umask = umask 077;
+ 
+@@ -1052,7 +1053,10 @@
+ 
+     # ensure the file handle is not semi-open in some way
+     if ($tmpfile) {
+-      close $tmpfile  or info("error closing $reportfile: $!");
++      if (! close $tmpfile) {
++       info("error closing $reportfile: $!");
++       $tmpfile=undef;
++      }
+     }
+   }
+
+--- sa-update.raw    2011-06-24 13:38:50.000000000 -0400
++++ sa-update.raw    2011-08-29 09:38:50.000000000 -0400
+@@ -677,9 +677,9 @@
+ 
+   # Write the content out to a temp file for GPG/Archive::Tar interaction
+   dbg("channel: populating temp content file");
+-  open(TMP, ">$content_file") || die "fatal: can't write to content temp file $content_file: $!\n";
++  open(TMP, ">$content_file") || die "fatal: couldn't create content temp file $content_file: $!\n";
+   binmode TMP;
+-  print TMP $content;
++  print TMP $content || die "fatal: can't write to content temp file $content_file: $!\n";
+   close(TMP);
+ 
+   # to sign  : gpg -bas file
+@@ -695,7 +695,7 @@
+       die "fatal: couldn't create temp file for GPG signature: $!\n";
+     }
+     binmode $tfh;
+-    print $tfh $GPG;
++    print $tfh $GPG || die "fatal: can't write temp file for GPG signature: $!\n";
+     close($tfh);
+ 
+     dbg("gpg: calling gpg");
diff -ruN /usr/ports/japanese/p5-Mail-SpamAssassin/files/patch-bug6698 ja-p5-Mail-SpamAssassin/files/patch-bug6698
--- /usr/ports/japanese/p5-Mail-SpamAssassin/files/patch-bug6698	1970-01-01 09:00:00.000000000 +0900
+++ ja-p5-Mail-SpamAssassin/files/patch-bug6698	2012-01-16 09:28:59.696265468 +0900
@@ -0,0 +1,1471 @@
+--- lib/Mail/SpamAssassin/Plugin/DCC.pm	2011-06-06 19:59:17.000000000 -0400
++++ lib/Mail/SpamAssassin/Plugin/DCC.pm	2011-11-26 07:22:36.000000000 -0500
+@@ -15,6 +15,20 @@
+ # limitations under the License.
+ # </@LICENSE>
+ 
++# Changes since SpamAssassin 3.3.2:
++#   support for DCC learning.  See dcc_learn_score.
++#   deal with orphan dccifd sockets
++#   use `cdcc -q` to not stall waiting to find a DCC server when deciding
++#     whether DCC checks are enabled
++#   use dccproc -Q or dccifd query if a pre-existing X-DCC header shows
++#     the message has already been reported
++#   dccproc now uses -w /var/dcc/whiteclnt so it acts more like dccifd
++#   warn about the use of ancient versions of dccproc and dccifd
++#   turn off dccifd greylisting
++#   query instead of reporting mail messages that contain X-DCC headers and
++#     and so has probably already been reported
++#   try harder to find dccproc and cdcc when not explicitly configured
++
+ =head1 NAME
+ 
+ Mail::SpamAssassin::Plugin::DCC - perform DCC check of messages
+@@ -30,30 +44,31 @@
+ 
+ The DCC or Distributed Checksum Clearinghouse is a system of servers
+ collecting and counting checksums of millions of mail messages.
+-TheSpamAssassin.pm counts can be used by SpamAssassin to detect and
+-reject or filter spam.
+-
+-Because simplistic checksums of spam can be easily defeated, the main
+-DCC checksums are fuzzy and ignore aspects of messages.  The fuzzy
+-checksums are changed as spam evolves.
++The counts can be used by SpamAssassin to detect and filter spam.
+ 
+-Note that DCC is disabled by default in C<init.pre> because it is not
+-open source.  See the DCC license for more details.
++See http://www.dcc-servers.net/dcc/ for more information about DCC.
+ 
+-See http://www.rhyolite.com/anti-spam/dcc/ for more information about
+-DCC.
++Note that DCC is disabled by default in C<v310.pre> because its use requires
++software that is not distributed with SpamAssassin and that has license
++restrictions for certain commercial uses.
++See the DCC license at http://www.dcc-servers.net/dcc/LICENSE for details.
++
++Enable it by uncommenting the "loadplugin Mail::SpamAssassin::Plugin::DCC"
++confdir/v310.pre or by adding this line to your local.pre.  It might also
++be necessary to install a DCC package, port, rpm, or equivalent from your
++operating system distributor or a tarball from the primary DCC source
++at http://www.dcc-servers.net/dcc/#download
++See also http://www.dcc-servers.net/dcc/INSTALL.html
+ 
+ =head1 TAGS
+ 
+ The following tags are added to the set, available for use in reports,
+ header fields, other plugins, etc.:
+ 
+-  _DCCB_    DCC server ID in a response
+-  _DCCR_    response from DCC - header field body in X-DCC-*-Metrics
+-  _DCCREP_  response from DCC - DCC reputation in percents (0..100)
+-
+-Tag _DCCREP_ provides a nonempty value only with commercial DCC systems.
+-This is the percentage of spam vs. ham sent from the first untrusted relay.
++  _DCCB_    DCC server ID in X-DCC-*-Metrics header field name
++  _DCCR_    X-DCC-*-Metrics header field body
++  _DCCREP_  DCC Reputation or percent bulk mail (0..100) from
++	      commercial DCC software
+ 
+ =cut
+ 
+@@ -75,8 +90,6 @@
+ use vars qw(@ISA);
+ @ISA = qw(Mail::SpamAssassin::Plugin);
+ 
+-use vars qw($have_inet6);
+-
+ sub new {
+   my $class = shift;
+   my $mailsaobject = shift;
+@@ -87,7 +100,7 @@
+ 
+   # are network tests enabled?
+   if ($mailsaobject->{local_tests_only}) {
+-    $self->{dcc_disabled} = 1;
++    $self->{use_dcc} = 0;
+     dbg("dcc: local tests only, disabling DCC");
+   }
+   else {
+@@ -128,20 +141,23 @@
+ 
+ =item dcc_fuz2_max NUMBER
+ 
+-This option sets how often a message's body/fuz1/fuz2 checksum must have been
+-reported to the DCC server before SpamAssassin will consider the DCC check as
+-matched.
+-
+-As nearly all DCC clients are auto-reporting these checksums, you should set
+-this to a relatively high value, e.g. C<999999> (this is DCC's MANY count).
++Sets how often a message's body/fuz1/fuz2 checksum must have been reported
++to the DCC server before SpamAssassin will consider the DCC check hit.
++C<999999> is DCC's MANY count.
+ 
+ The default is C<999999> for all these options.
+ 
+ =item dcc_rep_percent NUMBER
+ 
+-Only commercial DCC systems provide DCC reputation information. This is the
+-percentage of spam vs. ham sent from the first untrusted relay.  It will hit
+-on new spam from spam sources.  Default is C<90>.
++Only the commercial DCC software provides DCC Reputations.  A DCC Reputation
++is the percentage of bulk mail received from the last untrusted relay in the
++path taken by a mail message as measured by all commercial DCC installations.
++See http://www.rhyolite.com/dcc/reputations.html
++You C<must> whitelist your trusted relays or MX servers with MX or
++MXDCC lines in /var/dcc/whiteclnt as described in the main DCC man page
++to avoid seeing your own MX servers as sources of bulk mail.
++See http://www.dcc-servers.net/dcc/dcc-tree/dcc.html#White-and-Blacklists
++The default is C<90>.
+ 
+ =cut
+ 
+@@ -189,13 +205,9 @@
+ =item dcc_home STRING
+ 
+ This option tells SpamAssassin where to find the dcc homedir.
+-If not given, it will try to get dcc to specify one, and if that fails it
+-will try dcc's own default homedir of '/var/dcc'.
+-If C<dcc_path> is not specified, it will default to looking in
+-C<dcc_home/bin> for dcc client instead of relying on SpamAssassin to find it
+-in the current PATH.  If it isn't found there, it will look in the current
+-PATH. If a C<dccifd> socket is found in C<dcc_home> or specified explicitly,
+-it will use that interface instead of C<dccproc>.
++If not specified, try to use the locally configured directory
++from the C<cdcc homedir> command.
++Try /var/dcc if that command fails.
+ 
+ =cut
+ 
+@@ -205,7 +217,7 @@
+     type => $Mail::SpamAssassin::Conf::CONF_TYPE_STRING,
+     code => sub {
+       my ($self, $key, $value, $line) = @_;
+-      if (!defined $value || !length $value) {
++      if (!defined $value || $value eq '') {
+ 	return $Mail::SpamAssassin::Conf::MISSING_REQUIRED_VALUE;
+       }
+       $value = untaint_file_path($value);
+@@ -223,14 +235,16 @@
+ 
+ =item dcc_dccifd_path STRING
+ 
+-This option tells SpamAssassin where to find the dccifd socket. If
+-C<dcc_dccifd_path> is not specified, it will default to looking for a socket
+-named C<dccifd> in a directory C<dcc_home>.  The C<dcc_dccifd_path> can be
+-a Unix socket name (absolute path), or an INET socket specification in a form
+-C<[host]:port> or C<host:port>, where a host can be an IPv4 or IPv6 address
+-or a host name, and port is a TCP port number. In case of an IPv6 address the
+-brackets are required syntax. If a C<dccifd> socket is found, the plugin will
+-use it instead of C<dccproc>.
++This option tells SpamAssassin where to find the dccifd socket instead
++of a local Unix socket named C<dccifd> in the C<dcc_home> directory.
++If a socket is specified or found, use it instead of C<dccproc>.
++
++If specifed, C<dcc_dccifd_path> is the absolute path of local Unix socket
++or an INET socket specified as C<[Host]:Port> or C<Host:Port>.
++Host can be an IPv4 or IPv6 address or a host name
++Port is a TCP port number. The brackets are required for an IPv6 address.
++
++The default is C<undef>.
+ 
+ =cut
+ 
+@@ -240,45 +254,60 @@
+     type => $Mail::SpamAssassin::Conf::CONF_TYPE_STRING,
+     code => sub {
+       my ($self, $key, $value, $line) = @_;
+-      $value = ''  if !defined $value;
+-      $self->{dcc_dccifd_path_raw} = $value;  # for logging purposes
+-      undef $self->{dcc_dccifd_host};
+-      undef $self->{dcc_dccifd_port};
+-      undef $self->{dcc_dccifd_socket};
+-      local($1,$2,$3);
+-      if ($value eq '') {
++
++      if (!defined $value || $value eq '') {
+ 	return $Mail::SpamAssassin::Conf::MISSING_REQUIRED_VALUE;
+-      } elsif ($value =~ m{^ (?: \[ ([^\]]*) \] | ([^:]*) ) : ([^:]*) \z}sx) {
+-        # "[host]:port" or "host:port", where a host can be an IPv4 or IPv6
+-        # address or a host name, and port is a TCP port number or service name
+-        my $host = defined $1 ? $1 : $2;
+-        my $port = $3;
+-        $self->{dcc_dccifd_host} = untaint_var($host);
+-        $self->{dcc_dccifd_port} = untaint_var($port);
+-        dbg("config: dcc_dccifd_path set to [%s]:%s", $host,$port);
+-      } else {  # assume a unix socket
++      }
++
++      local($1,$2,$3);
++      if ($value =~ m{^ (?: \[ ([^\]]*) \] | ([^:]*) ) : ([^:]*) \z}sx) {
++	my $host = untaint_var(defined $1 ? $1 : $2);
++	my $port = untaint_var($3);
++	if (!$host) {
++	  info("config: missing or bad host name in dcc_dccifd_path '$value'");
++	  return $Mail::SpamAssassin::Conf::INVALID_VALUE;
++	}
++	if (!$port || $port !~ /^\d+\z/ || $port < 1 || $port > 65535) {
++	  info("config: bad TCP port number in dcc_dccifd_path '$value'");
++	  return $Mail::SpamAssassin::Conf::INVALID_VALUE;
++	}
++
++	$self->{dcc_dccifd_host} = $host;
++	$self->{dcc_dccifd_port} = $port;
++	if ($host !~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\z/) {
++	  # remember to try IPv6 if we can with a host name or non-IPv4 address
++	  $self->{dcc_dccifd_IPv6} = eval { require IO::Socket::INET6 };
++	}
++	dbg("config: dcc_dccifd_path set to [%s]:%s", $host, $port);
++
++      } else {
++	# assume a unix socket
+         if ($value !~ m{^/}) {
+-          info("config: dcc_dccifd_path should be an absolute socket path");
++	  info("config: dcc_dccifd_path '$value' is not an absolute path");
+         # return $Mail::SpamAssassin::Conf::INVALID_VALUE;  # abort or accept?
+         }
+         $value = untaint_file_path($value);
+-      # test disabled, dccifd may not yet be running at spamd startup time
+-      # if (!-S $value) {
+-      #   info("config: dcc_dccifd_path '$value' isn't a local socket");
+-      #   return $Mail::SpamAssassin::Conf::INVALID_VALUE;
+-      # }
++
+         $self->{dcc_dccifd_socket} = $value;
+         dbg("config: dcc_dccifd_path set to local socket %s", $value);
++	dbg("dcc: dcc_dccifd_path set to local socket %s", $value);
+       }
++
++      $self->{dcc_dccifd_path_raw} = $value;
+     }
+   });
+ 
+ =item dcc_path STRING
+ 
+-This option tells SpamAssassin specifically where to find the C<dccproc>
+-client instead of relying on SpamAssassin to find it in the current PATH.
+-Note that if I<taint mode> is enabled in the Perl interpreter, you should
+-use this, as the current PATH will have been cleared.
++Where to find the C<dccproc> client program instead of relying on SpamAssassin
++to find it in the current PATH or C<dcc_home/bin>. This must often be set,
++because the current PATH is cleared by I<taint mode> in the Perl interpreter,
++
++If a C<dccifd> socket is found in C<dcc_home> or specified explicitly
++with C<dcc_dccifd_path>, use the C<dccifd(8)> interface instead of C<dccproc>.
++
++The default is C<undef>.
++
+ 
+ =cut
+ 
+@@ -289,12 +318,12 @@
+     type => $Mail::SpamAssassin::Conf::CONF_TYPE_STRING,
+     code => sub {
+       my ($self, $key, $value, $line) = @_;
+-      if (!defined $value || !length $value) {
++      if (!defined $value || $value eq '') {
+ 	return $Mail::SpamAssassin::Conf::MISSING_REQUIRED_VALUE;
+       }
+       $value = untaint_file_path($value);
+       if (!-x $value) {
+-	info("config: dcc_path '$value' isn't an executable");
++	info("config: dcc_path '$value' is not executable");
+ 	return $Mail::SpamAssassin::Conf::INVALID_VALUE;
+       }
+ 
+@@ -304,7 +333,7 @@
+ 
+ =item dcc_options options
+ 
+-Specify additional options to the dccproc(8) command. Please note that only
++Specify additional options to the dccproc(8) command.  Only
+ characters in the range [0-9A-Za-z ,._/-] are allowed for security reasons.
+ 
+ The default is C<undef>.
+@@ -319,6 +348,7 @@
+     code => sub {
+       my ($self, $key, $value, $line) = @_;
+       if ($value !~ m{^([0-9A-Za-z ,._/-]+)$}) {
++	info("config: dcc_options '$value' contains impermissible characters");
+ 	return $Mail::SpamAssassin::Conf::INVALID_VALUE;
+       }
+       $self->{dcc_options} = $1;
+@@ -327,8 +357,9 @@
+ 
+ =item dccifd_options options
+ 
+-Specify additional options to send to the dccifd(8) daemon. Please note that only
+-characters in the range [0-9A-Za-z ,._/-] are allowed for security reasons.
++Specify additional options to send to the dccifd daemon with
++the ASCII protocol described on the dccifd(8) man page.
++Only characters in the range [0-9A-Za-z ,._/-] are allowed for security reasons.
+ 
+ The default is C<undef>.
+ 
+@@ -342,265 +373,306 @@
+     code => sub {
+       my ($self, $key, $value, $line) = @_;
+       if ($value !~ m{^([0-9A-Za-z ,._/-]+)$}) {
++	info("config: dccifd_options '$value' contains impermissible characters");
+ 	return $Mail::SpamAssassin::Conf::INVALID_VALUE;
+       }
+       $self->{dccifd_options} = $1;
+     }
+   });
+ 
++=item dcc_learn_score n		(default: undef)
++
++Report messages with total scores this much larger than the
++SpamAssassin spam threshold to DCC as spam.
++
++=cut
++
++  push (@cmds, {
++    setting => 'dcc_learn_score',
++    is_admin => 1,
++    default => undef,
++    type => $Mail::SpamAssassin::Conf::CONF_TYPE_NUMERIC,
++  });
++
+   $conf->{parser}->register_commands(\@cmds);
+ }
+ 
++
++
++
++sub ck_dir {
++  my ($self, $dir, $tgt, $src) = @_;
++
++  $dir = untaint_file_path($dir);
++  if (!stat($dir)) {
++    my $dir_errno = 0+$!;
++    if ($dir_errno == ENOENT) {
++      dbg("dcc: $tgt $dir from $src does not exist");
++    } else {
++      dbg("dcc: $tgt $dir from $src is not accessible: $!");
++    }
++    return;
++  }
++  if (!-d _) {
++    dbg("dcc: $tgt $dir from $src is not a directory");
++    return;
++  }
++
++  $self->{main}->{conf}->{$tgt} = $dir;
++  dbg("dcc: use '$tgt $dir' from $src");
++}
++
+ sub find_dcc_home {
+   my ($self) = @_;
++  my $dcc_libexec;
++
++  # just once
++  return if defined $self->{dcc_version};
++  $self->{dcc_version} = '?';
+ 
+   my $conf = $self->{main}->{conf};
+-  return if !$conf->{use_dcc};
+ 
+-  my $dcchome = $conf->{dcc_home} || '';
+ 
+-  # If we're not given the DCC homedir, try getting DCC to tell us it.
+-  # If that fails, try the DCC default homedir of '/var/dcc'.
+-  if ($dcchome eq '') {
++  # Get the DCC software version for talking to dccifd and formating the
++  # dccifd options and the built-in DCC homedir.  Use -q to prevent delays.
++  my $cdcc_home;
++  my $cdcc = $self->dcc_pgm_path('cdcc');
++  my $cmd = '-qV homedir libexecdir';
++  if ($cdcc && open(CDCC, "$cdcc $cmd 2>&1 |")) {
++    my $cdcc_output = do { local $/ = undef; <CDCC> };
++    close CDCC;
+ 
+-    my $cdcc = Mail::SpamAssassin::Util::find_executable_in_env_path('cdcc');
++    $cdcc_output =~ s/\n/ /g;		# everything in 1 line for debugging
++    dbg("dcc: `%s %s` reports '%s'", $cdcc, $cmd, $cdcc_output);
++    $self->{dcc_version} = ($cdcc_output =~ /^(\d+\.\d+\.\d+)/) ? $1 : '';
++    $cdcc_home = ($cdcc_output =~ /\s+homedir=(\S+)/) ? $1 : '';
++    if ($cdcc_output =~ /\s+libexecdir=(\S+)/) {
++      $self->ck_dir($1, 'dcc_libexec', 'cdcc');
++    }
++  }
+ 
+-    my $cdcc_home = '';
+-    if ($cdcc && -x $cdcc && open(CDCC, "$cdcc homedir 2>&1|")) {
+-      dbg("dcc: dcc_home not set, querying cdcc utility");
+-      $cdcc_home = <CDCC> || '';
+-      close CDCC;
++  # without a home, try the homedir from cdcc
++  if (!$conf->{dcc_home} && $cdcc_home) {
++    $self->ck_dir($cdcc_home, 'dcc_home', 'cdcc');
++  }
++  # finally fall back to /var/dcc
++  if (!$conf->{dcc_home}) {
++    $self->ck_dir($conf->{dcc_home} = '/var/dcc', 'dcc_home', 'default')
++  }
+ 
+-      chomp $cdcc_home;
+-      $cdcc_home =~ s/\s+homedir=//;
+-      dbg("dcc: cdcc reports homedir as '%s'", $cdcc_home);
+-    }
+-
+-    # try first with whatever the cdcc utility reported
+-    my $cdcc_home_errno = 0;
+-    if ($cdcc_home eq '') {
+-      $cdcc_home_errno = ENOENT;
+-    } elsif (!stat($cdcc_home)) {
+-      $cdcc_home_errno = 0+$!;
+-    }
+-    if ($cdcc_home_errno == ENOENT) {
+-      # no such file
+-    } elsif ($cdcc_home_errno != 0) {
+-      dbg("dcc: cdcc reported homedir $cdcc_home is not accessible: $!");
+-    } elsif (!-d _) {
+-      dbg("dcc: cdcc reported homedir $cdcc_home is not a directory");
+-    } else {  # ok
+-      dbg("dcc: cdcc reported homedir $cdcc_home exists, using it");
+-      $dcchome = untaint_var($cdcc_home);
+-    }
+-
+-    # try falling back to /var/dcc
+-    if ($dcchome eq '') {
+-      my $var_dcc_errno = stat('/var/dcc') ? 0 : 0+$!;
+-      if ($var_dcc_errno == ENOENT) {
+-        # no such file
+-      } elsif ($var_dcc_errno != 0) {
+-        dbg("dcc: dcc_home not set and dcc default homedir /var/dcc ".
+-            "is not accessible: $!");
+-      } elsif (!-d _) {
+-        dbg("dcc: dcc_home not set and dcc default homedir /var/dcc ".
+-            "is not a directory");
+-      } else {  # ok
+-        dbg("dcc: dcc_home not set but dcc default homedir /var/dcc exists, ".
+-            "using it");
+-        $dcchome = '/var/dcc';
++  # fall back to $conf->{dcc_home}/libexec or /var/dcc/libexec for dccsight
++  if (!$conf->{dcc_libexec}) {
++    $self->ck_dir($conf->{dcc_home} . '/libexec', 'dcc_libexec', 'dcc_home');
+       }
++  if (!$conf->{dcc_libexec}) {
++    $self->ck_dir('/var/dcc/libexec', 'dcc_libexec', 'dcc_home');
+     }
+ 
+-    if ($dcchome eq '') {
+-      dbg("dcc: unable to get homedir from cdcc ".
+-          "and the dcc default homedir was not found");
+-    }
+-
+-    # Remember found homedir path
+-    dbg("dcc: using '%s' as DCC homedir", $dcchome);
+-    $conf->{dcc_home} = $dcchome;
++  # format options for dccifd
++  my $opts = ($conf->{dccifd_options} || '') . "\n";
++  if ($self->{dcc_version} =~ /\d+\.(\d+)\.(\d+)$/ &&
++      ($1 < 3 || ($1 == 3 && $2 < 123))) {
++    if ($1 < 3 || ($1 == 3 && $2 < 50)) {
++      info("dcc: DCC version $self->{dcc_version} is years old, ".
++           "obsolete, and likely to cause problems.  ".
++           "See http://www.dcc-servers.net/dcc/old-versions.html");
++    }
++    $self->{dccifd_lookup_options} = "header " . $opts;
++    $self->{dccifd_report_options} = "header spam " . $opts;
++  } else {
++    # dccifd after version 1.2.123 understands "cksums" and "no-grey"
++    $self->{dccifd_lookup_options} = "cksums grey-off " . $opts;
++    $self->{dccifd_report_options} = "header spam grey-off " . $opts;
+   }
+ }
+ 
+-sub is_dccifd_available {
+-  my ($self) = @_;
+-
++sub dcc_pgm_path {
++  my ($self, $pgm) = @_;
++  my $pgmpath;
+   my $conf = $self->{main}->{conf};
+-  $self->{dccifd_available} = 0;
+ 
+-  if (!$conf->{use_dcc}) {
+-    dbg("dcc: dccifd is not available: use_dcc is false");
+-  } elsif (defined $conf->{dcc_dccifd_host}) {
+-    dbg("dcc: dccifd inet socket chosen: [%s]:%s",
+-        $conf->{dcc_dccifd_host}, $conf->{dcc_dccifd_port});
+-    $self->{dccifd_available} = 1;
+-  } else {
+-    my $sockpath = $conf->{dcc_dccifd_socket};
+-    my $dcchome = $conf->{dcc_home};
+-    if (defined $sockpath) {
+-      dbg("dcc: dccifd local socket chosen: %s", $sockpath);
+-    } elsif (defined $conf->{dcc_dccifd_path_raw}) {
+-      # avoid falling back to defaults if explicitly provided but wrong
+-    } elsif (defined $dcchome && $dcchome ne '' && -S "$dcchome/dccifd") {
+-      $sockpath = "$dcchome/dccifd";
+-      $conf->{dcc_dccifd_socket} = $sockpath;
+-      dbg("dcc: dccifd default local socket chosen: %s", $sockpath);
++  $pgmpath = $conf->{dcc_path};
++  if (defined $pgmpath && $pgmpath ne '') {
++    # accept explicit setting for dccproc
++    return $pgmpath if $pgm eq 'dccproc';
++    # try adapting it for cdcc and everything else
++    if ($pgmpath =~ s{[^/]+\z}{$pgm}s) {
++      $pgmpath = untaint_file_path($pgmpath);
++      if (-x $pgmpath) {
++        dbg("dcc: dcc_pgm_path, found %s in dcc_path: %s", $pgm,$pgmpath);
++        return $pgmpath;
+     }
+-    if (defined $sockpath && -S $sockpath && -w _ && -r _) {
+-      $self->{dccifd_available} = 1;
+-    } elsif (!defined $conf->{dcc_dccifd_path_raw}) {
+-      dbg("dcc: dccifd is not available: no r/w dccifd socket found");
+-    } else {
+-      dbg("dcc: dccifd is not available: no r/w dccifd socket found: %s",
+-          $conf->{dcc_dccifd_path_raw});
+     }
+   }
+ 
+-  return $self->{dccifd_available};
++  $pgmpath = Mail::SpamAssassin::Util::find_executable_in_env_path($pgm);
++  if (defined $pgmpath) {
++    dbg("dcc: dcc_pgm_path, found %s in env.path: %s", $pgm,$pgmpath);
++    return $pgmpath;
++  }
++
++  # try dcc_home/bin, dcc_libexec, and some desperate last attempts
++  foreach my $dir ($conf->{dcc_home}.'/bin',  $conf->{dcc_libexec},
++                   '/usr/local/bin', '/usr/local/dcc', '/var/dcc') {
++    $pgmpath = $dir . '/' . $pgm;
++    if (-x $pgmpath) {
++      dbg("dcc: dcc_pgm_path, found %s in %s: %s", $pgm,$dir,$pgmpath);
++      return $pgmpath;
++    }
++  }
++
++  return;
+ }
+ 
+-sub is_dccproc_available {
++sub is_dccifd_available {
+   my ($self) = @_;
+   my $conf = $self->{main}->{conf};
+ 
+-  $self->{dccproc_available} = 0;
++  # dccifd remains available until it breaks
++  return $self->{dccifd_available} if $self->{dccifd_available};
+ 
+-  if (!$conf->{use_dcc}) {
+-    dbg("dcc: dccproc is not available: use_dcc is false");
+-    return 0;
++  # deal with configured INET socket
++  if (defined $conf->{dcc_dccifd_host}) {
++    dbg("dcc: dccifd is available via INET socket [%s]:%s",
++	$conf->{dcc_dccifd_host}, $conf->{dcc_dccifd_port});
++    return ($self->{dccifd_available} = 1);
+   }
+-  my $dcchome = $conf->{dcc_home} || '';
+-  my $dccproc = $conf->{dcc_path} || '';
+ 
+-  if ($dccproc eq '' && ($dcchome ne '' && -x "$dcchome/bin/dccproc")) {
+-    $dccproc = "$dcchome/bin/dccproc";
++  # the first time here, compute a default local socket based on DCC home
++  # from self->find_dcc_home() called elsewhere
++  my $sockpath = $conf->{dcc_dccifd_socket};
++  if (!$sockpath) {
++      if ($conf->{dcc_dccifd_path_raw}) {
++	$sockpath = $conf->{dcc_dccifd_path_raw};
++      } else {
++	$sockpath = "$conf->{dcc_home}/dccifd";
+   }
+-  if ($dccproc eq '') {
+-    $dccproc = Mail::SpamAssassin::Util::find_executable_in_env_path('dccproc');
++      $conf->{dcc_dccifd_socket} = $sockpath;
+   }
+ 
+-  unless (defined $dccproc && $dccproc ne '' && -x $dccproc) {
+-    dbg("dcc: dccproc is not available: no dccproc executable found");
+-    return 0;
+-  }
++  # check the socket every time because it can appear and disappear
++  return ($self->{dccifd_available} = 1) if (-S $sockpath && -w _ && -r _);
+ 
+-  # remember any found dccproc
++  dbg("dcc: dccifd is not available; no r/w socket at %s", $sockpath);
++  return ($self->{dccifd_available} = 0);
++}
++
++sub is_dccproc_available {
++  my ($self) = @_;
++  my $conf = $self->{main}->{conf};
++
++  # dccproc remains (un)available so check only once
++  return $self->{dccproc_available} if  defined $self->{dccproc_available};
++
++  my $dccproc = $conf->{dcc_path};
++  if (!defined $dccproc || $dccproc eq '') {
++    $dccproc = $self->dcc_pgm_path('dccproc');
+   $conf->{dcc_path} = $dccproc;
++    if (!$dccproc || ! -x $dccproc) {
++      dbg("dcc: dccproc is not available: no dccproc executable found");
++      return ($self->{dccproc_available} = 0);
++    }
++  }
+ 
+-  dbg("dcc: dccproc is available: %s", $conf->{dcc_path});
+-  $self->{dccproc_available} = 1;
+-  return 1;
++  dbg("dcc: %s is available", $conf->{dcc_path});
++  return ($self->{dccproc_available} = 1);
+ }
+ 
+ sub dccifd_connect {
+-  my($self) = @_;
++  my($self, $tag) = @_;
+   my $conf = $self->{main}->{conf};
+   my $sockpath = $conf->{dcc_dccifd_socket};
+-  my $host = $conf->{dcc_dccifd_host};
+-  my $port = $conf->{dcc_dccifd_port};
+   my $sock;
++
+   if (defined $sockpath) {
+-    dbg("dcc: connecting to a local socket %s", $sockpath);
+-    $sock = IO::Socket::UNIX->new(
+-              Type => SOCK_STREAM, Peer => $sockpath);
+-    $sock or die "dcc: failed to connect to a socket $sockpath: $!\n";
+-  } elsif (defined $host) {
+-    my $specified_path = $conf->{dcc_dccifd_path_raw};
+-    if ($host eq '') {
+-      die "dcc: empty host specification: $specified_path\n";
+-    }
+-    if (!defined $port || $port !~ /^\d+\z/ || $port < 1 || $port > 65535) {
+-      die "dcc: bad TCP port number: $specified_path\n";
+-    }
+-    my $is_inet4 = $host =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\z/;
+-    if ($is_inet4) {  # inet4 socket (IPv4 address)
+-      dbg("dcc: connecting to inet4 socket [%s]:%s", $host,$port);
+-      $sock = IO::Socket::INET->new(
+-                Proto => 'tcp', PeerAddr => $host, PeerPort => $port);
+-    } else {
+-      if (!defined $have_inet6) {
+-        $have_inet6 = eval { require IO::Socket::INET6 };
+-        $have_inet6 = 0  if !defined $have_inet6;
++    $sock = IO::Socket::UNIX->new(Type => SOCK_STREAM, Peer => $sockpath);
++    if ($sock) {
++      dbg("$tag connected to local socket %s", $sockpath);
++      return $sock;
+       }
+-      if (!$have_inet6) {  # fallback to an inet4 socket (IPv4)
+-        dbg("dcc: connecting(2) to inet4 socket [%s]:%s", $host,$port);
+-        $sock = IO::Socket::INET->new(
+-                  Proto => 'tcp', PeerAddr => $host, PeerPort => $port);
+-      } else {  # inet6 socket (IPv6) or a host name
+-        dbg("dcc: connecting to inet6 socket [%s]:%s", $host,$port);
++    $self->{dccifd_available} = 0;
++    info("$tag failed to connect to local socket $sockpath");
++    return $sock
++  }
++
++  # must be TCP/IP
++  my $host = $conf->{dcc_dccifd_host};
++  my $port = $conf->{dcc_dccifd_port};
++
++  if ($conf->{dcc_dccifd_IPv6}) {
++    # try IPv6 if we can with a host name or non-IPv4 address
++    dbg("$tag connecting to inet6 socket [%s]:%s", $host,$port);
+         $sock = IO::Socket::INET6->new(
+                   Proto => 'tcp', PeerAddr => $host, PeerPort => $port);
++    # fall back to IPv4 if that failed
+       }
++  if (!$sock) {
++    dbg("$tag connecting to inet4 socket [%s]:%s", $host, $port);
++    $sock = IO::Socket::INET->new(
++		Proto => 'tcp', PeerAddr => $host, PeerPort => $port);
+     }
+-    $sock or die "dcc: failed to connect to [$host]:$port : $!\n";
+-  } else {
+-    die "dcc: dccifd socket not provided: $conf->{dcc_dccifd_path_raw}\n";
+-  }
++
++  info("failed to connect to [$host]:$port : $!") if !$sock;
+   return $sock;
+ }
+ 
++# check for dccifd every time in case enough uses of dccproc starts dccifd
+ sub get_dcc_interface {
+   my ($self) = @_;
++  my $conf = $self->{main}->{conf};
+ 
+-  if ($self->is_dccifd_available()) {
+-    $self->{dcc_interface} = "dccifd";
+-    $self->{dcc_disabled} = 0;
+-  }
+-  elsif ($self->is_dccproc_available()) {
+-    $self->{dcc_interface} = "dccproc";
+-    $self->{dcc_disabled} = 0;
++  if (!$conf->{use_dcc}) {
++    $self->{dcc_disabled} = 1;
++    return;
+   }
+-  else {
+-    dbg("dcc: dccifd and dccproc are not available, disabling DCC");
+-    $self->{dcc_interface} = "none";
++
++  $self->find_dcc_home();
++  if (!$self->is_dccifd_available() && !$self->is_dccproc_available()) {
++    dbg("dcc: dccifd and dccproc are not available");
+     $self->{dcc_disabled} = 1;
+   }
++
++  $self->{dcc_disabled} = 0;
+ }
+ 
+ sub dcc_query {
+-  my ($self, $permsgstatus, $full) = @_;
++  my ($self, $permsgstatus, $fulltext) = @_;
+ 
+   $permsgstatus->{dcc_checked} = 1;
+ 
++  if (!$self->{main}->{conf}->{use_dcc}) {
++    dbg("dcc: DCC is not available: use_dcc is 0");
++    return;
++  }
++
+   # initialize valid tags
+   $permsgstatus->{tag_data}->{DCCB} = "";
+   $permsgstatus->{tag_data}->{DCCR} = "";
+   $permsgstatus->{tag_data}->{DCCREP} = "";
+ 
+-  # short-circuit if there's already a X-DCC header with value of
+-  # "bulk" from an upstream DCC check
+-  if ($permsgstatus->get('ALL') =~
+-      /^(X-DCC-([^:]{1,80})?-?Metrics:.*bulk.*)$/m) {
+-    $permsgstatus->{dcc_response} = $1;
++  if ($$fulltext eq '') {
++    dbg("dcc: empty message; skipping dcc check");
+     return;
+   }
+ 
+-  my $timer = $self->{main}->time_method("check_dcc");
++  if ($permsgstatus->get('ALL') =~ /^(X-DCC-.*-Metrics:.*)$/m) {
++    $permsgstatus->{dcc_raw_x_dcc} = $1;
++    # short-circuit if there is already a X-DCC header with value of
++    # "bulk" from an upstream DCC check
++    # require "bulk" because then at least one body checksum will be "many"
++    # and so we know the X-DCC header is not forged by spammers
++    return if $permsgstatus->{dcc_raw_x_dcc} =~ / bulk /;
++  }
+ 
+-  $self->find_dcc_home();
++  my $timer = $self->{main}->time_method("check_dcc");
+ 
+   $self->get_dcc_interface();
+-  my $result;
+-  if ($self->{dcc_disabled}) {
+-    $result = 0;
+-  } elsif ($$full eq '') {
+-    dbg("dcc: empty message, skipping dcc check");
+-    $result = 0;
+-  } elsif ($self->{dccifd_available}) {
+-    my $client = $permsgstatus->{relays_external}->[0]->{ip};
+-    my $clientname = $permsgstatus->{relays_external}->[0]->{rdns};
+-    my $helo = $permsgstatus->{relays_external}->[0]->{helo} || "";
+-    if ($client) {
+-      $client = $client . "\r" . $clientname  if $clientname;
+-    } else {
+-      $client = "0.0.0.0";
+-    }
+-    $self->dccifd_lookup($permsgstatus, $full, $client, $clientname, $helo);
+-  } else {
+-    my $client = $permsgstatus->{relays_external}->[0]->{ip};
+-    $self->dccproc_lookup($permsgstatus, $full, $client);
+-  }
++  return if $self->{dcc_disabled};
++
++  my $envelope = $permsgstatus->{relays_external}->[0];
++  ($permsgstatus->{dcc_raw_x_dcc},
++   $permsgstatus->{dcc_cksums}) = $self->ask_dcc("dcc:", $permsgstatus,
++						 $fulltext, $envelope);
+ }
+ 
+ sub check_dcc {
+@@ -609,28 +681,27 @@
+ 
+   $self->dcc_query($permsgstatus, $full)  if !$permsgstatus->{dcc_checked};
+ 
+-  my $response = $permsgstatus->{dcc_response};
+-  return 0  if !defined $response || $response eq '';
++  my $x_dcc = $permsgstatus->{dcc_raw_x_dcc};
++  return 0  if !defined $x_dcc || $x_dcc eq '';
+ 
+-  local($1,$2);
+-  if ($response =~ /^X-DCC-(.*)-Metrics: (.*)$/) {
+-    $permsgstatus->{tag_data}->{DCCB} = $1;
+-    $permsgstatus->{tag_data}->{DCCR} = $2;
++  if ($x_dcc =~ /^X-DCC-(.*)-Metrics: (.*)$/) {
++    $permsgstatus->set_tag('DCCB', $1);
++    $permsgstatus->set_tag('DCCR', $2);
+   }
+-  $response =~ s/many/999999/ig;
+-  $response =~ s/ok\d?/0/ig;
++  $x_dcc =~ s/many/999999/ig;
++  $x_dcc =~ s/ok\d?/0/ig;
+ 
+   my %count = (body => 0, fuz1 => 0, fuz2 => 0, rep => 0);
+-  if ($response =~ /\bBody=(\d+)/) {
++  if ($x_dcc =~ /\bBody=(\d+)/) {
+     $count{body} = $1+0;
+   }
+-  if ($response =~ /\bFuz1=(\d+)/) {
++  if ($x_dcc =~ /\bFuz1=(\d+)/) {
+     $count{fuz1} = $1+0;
+   }
+-  if ($response =~ /\bFuz2=(\d+)/) {
++  if ($x_dcc =~ /\bFuz2=(\d+)/) {
+     $count{fuz2} = $1+0;
+   }
+-  if ($response =~ /\brep=(\d+)/) {
++  if ($x_dcc =~ /\brep=(\d+)/) {
+     $count{rep}  = $1+0;
+   }
+   if ($count{body} >= $conf->{dcc_body_max} ||
+@@ -651,185 +722,185 @@
+ }
+ 
+ sub check_dcc_reputation_range {
+-  my ($self, $permsgstatus, $full, $min, $max) = @_;
+-  $self->dcc_query($permsgstatus, $full)  if !$permsgstatus->{dcc_checked};
++  my ($self, $permsgstatus, $fulltext, $min, $max) = @_;
++
++  # this is called several times per message, so parse the X-DCC header once
++  my $dcc_rep = $permsgstatus->{dcc_rep};
++  if (!defined $dcc_rep) {
++    $self->dcc_query($permsgstatus, $fulltext)  if !$permsgstatus->{dcc_checked};
++    my $x_dcc = $permsgstatus->{dcc_raw_x_dcc};
++    if (defined $x_dcc && $x_dcc =~ /\brep=(\d+)/) {
++      $dcc_rep = $1+0;
++      $permsgstatus->set_tag('DCCREP', $dcc_rep);
++    } else {
++      $dcc_rep = -1;
++    }
++    $permsgstatus->{dcc_rep} = $dcc_rep;
++  }
+ 
+-  my $response = $permsgstatus->{dcc_response};
+-  return 0  if !defined $response || $response eq '';
++  # no X-DCC header or no reputation in the X-DCC header, perhaps for lack
++  # of data in the DCC Reputation server
++  return 0 if $dcc_rep < 0;
+ 
++  # cover the entire range of reputations if not told otherwise
+   $min = 0   if !defined $min;
+-  $max = 999 if !defined $max;
++  $max = 100 if !defined $max;
+ 
+-  local $1;
+-  my $dcc_rep;
+-  $dcc_rep = $1+0  if defined $response && $response =~ /\brep=(\d+)/;
+-  if (defined $dcc_rep) {
+-    $dcc_rep = int($dcc_rep);  # just in case, rule ranges are integer percents
+     my $result = $dcc_rep >= $min && $dcc_rep <= $max ? 1 : 0;
+     dbg("dcc: dcc_rep %s, min %s, max %s => result=%s",
+         $dcc_rep, $min, $max, $result?'YES':'no');
+-    $permsgstatus->{tag_data}->{DCCREP} = $dcc_rep;
+-    return $dcc_rep >= $min && $dcc_rep <= $max ? 1 : 0;
++  return $result;
++}
++
++# get the X-DCC header line and save the checksums from dccifd or dccproc
++sub parse_dcc_response {
++  my ($self, $resp) = @_;
++  my ($raw_x_dcc, $cksums);
++
++  # The first line is the header we want.  It uses SMTP folded whitespace
++  # if it is long.  The folded whitespace is always a single \t.
++  chomp($raw_x_dcc = shift @$resp);
++  my $v;
++  while (($v = shift @$resp) && $v =~ s/^\t(.+)\s*\n/ $1/) {
++    $raw_x_dcc .= $v;
++  }
++
++  # skip the "reported:" line between the X-DCC header and any checksums
++  # remove ':' to avoid a bug in versions 1.3.115 - 1.3.122 in dccsight
++  # with the length of "Message-ID:"
++  $cksums = '';
++  while (($v = shift @$resp) && $v =~ s/^([^:]*):/$1/) {
++    $cksums .= $v;
+   }
+-  return 0;
++
++  return ($raw_x_dcc, $cksums);
+ }
+ 
+-sub dccifd_lookup {
+-  my ($self, $permsgstatus, $fulltext, $client, $clientname, $helo) = @_;
++sub ask_dcc {
++  my ($self, $tag, $permsgstatus, $fulltext, $envelope) = @_;
+   my $conf = $self->{main}->{conf};
+-  my $response;
+-  my $left;
+-  my $right;
+-  my $timeout = $conf->{dcc_timeout};
+-  my $opts = $conf->{dccifd_options};
+-  my @opts = !defined $opts ? () : split(' ',$opts);
++  my ($pgm, $err, $sock, $pid, @resp);
++  my ($client, $clientname, $helo, $opts);
+ 
+   $permsgstatus->enter_helper_run_mode();
+ 
++  my $timeout = $conf->{dcc_timeout};
+   my $timer = Mail::SpamAssassin::Timeout->new(
+            { secs => $timeout, deadline => $permsgstatus->{master_deadline} });
+-  my $err = $timer->run_and_catch(sub {
+ 
++  $err = $timer->run_and_catch(sub {
+     local $SIG{PIPE} = sub { die "__brokenpipe__ignore__\n" };
+ 
+-    my $sock = $self->dccifd_connect();
+-    $sock or die "dcc: failed to connect to a dccifd socket";
+-
+-    # send the options and other parameters to the daemon
+-    $sock->print("header " . join(" ", at opts) . "\n")
+-                                 or die "dcc: failed write";  # options
+-    $sock->print($client . "\n") or die "dcc: failed write";  # client
+-    $sock->print($helo . "\n")   or die "dcc: failed write";  # HELO value
+-    $sock->print("\n")           or die "dcc: failed write";  # sender
+-    $sock->print("unknown\r\n")  or die "dcc: failed write";  # recipients
+-    $sock->print("\n")           or die "dcc: failed write";  # recipients
+-
+-    $sock->print($$fulltext)     or die "dcc: failed write";
+-
+-    $sock->shutdown(1) or die "dcc: failed socket shutdown: $!";
+-
+-    $sock->getline()   or die "dcc: failed read status";
+-    $sock->getline()   or die "dcc: failed read multistatus";
++    # prefer dccifd to dccproc
++    if ($self->{dccifd_available}) {
++      $pgm = 'dccifd';
+ 
+-    my @null = $sock->getlines();
+-    if (!@null) {
+-      # no facility prefix on this
+-      die "dcc: failed to read header\n";
+-    }
++      $sock = $self->dccifd_connect($tag);
++      if (!$sock) {
++	$self->{dccifd_available} = 0;
++	die("dccproc not available") if (!$self->is_dccproc_available());
+ 
+-    # the first line will be the header we want to look at
+-    chomp($response = shift @null);
+-    # but newer versions of DCC fold the header if it's too long...
+-    while (my $v = shift @null) {
+-      last unless ($v =~ s/^\s+/ /);  # if this line wasn't folded, stop
+-      chomp $v;
+-      $response .= $v;
++	# fall back on dccproc if the socket is an orphan from
++	# a killed dccifd daemon or some other obvious (no timeout) problem
++	dbg("$tag fall back on dccproc");
+     }
+-
+-    dbg("dcc: dccifd got response: %s", $response);
+-  
+-  });
+-
+-  $permsgstatus->leave_helper_run_mode();
+-
+-  if ($timer->timed_out()) {
+-    dbg("dcc: dccifd check timed out after $timeout secs.");
+-    return;
+   }
+ 
+-  if ($err) {
+-    chomp $err;
+-    warn("dcc: dccifd -> check skipped: $err\n");
+-    return;
+-  }
++    if ($self->{dccifd_available}) {
+ 
+-  if (!defined $response || $response !~ /^X-DCC/) {
+-    dbg("dcc: dccifd check failed - no X-DCC returned: %s", $response);
+-    return;
++      # send the options and other parameters to the daemon
++      $client = $envelope->{ip};
++      $clientname = $envelope->{rdns};
++      if (!defined $client) {
++	$client = '';
++      } else {
++	$client .= ("\r" . $clientname) if defined $clientname;
+   }
++      $helo = $envelope->{helo} || '';
++      if ($tag ne "dcc:") {
++	$opts = $self->{dccifd_report_options}
++      } else {
++	$opts = $self->{dccifd_lookup_options};
++	# only query if there is an X-DCC header
++	$opts =~ s/grey-off/& query/ if defined $permsgstatus->{dcc_raw_x_dcc};
++      }
++      $sock->print($opts)	   or die "failed write options\n";
++      $sock->print($client . "\n") or die "failed write SMTP client\n";
++      $sock->print($helo . "\n")   or die "failed write HELO value\n";
++      $sock->print("\n")	   or die "failed write sender\n";
++      $sock->print("unknown\n\n")  or die "failed write 1 recipient\n";
++      $sock->print($$fulltext)     or die "failed write mail message\n";
++      $sock->shutdown(1) or die "failed socket shutdown: $!";
+ 
+-  $response =~ s/[ \t]\z//;  # strip trailing whitespace
+-  $permsgstatus->{dcc_response} = $response;
+-}
++      $sock->getline()   or die "failed read status\n";
++      $sock->getline()   or die "failed read multistatus\n";
+ 
+-sub dccproc_lookup {
+-  my ($self, $permsgstatus, $fulltext, $client) = @_;
+-  my $conf = $self->{main}->{conf};
+-  my $response;
+-  my %count = (body => 0, fuz1 => 0, fuz2 => 0, rep => 0);
+-  my $timeout = $conf->{dcc_timeout};
++      @resp = $sock->getlines();
++      die "failed to read dccifd response\n" if !@resp;
+ 
+-  $permsgstatus->enter_helper_run_mode();
+-
+-  # use a temp file here -- open2() is unreliable, buffering-wise, under spamd
++    } else {
++      $pgm = 'dccproc';
++      # use a temp file -- open2() is unreliable, buffering-wise, under spamd
++      # first ensure that we do not hit a stray file from some other filter.
++      $permsgstatus->delete_fulltext_tmpfile();
+   my $tmpf = $permsgstatus->create_fulltext_tmpfile($fulltext);
+-  my $pid;
+-
+-  my $timer = Mail::SpamAssassin::Timeout->new(
+-           { secs => $timeout, deadline => $permsgstatus->{master_deadline} });
+-  my $err = $timer->run_and_catch(sub {
+-
+-    local $SIG{PIPE} = sub { die "__brokenpipe__ignore__\n" };
+ 
+-    # note: not really tainted, this came from system configuration file
+-    my $path = untaint_file_path($conf->{dcc_path});
+-
+-    my $opts = $conf->{dcc_options};
++      my $path = $conf->{dcc_path};
++      $opts = $conf->{dcc_options};
+     my @opts = !defined $opts ? () : split(' ',$opts);
+     untaint_var(\@opts);
++      unshift(@opts, '-w', 'whiteclnt');
++      $client = $envelope->{ip};
++      if ($client) {
++	unshift(@opts, '-a', untaint_var($client));
++      } else {
++	# get external relay IP address from Received: header if not available
++	unshift(@opts, '-R');
++      }
++      if ($tag eq "dcc:") {
++	# query instead of report if there is an X-DCC header from upstream
++	unshift(@opts, '-Q') if defined $permsgstatus->{dcc_raw_x_dcc};
++      } else {
++	# learn or report spam
++	unshift(@opts, '-t', 'many');
++      }
+ 
+-    unshift(@opts, "-a",
+-            untaint_var($client))  if defined $client && $client ne '';
+-
+-    dbg("dcc: opening pipe: %s",
+-         join(' ', $path, "-H", "-x", "0", @opts, "< $tmpf"));
++      dbg("$tag opening pipe to %s",
++	  join(' ', $path, "-C", "-x", "0", @opts, "<$tmpf"));
+ 
+     $pid = Mail::SpamAssassin::Util::helper_app_pipe_open(*DCC,
+-             $tmpf, 1, $path, "-H", "-x", "0", @opts);
++		$tmpf, 1, $path, "-C", "-x", "0", @opts);
+     $pid or die "$!\n";
+ 
+     # read+split avoids a Perl I/O bug (Bug 5985)
+     my($inbuf,$nread,$resp); $resp = '';
+     while ( $nread=read(DCC,$inbuf,8192) ) { $resp .= $inbuf }
+     defined $nread  or die "error reading from pipe: $!";
+-    my @null = split(/^/m, $resp, -1);  undef $resp;
++      @resp = split(/^/m, $resp, -1);  undef $resp;
+ 
+     my $errno = 0;  close DCC or $errno = $!;
+     proc_status_ok($?,$errno)
+-      or info("dcc: [%s] finished: %s", $pid, exit_status_str($?,$errno));
+-
+-    if (!@null) {
+-      # no facility prefix on this
+-      die "failed to read header\n";
+-    }
++	  or info("$tag [%s] finished: %s", $pid, exit_status_str($?,$errno));
+ 
+-    # the first line will be the header we want to look at
+-    chomp($response = shift @null);
+-    # but newer versions of DCC fold the header if it's too long...
+-    while (my $v = shift @null) {
+-      last unless ($v =~ s/^\s+/ /);  # if this line wasn't folded, stop
+-      chomp $v;
+-      $response .= $v;
++      die "failed to read X-DCC header from dccproc\n" if !@resp;
+     }
+-
+-    unless (defined($response)) {
+-      # no facility prefix on this
+-      die "no response\n";	# yes, this is possible
+-    }
+-
+-    dbg("dcc: got response: %s", $response);
+-
+   });
+ 
++  if ($pgm eq 'dccproc') {
+   if (defined(fileno(*DCC))) {  # still open
+     if ($pid) {
+-      if (kill('TERM',$pid)) { dbg("dcc: killed stale helper [$pid]") }
+-      else { dbg("dcc: killing helper application [$pid] failed: $!") }
++	if (kill('TERM',$pid)) {
++	  dbg("$tag killed stale dccproc process [$pid]")
++	} else {
++	  dbg("$tag killing dccproc process [$pid] failed: $!")
++	}
+     }
+     my $errno = 0;  close(DCC) or $errno = $!;
+-    proc_status_ok($?,$errno)
+-      or info("dcc: [%s] terminated: %s", $pid, exit_status_str($?,$errno));
++      proc_status_ok($?,$errno) or info("$tag [%s] dccproc terminated: %s",
++					$pid, exit_status_str($?,$errno));
++    }
+   }
++
+   $permsgstatus->leave_helper_run_mode();
+ 
+   if ($timer->timed_out()) {
+@@ -833,204 +904,182 @@
+   $permsgstatus->leave_helper_run_mode();
+ 
+   if ($timer->timed_out()) {
+-    dbg("dcc: check timed out after $timeout seconds");
+-    return;
++    dbg("$tag $pgm timed out after $timeout seconds");
++    return (undef, undef);
+   }
+ 
+   if ($err) {
+     chomp $err;
+-    if ($err eq "__brokenpipe__ignore__") {
+-      dbg("dcc: check failed: broken pipe");
+-    } elsif ($err eq "no response") {
+-      dbg("dcc: check failed: no response");
+-    } else {
+-      warn("dcc: check failed: $err\n");
+-    }
+-    return;
++    info("$tag $pgm failed: $err\n");
++    return (undef, undef);
+   }
+ 
+-  if (!defined($response) || $response !~ /^X-DCC/) {
+-    $response ||= '';
+-    dbg("dcc: check failed: no X-DCC returned (did you create a map file?): %s", $response);
+-    return;
++  my ($raw_x_dcc, $cksums) = $self->parse_dcc_response(\@resp);
++  if (!defined $raw_x_dcc || $raw_x_dcc !~ /^X-DCC/) {
++    info("$tag instead of X-DCC header, $pgm returned '%s'", $raw_x_dcc);
++    return (undef, undef);
+   }
+-
+-  $permsgstatus->{dcc_response} = $response;
++  dbg("$tag %s responded with '%s'", $pgm, $raw_x_dcc);
++  return ($raw_x_dcc, $cksums);
+ }
+ 
+-# only supports dccproc right now
+-sub plugin_report {
++# tell DCC server that the message is spam according to SpamAssassin
++sub check_post_learn {
+   my ($self, $options) = @_;
+ 
+-  return if $options->{report}->{options}->{dont_report_to_dcc};
+-  $self->get_dcc_interface();
+-  return if $self->{dcc_disabled};
+-
+-  # get the metadata from the message so we can pass the external relay information
+-  $options->{msg}->extract_message_metadata($options->{report}->{main});
+-  my $client = $options->{msg}->{metadata}->{relays_external}->[0]->{ip};
+-  if ($self->{dccifd_available}) {
+-    my $clientname = $options->{msg}->{metadata}->{relays_external}->[0]->{rdns};
+-    my $helo = $options->{msg}->{metadata}->{relays_external}->[0]->{helo} || "";
+-    if ($client) {
+-      if ($clientname) {
+-        $client = $client . "\r" . $clientname;
+-      }
+-    } else {
+-      $client = "0.0.0.0";
+-    }
+-    if ($self->dccifd_report($options, $options->{text}, $client, $helo)) {
+-      $options->{report}->{report_available} = 1;
+-      info("reporter: spam reported to DCC");
+-      $options->{report}->{report_return} = 1;
++  # learn only if allowed
++  return if $self->{learn_disabled};
++  my $conf = $self->{main}->{conf};
++  if (!$conf->{use_dcc}) {
++    $self->{learn_disabled} = 1;
++    return;
+     }
+-    else {
+-      info("reporter: could not report spam to DCC via dccifd");
++  my $learn_score = $conf->{dcc_learn_score};
++  if (!defined $learn_score || $learn_score eq '') {
++    dbg("dcc: DCC learning not enabled by dcc_learn_score");
++    $self->{learn_disabled} = 1;
++    return;
+     }
+-  } else {
+-    # use temporary file: open2() is unreliable due to buffering under spamd
+-    my $tmpf = $options->{report}->create_fulltext_tmpfile($options->{text});
+     
+-    if ($self->dcc_report($options, $tmpf, $client)) {
+-      $options->{report}->{report_available} = 1;
+-      info("reporter: spam reported to DCC");
+-      $options->{report}->{report_return} = 1;
++  # and if SpamAssassin concluded that the message is spam
++  # worse than our threshold
++  my $permsgstatus = $options->{permsgstatus};
++  if ($permsgstatus->is_spam()) {
++    my $score = $permsgstatus->get_score();
++    my $required_score = $permsgstatus->get_required_score();
++    if ($score < $required_score + $learn_score) {
++      dbg("dcc: score=%d required_score=%d dcc_learn_score=%d",
++	  $score, $required_score, $learn_score);
++      return;
+     }
+-    else {
+-      info("reporter: could not report spam to DCC via dccproc");
+     }
+-    $options->{report}->delete_fulltext_tmpfile();
++
++  # and if we checked the message
++  return if (!defined $permsgstatus->{dcc_raw_x_dcc});
++
++  # and if the DCC server thinks it was not spam
++  if ($permsgstatus->{dcc_raw_x_dcc} !~ /\b(Body|Fuz1|Fuz2)=\d/) {
++    dbg("dcc: already known as spam; no need to learn");
++    return;
+   }
++
++  # dccsight is faster than dccifd or dccproc if we have checksums,
++  #   which we do not have with dccifd before 1.3.123
++  my $old_cksums = $permsgstatus->{dcc_cksums};
++  return if ($old_cksums && $self->dccsight_learn($permsgstatus, $old_cksums));
++
++  # Fall back on dccifd or dccproc without saved checksums or dccsight.
++  # get_dcc_interface() was called when the message was checked
++
++  # is getting the full text this way kosher?  Is get_pristine() public?
++  my $fulltext = $permsgstatus->{msg}->get_pristine();
++  my $envelope = $permsgstatus->{relays_external}->[0];
++  my ($raw_x_dcc, $cksums) = $self->ask_dcc("dcc: learn:", $permsgstatus,
++					    \$fulltext, $envelope);
++  dbg("dcc: learned as spam") if defined $raw_x_dcc;
+ }
+ 
+-sub dccifd_report {
+-  my ($self, $options, $fulltext, $client, $helo) = @_;
+-  my $conf = $self->{main}->{conf};
+-  my $timeout = $conf->{dcc_timeout};
+-  # instead of header use whatever the report option is
+-  my $opts = $conf->{dccifd_options};
+-  my @opts = !defined $opts ? () : split(' ',$opts);
++sub dccsight_learn {
++  my ($self, $permsgstatus, $old_cksums) = @_;
++  my ($raw_x_dcc, $new_cksums);
++
++  return 0 if !$old_cksums;
++
++  my $dccsight = $self->dcc_pgm_path('dccsight');
++  if (!$dccsight) {
++    info("dcc: cannot find dccsight") if $dccsight eq '';
++    return 0;
++  }
+ 
+-  $options->{report}->enter_helper_run_mode();
+-  my $timer = Mail::SpamAssassin::Timeout->new({ secs => $timeout });
++  $permsgstatus->enter_helper_run_mode();
+ 
+-  my $err = $timer->run_and_catch(sub {
++  # use a temp file here -- open2() is unreliable, buffering-wise, under spamd
++  # ensure that we do not hit a stray file from some other filter.
++  $permsgstatus->delete_fulltext_tmpfile();
++  my $tmpf = $permsgstatus->create_fulltext_tmpfile(\$old_cksums);
++  my $pid;
+ 
++  my $timeout = $self->{main}->{conf}->{dcc_timeout};
++  my $timer = Mail::SpamAssassin::Timeout->new(
++	   { secs => $timeout, deadline => $permsgstatus->{master_deadline} });
++  my $err = $timer->run_and_catch(sub {
+     local $SIG{PIPE} = sub { die "__brokenpipe__ignore__\n" };
+ 
+-    my $sock = $self->dccifd_connect();
+-    $sock or die "report: failed to connect to a dccifd socket";
++    dbg("dcc: opening pipe to %s",
++	join(' ', $dccsight, "-t", "many", "<$tmpf"));
+ 
+-    # send the options and other parameters to the daemon
+-    $sock->print("spam " . join(" ", at opts) . "\n")
+-      or die "report: dccifd failed write"; # options
+-    $sock->print($client . "\n")
+-      or die "report: dccifd failed write"; # client
+-    $sock->print($helo . "\n")
+-      or die "report: dccifd failed write"; # HELO value
+-    $sock->print("\n")
+-      or die "report: dccifd failed write"; # sender
+-    $sock->print("unknown\r\n")
+-      or die "report: dccifd failed write"; # recipients
+-    $sock->print("\n")
+-      or die "report: dccifd failed write"; # recipients
++    $pid = Mail::SpamAssassin::Util::helper_app_pipe_open(*DCC,
++	    $tmpf, 1, $dccsight, "-t", "many");
++    $pid or die "$!\n";
+ 
+-    $sock->print($$fulltext) or die "report: dccifd failed write";
++    # read+split avoids a Perl I/O bug (Bug 5985)
++    my($inbuf,$nread,$resp); $resp = '';
++    while ( $nread=read(DCC,$inbuf,8192) ) { $resp .= $inbuf }
++    defined $nread  or die "error reading from pipe: $!";
++    my @resp = split(/^/m, $resp, -1);  undef $resp;
+ 
+-    $sock->shutdown(1) or die "report: dccifd failed socket shutdown: $!";
++    my $errno = 0;  close DCC or $errno = $!;
++    proc_status_ok($?,$errno)
++	  or info("dcc: [%s] finished: %s", $pid, exit_status_str($?,$errno));
+ 
+-    $sock->getline() or die "report: dccifd failed read status";
+-    $sock->getline() or die "report: dccifd failed read multistatus";
++    die "dcc: failed to read learning response\n" if !@resp;
+ 
+-    my @ignored = $sock->getlines();
++    ($raw_x_dcc, $new_cksums) = $self->parse_dcc_response(\@resp);
+   });
+ 
+-  $options->{report}->leave_helper_run_mode();
++  if (defined(fileno(*DCC))) {	  # still open
++    if ($pid) {
++      if (kill('TERM',$pid)) {
++	dbg("dcc: killed stale dccsight process [$pid]")
++      } else {
++	dbg("dcc: killing stale dccsight process [$pid] failed: $!") }
++    }
++    my $errno = 0;  close(DCC) or $errno = $!;
++    proc_status_ok($?,$errno) or info("dcc: dccsight [%s] terminated: %s",
++				      $pid, exit_status_str($?,$errno));
++  }
++  $permsgstatus->delete_fulltext_tmpfile();
++  $permsgstatus->leave_helper_run_mode();
+   
+   if ($timer->timed_out()) {
+-    dbg("reporter: DCC report via dccifd timed out after $timeout secs.");
++    dbg("dcc: dccsight timed out after $timeout seconds");
+     return 0;
+   }
+   
+   if ($err) {
+     chomp $err;
+-    if ($err eq "__brokenpipe__ignore__") {
+-      dbg("reporter: DCC report via dccifd failed: broken pipe");
+-    } else {
+-      warn("reporter: DCC report via dccifd failed: $err\n");
+-    }
++    info("dcc: dccsight failed: $err\n");
+     return 0;
+   }
+   
++  if ($raw_x_dcc) {
++    dbg("dcc: learned response: %s", $raw_x_dcc);
+   return 1;
+-}
+-  
+-sub dcc_report {
+-  my ($self, $options, $tmpf, $client) = @_;
+-  my $conf = $self->{main}->{conf};
+-  my $timeout = $options->{report}->{conf}->{dcc_timeout};
+-
+-  # note: not really tainted, this came from system configuration file
+-  my $path = untaint_file_path($options->{report}->{conf}->{dcc_path});
+-  my $opts = $conf->{dcc_options};
+-  my @opts = !defined $opts ? () : split(' ',$opts);
+-  untaint_var(\@opts);
+-
+-  # get the metadata from the message so we can pass the external relay info
+-
+-  unshift(@opts, "-a",
+-          untaint_var($client))  if defined $client && $client ne '';
+-
+-  my $timer = Mail::SpamAssassin::Timeout->new({ secs => $timeout });
+-
+-  $options->{report}->enter_helper_run_mode();
+-  my $err = $timer->run_and_catch(sub {
+-
+-    local $SIG{PIPE} = sub { die "__brokenpipe__ignore__\n" };
+-
+-    dbg("report: opening pipe: %s",
+-        join(' ', $path, "-H", "-t", "many", "-x", "0", @opts, "< $tmpf"));
+-
+-    my $pid = Mail::SpamAssassin::Util::helper_app_pipe_open(*DCC,
+-                $tmpf, 1, $path, "-H", "-t", "many", "-x", "0", @opts);
+-    $pid or die "$!\n";
++  }
+ 
+-    my($inbuf,$nread,$nread_all); $nread_all = 0;
+-    # response is ignored, just check its existence
+-    while ( $nread=read(DCC,$inbuf,8192) ) { $nread_all += $nread }
+-    defined $nread  or die "error reading from pipe: $!";
++  return 0;
++}
+ 
+-    dbg("dcc: empty response")  if $nread_all < 1;
++sub plugin_report {
++  my ($self, $options) = @_;
+ 
+-    my $errno = 0;  close DCC or $errno = $!;
+-    # closing a pipe also waits for the process executing on the pipe to
+-    # complete, no need to explicitly call waitpid
+-    # my $child_stat = waitpid($pid,0) > 0 ? $? : undef;
+-    proc_status_ok($?,$errno)
+-      or die "dcc: reporter error: ".exit_status_str($?,$errno)."\n";
+-  });
+-  $options->{report}->leave_helper_run_mode();
++  return if $options->{report}->{options}->{dont_report_to_dcc};
++  $self->get_dcc_interface();
++  return if $self->{dcc_disabled};
+ 
+-  if ($timer->timed_out()) {
+-    dbg("reporter: DCC report via dccproc timed out after $timeout seconds");
+-    return 0;
+-  }
++  # get the metadata from the message so we can report the external relay
++  $options->{msg}->extract_message_metadata($options->{report}->{main});
++  my $envelope = $options->{msg}->{metadata}->{relays_external}->[0];
++  my ($raw_x_dcc, $cksums) = $self->ask_dcc("reporter:", $options->{report},
++					    $options->{text}, $envelope);
+ 
+-  if ($err) {
+-    chomp $err;
+-    if ($err eq "__brokenpipe__ignore__") {
+-      dbg("reporter: DCC report via dccproc failed: broken pipe");
++  if (defined $raw_x_dcc) {
++    $options->{report}->{report_available} = 1;
++    info("reporter: spam reported to DCC");
++    $options->{report}->{report_return} = 1;
+     } else {
+-      warn("reporter: DCC report via dccproc failed: $err\n");
++    info("reporter: could not report spam to DCC");
+     }
+-    return 0;
+-  }
+-
+-  return 1;
+ }
+ 
+ 1;
+-
+-=back
+-
+-=cut
diff -ruN /usr/ports/japanese/p5-Mail-SpamAssassin/files/pkg-install.in ja-p5-Mail-SpamAssassin/files/pkg-install.in
--- /usr/ports/japanese/p5-Mail-SpamAssassin/files/pkg-install.in	1970-01-01 09:00:00.000000000 +0900
+++ ja-p5-Mail-SpamAssassin/files/pkg-install.in	2012-01-16 09:28:59.696265468 +0900
@@ -0,0 +1,77 @@
+#!/bin/sh
+#
+# $FreeBSD: ports/mail/p5-Mail-SpamAssassin/files/pkg-install.in,v 1.2 2012/01/02 13:27:09 scheidell Exp $
+#
+
+USER=%%USER%%
+GROUP=%%GROUP%%
+INSTALL="%%INSTALL%%"
+PREFIX=%%PREFIX%%
+
+if [ "$2" = "PRE-INSTALL" ];then exit; fi
+
+if [ -z "${INSTALL}" ];then
+echo "report this problem to scheidell at freebsd.org, $*"
+exit 1
+fi
+
+if [ "$2" = "POST-INSTALL" ];then 
+ask() {
+        local question default answer
+
+        question=$1
+        default=$2
+        if [ -z "${PACKAGE_BUILDING}" -a -z "${BATCH}" ]; then
+                read -t120 -p "${question} [${default}]? " answer
+        fi
+        echo ${answer:-${default}}
+}
+
+yesno() {
+        local question default answer
+
+        question=$1
+        default=$2
+        while :; do
+                answer=$(ask "${question}" "${default}")
+                case "${answer}" in
+                [Yy]*)  return 0;;
+                [Nn]*)  return 1;;
+                esac
+                echo "Please answer yes or no."
+        done
+}
+
+    # Create pid directory
+
+    ${INSTALL} -d -o ${USER} -g ${GROUP} /var/run/spamd
+    ${PREFIX}/bin/spamassassin -x -L --lint
+    if [ ${?} -ne 0 ];then
+        echo "
+*******************************************************
+* _  _  _ _______  ______ __   _ _____ __   _  ______ *
+* |  |  | |_____| |_____/ | \  |   |   | \  | |  ____ *
+* |__|__| |     | |    \_ |  \_| __|__ |  \_| |_____| *
+*                                                     *
+*******************************************************
+*    You must install rules before starting spamd!    *
+*******************************************************"
+        if [ -z "${PACKAGE_BUILDING}" -a -z "${BATCH}" ]; then
+           if yesno "Do you wish to run sa-update to fetch new rules" "N";then
+              ${PREFIX}/bin/sa-update || true
+	   else
+              echo ""
+           fi
+           ${PREFIX}/bin/spamassassin -x -L --lint
+           if [ ${?} -eq 0 ] && grep '^load.*Rule2XSBody' ${PREFIX}/etc/mail/spamassassin/v320.pre > /dev/null ;then
+              if yesno "Do you wish to compile rules with re2c (will take a long time)" "N";then
+                ${PREFIX}/bin/sa-compile || true
+        fi
+    fi
+       fi
+    fi
+
+    exit 0
+fi # post-install
+
+exit 0
diff -ruN /usr/ports/japanese/p5-Mail-SpamAssassin/files/sa-spamd.sh.in ja-p5-Mail-SpamAssassin/files/sa-spamd.sh.in
--- /usr/ports/japanese/p5-Mail-SpamAssassin/files/sa-spamd.sh.in	2012-01-14 17:55:50.000000000 +0900
+++ ja-p5-Mail-SpamAssassin/files/sa-spamd.sh.in	2012-01-16 09:28:59.696265468 +0900
@@ -1,6 +1,6 @@
 #!/bin/sh
 #
-# $FreeBSD: ports/japanese/p5-Mail-SpamAssassin/files/sa-spamd.sh.in,v 1.4 2012/01/14 08:55:50 dougb Exp $
+# $FreeBSD: ports/mail/p5-Mail-SpamAssassin/files/sa-spamd.sh.in,v 1.4 2012/01/14 08:55:59 dougb Exp $
 #
 
 # PROVIDE: spamd
diff -ruN /usr/ports/japanese/p5-Mail-SpamAssassin/pkg-install ja-p5-Mail-SpamAssassin/pkg-install
--- /usr/ports/japanese/p5-Mail-SpamAssassin/pkg-install	2011-08-11 16:50:30.000000000 +0900
+++ ja-p5-Mail-SpamAssassin/pkg-install	1970-01-01 09:00:00.000000000 +0900
@@ -1,66 +0,0 @@
-#!/bin/sh
-PKG_PREFIX=${PKG_PREFIX:-/usr/local}
-USER=${USER:-spamd}
-GROUP=${GROUP:-spamd}
-HOME=/var/spool/${USER}
-
-if [ "$2" = "POST-INSTALL" ];then
-ask() {
-        local question default answer
-
-        question=$1
-        default=$2
-        if [ -z "${PACKAGE_BUILDING}" -a -z "${BATCH}" ]; then
-                read -t120 -p "${question} [${default}]? " answer
-        fi
-        echo ${answer:-${default}}
-}
-
-yesno() {
-        local question default answer
-
-        question=$1
-        default=$2
-        while :; do
-                answer=$(ask "${question}" "${default}")
-                case "${answer}" in
-                [Yy]*)  return 0;;
-                [Nn]*)  return 1;;
-                esac
-                echo "Please answer yes or no."
-        done
-}
-
-    # Create pid directory
-    install -d -o ${USER} -g ${GROUP} /var/run/spamd
-    /usr/bin/su root -c "${PKG_PREFIX}/bin/spamassassin -x -L --lint"
-
-    if [ ${?} -eq 9 ];then
-        echo "***********************************************"
-        echo "*__        ___    ____  _   _ ___ _   _  ____ *"
-        echo "*\ \      / / \  |  _ \| \ | |_ _| \ | |/ ___|*"
-        echo "* \ \ /\ / / _ \ | |_) |  \| || ||  \| | |  _ *"
-        echo "*  \ V  V / ___ \|  _ <| |\  || || |\  | |_| |*"
-        echo "*   \_/\_/_/   \_\_| \_\_| \_|___|_| \_|\____|*"
-        echo "*                                             *"
-        echo "*You must install rules before starting spamd!*"
-        echo "***********************************************"
-        if [ -z "${PACKAGE_BUILDING}" -a -z "${BATCH}" ]; then
-           if yesno "Do you wish to run sa-update to fetch new rules" "N";then
-              ${PKG_PREFIX}/bin/sa-update || true
-	   else
-              echo ""
-           fi
-           /usr/bin/su root -c  "${PKG_PREFIX}/bin/spamassassin -x -L --lint"
-           if [ ${?} -eq 0 ] && grep '^load.*Rule2XSBody' ${PKG_PREFIX}/etc/mail/spamassassin/v320.pre > /dev/null ;then
-              if yesno "Do you wish to compile rules with re2c (will take a long time)" "N";then
-                ${PKG_PREFIX}/bin/sa-compile || true
-        fi
-    fi
-       fi
-    fi
-
-    exit 0
-fi  # post-install
-
-exit 0
diff -ruN /usr/ports/japanese/p5-Mail-SpamAssassin/pkg-plist ja-p5-Mail-SpamAssassin/pkg-plist
--- /usr/ports/japanese/p5-Mail-SpamAssassin/pkg-plist	2011-08-11 18:59:52.000000000 +0900
+++ ja-p5-Mail-SpamAssassin/pkg-plist	2012-01-16 09:41:14.145459198 +0900
@@ -7,7 +7,7 @@
 bin/spamassassin
 bin/spamc
 bin/spamd
- at unexec rm -rf %D/etc/mail/spamassassin/sa-update-keys || true
+ at unexec rm -rf %D/etc/mail/spamassassin/sa-update-keys
 etc/mail/spamassassin/local.cf.sample
 @unexec if cmp -s %B/init.pre.sample %B/init.pre; then rm -f %B/init.pre; fi
 etc/mail/spamassassin/init.pre.sample
@@ -137,10 +137,10 @@
 %%DATADIR%%/languages
 %%DATADIR%%/sa-update-pubkey.txt
 %%DATADIR%%/user_prefs.template
- at unexec rm -rf /var/lib/spamassassin/2* || true
- at unexec rmdir /var/lib/spamassassin 2>/dev/null  || true
- at unexec rmdir /var/lib 2>/dev/null || true
- at unexec rmdir /var/db/spamassassin || true
+ at unexec rm -rf /var/lib/spamassassin/2* 
+ at unexec rmdir /var/lib/spamassassin 2>/dev/null
+ at unexec rmdir /var/lib 2>/dev/null
+ at unexec rmdir /var/db/spamassassin
 @dirrm %%DATADIR%%
 @dirrm %%SITE_PERL%%/%%PERL_ARCH%%/auto/Mail/SpamAssassin
 @dirrmtry %%SITE_PERL%%/%%PERL_ARCH%%/auto/Mail
--- patch.txt ends here ---


>Release-Note:
>Audit-Trail:
>Unformatted:



More information about the freebsd-ports-bugs mailing list