#!/usr/local/bin/perl -w
#
#Modify Qecbec and font size in item choice  by #J.Tong Nopv. 24, 2003

use strict;
use integer;
use CGI;
use CGI::Carp qw(fatalsToBrowser);
use POSIX;

use vars qw ( $N_CONTINUE );
$N_CONTINUE       = 'Submit';

use vars qw ( $email_sales $company_name $website_name $products );
# $email_sales, $company_name, $website_name initialization deferred to main

use vars qw ( $F_REQUIRED $F_OMISSIBLE $F_MULTIVAL $F_SINGLEVAL $iOrder);
use vars qw ( $FIELDS_ORDER $FIELDS_HEADING $FIELDS_ACK_CAPTION $FIELDS_OMISSIBLE $FIELDS_VALTYPE $FIELDS_TEST );
use vars qw ( %fields );
$F_REQUIRED       = '';
$F_OMISSIBLE      = '*';

# Whether the field may contain one or more value
$F_SINGLEVAL 	  = 1;	# field only return a single value (eg. textfield)
$F_MULTIVAL		  = 0;	# field may return a list of values (eg. listbox, checkbox group)

my $fieldID = 0;
$FIELDS_ORDER     = $fieldID++;
$FIELDS_HEADING   = $fieldID++;
$FIELDS_ACK_CAPTION = $fieldID++;
$FIELDS_OMISSIBLE = $fieldID++;
$FIELDS_VALTYPE  = $fieldID++;	#either F_SINGLEVAL or F_MULTIVAL
$FIELDS_TEST      = $fieldID++;
$iOrder = 0;
%fields = (
   #  Field name   Order  Heading  AcknowledgementCaption  Omissible?    Single/Multiple value?  Additional tests
   'FirstName'  => [  $iOrder++, 'First Name', 'First Name', $F_REQUIRED, $F_SINGLEVAL,  undef ],
   'LastName'   => [  $iOrder++, 'Last Name', 'Last Name', $F_REQUIRED, $F_SINGLEVAL,  undef ],
   'Title'   	=> [  $iOrder++, 'Title', 'Title', $F_REQUIRED, $F_SINGLEVAL,  undef ],
   'Organization'    => [ $iOrder++, 'Organization', 'Organization', $F_REQUIRED, $F_SINGLEVAL,  undef ],
   'Phone'      => [  $iOrder++, 'Work Phone', 'Work Phone', $F_REQUIRED, $F_SINGLEVAL,  'isPhone' ],
   'Fax'        => [  $iOrder++, 'Fax', 'Fax', $F_OMISSIBLE, $F_SINGLEVAL, 'isPhone' ],
   'Email'      => [  $iOrder++, 'Email', 'Email', $F_REQUIRED, $F_SINGLEVAL,  'isEmail' ],
   'StreetAddress'   => [ $iOrder++, 'Street Address', 'Street Address', $F_REQUIRED, $F_SINGLEVAL,  undef ],
   'StreetAddress2'	=> [$iOrder++, 'Address (cont.)', '', $F_OMISSIBLE, $F_SINGLEVAL, undef],
   'City',      => [ $iOrder++, 'City', 'City', $F_REQUIRED, $F_SINGLEVAL,  undef ],
   'State',     => [ $iOrder++, 'State/Province', 'State/Province', $F_OMISSIBLE, $F_SINGLEVAL, undef ],
   'ZipCode'    => [ $iOrder++, 'ZIP/Postal Code', 'ZIP/Postal Code', $F_REQUIRED, $F_SINGLEVAL,  undef ],
   'Country'    => [ $iOrder++, 'Country', 'Country', $F_REQUIRED, $F_SINGLEVAL,  undef ],
   'url'   => [ $iOrder++, 'URL', 'URL', $F_OMISSIBLE, $F_SINGLEVAL, undef ],
   'BSNature' => [$iOrder++, 'Nature of Business', 'Nature of Business', $F_OMISSIBLE, $F_SINGLEVAL, undef ],
   'InterestArea' => [$iOrder++, 'Your interested area(s)', 'Your interested area(s)', $F_REQUIRED, $F_MULTIVAL, undef ],
   'Advertising' => [$iOrder++, 'How do you know about superbright.com?', 'You know about superbright.com from', $F_REQUIRED, $F_MULTIVAL, undef ],
   'comment'    => [ $iOrder++, 'Comments', 'Comments', $F_OMISSIBLE, $F_SINGLEVAL, undef ]
);

use vars qw ( $q );
use vars qw ( $CM_FIELDS_ORDER $CM_FIELDS_DEF );
use vars qw ( %cm_fields );
$q = new CGI;	# initialise the CGI query object
$CM_FIELDS_ORDER    = 0;
$CM_FIELDS_DEF      = 1;
my $cmFldsIdx = 0;
%cm_fields = (
   # CM field name    Order Definition function (assuming @_ is hash of fields)
   'Public/Private' => [ $cmFldsIdx++, sub { 'Public' } ],
   'Record Manager' => [ $cmFldsIdx++, sub { 'Peter Tang' } ],
   'Organization'   => [ $cmFldsIdx++, sub { $q->param('Organization') } ],
   'Contact'        => [ $cmFldsIdx++, sub { $q->param('FirstName') . ' '
				    	.$q->param('LastName') } ],
   'StreetAddress'  => [ $cmFldsIdx++, sub { $q->param('StreetAddress').' '
   						.$q->param('StreetAddress2') } ],
   'City'           => [ $cmFldsIdx++, sub { $q->param('City') } ],
   'State'          => [ $cmFldsIdx++, sub { $q->param('State') } ],
   'Zip'            => [ $cmFldsIdx++, sub { $q->param('ZipCode') } ],
   'Country'        => [ $cmFldsIdx++, sub { $q->param('Country') } ],
   'Phone'          => [ $cmFldsIdx++, sub { $q->param('Phone') } ],
   'Fax'            => [ $cmFldsIdx++, sub { $q->param('Fax') } ],
   'Title'          => [ $cmFldsIdx++, sub { $q->param('Title') } ],
   'First Name'     => [ $cmFldsIdx++, sub { $q->param('FirstName') } ],
   'Last Name'      => [ $cmFldsIdx++, sub { $q->param('LastName') } ],
   'URL'			=> [ $cmFldsIdx++, sub { $q->param('url') } ],
   'Record Creator' => [ $cmFldsIdx++, sub { "webmaster\@$ENV{HTTP_HOST}" } ],
   'E-mail Login'   => [ $cmFldsIdx++, sub { $q->param('Email') } ],
   'Last Results'   => [ $cmFldsIdx++, sub { POSIX::strftime(
			"Imported on %Y/%m/%d %H:%M:%S from $ENV{HTTP_HOST}",
			localtime time) } ],
   'ID/Status'      => [ $cmFldsIdx++, sub { "Visitor of $ENV{HTTP_HOST}" } ],
);

# from http://www.din.de/gremien/nas/nabd/iso3166ma/codlstp1/en_listp1.html
use vars qw( @countries );
@countries = (
   "Canada",
   "United States",
   "Afghanistan",
   "Albania",
   "Algeria",
   "American Samoa",
   "Andorra",
   "Angola",
   "Anguilla",
   "Antarctica",
   "Antigua And Barbuda",
   "Argentina",
   "Armenia",
   "Aruba",
   "Australia",
   "Austria",
   "Azerbaijan",
   "Bahamas",
   "Bahrain",
   "Bangladesh",
   "Barbados",
   "Belarus",
   "Belgium",
   "Belize",
   "Benin",
   "Bermuda",
   "Bhutan",
   "Bolivia",
   "Bosnia And Herzegovina",
   "Botswana",
   "Bouvet Island",
   "Brazil",
   "British Indian Ocean Territory",
   "Brunei Darussalam",
   "Bulgaria",
   "Burkina Faso",
   "Burundi",
   "Cambodia",
   "Cameroon",
   "Cape Verde",
   "Cayman Islands",
   "Central African Republic",
   "Chad",
   "Chile",
   "China",
   "Christmas Island",
   "Cocos (Keeling) Islands",
   "Colombia",
   "Comoros",
   "Congo",
   "Congo, The Democratic Republic Of The",
   "Cook Islands",
   "Costa Rica",
   "Cote d'Ivoire",
   "Croatia",
   "Cuba",
   "Cyprus",
   "Czech Republic",
   "Denmark",
   "Djibouti",
   "Dominica",
   "Dominican Republic",
   "East Timor",
   "Ecuador",
   "Egypt",
   "El Salvador",
   "Equatorial Guinea",
   "Eritrea",
   "Estonia",
   "Ethiopia",
   "Falkland Islands (Malvinas)",
   "Faroe Islands",
   "Fiji",
   "Finland",
   "France",
   "French Guiana",
   "French Polynesia",
   "French Southern Territories",
   "Gabon",
   "Gambia",
   "Georgia",
   "Germany",
   "Ghana",
   "Gibraltar",
   "Greece",
   "Greenland",
   "Grenada",
   "Guadeloupe",
   "Guam",
   "Guatemala",
   "Guinea",
   "Guinea-Bissau",
   "Guyana",
   "Haiti",
   "Heard Island And Mcdonald Islands",
   "Holy See (Vatican City State)",
   "Honduras",
   "Hong Kong",
   "Hungary",
   "Iceland",
   "India",
   "Indonesia",
   "Iran, Islamic Republic Of",
   "Iraq",
   "Ireland",
   "Israel",
   "Italy",
   "Jamaica",
   "Japan",
   "Jordan",
   "Kazakstan",
   "Kenya",
   "Kiribati",
   "Korea, Democratic People's Republic Of",
   "Korea, Republic Of",
   "Kuwait",
   "Kyrgyzstan",
   "Lao People's Democratic Republic",
   "Latvia",
   "Lebanon",
   "Lesotho",
   "Liberia",
   "Libyan Arab Jamahiriya",
   "Liechtenstein",
   "Lithuania",
   "Luxembourg",
   "Macau",
   "Macedonia, The Former Yugoslav Republic Of",
   "Madagascar",
   "Malawi",
   "Malaysia",
   "Maldives",
   "Mali",
   "Malta",
   "Marshall Islands",
   "Martinique",
   "Mauritania",
   "Mauritius",
   "Mayotte",
   "Mexico",
   "Micronesia, Federated States Of",
   "Moldova, Republic Of",
   "Monaco",
   "Mongolia",
   "Montserrat",
   "Morocco",
   "Mozambique",
   "Myanmar",
   "Namibia",
   "Nauru",
   "Nepal",
   "Netherlands",
   "Netherlands Antilles",
   "New Caledonia",
   "New Zealand",
   "Nicaragua",
   "Niger",
   "Nigeria",
   "Niue",
   "Norfolk Island",
   "Northern Mariana Islands",
   "Norway",
   "Oman",
   "Pakistan",
   "Palau",
   "Palestinian Territory, Occupied",
   "Panama",
   "Papua New Guinea",
   "Paraguay",
   "Peru",
   "Philippines",
   "Pitcairn",
   "Poland",
   "Portugal",
   "Puerto Rico",
   "Qatar",
   "RÉUnion",
   "Romania",
   "Russian Federation",
   "Rwanda",
   "Saint Helena",
   "Saint Kitts And Nevis",
   "Saint Lucia",
   "Saint Pierre And Miquelon",
   "Saint Vincent And The Grenadines",
   "Samoa",
   "San Marino",
   "Sao Tome And Principe",
   "Saudi Arabia",
   "Senegal",
   "Seychelles",
   "Sierra Leone",
   "Singapore",
   "Slovakia",
   "Slovenia",
   "Solomon Islands",
   "Somalia",
   "South Africa",
   "South Georgia And The South Sandwich Islands",
   "Spain",
   "Sri Lanka",
   "Sudan",
   "Suriname",
   "Svalbard And Jan Mayen",
   "Swaziland",
   "Sweden",
   "Switzerland",
   "Syrian Arab Republic",
   "Taiwan, Province Of China",
   "Tajikistan",
   "Tanzania, United Republic Of",
   "Thailand",
   "Togo",
   "Tokelau",
   "Tonga",
   "Trinidad And Tobago",
   "Tunisia",
   "Turkey",
   "Turkmenistan",
   "Turks And Caicos Islands",
   "Tuvalu",
   "Uganda",
   "Ukraine",
   "United Arab Emirates",
   "United Kingdom",
#  "United States Minor Outlying Islands",
   "Uruguay",
   "Uzbekistan",
   "Vanuatu",
   "Venezuela",
   "Viet Nam",
   "Virgin Islands, British",
   "Virgin Islands, U.S.",
   "Wallis And Futuna",
   "Western Sahara",
   "Yemen",
   "Yugoslavia",
   "Zambia",
   "Zimbabwe"
);

use vars qw( %provinces );
%provinces = (
   'Alabama' => 'AL',
   'Alaska' => 'AK',
   'Alberta' => 'AB',
   'Arizona' => 'AZ',
   'American Samoa' => 'AS',
   'Arkansas' => 'AR',
   'British Columbia ' => 'BC',
   'California' => 'CA',
   'Colorado' => 'CO',
   'Connecticut' => 'CT',
   'Delaware' => 'DE',
   'District of Colmbia' => 'DC',
   'Federated States of Micronesia' => 'FM',
   'Florida' => 'FL',
   'Georgia' => 'GA',
   'Hawaii' => 'HI',
   'Idaho' => 'ID',
   'Illinois' => 'IL',
   'Indiana' => 'IN',
   'Iowa' => 'IA',
   'Kansas' => 'KS',
   'Kentucky' => 'KY',
   'Louisana' => 'LA',
   'Maine' => 'ME',
   'Manitoba' => 'MB',
   'Marshall Islands' => 'MH',
   'Maryland' => 'MD',
   'Massachusetts' => 'MA',
   'Michigan' => 'MI',
   'Minnesota' => 'MN',
   'Mississippi' => 'MS',
   'Missouri' => 'MO',
   'Montana' => 'MT',
   'Nebraska' => 'NE',
   'Nevada' => 'NV',
   'New Brunswick' => 'NB',
   'New Hampshire' => 'NH',
   'New Jersey' => 'NJ',
   'New Mexico' => 'NM',
   'New York' => 'NY',
   'Newfoundland' => 'NF',
   'North Carolina' => 'NC',
   'North Dakota' => 'ND',
   'Northern Mariana Islands' => 'MP',
   'Northwest Territories' => 'NT',
   'Nova Scotia' => 'NS',
   'Ohio' => 'OH',
   'Oklahoma' => 'OK',
   'Ontario' => 'ON',
   'Oregon' => 'OR',
   'Palau' => 'PW',
   'Pennsylvania' => 'PA',
   'Prince Edward Island' => 'PE',
   'Puerto Rico' => 'PR',
   'Quebec' => 'QC',
   'Rhode Island' => 'RI',
   'Saskatchewan' => 'SK',
   'South Carolina' => 'SC',
   'South Dakota' => 'SD',
   'Tennessee' => 'TN',
   'Texas' => 'TX',
   'Utah' => 'UT',
   'Vermont' => 'VT',
   'Virgin Islands' => 'VI',
   'Virginia' => 'VA',
   'Washington' => 'WA',
   'West Virginia' => 'WV',
   'Wisconsin' => 'WI',
   'Wyoming' => 'WY',
   'Yukon' => 'YT',
);


sub isInArray($@)
{
	my ($val, @arrRef) = @_;
	foreach my $item (@arrRef)
	{
		if ($val eq $item) {
			return 1;
		}
	}
	return 0;
}

use vars qw (@interestAreas @interestAreaLabels @interestAreaValues);
@interestAreas = (
	{'Arm/Leg Band' => 'Arm/Leg Band'},
	{'Cuff' => 'Cuff'},
	{'Flag' => 'Flag'},
	{'Hi-vis Vest' => 'Hi-vis Vest'},
	{'Rain Wear' => 'Rain Wear'},
	{'Sash Belt' => 'Sash Belt'},
	{'T-shirt' => 'T-shirt'},
	{'Traffic Vest' => 'Traffic Vest'},
	{'Tearaway Vest' => 'Tearaway Vest'},
	{'ANSI/CSA Vest' => 'ANSI/CSA Vest'}
);
foreach $a (@interestAreas) {
	my ($key, $val);
	($key, $val) = %$a;
	push(@interestAreaLabels, $val); 
	push(@interestAreaValues, $key); 
}

use vars qw (@advertising @advertisingLabels @advertisingValues $searchField $othersField);
$searchField = $q->textfield(-name=>'Engine_Name', -maxlength=>50, -size=>25, -default=>'Which search engine ?', -onFocus=>'this.value=""');
$othersField = $q->textfield(-name=>'Other',-maxlength=>50, -size=>30);
@advertising = (
	#{Value => (Caption in main form) }
	{'Trade Show'=>'Trade Show'},
	{'Directory'=>'Directory'},
	{'Fax'=>'Fax'},
	{'Flyer'=>'Flyer'},
	{'Word of Mouth'=>'Word of Mouth'},
	{'Search Engine' =>'Search Engine '.$searchField},
	{'Others'=>'Others '.$othersField}
);
foreach $a (@advertising) {
	my ($key, $val);
	($key, $val) = %$a;
	push(@advertisingLabels, $val); 
	push(@advertisingValues, $key); 
}

# The following 2 foreach loops add extra records into cm_fields so that they come in the attachment
#
foreach $a (@interestAreas) {
	my ($key, $val) = %$a;
	$cm_fields{$key} = [$cmFldsIdx++, sub { isInArray($key, $q->param('InterestArea'))?'Y':'N'; } ];
}
foreach $a (@advertising) {
	my ($key, $val) = %$a;
	$cm_fields{$key} = [$cmFldsIdx++, 
		sub {
			if ($key eq 'Search Engine') {
				$q->param('Engine_Name');
			}
			elsif ($key eq 'Others') {
				$q->param('Other');
			}
			else {
				isInArray($key, $q->param('Advertising'))?'Y':'N';
			}
		}
	];
}
###

use vars qw ( $boundary_chars );	# Trends has very few modules! (^^;)
$boundary_chars = join('', 'A'..'Z', 'a'..'z', '0'..'9');

sub RFC1123_DATE_FORMAT () { '%a, %d %b %Y %H:%M:%S GMT' }

sub mydie ($);
do { eval { exit(main()) }; &mydie($@) } unless caller;

use vars qw( $appName $rcsrev $rcsdate $debugging );
use vars qw( $cgi_p $maintainer );

sub mydie ($) {
   my($msg) = @_;
   my $status = 400;
   my $summary = "$ENV{SCRIPT_NAME} Internal error";
   my $xchk = quotemeta($!);
   if ($msg =~ /$xchk$/) { # no s option, intentionally
      $status = 403 if $! == POSIX::EACCES;
      $status = 404 if $! == POSIX::ENOENT;
      $msg = "$1$2" if $status != 400 && $msg =~ /^.\/+([^:]+)(: $xchk.*)$/s;
   }
   print STDERR $msg;
   if ($cgi_p) {
      chomp $msg;
      $summary = $msg if $msg =~ /\S/s && $msg !~ /[\0-\037\177\377]/s;
      $msg =~ s/&/\&amp;/sg;
      $msg =~ s/</\&lt;/sg;
      print <<EOF;
Status: $status $summary
Content-Type: text/html; charset=iso-8859-1
Cache-Control: no-cache

EOF
      $SIG{__DIE__} = undef;
      print <<EOF; #

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>$summary</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
EOF

      print <<EOF; #


<meta name=generator content="$appName/$rcsrev ($rcsdate)">
<meta name=generator content="subst.pl/1.221 (2001/05/25)">
</head>
<body>
<h1>Internal error</h1>
<p><em>$msg</em></p>
EOF
      if (defined $q) {
	 my $dump = $q->dump();
	 print "<h2>Variables</h2>\n", $dump unless $dump eq '<UL></UL>';
      }
      if ($cgi_p) { # No need to dump the environment if we are in the shell
	 print "<h2>Environment</h2>\n<pre>\n";
	 for my $key (keys %ENV) {
	    print "$key=$ENV{$key}\n";
	 }
	 print "</pre>\n";
      }

      print <<EOF; #


<p>
Please report this error to <a href="mailto:$maintainer">$maintainer</a>.
Thanks in advance.
</p>
</body>
</html>
EOF
   }
   exit 1;
}

sub generate_checkbox_group($$$$;$$)
{
	# name = name of each checkbox
	# labels = Reference to array.the caption value for each checkbox
	# values = Reference to array. the param value for each checkbox
	# checked = Reference to array. which checkbox is in checked state. These are the param values for each checkbox.
	# rols = the number of rows to use to lay out the checkbox group
	# cols = the number of cols to use to lay out the checkbox group
	my ($name, $labels, $values, $checked, $rows, $cols) = @_;
	
	my $ret = '<table>';
	my @arrLabels = @$labels;
	my @arrVals = @$values;
	my $numElem = ($#arrLabels < $#arrVals) ? $#arrLabels : $#arrVals;
	my($i, $j, $r, $c);
	
	$r = $rows; $c = $cols;
	if ($r == undef && $c != undef) {
		$r = $numElem/$c+1;
	}
	elsif ($c == undef && $r != undef) {
		$c = $numElem/$r+1;
	}
	elsif ($r == undef && $c == undef)
	{
		$c = 1;
		$r = $numElem+1;
	}
		
	for ($i = 0; $i < $r; $i++) {
		$ret .= '<tr>';
		for ($j = 0; $j < $c; $j++) {
			if ($i*$c+$j <= $numElem) {
				my $bChecked = '';
				if (defined @$checked) {
					my $elem;
					foreach $elem (@$checked) {
						if (@$values[$i*$c+$j] eq $elem) {
							$bChecked = 'CHECKED';
						}
					}
				}
				
				$ret .= '<td><input type="CHECKBOX" '.$bChecked.' name="'.$name.'" value="'.
				@$values[$i*$c+$j].'"/>'.@$labels[$i*$c+$j].'</td>';
			}
		}
		$ret .= '</tr>';
	}
	
	$ret .= '</table>';
		
	return $ret;
}

sub display_contact_us_form (;@) {
   my(@errors) = @_;
   my $self = $q->url();
   my $field_FirstName = $q->textfield('-name' => 'FirstName',
	 '-maxlength' => 20, '-size' => 20);
   my $field_LastName = $q->textfield('-name' => 'LastName',
	 '-maxlength' => 20, '-size' => 20);
   my $field_Title = $q->textfield('-name' => 'Title',
	 '-maxlength' => 20, '-size' => 20);
   my $field_Organization = $q->textfield('-name' => 'Organization',
	 '-maxlength' => 80, '-size' => 40);
   my $field_Phone = $q->textfield('-name' => 'Phone',
	 '-maxlength' => 20, '-size' => 20);
   my $field_Fax = $q->textfield('-name' => 'Fax',
	 '-maxlength' => 20, '-size' => 20);
   my $field_Email = $q->textfield('-name' => 'Email',
	 '-maxlength' => 80, '-size' => 40);
   my $field_StreetAddress = $q->textfield('-name' => 'StreetAddress',
	 '-maxlength' => 80, '-size' => 40);
   my $field_StreetAddress2 = $q->textfield('-name' => 'StreetAddress2',
	 '-maxlength' => 80, '-size' => 40);
   # (58 letters), Wales
   my $field_City = $q->textfield('-name' => 'City',
	 '-maxlength' => 80, '-size' => 40);
   my $field_State = #($q->param('Country') !~ /^(?:United States|Canada)$/)?
	 #$q->textfield('-name' => 'State',
	 #'-maxlength' => 10, '-size' => 10):
	 $q->popup_menu('-name' => 'State', '-values' => [ sort keys %provinces ]);
   my $field_ZipCode = $q->textfield('-name' => 'ZipCode',
	 '-maxlength' => 10, '-size' => 10);
   my $field_Country = $q->popup_menu('-name' => 'Country',
	 '-values' => \@countries);
   my $field_url = $q->textfield('-name' => 'url',
	 '-maxlength' => 80, '-size' => 40);
   my $field_BSNature = $q->textfield('-name' => 'BSNature', '-maxlength'=>40, 'size'=>40);
   my @arrIntArea = $q->param('InterestArea');
   my $field_InterestArea = generate_checkbox_group('InterestArea', \@interestAreaLabels,
   		\@interestAreaValues, \@arrIntArea, 3, 4);
   my @arrAdvert = $q->param('Advertising');
   my $field_Advertising = generate_checkbox_group('Advertising', \@advertisingLabels,
   		\@advertisingValues, \@arrAdvert);
   my $field_comment = $q->textarea('-name' => 'comment',
	 '-wrap' => 'VIRTUAL',	# FIXME: textarea element has no wrap attribute
	 '-columns' => 40,
	 '-rows' => 10);
   my $js_validate_call = 'MM_validateForm('
	 . join(', ', map {
			  my $label = $fields{$_}->[$FIELDS_HEADING];
			  my $det = $fields{$_}->[$FIELDS_OMISSIBLE];	
			  my $test = $fields{$_}->[$FIELDS_TEST];
			  my $bRequired = ($fields{$_}->[$FIELDS_OMISSIBLE] eq $F_REQUIRED)?1:0;
			  if ($det eq $F_OMISSIBLE) {			  
				 $test? "'$_','$label','$test','$bRequired'": ()
			  } elsif ($det !~ /\S/) {
				 "'$_','$label','R$test', '$bRequired'"
			  } else {
				 die "Illegal omissible-field \"$det\" for field $_\n";
			  }
	       } sort { $fields{$a}->[$FIELDS_ORDER] <=> $fields{$b}->[$FIELDS_ORDER] } keys %fields).')';
   my $errors = '';
   if (@errors) {
      $errors = "<p>Please make sure that the form is filled in correctly:\n"
	 . "<ul>\n" . join('', map { "<li>$_\n" } @errors) . "</ul>\n";
   }
   my @headers = ('-type' => 'text/html; charset=iso-8859-1',
	 '-status' => '200 Ok',
	 '-Content-Script-Type' => 'text/javascript',
	 '-Date' => POSIX::strftime(RFC1123_DATE_FORMAT, gmtime time),
	 '-Last-Modified' => POSIX::strftime(RFC1123_DATE_FORMAT,
	       gmtime((stat $0)[9])));
   my $recipient = recipient(); # XXX for debugging only
   push @headers, ('-Cache-Control', 'no-cache') if $q->param;
   print $q->header(@headers);
   print <<EOF;


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Become a Distributor</title>
<!-- <header name="Content-Language" value="en"> -->
<meta http-equiv="Content-Language" content="en">
<!-- <header name="Content-Type" value="text/html; charset=iso-8859-1"> -->
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta http-equiv="Content-Script-Type" content="text/javascript">
<link rev=made href="$recipient">
<link rel="stylesheet" href="contact.css">
<script src="distributor.js" type="text/javascript" language="JavaScript" defer>
</script>
<meta name=generator content="subst.pl/1.221 (2001/05/25)">
</head>
<body bgcolor="#000000" text="#FFFFFF" lang="en">
<h1 class=companyname>Request to become a Distributor</h1>
<p>$company_name products are proudly presented by:</p>
<p><b class=companyname>KAN HOUSE OF KAGROO INC.</b></p>
<p>
We are one of the major manufacturers of safety $products in Canada
established since 1986.
We have dealers all over Canada and export to many other countries as well.
</p>
<p>To contact us please fill in the following form and send to us. </p>
<p>Fields with asterisk [*] are optional.</p>


$errors

<form method="post" action="$self">
  <!-- FIXME: I *know* the textarea element has no "wrap" attribute -->
  <table width="100%" border="0" cellspacing="0" cellpadding="2">
    <tbody>
    <tr valign="top">
		<td align="right">$fields{FirstName}->[$FIELDS_HEADING]:</td>
		<td align="left">$field_FirstName $fields{FirstName}->[$FIELDS_OMISSIBLE]</td></tr>
	<tr valign="top">
		<td align="right">$fields{LastName}->[$FIELDS_HEADING]:</td>
		<td align="left">$field_LastName $fields{LastName}->[$FIELDS_OMISSIBLE]</td></tr>
	<tr valign="top">
		<td align="right">$fields{Title}->[$FIELDS_HEADING]:</td>
		<td align="left">$field_Title $fields{Position}->[$FIELDS_OMISSIBLE]</td></tr>
	<tr valign="top">
		<td align="right">$fields{Organization}->[$FIELDS_HEADING]:</td>
		<td align="left">$field_Organization $fields{Organization}->[$FIELDS_OMISSIBLE]</td></tr>
    <tr valign="top">
		<td align="right">$fields{StreetAddress}->[$FIELDS_HEADING]:</td>
		<td align="left">$field_StreetAddress $fields{StreetAddress}->[$FIELDS_OMISSIBLE]<br/>
			$field_StreetAddress2</td></tr>
    <tr valign="top">
		<td align="right">$fields{City}->[$FIELDS_HEADING]:</td>
		<td align="left">$field_City $fields{City}->[$FIELDS_OMISSIBLE]</td></tr>
	<tr valign="top">
		<td align="right">$fields{State}->[$FIELDS_HEADING]:</td>
		<td align="left">$field_State $fields{State}->[$FIELDS_OMISSIBLE]</td></tr>
	<tr valign="top">
		<td align="right">$fields{ZipCode}->[$FIELDS_HEADING]:</td>
		<td align="left">$field_ZipCode $fields{ZipCode}->[$FIELDS_OMISSIBLE]</td></tr>
	<tr valign="top">
		<td align="right">$fields{Country}->[$FIELDS_HEADING]:</td>
		<td align="left">$field_Country $fields{Country}->[$FIELDS_OMISSIBLE]</td></tr>
	<tr valign="top">
        <td align="right">$fields{Phone}->[$FIELDS_HEADING]:</td>
        <td align="left">$field_Phone $fields{Phone}->[$FIELDS_OMISSIBLE]</td></tr>
    <tr valign="top">
		<td align="right">$fields{Fax}->[$FIELDS_HEADING]:</td>
		<td align="left">$field_Fax $fields{Fax}->[$FIELDS_OMISSIBLE]</td></tr>	
    <tr valign="top">
		<td align="right">$fields{Email}->[$FIELDS_HEADING]:</td>
		<td align="left">$field_Email $fields{Email}->[$FIELDS_OMISSIBLE]</td></tr>	
	<tr valign="top">
		<td align="right">$fields{url}->[$FIELDS_HEADING]:</td>
		<td align="left">$field_url $fields{url}->[$FIELDS_OMISSIBLE]</td></tr>
	<tr valign="top">
		<td align="right">$fields{BSNature}->[$FIELDS_HEADING]:</td>
		<td align="left">$field_BSNature $fields{BSNature}->[$FIELDS_OMISSIBLE]</td></tr>
	<tr valign="top">
		<td align="right">$fields{InterestArea}->[$FIELDS_HEADING]:</td>
		<td align="left">$field_InterestArea $fields{InterestArea}->[$FIELDS_OMISSIBLE]</td></tr>
	<tr valign="top">
		<td align="right">$fields{Advertising}->[$FIELDS_HEADING]:</td>
		<td align="left">$field_Advertising $fields{Advertising}->[$FIELDS_OMISSIBLE]</td></tr>
	<tr valign="top">
		<td align="right">$fields{comment}->[$FIELDS_HEADING]:</td>
		<td align="left">$field_comment $fields{comment}->[$FIELDS_OMISSIBLE]</td></tr>
	<tr valign="top">
		<td>&nbsp;</td>
		<td align="left"><input type="submit" name="Submit" value="$N_CONTINUE"
	    	onClick="$js_validate_call; return document.MM_returnValue">
          <input type="reset" name="Reset" value="Reset"></td></tr>
	</tbody></table>
</form>
<p>Or, contact us directly:</p>
<p><b class=companyname>KAN HOUSE OF KAGROO INC. </b></p>
<p>253 College Street, Suite 219, Toronto, Ontario, Canada M5T 1R5.<br>
  Telephone: +1 (416) 540-6966<br>
  Toll free: +1 866 633-6966<br>
  Fax: +1 (416) 875-6999<br>
  E-mail: <a href="mailto:$email_sales">$email_sales</a><br>
  Webpage: <a target="_top" href="http://$website_name">http://$website_name</a></p>
</body>
</html>
EOF
}

sub validate_form_data () {
   my @errors = ();
   local($&, $1, $2);
   for my $field (keys %fields) {
      my $label = $fields{$field}->[$FIELDS_HEADING];
      my $det = $fields{$field}->[$FIELDS_OMISSIBLE];
      # Replicate of MM_validateForm() logic in contact.js, sort of...
      my $val = join(",", $q->param($field));
      if ($val =~ /\S/) {
	 my $test = $fields{$field}->[$FIELDS_TEST];
	 if (!defined $test) {
	    ;
	 } elsif ($test =~ /isEmail/ ) {
	 	if ($val !~ /\w+([-+.]\w+)*@\w+(-.]\w+)*\.\w+([-.]\w+)*/ ) {
	    	push @errors, "$label must contain a valid e-mail address.";
	    }
	 } 
	 elsif ($test =~ /isPhone/ ) {
	 	if ($val !~ /^(\d{3}[ -]?){2}\d{4}$/ ) {
	 		push @errors, "Invalid $label format. Valid formats are 'xxx-xxx-xxxx', 'xxx xxx xxxx' or simply 'xxxxxxxxxx'.";
	 	}
	 }
	 else {
	    if ($val != $val + 0) { # FIXME
	       push @errors, "$label must contain a number.";
	    } elsif ($test =~ /inRange(-?\d+(?:\.\d+)?):(-?\d+(?:\.\d+)?)/) {
	       my($min, $max) = ($1, $2);
	       push @errors,
		     "$label must contain a number between $min and $max"
		  unless $min <= $val && $val <= $max;
	    }
	 }
      } elsif ($det eq $F_REQUIRED) {
	 push @errors, "$label is required.";
      }
   }
   return @errors;
}

sub recipient () {
   my $domain = $ENV{'HTTP_HOST'};#XXX Net::Domain::hostdomain();
   return $debugging? $maintainer: $email_sales;
}

sub display_acknowledgement_form () {
   my $self = $q->url();
   print $q->header('-type' => 'text/html; charset=iso-8859-1',
	 '-status' => '200 Ok',
	 '-Date' => POSIX::strftime(RFC1123_DATE_FORMAT, gmtime time),
	 '-Last-Modified' => POSIX::strftime(RFC1123_DATE_FORMAT,
	       gmtime((stat $0)[9])),
	 '-Cache-Control' => 'no-cache');
   my $recipient = recipient;
   print <<EOF;


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>The mail has been sent</title>

<!-- <header name="Content-Type" value="text/html; charset=iso-8859-1"> -->
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<link rel="stylesheet" href="contact.css">
<meta name=generator content="subst.pl/1.221 (2001/05/25)">
</HEAD><body bgcolor="#000000" text="#FFFFFF" lang="en">
<h1>The mail has been sent</h1>
<p>
E-mail with your contact information has been sent to $recipient.
</P><p>
The following is a copy of the information that you have sent:
</P><table width="100%" border="0" cellspacing="0" cellpadding="2">
<tbody>
EOF
   my $tr = '<tr valign="top">';
   my $td_head_none = '<td>&nbsp; ';
   my $_td_head_none = '</td>';
   my $td_head = '<td align="right" width="40%">';
   my $_td_head = '</td>';
   my $td_data = '<td align="left">';
   my $_td_data = '</td>';
   my $_tr = '</tr>';
   for my $field (sort {
	    $fields{$a}->[$FIELDS_ORDER] <=> $fields{$b}->[$FIELDS_ORDER]
	 } keys %fields) {

      my $label = $fields{$field}->[$FIELDS_ACK_CAPTION];
      if ($label ne "") { $label .= ':'; }
      print "$tr\n";
      print defined $label? "$td_head$label$_td_head":
	    "$td_head_none$_td_head_none";
	  
      my $val;
      if ($fields{$field}->[$FIELDS_VALTYPE] == $F_MULTIVAL) {
      	$val = join(", ", map { if ($_ eq 'Search Engine') {
      								$_ = $q->param('Engine_Name'); 
      							} elsif ($_ eq 'Others') {
      								$_ = $q->param('Other');
      							} else { $_; }
      					} $q->param($field));
      }
      else {
      	$val = $q->param($field);
      	if ($val eq '') {
      		$val = "(not specified)";
      	}
      }
      print "\n$td_data", $q->hidden($field, $val); # FIXME newlines are hosed
      $val =~ s/\n/<br>\n/g;
      print "$val$_td_data$_tr\n";
   }
   print <<EOF;


</TBODY></table>
</BODY></html>
EOF
}

sub display_send_mail_error ($) {
   my($error) = @_;
   my $self = $q->url();
   print $q->header('-type' => 'text/html; charset=iso-8859-1',
	 '-status' => '404 Error',
	 '-Date' => POSIX::strftime(RFC1123_DATE_FORMAT, gmtime time),
	 '-Last-Modified' => POSIX::strftime(RFC1123_DATE_FORMAT,
	       gmtime((stat $0)[9])),
	 '-Cache-Control' => 'no-cache');
   print <<EOF;


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Failed to send mail</title>

<!-- <header name="Content-Type" value="text/html; charset=iso-8859-1"> -->
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<link rel="stylesheet" href="contact.css">
<meta name=generator content="subst.pl/1.221 (2001/05/25)">
</HEAD><body bgcolor="#000000" text="#FFFFFF" lang="en">
<h1>Failed to send mail</h1>
<p>
Sorry, your request could not be sent.
$error
</P></BODY></html>
EOF
}


sub qp_send ($$) {
   my($smtp, $data) = @_;
   if (length $data) {
      local($&, $1);
      $data =~ s{([\0-\037\177-\377=])}{ sprintf("=%02X", ord $1) }sge;
      $data =~ s/((?:^|=0A)F)(?=rom )/\1=46/sg;
      $data =~ s/=0A$/\n/s;
      $data .= "=\n" unless $data =~ /\n$/s;
      # FIXME: length should be checked
      smtp_datasend($smtp, $data);
   }
   1;
}

sub smtp_unix_p ($) {
   my($smtp) = @_;
   my $det = ref $smtp;
   defined $det && $det eq ''; # FIXME this is probably wrong
}

sub smtp_new () {
   #my $smtp = Net::SMTP->new('mail');
   my $smtp = *SENDMAIL;
   my $sendmail = undef;
   for my $candidate ('/usr/lib/sendmail', '/usr/sbin/sendmail') {
      $sendmail = $candidate if -x $candidate;
   last if defined $sendmail;
   }
   if (smtp_unix_p($smtp)) {
      # We have sendmail, so this is probably Unix, have fork, and we are happy
      my $pid = open($smtp, '|-');
      die "sendmail: fork: $!\n" unless defined $pid;
      if (!$pid) {
	 exec($sendmail, '-t');
	 die "sendmail: exec: $!\n";
      }
   } else {
      eval {
	 require 'Net/Domain.pm'; import Net::Domain;	# deferred use
	 require 'Net/SMTP.pm';   import Net::SMTP;	# deferred use
      };
      die "Cannot find sendmail, but cannot use Net::SMTP either ($@)"
	 if length $@;
   }
   return $smtp;
}

sub smtp_mail ($$) {
   my($smtp, $sender) = @_;
   if (!smtp_unix_p($smtp)) {
      $smtp->mail($sender) || die "MAIL command failed.\n";
   }
}

sub smtp_to ($@) {
   my($smtp, @recipient) = @_;
   if (!smtp_unix_p($smtp)) {
      $smtp->to(@recipient) || die "RCPT command failed.\n";
   }
}

sub smtp_data ($) {
   my($smtp) = @_;
   if (!smtp_unix_p($smtp)) {
      $smtp->data() || die "DATA command failed\n";
   }
}

sub smtp_datasend ($$) {
   my($smtp, $data) = @_;
   if (smtp_unix_p($smtp)) {
      print $smtp $data;
   } else {
      $smtp->datasend($data) || die;
   }
}

sub smtp_dataend ($) {
   my($smtp) = @_;
   if (smtp_unix_p($smtp)) {
      close $smtp;
   } else {
      $smtp->dataend() || die ". command failed\n";
   }
}

sub smtp_quit ($) {
   my($smtp) = @_;
   $smtp->quit() if !smtp_unix_p($smtp);
}

sub send_mail () {
   my $smtp = smtp_new();
   local $@;
   die "Net::SMTP->new() returned undef" unless defined $smtp;
   eval {
      local $SIG{__DIE__} = 'DEFAULT';
      my $domain = $ENV{HTTP_HOST};#XXX Net::Domain::hostdomain();
      my($sender, $recipient) = ($email_sales, recipient);
      my $boundary = '=_';
      for (my $i = 1; $i <= 32; $i += 1) {
	 no integer;
	 $boundary .= substr($boundary_chars, length($boundary_chars)*rand, 1)
      }
      my $subboundary = "-$boundary";	# $boundary is prefix > confusion in IE
      smtp_mail($smtp, $sender);
      smtp_to($smtp, $recipient);
      smtp_data($smtp);
      my $user_agent = $q->user_agent();
      my $origin = $ENV{'REMOTE_HOST'}."(".$ENV{'REMOTE_ADDR'}.")";
      $origin .= " (for $ENV{HTTP_X_FORWARDED_FOR})"
	    if $ENV{HTTP_X_FORWARDED_FOR} =~ /\S/;
      smtp_datasend($smtp, <<EOF);
From: "Become a Distributor form CGI script" <$sender>
To: $recipient
Subject: Become a Distributor application posted from $origin
X-Origin-User-Agent: $user_agent
User-Agent: $appName/$rcsrev ($rcsdate)
MIME-Version: 1.0
Content-Type: multipart/mixed;
	boundary="$boundary"

EOF
      # Human-readable attachment
      smtp_datasend($smtp, <<EOF);

--$boundary
Content-Type: multipart/alternative;
	boundary="$subboundary"
Content-Description: Human-readable version of the data

EOF
      for my $html_p (0, 1) { # text first, then HTML
	 my $content_type = $html_p? 'text/html': 'text/plain';
	 smtp_datasend($smtp, <<EOF);

--$subboundary
Content-Type: $content_type; charset=iso-8859-1
Content-Transfer-Encoding: Quoted-Printable

EOF
	 qp_send $smtp, ($html_p? <<EOF: '');


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD><title>Posted contact data</title>
<meta name=generator content="subst.pl/1.221 (2001/05/25)">
</HEAD><BODY lang="en"><table>
<tbody>
EOF
	 for my $field (sort {
		  $fields{$a}->[$FIELDS_ORDER] <=> $fields{$b}->[$FIELDS_ORDER]
	       } keys %fields) {

	    my $label = $fields{$field}->[$FIELDS_HEADING];
	    my $val;
	    # such a hack
	    if ($fields{$field}->[$FIELDS_VALTYPE] == $F_MULTIVAL) {
			$val = join(", ", map { if ($_ eq 'Search Engine') {
									$_ = $q->param('Engine_Name'); 
								} elsif ($_ eq 'Others') {
									$_ = $q->param('Other');
								} else { $_; }
			} $q->param($field));
		}
		else {
			$val = $q->param($field);
			if ($val eq '') {
				$val = "(not specified)";
			}
      	}
	    $label = $field unless defined $label;
	    $val =~ s/\r\n/\n/sg;
	    $val =~ s/\r/ /sg;
	    my $data = "$label:";
	    if ($label =~ /\(line \d+\)$/) {
	       $data =~ s/ *\(line \d+\)//;
	       $data =~ s/./ /g;
	    }
	    if ($html_p) {
	       $val =~ s/&/\&amp;/g;
	       $val =~ s/</\&lt;/g;
	       $val =~ s/>/\%gt;/g;
	       $val =~ s/\n/<br>/g;
	       $data = '<tr valign="top"><td align="right">' . $data . ' '
		     . '</td><td align="left">' . $val
		     . '</td></tr>' . "\n";
	    } else {
	       if ($val =~ /\n(?!$)/s) {
		  $data .= "\n$val" . ($val =~ /\n$/s? "\n": "\n\n");
	       } else {
		  $data .= " $val\n";
	       }
	    }
	    qp_send $smtp, $data;
	 }
	 qp_send $smtp, ($html_p? <<EOF: '');


</TBODY></table>
</BODY></html>
EOF
      }
      # Machine-readable attachment
      my $filename = POSIX::strftime("%Y%m%d-%H%M%S-$$.txt", localtime time);
      if ($ENV{HTTP_HOST} =~ /([^\.]+)\.[^\.]+$/) {
	 $filename = "$1-$filename";
      }
      smtp_datasend($smtp, <<EOF);

--$subboundary--

--$boundary
Content-Type: text/plain; name="$filename"
Content-Transfer-Encoding: Quoted-Printable
Content-Description: Data for import into contact manager
Content-Disposition: attachment; filename="$filename"

EOF
	  
      # NOTE: \r\n (not \n) line ending for Windows systems!      
      my @keys = sort { $cm_fields{$a}->[$CM_FIELDS_ORDER]
	    <=> $cm_fields{$b}->[$CM_FIELDS_ORDER] } keys %cm_fields;
      my $data = join("\t", map {
	       my $val = &{$cm_fields{$_}->[$CM_FIELDS_DEF]};
	       $val =~ s/(?:[\t\r\n])/ /sg; # just in case
	       $val =~ s/^ +//s;
	       $val =~ s/ +$//s;
	       $val;
	    } @keys) . "\r\n";
      qp_send $smtp, join("\t", @keys) . "\r\n";
      qp_send $smtp, $data;
      smtp_datasend($smtp, <<EOF);

--$boundary--
EOF
      smtp_dataend($smtp);
      smtp_quit($smtp);
   };
   return $@;
}

sub main () {
   srand(time ^ $$);
   if ($q->virtual_host() =~ /\bsuperbright\.com$/i) {
      $email_sales = 'info@superbright.com';
      $company_name = 'SuperBright';
      $website_name = 'www.superbright.com';
      $products = 'apparel';
   } elsif ($q->virtual_host() =~ /\bhiwalite\.com$/i) {
      $email_sales = 'info@hiwalite.com';
      $company_name = 'HiwaLite';
      $website_name = 'www.hiwalite.com';
      $products = 'products';
   } else {
     #die "Not configured for virtual host " . $q->virtual_host();
     $email_sales = 'info@superbright.com';
     $company_name = 'SuperBright';
     $website_name = 'www.superbright.com';
     $products = 'apparel';
   }
   my $det = $q->param('Submit');
   if (!$q->param) {
      display_contact_us_form;
   } elsif ($det eq $N_CONTINUE) {
      my @errors = validate_form_data;
      if (@errors) {
	 display_contact_us_form(@errors);
      } else {      	
	 my $error = send_mail;
	 if (!$error) {
	    display_acknowledgement_form;
	 } else {
	    display_send_mail_error $error;
	 }
      }
   } else {
      # Illegal value in Submit variable
      display_contact_us_form;
   }
   return 0;
}


1;