#!/usr/bin/perl

=head1 NAME

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

=cut

package CCLib;

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 PREREQUISITES

This package requires the Net::SSLeay perl library which requires the 
SSLeay or OpenSSL package as well.

=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 Authorize.net
transaction type, or to the CyberCash:

    CyberCash       AuthorizeNet
    ------------------------------
    mauthonly           AO
    mauthcapture        NA

=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       AO
                        mauthcapture    NA
                        authonly        AO
                        authcapture     NA
                        / );

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;
