/*
 *  spf_example - An example program for how to use libspf-alt
 *	
 *  Author: Wayne Schlitt <wayne@midwestcs.com>
 *
 *  File:   spfquery.c
 *  Desc:   SPF command line utility
 *
 *
 * This program is in the public domain, there is no copyright, you
 * can do anything you want with it.
 */


/*
 * The libspf-alt library uses the GNU autoconf system to help make
 * the library more portable.  The config.h file should have the
 * HAVE_xxx defines that are appropriate for your system.  Either use
 * autconf to create it, or create it by hand.
 */


#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#ifdef STDC_HEADERS
# include <stdio.h>
# include <stdlib.h>       /* malloc / free */
#endif

#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>    /* types (u_char .. etc..) */
#endif

#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#endif

#ifdef HAVE_STRING_H
# include <string.h>       /* strstr / strdup */
#else
# ifdef HAVE_STRINGS_H
#  include <strings.h>       /* strstr / strdup */
# endif
#endif

#ifdef HAVE_SYS_SOCKET_H
# include <sys/socket.h>   /* inet_ functions / structs */
#endif
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>   /* inet_ functions / structs */
#endif
#ifdef HAVE_ARPA_INET_H
# include <arpa/inet.h>    /* in_addr struct */
#endif

#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

#ifdef HAVE_GETOPT_H
#include <getopt.h>
#endif


/*
 * libspf-alt public include files that are needed for this example
 * program
 */

#include "spf.h"
#include "spf_dns_resolv.h"
#include "spf_dns_cache.h"



/*
 * usage() just prints out the command line options for this program
 */
static void usage()
{
    fprintf(
	stderr,
	"Usage:\n"
	"\n"
	"spf_example [options]\n"
	"\n"
	"Valid data options are:\n"
	"    -i <IP address>            The IP address that is sending email\n"
	"    -s <email address>         The email address used as the\n"
	"                               envelope-from.  If no username (local\n"
	"                               part) is given, 'postmaster' will be\n"
	"                               assumed.\n"
	"    -h <domain name>           The domain name given on the SMTP HELO\n"
	"                               command.  This is only needed if the\n"
	"                               -sender option is not given.\n"
	"    -debug [debug level]       debug level.\n"
	);
}



/*
 * All the code is in the main routine, but most usages of libspf-alt
 * would have the code spread around into various subrotines.
 */

int main( int argc, char *argv[] )
{
    int c;
    int	res = 0;

    char *opt_ip = NULL;
    char *opt_sender = NULL;
    char *opt_helo = NULL;
    int   opt_debug = 0;

    SPF_config_t	spfcid = NULL;
    SPF_dns_config_t	spfdcid_resolv = NULL;
    SPF_dns_config_t	spfdcid = NULL;
    SPF_output_t	spf_output;
    

    /*
     * check the arguments
     */

    while (1)
    {
	c = getopt(argc, argv, "i:s:h:d::" );

	if (c == -1)
	    break;

	switch (c)
	{
	case 'i':
	    opt_ip = optarg;
	    break;

	case 's':
	    opt_sender = optarg;
	    break;

	case 'h':
	    opt_helo = optarg;
	    break;

	case 0:
	case '?':
	    usage();
	    res = 255;
	    goto error;
	    break;

	case 'd':
	    if (optarg == NULL)
		opt_debug = 1;
	    else
		opt_debug = atoi( optarg );
	    break;

	default:
	    fprintf( stderr, "Error: getopt returned character code 0%o ??\n", c);
	}
    }

    if (optind != argc
	|| opt_ip == NULL
	|| (opt_helo == NULL && opt_sender == NULL))
    {
	usage();
	res = 255;
	goto error;
    }

/*
 * Configure the SPF system.
 *
 * libspf-alt is designed so that configurations can be set up once
 * and reused many times different emails delivered in a single SMTP
 * session or in different SMTP sessions.
 */

    /*
     * set up the SPF configuration
     *
     * The SPF configuration contains all the data needed to process
     * the SPF check.  Configurations contain malloc so it must be
     * destroyed when you are finished with it. In a multi-threaded
     * environment, you need one per thread.
     */

    spfcid = SPF_create_config();
    if ( spfcid == NULL )
    {
	fprintf( stderr, "SPF_create_config failed.\n" );
	res = 255;
	goto error;
    }


    SPF_set_debug( spfcid, opt_debug );

    /* The domain name of the receiving MTA will default to gethostname() */
    /* SPF_set_rec_dom( spfcid, opt_name ); */
    

    /*
     * set up dns layers to use
     *
     * The SPF DNS configuration layers contains data needed to do the
     * DNS lookups and to return the results.  Configurations contain
     * malloc so it must be destroyed when you are finished with
     * it. In a multi-threaded environment, you need one per thread.
     * 
     * Even a small DNS cache can reduce the CPU usage compared with
     * even a local caching name server.
     */
    spfdcid_resolv = SPF_dns_create_config_resolv( NULL, opt_debug );
    spfdcid = SPF_dns_create_config_cache( spfdcid_resolv, 8, opt_debug );
	

/*
 * process the SPF request
 *
 * Now that the SPF system has been configured, we can process the requests.
 * There would normally be a loop around this code or it would be placed
 * in a subroutine to be called for each email.
 *
 * If a single email session sends several emails, you don't need to
 * reset the IP address or the HELO domain each time, just change the
 * envelope from.
 */

    /*
     * record the IP address of the client (sending) MTA.
     *
     * There are other SPF_set_ip*() functionx if you have a structure
     * instead of a string.
     */

    if ( SPF_set_ip_str( spfcid, opt_ip ) )
    {
	printf( "Invalid IP address.\n" );
	res = 255;
	goto error;
    }
	

    /*
     * record the HELO domain name of the client (sending) MTA from
     * the SMTP HELO or EHLO commands
     *
     * This domain name will be used if the envelope from address is
     * null (e.g. MAIL FROM:<>).  This happens when a bounce is being
     * sent and, in effect, it is the client MTA that is sending the
     * message.
     */

    if ( SPF_set_helo_dom( spfcid, opt_helo ) )
    {
	printf( "Invalid HELO domain.\n" );
	res = 255;
	goto error;
    }
	

    /*
     * record the envelope from email address from the SMTP MAIL FROM:
     * command.
     */

    if ( SPF_set_env_from( spfcid, opt_sender ) )
    {
	printf( "Invalid envelope from address.\n" );
	res = 255;
	goto error;
    }
	

    /*
     * now that we have all the information, see what the result of
     * the SPF check is.
     */

    spf_output = SPF_result( spfcid, spfdcid );

    if ( opt_debug > 0 )
    {
	printf ( "result = %s (%d)\n",
		 SPF_strresult( spf_output.result ), spf_output.result );
	printf ( "err = %s (%d)\n",
		 SPF_strerror( spf_output.err ), spf_output.err );
	printf ( "err_msg = %s\n", spf_output.err_msg ? spf_output.err_msg : "" );
    }

    printf( "%s\n%s\n%s\n%s\n",
	    SPF_strresult( spf_output.result ),
	    spf_output.smtp_comment ? spf_output.smtp_comment : "",
	    spf_output.header_comment ? spf_output.header_comment : "",
	    spf_output.received_spf ? spf_output.received_spf : "" );
	
    res = spf_output.result;


    /*
     * the ouput from the SPF check contains malloced data, so make sure
     * we free it.
     */

    SPF_free_output( &spf_output );

  error:

    /*
     * the SPF configuration variables contain malloced data, so we
     * have to vfree them also.
     */

    if ( spfcid ) SPF_destroy_config( spfcid );
    if ( spfdcid ) SPF_dns_destroy_config_cache( spfdcid );
    if ( spfdcid_resolv ) SPF_dns_destroy_config_resolv( spfdcid_resolv );
    SPF_destroy_default_config();
    
    return res;
}


syntax highlighted by Code2HTML, v. 0.9.1