"Fossies" - the Fresh Open Source Software Archive

Member "contact.pl" (19 Oct 2017, 79927 Bytes) of package /linux/www/contactform_5_00_00.tar.gz:


The requested HTML page contains a <FORM> tag that is unusable on "Fossies" in "automatic" (rendered) mode so that page is shown as HTML source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "contact.pl" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 4_03_03_vs_5_00_00.

    1 #!/usr/bin/perl -T -w
    2 # Contact Form is a Perl script that you can run on your website that will
    3 # allow others to send you email through a web interface.
    4 # See: http://ostermiller.org/contactform/
    5 # Copyright (C) 2002-2014 Stephen Ostermiller
    6 # http://ostermiller.org/contact.pl?regarding=Contact+Form
    7 #
    8 # This program is free software; you can redistribute it and/or modify
    9 # it under the terms of the GNU General Public License as published by
   10 # the Free Software Foundation; either version 2 of the License, or
   11 # (at your option) any later versicon.
   12 #
   13 # This program is distributed in the hope that it will be useful,
   14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
   15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
   16 # GNU General Public License for more details.
   17 #
   18 # See copying.txt for details.
   19 use strict;
   20 
   21 my($SubmittedData, $mail_message, $AliasesMap, $AliasesOrdered,
   22 $FieldMap, @Field_Order, $template_error, $field_name_to,
   23 $field_name_from_email, $field_name_from_name, $field_name_subject,
   24 $field_name_regarding, $field_name_referrer, $NO_DESCRIPTION,
   25 $VERSION, $LETTER, $DIGIT, $DOSEOL, $EOL, $LETTER_DIGIT,
   26 $LETTER_DIGIT_HYPHEN, $HEX_DIGIT, $QUOTEDSTRING, $ATOM, $SUBDOMAIN, $WORD,
   27 $DOMAIN, $LOCALPART, $EMAIL, $PHONE_DIGIT, $PHONE, $ZIPCODE, $PRICE, $FLOAT,
   28 $INTEGER, $SOMETHING, $ANYTHING, $ONE_LINE_REQUIRED, $ONE_LINE_OPTIONAL,
   29 $ZIPCODE_REQUIRED, $ZIPCODE_OPTIONAL, $PHONE_REQUIRED, $PHONE_OPTIONAL,
   30 $EMAIL_REQUIRED, $EMAIL_OPTIONAL, $PRICE_REQUIRED, $PRICE_OPTIONAL,
   31 $FLOAT_REQUIRED, $FLOAT_OPTIONAL, $INTEGER_REQUIRED, $INTEGER_OPTIONAL,
   32 $BLANK, $PHONE_NO_AREA_CODE_OPTIONAL, $PHONE_NO_AREA_CODE_REQUIRED,
   33 $PHONE_NO_AREA_CODE, $Aliases, $captcha, $FormFields, $disallowed_text,
   34 $translations, $settings,$captchaResult,$userLangs
   35 );
   36 
   37 sub settings(){
   38 
   39     # If the configuration file is set, then anything in the configuration
   40     # file over rides settings directly in this file.
   41     # It is recommended that the configuration file live outside of
   42     # webserver document root and it should be accessed by absolute path
   43     # here.  For example: $settings->{'configuration_file'} = "/etc/contact_form.conf"
   44     $settings->{'configuration_file'} = '';
   45 
   46     # List of email address to which mail can be sent.
   47     #
   48     # Mail cannot be sent to any email address which is not on this list.
   49     # If a single address is listed, it will be a hidden value on the
   50     # form, otherwise, the user will be presented with a pulldown menu
   51     # of aliases to which email can be sent.
   52     # The addresses listed here are never visible via served web pages.
   53     #
   54     # Both the names and the addresses here can be (but don't have to be)
   55     # translated. You might want to translate names for functional duties
   56     # such as 'webmaster' or 'customer support'.  You might want to put in
   57     # translations for the email addresses when different people or teams
   58     # would want to recieve the email in a different language.
   59     $Aliases = [
   60         'contact_administrator_name', 'contact_administrator_email',
   61 
   62         #### The following aliases are commented out examples, remove the leading # sign to use them
   63 
   64         ## A simple example of mail sent to John Smith
   65         #'John Smith','john@yoursite.tld',
   66 
   67         ## Here both the name and the email are translated.
   68         ## Translations can be edited in the translations section.
   69         #'contact_customer_support_name','contact_customer_support_email',
   70 
   71         ## Just the name is translated
   72         #'contact_postmaster_name','postmaster@yoursite.tld',
   73 
   74         ## A mailing list with multiple addresses separated by commas
   75         #'two people','webmaster@yoursite.tld,postmaster@yoursite.tld',
   76     ];
   77 
   78     # The email address that appears in the From and Sender field of sent
   79     # emails.  The email address of the user will then be used in the
   80     # Reply-To field, making it possible to respond to users.
   81     #
   82     # Historically, this contact form has put the user's email address in
   83     # the From field. That doesn't work well. Your mail server may not
   84     # accept mail, or will mark mail as spam, if it is sent on behalf of
   85     # the user but  doesn't come from the user's designated email server.
   86     # This behavior is still available by specifying 'user' as the value.
   87     #
   88     # If this is left blank, the from Field will be the same as the To field.
   89     #
   90     # Example: $settings->{'sender_email'} = "john.smith@example.com";
   91     $settings->{'sender_email'} = '';
   92 
   93     # Modify the following to control how the HTML pages look
   94 
   95     # Page structure -- the look and feel of the page
   96     # This variable may be either changed directly, or if the
   97     # page_template_file variable is set, this variable is
   98     # ignored and the template file is used instead.
   99     # Contact form can place content into any of four places:
  100     # $title -- the title of the page
  101     # $meta - meta tags such as rel canonical
  102     # $css -- style rules that control how the form looks
  103     # $javascript -- client side validation rules.
  104     # $content -- the form itself.
  105     # The css and title variables are optional and can easily
  106     # be omitted and replaced with your own elements to better
  107     # suit your taste.  The form will not work properly if either
  108     # the javascript or content variables are removed or duplicated.
  109     # This may be a translation key for providing different templates
  110     # for different languages.
  111     $settings->{'page_template'} =
  112     '<!DOCTYPE html>
  113     <html>
  114     <head>
  115     <title>$title</title>
  116     $meta
  117     $css
  118     $javascript
  119     </head>
  120     <body class="contactform cf_body" id="cf_body">
  121     <h1 class="contactform cf_header" id="cf_titleheader">$title</h1>
  122     $content
  123     </body>
  124     </html>
  125     ';
  126 
  127     # if the template file is set, the page_template variable
  128     # is ignored and the template is loaded from the named file.
  129     # for example:
  130     # $settings->{'page_template_file'} = "mytemplate.html";
  131     # or
  132     # $settings->{'page_template_file'} = "/home/me/contact.template";
  133     # If this file is set, the file will be read every time this script
  134     # is called, not the most efficient, but very convenient.
  135     # The template file must be in the same format as the page_template
  136     # variable above
  137     $settings->{'page_template_file'} = '';
  138 
  139     # Whether or not to show a link to the contact form website.
  140     # Set to 0 to disable.
  141     # If you do remove the link, please tell your friends about contact form,
  142     # link to contact form somewhere else, write a blog entry about
  143     # contact form, post in a forum about contact form, or otherwise
  144     # spread the word.
  145     $settings->{'show_contact_form_link'} = 1;
  146 
  147     # FormFields is the list of questions the user is expected
  148     # to answer. The questions will appear in the same order as
  149     # they are ordered here. You may safely remove the subject,
  150     # email, name, and message from the form. The to field should
  151     # not be removed. The name of each field should contain only
  152     # letters, numbers, and underscore.  Spaces or symbols should
  153     # not be used.  Each has several attributes that control the
  154     # display of the question to the user.
  155     #
  156     # "required"
  157     # a regular expression that describes what a valid submission looks
  158     # like.  By default, any entry at all is allowed.
  159     # Consider using the following pre-defined regular expressions:
  160     # $SOMETHING, $ANYTHING, $ONE_LINE_REQUIRED, $ONE_LINE_OPTIONAL,
  161     # $ZIPCODE_REQUIRED, $ZIPCODE_OPTIONAL, $PHONE_REQUIRED,
  162     # $PHONE_OPTIONAL, $EMAIL_REQUIRED, $EMAIL_OPTIONAL, $PRICE_REQUIRED,
  163     # $PRICE_OPTIONAL, $FLOAT_REQUIRED, $FLOAT_OPTIONAL,
  164     # $INTEGER_REQUIRED, $INTEGER_OPTIONAL, $BLANK, $PHONE_NO_AREA_CODE_OPTIONAL,
  165     # $PHONE_NO_AREA_CODE_REQUIRED
  166     #
  167     # "error"
  168     # A user friendly error message for each required
  169     # element that a user gets wrong.
  170     #
  171     # "type"
  172     # Type of input in web pages for each field.
  173     # Currently supported are 'text', 'hidden', 'radio',
  174     # 'select', and 'textarea'
  175     # If there is no type, 'text' is assumed.
  176     # Setting the type for the to field will have no effect since
  177     # the to field is handled specially.
  178     #
  179     # "description"
  180     # Description to appear next to entry forms and in
  181     # the email or $NO_DESCRIPTION for none
  182     # If no description is given the field name followed
  183     # by a colon is used
  184     #
  185     # "selected"
  186     # For fields of type "select", or "radio" indicates
  187     # the default selection
  188     #
  189     # "special"
  190     # Any special purpose for which the field is used.
  191     # Must be one of "to", "from", "name", "subject",
  192     # "regarding", or "referrer"
  193     #
  194     $FormFields = [
  195         'to', {
  196             'required' => $ONE_LINE_REQUIRED,
  197             'error' => 'field_to_error.',
  198             'description' => 'field_to_description',
  199             # Alias of the address put in the "To:" field of the email.
  200             'special' => 'to',
  201             'show_in_message' => 'false',
  202         },
  203         'email', {
  204             'required' => $EMAIL_REQUIRED,
  205             'error' => 'field_email_error',
  206             'type' => 'text',
  207             'description' => 'field_email_description',
  208             # Put in the "From:" field of the email as the email of the person it is from
  209             'special' => 'from',
  210             'show_in_message' => 'false',
  211         },
  212         'confirm', {
  213             # This is a field designed to thwart automated submissions
  214             # This field is not visible to the user.
  215             # Bots may attempt to fill it in which will prevent submission.
  216             'required' => $BLANK,
  217             'error' => 'field_trap_error',
  218             'type' => 'trap',
  219             'description' => 'field_trap_description',
  220         },
  221         'name', {
  222             'required' => $ONE_LINE_OPTIONAL,
  223             'error' => 'field_name_error',
  224             'type' => 'text',
  225             'description' => 'field_name_description',
  226             # Put in the "From:" field of the email as the name of the person it is from
  227             'special' => 'name',
  228             'show_in_message' => 'false',
  229         },
  230         'subject', {
  231             'required' => $ONE_LINE_REQUIRED,
  232             'error' => 'field_subject_error',
  233             'type' => 'text',
  234             'description' => 'field_subject_description',
  235             # Put in the "Subject:" field of the email.
  236             'special' => 'subject',
  237             'show_in_message' => 'false',
  238         },
  239         'message', {
  240             'required' => $SOMETHING,
  241             'error' => 'field_message_error',
  242             'type' => 'textarea',
  243             'description' => $NO_DESCRIPTION,
  244         },
  245         'regarding', {
  246             'required' => $ANYTHING,
  247             'error' => '',
  248             'type' => 'hidden',
  249             'description' => $NO_DESCRIPTION,
  250             # Put in the "Subject:" field of the email in parenthesis.
  251             'special' => 'regarding',
  252             'show_in_message' => 'false',
  253         },
  254         'referrer', {
  255             'required' => $ANYTHING,
  256             'error' => '',
  257             'type' => 'hidden',
  258             'description' => $NO_DESCRIPTION,
  259             # The original referring url.
  260             'special' => 'referrer',
  261             'show_in_message' => 'false',
  262         },
  263         # The following fields are disabled examples, remove the 'enabled' => 1 line to use them
  264         'phone', {
  265             'required' => $PHONE_OPTIONAL,
  266             'error' => 'field_phone_error',
  267             'type' => 'text',
  268             'description' => 'field_phone_description',
  269             'enabled' => 0,
  270         },
  271         'fax', {
  272             'required' => $PHONE_OPTIONAL,
  273             'error' => 'field_fax_error',
  274             'type' => 'text',
  275             'description' => 'field_fax_description',
  276             'enabled' => 0,
  277         },
  278         'address1', {
  279             'required' => $ONE_LINE_OPTIONAL,
  280             'error' => 'field_address_error',
  281             'type' => 'text',
  282             'description' => 'field_address_description',
  283             'enabled' => 0,
  284         },
  285         'address2', {
  286             'required' => $ONE_LINE_OPTIONAL,
  287             'error' => 'field_address_error',
  288             'type' => 'text',
  289             'description' => $NO_DESCRIPTION,
  290             'enabled' => 0,
  291         },
  292         'city', {
  293             'required' => '^(?:[a-zA-Z ]*)$',
  294             'error' => 'field_city_error',
  295             'type' => 'text',
  296             'description' => 'field_city_description',
  297             'enabled' => 0,
  298         },
  299         'state', {
  300             'required' => '^(?:AL|AK|AS|AZ|AR|CA|CO|CT|DE|DC|FL|GA|GU|HI|ID|IL|IN|IA|KS|KY|LA|ME|MD|MH|MA|MI|FM|MN|MS|MO|MT|NE|NV|NH|NJ|NM|NY|NC|ND|MP|OH|OK|OR|PW|PA|PR|RI|SC|SD|TN|TX|UT|VT|VA|VI|WA|WV|WI|WY)$',
  301             'error' => 'field_state_error',
  302             'type' => 'select',
  303             'description' => 'field_state_description',
  304             'enabled' => 0,
  305         },
  306         'zip', {
  307             'required' => $ZIPCODE_OPTIONAL,
  308             'error' => 'field_zip_error',
  309             'type' => 'text',
  310             'description' => 'field_zip_description',
  311             'enabled' => 0,
  312         },
  313         'most_basic_question', {
  314             # uses the default values for required, error, type, and description
  315             'enabled' => 0,
  316         },
  317         'color', {
  318             # A required select drop down
  319             'type' => 'select',
  320             'required' => 'field_color_required',
  321             'error' => 'field_color_error',
  322             'description' => 'field_color_description',
  323             'enabled' => 0,
  324         },
  325         'vegetable', {
  326             # An optional select drop down
  327             'type' => 'select',
  328             'required' => 'field_vegetable_required',
  329             'error' => 'field_vegetable_description',
  330             'description' => 'field_vegetable_description',
  331             'enabled' => 0,
  332         },
  333         'letter', {
  334             # A select drop down with a pre-filled option
  335             'type' => 'select',
  336             'required' => 'field_letter_required',
  337             'error' => 'field_letter_error',
  338             'description' => 'field_letter_description',
  339             'selected' => 'field_letter_selected',
  340             'enabled' => 0,
  341         },
  342         'yes_no', {
  343             # required radio buttons
  344             'type' => 'radio',
  345             'required' => 'field_yes_no_required',
  346             'error' => 'field_yes_no_error',
  347             'description' => 'field_yes_no_description',
  348             'enabled' => 0,
  349         },
  350         'true_false', {
  351             # radio buttons with a prefilled option
  352             'type' => 'radio',
  353             'required' => 'field_true_false_required',
  354             'error' => 'field_true_false_error',
  355             'description' => 'field_true_false_description',
  356             'selected' => 'field_true_false_selected',
  357             'enabled' => 0,
  358         },
  359         'vegetable2', {
  360             # optional radio buttons
  361             'type' => 'radio',
  362             'required' => 'field_vegetable2_required',
  363             'error' => 'field_vegetable_error',
  364             'description' => 'field_vegetable_description',
  365             'enabled' => 0,
  366         },
  367         'about', {
  368             # prefilled
  369             'type' => 'text',
  370             'required' => $ANYTHING,
  371             'error' => 'field_about_error',
  372             'description' => 'field_about_description',
  373             'default' => 'field_about_default',
  374             'enabled' => 0,
  375         },
  376     ];
  377 
  378     # Captcha settings -- Displays distorted text that the user
  379     # must type in to prove that they are human.
  380     # Sign up for a recaptach account at https://www.google.com/recaptcha/
  381     # enter the site and secret keys that they give you here
  382     # Your server must have the Captcha::reCAPTCHA::V2 library installed.
  383     # To install it, talk to your admin or use the command line:
  384     # cpan install 'Captcha::reCAPTCHA::V2'
  385     $settings->{'recaptcha_site_key'} = '';
  386     $settings->{'recaptcha_secret_key'} = '';
  387 
  388     # The name of the field for submit/preview action
  389     $settings->{'field_name_submit'} = 'do';
  390 
  391     # Regular expression describing urls which can host forms
  392     # pointing to this program. The referral URL is generated on the
  393     # client side by the browser. Therefore it useless to prevent
  394     # unauthorized submission by mail software robots. You can
  395     # prevent somebody from reliably hosting, on another server,
  396     # a form pointing to this email software.
  397     # Consider the following options:
  398     # This form can be used from any site at all: .*
  399     # This form can only be used from pages on yoursite.tld: ^http[s]?\:\/\/yoursite\.tld\/
  400     # This form can only be used from pages on the domain or ip address: ^http[s]?\:\/\/((yoursite\.tld)|(127\.0\.0\.1))\/
  401     # This form can only be used from a specific page: ^http[s]?\:\/\/yoursite\.tld\/directory\/page\.html\$
  402     $settings->{'allowedReferers'} = '.*';
  403 
  404     # Regular expressions for text that is not allowed in any fields.
  405     # Messages may be translation keys.
  406     $disallowed_text = {
  407         "\\<[ \\r\\n\\t]*[Aa][ \\r\\n\\t]","error_disallow_html_formatted_links",
  408         "\\[[ \\r\\n\\t]*[Uu][Rr][Ll][ \\r\\n\\t]*\\=","error_disallow_board_formatted_links",
  409     };
  410 
  411     # Whether or not users are required to preview
  412     # their message before sending.
  413     # 0 -- preview disabled (allows users to send mail the fastest)
  414     # 1 -- preview required (best for spam prevention)
  415     # 2 -- preview available, but not required  (most choice for users)
  416     $settings->{'require_preview'} = 1;
  417 
  418     # Whether or not to include the "To: <alias>" field in the email body.
  419     # This is usually desired when there are multiple recipients so that
  420     # each recipient can tell that the email was sent to multiple people.
  421     # yes -- always include the to field
  422     # multiple -- include the to field only when there are multiple recipients
  423     # no -- do not include the to field
  424     $settings->{'show_to_in_message'} = 'multiple';
  425 
  426     # The character set for the contact page.
  427     $settings->{'charset'} = 'UTF-8';
  428 
  429     # Command line program used to send email
  430     # '/usr/lib/sendmail -i -t' almost always works fine
  431     $settings->{'sendmail'} = '/usr/lib/sendmail -i -t';
  432 
  433     # Whether or not to include javascript that checks the form
  434     # before it is submitted.
  435     # This is generally good, but it increases the page size, increases the
  436     # complexity of the page, and could alert hackers to the
  437     # regular expressions you are using for verification.
  438     # Set to 0 to disable, 1 to enable.
  439     $settings->{'use_client_side_verification'} = 1;
  440 
  441     # This should be either 'POST' or 'GET'
  442     $settings->{'submit_method'} = 'POST';
  443 
  444     # Placed next to form elements that must be filled in
  445     # The required marker can be set to a translation key
  446     # such that translated text for something like "REQUIRED"
  447     # is shown to users rather than an asterisk.
  448     $settings->{'required_marker'} = '<span class="contactform cf_required">*</span>';
  449 
  450     # Text that should always go at the beginning of the subject
  451     # of emails that this contact form sends out.  This could be
  452     # useful as a signal for filtering email or seeing which emails
  453     # come in through contact form when scanning your inbox.
  454     # eg $settings->{'subject_prepend'} = '[WEB]';
  455     # This may be (but does not have to be) set to a translation key.
  456     $settings->{'subject_prepend'} = '';
  457 
  458     # Style rules for the input page.
  459     # to put question and answer on the same line use:
  460     # .cf_userentry, .cf_radioselection { display:inline; margin-left:0.25cm; }
  461     $settings->{'input_page_css'} =
  462     '<style>
  463     .cf_error { color:red; }
  464     .cf_textentry { min-width:300px; width:100%; max-width:600px; width:expression(document.body.clientWidth>600?"600px":"auto");}
  465     .cf_instructions { margin-bottom:1em; }
  466     textarea.contactform { height:4in; }
  467     .cf_required { color:green; }
  468     #cf_version { text-align:right; }
  469     #cf_global_error { margin-bottom:0.25cm; }
  470     .cf_field { margin-bottom:0.5cm; }
  471     .cf_nt { display:none; }
  472     .cf_preview { border:thin black ridge; padding:1cm; max-width:600px; width:expression(document.body.clientWidth>600?"600px":"auto");margin-bottom:1cm;}
  473     </style>
  474     ';
  475 
  476     # Style rules for thank you page
  477     $settings->{'sent_page_css'} =
  478     '<style>
  479     .cf_thankyou { margin-bottom:1em; }
  480     .cf_sent { border:thin black ridge; padding:1cm; max-width:600px; width:expression(document.body.clientWidth>600?"600px":"auto");}
  481     #cf_version { text-align:right; }
  482     </style>';
  483 
  484     # Link to favicon, placed in the head after the JavaScript
  485     $settings->{'icon_link'}='<link rel="icon" href="'.&escapeHTML($ENV{'SCRIPT_NAME'}).'/contactformicon.png" type="image/png">';
  486 
  487     # Form copyright header placed in the head after the JavaScript
  488     $settings->{'copyright_link'} = '<link rel="copyright" href="http://ostermiller.org/contactform/" type="text/html">';
  489 
  490     # Redirect to this url after the message has been sent
  491     # By default there is no redirect.  The url must
  492     # be fully qualified (must start with http://)
  493     # Example: $settings->{'redirect_url_sent'} = "http://example.com/";
  494     # This may be set to a translation key for redirecting to different
  495     # urls in different languages.
  496     $settings->{'redirect_url_sent'} = "";
  497 
  498     # Show the sent confirmation for this many seconds before redirecting
  499     # after the message has been sent if the redirect_url_sent has been defined.
  500     # If zero is specified, the message sent confirmation will not
  501     # be shown at all (you can redirect to your own thank you)
  502     $settings->{'redirect_delay_sent'} = 15;
  503 
  504     # The language to display to the user if the users preferred
  505     # language cannot be determined.
  506     $settings->{'default_language'} = 'en';
  507 
  508     # A list of allowed languages separated by spaces.
  509     # eg $settings->{'allowed_languages'} = 'en en_US fr de';
  510     # Contact form will only be shown in the languages listed.
  511     # If allowed_languages is blank, then any language for which
  512     # translations exist may be shown.
  513     $settings->{'allowed_languages'} = '';
  514 
  515     # Parameter name that specifies the language in which
  516     # contact form should be shown or blank not to use.
  517     # If this parameter is not used or not present,
  518     # contact form tries to detect the language from the
  519     # users browser settings, then falls back to the default
  520     # language setting.  A link to contact form with the param
  521     # might look something like this:
  522     # /contact.pl?cflang=de
  523     $settings->{'language_param'} = 'cflang';
  524 
  525     # The text shown to users by contact form. Each item should be
  526     # translated into each language used.
  527     #
  528     # Language keys: lower case two letter language code, optionally
  529     # followed by an underscore and uppercase two letter country code.
  530     # eg. en or en_US
  531     #
  532     # Translation keys: All lowercase letters, numbers, and underscores.
  533     # Each must contain at least one underscore.  New keys may be
  534     # added when adding new fields.
  535     #
  536     # NOTE to translators: Use a UTF-8 capable editor when saving
  537     # translations.  Text in curly braces in the translations such
  538     # as {required_marker} or {server_administrator} is replaced
  539     # automatically and should not be translated.
  540     $translations = {
  541         # English
  542         'en' => {
  543             # Core messaging
  544             'input_page_title' => 'Contact Us',
  545             'input_page_instructions' => 'Fill out the form below to send your comments.',
  546             'required_marker_description' => '{required_marker} denotes a required field.',
  547             'preview_button' => 'Preview',
  548             'send_button' => 'Send',
  549             'preview_page_instructions' => 'Please review your message before sending it. Changes can be made below.',
  550             'sent_page_title' => 'Message Sent',
  551             'sent_page_thank_you' => 'Thank you for your comments!',
  552             'email_header_to' => 'To:',
  553             'email_header_from' => 'From:',
  554             'email_header_subject' => 'Subject:',
  555             'contact_form_version' => 'Contact Form {version_number}',
  556             # Core fields
  557             'field_to_description' => 'To',
  558             'field_to_error' => 'You must specify a recipient.',
  559             'field_email_description' => 'Your email address:',
  560             'field_email_error' => 'The email address you entered does not appear to be valid.',
  561             'field_email_default' => 'nobody',
  562             'field_trap_description' => 'Leave blank:',
  563             'field_trap_error' => 'This field should be left blank.',
  564             'field_name_description' => 'Your name:',
  565             'field_name_error' => 'You must enter your name.',
  566             'field_subject_description' => 'Subject:',
  567             'field_subject_error' => 'You must enter a subject.',
  568             'field_subject_default' => 'Website Form Submission',
  569             'field_message_error' => 'You must enter a message.',
  570             'field_captcha_description' => 'Prove that you are a human:',
  571             'field_captcha_error' => 'Captcha problem',
  572             # Error messaging
  573             'error_get_post_only' => "This form must be submitted via either 'GET' or 'POST'.",
  574             'error_bad_referrer' => 'This form cannot be submitted from {referrer}.',
  575             'error_bad_recipient' => 'Your message cannot be sent to the specified recipient.',
  576             'error_generic_field' => "The field '{field_key}' does not appear to be valid.",
  577             'error_correction_required' => 'Please correct the error to continue.',
  578             'error_corrections_required' => 'Please correct all errors to continue.',
  579             'error_disallow_html_formatted_links' => 'You appear to be trying to include HTML formatted links.  Links should not be formatted like this.',
  580             'error_disallow_board_formatted_links' => 'You appear to be trying to include message board formatted links.  Links should not be formatted like this.',
  581             'error_module_missing_title' => '{perl_module} Perl Module Not Installed',
  582             'error_module_missing_no_config_file' => 'Install the {perl_module} module or do not use the configuration file feature',
  583             'error_module_missing_no_captcha' => 'Install the {perl_module} module or do not use the captcha feature',
  584             'error_bad_config_file_title' => 'Could Not Read Configuration File',
  585             'error_bad_config_file' => 'Check configuration file existence, permissions, and validity of XML; or do not use a configuration file.',
  586             'error_template_file_problem' => 'The template file could not be opened.',
  587             # Configuration examples
  588             'contact_administrator_name' => 'administrator',
  589             'contact_customer_support_name' => 'Customer Support',
  590             'contact_customer_support_email' => 'support@yoursite.tld',
  591             'contact_postmaster_name' => 'postmaster',
  592             'field_phone_error' => 'The phone number you entered does not appear to be valid.',
  593             'field_phone_description' => 'Phone Number:',
  594             'field_fax_error' => 'The fax number you entered does not appear to be valid.',
  595             'field_fax_description' => 'Fax Number:',
  596             'field_address_error' => 'Please enter your address.',
  597             'field_address_description' => 'Address:',
  598             'field_city_error' => 'Your city does not appear to be valid.',
  599             'field_city_description' => 'City:',
  600             'field_state_error' => 'Please choose your state.',
  601             'field_state_description' => 'State:',
  602             'field_zip_error' => 'Your zipcode does not appear to be valid.',
  603             'field_zip_description' => 'Zipcode:',
  604             'field_color_required' => '^(?:Red|Orange|Yellow|Green|Blue|Purple|Black|White)$',
  605             'field_color_error' => 'Please choose a color.',
  606             'field_color_description' => 'Choose a color:',
  607             'field_vegetable_required' => '^(?:|Corn|Peas|Beans|Carrots|Broccoli)$',
  608             'field_vegetable_error' => 'Please choose a valid vegetable.',
  609             'field_vegetable_description' => 'Which (if any) is your favorite vegetable:',
  610             'field_letter_required' => '^(?:A|B|C|D)$',
  611             'field_letter_error' => 'Please choose on of the four letters.',
  612             'field_letter_description' => 'Choose a letter (C is selected by default):',
  613             'field_letter_selected' => 'C',
  614             'field_yes_no_required' => '^(?:yes|no)$',
  615             'field_yes_no_error' => 'Please answer the yes/no question',
  616             'field_yes_no_description' => 'Yes or no:',
  617             'field_true_false_required' => '^(?:true|false)$',
  618             'field_true_false_error' => 'Please answer the true/false question',
  619             'field_true_false_description' => 'True or false (false is selected by default):',
  620             'field_true_false_selected' => 'false',
  621             'field_vegetable2_required' => '^(?:|Lettuce|Tomato|Brussel Sprouts)$',
  622             'field_about_error' => 'Please enter what this message is about.',
  623             'field_about_description' => 'What is this message about:',
  624             'field_about_default' => 'Email',
  625             # No translation needed
  626             'contact_administrator_email' => '{server_admin}',
  627         },
  628         # Dutch (Nederlands)
  629         # Copyright 2011 Piet Tutelaers
  630         # http://tuite.nl/contact.html
  631         'nl' => {
  632             # Hoofdmeldingen
  633             'input_page_title' => 'Neem contact met ons op',
  634             'input_page_instructions' => 'Vul dit formulier in als u opmerkingen heeft.',
  635             'required_marker_description' => '{required_marker} geeft een verplicht veld aan.',
  636             'preview_button' => 'Bericht bekijken',
  637             'send_button' => 'Versturen',
  638             'preview_page_instructions' => 'Controleer uw bericht a.u.b. voordat u het gaat versturen. Veranderingen kunnen hieronder worden aangebracht.',
  639             'sent_page_title' => 'Bericht verstuurd',
  640             'sent_page_thank_you' => 'Bedankt voor uw commentaar!',
  641             'email_header_to' => 'Aan:',
  642             'email_header_from' => 'Van:',
  643             'email_header_subject' => 'Onderwerp:',
  644             'contact_form_version' => 'Contactformulier {version_number}',
  645             # Hoofdvelden
  646             'field_to_description' => 'Aan',
  647             'field_to_error' => 'U moet een geadresseerde opgeven.',
  648             'field_email_description' => 'Uw e-mailadres:',
  649             'field_email_error' => 'Het door u opgegeven e-mailadres klopt niet.',
  650             'field_email_default' => 'onbekend',
  651             'field_trap_description' => 'Blanco laten:',
  652             'field_trap_error' => 'Dit veld blanco laten.',
  653             'field_name_description' => 'Uw naam:',
  654             'field_name_error' => 'Vul hier uw naam in.',
  655             'field_subject_description' => 'Onderwerp:',
  656             'field_subject_error' => 'U moet hier een onderwerp opgeven.',
  657             'field_subject_default' => 'Website formulier verzending',
  658             'field_message_error' => 'U moet hier een bericht invoeren.',
  659             'field_captcha_description' => 'Bewijs dat u een mens bent:',
  660             'field_captcha_error' => 'Captcha probleem',
  661             # Foutmeldingen
  662             'error_get_post_only' => "Dit formulier moet worden verstuurd via 'GET' of 'POST'.",
  663             'error_bad_referrer' => 'Dit formulier kan niet worden verstuurd van {referrer}.',
  664             'error_bad_recipient' => 'Uw bericht kan niet worden verstuurd naar de opgegeven geadresseerde.',
  665             'error_generic_field' => "Het opgegeven veld '{field_key}' lijkt niet te bestaan.",
  666             'error_correction_required' => 'Korrigeer de fout voordat u verder gaat.',
  667             'error_corrections_required' => 'Korrigeer alle fouten voordat u verder gaat.',
  668             'error_disallow_html_formatted_links' => 'Het lijkt erop dat u links gebruikt in HTML formaat. Dergelijke links kunnen niet gebruikt worden.',
  669             'error_disallow_board_formatted_links' => 'Het lijkt erop dat u links gebruikt in prikbord formaat. Dergelijke links kunnen niet gebruikt worden.',
  670             'error_module_missing_title' => '{perl_module} Perl module niet geïnstalleerd.',
  671             'error_module_missing_no_config_file' => 'Installeer de {perl_module} module of gebruik geen configuratiebestand".',
  672             'error_module_missing_no_captcha' => 'Installeer de {perl_module} module of gebruik geen "captcha".',
  673             'error_bad_config_file_title' => 'Configuratiebestand kan niet gelezen worden',
  674             'error_bad_config_file' => 'Controleer of er een configuratiebestand aanwezig is, de permissies en geldigheid van de XML; of gebruik geen configuratiebestand.',
  675             'error_template_file_problem' => 'Het templatebestand kan niet worden geopend.',
  676             # Configuratie voorbeelden
  677             'contact_administrator_name' => 'beheerder',
  678             'contact_customer_support_name' => 'Klantenondersteuning',
  679             'contact_customer_support_email' => 'support@yoursite.tld',
  680             'contact_postmaster_name' => 'postmaster',
  681             'field_phone_error' => 'Het opgegeven telefoonnummer lijkt ongeldig.',
  682             'field_phone_description' => 'Telefoonnummer:',
  683             'field_fax_error' => 'Het opgegeven faxnummer lijkt ongeldig.',
  684             'field_fax_description' => 'Faxnummer:',
  685             'field_address_error' => 'Geef a.u.b. uw adres.',
  686             'field_address_description' => 'Adres:',
  687             'field_city_error' => 'De opgegeven woonplaats lijkt ongeldig.',
  688             'field_city_description' => 'Woonplaats:',
  689             'field_state_error' => 'Geef a.u.b. uw provincie.',
  690             'field_state_description' => 'Provincie:',
  691             'field_zip_error' => 'De opgegeven postcode lijkt ongeldig.',
  692             'field_zip_description' => 'Postcode:',
  693             'field_color_required' => '^(?:Rood|Oranje|Geel|Groen|Blauw|Paars|Zwart|Wit)$',
  694             'field_color_error' => 'Kies een kleur a.u.b.',
  695             'field_color_description' => 'Kies een kleur:',
  696             'field_vegetable_required' => '^(?:|Maïs|Erwten|Bonen|Wortels|Broccoli)$',
  697             'field_vegetable_error' => 'Kies een geldige groente a.u.b.',
  698             'field_vegetable_description' => 'Wat (indien van toepassing) is je favouriete groente:',
  699             'field_letter_required' => '^(?:A|B|C|D)$',
  700             'field_letter_error' => 'Kies a.u.b. één van de vier letters.',
  701             'field_letter_description' => 'Kies een letter (anders wordt C gekozen):',
  702             'field_letter_selected' => 'C',
  703             'field_yes_no_required' => '^(?:ja|nee)$',
  704             'field_yes_no_error' => 'Beantwoord a.u.b. de ja/nee vraag',
  705             'field_yes_no_description' => 'Ja of nee:',
  706             'field_true_false_required' => '^(?:waar|onwaar)$',
  707             'field_true_false_error' => 'Beantwoord a.u.b. de waar/onwaar vraag',
  708             'field_true_false_description' => 'Waar of onwaar (onwaar is standaard):',
  709             'field_true_false_selected' => 'onwaar',
  710             'field_vegetable2_required' => '^(?:|Sla|Tomaat|Spruitjes)$',
  711             'field_about_error' => 'Geef a.u.b. aan waarover dit bericht gaat.',
  712             'field_about_description' => 'Waarover gaat dit bericht:',
  713             'field_about_default' => 'E-mail',
  714         },
  715         # Pig Latin (for testing)
  716         'pig' => {
  717             # Core messaging
  718             'input_page_title' => 'Ontactcay Uslay',
  719             'input_page_instructions' => 'Illfay outyay ethay ormfay elowbay ootay endsay oryay ommentscay.',
  720             'required_marker_description' => '{required_marker} enotesday ayay equiredray ieldfay.',
  721             'preview_button' => 'Eviewpray',
  722             'send_button' => 'Endsay',
  723             'preview_page_instructions' => 'Easeplay eviewray oryay essagemay eforeBay endingsay ityay. Angeschay ancay ebay ademay elowbay.',
  724             'sent_page_title' => 'Essagemay Entsay',
  725             'sent_page_thank_you' => 'Ankthay ooyay orfay oryay ommentsCay!',
  726             'email_header_to' => 'Ootay:',
  727             'email_header_from' => 'Omfray:',
  728             'email_header_subject' => 'Ubjectsay:',
  729             'contact_form_version' => 'Ontactcay Ormfay {version_number}',
  730             # Core fields
  731             'field_to_description' => 'Ootay:',
  732             'field_to_error' => 'Ouyay ustmay ecifyspay ayay ecipientray.',
  733             'field_email_description' => 'Ouryay emailyay addressyay:',
  734             'field_email_error' => 'Ethay emailyay addressyay ouyay enteredyay oesday otnay appearyay ootay ebay alidvay.',
  735             'field_trap_description' => 'Eavelay ankblay:',
  736             'field_trap_error' => 'Isthay ieldfay ouldshay ebay eftlay ankblay.',
  737             'field_name_description' => 'Ouryay amenay:',
  738             'field_name_error' => 'Ouyay ustmay enteryay ouryay amenay.',
  739             'field_subject_description' => 'Ubjectsay:',
  740             'field_subject_error' => 'Ouyay ustmay enteryay ayay ubjectsay.',
  741             'field_message_error' => 'Ouyay ustmay enteryay ayay essagemay.',
  742             'field_captcha_description' => 'Ovepray atthay ouyay areyay ayay umanhay:',
  743             'field_captcha_error' => 'Aptchacay oblempray',
  744             # Error messaging
  745             'error_get_post_only' => "Isthay ormfay ustmay ebay ubmittedsay iavay eitheryay 'GET' oryay 'POST'.",
  746             'error_bad_referrer' => 'Isthay ormfay annotcay ebay ubmittedsay romfay {referrer}.',
  747             'error_bad_recipient' => 'Oryay essagemay annotcay ebay entsay ootay ethey ecifiedspay ecipientray.',
  748             'error_generic_field' => "Ethay ielday '{field_key}' oesday otnay appearyay ootay ebay alidvay.",
  749             'error_correction_required' => 'Easeplay orrectcay ethay erroryay ootay ontinuecay.',
  750             'error_corrections_required' => 'Easeplay orrectcay allyay errorsyay ootay ontinuecay.',
  751             'error_disallow_html_formatted_links' => 'Ouyay appearyay ootay ebay yingtray ootay includeyay HTML ormattedfay inkslay.  Inkslay ouldshay otnay ebay ormattedfay ikelay isthay.',
  752             'error_disallow_board_formatted_links' => 'Ouyay appearyay ootay ebay yingtray ootay includeyay essagemay oardbay ormattedfay inkslay.  Inkslay ouldshay otnay ebay ormattedfay ikelay isthay.',
  753             'error_module_missing_title' => '{perl_module} Erlpay Odulemay Otnay Installedyay',
  754             'error_module_missing_no_config_file' => 'Installyay ethay {perl_module} odulemay oryay ooday otnay useyay ethay onfigurationcay ilefay eaturefay',
  755             'error_module_missing_no_captcha' => 'Installyay ethay {perl_module} odulemay oryay ooday otnay useyay ethay aptchacay eaturefay',
  756             'error_bad_config_file_title' => 'Ouldcay Otnay Eadray Onfigurationcay Ilefay',
  757             'error_bad_config_file' => 'Eckchay onfigurationcay ilefay existenceyay, ermissionspay, andyay alidityvay ofyay XML; oryay ooday otnay useyay ayay onfigurationcay ilefay.',
  758             'error_template_file_problem' => 'Ethay emplatetay ilefay ouldcay otnay ebay openedyay.',
  759             'field_captcha_error' => 'Aptchacay oblempray',
  760             'contact_administrator_name' => 'administratoryay',
  761             'field_email_default' => 'obodynay',
  762             # Configuration examples
  763             'contact_customer_support_name' => 'Ustomercay Upportsay',
  764             'contact_customer_support_email' => 'upportsay@ouyayrsite.tld',
  765             'contact_postmaster_name' => 'ostmasterpay',
  766             'field_onephay_error' => 'Ethay onephay umbernay ouyay enteredyay oesday otnay appearyayyay ootay ebay alidvay.',
  767             'field_onephay_description' => 'Onephay umbernay:',
  768             'field_fax_error' => 'Ethay axfay umbernay ouyay enteredyay oesday otnay appearyay ootay ebay alidvay.',
  769             'field_fax_description' => 'Axfay Umbernay:',
  770             'field_address_error' => 'Easeplay enteryay ouyayr addressyay.',
  771             'field_address_description' => 'Addressyay:',
  772             'field_city_error' => 'Ouryay itycay oesday otnay appearyay ootay ebay alidvay.',
  773             'field_city_description' => 'Itycay:',
  774             'field_state_error' => 'Easeplay oosechay ouyayr atestay.',
  775             'field_state_description' => 'Atestay:',
  776             'field_zip_error' => 'Ouryay ipcodezay oesday otnay appearyay ootay ebay alidvay.',
  777             'field_zip_description' => 'Ipcodezay:',
  778             'field_color_required' => '^(?:Edray|Orangeyay|Ellowyay|Eengray|Ueblay|Urplepay|Ackblay|Itewhay)$',
  779             'field_color_error' => 'Easeplay oosechay ayay olorcay.',
  780             'field_color_description' => 'Choose ayay olorcay:',
  781             'field_vegetable_required' => '^(?:|Orncay|Easpay|Eansbay|Arrotscay|Occolibray)$',
  782             'field_vegetable_error' => 'Easeplay oosechay ayay alidvay egetablevay.',
  783             'field_vegetable_description' => 'Ichwhay (ifyay anyay) isyay ouyayr avoritefay egetablevay:',
  784             'field_letter_required' => '^(?:Ayay|Byay|Cyay|Dyay)$',
  785             'field_letter_error' => 'Easeplay oosechay onyay ofyay ethay ourfay etterslay.',
  786             'field_letter_description' => 'Oosechay ayay etterlay (Cyay isyay electedsay ybay efaultday):',
  787             'field_letter_selected' => 'Cyay',
  788             'field_yes_no_required' => '^(?:esyay|onay)$',
  789             'field_yes_no_error' => 'Easeplay answeryay ethay esyay/onay estionquay',
  790             'field_yes_no_description' => 'Esyay or onay:',
  791             'field_true_false_required' => '^(?:uetray|alsefay)$',
  792             'field_true_false_error' => 'Easeplay answeryay ethay uetray/alsefay estionquay',
  793             'field_true_false_description' => 'Uetray or alsefay (alsefay isyay electedsay ybay efaultday):',
  794             'field_true_false_selected' => 'alsefay',
  795             'field_vegetable2_required' => '^(?:|Ettucelay|Omatotay|Usselbray Routspay)$',
  796             'field_about_error' => 'Easeplay enteryay atwhay isthay essagemay isyay aboutyay.',
  797             'field_about_description' => 'What isyay isthay essagemay aboutyay:',
  798             'field_about_default' => 'Emailyay',
  799         },
  800     };
  801 
  802     # These settings are here for backwards compatability
  803     # It is better to modify the translations directly
  804     $settings->{'input_page_title'} = 'input_page_title';
  805     $settings->{'sent_page_title'} = 'sent_page_title';
  806 }
  807 
  808 #=====================================================================
  809 # You need to know Perl to and have a strong stomach to
  810 # modify much of anything below this line
  811 
  812 &initConstants();
  813 &settings();
  814 &loadConfiguration();
  815 &loadTemplate();
  816 &parseInput();
  817 &createMaps();
  818 &sanityCheck();
  819 &composeEmail();
  820 &previewMessage();
  821 &sendEmail();
  822 &sentPage();
  823 
  824 sub initConstants {
  825 
  826     $settings = {};
  827 
  828     $translations = {};
  829 
  830     # initialize the path to something safe so we can later call sendmail
  831     $ENV{'PATH'} = '/bin:/usr/bin:/usr/local/bin';
  832 
  833     if (&safeHeader($ENV{'PATH_INFO'}) eq '/contactformicon.png'){
  834         &contactformicon();
  835     }
  836 
  837     # denotes that no description is desired.
  838     $NO_DESCRIPTION = "-";
  839 
  840     # Version number of this software.
  841     $VERSION = "5.00.00";
  842 
  843     # Reqular expression building blocks
  844     $LETTER = "[a-zA-Z]";
  845     $DIGIT = "[0-9]";
  846     $DOSEOL = "(?:[\r][\n])";
  847     $EOL = "(?:[\r\n]|$DOSEOL)";
  848     $LETTER_DIGIT = "[0-9a-zA-Z]";
  849     $LETTER_DIGIT_HYPHEN = "(?:[0-9a-zA-Z-])";
  850     $HEX_DIGIT = "(?:[0-9a-fA-F])";
  851     $QUOTEDSTRING = "(?:[\\\"](?:[^\\\"]|(?:[\\][\\\"]))*[\\\"])";
  852     $ATOM = "(?:[\\!\\#-\\\\\\'\\*\\+\\-\\/-9\\=\\?A-Z\\^-\\~]+)";
  853     $SUBDOMAIN = "(?:" . $LETTER_DIGIT . "(?:" . $LETTER_DIGIT_HYPHEN . "*" . $LETTER_DIGIT . ")?)";
  854     $WORD = "(?:" . $ATOM . "|" . $QUOTEDSTRING . ")";
  855     $DOMAIN = "(?:" . $SUBDOMAIN . "(?:[\\.]" . $SUBDOMAIN . ")+)";
  856     $LOCALPART = "(?:" . $WORD . "(?:[\\.]" . $WORD . ")*)";
  857     $EMAIL = "(?:" . $LOCALPART . "[\\@]" . $DOMAIN . ")";
  858     $PHONE_DIGIT = "[\\.\\-\\(\\)\\+\\ Xx]*";
  859     $PHONE = "(?:(?:" . $PHONE_DIGIT . $DIGIT . "){10,20})";
  860     $PHONE_NO_AREA_CODE = "(?:(?:" . $PHONE_DIGIT . $DIGIT . "){7,20})";
  861     $ZIPCODE = "(?:" . $DIGIT . "{5}(?:[\\-]" . $DIGIT . "{4})?)";
  862     $PRICE = "(?:" . $DIGIT . "+(?:[\\.]" . $DIGIT . "{2})?)|(?:[\\.]" . $DIGIT . "{2})";
  863     $FLOAT = "(?:" . $DIGIT . "+(?:[\\.]" . $DIGIT . "*)?)|(?:[\\.]" . $DIGIT . "+)";
  864     $INTEGER = "(?:" . $DIGIT . "+)";
  865 
  866     # Some recommended regular expressions
  867     $SOMETHING = ".+";
  868     $ANYTHING = ".*";
  869     $ONE_LINE_REQUIRED = "^(?:(?:[^\\n\\r])+)\$";
  870     $ONE_LINE_OPTIONAL = "^(?:(?:[^\\n\\r])*)\$";
  871     $ZIPCODE_REQUIRED = "^" . $ZIPCODE . "\$";
  872     $ZIPCODE_OPTIONAL = "^(?:" . $ZIPCODE . "?)\$";
  873     $PHONE_REQUIRED = "^" . $PHONE . "\$";
  874     $PHONE_OPTIONAL = "^(?:" . $PHONE . "?)\$";
  875     $PHONE_NO_AREA_CODE_REQUIRED = "^" . $PHONE_NO_AREA_CODE . "\$";
  876     $PHONE_NO_AREA_CODE_OPTIONAL = "^(?:" . $PHONE_NO_AREA_CODE . "?)\$";
  877     $EMAIL_REQUIRED = "^" . $EMAIL . "\$";
  878     $EMAIL_OPTIONAL = "^(?:" . $EMAIL . "?)\$";
  879     $PRICE_REQUIRED = "^" . $PRICE . "\$";
  880     $PRICE_OPTIONAL = "^(?:" . $PRICE . "?)\$";
  881     $FLOAT_REQUIRED = "^" . $FLOAT . "\$";
  882     $FLOAT_OPTIONAL = "^(?:" . $FLOAT . "?)\$";
  883     $INTEGER_REQUIRED = "^" . $INTEGER . "\$";
  884     $INTEGER_OPTIONAL = "^(?:" . $INTEGER . "?)\$";
  885     $BLANK = "^\$";
  886 }
  887 
  888 sub loadConfiguration(){
  889     return if (! defined $settings->{'configuration_file'} or $settings->{'configuration_file'} eq "");
  890 
  891     my $xmlmodule = "XML::Simple";
  892     eval "use $xmlmodule";
  893     if ($@) {
  894         &errorPage(
  895             &trans('error_module_missing_title',{'perl_module'=>$xmlmodule}),
  896             &trans('error_module_missing_no_config_file',{'perl_module'=>$xmlmodule})
  897         );
  898     }
  899     my $xmlsimple = $xmlmodule->new(forcearray => 1, keyattr => ['Aliases','FormFields','Translations']);
  900     my $xmlconf;
  901     eval {
  902         $xmlconf = $xmlsimple->XMLin($settings->{'configuration_file'});
  903     };
  904     if ($@) {
  905         &errorPage(
  906             &trans('error_bad_config_file_title'),
  907             &trans('error_bad_config_file')
  908         );
  909     }
  910 
  911     if ($xmlconf->{Aliases}){
  912         $Aliases = [];
  913         if ($xmlconf->{Aliases}->[0] and $xmlconf->{Aliases}->[0]->{Alias}){
  914             foreach my $alias(@{$xmlconf->{Aliases}->[0]->{Alias}}){
  915                 my $name =  $alias->{name};
  916                 my $email = $alias->{content};
  917                 $email = &safeHeader($ENV{'SERVER_ADMIN'}) if ($email eq "SERVER_ADMIN");
  918                 push(@$Aliases, $name);
  919                 push(@$Aliases, $email);
  920             }
  921         }
  922     }
  923 
  924     if ($xmlconf->{Setting}){
  925         foreach my $setting(@{$xmlconf->{Setting}}){
  926             my $name = $setting->{name};
  927             if ($name){
  928                 my $value = $setting->{content};
  929                 $value='' if (!$value);
  930                 if (defined $ENV{'SCRIPT_NAME'}){
  931                     my $escapedScript = &escapeHTML($ENV{'SCRIPT_NAME'});
  932                     $value =~ s/SCRIPT_NAME_ESCAPED/$escapedScript/g;
  933                 }
  934                 $value = &trimEachLine($value);
  935                 $settings->{$name} = $value;
  936             }
  937         }
  938     }
  939 
  940     if ($xmlconf->{DisallowedText}){
  941         $disallowed_text = {};
  942         if ($xmlconf->{DisallowedText}->[0] and $xmlconf->{DisallowedText}->[0]->{Disallow}){
  943             foreach my $disallow(@{$xmlconf->{DisallowedText}->[0]->{Disallow}}){
  944                 my $regex =  &trimEachLine($disallow->{content});
  945                 my $message = $disallow->{message};
  946                 $disallowed_text->{$regex} = $message;
  947             }
  948         }
  949     }
  950 
  951     if ($xmlconf->{Translations}){
  952         if ($xmlconf->{Translations}->[0] and $xmlconf->{Translations}->[0]->{Language}){
  953             foreach my $lang(@{$xmlconf->{Translations}->[0]->{Language}}){
  954                 my $langname = $lang->{name};
  955                 $translations->{$langname} = {} if (! exists $translations->{$langname});
  956                 foreach my $translation (@{$lang->{Translation}}){
  957                     my $content = "";
  958                     $content = $translation->{'content'} if (exists $translation->{'content'});
  959                     $translations->{$langname}->{$translation->{'key'}} = $content;
  960                 }
  961             }
  962         }
  963     }
  964 
  965     if ($xmlconf->{FormFields}){
  966         $FormFields = [];
  967         if ($xmlconf->{FormFields}->[0] and $xmlconf->{FormFields}->[0]->{Field}){
  968             foreach my $field(@{$xmlconf->{FormFields}->[0]->{Field}}){
  969                 my $name = $field->{name};
  970                 my $required = &trimEachLine($field->{content});
  971                 $required =~ s/\$SOMETHING/$SOMETHING/g if ($required);
  972                 $required =~ s/\$ANYTHING/$ANYTHING/g if ($required);
  973                 $required =~ s/\$ONE_LINE_REQUIRED/$ONE_LINE_REQUIRED/g if ($required);
  974                 $required =~ s/\$ONE_LINE_OPTIONAL/$ONE_LINE_OPTIONAL/g if ($required);
  975                 $required =~ s/\$ZIPCODE_REQUIRED/$ZIPCODE_REQUIRED/g if ($required);
  976                 $required =~ s/\$ZIPCODE_OPTIONAL/$ZIPCODE_OPTIONAL/g if ($required);
  977                 $required =~ s/\$PHONE_REQUIRED/$PHONE_REQUIRED/g if ($required);
  978                 $required =~ s/\$PHONE_OPTIONAL/$PHONE_OPTIONAL/g if ($required);
  979                 $required =~ s/\$PHONE_NO_AREA_CODE_REQUIRED/$PHONE_NO_AREA_CODE_REQUIRED/g if ($required);
  980                 $required =~ s/\$PHONE_NO_AREA_CODE_OPTIONAL/$PHONE_NO_AREA_CODE_OPTIONAL/g if ($required);
  981                 $required =~ s/\$EMAIL_REQUIRED/$EMAIL_REQUIRED/g if ($required);
  982                 $required =~ s/\$EMAIL_OPTIONAL/$EMAIL_OPTIONAL/g if ($required);
  983                 $required =~ s/\$PRICE_REQUIRED/$PRICE_REQUIRED/g if ($required);
  984                 $required =~ s/\$PRICE_OPTIONAL/$PRICE_OPTIONAL/g if ($required);
  985                 $required =~ s/\$FLOAT_REQUIRED/$FLOAT_REQUIRED/g if ($required);
  986                 $required =~ s/\$FLOAT_OPTIONAL/$FLOAT_OPTIONAL/g if ($required);
  987                 $required =~ s/\$INTEGER_REQUIRED/$INTEGER_REQUIRED/g if ($required);
  988                 $required =~ s/\$INTEGER_OPTIONAL/$INTEGER_OPTIONAL/g if ($required);
  989                 $required =~ s/\$BLANK/$BLANK/g if ($required);
  990                 my $error = $field->{error};
  991                 my $type = $field->{type};
  992                 my $description = $field->{description};
  993                 $description =~ s/\$NO_DESCRIPTION/$NO_DESCRIPTION/g if($description);
  994                 my $enabled = $field->{enabled};
  995                 my $default = $field->{default};
  996                 my $selected = $field->{selected};
  997                 my $special = $field->{special};
  998                 my $show_in_message = $field->{show_in_message};
  999                 push (@$FormFields, $name);
 1000                 push (@$FormFields, {
 1001                     'required' =>  $required,
 1002                     'error' =>  $error,
 1003                     'type' =>  $type,
 1004                     'description' =>  $description,
 1005                     'enabled' =>  $enabled,
 1006                     'default' =>  $default,
 1007                     'selected' =>  $selected,
 1008                     'special' =>  $special,
 1009                     'show_in_message' =>  $show_in_message,
 1010                 });
 1011             }
 1012         }
 1013     }
 1014 }
 1015 
 1016 sub trimEachLine(){
 1017     my ($s) = @_;
 1018     return '' if (!$s);
 1019     $s =~ s/^[ \t\n\r]+//g;
 1020     $s =~ s/[ \t\n\r]+$//g;
 1021     $s =~ s/[\n \t\r]*\n[\n \t\r]*/\n/g;
 1022     return $s;
 1023 }
 1024 
 1025 sub loadTemplate(){
 1026     $template_error = "";
 1027     if (defined $settings->{'page_template_file'} and $settings->{'page_template_file'} ne ""){
 1028         if (!open(TEMPLATE, &trans($settings->{'page_template_file'}))){
 1029             $template_error = "<div class=\"contactform cf_error\">".&trans('error_template_file_problem')."</div>\n";
 1030             return;
 1031         }
 1032         $settings->{'page_template'} = join("", <TEMPLATE>);
 1033         close(TEMPLATE);
 1034     }
 1035 }
 1036 
 1037 sub createOrderedMap(){
 1038     my ($arr, $keytransformfunction) = @_;
 1039     my $orderarr = [];
 1040     my $hash = {};
 1041     my $key;
 1042     foreach my $value (@$arr){
 1043         if ($key){
 1044             $hash->{$key} = $value;
 1045             undef $key;
 1046         } else {
 1047             $key = $keytransformfunction->($value);
 1048             push(@$orderarr, $key);
 1049         }
 1050     }
 1051     return ($orderarr, $hash);
 1052 }
 1053 
 1054 sub createMaps {
 1055     # Since hash maps are not ordered, Aliases and Form_Fields
 1056     # Are declared as arrays.  We need to create two data structures
 1057     # from each.  The first is an ordered key list, the second is an
 1058     # unordered map
 1059 
 1060     ($AliasesOrdered,$AliasesMap) = &createOrderedMap($Aliases,\&trans);
 1061 
 1062     $field_name_to = '';
 1063     $field_name_from_email = '';
 1064     $field_name_from_name = '';
 1065     $field_name_subject = '';
 1066     $field_name_regarding = '';
 1067     $field_name_referrer = '';
 1068 
 1069     $FieldMap = {};
 1070     my $key;
 1071     foreach my $value (@$FormFields){
 1072         if ($key){
 1073             my $field = $value;
 1074             if (! defined $field->{"enabled"} or $field->{"enabled"} != 0){
 1075                 push(@Field_Order, $key);
 1076                 if (defined $field->{"special"}){
 1077                     my $special = $field->{"special"};
 1078                     if ($special eq "to"){
 1079                         $field_name_to = $key;
 1080                     } elsif ($special eq "from"){
 1081                         $field_name_from_email = $key;
 1082                     } elsif ($special eq "name"){
 1083                         $field_name_from_name = $key;
 1084                     } elsif ($special eq "subject"){
 1085                         $field_name_subject = $key;
 1086                     } elsif ($special eq "regarding"){
 1087                         $field_name_regarding = $key;
 1088                     } elsif ($special eq "referrer"){
 1089                         $field_name_referrer = $key;
 1090                     }
 1091                 }
 1092                 if (defined $field->{"default"}){
 1093                     # 'default' is a synonym for 'selected', just copy it over
 1094                     $field->{"selected"} = $field->{"default"};
 1095                 }
 1096                 $FieldMap->{$key} = $field;
 1097             }
 1098             undef $key;
 1099         } else {
 1100             $key = $value;
 1101         }
 1102     }
 1103 
 1104     # Put the referrer header into the map if it is not there already
 1105     if ($field_name_referrer ne "" and $FieldMap->{$field_name_referrer} and ! exists $SubmittedData->{$field_name_referrer}){
 1106         if (defined $ENV{'HTTP_REFERER'}){
 1107             $SubmittedData->{$field_name_referrer} = $ENV{'HTTP_REFERER'};
 1108         } else {
 1109             $SubmittedData->{$field_name_referrer} = "-";
 1110         }
 1111     }
 1112 }
 1113 
 1114 sub errorPage {
 1115     my ($title, $body) =  @_;
 1116     &outputPage(
 1117         $title,
 1118         "",
 1119         "",
 1120         "<span style=\"color:red\">$body</span>\n"
 1121     );
 1122 
 1123 }
 1124 
 1125 sub parseInput {
 1126     my ($pair, @pairs, $buffer);
 1127 
 1128     if ($settings->{'recaptcha_site_key'} and $settings->{'recaptcha_secret_key'}){
 1129         my $captchamodule = "Captcha::reCAPTCHA::V2";
 1130         eval "use $captchamodule";
 1131         if ($@) {
 1132             &errorPage(
 1133                 &trans('error_module_missing_title',{'perl_module'=>$captchamodule}),
 1134                 &trans('error_module_missing_no_captcha',{'perl_module'=>$captchamodule})
 1135             );
 1136         }
 1137         $captcha = $captchamodule->new();
 1138     }
 1139 
 1140     if (&safeHeader($ENV{'REQUEST_METHOD'}) eq 'GET'){
 1141         @pairs = split(/&/, $ENV{'QUERY_STRING'});
 1142     } elsif (&safeHeader($ENV{'REQUEST_METHOD'}) eq 'POST'){
 1143         read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
 1144         @pairs = split(/&/, $buffer);
 1145     } elsif ($ENV{'SERVER_NAME'}){
 1146         &inputPage(&trans('error_get_post_only'));
 1147     }
 1148 
 1149     foreach $pair (@pairs){
 1150         if ($pair =~ /([^\=]+)(?:\=(.*))?/){
 1151 
 1152             my $name = $1;
 1153             $name =~ tr/+/ /;
 1154             $name =~ s/%($HEX_DIGIT{2})/pack("C", hex($1))/eg;
 1155             $name =~ tr/\0//d;
 1156 
 1157             my $value = "";
 1158             if ($2){
 1159                 $value = $2;
 1160                 $value =~ tr/+/ /;
 1161                 $value =~ s/%($HEX_DIGIT{2})/pack("C", hex($1))/eg;
 1162                 $value =~ tr/\0//d;
 1163             }
 1164 
 1165             $SubmittedData->{$name} = $value;
 1166         }
 1167     }
 1168 }
 1169 
 1170 sub getRequired {
 1171     my ($key) = @_;
 1172     return &trans($FieldMap->{$key}->{"required"}) if (defined $FieldMap->{$key}->{"required"});
 1173     return "" if (&getType($key) eq "select" || &getType($key) eq "radio");
 1174     return $ANYTHING;
 1175 }
 1176 
 1177 sub getError {
 1178     my ($key) = @_;
 1179     return &trans($FieldMap->{$key}->{"error"}) if (defined $FieldMap->{$key}->{"error"});
 1180     return &trans('error_generic_field', {'field_key'=>$key});
 1181 }
 1182 
 1183 sub getSpecial {
 1184     my ($key) = @_;
 1185     return $FieldMap->{$key}->{"special"} if (defined $FieldMap->{$key}->{"special"});
 1186     return undef;
 1187 }
 1188 
 1189 sub getShowInMessage {
 1190     my ($key) = @_;
 1191     return 1 if &isAffirmative($FieldMap->{$key}->{"show_in_message"});
 1192     return undef;
 1193 }
 1194 
 1195 
 1196 sub getType {
 1197     my ($key) = @_;
 1198     if ($key eq $field_name_to){
 1199         return "select" if (scalar(@$AliasesOrdered) > 1);
 1200         return "hidden";
 1201     }
 1202     return $FieldMap->{$key}->{"type"} if (defined $FieldMap->{$key}->{"type"});
 1203     return "text";
 1204 }
 1205 
 1206 sub getSelected {
 1207     my ($key) = @_;
 1208     return &trans($FieldMap->{$key}->{"selected"}) if (defined $FieldMap->{$key}->{"selected"});
 1209     return undef;
 1210 }
 1211 
 1212 sub getDescription {
 1213     my ($key) = @_;
 1214     return &trans($FieldMap->{$key}->{"description"}) if (defined $FieldMap->{$key}->{"description"});
 1215     return "$key:";
 1216 }
 1217 
 1218 sub isDefined(){
 1219     my ($key) = @_;
 1220     return defined($SubmittedData->{$key});
 1221 }
 1222 
 1223 sub isNotEmpty(){
 1224     my ($key) = @_;
 1225     return (&isDefined($key) and $SubmittedData->{$key} ne '');
 1226 }
 1227 
 1228 sub getSelection {
 1229     my ($key) = @_;
 1230     return $SubmittedData->{$key} if (defined($SubmittedData->{$key}));
 1231     return &getSelected($key) if (&getSelected($key));
 1232     return "";
 1233 }
 1234 
 1235 sub sanityCheck {
 1236 
 1237     # Check the referrer
 1238     my $allowedReferers = $settings->{'allowedReferers'};
 1239     if (&safeHeader($ENV{'HTTP_REFERER'}) && &safeHeader($ENV{'HTTP_REFERER'}) !~ /$allowedReferers/g){
 1240         &inputPage(&trans('error_bad_referrer',{'referrer'=>&escapeHTML($ENV{'HTTP_REFERER'})}));
 1241     }
 1242 
 1243     my $some_required_field_present = 0;
 1244     my $errorCount = 0;
 1245     my %errorHash = ();
 1246 
 1247     my @field_keys = &getOrderedFields();
 1248     foreach my $key (@field_keys){
 1249         my $required_value = &getRequired($key);
 1250         my $data = &getSelection($key);
 1251         my $form_type = &getType($key);
 1252         $errorHash{$key} = "";
 1253         if ($data !~ /$required_value/g){
 1254             if(&isDefined($key)){
 1255                 $errorCount++;
 1256                 $errorHash{$key} = &getError($key);
 1257             }
 1258         } elsif (&isDefined($key) && $form_type ne 'hidden'){
 1259             $some_required_field_present = 1;
 1260         }
 1261 
 1262         foreach my $disallow_check (keys(%$disallowed_text)){
 1263             if ($data =~ /$disallow_check/){
 1264                 $errorCount++;
 1265                 $errorHash{$key} .= &trans($disallowed_text->{$disallow_check});
 1266             }
 1267         }
 1268     }
 1269     if (!($some_required_field_present) or defined($SubmittedData->{"prefill"})){
 1270         &inputPage('', &trans('input_page_instructions'));
 1271     }
 1272 
 1273     foreach my $key (@field_keys){
 1274         if (&getType($key) eq "trap" and &isNotEmpty($key)){
 1275             $errorCount++;
 1276             $errorHash{$key} .=  &getError($key);
 1277         }
 1278     }
 1279     if ($errorCount > 0){
 1280         my $errorMessage = &getCorrectionsRequiredText($errorCount);
 1281         &inputPage($errorMessage, "", "", \%errorHash);
 1282     }
 1283 
 1284     if ($captcha and !&messagePreviewSubmitted()){
 1285         $captchaResult = $captcha->verify(
 1286             $settings->{'recaptcha_secret_key'},
 1287             $SubmittedData->{"g-recaptcha-response"},
 1288             $ENV{'REMOTE_ADDR'}
 1289         );
 1290         if (!$captchaResult->{success}){
 1291             $errorHash{"captcha"} = &trans('field_captcha_error');
 1292             &inputPage(&getCorrectionsRequiredText(1), "", "", \%errorHash, 1);
 1293         }
 1294     }
 1295 
 1296     if ((!$SubmittedData->{$field_name_to}) || $SubmittedData->{$field_name_to} eq ""){
 1297         &inputPage('', &trans('input_page_instructions'));
 1298     } else {
 1299         my $recipent = $SubmittedData->{$field_name_to};
 1300         if ((!$AliasesMap->{$recipent})){
 1301             &inputPage(&trans('error_bad_recipient'));
 1302         }
 1303     }
 1304 }
 1305 
 1306 sub getCorrectionsRequiredText(){
 1307     my ($errorCount) = @_;
 1308     return &trans('error_correction_required') if ($errorCount == 1);
 1309     return &trans('error_corrections_required');
 1310 }
 1311 
 1312 sub getFromEmail(){
 1313     if ($field_name_from_email and $FieldMap->{$field_name_from_email}){
 1314         my $email = &getSelection($field_name_from_email);
 1315         return $email if ($email);
 1316     }
 1317     return &trans('field_email_default');
 1318 }
 1319 
 1320 sub getFromName(){
 1321     return &getSelection($field_name_from_name) if ($field_name_from_name and $FieldMap->{$field_name_from_name});
 1322     return undef;
 1323 }
 1324 
 1325 sub getFrom(){
 1326     my $email = &getFromEmail();
 1327     my $name = &getFromName();
 1328     return "$name <$email>" if ($name);
 1329     return $email;
 1330 }
 1331 
 1332 sub getFromSender(){
 1333     my $email = &getSenderEmail();
 1334     my $name = &getFromName();
 1335     return "$name (via contact form) <$email>" if ($name);
 1336     return $email;
 1337 }
 1338 
 1339 sub getSenderEmail(){
 1340     return &getToEmail() if ($settings->{'sender_email'} !~ /\@/);
 1341     return $settings->{'sender_email'};
 1342 }
 1343 
 1344 sub useSender(){
 1345     return 1 if ($settings->{'sender_email'} eq "");
 1346     return 1 if ($settings->{'sender_email'} =~ /\@/);
 1347     return 0;
 1348 }
 1349 
 1350 sub getTo(){
 1351     my ($email) = @_;
 1352     my $name = &getToName();
 1353     return "$name <$email>" if ($name);
 1354     return $email;
 1355 }
 1356 
 1357 sub getToName(){
 1358     return &getSelection($field_name_to) if ($field_name_to and $FieldMap->{$field_name_to});
 1359     return undef;
 1360 }
 1361 
 1362 sub getSubject(){
 1363     my $subject = "";
 1364     $subject .= &trans($settings->{'subject_prepend'})." " if ($settings->{'subject_prepend'});
 1365     $subject .= &getSelection($field_name_subject) if ($field_name_subject and $FieldMap->{$field_name_subject});
 1366     $subject .= &trans('field_subject_default') if (!$subject);
 1367     return $subject;
 1368 }
 1369 
 1370 sub getRegarding(){
 1371     return &getSelection($field_name_regarding) if ($field_name_regarding and $FieldMap->{$field_name_regarding});
 1372     return undef;
 1373 }
 1374 
 1375 sub getSubjectAndRegarding(){
 1376     my $subject = &getSubject();
 1377     my $regarding = &getRegarding();
 1378     return "$subject ($regarding)" if ($regarding);
 1379     return $subject;
 1380 }
 1381 
 1382 sub isAffirmative(){
 1383     my ($s) = @_;
 1384     return 0 if (!$s);
 1385     return 1 if ($s =~ /^(?:1|true|t|yes|y)$/);
 1386     return 0;
 1387 }
 1388 
 1389 sub includeFieldInEmailBody(){
 1390     my ($key) = @_;
 1391     return 0 if (&getType($key) eq "trap");
 1392     return &getShowToInMessage() if ($key eq $field_name_to);
 1393     return &getShowInMessage($key) if (&getSpecial($key));
 1394     return 1;
 1395 }
 1396 
 1397 sub getShowToInMessage(){
 1398     return 1 if (&getShowInMessage($field_name_to));
 1399     return 1 if (&isAffirmative($settings->{'show_to_in_message'}));
 1400     return 0 if ('multiple' ne $settings->{'show_to_in_message'});
 1401     return 1 if (&getToEmail() =~ /,/);
 1402     return 0;
 1403 }
 1404 
 1405 sub composeEmail {
 1406     my @field_keys = &getOrderedFields();
 1407     my $needsnewline=-1;
 1408     foreach my $key (@field_keys){
 1409         if (&includeFieldInEmailBody($key)){
 1410             my $surroundfieldwithnewlines = 0;
 1411             my $value = &getSelection($key);
 1412             my $mail_description = &getDescription($key);
 1413             if ($mail_description eq $NO_DESCRIPTION){
 1414                 $mail_description = "";
 1415                 $surroundfieldwithnewlines = 1;
 1416             } elsif ($value =~ /[\r\n]/){
 1417                 $mail_description .= "\n";
 1418                 $surroundfieldwithnewlines = 1;
 1419             } else {
 1420                 $mail_description .= " ";
 1421             }
 1422             if ($needsnewline >= 0){
 1423                 $mail_message .= "\n" if ($needsnewline or $surroundfieldwithnewlines);
 1424             }
 1425             $mail_message .= $mail_description;
 1426             $mail_message .= &getSelection($key)."\n";
 1427             $needsnewline = $surroundfieldwithnewlines;
 1428         }
 1429     }
 1430 }
 1431 
 1432 sub getToEmail(){
 1433     return &trans($AliasesMap->{&getSelection($field_name_to)},{'server_admin'=>&safeHeader($ENV{'SERVER_ADMIN'})});
 1434 }
 1435 
 1436 sub sendEmail {
 1437     my @to_address_list = split(/,/,&getToEmail());
 1438     foreach my $to_address (@to_address_list){
 1439         open(MAIL,"|".$settings->{'sendmail'});
 1440         print MAIL "To: ".&safeHeader(&getTo($to_address))."\n";
 1441         if (&useSender()){
 1442             print MAIL "From: ".&safeHeader(&getFromSender())."\n";
 1443             print MAIL "Sender: ".&safeHeader(&getSenderEmail())."\n";
 1444             print MAIL "Reply-To: ".&safeHeader(&getFrom())."\n";
 1445         } else {
 1446             print MAIL "From: ".&safeHeader(&getFrom())."\n";
 1447         }
 1448         print MAIL "Subject: ".&safeHeader(&getSubjectAndRegarding())."\n";
 1449         print MAIL "Content-Type: text/plain; charset=".&safeHeader($settings->{'charset'})."\n";
 1450         print MAIL "X-Mailer: ContactForm/".&safeHeader($VERSION)." (http://ostermiller.org/contactform/)\n";
 1451         print MAIL "X-Server-Name: ".&safeHeader($ENV{'SERVER_NAME'})."\n";
 1452         print MAIL "X-Server-Admin: ".&safeHeader($ENV{'SERVER_ADMIN'})."\n";
 1453         print MAIL "X-Http-Url: ".&safeHeader(getCanonicalUrl())."\n";
 1454         print MAIL "X-Http-Host: ".&safeHeader($ENV{'HTTP_HOST'})."\n";
 1455         print MAIL "X-Script-Name: ".&safeHeader($ENV{'SCRIPT_NAME'})."\n";
 1456         print MAIL "X-Path-Info: ".&safeHeader($ENV{'PATH_INFO'})."\n";
 1457         print MAIL "X-Remote-Host: ".&safeHeader($ENV{'REMOTE_HOST'})."\n";
 1458         print MAIL "X-Remote-Addr: ".&safeHeader($ENV{'REMOTE_ADDR'})."\n";
 1459         print MAIL "X-Remote-User: ".&safeHeader($ENV{'REMOTE_USER'})."\n";
 1460         print MAIL "X-HTTP-User-Agent: ".&safeHeader($ENV{'HTTP_USER_AGENT'})."\n";
 1461         print MAIL "X-HTTP-Referer: ".&safeHeader($ENV{'HTTP_REFERER'})."\n";
 1462         if ($field_name_referrer ne ""){
 1463             print MAIL "X-First-HTTP-Referer: ".&safeHeader(&getSelection($field_name_referrer))."\n";
 1464         }
 1465         print MAIL $mail_message;
 1466         close (MAIL);
 1467     }
 1468 }
 1469 
 1470 sub previewRequired(){
 1471     return 1 if ($settings->{'require_preview'} == 1);
 1472     return 0;
 1473 }
 1474 
 1475 sub previewAllowed(){
 1476     return 1 if ($settings->{'require_preview'} != 0);
 1477     return 0;
 1478 }
 1479 
 1480 sub previewMessage(){
 1481     return if (!&previewAllowed());
 1482     return if (&messageSendSubmitted());
 1483     &inputPage('',&trans('preview_page_instructions'),&getMessageForWebDisplay());
 1484 }
 1485 
 1486 sub getMessageForWebDisplay(){
 1487     my $s = "";
 1488     $s .= &trans('email_header_to')." ".&getSelection($field_name_to)."\n" if (!getShowToInMessage());
 1489     $s .= &trans('email_header_from')." ".&getFrom()."\n" if (!getShowInMessage($field_name_from_name) and !getShowInMessage($field_name_from_email));
 1490     $s .= &trans('email_header_subject')." ".&getSubjectAndRegarding()."\n" if (!getShowInMessage($field_name_subject) and !getShowInMessage($field_name_regarding));
 1491     $s .= "\n";
 1492     $s .= $mail_message;
 1493     return &textToHTML($s);
 1494 }
 1495 
 1496 sub sentPage {
 1497     my $javascript = ""; # No javascript
 1498 
 1499     if ($settings->{'redirect_url_sent'} ne ""){
 1500         my $url = &trans($settings->{'redirect_url_sent'});
 1501         if ($settings->{'redirect_delay_sent'} == 0){
 1502             &redirect($url);
 1503         } else {
 1504             $javascript = "<meta http-equiv=\"refresh\" content=\"".$settings->{'redirect_delay_sent'}.";url=$url\">\n"
 1505         }
 1506     }
 1507 
 1508     my $sentthankyou = &trans('sent_page_thank_you');
 1509     $sentthankyou = "<div class=\"contactform cf_thankyou\">$sentthankyou</div>" if ($sentthankyou);
 1510 
 1511     &outputPage(
 1512         &trans($settings->{'sent_page_title'}),
 1513         $settings->{'sent_page_css'},
 1514         $javascript,
 1515         $sentthankyou."<div class=\"contactform cf_sent\">".&getMessageForWebDisplay()."</div>"
 1516     );
 1517 }
 1518 
 1519 sub redirect {
 1520     my ($url) = @_;
 1521     print "Location: $url\n\n";
 1522     exit 0;
 1523 }
 1524 
 1525 sub inputPage {
 1526     my ($error, $instructions, $preview, $fieldErrors, $allowSendAnyway) = @_;
 1527     my $haserror = 1;
 1528     if (!defined($error) or $error eq ""){
 1529         $error = "";
 1530         $haserror = 0;
 1531     }
 1532     my %FieldErrorsHash = ();
 1533     if (defined($fieldErrors)){
 1534         %FieldErrorsHash = %$fieldErrors;
 1535     }
 1536 
 1537     if (!defined($instructions)){
 1538         $instructions = "";
 1539     } elsif ($instructions){
 1540         $instructions="<div class=\"contactform cf_instructions\" id=\"cf_instructions\">$instructions</div>"
 1541     }
 1542 
 1543     if (!defined($preview)){
 1544         $preview = "";
 1545     } elsif ($preview){
 1546         $preview="<div class=\"contactform cf_preview\">$preview</div>"
 1547     }
 1548 
 1549     my (@orderedKeys, $key, $form_html, $script_call, $alias_selected, $client_side_check_script);
 1550 
 1551     my $errorStyle=" style=\"display:none;\"";
 1552     if ($error ne ""){
 1553         $errorStyle="";
 1554     }
 1555 
 1556     # Error div must always be present, even with no contents, for javascript output
 1557     $error="<div id=\"cf_global_error\"$errorStyle class=\"contactform cf_error\">$error</div>";
 1558 
 1559     $script_call = '';
 1560     if ($settings->{'use_client_side_verification'}){
 1561         $script_call="onSubmit=\"return cfCheckForm(this);\"";
 1562     }
 1563 
 1564     my $submit_method = "POST";
 1565     if (defined $settings->{'submit_method'} and $settings->{'submit_method'} eq "GET"){
 1566         $submit_method = "GET";
 1567     }
 1568 
 1569     $form_html="<form class=\"contactform\" id=\"cf_form\" action=\"".&escapeHTML($ENV{'SCRIPT_NAME'})."\" method=".$settings->{'submit_method'}." $script_call>\n";
 1570     my $lang = &escapeHTML(&getLanguageParamValue());
 1571     $form_html.= "<input type=\"hidden\" name=\"".$settings->{language_param}."\" value=\"$lang\">\n" if ($lang);
 1572     @orderedKeys = &getOrderedFields();
 1573     foreach $key (@orderedKeys){
 1574         my $html_description = &getDescription($key);
 1575         if ($html_description eq $NO_DESCRIPTION){
 1576             $html_description = '';
 1577         } else {
 1578             $html_description = "<label class=\"contactform cf_fieldlabel\" for=\"$key\">$html_description</label>";
 1579         }
 1580         my $fieldErrorMessage = "";
 1581         my $errorStyle=" style=\"display:none;\"";
 1582         if (defined $FieldErrorsHash{$key} and $FieldErrorsHash{$key} ne ""){
 1583             $fieldErrorMessage = $FieldErrorsHash{$key};
 1584             $errorStyle = "";
 1585         }
 1586         $fieldErrorMessage= "<span id=\"cf_error_$key\"$errorStyle class=\"contactform cf_error cf_fielderror\">".&escapeHTML($fieldErrorMessage)."</span>";
 1587         if ($key eq $field_name_to){
 1588             if (scalar(@$AliasesOrdered) == 1){
 1589                 my $alias = $AliasesOrdered->[0];
 1590                 $form_html.= "$fieldErrorMessage <input type=\"hidden\" name=\"$field_name_to\" value=\"$alias\">\n";
 1591             } else {
 1592                 $form_html.= "<div class=\"contactform cf_field\">".&trans($settings->{'required_marker'})." $html_description $fieldErrorMessage\n<div class=\"contactform cf_userentry\"><select id=\"$key\" name=\"$field_name_to\">\n";
 1593                 $form_html.= "<option value\"\"></option>\n";
 1594                 foreach my $alias (@$AliasesOrdered){
 1595                     if (defined $SubmittedData->{$field_name_to} and $alias eq $SubmittedData->{$field_name_to}){
 1596                         $alias_selected = 'selected'
 1597                     } else {
 1598                         $alias_selected = '';
 1599                     }
 1600                         $form_html.= "<option value=\"$alias\" $alias_selected>$alias</option>\n";
 1601                 }
 1602                 $form_html.= "</select></div></div>\n";
 1603             }
 1604         } else {
 1605             my $mark = '';
 1606             my $required_value = &getRequired($key);
 1607             my $data = &getSelection($key);
 1608             my $fieldText = "";
 1609             if (($data !~ /$required_value/g) && $html_description ne ''){
 1610                 if (length($fieldText) > 0){
 1611                     $fieldText .= " ";
 1612                 }
 1613                 $fieldText .= &trans($settings->{'required_marker'});
 1614             }
 1615             if (length($html_description) > 0){
 1616                 if (length($fieldText) > 0){
 1617                     $fieldText .= " ";
 1618                 }
 1619                 $fieldText .= $html_description;
 1620             }
 1621             if (length($fieldErrorMessage) > 0){
 1622                 if (length($fieldText) > 0){
 1623                     $fieldText .= " ";
 1624                 }
 1625                 $fieldText .= $fieldErrorMessage;
 1626             }
 1627             my $form_type=&getType($key);
 1628             if ($form_type eq 'select'){
 1629                 $form_html.="<div class=\"contactform cf_field\">$fieldText<div class=\"contactform cf_userentry\"><select id=\"$key\" class=\"contactform cf_select\" name=\"$key\">";
 1630                 my $required = &getRequired($key);
 1631                 if ("" !~ /$required/ and !&getSelected($key)){
 1632                     $form_html.="<option value=\"\"></option>";
 1633                 }
 1634                 my $selectvalue = $required;
 1635                 $selectvalue =~ s/^[\^\(\?\:]+//g;
 1636                 $selectvalue =~ s/[\)\$]+$//g;
 1637                 my @selectvalues = split(/\|/, $selectvalue);
 1638                 foreach my $selectval (@selectvalues){
 1639                     $selectval =~ s/^[\(\?\:]+//g;
 1640                     $selectval =~ s/[\)]+$//g;
 1641                     $selectval = &escapeHTML($selectval);
 1642                     my $selected="";
 1643                     if ($selectval eq $data){
 1644                         $selected = " selected";
 1645                     }
 1646                     $form_html.="<option value=\"$selectval\"$selected>$selectval</option>";
 1647                 }
 1648                 $form_html.="</select></div></div>\n";
 1649             } elsif ($form_type eq 'radio'){
 1650                 $form_html.="<div class=\"contactform cf_field\">$fieldText<div class=\"contactform cf_userentry\"><span id=\"$key\" class=\"contactform cf_radio\">";
 1651                 my $selectvalue = &getRequired($key);
 1652                 $selectvalue =~ s/^[\^\(\?\:]+//g;
 1653                 $selectvalue =~ s/[\)\$]+$//g;
 1654                 my @selectvalues = split(/\|/, $selectvalue);
 1655                 my $radionum=0;
 1656                 foreach my $selectval (@selectvalues){
 1657                     $selectval =~ s/^[\(\?\:]+//g;
 1658                     $selectval =~ s/[\)]+$//g;
 1659                     $selectval = &escapeHTML($selectval);
 1660                     if ($selectval ne ""){
 1661                         my $selected="";
 1662                         if ($selectval eq $data){
 1663                             $selected = " checked";
 1664                         }
 1665                         $form_html.="<div class=\"contactform cf_radioselection\"><input type=\"radio\" name=\"$key\" id=\"$key$radionum\" value=\"$selectval\"$selected><label for=\"$key$radionum\">$selectval</label></div>";
 1666                         $radionum++;
 1667                     }
 1668                 }
 1669                 $form_html.="</span></div></div>\n";
 1670             } elsif ($form_type eq 'textarea'){
 1671                 $form_html.="<div class=\"contactform cf_field\">$fieldText<div class=\"contactform cf_userentry\"><textarea id=\"$key\" class=\"contactform cf_textentry\" wrap=\"virtual\" name=\"$key\">".&escapeHTML($data)."</textarea></div></div>\n";
 1672             } elsif ($form_type eq 'hidden'){
 1673                 $form_html.="$fieldErrorMessage <input type=\"hidden\" name=\"$key\" value=\"".&escapeHTML($data)."\">\n";
 1674             } elsif ($form_type eq 'trap'){
 1675                 $form_html.="<div class=\"contactform cf_field cf_nt\">$fieldText<div class=\"contactform cf_userentry\"><input id=\"$key\" class=\"contactform cf_textentry\" type=\"text\" name=\"$key\" value=\"".&escapeHTML($data)."\"></div></div>\n";
 1676             } else {
 1677                 $form_html.="<div class=\"contactform cf_field\">$fieldText<div class=\"contactform cf_userentry\"><input id=\"$key\" class=\"contactform cf_textentry\" type=\"text\" name=\"$key\" value=\"".&escapeHTML($data)."\"></div></div>\n";
 1678             }
 1679         }
 1680     }
 1681     my $hasSendButton = &hasSendButton($haserror);
 1682     $hasSendButton = 1 if ($allowSendAnyway);
 1683     if ($hasSendButton and $captcha){
 1684         $form_html.="<div class=\"contactform cf_field\"><label class=\"contactform cf_fieldlabel\" for=\"recaptcha_response_field\">";
 1685         $form_html.=&trans($settings->{'required_marker'})." ".&trans('field_captcha_description');
 1686         if (defined $FieldErrorsHash{"captcha"} and $FieldErrorsHash{"captcha"} ne ""){
 1687             $form_html.=" <span id=\"cf_error_captcha\" class=\"contactform cf_error cf_fielderror\">".$FieldErrorsHash{"captcha"}."</span> ";
 1688         }
 1689         $form_html.="</label>\n";
 1690         my $captcha_error=undef;
 1691         $captcha_error = $captchaResult->{error} if ($captchaResult and !$captchaResult->{is_valid});
 1692         $form_html.=$captcha->html($settings->{'recaptcha_site_key'}, $captcha_error, undef, {lang=>&getUserLanguage()});
 1693         $form_html.="</div>\n";
 1694     }
 1695     if ($settings->{'require_preview'} eq "1" or $settings->{'require_preview'} eq "2"){
 1696         $form_html.="<input class=\"contactform\" id=\"cf_submit\" type=\"submit\" name=\"".$settings->{'field_name_submit'}."\" value=\"".&escapeHTML(&trans('preview_button'))."\">\n";
 1697     }
 1698     if ($hasSendButton){
 1699         $form_html.="<input class=\"contactform\" id=\"cf_submit\" type=\"submit\" name=\"".$settings->{'field_name_submit'}."\" value=\"".&escapeHTML(&trans('send_button'))."\">\n";
 1700     }
 1701     my $requiredMarkerDescription = &trans('required_marker_description',{required_marker=>&trans($settings->{'required_marker'})});
 1702     if ($requiredMarkerDescription){
 1703         $form_html.="<p class=\"contactform\" id=\"cf_requiredexplain\">$requiredMarkerDescription</p>\n";
 1704     }
 1705     $form_html.="</form>";
 1706 
 1707     $client_side_check_script = "";
 1708     if ($settings->{'use_client_side_verification'}){
 1709         $client_side_check_script .= "<script language=\"javascript\" type=\"text/javascript\"><!--\n";
 1710         $client_side_check_script .= "function cfRadioSelected(r){\n";
 1711         $client_side_check_script .= "for (i=0;i<r.length;i++) {\n";
 1712         $client_side_check_script .= "if (r[i].checked)return true;\n";
 1713         $client_side_check_script .= "}\n";
 1714         $client_side_check_script .= "return false;\n";
 1715         $client_side_check_script .= "}\n";
 1716         $client_side_check_script .= "function cfErrorOn(k,d,m,s,f,b){\n";
 1717         $client_side_check_script .= "var df=document.getElementById(d);\n";
 1718         $client_side_check_script .= "df.innerHTML=m;\n";
 1719         $client_side_check_script .= "df.style.display=b;\n";
 1720         $client_side_check_script .= "if(s)k.select();\n";
 1721         $client_side_check_script .= "if(f)k.focus();\n";
 1722         $client_side_check_script .= "}\n";
 1723         $client_side_check_script .= "function cfErrorOff(d){\n";
 1724         $client_side_check_script .= "var f=document.getElementById(d);\n";
 1725         $client_side_check_script .= "f.innerHTML='';\n";
 1726         $client_side_check_script .= "f.style.display='none';\n";
 1727         $client_side_check_script .= "}\n";
 1728         $client_side_check_script .= "function cfCheckForm(form){\n";
 1729         $client_side_check_script .= "var major = parseInt(navigator.appVersion);\n";
 1730         $client_side_check_script .= "var agent = navigator.userAgent.toLowerCase();\n";
 1731         $client_side_check_script .= "if (agent.indexOf('msie')!=-1){\n";
 1732         $client_side_check_script .= "major = parseFloat(agent.split('msie')[1]);\n";
 1733         $client_side_check_script .= "}\n";
 1734         $client_side_check_script .= "if (agent.indexOf('mozilla')==0 && major<=4){\n";
 1735         $client_side_check_script .= "// Internet Explorer 4 or Netscape 4 and earlier.\n";
 1736         $client_side_check_script .= "return true;\n";
 1737         $client_side_check_script .= "} else if (agent.indexOf('opera')!=-1){\n";
 1738         $client_side_check_script .= "// Opera doesn't seem to do regular expressions properly.\n";
 1739         $client_side_check_script .= "return true;\n";
 1740         $client_side_check_script .= "}\n";
 1741         $client_side_check_script .= "var ec=0;\n";
 1742         foreach $key (reverse(@orderedKeys)){
 1743             my $formType = &getType($key);
 1744             my $check = "";
 1745             if($formType eq 'hidden'){
 1746                 $check = "";
 1747             } elsif ($formType eq "select"){
 1748                 my $required = &getRequired($key);
 1749                 if ("" !~ /$required/ and !&getSelected($key)){
 1750                     $check = "form.$key.selectedIndex == 0";
 1751                 } else {
 1752                     $check = "";
 1753                 }
 1754             } elsif ($formType eq "radio"){
 1755                 my $required = &getRequired($key);
 1756                 if ("" !~ /$required/ and !&getSelected($key)){
 1757                     $check = "!cfRadioSelected(form.$key)"
 1758                 } else {
 1759                     $check = "";
 1760                 }
 1761             } else {
 1762                 $check = "!form.$key.value.match(new RegExp('".&escapeJavaScript(&getRequired($key))."', 'g'))";
 1763             }
 1764             if ($check ne ""){
 1765                 my $dofocus = "false";
 1766                 if ($formType ne "radio"){
 1767                     $dofocus = "true";
 1768                 }
 1769                 my $doselect = "false";
 1770                 if ($formType eq "text" or $formType eq "textarea"){
 1771                     $doselect = "true";
 1772                 }
 1773                 $client_side_check_script .= "if ($check){\n";
 1774                 $client_side_check_script .= "cfErrorOn(form.$key,'cf_error_$key','".&escapeJavaScript(&getError($key))."',$doselect,$dofocus,'inline');\n";
 1775                 $client_side_check_script .= "ec++;\n";
 1776                 $client_side_check_script .= "} else {\n";
 1777                 $client_side_check_script .= "cfErrorOff('cf_error_$key');\n";
 1778                 $client_side_check_script .= "}\n";
 1779             } else {
 1780                 $client_side_check_script .= "cfErrorOff('cf_error_$key');\n";
 1781             }
 1782         }
 1783         $client_side_check_script .= "\n";
 1784         $client_side_check_script .= "if(ec>0){\n";
 1785         $client_side_check_script .= "cfErrorOn('','cf_global_error',(ec==1?'".&escapeJavaScript(&getCorrectionsRequiredText(1))."':'".&escapeJavaScript(&getCorrectionsRequiredText(2))."'),false,false,'block');\n";
 1786         $client_side_check_script .= "scroll(0,0);";
 1787         $client_side_check_script .= "return false;\n";
 1788         $client_side_check_script .= "} else {\n";
 1789         $client_side_check_script .= "cfErrorOff('cf_global_error');\n";
 1790         $client_side_check_script .= "return true;\n";
 1791         $client_side_check_script .= "}\n";
 1792         $client_side_check_script .= "}\n";
 1793         $client_side_check_script .= "//--></script>\n";
 1794     }
 1795 
 1796     &outputPage(
 1797         &trans($settings->{'input_page_title'}),
 1798         $settings->{'input_page_css'},
 1799         $client_side_check_script,
 1800         $instructions.$preview.$error.$form_html
 1801     );
 1802 }
 1803 
 1804 
 1805 sub getUserLanguage(){
 1806     return &getUserLanguages()->[0];
 1807 }
 1808 
 1809 sub getLanguageParamValue(){
 1810     return "" if (!$settings->{'language_param'});
 1811     my $value = $SubmittedData->{$settings->{'language_param'}};
 1812     return "" if (!$value);
 1813     return "" if ($value !~ /^[a-zA-Z_]+$/);
 1814     return $value;
 1815 }
 1816 
 1817 sub getUserLanguages(){
 1818     return $userLangs if ($userLangs);
 1819 
 1820     my $allowed;
 1821     if ($settings->{'allowed_languages'}){
 1822         $allowed = {};
 1823         for my $lang (split(/[\,\; ]+/, $settings->{'allowed_languages'})){
 1824             $allowed->{$lang} = 1;
 1825         }
 1826     }
 1827     $userLangs = [];
 1828     my $langSet = {};
 1829     my $langs = "";
 1830     my $byparam = &getLanguageParamValue();
 1831     if ($byparam){
 1832         if (!$allowed or $allowed->{$byparam}){
 1833             push(@$userLangs, $byparam);
 1834         }
 1835     }
 1836     $langs = $ENV{HTTP_ACCEPT_LANGUAGE} if (defined $ENV{HTTP_ACCEPT_LANGUAGE});
 1837     for my $lang (split(/[\,\; ]+/, $langs)){
 1838         if ($lang =~ /^([A-Za-z]{2})(?:[\-\_]([A-Za-z]{2}))?$/){
 1839             my ($l, $c) = ($1, $2);
 1840             $l = lc($l);
 1841             if ($c){
 1842                 $c = uc($c);
 1843                 if (!$langSet->{"${l}_$c"}){
 1844                     if (!$allowed or $allowed->{"${l}_$c"}){
 1845                         push(@$userLangs, "${l}_$c");
 1846                         $langSet->{"${l}_$c"}=1;
 1847                     }
 1848                 }
 1849             }
 1850             if (!$langSet->{$l}){
 1851                 if (!$allowed or $allowed->{$l}){
 1852                     push(@$userLangs, $l);
 1853                     $langSet->{$l}=1;
 1854                 }
 1855             }
 1856         }
 1857     }
 1858     if (!$langSet->{$settings->{'default_language'}}){
 1859         push(@$userLangs, $settings->{'default_language'});
 1860     }
 1861     return $userLangs;
 1862 }
 1863 
 1864 sub trans(){
 1865     my ($key, $vars) = @_;
 1866     return $key if ($key !~ /^[a-z0-9]+_[a-z_0-9]+$/);
 1867     for my $lang (@{&getUserLanguages()}){
 1868         if (exists $translations->{$lang} and exists $translations->{$lang}->{$key}){
 1869             return &messageFormat($translations->{$lang}->{$key}, $vars);
 1870         }
 1871     }
 1872     return $key;
 1873 }
 1874 
 1875 sub messageFormat(){
 1876     my ($s, $vars) = @_;
 1877     return $s if (!$vars);
 1878     foreach my $name (keys(%$vars)){
 1879         my $value = $vars->{$name};
 1880         $s =~ s/\{$name\}/$value/g;
 1881     }
 1882     return $s;
 1883 }
 1884 
 1885 sub hasSendButton(){
 1886     my ($haserror) = @_;
 1887     return 1 if ($settings->{'require_preview'} eq "0");
 1888     return 1 if ($settings->{'require_preview'} eq "2" );
 1889     return 1 if (!$haserror and &messagePreviewSubmitted());
 1890     return 0;
 1891 }
 1892 
 1893 sub messagePreviewSubmitted(){
 1894     return 0 if (!defined $SubmittedData->{$settings->{'field_name_submit'}});
 1895     return 1 if ($SubmittedData->{$settings->{'field_name_submit'}} eq &trans('preview_button'));
 1896     return 0;
 1897 }
 1898 
 1899 sub messageSendSubmitted(){
 1900     return 1 if (!defined $SubmittedData->{$settings->{'field_name_submit'}});
 1901     return 1 if ($SubmittedData->{$settings->{'field_name_submit'}} eq &trans('send_button'));
 1902     return 0;
 1903 }
 1904 
 1905 sub getCanonicalUrl(){
 1906     my $protocol = "http://";
 1907     $protocol = "https://" if (&safeHeader($ENV{'HTTPS'}) eq 'ON');
 1908     my $path = $ENV{'SCRIPT_NAME'};
 1909     my $host = $ENV{'HTTP_HOST'};
 1910     my $port = "";
 1911     $port = ":".$ENV{SERVER_PORT} if ($ENV{SERVER_PORT} ne "80");
 1912     return "$protocol$host$port$path";
 1913 }
 1914 
 1915 sub outputPage(){
 1916     my ($title, $css, $javascript, $content) = @_;
 1917     my $meta = "<link rel=\"canonical\" href=\"".getCanonicalUrl()."\"/>";
 1918     my $page = &trans($settings->{'page_template'});
 1919     $page =~ s/\$title/$title/g;
 1920     $page =~ s/\$css/$css/g;
 1921     $page =~ s/\$meta/$meta/g;
 1922     my $icon_link = $settings->{'icon_link'};
 1923     my $copyright_link = $settings->{'copyright_link'};
 1924     $page =~ s/\$javascript/$javascript$icon_link\n$copyright_link/g;
 1925     my $contact_form_link = "<p class=\"contactform\" id=\"cf_version\"><a class=\"contactform cf_link\" href=\"http://ostermiller.org/contactform/\">".&trans('contact_form_version',{'version_number'=>$VERSION})."</a></p>";
 1926     $contact_form_link = "" if (defined $settings->{'contact_form_link'} and "" eq $settings->{'contact_form_link'});
 1927     $contact_form_link = "" if (!$settings->{'show_contact_form_link'});
 1928     $template_error = "" if (!$template_error);
 1929     $page =~ s/\$content/$template_error$content$contact_form_link/g;
 1930 
 1931     if ($ENV{'SERVER_NAME'}){
 1932         print "Content-type: text/html; charset=",$settings->{'charset'},"\n";
 1933         print "\n";
 1934     }
 1935 
 1936     print $page;
 1937 
 1938     exit;
 1939 }
 1940 
 1941 # Remove characters that would be unsafe in an email header.
 1942 sub safeHeader {
 1943     my ($headerText) = @_;
 1944     if (!defined($headerText)){
 1945         $headerText="";
 1946     }
 1947     $headerText =~ s/[\0\n\r]+/ /g;
 1948     return $headerText;
 1949 }
 1950 
 1951 sub safeHeaderName {
 1952     my ($headerText) = @_;
 1953     if (!defined($headerText)){
 1954         $headerText="";
 1955     }
 1956     $headerText =~ s/[\0\n\r\(\)\@\%\<\>]+/ /g;
 1957     return $headerText;
 1958 }
 1959 
 1960 # Convert <, >, & and " to their HTML equivalents.
 1961 sub escapeHTML {
 1962     my ($value) = @_;
 1963     if (!defined($value)){
 1964         $value="";
 1965     }
 1966     $value =~ s/\&/\&amp;/g;
 1967     $value =~ s/</\&lt;/g;
 1968     $value =~ s/>/\&gt;/g;
 1969     $value =~ s/"/\&quot;/g;
 1970     $value =~ s/'/\&#39;/g;
 1971     return $value;
 1972 }
 1973 
 1974 # escape HTML and make text into HTML paragraphs.
 1975 sub textToHTML {
 1976     my ($value) = @_;
 1977     if (!defined($value)){
 1978         $value="";
 1979     }
 1980     $value = escapeHTML($value);
 1981     $value =~ s/(\n[\r\n]+)|(\r\n[\r\n]+)|(\r\r[\r\n]*)/<p>/g;
 1982     $value =~ s/[\r\n]+/<br>/g;
 1983     $value =~ s/\<p\>/\n<p>\n/g;
 1984     $value =~ s/\<br\>/<br>\n/g;
 1985     return $value;
 1986 }
 1987 
 1988 # put in javascript escape sequences.
 1989 sub escapeJavaScript {
 1990     my ($value) = @_;
 1991     if (!defined($value)){
 1992         $value="";
 1993     }
 1994     $value =~ s/\\/\\\\/g;
 1995     $value =~ s/\'/\\'/g;
 1996     $value =~ s/\n/\\n'/g;
 1997     $value =~ s/\r/\\r'/g;
 1998     $value =~ s/\t/\\t'/g;
 1999     return $value;
 2000 }
 2001 
 2002 sub getOrderedFields {
 2003     return @Field_Order;
 2004 }
 2005 
 2006 sub contactformicon {
 2007     print "Content-type: image/png\n";
 2008     print "\n";
 2009     print "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52";
 2010     print "\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\x00\x00\x00\x1f\xf3\xff";
 2011     print "\x61\x00\x00\x01\xbc\x49\x44\x41\x54\x78\x9c\xa5\x92\x4d\x6e\x13";
 2012     print "\x41\x10\x85\xbf\xea\xee\xb1\x31\x72\xe2\xbf\x90\xe4\x0a\x88\x25";
 2013     print "\x87\x60\x83\x60\xc9\x6d\xb8\x0b\x6b\x96\x88\x15\x6b\x8e\x00\x6c";
 2014     print "\xed\x28\x12\xc1\x7f\x33\x4e\x6c\xc7\xe3\xe9\xae\x62\xe1\x38\x8e";
 2015     print "\x09\x28\x20\x6a\xd7\xaa\xf7\x5e\xd7\x7b\x55\xf0\x9f\x25\xef\xde";
 2016     print "\x5f\xbc\xed\x1c\xda\x4b\xef\x39\xaf\xa2\x9c\x95\x6b\x06\x55\x64";
 2017     print "\x20\x22\x83\x5a\x26\x67\xb5\x4c\xa6\xaf\x5f\x3c\x49\x7f\x14\xf8";
 2018     print "\xf8\xe9\xfb\x57\xef\x79\x7a\xd2\x53\xbc\x03\x03\x52\x82\xaa\x12";
 2019     print "\xd6\x11\x4b\x89\xcb\xa4\x72\x9e\x94\x41\x15\xe9\x97\x6b\x19\xac";
 2020     print "\x4a\xfa\x49\xa5\x1f\xbc\x7c\x0b\xe2\x48\xa7\x3d\xe5\xc7\xd4\x71";
 2021     print "\xda\x53\x44\x20\x78\x08\xde\x68\x80\x00\x2d\xb0\x16\xf0\x6c\xfb";
 2022     print "\xab\x1a\xcc\x97\xc2\x70\x22\x9f\x1d\x46\x74\x0e\x8e\x3b\x1b\x11";
 2023     print "\xb3\x87\x7d\xa7\x04\x31\x42\xaf\x6d\x3d\x67\x50\x01\x78\x0f\xbd";
 2024     print "\x96\x32\xca\xe5\x41\x72\x71\x25\x74\x5b\x06\x20\xce\x8c\xb8\x6d";
 2025     print "\x66\x01\xda\x07\xc6\xb8\xf8\xbd\x88\x19\x4c\x66\xc2\x51\xfb\x66";
 2026     print "\x4c\xc1\x39\x90\x78\x17\x54\xcb\xa0\xd9\x30\x86\xd3\xfb\x22\xa3";
 2027     print "\x7c\x43\x96\x5d\xcb\x39\x33\xab\x7e\x05\x2e\x4b\xc1\x7b\x98\xce";
 2028     print "\x76\xc8\x49\x21\xa8\x71\x97\x0c\x86\x06\x33\xf6\x04\xae\x96\x42";
 2029     print "\x70\x70\xd8\x34\xae\x4b\x61\x5c\x08\xde\x41\xe3\x11\x74\x6a\xb6";
 2030     print "\x6f\x01\x2c\x98\xc9\x7a\xfb\x5a\xad\xa1\xaa\xd8\x06\x44\xa3\x6e";
 2031     print "\x64\x1e\x92\x41\x3d\xdb\x60\x0e\x1e\x1b\xb3\xb9\xd0\x6a\xda\x26";
 2032     print "\x03\x35\x16\x00\x55\x84\xd9\x2e\xdd\xdb\x0a\x61\x47\x06\xa8\xd7";
 2033     print "\xc0\x39\x58\x95\xb7\x19\x10\x55\x61\x9c\x3b\x8e\xbb\x7f\x71\x04";
 2034     print "\x37\x53\x5c\x97\x42\x4a\x48\x50\x65\x7d\x31\x71\x9c\x74\x75\x3f";
 2035     print "\xa0\xad\x49\xdb\x5c\x9e\x2a\xa4\x24\x24\x85\xa4\x98\x08\xe5\x28";
 2036     print "\x77\x5f\xc2\xe2\x5a\x3e\x64\xc1\x9e\x0f\x73\x37\x57\x25\x57\xa5";
 2037     print "\x48\x4a\x1e\x93\xe4\x31\x51\xc4\x48\x9e\x94\xdc\x8c\x42\x44\x72";
 2038     print "\xef\x28\x42\x90\x4b\xef\xdd\xe2\xcd\xab\xa3\x7b\x1b\xfc\xe7\xfa";
 2039     print "\x09\xfd\xc8\xe6\x8e\x15\xeb\x74\x06\x00\x00\x00\x00\x49\x45\x4e";
 2040     print "\x44\xae\x42\x60\x82\x00";
 2041     exit;
 2042 }