#!/usr/bin/perl

=head1 NAME

CCLib.pm -- Compatibility module for AUTHORIZE.NET and CyberCash version 2

=cut

package CCLib;
# You need the SSLeay perl module installed, 
# look for it on http://www.cpan.org

use Net::SSLeay;
use Carp;
use Exporter;
@EXPORT = qw/ SetServer sendmserver /;

use POSIX qw/tmpnam/;
$VERSION = '0.01';

use vars qw/$VERSION/;

my $Port   = 443;
my $Server = 'www.authorize.net';
my $Path   = '/scripts/authnet25/AuthRequest.asp';
my $Password;
my $VendorID;
my $Reqavs;

=head1 VERSION

0.02

=head1 SYNOPSIS

#not used for minivend :)

use CCLib;

SetServer( 
            host     => 'www.authorize.net',
            port     => '443',                    
            secret   => 'test',                 
            vendor   => 'test',                  
            );

my $mode = 'mauthonly' || 'mauthcapture';

    %result = sendmserver(
            $actual{cyber_mode},
            'Order-ID'     => $orderID,
            'Amount'       => $amount,
            'Card-Number'  => $actual{mv_credit_card_number}

            'Card-Name'    => $actual{b_name},
            'Card-Address' => $actual{b_address},
            'Card-City'    => $actual{b_city},
            'Card-State'   => $actual{b_state},
            'Card-Zip'     => $actual{b_zip},
            'Card-Country' => $actual{b_country},
            'Card-Exp'     => $exp,
            );
    if($result{MStatus} !~ /^success/) {
        $error = $result{MErrMsg};
        return undef;
    }
    else {
        return 1;
    }

=head1 DESCRIPTION

This module interfaces Authorize.net servers to software
designed for CyberCash 2. It is also quite suitable for standalone use
with Perl.

This module was designed to work with MiniVend, so if you see
references to $Vend::Cfg that is the reason. You may ignore
those references; they should not cause problems.

If you want to set your Vendor ID in the environment, use 
$ENV{AUTHORIZENET_VENDORID}.

The C<socklink> executable can either reside in the Perl @INC
libary include path, or can be in your $ENV{PATH}. They are used
in that order.

=head2 Example of use with MiniVend

Set the following variables in catalog.cfg:

    # the authorize.net host
    Variable CYBER_HOST   www.authorize.net

    # the authorize.net port, defaults to 443
    #Variable CYBER_PORT   443

    # your password
    Variable CYBER_SECRET testlogin

    # your password
    Variable CYBER_VENDOR testpassword
 
    # Do you want to deny transactions with an AVS mismatch?
    Variable CYBER_AVS TRUE/FALSE

You can set your mv_cyber_mode variable to any valid PaymentNet
transaction type, or to the CyberCash:

    CyberCash       AuthorizeNet
    ------------------------------
    mauthonly           NA
    mauthcapture        PA

=head1 AUTHOR

Jeff Nappi, Cyberhighway Internet Services <brage@cyberhighway.net>

Based on paymentnet CyberCash 2 interface by Mike Heins of
Internet Robotics <mikeh@minivend.com>

=head1 BUGS

Doesn't capture and log approval. That would be easy to add.

=cut

sub SetServer {

#::logGlobal("Setserver called", @_);
        my (%hash) = @_;
        $Server = $hash{'host'}
                    if  $hash{'host'} and
                        $hash{'host'} ne 'localhost';
        $Port   = $hash{'port'}
                    if  $hash{'port'} and
                    $hash{'port'} ne '8000';
        $Password = $hash{'secret'}
                    if $hash{'secret'};

        if ($hash{'vendor'}) {
            $VendorID = $hash{'vendor'};
#::logGlobal("vendor id assigned from hash");
        }
        elsif($ENV{AUTHORIZENET_VENDORID}) {
#::logGlobal("vendor id assigned from AUTHORIZENET env");
            $VendorID = $ENV{AUTHORIZENET_VENDORID};
        }
        elsif(  defined $Vend::Cfg and
                ref     $Vend::Cfg->{Variable} and 
                $Vend::Cfg->{Variable}{CYBER_VENDOR}
                )
        {
#::logGlobal("vendor id assigned from CYBER_VENDOR");
            $VendorID = $Vend::Cfg->{Variable}{CYBER_VENDOR};
        }
        else {
            carp "No vendor id assigned.\n";
            $VendorID = 'test';
        }

   return 1;
}

my %mode_translate = ( qw/
                        NA NA
                        AO AO
                        CR CR
                        PA PA
                        mauthonly       NA
                        mauthcapture    PA
                        authonly        NA
                        authcapture     PA
                        / );

sub sendmserver {
        my $mode = shift;
        my %opt = @_;

if ($Vend::Cfg->{Variable}{CYBER_AVS} =~ "TRUE")
  {
    $Reqavs = "TRUE";
  } else {
    $Reqavs = "FALSE";
  }

my $debug = "mode=$mode\n";
for(keys %opt) {
    $debug .= "$_=$opt{$_}\n";
}

my $temp = $CGI::values{mv_order_number};
#::logGlobal("HELLO: sendmserver called:\n$debug");
        
        my (@err_parms);
        unless( $Server && $Password && $VendorID && $Port ) {
            @err_parms = ( 'MStatus' , 'error_before_connect', 'MErrMsg' );
            my $err = '';
            $err .= "No server set.\n" unless $Server;
            $err .= "No password given.\n" unless $Password;
            $err .= "No port set.\n" unless $Port;
            $err .= "No Vendor ID given.\n" unless $VendorID;
            push @err_parms, $err;
#::logGlobal("error", @err_parms);
            return(@err_parms);
        }

        $opt{'Card-Number'} =~ tr/0-9//cd;
        $opt{'Card-Exp'} =~ tr/0-9//cd;
        $opt{'Card-Exp'} = "0" .  $opt{'Card-Exp'}
            if length   $opt{'Card-Exp'} < 4;
        $opt{'Amount'} =~ tr/.0-9//cd;
        unless ($mode_translate{$mode}) {
            @err_parms = ('MStatus', 'error_before_connect',
                            'MErrMsg', 'No mode set.');
#::logGlobal("error", @err_parms);
            return(@err_parms);
        }
         my ($page,$server_response,%headers,$response,
             $authcode,$text,$avs,$transid);
	 ($page, $server_response, %headers)
         = &Net::SSLeay::post_https($Server, $Port, $Path, '',
                &Net::SSLeay::make_form(
                        'TESTREQUEST'   => 'FALSE',
                        'LOGIN'         => $VendorID,
                        'PASSWORD'      => $Password,
                        'AMOUNT'        => $opt{'Amount'},
                        'METHOD'        => $CGI::values{METHOD},
                        'TYPE'          => $mode_translate{$mode},
                        'CARDNUM'       => $opt{'Card-Number'},
                        'EXPDATE'       => $opt{'Card-Exp'},
                        'NAME'          => $opt{'Card-Name'},
                        'ADDRESS'       => $opt{'Card-Address'},
                        'CITY'          => $opt{'Card-City'},
                        'STATE'         => $opt{'Card-State'},
                        'ZIP'           => $opt{'Card-Zip'},
                        'COUNTRY'       => $opt{'Card-Country'},
                        'REJECTAVSMISMATCH' => $Reqavs));

        ($response,$authcode,$text,$avs,$transid) = split (/,/,$page);
#::logGlobal("response was --$response--\nauthcode was --$authcode--\ntext was --$text--\navs was --$avs--\ntransid was --$transid--\n");
        my %result;
        if ($response eq 'A' || $reponse eq 'P')
         {
#::logGlobal("response was --$response--\nset MStatus to success.\n");
            $result{MStatus} = 'success';
            $result{'order-id'} = 1;
         } else {
#::logGlobal("response was --$response--\nset MErrMsg to $text.\n");
            $result{MStatus} = 'failure';
            if (grep(/AVS/, $text))
              {
                $result{MErrMsg} = "You must enter the correct billing address of your credit card. The bank returned the following error: " . $text;
              } else {
                $result{MErrMsg} = $text;
              }
        }
  return (%result);
}
1;
