extra/HTML/Entities.pm
extra/IniConf.pm
extra/URI/URL.pm
+hints.pl
lib/Vend/Cart.pm
lib/Vend/Config.pm
lib/Vend/Control.pm
use File::Copy;
use File::Path;
use File::Basename;
+use File::Find;
use Data::Dumper;
use Cwd;
require 5.005;
my @mods_to_get;
my $Lock_troubles;
-$VERSION = '4.03';
+$VERSION = '4.04';
# See if we have the CPAN module
my $Cpan = 0;
$Cpan = 1;
}
-my @extra_lib_dirs;
-my @extra_lib_files;
+my @os_hints;
+eval {
+ # gets package 'mvhints'
+ require 'hints.pl';
+ @os_hints = mvhints::get_hints();
+};
+
my @chown_files = qw/
error.log
etc
};
}
-if($^O =~ /win32/i) {
- die "Windows is only supported for a binary distribution.\n";
-}
+my $Windows = $^O =~ /win32/i ? 1 : 0;
sub compare_file {
my($first,$second) = @_;
return CPAN::install($module);
}
+sub extra_libs {
+
+ my ($realdir) = @_;
+ # Do the extra library checks
+
+ my @extra_lib_dirs;
+ my @extra_lib_files;
+ # We will use our own version of File::CounterFile always
+ push @extra_lib_dirs, 'File';
+ push @extra_lib_files, 'File/CounterFile.pm';
+
+ eval {
+ require IniConf;
+ };
+ if ($@) {
+ push @extra_lib_files, 'IniConf.pm';
+ }
+
+
+ eval {
+ require HTML::Entities;
+ };
+ if ($@) {
+ push @extra_lib_dirs, 'HTML';
+ push @extra_lib_files, 'HTML/Entities.pm';
+ }
+
+ eval {
+ require Business::UPS;
+ };
+ if ($@) {
+ push @extra_lib_dirs, 'Business';
+ push @extra_lib_files, 'Business/UPS.pm';
+ }
+
+ eval {
+ require Storable;
+ };
+ unless ($@) {
+ my $def = 'y';
+ print <<EOF;
+
+You appear to have Raphael Manfredi's Storable module installed.
+
+This module will significantly improve your DBM storage and
+fetch times.
+
+You can reply one of:
+
+ n -- Don't use Storable
+ s -- Use for sessions only, won't break existing databases
+ y -- Use for both sessions and databases
+
+It is recommended that new installations reply YES, and that
+existing installations reply S unless there is a need for
+improved performance. Replying S will mean you have to delete all
+of your session files.
+
+If you reply YES and you use any GDBM or DB_File databases
+they will NEED TO BE REMADE for ALL CATALOGS using this
+MiniVend server instance.
+EOF
+
+ if($ENV{MINIVEND_STORABLE_DB} || -f "$realdir/_db_storable" || -f "_db_storable") {
+ $def = 'y';
+ }
+ elsif($ENV{MINIVEND_STORABLE} || -f "$realdir/_session_storable" || -f "_session_storable") {
+ $def = 's';
+ }
+ my $ask = my_prompt("Use Storable module? (y/n/s) ", $def);
+ if ($ask =~ /^\s*(y|d)/i) {
+ open(TSTORABLE, ">_db_storable")
+ or die "creat _db_storable: $!\n";
+ print TSTORABLE "REMOVE THIS FILE TO STOP USING Storable\n";
+ close TSTORABLE;
+ }
+ if ($ask =~ /^\s*(y|s)/i) {
+ open(TSTORABLE, ">_session_storable")
+ or die "creat _session_storable: $!\n";
+ print TSTORABLE "REMOVE THIS FILE TO STOP USING Storable\n";
+ close TSTORABLE;
+ }
+ }
+
+ COPYEXTRA: {
+ my $cpdir = '.';
+ mkdir $cpdir, 0777 unless -d $cpdir;
+ mkdir "$cpdir/lib", 0777 unless -d "$cpdir/lib";
+ for(@extra_lib_dirs) {
+ next if -d "$cpdir/lib/$_";
+ mkdir "$cpdir/lib/$_", 0777 or die "mkdir $cpdir/lib/$_: $!\n";
+ }
+ for(@extra_lib_files) {
+ File::Copy::copy ("extra/$_", "lib/$_")
+ or die "Couldn't copy $_: $!\n";
+ }
+ }
+}
+
+sub mk_initp {
+ my ($ref) = @_;
+ local($Data::Dumper::Terse);
+ $Data::Dumper::Terse = 1;
+ open (INITP, ">scripts/initp.pl")
+ or die "Can't write initp.pl: $!\n";
+ print INITP '$MV::Self = ';
+ print INITP Dumper($ref);
+ print INITP ";\n1;";
+ close INITP;
+}
+
sub initialize {
my %X;
$X{INSTALLDIRS} = "perl";
$X{RPMBUILDDIR} = $MV::Default{rpmbuilddir} || $MV::Default{RPMBUILDDIR};
$MV::Default{RPMBUILDDIR} = $X{RPMBUILDDIR};
}
+
+ return %X if $MV::Default{nocopy};
+
my $uid;
- if($> == 0 and ! $MV::Default{MINIVEND_USER}) {
+ if($> == 0 and ! $MV::Default{MINIVEND_USER} and ! $Windows) {
$uid = my_prompt(
qq{MiniVend cannot be run as root. Which user should run MiniVend? },
'minivend',
print UID "$uid";
close UID;
}
- else {
+ elsif (! $Windows) {
eval {
$uid = scalar getpwuid($>);
};
}
- return %X if $MV::Default{nocopy};
+
if($uid) {
open(UID, ">_uid")
or die "Can't write uid file: $!\n";
);
print "\n";
$realdir =~ s:[\\/]\s*$::;
+ $MV::Default{final} = $realdir if $Windows;
}
else {
$realdir = $MV::Default{final};
../pod/mvfaq.pod simple/download/mvfaq.pod
);
+ if($Windows) {
+ mk_initp(\%X);
+ my ($in, $out);
+ my $ref = delete $X{PL_FILES};
+ if(! -d 'bin') {
+ File::Path::mkpath('bin');
+ }
+ my (@f);
+ while ( ($in, $out) = each %$ref) {
+ system "$^X $in";
+ if($?) {
+ die "Error making $in into $out: $!\n";
+ }
+ my $targ = $out;
+ $targ =~ s:.*/::;
+ File::Copy::copy($out, 'bin');
+ push @f, "bin/$targ";
+ system "pl2bat.bat $out";
+ if($?) {
+ warn "PL2BAT did not succeed for $out.\n";
+ }
+ else {
+ File::Copy::copy("$out.bat", 'bin');
+ push @f, "bin/$targ.bat";
+ }
+ }
+ # Check for extra needed libraries
+ extra_libs($realdir);
+ my $wanted = sub {
+ return unless -f $_;
+ push @f, $File::Find::name;
+ };
+ File::Find::find($wanted, 'lib');
+ for (@f) {
+ install_file('.', $realdir, $_);
+ }
+ }
if($MV::Default{final}) {
$\17 = 0;
for(glob "_*") {
for (@files) {
install_file('.', $realdir, $_);
}
+ for(@os_hints) {
+ my ($condition, $routine) = @$_;
+ unless (ref($condition) =~ /CODE/ and ref($routine) =~ /CODE/) {
+ warn <<EOF;
+OS hint condititon and routine must be code reference, is
+
+ condition: $condition
+ routine: $routine
+
+Skipping.
+EOF
+ next;
+ }
+ next unless $condition->();
+ my $odir = cwd();
+ chdir $realdir
+ or die "Cannot chdir to $realdir: $!\n";
+ $routine->();
+
+ }
if(-f "$realdir/_uid" and $> == 0) {
open(UID, "$realdir/_uid")
or die "Can't open uid file: $!\n";
}
- # Do the extra library checks
-
- # We will use our own version of File::CounterFile always
- push @extra_lib_dirs, 'File';
- push @extra_lib_files, 'File/CounterFile.pm';
-
- eval {
- require IniConf;
- };
- if ($@) {
- push @extra_lib_files, 'IniConf.pm';
- }
-
-
- eval {
- require HTML::Entities;
- };
- if ($@) {
- push @extra_lib_dirs, 'HTML';
- push @extra_lib_files, 'HTML/Entities.pm';
- }
-
- eval {
- require Business::UPS;
- };
- if ($@) {
- push @extra_lib_dirs, 'Business';
- push @extra_lib_files, 'Business/UPS.pm';
- }
-
- eval {
- require Storable;
- };
- unless ($@) {
- my $def = 'y';
- print <<EOF;
-
-You appear to have Raphael Manfredi's Storable module installed.
-
-This module will significantly improve your DBM storage and
-fetch times.
-
-You can reply one of:
-
- n -- Don't use Storable
- s -- Use for sessions only, won't break existing databases
- y -- Use for both sessions and databases
-
-It is recommended that new installations reply YES, and that
-existing installations reply S unless there is a need for
-improved performance. Replying S will mean you have to delete all
-of your session files.
-
-If you reply YES and you use any GDBM or DB_File databases
-they will NEED TO BE REMADE for ALL CATALOGS using this
-MiniVend server instance.
-EOF
-
- if($ENV{MINIVEND_STORABLE_DB} || -f "$realdir/_db_storable" || -f "_db_storable") {
- $def = 'y';
- }
- elsif($ENV{MINIVEND_STORABLE} || -f "$realdir/_session_storable" || -f "_session_storable") {
- $def = 's';
- }
- my $ask = my_prompt("Use Storable module? (y/n/s) ", $def);
- if ($ask =~ /^\s*(y|d)/i) {
- open(TSTORABLE, ">_db_storable")
- or die "creat _db_storable: $!\n";
- print TSTORABLE "REMOVE THIS FILE TO STOP USING Storable\n";
- close TSTORABLE;
- }
- if ($ask =~ /^\s*(y|s)/i) {
- open(TSTORABLE, ">_session_storable")
- or die "creat _session_storable: $!\n";
- print TSTORABLE "REMOVE THIS FILE TO STOP USING Storable\n";
- close TSTORABLE;
- }
- }
-
MODCHECK: {
-
last MODCHECK unless $Cpan;
eval {
- require MD5;
+ require Digest::MD5;
};
- push(@mods_to_get, 'MD5') if $@ and $Cpan;
+ push(@mods_to_get, 'Digest::MD5') if $@ and $Cpan;
eval {
require SQL::Statement;
};
push(@mods_to_get, 'SQL::Statement') if $@ and $Cpan;
eval {
+ require Safe::Hole;
+ };
+ push(@mods_to_get, 'Safe::Hole') if $@ and $Cpan;
+ eval {
require MIME::Base64;
};
push(@mods_to_get, 'MIME::Base64') if $@ and $Cpan;
require URI::URL;
};
push(@mods_to_get, 'URI::URL') if $@ and $Cpan;
-
- }
-
- COPYEXTRA: {
- my $cpdir = '.';
- mkdir $cpdir, 0777 unless -d $cpdir;
- mkdir "$cpdir/lib", 0777 unless -d "$cpdir/lib";
- for(@extra_lib_dirs) {
- next if -d "$cpdir/lib/$_";
- mkdir "$cpdir/lib/$_", 0777 or die "mkdir $cpdir/lib/$_: $!\n";
- }
- for(@extra_lib_files) {
- File::Copy::copy ("extra/$_", "lib/$_")
- or die "Couldn't copy $_: $!\n";
- }
}
+ local($\17);
$\17 = 0;
MODGET: {
or die "Couldn't return to original dir $odir: $!\n";
}
- $Data::Dumper::Terse = 1;
- open (INITP, ">scripts/initp.pl")
- or die "Can't write initp.pl: $!\n";
- print INITP '$MV::Self = ';
- print INITP Dumper(\%X);
- print INITP ";\n1;";
- close INITP;
+ # Check for extra needed libraries
+ extra_libs($realdir);
+
+ mk_initp(\%X);
delete $X{RPMBUILDDIR};
return \%X;
}
# print "OPT: " . Dumper(\%MV::Default);
@ARGV = grep ! $delete{$_}, @saveargs;
-WriteMakefile(
- NAME => "MiniVend",
- MAN3PODS => {
- 'pod/mvdocs.pod' => 'blib/man3/mvdocs.8',
- 'pod/mvtags.pod' => 'blib/man3/mvtags.8',
- 'pod/mvfaq.pod' => 'blib/man3/mvfaq.8',
+if($Windows) {
+ &initialize;
+}
+else {
+ WriteMakefile(
+ NAME => "MiniVend",
+ MAN3PODS => {
+ 'pod/mvdocs.pod' => 'blib/man3/mvdocs.8',
+ 'pod/mvtags.pod' => 'blib/man3/mvtags.8',
+ 'pod/mvfaq.pod' => 'blib/man3/mvfaq.8',
+ },
+ DISTNAME => "minivend",
+ clean => {
+ FILES=> "lib/IniConf.pm _uid _db_storable _session_storable lib/File/CounterFile.pm scripts/initp.pl scripts/compile_link scripts/config_prog scripts/configdump scripts/dump scripts/expire scripts/localize scripts/expireall scripts/makecat scripts/minivend scripts/offline scripts/restart scripts/update dist/simple/download/mvdocs.pod dist/simple/download/mvtags.pod dist/simple/download/mvfaq.pod pod/mvtags.pod",
+ },
+
+ dist => {
+ CI => "ci -l -t-Initial",
+ SUFFIX => ".gz",
+ DIST_DEFAULT => 'all tardist',
+ COMPRESS => "gzip -9f",
+ ZIP_FLAGS => '-pr9',
},
- DISTNAME => "minivend",
- clean => {
- FILES=> "lib/IniConf.pm _uid _db_storable _session_storable lib/File/CounterFile.pm scripts/initp.pl scripts/compile_link scripts/config_prog scripts/configdump scripts/dump scripts/expire scripts/localize scripts/expireall scripts/makecat scripts/minivend scripts/offline scripts/restart scripts/update dist/simple/download/mvdocs.pod dist/simple/download/mvtags.pod dist/simple/download/mvfaq.pod pod/mvtags.pod",
- },
-
- dist => {
- CI => "ci -l -t-Initial",
- SUFFIX => ".gz",
- DIST_DEFAULT => 'all tardist',
- COMPRESS => "gzip -9f",
- ZIP_FLAGS => '-pr9',
- },
- VERSION_FROM => "scripts/minivend.PL",
- EXE_FILES => [],
- CONFIGURE => \&initialize,
-);
+ VERSION_FROM => "scripts/minivend.PL",
+ EXE_FILES => [],
+ CONFIGURE => \&initialize,
+ );
+}
in most cases. See the Minivend website at http://www.minivend.com/
for more information.
+--------------------------------------------------------------
+
+ M I N I V E N D
+
+ Minivend is a full-featured electronic catalog system (commonly known
+ as a shopping cart) with online ordering capability. It is a high-end
+ database access and retrieval system with SQL support via the Perl DBI.
+
+ A full list of its features is available at:
+
+ http://www.minivend.com/
+
IMPORTANT NOTE: Minivend 4.0 requires, repeat REQUIRES, Perl 5.005 or Perl 5.6.
The information you need is in the following files:
test.pl The installation test script.
win/ Windows-specific files
-
---------------------------------------------------------------
-
- M I N I V E N D
-
- Minivend is a full-featured electronic catalog system (commonly known
- as a shopping cart) with online ordering capability. It is a high-end
- database access and retrieval system with SQL support via the Perl DBI.
-
- Minivend is freely-redistributable under the GNU General Public
- License -- you can download it via FTP.
-
- Minivend 4.0 Features
-
- * Users maintain a "shopping cart" for ordered items
- * Multiple independent or shared catalogs allow one server
- to run many storefronts or a "mall"
- * SSL support means secure and practical credit card ordering
- * PGP and GPG support for secure off-site mailing of orders
- * Complete addressable database support with virtually
- unlimited rows and columns
- * Complete SQL support via DBI
- * Catalogs can be of almost unlimited size with excellent
- performance
- * Multi-server mode for very high capacity on systems with
- sufficient memory
- * Cookie support allows browsers to leave catalog and come
- back without losing session state
- * Minimate web administration interface allows complete
- database editing
- * Complete user authentication and database with address
- books and stored shopping carts
- * Many, many, other features
-
- Powerful search capability
-
- * One-click scan and search -- build a whole search in a single HREF
- * Pageable results, configurable in many ways
- * Versatile built-in text search
- * Complete Glimpse support
- * Fast binary search
- * Independent field search selection and return
- * Range searching, numeric and alphanumeric
- * Search sorting with reverse, numeric and case-insensitive options
- * Search any file, build results from any database
-
- Complete control of appearance
-
- * Over 90 predefined tag functions
- * Powerful user-definable tags
- * Catalog pages automatically selected -- either built
- "on the fly" from the database or pre-made for popular items
- * Embedded Perl and conditional HTML allow complex and
- flexible catalog pages to be completely built from the database
- * ASP-like syntax available
-
- Flexible Ordering Process
-
- * Single- or multi-level order screens with configurable field
- verification
- * Multiple shopping carts per catalog, allows both buy
- and sell operations
- * Shipping calculation, mixed modes, with UPS table lookup
- * Sales tax calculation, with fully independent non-taxable
- item and taxed shipping
- * Route orders to multiple fulfillment houses with
- complete configurability
- * PGP encryption of credit card information or
- the entire emailed order
- * Fully-configurable discounts with coupons or
- across-the-board discounts
- * Fully-configurable quantity pricing
- * Fully-configurable item price adjustments
- * Sophisticated back end order entry capability including CyberCash(R)
- * Fully configurable order reports and receipts
-
- Miscellaneous
-
- * Automated installation and configuration
- * Runs under Perl 5.005/5.6, Windows, and almost any UNIX
- * Designed to be secure
- * Static page build option for high performance
- * Works well with all browsers
-
--------------------------------------------------------------------
-
- A V A I L A B I L I T Y
- A N D
- C O M P A T I B I L I T Y
-
-Minivend 4 has been tested on Solaris 2, Linux, FreeBSD, and Digital
-UNIX/Tru64. Its predecessor Minivend 3 also reportedly runs on SCO, AIX,
-and other Unix ports. It should work on any UNIX or Win32 OS with Perl
-5.005 or higher.
-
-Windows does not support fork(), so the server runs in the foreground. There
-are other differences; the canonical installation is UNIX.
UNIX INSTALLATION
------------------
Here is the short version:
- gzip -dc minivend-4.xxx.tar.gz | tar xvf -
+ gzip -dc minivend-4.xx.tar.gz | tar xvf -
cd minivend-4*
perl Makefile.PL
+ make
make test && make install
-- WHEN IN DOUBT, RE-START THE SERVER. It won't take but a few
WINDOWS INSTALLATION
--------------------
+Not yet. When is not yet determined, but it will not be soon.
+If you are very experienced, you might try installing the ZIP
+file with "perl Makefile.PL". But *at least* the following problems will
+be present:
+
+ 1. You need to put "SessionType DB_File" in catalog.cfg.
+ 2. Minimate will not work (unless you can build Safe::Hole).
+ 3. You probably need to use Apache since we no longer support
+ cygwin.dll and tlink.exe. If you can get tlink.pl running
+ on other web servers, patches are welcome.
+
+Do not use it in a production system.
+
+-------------------------------------------------------------------
+
+ A V A I L A B I L I T Y
+ A N D
+ C O M P A T I B I L I T Y
+
+Minivend 4 has been tested on Solaris 2, Linux, FreeBSD, and Digital
+UNIX/Tru64. Its predecessor Minivend 3 also reportedly runs on SCO, AIX,
+and other Unix ports. It should work on any UNIX or Win32 OS with Perl
+5.005 or higher.
- Not yet. You can manually create a software directory and
- get things going if you know your way around Perl. But I
- don't recommend trying unless you are prepared for some
- serious work.
+IMPORTANT NOTE FOR BSD USERS: Minivend has been known to segfault when
+reading sockets on Perl. This occurs more frequently on a busy system.
+The workaround is to set in minivend.cfg:
+
+ MaxServers 0
+ Housekeeping 1
+
+Windows does not support fork(), so the server runs in the foreground. There
+are other differences; the canonical installation is UNIX.
-------------------------------------------------------------------
K N O W N P R O B L E M S
-BSDI, FreeBSD:
- If installing as root, you should use this procedure:
+BSDI, FreeBSD, Net BSD:
+ You will need to make sure the following are in effect
+ in minivend.cfg:
+
+ MaxServers 0
+ Housekeeping 1
+
+ Expect lots of crashes if you don't do this.
- perl Makefile.PL PREFIX=/usr/local/minivend
+Apache with SUEXEC:
+ VLINK/UNIX socket mode will not work well unless you do the
+ install as a normal user. If you are going to support multiple
+ users, you must use TLINK/INET mode.
Windows:
- Just a few things don't work the same as UNIX. See the
- README-win.txt file for more information.
+ Many things won't work the same as UNIX. See the
+ README-win.txt file for more information.
---------------------------------------------------------------------
+Minivend-4.04 changes:
+* Demo: Fixed COLSPAN=0 in logo bars -- it was killing Gecko rendering.
+* Demo: fixed email password function
+* Makefile.PL adjusts for BSD MaxServers
+* Added README notes about BSD and MaxServers.
+* Config.pm: added AutoEnd to match Autoload
+* Interpolate.pm: fixed bug in shipping which prevented old-style
+ geographic qualification from working -- thanks to Bob Jordan.
+* Order.pm: fixed multi-item order / mv_order_group problem
+* Session.pm: changed session retries to internal code. Thanks to
+ Jim Balster.
+* UserDB.pm: added "load" function to complement "save". Thanks to
+ Christopher Thompson.
+* Util.pm: changed Data::Dumper::Indent setting to localize
+* makecat now handles symlinked minivend.cfg
+* minivend executable:
+ -- AutoEnd added
+ -- adjusted path settings so that FinalPath can be set in Autoload
+ -- Added ability to call GlobalSub as Autoload when matches /^\w+$/
+ -- cleaned up macro calls (remove redundant/unneeded defined checks)
+* doc updates -- thanks to Jeff Carnahan, Hans-Joachim Leidinger, and Bill Randle.
+* Fixed major problems in [sort ....], now works
+* Added vestigial Windows install
+
Minivend-4.03 changes:
* MiniMate now a part of Minivend
* Fixed partial update problems with SQL databases
SpecialPage report ../etc/report
SpecialPage receipt ../etc/receipt
+NoCache reconfig special config query ord multi
Static No
StaticAll Yes
StaticDBM static
<TD WIDTH=150 VALIGN=top __HEADERBG__>
<TABLE WIDTH=150 VALIGN=TOP ALIGN=left CELLSPACING=0 BORDER=0 CELLPADDING=0>
<TR VALIGN=top ALIGN=left>
- <TD WIDTH=150 COLSPAN=0 BGCOLOR=__BARBG__ HEIGHT=13 VALIGN=top ROWSPAN=0 ALIGN=middle><FONT SIZE=1 FACE="Tahoma, Arial, Helvetica" COLOR=__BARTEXT__><B>Search for product</B></FONT>
+ <TD WIDTH=150 BGCOLOR=__BARBG__ HEIGHT=13 VALIGN=top ALIGN=middle><FONT SIZE=1 FACE="Tahoma, Arial, Helvetica" COLOR=__BARTEXT__><B>Search for product</B></FONT>
</TD>
</TR>
<TR>
- <TD WIDTH=150 COLSPAN=0 __HEADERBG__ HEIGHT=82 VALIGN=top ROWSPAN=0 ALIGN=left><FORM ACTION="[area search]"><IMG SRC="clear.gif" WIDTH=1 ALT="" HEIGHT=5 BORDER=0><BR>
+ <TD WIDTH=150 __HEADERBG__ HEIGHT=82 VALIGN=top ALIGN=left><FORM ACTION="[area search]"><IMG SRC="clear.gif" WIDTH=1 ALT="" HEIGHT=5 BORDER=0><BR>
<INPUT TYPE=hidden NAME=mv_coordinate VALUE=1>
<INPUT TYPE=hidden NAME=mv_search_field VALUE=category>
<INPUT TYPE=hidden NAME=mv_search_field VALUE=":artist,title,comment,display">
<TD WIDTH=320 VALIGN=top __HEADERBG__>
<TABLE WIDTH=320 VALIGN=TOP ALIGN=left CELLSPACING=0 BORDER=0 CELLPADDING=0>
<TR VALIGN=top ALIGN=left>
- <TD WIDTH=320 COLSPAN=0 BGCOLOR=__LINECOLOR__ HEIGHT=65 VALIGN=top ROWSPAN=0 ALIGN=left><IMG SRC="__LOGO__" WIDTH=320 ALT="" HEIGHT=65 BORDER=0></TD>
+ <TD WIDTH=320 BGCOLOR=__LINECOLOR__ HEIGHT=65 VALIGN=top ALIGN=left><IMG SRC="__LOGO__" WIDTH=320 ALT="" HEIGHT=65 BORDER=0></TD>
</TR>
<TR VALIGN=top ALIGN=left>
<TD WIDTH=320 BGCOLOR=__LINECOLOR__ HEIGHT=1 VALIGN=top ALIGN=left><IMG SRC="clear.gif" WIDTH=1 ALT="" HEIGHT=1 BORDER=0></TD>
</TR>
<TR VALIGN=top ALIGN=left>
- <TD WIDTH=620 COLSPAN=3 BGCOLOR=__LINECOLOR__ HEIGHT=1 VALIGN=top ROWSPAN=0 ALIGN=left><IMG SRC="clear.gif" WIDTH=1 ALT="" HEIGHT=1 BORDER=0></TD>
+ <TD WIDTH=620 COLSPAN=3 BGCOLOR=__LINECOLOR__ HEIGHT=1 VALIGN=top ALIGN=left><IMG SRC="clear.gif" WIDTH=1 ALT="" HEIGHT=1 BORDER=0></TD>
</TR>
</TABLE>
<TD VALIGN=top __HEADERBG__>
<TABLE WIDTH=320 VALIGN=TOP ALIGN=left CELLSPACING=0 BORDER=0 CELLPADDING=0>
<TR VALIGN=top ALIGN=left>
- <TD WIDTH=320 COLSPAN=0 BGCOLOR=__LINECOLOR__ HEIGHT=65 VALIGN=top ROWSPAN=0 ALIGN=left>
+ <TD WIDTH=320 BGCOLOR=__LINECOLOR__ HEIGHT=65 VALIGN=top ALIGN=left>
<IMG SRC="__LOGO__" WIDTH=320 HEIGHT=65 BORDER=0>
</TD>
</TR>
</TR>
<TR VALIGN=top ALIGN=left>
- <TD WIDTH=620 COLSPAN=3 BGCOLOR=__LINECOLOR__ HEIGHT=1 VALIGN=top ROWSPAN=0 ALIGN=left><IMG SRC="clear.gif" WIDTH=1 HEIGHT=1 BORDER=0></TD>
+ <TD WIDTH=620 COLSPAN=3 BGCOLOR=__LINECOLOR__ HEIGHT=1 VALIGN=top ALIGN=left><IMG SRC="clear.gif" WIDTH=1 HEIGHT=1 BORDER=0></TD>
</TR>
</TABLE>
<TD WIDTH=150 VALIGN=top __HEADERBG__>
<TABLE WIDTH=150 VALIGN=TOP ALIGN=left CELLSPACING=0 BORDER=0 CELLPADDING=0>
<TR VALIGN=top ALIGN=left>
- <TD WIDTH=150 COLSPAN=0 BGCOLOR=__BARBG__ HEIGHT=13 VALIGN=top ROWSPAN=0 ALIGN=middle><FONT SIZE=1 FACE="Tahoma, Arial, Helvetica" COLOR=__BARTEXT__><B>Search for product</B></FONT>
+ <TD WIDTH=150 BGCOLOR=__BARBG__ HEIGHT=13 VALIGN=top ALIGN=middle><FONT SIZE=1 FACE="Tahoma, Arial, Helvetica" COLOR=__BARTEXT__><B>Search for product</B></FONT>
</TD>
</TR>
<TR>
- <TD WIDTH=150 COLSPAN=0 __HEADERBG__ HEIGHT=82 VALIGN=top ROWSPAN=0 ALIGN=left><FORM ACTION="[area search]"><IMG SRC="clear.gif" WIDTH=1 ALT="" HEIGHT=5 BORDER=0><BR>
+ <TD WIDTH=150 __HEADERBG__ HEIGHT=82 VALIGN=top ALIGN=left><FORM ACTION="[area search]"><IMG SRC="clear.gif" WIDTH=1 ALT="" HEIGHT=5 BORDER=0><BR>
<INPUT TYPE=hidden NAME=mv_coordinate VALUE=1>
<INPUT TYPE=hidden NAME=mv_search_field VALUE=category>
<INPUT TYPE=hidden NAME=mv_search_field VALUE=":artist,title,comment,display">
<TD WIDTH=320 VALIGN=top __HEADERBG__>
<TABLE WIDTH=320 VALIGN=TOP ALIGN=left CELLSPACING=0 BORDER=0 CELLPADDING=0>
<TR VALIGN=top ALIGN=left>
- <TD WIDTH=320 COLSPAN=0 BGCOLOR=__LINECOLOR__ HEIGHT=65 VALIGN=top ROWSPAN=0 ALIGN=left><IMG SRC="__LOGO__" WIDTH=320 ALT="" HEIGHT=65 BORDER=0></TD>
+ <TD WIDTH=320 BGCOLOR=__LINECOLOR__ HEIGHT=65 VALIGN=top ALIGN=left><IMG SRC="__LOGO__" WIDTH=320 ALT="" HEIGHT=65 BORDER=0></TD>
</TR>
<TR VALIGN=top ALIGN=left>
<TD WIDTH=320 BGCOLOR=__LINECOLOR__ HEIGHT=1 VALIGN=top ALIGN=left><IMG SRC="clear.gif" WIDTH=1 ALT="" HEIGHT=1 BORDER=0></TD>
</TR>
<TR VALIGN=top ALIGN=left>
- <TD WIDTH=620 COLSPAN=3 BGCOLOR=__LINECOLOR__ HEIGHT=1 VALIGN=top ROWSPAN=0 ALIGN=left><IMG SRC="clear.gif" WIDTH=1 ALT="" HEIGHT=1 BORDER=0></TD>
+ <TD WIDTH=620 COLSPAN=3 BGCOLOR=__LINECOLOR__ HEIGHT=1 VALIGN=top ALIGN=left><IMG SRC="clear.gif" WIDTH=1 ALT="" HEIGHT=1 BORDER=0></TD>
</TR>
</TABLE>
<TD VALIGN=top __HEADERBG__>
<TABLE WIDTH=320 VALIGN=TOP ALIGN=left CELLSPACING=0 BORDER=0 CELLPADDING=0>
<TR VALIGN=top ALIGN=left>
- <TD WIDTH=320 COLSPAN=0 BGCOLOR=__LINECOLOR__ HEIGHT=65 VALIGN=top ROWSPAN=0 ALIGN=left>
+ <TD WIDTH=320 BGCOLOR=__LINECOLOR__ HEIGHT=65 VALIGN=top ALIGN=left>
<IMG SRC="__LOGO__" WIDTH=320 HEIGHT=65 BORDER=0>
</TD>
</TR>
</TR>
<TR VALIGN=top ALIGN=left>
- <TD WIDTH=620 COLSPAN=3 BGCOLOR=__LINECOLOR__ HEIGHT=1 VALIGN=top ROWSPAN=0 ALIGN=left><IMG SRC="clear.gif" WIDTH=1 HEIGHT=1 BORDER=0></TD>
+ <TD WIDTH=620 COLSPAN=3 BGCOLOR=__LINECOLOR__ HEIGHT=1 VALIGN=top ALIGN=left><IMG SRC="clear.gif" WIDTH=1 HEIGHT=1 BORDER=0></TD>
</TR>
</TABLE>
<TD WIDTH=150 VALIGN=top __HEADERBG__>
<TABLE WIDTH=150 VALIGN=TOP ALIGN=left CELLSPACING=0 BORDER=0 CELLPADDING=0>
<TR VALIGN=top ALIGN=left>
- <TD WIDTH=150 COLSPAN=0 BGCOLOR=__BARBG__ HEIGHT=13 VALIGN=top ROWSPAN=0 ALIGN=middle><FONT SIZE=1 FACE="Tahoma, Arial, Helvetica" COLOR=__BARTEXT__><B>Search for product</B></FONT>
+ <TD WIDTH=150 BGCOLOR=__BARBG__ HEIGHT=13 VALIGN=top ALIGN=middle><FONT SIZE=1 FACE="Tahoma, Arial, Helvetica" COLOR=__BARTEXT__><B>Search for product</B></FONT>
</TD>
</TR>
<TR>
- <TD WIDTH=150 COLSPAN=0 __HEADERBG__ HEIGHT=82 VALIGN=top ROWSPAN=0 ALIGN=left><FORM ACTION="[area search]"><IMG SRC="clear.gif" WIDTH=1 ALT="" HEIGHT=5 BORDER=0><BR>
+ <TD WIDTH=150 __HEADERBG__ HEIGHT=82 VALIGN=top ALIGN=left><FORM ACTION="[area search]"><IMG SRC="clear.gif" WIDTH=1 ALT="" HEIGHT=5 BORDER=0><BR>
<INPUT TYPE=hidden NAME=mv_coordinate VALUE=1>
<INPUT TYPE=hidden NAME=mv_search_field VALUE=category>
<INPUT TYPE=hidden NAME=mv_search_field VALUE=":artist,title,comment,display">
<TD WIDTH=320 VALIGN=top __HEADERBG__>
<TABLE WIDTH=320 VALIGN=TOP ALIGN=left CELLSPACING=0 BORDER=0 CELLPADDING=0>
<TR VALIGN=top ALIGN=left>
- <TD WIDTH=320 COLSPAN=0 BGCOLOR=__LINECOLOR__ HEIGHT=65 VALIGN=top ROWSPAN=0 ALIGN=left><IMG SRC="__LOGO__" WIDTH=320 ALT="" HEIGHT=65 BORDER=0></TD>
+ <TD WIDTH=320 BGCOLOR=__LINECOLOR__ HEIGHT=65 VALIGN=top ALIGN=left><IMG SRC="__LOGO__" WIDTH=320 ALT="" HEIGHT=65 BORDER=0></TD>
</TR>
<TR VALIGN=top ALIGN=left>
<TD WIDTH=320 BGCOLOR=__LINECOLOR__ HEIGHT=1 VALIGN=top ALIGN=left><IMG SRC="clear.gif" WIDTH=1 ALT="" HEIGHT=1 BORDER=0></TD>
</TR>
<TR VALIGN=top ALIGN=left>
- <TD WIDTH=620 COLSPAN=3 BGCOLOR=__LINECOLOR__ HEIGHT=1 VALIGN=top ROWSPAN=0 ALIGN=left><IMG SRC="clear.gif" WIDTH=1 ALT="" HEIGHT=1 BORDER=0></TD>
+ <TD WIDTH=620 COLSPAN=3 BGCOLOR=__LINECOLOR__ HEIGHT=1 VALIGN=top ALIGN=left><IMG SRC="clear.gif" WIDTH=1 ALT="" HEIGHT=1 BORDER=0></TD>
</TR>
</TABLE>
<TD VALIGN=top __HEADERBG__>
<TABLE WIDTH=320 VALIGN=TOP ALIGN=left CELLSPACING=0 BORDER=0 CELLPADDING=0>
<TR VALIGN=top ALIGN=left>
- <TD WIDTH=320 COLSPAN=0 BGCOLOR=__LINECOLOR__ HEIGHT=65 VALIGN=top ROWSPAN=0 ALIGN=left>
+ <TD WIDTH=320 BGCOLOR=__LINECOLOR__ HEIGHT=65 VALIGN=top ALIGN=left>
<IMG SRC="__LOGO__" WIDTH=320 HEIGHT=65 BORDER=0>
</TD>
</TR>
</TR>
<TR VALIGN=top ALIGN=left>
- <TD WIDTH=620 COLSPAN=3 BGCOLOR=__LINECOLOR__ HEIGHT=1 VALIGN=top ROWSPAN=0 ALIGN=left><IMG SRC="clear.gif" WIDTH=1 HEIGHT=1 BORDER=0></TD>
+ <TD WIDTH=620 COLSPAN=3 BGCOLOR=__LINECOLOR__ HEIGHT=1 VALIGN=top ALIGN=left><IMG SRC="clear.gif" WIDTH=1 HEIGHT=1 BORDER=0></TD>
</TR>
</TABLE>
<TD WIDTH=150 VALIGN=top BGCOLOR=#4F87CB>
<TABLE WIDTH=150 VALIGN=TOP ALIGN=left CELLSPACING=0 BORDER=0 CELLPADDING=0>
<TR VALIGN=top ALIGN=left>
- <TD WIDTH=150 COLSPAN=0 BGCOLOR=#FF6701 HEIGHT=13 VALIGN=top ROWSPAN=0 ALIGN=middle><FONT SIZE=1 FACE="Tahoma, Arial, Helvetica" COLOR=#FFFFFF><B>Search for product</B></FONT>
+ <TD WIDTH=150 BGCOLOR=#FF6701 HEIGHT=13 VALIGN=top ALIGN=middle><FONT SIZE=1 FACE="Tahoma, Arial, Helvetica" COLOR=#FFFFFF><B>Search for product</B></FONT>
</TD>
</TR>
<TR>
- <TD WIDTH=150 COLSPAN=0 BGCOLOR=#4F87CB HEIGHT=82 VALIGN=top ROWSPAN=0 ALIGN=left><FORM ACTION="http://__MVC_SERVERNAME____MVC_CGIURL__/search.html"><IMG SRC="__MVC_IMAGEURL__/clear.gif" WIDTH=1 ALT="" HEIGHT=5 BORDER=0><BR>
+ <TD WIDTH=150 BGCOLOR=#4F87CB HEIGHT=82 VALIGN=top ALIGN=left><FORM ACTION="http://__MVC_SERVERNAME____MVC_CGIURL__/search.html"><IMG SRC="__MVC_IMAGEURL__/clear.gif" WIDTH=1 ALT="" HEIGHT=5 BORDER=0><BR>
<INPUT TYPE=hidden NAME=mv_coordinate VALUE=1>
<INPUT TYPE=hidden NAME=mv_search_field VALUE=category>
<INPUT TYPE=hidden NAME=mv_search_field VALUE=":artist,title,comment,display">
<TD WIDTH=320 VALIGN=top BGCOLOR=#4F87CB>
<TABLE WIDTH=320 VALIGN=TOP ALIGN=left CELLSPACING=0 BORDER=0 CELLPADDING=0>
<TR VALIGN=top ALIGN=left>
- <TD WIDTH=320 COLSPAN=0 BGCOLOR=#000000 HEIGHT=65 VALIGN=top ROWSPAN=0 ALIGN=left><IMG SRC="__MVC_IMAGEURL__/blue1/logo.png" WIDTH=320 ALT="" HEIGHT=65 BORDER=0></TD>
+ <TD WIDTH=320 BGCOLOR=#000000 HEIGHT=65 VALIGN=top ALIGN=left><IMG SRC="__MVC_IMAGEURL__/blue1/logo.png" WIDTH=320 ALT="" HEIGHT=65 BORDER=0></TD>
</TR>
<TR VALIGN=top ALIGN=left>
<TD WIDTH=320 BGCOLOR=#000000 HEIGHT=1 VALIGN=top ALIGN=left><IMG SRC="__MVC_IMAGEURL__/clear.gif" WIDTH=1 ALT="" HEIGHT=1 BORDER=0></TD>
</TR>
<TR VALIGN=top ALIGN=left>
- <TD WIDTH=620 COLSPAN=3 BGCOLOR=#000000 HEIGHT=1 VALIGN=top ROWSPAN=0 ALIGN=left><IMG SRC="__MVC_IMAGEURL__/clear.gif" WIDTH=1 ALT="" HEIGHT=1 BORDER=0></TD>
+ <TD WIDTH=620 COLSPAN=3 BGCOLOR=#000000 HEIGHT=1 VALIGN=top ALIGN=left><IMG SRC="__MVC_IMAGEURL__/clear.gif" WIDTH=1 ALT="" HEIGHT=1 BORDER=0></TD>
</TR>
</TABLE>
</TR>
<TR ALIGN=LEFT>
<TD WIDTH=620 COLSPAN=2 BGCOLOR=MAROON HEIGHT=13 VALIGN=TOP ALIGN=CENTER>
-<FONT SIZE=1 FACE="Tahoma, Arial, Helvetica" COLOR=#FFFFFF><A HREF="__MVC_SERVERNAME____MVC_CGIURL__/index.html"><B><FONT SIZE=1 FACE="Tahoma, Arial, Helvetica" COLOR=#FFFFFF>Home</FONT></B></A>
- <A HREF="__MVC_SERVERNAME____MVC_CGIURL__/account.html"><B><FONT SIZE=1 FACE="Tahoma, Arial, Helvetica" COLOR=#FFFFFF>Profile</FONT></B></A>
- <A HREF="__MVC_SERVERNAME____MVC_CGIURL__/browse1.html"><B><FONT SIZE=1 FACE="Tahoma, Arial, Helvetica" COLOR=#FFFFFF>Products</FONT></B></A>
- <A HREF="__MVC_SERVERNAME____MVC_CGIURL__/feedback.html"><B><FONT SIZE=1 FACE="Tahoma, Arial, Helvetica" COLOR=#FFFFFF>Contact</FONT></B></A>
- <A HREF="__MVC_SERVERNAME____MVC_CGIURL__/new_account.html"><B><FONT SIZE=1 FACE="Tahoma, Arial, Helvetica" COLOR=#FFFFFF>Registration</FONT></B></A>
+<FONT SIZE=1 FACE="Tahoma, Arial, Helvetica" COLOR=#FFFFFF><A HREF="http://__MVC_SERVERNAME____MVC_CGIURL__/index.html"><B><FONT SIZE=1 FACE="Tahoma, Arial, Helvetica" COLOR=#FFFFFF>Home</FONT></B></A>
+ <A HREF="http://__MVC_SERVERNAME____MVC_CGIURL__/account.html"><B><FONT SIZE=1 FACE="Tahoma, Arial, Helvetica" COLOR=#FFFFFF>Profile</FONT></B></A>
+ <A HREF="http://__MVC_SERVERNAME____MVC_CGIURL__/browse1.html"><B><FONT SIZE=1 FACE="Tahoma, Arial, Helvetica" COLOR=#FFFFFF>Products</FONT></B></A>
+ <A HREF="http://__MVC_SERVERNAME____MVC_CGIURL__/feedback.html"><B><FONT SIZE=1 FACE="Tahoma, Arial, Helvetica" COLOR=#FFFFFF>Contact</FONT></B></A>
+ <A HREF="http://__MVC_SERVERNAME____MVC_CGIURL__/new_account.html"><B><FONT SIZE=1 FACE="Tahoma, Arial, Helvetica" COLOR=#FFFFFF>Registration</FONT></B></A>
</FONT></TD>
</TR>
<TR ALIGN=LEFT>
__MENUBAR__
__LEFTSIDE__
<H1>Trying to retrieve....</H1>
+[perl]
+ $CGI->{mv_todo} = 'search';
+ $Config->{NoSearch} = '';
+[/perl]
[update process]
[search-region]
[set get_id_matches][search-list][if-item-data userdb email][item-code][/if-item-data][/search-list][/set]
[/no-match]
[/search-region]
+[perl]
+ $Config->{NoSearch} = 'userdb';
+ return;
+[/perl]
+
[if value mv_search_match_count > 1]
<H2>That one generated more than one match. [page login]Try again[/page] with more info?</H2>
[elsif scratch get_id_matches]
</FORM>
<P>
-<FORM METHOD="POST" ACTION="[area get_password]">
+<FORM METHOD="POST" ACTION="[area action/get_password]">
<INPUT TYPE=hidden NAME=mv_coordinate VALUE=yes>
<INPUT TYPE=hidden NAME=mv_searchtype VALUE=db>
<INPUT TYPE=hidden NAME=mv_search_file VALUE=userdb>
#!/usr/bin/perl -wT
# tlink.pl: runs as a cgi program and passes request to Vend server
#
-# $Id: tlink.pl,v 1.1.1.1 2000/03/09 19:08:20 mike Exp $
+# $Id: tlink.pl,v 1.2 2000/04/16 00:18:27 mike Exp $
#
# Copyright 1996-1998 by Michael J. Heins <mikeh@minivend.com>
#
$SIG{PIPE} = sub { die_page("signal"); };
$SIG{ALRM} = sub { server_not_running(); exit 1; };
-alarm $LINK_TIMEOUT;
+eval { alarm $LINK_TIMEOUT; };
my ($remote, $port, $iaddr, $paddr, $proto, $line);
UserTag db-date PosNumber 2
UserTag db-date Routine <<EOF
sub {
- my ($format, $db) = @_;
+ my ($db, $format) = @_;
+ my ($dbfile, $mtime);
- $format = '%A %d %b %Y' unless $format;
+ # use defaults if necessary
$db = 'products' unless $db;
+ $format = '%A %d %b %Y' unless $format;
+
+ # build database file name
+ $dbfile = $Vend::Cfg->{ProductDir} . '/'
+ . $Vend::Cfg->{Database}{$db}{'file'};
- my $mtime = (stat($Vend::Cfg->{Database}{'db_file'}))[9];
- return POSIX::strftime($format, localtime($mtime));
+ # get last modified time
+ $mtime = (stat ($dbfile))[9];
+ if (defined ($mtime)) {
+ return POSIX::strftime($format, localtime($mtime));
+ } else {
+ logError ("Couldn't stat $dbfile: $!\n");
+ }
}
EOF
--- /dev/null
+#!/usr/bin/perl
+
+package mvhints;
+
+sub get_hints {
+ my @out;
+
+ my $condition;
+ my $routine;
+
+ $condition = sub { $^O =~ /bsd/i };
+ $routine = sub {
+ my $fn = 'minivend.cfg.dist';
+ rename $fn, "$fn.bak";
+ open HINTIN, "$fn.bak"
+ or die "cannot open $fn.bak: $!\n";
+ open HINTOUT, ">$fn"
+ or die "cannot write $fn: $!\n";
+ while(<HINTIN>) {
+ s/
+ ^\s*Housekeeping\s+\d+.*$
+ /# Changed for $^O, no safe signals\nHousekeeping 1/xi;
+ s/
+ ^\s*MaxServers\s+\d+.*$
+ /# Changed for $^O, no safe signals\nMaxServers 0/xi;
+ print HINTOUT $_;
+ }
+ close HINTIN;
+ close HINTOUT;
+ unlink "$fn.bak";
+ return 1;
+ };
+ push @out, [ $condition, $routine ];
+
+ return @out;
+}
+
+1;
# Config.pm - Configure Minivend
#
-# $Id: Config.pm,v 1.2 2000/03/28 05:04:45 mike Exp $
+# $Id: Config.pm,v 1.4 2000/04/12 15:07:04 mike Exp $
#
# Copyright 1996-2000 by Michael J. Heins <mikeh@minivend.com>
#
};
}
-$VERSION = substr(q$Revision: 1.2 $, 10);
+$VERSION = substr(q$Revision: 1.4 $, 10);
for( qw(search refresh cancel return secure unsecure submit control checkout) ) {
$Global::LegalAction{$_} = 1;
PriceCommas
PriceDivide
PriceField
+ PriceDefault
SalesTax
TaxShipping
@Locale_directives_scalar = (
qw/
Autoload
+ AutoEnd
CommonAdjust
DescriptionField
ImageDir
PriceDivide
PriceCommas
PriceField
+ PriceDefault
SalesTax
StaticPath
HTMLsuffix
['DumpStructure', 'yesno', 'No'],
['DisplayErrors', 'yesno', 'No'],
['TcpPort', 'warn', ''],
- ['TcpMap', 'hash', '7786 mv_admin 7787 "" 7788 "" 7789 ""'],
+ ['TcpMap', 'hash', ''],
['Environment', 'array', ''],
['TcpHost', undef, 'localhost 127.0.0.1'],
['SendMailProgram', 'executable', $Global::SendMailLocation
['SessionLockFile', undef, 'etc/session.lock'],
['Database', 'database', ''],
['Autoload', undef, ''],
+ ['AutoEnd', undef, ''],
['Replace', 'replace', ''],
['Member', 'variable', ''],
['WritePermission', 'permission', 'user'],
['OnFly', undef, ''],
['HTMLmirror', 'yesno', 'No'],
['DescriptionField', undef, 'description'],
+ ['PriceDefault', undef, 'price'],
['PriceField', undef, 'price'],
['Shipping', 'locale', ''],
sub parse_hash {
my($item,$settings) = @_;
return {} if ! $settings;
+ $settings =~ s/^\s+//;
+ $settings =~ s/\s+$//;
my(@setting) = Text::ParseWords::shellwords($settings);
my $c;
my $i;
for ($i = 0; $i < @setting; $i += 2) {
$c->{$setting[$i]} = $setting[$i + 1];
+#::logDebug("$item hash $setting[$i]=$setting[$i+1]");
}
$c;
}
);
+my $Have_set_global_defaults;
my %Default = (
+ TcpMap => sub {
+ shift;
+ return 1 if defined $Have_set_global_defaults;
+ $Have_set_global_defaults = 1;
+ my (@sets) = keys %{$Global::TcpMap};
+ return 1 if @sets;
+ $Global::TcpMap->{7786} = '-';
+ return 1;
+ },
ProductFiles => sub {
shift;
# Data.pm - Minivend databases
#
-# $Id: Data.pm,v 1.1.1.1 2000/03/09 19:08:20 mike Exp $
+# $Id: Data.pm,v 1.2 2000/04/02 10:20:34 mike Exp $
#
# Copyright 1996-2000 by Michael J. Heins <mikeh@minivend.com>
#
$price = $item->{mv_price} || $mod;
redo CHAIN;
}
- elsif($mod =~ /^(\w*):([^:]+)(:(\S*))?$/) {
+ elsif($mod =~ /^(\w*):([^:]*)(:(\S*))?$/) {
my ($table,$field,$key) = ($1, $2, $4);
+ $field = $Vend::Cfg->{PriceDefault} if ! $field;
if($passed_key) {
(! $key and $key = $passed_key)
or
# Error.pm - Handle MiniVend error pages and messages
#
-# $Id: Error.pm,v 1.1.1.1 2000/03/09 19:08:21 mike Exp $
+# $Id: Error.pm,v 1.2 2000/04/02 10:20:34 mike Exp $
#
# Copyright 1996-2000 by Michael J. Heins <mikeh@minivend.com>
#
use vars qw/$VERSION/;
-$VERSION = sprintf("%d.%02d", q$Revision: 1.1.1.1 $ =~ /(\d+)\.(\d+)/);
+$VERSION = sprintf("%d.%02d", q$Revision: 1.2 $ =~ /(\d+)\.(\d+)/);
my $wantref = 1;
$out .= "$_: $Vend::Session->{$_}\n";
}
- for(keys %$::Carts) {
- $out .= scalar @{$::Carts->{$_}};
+ for(keys %{$Vend::Session->{carts}} ) {
+ next if ! $Vend::Session->{carts}->{$_};
+ $out .= scalar @{$Vend::Session->{carts}->{$_}};
$out .= " items in $_ cart.\n";
}
return $out;
#!/usr/bin/perl
# Interpolate.pm - Interpret MiniVend tags
#
-# $Id: Interpolate.pm,v 1.5 2000/03/25 07:16:49 mike Exp $
+# $Id: Interpolate.pm,v 1.10 2000/04/16 00:18:43 mike Exp $
#
# Copyright 1996-2000 by Michael J. Heins <mikeh@minivend.com>
#
require Exporter;
@ISA = qw(Exporter);
-$VERSION = substr(q$Revision: 1.5 $, 10);
+$VERSION = substr(q$Revision: 1.10 $, 10);
@EXPORT = qw (
}
$out .= "$anchor</A>";
},
+ 'tt' => sub { return '<TT>' . shift(@_) . '</TT>'; },
+ 'pre' => sub { return '<PRE>' . shift(@_) . '</PRE>'; },
'bold' => sub { return '<B>' . shift(@_) . '</B>'; },
'italics' => sub { return '<I>' . shift(@_) . '</I>'; },
'strikeout' => sub { return '<strike>' . shift(@_) . '</strike>'; },
$value =~ s/"/"/g;
$value eq '' and $default eq '' and $select = "CHECKED";
- $default =~ /\b\Q$value\E\b/ and $select = "CHECKED" if length($value);
+
+ if(length $value) {
+ my $regex = $opt->{contains}
+ ? qr/\Q$value\E/
+ : qr/\b\Q$value\E\b/;
+ $default =~ $regex and $select = "CHECKED";
+ }
$label =~ s/ / /g if $xlt;
if "\L$type" eq 'hidden';
return qq|<INPUT TYPE="hidden" NAME="$name" VALUE="$attrib_value">$attrib_value|
if $type =~ /hidden/;
- return qq|<TEXTAREA NAME="$name" ROWS=$1 COLS=$2>$attrib_value</TEXTAREA>|
- if "\L$type" =~ /^textarea_(\d+)_(\d+)$/;
- return qq|<INPUT TYPE=text NAME="$name" SIZE=$1 VALUE="$attrib_value">|
- if "\L$type" =~ /^text_(\d+)$/;
+ if($type =~ /^text/i) {
+ HTML::Entities::encode($attrib_value);
+ return qq|<TEXTAREA NAME="$name" ROWS=$1 COLS=$2>$attrib_value</TEXTAREA>|
+ if "\L$type" =~ /^textarea_(\d+)_(\d+)$/;
+ return qq|<INPUT TYPE=text NAME="$name" SIZE=$1 VALUE="$attrib_value">|
+ if "\L$type" =~ /^text_(\d+)$/;
+ }
my ($default, $label, $select, $value, $run);
my @opts = split /\s*,\s*/, $data;
$ready_safe->share(@share) if @share;
$MVSAFE::Safe = 1;
- if($opt->{global} and $Global::AllowGlobal->{$Vend::Cfg->{CatalogName}}) {
+ if (
+ $opt->{global}
+ and
+ $Global::AllowGlobal->{$Vend::Cfg->{CatalogName}}
+ )
+ {
$MVSAFE::Safe = 0 unless $MVSAFE::Unsafe;
}
my (@Flds);
my %Sort = (
- '' => sub { $a cmp $b },
- none => sub { $a cmp $b },
- f => sub { (lc $a) cmp (lc $b) },
- fr => sub { (lc $b) cmp (lc $a) },
+ '' => sub { $_[0] cmp $_[1] },
+ none => sub { $_[0] cmp $_[1] },
+ f => sub { (lc $_[0]) cmp (lc $_[1]) },
+ fr => sub { (lc $_[1]) cmp (lc $_[0]) },
l => sub {
- my ($a1,$a2) = split /[,.]/, $a, 2;
- my ($b1,$b2) = split /[,.]/, $b, 2;
+ my ($a1,$a2) = split /[,.]/, $_[0], 2;
+ my ($b1,$b2) = split /[,.]/, $_[1], 2;
return $a1 <=> $b1 || $a2 <=> $b2;
},
lr => sub {
- my ($a1,$a2) = split /[,.]/, $a, 2;
- my ($b1,$b2) = split /[,.]/, $b, 2;
+ my ($a1,$a2) = split /[,.]/, $_[0], 2;
+ my ($b1,$b2) = split /[,.]/, $_[1], 2;
return $b1 <=> $a1 || $b2 <=> $a2;
},
- n => sub { $a <=> $b },
- nr => sub { $b <=> $a },
- r => sub { $b cmp $a },
+ n => sub { $_[0] <=> $_[1] },
+ nr => sub { $_[1] <=> $_[0] },
+ r => sub { $_[1] cmp $_[0] },
);
@Sort{qw/rf rl rn/} = @Sort{qw/fr lr nr/};
use vars qw/%Sort_field/;
%Sort_field = %Sort;
-sub field_sort {
- my(@a) = split /\t/, $a;
- my(@b) = split /\t/, $b;
- my ($r, $i);
- for($i = 0; $i < @Flds; $i++) {
- $r = &{$Vend::Interpolate::Sort_field{$Opts[$i]}}($a[$Flds[$i]], $b[$Flds[$i]]);
- return $r if $r;
- }
-}
-
sub tag_sort_ary {
my($opts, $list) = (@_);
$opts =~ s/^\s+//;
my $key = 0;
my ($start, $end, $num);
+ my $glob_opt = 'none';
my @opts = split /\s+/, $opts;
my @option; my @bases; my @fields;
for(@opts) {
my ($base, $fld, $opt) = split /:/, $_;
- if($base =~ /^([-\d]\d*)$/) {
+ if($base =~ /^(\d+)$/) {
$key = $1;
+ $glob_opt = $fld || $opt || 'none';
next;
}
if($base =~ /^([-=+])(\d+)-?(\d*)/) {
$routine .= '&{$Vend::Interpolate::Sort_field{"' .
$option[$i] .
'"}}(' . "\n";
- $routine .= "tag_data('$bases[$i]','$fields[$i]', \$a->[$key]),\n";
- $routine .= "tag_data('$bases[$i]','$fields[$i]', \$b->[$key]) ) or ";
+ $routine .= "tag_data('$bases[$i]','$fields[$i]', \$_[0]->[$key]),\n";
+ $routine .= "tag_data('$bases[$i]','$fields[$i]', \$_[1]->[$key]) ) or ";
}
- $routine .= '0 or &{$Vend::Interpolate::Sort_field{none}}';
- $routine .= '($a->[$key],$b->[$key]); }';
+ $routine .= qq!0 or &{\$Vend::Interpolate::Sort_field{"$glob_opt"}}!;
+ $routine .= '($_[0]->[$key],$_[1]->[$key]); }';
#::logDebug("tag_sort_ary routine: $routine\n");
my $code = eval $routine;
die "Bad sort routine\n" if $@;
#Prime the sort? Prevent variable suicide??
- &{$Vend::Interpolate::Sort_field{'n'}}('31', '30');
+ #&{$Vend::Interpolate::Sort_field{'n'}}('31', '30');
use locale;
if($::Scratch->{mv_locale}) {
$::Scratch->{mv_locale});
}
- @codes = sort {&$code} @$list;
+ @codes = sort {&$code($a, $b)} @$list;
if(defined $start and $start > 1) {
splice(@codes, 0, $start - 1);
my $key = 'code';
my ($start, $end, $num);
+ my $glob_opt = 'none';
my @opts = split /\s+/, $opts;
my @option; my @bases; my @fields;
for(@opts) {
- if(/^(\w+)$/) {
+ if(/^(\w+)(:([flnr]+))?$/) {
$key = $1;
+ $glob_opt = $3 || 'none';
next;
}
if(/^([-=+])(\d+)-?(\d*)/) {
$routine .= '&{$Vend::Interpolate::Sort_field{"' .
$option[$i] .
'"}}(' . "\n";
- $routine .= "tag_data('$bases[$i]','$fields[$i]', \$a->{$key}),\n";
- $routine .= "tag_data('$bases[$i]','$fields[$i]', \$b->{$key}) ) or ";
+ $routine .= "tag_data('$bases[$i]','$fields[$i]', \$_[0]->{$key}),\n";
+ $routine .= "tag_data('$bases[$i]','$fields[$i]', \$_[1]->{$key}) ) or ";
}
- $routine .= '0 or &{$Vend::Interpolate::Sort_field{none}}';
- $routine .= '($a->{$key},$b->{$key}); }';
+ $routine .= qq!0 or &{\$Vend::Interpolate::Sort_field{"$glob_opt"}}!;
+ $routine .= '($a->{$key},$_[1]->{$key}); }';
#::logDebug("tag_sort_hash routine: $routine\n");
my $code = eval $routine;
die "Bad sort routine\n" if $@;
#Prime the sort? Prevent variable suicide??
- &{$Vend::Interpolate::Sort_field{'n'}}('31', '30');
+ #&{$Vend::Interpolate::Sort_field{'n'}}('31', '30');
use locale;
if($::Scratch->{mv_locale}) {
$::Scratch->{mv_locale});
}
- @codes = sort {&$code} @$list;
+ @codes = sort {&$code($a,$b)} @$list;
if(defined $start and $start > 1) {
splice(@codes, 0, $start - 1);
return \@codes;
}
-sub tag_sort_text {
- my($opts, $list, $joiner) = (@_);
- my $hash;
- my $key;
- $opts =~ s/^\s+//;
- $opts =~ s/\s+$//;
-#::logDebug("tag_sort_text: opts=$opts list:\n$list");
- my @codes;
- $list =~ s/^\s+//;
- $list =~ s/\s+$//;
- if(defined $joiner) {
- @codes = split $joiner, $list;
- }
- else {
- @codes = split /\s+/, $list;
- }
- $joiner = " " unless defined $joiner;
-
- my ($start, $end, $num);
-
- my @opts = split /\s+/, $opts;
- my @option; my @bases; my @fields;
-
- for(@opts) {
- my ($base, $fld, $opt) = split /:/, $_;
-
- if($base =~ /^(\w+)$/) {
- $key = $1;
- next;
- }
- if($base =~ /^([-=+])(\d+)-?(\d*)/) {
- my $op = $1;
- if ($op eq '-') { $start = $2 }
- elsif ($op eq '+') { $num = $2 }
- elsif ($op eq '=') {
- $start = $2;
- $end = ($3 || undef);
- }
- next;
- }
-
- push @bases, $base;
- push @fields, $fld;
- push @option, (defined $Vend::Interpolate::Sort_field{$opt} ? $opt : 'none');
- }
-
- if(defined $end) {
- $num = 1 + $end - $start;
- $num = undef if $num < 1;
- }
-
- my $i;
- my $routine = 'sub { ';
- for( $i = 0; $i < @bases; $i++) {
- $routine .= '&{$Vend::Interpolate::Sort_field{"' . $option[$i] . '"}}(' . "\n";
- $routine .= "tag_data('$bases[$i]','$fields[$i]'," . '$a),' . "\n";
- $routine .= "tag_data('$bases[$i]','$fields[$i]'," . '$b) ) or ';
- }
- $routine .= '0 or &{$Vend::Interpolate::Sort_field{none}}($a,$b); }';
- my $code = eval $routine;
- die "Bad sort routine\n" if $@;
-
- #Prime the sort? Prevent variable suicide??
- &{$Vend::Interpolate::Sort_field{'n'}}('31', '30');
-
- use locale;
- if($::Scratch->{mv_locale}) {
- POSIX::setlocale(POSIX::LC_COLLATE(),
- $::Scratch->{mv_locale});
- }
-
- @codes = sort {&$code} @codes;
-
- if(defined $start and $start > 1) {
- splice(@codes, 0, $start - 1);
- }
-
- if(defined $num) {
- splice(@codes, $num);
- }
-#::logDebug("sort routine returns: " . ::uneval(\@codes));
- return join $joiner, @codes;
-}
-
my %Prev;
sub check_change {
push @codes, $code;
}
- $sort_order = tag_sort($options, \@codes);
+ $sort_order = tag_sort_hash($options, \@codes);
foreach $code (@$sort_order) {
push @out, @{$order{$code}};
if $o->{qual};
}
elsif($lines[0][CRIT] =~ /[[\s]|__/) {
- ($field, $qual) = split /\s+/, interpolate_html($field), 2;
+ ($field, $qual) = split /\s+/, interpolate_html($lines[0][CRIT]), 2;
if($qual =~ /{}/) {
logError("Bad qualification code '%s', returning 0", $qual);
goto SHIPFORMAT;
# Static.pm - MiniVend static page routines
#
-# $Id: Static.pm,v 1.1.1.1 2000/03/09 19:08:21 mike Exp $
+# $Id: Static.pm,v 1.2 2000/04/02 10:20:56 mike Exp $
#
# Copyright 1996-2000 by Michael J. Heins <mikeh@minivend.com>
#
my $c = { mv_search_immediate => 1 };
find_search_params($c,$path);
return undef if $c->{mv_more_matches};
- return ::perform_search($c);
+ ::perform_search($c);
+ $page = readin($CGI::values{mv_nextpage} || ::find_special_page('results'));
+ return ::interpolate_html($page, 1);
}
# STATICPAGE
$Vend::Cfg->{StaticPage}{"scan/$search"}
=~ s/$Vend::Cfg->{StaticSuffix}$//o;
push @post, $Vend::Found_scan{$search};
- Vend::Util::writefile(">$dir/$file", $newpage)
+ Vend::Util::writefile(">$dir/$file", $$newpage)
or die "Couldn't write $dir/$file: $!\n";
if($Vend::ScanName) {
eval {
#
# MiniVend version 4.0
#
-# $Id: Order.pm,v 1.3 2000/03/25 07:16:49 mike Exp $
+# $Id: Order.pm,v 1.4 2000/04/12 15:07:04 mike Exp $
#
# Copyright 1996-2000 by Michael J. Heins <mikeh@minivend.com>
#
package Vend::Order;
require Exporter;
-$VERSION = substr(q$Revision: 1.3 $, 10);
+$VERSION = substr(q$Revision: 1.4 $, 10);
@ISA = qw(Exporter);
$j = 0;
my $set;
foreach $code (@items) {
-
+ undef $item;
$quantity = defined $quantities[$j] ? $quantities[$j] : 1;
($j++,next) unless $quantity;
$set = $quantity =~ s/^=//;
# Server.pm: listen for cgi requests as a background server
#
-# $Id: Server.pm,v 1.2 2000/03/28 04:27:22 mike Exp $
+# $Id: Server.pm,v 1.3 2000/04/02 10:20:34 mike Exp $
#
# Copyright 1996-2000 by Michael J. Heins <mikeh@minivend.com>
#
package Vend::Server;
use vars qw($VERSION);
-$VERSION = substr(q$Revision: 1.2 $, 10);
+$VERSION = substr(q$Revision: 1.3 $, 10);
use POSIX qw(setsid strftime);
use Vend::Util;
foreach $port (keys %{$Global::TcpMap}) {
my $fh = gensym();
-#::logDebug("Trying to run server on $port, fh created: $fh");
-
+ my $bind_addr;
+ my $bind_ip;
+#::logDebug("starting to parse port $port, fh created: $fh");
+ if ($port =~ s/^([-\w.]+):(\d+)$/$2/) {
+ $bind_ip = $1;
+ $bind_addr = inet_aton($bind_ip);
+ }
+ else {
+ $bind_ip = '0.0.0.0';
+ $bind_addr = INADDR_ANY;
+ }
+#::logDebug("Trying to run server on ip=$bind_ip port=$port");
+ if(! $bind_addr) {
+ ::logGlobal({},
+ "Could not bind to IP address %s on port %s: %s",
+ $bind_ip,
+ $port,
+ $!,
+ );
+ next;
+ }
eval {
socket($fh, PF_INET, SOCK_STREAM, $proto)
|| die "socket: $!";
setsockopt($fh, SOL_SOCKET, SO_REUSEADDR, pack("l", 1))
|| die "setsockopt: $!";
- bind($fh, sockaddr_in($port, INADDR_ANY))
+ bind($fh, sockaddr_in($port, $bind_addr))
|| die "bind: $!";
listen($fh,$so_max)
|| die "listen: $!";
$rin = '';
vec($rin, fileno($fh), 1) = 1;
$vector |= $rin;
- $vec_map{$port} = fileno($fh);
- $fh_map{$port} = $fh;
+ $vec_map{"$bind_ip:$port"} = fileno($fh);
+ $fh_map{"$bind_ip:$port"} = $fh;
}
else {
::logGlobal({},
# Session.pm - Minivend Sessions
#
-# $Id: Session.pm,v 1.1.1.1 2000/03/09 19:08:20 mike Exp $
+# $Id: Session.pm,v 1.3 2000/04/12 15:07:04 mike Exp $
#
# Copyright 1996-2000 by Michael J. Heins <mikeh@minivend.com>
#
require Exporter;
use vars qw($VERSION);
-$VERSION = substr(q$Revision: 1.1.1.1 $, 10);
+$VERSION = substr(q$Revision: 1.3 $, 10);
@ISA = qw(Exporter);
my($s);
#::logDebug ("read session id=$Vend::SessionID name=$Vend::SessionName\n");
- $s = $Vend::SessionDBM{$Vend::SessionName};
+ $s = $Vend::SessionDBM{$Vend::SessionName}
+ or $Global::Variable->{MV_SESSION_READ_RETRY}
+ and do {
+ my $i = 0;
+ my $tries = $Global::Variable->{MV_SESSION_READ_RETRY} + 0 || 5;
+ while($i++ < $tries) {
+ ::logDebug("retrying session read on undef, try $i");
+ $s = $Vend::SessionDBM{$Vend::SessionName};
+ next unless $s;
+ ::logDebug("Session re-read successfully on try $i");
+ last;
+ }
+ };
+
#::logDebug ("Session:\n$s\n");
return new_session() unless $s;
$Vend::Session = ref $s ? $s : evalr($s);
# SessionFile.pm: stores session information in files
#
-# $Id: SessionFile.pm,v 1.2 2000/03/28 04:27:22 mike Exp $
+# $Id: SessionFile.pm,v 1.3 2000/04/02 10:20:34 mike Exp $
#
# Copyright 1996-2000 by Michael J. Heins <mikeh@minivend.com>
#
# MA 02111-1307 USA.
-# $Id: SessionFile.pm,v 1.2 2000/03/28 04:27:22 mike Exp $
+# $Id: SessionFile.pm,v 1.3 2000/04/02 10:20:34 mike Exp $
package Vend::SessionFile;
require Tie::Hash;
@ISA = qw(Tie::Hash);
+use Symbol;
use strict;
use Vend::Util;
use vars qw($VERSION);
-$VERSION = substr(q$Revision: 1.2 $, 10);
+$VERSION = substr(q$Revision: 1.3 $, 10);
my $SessionDir;
my $SessionFile;
my $SessionLock;
my %HaveLock;
+my $Lh;
+my $Fh;
my $Last;
my @Each;
return undef unless -f $SessionFile;
my $str;
unless ($HaveLock{$SessionFile} || $Global::Windows) {
- open(SESSIONLOCK, "+>>$SessionLock")
+ $Lh = gensym();
+ open($Lh, "+>>$SessionLock")
or die "Can't open '$SessionLock': $!\n";
- lockfile(\*SESSIONLOCK, 1, 1)
+ lockfile($Lh, 1, 1)
and $HaveLock{$SessionFile} = 1;
}
my $ref = Vend::Util::eval_file($SessionFile);
$SessionLock = $SessionFile . ".lock";
unlink $SessionFile;
unless ($HaveLock{$SessionFile} || $Global::Windows) {
- open(SESSIONLOCK, "+>>$SessionLock")
+ $Lh = gensym();
+ open($Lh, "+>>$SessionLock")
or die "Can't open '$SessionLock': $!\n";
- lockfile(\*SESSIONLOCK, 1, 1)
+ lockfile($Lh, 1, 1)
and $HaveLock{$SessionFile} = 1;
}
#::logDebug("storing in $SessionFile: " . ::uneval($ref));
sub DESTROY {
my($self) = @_;
- close(SESSION);
- unlockfile(\*SESSIONLOCK);
- close(SESSIONLOCK);
+ unlockfile($Lh)
+ and delete $HaveLock{$SessionFile};
+ close($Lh);
undef $self;
}
#!/usr/bin/perl
#
-# $Id: UserDB.pm,v 1.2 2000/03/18 16:04:49 mike Exp $
+# $Id: UserDB.pm,v 1.3 2000/04/12 15:07:04 mike Exp $
#
# Copyright 1996-2000 by Michael J. Heins <mikeh@minivend.com>
#
package Vend::UserDB;
-$VERSION = substr(q$Revision: 1.2 $, 10);
+$VERSION = substr(q$Revision: 1.3 $, 10);
use vars qw! $VERSION @S_FIELDS @B_FIELDS @P_FIELDS %S_to_B %B_to_S!;
}
$status = $user->set_values();
}
+ elsif($function eq 'load') {
+ $user = new Vend::UserDB %options;
+ unless (defined $user) {
+ $Vend::Session->{failure} = "Unable to access user database.";
+ return undef;
+ }
+ $status = $user->get_values();
+ }
else {
$user = new Vend::UserDB %options;
unless (defined $user) {
# Util.pm - Minivend utility functions
#
-# $Id: Util.pm,v 1.2 2000/03/18 16:04:49 mike Exp $
+# $Id: Util.pm,v 1.4 2000/04/12 15:07:04 mike Exp $
#
# Copyright 1996-2000 by Michael J. Heins <mikeh@minivend.com>
#
use Fcntl;
use subs qw(logError logGlobal);
use vars qw($VERSION @EXPORT @EXPORT_OK);
-$VERSION = substr(q$Revision: 1.2 $, 10);
+$VERSION = substr(q$Revision: 1.4 $, 10);
BEGIN {
eval {
unless $::Scratch->{mv_no_count};
$r .= '/' . $path;
- $r .= '.html' if $::Scratch->{mv_add_dot_html};
+ $r .= '.html' if $::Scratch->{mv_add_dot_html} and $r !~ /\.html?/;
push @parms, "$::VN->{mv_session_id}=$id" if defined $id;
push @parms, "$::VN->{mv_arg}=" . hexify($arguments) if defined $arguments;
push @parms, "$::VN->{mv_pc}=$ct" if defined $ct;
$name =~ s/\.cfg$//;
$name .= '.structure';
open(UNEV, ">$name") or die "Couldn't write structure $name: $!\n";
- if(defined $Data::Dumper::Indent) {
- $save = $Data::Dumper::Indent;
- $Data::Dumper::Indent = 2;
- }
+ local($Data::Dumper::Indent);
+ $Data::Dumper::Indent = 2;
print UNEV uneval($ref);
close UNEV;
- $Data::Dumper::Indent = $save if defined $save;
}
# Do an internal HTTP authorization check
[/else]
[/if]
+If you want to use another tag to select the key, and it is not
+a looping tag construct, you must use named parameters:
+
+ [set code]99-102[/set]
+ [if type=data term="products::size::[scratch code]"]
+ There is size information.
+ [else]
+ No size information.
+ [/else]
+ [/if]
+
=item discount
Checks to see if a discount is present for an item.
databases. The value placed by the C<[item-code]> tag is set to
the first field returned from the search.
+The basic structure looks like this:
+
+[search-region]
+[search-list]
+ your iterating code, once for each match
+[/search-list]
+[no-match]
+ Text / tags to be output if no matches found (optional but recommended)
+[/no-match]
+[more-list]
+ More / paging area (optional)
+[/more-list]
+[/search-region]
+
+TIP FOR MV3 PORTS: A C<[search-list][/search-list]> must always be surrounded by a
+C<[search-region][/search-region]> pair. This is a change from Minivend 3.
+
=over 4
=item [search-list]
list of items with part number, description, price, and hyperlinks to
order or go to its catalog page.
-The set of tags for C<[item-list]> are available, with the exception
-of tags like C<[item-modifier]>, C<[modifier-name]>, C<[item-accessories]>,
-and others that access shopping-cart specific elements. Thse include:
-
- [if-item-data table column] [/if-item-data]
- [if-item-field column] [/if-item-field]
- [item-code]
- [item-data table column]
- [item-discount]
- [item-field column]
- [item-price quantity* noformat*]
-
-In fact, any of the MiniVend database access tags can be used,
-allowing you to pull data from any of the fields in any of
-your predefined databases. Along with the MiniVend conditional
-tags, very complex pages can be built for each individual item
-returned in the search.
+The example tags shown have an C<item-> prefix, which is the
+default. You can set any prefix you want with the C<prefix> parameter
+to C<[search-region]>:
+
+ [search-region prefix=my]
+ [search-list]
+ SKU: [my-code]
+ Title: [my-data products title]
+ [/search-list]
+ [/search-region]
+
+The standard set of Minivend iterative MML tags are available. They are
+interpolated in this order:
+
+ [item-alternate N] true [else] false [/else] [/item-alternate]
+ [if-item-param named_field] true [else] false [/else] [/if-item-param]
+ [item-param named_field]
+ [if-item-pos N] true [else] false [/else] [/if-item-pos]
+ [item-pos N]
+ [if-item-field products_field] true [else] false [/else] [/if-item-field]
+ [item-field products_column]
+ [item-increment]
+ [item-accessories]
+ [item-code]
+ [item-description]
+ [if-item-data table column] true [else] false [/else] [/if-item-data]
+ [item-data table column]
+ [item-price N* noformat=1*]
+ [item-calc] [/item-calc]
+ [item-change marker]
+ [condition]variable text[/condition]
+ true
+ [else] false [/else]
+ [/item-change marker]
+ [item-last] condition [/item-last]
+ [item-next] condition [/item-next]
+
+NOTE: those that reference the shopping cart do not apply, i.e. [item-quantity],
+[item-modifier ...] and friends.
=item [/search-list]
options are supplied, sorts according to the return code. See
I<SORTING>.
-=item [sort]<options>[/sort]
-
-(This form of sort is deprecated, as it is difficult to use.
-Use the above method.)
-
-Placed inside the search list. Causes sorting of the search return
-based on the passed options. The fields that are there
-to sort are set by C<mv_return_fields>.
-
-The field options passed in either numeric or field name form. If
-they are field numbers, they are numbered as sent to the search list
-in the order specified by F<mv_return_fields>,
-starting from 0 and proceeding upwards. If column names, they are
-as found in the first record of the searched file (by default the
-ASCII source for the product database), F<except for the key or first field>.
-followed by a F<required> colon (:) and the options, if any.
-
-Accepts none, any, or combinations of the flags:
-
- f case-insensitive sort (folded) (mutually exclusive of n)
- n numeric order (mutually exclusive of f)
- r reverse sort
-
-The <options> are a field number and an optional flag or flags, in a
-similar fashion to the Unix sort command, and are interpolated for form
-values before being used. As an example, if you set up the following
-fields on your search form:
-
- <INPUT TYPE="hidden" NAME="mv_return_fields" VALUE="0,title,artist,price">
- <INPUT TYPE="radio" NAME="the_sort_field" VALUE="title"> Sort by Title
- <INPUT TYPE="radio" NAME="the_sort_field" VALUE="artist"> Sort by Artist
- <INPUT TYPE="radio" NAME="the_sort_option" VALUE=""> Forward sort
- <INPUT TYPE="radio" NAME="the_sort_option" VALUE="r"> Reverse sort
-
- NOTE: The 0 refers to the database code/key used for [item-code]
-
-This would combine with the following search result page fragment
-to sort by either title or artist.
-
- [search-list]
- [sort]
- [value the_sort_field]:[value the_sort_option]
- [/sort]
- <B>[item-field title]</B>, by [item-field artist]<BR>
- [/search-list]
-
-The [value...] lines will end up looking like C<artist:r> or C<title:>. This
-could also be specified with C<2r> or C<1>.
-
-PERFORMANCE TIP: on heavily trafficked systems, it will pay to use only
-column numbers rather than named fields, as it reduces processing and may
-obviate an access to the searched file to find the field names.
+This is slow, and it is far better to pre-sort your return in the
+search specification.
=item [item-change marker]
should be put around images in the C<page_img> selection. The <border_selected>
is used for the current page if set.
-As an example, if you use C<[more-list next.gif prev.gif page_num.cgi]>, the
-following will be the anchors:
+Examples:
+
+C<[more-list next.gif prev.gif page_num.cgi 3]> causes anchors of:
+
+ Previous <IMG SRC="prev.gif" Border=3>
+ Page 1 <IMG SRC="/cgi-bin/page_num.cgi?1">
+ Page 2 <IMG SRC="/cgi-bin/page_num.cgi?2">
+ Next <IMG SRC="next.gif" Border=3>
+
+C<[more-list next.gif prev.gif page_num.cgi]> causes anchors of:
+
+ Previous <IMG SRC="prev.gif">
+ Page 1 <IMG SRC="/cgi-bin/page_num.cgi?1">
+ Page 2 <IMG SRC="/cgi-bin/page_num.cgi?2">
+ Next <IMG SRC="next.gif">
- Previous <IMG SRC="prev.gif">
- Page 1 <IMG SRC="/cgi-bin/page_num.cgi?1">
- Page 2 <IMG SRC="/cgi-bin/page_num.cgi?2">
- Next <IMG SRC="next.gif">
+C<[more-list next.gif prev.gif 0 0]> causes anchors of:
+
+
+ Previous <IMG SRC="prev.gif" Border=0>
+ Page 1 <IMG SRC="/cgi-bin/page_num.cgi?1">
+ Page 2 <IMG SRC="/cgi-bin/page_num.cgi?2">
+ Next <IMG SRC="next.gif" Border=0>
If you wish to set custom text for the "Previous" and "Next" usually
used, then you can define the next_img, prev_img, and page_img with
=back
-=head2 Updating session variables after a search
-
-You may notice that if you set a scratch variable or reference a
-variable set in a search routine on the results page, the change does
-not stay in the user session.
-
-To change this, set the B<scratch> variable C<mv_put_session> on the page
-in question:
-
- [set mv_put_session]Yes[/set]
-
-This setting is persistent, so it is recommended that you
-do it once at the beginning of the user session if you wish it to be the
-default. If you don't want it to be the default, reset it to the
-empty value (or zero) on another page:
-
- [set mv_put_session][/set]
-
-=head2 Using a Search Cache
-
-Each catalog may maintain a search cache, which is enabled by specifying
-C<Yes> for the I<SearchCache> directive in F<catalog.cfg>. It operates
-by developing a MD5 key or 3-byte checksum of the combined parameters
-of a search.
-
-If your catalog frequently specifies category searches in a
-large catalog, speed of search return can be increased by a
-large factor, mostly by obviating the need for database lookups.
-
-If you have mostly dynamic session-based content based on user
-variables, you should not use SearchCache unless you want
-to give that up. MiniVend will not cache pages with dynamic
-content, and using cache slows down searches that don't cache.
-
-If you have the MD5 module installed on Perl, it will be used to generate
-the cache keys. This will guarantee a unique cache ID. If you don't
-have MD5 installed, a 32-bit checksum will be used to create the cache
-key. It is conceivable, indeed likely in a large catalog, that two
-separate searches could generate the same 32-bit checksum and return
-the same cached search.
-
-The search cache is invalidated when a user hits "RELOAD". It
-can also be invalidated by a C<[set mv_no_cache]1[/set]> scratch setting,
-which only takes effect for the next page.
-
-If you change your product database or any other files you search, you
-should reconfigure or the search returns may be wrong. You also may just
-remove all files in the tmp/ directory.
-
-Search caching is disabled on a client-by-client basis if the
-client browser does not have cookie capability, for the generated
-session numbers would be incorrect otherwise.
-
-Multiple page returns are also cached. If you C<[set mv_no_count]1[/set]>
-on the calling page, then the user's browser will keep track of the
-traveled links.
-
-The last search can be recalled with C<[page href="[data session last_search]"]>.
-
=head1 THE ORDER PROCESS
MiniVend has a completely flexible order basket and checkout
If you want to place multiple order profiles in the same file,
separate them with __END__, which must be on a line by itself.
+
+User-defined check routines can be defined in a GlobalSub:
+
+ GlobalSub <<EOF
+ sub set_up_extra_check {
+ BEGIN {
+ package Vend::Order;
+ sub _pt_postcode {
+ # $ref is to Vend::Session->{'values'} hash
+ # $var is the passed name of the variable
+ # $val is current value of checked variable
+ my($ref, $var, $val) = @_;
+
+ if ($ref->{country} =~ /^(PT|portugal)$/i) {
+ return $val =~ /^\d\d\d\d$/ ? 1 : 0;
+ }
+ else {
+ return 1;
+ }
+ }
+ }
+ }
+ EOF
+
+Now you can specify in an order profile:
+
+ postcode=pt_postcode
+
+There must be an underscore preceding the routine name in this
+case. Very elaborate checks are possible, of course. If some user
+takes on the polyglot it would be appreciated if they contribute
+the routines.
+
=head2 Simple Order Report File
The simple order report file, "report", defines the layout of the order
[item-price] [item-code]<BR>
[/item-list]
- [tag each products]
+ [loop search="ra=yes"]
[sort products:category products:title]
[loop-field category] [loop-field title] <BR>
- [/tag]
+ [/loop]
All sort situations -- C<[search list]> , C<[loop list]> , C<[tag each table]>, and
C<[item-list]>, take options of the form:
With this in effect, the internal HTTP server would map the following
addresses:
- http://www.minivend.com:7786 mv_admin
- http://www.minivend.com:7787 simple
- http://www.minivend.com:7788 sample
- http://www.minivend.com:7789 search
+ *:7786 mv_admin
+ *:7787 simple
+ *:7788 sample
+ *:7789 search
NOTE: This does not pertain to the use of C<tlink>, which still
relies on the CGI SCRIPT_PATH.
Catalog simple /home/minivend/catalogs/simple /cgi-bin/simple /simple
+If you want to bind to specific IP addresses, add them in the same
+fashion that you would an Apache Listen directive:
+
+ TcpMap <<EOF
+ 127.0.0.1:7786 -
+ www.minivend.com:7787 -
+ EOF
+
+NOTE: As usual, the EOF should be at the beginning of a line with no leading
+or trailing whitespace.
+
=head2 TemplateDir
Sets a directory which will be searched for pages if not found in the users
Bob Jordan
Brian Bullen
Bruce Albrecht
+ Christian Mueller
+ Christopher Thompson
Don Grodecki
Frank Bonita
Gunnar Hellekson
=head2 VERSION
-Document version: $Id: mvfaq.pod,v 1.4 2000/03/28 05:37:15 mike Exp $
+Document version: $Id: mvfaq.pod,v 1.5 2000/04/02 10:21:09 mike Exp $
This document describes MiniVend 4.0 and later.
These modules are strongly recommended:
- MD5
+ Digest::MD5
MIME::Base64
SQL::Statement
URI::URL
=head1 CHANGES
$Log: mvfaq.pod,v $
+Revision 1.5 2000/04/02 10:21:09 mike
+* minor updates
+
Revision 1.4 2000/03/28 05:37:15 mike
Minor pod warning fixes.
cgiurl => sub {
return $ENV{MVC_CGIURL} if $ENV{MVC_CGIURL};
my $url = '';
- if ($Windows) {
- $url .= $Conf{cgibase} . '/' .
- $catalog_name . '.exe';
- }
- elsif ($Conf{cgibase} eq '') {
+ if ($Conf{cgibase} eq '') {
$url = $Tilde if defined $Tilde;
$url .= '/' .
$catalog_name .
}
$Cfg->WriteConfig("$Configfile.new")
- and rename "$Configfile.new", $Configfile;
+ and File::Copy::copy "$Configfile.new", $Configfile;
print "######### END BASE CONFIGURATION #########\n\n";
}
elsif ( ! prefix('nocopy') ) {
$Cfg->WriteConfig("$Configfile.new")
- and rename "$Configfile.new", $Configfile;
+ and File::Copy::copy "$Configfile.new", $Configfile;
}
undef $Cfg;
}
if ($Windows) {
$Conf{linkmode} = 'INET';
- $prog = -f "$Conf{relocate}$Conf{vendroot}/win/tlink.exe"
- ? "$Conf{relocate}$Conf{vendroot}/win/tlink.exe"
- : "$Conf{relocate}$ProgRoot/win/tlink.exe";
+ $prog = "$Conf{relocate}$Conf{vendroot}/src/tlink.pl";
last SETLINKMODE;
}
print <<EOF;
my ($newcfgline, $mark, @out);
my ($tmpfile) = "minivend.cfg.$$";
if (-f 'minivend.cfg') {
- rename ("minivend.cfg", $tmpfile)
- or die "\nCouldn't rename minivend.cfg: $!\n";
+ File::Copy::copy ("minivend.cfg", $tmpfile)
+ or die "\nCouldn't copy minivend.cfg: $!\n";
}
else {
File::Copy::copy('minivend.cfg.dist', $tmpfile);
=head1 VERSION
-$Id: makecat.PL,v 1.4 2000/03/25 21:51:48 racke Exp $
+$Id: makecat.PL,v 1.7 2000/04/16 00:19:12 mike Exp $
=head1 INTRODUCTION
#
# MiniVend version 4.0xxx
#
-# $Id: minivend.PL,v 1.4 2000/03/28 04:28:06 mike Exp $
+# $Id: minivend.PL,v 1.7 2000/04/16 00:19:12 mike Exp $
#
# Copyright 1996-2000 by Michael J. Heins <mikeh@minivend.com>
#
require Exporter;
BEGIN {
- $VERSION = '4.03';
+ $VERSION = '4.04';
}
}
-eval {
- package Vend::Order;
- require CCLib;
- $Vend::CC2 = 1;
- my $ver = $CCLib::VERSION || '2.1';
- ::logGlobal({}, "CyberCash module found (Version %s)", $ver )
- unless $Vend::Quiet;
-};
-
-$Vend::CyberCash = ! $@;
-
-eval {
- package Vend::Order;
- require CCMckLib3_2 ;
- import CCMckLib3_2 qw/InitConfig %Config $MCKversion/;
- require CCMckDirectLib3_2;
- import CCMckDirectLib3_2 qw/SendCC2_1Server doDirectPayment/;
- require CCMckErrno3_2;
- import CCMckErrno3_2 qw/MCKGetErrorMessage/;
- $Vend::CC3 = 1;
- $Vend::CC3server = 0;
- my $ver = $CCMckLib3_2::VERSION || '3.x';
- ::logGlobal({}, "CyberCash module found (Version %s)", $ver )
- unless $Vend::Quiet;
-};
-
-$Vend::CyberCash = $Vend::CyberCash || ! $@;
-
-
use Vend::Util;
use Vend::Server;
use Vend::Session;
adjust_cgi();
- my($sessionid, $path);
+ my($sessionid);
my(@path);
my($g, $action);
$CGI::pragma = 'no-cache'
if delete $Vend::Session->{scratch}{mv_no_cache};
- $path = $Vend::Session->{last_url} = $CGI::path_info;
- if( defined $Vend::Session->{one_time_path_alias}{$path} ) {
- $CGI::path_info = $path = delete $Vend::Session->{one_time_path_alias}{$path};
+ $Vend::FinalPath = $Vend::Session->{last_url} = $CGI::path_info;
+ if( defined $Vend::Session->{one_time_path_alias}{$Vend::FinalPath} ) {
+ $CGI::path_info
+ = $Vend::FinalPath
+ = delete $Vend::Session->{one_time_path_alias}{$Vend::FinalPath};
}
- elsif( defined $Vend::Session->{path_alias}{$path} ) {
- $CGI::path_info = $path = $Vend::Session->{path_alias}{$path};
+ elsif( defined $Vend::Session->{path_alias}{$Vend::FinalPath} ) {
+ $CGI::path_info
+ = $Vend::FinalPath
+ = $Vend::Session->{path_alias}{$Vend::FinalPath};
}
- url_history($path) if $Vend::Cfg->{History};
+ url_history($Vend::FinalPath) if $Vend::Cfg->{History};
if($Vend::Cfg->{DisplayErrors} and $Global::DisplayErrors) {
$SIG{"__DIE__"} = sub {
# LEGACY
ROUTINES: {
- last ROUTINES unless index($path, '/process/') == 0;
- while ($path =~ s:/process/(locale|language|currency)/([^/]*)/:/process/:) {
+ last ROUTINES unless index($Vend::FinalPath, '/process/') == 0;
+ while ($Vend::FinalPath =~ s:/process/(locale|language|currency)/([^/]*)/:/process/:) {
$Vend::Session->{scratch}->{"mv_$1"} = $2;
}
- $path =~ s:/process/page/:/:;
+ $Vend::FinalPath =~ s:/process/page/:/:;
}
my $locale;
if($locale = $Vend::Session->{scratch}->{mv_language}) {
# END LEGACY
my $macro;
- if (
- defined $Vend::Cfg->{Autoload} and
- $macro = $Vend::Cfg->{Autoload}
- )
- {
+ if ($macro = $Vend::Cfg->{Autoload}) {
if($macro =~ /\[\w+/) {
interpolate_html($macro);
}
+ elsif ($macro =~ /^\w+$/) {
+ my $sub = $Vend::Cfg->{Sub}{$macro} || $Global::GlobalSub->{$macro};
+ $sub->();
+ }
}
- if (
- defined $Vend::Cfg->{Filter} and
- $macro = $Vend::Cfg->{Filter}
- )
- {
+ if ($macro = $Vend::Cfg->{Filter}) {
for(keys %$macro) {
Vend::Interpolate::input_filter_do($_, { 'op' => $macro->{$_} } );
}
# If the cgi-bin program was invoked with no extra path info,
# just display the catalog page.
- if (! $path || $path =~ m:^/+$:) {
- $path = find_special_page('catalog');
+ if (! $Vend::FinalPath || $Vend::FinalPath =~ m:^/+$:) {
+ $Vend::FinalPath = find_special_page('catalog');
}
- $path =~ s:^/+::;
- $path =~ s/\.html?$//;
-#::logDebug("path=$path");
- $Vend::FinalPath = $path;
- @path = split('/', $path, 2);
+ $Vend::FinalPath =~ s:^/+::;
+ $Vend::FinalPath =~ s/\.html?$//;
+#::logDebug("path=$Vend::FinalPath");
+
+ @path = split('/', $Vend::FinalPath, 2);
if (defined $CGI::values{mv_action}) {
$Vend::Action = 'process';
$CGI::values{mv_todo} = $CGI::values{mv_action}
if ! defined $CGI::values{mv_todo} and ! defined $CGI::values{mv_doit};
- $CGI::values{mv_nextpage} = $path
+ $CGI::values{mv_nextpage} = $Vend::FinalPath
if ! defined $CGI::values{mv_nextpage};
}
else {
$Vend::Action = shift @path;
- $Vend::FinalPath = join "", @path;
}
-#::logDebug("action=$Vend::Action path=$path");
+#::logDebug("action=$Vend::Action path=$Vend::FinalPath");
my ($sub, $status);
Vend::Interpolate::reset_calc();
if(defined $Vend::Cfg->{ActionMap}{$Vend::Action}) {
$CGI::values{mv_nextpage} = $Vend::FinalPath
if ! defined $CGI::values{mv_nextpage};
}
- elsif ( ! defined ($sub = $action{$Vend::Action}) ) {
- $Vend::FinalPath = $path;
+ elsif ( defined ($sub = $action{$Vend::Action}) ) {
+ $Vend::FinalPath = join "", @path;
}
eval {
::response($template);
}
- $CGI::values{mv_nextpage} = $path
+ $CGI::values{mv_nextpage} = $Vend::FinalPath
if ! defined $CGI::values{mv_nextpage};
do_page() if $status;
#::logDebug ("end dispatch: " . (join " ", times()) . "\n");
+ if(my $macro = $Vend::Cfg->{AutoEnd}) {
+ if($macro =~ /\[\w+/) {
+ interpolate_html($macro);
+ }
+ elsif ($macro =~ /^\w+$/) {
+ $sub = $Vend::Cfg->{Sub}{$macro} || $Global::GlobalSub->{$macro};
+ $sub->();
+ }
+ }
+
put_session() if $Vend::HaveSession;
close_database();
$Global::PIDfile = "$Global::ConfDir/minivend.pid";
$Vend::mode = 'serve'; # mode will be reset by options if appropriate
parse_options() or die usage() . "\n";
- if($> == 0) {
+ if($> == 0 and ! $Global::Windows) {
die errmsg("The Minivend server must not be run as root.\n")
unless $ENV{MINIVEND_ROOT} =~ m{/blib$};
}
+
+ ## Moved here to prevent unwanted messages
+ eval {
+ package Vend::Order;
+ require CCLib;
+ $Vend::CC2 = 1;
+ my $ver = $CCLib::VERSION || '2.1';
+ ::logGlobal({}, "CyberCash module found (Version %s)", $ver )
+ unless $Vend::Quiet;
+ };
+
+ $Vend::CyberCash = ! $@;
+
+ eval {
+ package Vend::Order;
+ require CCMckLib3_2 ;
+ import CCMckLib3_2 qw/InitConfig %Config $MCKversion/;
+ require CCMckDirectLib3_2;
+ import CCMckDirectLib3_2 qw/SendCC2_1Server doDirectPayment/;
+ require CCMckErrno3_2;
+ import CCMckErrno3_2 qw/MCKGetErrorMessage/;
+ $Vend::CC3 = 1;
+ $Vend::CC3server = 0;
+ my $ver = $CCMckLib3_2::VERSION || '3.x';
+ ::logGlobal({}, "CyberCash module found (Version %s)", $ver )
+ unless $Vend::Quiet;
+ };
+
+ $Vend::CyberCash = $Vend::CyberCash || ! $@;
+
delete $INC{'FindBin.pm'};
delete $INC{'Getopt/Long.pm'};
$Global::ErrorFile = "$Global::VendRoot/error.log"
Brian Bullen
Bruce Albrecht
Christian Mueller
+ Christopher Thompson
Don Grodecki
Frank Bonita
Gunnar Hellekson