ports/157107: conflict between mail/p5-Mail-SPF and mail/libspf2

Koen Martens gmc at sonologic.nl
Tue May 24 18:00:21 UTC 2011


The following reply was made to PR ports/157107; it has been noted by GNATS.

From: Koen Martens <gmc at sonologic.nl>
To: bug-followup at FreeBSD.ORG
Cc:  
Subject: Re: ports/157107: conflict between mail/p5-Mail-SPF and mail/libspf2
Date: Tue, 24 May 2011 19:58:20 +0200

 --r5Pyd7+fXNt84Ff3
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
 
 This patch should fix it.
 
 On Tue, May 17, 2011 at 09:10:24AM +0000, Edwin Groothuis wrote:
 > Maintainer of mail/p5-Mail-SPF,
 > 
 > Please note that PR ports/157107 has just been submitted.
 > 
 > If it contains a patch for an upgrade, an enhancement or a bug fix
 > you agree on, reply to this email stating that you approve the patch
 > and a committer will take care of it.
 > 
 > The full text of the PR can be found at:
 >     http://www.freebsd.org/cgi/query-pr.cgi?pr=ports/157107
 > 
 > -- 
 > Edwin Groothuis via the GNATS Auto Assign Tool
 > edwin at FreeBSD.org
 > 
 > 
 
 -- 
 http://www.sonologic.nl/
 http://koenmartens.nl/
 https://www.revspace.nl/
 http://hxxfoundation.com/
 
 --r5Pyd7+fXNt84Ff3
 Content-Type: text/x-diff; charset=us-ascii
 Content-Disposition: attachment; filename="p5-Mail-SPF.patch"
 
 diff -Naur p5-Mail-SPF.dist/Makefile p5-Mail-SPF/Makefile
 --- p5-Mail-SPF.dist/Makefile	2009-11-15 10:07:11.000000000 +0100
 +++ p5-Mail-SPF/Makefile	2011-05-24 19:52:00.000000000 +0200
 @@ -15,6 +15,9 @@
  MAINTAINER=	gmc at sonologic.nl
  COMMENT=	Reference implementation of the RFC 4408 SPF protocol
  
 +OPTIONS=	SPFQUERY "Install spfquery command-line tool" on \
 +		SPFQUERY_SUFFIX "Add .pl suffix to spfquery" off
 +
  RUN_DEPENDS=	p5-Net-DNS-Resolver-Programmable>=0.002.1:${PORTSDIR}/dns/p5-Net-DNS-Resolver-Programmable \
  		p5-Net-DNS>=0.58:${PORTSDIR}/dns/p5-Net-DNS \
  		p5-version>0:${PORTSDIR}/devel/p5-version \
 @@ -28,7 +31,6 @@
  PERL_MODBUILD=	5.6.0+
  CONFIGURE_ARGS=	--install_path sbin=${PREFIX}/sbin
  
 -MAN1=		spfquery.1
  MAN3=		Mail::SPF.3 Mail::SPF::Mech::PTR.3 Mail::SPF::Mech.3 \
  		Mail::SPF::SenderIPAddrMech.3 Mail::SPF::MacroString.3 \
  		Mail::SPF::Mech::IP4.3 Mail::SPF::Mech::A.3 \
 @@ -45,6 +47,24 @@
  DOCSDIR=	${PREFIX}/share/doc/p5-Mail-SPF
  DOCS=		CHANGES INSTALL LICENSE README TODO
  
 +.if defined(WITH_SPFQUERY)
 +PLIST_SUB+= SPFQUERY=""
 +
 +.if defined(WITH_SPFQUERY_SUFFIX)
 +PLIST_SUB+= SPFQUERY_SUFFIX=".pl"
 +EXTRA_PATCHES+= ${FILESDIR}/extra-patch-spfquery-suffix
 +MAN1+=		spfquery.pl.1
 +.else
 +PLIST_SUB+= SPFQUERY_SUFFIX=""
 +MAN1+=		spfquery.1
 +CONFLICTS+=	libspf2*
 +.endif
 +
 +.else
 +PLIST_SUB+= SPFQUERY="@comment "
 +EXTRA_PATCHES+= ${FILESDIR}/extra-patch-no-spfquery
 +.endif
 +
  post-install:
  .if !defined(NOPORTDOCS)
  	@${MKDIR} ${DOCSDIR}
 diff -Naur p5-Mail-SPF.dist/files/extra-patch-no-spfquery p5-Mail-SPF/files/extra-patch-no-spfquery
 --- p5-Mail-SPF.dist/files/extra-patch-no-spfquery	1970-01-01 01:00:00.000000000 +0100
 +++ p5-Mail-SPF/files/extra-patch-no-spfquery	2011-05-24 19:30:10.000000000 +0200
 @@ -0,0 +1,33 @@
 +diff -Naur orig/Build.PL Build.PL
 +--- orig/Build.PL	2009-10-31 23:16:14.000000000 +0100
 ++++ Build.PL	2011-05-24 19:27:19.000000000 +0200
 +@@ -66,7 +66,6 @@
 +                         => 'v0.002.1',
 +     },
 +     script_files    => [
 +-        'bin/spfquery'
 +     ],
 +     install_path    => {
 +         'sbin'          => '/usr/sbin'
 +diff -Naur orig/MANIFEST MANIFEST
 +--- orig/MANIFEST	2009-10-31 23:16:14.000000000 +0100
 ++++ MANIFEST	2011-05-24 19:26:56.000000000 +0200
 +@@ -1,4 +1,3 @@
 +-bin/spfquery
 + Build.PL
 + CHANGES
 + debian/changelog
 +diff -Naur orig/README README
 +--- orig/README	2009-10-31 23:16:14.000000000 +0100
 ++++ README	2011-05-24 19:27:05.000000000 +0200
 +@@ -12,9 +12,8 @@
 + This release of Mail::SPF fully conforms to RFC 4408 and passes the 2008.08
 + release of the official test-suite <http://www.openspf.org/Test_Suite>.
 + 
 +-The Mail::SPF source package includes the following additional tools:
 ++The Mail::SPF source package includes the following additional tool:
 + 
 +-  * spfquery:  A command-line tool for performing SPF checks.
 +   * spfd:      A daemon for services that perform SPF checks frequently.
 + 
 + Mail::SPF is not your mother!
 diff -Naur p5-Mail-SPF.dist/files/extra-patch-spfquery-suffix p5-Mail-SPF/files/extra-patch-spfquery-suffix
 --- p5-Mail-SPF.dist/files/extra-patch-spfquery-suffix	1970-01-01 01:00:00.000000000 +0100
 +++ p5-Mail-SPF/files/extra-patch-spfquery-suffix	2011-05-24 19:41:56.000000000 +0200
 @@ -0,0 +1,1505 @@
 +diff -Naur orig/Build.PL Build.PL
 +--- orig/Build.PL	2009-10-31 23:16:14.000000000 +0100
 ++++ Build.PL	2011-05-24 19:40:10.000000000 +0200
 +@@ -66,7 +66,7 @@
 +                         => 'v0.002.1',
 +     },
 +     script_files    => [
 +-        'bin/spfquery'
 ++        'bin/spfquery.pl'
 +     ],
 +     install_path    => {
 +         'sbin'          => '/usr/sbin'
 +diff -Naur orig/MANIFEST MANIFEST
 +--- orig/MANIFEST	2009-10-31 23:16:14.000000000 +0100
 ++++ MANIFEST	2011-05-24 19:40:36.000000000 +0200
 +@@ -1,4 +1,4 @@
 +-bin/spfquery
 ++bin/spfquery.pl
 + Build.PL
 + CHANGES
 + debian/changelog
 +diff -Naur orig/README README
 +--- orig/README	2009-10-31 23:16:14.000000000 +0100
 ++++ README	2011-05-24 19:40:54.000000000 +0200
 +@@ -14,8 +14,8 @@
 + 
 + The Mail::SPF source package includes the following additional tools:
 + 
 +-  * spfquery:  A command-line tool for performing SPF checks.
 +-  * spfd:      A daemon for services that perform SPF checks frequently.
 ++  * spfquery.pl: A command-line tool for performing SPF checks.
 ++  * spfd:        A daemon for services that perform SPF checks frequently.
 + 
 + Mail::SPF is not your mother!
 + -----------------------------
 +diff -Naur orig/bin/spfquery bin/spfquery
 +--- orig/bin/spfquery	2009-10-31 23:16:14.000000000 +0100
 ++++ bin/spfquery	1970-01-01 01:00:00.000000000 +0100
 +@@ -1,731 +0,0 @@
 +-#!/usr/bin/perl
 +-
 +-# 
 +-# spfquery: Command-line tool for performing SPF queries
 +-#
 +-# (C) 2005-2008 Julian Mehnle <julian at mehnle.net>
 +-#     2004      Wayne Schlitt <wayne at schlitt.net>
 +-# $Id: spfquery 138 2006-01-22 18:00:34Z julian $
 +-#
 +-##############################################################################
 +-
 +-=head1 NAME
 +-
 +-spfquery - (Mail::SPF) - Checks if a given set of e-mail parameters matches a
 +-domain's SPF policy
 +-
 +-=head1 VERSION
 +-
 +-2.501
 +-
 +-=head1 SYNOPSIS
 +-
 +-=over
 +-
 +-=item B<Preferred usage:>
 +-
 +-B<spfquery> [B<--versions>|B<-v> B<1>|B<2>|B<1,2>] [B<--scope>|B<-s> B<helo>|B<mfrom>|B<pra>]
 +-B<--identity>|B<--id> I<identity> B<--ip-address>|B<--ip> I<ip-address>
 +-[B<--helo-identity>|B<--helo-id> I<helo-identity>] [I<OPTIONS>]
 +-
 +-B<spfquery> [B<--versions>|B<-v> B<1>|B<2>|B<1,2>] [B<--scope>|B<-s> B<helo>|B<mfrom>|B<pra>]
 +-B<--file>|B<-f> I<filename>|B<-> [I<OPTIONS>]
 +-
 +-=item B<Legacy usage:>
 +-
 +-B<spfquery> B<--helo> I<helo-identity> B<--ip-address>|B<--ip> I<ip-address> [I<OPTIONS>]
 +-
 +-B<spfquery> B<--mfrom> I<mfrom-identity> B<--ip-address>|B<--ip> I<ip-address>
 +-[B<--helo> I<helo-identity>] [I<OPTIONS>]
 +-
 +-B<spfquery> B<--pra> I<pra-identity> B<--ip-address>|B<--ip> I<ip-address> [I<OPTIONS>]
 +-
 +-=item B<Other usage:>
 +-
 +-B<spfquery> B<--version>|B<-V>
 +-
 +-B<spfquery> B<--help>
 +-
 +-=back
 +-
 +-=head1 DESCRIPTION
 +-
 +-B<spfquery> checks if a given set of e-mail parameters (e.g., the SMTP sender's
 +-IP address) matches the responsible domain's Sender Policy Framework (SPF)
 +-policy.  For more information on SPF see L<http://www.openspf.org>.
 +-
 +-=head2 Preferred Usage
 +-
 +-The following usage forms are preferred over the L<legacy forms|/Legacy usage>
 +-used by older B<spfquery> versions:
 +-
 +-The B<--identity> form checks if the given I<ip-address> is an authorized SMTP
 +-sender for the given C<helo> hostname, C<mfrom> envelope sender e-mail address,
 +-or C<pra> (so-called purported resonsible address) e-mail address, depending
 +-on the value of the B<--scope> option (which defaults to B<mfrom> if omitted).
 +-
 +-The B<--file> form reads "I<ip-address> I<identity> [I<helo-identity>]" tuples
 +-from the file with the specified I<filename>, or from standard input if
 +-I<filename> is B<->, and checks them against the specified scope (B<mfrom> by
 +-default).
 +-
 +-Both forms support an optional B<--versions> option, which specifies a
 +-comma-separated list of the SPF version numbers of SPF records that may be
 +-used.  B<1> means that C<v=spf1> records should be used.  B<2> means that
 +-C<spf2.0> records should be used.  Defaults to B<1,2>, i.e., uses any SPF
 +-records that are available.  Records of a higher version are preferred.
 +-
 +-=head2 Legacy Usage
 +-
 +-B<spfquery> versions before 2.500 featured the following usage forms, which are
 +-discouraged but still supported for L<backwards compatibility|/COMPATIBILITY>:
 +-
 +-The B<--helo> form checks if the given I<ip-address> is an authorized SMTP
 +-sender for the C<HELO> hostname given as the I<identity> (so-called C<HELO>
 +-check).
 +-
 +-The B<--mfrom> form checks if the given I<ip-address> is an authorized SMTP
 +-sender for the envelope sender email-address (or domain) given as the
 +-I<identity> (so-called C<MAIL FROM> check).  If a domain is given instead of an
 +-e-mail address, C<postmaster> will be substituted for the localpart.
 +-
 +-The B<--pra> form checks if the given I<ip-address> is an authorized SMTP
 +-sender for the PRA (Purported Responsible Address) e-mail address given as the
 +-identity.
 +-
 +-=head2 Other Usage
 +-
 +-The B<--version> form prints version information of spfquery.  The B<--help>
 +-form prints usage information for spfquery.
 +-
 +-=head1 OPTIONS
 +-
 +-=head2 Standard Options
 +-
 +-The preferred and legacy forms optionally take any of the following
 +-I<OPTIONS>:
 +-
 +-=over
 +-
 +-=item B<--default-explanation> I<string>
 +-
 +-=item B<--def-exp> I<string>
 +-
 +-Use the specified I<string> as the default explanation if the authority domain
 +-does not specify an explanation string of its own.
 +-
 +-=item B<--hostname> I<hostname>
 +-
 +-Use I<hostname> as the host name of the local system instead of auto-detecting
 +-it.
 +-
 +-=item B<--keep-comments>
 +-
 +-=item B<--no-keep-comments>
 +-
 +-Do (not) print any comments found when reading from a file or from standard
 +-input.
 +-
 +-=item B<--sanitize> (currently ignored)
 +-
 +-=item B<--no-sanitize> (currently ignored)
 +-
 +-Do (not) sanitize the output by condensing consecutive white-space into a
 +-single space and replacing non-printable characters with question marks.
 +-Enabled by default.
 +-
 +-=item B<--debug> (currently ignored)
 +-
 +-Print out debug information.
 +-
 +-=back
 +-
 +-=head2 Black Magic Options
 +-
 +-Several options that were supported by earlier versions of B<spfquery> are
 +-considered black magic (i.e. potentially dangerous for the innocent user) and
 +-are thus disabled by default.  If the L<B<Mail::SPF::BlackMagic>> Perl module
 +-is installed, they may be enabled by specifying B<--enable-black-magic>.
 +-
 +-=over
 +-
 +-=item B<--max-dns-interactive-terms> I<n>
 +-
 +-Evaluate a maximum of I<n> DNS-interactive mechanisms and modifiers per SPF
 +-check.  Defaults to B<10>.  Do I<not> override the default unless you know what
 +-you are doing!
 +-
 +-=item B<--max-name-lookups-per-term> I<n>
 +-
 +-Perform a maximum of I<n> DNS name look-ups per mechanism or modifier.
 +-Defaults to B<10>.  Do I<not> override the default unless you know what you are
 +-doing!
 +-
 +-=item B<--authorize-mxes-for> I<email-address>|I<domain>B<,>...
 +-
 +-Consider all the MXes of the comma-separated list of I<email-address>es and
 +-I<domain>s as inherently authorized.
 +-
 +-=item B<--tfwl>
 +-
 +-Perform C<trusted-forwarder.org> accreditation checking.
 +-
 +-=item B<--guess> I<spf-terms>
 +-
 +-Use I<spf-terms> as a default record if no SPF record is found.
 +-
 +-=item B<--local> I<spf-terms>
 +-
 +-Process I<spf-terms> as local policy before resorting to a default result
 +-(the implicit or explicit C<all> mechanism at the end of the domain's SPF
 +-record).  For example, this could be used for white-listing one's secondary
 +-MXes: C<mx:mydomain.example.org>.
 +-
 +-=item B<--override> I<domain>B<=>I<spf-record>
 +-
 +-=item B<--fallback> I<domain>B<=>I<spf-record>
 +-
 +-Set overrides and fallbacks.  Each option can be specified multiple times.  For
 +-example:
 +-
 +-    --override example.org='v=spf1 -all'
 +-    --override '*.example.net'='v=spf1 a mx -all'
 +-    --fallback example.com='v=spf1 -all'
 +-
 +-=back
 +-
 +-=head1 RESULT CODES
 +-
 +-=over 12
 +-
 +-=item B<pass>
 +-
 +-The specified IP address is an authorized SMTP sender for the identity.
 +-
 +-=item B<fail>
 +-
 +-The specified IP address is not an authorized SMTP sender for the identity.
 +-
 +-=item B<softfail>
 +-
 +-The specified IP address is not an authorized SMTP sender for the identity,
 +-however the authority domain is still testing out its SPF policy.
 +-
 +-=item B<neutral>
 +-
 +-The identity's authority domain makes no assertion about the status of the IP
 +-address.
 +-
 +-=item B<permerror>
 +-
 +-A permanent error occurred while evaluating the authority domain's policy
 +-(e.g., a syntax error in the SPF record).  Manual intervention is required
 +-from the authority domain.
 +-
 +-=item B<temperror>
 +-
 +-A temporary error occurred while evaluating the authority domain's policy
 +-(e.g., a DNS error).  Try again later.
 +-
 +-=item B<none>
 +-
 +-There is no applicable SPF policy for the identity domain.
 +-
 +-=back
 +-
 +-=head1 EXIT CODES
 +-
 +-  Result    | Exit code
 +- -----------+-----------
 +-  pass      |     0
 +-  fail      |     1
 +-  softfail  |     2
 +-  neutral   |     3
 +-  permerror |     4
 +-  temperror |     5
 +-  none      |     6
 +-
 +-=head1 EXAMPLES
 +-
 +-    spfquery --scope mfrom --id user at example.com --ip 1.2.3.4
 +-    spfquery --file test_data
 +-    echo "127.0.0.1 user at example.com helohost.example.com" | spfquery -f -
 +-
 +-=head1 COMPATIBILITY
 +-
 +-B<spfquery> has undergone the following interface changes compared to earlier
 +-versions:
 +-
 +-=over
 +-
 +-=item B<2.500>
 +-
 +-=over
 +-
 +-=item *
 +-
 +-A new preferred usage style for performing individual SPF checks has been
 +-introduced.  The new style accepts a unified B<--identity> option and an
 +-optional B<--scope> option that specifies the type (scope) of the identity.  In
 +-contrast, the legacy usage style requires a separate usage form for every
 +-supported scope.  See L</Preferred usage> and L</Legacy usage> for details.
 +-
 +-=item *
 +-
 +-The former C<unknown> and C<error> result codes have been renamed to C<permerror>
 +-and C<temperror>, respectively, in order to comply with RFC 4408 terminology.
 +-
 +-=item *
 +-
 +-SPF checks with an empty identity are no longer supported.  In the case of an
 +-empty C<MAIL FROM> SMTP transaction parameter, perform a check with the C<helo>
 +-scope directly.
 +-
 +-=item *
 +-
 +-The B<--debug> and B<--(no-)sanitize> options are currently ignored by this
 +-version of B<spfquery>.  They will again be supported in the future.
 +-
 +-=item *
 +-
 +-Several features that were supported by earlier versions of B<spfquery> are
 +-considered black magic and thus are now disabled by default.  See L</Black
 +-Magic Options>.
 +-
 +-=item *
 +-
 +-Several option names have been deprecated.  This is a list of them and their
 +-preferred synonyms:
 +-
 +-  Deprecated options  | Preferred options
 +- ---------------------+-----------------------------
 +-  --sender, -s        | --mfrom
 +-  --ipv4, -i          | --ip-address, --ip
 +-  --name              | --hostname
 +-  --max-lookup-count, | --max-dns-interactive-terms
 +-    --max-lookup      |
 +-  --rcpt-to, -r       | --authorize-mxes-for
 +-  --trusted           | --tfwl
 +-
 +-=back
 +-
 +-=back
 +-
 +-=head1 SEE ALSO
 +-
 +-L<Mail::SPF>, L<spfd(8)>
 +-
 +-L<http://www.ietf.org/rfc/rfc4408.txt>
 +-
 +-=head1 AUTHORS
 +-
 +-This version of B<spfquery> is a complete rewrite by Julian Mehnle
 +-<julian at mehnle.net>, based on an earlier version written by Meng Weng Wong
 +-<mengwong+spf at pobox.com> and Wayne Schlitt <wayne at schlitt.net>.
 +-
 +-=cut
 +-
 +-our $VERSION = '2.501';
 +-
 +-use warnings;
 +-use strict;
 +-
 +-use IO::File;
 +-use Getopt::Long qw(:config gnu_compat no_ignore_case);
 +-use Error ':try';
 +-use Mail::SPF;
 +-
 +-use constant TRUE   => (0 == 0);
 +-use constant FALSE  => not TRUE;
 +-
 +-use constant exit_codes_by_result_code => {
 +-    pass        => 0,
 +-    fail        => 1,
 +-    softfail    => 2,
 +-    neutral     => 3,
 +-    permerror   => 4,
 +-    temperror   => 5,
 +-    none        => 6
 +-};
 +-
 +-# Helper Functions
 +-##############################################################################
 +-
 +-sub usage {
 +-    STDERR->printf(<<'EOT');
 +-Preferred Usage:
 +-    spfquery [--versions|-v 1|2|1,2] [--scope|-s helo|mfrom|pra]
 +-        --identity|--id <identity> --ip-address|--ip <ip-address>
 +-        [--helo-identity|--helo-id <helo-identity>] [OPTIONS]
 +-    spfquery [--versions|-v 1|2|1,2] [--scope|-s helo|mfrom|pra]
 +-        --file|-f <filename>|- [OPTIONS]
 +-
 +-Legacy Usage:
 +-    spfquery --helo <helo-identity> --ip-address|--ip <ip-address> [OPTIONS]
 +-    spfquery --mfrom <mfrom-identity> --ip-address|--ip <ip-address>
 +-        [--helo <helo-identity>] [OPTIONS]
 +-    spfquery --pra <pra-identity> --ip-address|--ip <ip-address> [OPTIONS]
 +-
 +-Other Usage:
 +-    spfquery --version|-V
 +-
 +-See `spfquery --help` for more information.
 +-EOT
 +-    return;
 +-}
 +-
 +-sub help {
 +-    print(<<'EOT');
 +-Preferred Usage:
 +-    spfquery [--versions|-v 1|2|1,2] [--scope|-s helo|mfrom|pra]
 +-        --identity|--id <identity> --ip-address|--ip <ip-address>
 +-        [--helo-identity|--helo-id <helo-identity>] [OPTIONS]
 +-    spfquery [--versions|-v 1|2|1,2] [--scope|-s helo|mfrom|pra]
 +-        --file|-f <filename>|- [OPTIONS]
 +-
 +-Legacy Usage:
 +-    spfquery --helo <helo-identity> --ip-address|--ip <ip-address> [OPTIONS]
 +-    spfquery --mfrom <mfrom-identity> --ip-address|--ip <ip-address>
 +-        [--helo <helo-identity>] [OPTIONS]
 +-    spfquery --pra <pra-identity> --ip-address|--ip <ip-address> [OPTIONS]
 +-
 +-Other Usage:
 +-    spfquery --version|-V
 +-
 +-spfquery performs SPF checks based on the command-line arguments or data given
 +-in a file or on standard input.
 +-
 +-Only the preferred and other usage forms are explained here.  See the
 +-spfquery(1) man-page for an explanation of the legacy usage forms.
 +-
 +-The "--identity" form checks if the given <ip-address> is an authorized SMTP
 +-sender for the given "helo" hostname, "mfrom" envelope sender e-mail address,
 +-or "pra" (purported resonsible address) e-mail address, depending on the value
 +-of the "--scope" option (which defaults to "mfrom" if omitted).
 +-
 +-The "--file" form reads "<ip-address> <identity> [<helo-identity>]" tuples from
 +-the file with the specified <filename>, or from standard input if <filename> is
 +-"-", and checks them against the specified scope ("mfrom" by default).
 +-
 +-The "--version" form prints version information of spfquery.
 +-
 +-Valid OPTIONS (and their defaults) are:
 +-    --default-explanation <string>
 +-                        Default explanation string to use (sensible default).
 +-    --hostname <hostname>
 +-                        The name of the system doing the SPF checking (local
 +-                        system's configured hostname).
 +-    --keep-comments     Print comments found when reading from a file.
 +-    --no-sanitize       Do not clean up invalid characters in output.
 +-    --debug             Output debugging information.
 +-
 +-Black-magic OPTIONS are:
 +-    --max-dns-interactive-terms <n>
 +-                        Maximum number of DNS-interactive mechanisms and
 +-                        modifiers (10).
 +-    --max-name-lookups-per-term <n>
 +-                        Maximum number of DNS name look-ups per mechanism or
 +-                        modifier (10).
 +-    --authorize-mxes-for <email-address>|<domain>,...
 +-                        A comma-separated list of e-mail addresses and domains
 +-                        whose MXes will be considered inherently authorized.
 +-    --tfwl              Check trusted-forwarder.org white-list.
 +-    --guess <spf-terms> Default checks if no SPF record is found.
 +-    --local <spf-terms> Local policy to process before default result.
 +-    --override <domain>=<spf-record>
 +-    --fallback <domain>=<spf-record>
 +-                        Set override and fallback SPF records for domains.
 +-
 +-Examples:
 +-    spfquery --scope mfrom --id user at example.com --ip 1.2.3.4
 +-    spfquery --file test_data
 +-    echo "127.0.0.1 user at example.com helohost.example.com" | spfquery -f -
 +-EOT
 +-    return;
 +-}
 +-
 +-sub deprecated_option {
 +-    my ($old_option, $new_option, $options) = @_;
 +-    return FALSE if not exists($options->{$old_option});
 +-    STDERR->print(
 +-        "Warning: '$old_option' option is deprecated" .
 +-        ($new_option ? "; use '$new_option' instead" : '') .
 +-        ".\n"
 +-    );
 +-    $options->{$new_option} = delete($options->{$old_option});
 +-    return TRUE;
 +-}
 +-
 +-sub unsupported_option {
 +-    my ($option_name, $options) = @_;
 +-    return FALSE if not exists($options->{$option_name});
 +-    STDERR->print("Error: '$option_name' option is no longer supported.\n");
 +-    return TRUE;
 +-}
 +-
 +-sub black_magic_option {
 +-    my ($option_name, $options) = @_;
 +-    return FALSE if not exists($options->{$option_name});
 +-    STDERR->print("Error: '$option_name' option is black magic! Do not use it!\n");
 +-    return TRUE;
 +-}
 +-
 +-# Command-line Option Handling
 +-##############################################################################
 +-
 +-my $options = {};
 +-my $getopt_result = GetOptions(
 +-    $options,
 +-    
 +-    'file|f=s',
 +-    
 +-    'versions|v=s',
 +-    'scope=s',
 +-    's=s',  # Special handling for ambiguous 's' option (formerly a synonym
 +-            # for 'sender', now preferredly a synonym for 'scope').
 +-    'identity|id=s',
 +-    'ip-address|ip=s',
 +-    'helo-identity|helo-id=s',
 +-    
 +-    # Legacy/shortcut options:
 +-    'mfrom|mail-from|m=s',
 +-    'helo|h=s',
 +-    
 +-    'default-explanation|def-exp=s',
 +-    'hostname=s',
 +-    
 +-    'keep-comments!',
 +-    'debug!',       # TODO Implement!
 +-    'sanitize!',    # TODO Implement!
 +-    
 +-    # Black Magic options:
 +-    'enable-black-magic!',
 +-    'max-dns-interactive-terms=i',
 +-    'max-name-lookups-per-term=i',
 +-    'authorize-mxes-for=s',
 +-                    # TODO implement!
 +-    'tfwl!',        # TODO Implement!
 +-    'guess=s',      # TODO Implement!
 +-    'local=s',      # TODO Implement!
 +-    'override=s%',  # TODO Implement!
 +-    'fallback=s%',  # TODO Implement!
 +-    
 +-    # Meta actions:
 +-    'version|V!',
 +-    'help!',
 +-    
 +-    # Deprecated options:
 +-    'sender=s',     # Now 'scope'/'identity' or 'mfrom'
 +-    'ipv4=s',       # Now 'ip-address'
 +-    'i=s',          # Now 'ip-address'
 +-    'name=s',       # Now 'hostname'
 +-    'max-lookup-count=i',
 +-    'max-lookup=i', # Now 'max-dns-interactive-terms'
 +-    'rcpt-to=s',    # Now 'authorize-mxes-for'
 +-    'r=s',          # Now 'authorize-mxes-for'
 +-    'trusted!'      # Now 'tfwl'
 +-);
 +-
 +-if (not $getopt_result) {
 +-    usage();
 +-    exit(255);
 +-}
 +-
 +-if ($options->{help}) {
 +-    help();
 +-    exit(0);
 +-}
 +-
 +-if ($options->{version}) {
 +-    print("spfquery version $VERSION (using Mail::SPF)\n");
 +-    exit(0);
 +-}
 +-
 +-deprecated_option('sender',           'mfrom',                     $options);
 +-deprecated_option('ipv4',             'ip-address',                $options);
 +-deprecated_option('i',                'ip-address',                $options);
 +-deprecated_option('name',             'hostname',                  $options);
 +-deprecated_option('max-lookup-count', 'max-dns-interactive-terms', $options);
 +-deprecated_option('max-lookup',       'max-dns-interactive-terms', $options);
 +-deprecated_option('rcpt-to',          'authorize-mxes-for',        $options);
 +-deprecated_option('r',                'authorize-mxes-for',        $options);
 +-deprecated_option('trusted',          'tfwl',                      $options);
 +-
 +-if ($options->{'enable-black-magic'}) {
 +-    if (not defined(eval('require Mail::SPF::BlackMagic'))) {
 +-        STDERR->print("Error: Cannot enable black magic. Unable to load Mail::SPF::BlackMagic.\n");
 +-        exit(255);
 +-    }
 +-    # else: Black magic enabled!
 +-}
 +-elsif (
 +-    black_magic_option('max-dns-interactive-terms', $options) or
 +-    black_magic_option('max-name-lookups-per-term', $options) or
 +-    black_magic_option('rcpt-to',                   $options) or
 +-    black_magic_option('trusted',                   $options) or
 +-    black_magic_option('guess',                     $options) or
 +-    black_magic_option('local',                     $options) or
 +-    black_magic_option('override',                  $options) or
 +-    black_magic_option('fallback',                  $options)
 +-) {
 +-    exit(255);
 +-}
 +-
 +-my @versions            = split(',', $options->{versions} || '');
 +-my $scope               = $options->{scope};
 +-my $identity            = $options->{identity};
 +-my $ip_address          = $options->{'ip-address'};
 +-my $helo_identity       = $options->{'helo-identity'};
 +-
 +-# Heuristic for distinguishing between 's(cope)' and 's(ender)':
 +-if (defined(my $s = $options->{s})) {
 +-    if (
 +-        not defined($scope) and  # No explicit 'scope' option has been specified, and
 +-        $s !~ /[@.]/             # 's' option contains neither an '@' nor a dot,
 +-                                 # so it cannot be an e-mail address or a domain.
 +-    ) {
 +-        # Thus it must be meant as the 'scope' option:
 +-        $scope = $s;
 +-    }
 +-    else {
 +-        # Else, it must be meant as the deprecated 'sender' option:
 +-        $options->{mfrom} = $s;
 +-    }
 +-}
 +-
 +-# Heuristic for when explicit 'scope'/'s(cope)' option is absent:
 +-if (not defined($scope)) {
 +-    if (defined($identity) or defined($options->{file})) {
 +-        # Identity has been specified, or input will be read from file:
 +-        # apply the 'scope' option default:
 +-        $scope    = 'mfrom';
 +-    }
 +-    elsif (defined($options->{helo})) {
 +-        $scope    = 'helo';
 +-        $identity = $options->{helo};
 +-    }
 +-    elsif (defined($options->{mfrom})) {
 +-        $scope    = 'mfrom';
 +-        $identity = $options->{mfrom};
 +-        $helo_identity ||= $options->{helo};
 +-    }
 +-    elsif (defined($options->{pra})) {
 +-        $scope    = 'pra';
 +-        $identity = $options->{pra};
 +-    }
 +-}
 +-
 +-my $default_explanation = $options->{'default-explanation'};
 +-my $hostname            = $options->{hostname};
 +-
 +-if (
 +-    not defined($scope) or
 +-    not (defined($identity) xor defined($options->{file}))
 +-) {
 +-    usage();
 +-    exit(255);
 +-}
 +-
 +-if (defined($identity) and $identity eq '') {
 +-    STDERR->print("Error: Empty identities are not supported. See spfquery(1).\n");
 +-    exit(255);
 +-}
 +-
 +-# Process the SPF Request(s)
 +-##############################################################################
 +-
 +-try {
 +-    my $spf_server = Mail::SPF::Server->new(
 +-        default_authority_explanation
 +-                        => $default_explanation,
 +-        hostname        => $hostname,
 +-    #    debug           => $options->{debug},
 +-    #    sanitize        => $options->{sanitize},
 +-
 +-        # Black Magic:
 +-        (
 +-            exists($options->{'max-dns-interactive-terms'}) ?
 +-                (max_dns_interactive_terms  => $options->{'max-dns-interactive-terms'} || undef)
 +-            :   ()
 +-        ),
 +-        (
 +-            exists($options->{'max-name-lookups-per-term'}) ?
 +-                (max_name_lookups_per_term  => $options->{'max-name-lookups-per-term'} || undef)
 +-            :   ()
 +-        )
 +-    #    rcpt_to         => $options->{'rcpt-to'},
 +-    #    trusted         => $options->{trusted},
 +-    #    guess           => $options->{guess},
 +-    #    local           => $options->{local},
 +-    #    override        => $options->{override},
 +-    #    fallback        => $options->{fallback},
 +-    );
 +-
 +-    my $exit_code;
 +-
 +-    if (not defined($options->{file})) {
 +-        # Single request:
 +-        my $result_code = do_process(
 +-            $spf_server,
 +-            versions        => @versions ? [@versions] : undef,
 +-            scope           => $scope,
 +-            identity        => $identity,
 +-            ip_address      => $ip_address,
 +-            helo_identity   => $helo_identity
 +-        );
 +-        $exit_code = exit_codes_by_result_code->{$result_code};
 +-    }
 +-    else {
 +-        # File request:
 +-        my $file = $options->{file} eq '-' ? \*STDIN : IO::File->new($options->{file})
 +-            or die("Could not open: $options->{file}\n");
 +-        while (<$file>) {
 +-            chomp;
 +-            s/^\s*//;
 +-            next if /^$/;
 +-            if (/^#/) {
 +-                print("$_\n") if $options->{'keep-comments'};
 +-                next;
 +-            }
 +-            ($ip_address, $identity, $helo_identity) = split;
 +-            my $result_code = do_process(
 +-                $spf_server,
 +-                versions        => @versions ? [@versions] : undef,
 +-                scope           => $scope,
 +-                identity        => $identity,
 +-                ip_address      => $ip_address,
 +-                helo_identity   => $helo_identity
 +-            );
 +-            $exit_code ||= exit_codes_by_result_code->{$result_code};
 +-        }
 +-    }
 +-
 +-    exit($exit_code);
 +-}
 +-catch Mail::SPF::Exception with {
 +-    my ($e) = @_;
 +-    STDERR->printf("Error: %s.\n", $e->text);
 +-    exit(255);
 +-};
 +-
 +-
 +-# Helper Function
 +-##############################################################################
 +-
 +-sub do_process {
 +-    my ($spf_server, %request_options) = @_;
 +-    my $request = Mail::SPF::Request->new(%request_options);
 +-    my $result  = $spf_server->process($request);
 +-    printf(
 +-        "%s\n%s\n%s\n%s\n",
 +-        $result->code,
 +-        (
 +-            $result->can('authority_explanation') ?
 +-                $result->authority_explanation
 +-            :   $result->local_explanation
 +-        ),
 +-        $result->local_explanation,
 +-        $result->received_spf_header
 +-    );
 +-    return $result->code;
 +-}
 +diff -Naur orig/bin/spfquery.pl bin/spfquery.pl
 +--- orig/bin/spfquery.pl	1970-01-01 01:00:00.000000000 +0100
 ++++ bin/spfquery.pl	2009-10-31 23:16:14.000000000 +0100
 +@@ -0,0 +1,731 @@
 ++#!/usr/bin/perl
 ++
 ++# 
 ++# spfquery: Command-line tool for performing SPF queries
 ++#
 ++# (C) 2005-2008 Julian Mehnle <julian at mehnle.net>
 ++#     2004      Wayne Schlitt <wayne at schlitt.net>
 ++# $Id: spfquery 138 2006-01-22 18:00:34Z julian $
 ++#
 ++##############################################################################
 ++
 ++=head1 NAME
 ++
 ++spfquery - (Mail::SPF) - Checks if a given set of e-mail parameters matches a
 ++domain's SPF policy
 ++
 ++=head1 VERSION
 ++
 ++2.501
 ++
 ++=head1 SYNOPSIS
 ++
 ++=over
 ++
 ++=item B<Preferred usage:>
 ++
 ++B<spfquery> [B<--versions>|B<-v> B<1>|B<2>|B<1,2>] [B<--scope>|B<-s> B<helo>|B<mfrom>|B<pra>]
 ++B<--identity>|B<--id> I<identity> B<--ip-address>|B<--ip> I<ip-address>
 ++[B<--helo-identity>|B<--helo-id> I<helo-identity>] [I<OPTIONS>]
 ++
 ++B<spfquery> [B<--versions>|B<-v> B<1>|B<2>|B<1,2>] [B<--scope>|B<-s> B<helo>|B<mfrom>|B<pra>]
 ++B<--file>|B<-f> I<filename>|B<-> [I<OPTIONS>]
 ++
 ++=item B<Legacy usage:>
 ++
 ++B<spfquery> B<--helo> I<helo-identity> B<--ip-address>|B<--ip> I<ip-address> [I<OPTIONS>]
 ++
 ++B<spfquery> B<--mfrom> I<mfrom-identity> B<--ip-address>|B<--ip> I<ip-address>
 ++[B<--helo> I<helo-identity>] [I<OPTIONS>]
 ++
 ++B<spfquery> B<--pra> I<pra-identity> B<--ip-address>|B<--ip> I<ip-address> [I<OPTIONS>]
 ++
 ++=item B<Other usage:>
 ++
 ++B<spfquery> B<--version>|B<-V>
 ++
 ++B<spfquery> B<--help>
 ++
 ++=back
 ++
 ++=head1 DESCRIPTION
 ++
 ++B<spfquery> checks if a given set of e-mail parameters (e.g., the SMTP sender's
 ++IP address) matches the responsible domain's Sender Policy Framework (SPF)
 ++policy.  For more information on SPF see L<http://www.openspf.org>.
 ++
 ++=head2 Preferred Usage
 ++
 ++The following usage forms are preferred over the L<legacy forms|/Legacy usage>
 ++used by older B<spfquery> versions:
 ++
 ++The B<--identity> form checks if the given I<ip-address> is an authorized SMTP
 ++sender for the given C<helo> hostname, C<mfrom> envelope sender e-mail address,
 ++or C<pra> (so-called purported resonsible address) e-mail address, depending
 ++on the value of the B<--scope> option (which defaults to B<mfrom> if omitted).
 ++
 ++The B<--file> form reads "I<ip-address> I<identity> [I<helo-identity>]" tuples
 ++from the file with the specified I<filename>, or from standard input if
 ++I<filename> is B<->, and checks them against the specified scope (B<mfrom> by
 ++default).
 ++
 ++Both forms support an optional B<--versions> option, which specifies a
 ++comma-separated list of the SPF version numbers of SPF records that may be
 ++used.  B<1> means that C<v=spf1> records should be used.  B<2> means that
 ++C<spf2.0> records should be used.  Defaults to B<1,2>, i.e., uses any SPF
 ++records that are available.  Records of a higher version are preferred.
 ++
 ++=head2 Legacy Usage
 ++
 ++B<spfquery> versions before 2.500 featured the following usage forms, which are
 ++discouraged but still supported for L<backwards compatibility|/COMPATIBILITY>:
 ++
 ++The B<--helo> form checks if the given I<ip-address> is an authorized SMTP
 ++sender for the C<HELO> hostname given as the I<identity> (so-called C<HELO>
 ++check).
 ++
 ++The B<--mfrom> form checks if the given I<ip-address> is an authorized SMTP
 ++sender for the envelope sender email-address (or domain) given as the
 ++I<identity> (so-called C<MAIL FROM> check).  If a domain is given instead of an
 ++e-mail address, C<postmaster> will be substituted for the localpart.
 ++
 ++The B<--pra> form checks if the given I<ip-address> is an authorized SMTP
 ++sender for the PRA (Purported Responsible Address) e-mail address given as the
 ++identity.
 ++
 ++=head2 Other Usage
 ++
 ++The B<--version> form prints version information of spfquery.  The B<--help>
 ++form prints usage information for spfquery.
 ++
 ++=head1 OPTIONS
 ++
 ++=head2 Standard Options
 ++
 ++The preferred and legacy forms optionally take any of the following
 ++I<OPTIONS>:
 ++
 ++=over
 ++
 ++=item B<--default-explanation> I<string>
 ++
 ++=item B<--def-exp> I<string>
 ++
 ++Use the specified I<string> as the default explanation if the authority domain
 ++does not specify an explanation string of its own.
 ++
 ++=item B<--hostname> I<hostname>
 ++
 ++Use I<hostname> as the host name of the local system instead of auto-detecting
 ++it.
 ++
 ++=item B<--keep-comments>
 ++
 ++=item B<--no-keep-comments>
 ++
 ++Do (not) print any comments found when reading from a file or from standard
 ++input.
 ++
 ++=item B<--sanitize> (currently ignored)
 ++
 ++=item B<--no-sanitize> (currently ignored)
 ++
 ++Do (not) sanitize the output by condensing consecutive white-space into a
 ++single space and replacing non-printable characters with question marks.
 ++Enabled by default.
 ++
 ++=item B<--debug> (currently ignored)
 ++
 ++Print out debug information.
 ++
 ++=back
 ++
 ++=head2 Black Magic Options
 ++
 ++Several options that were supported by earlier versions of B<spfquery> are
 ++considered black magic (i.e. potentially dangerous for the innocent user) and
 ++are thus disabled by default.  If the L<B<Mail::SPF::BlackMagic>> Perl module
 ++is installed, they may be enabled by specifying B<--enable-black-magic>.
 ++
 ++=over
 ++
 ++=item B<--max-dns-interactive-terms> I<n>
 ++
 ++Evaluate a maximum of I<n> DNS-interactive mechanisms and modifiers per SPF
 ++check.  Defaults to B<10>.  Do I<not> override the default unless you know what
 ++you are doing!
 ++
 ++=item B<--max-name-lookups-per-term> I<n>
 ++
 ++Perform a maximum of I<n> DNS name look-ups per mechanism or modifier.
 ++Defaults to B<10>.  Do I<not> override the default unless you know what you are
 ++doing!
 ++
 ++=item B<--authorize-mxes-for> I<email-address>|I<domain>B<,>...
 ++
 ++Consider all the MXes of the comma-separated list of I<email-address>es and
 ++I<domain>s as inherently authorized.
 ++
 ++=item B<--tfwl>
 ++
 ++Perform C<trusted-forwarder.org> accreditation checking.
 ++
 ++=item B<--guess> I<spf-terms>
 ++
 ++Use I<spf-terms> as a default record if no SPF record is found.
 ++
 ++=item B<--local> I<spf-terms>
 ++
 ++Process I<spf-terms> as local policy before resorting to a default result
 ++(the implicit or explicit C<all> mechanism at the end of the domain's SPF
 ++record).  For example, this could be used for white-listing one's secondary
 ++MXes: C<mx:mydomain.example.org>.
 ++
 ++=item B<--override> I<domain>B<=>I<spf-record>
 ++
 ++=item B<--fallback> I<domain>B<=>I<spf-record>
 ++
 ++Set overrides and fallbacks.  Each option can be specified multiple times.  For
 ++example:
 ++
 ++    --override example.org='v=spf1 -all'
 ++    --override '*.example.net'='v=spf1 a mx -all'
 ++    --fallback example.com='v=spf1 -all'
 ++
 ++=back
 ++
 ++=head1 RESULT CODES
 ++
 ++=over 12
 ++
 ++=item B<pass>
 ++
 ++The specified IP address is an authorized SMTP sender for the identity.
 ++
 ++=item B<fail>
 ++
 ++The specified IP address is not an authorized SMTP sender for the identity.
 ++
 ++=item B<softfail>
 ++
 ++The specified IP address is not an authorized SMTP sender for the identity,
 ++however the authority domain is still testing out its SPF policy.
 ++
 ++=item B<neutral>
 ++
 ++The identity's authority domain makes no assertion about the status of the IP
 ++address.
 ++
 ++=item B<permerror>
 ++
 ++A permanent error occurred while evaluating the authority domain's policy
 ++(e.g., a syntax error in the SPF record).  Manual intervention is required
 ++from the authority domain.
 ++
 ++=item B<temperror>
 ++
 ++A temporary error occurred while evaluating the authority domain's policy
 ++(e.g., a DNS error).  Try again later.
 ++
 ++=item B<none>
 ++
 ++There is no applicable SPF policy for the identity domain.
 ++
 ++=back
 ++
 ++=head1 EXIT CODES
 ++
 ++  Result    | Exit code
 ++ -----------+-----------
 ++  pass      |     0
 ++  fail      |     1
 ++  softfail  |     2
 ++  neutral   |     3
 ++  permerror |     4
 ++  temperror |     5
 ++  none      |     6
 ++
 ++=head1 EXAMPLES
 ++
 ++    spfquery --scope mfrom --id user at example.com --ip 1.2.3.4
 ++    spfquery --file test_data
 ++    echo "127.0.0.1 user at example.com helohost.example.com" | spfquery -f -
 ++
 ++=head1 COMPATIBILITY
 ++
 ++B<spfquery> has undergone the following interface changes compared to earlier
 ++versions:
 ++
 ++=over
 ++
 ++=item B<2.500>
 ++
 ++=over
 ++
 ++=item *
 ++
 ++A new preferred usage style for performing individual SPF checks has been
 ++introduced.  The new style accepts a unified B<--identity> option and an
 ++optional B<--scope> option that specifies the type (scope) of the identity.  In
 ++contrast, the legacy usage style requires a separate usage form for every
 ++supported scope.  See L</Preferred usage> and L</Legacy usage> for details.
 ++
 ++=item *
 ++
 ++The former C<unknown> and C<error> result codes have been renamed to C<permerror>
 ++and C<temperror>, respectively, in order to comply with RFC 4408 terminology.
 ++
 ++=item *
 ++
 ++SPF checks with an empty identity are no longer supported.  In the case of an
 ++empty C<MAIL FROM> SMTP transaction parameter, perform a check with the C<helo>
 ++scope directly.
 ++
 ++=item *
 ++
 ++The B<--debug> and B<--(no-)sanitize> options are currently ignored by this
 ++version of B<spfquery>.  They will again be supported in the future.
 ++
 ++=item *
 ++
 ++Several features that were supported by earlier versions of B<spfquery> are
 ++considered black magic and thus are now disabled by default.  See L</Black
 ++Magic Options>.
 ++
 ++=item *
 ++
 ++Several option names have been deprecated.  This is a list of them and their
 ++preferred synonyms:
 ++
 ++  Deprecated options  | Preferred options
 ++ ---------------------+-----------------------------
 ++  --sender, -s        | --mfrom
 ++  --ipv4, -i          | --ip-address, --ip
 ++  --name              | --hostname
 ++  --max-lookup-count, | --max-dns-interactive-terms
 ++    --max-lookup      |
 ++  --rcpt-to, -r       | --authorize-mxes-for
 ++  --trusted           | --tfwl
 ++
 ++=back
 ++
 ++=back
 ++
 ++=head1 SEE ALSO
 ++
 ++L<Mail::SPF>, L<spfd(8)>
 ++
 ++L<http://www.ietf.org/rfc/rfc4408.txt>
 ++
 ++=head1 AUTHORS
 ++
 ++This version of B<spfquery> is a complete rewrite by Julian Mehnle
 ++<julian at mehnle.net>, based on an earlier version written by Meng Weng Wong
 ++<mengwong+spf at pobox.com> and Wayne Schlitt <wayne at schlitt.net>.
 ++
 ++=cut
 ++
 ++our $VERSION = '2.501';
 ++
 ++use warnings;
 ++use strict;
 ++
 ++use IO::File;
 ++use Getopt::Long qw(:config gnu_compat no_ignore_case);
 ++use Error ':try';
 ++use Mail::SPF;
 ++
 ++use constant TRUE   => (0 == 0);
 ++use constant FALSE  => not TRUE;
 ++
 ++use constant exit_codes_by_result_code => {
 ++    pass        => 0,
 ++    fail        => 1,
 ++    softfail    => 2,
 ++    neutral     => 3,
 ++    permerror   => 4,
 ++    temperror   => 5,
 ++    none        => 6
 ++};
 ++
 ++# Helper Functions
 ++##############################################################################
 ++
 ++sub usage {
 ++    STDERR->printf(<<'EOT');
 ++Preferred Usage:
 ++    spfquery [--versions|-v 1|2|1,2] [--scope|-s helo|mfrom|pra]
 ++        --identity|--id <identity> --ip-address|--ip <ip-address>
 ++        [--helo-identity|--helo-id <helo-identity>] [OPTIONS]
 ++    spfquery [--versions|-v 1|2|1,2] [--scope|-s helo|mfrom|pra]
 ++        --file|-f <filename>|- [OPTIONS]
 ++
 ++Legacy Usage:
 ++    spfquery --helo <helo-identity> --ip-address|--ip <ip-address> [OPTIONS]
 ++    spfquery --mfrom <mfrom-identity> --ip-address|--ip <ip-address>
 ++        [--helo <helo-identity>] [OPTIONS]
 ++    spfquery --pra <pra-identity> --ip-address|--ip <ip-address> [OPTIONS]
 ++
 ++Other Usage:
 ++    spfquery --version|-V
 ++
 ++See `spfquery --help` for more information.
 ++EOT
 ++    return;
 ++}
 ++
 ++sub help {
 ++    print(<<'EOT');
 ++Preferred Usage:
 ++    spfquery [--versions|-v 1|2|1,2] [--scope|-s helo|mfrom|pra]
 ++        --identity|--id <identity> --ip-address|--ip <ip-address>
 ++        [--helo-identity|--helo-id <helo-identity>] [OPTIONS]
 ++    spfquery [--versions|-v 1|2|1,2] [--scope|-s helo|mfrom|pra]
 ++        --file|-f <filename>|- [OPTIONS]
 ++
 ++Legacy Usage:
 ++    spfquery --helo <helo-identity> --ip-address|--ip <ip-address> [OPTIONS]
 ++    spfquery --mfrom <mfrom-identity> --ip-address|--ip <ip-address>
 ++        [--helo <helo-identity>] [OPTIONS]
 ++    spfquery --pra <pra-identity> --ip-address|--ip <ip-address> [OPTIONS]
 ++
 ++Other Usage:
 ++    spfquery --version|-V
 ++
 ++spfquery performs SPF checks based on the command-line arguments or data given
 ++in a file or on standard input.
 ++
 ++Only the preferred and other usage forms are explained here.  See the
 ++spfquery(1) man-page for an explanation of the legacy usage forms.
 ++
 ++The "--identity" form checks if the given <ip-address> is an authorized SMTP
 ++sender for the given "helo" hostname, "mfrom" envelope sender e-mail address,
 ++or "pra" (purported resonsible address) e-mail address, depending on the value
 ++of the "--scope" option (which defaults to "mfrom" if omitted).
 ++
 ++The "--file" form reads "<ip-address> <identity> [<helo-identity>]" tuples from
 ++the file with the specified <filename>, or from standard input if <filename> is
 ++"-", and checks them against the specified scope ("mfrom" by default).
 ++
 ++The "--version" form prints version information of spfquery.
 ++
 ++Valid OPTIONS (and their defaults) are:
 ++    --default-explanation <string>
 ++                        Default explanation string to use (sensible default).
 ++    --hostname <hostname>
 ++                        The name of the system doing the SPF checking (local
 ++                        system's configured hostname).
 ++    --keep-comments     Print comments found when reading from a file.
 ++    --no-sanitize       Do not clean up invalid characters in output.
 ++    --debug             Output debugging information.
 ++
 ++Black-magic OPTIONS are:
 ++    --max-dns-interactive-terms <n>
 ++                        Maximum number of DNS-interactive mechanisms and
 ++                        modifiers (10).
 ++    --max-name-lookups-per-term <n>
 ++                        Maximum number of DNS name look-ups per mechanism or
 ++                        modifier (10).
 ++    --authorize-mxes-for <email-address>|<domain>,...
 ++                        A comma-separated list of e-mail addresses and domains
 ++                        whose MXes will be considered inherently authorized.
 ++    --tfwl              Check trusted-forwarder.org white-list.
 ++    --guess <spf-terms> Default checks if no SPF record is found.
 ++    --local <spf-terms> Local policy to process before default result.
 ++    --override <domain>=<spf-record>
 ++    --fallback <domain>=<spf-record>
 ++                        Set override and fallback SPF records for domains.
 ++
 ++Examples:
 ++    spfquery --scope mfrom --id user at example.com --ip 1.2.3.4
 ++    spfquery --file test_data
 ++    echo "127.0.0.1 user at example.com helohost.example.com" | spfquery -f -
 ++EOT
 ++    return;
 ++}
 ++
 ++sub deprecated_option {
 ++    my ($old_option, $new_option, $options) = @_;
 ++    return FALSE if not exists($options->{$old_option});
 ++    STDERR->print(
 ++        "Warning: '$old_option' option is deprecated" .
 ++        ($new_option ? "; use '$new_option' instead" : '') .
 ++        ".\n"
 ++    );
 ++    $options->{$new_option} = delete($options->{$old_option});
 ++    return TRUE;
 ++}
 ++
 ++sub unsupported_option {
 ++    my ($option_name, $options) = @_;
 ++    return FALSE if not exists($options->{$option_name});
 ++    STDERR->print("Error: '$option_name' option is no longer supported.\n");
 ++    return TRUE;
 ++}
 ++
 ++sub black_magic_option {
 ++    my ($option_name, $options) = @_;
 ++    return FALSE if not exists($options->{$option_name});
 ++    STDERR->print("Error: '$option_name' option is black magic! Do not use it!\n");
 ++    return TRUE;
 ++}
 ++
 ++# Command-line Option Handling
 ++##############################################################################
 ++
 ++my $options = {};
 ++my $getopt_result = GetOptions(
 ++    $options,
 ++    
 ++    'file|f=s',
 ++    
 ++    'versions|v=s',
 ++    'scope=s',
 ++    's=s',  # Special handling for ambiguous 's' option (formerly a synonym
 ++            # for 'sender', now preferredly a synonym for 'scope').
 ++    'identity|id=s',
 ++    'ip-address|ip=s',
 ++    'helo-identity|helo-id=s',
 ++    
 ++    # Legacy/shortcut options:
 ++    'mfrom|mail-from|m=s',
 ++    'helo|h=s',
 ++    
 ++    'default-explanation|def-exp=s',
 ++    'hostname=s',
 ++    
 ++    'keep-comments!',
 ++    'debug!',       # TODO Implement!
 ++    'sanitize!',    # TODO Implement!
 ++    
 ++    # Black Magic options:
 ++    'enable-black-magic!',
 ++    'max-dns-interactive-terms=i',
 ++    'max-name-lookups-per-term=i',
 ++    'authorize-mxes-for=s',
 ++                    # TODO implement!
 ++    'tfwl!',        # TODO Implement!
 ++    'guess=s',      # TODO Implement!
 ++    'local=s',      # TODO Implement!
 ++    'override=s%',  # TODO Implement!
 ++    'fallback=s%',  # TODO Implement!
 ++    
 ++    # Meta actions:
 ++    'version|V!',
 ++    'help!',
 ++    
 ++    # Deprecated options:
 ++    'sender=s',     # Now 'scope'/'identity' or 'mfrom'
 ++    'ipv4=s',       # Now 'ip-address'
 ++    'i=s',          # Now 'ip-address'
 ++    'name=s',       # Now 'hostname'
 ++    'max-lookup-count=i',
 ++    'max-lookup=i', # Now 'max-dns-interactive-terms'
 ++    'rcpt-to=s',    # Now 'authorize-mxes-for'
 ++    'r=s',          # Now 'authorize-mxes-for'
 ++    'trusted!'      # Now 'tfwl'
 ++);
 ++
 ++if (not $getopt_result) {
 ++    usage();
 ++    exit(255);
 ++}
 ++
 ++if ($options->{help}) {
 ++    help();
 ++    exit(0);
 ++}
 ++
 ++if ($options->{version}) {
 ++    print("spfquery version $VERSION (using Mail::SPF)\n");
 ++    exit(0);
 ++}
 ++
 ++deprecated_option('sender',           'mfrom',                     $options);
 ++deprecated_option('ipv4',             'ip-address',                $options);
 ++deprecated_option('i',                'ip-address',                $options);
 ++deprecated_option('name',             'hostname',                  $options);
 ++deprecated_option('max-lookup-count', 'max-dns-interactive-terms', $options);
 ++deprecated_option('max-lookup',       'max-dns-interactive-terms', $options);
 ++deprecated_option('rcpt-to',          'authorize-mxes-for',        $options);
 ++deprecated_option('r',                'authorize-mxes-for',        $options);
 ++deprecated_option('trusted',          'tfwl',                      $options);
 ++
 ++if ($options->{'enable-black-magic'}) {
 ++    if (not defined(eval('require Mail::SPF::BlackMagic'))) {
 ++        STDERR->print("Error: Cannot enable black magic. Unable to load Mail::SPF::BlackMagic.\n");
 ++        exit(255);
 ++    }
 ++    # else: Black magic enabled!
 ++}
 ++elsif (
 ++    black_magic_option('max-dns-interactive-terms', $options) or
 ++    black_magic_option('max-name-lookups-per-term', $options) or
 ++    black_magic_option('rcpt-to',                   $options) or
 ++    black_magic_option('trusted',                   $options) or
 ++    black_magic_option('guess',                     $options) or
 ++    black_magic_option('local',                     $options) or
 ++    black_magic_option('override',                  $options) or
 ++    black_magic_option('fallback',                  $options)
 ++) {
 ++    exit(255);
 ++}
 ++
 ++my @versions            = split(',', $options->{versions} || '');
 ++my $scope               = $options->{scope};
 ++my $identity            = $options->{identity};
 ++my $ip_address          = $options->{'ip-address'};
 ++my $helo_identity       = $options->{'helo-identity'};
 ++
 ++# Heuristic for distinguishing between 's(cope)' and 's(ender)':
 ++if (defined(my $s = $options->{s})) {
 ++    if (
 ++        not defined($scope) and  # No explicit 'scope' option has been specified, and
 ++        $s !~ /[@.]/             # 's' option contains neither an '@' nor a dot,
 ++                                 # so it cannot be an e-mail address or a domain.
 ++    ) {
 ++        # Thus it must be meant as the 'scope' option:
 ++        $scope = $s;
 ++    }
 ++    else {
 ++        # Else, it must be meant as the deprecated 'sender' option:
 ++        $options->{mfrom} = $s;
 ++    }
 ++}
 ++
 ++# Heuristic for when explicit 'scope'/'s(cope)' option is absent:
 ++if (not defined($scope)) {
 ++    if (defined($identity) or defined($options->{file})) {
 ++        # Identity has been specified, or input will be read from file:
 ++        # apply the 'scope' option default:
 ++        $scope    = 'mfrom';
 ++    }
 ++    elsif (defined($options->{helo})) {
 ++        $scope    = 'helo';
 ++        $identity = $options->{helo};
 ++    }
 ++    elsif (defined($options->{mfrom})) {
 ++        $scope    = 'mfrom';
 ++        $identity = $options->{mfrom};
 ++        $helo_identity ||= $options->{helo};
 ++    }
 ++    elsif (defined($options->{pra})) {
 ++        $scope    = 'pra';
 ++        $identity = $options->{pra};
 ++    }
 ++}
 ++
 ++my $default_explanation = $options->{'default-explanation'};
 ++my $hostname            = $options->{hostname};
 ++
 ++if (
 ++    not defined($scope) or
 ++    not (defined($identity) xor defined($options->{file}))
 ++) {
 ++    usage();
 ++    exit(255);
 ++}
 ++
 ++if (defined($identity) and $identity eq '') {
 ++    STDERR->print("Error: Empty identities are not supported. See spfquery(1).\n");
 ++    exit(255);
 ++}
 ++
 ++# Process the SPF Request(s)
 ++##############################################################################
 ++
 ++try {
 ++    my $spf_server = Mail::SPF::Server->new(
 ++        default_authority_explanation
 ++                        => $default_explanation,
 ++        hostname        => $hostname,
 ++    #    debug           => $options->{debug},
 ++    #    sanitize        => $options->{sanitize},
 ++
 ++        # Black Magic:
 ++        (
 ++            exists($options->{'max-dns-interactive-terms'}) ?
 ++                (max_dns_interactive_terms  => $options->{'max-dns-interactive-terms'} || undef)
 ++            :   ()
 ++        ),
 ++        (
 ++            exists($options->{'max-name-lookups-per-term'}) ?
 ++                (max_name_lookups_per_term  => $options->{'max-name-lookups-per-term'} || undef)
 ++            :   ()
 ++        )
 ++    #    rcpt_to         => $options->{'rcpt-to'},
 ++    #    trusted         => $options->{trusted},
 ++    #    guess           => $options->{guess},
 ++    #    local           => $options->{local},
 ++    #    override        => $options->{override},
 ++    #    fallback        => $options->{fallback},
 ++    );
 ++
 ++    my $exit_code;
 ++
 ++    if (not defined($options->{file})) {
 ++        # Single request:
 ++        my $result_code = do_process(
 ++            $spf_server,
 ++            versions        => @versions ? [@versions] : undef,
 ++            scope           => $scope,
 ++            identity        => $identity,
 ++            ip_address      => $ip_address,
 ++            helo_identity   => $helo_identity
 ++        );
 ++        $exit_code = exit_codes_by_result_code->{$result_code};
 ++    }
 ++    else {
 ++        # File request:
 ++        my $file = $options->{file} eq '-' ? \*STDIN : IO::File->new($options->{file})
 ++            or die("Could not open: $options->{file}\n");
 ++        while (<$file>) {
 ++            chomp;
 ++            s/^\s*//;
 ++            next if /^$/;
 ++            if (/^#/) {
 ++                print("$_\n") if $options->{'keep-comments'};
 ++                next;
 ++            }
 ++            ($ip_address, $identity, $helo_identity) = split;
 ++            my $result_code = do_process(
 ++                $spf_server,
 ++                versions        => @versions ? [@versions] : undef,
 ++                scope           => $scope,
 ++                identity        => $identity,
 ++                ip_address      => $ip_address,
 ++                helo_identity   => $helo_identity
 ++            );
 ++            $exit_code ||= exit_codes_by_result_code->{$result_code};
 ++        }
 ++    }
 ++
 ++    exit($exit_code);
 ++}
 ++catch Mail::SPF::Exception with {
 ++    my ($e) = @_;
 ++    STDERR->printf("Error: %s.\n", $e->text);
 ++    exit(255);
 ++};
 ++
 ++
 ++# Helper Function
 ++##############################################################################
 ++
 ++sub do_process {
 ++    my ($spf_server, %request_options) = @_;
 ++    my $request = Mail::SPF::Request->new(%request_options);
 ++    my $result  = $spf_server->process($request);
 ++    printf(
 ++        "%s\n%s\n%s\n%s\n",
 ++        $result->code,
 ++        (
 ++            $result->can('authority_explanation') ?
 ++                $result->authority_explanation
 ++            :   $result->local_explanation
 ++        ),
 ++        $result->local_explanation,
 ++        $result->received_spf_header
 ++    );
 ++    return $result->code;
 ++}
 diff -Naur p5-Mail-SPF.dist/pkg-plist p5-Mail-SPF/pkg-plist
 --- p5-Mail-SPF.dist/pkg-plist	2008-02-22 22:40:33.000000000 +0100
 +++ p5-Mail-SPF/pkg-plist	2011-05-24 19:42:51.000000000 +0200
 @@ -1,4 +1,4 @@
 -bin/spfquery
 +%%SPFQUERY%%bin/spfquery%%SPFQUERY_SUFFIX%%
  sbin/spfd
  %%SITE_PERL%%/Mail/SPF.pm
  %%SITE_PERL%%/Mail/SPF/MacroString.pm
 
 --r5Pyd7+fXNt84Ff3--



More information about the freebsd-ports-bugs mailing list