#!/usr/bin/perl -w-

eval 'exec /usr/bin/perl -w- -S $0 ${1+"$@"}'
    if 0; # not running under some shell

# spfquery - Sender Permitted From command line utility
#
#  Author: Wayne Schlitt <wayne@midwestcs.com>
#
#  File:   spfquery.c
#  Desc:   SPF command line utility
#
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of either:
#
#  a) the GNU General Public License as published by the Free Software
#     Foundation; either version 1, or (at your option) any later
#     version, or
#
#  OR
#
#  b) The following license:
#
#  License:
#
#  The libspf Software License, Version 1.0
#
#  Copyright (c) 2004 Wayne Schlitt  All rights reserved.
#
#  Redistribution and use in source and binary forms, with or without
#  modification, are permitted provided that the following conditions
#  are met:
#
#  1. Redistributions of source code must retain the above copyright
#     notice, this list of conditions and the following disclaimer.
#
#  2. Redistributions in binary form must reproduce the above copyright
#     notice, this list of conditions and the following disclaimer in
#     the documentation and/or other materials provided with the
#     distribution.
#
#  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
#  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
#  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
#  DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
#  ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
#  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
#  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
#  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
#  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
#  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
#  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
#  SUCH DAMAGE.


use Mail::SPF::Query;

use Getopt::Long qw(:config gnu_compat);

sub usage() {
  printf STDERR "Usage:\n";
  printf STDERR "\n";
  printf STDERR "spfquery [-v] [-f <file>|spf data options]\n";

  printf STDERR "\n";

  printf STDERR "spfquery -ipv4=<IP Address> -sender=<email address> -helo=<domain>\n";
  printf STDERR "spfquery -f test_data\n";
  printf STDERR "echo \"127.0.0.1 myname\@mydomain.com helohost.com\" | spfquery -f -\n";
}


my $opt_file = undef;

my $opt_ipv4 = 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 $result = GetOptions('file=s'		=> \$opt_file,

			'ipv4:s'		=> \$opt_ipv4,
			'sender:s'		=> \$opt_sender,
			'helo:s'		=> \$opt_helo,
			'rcpt-to:s'		=> \$opt_rcpt_to,
			
			'local:s'		=> \$opt_local,
			'trusted:s'		=> \$opt_trusted,
			'guess:s'		=> \$opt_guess,
			'default-explanation:s' => \$opt_exp,
			'max-lookup:s'		=> \$opt_max_lookup,
			'sanitize:s'		=> \$opt_sanitize,
			'name:s'		=> \$opt_name,

			'debug=i'		=> \$opt_debug,
			'version'		=> \$opt_help,
			'help'			=> \$opt_help
			);

if ($opt_help  || !$result) {
  usage();
  exit 255;
}


#
# process the SPF request
#
my $res;

if (!defined($opt_ipv4) || !defined($opt_sender) || !defined($opt_helo)) {
  if (!defined($opt_file) ||
      defined($opt_ipv4) || defined($opt_sender) || defined($opt_helo)) {
    usage();
    exit 255;
  }

  #
  # the requests are on STDIN
  #
	
  local *FIN;

  if ( $opt_file eq "-" ) {
    *FIN = \*STDIN;
  }
  else {
    open( FIN, $opt_file ) || die "Could not open: %s\n", $opt_file;
  }
	
  while ( <FIN> ) {
    chomp;

    s/^\s*//;
    next if /^$/;
    next if /^#/;

    ($opt_ipv4, $opt_sender, $opt_helo, $opt_rcpt_to) = split;

    $res = do_query();
  }
}
else {
  if (defined($opt_file)) {
    usage();
    exit 255;
  }

  $res = do_query();
}

exit $res;



sub do_query {


  #
  # Process the SPF request and print the results
  #

  my $query = new Mail::SPF::Query (ipv4       => $opt_ipv4,
				    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,
				    debug      => $opt_debug,
				   );

  my ($result, $smtp_comment, $header_comment);
  if (!defined($opt_rcpt_to) || $opt_rcpt_to eq "") {
    ($result, $smtp_comment, $header_comment) = $query->result;
  }
  else {
    my $per_result;
    $result = "";
    foreach my $recip (split(',', $opt_rcpt_to)) {

      ($per_result, $smtp_comment, $header_comment) = $query->result2( split(';', $recip));
      if ($result eq "" ) {
	$result = $per_result;
      }
      else {
	$result .= ",".$per_result;
      }
    }
    ($per_result, $smtp_comment, $header_comment) = $query->message_result2;

    if ($result eq "" ) {
      $result = $per_result;
    }
    else {
      $result .= ",".$per_result;
    }
  }
	
  print "$result\n$smtp_comment\n$header_comment\n";

  return 0 if $result eq "pass";
  return 0 if $result eq "softfail";
  return 1 if $result eq "fail";
  return 2 if $result eq "error";
  return 3 if $result eq "unknown";
  return 3 if $result eq "none";

  return 255;
}

