#!/usr/bin/perl5.003
$ConfigFile="boutique.cfg";
##############################################################################
# Notice
# ------
# This software is proprietary and may not be modified, copied,
# or reproduced in any manner without the expressed witten permission
# of Virtual Publisher, Inc. This software is distributed under a site
# license that permits it's use on a single domain/web site.
# The complete source code license agreement that accompanies this
# software is made a part of this software as if written herein.
#
#
# File: boutique.cgi
#
# Auth: Virtual Publisher, Inc., Copyright 1996, 1997 All Rights Reserved
# Website-http://virtualpublisher.com
# Version: 3.0
# Release: September 21, 1997
#
#
# Desc: Boutique Shopping Script
#
# This script works with both the "GET" and "POST" CGI
# methods and is compatible with both Perl 4 and Perl 5.
#
################################################################
#####
# Modified: 05/08/97
# M.H.A.
# Modified: 10/18/97
# 1. rename shoppro.lock to boutique.lock
#################################################################
require "customshipping.pl";
#################################################################
# DEBUG FEATURES
#################################################################
$ProgramName = "Boutique";
# If DEBUG is ON the Logger sub will produce output in the LogFile
#$DEBUG = "ON";
$DEBUG = "OFF";
@ReservedParamNames =
(
'Prevpage',
'Template',
'Address',
'Address2',
'Subject',
'Confpage',
'ThankYouPage',
'CashRegister',
'Minpurchase',
'Minqty',
'Discount',
'FromAddress',
'Operation',
'MasterCdDb',
'dbDir',
'IndexHtmlDb'
);
# added Department, Size, Weight
@ProductInfoParamNames =
(
'Prodno',
'Qty',
'Price',
'Item',
'Describe',
'Info',
'Amount',
'Department',
'Size',
'Weight',
);
# added Total_Items and Total_Weight
@SummaryInfoParamNames =
(
'SubTotal',
'Taxes',
'Tax',
'Shipping',
'FShipping',
'Pshipping',
'Cshipping',
'Total',
'SubTotalAfterDiscount',
'DiscountAmount',
'TotalItems',
'TotalWeight'
);
# added DepartmentName and DepartmentSubTotal
@DepartmentSubTotalInfoParamNames =
(
'DepartmentName'
);
# required elements at Shopping
@RequiredElements = ();
# required elements at card payment
@CardElements = ();
# array for holding order records
@Order = ();
# hashtable for Taxes:
# in boutique* : key= taxtable
#
# format: key = value for boutique*
# and vendorId.key = value for shopmall
%TaxTable = ();
#V ReadParametersFromFile . . . . . if true forces cgi params read from file
#V SaveParametersToFile . . . . . . . . . . if true dumps cgi params to file
$ReadParametersFromFile = 0;
$SaveParametersToFile = 0;
$ParameterFileName = "param.txt";
#S Error Messages . . . . . . . . . . . . . . . . .error messages defintions
##
#
$ErrMsg{'Sys_Open_File'} = "Error opening file <%PlaceHolder%>";
$ErrMsg{'Sys_Open_ConfigFile'} = "Could not open configuration file: <%PlaceHolder%>";
$ErrMsg{'Sys_Open_TemplateFile'} = "Error opening template file: <%PlaceHolder%>";
$ErrMsg{'Sys_Open_LogFile'} = "Could not open log file: <%PlaceHolder%>";
$ErrMsg{'Sys_Open_MasterFile'} = "Could not open master file: <%PlaceHolder%>";
$ErrMsg{'Sys_Open_IndexFile'} = "Could not open index file: <%PlaceHolder%>";
$ErrMsg{'Sys_Open_OrderFile'} = "Could not open order number file: <%PlaceHolder%>";
$ErrMsg{'Sys_Append_MasterFile'} = "Could not open for append master file: <%PlaceHolder%>";
$ErrMsg{'Parameters_NoParameters'} = "No CGI parameters passed to <%PlaceHolder%>";
$ErrMsg{'Sys_No_Param'} = "No CGI parameters passed to <%PlaceHolder%>";
$ErrMsg{'Sys_Missing_ConfigFile'} = "Missing ConfigFile parameter";
$ErrMsg{'User_Blank_Elem'} = "Please input value at field: <%PlaceHolder%>";
$ErrMsg{'User_Blank_Card'} = "Please input the information needed concerning your Credit Card, at field: <%PlaceHolder%>";
$ErrMsg{'User_No_Order'} = "No products were ordered";
#V DefaultErrorPage. . . display this page if no other page could be read in
##
#
$DefaultErrorPage =
"\n" .
"
\n" .
"An error has occured\n" .
"\n" .
"\n" .
"\n" .
"An error has occured.
\n" .
"\n" .
"Tech support could not be notified!
\n" .
"\n" .
"\n" .
"\n" .
"\n";
########################################################################
# PROGRAM BODY #
########################################################################
&main();
exit( 0 );
#########################################################################
# ERROR HANDLING #
#########################################################################
#F UserMessage( message ) . . . . . . . . . . . . . . . . .display a message
##
#
sub UserMessage
{
local( $errorId, $errorMessage, $notificationFailed ) = @_;
local( $htmlFile );
local( $message );
local( $anchor );
local( $html );
# read the current HTML file and insert the message
if ( $notificationFailed == 2 ) {
$htmlFile = $conf{'ERROR_PAGE.CriticalErrorPage'};
}
elsif ( $notificationFailed == 1 ) {
$htmlFile = $conf{'ERROR_PAGE.ErrorPage'};
}
else {
$htmlFile = $conf{'ERROR_PAGE.UserErrorPage'};
}
if ( open( HTMLH, $htmlFile ) ) {
$html = join( '', );
close( HTMLH );
}
else {
$html = $DefaultErrorPage;
}
$anchor = "";
if ( $notificationFailed eq 0 ) {
$message = "$errorMessage
\n";
}
else {
$message = "The encountered error was:
\n" .
"$errorMessage
\n";
}
$html =~ s/$anchor/$anchor\n$message/;
print "Content-type: text/html\n\n";
print $html;
}
#F ErrorMail( errorId, optional_param). . . . . . . . mails an error message
##
#
sub ErrorMail
{
local( $errorId, $errorMessage ) = @_;
local( $errorStr );
# return if the tech support address is undefined
if ( ! $conf{'TECH_SUPPORT.Address'} ) {
return 0;
}
$errorStr = "$conf{'GENERAL_INFORMATION.ProgramName'} encountered"
. " the following error:\n\n";
$errorStr .= $errorMessage;
$conf{'TECH_SUPPORT.FromAddress'} =~ s/\n//;
if (!$conf{'TECH_SUPPORT.FromAddress'}) {
$conf{'TECH_SUPPORT.FromAddress'} = $SystemName;
}
if (!$conf{'TECH_SUPPORT.Subject'}) {
$conf{'TECH_SUPPORT.Subject'} = "$SystemName Error";
}
if ( ! open( MAILH,
"| $conf{'GENERAL_INFORMATION.Sendmail'} $conf{'TECH_SUPPORT.Address'}" ) ) {
return 0;
}
print MAILH "From: $conf{'TECH_SUPPORT.FromAddress'}\n";
print MAILH "Subject: $conf{'TECH_SUPPORT.Subject'}\n\n";
print MAILH "$errorStr\n";
close( MAILH );
return 1;
}
#F Error( errorId, optional_param). . . . . . . . . . . . . . .error handler
##
## ARGUMENTS
## errorId : error identification
##
## REMARKS
## This function is called in case of system errors.
#
sub Error
{
local( $errorId, $filename ) = @_;
local( $errorMessage );
local( $notificationFailed );
# compose the error message
$notificationFailed = 0;
# if it is a system error mail to the administrator
if ( $errorId =~ /Sys_/ ) {
$errorMessage = "Error Id: $errorId ($ErrMsg{$errorId})\n";
$errorMessage =~ s/<%PlaceHolder%>/${filename}/;
if ( ! &ErrorMail( $errorId, $errorMessage ) ) {
$notificationFailed = 2;
}
else {
$notificationFailed = 1;
}
}
else {
$errorMessage = "$ErrMsg{$errorId}\n";
$errorMessage =~ s/<%PlaceHolder%>/$filename/;
}
# write a message for the user
&UserMessage( $errorId, $errorMessage, $notificationFailed );
exit( 1 );
}
#########################################################################
# CGI PARAM HANDLING #
#########################################################################
#F ReadParse(in) . . . . . . . . . . . . . read the CGI parameters into 'in'
##
## ARGUMENTS
## inHash : hash array, will contain the read in (name,value) pairs
## inArray : array, will contain the read in pairs as 'name=value' strings
##
## DESCRIPTION
## Reads in GET or POST data, converts it to unescaped text, and puts
## one key=value in each member of the list "@inArray".
## Also creates key/value pairs in %inHash, using '\0' to separate multiple
## selections.
##
## NOTE
## The function was adapted from Steven Brenner's "ReadParse" function
## in his "cgi-lib.pl" library.
## Copyright (c) 1995 Steven E. Brenner
## Unpublished work.
## Permission granted to use and modify this library so long as the
## copyright above is maintained, modifications are documented, and
## credit is given for any use of the library.
#
sub ReadParse
{
local ( *in ) = @_ if @_;
local ( $i, $key, $val, $in );
# Read in text
if ($ENV{'REQUEST_METHOD'} eq "GET") {
$in = $ENV{'QUERY_STRING'};
}
elsif ($ENV{'REQUEST_METHOD'} eq "POST") {
read(STDIN,$in,$ENV{'CONTENT_LENGTH'});
}
@in = split(/[&;]/,$in);
foreach $i (0 .. $#in) {
# Convert plus's to spaces
$in[$i] =~ s/\+/ /g;
# Split into key and value.
# splits on the first =.
($key, $val) = split(/=/,$in[$i],2);
# Convert %XX from hex numbers to alphanumeric
$key =~ s/%(..)/pack("c",hex($1))/ge;
$val =~ s/%(..)/pack("c",hex($1))/ge;
# Associate key and value
$in{$key} .= "\0" if (defined($in{$key})); # \0 is the multiple separator
$in{$key} .= $val;
}
return scalar(@in);
}
#F WriteParamsToFile(fileName,params). . . . . . .write the params to a file
##
## ARGUMENTS
## fileName: the file name of the file used for writing the parameters
## params : the parameters
#
sub WriteParamsToFile
{
local( $fileName, *paramsHash, *paramsArray ) = @_;
local( $keys, $values, $total );
local( $separator1, $separator2 );
local( $paramName, $paramValue );
local( $i );
$separator1 = qq(--sepa1--);
$separator2 = qq(--sepa2--);
if ( !open( FILEHANDLE, ">${fileName}" ) ) {
&Error( 'Sys_Open_File', $fileName );
return 0;
}
$keys = "";
$values = "";
foreach $i ( 0 .. $#paramsArray-1 ) {
( $paramName, $paramValue ) = split( /=/, $paramsArray[ $i ], 2 );
$keys .= $paramName . $separator1;
$values .= $paramValue . $separator1;
}
( $paramName, $paramValue ) = split( /=/, $paramsArray[ $#paramsArray ], 2 );
$keys .= $paramName;
$values .= $paramValue;
$total = $keys . $separator2 . $values;
print FILEHANDLE $total;
close( FILEHANDLE );
# `chmod 666 $fileName`;
}
#F ReadParamsFromFile(fileName, params). . . . . . . . read params from file
##
## ARGUMENTS
## fileName: the file name of the file used for writing the parameters
## params : the parameters
#
sub ReadParamsFromFile
{
local( $fileName, *paramsHash, *paramsArray ) = @_;
local( $keys, $values, $total );
local( $content );
local( $separator1, $separator2 );
$separator1 = qq(--sepa1--);
$separator2 = qq(--sepa2--);
#get the file content
open( FILEHANDLE, $fileName ) ||
&Error( 'Sys_Open_File',$fileName );
$content = join( "", );
close( FILEHANDLE );
#get the keys and the values
( $keys, $values ) = split( $separator2, $content );
@keys = split( $separator1, $keys );
@values = split( $separator1, $values );
#setup the params hash
while( @keys ) {
$key = shift( @keys );
$value = shift( @values );
$paramsHash{$key} = $value;
push( @paramsArray, "$key=$value" );
}
return 1;
}
#
#F ReadCgiParameters . . . . . . . . . . . read the CGI parameters into 'in'
##
## PARAMETERS
## in: hash array, will contain the read in (name,value) pairs
##
## DESCRIPTION
##
##
#
sub ReadCgiParameters
{
local( *inHash, *inArray ) = @_;
if( $SaveParametersToFile == 1 ) {
print "Content-type: text/plain\n\n";
if ( !&ReadParse ) {
&Error( 'Sys_No_Param', "boutique.cgi" );
return 0;
}
&WriteParamsToFile( $ParameterFileName, *inHash, *inArray );
exit;
}
if( $ReadParametersFromFile == 1 ) {
return &ReadParamsFromFile( $ParameterFileName, *inHash, *inArray );
}
else {
if ( ! &ReadParse( *inHash, *inArray ) ) {
&Error( 'Sys_No_Param', "boutique.cgi" );
return 0;
}
return 1;
}
}
##########################################################################
# CONFIG FILE HANDLING #
##########################################################################
#F ReadConfigFile(fileName,conf). . . . . . . process the configuration file
##
## Reads from configuration file and outputs
## %conf , containing ($name, $value) pairs.
##
sub ReadConfigFile
{
local( $fileName, *conf ) = @_;
local( $section) = "";
local( $name) = "";
local( $value) = "";
local( $flagmulti) = 0;
local( $flagsection) = 1;
# open configuration file
if ( ! open( CONFIG_FILE, "<$fileName" ) ) {
&Error( 'Sys_Open_ConfigFile', $fileName );
return 0;
}
# parse configuration file
READ_LABEL:
while ( ) {
# ignore empty line
if (/^\n$/) {
next READ_LABEL;
}
# ignore comments
if (/^[#;].*$/) {
next READ_LABEL;
}
# encounter section
if ( /^\[(.*)\]$/ ) {
if ( $flagmulti ) {
%conf = (%conf, $name, $value);
}
$flagsection = 0;
$flagmulti = 1;
$section = $1;
$value = '';
# add section information
%conf = (%conf, $section, 'true' );
next READ_LABEL;
}
# name = value
if ( /\s*(\S+)\s*=\s*([^\n]*)/ ) {
if ( $flagmulti && $flagsection ) {
%conf = (%conf, $name, $value);
}
if ( ( defined( $section ) ) && ( $section ne "" ) ) {
$name =$section . ".";
}
$name .= $1;
$value = $2;
$flagsection = 1;
next READ_LABEL;
}
# if none of the above
if ( $flagmulti ) {
/(.*)/;
$value .= "$1\n";
}
next READ_LABEL;
}
# this should happen
if ( $flagmulti ) {
%conf = (%conf, $name, $value);
}
close( CONFIG_FILE );
return 1;
}
#
#F UpdateInHash(inHash,conf). . . . . . . updates the inHash table with
## values from %conf
##
sub UpdateInHash
{
# creates the link between old and new variable names
$inHash{'Taxes'} = "";
&Logger( "UpdateInHash begin..." );
# Config file values
#
# GENERAL_INFORMATION part
$inHash{'TemplatePath'} = $conf{'GENERAL_INFORMATION.TemplatePath'};
$inHash{'HtmlUrl'} = $conf{'GENERAL_INFORMATION.HtmlUrl'};
$inHash{'Prevpage'} = $inHash{'HtmlUrl'} . "/"
. $conf{'GENERAL_INFORMATION.MainProductPage'};
$inHash{'Confpage'} = $inHash{'TemplatePath'} . "/"
. $conf{'GENERAL_INFORMATION.SaleslipPage'};
$inHash{'CashRegister'} = $inHash{'TemplatePath'} . "/"
. $conf{'GENERAL_INFORMATION.CheckoutPage'};
$inHash{'ThankYouPage'} = $inHash{'TemplatePath'} . "/"
. $conf{'GENERAL_INFORMATION.ThankYouPage'};
if ( defined( $conf{'GENERAL_INFORMATION.Frames'} ) ) {
$inHash{'Frames'} = $conf{'GENERAL_INFORMATION.Frames'}
}
if ( (!$inHash{'NextUrl'} ) && ( $conf{'GENERAL_INFORMATION.NextUrl'} ) ) {
$inHash{'NextUrl'} = $conf{'GENERAL_INFORMATION.NextUrl'};
}
$inHash{'OrderNoFile'} = $conf{'GENERAL_INFORMATION.OrderNoFile'};
# VENDOR_INFORMATION part
$inHash{'Address'} = $conf{'VENDOR_INFORMATION.DefaultAddress'};
$inHash{'Subject'} = $conf{'VENDOR_INFORMATION.DefaultSubject'};
$inHash{'FromAddress'} = $conf{'VENDOR_INFORMATION.DefaultFromAddress'};
$inHash{'Template'} = "";
if ( defined( $conf{'VENDOR_INFORMATION.DefaultTemplate'} )
&& ( $conf{'VENDOR_INFORMATION.DefaultTemplate'} ne "" ) ) {
$inHash{'Template'} = $inHash{'TemplatePath'} . "/"
. $conf{'VENDOR_INFORMATION.DefaultTemplate'};
}
if ( defined ( $conf{'VENDOR_INFORMATION.ForwardAddress'} ) ) {
$inHash{'ForwardAddress'} = $conf{'VENDOR_INFORMATION.ForwardAddress'};
}
$inHash{'ForwardTemplate'} = "";
if ( defined( $conf{'VENDOR_INFORMATION.ForwardTemplate'} )
&& ( $conf{'VENDOR_INFORMATION.ForwardTemplate'} ne "" ) ) {
$inHash{'ForwardTemplate'} = $inHash{'TemplatePath'} . "/"
. $conf{'VENDOR_INFORMATION.ForwardTemplate'};
}
# STORAGE_INFORMATION part
$inHash{'TemplateDbPath'} = $conf{'STORAGE_INFORMATION.Template_db_path'};
$inHash{'TemplateDbPath'} = $conf{'STORAGE_INFORMATION.Template_db_path'};
$inHash{'dbDir'} = $conf{'STORAGE_INFORMATION.db_dir'};
$inHash{'TemplateMCdDb'} = $inHash{'TemplateDbPath'} . "/"
. $conf{'STORAGE_INFORMATION.Template_m_cd_db'};
$inHash{'MasterCdDb'} = $inHash{'dbDir'} . "/"
. $conf{'STORAGE_INFORMATION.Master_cd_db'};
$inHash{'IndexHtmlDb'} = $inHash{'dbDir'} ."/"
.$conf{'STORAGE_INFORMATION.Index_html_db'};
$inHash{'TemplateIndexDb'} = $inHash{'TemplateDbPath'} . "/"
.$conf{'STORAGE_INFORMATION.Template_index_db'};
$inHash{'TemplateMHtmlDb' } = $inHash{'TemplateDbPath'} . "/"
. $conf{'STORAGE_INFORMATION.Template_m_html_db'};
# CALCULATIONS part
$inHash{'Minqty'} = $conf{'CALCULATIONS.Minqty'};
$inHash{'Minpurchase'} = $conf{'CALCULATIONS.Minpurchase'};
$inHash{'Discount'} = $conf{'CALCULATIONS.Discount'};
if ( defined ( $conf{'CALCULATIONS.Fshipping'} ) ) {
$inHash{'Fshipping'} = $conf{'CALCULATIONS.Fshipping'};
}
if ( defined ( $conf{'CALCULATIONS.Pshipping'} ) ) {
$inHash{'Pshipping'} = $conf{'CALCULATIONS.Pshipping'};
}
if ( defined ( $conf{'CALCULATIONS.Cshipping'} ) ) {
$inHash{'Cshipping'} = $conf{'CALCULATIONS.Cshipping'};
}
}
#F CreateRequiredElements
##
## DESCRIPTION
## creates the required elements for user input at saleslip.html.
## or creates the Vendors cfg files hashtable with path to *.cfg
## from shopmall.cfg VENDOR_INFORMATION.
##
#
sub CreateRequiredElements
{
local( $typeOfRequiredElements ) = @_;
local( @confKeys );
local( $matchString );
local( @returnedElements ) = ();
&Logger("CreateRequiredElements begin");
@confKeys = keys( %conf );
if ( $typeOfRequiredElements eq "Fields" ) {
$matchString = "REQUIRED_FIELDS\.";
}
if ( $typeOfRequiredElements eq "Cards" ) {
$matchString = "CARD_FIELDS\.";
}
foreach $element ( @confKeys ) {
if ( $element =~ /^$matchString.*$/ ) {
$element =~ s/$matchString//;
push( @returnedElements, $element );
}
}
return @returnedElements;
}
#F CreateTaxTable . . . . . . .create the Taxes hashtable with
## values from %conf
##
#
sub CreateTaxTable
{
local( $key, $value );
local( @taxElements );
&Logger( "CreateTaxTable begin..." );
if ( defined( $conf{'TAX_TABLE.TaxTable'} ) ) {
@taxElements = split( /;/, $conf{'TAX_TABLE.TaxTable'} );
foreach $element ( @taxElements ) {
( $key, $value ) = split( /,/, $element, 2 );
$TaxTable{$key} = $value;
}
}
}
##########################################################################
# DEBUG FEATURE #
##########################################################################
##########################################################################
# This subroutine is used for error loging.
# The output will be written in the TmpDir directory
#
##########################################################################
sub Logger
{
local( $message ) = @_;
local( $LogFile ) = "$conf{'GENERAL_INFORMATION.TmpDir'}/boutique.log";
if ( $DEBUG eq "ON" ) {
# open logger file
if ( ! -e "$LogFile" ) {
if ( ! open( LOG, ">$LogFile" ) ) {
&Error( 'Sys_Open_LogFile', $LogFile );
return 0;
}
}
else {
if ( ! open( LOG, ">>$LogFile" ) ) {
&Error( 'Sys_Open_LogFile', $LogFile );
return 0;
}
}
print LOG $message,"\n";
close ( LOG );
}
}
##########################################################################
# CHECKINGS #
##########################################################################
#F VerifyRequiredFields . . . . . . . . . . . . . . . .check required fields
##
## ARGUMENTS
##
##
## DESCRIPTION
## Checks to see if all the required fields are defined. If not, outputs an
## error message page.
#
sub VerifyRequiredFields
{
local( *in ) = shift;
local( $key, $val, $printedHeaderFlag );
&Logger( "VerifyRequiredFFields begin..." );
$printedHeaderFlag = 0;
while ( ( $key, $val ) = each(%in) ) {
if ( substr( $key, 0, 2 ) eq 'R_' && $val eq '' ) {
if ( ! $printedHeaderFlag ) {
print <Required Fields Were Left Blank
Required Fields Were Left Blank
END
$printedHeaderFlag = 1;
}
# The E-mail address is treated separately.
# In the error message will apear "e-mail Address"
# replacing the ?_Address word
if ( ( $key eq 'Address' ) || ( $key eq 'R_Address' ) ||
( $key eq 'Address2' ) || ( $key eq 'R_Address2' ) ) {
$key = 'e-mail Address' ;
}
else {
# Chop the leading "R_" off param names for display.
# Replace any other "_" characters appearing in the
# key name with " " to make the error message more
# user friendly.
$key = substr( $key, 2 );
$key =~ s/_/ /g;
}
print "
The required field '${key}' was left blank."
}
}
if ( $printedHeaderFlag ) {
print <Please press the 'BACK' button in your browser and make corrections.