#!/usr/bin/perl
#
# xm-spf.pl by Davide Libenzi ( XMail Perl filter for SPF )
# Copyright (C) 2004  Davide Libenzi
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# Davide Libenzi <davidel@xmailserver.org>
#

use strict;
use Mail::SPF::Query;

my $opt_file = undef;
my $opt_ip = undef;
my $opt_sender = undef;
my $opt_helo = undef;
my $opt_rcpt_to = undef;
my $opt_local = undef;
my $opt_trusted = undef;
my $opt_guess = undef;
my $opt_exp = undef;
my $opt_max_lookup = undef;
my $opt_sanitize = undef;
my $opt_name = "spfquery";
my $opt_debug = 0;
my $opt_keep_comments = 0;
my $opt_fallback = undef;
my $opt_override = undef;
my $opt_dns = undef;
my $opt_help = undef;
my $opt_pcode = 0;
my $opt_fcode = 19;
my @opt_bypass = undef;

my $i;

for ($i = 0; $i <= $#ARGV; $i++) {
	if ($ARGV[$i] eq "--file") {
		if (++$i <= $#ARGV) {
			$opt_file = $ARGV[$i];
		}
	} elsif ($ARGV[$i] eq "--ip") {
		if (++$i <= $#ARGV) {
			$opt_ip = $ARGV[$i];
		}
	} elsif ($ARGV[$i] eq "--sender") {
		if (++$i <= $#ARGV) {
			$opt_sender = $ARGV[$i];
		}
	} elsif ($ARGV[$i] eq "--helo") {
		if (++$i <= $#ARGV) {
			$opt_helo = $ARGV[$i];
		}
	} elsif ($ARGV[$i] eq "--rcpt-to") {
		if (++$i <= $#ARGV) {
			$opt_rcpt_to = $ARGV[$i];
		}
	} elsif ($ARGV[$i] eq "--debug") {
		if (++$i <= $#ARGV) {
			$opt_debug = int($ARGV[$i]);
		}
	} elsif ($ARGV[$i] eq "--local") {
		if (++$i <= $#ARGV) {
			$opt_local = $ARGV[$i];
		}
	} elsif ($ARGV[$i] eq "--trusted") {
		if (++$i <= $#ARGV) {
			$opt_trusted = $ARGV[$i];
		}
	} elsif ($ARGV[$i] eq "--guess") {
		if (++$i <= $#ARGV) {
			$opt_guess = $ARGV[$i];
		}
	} elsif ($ARGV[$i] eq "--expl") {
		if (++$i <= $#ARGV) {
			$opt_exp = $ARGV[$i];
		}
	} elsif ($ARGV[$i] eq "--max-lookup") {
		if (++$i <= $#ARGV) {
			$opt_max_lookup = $ARGV[$i];
		}
	} elsif ($ARGV[$i] eq "--sanitize") {
		if (++$i <= $#ARGV) {
			$opt_sanitize = $ARGV[$i];
		}
	} elsif ($ARGV[$i] eq "--name") {
		if (++$i <= $#ARGV) {
			$opt_name = $ARGV[$i];
		}
	} elsif ($ARGV[$i] eq "--fallback") {
		if (++$i <= $#ARGV) {
			$opt_fallback = $ARGV[$i];
		}
	} elsif ($ARGV[$i] eq "--override") {
		if (++$i <= $#ARGV) {
			$opt_override = $ARGV[$i];
		}
	} elsif ($ARGV[$i] eq "--dns") {
		if (++$i <= $#ARGV) {
			$opt_dns = $ARGV[$i];
		}
	} elsif ($ARGV[$i] eq "--pcode") {
		if (++$i <= $#ARGV) {
			$opt_pcode = $ARGV[$i];
		}
	} elsif ($ARGV[$i] eq "--fcode") {
		if (++$i <= $#ARGV) {
			$opt_fcode = $ARGV[$i];
		}
	} elsif ($ARGV[$i] eq "--bypass") {
		if (++$i <= $#ARGV) {
			push(@opt_bypass, $ARGV[$i]);
		}
	} elsif ($ARGV[$i] eq "--help") {
		$opt_help = 1;
	}
}

if ($opt_help) {

	exit($opt_pcode);
}

if (defined($opt_file)) {
	my $ln;
	my @hvars;

	if (!open(MFIL, "$opt_file")) {
		print STDERR "unable to open ${opt_file}\n";
		exit($opt_pcode);
	}
# Read message info
	$ln = <MFIL>;
	chomp($ln);
	@hvars = split(/;/, $ln);
# Discard SMTP domain
	$ln = <MFIL>;
# Discard message ID
	$ln = <MFIL>;
# Read MAIL FROM
	$ln = <MFIL>;
	chomp($ln);
	close(MFIL);
# Handle both cases of early message file and spool file
	($opt_sender = $ln) =~ s/[^<]+<([^>]*)>.*/$1/;
	if ($#hvars > 3) {
		$opt_helo = $hvars[0];
		($opt_ip = $hvars[1]) =~ s/([^:]+):[0-9]+/$1/;
	} else {
		($opt_ip = $hvars[0]) =~ s/([^:]+):[0-9]+/$1/;
	}
}

if (!defined($opt_helo) && ($opt_sender =~ /\@/)) {
	($opt_helo = $opt_sender) =~ s/.*\@(.*)/$1/;
}

for ($i = 0; $i <= $#opt_bypass; $i++) {
	if ($opt_ip =~ /$opt_bypass[$i]/) {
		if ($opt_debug) {
			print "whitelist ip ${opt_ip}\n";
		}
		exit($opt_pcode);
	}
}

my $query = new Mail::SPF::Query(ipv4       => $opt_ip,
				 sender     => $opt_sender,
				 helo       => $opt_helo,
				 local      => $opt_local,
				 trusted    => $opt_trusted,
				 guess      => $opt_guess,
				 default_explanation => $opt_exp,
				 max_lookup => $opt_max_lookup,
				 sanitize   => $opt_sanitize,
				 myhostname => $opt_name,
				 fallback   => $opt_fallback,
				 override   => $opt_override,
				 debug      => $opt_debug,
				 );

my $rcode = ($query->result eq "fail") ? $opt_fcode: $opt_pcode;

if ($opt_debug) {
	print $query->result . "\n";
}

exit($rcode);

