home *** CD-ROM | disk | FTP | other *** search
/ ftp.anonawest.com / ftp.anonawest.com.tar / ftp.anonawest.com / anonawest.com / formmail.php < prev    next >
PHP Script  |  2017-06-01  |  416KB  |  11,431 lines

  1. <?php
  2. $FM_VERS = "8.15";      // script version
  3.  
  4. /* ex:set ts=4 sw=4 et:
  5.  * FormMail PHP script from Tectite.com.  This script requires PHP 4 or later.
  6.  * Copyright (c) 2001-2009 Root Software and Open Concepts (Vic) Pty Ltd
  7.  * (ABN 12 130 429 248), Melbourne, Australia.
  8.  * This script is free for all use as described in the "Copying and Use" and
  9.  * "Warranty and Disclaimer" sections below.
  10.  *
  11.  * Visit us at http://www.tectite.com/ for updates and more information.
  12.  *
  13.  *** If you use Tectite FormMail, please support its development and other
  14.  *** freeware products by putting the following link on your website:
  15.  ***  Visit www.tectite.com for free <a href="http://www.tectite.com/">FormMail</a>.
  16.  *
  17.  * Author: Russell Robinson, 2nd October 2001
  18.  *
  19.  * Read This First
  20.  * ~~~~~~~~~~~~~~~
  21.  *  This script is very well documented and quite large!  It looks daunting,
  22.  *  but really isn't.
  23.  *  If you have experience with PHP or other scripting languages,
  24.  *  here's what you *need* to read:
  25.  *      - Configuration (TARGET_EMAIL & DEF_ALERT)
  26.  *      - Creating Forms
  27.  *  That's it!  (Alternatively, just read the Quick Start and/or
  28.  *  Quicker Start section below).
  29.  *  Full configuration documentation is here:
  30.  *      http://www.tectite.com/fmdoc/index.php
  31.  *
  32.  *  NOTE: do not read or modify this script or any PHP script
  33.  *  with DreamWeaver or FrontPage!
  34.  *  Many versions of those programs silently corrupt PHP scripts.
  35.  *
  36.  * Purpose:
  37.  * ~~~~~~~~
  38.  *  To accept information from an HTML form via HTTP and mail it to recipients.
  39.  *
  40.  * What does this PHP script do?
  41.  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  42.  *  On your web site, you may have one or more HTML forms that accept
  43.  *  information from people visiting your website.  Your aim is for your
  44.  *  website to email that information to you and/or add it to a database.
  45.  *  FormMail performs those functions.
  46.  *
  47.  * Quick Start
  48.  * ~~~~~~~~~~~
  49.  *  1. Edit this file and set TARGET_EMAIL for your requirements (near
  50.  *      line 246 in this file - replace "yourhost\.com" with your mail server's
  51.  *      name).  We also strongly recommend you set DEF_ALERT (the next
  52.  *      configuration below TARGET_EMAIL).
  53.  *  2. Install this file as formmail.php (or other name ending in .php)
  54.  *     on your web server.
  55.  *     Test alerts by using your browser to open a URL to the script:
  56.  *          http://www.yourhost.com/formmail.php?testalert=1
  57.  *     Alerts are the only way FormMail can tell you the details of
  58.  *     errors or faults.
  59.  *  3. Create an HTML form and:
  60.  *      - specify a hidden field called "recipients" with the email address
  61.  *        of the person to receive the form's results.
  62.  *      - in the your form tag set the action attribute to
  63.  *        the formmail.php you uploaded to your web server
  64.  *
  65.  *  Once you have FormMail working, you may be interested in some advanced
  66.  *  usage and features.  We have HOW-TO guides at www.tectite.com which
  67.  *  describe many of the advanced processing you can do with FormMail.
  68.  *      http://www.tectite.com/fmhowto/guides.php
  69.  *
  70.  * Quicker Start
  71.  * ~~~~~~~~~~~~~
  72.  *  Use the FormMail Configuration Wizard here:
  73.  *      http://www.tectite.com/wizards/fmconf.php
  74.  *  By answering a few questions you'll get a configured FormMail and
  75.  *  a sample HTML form ready to upload and use on your server.
  76.  *
  77.  * Features
  78.  * ~~~~~~~~
  79.  *  For a list of features go to: http://www.tectite.com/formmailpage.php
  80.  *
  81.  * Security
  82.  * ~~~~~~~~
  83.  *  Security is the primary concern in accepting data from your website
  84.  *  visitors.
  85.  *  Tectite FormMail has several security features designed into it.  Note,
  86.  *  however, it requires configuration for your particular web site.
  87.  *
  88.  * Configuration
  89.  * ~~~~~~~~~~~~~
  90.  *  To configure this script, go to the section titled "CONFIGURATION"
  91.  *  (after reading the legal stuff below).
  92.  *
  93.  *  There is only one mandatory setting: TARGET_EMAIL
  94.  *  and one strongly recommended setting: DEF_ALERT
  95.  *
  96.  *  Full configuration information is available here:
  97.  *      http://www.tectite.com/fmdoc/index.php
  98.  *
  99.  * Creating Forms
  100.  * ~~~~~~~~~~~~~~
  101.  *  Go to this URL to learn how to write HTML forms for use with
  102.  *  Tectite FormMail: http://www.tectite.com/fmdoc/creating_forms.php
  103.  *
  104.  * Copying and Use (Software License)
  105.  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  106.  *  Tectite FormMail is provided free of charge and may be freely distributed
  107.  *  and used provided that you:
  108.  *      1. keep this header, including copyright and comments,
  109.  *         in place and unmodified; and,
  110.  *      2. do not charge a fee for distributing it, without an agreement
  111.  *         in writing with Root Software allowing you to do so; and,
  112.  *      3. if you modify FormMail before distributing it, you clearly
  113.  *         identify:
  114.  *              a) who you are
  115.  *              b) how to contact you
  116.  *              c) what changes you have made
  117.  *              d) why you have made those changes.
  118.  *
  119.  *  By using any of our products, including this script, you are
  120.  *  agreeing to our standard Terms and Conditions, available here:
  121.  *      http://www.tectite.com/TermsAndConditions.pdf
  122.  *
  123.  *  This is free software and the Software License shown above
  124.  *  is to be read in conjunction with our standard Terms and Conditions.
  125.  *
  126.  * Warranty and Disclaimer
  127.  * ~~~~~~~~~~~~~~~~~~~~~~~
  128.  *  Tectite FormMail is provided free-of-charge and with ABSOLUTELY NO WARRANTY.
  129.  *  It has not been verified for use in critical applications, including,
  130.  *  but not limited to, medicine, defense, aircraft, space exploration,
  131.  *  or any other potentially dangerous activity.
  132.  *
  133.  *  By using Tectite FormMail you agree to indemnify Root Software and
  134.  *  Open Concepts (Vic) Pty Ltd, their agents, employees, directors and
  135.  *  associated companies and businesses from any liability whatsoever.
  136.  *
  137.  * We still care
  138.  * ~~~~~~~~~~~~~
  139.  *  If you find a bug or fault in FormMail, please report it to us.
  140.  *  We will respond to your report and make endeavours to rectify any
  141.  *  faults you've detected as soon as possible.
  142.  *
  143.  *  To contact us please register on our forums at:
  144.  *      http://www.tectite.com/vbforums/
  145.  *  or view our contact information:
  146.  *      http://www.tectite.com/contacts.php
  147.  *
  148.  * Version History
  149.  * ~~~~~~~~~~~~~~~
  150.  *  Near the top of this file, you'll find its version. The version
  151.  *  line looks like this:
  152.  *       $FM_VERS = "N.MM";     /* script version ...
  153.  *
  154.  *  The version history used to be located within this file.  However,
  155.  *  starting with Version 8.00 we've moved it...
  156.  *
  157.  *  You can read the complete version history of FormMail on our
  158.  *  main website here:
  159.  *   http://www.tectite.com/fmdoc/version_history.php
  160.  */
  161.  
  162.     //
  163.     // Capture the current date and time, for various purposes.
  164.     //
  165. $lNow = time();
  166.  
  167. set_magic_quotes_runtime(0);        // disable this silly setting (usually not enabled)
  168. ini_set('track_errors',1);          // enable $php_errormsg
  169.  
  170. $aAlertInfo = array();
  171. $aPHPVERSION = array();
  172.  
  173. $sLangID = "";                      // the language ID
  174. $aMessages = array();               // all FormMail messages in the appropriate
  175.                                     // language
  176.  
  177. $bUseOldVars = IsOldVersion($aPHPVERSION);
  178.  
  179.     //
  180.     // seed the random number generate if not version 4.2.0 or later
  181.     //
  182. if (!IsPHPAtLeast("4.2.0"))
  183.     mt_srand(time());
  184.  
  185.     //
  186.     // we set references to the appropriate arrays to handle PHP version differences
  187.     // Session vars are selected after we start the session.
  188.     //
  189. if ($bUseOldVars)
  190. {
  191.     $aServerVars = &$HTTP_SERVER_VARS;
  192.     $aGetVars = &$HTTP_GET_VARS;
  193.     $aFormVars = &$HTTP_POST_VARS;
  194.     $aFileVars = &$HTTP_POST_FILES;
  195.     $aEnvVars = &$HTTP_ENV_VARS;
  196. }
  197. else
  198. {
  199.     $aServerVars = &$_SERVER;
  200.     $aGetVars = &$_GET;
  201.     $aFormVars = &$_POST;
  202.     $aFileVars = &$_FILES;
  203.     $aEnvVars = &$_ENV;
  204. }
  205. $bIsGetMethod = false;
  206.  
  207.     //
  208.     // If the form submission was using the GET method, switch to the
  209.     // GET vars instead of the POST vars
  210.     //
  211. if (isset($aServerVars["REQUEST_METHOD"]) && $aServerVars["REQUEST_METHOD"] === "GET")
  212. {
  213.     $bIsGetMethod = true;
  214.     if ($bUseOldVars)
  215.         $aFormVars = &$HTTP_GET_VARS;
  216.     else
  217.         $aFormVars = &$_GET;
  218. }
  219.  
  220. if (!isset($REAL_DOCUMENT_ROOT))
  221.     SetRealDocumentRoot();
  222.  
  223. if (isset($aServerVars['SERVER_PORT']))
  224.     $SCHEME = ($aServerVars['SERVER_PORT'] == 80) ? "http://" : "https://";
  225. else
  226.     $SCHEME = "";
  227. if (isset($aServerVars['SERVER_NAME']) && $aServerVars['SERVER_NAME'] !== "")
  228.     $SERVER = $aServerVars['SERVER_NAME'];
  229. elseif (isset($aServerVars['SERVER_ADDR']) && $aServerVars['SERVER_ADDR'] !== "")
  230.     $SERVER = $aServerVars['SERVER_ADDR'];
  231. else
  232.     $SERVER = "";
  233.  
  234. /*****************************************************************************/
  235. /* CONFIGURATION (do not alter this line in any way!!!)                      */
  236. /*****************************************************************************
  237.  * This is the *only* place where you need to modify things to use formmail.php
  238.  * on your particular system.  This section finishes at "END OF CONFIGURATION".
  239.  * Help for all settings can be found on our website:
  240.  *  http://www.tectite.com/fmdoc/index.php
  241.  *
  242.  * Also, above each setting is a direct URL to the help information for the
  243.  * setting.
  244.  *****************************************************************************/
  245.  
  246.             /* Help: http://www.tectite.com/fmdoc/email_name.php */
  247. define("EMAIL_NAME","^[-a-z0-9.]+");    // the '^' is an important security feature!
  248.  
  249.             /* Help: http://www.tectite.com/fmdoc/target_email.php */
  250. $TARGET_EMAIL = array(EMAIL_NAME."anonapalooza@gmail\.com$");
  251.  
  252.             /* Help: http://www.tectite.com/fmdoc/def_alert.php */
  253. define("DEF_ALERT","anonapalooza@gmail.com");
  254.  
  255.             /* Help: http://www.tectite.com/fmdoc/set_real_document_root.php */
  256. $SET_REAL_DOCUMENT_ROOT = "";       // overrides the value set by SetRealDocumentRoot function
  257.  
  258.     //
  259.     // override $REAL_DOCUMENT_ROOT from the $SET_REAL_DOCUMENT_ROOT value (if any)
  260.     // Do not alter the following code (next 3 lines)!
  261.     //
  262. if (isset($SET_REAL_DOCUMENT_ROOT) && $SET_REAL_DOCUMENT_ROOT !== "")
  263.     $REAL_DOCUMENT_ROOT = $SET_REAL_DOCUMENT_ROOT;
  264.  
  265.             /* Help: http://www.tectite.com/fmdoc/config_check.php */
  266. $CONFIG_CHECK = array("TARGET_EMAIL");
  267.  
  268.             /* Help: http://www.tectite.com/fmdoc/at_mangle.php */
  269. define("AT_MANGLE","");
  270.  
  271.             /* Help: http://www.tectite.com/fmdoc/target_urls.php */
  272. $TARGET_URLS = array();         // default; no URLs allowed
  273.  
  274.             /* Help: http://www.tectite.com/fmdoc/head_crlf.php */
  275. define("HEAD_CRLF","\r\n");
  276.  
  277.             /* Help: http://www.tectite.com/fmdoc/body_lf.php */
  278. define("BODY_LF","\r\n");       // the new default: use this for CR+LF
  279. //define("BODY_LF","\n");       // the old default: just LF
  280.  
  281.             /* Help: http://www.tectite.com/fmdoc/from_user.php */
  282. $FROM_USER = "";                            // the default - setting not used
  283.  
  284.             /* Help: http://www.tectite.com/fmdoc/sendmail_f_option.php */
  285. define("SENDMAIL_F_OPTION",false);
  286. define("SENDMAIL_F_OPTION_LINE",__LINE__-1);    // don't modify this line!
  287.  
  288.             /* Help: http://www.tectite.com/fmdoc/fixed_sender.php */
  289. $FIXED_SENDER = "";
  290.  
  291.             /* Help: http://www.tectite.com/fmdoc/set_sender_from_email.php */
  292. define("SET_SENDER_FROM_EMAIL",false);
  293.  
  294.             /* Help: http://www.tectite.com/fmdoc/ini_set_from.php */
  295. define("INI_SET_FROM",false);
  296.  
  297.             /* Help: http://www.tectite.com/fmdoc/logdir.php */
  298. $LOGDIR = "";                           // directory for log files; empty string to
  299.                                         // disallow log files
  300.             /* Help: http://www.tectite.com/fmdoc/autorespondlog.php */
  301. $AUTORESPONDLOG = "";           // file name in $LOGDIR for the auto responder
  302.                                 // log; empty string for no auto responder log
  303.  
  304.             /* Help: http://www.tectite.com/fmdoc/csv_file_settings.php */
  305. $CSVDIR = "";                       // directory for csv files; empty string to
  306.                                     // disallow csv files
  307. $CSVSEP = ",";      // comma separator between fields (columns)
  308. $CSVINTSEP = ";";   // semicolon is the separator for fields (columns)
  309.                     // with multiple values (checkboxes, etc.)
  310. $CSVQUOTE = '"';    // all fields in the CSV are quoted with this character;
  311.                     // default is double quote.  You can change it to
  312.                     // single quote or leave it empty for no quotes.
  313. //$CSVQUOTE = "'";  // use this if you want single quotes
  314. $CSVOPEN = "";      // set to "b" to force line terminations to be
  315.                     // kept as $CSVLINE setting below, regardless of
  316.                     // operating system.  Keep as empty string and
  317.                     // leave $CSVLINE unchanged, to get text file
  318.                     // terminations for your server's operating system.
  319.                     // (Line feed on UNIX, carriage-return line feed on Windows).
  320. $CSVLINE = "\n";    // line termination for CSV files.  The default is
  321.                     // a single line feed, which may be modified for your
  322.                     // server's operating system.  If you want to change
  323.                     // this value, you *must* set $CSVOPEN = "b".
  324.  
  325.             /* Help: http://www.tectite.com/fmdoc/templatedir.php */
  326. $TEMPLATEDIR = "";                  // directory for template files; empty string
  327.                                     // if you don't have any templates
  328.  
  329.             /* Help: http://www.tectite.com/fmdoc/templateurl.php */
  330. $TEMPLATEURL = "";                  // default; no template URL
  331.  
  332.             /* Help: http://www.tectite.com/fmdoc/multiformdir.php */
  333. $MULTIFORMDIR = "";         // directory for multi-form template files; empty string
  334.                             // if you're not using multi-forms
  335.  
  336.             /* Help: http://www.tectite.com/fmdoc/multiformurl.php */
  337. $MULTIFORMURL = "";                 // default; no multi-forms templates URL
  338.  
  339.             /* Help: http://www.tectite.com/fmdoc/authentication_settings.php */
  340. $AUTHENTICATE = "";
  341. //$AUTHENTICATE = "Basic cnVzc2VsbHI6dGVzdA==";        // example
  342. $AUTH_USER = "";
  343. $AUTH_PW = "";
  344.  
  345.             /* Help: http://www.tectite.com/fmdoc/form_ini_file.php */
  346. $FORM_INI_FILE = "";
  347.  
  348.             /* Help: http://www.tectite.com/fmdoc/moduledir.php */
  349. $MODULEDIR = ".";
  350.  
  351.             /* Help: http://www.tectite.com/fmdoc/fmcompute.php */
  352. $FMCOMPUTE = "fmcompute.php";
  353.  
  354.             /* Help: http://www.tectite.com/fmdoc/fmgeoip.php */
  355. $FMGEOIP = "fmgeoip.php";
  356.  
  357.             /* Help: http://www.tectite.com/fmdoc/advanced_templates.php */
  358. define("ADVANCED_TEMPLATES",false);     // set to true for advanced templates
  359.  
  360.             /* Help: http://www.tectite.com/fmdoc/limited_import.php */
  361. define("LIMITED_IMPORT",true);      // set to true if your database cannot
  362.                                     // handle escaped quotes or newlines within
  363.                                     // imported data.  Microsoft Access is one
  364.                                     // example.
  365.  
  366.             /* Help: http://www.tectite.com/fmdoc/valid_env.php */
  367. $VALID_ENV = array('HTTP_REFERER','REMOTE_HOST','REMOTE_ADDR','REMOTE_USER',
  368.                 'HTTP_USER_AGENT');
  369.  
  370.             /* Help: http://www.tectite.com/fmdoc/fileuploads.php */
  371. define("FILEUPLOADS",false);        // set to true to allow file attachments
  372.  
  373.             /* Help: http://www.tectite.com/fmdoc/max_file_upload_size.php */
  374. define("MAX_FILE_UPLOAD_SIZE",0);       // default of 0 means that other software
  375.                                         // controls the maximum file upload size
  376.                                         // (FormMail doesn't test the file size)
  377.  
  378.             /* Help: http://www.tectite.com/fmdoc/file_repository.php */
  379. $FILE_REPOSITORY = "";
  380.  
  381.             /* Help: http://www.tectite.com/fmdoc/file_mode.php */
  382. define("FILE_MODE",0664);     // always precede with 0 to specify octal!
  383.  
  384.             /* Help: http://www.tectite.com/fmdoc/file_overwrite.php */
  385. define("FILE_OVERWRITE",true);
  386.  
  387.             /* Help: http://www.tectite.com/fmdoc/next_num_file.php */
  388. $NEXT_NUM_FILE = "";
  389.  
  390.             /* Help: http://www.tectite.com/fmdoc/put_data_in_url.php */
  391. define("PUT_DATA_IN_URL",true); // set to true to place data in the URL
  392.                                 // for bad_url redirects
  393.  
  394.             /* Help: http://www.tectite.com/fmdoc/db_see_input.php */
  395. define("DB_SEE_INPUT",false);   // set to true to just see the input values
  396.  
  397.             /* Help: http://www.tectite.com/fmdoc/db_see_ini.php */
  398. define("DB_SEE_INI",false);     // set to true to just see the ini file
  399.  
  400.             /* Help: http://www.tectite.com/fmdoc/maxstring.php */
  401. define("MAXSTRING",1024);       // maximum string length for a value
  402.  
  403.             /* Help: http://www.tectite.com/fmdoc/require_captcha.php */
  404. $REQUIRE_CAPTCHA = "";          // set to a message string if your forms
  405.                                 // must provide a CAPTCHA string
  406.  
  407.             /* Help: http://www.tectite.com/fmdoc/bshowmesgnumbers.php */
  408. $bShowMesgNumbers = false;
  409.  
  410.             /* Help: http://www.tectite.com/fmdoc/filters.php */
  411.             /* Note for Tectite personnel: the upgrade Wizard will merge new values
  412.              * but be careful of $var usage and quoting in new entries.
  413.              */
  414. $FILTERS = array("encode"=>"$REAL_DOCUMENT_ROOT/cgi-bin/fmencoder -kpubkey.txt",
  415.                 "null"=>"null",
  416.                 "csv"=>"csv");
  417.  
  418.             /* Help: http://www.tectite.com/fmdoc/socket_filters.php */
  419. $SOCKET_FILTERS = array(
  420.                  "httpencode"=>array("site"=>"YourSiteHere",
  421.                     "port"=>80,
  422.                     "path"=>"/cgi-bin/fmencoder",
  423.                     "params"=>array(array("name"=>"key",
  424.                             "file"=>"$REAL_DOCUMENT_ROOT/cgi-bin/pubkey.txt"))),
  425.                  "sslencode"=>array("site"=>"ssl://YourSecureSiteHere",
  426.                     "port"=>443,
  427.                     "path"=>"/cgi-bin/fmencoder",
  428.                     "params"=>array(array("name"=>"key",
  429.                             "file"=>"$REAL_DOCUMENT_ROOT/cgi-bin/pubkey.txt"))),
  430.                 );
  431.  
  432.             /* Help: http://www.tectite.com/fmdoc/filter_attribs.php */
  433. $FILTER_ATTRIBS = array("encode"=>"Strips,MIME=application/vnd.fmencoded,Encrypts",
  434.                         "httpencode"=>"Strips,MIME=application/vnd.fmencoded,Encrypts",
  435.                         "sslencode"=>"Strips,MIME=application/vnd.fmencoded,Encrypts",
  436.                         "csv"=>"Strips,MIME=text/csv",);
  437.  
  438.             /* Help: http://www.tectite.com/fmdoc/check_for_new_version.php */
  439. define("CHECK_FOR_NEW_VERSION",true);
  440. define("CHECK_DAYS",30);
  441.  
  442.             /* Help: http://www.tectite.com/fmdoc/scratch_pad.php */
  443. $SCRATCH_PAD = "";
  444.  
  445.             /* Help: http://www.tectite.com/fmdoc/cleanup_time.php */
  446. $CLEANUP_TIME = 60;     // cleanup time in minutes
  447.  
  448.             /* Help: http://www.tectite.com/fmdoc/cleanup_chance.php */
  449. $CLEANUP_CHANCE = 20;     // percentage probability that cleanup will be performed
  450.  
  451.             /* Help: http://www.tectite.com/fmdoc/pear_settings.php */
  452. $PEAR_SMTP_HOST = "";
  453. $PEAR_SMTP_PORT = 25;
  454. $PEAR_SMTP_USER = "";
  455. $PEAR_SMTP_PWD = "";
  456.  
  457.             /* Help: http://www.tectite.com/fmdoc/alert_on_user_error.php */
  458. define("ALERT_ON_USER_ERROR",true);
  459.  
  460.             /* Help: http://www.tectite.com/fmdoc/enable_attack_detection.php */
  461. define("ENABLE_ATTACK_DETECTION",true);
  462.  
  463.             /* Help: http://www.tectite.com/fmdoc/attack_detection_url.php */
  464. define("ATTACK_DETECTION_URL","");
  465.  
  466.             /* Help: http://www.tectite.com/fmdoc/alert_on_attack_detection.php */
  467. define("ALERT_ON_ATTACK_DETECTION",false);
  468.  
  469.             /* Help: http://www.tectite.com/fmdoc/attack_detection_mime.php */
  470. define("ATTACK_DETECTION_MIME",true);
  471.  
  472.             /* Help: http://www.tectite.com/fmdoc/attack_detection_junk.php */
  473. define("ATTACK_DETECTION_JUNK",false);
  474. define("ATTACK_DETECTION_JUNK_CONSONANTS","bcdfghjklmnpqrstvwxz");
  475. define("ATTACK_DETECTION_JUNK_VOWELS","aeiouy");
  476. define("ATTACK_DETECTION_JUNK_CONSEC_CONSONANTS",5);
  477. define("ATTACK_DETECTION_JUNK_CONSEC_VOWELS",4);
  478. define("ATTACK_DETECTION_JUNK_TRIGGER",2);
  479. $ATTACK_DETECTION_JUNK_LANG_STRIP = array(
  480.     "aiia",  /* Hawaiian */
  481.     "aeoa",  /* palaeoanthropic */
  482.     "aeoe",  /* palaeoethnic */
  483.     "ooee",  /* cooee */
  484.     "oeia",  /* pharmacopoeia */
  485.     "ioau",  /* radioautograph */
  486.     "uaia",  /* guaiac */
  487.     "ueou",  /* aqueous */
  488.     "uiou",  /* obsequious */
  489.     "queue", /* queue, queueing */
  490.     "earth", /* earthquake, earthslide */
  491.     "cks",   /* jockstrap, backscratcher */
  492.     "ngth",  /* strengths, length */
  493.     "ndths", /* thousandths */
  494.     "ght",   /* nightclub, knightsbridge */
  495.     "phth",  /* ophthalmology */
  496.     "sch",   /* rothschild */
  497.     "shch",  /* borshch */
  498.     "scr",   /* corkscrew */
  499.     "spr",   /* wingspread, offspring */
  500.     "str",   /* armstrong, songstress */
  501.     "sts",   /* bursts, postscript */
  502.     "tch",   /* catchphrase, scratchproof */
  503.     "thst",  /* northstar, birthstone */
  504.     "http",  /* https, http */
  505.     "html",  /* HTML, XHTML */
  506.     );
  507.         
  508.  
  509.             /* Help: http://www.tectite.com/fmdoc/attack_detection_dups.php */
  510. $ATTACK_DETECTION_DUPS = array("realname","address1","address2","country","zip",
  511.                                 "phone","postcode","state","email");
  512.  
  513.             /* Help: http://www.tectite.com/fmdoc/attack_detection_specials.php */
  514. define("ATTACK_DETECTION_SPECIALS",true);
  515.  
  516.             /* Help: http://www.tectite.com/fmdoc/attack_detection_specials.php */
  517. $ATTACK_DETECTION_SPECIALS_ONLY_EMAIL = array("derive_fields","required",
  518.                     "mail_options","good_url","bad_url","good_template",
  519.                     "bad_template");
  520.  
  521.             /* Help: http://www.tectite.com/fmdoc/attack_detection_specials.php */
  522. $ATTACK_DETECTION_SPECIALS_ANY_EMAIL = array("subject");
  523.  
  524.             /* Help: http://www.tectite.com/fmdoc/attack_detection_many_urls.php */
  525. define("ATTACK_DETECTION_MANY_URLS",0);
  526.  
  527.             /* Help: http://www.tectite.com/fmdoc/attack_detection_many_url_fields.php */
  528. define("ATTACK_DETECTION_MANY_URL_FIELDS",0);
  529.  
  530.             /* Help: http://www.tectite.com/fmdoc/attack_detection_url_patterns.php */
  531. $ATTACK_DETECTION_URL_PATTERNS = array(
  532.             '(^|[^-a-z_.0-9]+)(?<!@)([-a-z0-9]+\.)+(com|org|net|biz|info|name|pro|tel|asia|cat)\b',
  533.             '(^|[^-a-z_.0-9]+)(?<!@)([-a-z0-9]+\.)+(com{0,1}|org|net)\.[a-z][a-z]\b');
  534.  
  535.             /* Help: http://www.tectite.com/fmdoc/attack_detection_ignore_errors.php */
  536. define("ATTACK_DETECTION_IGNORE_ERRORS",false);
  537.  
  538.             /* Help: http://www.tectite.com/fmdoc/attack_detection_reverse_captcha.php */
  539. $ATTACK_DETECTION_REVERSE_CAPTCHA = array();
  540.  
  541.             /* Help: http://www.tectite.com/fmdoc/geoip_lic.php */
  542. $GEOIP_LIC = "";        // default - no GeoIP
  543.  
  544.             /* Help: http://www.tectite.com/fmdoc/zero_is_empty.php */
  545. define("ZERO_IS_EMPTY",false);
  546.  
  547.             /* Help: http://www.tectite.com/fmdoc/session_name.php */
  548. $SESSION_NAME = "";
  549.  
  550.             /* Help: http://www.tectite.com/fmdoc/session_access.php */
  551. $SESSION_ACCESS = array();
  552.  
  553.             /* Help: http://www.tectite.com/fmdoc/destroy_session.php */
  554. define("DESTROY_SESSION",true);
  555.  
  556.             /* Help: http://www.tectite.com/fmdoc/hook_dir.php */
  557. $HOOK_DIR = "";
  558.  
  559. /* UPGRADE CONTROL
  560. **
  561. ** FILTERS:lt:8.04:merge:The FILTERS configuration has
  562. ** been modified to include some new standard filters.:
  563. **
  564. ** FILTER_ATTRIBS:lt:8.04:no_keep:The FILTER_ATTRIBS configuration has
  565. ** been modified to include new information about the standard filters.:
  566. **
  567. ** ATTACK_DETECTION_URL_PATTERNS:eq:8.02:no_keep:The ATTACK_DETECTION_URL_PATTERNS
  568. ** configuration has been modified to fix a bug.:
  569. **
  570. ** FILTER_ATTRIBS:lt:4.00:no_keep:The FILTER_ATTRIBS configuration has
  571. ** been modified to include new information about the standard filters.:
  572. **
  573. ** SET_REAL_DOCUMENT_ROOT:gt:4.07:copy_from=REAL_DOCUMENT_ROOT:The
  574. ** REAL_DOCUMENT_ROOT configuration has been renamed to SET_REAL_DOCUMENT_ROOT.:
  575. **
  576. ** EMAIL_NAME:lt:6.01:no_keep:The EMAIL_NAME configuration has
  577. ** been modified to match hyphens ('-') in email addresses.:
  578. **
  579. ** ZERO_IS_EMPTY:le:6.01:set_to=true:ZERO_IS_EMPTY has been
  580. ** set to a value that duplicates previous behaviour.:
  581. **
  582. ** END OF CONTROL
  583. */
  584.  
  585. /*****************************************************************************/
  586. /* END OF CONFIGURATION (do not alter this line in any way!!!)               */
  587. /*****************************************************************************/
  588.     //
  589.     // the following constants define all FormMail messages
  590.     //
  591. define('MSG_SCRIPT_VERSION',0);     // This script requires at least PHP version...
  592. define('MSG_END_VERS_CHK',1);       // If you're happy...
  593. define('MSG_VERS_CHK',2);           // A later version of FormMail is available...
  594. define('MSG_CHK_FILE_ERROR',3);     // Unable to create check file...
  595. define('MSG_UNK_VALUE_SPEC',4);     // derive_fields: unknown value specification...
  596. define('MSG_INV_VALUE_SPEC',5);     // derive_fields: invalid value specification...
  597. define('MSG_DERIVED_INVALID',6);    // Some derive_fields specifications...
  598. define('MSG_INT_FORM_ERROR',7);     // Internal form error...
  599. define('MSG_OPTIONS_INVALID',8);    // Some mail_options settings...
  600. define('MSG_PLSWAIT_REDIR',9);      // Please wait while you are redirected...
  601. define('MSG_IFNOT_REDIR',10);       // If you are not redirected...
  602. define('MSG_PEAR_OBJ',11);          // Failed to create PEAR Mail object...
  603. define('MSG_PEAR_ERROR',12);        // PEAR Mail error...
  604. define('MSG_NO_FOPT_ADDR',13);      // You have specified "SendMailFOption"...
  605. define('MSG_MORE_INFO',14);         // More information...
  606. define('MSG_INFO_STOPPED',15);      // Extra alert information suppressed...
  607. define('MSG_FM_ALERT',16);          // FormMail alert
  608. define('MSG_FM_ERROR',17);          // FormMail script error
  609. define('MSG_FM_ERROR_LINE',18);     // The following error occurred...
  610. define('MSG_USERDATA_STOPPED',19);  // User data suppressed...
  611. define('MSG_FILTERED',20);          // This alert has been filtered...
  612. define('MSG_TEMPLATES',21);         // You must set either TEMPLATEDIR or TEMPLATEURL...
  613. define('MSG_OPEN_TEMPLATE',22);     // Failed to open template...
  614. define('MSG_ERROR_PROC',23);        // An error occurred while processing...
  615. define('MSG_ALERT_DONE',24);        // Our staff have been alerted...
  616. define('MSG_PLS_CONTACT',25);       // Please contact us directly...
  617. define('MSG_APOLOGY',26);           // We apologize for any inconvenience...
  618. define('MSG_ABOUT_FORMMAIL',27);    // Your form submission was processed by...
  619. define('MSG_PREG_FAILED',28);       // preg_match_all failed in FindCRMFields...
  620. define('MSG_URL_INVALID',29);       // CRM URL "$URL" is not valid...
  621. define('MSG_URL_OPEN',30);          // Failed to open Customer Relationship...
  622. define('MSG_CRM_FAILED',31);        // Failure report from CRM...
  623. define('MSG_CRM_FORM_ERROR',32);    // Your form submission was not...
  624. define('MSG_OR',33);                // "$ITEM1" or "$ITEM2"
  625. define('MSG_NOT_BOTH',34);          // not both "$ITEM1" and "$ITEM2"
  626. define('MSG_XOR',35);               // "$ITEM1" or "$ITEM2" (but not both)
  627. define('MSG_IS_SAME_AS',36);        // "$ITEM1" is the same as "$ITEM2"
  628. define('MSG_IS_NOT_SAME_AS',37);    // "$ITEM1" is not the same as "$ITEM2"
  629. define('MSG_REQD_OPER',38);         // Operator "$OPER" is not valid for "required"
  630. define('MSG_PAT_FAILED',39);        // Pattern operator "$OPER" failed: pattern...
  631. define('MSG_COND_OPER',40);         // Operator "$OPER" is not valid...
  632. define('MSG_INV_COND',41);          // Invalid "conditions" field...
  633. define('MSG_COND_CHARS',42);        // The conditions field "$FLD" is not valid...
  634. define('MSG_COND_INVALID',43);      // The conditions field "$FLD" is not valid...
  635. define('MSG_COND_TEST_LONG',44);    // Field "$FLD" has too many components...
  636. define('MSG_COND_IF_SHORT',45);     // Field "$FLD" has too few components for...
  637. define('MSG_COND_IF_LONG',46);      // Field "$FLD" has too many components for...
  638. define('MSG_COND_UNK',47);          // Field "$FLD" has an unknown command word...
  639. define('MSG_MISSING',48);           // Missing "$ITEM"...
  640. define('MSG_NEED_ARRAY',49);        // "$ITEM" must be an array...
  641. define('MSG_SUBM_FAILED',50);       // Your form submission has failed...
  642. define('MSG_FILTER_WRONG',51);      // Filter "$FILTER" is not properly...
  643. define('MSG_FILTER_CONNECT',52);    // Could not connect to site "$SITE"...
  644. define('MSG_FILTER_PARAM',53);      // Filter "$FILTER" has invalid parameter...
  645. define('MSG_FILTER_OPEN_FILE',54);  // Filter "$FILTER" cannot open file...
  646. define('MSG_FILTER_FILE_ERROR',55); // Filter "$FILTER": read error on file...
  647. define('MSG_FILTER_READ_ERROR',56); // Filter '$filter' failed: read error...
  648. define('MSG_FILTER_NOT_OK',57);     // Filter 'FILTER' failed...
  649. define('MSG_FILTER_UNK',58);        // Unknown filter...
  650. define('MSG_FILTER_CHDIR',59);      // Cannot chdir...
  651. define('MSG_FILTER_NOTFOUND',60);   // Cannot execute...
  652. define('MSG_FILTER_ERROR',61);      // Filter "$FILTER" failed...
  653. define('MSG_SPARE',62);             // this value is now spare
  654. define('MSG_TEMPLATE_ERRORS',63);   // Template "$NAME" caused the...
  655. define('MSG_TEMPLATE_FAILED',64);   // Failed to process template "$NAME"...
  656. define('MSG_MIME_PREAMBLE',65);     // (Your mail reader should not show this...
  657. define('MSG_MIME_HTML',66);         // This message has been generated by FormMail...
  658. define('MSG_FILE_OPEN_ERROR',67);   // Failed to open file "$NAME"...
  659. define('MSG_ATTACH_DATA',68);       // Internal error: AttachFile requires...
  660. define('MSG_PHP_HTML_TEMPLATES',69);    // HTMLTemplate option is only ...
  661. define('MSG_PHP_FILE_UPLOADS',70);  // For security reasons, file upload...
  662. define('MSG_FILE_UPLOAD',71);       // File upload attempt ignored...
  663. define('MSG_FILE_UPLOAD_ATTACK',72);// Possible file upload attack...
  664. define('MSG_PHP_PLAIN_TEMPLATES',73);// PlainTemplate option is only...
  665. define('MSG_ATTACH_NAME',74);       // filter_options: Attach must contain a name...
  666. define('MSG_PHP_BCC',75);           // Warning: BCC is probably not supported...
  667. define('MSG_CSVCOLUMNS',76);        // The "csvcolumns" setting is not...
  668. define('MSG_CSVFILE',77);           // The "csvfile" setting is not...
  669. define('MSG_TARG_EMAIL_PAT_START',78);  // Warning: Your TARGET_EMAIL pattern...
  670. define('MSG_TARG_EMAIL_PAT_END',79);    // Warning: Your TARGET_EMAIL pattern...
  671. define('MSG_CONFIG_WARN',80);       // The following potential problems...
  672. define('MSG_PHP_AUTORESP',81);      // Autorespond is only supported...
  673. define('MSG_ALERT',82);             // This is a test alert message...
  674. define('MSG_NO_DEF_ALERT',83);      // No DEF_ALERT value has been set....
  675. define('MSG_TEST_SENT',84);         // Test message sent.  Check your email.....
  676. define('MSG_TEST_FAILED',85);       // FAILED to send alert message...
  677. define('MSG_NO_DATA_PAGE',86);      // This URL is a Form submission program...
  678. define('MSG_REQD_ERROR',87);        // The form required some values that you...
  679. define('MSG_COND_ERROR',88);        // Some of the values you provided...
  680. define('MSG_CRM_FAILURE',89);       // The form submission did not succeed...
  681. define('MSG_FOPTION_WARN',90);      // Warning: You've used SendMailFOption in...
  682. define('MSG_NO_ACTIONS',91);        // The form has an internal error...
  683. define('MSG_NO_RECIP',92);          // The form has an internal error...
  684. define('MSG_INV_EMAIL',93);         // Invalid email addresses...
  685. define('MSG_FAILED_SEND',94);       // Failed to send email...
  686. define('MSG_ARESP_EMAIL',96);       // No "email" field was found. Autorespond...
  687. define('MSG_ARESP_SUBJ',97);        // Your form submission...
  688. define('MSG_LOG_NO_VERIMG',98);     // No VerifyImgString in session...
  689. define('MSG_ARESP_NO_AUTH',99);     // Failed to obtain authorization...
  690. define('MSG_LOG_NO_MATCH',100);     // User did not match image...
  691. define('MSG_ARESP_NO_MATCH',101);   // Your entry did not match...
  692. define('MSG_LOG_FAILED',102);       // Failed
  693. define('MSG_ARESP_FAILED',103);     // Autoresponder failed
  694. define('MSG_LOG_OK',104);           // OK
  695. define('MSG_THANKS_PAGE',105);      // Thanks!  We've received your....
  696. define('MSG_LOAD_MODULE',106);      // Cannot load module....
  697. define('MSG_LOAD_FMCOMPUTE',107);   // Cannot load FMCompute....
  698. define('MSG_REGISTER_MODULE',108);  // Cannot register module....
  699. define('MSG_COMP_PARSE',109);       // These parse errors occurred....
  700. define('MSG_COMP_REG_DATA',110);    // Failed to register data field....
  701. define('MSG_COMP_ALERT',111);       // The following alert messages....
  702. define('MSG_COMP_DEBUG',112);       // The following debug messages...
  703. define('MSG_COMP_EXEC',113);        // The following errors occurred....
  704. define('MSG_REG_FMCOMPUTE',114);    // Cannot register function...
  705. define('MSG_USER_ERRORS',115);      // A number of errors occurred...
  706. define('MSG_CALL_PARAM_COUNT',116); // Invalid parameter count...
  707. define('MSG_CALL_UNK_FUNC',117);    // Unknown function...
  708. define('MSG_SAVE_FILE',118);        // Failed to save file....
  709. define('MSG_CHMOD',119);            // Failed to chmod file....
  710. define('MSG_VERIFY_MISSING',120);   // Image verification string missing...
  711. define('MSG_VERIFY_MATCH',121);     // Your entry did not match...
  712. define('MSG_FILE_NAMES_INVALID',122);// Some file_names specifications...
  713. define('MSG_FILE_NAMES_NOT_FILE',123);// Your file_names specification...
  714. define('MSG_TEMPL_ALERT',124);       // The following alert messages....
  715. define('MSG_TEMPL_DEBUG',125);       // The following debug messages...
  716. define('MSG_TEMPL_PROC',126);        // The following errors occurred....
  717. define('MSG_SAVE_FILE_EXISTS',127);  // Cannot save file....
  718. define('MSG_EMPTY_ADDRESSES',128);   // $COUNT empty addresses
  719. define('MSG_CALL_INVALID_PARAM',129); // Invalid parameter....
  720.  
  721. define('MSG_AND',133);              // "$ITEM1" and "$ITEM2"
  722. define('MSG_NEXT_PLUS_GOOD',134);   // The form specifies both next_form and....
  723. define('MSG_MULTIFORM',135);        // You must set either MULTIFORMDIR or MULTIFORMURL...
  724. define('MSG_MULTIFORM_FAILED',136); // Failed to process multi-page form template "$NAME"...
  725. define('MSG_NEED_THIS_FORM',137);   // Multi-page forms require "this_form" field...
  726. define('MSG_NO_PHP_SELF',138);      // PHP on the server is not providing "PHP_SELF"
  727. define('MSG_RETURN_URL_INVALID',139); // Return "$URL" is not valid...
  728. define('MSG_GO_BACK',140);          // Cannot 'go back' if not a multi-page form...
  729. define('MSG_OPEN_URL',141);         // Cannot open URL...
  730. define('MSG_CANNOT_RETURN',142);    // Cannot return to page....
  731. define('MSG_ATTACK_DETECTED',143);  // Server attack detected....
  732. define('MSG_ATTACK_PAGE',144);      // Your form submission....
  733. define('MSG_ATTACK_MIME_INFO',145); // The field "$FLD" contained...
  734. define('MSG_ATTACK_DUP_INFO',146);  // The fields "$FLD1" and...
  735. define('MSG_ATTACK_SPEC_INFO',147); // Special field "$FLD"...
  736. define('MSG_NEED_SCRATCH_PAD',148); // You need to set SCRATCH_PAD...
  737. define('MSG_MULTI_UPLOAD',149);     // File upload processing failed during multi-page form processing.
  738. define('MSG_OPEN_SCRATCH_PAD',150); // Cannot open directory...
  739. define('MSG_NO_NEXT_NUM_FILE',151); // You cannot use the %nextnum% feature...
  740. define('MSG_NEXT_NUM_FILE',152);    // Cannot process next number...
  741. define('MSG_ATTACK_MANYURL_INFO',153); // Field "$FLD"...
  742. define('MSG_ATTACK_MANYFIELDS_INFO',154); // $NUM fields have URLs....
  743. define('MSG_REV_CAP',155);           // ATTACK_DETECTION_REVERSE_CAPTCHA setting....
  744. define('MSG_ATTACK_REV_CAP_INFO',156); // The field "$FLD" contained...
  745. define('MSG_ATTACK_JUNK_INFO',157); // The field "$FLD" contained...
  746.  
  747. define('MSG_URL_PARSE',160);        // URL parse failed
  748. define('MSG_URL_SCHEME',161);       // Unsupported URL scheme...
  749. define('MSG_SOCKET',162);           // Socket error ...
  750. define('MSG_GETURL_OPEN',163);      // Open URL failed: ...
  751.  
  752.     //
  753.     // The following are PHP's file upload error messages
  754.     //
  755. define('MSG_FILE_UPLOAD_ERR_UNK',180);  // Unknown error code.
  756. define('MSG_FILE_UPLOAD_ERR1',181);     // The uploaded file exceeds the upload_max_filesize directive in php.ini.
  757. define('MSG_FILE_UPLOAD_ERR2',182);     // The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the html form.
  758. define('MSG_FILE_UPLOAD_ERR3',183);     // The uploaded file was only partially uploaded.
  759. define('MSG_FILE_UPLOAD_ERR4',184);     // No file was uploaded.
  760. define('MSG_FILE_UPLOAD_ERR6',186);     // Missing a temporary folder.
  761. define('MSG_FILE_UPLOAD_ERR7',187);     // Failed to write file to disk.
  762. define('MSG_FILE_UPLOAD_ERR8',188);     // File upload stopped by extension.
  763. define('MSG_FILE_UPLOAD_SIZE',189);     // Uploaded file "$NAME" is too big...
  764.                                         // (not a PHP error code - internal maximum file size error)
  765.  
  766.     //
  767.     // following are for derive_fields functions
  768.     //
  769. define('MSG_DER_FUNC_ERROR',200);       // derive_fields: invalid function....
  770. define('MSG_DER_FUNC_SIZE_FMT',201);    // function 'size' requires....
  771. define('MSG_DER_FUNC_IF_FMT',202);      // function 'if' requires....
  772. define('MSG_DER_FUNC_NEXTNUM_FMT',203); // function 'nextnum' requires....
  773. define('MSG_DER_FUNC_EXT_FMT',204);     // function 'ext' requires....
  774. define('MSG_DER_FUNC1_FMT',205);        // function 'FUNC' requires....
  775.  
  776. define('MSG_USER_ATTACK_JUNK',220);     // The following input ...
  777. define('MSG_USER_ATTACK_REV_CAP',221);  // Your input ...
  778. define('MSG_USER_ATTACK_DUP',222);      // You have ...
  779. define('MSG_USER_ATTACK_MANY_URLS',223);// Your input ...
  780. define('MSG_USER_ATTACK_MANY_URL_FIELDS',224);// Your input ...
  781.  
  782. // <A NAME="MessageNumbers"> Jump to: <A HREF="#BuiltinMessages">
  783.  
  784.     //
  785.     // Return true if using the built-in language
  786.     //
  787. function IsBuiltInLanguage()
  788. {
  789.     global  $sLangID;
  790.  
  791.     return (strpos($sLangID,"builtin") !== false);
  792. }
  793.  
  794. $sSavePath = "";
  795. $bPathSaved = false;
  796.     //
  797.     // Set include path to include the given directory.
  798.     //
  799. function AddIncludePath($s_dir = ".")
  800. {
  801.     global  $sSavePath,$bPathSaved;
  802.  
  803.     $s_path = ini_get('include_path');
  804.     $i_path_len = strlen($s_path);
  805.     $s_sep = IsServerWindows() ? ";" : ":";     // get path separator
  806.         //
  807.         // look for it in the include_path
  808.         //
  809.     $b_found = false;
  810.     $i_pos = 0;
  811.     $i_len = strlen($s_dir);
  812.     while (!$b_found && ($i_pos = strpos($s_path,$s_dir,$i_pos)) !== false)
  813.     {
  814.         if ($i_pos == 0)
  815.         {
  816.             if ($i_len == $i_path_len)
  817.                 $b_found = true;        // the path only has $s_dir
  818.             elseif ($s_path{$i_len} == $s_sep)
  819.                 $b_found = true;
  820.         }
  821.         elseif ($s_path{$i_pos-1} == $s_sep &&
  822.                     ($i_pos + $i_len == $i_path_len ||
  823.                     $s_path{$i_pos + $i_len} == $s_sep))
  824.                 $b_found = true;
  825.         if (!$b_found)
  826.             $i_pos++;
  827.     }
  828.     if (!$b_found)
  829.     {
  830.             //
  831.             // allow multiple calls, but only store the original path once
  832.             //
  833.         if (!$bPathSaved)
  834.             $sSavePath = $s_path;
  835.         if (empty($s_path))
  836.             $s_path = $s_dir;
  837.         else
  838.                 //
  839.                 // prepend the directory
  840.                 //
  841.             $s_path = $s_dir.$s_sep.$s_path;
  842.         ini_set('include_path',$s_path);
  843.         $bPathSaved = true;
  844.     }
  845. }
  846.  
  847.     //
  848.     // Reset the include path after a call to AddIncludePath.
  849.     //
  850. function ResetIncludePath()
  851. {
  852.     global  $sSavePath,$bPathSaved;
  853.  
  854.     if ($bPathSaved)
  855.     {
  856.         ini_set('include_path',$sSavePath);
  857.         $bPathSaved = false;
  858.     }
  859. }
  860.  
  861.     //
  862.     // Load a language file
  863.     //
  864. function LoadLanguageFile()
  865. {
  866.     global  $aMessages,$sLangID,$sHTMLCharSet;
  867.  
  868.     AddIncludePath();
  869.     if (!@include("language.inc.php"))
  870.         @include("language.inc");
  871.     ResetIncludePath();
  872.     if (isset($sHTMLCharSet) && $sHTMLCharSet !== "")
  873.         header("Content-Type: text/html; charset=$sHTMLCharSet");
  874. }
  875.  
  876.     //
  877.     // Load the messages array from the default language, and then
  878.     // override with an optional language file.
  879.     // Note: all messages get the MNUM parameter sent which they can use.
  880.     // If they don't use it, the message number is appended.
  881.     //
  882. function LoadBuiltinLanguage()
  883. {
  884.     global  $aMessages,$sLangID;
  885.  
  886.     $sLangID = "English (builtin)";
  887.         // MSG_SCRIPT_VERSION is shown if the PHP version is too old to run
  888.         // FormMail
  889.         // Parameters:
  890.         //  $PHPREQ     is the minimum required PHP version
  891.         //  $PHPVERS    is  the version the server currently has installed.
  892.     $aMessages[MSG_SCRIPT_VERSION] = 'This script requires at least PHP version '.
  893.                                      '$PHPREQ.  You have PHP version $PHPVERS.';
  894.  
  895.         // MSG_END_VERS_CHK is sent at the end of an Alert message when
  896.         // FormMail detects that there's a newer version available
  897.         // Parameters: none
  898.     $aMessages[MSG_END_VERS_CHK] =  '***************************************************\n'.
  899.                                     'If you are happy with your current version and want\n'.
  900.                                     'to stop these reminders, edit formmail.php and\n'.
  901.                                     'set CHECK_FOR_NEW_VERSION to false.\n'.
  902.                                     '***************************************************\n';
  903.  
  904.         // MSG_VERS_CHK is sent in an Alert message when
  905.         // FormMail detects that there's a newer version available
  906.         // Parameters:
  907.         //  $TECTITE    the website to go to
  908.         //  $FM_VERS    the current FormMail version
  909.         //  $NEWVERS    the new FormMail version that's available
  910.     $aMessages[MSG_VERS_CHK] =  'A later version of FormMail is available from $TECTITE.\n'.
  911.                                 'You are currently using version $FM_VERS.\n'.
  912.                                 'The new version available is $NEWVERS.\n';
  913.  
  914.         // MSG_CHK_FILE_ERROR is sent in an Alert message when
  915.         // FormMail cannot create a file to record the time of version check.
  916.         // Parameters:
  917.         //  $FILE   the file name that could not be created
  918.         //  $ERROR  the actual error message
  919.     $aMessages[MSG_CHK_FILE_ERROR] = 'Unable to create check file "$FILE": $ERROR';
  920.  
  921.         // MSG_UNK_VALUE_SPEC is sent in an Alert message when
  922.         // a form uses an unknown value specification in derive_fields.
  923.         // Parameters:
  924.         //  $SPEC   the unknown value specification
  925.         //  $MSG    additional message
  926.     $aMessages[MSG_UNK_VALUE_SPEC] = 'derive_fields: unknown value specification '.
  927.                                      '"$SPEC"$MSG';
  928.  
  929.         // MSG_INV_VALUE_SPEC is sent in an Alert message when
  930.         // a form uses a value specification in derive_fields that's
  931.         // formatted incorrectly (missing terminating '%')
  932.         // Parameters:
  933.         //  $SPEC   the invalid value specification
  934.     $aMessages[MSG_INV_VALUE_SPEC] = 'derive_fields: invalid value specification '.
  935.                                      '"$SPEC" (possibly missing a "%")';
  936.  
  937.         // MSG_DERIVED_INVALID is sent in an Alert message when
  938.         // a form's derive_fields setting has errors
  939.         // Parameters: none
  940.         // A list of errors is appended on separate lines
  941.     $aMessages[MSG_DERIVED_INVALID] = 'Some derive_fields specifications are invalid $MNUM:\n';
  942.  
  943.         // MSG_INT_FORM_ERROR is sent in an Alert message and displayed
  944.         // to the form user
  945.         // Parameters: none
  946.     $aMessages[MSG_INT_FORM_ERROR] = 'Internal form error';
  947.  
  948.         // MSG_OPTIONS_INVALID is sent in an Alert message when
  949.         // a form's options settings are invalid.  This applies to
  950.         // mail_options, filter_options, crm_options, and autorespond
  951.         // Parameters:
  952.         //  $OPT    the name of the options field
  953.         // A list of errors is appended on separate lines
  954.     $aMessages[MSG_OPTIONS_INVALID] = 'Some $OPT settings are undefined $MNUM:\n';
  955.  
  956.         // MSG_PLSWAIT_REDIR is shown to the user for a redirect
  957.         // with JavaScript
  958.         // Parameters: none
  959.     $aMessages[MSG_PLSWAIT_REDIR] = 'Please wait while you are redirected...';
  960.  
  961.         // MSG_IFNOT_REDIR is shown to the user for a redirect
  962.         // with JavaScript
  963.         // Parameters:
  964.         //  $URL    the URL to redirect to
  965.     $aMessages[MSG_IFNOT_REDIR] = 'If you are not automatically redirected, '.
  966.                                   'please <a href="$URL">click here</a>.';
  967.  
  968.         // MSG_PEAR_OBJ is shown to the user if the PEAR Mail object
  969.         // cannot be created
  970.         // Parameters: none
  971.     $aMessages[MSG_PEAR_OBJ] = 'Failed to create PEAR Mail object';
  972.  
  973.         // MSG_PEAR_ERROR is sent in an Alert message if the PEAR Mail processing
  974.         // reports an error
  975.         // Parameters:
  976.         //  $MSG    the error message from PEAR
  977.     $aMessages[MSG_PEAR_ERROR] = 'PEAR Mail error: $MSG';
  978.  
  979.         // MSG_NO_FOPT_ADDR is sent in an Alert message SendMailFOption is
  980.         // specified in the form and no email address has been provided
  981.         // Parameters: none
  982.     $aMessages[MSG_NO_FOPT_ADDR] = 'You have specified "SendMailFOption" in your '.
  983.                                    'form, but there is no email address to use';
  984.  
  985.         // MSG_MORE_INFO is sent in an Alert message on a line by itself, just
  986.         // before extra information about the FormMail processing that may have
  987.         // led to the alert message
  988.         // Parameters: none
  989.     $aMessages[MSG_MORE_INFO] = 'More information:';
  990.  
  991.         // MSG_INFO_STOPPED is sent in an Alert message to say that extra
  992.         // alert information has been suppressed because of potential security
  993.         // problems with showing it.
  994.         // Parameters: none
  995.     $aMessages[MSG_INFO_STOPPED] = '(Extra alert information suppressed for '.
  996.                                    'security purposes. $MNUM)';
  997.  
  998.         // MSG_FM_ALERT is sent as the subject line of an Alert message
  999.         // Parameters: none
  1000.     $aMessages[MSG_FM_ALERT] = 'FormMail alert';
  1001.  
  1002.         // MSG_FM_ERROR is sent as the subject line of an Alert message
  1003.         // Parameters: none
  1004.     $aMessages[MSG_FM_ERROR] = 'FormMail script error';
  1005.  
  1006.         // MSG_FM_ERROR_LINE is sent in an Alert message on a
  1007.         // separate line to introduce the actual error message
  1008.         // Parameters: none
  1009.     $aMessages[MSG_FM_ERROR_LINE] = 'The following error occurred in FormMail $MNUM:';
  1010.  
  1011.         // MSG_USERDATA_STOPPED is sent in an Alert message to say that the
  1012.         // user's data has been suppressed because of potential security
  1013.         // problems with showing it.
  1014.         // Parameters: none
  1015.     $aMessages[MSG_USERDATA_STOPPED] = '(User data suppressed for security '.
  1016.                                        'purposes. $MNUM)';
  1017.  
  1018.         // MSG_FILTERED is sent in an Alert message to show what filter
  1019.         // has been used on the message
  1020.         // Parameters:
  1021.         //  $FILTER     the name of the filter
  1022.     $aMessages[MSG_FILTERED] = 'This alert has been filtered through "$FILTER" '.
  1023.                                'for security purposes.';
  1024.  
  1025.         // MSG_TEMPLATES is sent in an Alert message when a form tries
  1026.         // to use a template, but templates have not been configured in
  1027.         // formmail.php
  1028.         // Parameters: none
  1029.     $aMessages[MSG_TEMPLATES] = 'You must set either TEMPLATEDIR or TEMPLATEURL '.
  1030.                                 'in formmail.php before you can specify '.
  1031.                                 'templates in your forms.';
  1032.  
  1033.         // MSG_OPEN_TEMPLATE is sent in an Alert message when FormMail cannot
  1034.         // open a template file
  1035.         // Parameters:
  1036.         //  $NAME   the name of the template file
  1037.         //  $ERROR  information about the error
  1038.     $aMessages[MSG_OPEN_TEMPLATE] = 'Failed to open template "$NAME" $MNUM: $ERROR';
  1039.  
  1040.         // MSG_ERROR_PROC is shown to the user as part of an error
  1041.         // page.  This message introduces the error.
  1042.         // Parameters: none
  1043.     $aMessages[MSG_ERROR_PROC] = 'An error occurred while processing the '.
  1044.                                  'form $MNUM.\n\n';
  1045.  
  1046.         // MSG_ALERT_DONE is shown to the user as part of an error
  1047.         // page if an Alert message has been sent to the website owner.
  1048.         // Parameters:
  1049.         //  SERVER      the name of the server (website)
  1050.     $aMessages[MSG_ALERT_DONE] = 'The staff at $SERVER have been alerted to the error $MNUM.\n';
  1051.  
  1052.         // MSG_PLS_CONTACT is shown to the user as part of an error
  1053.         // page if an Alert message could *not* be sent to the website owner.
  1054.         // Parameters:
  1055.         //  SERVER      the name of the server (website)
  1056.     $aMessages[MSG_PLS_CONTACT] = 'Please contact us ($SERVER) directly since this form '.
  1057.                                   'is not working $MNUM.\n';
  1058.  
  1059.         // MSG_APOLOGY is shown to the user as part of an error
  1060.         // page as an apology for a problem with the form.
  1061.         // Parameters:
  1062.         //  SERVER      the name of the server (website)
  1063.     $aMessages[MSG_APOLOGY] = '$SERVER apologizes for any inconvenience this error '.
  1064.                               'may have caused.';
  1065.  
  1066.         // MSG_ABOUT_FORMMAIL is shown to the user at the foot of pages
  1067.         // generated by FormMail (e.g. the default "Thanks" page and default
  1068.         // error page).
  1069.         // Parameters:
  1070.         //  $FM_VERS    the FormMail version number
  1071.         //  $TECTITE    www.tectite.com
  1072.     $aMessages[MSG_ABOUT_FORMMAIL] = 'Your form submission was processed by '.
  1073.                                      '($FM_VERS), available from '.
  1074.                                      '<a href="http://$TECTITE/">$TECTITE</a>.';
  1075.  
  1076.         // MSG_PREG_FAILED is sent in an Alert message if the TectiteCRM
  1077.         // system failed to return the expected result.
  1078.         // Parameters: none
  1079.     $aMessages[MSG_PREG_FAILED] = 'preg_match_all failed in FindCRMFields';
  1080.  
  1081.         // MSG_URL_INVALID is sent in an Alert message if the specified
  1082.         // URL for TectiteCRM is not valid according to the TARGET_URLS
  1083.         // configuration setting
  1084.         // Parameters:
  1085.         //  $URL        the invalid URL
  1086.     $aMessages[MSG_URL_INVALID] = 'The URL "$URL" to access the Customer '.
  1087.                                   'Relationship Management System is not valid '.
  1088.                                   '(see TARGET_URLS in formmail.php)';
  1089.  
  1090.         // MSG_URL_OPEN is sent in an Alert message if the specified
  1091.         // URL for TectiteCRM cannot be opened
  1092.         // Parameters:
  1093.         //  $URL    the invalid URL
  1094.         //  $ERROR  information about the error
  1095.     $aMessages[MSG_URL_OPEN] = 'Failed to open Customer Relationship '.
  1096.                                'Management System URL "$URL" $MNUM: $ERROR';
  1097.  
  1098.         // MSG_CRM_FAILED is sent in an Alert message if the TectiteCRM
  1099.         // system doesn't return an OK message
  1100.         // Parameters:
  1101.         //  $URL    the invalid URL
  1102.         //  $MSG    more information
  1103.     $aMessages[MSG_CRM_FAILED] = 'Failure report from Customer Relationship '.
  1104.                                  'Management System (url="$URL") $MNUM: $MSG';
  1105.  
  1106.         // MSG_CRM_FORM_ERROR is shown to the user if the information
  1107.         // passed to TectiteCRM was not accepted
  1108.         // Parameters: none
  1109.     $aMessages[MSG_CRM_FORM_ERROR] = 'Your form submission was not accepted';
  1110.  
  1111.         // MSG_AND is shown to the user; it shows two items separated
  1112.         // by "and"
  1113.         // Parameters:
  1114.         //  $ITEM1      the first item
  1115.         //  $ITEM2      the second item
  1116.     $aMessages[MSG_AND] = '"$ITEM1" and "$ITEM2"';
  1117.  
  1118.         // MSG_OR is shown to the user; it shows two items separated
  1119.         // by "or"
  1120.         // Parameters:
  1121.         //  $ITEM1      the first item
  1122.         //  $ITEM2      the second item
  1123.     $aMessages[MSG_OR] = '"$ITEM1" or "$ITEM2"';
  1124.  
  1125.         // MSG_NOT_BOTH is shown to the user; it shows two items that must
  1126.         // be specified together
  1127.         // Parameters:
  1128.         //  $ITEM1      the first item
  1129.         //  $ITEM2      the second item
  1130.     $aMessages[MSG_NOT_BOTH] = 'not both "$ITEM1" and "$ITEM2"';
  1131.  
  1132.         // MSG_XOR is shown to the user; it shows two items that must
  1133.         // not be specified together
  1134.         // Parameters:
  1135.         //  $ITEM1      the first item
  1136.         //  $ITEM2      the second item
  1137.     $aMessages[MSG_XOR] = '"$ITEM1" or "$ITEM2" (but not both)';
  1138.  
  1139.         // MSG_IS_SAME_AS is shown to the user; it shows two items that must
  1140.         // not be the same value
  1141.         // Parameters:
  1142.         //  $ITEM1      the first item
  1143.         //  $ITEM2      the second item
  1144.     $aMessages[MSG_IS_SAME_AS] = '"$ITEM1" is the same as "$ITEM2"';
  1145.  
  1146.         // MSG_IS_NOT_SAME_AS is shown to the user; it shows two items that must
  1147.         // be the same value
  1148.         // Parameters:
  1149.         //  $ITEM1      the first item
  1150.         //  $ITEM2      the second item
  1151.     $aMessages[MSG_IS_NOT_SAME_AS] = '"$ITEM1" is not the same as "$ITEM2"';
  1152.  
  1153.         // MSG_REQD_OPER is sent in an Alert message when an unknown
  1154.         // operator has been used in a "required" specification
  1155.         // Parameters:
  1156.         //  $OPER       the unknown operator
  1157.     $aMessages[MSG_REQD_OPER] = 'Operator "$OPER" is not valid for "required"';
  1158.  
  1159.         // MSG_PAT_FAILED is sent in an Alert message when a "conditions" pattern
  1160.         // match has not matched anything (this isn't necessarily an error)
  1161.         // Parameters:
  1162.         //  $OPER       the "conditions" operator
  1163.         //  $PAT        the "conditions" pattern
  1164.         //  $VALUE      the value that was searched
  1165.     $aMessages[MSG_PAT_FAILED] = 'Pattern operator "$OPER" failed: pattern '.
  1166.                                  '"$PAT", value searched was "$VALUE".';
  1167.  
  1168.         // MSG_COND_OPER is sent in an Alert message when a "conditions"
  1169.         // operator is not value
  1170.         // Parameters:
  1171.         //  $OPER       the "conditions" operator
  1172.     $aMessages[MSG_COND_OPER] = 'Operator "$OPER" is not valid for "conditions"';
  1173.  
  1174.         // MSG_INV_COND is sent in an Alert message when a "conditions"
  1175.         // field is not valid
  1176.         // Parameters:
  1177.         //  FLD     the field name
  1178.     $aMessages[MSG_INV_COND] = 'Invalid "conditions" field "$FLD" - not a string or array.';
  1179.  
  1180.         // MSG_COND_CHARS is sent in an Alert message when a "conditions"
  1181.         // field is missing the mandatory first 2 characters (the separators)
  1182.         // Parameters:
  1183.         //  FLD     the field name
  1184.         //  COND    the conditions field value
  1185.     $aMessages[MSG_COND_CHARS] = 'The conditions field "$FLD" is not valid. '.
  1186.                                  'You must provide the two separator '.
  1187.                                  'characters at the beginning. You had "$COND".';
  1188.  
  1189.         // MSG_COND_INVALID is sent in an Alert message when a "conditions"
  1190.         // field has the wrong format
  1191.         // Parameters:
  1192.         //  FLD     the field name
  1193.         //  COND    the conditions field value
  1194.         //  SEP     the internal separator character for the field.
  1195.     $aMessages[MSG_COND_INVALID] = 'The conditions field "$FLD" is not valid. '.
  1196.                                    'There must be at least 5 components '.
  1197.                                    'separated by "$SEP". Your value was "$COND".';
  1198.  
  1199.         // MSG_COND_TEST_LONG is sent in an Alert message when a "conditions"
  1200.         // TEST value has too many components
  1201.         // Parameters:
  1202.         //  FLD     the field name
  1203.         //  COND    the conditions field value
  1204.         //  SEP     the list separator character for the field.
  1205.     $aMessages[MSG_COND_TEST_LONG] = 'Field "$FLD" has too many components for '.
  1206.                                      'a "TEST" command: "$COND".\nAre you missing '.
  1207.                                      'a "$SEP"?';
  1208.  
  1209.         // MSG_COND_IF_SHORT is sent in an Alert message when a "conditions"
  1210.         // IF value has too few components
  1211.         // Parameters:
  1212.         //  FLD     the field name
  1213.         //  COND    the conditions field value
  1214.         //  SEP     the internal separator character for the field.
  1215.     $aMessages[MSG_COND_IF_SHORT] = 'Field "$FLD" has too few components for '.
  1216.                                     'an "IF" command: "$COND".\nThere must be '.
  1217.                                     'at least 6 components separated by "$SEP"';
  1218.  
  1219.         // MSG_COND_IF_LONG is sent in an Alert message when a "conditions"
  1220.         // IF value has too many components
  1221.         // Parameters:
  1222.         //  FLD     the field name
  1223.         //  COND    the conditions field value
  1224.         //  SEP     the list separator character for the field.
  1225.     $aMessages[MSG_COND_IF_LONG] = 'Field "$FLD" has too many components for '.
  1226.                                    'an "IF" command: "$COND".\nAre you missing '.
  1227.                                    'a "$SEP"?';
  1228.  
  1229.         // MSG_COND_UNK is sent in an Alert message when a "conditions"
  1230.         // value has an unknown command
  1231.         // Parameters:
  1232.         //  FLD     the field name
  1233.         //  COND    the conditions field value
  1234.         //  CMD     the unknown command
  1235.     $aMessages[MSG_COND_UNK] = 'Field "$FLD" has an unknown command word '.
  1236.                                '"$CMD": "$COND".';
  1237.  
  1238.         // MSG_MISSING is sent in an Alert message when
  1239.         // a socket filter is incorrectly defined
  1240.         // Parameters:
  1241.         //  ITEM    the missing item
  1242.     $aMessages[MSG_MISSING] = 'Missing "$ITEM"';
  1243.  
  1244.         // MSG_NEED_ARRAY is sent in an Alert message when
  1245.         // a socket filter is incorrectly defined
  1246.         // Parameters:
  1247.         //  ITEM    the item that should be an array
  1248.     $aMessages[MSG_NEED_ARRAY] = '"$ITEM" must be an array';
  1249.  
  1250.         // MSG_SUBM_FAILED is shown to the user when an internal error
  1251.         // as occurred and that error is not to be shown
  1252.         // Parameters: none
  1253.     $aMessages[MSG_SUBM_FAILED] = 'Your form submission has failed due to '.
  1254.                                   'an error on our server.';
  1255.  
  1256.         // MSG_FILTER_WRONG is sent in an Alert message when
  1257.         // a socket filter is incorrectly defined
  1258.         // Parameters:
  1259.         //  FILTER  the filter name
  1260.         //  ERRORS  a string containing a list of errors
  1261.     $aMessages[MSG_FILTER_WRONG] = 'Filter "$FILTER" is not properly defined: '.
  1262.                                    '$ERRORS';
  1263.  
  1264.         // MSG_FILTER_CONNECT is sent in an Alert message when FormMail
  1265.         // cannot connect to a socket filter
  1266.         // Parameters:
  1267.         //  FILTER  the filter name
  1268.         //  SITE    the site
  1269.         //  ERRNUM  socket error number
  1270.         //  ERRSTR  socket error message
  1271.     $aMessages[MSG_FILTER_CONNECT] = 'Could not connect to site "$SITE" '.
  1272.                                      'for filter "$FILTER" ($ERRNUM): $ERRSTR';
  1273.  
  1274.         // MSG_FILTER_PARAM is sent in an Alert message when a socket
  1275.         // filter has an invalid parameter specification
  1276.         // Parameters:
  1277.         //  FILTER  the filter name
  1278.         //  NUM     parameter number
  1279.         //  NAME    parameter name
  1280.     $aMessages[MSG_FILTER_PARAM] = 'Filter "$FILTER" has invalid parameter '.
  1281.                                    '#$NUM: no "$NAME"';
  1282.  
  1283.         // MSG_FILTER_OPEN_FILE is sent in an Alert message when a socket
  1284.         // filter cannot open the required file
  1285.         // Parameters:
  1286.         //  FILTER  the filter name
  1287.         //  FILE    the file that could not be opened
  1288.         //  ERROR   the error message
  1289.     $aMessages[MSG_FILTER_OPEN_FILE] = 'Filter "$FILTER" cannot open file '.
  1290.                                        '"$FILE": $ERROR';
  1291.  
  1292.         // MSG_FILTER_FILE_ERROR is sent in an Alert message when a socket
  1293.         // filter gets an error message during reading a file
  1294.         // Parameters:
  1295.         //  FILTER  the filter name
  1296.         //  FILE    the file that could not be opened
  1297.         //  ERROR   the error message
  1298.         //  NLINES  the number of lines that were read successfully
  1299.     $aMessages[MSG_FILTER_FILE_ERROR] = 'Filter "$FILTER": read error on file '.
  1300.                                         '"$FILE" after $NLINES lines: $ERROR';
  1301.  
  1302.         // MSG_FILTER_READ_ERROR is sent in an Alert message when a socket
  1303.         // filter gets an error during reading from the socket
  1304.         // Parameters:
  1305.         //  FILTER  the filter name
  1306.         //  ERROR   the error message
  1307.     $aMessages[MSG_FILTER_READ_ERROR] = 'Filter "$FILTER" failed: read error: '.
  1308.                                         '$ERROR';
  1309.  
  1310.         // MSG_FILTER_NOT_OK is sent in an Alert message when a socket
  1311.         // filter fails to return the agreed __OK__ indicator
  1312.         // Parameters:
  1313.         //  FILTER  the filter name
  1314.         //  DATA    the data returned from the filter
  1315.     $aMessages[MSG_FILTER_NOT_OK] = 'Filter "$FILTER" failed (missing '.
  1316.                                     '__OK__ line): $DATA';
  1317.  
  1318.         // MSG_FILTER_UNK is sent in an Alert message
  1319.         // when an unknown filter is specified by a form
  1320.         // Parameters:
  1321.         //  FILTER  the filter name
  1322.     $aMessages[MSG_FILTER_UNK] = 'Unknown filter "$FILTER"';
  1323.  
  1324.         // MSG_FILTER_CHDIR is sent in an Alert message
  1325.         // when FormMail cannot change to the filter's directory
  1326.         // Parameters:
  1327.         //  FILTER  the filter name
  1328.         //  DIR     the directory name
  1329.         //  ERROR   an error message from the system
  1330.     $aMessages[MSG_FILTER_CHDIR] = 'Cannot chdir to "$DIR" to run filter '.
  1331.                                    '"$FILTER": $ERROR';
  1332.  
  1333.         // MSG_FILTER_NOTFOUND is sent in an Alert message
  1334.         // when FormMail cannot execute the filter
  1335.         // Parameters:
  1336.         //  FILTER  the filter name
  1337.         //  CMD     the command line being executed
  1338.         //  ERROR   an error message from the system
  1339.     $aMessages[MSG_FILTER_NOTFOUND] = 'Cannot execute filter "$FILTER" with '.
  1340.                                       'command "$CMD": $ERROR';
  1341.  
  1342.         // MSG_FILTER_ERROR is sent in an Alert message
  1343.         // when a filter returns a non-zero status
  1344.         // Parameters:
  1345.         //  FILTER  the filter name
  1346.         //  ERROR   an error message from the system
  1347.         //  STATUS  the status return from the command
  1348.     $aMessages[MSG_FILTER_ERROR] = 'Filter "$FILTER" failed (status $STATUS): '.
  1349.                                    '$ERROR';
  1350.  
  1351.         // MSG_TEMPLATE_ERRORS is sent as part of an Alert message
  1352.         // when a template has generated some errors.  The message
  1353.         // should end with a new line and the actual errors are
  1354.         // output after it.
  1355.         // Parameters:
  1356.         //  NAME    the template name
  1357.     $aMessages[MSG_TEMPLATE_ERRORS] = 'Template "$NAME" caused the '.
  1358.                                       'following errors $MNUM:\n';
  1359.  
  1360.         // MSG_TEMPLATE_FAILED is sent in an Alert message
  1361.         // when processing a template has failed.
  1362.         // Parameters:
  1363.         //  NAME    the template name
  1364.     $aMessages[MSG_TEMPLATE_FAILED] = 'Failed to process template "$NAME"';
  1365.  
  1366.         // MSG_MIME_PREAMBLE is sent in the preamble of MIME emails
  1367.         // Parameters: none
  1368.     $aMessages[MSG_MIME_PREAMBLE] = '(Your mail reader should not show this '.
  1369.                                     'text.\nIf it does you may need to '.
  1370.                                     'upgrade to more modern software.)';
  1371.  
  1372.         // MSG_MIME_HTML is sent in the preamble of HTML emails
  1373.         // Parameters:
  1374.         //  NAME    the template name
  1375.     $aMessages[MSG_MIME_HTML] = 'This message has been generated by FormMail '.
  1376.                                 'using an HTML template\ncalled "$NAME". The '.
  1377.                                 'raw text of the form results\nhas been '.
  1378.                                 'included below, but your mail reader should '.
  1379.                                 'display the HTML\nversion only (unless it\'s '.
  1380.                                 'not capable of doing so).';
  1381.  
  1382.         // MSG_FILE_OPEN_ERROR is sent in an Alert message when FormMail
  1383.         // cannot open a file
  1384.         // Parameters:
  1385.         //  NAME    the file name
  1386.         //  TYPE    the type of file
  1387.         //  ERROR   the system error message
  1388.     $aMessages[MSG_FILE_OPEN_ERROR] = 'Failed to open $TYPE file "$NAME": $ERROR';
  1389.  
  1390.         // MSG_ATTACH_DATA is sent in an Alert message when the file
  1391.         // attachment through 'data' has gone wrong.
  1392.         // Parameters: none
  1393.     $aMessages[MSG_ATTACH_DATA] = 'Internal error: AttachFile requires '.
  1394.                                   '"tmp_name" or "data"';
  1395.  
  1396.         // MSG_PHP_HTML_TEMPLATES is sent in an Alert message when an
  1397.         // HTML template is used but the PHP version is too old.
  1398.         // Parameters:
  1399.         //  $PHPVERS    the current PHP version
  1400.     $aMessages[MSG_PHP_HTML_TEMPLATES] = 'HTMLTemplate option is only supported '.
  1401.                                      'with PHP version 4.0.5 or above.  Your '.
  1402.                                      'server is running version $PHPVERS.';
  1403.  
  1404.         // MSG_PHP_FILE_UPLOADS is sent in an Alert message when
  1405.         // file upload is used but the PHP version is too old.
  1406.         // Parameters:
  1407.         //  $PHPVERS    the current PHP version
  1408.     $aMessages[MSG_PHP_FILE_UPLOADS] = 'For security reasons, file upload is only '.
  1409.                                    'allowed with PHP version 4.0.3 or above. '.
  1410.                                    'Your server is running version $PHPVERS.';
  1411.  
  1412.         // MSG_FILE_UPLOAD is sent in an Alert message when
  1413.         // file upload is attempted but FormMail is not configured to allow
  1414.         // it
  1415.         // Parameters: none
  1416.     $aMessages[MSG_FILE_UPLOAD] = 'File upload attempt ignored';
  1417.  
  1418.         // MSG_FILE_UPLOAD_ATTACK is sent in an Alert message when
  1419.         // possible file upload attack is detected
  1420.         // Parameters:
  1421.         //  NAME    file name
  1422.         //  TEMP    temporary file name
  1423.         //  FLD     name of the file upload field
  1424.     $aMessages[MSG_FILE_UPLOAD_ATTACK] = 'Possible file upload attack '.
  1425.                                          'detected: field="$FLD", name="$NAME" '.
  1426.                                          'temp name="$TEMP"';
  1427.  
  1428.         // MSG_PHP_PLAIN_TEMPLATES is sent in an Alert message when a
  1429.         // Plain template is used but the PHP version is too old.
  1430.         // Parameters:
  1431.         //  $PHPVERS    the current PHP version
  1432.     $aMessages[MSG_PHP_PLAIN_TEMPLATES] = 'PlainTemplate option is only supported '.
  1433.                                      'with PHP version 4.0.5 or above.  Your '.
  1434.                                      'server is running version $PHPVERS.';
  1435.  
  1436.         // MSG_ATTACH_NAME is sent in an Alert message when a
  1437.         // the form uses the Attach feature without specifying a file name
  1438.         // Parameters: none
  1439.     $aMessages[MSG_ATTACH_NAME] = 'filter_options: Attach must contain a name '.
  1440.                                   '(e.g. Attach=data.txt)';
  1441.  
  1442.         // MSG_PHP_BCC is sent in an Alert message when a
  1443.         // the form uses the BCC feature and the PHP version may not support it
  1444.         // Parameters:
  1445.         //  $PHPVERS    the current PHP version
  1446.     $aMessages[MSG_PHP_BCC] = 'Warning: BCC is probably not supported on your '.
  1447.                               'PHP version ($PHPVERS)';
  1448.  
  1449.         // MSG_CSVCOLUMNS is sent in an Alert message when a csvcolumns field
  1450.         // is not correct
  1451.         // Parameters:
  1452.         //  $VALUE  the csvcolumns field value
  1453.     $aMessages[MSG_CSVCOLUMNS] = 'The "csvcolumns" setting is not '.
  1454.                                  'valid: "$VALUE"';
  1455.  
  1456.         // MSG_CSVFILE is sent in an Alert message when a csvfile field
  1457.         // is not correct
  1458.         // Parameters:
  1459.         //  $VALUE  the csvfile field value
  1460.     $aMessages[MSG_CSVFILE] = 'The "csvfile" setting is not valid: "$VALUE"';
  1461.  
  1462.         // MSG_TARG_EMAIL_PAT_START is sent in an Alert message when a
  1463.         // $TARGET_EMAIL pattern is insecure because of a missing '^'
  1464.         // at the beginning
  1465.         // Parameters:
  1466.         //  $PAT    the pattern
  1467.     $aMessages[MSG_TARG_EMAIL_PAT_START] = 'Warning: Your TARGET_EMAIL pattern '.
  1468.                                            '"$PAT" is missing a ^ at the '.
  1469.                                            'beginning.';
  1470.  
  1471.         // MSG_TARG_EMAIL_PAT_END is sent in an Alert message when a
  1472.         // $TARGET_EMAIL pattern is insecure because of a missing '$'
  1473.         // at the end
  1474.         // Parameters:
  1475.         //  $PAT    the pattern
  1476.     $aMessages[MSG_TARG_EMAIL_PAT_END] = 'Warning: Your TARGET_EMAIL pattern '.
  1477.                                          '"$PAT" is missing a $ at the end.';
  1478.  
  1479.         // MSG_CONFIG_WARN is sent in an Alert message when the FormMail
  1480.         // configuration may have some problems.  The messages are
  1481.         // passed on separate lines, so the line terminations below
  1482.         // are important.
  1483.         // Parameters:
  1484.         //  $MESGS  lines of messages
  1485.     $aMessages[MSG_CONFIG_WARN] = 'The following potential problems were found '.
  1486.                                   'in your configuration:\n$MESGS\n\n'.
  1487.                                   'These are not necessarily errors, but you '.
  1488.                                   'should review the documentation\n'.
  1489.                                   'inside formmail.php.  If you are sure your '.
  1490.                                   'configuration is correct\n'.
  1491.                                   'you can disable the above messages by '.
  1492.                                   'changing the CONFIG_CHECK settings.';
  1493.  
  1494.         // MSG_PHP_AUTORESP is sent in an Alert message when the PHP version
  1495.         // does not support autoresponding
  1496.         // Parameters:
  1497.         //  $PHPVERS    current PHP version
  1498.     $aMessages[MSG_PHP_AUTORESP] = 'Autorespond is only supported with PHP '.
  1499.                                    'version 4.0.5 or above.  Your server is '.
  1500.                                    'running version $PHPVERS.';
  1501.  
  1502.         // MSG_ALERT is the test alert message (formmail.php?testalert=1)
  1503.         // Parameters:
  1504.         //  $LANG               the language ID
  1505.         //  $PHPVERS            PHP version
  1506.         //  $FM_VERS            FormMail version
  1507.         //  $SERVER             server type
  1508.         //  $DOCUMENT_ROOT      PHP's DOCUMENT_ROOT value
  1509.         //  $SCRIPT_FILENAME    PHP's SCRIPT_FILENAME value
  1510.         //  $PATH_TRANSLATED    PHP's PATH_TRANSLATED value
  1511.         //  $REAL_DOCUMENT_ROOT the REAL_DOCUMENT_ROOT value
  1512.     $aMessages[MSG_ALERT] = 'This is a test alert message $MNUM\n'.
  1513.                             'Loaded language is $LANG\n'.
  1514.                             'PHP version is $PHPVERS\n'.
  1515.                             'FormMail version is $FM_VERS\n'.
  1516.                             'Server type: $SERVER\n'.
  1517.                             '\n'.
  1518.                             'DOCUMENT_ROOT: $DOCUMENT_ROOT\n'.
  1519.                             'SCRIPT_FILENAME: $SCRIPT_FILENAME\n'.
  1520.                             'PATH_TRANSLATED: $PATH_TRANSLATED\n'.
  1521.                             'REAL_DOCUMENT_ROOT: $REAL_DOCUMENT_ROOT';
  1522.  
  1523.         // MSG_NO_DEF_ALERT is displayed if you use the testalert feature
  1524.         // and no DEF_ALERT setting has been provided.
  1525.         // Parameters: none
  1526.     $aMessages[MSG_NO_DEF_ALERT] = 'No DEF_ALERT value has been set.';
  1527.  
  1528.         // MSG_TEST_SENT is displayed if when use the testalert feature
  1529.         // Parameters: none
  1530.     $aMessages[MSG_TEST_SENT] = 'Test message sent.  Check your email.';
  1531.  
  1532.         // MSG_TEST_FAILED is displayed if when use the testalert feature
  1533.         // and the mail sending fails.
  1534.         // Parameters: none
  1535.     $aMessages[MSG_TEST_FAILED] = 'FAILED to send alert message.  Check your '.
  1536.                                   'server error logs.';
  1537.  
  1538.         // MSG_NO_DATA_PAGE is the page that's displayed if the user
  1539.         // just opens the URL to FormMail directly.
  1540.         // Parameters: none
  1541.     $aMessages[MSG_NO_DATA_PAGE] =  'This URL is a Form submission program.\n'.
  1542.                                     'It appears the form is not working '.
  1543.                                     'correctly as there was no data found.\n'.
  1544.                                     'You\'re not supposed to browse to this '.
  1545.                                     'URL; it should be accessed from a form.';
  1546.  
  1547.         // MSG_REQD_ERROR is displayed to the user as a default error
  1548.         // message when they haven't supplied some required fields
  1549.         // Parameters: none
  1550.     $aMessages[MSG_REQD_ERROR] = 'The form required some values that you '.
  1551.                                  'did not seem to provide.';
  1552.  
  1553.         // MSG_COND_ERROR is displayed to the user as a default error
  1554.         // message when some form conditions have failed
  1555.         // Parameters: none
  1556.     $aMessages[MSG_COND_ERROR] = 'Some of the values you provided are not valid.';
  1557.  
  1558.         // MSG_CRM_FAILURE is displayed to the user when submission
  1559.         // to the CRM has failed.
  1560.         // Parameters:
  1561.         //      $URL    the URL that was used
  1562.         //      $DATA   data returned from the CRM
  1563.     $aMessages[MSG_CRM_FAILURE] = 'The form submission did not succeed due to '.
  1564.                                   'a CRM failure. URL was \'$URL\'. '.
  1565.                                   'Returned CRM data:\n$DATA';
  1566.  
  1567.         // MSG_FOPTION_WARN is sent in an Alert message when the form
  1568.         // uses the superseded SendMailFOption feature
  1569.         // Parameters:
  1570.         //  $LINE   line number for SENDMAIL_F_OPTION
  1571.     $aMessages[MSG_FOPTION_WARN] = 'Warning: You\'ve used SendMailFOption in '.
  1572.                                    '"mail_options" in your form. This has been '.
  1573.                                    'superseded with a configuration setting '.
  1574.                                    'inside formmail.php.  Please update your '.
  1575.                                    'formmail.php configuration (look for '.
  1576.                                    'SENDMAIL_F_OPTION on line $LINE) and set '.
  1577.                                    'it to "true", then remove SendMailFOption '.
  1578.                                    'from your form(s).';
  1579.  
  1580.         // MSG_NO_ACTIONS is sent in an Alert message when there is no
  1581.         // action to perform or email address to send to
  1582.         // Parameters: none
  1583.     $aMessages[MSG_NO_ACTIONS] = 'The form has an internal error - no actions '.
  1584.                                  'or recipients were specified.';
  1585.  
  1586.         // MSG_NO_RECIP is sent in an Alert message when there are no
  1587.         // valid recipients to send to
  1588.         // Parameters: none
  1589.     $aMessages[MSG_NO_RECIP] = 'The form has an internal error - no valid '.
  1590.                                'recipients were specified.';
  1591.  
  1592.         // MSG_INV_EMAIL is sent in an Alert message when there are errors
  1593.         // in the email addresses specified in the form
  1594.         // Parameters:
  1595.         //  $ERRORS     list of errors
  1596.     $aMessages[MSG_INV_EMAIL] = 'Invalid email addresses were specified '.
  1597.                                 'in the form $MNUM:\n$ERRORS';
  1598.  
  1599.         // MSG_FAILED_SEND is sent in an Alert message when the mail sending fails.
  1600.         // Parameters: none
  1601.     $aMessages[MSG_FAILED_SEND] = 'Failed to send email';
  1602.  
  1603.         // MSG_ARESP_EMAIL is sent in an Alert message when
  1604.         // no email address has been specified for an autoreponse
  1605.         // Parameters: none
  1606.     $aMessages[MSG_ARESP_EMAIL] = 'No "email" field was found. Autorespond '.
  1607.                                   'requires the submitter\'s email address.';
  1608.  
  1609.         // MSG_ARESP_SUBJ is the default subject for the auto response email
  1610.         // Parameters: none
  1611.     $aMessages[MSG_ARESP_SUBJ] = 'Your form submission';
  1612.  
  1613.         // MSG_LOG_NO_VERIMG is written to the auto respond log file
  1614.         // if no VerifyImgString session variable was found
  1615.         // Parameters: none
  1616.     $aMessages[MSG_LOG_NO_VERIMG] = 'No VerifyImgString in session';
  1617.  
  1618.         // MSG_ARESP_NO_AUTH is shown to the user
  1619.         // if no VerifyImgString session variable was found
  1620.         // Parameters: none
  1621.     $aMessages[MSG_ARESP_NO_AUTH] = 'Failed to obtain authorization to send '.
  1622.                                     'you email. This is probably a fault on '.
  1623.                                     'the server.';
  1624.  
  1625.         // MSG_LOG_NO_MATCH is written to the auto respond log file
  1626.         // if the user's entry did not match the image verification
  1627.         // Parameters: none
  1628.     $aMessages[MSG_LOG_NO_MATCH] = 'User did not match image';
  1629.  
  1630.         // MSG_ARESP_NO_MATCH is shown to the user
  1631.         // if the user's entry did not match the image verification
  1632.         // Parameters: none
  1633.     $aMessages[MSG_ARESP_NO_MATCH] = 'Your entry did not match the image';
  1634.  
  1635.         // MSG_LOG_FAILED is written to the auto respond log file
  1636.         // if the autoresponding failed
  1637.         // Parameters: none
  1638.     $aMessages[MSG_LOG_FAILED] = 'Failed';
  1639.  
  1640.         // MSG_ARESP_FAILED is sent in an Alert message
  1641.         // if the autoresponding failed
  1642.         // Parameters: none
  1643.     $aMessages[MSG_ARESP_FAILED] = 'Autoresponder failed';
  1644.  
  1645.         // MSG_LOG_OK is written to the auto respond log file
  1646.         // if the autoresponding succeeded
  1647.         // Parameters: none
  1648.     $aMessages[MSG_LOG_OK] = 'OK';
  1649.  
  1650.         // MSG_THANKS_PAGE is the default page that's displayed if the
  1651.         // submission is successful
  1652.         // Parameters: none
  1653.     $aMessages[MSG_THANKS_PAGE] = 'Thanks!  We\'ve received your information '.
  1654.                                   'and, if it\'s appropriate, we\'ll be in '.
  1655.                                   'contact with you soon.';
  1656.  
  1657.         // MSG_LOAD_MODULE is sent in an alert message if a module
  1658.         // could not be loaded.
  1659.         // Parameters:
  1660.         //  $FILE    the file name
  1661.         //  $ERROR   the error message
  1662.     $aMessages[MSG_LOAD_MODULE] = 'Cannot load module from file \'$FILE\': $ERROR';
  1663.  
  1664.         // MSG_LOAD_FMCOMPUTE is sent in an alert message if the form
  1665.         // specifies at least one "fmcompute" field and the FMCompute
  1666.         // module cannot be loaded.
  1667.         // Parameters:
  1668.         //  $FILE    the file name
  1669.         //  $ERROR   the error message
  1670.     $aMessages[MSG_LOAD_FMCOMPUTE] = 'Cannot load FMCompute module from file '.
  1671.                                         '\'$FILE\': $ERROR';
  1672.  
  1673.         // MSG_REGISTER_MODULE is sent in an alert message if a module
  1674.         // could not register with FMCompute
  1675.         // Parameters:
  1676.         //  $NAME    the name of the module
  1677.         //  $ERROR   the error message
  1678.     $aMessages[MSG_REGISTER_MODULE] = 'Cannot register module $NAME with '.
  1679.                                         'FMCompute: $ERROR';
  1680.  
  1681.  
  1682.         // MSG_COMP_PARSE is sent in an alert message if a parse error
  1683.         // occurs in an fmcompute field
  1684.         // Parameters:
  1685.         //  $CODE    the code with an error
  1686.         //  $ERRORS  the error messages
  1687.     $aMessages[MSG_COMP_PARSE] = 'These parse errors occurred in the following '.
  1688.                                     'code:\n$ERRORS\n$CODE';
  1689.  
  1690.         // MSG_COMP_REG_DATA is sent in an alert message if FormMail cannot
  1691.         // register a data field with the FMCompute module
  1692.         // Parameters:
  1693.         //  $NAME    the field name
  1694.         //  $ERROR  the error message
  1695.     $aMessages[MSG_COMP_REG_DATA] = 'Failed to register data field \'$NAME\': '.
  1696.                                     '$ERROR';
  1697.  
  1698.         // MSG_COMP_ALERT is sent in an alert message if the FMCompute
  1699.         // module has generated some alert messages.
  1700.         // Parameters:
  1701.         //  $ALERTS  the alerts
  1702.     $aMessages[MSG_COMP_ALERT] = 'The following alert messages were reported '.
  1703.                                 'from the FMCompute module: $ALERTS';
  1704.  
  1705.         // MSG_COMP_DEBUG is sent in an alert message if the FMCompute
  1706.         // module has generated some debug messages.
  1707.         // Parameters:
  1708.         //  $DEBUG  the alerts
  1709.     $aMessages[MSG_COMP_DEBUG] = 'The following debug messages were reported '.
  1710.                                 'from the FMCompute module: $DEBUG';
  1711.  
  1712.         // MSG_COMP_EXEC is sent in an alert message if the FMCompute
  1713.         // module has generated some error messages during execution
  1714.         // Parameters:
  1715.         //  $ERRORS  the errors
  1716.     $aMessages[MSG_COMP_EXEC] = 'The following error messages were reported '.
  1717.                                 'from the FMCompute module: $ERRORS';
  1718.  
  1719.         // MSG_TEMPL_ALERT is sent in an alert message if Advanced Template
  1720.         // Processing has generated some alert messages.
  1721.         // Parameters:
  1722.         //  $ALERTS  the alerts
  1723.     $aMessages[MSG_TEMPL_ALERT] = 'The following alert messages were reported '.
  1724.                                 'from the Advanced Template Processor: $ALERTS';
  1725.  
  1726.         // MSG_TEMPL_DEBUG is sent in an alert message if Advanced Template
  1727.         // Processing has generated some debug messages.
  1728.         // Parameters:
  1729.         //  $DEBUG  the alerts
  1730.     $aMessages[MSG_TEMPL_DEBUG] = 'The following debug messages were reported '.
  1731.                                 'from the Advanced Template Processor: $DEBUG';
  1732.  
  1733.         // MSG_TEMPL_PROC is sent in an alert message if Advanced Template Processing
  1734.         // has generated some error messages during processing
  1735.         // Parameters:
  1736.         //  $ERRORS  the errors
  1737.     $aMessages[MSG_TEMPL_PROC] = 'The following error messages were reported '.
  1738.                                 'from the Advanced Template Processor: $ERRORS';
  1739.  
  1740.         // MSG_REG_FMCOMPUTE is sent in an Alert message when FormMail
  1741.         // cannot register an external function with FMCompute.
  1742.         // Parameters:
  1743.         //  FUNC    the function that could not be registered
  1744.         //  ERROR   the error message
  1745.     $aMessages[MSG_REG_FMCOMPUTE] = 'Cannot register function "$FUNC" with '.
  1746.                                     'FMCompute: $ERROR';
  1747.  
  1748.  
  1749.         // MSG_USER_ERRORS is shown as part of a user error when an FMCompute
  1750.         // has called the "UserError" function one or more times.
  1751.         // Parameters:
  1752.         //  NONE
  1753.     $aMessages[MSG_USER_ERRORS] = 'One or more errors occurred in your form submission';
  1754.  
  1755.  
  1756.         // MSG_CALL_PARAM_COUNT is sent in an alert when a call to a FormMail
  1757.         // function from FMCompute has the wrong number of parameters
  1758.         // Parameters:
  1759.         //  FUNC    the function name
  1760.         //  COUNT   the actual number of parameters passed
  1761.     $aMessages[MSG_CALL_PARAM_COUNT] = 'FMCompute called FormMail function '.
  1762.                                        '\'$FUNC\' with wrong number of '.
  1763.                                        'parameters: $COUNT';
  1764.  
  1765.         // MSG_CALL_UNK_FUNC is sent in an alert when FMCompute calls an
  1766.         // unknown FormMail function
  1767.         // Parameters:
  1768.         //  FUNC    the function name
  1769.     $aMessages[MSG_CALL_UNK_FUNC] = 'FMCompute called unknown FormMail function '.
  1770.                                        '\'$FUNC\'';
  1771.  
  1772.         // MSG_SAVE_FILE is sent in an alert when saving a file to
  1773.         // the server has failed
  1774.         // Parameters:
  1775.         //  FILE    the source file name (usually a temporary file name)
  1776.         //  DEST    the destination file name
  1777.         //  ERR     the error message
  1778.     $aMessages[MSG_SAVE_FILE] = 'Failed to save file \'$FILE\' to \'$DEST\': $ERR';
  1779.  
  1780.         // MSG_SAVE_FILE_EXISTS is sent as part of an alert when saving a file to
  1781.         // the repository ($FILE_REPOSITORY) has failed because the file
  1782.         // already exists and FILE_OVERWRITE is set to false.
  1783.         // Parameters:
  1784.         //  FILE    the destination file name
  1785.     $aMessages[MSG_SAVE_FILE_EXISTS] = 'Cannot save file to repository as this would '.
  1786.                                         'overwrite \'$FILE\' and you have '.
  1787.                                         'set FILE_OVERWRITE to false.';
  1788.  
  1789.         // MSG_EMPTY_ADDRESSES is sent as part of an alert when a number of empty
  1790.         // email addresses have been specified in recipients, cc, or bcc
  1791.         // *and* there are no valid addresses provided
  1792.         // in the list
  1793.         // Parameters:
  1794.         //  COUNT    the number of empty addresses
  1795.     $aMessages[MSG_EMPTY_ADDRESSES] = '$COUNT empty addresses';
  1796.  
  1797.         // MSG_CALL_INVALID_PARAM is sent in an alert when a call to a FormMail
  1798.         // function from FMCompute has an invalid parameter
  1799.         // Parameters:
  1800.         //  FUNC    the function name
  1801.         //  PARAM   the parameter number
  1802.         //  CORRECT information about correct values
  1803.     $aMessages[MSG_CALL_INVALID_PARAM] = 'FMCompute called FormMail function '.
  1804.                                        '\'$FUNC\' with an invalid parameter '.
  1805.                                        'number $PARAM. Correct values are: $CORRECT';
  1806.  
  1807.         // MSG_CHMOD is sent in an alert when changing the protection
  1808.         // mode of a file to has failed
  1809.         // Parameters:
  1810.         //  FILE    the file name
  1811.         //  MODE    the mode
  1812.         //  ERR     the error message
  1813.     $aMessages[MSG_CHMOD] = 'Failed to change protection mode of file \'$FILE\' '.
  1814.                             'to $MODE: $ERR';
  1815.  
  1816.         // MSG_VERIFY_MISSING is shown to the user image verification string
  1817.         // was not found
  1818.         // Parameters: none
  1819.     $aMessages[MSG_VERIFY_MISSING] = 'Image verification string missing. This'.
  1820.                                      ' is probably a fault on the server.';
  1821.  
  1822.         // MSG_VERIFY_MATCH is shown to the user
  1823.         // if the user's entry did not match the image verification for the
  1824.         // imgverify option
  1825.         // Parameters: none
  1826.     $aMessages[MSG_VERIFY_MATCH] = 'Your entry did not match the image';
  1827.  
  1828.         // MSG_FILE_NAMES_INVALID is sent in an Alert message when
  1829.         // a form's file_names setting has errors
  1830.         // Parameters: none
  1831.         // A list of errors is appended on separate lines
  1832.     $aMessages[MSG_FILE_NAMES_INVALID] = 'Some file_names specifications are invalid $MNUM:\n';
  1833.  
  1834.         // MSG_FILE_NAMES_NOT_FILE is sent in an Alert message when
  1835.         // a form's file_names setting refers to a file field that doesn't
  1836.         // exist
  1837.         // Parameters:
  1838.         //      NAME    the name of the file field that doesn't exist
  1839.     $aMessages[MSG_FILE_NAMES_NOT_FILE] = 'Your file_names specification has '.
  1840.                                           'an error. \'$NAME\' is not the name '.
  1841.                                           'of a file upload field\n';
  1842.  
  1843.         // MSG_NEXT_PLUS_GOOD is sent in an alert message if the form is
  1844.         // ambiguous and specifies both "next_form" and "good_url" or
  1845.         // "good_template"
  1846.         // Parameters:
  1847.         //  $WHICH  the "good_" field that was specified
  1848.     $aMessages[MSG_NEXT_PLUS_GOOD] = 'The form has specified both "next_form" '.
  1849.                                     'and "$WHICH" fields - the action to '.
  1850.                                     'to perform is ambiguous';
  1851.  
  1852.         // MSG_MULTIFORM is sent in an Alert message when a form tries
  1853.         // to use a multi-form template, but templates have not been configured in
  1854.         // formmail.php
  1855.         // Parameters: none
  1856.     $aMessages[MSG_MULTIFORM] = 'You must set either MULTIFORMDIR or MULTIFORMURL '.
  1857.                                 'in formmail.php before you can use '.
  1858.                                 'multi-page forms.';
  1859.  
  1860.         // MSG_MULTIFORM_FAILED is sent in an Alert message
  1861.         // when processing a multi-page form template has failed.
  1862.         // Parameters:
  1863.         //  NAME    the template name
  1864.     $aMessages[MSG_MULTIFORM_FAILED] = 'Failed to process multi-page form template "$NAME"';
  1865.  
  1866.         // MSG_NEED_THIS_FORM is sent in an Alert message
  1867.         // when a multi-page form does not specify the "this_form" field.
  1868.         // Parameters:
  1869.         //  none
  1870.     $aMessages[MSG_NEED_THIS_FORM] = 'Multi-page forms require "this_form" field';
  1871.  
  1872.         // MSG_NO_PHP_SELF is sent in an Alert message
  1873.         // when FormMail requires the "PHP_SELF" server variable and PHP is not
  1874.         // providing it.
  1875.         // Parameters:
  1876.         //  none
  1877.     $aMessages[MSG_NO_PHP_SELF] = 'PHP on the server is not providing "PHP_SELF"';
  1878.  
  1879.         // MSG_RETURN_URL_INVALID is sent in an Alert message
  1880.         // when "this_form" is not a valid return URL.  This occurs for
  1881.         // multi-page forms.
  1882.         // Parameters:
  1883.         //  URL     the invalid URL
  1884.     $aMessages[MSG_RETURN_URL_INVALID] = 'Return URL "$URL" is not valid';
  1885.  
  1886.         // MSG_GO_BACK is sent in an Alert message
  1887.         // when "multi_go_back" has been submitted but this isn't part of a
  1888.         // multi-page form.
  1889.         // Parameters:
  1890.         //  none
  1891.     $aMessages[MSG_GO_BACK] = 'Cannot "go back" if not in a multi-page form '.
  1892.                               'sequence or at the first page of the form '.
  1893.                               'sequence';
  1894.  
  1895.         // MSG_OPEN_URL is sent in an Alert message when a URL cannot
  1896.         // be opened.
  1897.         // Parameters:
  1898.         //  URL     the invalid URL
  1899.         //  ERROR   error message
  1900.     $aMessages[MSG_OPEN_URL] = 'Cannot open URL "$URL": $ERROR';
  1901.  
  1902.         // MSG_CANNOT_RETURN is sent in an Alert message when an invalid return
  1903.         // request is made in a multi-page form sequence.
  1904.         // Parameters:
  1905.         //  TO          the requested page index
  1906.         //  TOPINDEX    the top page index
  1907.     $aMessages[MSG_CANNOT_RETURN] = 'Cannot return to page $TO.  The top page '.
  1908.                                     'index is $TOPINDEX';
  1909.  
  1910.         // MSG_ATTACK_DETECTED is sent in an Alert message when an attack on
  1911.         // the server has been detected
  1912.         // Parameters:
  1913.         //  ATTACK      name or description of the attack
  1914.         //  INFO        more information about the attack
  1915.     $aMessages[MSG_ATTACK_DETECTED] = 'Server attack "$ATTACK" detected. '.
  1916.                                       'Your server is safe as FormMail is '.
  1917.                                       'invulnerable to this attack.  You can '.
  1918.                                       'disable these messages by setting '.
  1919.                                       'ALERT_ON_ATTACK_DETECTION to false '.
  1920.                                       'in FormMail\'s configuration section.'.
  1921.                                       '\nMore information:\n$INFO';
  1922.  
  1923.         // MSG_ATTACK_PAGE is the contents of the browser page displayed to the
  1924.         // user when an attack is detected
  1925.         // Parameters:
  1926.         //  SERVER      the name of the server (website)
  1927.         //  USERINFO    details of the error
  1928.     $aMessages[MSG_ATTACK_PAGE] = 'Your form submission has been rejected '.
  1929.                                   'as it appears to be an abuse of our server ('.
  1930.                                   '$SERVER).<br />'.
  1931.                                   'Our supplier of forms processing software has '.
  1932.                                   'provided <a href="http://www.tectite.com/serverabuse.php" '.
  1933.                                   ' target="_blank">more information about this error</a>.<br /><br />'.
  1934.                                   '$USERINFO';
  1935.  
  1936.         // MSG_ATTACK_MIME_INFO is the contents of the INFO parameter
  1937.         // to the MSG_ATTACK_DETECTED message for the MIME attack
  1938.         // Parameters:
  1939.         //  FLD     name of the field
  1940.         //  CONTENT the invalid content found in the field
  1941.     $aMessages[MSG_ATTACK_MIME_INFO] = 'The field "$FLD" contained invalid '.
  1942.                                        'content "$CONTENT"';
  1943.  
  1944.         // MSG_ATTACK_DUP_INFO is the contents of the INFO parameter
  1945.         // to the MSG_ATTACK_DETECTED message for the Duplicate Data attack
  1946.         // Parameters:
  1947.         //  FLD1     name of the first field
  1948.         //  FLD2     name of the second field
  1949.     $aMessages[MSG_ATTACK_DUP_INFO] = 'The fields "$FLD1" and "$FLD2" contained '.
  1950.                                       'duplicate data';
  1951.  
  1952.         // MSG_ATTACK_SPEC_INFO is the contents of the INFO parameter
  1953.         // to the MSG_ATTACK_DETECTED message for the Special Field attack
  1954.         // Parameters:
  1955.         //  FLD     name of the special field
  1956.     $aMessages[MSG_ATTACK_SPEC_INFO] = 'Special field "$FLD" contained an email address';
  1957.  
  1958.         // MSG_ATTACK_MANYURL_INFO is the contents of the INFO parameter
  1959.         // to the MSG_ATTACK_DETECTED message for the Many URLs attack
  1960.         // Parameters:
  1961.         //  FLD     name of the field
  1962.         //  NUM     number of URLs detected
  1963.     $aMessages[MSG_ATTACK_MANYURL_INFO] = 'Field "$FLD" contained $NUM URLs';
  1964.  
  1965.         // MSG_ATTACK_MANYFIELDS_INFO is the contents of the INFO parameter
  1966.         // to the MSG_ATTACK_DETECTED message for the Many Fields with URLs
  1967.         // attack
  1968.         // Parameters:
  1969.         //  NUM     number of fields detected with URLs
  1970.         //  FLDS    list of fields with URLs in them
  1971.     $aMessages[MSG_ATTACK_MANYFIELDS_INFO] = '$NUM fields contained URLs: $FLDS';
  1972.  
  1973.         // MSG_REV_CAP is an error regarding the setting of ATTACK_DETECTION_REVERSE_CAPTCHA
  1974.         // Parameters: none
  1975.     $aMessages[MSG_REV_CAP] = 'ATTACK_DETECTION_REVERSE_CAPTCHA is not set correctly, '.
  1976.                                 'and will be ignored. Please refer to the documentation '.
  1977.                                 'to make the correct setting.';
  1978.  
  1979.         // MSG_ATTACK_REV_CAP_INFO is the contents of the INFO parameter
  1980.         // to the MSG_ATTACK_DETECTED message for the Reverse Captcha attack
  1981.         // detection
  1982.         // Parameters:
  1983.         //  FLD     name of the field
  1984.         //  CONTENT the invalid content found in the field
  1985.     $aMessages[MSG_ATTACK_REV_CAP_INFO] = 'The field "$FLD" contained unexpected '.
  1986.                                        'content "$CONTENT".';
  1987.  
  1988.         // MSG_ATTACK_JUNK_INFO is the contents of the INFO parameter
  1989.         // to the MSG_ATTACK_DETECTED message for the JUNK attack
  1990.         // Parameters:
  1991.         //  FLD     name of the field
  1992.         //  JUNK    the junk that was found
  1993.     $aMessages[MSG_ATTACK_JUNK_INFO] = 'The field "$FLD" contained junk '.
  1994.                                        'data "$JUNK"';
  1995.  
  1996.  
  1997.         // MSG_NEED_SCRATCH_PAD is an alert message when processing requires
  1998.         // SCRATCH_PAD configuration for file upload processing.  This occurs
  1999.         // when you upload files in pages of a multi page form sequence.
  2000.         // Parameters:
  2001.         //  none
  2002.     $aMessages[MSG_NEED_SCRATCH_PAD] = 'You need to set SCRATCH_PAD in the '.
  2003.                                         'configuration section to process '.
  2004.                                         'uploaded files.';
  2005.  
  2006.         // MSG_OPEN_SCRATCH_PAD is an alert message when the SCRATCH_PAD
  2007.         // directory cannot be opened for cleanup.
  2008.         // Parameters:
  2009.         //  DIR     name of the directory
  2010.         //  ERR     more error information
  2011.     $aMessages[MSG_OPEN_SCRATCH_PAD] = 'Cannot open SCRATCH_PAD directory '.
  2012.                                         '"$DIR".  Open failed: $ERR';
  2013.  
  2014.         // MSG_NO_NEXT_NUM_FILE is an alert message when a form tries to
  2015.         // use the %nextnum% derivation feature but you haven't
  2016.         // setup FormMail's configuration correctly.
  2017.         // Parameters:
  2018.         //  none
  2019.     $aMessages[MSG_NO_NEXT_NUM_FILE] = 'You cannot use the %nextnum% feature: '.
  2020.                                         'you have not configured NEXT_NUM_FILE';
  2021.  
  2022.         // MSG_NEXT_NUM_FILE is an alert message when a form tries to
  2023.         // use the %nextnum% derivation feature but the next number file cannot
  2024.         // be processed.
  2025.         // Parameters:
  2026.         //  FILE    name of the file
  2027.         //  ACT     action
  2028.         //  ERR     more error information
  2029.     $aMessages[MSG_NEXT_NUM_FILE] = 'Cannot $ACT next number file '.
  2030.                                             '\'$FILE\': $ERR';
  2031.  
  2032.         // MSG_MULTI_UPLOAD is an alert message when processing of uploaded
  2033.         // fails during a multi-page form sequence
  2034.         // Parameters:
  2035.         //  none
  2036.     $aMessages[MSG_MULTI_UPLOAD] = 'File upload processing failed during '.
  2037.                                     'multi-page form processing.';
  2038.  
  2039.         // MSG_URL_PARSE is an error message when a URL to be opened
  2040.         // cannot be parsed
  2041.         // Parameters:
  2042.         //  none
  2043.     $aMessages[MSG_URL_PARSE] = 'Failed to parse URL';
  2044.  
  2045.         // MSG_URL_SCHEME is an error message when a URL to be opened
  2046.         // has an unsupported "scheme" value
  2047.         // Parameters:
  2048.         //  SCHEME     the scheme that was seen
  2049.     $aMessages[MSG_URL_SCHEME] = 'Unsupported URL scheme "$SCHEME"';
  2050.  
  2051.         // MSG_SOCKET is an error message when opening a socket for a URL
  2052.         // fails
  2053.         // Parameters:
  2054.         //  ERRNO     the error code
  2055.         //  ERRSTR    the error string
  2056.         //  PHPERR    the value of $php_errormsg
  2057.     $aMessages[MSG_SOCKET] = 'Socket error $ERRNO: $ERRSTR: $PHPERR';
  2058.  
  2059.         // MSG_GETURL_OPEN is an error message when the web server reports
  2060.         // a failure on opening a URL
  2061.         // Parameters:
  2062.         //  STATUS     the HTTP status value (number + string)
  2063.     $aMessages[MSG_GETURL_OPEN] = 'Open URL failed: $STATUS';
  2064.  
  2065.         // MSG_FILE_UPLOAD_ERRn are the error messages corresponding to the
  2066.         // PHP file upload error code n.
  2067.         // Parameters:
  2068.         //  none
  2069.     $aMessages[MSG_FILE_UPLOAD_ERR1] = 'The uploaded file exceeds the upload_max_filesize directive in php.ini.';
  2070.     $aMessages[MSG_FILE_UPLOAD_ERR2] = 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the html form.';
  2071.     $aMessages[MSG_FILE_UPLOAD_ERR3] = 'The uploaded file was only partially uploaded.';
  2072.     $aMessages[MSG_FILE_UPLOAD_ERR4] = 'No file was uploaded.';
  2073.     $aMessages[MSG_FILE_UPLOAD_ERR6] = 'Missing a temporary folder.';
  2074.     $aMessages[MSG_FILE_UPLOAD_ERR7] = 'Failed to write file to disk.';
  2075.     $aMessages[MSG_FILE_UPLOAD_ERR8] = 'File upload stopped by extension.';
  2076.  
  2077.         // MSG_FILE_UPLOAD_ERR_UNK is displayed when an unknown error code
  2078.         // is provided by PHP for a file upload
  2079.         // Parameters:
  2080.         //  ERRNO   the error code
  2081.     $aMessages[MSG_FILE_UPLOAD_ERR_UNK] = 'Unknown file upload error code $ERRNO';
  2082.  
  2083.         // MSG_FILE_UPLOAD_SIZE is displayed when an uploaded file exceeds
  2084.         // the configured maximum size
  2085.         // Parameters:
  2086.         //  NAME   the uploaded file's name
  2087.         //  SIZE   the size of the uploaded file
  2088.         //  MAX    the maximum size that was exceeded
  2089.     $aMessages[MSG_FILE_UPLOAD_SIZE] = 'Uploaded file "$NAME" is too big ('.
  2090.                                         '$SIZE bytes). The maximum permitted '.
  2091.                                         'size is $MAX kilobytes.';
  2092.  
  2093.         // MSG_DER_FUNC_ERROR is sent in an Alert message when
  2094.         // a form uses a derive_fields function that's
  2095.         // formatted incorrectly
  2096.         // Parameters:
  2097.         //  $SPEC   the invalid value specification
  2098.         //  $MSG    a message describing the error or providing an example
  2099.     $aMessages[MSG_DER_FUNC_ERROR] = 'derive_fields: invalid function specification '.
  2100.                                      '"$SPEC": $MSG';
  2101.  
  2102.         // MSG_DER_FUNC_SIZE_FMT describes the right syntax for the "size" function
  2103.         // Parameters:
  2104.         //  none
  2105.     $aMessages[MSG_DER_FUNC_SIZE_FMT] = '"size" function requires this format: '.
  2106.                                     'size(file_field)';
  2107.  
  2108.         // MSG_DER_FUNC_IF_FMT describes the right syntax for the "if" function
  2109.         // Parameters:
  2110.         //  none
  2111.     $aMessages[MSG_DER_FUNC_IF_FMT] = '"if" function requires this format: '.
  2112.                                     'if(field;spec;spec)';
  2113.  
  2114.         // MSG_DER_FUNC_NEXTNUM_FMT describes the right syntax for the "nextnum" function
  2115.         // Parameters:
  2116.         //  none
  2117.     $aMessages[MSG_DER_FUNC_NEXTNUM_FMT] = '"nextnum" function requires this format: '.
  2118.                                     'nextnum(pad) or nextnum(pad;base).  pad and base '.
  2119.                                     'must be numbers. base must be 2 to 36 inclusive';
  2120.  
  2121.         // MSG_DER_FUNC_EXT_FMT describes the right syntax for the "ext" function
  2122.         // Parameters:
  2123.         //  none
  2124.     $aMessages[MSG_DER_FUNC_EXT_FMT] = '"ext" function requires this format: '.
  2125.                                     'ext(file_field)';
  2126.  
  2127.         // MSG_DER_FUNC1_FMT describes the right syntax for a function
  2128.         // requiring one parameter
  2129.         // Parameters:
  2130.         //  FUNC    name of the function
  2131.     $aMessages[MSG_DER_FUNC1_FMT] = '"$FUNC" function requires this format: '.
  2132.                                     '$FUNC(fieldname)';
  2133.  
  2134.         // MSG_USER_ATTACK_JUNK is a message shown to the user when a junk
  2135.         // attack has been detected
  2136.         // Parameters:
  2137.         //  INPUT   the data the user input
  2138.     $aMessages[MSG_USER_ATTACK_JUNK] = 'The following input looks like a junk attack '.
  2139.                                         'on our server.  Please avoid scientific '.
  2140.                                         'or technical terms with long sequences '.
  2141.                                         'of consonants or vowels: $INPUT';
  2142.  
  2143.         // MSG_USER_ATTACK_REV_CAP is a message shown to the user when a reverse
  2144.         // captcha attack has been detected
  2145.         // Parameters:
  2146.         //  none
  2147.     $aMessages[MSG_USER_ATTACK_REV_CAP] = 'Your input looks like an automated spambot '.
  2148.                                         'attacking our server.  Some automatic form '.
  2149.                                         'fillers can trigger this detection. Try '.
  2150.                                         'filling in our form manually.';
  2151.  
  2152.         // MSG_USER_ATTACK_DUP is a message shown to the user when a duplicate
  2153.         // data attack has been detected
  2154.         // Parameters:
  2155.         //  none
  2156.     $aMessages[MSG_USER_ATTACK_DUP] = 'You have input the same information in '.
  2157.                                         'several fields in the form. Please '.
  2158.                                         're-submit the form without duplication';
  2159.  
  2160.         // MSG_USER_ATTACK_MANY_URLS is a message shown to the user when a many urls
  2161.         // attack has been detected
  2162.         // Parameters:
  2163.         //  none
  2164.     $aMessages[MSG_USER_ATTACK_MANY_URLS] = 'Your input includes a number of URLs. '.
  2165.                                             'This server has been configured to reject '.
  2166.                                             'form submissions with too many URLs. '.
  2167.                                             'Please re-submit the form without URLs or '.
  2168.                                             'with fewer URLs.';
  2169.  
  2170.         // MSG_USER_ATTACK_MANY_URL_FIELDS is a message shown to the user when a many urls
  2171.         // attack has been detected
  2172.         // Parameters:
  2173.         //  none
  2174.     $aMessages[MSG_USER_ATTACK_MANY_URL_FIELDS] = $aMessages[MSG_USER_ATTACK_MANY_URLS];
  2175.  
  2176. }  // <A NAME="BuiltinMessages"> Jump to: <A HREF="#MessageNumbers">
  2177.  
  2178.     //
  2179.     // Load the default language, and then override with an optional language file.
  2180.     //
  2181. function LoadLanguage()
  2182. {
  2183.     LoadBuiltinLanguage();
  2184.     LoadLanguageFile();
  2185. }
  2186.  
  2187.     //
  2188.     // To return the value of a string or empty string if not set.
  2189.     //
  2190. function CheckString($ss)
  2191. {
  2192.     return (isset($ss) ? $ss : "");
  2193. }
  2194.  
  2195. $aGetMessageSubstituteErrors = array();
  2196. $aGetMessageSubstituteFound = array();
  2197. $bGetMessageSubstituteNoErrors = false;
  2198.  
  2199.     //
  2200.     // Worker function for GetMessage's preg_replace_callback calls.
  2201.     // Returns the value of the matched variable name.
  2202.     // Variables are searched for in the global $aGetMessageValues.
  2203.     // If no such variable exists, an empty string is returned and the
  2204.     // global variable $aGetMessageSubstituteErrors lists the missing names.
  2205.     //
  2206. function GetMessageSubstituteParam($a_matches)
  2207. {
  2208.     global  $aGetMessageValues,$aGetMessageSubstituteErrors;
  2209.     global  $aGetMessageSubstituteFound,$bGetMessageSubstituteNoErrors;
  2210.  
  2211.     $s_name = $a_matches[1];
  2212.     $aGetMessageSubstituteFound[] = $s_name;
  2213.     $s_value = "";
  2214.     if (isset($aGetMessageValues[$s_name]))
  2215.         $s_value = $aGetMessageValues[$s_name];
  2216.     elseif ($bGetMessageSubstituteNoErrors)
  2217.         $s_value = '$'.$s_name;
  2218.     else
  2219.         $aGetMessageSubstituteErrors[] = $s_name;
  2220.     return ($s_value);
  2221. }
  2222.  
  2223.     //
  2224.     // Returns message text from a message number, with optional parameters.
  2225.     //
  2226. function GetMessage($i_msg_num,$a_params = array(),
  2227.                         $b_show_mnum = true,$b_no_errors = false)
  2228. {
  2229.     global  $aMessages,$sLangID,$bShowMesgNumbers;
  2230.  
  2231.     if (!isset($aMessages[$i_msg_num]))
  2232.     {
  2233.         SendAlert("Unknown Message Number $i_msg_num was used",false,true);
  2234.         $s_text = "<UNKNOWN MESSAGE NUMBER>";
  2235.     }
  2236.     else
  2237.         $s_text = $aMessages[$i_msg_num];
  2238.     $s_mno = $bShowMesgNumbers ? "[M$i_msg_num]" : "";
  2239.  
  2240.     $s_orig_text = $s_text;
  2241.         //
  2242.         // substitute parameters; only works with PHP version 4.0.5 or later
  2243.         //
  2244.     if (strpos($s_text,'$') !== false)
  2245.     {
  2246.         global  $aGetMessageValues,$aGetMessageSubstituteErrors;
  2247.         global  $aGetMessageSubstituteFound,$bGetMessageSubstituteNoErrors;
  2248.  
  2249.         $aGetMessageSubstituteErrors = array();
  2250.         $aGetMessageSubstituteFound = array();
  2251.         $aGetMessageValues = HTMLEntitiesArray($a_params);
  2252.         $bGetMessageSubstituteNoErrors = $b_no_errors;
  2253.         $aGetMessageValues["MNUM"] = $s_mno;    // add the message number
  2254.             //
  2255.             // search for words in this form:
  2256.             //      $word
  2257.             // where word begins with an alphabetic character and
  2258.             // consists of alphanumeric and underscore
  2259.             //
  2260.         $s_text = preg_replace_callback('/\$([a-z][a-z0-9_]*)/i',
  2261.                                             'GetMessageSubstituteParam',$s_text);
  2262.         if (count($aGetMessageSubstituteErrors) > 0)
  2263.             SendAlert("Message Number $i_msg_num ('$s_orig_text') in language $sLangID ".
  2264.                         "specified the following unsupported parameters: ".
  2265.                         implode(',',$aGetMessageSubstituteErrors));
  2266.         if (!in_array("MNUM",$aGetMessageSubstituteFound))
  2267.                 //
  2268.                 // append the message number
  2269.                 //
  2270.             $s_text .= $b_show_mnum ? " $s_mno" : "";
  2271.     }
  2272.     else
  2273.             //
  2274.             // append the message number
  2275.             //
  2276.         $s_text .= $b_show_mnum ? " $s_mno" : "";
  2277.         //
  2278.         // replace '\n' sequences with new lines
  2279.         //
  2280.     return (str_replace('\n',"\n",$s_text));
  2281. }
  2282.  
  2283.     //
  2284.     // Check for old version of PHP - die if too old.
  2285.     //
  2286. function IsOldVersion(&$a_this_version)
  2287. {
  2288.     $a_modern = array(4,1,0);   // versions prior to this are "old" - "4.1.0"
  2289.     $s_req_string = "4.0.5";    // version 4.0.5 of PHP is required from
  2290.                                 // FormMail 5.00 onward (because we use
  2291.                                 // preg_replace_callback for all messages to
  2292.                                 // support languages other than English)
  2293.     $a_too_old = explode(".",$s_req_string);
  2294.  
  2295.     $i_cannot_use = ($a_too_old[0] * 10000) +
  2296.                     ($a_too_old[1] * 100) +
  2297.                     $a_too_old[2];
  2298.  
  2299.     $s_vers_string = phpversion();
  2300.     $a_this_version = explode(".",$s_vers_string);
  2301.     $i_this_num = ($a_this_version[0] * 10000) +
  2302.                     ($a_this_version[1] * 100) +
  2303.                     $a_this_version[2];
  2304.  
  2305.     if ($i_this_num <= $i_cannot_use)
  2306.         die(GetMessage(MSG_SCRIPT_VERSION,array("PHPREQ"=>$s_req_string,
  2307.                                                 "PHPVERS"=>$s_vers_string)));
  2308.     $i_modern_num = ($a_modern[0] * 10000) +
  2309.                     ($a_modern[1] * 100) +
  2310.                     $a_modern[2];
  2311.     return ($i_this_num < $i_modern_num);
  2312. }
  2313.  
  2314.     //
  2315.     // Check if the server is Windows
  2316.     //
  2317. function IsServerWindows()
  2318. {
  2319.     static  $bGotAnswer = false;
  2320.     static  $bAnswer;
  2321.  
  2322.     if (!$bGotAnswer)
  2323.     {
  2324.         if ((isset($_ENV["OS"]) && stristr($_ENV["OS"],"windows") !== false) ||
  2325.             (isset($_SERVER["PATH"]) && stristr($_SERVER["PATH"],"winnt") !== false) ||
  2326.             (isset($_SERVER["PATH"]) && stristr($_SERVER["PATH"],"windows") !== false) ||
  2327.             (isset($_SERVER["SystemRoot"]) && stristr($_SERVER["SystemRoot"],"winnt") !== false) ||
  2328.             (isset($_ENV["SystemRoot"]) && stristr($_ENV["SystemRoot"],"winnt") !== false) ||
  2329.             (isset($_SERVER["SystemRoot"]) && stristr($_SERVER["SystemRoot"],"windows") !== false) ||
  2330.             (isset($_ENV["SystemRoot"]) && stristr($_ENV["SystemRoot"],"windows") !== false) ||
  2331.             (isset($_SERVER["Path"]) && stristr($_SERVER["Path"],"windows") !== false))
  2332.             $bAnswer = true;
  2333.         else
  2334.             $bAnswer = false;
  2335.         $bGotAnswer = true;
  2336.     }
  2337.     return ($bAnswer);
  2338. }
  2339.  
  2340.     //
  2341.     // To return a temporary file name from $SCRATCH_PAD
  2342.     //
  2343. function GetScratchPadFile($s_prefix)
  2344. {
  2345.     global  $SCRATCH_PAD;
  2346.  
  2347.     switch (substr($SCRATCH_PAD,-1))
  2348.     {
  2349.     case '/':
  2350.     case '\\':
  2351.         $s_dir = substr($SCRATCH_PAD,0,-1);
  2352.         break;
  2353.     default:
  2354.         $s_dir = $SCRATCH_PAD;
  2355.         break;
  2356.     }
  2357.         //
  2358.         // Ideally, we could use tempnam. But,
  2359.         // tempnam is system dependent and might not use the
  2360.         // SCRATCH_PAD directory even if we tell it to.
  2361.         // So, we'll force the file into SCRATCH_PAD.
  2362.         //
  2363.         // Note that we do *not* create the file, even though tempnam
  2364.         // does create it in PHP version 4.0.3 and above. (The reason is
  2365.         // we can't guarantee a non-race condition anyway.)
  2366.         //
  2367.     do
  2368.     {
  2369.         $i_rand = mt_rand(0,16777215);  // 16777215 is FFFFFF in hex
  2370.         $s_name = $SCRATCH_PAD."/".$s_prefix.sprintf("%06X",$i_rand);
  2371.     }
  2372.     while (file_exists($s_name));
  2373.     return ($s_name);
  2374. }
  2375.  
  2376.     //
  2377.     // To return a temporary file name.
  2378.     //
  2379. function GetTempName($s_prefix)
  2380. {
  2381.     global  $SCRATCH_PAD;
  2382.  
  2383.     if (isset($SCRATCH_PAD) && !empty($SCRATCH_PAD))
  2384.         $s_name = GetScratchPadFile($s_prefix);
  2385.     else
  2386.         $s_name = tempnam("/tmp",$s_prefix);
  2387.     return ($s_name);
  2388. }
  2389.  
  2390.     //
  2391.     // To find a directory on the server for temporary files.
  2392.     //
  2393. function GetTempDir()
  2394. {
  2395.     $s_name = GetTempName("fm");
  2396.     if (file_exists($s_name))
  2397.         unlink($s_name);
  2398.     $s_dir = dirname($s_name);
  2399.     return ($s_dir);
  2400. }
  2401.  
  2402.     //
  2403.     // Returns true if the PHP version is at or later than the string specified
  2404.     // (can't use "version_compare" before 4.1.0).
  2405.     //
  2406. function IsPHPAtLeast($s_vers)
  2407. {
  2408.     global  $aPHPVERSION;
  2409.  
  2410.     $a_test_version = explode(".",$s_vers);
  2411.     if (count($a_test_version) < 3)
  2412.         return (false);
  2413.     return ($aPHPVERSION[0] > $a_test_version[0] ||
  2414.             ($aPHPVERSION[0] == $a_test_version[0] &&
  2415.                 ($aPHPVERSION[1] > $a_test_version[1] ||
  2416.                     $aPHPVERSION[1] == $a_test_version[1] &&
  2417.                         $aPHPVERSION[2] >= $a_test_version[2])));
  2418. }
  2419.  
  2420. define('DEBUG',false);      // for production
  2421. //define('DEBUG',true);         // for development and debugging
  2422.  
  2423. if (DEBUG)
  2424. {
  2425.     error_reporting(E_ALL);     // trap everything!
  2426.     LoadLanguage();
  2427. }
  2428. else
  2429. {
  2430.     $iOldLevel = error_reporting(E_ALL ^ E_WARNING);
  2431.     LoadLanguage();
  2432.         //
  2433.         // report everyting except warnings and notices
  2434.         //
  2435.     error_reporting(E_ALL ^ E_WARNING ^ E_NOTICE);
  2436. }
  2437.  
  2438. function SetRealDocumentRoot()
  2439. {
  2440.     global  $aServerVars,$REAL_DOCUMENT_ROOT;
  2441.  
  2442.     if (isset($aServerVars['SCRIPT_FILENAME']))
  2443.         $REAL_DOCUMENT_ROOT = $aServerVars['SCRIPT_FILENAME'];
  2444.     elseif (isset($aServerVars['PATH_TRANSLATED']))
  2445.         $REAL_DOCUMENT_ROOT = $aServerVars['PATH_TRANSLATED'];
  2446.     else
  2447.         $REAL_DOCUMENT_ROOT = "";
  2448.         //
  2449.         // look for 'www' or 'public_html' and strip back to that if found,
  2450.         // otherwise just get the directory name
  2451.         //
  2452.     if (($i_pos = strpos($REAL_DOCUMENT_ROOT,"/www/")) !== false)
  2453.         $REAL_DOCUMENT_ROOT = substr($REAL_DOCUMENT_ROOT,0,$i_pos+4);
  2454.     elseif (($i_pos = strpos($REAL_DOCUMENT_ROOT,"/public_html/")) !== false)
  2455.         $REAL_DOCUMENT_ROOT = substr($REAL_DOCUMENT_ROOT,0,$i_pos+12);
  2456.     elseif (!empty($REAL_DOCUMENT_ROOT))
  2457.         $REAL_DOCUMENT_ROOT = dirname($REAL_DOCUMENT_ROOT);
  2458.     elseif (isset($aServerVars['DOCUMENT_ROOT']) &&
  2459.             !empty($aServerVars['DOCUMENT_ROOT']))
  2460.         $REAL_DOCUMENT_ROOT = $aServerVars['DOCUMENT_ROOT'];
  2461. }
  2462.  
  2463.     //
  2464.     // Hook system: before initialization (but after configuration)
  2465.     //
  2466. if ($HOOK_DIR !== "")
  2467.     if (!@include("$HOOK_DIR/fmhookpreinit.inc.php"))
  2468.         @include("$HOOK_DIR/fmhookpreinit.inc");
  2469.  
  2470. if (!empty($SESSION_NAME))
  2471.     session_name($SESSION_NAME);
  2472.  
  2473. session_start();
  2474.  
  2475. function ZapSession()
  2476. {
  2477.     global  $aSessionVarNames,$aSessionVars;
  2478.  
  2479.     if (DESTROY_SESSION)
  2480.         session_destroy();
  2481.     else
  2482.     {
  2483.         foreach ($aSessionVarNames as $s_var_name)
  2484.             unset($aSessionVars[$s_var_name]);
  2485.     }
  2486. }
  2487.  
  2488. if ($bUseOldVars)
  2489.     $aSessionVars = &$HTTP_SESSION_VARS;
  2490. else
  2491.     $aSessionVars = &$_SESSION;
  2492.  
  2493.     //
  2494.     // This array lists the private variables used by FormMail.
  2495.     // We use the names here to cleanup the session when FormMail has
  2496.     // finished its processing.
  2497.     //
  2498. $aSessionVarNames = array("FormError","FormErrorInfo","FormErrorCode",
  2499.                         "FormErrorItems","FormData","FormIsUserError",
  2500.                         "FormAlerted","FormSavedFiles","FormIndex",
  2501.                         "FormList","FormKeep","VerifyImgString",
  2502.                         "turing_string");
  2503.  
  2504. $aSessionVars["FormError"] = NULL;
  2505. unset($aSessionVars["FormError"]);                  // start with no error
  2506. $aSessionVars["FormErrorInfo"] = NULL;
  2507. unset($aSessionVars["FormErrorInfo"]);              // start with no error
  2508. $aSessionVars["FormErrorCode"] = NULL;
  2509. unset($aSessionVars["FormErrorCode"]);              // start with no error
  2510. $aSessionVars["FormErrorItems"] = NULL;
  2511. unset($aSessionVars["FormErrorItems"]);             // start with no error
  2512. $aSessionVars["FormData"] = NULL;
  2513. unset($aSessionVars["FormData"]);                   // start with no data
  2514. $aSessionVars["FormIsUserError"] = NULL;
  2515. unset($aSessionVars["FormIsUserError"]);            // start with no data
  2516. $aSessionVars["FormAlerted"] = NULL;
  2517. unset($aSessionVars["FormAlerted"]);                // start with no data
  2518.  
  2519. //
  2520. // Note that HTTP_REFERER is easily spoofed, so there's no point in
  2521. // using it for security.
  2522. //
  2523.  
  2524.     //
  2525.     // SPECIAL_FIELDS is the list of fields that formmail.php looks for to
  2526.     // control its operation
  2527.     //
  2528. $SPECIAL_FIELDS = array(
  2529.         "email",        // email address of the person who filled in the form
  2530.         "realname",     // the real name of the person who filled in the form
  2531.         "recipients",   // comma-separated list of email addresses to which we'll send the results
  2532.         "cc",           // comma-separated list of email addresses to which we'll CC the results
  2533.         "bcc",          // comma-separated list of email addresses to which we'll BCC the results
  2534.         "replyto",      // comma-separated list of email addresses to whom replies should be sent
  2535.         "required",     // comma-separated list of fields that must be found in the input
  2536.         "conditions",   // complex condition tests
  2537.         "fmcompute",    // computations
  2538.         "fmmodules",    // list of modules required
  2539.         "mail_options", // comma-separated list of options
  2540.         "good_url",     // URL to go to on success
  2541.         "good_template",// template file to display on success
  2542.         "bad_url",      // URL to go to on error
  2543.         "bad_template", // template file to display on error
  2544.         "template_list_sep", // separator when expanding lists in templates
  2545.         "this_form",    // the URL of the form (can be used by bad_url)
  2546.         "subject",      // subject for the email
  2547.         "env_report",   // comma-separated list of environment variables to report
  2548.         "filter",       // a supported filter to use
  2549.         "filter_options",// options for using the filter
  2550.         "filter_fields",// list of fields to filter (default is to filter all fields)
  2551.         "logfile",      // log file to write to
  2552.         "csvfile",      // file to write CSV records to
  2553.         "csvcolumns",   // columns to save in the csvfile
  2554.         "crm_url",      // URL for sending data to the CRM; note that the
  2555.                         // value must have a valid prefix specified in TARGET_URLS
  2556.         "crm_spec",     // CRM specification (field mapping)
  2557.         "crm_options",  // comma-separated list of options to control CRM processing
  2558.         "derive_fields", // a list of fields to derive from other fields
  2559.         "file_names",   // specifies names for files being uploaded
  2560.         "autorespond",  // specification for auto-responding
  2561.         "arverify",     // verification field to allow auto-responding
  2562.         "imgverify",    // verification field to allow submission
  2563.         "multi_start",  // set this field on the first page of a multi-page form sequence
  2564.         "multi_keep",   // set this field on the pages of a multi-page form sequence
  2565.                         // to the list of fields that should be kept when moving
  2566.                         // forward after going backwards
  2567.         "next_form",    // next form name or empty for last form
  2568.         "multi_go_back",// this field should be set when the user clicks the
  2569.                         // back button or link in a multi-page form sequence
  2570.         "alert_to");    // email address to send alerts (errors) to
  2571.  
  2572.     //
  2573.     // $SPECIAL_MULTI is the list of fields from $SPECIAL_FIELDS that can
  2574.     // have multiple values, for example:
  2575.     //      name="conditions1"
  2576.     //      name="conditions2"
  2577.     //
  2578. $SPECIAL_MULTI = array(
  2579.         "conditions",
  2580.         "fmcompute",
  2581.         );
  2582.  
  2583.     //
  2584.     // $SPECIAL_ARRAYS is the list of fields from $SPECIAL_FIELDS that can
  2585.     // be submitted as arrays of values, for example:
  2586.     //      <select name="recipients[]">
  2587.     //      <option value="sales">Sales</option>
  2588.     //      <option value="service">Service</option>
  2589.     //      </select>
  2590.     //
  2591. $SPECIAL_ARRAYS = array(
  2592.         "recipients",
  2593.         "cc",
  2594.         "bcc",
  2595.         "replyto",
  2596.         );
  2597.  
  2598.     //
  2599.     // $SPECIAL_NOSTRIP is the list of fields from $SPECIAL_FIELDS that
  2600.     // should not be stripped (other than for magic_quotes_gpc reasons).
  2601.     //
  2602. $SPECIAL_NOSTRIP = array(
  2603.         "conditions",
  2604.         "fmcompute",
  2605.         );
  2606.  
  2607.     //
  2608.     // VALID_MAIL_OPTIONS lists the valid mail_options words
  2609.     //
  2610. $VALID_MAIL_OPTIONS = array(
  2611.         "AlwaysList"=>true,
  2612.         "CharSet"=>true,
  2613.         "DupHeader"=>true,
  2614.         "Exclude"=>true,
  2615.         "FromAddr"=>true,
  2616.         "FromLineStyle"=>true,
  2617.         "HTMLTemplate"=>true,
  2618.         "KeepLines"=>true,
  2619.         "NoEmpty"=>true,
  2620.         "NoPlain"=>true,
  2621.         "PlainTemplate"=>true,
  2622.         "SendMailFOption"=>true,
  2623.         "StartLine"=>true,
  2624.         "TemplateMissing"=>true,
  2625.         );
  2626.  
  2627.     //
  2628.     // VALID_CRM_OPTIONS lists the valid crm_options words
  2629.     //
  2630. $VALID_CRM_OPTIONS = array(
  2631.         "ErrorOnFail"=>true,
  2632.         );
  2633.  
  2634.     //
  2635.     // VALID_AR_OPTIONS lists the valid autorespond words
  2636.     //
  2637. $VALID_AR_OPTIONS = array(
  2638.         "Subject"=>true,
  2639.         "HTMLTemplate"=>true,
  2640.         "PlainTemplate"=>true,
  2641.         "TemplateMissing"=>true,
  2642.         "FromAddr"=>true,
  2643.         );
  2644.  
  2645.     //
  2646.     // VALID_FILTER_OPTIONS lists the valid filter_options words
  2647.     //
  2648. $VALID_FILTER_OPTIONS = array(
  2649.         "Attach"=>true,
  2650.         "KeepInLine"=>true,
  2651.         "CSVHeading"=>true,
  2652.         "CSVSep"=>true,
  2653.         "CSVIntSep"=>true,
  2654.         "CSVQuote"=>true,
  2655.         "CSVEscPolicy"=>true,
  2656.         "CSVRaw"=>true,
  2657.         );
  2658.  
  2659.     //
  2660.     // SPECIAL_VALUES is set to the value of the fields we've found
  2661.     //  usage: $SPECIAL_VALUES["email"] is the value of the email field
  2662.     //
  2663. $SPECIAL_VALUES = array();
  2664.     //
  2665.     // Array of mail options; set by the function 'ProcessMailOptions'
  2666.     //
  2667. $MAIL_OPTS = array();
  2668.     //
  2669.     // Array of crm options; set by the function 'ProcessCRMOptions'
  2670.     //
  2671. $CRM_OPTS = array();
  2672.     //
  2673.     // Array of autorespond options; set by the function 'ProcessAROptions'
  2674.     //
  2675. $AR_OPTS = array();
  2676.     //
  2677.     // Array of filter options; set by the function 'ProcessFilterOptions'
  2678.     //
  2679. $FILTER_OPTS = array();
  2680.  
  2681.     //
  2682.     // initialise $SPECIAL_VALUES so that we don't fail on using unset values
  2683.     //
  2684. foreach ($SPECIAL_FIELDS as $sFieldName)
  2685.     $SPECIAL_VALUES[$sFieldName] = "";
  2686.  
  2687.     //
  2688.     // Special defaults for some fields....
  2689.     //
  2690. $SPECIAL_VALUES['template_list_sep'] = ",";
  2691.  
  2692.     //
  2693.     // FORMATTED_INPUT contains the input variables formatted nicely
  2694.     // This is used for error reporting and debugging only.
  2695.     //
  2696. $FORMATTED_INPUT = array();
  2697.  
  2698.     //
  2699.     // $FILTER_ATTRIBS_LOOKUP is the parsed $FILTER_ATTRIBS array
  2700.     //
  2701. $FILTER_ATTRIBS_LOOKUP = array();
  2702.  
  2703.     //
  2704.     // $EMAIL_ADDRS is the array of email addresses from the $FORM_INI_FILE
  2705.     //
  2706. $EMAIL_ADDRS = array();
  2707.  
  2708. /* 
  2709.  * Class:       EmailChecker
  2710.  * Description:     
  2711.  *  Contains a list of valid email addresses and email address patterns.
  2712.  *  Provides methods for checking the validity of an email address.
  2713.  */
  2714. class   EmailChecker
  2715. {
  2716.     var     $_aAddresses;       // valid email addresses (as keys)
  2717.     var     $_aTargetPatterns;  // valid email address patterns
  2718.  
  2719.     /*
  2720.      * Method:      EmailChecker ctor
  2721.      * Parameters:  $a_patterns     an array of email address patterns
  2722.      * Returns:     n/a
  2723.      * Description: 
  2724.      *  Constructs the object.
  2725.      */
  2726.     function    EmailChecker($a_patterns = array())
  2727.     {
  2728.         $this->_aAddresses = array();
  2729.         $this->_aTargetPatterns = $a_patterns;
  2730.     }
  2731.  
  2732.     /*
  2733.      * Method:      EmailChecker::AddAddress
  2734.      * Parameters:  $s_addr     an email address
  2735.      * Returns:     void
  2736.      * Description: 
  2737.      *  Adds an email address to the list of valid email addresses.
  2738.      */
  2739.     function    AddAddress($s_addr)
  2740.     {
  2741.         $this->_aAddresses[$s_addr] = true;
  2742.     }
  2743.  
  2744.     /*
  2745.      * Method:      EmailChecker::AddAddresses
  2746.      * Parameters:  $s_list     a list ofemail addresses
  2747.      * Returns:     void
  2748.      * Description: 
  2749.      *  Adds a comma-separated list of email addresses to the list of valid email addresses.
  2750.      */
  2751.     function    AddAddresses($s_list)
  2752.     {
  2753.         $a_addrs = TrimArray(explode(",",$s_list));
  2754.         foreach ($a_addrs as $s_addr)
  2755.             $this->AddAddress($s_addr);
  2756.     }
  2757.  
  2758.     /*
  2759.      * Method:      EmailChecker::CheckAddress
  2760.      * Parameters:  $s_email    an email address
  2761.      * Returns:     bool        true if the address is valid, otherwise false
  2762.      * Description: 
  2763.      *  Checks an email address for validity.
  2764.      */
  2765.     function    CheckAddress($s_email)
  2766.     {
  2767.         $b_is_valid = false;
  2768.         if (isset($this->_aAddresses[$s_email]))
  2769.             $b_is_valid = true;
  2770.         else
  2771.         {
  2772.             for ($ii = 0 ; $ii < count($this->_aTargetPatterns) ; $ii++)
  2773.                 if (eregi($this->_aTargetPatterns[$ii],$s_email))
  2774.                 {
  2775.                     $b_is_valid = true;
  2776.                     break;
  2777.                 }
  2778.         }
  2779.         return ($b_is_valid);
  2780.     }
  2781. };
  2782.  
  2783.     //
  2784.     // Create the object for checking emails
  2785.     //
  2786. $ValidEmails = new EmailChecker($TARGET_EMAIL);
  2787.  
  2788.     //
  2789.     // Access the www.tectite.com website to get the current version.
  2790.     //
  2791. function CheckVersion()
  2792. {
  2793.     global  $FM_VERS;
  2794.  
  2795. @   $fp = fopen("http://www.tectite.com/fmversion.txt","r");
  2796.     if ($fp !== false)
  2797.     {
  2798.             //
  2799.             // version file looks like this:
  2800.             //      Version=versionumber
  2801.             //      Message=a message to send in the alert
  2802.             //
  2803.         $s_version = "";
  2804.         $s_message = "";
  2805.         $s_line = "";
  2806.         $b_in_mesg = false;
  2807.         while (!feof($fp))
  2808.         {
  2809.             $s_line = fgets($fp,1024);
  2810.             if ($b_in_mesg)
  2811.                 $s_message .= $s_line;
  2812.             else
  2813.             {
  2814.                 $s_prefix = substr($s_line,0,8);
  2815.                 if ($s_prefix == "Message=")
  2816.                 {
  2817.                     $s_message .= substr($s_line,8);
  2818.                     $b_in_mesg = true;
  2819.                 }
  2820.                 elseif ($s_prefix == "Version=")
  2821.                     $s_version = substr($s_line,8);
  2822.             }
  2823.         }
  2824.         fclose($fp);
  2825.         $s_version = str_replace("\r","",$s_version);
  2826.         $s_version = str_replace("\n","",$s_version);
  2827.         $s_stop_mesg = GetMessage(MSG_END_VERS_CHK);
  2828.         if ((float) $s_version > (float) $FM_VERS)
  2829.             SendAlert(GetMessage(MSG_VERS_CHK,array(
  2830.                         "TECTITE"=>"www.tectite.com",
  2831.                         "FM_VERS"=>"$FM_VERS",
  2832.                         "NEWVERS"=>$s_version,
  2833.                         ))."\n$s_message\n$s_stop_mesg",true,true);
  2834.     }
  2835. }
  2836.  
  2837.     //
  2838.     // Check for new FormMail version
  2839.     //
  2840. function Check4Update($s_chk_file,$s_id = "")
  2841. {
  2842.     global  $lNow,$php_errormsg;
  2843.  
  2844. @   $l_last_chk = filemtime($s_chk_file);
  2845.     if ($l_last_chk === false || $lNow - $l_last_chk >= (CHECK_DAYS*24*60*60))
  2846.     {
  2847.         CheckVersion();
  2848.             //
  2849.             // update the check file's time stamp
  2850.             //
  2851.     @   $fp = fopen($s_chk_file,"w");
  2852.         if ($fp !== false)
  2853.         {
  2854.             fwrite($fp,"FormMail version check ".
  2855.                 (empty($s_id) ? "" : "for identifier '$s_id' ").
  2856.                 "at ".date("H:i:s d-M-Y",$lNow)."\n");
  2857.             fclose($fp);
  2858.         }
  2859.         else
  2860.             SendAlert(GetMessage(MSG_CHK_FILE_ERROR,array("FILE"=>$s_chk_file,
  2861.                             "ERROR"=>CheckString($php_errormsg))));
  2862.     }
  2863. }
  2864.  
  2865.     //
  2866.     // Perform various processing at the end of the script's execution.
  2867.     //
  2868. function OnExit()
  2869. {
  2870.     global  $TARGET_EMAIL,$CHECK_FILE;
  2871.  
  2872.         //
  2873.         // Check the www.tectite.com website for a new version, but only
  2874.         // do this check once every CHECK_DAYS days (or on server reboot).
  2875.         //
  2876.     if (CHECK_FOR_NEW_VERSION)
  2877.     {
  2878.         global  $SERVER;
  2879.  
  2880.         if (isset($TARGET_EMAIL[0]))
  2881.         {
  2882.                 //
  2883.                 // use the first few characters of the MD5 of first email
  2884.                 // address pattern from $TARGET_EMAIL to get a unique file
  2885.                 // for the server
  2886.                 //
  2887.             $s_id = "";
  2888.             if (isset($SERVER) && !empty($SERVER))
  2889.                 $s_id = $SERVER;
  2890.             $s_dir = GetTempDir();
  2891.             $s_md5 = md5($TARGET_EMAIL[0]);
  2892.             $s_uniq = substr($s_md5,0,6);
  2893.             $s_chk_file = "fm"."$s_uniq".".txt";
  2894.             Check4Update($s_dir."/".$s_chk_file,$s_id);
  2895.         }
  2896.     }
  2897. }
  2898.  
  2899. register_shutdown_function('OnExit');
  2900.  
  2901.     //
  2902.     // Return the array with each string processed by htmlentities
  2903.     //
  2904. function HTMLEntitiesArray($a_array)
  2905. {
  2906.     foreach ($a_array as $m_key=>$s_str)
  2907.     {
  2908.             //
  2909.             // only encode the value after the '='
  2910.             //
  2911.         if (($i_pos = strpos($s_str,'=')) !== false)
  2912.             $a_array[$m_key] = substr($s_str,0,$i_pos+1).
  2913.                                 FixedHTMLEntities(substr($s_str,$i_pos+1));
  2914.         else
  2915.             $a_array[$m_key] = FixedHTMLEntities($s_str);
  2916.     }
  2917.     return ($a_array);
  2918. }
  2919.  
  2920.     //
  2921.     // Unfortunately, htmlentities gets some characters
  2922.     // wrong and converts them even when the charset is provided.
  2923.     // This function overcomes this problem.
  2924.     //
  2925. function    FixedHTMLEntities($s_str)
  2926. {
  2927.     global  $sHTMLCharSet;
  2928.  
  2929.     if (isset($sHTMLCharSet) && $sHTMLCharSet != "")
  2930.         return (htmlspecialchars($s_str,ENT_COMPAT,$sHTMLCharSet));
  2931.     return (htmlentities($s_str));
  2932. }
  2933.  
  2934.     //
  2935.     // Return the array with each string urlencode'd.
  2936.     //
  2937. function URLEncodeArray($a_array)
  2938. {
  2939.     foreach ($a_array as $m_key=>$s_str)
  2940.     {
  2941.             //
  2942.             // only encode the value after the '='
  2943.             //
  2944.         if (($i_pos = strpos($s_str,'=')) !== false)
  2945.             $a_array[$m_key] = substr($s_str,0,$i_pos+1).
  2946.                                 urlencode(substr($s_str,$i_pos+1));
  2947.         else
  2948.             $a_array[$m_key] = urlencode($s_str);
  2949.     }
  2950.     return ($a_array);
  2951. }
  2952.  
  2953.     //
  2954.     // Add a parameter or list of parameters to a URL.
  2955.     //
  2956. function AddURLParams($s_url,$m_params,$b_encode = true)
  2957. {
  2958.     if (!empty($m_params))
  2959.     {
  2960.         if (!is_array($m_params))
  2961.             $m_params = array($m_params);
  2962.         if (strpos($s_url,'?') === false)
  2963.             $s_url .= '?';
  2964.         else
  2965.             $s_url .= '&';
  2966.         $s_url .= implode('&',($b_encode) ? URLEncodeArray($m_params) : $m_params);
  2967.     }
  2968.     return ($s_url);
  2969. }
  2970.  
  2971.     //
  2972.     // Recursively trim an array of strings (non string values are converted
  2973.     // to a string first).
  2974.     //
  2975. function TrimArray($a_list)
  2976. {
  2977.     foreach ($a_list as $m_key=>$m_item)
  2978.         if (is_array($m_item))
  2979.             $a_list[$m_key] = TrimArray($m_item);
  2980.         elseif (is_scalar($m_item))
  2981.             $a_list[$m_key] = trim("$m_item");
  2982.         else
  2983.             $a_list[$m_key] = "";
  2984.     return ($a_list);
  2985. }
  2986.  
  2987.     //
  2988.     // Parse a derivation specification and return an array of
  2989.     // field names and operators.
  2990.     //
  2991. function ParseDerivation($a_form_data,$s_fld_spec,$s_name,&$a_errors)
  2992. {
  2993.     $a_deriv = array();
  2994.     while (($i_len = strlen($s_fld_spec)) > 0)
  2995.     {
  2996.             //
  2997.             // we support the following operators:
  2998.             //      +   concatenate with a single space between, but skip the space
  2999.             //          if the next field is empty
  3000.             //      *   concatenate with a single space between
  3001.             //      .   concatenate with no space between
  3002.             //
  3003.         $i_span = strcspn($s_fld_spec,'+*.');
  3004.         if ($i_span == 0)
  3005.         {
  3006.             $a_errors[] = $s_name;
  3007.             return (false);
  3008.         }
  3009.         $a_deriv[] = trim(substr($s_fld_spec,0,$i_span));
  3010.         if ($i_span < $i_len)
  3011.         {
  3012.             $a_deriv[] = substr($s_fld_spec,$i_span,1);
  3013.             $s_fld_spec = substr($s_fld_spec,$i_span+1);
  3014.         }
  3015.         else
  3016.             $s_fld_spec = "";
  3017.     }
  3018.     return ($a_deriv);
  3019. }
  3020.  
  3021.     //
  3022.     // Test if a character is an alphabetic.
  3023.     //
  3024. function IsAlpha($ch)
  3025. {
  3026.     return (strpos("abcdefghijklmnopqrstuvwxyz",strtolower($ch)) !== false);
  3027. }
  3028.  
  3029.     //
  3030.     // Test if a character is a digit.
  3031.     //
  3032. function IsNumeric($ch)
  3033. {
  3034.     return (strpos("0123456789",$ch) !== false);
  3035. }
  3036.  
  3037.     //
  3038.     // Test if a character is an alphanumeric
  3039.     //
  3040. function IsAlnum($ch)
  3041. {
  3042.     return (IsAlpha($ch) || IsNumeric($ch));
  3043. }
  3044.  
  3045.     //
  3046.     // Return an array of tokens extracted from the given string.
  3047.     // A token is:
  3048.     //  - a word (begins with alpha or _, and is followed by any number
  3049.     //    of alphanumerics or _ chars)
  3050.     //  - a number (any number of consecutive digits with up to one period)
  3051.     //  - a string enclosed in specified quotes (this can be disabled)
  3052.     //  - any punctuation character
  3053.     //
  3054.     // Anything not matching the above is silently ignored!
  3055.     //
  3056. function GetTokens($s_str,$s_quotes = "'\"")
  3057. {
  3058.     $b_allow_strings = ($s_quotes !== "") ? true : false;
  3059.     $ii = 0;
  3060.     $i_len = strlen($s_str);
  3061.     $a_toks = array();
  3062.  
  3063.     while ($ii < $i_len)
  3064.     {
  3065.         switch ($ch = $s_str{$ii})
  3066.         {
  3067.         case " ":
  3068.         case "\t":
  3069.         case "\n":
  3070.         case "\r":
  3071.             $ii++;
  3072.             continue;
  3073.         }
  3074.             //
  3075.             // start of a token
  3076.             //
  3077.         $i_start = $ii;
  3078.         if ($ch == "_" || IsAlpha($ch))
  3079.         {
  3080.                 //
  3081.                 // a word
  3082.                 //
  3083.             $i_count = 1;
  3084.             while (++$ii < $i_len &&
  3085.                    ($s_str{$ii} == "_" || IsAlnum($s_str{$ii})))
  3086.                 ++$i_count;
  3087.             $a_toks[] = substr($s_str,$i_start,$i_count);
  3088.         }
  3089.         elseif (($ch == "." && $ii < ($i_len-1) && IsNumeric($s_str{$ii+1}))||
  3090.                 IsNumeric($ch))
  3091.         {
  3092.                 //
  3093.                 // a number
  3094.                 //
  3095.             $b_had_dot = ($ch == ".");
  3096.             $i_count = 1;
  3097.             while (++$ii < $i_len)
  3098.             {
  3099.                 if (IsNumeric($s_str{$ii}))
  3100.                     ++$i_count;
  3101.                 elseif ($s_str{$ii} == "." && !$b_had_dot)
  3102.                 {
  3103.                     ++$i_count;
  3104.                     $b_had_dot = true;
  3105.                 }
  3106.                 else
  3107.                     break;
  3108.             }
  3109.             $a_toks[] = substr($s_str,$i_start,$i_count);
  3110.         }
  3111.         elseif ($b_allow_strings && strpos($s_quotes,$ch) !== false)
  3112.         {
  3113.             $c_quote = $ch;
  3114.                 //
  3115.                 // a quoted string
  3116.                 //
  3117.             while (++$ii < $i_len)
  3118.             {
  3119.                 if ($s_str{$ii} == $c_quote)
  3120.                 {
  3121.                     ++$ii;  // include the terminating quote
  3122.                     break;
  3123.                 }
  3124.             }
  3125.             $a_toks[] = substr($s_str,$i_start,$ii-$i_start);
  3126.         }
  3127.         else
  3128.         {
  3129.             $s_punct = "~!@#$%^&*()-+={}[]|:;<>,.?/`\\";
  3130.             if (!$b_allow_strings)
  3131.                 $s_punct .= "'\"";
  3132.             if (strpos($s_punct,$ch) !== false)
  3133.                 $a_toks[] = $ch;
  3134.             ++$ii;
  3135.         }
  3136.     }
  3137.     return ($a_toks);
  3138. }
  3139.  
  3140.     //
  3141.     // Return the value from a derive_fields specification.
  3142.     // Specifications are in this format:
  3143.     //      %info%
  3144.     // where info is a predefined word or a literal in quotes
  3145.     // (e.g. 'the time is ')
  3146.     //
  3147. function ValueSpec($s_spec,$a_form_data,&$a_errors)
  3148. {
  3149.     global  $lNow;
  3150.  
  3151.     $s_value = "";
  3152.     switch (trim($s_spec))
  3153.     {
  3154.     case 'date':        // "standard" date format: DD-MMM-YYYY
  3155.         $s_value = date('d-M-Y',$lNow);
  3156.         break;
  3157.     case 'time':        // "standard" time format: HH:MM:SS
  3158.         $s_value = date('H:i:s',$lNow);
  3159.         break;
  3160.     case 'ampm':        // am or pm
  3161.         $s_value = date('a',$lNow);
  3162.         break;
  3163.     case 'AMPM':        // AM or PM
  3164.         $s_value = date('A',$lNow);
  3165.         break;
  3166.     case 'dom0':        // day of month with possible leading zero
  3167.         $s_value = date('d',$lNow);
  3168.         break;
  3169.     case 'dom':         // day of month with no leading zero
  3170.         $s_value = date('j',$lNow);
  3171.         break;
  3172.     case 'day':         // day name (abbreviated)
  3173.         $s_value = date('D',$lNow);
  3174.         break;
  3175.     case 'dayname':     // day name (full)
  3176.         $s_value = date('l',$lNow);
  3177.         break;
  3178.     case 'daysuffix':   // day number suffix for English (st for 1st, nd for 2nd, etc.)
  3179.         $s_value = date('S',$lNow);
  3180.         break;
  3181.     case 'moy0':        // month of year with possible leading zero
  3182.         $s_value = date('m',$lNow);
  3183.         break;
  3184.     case 'moy':         // month of year with no leading zero
  3185.         $s_value = date('n',$lNow);
  3186.         break;
  3187.     case 'month':       // month name (abbreviated)
  3188.         $s_value = date('M',$lNow);
  3189.         break;
  3190.     case 'monthname':   // month name (full)
  3191.         $s_value = date('F',$lNow);
  3192.         break;
  3193.     case 'year':        // year (two digits)
  3194.         $s_value = date('y',$lNow);
  3195.         break;
  3196.     case 'fullyear':    // year (full)
  3197.         $s_value = date('Y',$lNow);
  3198.         break;
  3199.     case 'rfcdate':     // date formatted according to RFC 822
  3200.         $s_value = date('r',$lNow);
  3201.         break;
  3202.     case 'tzname':      // timezone name
  3203.         $s_value = date('T',$lNow);
  3204.         break;
  3205.     case 'tz':          // timezone difference from Greenwich +NNNN or -NNNN
  3206.         $s_value = date('O',$lNow);
  3207.         break;
  3208.     case 'hour120':     // hour of day (01-12) with possible leading zero
  3209.         $s_value = date('h',$lNow);
  3210.         break;
  3211.     case 'hour240':     // hour of day (00-23) with possible leading zero
  3212.         $s_value = date('H',$lNow);
  3213.         break;
  3214.     case 'hour12':      // hour of day (1-12) with no leading zero
  3215.         $s_value = date('g',$lNow);
  3216.         break;
  3217.     case 'hour24':      // hour of day (0-23) with no leading zero
  3218.         $s_value = date('G',$lNow);
  3219.         break;
  3220.     case 'min':         // minute of hour (00-59)
  3221.         $s_value = date('i',$lNow);
  3222.         break;
  3223.     case 'sec':         // seconds of minute (00-59)
  3224.         $s_value = date('s',$lNow);
  3225.         break;
  3226.     default:
  3227.         if ($s_spec{0} == "'")
  3228.         {
  3229.                 //
  3230.                 // to get a quote, use 3 quotes:
  3231.                 //      '''
  3232.                 //
  3233.             if ($s_spec == "'''")
  3234.                 $s_value = "'";
  3235.             elseif (substr($s_spec,-1,1) == "'")
  3236.                 $s_value = substr($s_spec,1,-1);
  3237.             else
  3238.                     //
  3239.                     // missing final quote is OK
  3240.                     //
  3241.                 $s_value = substr($s_spec,1);
  3242.         }
  3243.         elseif (strspn($s_spec,"0123456789ABCDEF") == 2)
  3244.         {
  3245.                 //
  3246.                 // insert the ASCII character corresponding to
  3247.                 // the hexadecimal value
  3248.                 //
  3249.             $i_val = intval(substr($s_spec,0,2),16);
  3250.             $s_value = chr($i_val);
  3251.         }
  3252.         else
  3253.         {
  3254.                 //
  3255.                 // look for supported functions, start by getting all
  3256.                 // the tokens
  3257.                 //
  3258.             $a_toks = GetTokens($s_spec);
  3259.             if (count($a_toks) > 0)
  3260.             {
  3261.                 switch ($a_toks[0])
  3262.                 {
  3263.                 case "if":
  3264.                         //
  3265.                         // "if" function: test first field
  3266.                         //       if not empty, then use second field
  3267.                         //       else, use third field
  3268.                         //
  3269.                         // Example: if(fld1 ; fld2 ; fld3)
  3270.                         //
  3271.                         // tokens are:
  3272.                         //      1               (
  3273.                         //      2               the field name to test (first)
  3274.                         //      3               ;
  3275.                         //      4               the "then" spec (can be missing)
  3276.                         //      5               ;
  3277.                         //      6               the "else" spec (can be missing)
  3278.                         //      7               )
  3279.                         //
  3280.                     if (($n_tok = count($a_toks)) < 6 ||
  3281.                             $a_toks[1] != "(" ||
  3282.                             $a_toks[3] != ";" ||
  3283.                             $a_toks[$n_tok-1] != ")")
  3284.                         SendAlert(GetMessage(MSG_DER_FUNC_ERROR,
  3285.                                         array("SPEC"=>$s_spec,
  3286.                                               "MSG"=>GetMessage(MSG_DER_FUNC_IF_FMT))));
  3287.                     else
  3288.                     {
  3289.                         $b_ok = true;
  3290.                         $s_fld_name = $a_toks[2];
  3291.                         $s_then_spec = $s_else_spec = "";
  3292.                         for ($ii = 4 ; $ii < $n_tok && $a_toks[$ii] != ';' ; $ii++)
  3293.                             $s_then_spec .= $a_toks[$ii];
  3294.                         if ($ii == $n_tok)
  3295.                             $b_ok = false;
  3296.                         else
  3297.                         {
  3298.                                 //
  3299.                                 // Concatenate tokens until the ')'.
  3300.                                 // This provides the "else" spec.
  3301.                                 //
  3302.                             for ( ; ++$ii < $n_tok && $a_toks[$ii] != ')' ; )
  3303.                                 $s_else_spec .= $a_toks[$ii];
  3304.                             if ($ii == $n_tok)
  3305.                                 $b_ok = false;
  3306.                         }
  3307.                         if ($b_ok)
  3308.                         {
  3309.                             if (!TestFieldEmpty($s_fld_name,$a_form_data,$s_mesg))
  3310.                                 $s_fld_spec = $s_then_spec;
  3311.                             else
  3312.                                 $s_fld_spec = $s_else_spec;
  3313.                             $s_value = GetDerivedValue($a_form_data,$s_fld_spec);
  3314.                         }
  3315.                         else
  3316.                             SendAlert(GetMessage(MSG_DER_FUNC_ERROR,
  3317.                                             array("SPEC"=>$s_spec,
  3318.                                                   "MSG"=>GetMessage(MSG_DER_FUNC_IF_FMT))));
  3319.                     }
  3320.                     break;
  3321.                 case "size":
  3322.                         //
  3323.                         // "size" function: return size of uploaded file
  3324.                         //
  3325.                         // Example: size(fieldname)
  3326.                         //
  3327.                         // tokens are:
  3328.                         //      1               (
  3329.                         //      2               the field name for the file upload
  3330.                         //      3               )
  3331.                         //
  3332.                     if (count($a_toks) != 4 ||
  3333.                             $a_toks[1] != "(" ||
  3334.                             $a_toks[3] != ")")
  3335.                         SendAlert(GetMessage(MSG_DER_FUNC_ERROR,
  3336.                                         array("SPEC"=>$s_spec,
  3337.                                               "MSG"=>GetMessage(MSG_DER_FUNC_SIZE_FMT))));
  3338.                     elseif (($i_size = GetFileSize($a_toks[2])) !== false)
  3339.                         $s_value = "$i_size";
  3340.                     break;
  3341.                 case "ext":
  3342.                         //
  3343.                         // "ext" function: return filename extension of uploaded file
  3344.                         //
  3345.                         // Example: ext(fieldname)
  3346.                         //
  3347.                         // tokens are:
  3348.                         //      1               (
  3349.                         //      2               the field name for the file upload
  3350.                         //      3               )
  3351.                         //
  3352.                     if (count($a_toks) != 4 ||
  3353.                             $a_toks[1] != "(" ||
  3354.                             $a_toks[3] != ")")
  3355.                         SendAlert(GetMessage(MSG_DER_FUNC_ERROR,
  3356.                                         array("SPEC"=>$s_spec,
  3357.                                               "MSG"=>GetMessage(MSG_DER_FUNC_EXT_FMT))));
  3358.                     elseif (($s_name = GetFileName($a_toks[2])) !== false)
  3359.                     {
  3360.                         if (($i_pos = strrpos($s_name,".")) !== false)
  3361.                             $s_value = substr($s_name,$i_pos+1);
  3362.                     }
  3363.                     break;
  3364.                 case "ucase":
  3365.                 case "lcase":
  3366.                         //
  3367.                         // "ucase" and "lcase" functions: return field
  3368.                         // converted to upper or lower case
  3369.                         //
  3370.                         // Example: lcase(fieldname)
  3371.                         //
  3372.                         // tokens are:
  3373.                         //      1               (
  3374.                         //      2               the field name to convert
  3375.                         //      3               )
  3376.                         //
  3377.                     if (count($a_toks) != 4 ||
  3378.                             $a_toks[1] != "(" ||
  3379.                             $a_toks[3] != ")")
  3380.                         SendAlert(GetMessage(MSG_DER_FUNC_ERROR,
  3381.                                         array("SPEC"=>$s_spec,
  3382.                                               "MSG"=>GetMessage(MSG_DER_FUNC1_FMT,
  3383.                                                     array("FUNC"=>$a_toks[0])))));
  3384.                     elseif ($a_toks[0] == "ucase")
  3385.                         $s_value = strtoupper(GetFieldValue($a_toks[2],$a_form_data));
  3386.                     else
  3387.                         $s_value = strtolower(GetFieldValue($a_toks[2],$a_form_data));
  3388.                     break;
  3389.                 case "ltrim":
  3390.                 case "rtrim":
  3391.                 case "trim":
  3392.                         //
  3393.                         // trim functions: return field with whitespace removed
  3394.                         // from left (ltrim), right (rtrim), or both (trim)
  3395.                         // ends.
  3396.                         //
  3397.                         // Example: ltrim(fieldname)
  3398.                         //
  3399.                         // tokens are:
  3400.                         //      1               (
  3401.                         //      2               the field name to trim
  3402.                         //      3               )
  3403.                         //
  3404.                     if (count($a_toks) != 4 ||
  3405.                             $a_toks[1] != "(" ||
  3406.                             $a_toks[3] != ")")
  3407.                         SendAlert(GetMessage(MSG_DER_FUNC_ERROR,
  3408.                                         array("SPEC"=>$s_spec,
  3409.                                               "MSG"=>GetMessage(MSG_DER_FUNC1_FMT,
  3410.                                               array("FUNC"=>$a_toks[0])))));
  3411.                     else
  3412.                         $s_value = $a_toks[0](GetFieldValue($a_toks[2],$a_form_data));
  3413.                     break;
  3414.                 case "ltrim0":
  3415.                         //
  3416.                         // ltrim0 function: return field with blanks and
  3417.                         // leading 0's removed from the left.
  3418.                         //
  3419.                         // Example: ltrim0(fieldname)
  3420.                         //
  3421.                         // tokens are:
  3422.                         //      1               (
  3423.                         //      2               the field name to trim
  3424.                         //      3               )
  3425.                         //
  3426.                     if (count($a_toks) != 4 ||
  3427.                             $a_toks[1] != "(" ||
  3428.                             $a_toks[3] != ")")
  3429.                         SendAlert(GetMessage(MSG_DER_FUNC_ERROR,
  3430.                                         array("SPEC"=>$s_spec,
  3431.                                               "MSG"=>GetMessage(MSG_DER_FUNC1_FMT,
  3432.                                               array("FUNC"=>$a_toks[0])))));
  3433.                     else
  3434.                     {
  3435.                         $s_value = GetFieldValue($a_toks[2],$a_form_data);
  3436.                         $s_value = ltrim($s_value);     // trim blanks on left
  3437.                         $i_len = strspn($s_value,"0");
  3438.                             //
  3439.                             // if the whole string is zeroes, make sure we leave
  3440.                             // one of them!
  3441.                             //
  3442.                         if ($i_len == strlen($s_value))
  3443.                             if (--$i_len < 0)
  3444.                                 $i_len = 0;
  3445.                         $s_value = substr($s_value,$i_len);
  3446.                     }
  3447.                     break;
  3448.                 case "nextnum":
  3449.                         //
  3450.                         // "nextnum" function: return a unique number (next number)
  3451.                         //
  3452.                         // Usage: nextnum[(pad[,base])]
  3453.                         //
  3454.                         // Examples:
  3455.                         //      %nextnum%
  3456.                         //      %nextnum(8)%
  3457.                         //      %nextnum(5;16)%
  3458.                         //
  3459.                         // You can provide a padding amount. In this case, the
  3460.                         // number is padded on the left with zeroes to the number
  3461.                         // of digits specified.
  3462.                         //
  3463.                         // You can also provide a base for your numbers.  Valid
  3464.                         // values for base are 2 to 36, inclusive.
  3465.                         //
  3466.                         // tokens are:
  3467.                         //      1               (
  3468.                         //      2               the padding amount
  3469.                         //      3               ;
  3470.                         //      4               the base
  3471.                         //      5               )
  3472.                         //
  3473.                     $i_pad = 0;     // no padding
  3474.                     $i_base = 10;   // base 10
  3475.                     if (($n_tok = count($a_toks)) > 1)
  3476.                     {
  3477.                         if (($n_tok != 4 && $n_tok != 6) ||
  3478.                             $a_toks[1] != "(" ||
  3479.                             $a_toks[$n_tok-1] != ")")
  3480.                             SendAlert(GetMessage(MSG_DER_FUNC_ERROR,
  3481.                                         array("SPEC"=>$s_spec,
  3482.                                               "MSG"=>GetMessage(MSG_DER_FUNC_NEXTNUM_FMT)." (T1)")));
  3483.                         if ($n_tok == 6 && $a_toks[3] != ";")
  3484.                             SendAlert(GetMessage(MSG_DER_FUNC_ERROR,
  3485.                                         array("SPEC"=>$s_spec,
  3486.                                               "MSG"=>GetMessage(MSG_DER_FUNC_NEXTNUM_FMT)." (T2)")));
  3487.                         if (!is_numeric($a_toks[2]) ||
  3488.                             ($n_tok == 6 && !is_numeric($a_toks[4])))
  3489.                             SendAlert(GetMessage(MSG_DER_FUNC_ERROR,
  3490.                                         array("SPEC"=>$s_spec,
  3491.                                               "MSG"=>GetMessage(MSG_DER_FUNC_NEXTNUM_FMT)." (T3)")));
  3492.                         $i_pad = intval($a_toks[2]);
  3493.                         if ($n_tok == 6)
  3494.                         {
  3495.                             $i_base = intval($a_toks[4]);
  3496.                             if ($i_base < 2 || $i_base > 36)
  3497.                             {
  3498.                                 SendAlert(GetMessage(MSG_DER_FUNC_ERROR,
  3499.                                             array("SPEC"=>$s_spec,
  3500.                                                   "MSG"=>GetMessage(MSG_DER_FUNC_NEXTNUM_FMT)." (T4)")));
  3501.                                 $i_base = 10;
  3502.                             }
  3503.                         }
  3504.                         $s_value = GetNextNum($i_pad,$i_base);
  3505.                     }
  3506.                     else
  3507.                     {
  3508.                         $s_value = GetNextNum($i_pad,$i_base);
  3509.                     }
  3510.                     break;
  3511.                 default:
  3512.                     SendAlert(GetMessage(MSG_UNK_VALUE_SPEC,
  3513.                                     array("SPEC"=>$s_spec,"MSG"=>"")));
  3514.                     break;
  3515.                 }
  3516.             }
  3517.             else
  3518.                 SendAlert(GetMessage(MSG_UNK_VALUE_SPEC,array("SPEC"=>$s_spec,
  3519.                                                             "MSG"=>"")));
  3520.         }
  3521.         break;
  3522.     }
  3523.     return ($s_value);
  3524. }
  3525.  
  3526.     //
  3527.     // Return the next number or fail on error
  3528.     //
  3529. function GetNextNum($i_pad,$i_base)
  3530. {
  3531.     global  $NEXT_NUM_FILE,$php_errormsg;
  3532.  
  3533.     if (!isset($NEXT_NUM_FILE) || $NEXT_NUM_FILE === "")
  3534.     {
  3535.         ErrorWithIgnore("next_num_config",GetMessage(MSG_NO_NEXT_NUM_FILE));
  3536.         exit;
  3537.     }
  3538.     if (($fp = @fopen($NEXT_NUM_FILE,"r+")) === false)
  3539.     {
  3540.         Error("next_num_file",GetMessage(MSG_NEXT_NUM_FILE,
  3541.                                     array("FILE"=>$NEXT_NUM_FILE,
  3542.                                         "ACT"=>"open",
  3543.                                         "ERR"=>$php_errormsg)));
  3544.         exit;
  3545.     }
  3546.     if (!flock($fp,defined("LOCK_EX") ? LOCK_EX : 2))
  3547.     {
  3548.         Error("next_num_file",GetMessage(MSG_NEXT_NUM_FILE,
  3549.                                     array("FILE"=>$NEXT_NUM_FILE,
  3550.                                         "ACT"=>"flock",
  3551.                                         "ERR"=>$php_errormsg)));
  3552.         exit;
  3553.     }
  3554.         //
  3555.         // read the first line only
  3556.         //
  3557.     if (!feof($fp))
  3558.     {
  3559.         if (($s_line = fread($fp,1024)) === false)
  3560.             $i_next = 1;
  3561.         elseif (($i_next = intval($s_line)) <= 0)
  3562.             $i_next = 1;
  3563.     }
  3564.     else
  3565.         $i_next = 1;
  3566.     if (rewind($fp) == 0)
  3567.     {
  3568.         Error("next_num_file",GetMessage(MSG_NEXT_NUM_FILE,
  3569.                                     array("FILE"=>$NEXT_NUM_FILE,
  3570.                                         "ACT"=>"rewind",
  3571.                                         "ERR"=>$php_errormsg)));
  3572.         exit;
  3573.     }
  3574.     $s_ret = strval($i_next++);
  3575.     if (fputs($fp,"$i_next\r\n") <= 0)
  3576.     {
  3577.         Error("next_num_file",GetMessage(MSG_NEXT_NUM_FILE,
  3578.                                     array("FILE"=>$NEXT_NUM_FILE,
  3579.                                         "ACT"=>"fputs",
  3580.                                         "ERR"=>$php_errormsg)));
  3581.         exit;
  3582.     }
  3583.     fclose($fp);
  3584.     if ($i_base != 10)
  3585.     {
  3586.         $s_ret = base_convert($s_ret,10,$i_base);
  3587.         $s_ret = strtoupper($s_ret);    // always upper case if alphas are used
  3588.     }
  3589.     if ($i_pad != 0)
  3590.         $s_ret = str_pad($s_ret,$i_pad,"0",STR_PAD_LEFT);
  3591.     return ($s_ret);
  3592. }
  3593.  
  3594.     //
  3595.     // Return the value of an object or array as a string.
  3596.     //
  3597. function GetObjectAsString($m_value)
  3598. {
  3599.     ob_start();
  3600.     print_r($m_value);
  3601.     $s_ret = ob_get_contents();
  3602.     ob_end_clean();
  3603.     return ($s_ret);
  3604. }
  3605.  
  3606.     //
  3607.     // Return a Server or Environment variable value.  Returns false if
  3608.     // not found, otherwise a string value.
  3609.     //
  3610. function GetEnvValue($s_name)
  3611. {
  3612.     global  $aServerVars,$aEnvVars;
  3613.  
  3614.     if (isset($aEnvVars[$s_name]))
  3615.         $m_value = $aEnvVars[$s_name];
  3616.     elseif (isset($aServerVars[$s_name]))
  3617.         $m_value = $aServerVars[$s_name];
  3618.         //
  3619.         // some values might not be strings - so convert
  3620.         //
  3621.     if (isset($m_value) && !is_scalar($m_value))
  3622.         $m_value = GetObjectAsString($m_value);
  3623.     return (isset($m_value) ? ((string) $m_value) : false);
  3624. }
  3625.  
  3626.     //
  3627.     // Same as "empty" but checks for true emptiness if ZERO_IS_EMPTY is
  3628.     // set to false.
  3629.     //
  3630. function IsFieldEmpty($s_value)
  3631. {
  3632.     if (ZERO_IS_EMPTY || is_array($s_value))
  3633.         return (empty($s_value));
  3634.     else
  3635.         return ($s_value === "");
  3636. }
  3637.  
  3638.     //
  3639.     // Test if a field is set in the given vars array or in the uploaded
  3640.     // files.
  3641.     //
  3642. function IsFieldSet($s_fld,$a_main_vars)
  3643. {
  3644.     global  $aFileVars,$aSessionVars;
  3645.  
  3646.     return (isset($a_main_vars[$s_fld]) ||
  3647.             (FILEUPLOADS &&
  3648.                 (isset($aFileVars[$s_fld]) ||
  3649.                     (isset($aSessionVars["FormSavedFiles"]) &&
  3650.                         isset($aSessionVars["FormSavedFiles"][$s_fld]))
  3651.                 )
  3652.             ));
  3653. }
  3654.  
  3655.     //
  3656.     // Delete the info for an uploaded file
  3657.     //
  3658. function DeleteFileInfo($s_fld)
  3659. {
  3660.     global  $aFileVars,$aSessionVars;
  3661.     global  $aCleanedValues,$aRawDataValues,$aAllRawValues;
  3662.  
  3663.     if (FILEUPLOADS)
  3664.     {
  3665.         if (isset($aSessionVars["FormSavedFiles"]) &&
  3666.                 isset($aSessionVars["FormSavedFiles"][$s_fld]))
  3667.             unset($aSessionVars["FormSavedFiles"][$s_fld]);
  3668.         if (isset($aFileVars[$s_fld]))
  3669.             unset($aFileVars[$s_fld]);
  3670.             //
  3671.             // zap any "name_of" field that has been created
  3672.             //
  3673.         $s_name = "name_of_$s_fld";
  3674.         unset($aCleanedValues[$s_name]);
  3675.         unset($aRawDataValues[$s_name]);
  3676.         unset($aAllRawValues[$s_name]);
  3677.     }
  3678. }
  3679.  
  3680.     //
  3681.     // Return the info for the uploaded file, or false on error.
  3682.     //
  3683. function GetFileInfo($s_fld)
  3684. {
  3685.     global  $aFileVars,$aSessionVars;
  3686.  
  3687.     if (FILEUPLOADS)
  3688.     {
  3689.             //
  3690.             // Must look at new file uploads first.
  3691.             //
  3692.         if (isset($aFileVars[$s_fld]) && !empty($aFileVars[$s_fld]))
  3693.             $a_upload = $aFileVars[$s_fld];
  3694.         elseif (isset($aSessionVars["FormSavedFiles"]) &&
  3695.                 isset($aSessionVars["FormSavedFiles"][$s_fld]))
  3696.             $a_upload = $aSessionVars["FormSavedFiles"][$s_fld];
  3697.     }
  3698.     if (isset($a_upload))
  3699.     {
  3700.         if (isset($a_upload["tmp_name"]) && !empty($a_upload["tmp_name"]) &&
  3701.             isset($a_upload["name"]) && !empty($a_upload["name"]) &&
  3702.             IsUploadedFile($a_upload))
  3703.                 return ($a_upload);
  3704.     }
  3705.     return (false);
  3706. }
  3707.  
  3708.     //
  3709.     // Return the original name of the uploaded file or false on error.
  3710.     //
  3711. function GetFileName($s_fld)
  3712. {
  3713.     if (($a_upload = GetFileInfo($s_fld)) !== false)
  3714.         return ($a_upload["name"]);
  3715.     return (false);
  3716. }
  3717.  
  3718.     //
  3719.     // Return the size of the uploaded file or false on error.
  3720.     //
  3721. function GetFileSize($s_fld)
  3722. {
  3723.     if (($a_upload = GetFileInfo($s_fld)) !== false)
  3724.         return ($a_upload["size"]);
  3725.     return (false);
  3726. }
  3727.  
  3728.     //
  3729.     // Return a field value.  Empty string is returned if the field is
  3730.     // not found. File fields return the original name of the uploaded file.
  3731.     //
  3732. function GetFieldValue($s_fld,$a_main_vars)
  3733. {
  3734.     if (!isset($a_main_vars[$s_fld]))
  3735.     {
  3736.         if (($s_name = GetFileName($s_fld)) === false)
  3737.             $s_name = "";
  3738.         return ($s_name);
  3739.     }
  3740.     return ((string) $a_main_vars[$s_fld]);
  3741. }
  3742.  
  3743.     //
  3744.     // Tests a field against an array of vars for emptyness.
  3745.     // If the var isn't found there, then the POSTed files array is checked.
  3746.     // Returns true if the field is empty (a specific error may
  3747.     // be returned in the $s_mesg parameter).
  3748.     //
  3749. function TestFieldEmpty($s_fld,$a_main_vars,&$s_mesg)
  3750. {
  3751.     global  $aFileVars,$aSessionVars;
  3752.  
  3753.     $s_mesg = "";
  3754.     $b_empty = TRUE;
  3755.     if (!isset($a_main_vars[$s_fld]))
  3756.     {
  3757.             //
  3758.             // Each file var is an array with these elements:
  3759.             //      "name" => The original name of the file on the client machine.
  3760.             //      "type" => The mime type of the file, if the browser provided this information.
  3761.             //      "tmp_name" => The temporary filename of the file in which the uploaded file was stored on the server.
  3762.             //      "error" => The error code associated with this file upload.
  3763.             //                  NOTE: "error" was added in PHP 4.2.0
  3764.             //      "size" => The size, in bytes, of the uploaded file.
  3765.             //
  3766.             // Error codes (the constants are only available from PHP 4.3.0 so
  3767.             // we have to use the raw numbers):
  3768.             //  UPLOAD_ERR_OK
  3769.             //      Value: 0; There is no error, the file uploaded with success.
  3770.             //  UPLOAD_ERR_INI_SIZE
  3771.             //      Value: 1; The uploaded file exceeds the upload_max_filesize directive in php.ini.
  3772.             //  UPLOAD_ERR_FORM_SIZE
  3773.             //      Value: 2; The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the html form.
  3774.             //  UPLOAD_ERR_PARTIAL
  3775.             //      Value: 3; The uploaded file was only partially uploaded.
  3776.             //  UPLOAD_ERR_NO_FILE
  3777.             //      Value: 4; No file was uploaded.
  3778.             //
  3779.         if (FILEUPLOADS)
  3780.         {
  3781.             if (isset($aSessionVars["FormSavedFiles"]) &&
  3782.                     isset($aSessionVars["FormSavedFiles"][$s_fld]))
  3783.                 $a_upload = $aSessionVars["FormSavedFiles"][$s_fld];
  3784.             elseif (isset($aFileVars[$s_fld]))
  3785.                 $a_upload = $aFileVars[$s_fld];
  3786.         }
  3787.         if (isset($a_upload))
  3788.         {
  3789.             if (isset($a_upload["tmp_name"]) && !empty($a_upload["tmp_name"]) &&
  3790.                 isset($a_upload["name"]) && !empty($a_upload["name"]))
  3791.             {
  3792.                 if (IsUploadedFile($a_upload))
  3793.                     $b_empty = false;
  3794.             }
  3795.             if ($b_empty && isset($a_upload["error"]))
  3796.                 switch ($a_upload["error"])
  3797.                 {
  3798.                 case 1:
  3799.                     $s_mesg = GetMessage(MSG_FILE_UPLOAD_ERR1);
  3800.                     break;
  3801.                 case 2:
  3802.                     $s_mesg = GetMessage(MSG_FILE_UPLOAD_ERR2);
  3803.                     break;
  3804.                 case 3:
  3805.                     $s_mesg = GetMessage(MSG_FILE_UPLOAD_ERR3);
  3806.                     break;
  3807.                 case 4:
  3808.                     $s_mesg = GetMessage(MSG_FILE_UPLOAD_ERR4);
  3809.                     break;
  3810.                 case 6:
  3811.                     $s_mesg = GetMessage(MSG_FILE_UPLOAD_ERR6);
  3812.                     break;
  3813.                 case 7:
  3814.                     $s_mesg = GetMessage(MSG_FILE_UPLOAD_ERR7);
  3815.                     break;
  3816.                 case 8:
  3817.                     $s_mesg = GetMessage(MSG_FILE_UPLOAD_ERR8);
  3818.                     break;
  3819.                 default:
  3820.                     $s_mesg = GetMessage(MSG_FILE_UPLOAD_ERR_UNK,
  3821.                                     array("ERRNO"=>$a_upload["error"]));
  3822.                     break;
  3823.                 }
  3824.         }
  3825.     }
  3826.     else
  3827.         $b_empty = IsFieldEmpty($a_main_vars[$s_fld]);
  3828.     return ($b_empty);
  3829. }
  3830.  
  3831.     //
  3832.     // Return a derived field value or value specification.
  3833.     //
  3834. function GetDerivedValue($a_form_data,$s_word,&$a_errors)
  3835. {
  3836.     $s_value = "";
  3837.         //
  3838.         // a field name or a value specification
  3839.         // value specifications have the following format:
  3840.         //      %spec%
  3841.         //
  3842.     if (substr($s_word,0,1) == '%')
  3843.     {
  3844.         if (substr($s_word,-1,1) != '%')
  3845.         {
  3846.             SendAlert(GetMessage(MSG_INV_VALUE_SPEC,array("SPEC"=>$s_word)));
  3847.             $s_value = $s_word;
  3848.         }
  3849.         else
  3850.         {
  3851.             $s_spec = substr($s_word,1,-1);
  3852.             $s_value = ValueSpec($s_spec,$a_form_data,$a_errors);
  3853.         }
  3854.     }
  3855.     else
  3856.     {
  3857.         $s_fld_name = $s_word;
  3858.             //
  3859.             // try form data first, then the environment/server data
  3860.             //
  3861.         if (IsFieldSet($s_fld_name,$a_form_data))
  3862.             $s_value = GetFieldValue($s_fld_name,$a_form_data);
  3863.         elseif (($s_value = GetEnvValue($s_fld_name)) === false)
  3864.             $s_value = "";
  3865.         $s_value = trim($s_value);
  3866.     }
  3867.     return ($s_value);
  3868. }
  3869.  
  3870.     //
  3871.     // Derive a value from the form data using the specification returned
  3872.     // from ParseDerivation.
  3873.     //
  3874. function DeriveValue($a_form_data,$a_value_spec,$s_name,&$a_errors)
  3875. {
  3876.     $s_value = "";
  3877.     for ($ii = 0 ; $ii < count($a_value_spec) ; $ii++)
  3878.     {
  3879.         switch ($a_value_spec[$ii])
  3880.         {
  3881.         case '+':
  3882.                 //
  3883.                 // concatenate with a single space between, but skip the space
  3884.                 // if the next field is empty
  3885.                 //
  3886.             if ($ii < count($a_value_spec)-1)
  3887.             {
  3888.                 $s_temp = GetDerivedValue($a_form_data,$a_value_spec[$ii+1],$a_errors);
  3889.                 if (!IsFieldEmpty($s_temp))
  3890.                     $s_value .= ' ';
  3891.             }
  3892.             break;
  3893.         case '.':
  3894.                 //
  3895.                 // concatenate with no space between
  3896.                 //
  3897.             break;
  3898.         case '*':
  3899.                 //
  3900.                 // concatenate with a single space between
  3901.                 //
  3902.             $s_value .= ' ';
  3903.             break;
  3904.         default:
  3905.                 //
  3906.                 // a field name or a value specification
  3907.                 // value specifications have the following format:
  3908.                 //      %name%
  3909.                 //
  3910.             $s_value .= GetDerivedValue($a_form_data,$a_value_spec[$ii],$a_errors);
  3911.             break;
  3912.         }
  3913.     }
  3914.     return ($s_value);
  3915. }
  3916.  
  3917.     //
  3918.     // Create derived fields specified by the "derive_fields" value.
  3919.     //
  3920. function CreateDerived($a_form_data)
  3921. {
  3922.     if (isset($a_form_data["derive_fields"]))
  3923.     {
  3924.         $a_errors = array();
  3925.             //
  3926.             // get the list of derived field specifications
  3927.             //
  3928.         $a_list = TrimArray(explode(",",$a_form_data["derive_fields"]));
  3929.         foreach ($a_list as $s_fld_spec)
  3930.         {
  3931.             if ($s_fld_spec === "")
  3932.                     //
  3933.                     // silently ignore empty derivations
  3934.                     //
  3935.                 continue;
  3936.             if (($i_pos = strpos($s_fld_spec,"=")) === false)
  3937.             {
  3938.                 $a_errors[] = $s_fld_spec;
  3939.                 continue;
  3940.             }
  3941.             $s_name = trim(substr($s_fld_spec,0,$i_pos));
  3942.             $s_fld_spec = substr($s_fld_spec,$i_pos+1);
  3943.  
  3944.             if (($a_value_spec = ParseDerivation($a_form_data,$s_fld_spec,
  3945.                                                 $s_name,$a_errors)) === false)
  3946.                 break;
  3947.             $a_form_data[$s_name] = DeriveValue($a_form_data,$a_value_spec,$s_name,$a_errors);
  3948.         }
  3949.         if (count($a_errors) > 0)
  3950.         {
  3951.             SendAlert(GetMessage(MSG_DERIVED_INVALID).implode("\n",$a_errors));
  3952.             Error("derivation_failure",GetMessage(MSG_INT_FORM_ERROR));
  3953.         }
  3954.     }
  3955.     return ($a_form_data);
  3956. }
  3957.  
  3958.     //
  3959.     // To process the name specification for files and update the
  3960.     // array of file variables accordingly.
  3961.     //
  3962. function SetFileNames($s_name_spec,$a_order,$a_fields,$a_raw_fields,$a_all_raw_values,$a_file_vars)
  3963. {
  3964.     $a_errors = array();
  3965.         //
  3966.         // get the list of file name derivations
  3967.         //
  3968.     $a_list = TrimArray(explode(",",$s_name_spec));
  3969.     foreach ($a_list as $s_fld_spec)
  3970.     {
  3971.         if ($s_fld_spec === "")
  3972.                 //
  3973.                 // silently ignore empty file name derivations
  3974.                 //
  3975.             continue;
  3976.         if (($i_pos = strpos($s_fld_spec,"=")) === false)
  3977.         {
  3978.             $a_errors[] = $s_fld_spec;
  3979.             continue;
  3980.         }
  3981.         $s_name = trim(substr($s_fld_spec,0,$i_pos));
  3982.         $s_fld_spec = substr($s_fld_spec,$i_pos+1);
  3983.  
  3984.         if (($a_value_spec = ParseDerivation($a_raw_fields,$s_fld_spec,
  3985.                                             $s_name,$a_errors)) === false)
  3986.             break;
  3987.         if (isset($a_file_vars[$s_name]) && is_array($a_file_vars[$s_name]))
  3988.         {
  3989.                 //
  3990.                 // we create our own special entry in the file variable's data
  3991.                 //
  3992.             $a_file_vars[$s_name]["new_name"] = DeriveValue($a_raw_fields,
  3993.                                                         $a_value_spec,$s_name,
  3994.                                                         $a_errors);
  3995.                 //
  3996.                 // we also create (derive) a new field called 'name_of_X'
  3997.                 // where X is the file fields's name
  3998.                 //
  3999.             ProcessField("name_of_$s_name",$a_file_vars[$s_name]["new_name"],
  4000.                         $a_order,$a_fields,$a_raw_fields);
  4001.             $a_all_raw_values["name_of_$s_name"] = $a_file_vars[$s_name]["new_name"];
  4002.         }
  4003.         /* This is annoying if a file upload is optional.  Just ignore missing
  4004.             file upload fields.
  4005.         else
  4006.             SendAlert(GetMessage(MSG_FILE_NAMES_NOT_FILE,
  4007.                                             array("NAME"=>$s_name)));*/
  4008.     }
  4009.     if (count($a_errors) > 0)
  4010.     {
  4011.         SendAlert(GetMessage(MSG_FILE_NAMES_INVALID).implode("\n",$a_errors));
  4012.         Error("file_names_derivation_failure",GetMessage(MSG_INT_FORM_ERROR));
  4013.     }
  4014.     return (array($a_order,$a_fields,$a_raw_fields,$a_all_raw_values,$a_file_vars));
  4015. }
  4016.  
  4017.     //
  4018.     // Process a list of attributes or options.
  4019.     // Format for each attribute/option:
  4020.     //      name
  4021.     // or
  4022.     //      name=value
  4023.     //
  4024.     // Values can be simple values or semicolon (;) separated lists:
  4025.     //          avalue
  4026.     //          value1;value2;value3;...
  4027.     //
  4028.     // Returns attribute/options in the associative array $a_attribs.
  4029.     // Optionally, valid attributes can be provided in $a_valid_attribs
  4030.     // (if empty, all attributes found are considered valid).
  4031.     // Errors are returned in $a_errors.
  4032.     //
  4033. function ProcessAttributeList($a_list,&$a_attribs,&$a_errors,
  4034.                         $a_valid_attribs = array())
  4035. {
  4036.     $b_got_valid_list = (count($a_valid_attribs) > 0);
  4037.     foreach ($a_list as $s_attrib)
  4038.     {
  4039.             //
  4040.             // if the name begins with '.' then silently ignore it;
  4041.             // this allows you to temporarily disable an option without
  4042.             // getting an alert message
  4043.             //
  4044.         if (($i_pos = strpos($s_attrib,"=")) === false)
  4045.         {
  4046.             $s_name = trim($s_attrib);
  4047.             if (empty($s_name) || $s_name{0} == '.')
  4048.                 continue;
  4049.                 //
  4050.                 // option is a simple "present" value
  4051.                 //
  4052.             $a_attribs[$s_name] = true;
  4053.         }
  4054.         else
  4055.         {
  4056.             $s_name = trim(substr($s_attrib,0,$i_pos));
  4057.             if (empty($s_name) || $s_name{0} == '.')
  4058.                 continue;
  4059.             $s_value_list = substr($s_attrib,$i_pos+1);
  4060.             if (($i_pos = strpos($s_value_list,";")) === false)
  4061.                     //
  4062.                     // single value
  4063.                     //
  4064.                 $a_attribs[$s_name] = trim($s_value_list);
  4065.             else
  4066.                     //
  4067.                     // list of values
  4068.                     //
  4069.                 $a_attribs[$s_name] = TrimArray(explode(";",$s_value_list));
  4070.         }
  4071.         if ($b_got_valid_list && !isset($a_valid_attribs[$s_name]))
  4072.             $a_errors[] = $s_name;
  4073.     }
  4074. }
  4075.  
  4076.     //
  4077.     // Process the options specified in the form.
  4078.     // Options can be specified in this format:
  4079.     //          option1,option2,option3,...
  4080.     // Each option can be a simple word or a word and value:
  4081.     //          name
  4082.     //          name=value
  4083.     // No name or value can contain a comma.
  4084.     // Values can be simple values or semicolon (;) separated lists:
  4085.     //          avalue
  4086.     //          value1;value2;value3;...
  4087.     // No value can contain a semicolon.
  4088.     // Be careful of values beginning and ending with whitespace characters;
  4089.     // they will be trimmed.
  4090.     //
  4091. function ProcessOptions($s_name,$a_form_data,&$a_options,$a_valid_options)
  4092. {
  4093.     $a_errors = array();
  4094.     $a_options = array();
  4095.     if (isset($a_form_data[$s_name]))
  4096.     {
  4097.             //
  4098.             // get the options list and trim each one
  4099.             //
  4100.         $a_list = TrimArray(explode(",",$a_form_data[$s_name]));
  4101.         ProcessAttributeList($a_list,$a_options,$a_errors,$a_valid_options);
  4102.     }
  4103.     if (count($a_errors) > 0)
  4104.         SendAlert(GetMessage(MSG_OPTIONS_INVALID,array("OPT"=>$s_name)).
  4105.                     implode("\n",$a_errors));
  4106. }
  4107.  
  4108.     //
  4109.     // Process the mail_options specified in the form.
  4110.     //
  4111. function ProcessMailOptions($a_form_data)
  4112. {
  4113.     global  $MAIL_OPTS,$VALID_MAIL_OPTIONS;
  4114.  
  4115.     ProcessOptions("mail_options",$a_form_data,$MAIL_OPTS,$VALID_MAIL_OPTIONS);
  4116. }
  4117.  
  4118.     //
  4119.     // Check if an option is set
  4120.     //
  4121. function IsMailOptionSet($s_name)
  4122. {
  4123.     global  $MAIL_OPTS;
  4124.  
  4125.     return (isset($MAIL_OPTS[$s_name]));
  4126. }
  4127.  
  4128.     //
  4129.     // Return an option's value or NULL if not set.
  4130.     //
  4131. function GetMailOption($s_name)
  4132. {
  4133.     global  $MAIL_OPTS;
  4134.  
  4135.     return (isset($MAIL_OPTS[$s_name]) ? $MAIL_OPTS[$s_name] : NULL);
  4136. }
  4137.  
  4138.     //
  4139.     // Process the crm_options specified in the form.
  4140.     //
  4141. function ProcessCRMOptions($a_form_data)
  4142. {
  4143.     global  $CRM_OPTS,$VALID_CRM_OPTIONS;
  4144.  
  4145.     ProcessOptions("crm_options",$a_form_data,$CRM_OPTS,$VALID_CRM_OPTIONS);
  4146. }
  4147.  
  4148.     //
  4149.     // Check if an option is set
  4150.     //
  4151. function IsCRMOptionSet($s_name)
  4152. {
  4153.     global  $CRM_OPTS;
  4154.  
  4155.     return (isset($CRM_OPTS[$s_name]));
  4156. }
  4157.  
  4158.     //
  4159.     // Return an option's value or NULL if not set.
  4160.     //
  4161. function GetCRMOption($s_name)
  4162. {
  4163.     global  $CRM_OPTS;
  4164.  
  4165.     return (isset($CRM_OPTS[$s_name]) ? $CRM_OPTS[$s_name] : NULL);
  4166. }
  4167.  
  4168.     //
  4169.     // Check if a field is in the mail exclusion list.
  4170.     //
  4171. function IsMailExcluded($s_name)
  4172. {
  4173.     $a_list = GetMailOption("Exclude");
  4174.     if (!isset($a_list))
  4175.         return (false);
  4176.     if (is_array($a_list))
  4177.         return (in_array($s_name,$a_list));
  4178.     else
  4179.         return ($s_name === $a_list);
  4180. }
  4181.  
  4182.     //
  4183.     // Process the autorespond specified in the form.
  4184.     //
  4185. function ProcessAROptions($a_form_data)
  4186. {
  4187.     global  $AR_OPTS,$VALID_AR_OPTIONS;
  4188.  
  4189.     ProcessOptions("autorespond",$a_form_data,$AR_OPTS,$VALID_AR_OPTIONS);
  4190. }
  4191.  
  4192.     //
  4193.     // Check if an option is set
  4194.     //
  4195. function IsAROptionSet($s_name)
  4196. {
  4197.     global  $AR_OPTS;
  4198.  
  4199.     return (isset($AR_OPTS[$s_name]));
  4200. }
  4201.  
  4202.     //
  4203.     // Return an option's value or NULL if not set.
  4204.     //
  4205. function GetAROption($s_name)
  4206. {
  4207.     global  $AR_OPTS;
  4208.  
  4209.     return (isset($AR_OPTS[$s_name]) ? $AR_OPTS[$s_name] : NULL);
  4210. }
  4211.  
  4212.     //
  4213.     // Process the mail_options specified in the form.
  4214.     //
  4215. function ProcessFilterOptions($a_form_data)
  4216. {
  4217.     global  $FILTER_OPTS,$VALID_FILTER_OPTIONS;
  4218.  
  4219.     ProcessOptions("filter_options",$a_form_data,$FILTER_OPTS,$VALID_FILTER_OPTIONS);
  4220. }
  4221.  
  4222.     //
  4223.     // Check if an option is set
  4224.     //
  4225. function IsFilterOptionSet($s_name)
  4226. {
  4227.     global  $FILTER_OPTS;
  4228.  
  4229.     return (isset($FILTER_OPTS[$s_name]));
  4230. }
  4231.  
  4232.     //
  4233.     // Return an option's value or NULL if not set.
  4234.     //
  4235. function GetFilterOption($s_name)
  4236. {
  4237.     global  $FILTER_OPTS;
  4238.  
  4239.     return (isset($FILTER_OPTS[$s_name]) ? $FILTER_OPTS[$s_name] : NULL);
  4240. }
  4241.  
  4242.     //
  4243.     // Lookup a filter attribute for the given filter.
  4244.     // Return it's value or false if not set.
  4245.     //
  4246. function GetFilterAttrib($s_filter,$s_attrib)
  4247. {
  4248.     global  $FILTER_ATTRIBS,$FILTER_ATTRIBS_LOOKUP;
  4249.  
  4250.     if (!isset($FILTER_ATTRIBS[$s_filter]))
  4251.             //
  4252.             // no attributes for the filter
  4253.             //
  4254.         return (false);
  4255.     if (!isset($FILTER_ATTRIBS_LOOKUP[$s_filter]))
  4256.     {
  4257.             //
  4258.             // the attributes have not yet been parsed - create the lookup table
  4259.             //
  4260.         $a_list = TrimArray(explode(",",$FILTER_ATTRIBS[$s_filter]));
  4261.         $FILTER_ATTRIBS_LOOKUP[$s_filter] = array();
  4262.         $a_errors = array();
  4263.  
  4264.         ProcessAttributeList($a_list,$FILTER_ATTRIBS_LOOKUP[$s_filter],$a_errors);
  4265.     }
  4266.         //
  4267.         // perform the lookup and return the value
  4268.         //
  4269.     if (!isset($FILTER_ATTRIBS_LOOKUP[$s_filter][$s_attrib]))
  4270.         return (false);
  4271.     return ($FILTER_ATTRIBS_LOOKUP[$s_filter][$s_attrib]);
  4272. }
  4273.  
  4274.     //
  4275.     // Check the filter attributes for the given filter.
  4276.     // Return true if the given attribute is set otherwise false.
  4277.     //
  4278. function IsFilterAttribSet($s_filter,$s_attrib)
  4279. {
  4280.     return (GetFilterAttrib($s_filter,$s_attrib));
  4281. }
  4282.  
  4283.     //
  4284.     // Process the given .ini file.
  4285.     //
  4286. function ProcessFormIniFile($s_file)
  4287. {
  4288.     global  $EMAIL_ADDRS,$ValidEmails;
  4289.  
  4290.     $a_sections = parse_ini_file($s_file,TRUE);
  4291.     if (DB_SEE_INI)
  4292.     {
  4293.             //
  4294.             // just display the ini file
  4295.             //
  4296.         $s_text = "<p><b>The following settings were found in the file '$s_file':</b></p>";
  4297.         foreach ($a_sections as $s_sect=>$a_settings)
  4298.         {
  4299.             $s_text .= "<p>[$s_sect]\n";
  4300.             foreach ($a_settings as $s_name=>$s_value)
  4301.                 $s_text .= "$s_name = \"$s_value\"\n";
  4302.             $s_text .= "</p>";
  4303.         }
  4304.         CreatePage($s_text);
  4305.         exit;
  4306.     }
  4307.         //
  4308.         // Load the email_addresses section.
  4309.         //
  4310.     if (isset($a_sections["email_addresses"]))
  4311.     {
  4312.         $EMAIL_ADDRS = $a_sections["email_addresses"];
  4313.             //
  4314.             // make these addresses valid
  4315.             //
  4316.         foreach ($EMAIL_ADDRS as $s_list)
  4317.             $ValidEmails->AddAddresses($s_list);
  4318.     }
  4319.         //
  4320.         // Process special fields
  4321.         //
  4322.     if (isset($a_sections["special_fields"]))
  4323.     {
  4324.         foreach ($a_sections["special_fields"] as $s_name=>$m_value)
  4325.         {
  4326.             if (IsSpecialField($s_name))
  4327.             {
  4328.                 SetSpecialField($s_name,$m_value);
  4329.                     //
  4330.                     // if this is the recipients, cc, or bcc field,
  4331.                     // make the addresses valid
  4332.                     //
  4333.                 if ($s_name === "recipients" || $s_name === "cc" || $s_name === "bcc")
  4334.                         //
  4335.                         // coming from the INI file, the values can only be strings
  4336.                         //
  4337.                     if (is_string($m_value))
  4338.                         $ValidEmails->AddAddresses($m_value);
  4339.             }
  4340.                 //
  4341.                 // check for multiple valued special fields
  4342.                 //
  4343.             if (($a_multi_fld = IsSpecialMultiField($s_name)) !== false)
  4344.                 SetSpecialMultiField($a_multi_fld[0],$a_multi_fld[1],$m_value);
  4345.         }
  4346.     }
  4347. }
  4348.  
  4349.     //
  4350.     // UnMangle an email address
  4351.     //
  4352. function UnMangle($email)
  4353. {
  4354.     global  $EMAIL_ADDRS;
  4355.  
  4356.         //
  4357.         // map from a name to the real email address
  4358.         //
  4359.     if (isset($EMAIL_ADDRS[$email]))
  4360.         $email = $EMAIL_ADDRS[$email];
  4361.         //
  4362.         // unmangle
  4363.         //
  4364.     if (AT_MANGLE != "")
  4365.         $email = str_replace(AT_MANGLE,"@",$email);
  4366.     return ($email);
  4367. }
  4368.  
  4369.     //
  4370.     // Check a list of email addresses (comma separated); returns a list
  4371.     // of valid email addresses (comma separated).
  4372.     // The list can be an array of comma separated lists.
  4373.     // The return value is true if there is at least one valid email address.
  4374.     //
  4375. function CheckEmailAddress($m_addr,&$s_valid,&$s_invalid,$b_check = true)
  4376. {
  4377.     global  $ValidEmails;
  4378.  
  4379.     $s_invalid = $s_valid = "";
  4380.     if (is_array($m_addr))
  4381.     {
  4382.         $a_list = array();
  4383.         foreach ($m_addr as $s_addr_list)
  4384.             $a_list = array_merge($a_list,TrimArray(explode(",",$s_addr_list)));
  4385.     }
  4386.     else
  4387.         $a_list = TrimArray(explode(",",$m_addr));
  4388.     $a_invalid = array();
  4389.     $n_empty = 0;
  4390.     for ($ii = 0 ; $ii < count($a_list) ; $ii++)
  4391.     {
  4392.         if ($a_list[$ii] === "")
  4393.         {
  4394.                 //
  4395.                 // ignore, but count empty addresses
  4396.                 //
  4397.             $n_empty++;
  4398.             continue;
  4399.         }
  4400.         $s_email = UnMangle($a_list[$ii]);
  4401.             //
  4402.             // UnMangle works with INI files too, and a single
  4403.             // word can expand to a list of email addresses.
  4404.             //
  4405.         $a_this_list = TrimArray(explode(",",$s_email));
  4406.         foreach ($a_this_list as $s_email)
  4407.         {
  4408.             if ($s_email === "")
  4409.             {
  4410.                     //
  4411.                     // ignore, but count empty addresses
  4412.                     //
  4413.                 $n_empty++;
  4414.                 continue;
  4415.             }
  4416.             if ($b_check)
  4417.                 $b_is_valid = $ValidEmails->CheckAddress($s_email);
  4418.             else
  4419.                 $b_is_valid = true;
  4420.             if ($b_is_valid)
  4421.             {
  4422.                 if (empty($s_valid))
  4423.                     $s_valid = $s_email;
  4424.                 else
  4425.                     $s_valid .= ",".$s_email;
  4426.             }
  4427.             else
  4428.                 $a_invalid[] = $s_email;
  4429.         }
  4430.     }
  4431.         //
  4432.         // just ignore empty recipients unless there are *no* valid recipients
  4433.         //
  4434.     if (empty($s_valid) && $n_empty > 0)
  4435.         $a_invalid[] = GetMessage(MSG_EMPTY_ADDRESSES,array("COUNT"=>$n_empty));
  4436.     if (count($a_invalid) > 0)
  4437.         $s_invalid = implode(",",$a_invalid);
  4438.     return (!empty($s_valid));
  4439. }
  4440.  
  4441.     //
  4442.     // Redirect to another URL
  4443.     //
  4444. function Redirect($url)
  4445. {
  4446.         //
  4447.         // for browsers without cookies enabled, append the Session ID
  4448.         //
  4449.     if (session_id() !== "")
  4450.         $url = AddURLParams($url,session_name()."=".urlencode(session_id()));
  4451.     elseif (defined("SID"))
  4452.         $url = AddURLParams($url,SID);
  4453.  
  4454.         //
  4455.         // this is probably a good idea to ensure the session data
  4456.         // is written away
  4457.         //
  4458.     if (function_exists('session_write_close'))
  4459.         session_write_close();
  4460.  
  4461.     header("Location: $url");
  4462.         //
  4463.         // if the header doesn't work, try JavaScript.
  4464.         // if that doesn't work, provide a manual link
  4465.         //
  4466.     $s_text = GetMessage(MSG_PLSWAIT_REDIR)."\n\n";
  4467.     $s_text .= "<script language=\"JavaScript\" type=\"text/javascript\">";
  4468.     $s_text .= "window.location.href = '$url';";
  4469.     $s_text .= "</script>";
  4470.     $s_text .= "\n\n".GetMessage(MSG_IFNOT_REDIR,array("URL"=>$url));
  4471.     CreatePage($s_text);
  4472.     exit;
  4473. }
  4474.  
  4475.     //
  4476.     // JoinLines is just like "implode" except that it checks
  4477.     // the end of each array for the separator already being
  4478.     // there. This allows us to join a mixture of mail
  4479.     // header lines (already terminated) with body lines.
  4480.     // This logic works if HEAD_CRLF, for example, is the same
  4481.     // as BODY_LF (i.e. both "\r\n") or if BODY_LF is the
  4482.     // same as the last character in HEAD_CRLF (i.e.
  4483.     // HEAD_CRLF = "\r\n" and BODY_LF = "\n").
  4484.     // Other value combinations may break things.
  4485.     //
  4486. function JoinLines($s_sep,$a_lines)
  4487. {
  4488.     $s_str = "";
  4489.     if (($i_sep_len = strlen($s_sep)) == 0)
  4490.             //
  4491.             // no separator
  4492.             //
  4493.         return (implode("",$a_lines));
  4494.     $n_lines = count($a_lines);
  4495.     for ($ii = 0 ; $ii < $n_lines ; $ii++)
  4496.     {
  4497.         $s_line = $a_lines[$ii];
  4498.         if (substr($s_line,-$i_sep_len) == $s_sep)
  4499.             $s_str .= $s_line;
  4500.         else
  4501.         {
  4502.             $s_str .= $s_line;
  4503.                 //
  4504.                 // don't append a separator to the last line
  4505.                 //
  4506.             if ($ii < $n_lines-1)
  4507.                 $s_str .= $s_sep;
  4508.         }
  4509.     }
  4510.     return ($s_str);
  4511. }
  4512.  
  4513.     //
  4514.     // Re-orders an array of email headers into the
  4515.     // order recommended by RFC822, section 4.1:
  4516.     //      It  is  recommended that,  if  present,
  4517.     //      headers be sent in the order "Return-
  4518.     //      Path", "Received", "Date",  "From",  "Subject",
  4519.     //      "Sender", "To", "cc", etc.
  4520.     //
  4521.     // Note that RFC822 is obsoleted by RFC2822 and
  4522.     // the latter states that field order doesn't
  4523.     // matter (except for some tracing fields).
  4524.     // However, a FormMail user reported that Yahoo doesn't like
  4525.     // email where the CC header appears before the From
  4526.     // header. So, as always, we try to work with broken
  4527.     // servers too...
  4528.     //
  4529.     // Returns an array indexed by the require numerical
  4530.     // order.  Each element is an array containing the
  4531.     // header value (name,value pair).
  4532.     //
  4533. function OrderHeaders($a_headers)
  4534. {
  4535.         //
  4536.         // we list the headers we're responsible for
  4537.         // in the order suggested
  4538.         //
  4539.     $a_ordering = array("From","Subject","To","Cc","Bcc","Reply-To");
  4540.     $a_ordered_headers = array();
  4541.     foreach ($a_ordering as $s_name)
  4542.     {
  4543.         if (isset($a_headers[$s_name]))
  4544.         {
  4545.             $a_ordered_headers[] = array($s_name=>$a_headers[$s_name]);
  4546.             unset($a_headers[$s_name]);
  4547.         }
  4548.     }
  4549.         //
  4550.         // now add in the remaining headers
  4551.         //
  4552.     foreach ($a_headers as $s_name=>$s_value)
  4553.         $a_ordered_headers[] = array($s_name=>$a_headers[$s_name]);
  4554.     return ($a_ordered_headers);
  4555. }
  4556.  
  4557.     //
  4558.     // Makes a mail header field body "safe".
  4559.     // This simply places a backslash in front every double-quote.
  4560.     // There's probably more we could do if required, but this
  4561.     // attempts to provide the same protection that was in the first
  4562.     // version of FormMail.  In that version, every incoming
  4563.     // field had double-quotes replaced with single quotes.
  4564.     // That processing is no longer performed, and this
  4565.     // function is used to protect against potential attacks in
  4566.     // header fields - not by replacing double quotes with single quotes,
  4567.     // but by using the backslash "quoting" feature of RFC2822.
  4568.     //
  4569.     // This code could be improved by parsing the header and rewriting
  4570.     // it to be valid, possibly removing junk.
  4571.     //
  4572.     // That's a lot of code, though!
  4573.     //
  4574. function    SafeHeader($s_str)
  4575. {
  4576.     return (str_replace('"','\\"',$s_str));
  4577. }
  4578.  
  4579.     //
  4580.     // makes a string safe to put as words in a header
  4581.     //
  4582. function    SafeHeaderWords($s_str)
  4583. {
  4584.         //
  4585.         // We zap various characters and replace them with a question mark.
  4586.         // Also, we don't handle quoted strings, which are valid words.
  4587.         //
  4588.     $s_specials = '()<>@,;:\\".[]';    // special characters defined by RFC822
  4589.     $s_str = preg_replace('/[[:cntrl:]]+/',"?",$s_str);    // zap all control chars
  4590.     $s_str = preg_replace("/[".preg_quote($s_specials,"/")."]/","?",$s_str);    // zap all specials
  4591.     return ($s_str);
  4592. }
  4593.  
  4594.     //
  4595.     // makes a string safe to put as a quoted string in a header
  4596.     //
  4597. function    SafeHeaderQString($s_str)
  4598. {
  4599.     return (str_replace('"','\\"',
  4600.                 str_replace("\\","\\\\",
  4601.                     str_replace("\r"," ",
  4602.                         str_replace("\r\n"," ",$s_str)))));
  4603. }
  4604.  
  4605.     //
  4606.     // makes a string safe to put in a header comment
  4607.     //
  4608. function    SafeHeaderComment($s_str)
  4609. {
  4610.     return (str_replace("(","\\(",
  4611.                 str_replace(")","\\)",
  4612.                     str_replace("\\","\\\\",
  4613.                         str_replace("\r"," ",
  4614.                             str_replace("\r\n"," ",$s_str))))));
  4615. }
  4616.  
  4617.     //
  4618.     // makes a string safe to put in a header as an email address
  4619.     //
  4620. function    SafeHeaderEmail($s_str)
  4621. {
  4622.         //
  4623.         // and email address is made up of local and domain parts
  4624.         // each of these is made up of "words" separated by "."
  4625.         // each "word" can be a sequence of characters excluding
  4626.         // specials, space and control characters OR it can be
  4627.         // a quoted string
  4628.         //
  4629.         // The correct processing would be to completely
  4630.         // parse the address, strip junk, double-quote
  4631.         // words that need to be turned into quote strings,
  4632.         // and return a well-formed email address.
  4633.         //
  4634.         // That's a lot of code!
  4635.         //
  4636.         // So, instead, we opt for stripping out control characters.
  4637.         // This is probably not necessary because there shouldn't be
  4638.         // any control characters at this point, but this is just extra
  4639.         // safety.
  4640.         //
  4641.     $s_str = preg_replace('/[[:cntrl:]]+/',"",$s_str);    // zap all control chars
  4642.     return ($s_str);
  4643. }
  4644.  
  4645.     //
  4646.     // Expands an array of mail headers into mail header lines.
  4647.     //
  4648. function ExpandMailHeaders($a_headers)
  4649. {
  4650.     $s_hdrs = "";
  4651.     $a_ordered_headers = OrderHeaders($a_headers);
  4652.     for ($ii = 0 ; $ii < count($a_ordered_headers) ; $ii++)
  4653.     {
  4654.         foreach ($a_ordered_headers[$ii] as $s_name=>$s_value)
  4655.             if ($s_name != "")
  4656.             {
  4657.                 if ($s_hdrs != "")
  4658.                     $s_hdrs .= HEAD_CRLF;
  4659.                 $s_hdrs .= $s_name.": ".$s_value;
  4660.             }
  4661.     }
  4662.     return ($s_hdrs);
  4663. }
  4664.  
  4665.     //
  4666.     // Expands an array of mail headers into an array containing header lines.
  4667.     //
  4668. function ExpandMailHeadersArray($a_headers)
  4669. {
  4670.     $a_hdrs = array();
  4671.     $a_ordered_headers = OrderHeaders($a_headers);
  4672.     for ($ii = 0 ; $ii < count($a_ordered_headers) ; $ii++)
  4673.     {
  4674.         foreach ($a_ordered_headers[$ii] as $s_name=>$s_value)
  4675.             if ($s_name != "")
  4676.                 $a_hdrs[] = $s_name.": ".$s_value.HEAD_CRLF;
  4677.     }
  4678.     return ($a_hdrs);
  4679. }
  4680.  
  4681.     //
  4682.     // Low-level email send function; either calls PHP's mail function
  4683.     // or uses the PEAR Mail object.
  4684.     // NOTE: for some errors, there's no point trying to email
  4685.     // an alert message!  So, in these cases, we just display the error to
  4686.     // the user.
  4687.     // $s_options are ignored for PEAR sending.
  4688.     //
  4689. function DoMail($s_to,$s_subject,$s_mesg,$a_headers,$s_options)
  4690. {
  4691.     global  $PEAR_SMTP_HOST,$PEAR_SMTP_PORT,$PEAR_SMTP_USER,$PEAR_SMTP_PWD;
  4692.  
  4693.     if (isset($PEAR_SMTP_HOST) && !empty($PEAR_SMTP_HOST))
  4694.     {
  4695.         require_once("Mail.php");
  4696.  
  4697.         $a_params = array(  "host"=>$PEAR_SMTP_HOST,
  4698.                             "port"=>$PEAR_SMTP_PORT);
  4699.         if (isset($PEAR_SMTP_USER) && !empty($PEAR_SMTP_USER))
  4700.         {
  4701.             $a_params["auth"] = TRUE;
  4702.             $a_params["username"] = $PEAR_SMTP_USER;
  4703.             $a_params["password"] = $PEAR_SMTP_PWD;
  4704.         }
  4705.         $mailer = Mail::factory("smtp",$a_params);
  4706.         if (!is_object($mailer))
  4707.         {
  4708.             ShowError("pear_error",GetMessage(MSG_PEAR_OBJ),FALSE,FALSE);
  4709.             exit;
  4710.         }
  4711.         if (strtolower(get_class($mailer)) === 'pear_error')
  4712.         {
  4713.             ShowError("pear_error",$mailer->getMessage(),FALSE,FALSE);
  4714.             exit;
  4715.         }
  4716.         if (!isset($a_headers['To']) && !isset($a_headers['to']))
  4717.             $a_headers['To'] = SafeHeader($s_to);
  4718.         if (!isset($a_headers['Subject']) && !isset($a_headers['subject']))
  4719.             $a_headers['Subject'] = SafeHeader($s_subject);
  4720.         $res = $mailer->send($s_to,$a_headers,$s_mesg);
  4721.         if ($res === TRUE)
  4722.             return (TRUE);
  4723.  
  4724.         global  $aAlertInfo;
  4725.  
  4726.         $aAlertInfo[] = GetMessage(MSG_PEAR_ERROR,array("MSG"=>$res->getMessage()));
  4727.         return (FALSE);
  4728.     }
  4729.     if ($s_options !== "")
  4730.         return (mail($s_to,$s_subject,$s_mesg,ExpandMailHeaders($a_headers),$s_options));
  4731.     else
  4732.         return (mail($s_to,$s_subject,$s_mesg,ExpandMailHeaders($a_headers)));
  4733. }
  4734.  
  4735.     //
  4736.     // Send an email
  4737.     //
  4738. function SendCheckedMail($to,$subject,$mesg,$sender,$a_headers = array())
  4739. {
  4740.     global  $PEAR_SMTP_HOST;
  4741.  
  4742.     $b_f_option = false;
  4743.     $b_form_option = IsMailOptionSet("SendMailFOption");    // this is superseded, but still supported
  4744.     if (SENDMAIL_F_OPTION || $b_form_option)
  4745.     {
  4746.         if (empty($sender))
  4747.         {
  4748.                 //
  4749.                 // SENDMAIL_F_OPTION with no sender is silently ignored
  4750.                 //
  4751.             if ($b_form_option)
  4752.             {
  4753.                     //
  4754.                     // form has specified SendMailFOption, but there's no
  4755.                     // sender address
  4756.                     //
  4757.                 static  $b_in_here = false;
  4758.                 global  $SERVER;
  4759.  
  4760.                 if (!$b_in_here)        // prevent infinite recursion
  4761.                 {
  4762.                     $b_in_here = true;
  4763.                     SendAlert(GetMessage(MSG_NO_FOPT_ADDR));
  4764.                     $b_in_here = false;
  4765.                 }
  4766.                     //
  4767.                     // if there's no from address, create a dummy one
  4768.                     //
  4769.                 $sender = "dummy@".(isset($SERVER) ? $SERVER : "UnknownServer");
  4770.                 $a_headers['From'] = $sender;
  4771.                 $b_f_option = true;
  4772.             }
  4773.         }
  4774.         else
  4775.             $b_f_option = true;
  4776.     }
  4777.     if (INI_SET_FROM && !empty($sender))
  4778.         ini_set('sendmail_from',$sender);
  4779.  
  4780.     return (DoMail($to,$subject,$mesg,$a_headers,($b_f_option ? "-f$sender" : "")));
  4781. }
  4782.  
  4783.     //
  4784.     // Send an alert email
  4785.     //
  4786. function SendAlert($s_error,$b_filter = true,$b_non_error = false)
  4787. {
  4788.     global  $SPECIAL_VALUES,$FORMATTED_INPUT,$FROM_USER,$aServerVars,$aStrippedFormVars;
  4789.     global  $aAlertInfo,$aCleanedValues,$aFieldOrder,$sHTMLCharSet;
  4790.  
  4791.     $s_error = str_replace("\n",BODY_LF,$s_error);
  4792.     $b_got_filter = (isset($SPECIAL_VALUES["filter"]) && !empty($SPECIAL_VALUES["filter"]));
  4793.  
  4794.         //
  4795.         // if there is a filter specified and we're not sending the alert
  4796.         // through the filter, don't show the user's data.  This is
  4797.         // on the assumption that the filter is an encryption program; so,
  4798.         // we don't want to send the user's data in clear text inside the
  4799.         // alerts.
  4800.         //
  4801.     $b_show_data = true;
  4802.     if ($b_got_filter && !$b_filter)
  4803.         $b_show_data = false;
  4804.  
  4805.     $s_form_subject = $s_alert_to = "";
  4806.     $b_check = true;
  4807.         //
  4808.         // might be too early to have $SPECIAL_VALUES set, so
  4809.         // look in the form vars too
  4810.         //
  4811.     if (isset($SPECIAL_VALUES["alert_to"]))
  4812.         $s_alert_to = trim($SPECIAL_VALUES["alert_to"]);
  4813.     if (empty($s_alert_to) && isset($aStrippedFormVars["alert_to"]))
  4814.         $s_alert_to = trim($aStrippedFormVars["alert_to"]);
  4815.  
  4816.     if (isset($SPECIAL_VALUES["subject"]))
  4817.         $s_form_subject = trim($SPECIAL_VALUES["subject"]);
  4818.     if (empty($s_form_subject) && isset($aStrippedFormVars["subject"]))
  4819.         $s_form_subject = trim($aStrippedFormVars["subject"]);
  4820.  
  4821.     if (empty($s_alert_to))
  4822.     {
  4823.         $s_alert_to = DEF_ALERT;
  4824.         $b_check = false;
  4825.     }
  4826.     if (!empty($s_alert_to))
  4827.     {
  4828.         $s_from_addr = $s_from = "";
  4829.         $a_headers = array();
  4830.         if (isset($FROM_USER) && !empty($FROM_USER))
  4831.         {
  4832.             if ($FROM_USER != "NONE")
  4833.             {
  4834.                 $a_headers['From'] = $FROM_USER;
  4835.                 $s_from = "From: $FROM_USER";
  4836.                 $s_from_addr = $FROM_USER;
  4837.             }
  4838.         }
  4839.         else
  4840.         {
  4841.             global  $SERVER;
  4842.  
  4843.             $s_from_addr = "FormMail@".$SERVER;
  4844.             $a_headers['From'] = $s_from_addr;
  4845.             $s_from = "From: $s_from_addr";
  4846.         }
  4847.         $s_mesg = "To: ".UnMangle($s_alert_to).BODY_LF;
  4848.             //
  4849.             // if a language pack has been included, a lot of error messages
  4850.             // may need the character set to be provided.
  4851.             // If that's available from the language pack, use it,
  4852.             // otherwise, if it's a mail_option, use it from there.
  4853.             //
  4854.         $s_charset = "";
  4855.         if (isset($sHTMLCharSet) && $sHTMLCharSet !== "")
  4856.             $s_charset = $sHTMLCharSet;
  4857.         else if (IsMailOptionSet("CharSet"))
  4858.             $s_charset = GetMailOption("CharSet");
  4859.  
  4860.             //
  4861.             // Alerts are plain text emails, so convert any HTML entities
  4862.             // back to their original characters.  Note, this will only work on PHP
  4863.             // version 4.3.0 and above.
  4864.             //
  4865.         if (function_exists("html_entity_decode"))
  4866.             $s_error = html_entity_decode($s_error,ENT_COMPAT,$s_charset);
  4867.  
  4868.         if ($s_charset !== "")
  4869.             $a_headers['Content-Type'] = SafeHeader("text/plain; charset=$s_charset");
  4870.  
  4871.         if (!empty($s_from))
  4872.             $s_mesg .= $s_from.BODY_LF;
  4873.         $s_mesg .= BODY_LF;
  4874.         if (count($aAlertInfo) > 0)
  4875.         {
  4876.             if ($b_show_data)
  4877.             {
  4878.                 $s_error .= BODY_LF.GetMessage(MSG_MORE_INFO).BODY_LF;
  4879.                 $s_error .= implode(BODY_LF,$aAlertInfo);
  4880.             }
  4881.             else
  4882.                 $s_error .= BODY_LF.GetMessage(MSG_INFO_STOPPED).BODY_LF;
  4883.         }
  4884.             //
  4885.             // some fields aren't security issues - show those in the alert
  4886.             //
  4887.         $a_safe_fields = array(
  4888.                     "email: ".$SPECIAL_VALUES["email"],
  4889.                     "realname: ".$SPECIAL_VALUES["realname"],
  4890.                         );
  4891.         $s_safe_data = implode(BODY_LF,$a_safe_fields);
  4892.  
  4893.         if ($b_non_error)
  4894.         {
  4895.             $s_preamble = $s_error.BODY_LF.BODY_LF;
  4896.             $s_mesg .= $s_preamble;
  4897.             $s_subj = GetMessage(MSG_FM_ALERT);
  4898.             if (!empty($s_form_subject))
  4899.                 $s_subj .= " ($s_form_subject)";
  4900.         }
  4901.         else
  4902.         {
  4903.             $s_preamble = GetMessage(MSG_FM_ERROR_LINE).BODY_LF.
  4904.                             $s_error.BODY_LF.BODY_LF;
  4905.             $s_mesg .= $s_preamble;
  4906.             $s_subj = GetMessage(MSG_FM_ERROR);
  4907.             if (!empty($s_form_subject))
  4908.                 $s_subj .= " ($s_form_subject)";
  4909.             $s_mesg .= $s_safe_data;
  4910.             $s_mesg .= BODY_LF.BODY_LF;
  4911.             if ($b_show_data)
  4912.                 $s_mesg .= implode(BODY_LF,$FORMATTED_INPUT);
  4913.             else
  4914.                 $s_mesg .= GetMessage(MSG_USERDATA_STOPPED);
  4915.         }
  4916.             
  4917.             /*
  4918.              * We only need to filter the form fields if the filter that
  4919.              * is specified is an encrypting filter.
  4920.              */
  4921.         if ($b_filter && $b_got_filter &&
  4922.                 IsFilterAttribSet($SPECIAL_VALUES["filter"],"Encrypts"))
  4923.         {
  4924.             $s_new_mesg = $s_preamble.$s_safe_data;
  4925.             $s_new_mesg .= BODY_LF.BODY_LF;
  4926.  
  4927.             $s_filter = $SPECIAL_VALUES["filter"];
  4928.  
  4929.             if (($a_filter_list = GetFilterList()) !== false)
  4930.             {
  4931.                     //
  4932.                     // just filter the critical fields
  4933.                     //
  4934.                 list($s_unfiltered,$s_filtered_results) =
  4935.                             GetFilteredOutput($aFieldOrder,$aCleanedValues,
  4936.                                     $s_filter,$a_filter_list);
  4937.                 $s_new_mesg .= $s_unfiltered;
  4938.             }
  4939.             else
  4940.             {
  4941.                     //
  4942.                     // filter everything
  4943.                     //
  4944.                 $s_filtered_results = Filter($s_filter,$s_mesg);
  4945.             }
  4946.             $s_new_mesg .= GetMessage(MSG_FILTERED,array("FILTER"=>$s_filter)).
  4947.                             BODY_LF.BODY_LF.
  4948.                             $s_filtered_results;
  4949.             $s_mesg = $s_new_mesg;
  4950.         }
  4951.         if (isset($aServerVars['HTTP_REFERER']))
  4952.             $s_mesg .= BODY_LF.BODY_LF."Referring page was ".$aServerVars['HTTP_REFERER'];
  4953.         elseif (isset($SPECIAL_VALUES['this_form']) && $SPECIAL_VALUES['this_form'] !== "")
  4954.             $s_mesg .= BODY_LF.BODY_LF."Referring form was ".$SPECIAL_VALUES['this_form'];
  4955.  
  4956.         if (isset($aServerVars['REMOTE_ADDR']))
  4957.             $s_mesg .= BODY_LF.BODY_LF."User IP address was ".$aServerVars['REMOTE_ADDR'];
  4958.  
  4959.         if ($b_check)
  4960.         {
  4961.             if (CheckEmailAddress($s_alert_to,$s_valid,$s_invalid))
  4962.                 return (SendCheckedMail($s_valid,$s_subj,$s_mesg,$s_from_addr,$a_headers));
  4963.         }
  4964.         else
  4965.             return (SendCheckedMail($s_alert_to,$s_subj,$s_mesg,$s_from_addr,$a_headers));
  4966.     }
  4967.     return (false);
  4968. }
  4969.  
  4970.     //
  4971.     // Read the lines in a file and return an array.
  4972.     // Each line is stripped of line termination characters.
  4973.     //
  4974. function ReadLines($fp)
  4975. {
  4976.     $a_lines = array();
  4977.     while (!feof($fp))
  4978.     {
  4979.         $s_line = fgets($fp,4096);
  4980.             //
  4981.             // strip carriage returns and line feeds
  4982.             //
  4983.         $s_line = str_replace("\r","",$s_line);
  4984.         $s_line = str_replace("\n","",$s_line);
  4985.         $a_lines[] = $s_line;
  4986.     }
  4987.     return ($a_lines);
  4988. }
  4989.  
  4990.     //
  4991.     // Open a URL and return the data from it as a string.
  4992.     // Returns false on failure ($s_error has the error string)
  4993.     //
  4994. function GetURL($s_url,&$s_error)
  4995. {
  4996.     global  $php_errormsg,$aServerVars,$FM_VERS;
  4997.     global  $AUTHENTICATE,$AUTH_USER,$AUTH_PW;
  4998.  
  4999.         //
  5000.         // open the URL with the same session as we have
  5001.         //
  5002.     if (session_id() !== "")
  5003.         $s_url = AddURLParams($s_url,session_name()."=".urlencode(session_id()));
  5004.     elseif (defined("SID"))
  5005.         $s_url = AddURLParams($s_url,SID);
  5006.         //
  5007.         // parse the URL to get the component parts
  5008.         //
  5009.     $a_parts = parse_url($s_url);
  5010.         //
  5011.         // must have a host
  5012.         //
  5013.     if (!isset($a_parts["host"]))
  5014.     {
  5015.         $s_error = GetMessage(MSG_URL_PARSE);
  5016.         return (false);
  5017.     }
  5018.     $s_host_hdr = $a_parts["host"];
  5019.         //
  5020.         // if no port number is given, we support http and https
  5021.         //
  5022.     if (!isset($a_parts["port"]))
  5023.     {
  5024.         if (!isset($a_parts["scheme"]) || strtolower($a_parts["scheme"]) == "http")
  5025.             $a_parts["port"] = 80;
  5026.         elseif (strtolower($a_parts["scheme"]) == "https")
  5027.             $a_parts["port"] = 443;
  5028.         else
  5029.         {
  5030.            $s_error = GetMessage(MSG_URL_SCHEME,
  5031.                                     array("SCHEME"=>$a_parts["scheme"]));
  5032.            return (false);
  5033.         }
  5034.     }
  5035.     if ($a_parts["port"] == 443)
  5036.             //
  5037.             // fsockopen requires ssl:// in the host name
  5038.             //
  5039.         $a_parts["host"] = "ssl://".$a_parts["host"];
  5040.  
  5041.         //
  5042.         // default the path if empty
  5043.         //
  5044.     if (!isset($a_parts["path"]) || $a_parts["path"] === "")
  5045.         $a_parts["path"] = "/";
  5046.  
  5047.     $f_sock = @fsockopen($a_parts["host"],(int) $a_parts["port"],$i_errno,$s_errstr,30);
  5048.     if ($f_sock === false)
  5049.     {
  5050.         $s_error = GetMessage(MSG_SOCKET,
  5051.                             array("ERRNO"=>$i_errno,
  5052.                                 "ERRSTR"=>$s_errstr,
  5053.                                 "PHPERR"=>isset($php_errormsg) ? $php_errormsg : ""));
  5054.         return (false);
  5055.     }
  5056.  
  5057.     $s_req = $a_parts["path"];
  5058.         //
  5059.         // add the query to the path
  5060.         // Note that parse_url decodes the query string (urldecode), so
  5061.         // we need to split it into its component parameters
  5062.         // are re-encode their values.  Calling urlencode($a_parts["query"])
  5063.         // encodes the '=' between parameters and this breaks things.
  5064.         //
  5065.     if (isset($a_parts["query"]))
  5066.     {
  5067.         $a_params = explode('&',$a_parts["query"]);
  5068.         foreach ($a_params as $i_idx=>$s_param)
  5069.         {
  5070.             if (($i_pos = strpos($s_param,"=")) === false)
  5071.                 $a_params[$i_idx] = urlencode($s_param);
  5072.             else
  5073.                 $a_params[$i_idx] = substr($s_param,0,$i_pos).'='.
  5074.                                         urlencode(substr($s_param,$i_pos+1));
  5075.         }
  5076.         $s_req .= '?'.implode('&',$a_params);
  5077.     }
  5078.  
  5079.         //
  5080.         // add the fragment to the path.  Note, however, this
  5081.         // won't actually make the user's browser jump to that
  5082.         // location (because we'd need to alter our current URL
  5083.         // and add the fragment to achieve that - we might
  5084.         // add that feature in a later version if we can
  5085.         // figure out how to do it!)
  5086.         //
  5087.     if (isset($a_parts["fragment"]))
  5088.         $s_req .= '#'.urlencode($a_parts["fragment"]);
  5089.  
  5090.         //
  5091.         // Since we might be opening a URL within the same session, we can
  5092.         // get locks.  So, close the session for writing to prevent this.
  5093.         //
  5094.     if (function_exists('session_write_close'))
  5095.     {
  5096.         session_write_close();
  5097.         ob_flush();             // probably a good idea
  5098.     }
  5099.         //
  5100.         // the GET request
  5101.         //
  5102.     fputs($f_sock,"GET ".$s_req." HTTP/1.0\r\n");
  5103.  
  5104.         //
  5105.         // Determine authentication requirements
  5106.         //
  5107.     if ($AUTHENTICATE !== "" || $AUTH_USER !== "" || $AUTH_PW !== "")
  5108.     {
  5109.         if ($AUTHENTICATE === "")
  5110.             fputs($f_sock,"Authorization: Basic ".
  5111.                         base64_encode("$AUTH_USER:$AUTH_PW")."\r\n");
  5112.         else
  5113.             fputs($f_sock,"Authorization: $AUTHENTICATE\r\n");
  5114.  
  5115.     }
  5116.     else
  5117.     {
  5118.         if (isset($a_parts["user"]) || isset($a_parts["pass"]))
  5119.         {
  5120.             $s_auth_user = isset($a_parts["user"]) ? $a_parts["user"] : "";
  5121.             $s_auth_pass = isset($a_parts["pass"]) ? $a_parts["pass"] : "";
  5122.         }
  5123.         else
  5124.         {
  5125.             $s_auth_type = isset($aServerVars["PHP_AUTH_TYPE"]) ? $aServerVars["PHP_AUTH_TYPE"] : "";
  5126.             $s_auth_user = isset($aServerVars["PHP_AUTH_USER"]) ? $aServerVars["PHP_AUTH_USER"] : "";
  5127.             $s_auth_pass = isset($aServerVars["PHP_AUTH_PW"]) ? $aServerVars["PHP_AUTH_PW"] : "";
  5128.         }
  5129.         if (!isset($s_auth_type) || $s_auth_type === "")
  5130.             $s_auth_type = "Basic";
  5131.             //
  5132.             // Add the authentication header
  5133.             //
  5134.         if ($s_auth_user !== "" || $s_auth_pass !== "")
  5135.             fputs($f_sock,"Authorization: $s_auth_type ".
  5136.                         base64_encode("$s_auth_user:$s_auth_pass")."\r\n");
  5137.     }
  5138.  
  5139.         //
  5140.         // Specify the host name
  5141.         //
  5142.     fputs($f_sock,"Host: $s_host_hdr\r\n");
  5143.         //
  5144.         // Specify the user agent
  5145.         //
  5146.     fputs($f_sock,"User-Agent: FormMail/$FM_VERS (from www.tectite.com)\r\n");
  5147.         //
  5148.         // Accept any output
  5149.         //
  5150.     fputs($f_sock,"Accept: */*\r\n");
  5151.         //
  5152.         // End of request headers
  5153.         //
  5154.     fputs($f_sock,"\r\n");
  5155.  
  5156.         //
  5157.         // Read and parse the response header
  5158.         //
  5159.     $i_http_code = 0;
  5160.     $s_status = "";
  5161.     while (!feof($f_sock))
  5162.     {
  5163.         $s_line = fgets($f_sock,4096);
  5164.         if ($s_line == "\r\n" || $s_line == "\n")
  5165.             break;
  5166.         if (substr($s_line,0,4) == "HTTP")
  5167.         {
  5168.             $i_pos = strpos($s_line," ");
  5169.             $s_status = substr($s_line,$i_pos+1);
  5170.             $i_end_pos = strpos($s_status," ");
  5171.             if ($i_end_pos === false)
  5172.                 $i_end_pos = strlen($s_status);
  5173.             $i_http_code = (int) substr($s_status,0,$i_end_pos);
  5174.         }
  5175.     }
  5176.     if ($i_http_code < 200 || $i_http_code > 299)
  5177.     {
  5178.         $s_error = GetMessage(MSG_GETURL_OPEN,array("STATUS"=>$s_status));
  5179.         $m_buf = false;
  5180.     }
  5181.     else
  5182.     {
  5183.             //
  5184.             // read content into one big string buffer and return
  5185.             //
  5186.         $m_buf = "";
  5187.         while (!feof($f_sock))
  5188.             $m_buf .= fread($f_sock,1024);
  5189.     }
  5190.     fclose($f_sock);
  5191.         //
  5192.         // re-open our session
  5193.         //
  5194.     session_start();
  5195.     return ($m_buf);
  5196. }
  5197.  
  5198.     //
  5199.     // Load a template file into a string.
  5200.     //
  5201. function LoadTemplate($s_name,$s_dir,$s_url,$b_ret_lines = false)
  5202. {
  5203.     global  $php_errormsg;
  5204.  
  5205.     $s_buf = "";
  5206.     $a_lines = array();
  5207.     if (!empty($s_dir))
  5208.     {
  5209.         $s_name = "$s_dir/".basename($s_name);
  5210. @       $fp = fopen($s_name,"r");
  5211.         if ($fp === false)
  5212.         {
  5213.             SendAlert(GetMessage(MSG_OPEN_TEMPLATE,array("NAME"=>$s_name,
  5214.                                                     "ERROR"=>CheckString($php_errormsg))));
  5215.             return (false);
  5216.         }
  5217.         if ($b_ret_lines)
  5218.             $a_lines = ReadLines($fp);
  5219.         else
  5220.                 //
  5221.                 // load the whole template into a string
  5222.                 //
  5223.             $s_buf = fread($fp,filesize($s_name));
  5224.         fclose($fp);
  5225.     }
  5226.     else
  5227.     {
  5228.         global  $aServerVars;
  5229.  
  5230.         $s_name = "$s_url/".basename($s_name);
  5231.         if (isset($aServerVars['HTTP_USER_AGENT']))
  5232.             $s_name = AddURLParams($s_name,"USER_AGENT=".$aServerVars['HTTP_USER_AGENT']);
  5233.  
  5234.             //
  5235.             // open the URL with the same session as we have
  5236.             //
  5237.         if (session_id() !== "")
  5238.             $s_name = AddURLParams($s_name,session_name()."=".urlencode(session_id()));
  5239.         elseif (defined("SID"))
  5240.             $s_name = AddURLParams($s_name,SID);
  5241.  
  5242.             //
  5243.             // Since we might be opening a URL within the same session, we can
  5244.             // get locks.  So, close the session for writing to prevent this.
  5245.             //
  5246.         if (function_exists('session_write_close'))
  5247.         {
  5248.             session_write_close();
  5249.             //ob_flush();             // this prevents automatic redirects if $TEMPLATEURL
  5250.                                       // is in use and JavaScript is switched off
  5251.         }
  5252.  
  5253. @       $fp = fopen($s_name,"r");
  5254.         if ($fp === false)
  5255.         {
  5256.             SendAlert(GetMessage(MSG_OPEN_TEMPLATE,array("NAME"=>$s_name,
  5257.                                                     "ERROR"=>CheckString($php_errormsg))));
  5258.             return (false);
  5259.         }
  5260.         if ($b_ret_lines)
  5261.             $a_lines = ReadLines($fp);
  5262.         else
  5263.                 //
  5264.                 // load the whole template into a string
  5265.                 //
  5266.             while (!feof($fp))
  5267.                 $s_buf .= fread($fp,4096);
  5268.         fclose($fp);
  5269.             //
  5270.             // now re-open our session
  5271.             //
  5272.         session_start();
  5273.     }
  5274.     return ($b_ret_lines ? $a_lines : $s_buf);
  5275. }
  5276.  
  5277.     //
  5278.     // To show an error template.  The template must be HTML and, for security
  5279.     // reasons, must be a file on the server in the directory specified
  5280.     // by $TEMPLATEDIR or $TEMPLATEURL.
  5281.     // $a_specs is an array of substitutions to perform, as follows:
  5282.     //      tag-name    replacement string
  5283.     //
  5284.     // For example:
  5285.     //      "fmerror"=>"An error message"
  5286.     //
  5287. function ShowErrorTemplate($s_name,$a_specs,$b_user_error)
  5288. {
  5289.     global  $TEMPLATEURL,$TEMPLATEDIR;
  5290.  
  5291.     if (empty($TEMPLATEDIR) && empty($TEMPLATEURL))
  5292.     {
  5293.         SendAlert(GetMessage(MSG_TEMPLATES));
  5294.         return (false);
  5295.     }
  5296.     if (($s_buf = LoadTemplate($s_name,$TEMPLATEDIR,$TEMPLATEURL)) === false)
  5297.         return (false);
  5298.  
  5299.         //
  5300.         // now look for the tags to replace
  5301.         //
  5302.     foreach ($a_specs as $s_tag=>$s_value)
  5303.             //
  5304.             // search for
  5305.             //      <tagname/>
  5306.             // with optional whitespace
  5307.             //
  5308.         $s_buf = preg_replace('/<\s*'.preg_quote($s_tag,"/").'\s*\/\s*>/ims',
  5309.                             nl2br($s_value),$s_buf);
  5310.     if ($b_user_error)
  5311.     {
  5312.             // strip any <fmusererror> and </fmusererror> tags
  5313.             //
  5314.             // You can show information that's specific to user
  5315.             // errors between these special tags.
  5316.             //
  5317.         $s_buf = preg_replace('/<\s*\/?\s*fmusererror\s*>/ims','',$s_buf);
  5318.             //
  5319.             // since this isn't a system error, strip anything between
  5320.             // <fmsyserror> and </fmsyserror>
  5321.             //
  5322.         $s_buf = preg_replace('/<\s*fmsyserror\s*>.*<\s*\/\s*fmsyserror\s*>/ims','',$s_buf);
  5323.     }
  5324.     else
  5325.     {
  5326.             // strip any <fmsyserror> and </fmsyserror> tags
  5327.             //
  5328.             // You can show information that's specific to system
  5329.             // errors between these special tags.
  5330.             //
  5331.         $s_buf = preg_replace('/<\s*\/?\s*fmsyserror\s*>/ims','',$s_buf);
  5332.             //
  5333.             // since this isn't a user error, strip anything between
  5334.             // <fmusererror> and </fmusererror>
  5335.             //
  5336.         $s_buf = preg_replace('/<\s*fmusererror\s*>.*<\s*\/\s*fmusererror\s*>/ims','',$s_buf);
  5337.     }
  5338.         //
  5339.         // just output the page
  5340.         //
  5341.     echo $s_buf;
  5342.     return (true);
  5343. }
  5344.  
  5345.     //
  5346.     // To show an error to the user.
  5347.     //
  5348. function ShowError($error_code,$error_mesg,$b_user_error,
  5349.                 $b_alerted = false,$a_item_list = array(),$s_extra_info = "")
  5350. {
  5351.     global  $SPECIAL_FIELDS,$SPECIAL_MULTI,$SPECIAL_VALUES;
  5352.     global  $aServerVars,$aSessionVars,$aStrippedFormVars;
  5353.  
  5354.         //
  5355.         // Testing with PHP 4.0.6 indicates that sessions don't always work.
  5356.         // So, we'll also add the error to the URL, unless
  5357.         // PUT_DATA_IN_URL is false.
  5358.         //
  5359.     $aSessionVars["FormError"] = $error_mesg;
  5360.     $aSessionVars["FormErrorInfo"] = $s_extra_info;
  5361.     $aSessionVars["FormErrorCode"] = $error_code;
  5362.     $aSessionVars["FormErrorItems"] = $a_item_list;
  5363.     $aSessionVars["FormIsUserError"] = $b_user_error;
  5364.     $aSessionVars["FormAlerted"] = $b_alerted;
  5365.     $aSessionVars["FormData"] = array();
  5366.  
  5367.     $bad_url = $SPECIAL_VALUES["bad_url"];
  5368.     $bad_template = $SPECIAL_VALUES["bad_template"];
  5369.     $this_form = $SPECIAL_VALUES["this_form"];
  5370.     if (!empty($bad_url))
  5371.     {
  5372.         $a_params = array();
  5373.         $a_params[] = "this_form=".urlencode("$this_form");
  5374.         $a_params[] = "bad_template=".urlencode("$bad_template");
  5375.         if (PUT_DATA_IN_URL)
  5376.         {
  5377.             $a_params[] = "error=".urlencode("$error_mesg");
  5378.             $a_params[] = "extra=".urlencode("$s_extra_info");
  5379.             $a_params[] = "errcode=".urlencode("$error_code");
  5380.             $a_params[] = "isusererror=".($b_user_error ? "1" : "0");
  5381.             $a_params[] = "alerted=".($b_alerted ? "1" : "0");
  5382.             $i_count = 1;
  5383.             foreach ($a_item_list as $s_item)
  5384.             {
  5385.                 $a_params[] = "erroritem$i_count=".urlencode("$s_item");
  5386.                 $i_count++;
  5387.             }
  5388.         }
  5389.         else
  5390.                 //
  5391.                 // tell the bad_url to look in the session only
  5392.                 //
  5393.             $a_params[] = "insession=1";
  5394.             //
  5395.             // Add the posted data to the URL so that an intelligent
  5396.             // $bad_url can call the form again
  5397.             //
  5398.         foreach ($aStrippedFormVars as $s_name=>$m_value)
  5399.         {
  5400.                 //
  5401.                 // skip special fields
  5402.                 //
  5403.             $b_special = false;
  5404.             if (in_array($s_name,$SPECIAL_FIELDS))
  5405.                 $b_special = true;
  5406.             else
  5407.             {
  5408.                 foreach ($SPECIAL_MULTI as $s_multi_fld)
  5409.                 {
  5410.                     $i_len = strlen($s_multi_fld);
  5411.                     if (substr($s_name,0,$i_len) == $s_multi_fld)
  5412.                     {
  5413.                         $i_index = (int) substr($s_name,$i_len);
  5414.                         if ($i_index > 0)
  5415.                         {
  5416.                             $b_special = true;
  5417.                             break;
  5418.                         }
  5419.                     }
  5420.                 }
  5421.             }
  5422.             if (!$b_special)
  5423.             {
  5424.                 if (PUT_DATA_IN_URL)
  5425.                 {
  5426.                     if (is_array($m_value))
  5427.                         foreach ($m_value as $s_value)
  5428.                             $a_params[] = "$s_name".'[]='.
  5429.                                         urlencode(substr($s_value,0,MAXSTRING));
  5430.                     else
  5431.                         $a_params[] = "$s_name=".urlencode(substr($m_value,0,MAXSTRING));
  5432.                 }
  5433.                 else
  5434.                 {
  5435.                     if (is_array($m_value))
  5436.                         $aSessionVars["FormData"]["$s_name"] = $m_value;
  5437.                     else
  5438.                         $aSessionVars["FormData"]["$s_name"] = substr($m_value,0,MAXSTRING);
  5439.                 }
  5440.             }
  5441.         }
  5442.             //
  5443.             // Now add the authentication data, if any
  5444.             //
  5445.         if ((isset($aServerVars["PHP_AUTH_USER"]) &&
  5446.                 $aServerVars["PHP_AUTH_USER"] !== "") ||
  5447.             (isset($aServerVars["PHP_AUTH_PW"]) &&
  5448.                 $aServerVars["PHP_AUTH_PW"] !== ""))
  5449.         {
  5450.             if (PUT_DATA_IN_URL)
  5451.             {
  5452.                 if (isset($aServerVars["PHP_AUTH_USER"]))
  5453.                     $a_params[] = "PHP_AUTH_USER=".urlencode($aServerVars["PHP_AUTH_USER"]);
  5454.  
  5455.                 if (isset($aServerVars["PHP_AUTH_PW"]))
  5456.                     $a_params[] = "PHP_AUTH_PW=".urlencode($aServerVars["PHP_AUTH_PW"]);
  5457.  
  5458.                 if (isset($aServerVars["PHP_AUTH_TYPE"]))
  5459.                     $a_params[] = "PHP_AUTH_TYPE=".urlencode($aServerVars["PHP_AUTH_TYPE"]);
  5460.             }
  5461.             else
  5462.             {
  5463.                 if (isset($aServerVars["PHP_AUTH_USER"]))
  5464.                     $aSessionVars["FormData"]["PHP_AUTH_USER"] = $aServerVars["PHP_AUTH_USER"];
  5465.  
  5466.                 if (isset($aServerVars["PHP_AUTH_PW"]))
  5467.                     $aSessionVars["FormData"]["PHP_AUTH_PW"] = $aServerVars["PHP_AUTH_PW"];
  5468.  
  5469.                 if (isset($aServerVars["PHP_AUTH_TYPE"]))
  5470.                     $aSessionVars["FormData"]["PHP_AUTH_TYPE"] = $aServerVars["PHP_AUTH_TYPE"];
  5471.             }
  5472.         }
  5473.         $bad_url = AddURLParams($bad_url,$a_params,false);
  5474.         Redirect($bad_url);
  5475.     }
  5476.     else
  5477.     {
  5478.         if (!empty($bad_template))
  5479.         {
  5480.             $a_specs = array("fmerror"=>htmlspecialchars("$error_mesg"),
  5481.                             "fmerrorcode"=>htmlspecialchars("$error_code"),
  5482.                             "fmfullerror"=>htmlspecialchars("$error_mesg")."\n".
  5483.                                             htmlspecialchars("$s_extra_info"),
  5484.                             "fmerrorextra"=>htmlspecialchars("$s_extra_info"),);
  5485.             $i_count = 1;
  5486.             foreach ($a_item_list as $s_item)
  5487.             {
  5488.                 $a_specs["fmerroritem$i_count"] = htmlspecialchars($s_item);
  5489.                 $i_count++;
  5490.             }
  5491.             $s_list = "";
  5492.             foreach ($a_item_list as $s_item)
  5493.                 $s_list .= "<li>".htmlspecialchars($s_item)."</li>\n";
  5494.             $a_specs["fmerroritemlist"] = $s_list;
  5495.             if (ShowErrorTemplate($bad_template,$a_specs,$b_user_error))
  5496.                 return;
  5497.         }
  5498.         $s_text = GetMessage(MSG_ERROR_PROC);
  5499.         if ($b_user_error)
  5500.             $s_text .= $error_mesg."\n".FixedHTMLEntities($s_extra_info);
  5501.         else
  5502.         {
  5503.             global  $SERVER;
  5504.  
  5505.             if ($b_alerted)
  5506.                 $s_text .= GetMessage(MSG_ALERT_DONE,array("SERVER"=>$SERVER));
  5507.             else
  5508.                 $s_text .= GetMessage(MSG_PLS_CONTACT,array("SERVER"=>$SERVER));
  5509.             $s_text .= GetMessage(MSG_APOLOGY,array("SERVER"=>$SERVER));
  5510.         }
  5511.         CreatePage($s_text,false);
  5512.             //
  5513.             // the session data is not needed now
  5514.             //
  5515.         ZapSession();
  5516.     }
  5517. }
  5518.  
  5519.     //
  5520.     // Report an error.  Same as Error, but implements
  5521.     // ATTACK_DETECTION_IGNORE_ERRORS.
  5522.     //
  5523. function ErrorWithIgnore($error_code,$error_mesg,$b_filter = true,$show = true,$int_mesg = "")
  5524. {
  5525.     $b_alerted = false;
  5526.     if (!ATTACK_DETECTION_IGNORE_ERRORS)
  5527.         if (SendAlert("$error_code\n *****$int_mesg*****\nError=$error_mesg\n",$b_filter))
  5528.             $b_alerted = true;
  5529.     if ($show)
  5530.         ShowError($error_code,$error_mesg,false,$b_alerted);
  5531.     else
  5532.             //
  5533.             // show something to the user
  5534.             //
  5535.         ShowError($error_code,GetMessage(MSG_SUBM_FAILED),false,$b_alerted);
  5536.     exit;
  5537. }
  5538.  
  5539.     //
  5540.     // Report an error
  5541.     //
  5542. function Error($error_code,$error_mesg,$b_filter = true,$show = true,$int_mesg = "")
  5543. {
  5544.     $b_alerted = false;
  5545.     if (SendAlert("$error_code\n *****$int_mesg*****\nError=$error_mesg\n",$b_filter))
  5546.         $b_alerted = true;
  5547.     if ($show)
  5548.         ShowError($error_code,$error_mesg,false,$b_alerted);
  5549.     else
  5550.             //
  5551.             // show something to the user
  5552.             //
  5553.         ShowError($error_code,GetMessage(MSG_SUBM_FAILED),false,$b_alerted);
  5554.     exit;
  5555. }
  5556.  
  5557.     //
  5558.     // Report a user error
  5559.     //
  5560. function UserError($s_error_code,$s_error_mesg,
  5561.                     $s_extra_info = "",$a_item_list = array())
  5562. {
  5563.     $b_alerted = false;
  5564.     if (ALERT_ON_USER_ERROR &&
  5565.             SendAlert("$s_error_code\nError=$s_error_mesg\n$s_extra_info\n"))
  5566.         $b_alerted = true;
  5567.     ShowError($s_error_code,$s_error_mesg,true,$b_alerted,$a_item_list,$s_extra_info);
  5568.     exit;
  5569. }
  5570.  
  5571.     //
  5572.     // Create a simple page with the given text.
  5573.     //
  5574. function CreatePage($text,$b_show_about = true)
  5575. {
  5576.     global  $FM_VERS,$sHTMLCharSet;
  5577.  
  5578.     echo "<html>\n";
  5579.     echo "<head>\n";
  5580.     if (isset($sHTMLCharSet) && $sHTMLCharSet !== "")
  5581.         echo "<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=$sHTMLCharSet\">\n";
  5582.     echo "</head>\n";
  5583.     echo "<body>\n";
  5584.     echo nl2br($text);
  5585.     echo "<p />";
  5586.     if ($b_show_about)
  5587.     {
  5588.         echo "<p><small>\n";
  5589.         echo GetMessage(MSG_ABOUT_FORMMAIL,array("FM_VERS"=>$FM_VERS,
  5590.                                                 "TECTITE"=>"www.tectite.com"));
  5591.         echo "</small></p>\n";
  5592.     }
  5593.     echo "</body>\n";
  5594.     echo "</html>\n";
  5595. }
  5596.  
  5597.     //
  5598.     // Strip slashes if magic_quotes_gpc is set.
  5599.     //
  5600. function StripGPC($s_value)
  5601. {
  5602.     if (get_magic_quotes_gpc() != 0)
  5603.         $s_value = stripslashes($s_value);
  5604.     return ($s_value);
  5605. }
  5606.  
  5607.     //
  5608.     // return an array, stripped of slashes if magic_quotes_gpc is set
  5609.     //
  5610. function StripGPCArray($a_values)
  5611. {
  5612.     if (get_magic_quotes_gpc() != 0)
  5613.         foreach ($a_values as $m_key=>$m_value)
  5614.             if (is_array($m_value))
  5615.                     //
  5616.                     // strip arrays recursively
  5617.                     //
  5618.                 $a_values[$m_key] = StripGPCArray($m_value);
  5619.             else
  5620.                     //
  5621.                     // convert scalar to string and strip
  5622.                     //
  5623.                 $a_values[$m_key] = stripslashes("$m_value");
  5624.     return ($a_values);
  5625. }
  5626.  
  5627.     //
  5628.     // Strip a value of unwanted characters, which might be hacks.
  5629.     //
  5630. function Strip($value)
  5631. {
  5632.         //
  5633.         // note that [:cntrl:] etc seems to work with preg_replace, even
  5634.         // though I can't find documentation for it!
  5635.         //
  5636.     $value = preg_replace('/[[:cntrl:][:space:]]+/'," ",$value);    // zap all control chars and multiple blanks
  5637.     return ($value);
  5638. }
  5639.  
  5640.     //
  5641.     // Clean a value.  This means:
  5642.     //  1. convert to string
  5643.     //  2. truncate to maximum length
  5644.     //  3. strip the value of unwanted or dangerous characters (hacks)
  5645.     //  4. trim both ends of whitespace
  5646.     // Each element of an array is cleaned as above.  This process occurs
  5647.     // recursively, so arrays of arrays work OK too (though there's no
  5648.     // need for that in this program).
  5649.     //
  5650.     // Non-scalar values are changed to the string "<X>" where X is the type.
  5651.     // In general, FormMail won't receive non-scalar non-array values, so this
  5652.     // is more a future-proofing measure.
  5653.     //
  5654. function CleanValue($m_value)
  5655. {
  5656.     if (is_array($m_value))
  5657.     {
  5658.         foreach ($m_value as $m_key=>$m_item)
  5659.             $m_value[$m_key] = CleanValue($m_item);
  5660.     }
  5661.     elseif (!is_scalar($m_value))
  5662.         $m_value = "<".gettype($m_value).">";
  5663.     else
  5664.     {
  5665.             //
  5666.             // convert to string and truncate
  5667.             //
  5668.         $m_value = substr("$m_value",0,MAXSTRING);
  5669.             //
  5670.             // strip unwanted chars and trim
  5671.             //
  5672.         $m_value = trim(Strip($m_value));
  5673.     }
  5674.     return ($m_value);
  5675. }
  5676.  
  5677.     //
  5678.     // Clean a special value.  Special values listed in $SPECIAL_NOSTRIP
  5679.     // will not be cleaned.
  5680.     //
  5681. function SpecialCleanValue($s_name,$m_value)
  5682. {
  5683.     global  $SPECIAL_NOSTRIP;
  5684.  
  5685.     if (!in_array($s_name,$SPECIAL_NOSTRIP))
  5686.         $m_value = CleanValue($m_value);
  5687.     return ($m_value);
  5688. }
  5689.  
  5690.     //
  5691.     // Return the fields and their values in a string containing one
  5692.     // field per line.
  5693.     //
  5694. function MakeFieldOutput($a_order,$a_fields,$s_line_feed = BODY_LF)
  5695. {
  5696.     $n_order = count($a_order);
  5697.     $s_output = "";
  5698.     for ($ii = 0 ; $ii < $n_order ; $ii++)
  5699.     {
  5700.         $s_name = $a_order[$ii];
  5701.         if (isset($a_fields[$s_name]))
  5702.             $s_output .= "$s_name: ".$a_fields[$s_name].$s_line_feed;
  5703.     }
  5704.     return ($s_output);
  5705. }
  5706.  
  5707.     //
  5708.     // Check if a field name is special. Returns true if it is.
  5709.     //
  5710. function IsSpecialField($s_name)
  5711. {
  5712.     global  $SPECIAL_FIELDS;
  5713.  
  5714.     return (in_array($s_name,$SPECIAL_FIELDS));
  5715. }
  5716.  
  5717.     //
  5718.     // Set a special field value.
  5719.     //
  5720. function SetSpecialField($s_name,$m_value)
  5721. {
  5722.     global  $SPECIAL_VALUES;
  5723.  
  5724.         //
  5725.         // most special values cannot be arrays; ignore them if they are
  5726.         //
  5727.     if (is_array($m_value))
  5728.     {
  5729.         global  $SPECIAL_ARRAYS;
  5730.  
  5731.         if (!in_array($s_name,$SPECIAL_ARRAYS))
  5732.             return;
  5733.     }
  5734.     $SPECIAL_VALUES[$s_name] = SpecialCleanValue($s_name,$m_value);
  5735. }
  5736.  
  5737.     //
  5738.     // Check if a field name is a special "multi" field.
  5739.     // A multi field is the name plus a sequence number.  For example,
  5740.     //      conditions1
  5741.     //      conditions2
  5742.     // Returns a list (array) if it is, otherwise false if not.
  5743.     // The list contains:
  5744.     //      1. the name of the special multi field
  5745.     //      2. the index number for multi field
  5746.     //
  5747. function IsSpecialMultiField($s_name)
  5748. {
  5749.     global  $SPECIAL_MULTI;
  5750.  
  5751.     foreach ($SPECIAL_MULTI as $s_multi_fld)
  5752.     {
  5753.         $i_len = strlen($s_multi_fld);
  5754.             //
  5755.             // look for nameN where N is a number starting from 1
  5756.             //
  5757.         if (substr($s_name,0,$i_len) == $s_multi_fld)
  5758.         {
  5759.             $i_index = (int) substr($s_name,$i_len);
  5760.             if ($i_index > 0)
  5761.             {
  5762.                     //
  5763.                     // re-index to zero
  5764.                     //
  5765.                 --$i_index;
  5766.                 return (array($s_multi_fld,$i_index));
  5767.             }
  5768.         }
  5769.     }
  5770.     return (false);
  5771. }
  5772.  
  5773.     //
  5774.     // Set a multi field value.
  5775.     //
  5776. function SetSpecialMultiField($s_name,$i_index,$m_value)
  5777. {
  5778.     global  $SPECIAL_VALUES;
  5779.  
  5780.         //
  5781.         // these special fields cannot be arrays - ignore if it is
  5782.         //
  5783.     if (!is_array($m_value))
  5784.         $SPECIAL_VALUES[$s_name][$i_index] = SpecialCleanValue($s_name,$m_value);
  5785. }
  5786.  
  5787.     //
  5788.     // Process a field
  5789.     //
  5790. function ProcessField($s_name,$raw_value,&$a_order,&$a_fields,&$a_raw_fields)
  5791. {
  5792.     global  $FORMATTED_INPUT;
  5793.  
  5794.         //
  5795.         // fields go into an array of special values or an array of other values
  5796.         //
  5797.     $b_special = false;
  5798.     if (IsSpecialField($s_name))
  5799.     {
  5800.         SetSpecialField($s_name,$raw_value);
  5801.         $b_special = true;
  5802.     }
  5803.         //
  5804.         // check for multiple valued special fields
  5805.         //
  5806.     if (($a_multi_fld = IsSpecialMultiField($s_name)) !== false)
  5807.     {
  5808.         SetSpecialMultiField($a_multi_fld[0],$a_multi_fld[1],$raw_value);
  5809.         $b_special = true;
  5810.     }
  5811.     if (!$b_special)
  5812.     {
  5813.             //
  5814.             // return the raw value unchanged in the $a_raw_fields array
  5815.             //
  5816.         $a_raw_fields[$s_name] = $raw_value;
  5817.             //
  5818.             // handle checkboxes and multiple-selection lists
  5819.             // Thanks go to Theodore Boardman for the suggestion
  5820.             // and initial working code.
  5821.             //
  5822.         if (is_array($raw_value))
  5823.         {
  5824.                 //
  5825.                 // the array must be an array of scalars (not an array
  5826.                 // of arrays, for example)
  5827.                 //
  5828.             if (is_scalar($raw_value[0]))
  5829.             {
  5830.                 $a_cleaned_values = CleanValue($raw_value);
  5831.                     //
  5832.                     // the output is a comma separated list of values for the
  5833.                     // checkbox.  For example,
  5834.                     //          events: Diving,Cycling,Running
  5835.                     //
  5836.                     // Set the clean value to the list of cleaned checkbox
  5837.                     // values.
  5838.                     // First, remove any commas in the values themselves.
  5839.                     //
  5840.                 $a_cleaned_values = str_replace(",","",$a_cleaned_values);
  5841.                 $s_cleaned_value = implode(",",$a_cleaned_values);
  5842.             }
  5843.             else
  5844.                 $s_cleaned_value = "<invalid list>";
  5845.         }
  5846.         else
  5847.         {
  5848.                 //
  5849.                 // NOTE: there is a minor bug here now that we support
  5850.                 // $FORM_INI_FILE. The INI file is processed at the end
  5851.                 // so if you set the mail_options below in the INI file they
  5852.                 // won't get processed here.  This means you must set
  5853.                 // the following mail_options in the HTML form for now.
  5854.                 // (To be fixed at a later date.  RJR 17-Feb-06).
  5855.                 //
  5856.  
  5857.                 //
  5858.                 // if the form specifies the "KeepLines" option,
  5859.                 // don't strip new lines
  5860.                 //
  5861.             if (IsMailOptionSet("KeepLines") && strpos($raw_value,"\n") !== false)
  5862.             {
  5863.                     //
  5864.                     // truncate first
  5865.                     //
  5866.                 $s_truncated = substr("$raw_value",0,MAXSTRING);
  5867.                     //
  5868.                     // split into lines, clean each individual line,
  5869.                     // then put it back together again
  5870.                     //
  5871.                 $a_lines = explode("\n",$s_truncated);
  5872.                 $a_lines = CleanValue($a_lines);
  5873.                 $s_cleaned_value = implode(BODY_LF,$a_lines);
  5874.                     //
  5875.                     // and, for this special case, prepend a new line
  5876.                     // so that the value is shown on a fresh line
  5877.                     //
  5878.                 $s_cleaned_value = BODY_LF.$s_cleaned_value;
  5879.             }
  5880.             else
  5881.                 $s_cleaned_value = CleanValue($raw_value);
  5882.         }
  5883.             //
  5884.             // if the form specifies the "NoEmpty" option, skip
  5885.             // empty values.
  5886.             //
  5887.         if (!IsMailOptionSet("NoEmpty") || !IsFieldEmpty($s_cleaned_value))
  5888.             if (!IsMailExcluded($s_name))
  5889.             {
  5890.                     //
  5891.                     // by default, we maintain the order as passed in
  5892.                     // the HTTP request
  5893.                     //
  5894.                 $a_order[] = $s_name;
  5895.                 $a_fields[$s_name] = $s_cleaned_value;
  5896.             }
  5897.  
  5898.             //
  5899.             // add to the $FORMATTED_INPUT array for debugging and
  5900.             // error reporting
  5901.             //
  5902.         array_push($FORMATTED_INPUT,"$s_name: '$s_cleaned_value'");
  5903.     }
  5904. }
  5905.  
  5906.     //
  5907.     // Parse the input variables and return:
  5908.     //  1. an array that specifies the required field order in the output
  5909.     //  2. an array containing the non-special cleaned field values indexed
  5910.     //     by field name.
  5911.     //  3. an array containing the non-special raw field values indexed by
  5912.     //     field name.
  5913.     //
  5914. function ParseInput($a_vars)
  5915. {
  5916.     $a_order = array();
  5917.     $a_fields = array();
  5918.     $a_raw_fields = array();
  5919.         //
  5920.         // scan the array of values passed in (name-value pairs) and
  5921.         // produce slightly formatted (not HTML) textual output
  5922.         // and extract any special values found.
  5923.         //
  5924.     foreach ($a_vars as $s_name=>$raw_value)
  5925.         ProcessField($s_name,$raw_value,$a_order,$a_fields,$a_raw_fields);
  5926.  
  5927.     return (array($a_order,$a_fields,$a_raw_fields));
  5928. }
  5929.  
  5930.     //
  5931.     // Get the URL for sending to the CRM.
  5932.     //
  5933. function GetCRMURL($spec,$vars,$url)
  5934. {
  5935.     $bad = false;
  5936.     $list = TrimArray(explode(",",$spec));
  5937.     $map = array();
  5938.     for ($ii = 0 ; $ii < count($list) ; $ii++)
  5939.     {
  5940.         $name = $list[$ii];
  5941.         if ($name)
  5942.         {
  5943.                 //
  5944.                 // the specification must be in this format:
  5945.                 //      form-field-name:CRM-field-name
  5946.                 //
  5947.             if (($i_crm_name_pos = strpos($name,":")) > 0)
  5948.             {
  5949.                 $s_crm_name = substr($name,$i_crm_name_pos + 1);
  5950.                 $name = substr($name,0,$i_crm_name_pos);
  5951.                 if (isset($vars[$name]))
  5952.                 {
  5953.                     $map[] = $s_crm_name."=".urlencode($vars[$name]);
  5954.                     $map[] = "Orig_".$s_crm_name."=".urlencode($name);
  5955.                 }
  5956.             }
  5957.             else
  5958.             {
  5959.                     //
  5960.                     // not the right format, so just include as a parameter
  5961.                     // check for name=value format to choose encoding
  5962.                     //
  5963.                 $a_values = explode("=",$name);
  5964.                 if (count($a_values) > 1)
  5965.                     $map[] = urlencode($a_values[0])."=".urlencode($a_values[1]);
  5966.                 else
  5967.                     $map[] = urlencode($a_values[0]);
  5968.             }
  5969.         }
  5970.     }
  5971.     if (count($map) == 0)
  5972.         return ("");
  5973.     return (AddURLParams($url,$map,false));
  5974. }
  5975.  
  5976.     //
  5977.     // strip the HTML from a string or array of strings
  5978.     //
  5979. function StripHTML($m_value,$s_line_feed = "\n")
  5980. {
  5981.     if (is_array($m_value))
  5982.     {
  5983.         foreach ($m_value as $m_key=>$s_str)
  5984.             $m_value[$m_key] = StripHTML($s_str);
  5985.         return ($m_value);
  5986.     }
  5987.     $s_str = $m_value;
  5988.         //
  5989.         // strip HTML comments (s option means include new lines in matches)
  5990.         //
  5991.     $s_str = preg_replace('/<!--([^-]*([^-]|-([^-]|-[^>])))*-->/s','',$s_str);
  5992.         //
  5993.         // strip any scripts (i option means case-insensitive)
  5994.         //
  5995.     $s_str = preg_replace('/<script[^>]*?>.*?<\/script[^>]*?>/si','',$s_str);
  5996.         //
  5997.         // replace paragraphs with new lines (line feeds)
  5998.         //
  5999.     $s_str = preg_replace('/<p[^>]*?>/i',$s_line_feed,$s_str);
  6000.         //
  6001.         // replace breaks with new lines (line feeds)
  6002.         //
  6003.     $s_str = preg_replace('/<br[[:space:]]*\/?[[:space:]]*>/i',$s_line_feed,$s_str);
  6004.         //
  6005.         // overcome this bug: http://bugs.php.net/bug.php?id=21311
  6006.         //
  6007.     $s_str = preg_replace('/<![^>]*>/s','',$s_str);
  6008.         //
  6009.         // get rid of all HTML tags
  6010.         //
  6011.     $s_str = strip_tags($s_str);
  6012.     return ($s_str);
  6013. }
  6014.  
  6015.     //
  6016.     // Check for valid URL in TARGET_URLS
  6017.     //
  6018. function CheckValidURL($s_url)
  6019. {
  6020.     global  $TARGET_URLS;
  6021.  
  6022.     foreach ($TARGET_URLS as $s_prefix)
  6023.         if (!empty($s_prefix) &&
  6024.                 strtolower(substr($s_url,0,strlen($s_prefix))) ==
  6025.                 strtolower($s_prefix))
  6026.             return (true);
  6027.     return (false);
  6028. }
  6029.  
  6030.     //
  6031.     // Scan the given data for fields returned from the CRM.
  6032.     // A field has this following format:
  6033.     //      __FIELDNAME__=value
  6034.     // terminated by a line feed.
  6035.     //
  6036. function FindCRMFields($s_data)
  6037. {
  6038.     $a_ret = array();
  6039.     if (preg_match_all('/^__([A-Za-z][A-Za-z0-9_]*)__=(.*)$/m',$s_data,$a_matches) === false)
  6040.         SendAlert(GetMessage(MSG_PREG_FAILED));
  6041.     else
  6042.     {
  6043.         $n_matches = count($a_matches[0]);
  6044.     //  SendAlert("$n_matches on '$s_data'");
  6045.         for ($ii = 0 ; $ii < $n_matches ; $ii++)
  6046.             if (isset($a_matches[1][$ii]) && isset($a_matches[2][$ii]))
  6047.                 $a_ret[$a_matches[1][$ii]] = $a_matches[2][$ii];
  6048.     }
  6049.     return ($a_ret);
  6050. }
  6051.  
  6052.     //
  6053.     // open the given URL to send data to it, we expect the response
  6054.     // to contain at least '__OK__=' followed by true or false
  6055.     //
  6056. function SendToCRM($s_url,&$a_data)
  6057. {
  6058.     global  $php_errormsg;
  6059.  
  6060.     if (!CheckValidURL($s_url))
  6061.     {
  6062.         SendAlert(GetMessage(MSG_URL_INVALID,array("URL"=>$s_url)));
  6063.         return (false);
  6064.     }
  6065. @   $fp = fopen($s_url,"r");
  6066.     if ($fp === false)
  6067.     {
  6068.         SendAlert(GetMessage(MSG_URL_OPEN,array("URL"=>$s_url,
  6069.                                         "ERROR"=>CheckString($php_errormsg))));
  6070.         return (false);
  6071.     }
  6072.     $s_mesg = "";
  6073.     while (!feof($fp))
  6074.     {
  6075.         $s_line = fgets($fp,4096);
  6076.         $s_mesg .= $s_line;
  6077.     }
  6078.     fclose($fp);
  6079.     $s_mesg = StripHTML($s_mesg);
  6080.     $s_result = preg_match('/__OK__=(.*)/',$s_mesg,$a_matches);
  6081.     if (count($a_matches) < 2 || $a_matches[1] === "")
  6082.     {
  6083.             //
  6084.             // no agreed __OK__ value returned - assume system error
  6085.             //
  6086.         SendAlert(GetMessage(MSG_CRM_FAILED,array("URL"=>$s_url,
  6087.                                                 "MSG"=>$s_mesg)));
  6088.         return (false);
  6089.     }
  6090.         //
  6091.         // look for fields to return
  6092.         //
  6093.     $a_data = FindCRMFields($s_mesg);
  6094.         //
  6095.         // check for success or user error
  6096.         //
  6097.     switch (strtolower($a_matches[1]))
  6098.     {
  6099.     case "true":
  6100.         break;
  6101.     case "false":
  6102.             //
  6103.             // check for user error
  6104.             //
  6105.         if (isset($a_data["USERERRORCODE"]))
  6106.         {
  6107.             $s_error_code = "crm_error";
  6108.             $s_error_mesg = GetMessage(MSG_CRM_FORM_ERROR);
  6109.             $s_error_code .= $a_data["USERERRORCODE"];
  6110.             if (isset($a_data["USERERRORMESG"]))
  6111.                 $s_error_mesg = $a_data["USERERRORMESG"];
  6112.             UserError($s_error_code,$s_error_mesg);
  6113.                 // no return
  6114.         }
  6115.         return (false);
  6116.     }
  6117.     return (true);
  6118. }
  6119.  
  6120.     //
  6121.     // Split into field name and friendly name; returns an array with
  6122.     // two elements.
  6123.     // Format is:
  6124.     //      fieldname:Nice printable name for displaying
  6125.     //
  6126. function GetFriendlyName($s_name)
  6127. {
  6128.     if (($i_pos = strpos($s_name,':')) === false)
  6129.         return (array(trim($s_name),trim($s_name)));
  6130.     return (array(trim(substr($s_name,0,$i_pos)),trim(substr($s_name,$i_pos+1))));
  6131. }
  6132.  
  6133. define("REQUIREDOPS","|^!=");       // operand characters for advanced required processing
  6134.  
  6135.     //
  6136.     // Perform a field comparison test.
  6137.     //
  6138. function FieldTest($s_oper,$s_fld1,$s_fld2,$a_vars,&$s_error_mesg,
  6139.                         $s_friendly1 = "",$s_friendly2 = "")
  6140. {
  6141.     $b_ok = true;
  6142.         //
  6143.         // perform the test
  6144.         //
  6145.     switch ($s_oper)
  6146.     {
  6147.     case '&':       // both fields must be present
  6148.         if (!TestFieldEmpty($s_fld1,$a_vars,$s_empty1) &&
  6149.             !TestFieldEmpty($s_fld2,$a_vars,$s_empty2))
  6150.             ;       // OK
  6151.         else
  6152.         {
  6153.                 //
  6154.                 // failed
  6155.                 //
  6156.             $s_error_mesg = GetMessage(MSG_AND,array("ITEM1"=>$s_friendly1,
  6157.                                                     "ITEM2"=>$s_friendly2));
  6158.             $b_ok = false;
  6159.         }
  6160.         break;
  6161.     case '|':       // either field or both must be present
  6162.         if (!TestFieldEmpty($s_fld1,$a_vars,$s_empty1) ||
  6163.             !TestFieldEmpty($s_fld2,$a_vars,$s_empty2))
  6164.             ;       // OK
  6165.         else
  6166.         {
  6167.                 //
  6168.                 // failed
  6169.                 //
  6170.             $s_error_mesg = GetMessage(MSG_OR,array("ITEM1"=>$s_friendly1,
  6171.                                                     "ITEM2"=>$s_friendly2));
  6172.             $b_ok = false;
  6173.         }
  6174.         break;
  6175.     case '^':       // either field but not both must be present
  6176.         $b_got1 = !TestFieldEmpty($s_fld1,$a_vars,$s_empty1);
  6177.         $b_got2 = !TestFieldEmpty($s_fld2,$a_vars,$s_empty2);
  6178.         if ($b_got1 || $b_got2)
  6179.         {
  6180.             if ($b_got1 && $b_got2)
  6181.             {
  6182.                     //
  6183.                     // failed
  6184.                     //
  6185.                 $s_error_mesg = GetMessage(MSG_NOT_BOTH,
  6186.                                             array("ITEM1"=>$s_friendly1,
  6187.                                                   "ITEM2"=>$s_friendly2));
  6188.                 $b_ok = false;
  6189.             }
  6190.         }
  6191.         else
  6192.         {
  6193.                 //
  6194.                 // failed
  6195.                 //
  6196.             $s_error_mesg = GetMessage(MSG_XOR,
  6197.                                         array("ITEM1"=>$s_friendly1,
  6198.                                               "ITEM2"=>$s_friendly2));
  6199.             $b_ok = false;
  6200.         }
  6201.         break;
  6202.     case '!=':
  6203.     case '=':
  6204.         $b_got1 = !TestFieldEmpty($s_fld1,$a_vars,$s_empty1);
  6205.         $b_got2 = !TestFieldEmpty($s_fld2,$a_vars,$s_empty2);
  6206.         if ($b_got1 && $b_got2)
  6207.             $b_match = (GetFieldValue($s_fld1,$a_vars) ==
  6208.                             GetFieldValue($s_fld2,$a_vars));
  6209.         elseif (!$b_got1 && !$b_got2)
  6210.                 //
  6211.                 // haven't got either value - they match
  6212.                 //
  6213.             $b_match = true;
  6214.         else
  6215.                 //
  6216.                 // got one value, but not the other - they don't match
  6217.                 //
  6218.             $b_match = false;
  6219.         if ($s_oper != '=')
  6220.         {
  6221.                 //
  6222.                 // != operator
  6223.                 //
  6224.             $b_match = !$b_match;
  6225.             $s_desc = GetMessage(MSG_IS_SAME_AS,
  6226.                                         array("ITEM1"=>$s_friendly1,
  6227.                                               "ITEM2"=>$s_friendly2));
  6228.         }
  6229.         else
  6230.             $s_desc = GetMessage(MSG_IS_NOT_SAME_AS,
  6231.                                         array("ITEM1"=>$s_friendly1,
  6232.                                               "ITEM2"=>$s_friendly2));
  6233.         if (!$b_match)
  6234.         {
  6235.                 //
  6236.                 // failed
  6237.                 //
  6238.             $s_error_mesg = $s_desc;
  6239.             $b_ok = false;
  6240.         }
  6241.         break;
  6242.     }
  6243.     return ($b_ok);
  6244. }
  6245.  
  6246.     //
  6247.     // Process advanced "required" conditionals
  6248.     //
  6249. function AdvancedRequired($s_cond,$i_span,$a_vars,&$s_missing,&$a_missing_list)
  6250. {
  6251.     $b_ok = true;
  6252.         //
  6253.         // get first field name
  6254.         //
  6255.     list($s_fld1,$s_friendly1) = GetFriendlyName(substr($s_cond,0,$i_span));
  6256.         //
  6257.         // get the operator
  6258.         //
  6259.     $s_rem = substr($s_cond,$i_span);
  6260.     $i_span = strspn($s_rem,REQUIREDOPS);
  6261.     $s_oper = substr($s_rem,0,$i_span);
  6262.     switch ($s_oper)
  6263.     {
  6264.     case '|':
  6265.     case '^':
  6266.     case '=':
  6267.     case '!=':
  6268.             //
  6269.             // second component is a field name
  6270.             //
  6271.         list($s_fld2,$s_friendly2) = GetFriendlyName(substr($s_rem,$i_span));
  6272.         if (!FieldTest($s_oper,$s_fld1,$s_fld2,$a_vars,$s_error_mesg,
  6273.                                                     $s_friendly1,$s_friendly2))
  6274.         {
  6275.                 //
  6276.                 // failed
  6277.                 //
  6278.             $s_missing .= "$s_error_mesg\n";
  6279.             $a_missing_list[] = "$s_error_mesg";
  6280.             $b_ok = false;
  6281.         }
  6282.         break;
  6283.     default:
  6284.         SendAlert(GetMessage(MSG_REQD_OPER,array("OPER"=>$s_oper)));
  6285.         break;
  6286.     }
  6287.     return ($b_ok);
  6288. }
  6289.  
  6290.     //
  6291.     // Check the input for required values.  The list of required fields
  6292.     // is a comma-separated list of field names or conditionals
  6293.     //
  6294. function CheckRequired($s_reqd,$a_vars,&$s_missing,&$a_missing_list)
  6295. {
  6296.     $b_bad = false;
  6297.     $a_list = TrimArray(explode(",",$s_reqd));
  6298.     $s_missing = "";
  6299.     $a_missing_list = array();
  6300.     for ($ii = 0 ; $ii < count($a_list) ; $ii++)
  6301.     {
  6302.         $s_cond = $a_list[$ii];
  6303.         $i_len = strlen($s_cond);
  6304.         if ($i_len <= 0)
  6305.             continue;
  6306.         if (($i_span = strcspn($s_cond,REQUIREDOPS)) >= $i_len)
  6307.         {
  6308.                 //
  6309.                 // no advanced operator; just a field name
  6310.                 //
  6311.             list($s_fld,$s_friendly) = GetFriendlyName($s_cond);
  6312.             if (TestFieldEmpty($s_fld,$a_vars,$s_mesg))
  6313.             {
  6314.                 if ($s_mesg === "")
  6315.                     $s_mesg = "$s_friendly";
  6316.                 else
  6317.                     $s_mesg = "$s_friendly ($s_mesg)";
  6318.                 $b_bad = true;
  6319.                 $s_missing .= "$s_mesg\n";
  6320.                 $a_missing_list[] = "$s_mesg";
  6321.             }
  6322.         }
  6323.         elseif (!AdvancedRequired($s_cond,$i_span,$a_vars,
  6324.                                     $s_missing,$a_missing_list))
  6325.             $b_bad = true;
  6326.     }
  6327.  
  6328.     global  $REQUIRE_CAPTCHA,$SPECIAL_VALUES;
  6329.  
  6330.         //
  6331.         // implement REQUIRE_CAPTCHA feature
  6332.         //
  6333.     if ($REQUIRE_CAPTCHA !== "")
  6334.     {
  6335.         if (!isset($SPECIAL_VALUES["imgverify"]) || $SPECIAL_VALUES["imgverify"] === "")
  6336.         {
  6337.             $s_missing .= "$REQUIRE_CAPTCHA\n";
  6338.             $a_missing_list[] = "$REQUIRE_CAPTCHA";
  6339.             $b_bad = true;
  6340.         }
  6341.     }
  6342.     return (!$b_bad);
  6343. }
  6344.  
  6345.     //
  6346.     // Run a condition test
  6347.     //
  6348. function RunTest($s_test,$a_vars)
  6349. {
  6350.     global  $aAlertInfo;
  6351.  
  6352.     $s_op_chars = "&|^!=~#<>";      // these are the characters for the operators
  6353.     $i_len = strlen($s_test);
  6354.     $b_ok = true;
  6355.     if ($i_len <= 0)
  6356.             //
  6357.             // empty test - true
  6358.             //
  6359.         ;
  6360.     elseif ($s_test == "!")
  6361.             //
  6362.             // test asserts false
  6363.             //
  6364.         $b_ok = false;
  6365.     elseif (($i_span = strcspn($s_test,$s_op_chars)) >= $i_len)
  6366.             //
  6367.             // no operator - just check field presence
  6368.             //
  6369.         $b_ok = !TestFieldEmpty($s_test,$a_vars,$s_mesg);
  6370.     else
  6371.     {
  6372.             //
  6373.             // get first field name
  6374.             //
  6375.         $s_fld1 = trim(substr($s_test,0,$i_span));
  6376.             //
  6377.             // get the operator
  6378.             //
  6379.         $s_rem = substr($s_test,$i_span);
  6380.         $i_span = strspn($s_rem,$s_op_chars);
  6381.         $s_oper = substr($s_rem,0,$i_span);
  6382.         switch ($s_oper)
  6383.         {
  6384.         case '&':
  6385.         case '|':
  6386.         case '^':
  6387.         case '=':
  6388.         case '!=':
  6389.                 //
  6390.                 // get the second field name
  6391.                 //
  6392.             $s_fld2 = trim(substr($s_rem,$i_span));
  6393.             $b_ok = FieldTest($s_oper,$s_fld1,$s_fld2,$a_vars,$s_error_mesg);
  6394.             break;
  6395.         case '~':
  6396.         case '!~':
  6397.                 //
  6398.                 // get the regular expression
  6399.                 //
  6400.             $s_pat = trim(substr($s_rem,$i_span));
  6401.             if (!TestFieldEmpty($s_fld1,$a_vars,$s_mesg))
  6402.                 $s_value = GetFieldValue($s_fld1,$a_vars);
  6403.             else
  6404.                 $s_value = "";
  6405.             //echo "<p>Pattern: '".htmlspecialchars($s_pat)."': count=".preg_match($s_pat,$s_value)."<br /></p>";
  6406.                 //
  6407.                 // match the regular expression
  6408.                 //
  6409.             if (preg_match($s_pat,$s_value) > 0)
  6410.                 $b_ok = ($s_oper == '~');
  6411.             else
  6412.                 $b_ok = ($s_oper == '!~');
  6413.             if (!$b_ok)
  6414.                 $aAlertInfo[] = GetMessage(MSG_PAT_FAILED,array("OPER"=>$s_oper,
  6415.                                                             "PAT"=>$s_pat,
  6416.                                                             "VALUE"=>$s_value));
  6417.             break;
  6418.         case '#=':
  6419.         case '#!=':
  6420.         case '#<':
  6421.         case '#>':
  6422.         case '#<=':
  6423.         case '#>=':
  6424.                 //
  6425.                 // numeric tests
  6426.                 //
  6427.             $s_num = trim(substr($s_rem,$i_span));
  6428.                 //
  6429.                 // if this is a file field, get the size of the file for
  6430.                 // numeric tests
  6431.                 //
  6432.             if (($s_value = GetFileSize($s_fld1)) === false)
  6433.                 $s_value = $a_vars[$s_fld1];
  6434.             if (strpos($s_num,'.') === false)
  6435.             {
  6436.                     //
  6437.                     // treat as integer
  6438.                     //
  6439.                 $m_num = (int) $s_num;
  6440.                 $m_fld = (int) $s_value;
  6441.             }
  6442.             else
  6443.             {
  6444.                     //
  6445.                     // treat as floating point
  6446.                     //
  6447.                 $m_num = (float) $s_num;
  6448.                 $m_fld = (float) $s_value;
  6449.             }
  6450.             switch ($s_oper)
  6451.             {
  6452.             case '#=':
  6453.                 $b_ok = ($m_fld == $m_num);
  6454.                 break;
  6455.             case '#!=':
  6456.                 $b_ok = ($m_fld != $m_num);
  6457.                 break;
  6458.             case '#<':
  6459.                 $b_ok = ($m_fld < $m_num);
  6460.                 break;
  6461.             case '#>':
  6462.                 $b_ok = ($m_fld > $m_num);
  6463.                 break;
  6464.             case '#<=':
  6465.                 $b_ok = ($m_fld <= $m_num);
  6466.                 break;
  6467.             case '#>=':
  6468.                 $b_ok = ($m_fld >= $m_num);
  6469.                 break;
  6470.             }
  6471.             break;
  6472.         default:
  6473.             SendAlert(GetMessage(MSG_COND_OPER,array("OPER"=>$s_oper)));
  6474.             break;
  6475.         }
  6476.     }
  6477.     return ($b_ok);
  6478. }
  6479.  
  6480.     //
  6481.     // Check the input for condition tests.
  6482.     //
  6483. function CheckConditions($m_conditions,$a_vars,&$s_missing,&$a_missing_list,$m_id = false)
  6484. {
  6485.     if (is_array($m_conditions))
  6486.     {
  6487.             //
  6488.             // Sort the conditions by their numeric value.  This ensures
  6489.             // conditions are executed in the right order.
  6490.             //
  6491.         ksort($m_conditions,SORT_NUMERIC);
  6492.         foreach ($m_conditions as $m_key=>$s_cond)
  6493.             if (!CheckConditions($s_cond,$a_vars,$s_missing,$a_missing_list,$m_key))
  6494.                 return (false);
  6495.         return (true);
  6496.     }
  6497.     $s_fld_name = "conditions".($m_id === false ? "" : ($m_id+1));
  6498.     if (!is_string($m_conditions))
  6499.     {
  6500.         SendAlert(GetMessage(MSG_INV_COND,array("FLD"=>$s_fld_name)));
  6501.         return (true);  // pass invalid conditions
  6502.     }
  6503.     if ($m_conditions == "")
  6504.         return (true);  // pass empty conditions
  6505.     $s_cond = $m_conditions;
  6506.         //
  6507.         // extract the separator characters
  6508.         //
  6509.     if (strlen($s_cond) < 2)
  6510.     {
  6511.         SendAlert(GetMessage(MSG_COND_CHARS,
  6512.                         array("FLD"=>$s_fld_name,"COND"=>$s_cond)));
  6513.         return (true);  // pass invalid conditions
  6514.     }
  6515.     $s_list_sep = $s_cond{0};
  6516.     $s_int_sep = $s_cond{1};
  6517.     $s_full_cond = $s_cond = substr($s_cond,2);
  6518.     $b_bad = false;
  6519.     $a_list = TrimArray(explode($s_list_sep,$s_cond));
  6520.     $s_missing = "";
  6521.     $a_missing_list = array();
  6522.     for ($ii = 0 ; $ii < count($a_list) ; $ii++)
  6523.     {
  6524.         $s_cond = $a_list[$ii];
  6525.         $i_len = strlen($s_cond);
  6526.         if ($i_len <= 0)
  6527.             continue;
  6528.             //
  6529.             // split the condition into its internal components
  6530.             //
  6531.         $a_components = TrimArray(explode($s_int_sep,$s_cond));
  6532.         if (count($a_components) < 5)
  6533.         {
  6534.             SendAlert(GetMessage(MSG_COND_INVALID,
  6535.                         array("FLD"=>$s_fld_name,"COND"=>$s_cond,
  6536.                               "SEP"=>$s_int_sep)));
  6537.                 //
  6538.                 // the smallest condition has 5 components
  6539.                 //
  6540.             continue;
  6541.         }
  6542.             //
  6543.             // first component is ignored (it's blank)
  6544.             //
  6545.         $a_components = array_slice($a_components,1);
  6546.         switch ($a_components[0])
  6547.         {
  6548.         case "TEST":
  6549.             if (count($a_components) > 5)
  6550.             {
  6551.                 SendAlert(GetMessage(MSG_COND_TEST_LONG,
  6552.                         array("FLD"=>$s_fld_name,"COND"=>$s_cond,
  6553.                               "SEP"=>$s_list_sep)));
  6554.                 continue;
  6555.             }
  6556.             if (!RunTest($a_components[1],$a_vars))
  6557.             {
  6558.                 $s_missing .= $a_components[2]."\n";
  6559.                 $a_missing_list[] = $a_components[2];
  6560.                 $b_bad = true;
  6561.             }
  6562.             break;
  6563.         case "IF":
  6564.             if (count($a_components) < 6)
  6565.             {
  6566.                 SendAlert(GetMessage(MSG_COND_IF_SHORT,
  6567.                         array("FLD"=>$s_fld_name,"COND"=>$s_cond,
  6568.                               "SEP"=>$s_int_sep)));
  6569.                 continue;
  6570.             }
  6571.             if (count($a_components) > 7)
  6572.             {
  6573.                 SendAlert(GetMessage(MSG_COND_IF_LONG,
  6574.                         array("FLD"=>$s_fld_name,"COND"=>$s_cond,
  6575.                               "SEP"=>$s_list_sep)));
  6576.                 continue;
  6577.             }
  6578.             if (RunTest($a_components[1],$a_vars))
  6579.                 $b_test = RunTest($a_components[2],$a_vars);
  6580.             else
  6581.                 $b_test = RunTest($a_components[3],$a_vars);
  6582.             if (!$b_test)
  6583.             {
  6584.                 $s_missing .= $a_components[4]."\n";
  6585.                 $a_missing_list[] = $a_components[4];
  6586.                 $b_bad = true;
  6587.             }
  6588.             break;
  6589.         default:
  6590.             SendAlert(GetMessage(MSG_COND_UNK,
  6591.                         array("FLD"=>$s_fld_name,"COND"=>$s_cond,
  6592.                               "CMD"=>$a_components[0])));
  6593.             break;
  6594.         }
  6595.     }
  6596.     return (!$b_bad);
  6597. }
  6598.  
  6599.     //
  6600.     // Return a formatted list of the given environment variables.
  6601.     //
  6602. function GetEnvVars($list,$s_line_feed)
  6603. {
  6604.     global  $VALID_ENV,$aServerVars;
  6605.  
  6606.     $output = "";
  6607.     for ($ii = 0 ; $ii < count($list) ; $ii++)
  6608.     {
  6609.         $name = $list[$ii];
  6610.         if ($name && array_search($name,$VALID_ENV,true) !== false)
  6611.         {
  6612.                 //
  6613.                 // if the environment variable is empty or non-existent, try
  6614.                 // looking for the value in the server vars.
  6615.                 //
  6616.             if (($s_value = getenv($name)) === "" || $s_value === false)
  6617.                 if (isset($aServerVars[$name]))
  6618.                     $s_value = $aServerVars[$name];
  6619.                 else
  6620.                     $s_value = "";
  6621.             $output .= $name."=".$s_value.$s_line_feed;
  6622.         }
  6623.     }
  6624.     return ($output);
  6625. }
  6626.     //
  6627.     // open a socket connection to a filter and post the data there
  6628.     //
  6629. function SocketFilter($filter,$a_filter_info,$m_data)
  6630. {
  6631.     static  $b_in_here = false;
  6632.     global  $php_errormsg;
  6633.  
  6634.         //
  6635.         // prevent recursive errors
  6636.         //
  6637.     if ($b_in_here)
  6638.         return ("<DATA DISCARDED>");
  6639.     $b_in_here = true;
  6640.  
  6641.     $a_errors = array();
  6642.     if (!isset($a_filter_info["site"]))
  6643.         $a_errors[] = GetMessage(MSG_MISSING,array("ITEM"=>"site"));
  6644.     else
  6645.         $s_site = $a_filter_info["site"];
  6646.  
  6647.     if (!isset($a_filter_info["port"]))
  6648.         $a_errors[] = GetMessage(MSG_MISSING,array("ITEM"=>"port"));
  6649.     else
  6650.         $i_port = (int) $a_filter_info["port"];
  6651.  
  6652.     if (!isset($a_filter_info["path"]))
  6653.         $a_errors[] = GetMessage(MSG_MISSING,array("ITEM"=>"path"));
  6654.     else
  6655.         $s_path = $a_filter_info["path"];
  6656.  
  6657.     if (!isset($a_filter_info["params"]))
  6658.         $a_params = array();
  6659.     elseif (!is_array($a_filter_info["params"]))
  6660.         $a_errors[] = GetMessage(MSG_NEED_ARRAY,array("ITEM"=>"params"));
  6661.     else
  6662.         $a_params = $a_filter_info["params"];
  6663.  
  6664.     if (!empty($a_errors))
  6665.     {
  6666.         Error("bad_filter",GetMessage(MSG_FILTER_WRONG,array(
  6667.                             "FILTER"=>$filter,
  6668.                             "ERRORS"=>implode(', ',$a_errors))),false,false);
  6669.         exit;
  6670.     }
  6671.  
  6672.         //
  6673.         // ready to build the socket - we need a longer time limit for the
  6674.         // script if we're doing this; we allow 30 seconds for the connection
  6675.         // (should be instantaneous, especially if it's the same domain)
  6676.         //
  6677.     set_time_limit(60);
  6678. @   $f_sock = fsockopen($s_site,$i_port,$i_errno,$s_errstr,30);
  6679.     if ($f_sock === false)
  6680.     {
  6681.         Error("filter_connect",GetMessage(MSG_FILTER_CONNECT,array(
  6682.                             "FILTER"=>$filter,
  6683.                             "SITE"=>$s_site,
  6684.                             "ERRNUM"=>$i_errno,
  6685.                             "ERRSTR"=>"$s_errstr (".CheckString($php_errormsg).")")),
  6686.                             false,false);
  6687.         exit;
  6688.     }
  6689.         //
  6690.         // build the data to send
  6691.         //
  6692.     $m_request_data = array();
  6693.     $i_count = 0;
  6694.     foreach ($a_params as $m_var)
  6695.     {
  6696.         $i_count++;
  6697.             //
  6698.             // if the parameter spec is an array, process it specially;
  6699.             // it must have "name" and "file" elements
  6700.             //
  6701.         if (is_array($m_var))
  6702.         {
  6703.             if (!isset($m_var["name"]))
  6704.             {
  6705.                 Error("bad_filter",GetMessage(MSG_FILTER_PARAM,
  6706.                                     array("FILTER"=>$filter,
  6707.                                           "NUM"=>$i_count,
  6708.                                           "NAME"=>"name")),false,false);
  6709.                 fclose($f_sock);
  6710.                 exit;
  6711.             }
  6712.             $s_name = $m_var["name"];
  6713.             if (!isset($m_var["file"]))
  6714.             {
  6715.                 Error("bad_filter",GetMessage(MSG_FILTER_PARAM,
  6716.                                     array("FILTER"=>$filter,
  6717.                                           "NUM"=>$i_count,
  6718.                                           "NAME"=>"file")),false,false);
  6719.                 fclose($f_sock);
  6720.                 exit;
  6721.             }
  6722.                 //
  6723.                 // open the file and read its contents
  6724.                 //
  6725. @           $fp = fopen($m_var["file"],"r");
  6726.             if ($fp === false)
  6727.             {
  6728.                 Error("filter_error",GetMessage(MSG_FILTER_OPEN_FILE,
  6729.                                     array("FILTER"=>$filter,
  6730.                                           "FILE"=>$m_var["file"],
  6731.                                           "ERROR"=>CheckString($php_errormsg))),false,false);
  6732.                 fclose($f_sock);
  6733.                 exit;
  6734.             }
  6735.             $s_data = "";
  6736.             $n_lines = 0;
  6737.             while (!feof($fp))
  6738.             {
  6739.                 if (($s_line = fgets($fp,2048)) === false)
  6740.                     if (feof($fp))
  6741.                         break;
  6742.                     else
  6743.                     {
  6744.                         Error("filter_error",GetMessage(MSG_FILTER_FILE_ERROR,
  6745.                                     array("FILTER"=>$filter,
  6746.                                           "FILE"=>$m_var["file"],
  6747.                                           "ERROR"=>CheckString($php_errormsg),
  6748.                                           "NLINES"=>$n_lines)),false,false);
  6749.                         fclose($f_sock);
  6750.                         exit;
  6751.                     }
  6752.                 $s_data .= $s_line;
  6753.                 $n_lines++;
  6754.             }
  6755.  
  6756.             fclose($fp);
  6757.             $m_request_data[] = "$s_name=".urlencode($s_data);
  6758.         }
  6759.         else
  6760.             $m_request_data[] = (string) $m_var;
  6761.     }
  6762.         //
  6763.         // add the data
  6764.         //
  6765.     if (is_array($m_data))
  6766.         $m_request_data[] = "data=".urlencode(implode(BODY_LF,$m_data));
  6767.     else
  6768.         $m_request_data[] = "data=".urlencode($m_data);
  6769.     $s_request = implode("&",$m_request_data);
  6770.  
  6771.     if (($i_pos = strpos($s_site,"://")) !== false)
  6772.         $s_site_name = substr($s_site,$i_pos+3);
  6773.     else
  6774.         $s_site_name = $s_site;
  6775.  
  6776.     fputs($f_sock,"POST $s_path HTTP/1.0\r\n");
  6777.     fputs($f_sock,"Host: $s_site_name\r\n");
  6778.     fputs($f_sock,"Content-Type: application/x-www-form-urlencoded\r\n");
  6779.     fputs($f_sock,"Content-Length: ".strlen($s_request)."\r\n");
  6780.     fputs($f_sock,"\r\n");
  6781.     fputs($f_sock,"$s_request\r\n");
  6782.  
  6783.         //
  6784.         // now read the response
  6785.         //
  6786.     $m_hdr = "";
  6787.     $m_data = "";
  6788.     $b_in_hdr = true;
  6789.     $b_ok = false;
  6790.     while (!feof($f_sock))
  6791.     {
  6792.         if (($s_line = fgets($f_sock,2048)) === false)
  6793.             if (feof($f_sock))
  6794.                 break;
  6795.             else
  6796.             {
  6797.                 Error("filter_failed",GetMessage(MSG_FILTER_READ_ERROR,
  6798.                             array("FILTER"=>$filter,
  6799.                                   "ERROR"=>CheckString($php_errormsg))),false,false);
  6800.                 fclose($f_sock);
  6801.                 exit;
  6802.             }
  6803.             //
  6804.             // look for an "__OK__" line
  6805.             //
  6806.         if (trim($s_line) == "__OK__")
  6807.             $b_ok = true;
  6808.         elseif ($b_in_hdr)
  6809.         {
  6810.                 //
  6811.                 // blank line signals end of header
  6812.                 //
  6813.             if (trim($s_line) == "")
  6814.                 $b_in_hdr = false;
  6815.             else
  6816.                 $m_hdr .= $s_line;
  6817.         }
  6818.         else
  6819.             $m_data .= $s_line;
  6820.     }
  6821.         //
  6822.         // if not OK, then report error
  6823.         //
  6824.     if (!$b_ok)
  6825.     {
  6826.         Error("filter_failed",GetMessage(MSG_FILTER_NOT_OK,
  6827.                     array("FILTER"=>$filter,
  6828.                           "DATA"=>$m_data)),false,false);
  6829.         fclose($f_sock);
  6830.         exit;
  6831.     }
  6832.     fclose($f_sock);
  6833.     $b_in_here = false;
  6834.     return ($m_data);
  6835. }
  6836.  
  6837.     //
  6838.     // run data through a supported filter
  6839.     //
  6840. function Filter($filter,$m_data)
  6841. {
  6842.     global  $FILTERS,$SOCKET_FILTERS;
  6843.     global  $php_errormsg;
  6844.     static  $b_in_here = false;
  6845.  
  6846.         //
  6847.         // prevent recursive errors
  6848.         //
  6849.     if ($b_in_here)
  6850.         return ("<DATA DISCARDED>");
  6851.     $b_in_here = true;
  6852.  
  6853.         //
  6854.         // Any errors sent in an alert are flagged to not run through the
  6855.         // filter - this also means the user's data won't be included in the
  6856.         // alert.
  6857.         // The reason for this is that the Filter is typically an encryption
  6858.         // program. If the filter fails, then sending the user's data in
  6859.         // clear text in an alert breaks the security of having encryption
  6860.         // in the first place!
  6861.         //
  6862.  
  6863.         //
  6864.         // find the filter
  6865.         //
  6866.     if (!isset($FILTERS[$filter]) || $FILTERS[$filter] == "")
  6867.     {
  6868.             //
  6869.             // check for SOCKET_FILTERS
  6870.             //
  6871.         if (!isset($SOCKET_FILTERS[$filter]) || $SOCKET_FILTERS[$filter] == "")
  6872.         {
  6873.             ErrorWithIgnore("bad_filter",GetMessage(MSG_FILTER_UNK,
  6874.                         array("FILTER"=>$filter)),false,false);
  6875.             exit;
  6876.         }
  6877.         $m_data = SocketFilter($filter,$SOCKET_FILTERS[$filter],$m_data);
  6878.     }
  6879.     elseif ($FILTERS[$filter] == "null")
  6880.             //
  6881.             // do nothing - just return the original data unchanged
  6882.             //
  6883.         ;
  6884.     elseif ($FILTERS[$filter] == "csv")
  6885.         $m_data = BuiltinFilterCSV();
  6886.     else
  6887.     {
  6888.         $cmd = $FILTERS[$filter];
  6889.             //
  6890.             // get the program name - assumed to be the first blank-separated word
  6891.             //
  6892.         $a_words = preg_split('/\s+/',$cmd);
  6893.         $prog = $a_words[0];
  6894.  
  6895.         $s_cwd = getcwd();
  6896.             //
  6897.             // change to the directory that contains the filter program
  6898.             //
  6899.         $dirname = dirname($prog);
  6900.         if ($dirname != "" && $dirname != "." && !chdir($dirname))
  6901.         {
  6902.             Error("chdir_filter",GetMessage(MSG_FILTER_CHDIR,
  6903.                         array("DIR"=>$dirname,"FILTER"=>$filter,
  6904.                               "ERROR"=>CheckString($php_errormsg))),false,false);
  6905.             exit;
  6906.         }
  6907.  
  6908.             //
  6909.             // the output of the filter goes to a temporary file; this works
  6910.             // OK on Windows too, even with the Unix shell syntax.
  6911.             //
  6912.         $temp_file = GetTempName("FMF");
  6913.         $cmd = "$cmd > $temp_file 2>&1";
  6914.             //
  6915.             // start the filter
  6916.             //
  6917.         $pipe = popen($cmd,"w");
  6918.         if ($pipe === false)
  6919.         {
  6920.             $s_sv_err = CheckString($php_errormsg);
  6921.             $err = join('',file($temp_file));
  6922.             unlink($temp_file);
  6923.             Error("filter_not_found",GetMessage(MSG_FILTER_NOTFOUND,
  6924.                         array("CMD"=>$cmd,"FILTER"=>$filter,
  6925.                               "ERROR"=>$s_sv_err)),false,false,$err);
  6926.             exit;
  6927.         }
  6928.             //
  6929.             // write the data to the filter
  6930.             //
  6931.         if (is_array($m_data))
  6932.             fwrite($pipe,implode(BODY_LF,$m_data));
  6933.         else
  6934.             fwrite($pipe,$m_data);
  6935.         if (($i_st = pclose($pipe)) != 0)
  6936.         {
  6937.             $s_sv_err = CheckString($php_errormsg);
  6938.             $err = join('',file($temp_file));
  6939.             unlink($temp_file);
  6940.             Error("filter_failed",GetMessage(MSG_FILTER_ERROR,
  6941.                         array("FILTER"=>$filter,
  6942.                               "ERROR"=>$s_sv_err,
  6943.                               "STATUS"=>$i_st)),false,false,$err);
  6944.             exit;
  6945.         }
  6946.             //
  6947.             // read in the filter's output and return as the data to be sent
  6948.             //
  6949.         $m_data = join('',file($temp_file));
  6950.         unlink($temp_file);
  6951.  
  6952.             //
  6953.             // return to previous directory
  6954.             //
  6955.         chdir($s_cwd);
  6956.     }
  6957.     $b_in_here = false;
  6958.     return ($m_data);
  6959. }
  6960.  
  6961. /*
  6962.  * Class:       CSVFormat
  6963.  * Description:     
  6964.  *  Manages formatting of CSV content.
  6965.  */
  6966. class   CSVFormat
  6967. {
  6968.     var         $_cSep;         /* field separator character */
  6969.     var         $_cQuote;       /* field quote character */
  6970.     var         $_cIntSep;      /* internal separator character (for lists) */
  6971.     var         $_sEscPolicy;   /* escape processing policy */
  6972.     var         $_sCleanFunc;   /* cleaning function for fields */
  6973.  
  6974.     /*
  6975.      * Method:      CSVFormat ctor
  6976.      * Parameters:  $c_sep          the field separator
  6977.      *              $c_quote        the quote character to use
  6978.      *              $c_int_sep      the internal field separator to use
  6979.      *              $s_esc_policy   escape processing policy to use
  6980.      *              $s_clean_func   a cleaning function
  6981.      * Returns:     n/a
  6982.      * Description: 
  6983.      *  Constructs the object.
  6984.      */
  6985.     function    CSVFormat($c_sep = ',',$c_quote = '"',$c_int_sep = ';',
  6986.                             $s_esc_policy = "backslash",$s_clean_func = NULL)
  6987.     {
  6988.         $this->SetSep($c_sep);
  6989.         $this->SetQuote($c_quote);
  6990.         $this->SetIntSep($c_int_sep);
  6991.         $this->SetEscPolicy($s_esc_policy);
  6992.         $this->SetCleanFunc($s_clean_func);
  6993.     }
  6994.  
  6995.     /*
  6996.      * Method:      SetEscPolicy
  6997.      * Parameters:  $s_esc_policy   a string specifying the escape processing
  6998.      *                              policy to use
  6999.      * Returns:     void
  7000.      * Description: 
  7001.      *  Set the escape processing policy.
  7002.      */
  7003.  
  7004.     function    SetEscPolicy($s_esc_policy)
  7005.     {
  7006.         switch ($s_esc_policy)
  7007.         {
  7008.         default:        /* should generate a warning */
  7009.         case "backslash":
  7010.                 $this->_sEscPolicy = "b";
  7011.                 break;
  7012.         case "double":
  7013.                 $this->_sEscPolicy = "d";
  7014.                 break;
  7015.         case "strip":
  7016.                 $this->_sEscPolicy = "s";
  7017.                 break;
  7018.         case "conv":
  7019.                 $this->_sEscPolicy = "c";
  7020.                 break;
  7021.         }
  7022.     }
  7023.  
  7024.     /*
  7025.      * Method:      SetSep
  7026.      * Parameters:  $c_sep      the separator character to use
  7027.      * Returns:     void
  7028.      * Description: 
  7029.      *  Set the separator character for between fields.
  7030.      */
  7031.     function    SetSep($c_sep)
  7032.     {
  7033.         $this->_cSep = $c_sep;
  7034.     }
  7035.  
  7036.     /*
  7037.      * Method:      SetQuote
  7038.      * Parameters:  $c_quote      the quote character to use
  7039.      * Returns:     void
  7040.      * Description: 
  7041.      *  Set the quote character for quoting fields.
  7042.      */
  7043.     function    SetQuote($c_quote)
  7044.     {
  7045.         $this->_cQuote = $c_quote;
  7046.     }
  7047.  
  7048.     /*
  7049.      * Method:      SetIntSep
  7050.      * Parameters:  $c_int_sep      the internal separator character to use
  7051.      * Returns:     void
  7052.      * Description: 
  7053.      *  Set the internal separator character for inside fields.
  7054.      */
  7055.     function    SetIntSep($c_int_sep)
  7056.     {
  7057.         $this->_cIntSep = $c_int_sep;
  7058.     }
  7059.  
  7060.     /*
  7061.      * Method:      SetCleanFunc
  7062.      * Parameters:  $s_clean_func   the name of a cleaning function (can be NULL)
  7063.      * Returns:     void
  7064.      * Description: 
  7065.      *  Set the cleaning function for fields.
  7066.      */
  7067.     function    SetCleanFunc($s_clean_func)
  7068.     {
  7069.         $this->_sCleanFunc = $s_clean_func;
  7070.     }
  7071.  
  7072.     /*
  7073.      * Method:      _Escape
  7074.      * Parameters:  $m_value    the field value; string or array of strings 
  7075.      * Returns:     mixed       the field value escaped according to the
  7076.      *                          escape processing policy
  7077.      * Description: 
  7078.      *  Escapes a field value according to the configured requirements.
  7079.      */
  7080.     function    _Escape($m_value)
  7081.     {
  7082.         switch ($this->_sEscPolicy)
  7083.         {
  7084.         default:            /* should generate an error */
  7085.         case "b":
  7086.                     /*
  7087.                      * 'backslash' escape policy: replace \ with \\ and
  7088.                      * " with \"
  7089.                      */
  7090.                 $m_value = str_replace("\\","\\\\",$m_value);
  7091.                 $m_value = str_replace($this->_cQuote,"\\".$this->_cQuote,
  7092.                                                                     $m_value);
  7093.                 break;
  7094.         case "d":
  7095.                     /*
  7096.                      * 'double' escape policy: replace " with ""
  7097.                      * This is suitable for Microsoft apps such as Excel
  7098.                      * and Access. It also meets the specification of
  7099.                      * RFC4180, though this RFC only specified double
  7100.                      * quotes whereas we handle any quote character.
  7101.                      */
  7102.                 $m_value = str_replace($this->_cQuote,
  7103.                                         $this->_cQuote.$this->_cQuote,$m_value);
  7104.                 break;
  7105.         case "s":
  7106.                     /*
  7107.                      * 'strip' escape policy: strip quotes
  7108.                      */
  7109.                 $m_value = str_replace($this->_cQuote,"",$m_value);
  7110.                 break;
  7111.         case "c":
  7112.                     /*
  7113.                      * 'conv' escape policy: convert quotes to the other quotes
  7114.                      */
  7115.                 switch ($this->_cQuote)
  7116.                 {
  7117.                 case '"':
  7118.                         /*
  7119.                          * convert double quotes in the data to single quotes
  7120.                          */
  7121.                     $m_value = str_replace("\"","'",$m_value);
  7122.                     break;
  7123.                 case '\'':
  7124.                         /*
  7125.                          * convert single quotes in the data to double quotes
  7126.                          */
  7127.                     $m_value = str_replace("'","\"",$m_value);
  7128.                     break;
  7129.                 default:
  7130.                         /*
  7131.                          * otherwise, leave the data unchanged
  7132.                          */
  7133.                     break;
  7134.                 }
  7135.                 break;
  7136.         }
  7137.         return ($m_value);
  7138.     }
  7139.  
  7140.     function    _Format($m_value)
  7141.     {
  7142.         $m_value = $this->_Escape($m_value);
  7143.             /*
  7144.              * we handle strings and arrays of strings
  7145.              */
  7146.         if (is_array($m_value))
  7147.                 /*
  7148.                  * separate the values with the internal field separator
  7149.                  */
  7150.             $m_value = implode($this->_cIntSep,$m_value);
  7151.         return ($this->_cQuote.$m_value.$this->_cQuote);
  7152.     }
  7153.  
  7154.     /*
  7155.      * Method:      MakeCSVRecord
  7156.      * Parameters:  $a_column_list  a list of column names (field names) to
  7157.      *                              include
  7158.      *              $a_vars         raw data array indexed by column name
  7159.      *                              (field name).
  7160.      *                              A data value can be a string or an array
  7161.      *                              of strings.
  7162.      * Returns:     string          the comma-separated value    
  7163.      * Description: 
  7164.      *  Creates a single CSV record for a list of columns.
  7165.      */
  7166.     function    MakeCSVRecord($a_column_list,$a_vars)
  7167.     {
  7168.         $s_rec = "";
  7169.         $n_columns = count($a_column_list);
  7170.         for ($ii = 0 ; $ii < $n_columns ; $ii++)
  7171.         {
  7172.             $s_col_name = $a_column_list[$ii];
  7173.                 /*
  7174.                  * if a column is specified it must be included, even if there
  7175.                  * is no data for it.
  7176.                  */
  7177.             if (isset($a_vars[$s_col_name]))
  7178.             {
  7179.                 $m_value = $a_vars[$s_col_name];
  7180.                 if (isset($this->_sCleanFunc))
  7181.                 {
  7182.                     $s_func = $this->_sCleanFunc;
  7183.                     $m_value = $s_func($m_value);
  7184.                 }
  7185.             }
  7186.             else
  7187.                 $m_value = "";
  7188.  
  7189.             $m_value = $this->_Format($m_value);
  7190.             if ($ii > 0)
  7191.                     /*
  7192.                      * prepend the separator from the second field onwards
  7193.                      */
  7194.                 $s_rec .= $this->_cSep;
  7195.             $s_rec .= $m_value;
  7196.         }
  7197.         return ($s_rec);
  7198.     }
  7199.  
  7200.     /*
  7201.      * Method:      MakeHeading
  7202.      * Parameters:  $a_column_list  a list of column names (field names) to
  7203.      *                              include
  7204.      * Returns:     string          the comma-separated heading record    
  7205.      * Description: 
  7206.      *  Creates a heading record for the CSV data.
  7207.      */
  7208.     function    MakeHeading($a_column_list)
  7209.     {
  7210.         $s_rec = "";
  7211.         $n_columns = count($a_column_list);
  7212.         for ($ii = 0 ; $ii < $n_columns ; $ii++)
  7213.         {
  7214.             $s_col_name = $a_column_list[$ii];
  7215.             $m_value = $this->_Format($s_col_name);
  7216.             if ($ii > 0)
  7217.                     /*
  7218.                      * prepend the separator from the second field onwards
  7219.                      */
  7220.                 $s_rec .= $this->_cSep;
  7221.             $s_rec .= $m_value;
  7222.         }
  7223.         return ($s_rec);
  7224.     }
  7225. };
  7226.  
  7227.     /*
  7228.      * Built-in filter.  Generates CSV (comma separated values) content from
  7229.      * the submitted fields. The special field "filter_fields" determines
  7230.      * which fields to include in the CSV content.
  7231.      * The following options are support in "filter_options":
  7232.      *      CSVHeading  if set, includes a heading line first with the field names
  7233.      *      CSVSep      specifies a separator character instead of comma
  7234.      *      CSVIntSep   specifies an internal separator character for lists
  7235.      *      CSVQuote    specifies the character to use to quote each column; default
  7236.      *                  is double quotes
  7237.      *      CSVEscPolicy controls the way quotes are escaped in the data.  Supported
  7238.      *                  values are: backslash (the default),double,strip
  7239.      *      CSVRaw      if set, then the fields are recorded as raw values and
  7240.      *                  are *not* cleaned according to FormMail's normal field
  7241.      *                  cleaning process.
  7242.      * If the "filter_fields" field does not exist, then the "csvcolumns" field is
  7243.      * used instead.  If neither exist, then all fields are included along with
  7244.      * a Heading line.
  7245.      */
  7246. function BuiltinFilterCSV()
  7247. {
  7248.     global  $aAllRawValues,$aRawDataValues,$SPECIAL_VALUES,$CSVLINE;
  7249.  
  7250.     $b_heading = false;
  7251.     $a_column_list = array();
  7252.     $s_cols = $SPECIAL_VALUES["filter_fields"];
  7253.     if (!isset($s_cols) || empty($s_cols) || !is_string($s_cols))
  7254.     {
  7255.         $s_cols = $SPECIAL_VALUES["csvcolumns"];
  7256.         if (!isset($s_cols) || empty($s_cols) || !is_string($s_cols))
  7257.         {
  7258.                 /*
  7259.                  * neither filter_fields nor csvcolumns defined - get all
  7260.                  * columns
  7261.                  */
  7262.             $s_cols = "";
  7263.                 /*
  7264.                  * special case - include these two special fields
  7265.                  */
  7266.             $a_column_list = array("email","realname");
  7267.                 /*
  7268.                  * now include all the data fields
  7269.                  */
  7270.             $a_column_list = array_merge($a_column_list,
  7271.                                             array_keys($aRawDataValues));
  7272.             $b_heading = true;
  7273.         }
  7274.     }
  7275.     if (empty($a_column_list))
  7276.         $a_column_list = TrimArray(explode(",",$s_cols));
  7277.  
  7278.     $csv_format = new CSVFormat();
  7279.  
  7280.         /*
  7281.          * get the various options and set them
  7282.          */
  7283.     $m_temp = GetFilterOption("CSVQuote");
  7284.     if (isset($m_temp))
  7285.         $csv_format->SetQuote($m_temp);
  7286.     $m_temp = GetFilterOption("CSVSep");
  7287.     if (isset($m_temp))
  7288.         $csv_format->SetSep($m_temp);
  7289.     $m_temp = GetFilterOption("CSVIntSep");
  7290.     if (isset($m_temp))
  7291.         $csv_format->SetIntSep($m_temp);
  7292.     $m_temp = GetFilterOption("CSVEscPolicy");
  7293.     if (isset($m_temp))
  7294.         $csv_format->SetEscPolicy($m_temp);
  7295.     $m_temp = GetFilterOption("CSVHeading");
  7296.     if (isset($m_temp))
  7297.         $b_heading = true;
  7298.  
  7299.         /*
  7300.          * clean fields unless CSVRaw is specified
  7301.          */
  7302.     $m_temp = GetFilterOption("CSVRaw");
  7303.     if (!isset($m_temp))
  7304.         $csv_format->SetCleanFunc(create_function('$m_value',
  7305.                                     'return CleanValue($m_value);'));
  7306.  
  7307.     $s_csv = $csv_format->MakeCSVRecord($a_column_list,$aAllRawValues);
  7308.  
  7309.     if ($b_heading)
  7310.     {
  7311.         $s_head = $csv_format->MakeHeading($a_column_list);
  7312.             /*
  7313.              * return the heading and the record with $CSVLINE as record separator
  7314.              */
  7315.         return ($s_head.$CSVLINE.$s_csv.$CSVLINE);
  7316.     }
  7317.     else
  7318.             /*
  7319.              * return this record with $CSVLINE appended
  7320.              */
  7321.         return ($s_csv.$CSVLINE);
  7322. }
  7323.  
  7324. $aSubstituteErrors = array();
  7325. $aSubstituteValues = NULL;
  7326. $sSubstituteMissing = NULL;
  7327.  
  7328.     //
  7329.     // Run htmlspecialchars on every value in an array.
  7330.     //
  7331. function ArrayHTMLSpecialChars($a_list)
  7332. {
  7333.     $a_new = array();
  7334.     foreach ($a_list as $m_key=>$m_value)
  7335.         if (is_array($m_value))
  7336.             $a_new[$m_key] = ArrayHTMLSpecialChars($m_value);
  7337.         else
  7338.             $a_new[$m_key] = htmlspecialchars($m_value);
  7339.     return ($a_new);
  7340. }
  7341.  
  7342.     //
  7343.     // Worker function for SubstituteValue and SubstituteValueForPage.
  7344.     // Returns the value of the matched variable name.
  7345.     // Variables are searched for in the global $aSubstituteValues.
  7346.     // If no such variable exists, an error is reported or the given
  7347.     // replacement string is used.
  7348.     // Errors are stored in the global $aSubstituteErrors.
  7349.     //
  7350. function SubstituteValueWorker($a_matches,$s_repl,$b_html = true)
  7351. {
  7352.     global  $aSubstituteErrors,$aSubstituteValues,$SPECIAL_VALUES;
  7353.  
  7354.     $b_insert_br = true;       // option to put "<br />" tags before newlines in HTML templates
  7355.  
  7356.     $s_name = $a_matches[0];
  7357.     assert(strlen($s_name) > 1 && $s_name{0} == '$');
  7358.     $s_name = substr($s_name,1);
  7359.     if (($i_len = strlen($s_name)) > 0 && $s_name{0} == '{')
  7360.     {
  7361.         assert($s_name{$i_len-1} == '}');
  7362.         $s_name = substr($s_name,1,-1);
  7363.             //
  7364.             // grab any processing options
  7365.             //
  7366.         $a_args = explode(":",$s_name);
  7367.         $s_name = $a_args[0];
  7368.         if (($n_args = count($a_args)) > 1)
  7369.         {
  7370.             for ($ii = 1 ; $ii < $n_args ; $ii++)
  7371.             {
  7372.                 switch ($a_args[$ii])
  7373.                 {
  7374.                 case "nobr":
  7375.                     $b_insert_br = false;
  7376.                     break;
  7377.                 }
  7378.             }
  7379.         }
  7380.     }
  7381.     $s_value = "";
  7382.     if (IsFieldSet($s_name,$aSubstituteValues) &&
  7383.         !TestFieldEmpty($s_name,$aSubstituteValues,$s_mesg))
  7384.     {
  7385.         if (isset($aSubstituteValues[$s_name]) &&
  7386.             is_array($aSubstituteValues[$s_name]))
  7387.                 //
  7388.                 // note that the separator can include HTML special chars
  7389.                 //
  7390.             $s_value = implode($SPECIAL_VALUES['template_list_sep'],
  7391.                             $b_html ?
  7392.                             ArrayHTMLSpecialChars($aSubstituteValues[$s_name]) :
  7393.                             $aSubstituteValues[$s_name]);
  7394.         else
  7395.         {
  7396.             $s_value = GetFieldValue($s_name,$aSubstituteValues);
  7397.             if ($b_html)
  7398.                 $s_value = htmlspecialchars($s_value);
  7399.         }
  7400.         if ($b_html && $b_insert_br)
  7401.                 //
  7402.                 // Insert HTML line breaks before newlines.
  7403.                 //
  7404.             $s_value = nl2br($s_value);
  7405.     }
  7406.     elseif (isset($SPECIAL_VALUES[$s_name]) && (string) $SPECIAL_VALUES[$s_name] != "")
  7407.         $s_value = $b_html ?
  7408.                         htmlspecialchars((string) $SPECIAL_VALUES[$s_name]) :
  7409.                         (string) $SPECIAL_VALUES[$s_name];
  7410.     elseif (isset($s_repl))
  7411.             //
  7412.             // If a replacement value has been specified use it, and
  7413.             // don't call htmlspecialchars.  This allows the use
  7414.             // of HTML tags in a replacement string.
  7415.             //
  7416.         $s_value = $s_repl;
  7417.     else
  7418.         $s_value = "";
  7419.     return ($s_value);
  7420. }
  7421.  
  7422.     //
  7423.     // Callback function for preg_replace_callback.  Returns the value
  7424.     // of the matched variable name.
  7425.     // Variables are searched for in the global $aSubstituteValues.
  7426.     // If no such variable exists, an error is reported or an special
  7427.     // replacement string is used.
  7428.     // Errors are stored in the global $aSubstituteErrors.
  7429.     //
  7430. function SubstituteValue($a_matches)
  7431. {
  7432.     global  $sSubstituteMissing;
  7433.  
  7434.     return (SubstituteValueWorker($a_matches,$sSubstituteMissing));
  7435. }
  7436.  
  7437.     //
  7438.     // Callback function for preg_replace_callback.  Returns the value
  7439.     // of the matched variable name.
  7440.     // Variables are searched for in the global $aSubstituteValues.
  7441.     // If no such variable exists, an error is reported or an special
  7442.     // replacement string is used.
  7443.     // Errors are stored in the global $aSubstituteErrors.
  7444.     //
  7445. function SubstituteValuePlain($a_matches)
  7446. {
  7447.     global  $sSubstituteMissing;
  7448.  
  7449.     return (SubstituteValueWorker($a_matches,$sSubstituteMissing,false));
  7450. }
  7451.  
  7452.     //
  7453.     // Callback function for preg_replace_callback.  Returns the value
  7454.     // of the matched variable name.
  7455.     // Variables are searched for in the global $aSubstituteValues.
  7456.     // If no such variable exists, the empty string is substituted.
  7457.     // Errors are stored in the global $aSubstituteErrors.
  7458.     //
  7459. function SubstituteValueForPage($a_matches)
  7460. {
  7461.     return (SubstituteValueWorker($a_matches,""));
  7462. }
  7463.  
  7464.     //
  7465.     // Process the given HTML template and fill the fields.
  7466.     //
  7467. function DoProcessTemplate($s_dir,$s_url,$s_template,&$a_lines,
  7468.                             $a_values,$s_missing,$s_subs_func)
  7469. {
  7470.     global  $aSubstituteErrors,$aSubstituteValues,$sSubstituteMissing;
  7471.  
  7472.     if (($a_template_lines = LoadTemplate($s_template,$s_dir,
  7473.                                             $s_url,true)) === false)
  7474.         return (false);
  7475.  
  7476.     $b_ok = true;
  7477.         //
  7478.         // initialize the errors list
  7479.         //
  7480.     $aSubstituteErrors = array();
  7481.         //
  7482.         // initialize the values
  7483.         //
  7484.     $aSubstituteValues = $a_values;
  7485.     $sSubstituteMissing = $s_missing;
  7486.  
  7487.     foreach ($a_template_lines as $s_line)
  7488.     {
  7489.             //
  7490.             // search for words in these forms:
  7491.             //      $word
  7492.             //      ${word:options}
  7493.             // where word begins with an alphabetic character and
  7494.             // consists of alphanumeric and underscore
  7495.             //
  7496.         $a_lines[] = preg_replace_callback('/\$[a-z][a-z0-9_]*|\$\{[a-z][a-z0-9_]*(:[^\}]*)*\}/i',
  7497.                                             $s_subs_func,$s_line);
  7498.     }
  7499.  
  7500. //  SendAlert("Error count=".count($aSubstituteErrors));
  7501.     if (count($aSubstituteErrors) != 0)
  7502.     {
  7503.         SendAlert(GetMessage(MSG_TEMPLATE_ERRORS,array("NAME"=>$s_template)).
  7504.                             implode("\n",$aSubstituteErrors));
  7505.         $b_ok = false;
  7506.     }
  7507.     global  $FMCTemplProc;
  7508.  
  7509.         //
  7510.         // note that it's possible for an old version of FormMail Computation
  7511.         // module to get loaded which doesn't provide FMCTemplProc
  7512.         //
  7513.     if ($b_ok && ADVANCED_TEMPLATES && isset($FMCTemplProc))
  7514.     {
  7515.         $a_mesgs = array();
  7516.         /*foreach ($a_lines as $i_lno=>$s_line)
  7517.             if (strpos($s_line,"\n") !== false)
  7518.                 SendAlert("Line $i_lno has a newline");*/
  7519.         set_time_limit(60);
  7520.         if (($m_result = $FMCTemplProc->Process(implode("\n",$a_lines),$a_mesgs)) === false)
  7521.         {
  7522.             $s_msgs = "\n";
  7523.             foreach ($a_mesgs as $a_msg)
  7524.             {
  7525.                 $s_msgs .= "Line ".$a_msg["LINE"];
  7526.                 $s_msgs .= ", position ".$a_msg["CHAR"].": ";
  7527.                 $s_msgs .= $a_msg["MSG"]."\n";
  7528.             }
  7529.             Error("fmadvtemplates",GetMessage(MSG_TEMPL_PROC,
  7530.                         array("ERRORS"=>$s_msgs)),false,false);
  7531.             $b_ok = false;
  7532.         }
  7533.         else
  7534.         {
  7535.             /*foreach ($m_result as $i_lno=>$s_line)
  7536.                 if (($nn = substr_count($s_line,"\n")) > 1)
  7537.                     SendAlert("Result line $i_lno has $nn newlines");*/
  7538.                 //
  7539.                 // strip the new lines
  7540.                 //
  7541.             $a_lines = explode("\n",implode("",$m_result));
  7542.         }
  7543.         $a_alerts = $FMCTemplProc->GetAlerts();
  7544.         if (count($a_alerts) > 0)
  7545.             SendAlert(GetMessage(MSG_TEMPL_ALERT,
  7546.                         array("ALERTS"=>implode("\n",StripHTML($a_alerts)))));
  7547.         $a_debug = $FMCTemplProc->GetDebug();
  7548.         if (count($a_debug) > 0)
  7549.             SendAlert(GetMessage(MSG_TEMPL_DEBUG,
  7550.                         array("DEBUG"=>implode("\n",StripHTML($a_debug)))));
  7551.     }
  7552.  
  7553.     return ($b_ok);
  7554. }
  7555.  
  7556.     //
  7557.     // Process the given HTML template and fill the fields.
  7558.     //
  7559. function ProcessTemplate($s_template,&$a_lines,$a_values,$s_missing = NULL,
  7560.                             $s_subs_func = 'SubstituteValue')
  7561. {
  7562.     global  $TEMPLATEURL,$TEMPLATEDIR;
  7563.  
  7564.     if (empty($TEMPLATEDIR) && empty($TEMPLATEURL))
  7565.     {
  7566.         SendAlert(GetMessage(MSG_TEMPLATES));
  7567.         return (false);
  7568.     }
  7569.     return (DoProcessTemplate($TEMPLATEDIR,$TEMPLATEURL,$s_template,$a_lines,
  7570.                                 $a_values,$s_missing,$s_subs_func));
  7571. }
  7572.  
  7573.     //
  7574.     // Output the given HTML template after filling in the fields.
  7575.     //
  7576. function OutputTemplate($s_template,$a_values)
  7577. {
  7578.     $a_lines = array();
  7579.     if (!ProcessTemplate($s_template,$a_lines,$a_values,"",'SubstituteValueForPage'))
  7580.         Error("template_failed",GetMessage(MSG_TEMPLATE_FAILED,
  7581.                                     array("NAME"=>$s_template)),false,false);
  7582.     else
  7583.     {
  7584.         for ($ii = 0 ; $ii < count($a_lines) ; $ii++)
  7585.             echo $a_lines[$ii]."\n";
  7586.     }
  7587. }
  7588.  
  7589.     //
  7590.     // This function handles input type fields.
  7591.     //
  7592. function RemoveFieldValue($s_name,$s_buf)
  7593. {
  7594.         //
  7595.         // we search for:
  7596.         //  <input ... name="thename" ... >
  7597.         // and change it to:
  7598.         //  <!-- disabled by FormMail: input ... name="thename" ... -->
  7599.         //
  7600.  
  7601.         // handle name attribute first
  7602.     $s_pat  = '/<(\s*input[^>]*name="';
  7603.     $s_pat .= preg_quote($s_name,"/");
  7604.     $s_pat .= '"[^>]*)>';
  7605.     $s_pat .= '/ims';
  7606.     $s_buf = preg_replace($s_pat,'<!-- disabled by FormMail: $1 -->',$s_buf);
  7607.  
  7608.     return ($s_buf);
  7609. }
  7610.  
  7611.     //
  7612.     // Quote special characters in a replacement expression
  7613.     // for preg_replace.
  7614.     //
  7615. function RegReplaceQuote($s_value)
  7616. {
  7617.     return (str_replace('$','\\$',str_replace('\\','\\\\',$s_value)));
  7618. }
  7619.  
  7620.     //
  7621.     // This function handles input type "text" and "password"
  7622.     //
  7623. function FixInputText($s_name,$s_value,$s_buf)
  7624. {
  7625.         //
  7626.         // we search for:
  7627.         //  <input type="text" name="thename"...
  7628.         // and change it to:
  7629.         //  <input type="text" name="thename" value="thevalue" ...
  7630.         //
  7631.         // Note that the value attribute must appear *after* the
  7632.         // type and name attributes.
  7633.         //
  7634.  
  7635.         //
  7636.         // first strip any current value attribute for the field
  7637.         //
  7638.  
  7639.         //
  7640.         // (?:) is a grouping subpattern that does no capturing
  7641.         //
  7642.  
  7643.         // handle type attribute first
  7644.     $s_pat  = '/(<\s*input[^>]*type="(?:text|password)"[^>]*name="';
  7645.     $s_pat .= preg_quote($s_name,"/");
  7646.     $s_pat .= '"[^>]*)(value="[^"]*")([^>]*?)(\s*\/\s*)?>';
  7647.     $s_pat .= '/ims';
  7648.     $s_buf = preg_replace($s_pat,'$1$3$4>',$s_buf);
  7649.  
  7650.         // handle name attribute first
  7651.     $s_pat  = '/(<\s*input[^>]*name="';
  7652.     $s_pat .= preg_quote($s_name,"/");
  7653.     $s_pat .= '"[^>]*type="(?:text|password)"[^>]*)(value="[^"]*")([^>]*?)(\s*\/\s*)?>';
  7654.     $s_pat .= '/ims';
  7655.     $s_buf = preg_replace($s_pat,'$1$3$4>',$s_buf);
  7656.  
  7657.         //
  7658.         // now add in the new value
  7659.         //
  7660.     $s_repl  = '$1 value="'.htmlspecialchars(RegReplaceQuote($s_value)).'" $2>';
  7661.  
  7662.         // handle type attribute first
  7663.     $s_pat  = '/(<\s*input[^>]*type="(?:text|password)"[^>]*name="';
  7664.     $s_pat .= preg_quote($s_name,"/");
  7665.     $s_pat .= '"[^>]*?)(\s*\/\s*)?>';
  7666.     $s_pat .= '/ims';
  7667.     $s_buf = preg_replace($s_pat,$s_repl,$s_buf);
  7668.  
  7669.         // handle name attribute first
  7670.     $s_pat  = '/(<\s*input[^>]*name="';
  7671.     $s_pat .= preg_quote($s_name,"/");
  7672.     $s_pat .= '"[^>]*type="(?:text|password)"[^>]*?)(\s*\/\s*)?>';
  7673.     $s_pat .= '/ims';
  7674.     $s_buf = preg_replace($s_pat,$s_repl,$s_buf);
  7675.  
  7676.     return ($s_buf);
  7677. }
  7678.  
  7679.     //
  7680.     // This function handles textareas.
  7681.     //
  7682. function FixTextArea($s_name,$s_value,$s_buf)
  7683. {
  7684.         //
  7685.         // we search for:
  7686.         //  <textarea name="thename"...>value</textarea>
  7687.         // and change it to:
  7688.         //  <textarea name="thename"...>new value</textarea>
  7689.         //
  7690.  
  7691.     $s_pat  = '/(<\s*textarea[^>]*name="';
  7692.     $s_pat .= preg_quote($s_name,"/");
  7693.     $s_pat .= '"[^>]*)>.*?<\s*\/\s*textarea\s*>';
  7694.     $s_pat .= '/ims';
  7695.         //
  7696.         // we exclude the closing '>' from the match above so that
  7697.         // we can put it below.  We need to do this so that the replacement
  7698.         // string is not faulty if the value begins with a digit:
  7699.         //      $19 Some Street
  7700.         //
  7701.     $s_repl = '$1>'.htmlspecialchars(RegReplaceQuote($s_value)).'</textarea>';
  7702.     $s_buf = preg_replace($s_pat,$s_repl,$s_buf);
  7703.  
  7704.     return ($s_buf);
  7705. }
  7706.  
  7707.     //
  7708.     // This function handles radio buttons and non-array checkboxes.
  7709.     //
  7710. function FixButton($s_name,$s_value,$s_buf)
  7711. {
  7712.         //
  7713.         // we search for:
  7714.         //  <input type="radio" name="thename" value="thevalue" ...
  7715.         // and change it to:
  7716.         //  <input type="radio" name="thename" value="thevalue" checked="checked"
  7717.         //
  7718.         // Note that the value attribute must appear *after* the
  7719.         // type and name attributes.
  7720.         //
  7721.  
  7722.         //
  7723.         // first strip any current checked attributes
  7724.         //
  7725.  
  7726.         //
  7727.         // (?:) is a grouping subpattern that does no capturing
  7728.         //
  7729.  
  7730.         // handle type attribute first
  7731.         // match: input tag with type 'radio' or 'checkbox' with attribute
  7732.         // 'checked' or 'checked="checked"'
  7733.         //              <A NAME="PatternInfo">
  7734.         //      [^>]*?[^"\w] matches up to a word boundary starting with
  7735.         //      'checked' but not '"checked'
  7736.         //      (="checked"|(?=[^"\w]))? this matches:
  7737.         //              nothing
  7738.         //              ="checked"
  7739.         //              any character except a word character or " (without
  7740.         //              consuming it)
  7741.         //
  7742.     $s_pat  = '/(<\s*input[^>]*type="(?:radio|checkbox)"[^>]*name="';
  7743.     $s_pat .= preg_quote($s_name,"/");
  7744.     $s_pat .= '"[^>]*?[^"\w])checked(="checked"|(?=[^"\w]))?([^>]*?)(\s*\/\s*)?>';
  7745.     $s_pat .= '/ims';
  7746.     $s_buf = preg_replace($s_pat,'$1$3$4>',$s_buf);
  7747.  
  7748.         // handle name attribute first
  7749.     $s_pat  = '/(<\s*input[^>]*name="';
  7750.     $s_pat .= preg_quote($s_name,"/");
  7751.     $s_pat .= '"[^>]*type="(?:radio|checkbox)"[^>]*?[^"\w])checked(="checked"|(?=[^"\w]))?([^>]*?)(\s*\/\s*)?>';
  7752.     $s_pat .= '/ims';
  7753.     $s_buf = preg_replace($s_pat,'$1$3$4>',$s_buf);
  7754.  
  7755.         // handle type attribute first
  7756.     $s_pat  = '/(<\s*input[^>]*type="(?:radio|checkbox)"[^>]*name="';
  7757.     $s_pat .= preg_quote($s_name,"/");
  7758.     $s_pat .= '"[^>]*value="';
  7759.     $s_pat .= preg_quote($s_value,"/");
  7760.     $s_pat .= '")([^>]*?)(\s*\/\s*)?>';
  7761.     $s_pat .= '/ims';
  7762.     $s_buf = preg_replace($s_pat,'$1$2 checked="checked" $3>',$s_buf);
  7763.  
  7764.         // handle name attribute first
  7765.     $s_pat  = '/(<\s*input[^>]*name="';
  7766.     $s_pat .= preg_quote($s_name,"/");
  7767.     $s_pat .= '"[^>]*type="(?:radio|checkbox)"[^>]*value="';
  7768.     $s_pat .= preg_quote($s_value,"/");
  7769.     $s_pat .= '")([^>]*?)(\s*\/\s*)?>';
  7770.     $s_pat .= '/ims';
  7771.     $s_buf = preg_replace($s_pat,'$1$2 checked="checked" $3>',$s_buf);
  7772.  
  7773.     return ($s_buf);
  7774. }
  7775.  
  7776.     //
  7777.     // This function handles checkboxes as an array of values.
  7778.     //
  7779. function FixCheckboxes($s_name,$a_values,$s_buf)
  7780. {
  7781.     //global $aDebug;
  7782.  
  7783.         //
  7784.         // we search for:
  7785.         //  <input type="checkbox" name="thename" value="thevalue" ...
  7786.         // and change it to:
  7787.         //  <input type="checkbox" name="thename" value="thevalue" checked
  7788.         //
  7789.         // Note that the value attribute must appear *after* the
  7790.         // type and name attributes.
  7791.         //
  7792.  
  7793.         //
  7794.         // first strip any current checked attributes
  7795.         //
  7796.     //$aDebug[] = "FixCheckboxes: Name='$s_name'";
  7797.  
  7798.         // handle type attribute first
  7799.         // see <A HREF="fmbadhandler.php#PatternInfo">
  7800.     $s_pat  = '/(<\s*input[^>]*type="checkbox"[^>]*name="';
  7801.     $s_pat .= preg_quote($s_name,"/");
  7802.     $s_pat .= '\[]"[^>]*?[^"\w])checked(="checked"|(?=[^"\w]))?([^>]*?)(\s*\/\s*)?>';
  7803.     $s_pat .= '/ims';
  7804.     $s_buf = preg_replace($s_pat,'$1$3$4>',$s_buf);
  7805.  
  7806.         // handle name attribute first
  7807.     $s_pat  = '/(<\s*input[^>]*name="';
  7808.     $s_pat .= preg_quote($s_name,"/");
  7809.     $s_pat .= '\[]"[^>]*type="checkbox"[^>]*?[^"\w])checked(="checked"|(?=[^"\w]))?([^>]*?)(\s*\/\s*)?>';
  7810.     $s_pat .= '/ims';
  7811.     $s_buf = preg_replace($s_pat,'$1$3$4>',$s_buf);
  7812.  
  7813.     foreach ($a_values as $s_value)
  7814.     {
  7815.             // handle type attribute first
  7816.         $s_pat  = '/(<\s*input[^>]*type="checkbox"[^>]*name="';
  7817.         $s_pat .= preg_quote($s_name,"/");
  7818.         $s_pat .= '\[\]"[^>]*value="';
  7819.         $s_pat .= preg_quote($s_value,"/");
  7820.         $s_pat .= '")([^>]*?)(\s*\/\s*)?>';
  7821.         $s_pat .= '/ims';
  7822.         $s_buf = preg_replace($s_pat,'$1$2 checked="checked"$3>',$s_buf);
  7823.         //$aDebug[] = "Name='$s_name', pat='$s_pat'";
  7824.  
  7825.             // handle name attribute first
  7826.         $s_pat  = '/(<\s*input[^>]*name="';
  7827.         $s_pat .= preg_quote($s_name,"/");
  7828.         $s_pat .= '\[\]"[^>]*type="checkbox"[^>]*value="';
  7829.         $s_pat .= preg_quote($s_value,"/");
  7830.         $s_pat .= '")([^>]*?)(\s*\/\s*)?>';
  7831.         $s_pat .= '/ims';
  7832.         $s_buf = preg_replace($s_pat,'$1$2 checked="checked">',$s_buf);
  7833.     }
  7834.     return ($s_buf);
  7835. }
  7836.  
  7837.     //
  7838.     // This function handles selects.
  7839.     //
  7840. function FixSelect($s_name,$s_value,$s_buf)
  7841. {
  7842.         //
  7843.         // we search for:
  7844.         //  <select name="thename"...>
  7845.         //  <option value="thevalue">...</option>
  7846.         //  </select>
  7847.         //
  7848.  
  7849.     $s_pat  = '/(<\s*select[^>]*name="';
  7850.     $s_pat .= preg_quote($s_name,"/");
  7851.     $s_pat .= '".*?<\s*option[^>]*value="';
  7852.     $s_pat .= preg_quote($s_value,"/");
  7853.     $s_pat .= '"[^>]*)>';
  7854.     $s_pat .= '/ims';
  7855.     $s_repl = '$1 selected="selected">';
  7856. //  echo "<p>pat: ".htmlspecialchars($s_pat);
  7857.     $s_buf = preg_replace($s_pat,$s_repl,$s_buf);
  7858.  
  7859.     return ($s_buf);
  7860. }
  7861.  
  7862.     //
  7863.     // This function handles multiple selects.
  7864.     //
  7865. function FixMultiSelect($s_name,$a_values,$s_buf)
  7866. {
  7867.         //
  7868.         // we search for:
  7869.         //  <select name="thename"...>
  7870.         //  <option value="thevalue">...</option>
  7871.         //  </select>
  7872.         //
  7873.  
  7874.     foreach ($a_values as $s_value)
  7875.     {
  7876.         $s_pat  = '/(<\s*select[^>]*name="';
  7877.         $s_pat .= preg_quote($s_name,"/");
  7878.         $s_pat .= '\[\]".*?<\s*option[^>]*value="';
  7879.         $s_pat .= preg_quote($s_value,"/");
  7880.         $s_pat .= '"[^>]*)>';
  7881.         $s_pat .= '/ims';
  7882.         $s_repl = '$1 selected="selected">';
  7883.     //  echo "<p>pat: ".htmlspecialchars($s_pat);
  7884.         $s_buf = preg_replace($s_pat,$s_repl,$s_buf);
  7885.     }
  7886.     return ($s_buf);
  7887. }
  7888.  
  7889.     //
  7890.     // This function unchecks all checkboxes and select options.
  7891.     //
  7892. function UnCheckStuff($s_buf)
  7893. {
  7894.     global  $php_errormsg;
  7895.  
  7896.         //
  7897.         // we search for:
  7898.         //  <input type="checkbox" ... checked
  7899.         // and remove "checked" (checked="checked" is OK too)
  7900.         //
  7901.         // Note that the check attribute must appear *after* the
  7902.         // type attribute.
  7903.         // see <A HREF="fmbadhandler.php#PatternInfo">
  7904.         //
  7905.  
  7906.     $s_pat  = '/(<\s*input[^>]*type="checkbox"[^>]*?[^"\w])checked(="checked"|(?=[^"\w]))?([^>]*?)(\s*\/\s*)?>';
  7907.     $s_pat .= '/ims';
  7908.     $s_buf = preg_replace($s_pat,'$1$3$4>',$s_buf);
  7909.  
  7910.         //
  7911.         // we search for:
  7912.         //  <option... selected
  7913.         // and remove "selected" (selected="selected" is OK too)
  7914.         // see <A HREF="fmbadhandler.php#PatternInfo">
  7915.         //
  7916.  
  7917.     $s_pat  = '/(<\s*option[^>]*?[^"\w])selected(="selected"|(?=[^"\w]))?([^>]*)>';
  7918.     $s_pat .= '/ims';
  7919.     $s_buf = preg_replace($s_pat,'$1$3>',$s_buf);
  7920.  
  7921.     return ($s_buf);
  7922. }
  7923.  
  7924.     //
  7925.     // Add the user agent to the url as a parameter called USER_AGENT.
  7926.     // This allows dynamic web sites to know what the user's browser is.
  7927.     //
  7928. function AddUserAgent($s_url)
  7929. {
  7930.     global  $aServerVars;
  7931.  
  7932.         //
  7933.         // check for ? in the name
  7934.         //
  7935.     $b_quest = (strpos($s_url,'?') !== false);
  7936.     unset($s_agent);
  7937.     if (isset($aServerVars['HTTP_USER_AGENT']))
  7938.         $s_agent = $aServerVars['HTTP_USER_AGENT'];
  7939.     if (isset($s_agent))
  7940.         $s_url .= ($b_quest ? '&' : '?')."USER_AGENT=".urlencode($s_agent);
  7941.     return ($s_url);
  7942. }
  7943.  
  7944.     //
  7945.     // Sets previous values in a form.
  7946.     //
  7947. function SetPreviousValues($s_form_buf,$a_values,$a_strip = array())
  7948. {
  7949.         //
  7950.         // Uncheck any checkboxes and select options
  7951.         //
  7952.     $s_form_buf = UnCheckStuff($s_form_buf);
  7953.     foreach ($a_values as $s_name=>$m_value)
  7954.     {
  7955.         if (is_array($m_value))
  7956.         {
  7957.                 //
  7958.                 // note that if no values are selected for a field,
  7959.                 // then we will never get here for that field
  7960.                 //
  7961.             $s_form_buf = FixCheckboxes($s_name,$m_value,$s_form_buf);
  7962.             $s_form_buf = FixMultiSelect($s_name,$m_value,$s_form_buf);
  7963.         }
  7964.         else
  7965.         {
  7966.                 //
  7967.                 // Fix the field if it's an input type "text" or "password".
  7968.                 //
  7969.             $s_form_buf = FixInputText($s_name,$m_value,$s_form_buf);
  7970.                 //
  7971.                 // Fix the field if it's radio button.
  7972.                 //
  7973.             $s_form_buf = FixButton($s_name,$m_value,$s_form_buf);
  7974.                 //
  7975.                 // Fix the field if it's a "textarea".
  7976.                 //
  7977.             $s_form_buf = FixTextArea($s_name,$m_value,$s_form_buf);
  7978.                 //
  7979.                 // Fix the field if it's a "select".
  7980.                 //
  7981.             $s_form_buf = FixSelect($s_name,$m_value,$s_form_buf);
  7982.         }
  7983.     }
  7984.         //
  7985.         // Now strip particular field values.
  7986.         //
  7987.     foreach ($a_strip as $s_name)
  7988.         $s_form_buf = RemoveFieldValue($s_name,$s_form_buf);
  7989.     return ($s_form_buf);
  7990. }
  7991.  
  7992.     //
  7993.     // Open a URL, do value substitutions, and send to browser.
  7994.     // The a_strip array provides a list of fields (usually
  7995.     // hidden fields) to remove from the form (their values are
  7996.     // set to empty).
  7997.     //
  7998. function ProcessReturnToForm($s_url,$a_values,$a_strip = array())
  7999. {
  8000.     global  $aSubstituteErrors,$aSubstituteValues,$sSubstituteMissing;
  8001.     global  $php_errormsg;
  8002.  
  8003.         //
  8004.         // read the original form, and modify it to provide values
  8005.         // for the fields
  8006.         //
  8007.     if (!CheckValidURL($s_url))
  8008.         Error("invalid_url",GetMessage(MSG_RETURN_URL_INVALID,
  8009.                                     array("URL"=>$s_url)),false,false);
  8010.  
  8011.     $s_form_url = AddUserAgent($s_url);
  8012.     $s_error = "";
  8013.     $s_form_buf = GetURL($s_form_url,$s_error);
  8014.     if ($s_form_buf === false)
  8015.         Error("invalid_url",GetMessage(MSG_OPEN_URL,
  8016.                                 array("URL"=>$s_form_url,
  8017.                                       "ERROR"=>$s_error.": ".(isset($php_errormsg) ?
  8018.                                             $php_errormsg : ""))),false,false);
  8019.  
  8020.         //
  8021.         // Next, we replace or set actual field values.
  8022.         //
  8023.     echo SetPreviousValues($s_form_buf,$a_values,$a_strip);
  8024. }
  8025.  
  8026.     //
  8027.     // To return the URL for returning to a particular multi-page form URL.
  8028.     //
  8029. function GetReturnLink($s_this_script,$i_form_index)
  8030. {
  8031.     if (!CheckValidURL($s_this_script))
  8032.         Error("not_valid_url",GetMessage(MSG_RETURN_URL_INVALID,
  8033.                                 array("URL"=>$s_this_script)),false,false);
  8034.  
  8035.     $a_params = array();
  8036.     $a_params[] = "return=$i_form_index";
  8037.     if (isset($aServerVars["QUERY_STRING"]))
  8038.         $a_params[] = $aServerVars["QUERY_STRING"];
  8039.     $a_params[] = session_name()."=".session_id();
  8040.     return (AddURLParams($s_this_script,$a_params));
  8041. }
  8042.  
  8043.     //
  8044.     // Process a multi-page form template.
  8045.     //
  8046. function ProcessMultiFormTemplate($s_template,$a_values,&$a_lines)
  8047. {
  8048.     global  $MULTIFORMURL,$MULTIFORMDIR,$SPECIAL_VALUES,$aSessionVars;
  8049.  
  8050.     if (empty($MULTIFORMDIR) && empty($MULTIFORMURL))
  8051.     {
  8052.         SendAlert(GetMessage(MSG_MULTIFORM));
  8053.         return (false);
  8054.     }
  8055.         //
  8056.         // create the "this_form_url" field
  8057.         //
  8058.     $i_index = $aSessionVars["FormIndex"];
  8059.     $a_values["this_form_url"] = $aSessionVars["FormList"][$i_index]["URL"];
  8060.         //
  8061.         // get the persistent file fields
  8062.         //
  8063.     $a_values = GetSavedFileNames($a_values);
  8064.     //$a_values["prev_form"] = GetReturnLink($SPECIAL_VALUES["this_form"]);
  8065.     return (DoProcessTemplate($MULTIFORMDIR,$MULTIFORMURL,$s_template,$a_lines,
  8066.                             $a_values,"",'SubstituteValueForPage'));
  8067. }
  8068.  
  8069.     //
  8070.     // Output the multi-form template after filling in the fields.
  8071.     //
  8072. function OutputMultiFormTemplate($s_template,$a_values)
  8073. {
  8074.     $a_lines = array();
  8075.     if (!ProcessMultiFormTemplate($s_template,$a_values,$a_lines))
  8076.         Error("multi_form_failed",GetMessage(MSG_MULTIFORM_FAILED,
  8077.                                     array("NAME"=>$s_template)),false,false);
  8078.     else
  8079.     {
  8080.         $n_lines = count($a_lines);
  8081.         $s_buf = "";
  8082.         for ($ii = 0 ; $ii < $n_lines ; $ii++)
  8083.         {
  8084.             $s_buf .= $a_lines[$ii]."\n";
  8085.             unset($a_lines[$ii]);       // free memory (hopefully)
  8086.         }
  8087.         unset($a_lines);       // free memory (hopefully)
  8088.  
  8089.         global  $aSessionVars;
  8090.  
  8091.         if (isset($aSessionVars["FormKeep"]))
  8092.                 //
  8093.                 // put in any values that are being forward-remembered
  8094.                 //
  8095.             echo SetPreviousValues($s_buf,$aSessionVars["FormKeep"]);
  8096.         else
  8097.             echo $s_buf;
  8098.     }
  8099. }
  8100.  
  8101.     //
  8102.     // Insert a preamble into a MIME message.
  8103.     //
  8104. function MimePreamble(&$a_lines,$a_mesg = array())
  8105. {
  8106.     $a_preamble = explode("\n",GetMessage(MSG_MIME_PREAMBLE));
  8107.     foreach ($a_preamble as $s_line)
  8108.         $a_lines[] = $s_line.HEAD_CRLF;
  8109.  
  8110.     $a_lines[] = HEAD_CRLF;     // blank line
  8111.     $b_need_blank = false;
  8112.     foreach ($a_mesg as $s_line)
  8113.     {
  8114.         $a_lines[] = $s_line.HEAD_CRLF;
  8115.         if (!empty($s_line))
  8116.             $b_need_blank = true;
  8117.     }
  8118.     if ($b_need_blank)
  8119.         $a_lines[] = HEAD_CRLF;     // blank line
  8120. }
  8121.  
  8122.     //
  8123.     // Create the HTML mail
  8124.     //
  8125. function HTMLMail(&$a_lines,&$a_headers,$s_body,$s_template,$s_missing,$s_filter,
  8126.                             $s_boundary,$a_raw_fields,$b_no_plain)
  8127. {
  8128.     $s_charset = GetMailOption("CharSet");
  8129.     if (!isset($s_charset))
  8130.         $s_charset = "ISO-8859-1";
  8131.     if ($b_no_plain)
  8132.     {
  8133.         $b_multi = false;
  8134.             //
  8135.             // don't provide a plain text version - just the HTML
  8136.             //
  8137.         $a_headers['Content-Type'] = SafeHeader("text/html; charset=$s_charset");
  8138.     }
  8139.     else
  8140.     {
  8141.         $b_multi = true;
  8142.         $a_headers['Content-Type'] = "multipart/alternative; boundary=\"$s_boundary\"";
  8143.  
  8144.         $a_pre_lines = explode("\n",GetMessage(MSG_MIME_HTML,
  8145.                                                 array("NAME"=>$s_template)));
  8146.  
  8147.         MimePreamble($a_lines,$a_pre_lines);
  8148.  
  8149.             //
  8150.             // first part - the text version only
  8151.             //
  8152.         $a_lines[] = "--$s_boundary".HEAD_CRLF;
  8153.         $a_lines[] = "Content-Type: text/plain; charset=$s_charset".HEAD_CRLF;
  8154.         $a_lines[] = HEAD_CRLF;     // blank line
  8155.             //
  8156.             // treat the body like one line, even though it isn't
  8157.             //
  8158.         $a_lines[] = $s_body;
  8159.         $a_lines[] = HEAD_CRLF;     // blank line
  8160.             //
  8161.             // second part - the HTML version
  8162.             //
  8163.         $a_lines[] = "--$s_boundary".HEAD_CRLF;
  8164.         $a_lines[] = "Content-Type: text/html; charset=$s_charset".HEAD_CRLF;
  8165.         $a_lines[] = HEAD_CRLF;     // blank line
  8166.     }
  8167.  
  8168.     $a_html_lines = array();
  8169.     if (!ProcessTemplate($s_template,$a_html_lines,$a_raw_fields,$s_missing))
  8170.         return (false);
  8171.  
  8172.     if (!empty($s_filter))
  8173.             //
  8174.             // treat the data like one line, even though it isn't
  8175.             //
  8176.         $a_lines[] = Filter($s_filter,$a_html_lines);
  8177.     else
  8178.         foreach ($a_html_lines as $s_line)
  8179.             $a_lines[] = $s_line;
  8180.  
  8181.     if ($b_multi)
  8182.     {
  8183.             //
  8184.             // end
  8185.             //
  8186.         $a_lines[] = "--$s_boundary--".HEAD_CRLF;
  8187.         $a_lines[] = HEAD_CRLF;     // blank line
  8188.     }
  8189.     return (true);
  8190. }
  8191.  
  8192.     //
  8193.     // Add the contents of a file in base64 encoding.
  8194.     //
  8195. function AddFile(&$a_lines,$s_file_name,$i_file_size,$b_remove = true)
  8196. {
  8197.     global  $php_errormsg;
  8198.  
  8199. @   $fp = fopen($s_file_name,"rb");
  8200.     if ($fp === false)
  8201.     {
  8202.         SendAlert(GetMessage(MSG_FILE_OPEN_ERROR,array("NAME"=>$s_file_name,
  8203.                                             "TYPE"=>"attachment",
  8204.                                             "ERROR"=>CheckString($php_errormsg))));
  8205.         return (false);
  8206.     }
  8207.         //
  8208.         // PHP under IIS has problems with the filesize function when
  8209.         // the file is on another drive.  So, we replaced a call
  8210.         // to filesize with the $i_file_size parameter (this occurred
  8211.         // in version 3.01).
  8212.         //
  8213.     $s_contents = fread($fp,$i_file_size);
  8214.         //
  8215.         // treat as a single line, even though it isn't
  8216.         //
  8217.     $a_lines[] = chunk_split(base64_encode($s_contents));
  8218.     fclose($fp);
  8219.     if ($b_remove)
  8220.         @unlink($s_file_name);
  8221.     return (true);
  8222. }
  8223.  
  8224.     //
  8225.     // Add the contents of a string in base64 encoding.
  8226.     //
  8227. function AddData(&$a_lines,$s_data)
  8228. {
  8229.         //
  8230.         // treat as a single line, even though it isn't
  8231.         //
  8232.     $a_lines[] = chunk_split(base64_encode($s_data));
  8233.     return (true);
  8234. }
  8235.     //
  8236.     // Check if a file is a valid uploaded file.
  8237.     //
  8238. function IsUploadedFile($a_file_spec)
  8239. {
  8240.         //
  8241.         // $a_file_spec["moved"] is our own internal flag to say we've
  8242.         // saved the file
  8243.         //
  8244.     if (isset($a_file_spec["moved"]) && $a_file_spec["moved"])
  8245.         return (true);
  8246.     return (is_uploaded_file($a_file_spec["tmp_name"]));
  8247. }
  8248.  
  8249.     //
  8250.     // Save an uploaded file to the repository directory.
  8251.     //
  8252. function SaveFileInRepository(&$a_file_spec)
  8253. {
  8254.     global  $php_errormsg,$FILE_REPOSITORY;
  8255.  
  8256.         //
  8257.         // if a replacement name has been specified, use that, otherwise
  8258.         // use the original name
  8259.         //
  8260.     if (isset($a_file_spec["new_name"]))
  8261.         $s_file_name = basename($a_file_spec["new_name"]);
  8262.     else
  8263.         $s_file_name = basename($a_file_spec["name"]);
  8264.     $s_dest = $FILE_REPOSITORY."/".$s_file_name;
  8265.  
  8266.     $b_ok = true;
  8267.     $s_error = "";
  8268.  
  8269.     if (isset($a_file_spec["saved_as"]) && !empty($a_file_spec["saved_as"]))
  8270.         $s_srce = $a_file_spec["saved_as"];
  8271.     else
  8272.         $s_srce = $a_file_spec["tmp_name"];
  8273.  
  8274.     if (!FILE_OVERWRITE)
  8275.     {
  8276.         clearstatcache();
  8277.         if (@file_exists($s_dest))
  8278.         {
  8279.             $b_ok = false;
  8280.             $s_error = GetMessage(MSG_SAVE_FILE_EXISTS,array("FILE"=>$s_dest));
  8281.         }
  8282.     }
  8283.     if (MAX_FILE_UPLOAD_SIZE != 0 &&
  8284.         $a_file_spec["size"] > MAX_FILE_UPLOAD_SIZE*1024)
  8285.             //
  8286.             // this exits
  8287.             //
  8288.         UserError("upload_size",GetMessage(MSG_FILE_UPLOAD_SIZE,
  8289.                                   array("NAME"=>$a_file_spec["name"],
  8290.                                         "SIZE"=>$a_file_spec["size"],
  8291.                                         "MAX"=>MAX_FILE_UPLOAD_SIZE)));
  8292.     if ($b_ok)
  8293.     {
  8294.         if (isset($a_file_spec["saved_as"]) && !empty($a_file_spec["saved_as"]))
  8295.         {
  8296.             if (!copy($s_srce,$s_dest) || !@unlink($s_srce))
  8297.                 $b_ok = false;
  8298.         }
  8299.         else
  8300.         {
  8301.             if (!move_uploaded_file($s_srce,$s_dest))
  8302.                 $b_ok = false;
  8303.         }
  8304.         if ($b_ok)
  8305.         {
  8306.                 //
  8307.                 // Flag to say it's been put in the repository.
  8308.                 //
  8309.             $a_file_spec["in_repository"] = true;
  8310.                 //
  8311.                 // Its new location
  8312.                 //
  8313.             $a_file_spec["saved_as"] = $s_dest;
  8314.                 //
  8315.                 // Now that the file has been saved, "is_uploaded_file"
  8316.                 // will return false.  So, we create a flag to say it was
  8317.                 // valid.
  8318.                 //
  8319.             $a_file_spec["moved"] = true;
  8320.         }
  8321.         else
  8322.             $s_error = $php_errormsg;
  8323.     }
  8324.     if (!$b_ok)
  8325.     {
  8326.         SendAlert(GetMessage(MSG_SAVE_FILE,array(
  8327.                             "FILE"=>$s_srce,
  8328.                             "DEST"=>$s_dest,
  8329.                             "ERR"=>$s_error)));
  8330.         return (false);
  8331.     }
  8332.         //
  8333.         // ignore chmod fails (other than reporting them)
  8334.         //
  8335.     if (FILE_MODE != 0 && !chmod($s_dest,FILE_MODE))
  8336.         SendAlert(GetMessage(MSG_CHMOD,array(
  8337.                             "FILE"=>$s_dest,
  8338.                             "MODE"=>FILE_MODE,
  8339.                             "ERR"=>$s_error)));
  8340.     return (true);
  8341. }
  8342.  
  8343.     //
  8344.     // Save all uploaded files to the repository directory.
  8345.     //
  8346. function SaveAllFilesToRepository()
  8347. {
  8348.     global  $aFileVars,$aSessionVars;
  8349.  
  8350.     if (!FILEUPLOADS || $FILE_REPOSITORY === "")
  8351.             //
  8352.             // nothing to do
  8353.             //
  8354.         return (true);
  8355.  
  8356.     foreach ($aFileVars as $m_file_key=>$a_upload)
  8357.     {
  8358.             //
  8359.             // One customer reported:
  8360.             //  Possible file upload attack detected: name='' temp name='none'
  8361.             // on PHP 4.1.2 on RAQ4.
  8362.             // So, we now also test for "name".
  8363.             //
  8364.         if (!isset($a_upload["tmp_name"]) || empty($a_upload["tmp_name"]) ||
  8365.             !isset($a_upload["name"]) || empty($a_upload["name"]))
  8366.             continue;
  8367.         if (isset($a_upload["in_repository"]) && $a_upload["in_repository"])
  8368.                 //
  8369.                 // already saved
  8370.                 //
  8371.             continue;
  8372.         if (!IsUploadedFile($a_upload))
  8373.         {
  8374.             SendAlert(GetMessage(MSG_FILE_UPLOAD_ATTACK,
  8375.                             array("NAME"=>$a_upload["name"],
  8376.                                     "TEMP"=>$a_upload["tmp_name"],
  8377.                                     "FLD"=>$m_file_key)));
  8378.             continue;
  8379.         }
  8380.         if (!SaveFileInRepository($aFileVars[$m_file_key]))
  8381.             return (false);
  8382.             //
  8383.             // Now the file has been saved in the repository, make
  8384.             // the field persistent through all further processing
  8385.             // (e.g. all movements in a multi-page form)
  8386.             //
  8387.         if (!isset($aSessionVars["FormSavedFiles"]))
  8388.             $aSessionVars["FormSavedFiles"] = array();
  8389.         $aSessionVars["FormSavedFiles"]["repository_".$m_file_key] = $aFileVars[$m_file_key];
  8390.     }
  8391.     return (true);
  8392. }
  8393.  
  8394.     //
  8395.     // Delete an uploaded file from the repository directory.
  8396.     // For security reasons, only the field name can be used.  This
  8397.     // uniquely identifies an uploaded file by this form process.
  8398.     //
  8399. function DeleteFileFromRepository($s_fld)
  8400. {
  8401.     global  $aFileVars,$aSessionVars;
  8402.  
  8403.     if (!FILEUPLOADS || $FILE_REPOSITORY === "")
  8404.             //
  8405.             // nothing to do
  8406.             //
  8407.         return (false);
  8408.  
  8409.     if (($a_upload = GetFileInfo($s_fld)) === false)
  8410.         return (false);
  8411.  
  8412.     if (isset($a_upload["in_repository"]) && $a_upload["in_repository"])
  8413.     {
  8414.         if (isset($a_upload["saved_as"]) && !empty($a_upload["saved_as"]))
  8415.             @unlink($a_upload["saved_as"]);
  8416.     }
  8417.     DeleteFileInfo($s_fld);
  8418.     return (true);
  8419. }
  8420.  
  8421.     //
  8422.     // Save an uploaded file for later processing.
  8423.     //
  8424. function SaveUploadedFile(&$a_file_spec,$s_prefix)
  8425. {
  8426.     global  $php_errormsg;
  8427.  
  8428.     $s_dest = GetScratchPadFile($s_prefix);
  8429.     if (!move_uploaded_file($a_file_spec["tmp_name"],$s_dest))
  8430.     {
  8431.         SendAlert(GetMessage(MSG_SAVE_FILE,array(
  8432.                             "FILE"=>$a_file_spec["tmp_name"],
  8433.                             "DEST"=>$s_dest,
  8434.                             "ERR"=>$php_errormsg)));
  8435.         return (false);
  8436.     }
  8437.     $a_file_spec["saved_as"] = $s_dest;
  8438.     $a_file_spec["moved"] = true;
  8439.     return (true);
  8440. }
  8441.  
  8442.     //
  8443.     // Remove old files from the scratchpad directory.
  8444.     //
  8445. function CleanScratchPad($s_prefix = "")
  8446. {
  8447.     global  $lNow,$CLEANUP_TIME,$CLEANUP_CHANCE;
  8448.     global  $php_errormsg,$SCRATCH_PAD;
  8449.  
  8450.     if (!isset($SCRATCH_PAD) || empty($SCRATCH_PAD))
  8451.             //
  8452.             // no scratchpad to cleanup!
  8453.             //
  8454.         return;
  8455.     if ($CLEANUP_TIME <= 0)
  8456.             //
  8457.             // cleanup disabled
  8458.             //
  8459.         return;
  8460.         //
  8461.         // compute chance of cleanup
  8462.         //
  8463.     if ($CLEANUP_CHANCE < 100)
  8464.     {
  8465.         $i_rand = mt_rand(1,100);
  8466.         if ($i_rand > $CLEANUP_CHANCE)
  8467.             return;
  8468.     }
  8469.     if (($f_dir = @opendir($SCRATCH_PAD)) === false)
  8470.     {
  8471.         Error("open_scratch_pad",GetMessage(MSG_OPEN_SCRATCH_PAD,array(
  8472.                                         "DIR"=>$SCRATCH_PAD,
  8473.                                         "ERR"=>$php_errormsg)),false,false);
  8474.         return;
  8475.     }
  8476.     $i_len = strlen($s_prefix);
  8477.     while (($s_file = readdir($f_dir)) !== false)
  8478.     {
  8479.         $s_path = $SCRATCH_PAD."/".$s_file;
  8480.         if (is_file($s_path) && ($i_len == 0 || substr($s_file,0,$i_len) == $s_prefix))
  8481.         {
  8482.             if (($a_stat = @stat($s_path)) !== false)
  8483.             {
  8484.                 if (isset($a_stat['mtime']))
  8485.                     $l_time = $a_stat['mtime'];
  8486.                 else
  8487.                     $l_time = $a_stat[9];
  8488.                 if (($lNow - $l_time) / 60 >= $CLEANUP_TIME)
  8489.                     @unlink($s_path);
  8490.             }
  8491.         }
  8492.     }
  8493.     closedir($f_dir);
  8494. }
  8495.  
  8496.     //
  8497.     // Save all uploaded files for later processing.
  8498.     //
  8499. function SaveAllUploadedFiles(&$a_file_vars)
  8500. {
  8501.     global  $php_errormsg,$SCRATCH_PAD;
  8502.  
  8503.     $s_prefix = "UPLD";
  8504.     if (!isset($SCRATCH_PAD) || empty($SCRATCH_PAD))
  8505.     {
  8506.         Error("need_scratch_pad",GetMessage(MSG_NEED_SCRATCH_PAD),false,false);
  8507.         return (false);
  8508.     }
  8509.  
  8510.         //
  8511.         // remove old uploaded files that have not been moved out.
  8512.         //
  8513.     CleanScratchPad($s_prefix);
  8514.  
  8515.     foreach (array_keys($a_file_vars) as $m_file_key)
  8516.     {
  8517.         $a_upload = &$a_file_vars[$m_file_key];
  8518.             //
  8519.             // One customer reported:
  8520.             //  Possible file upload attack detected: name='' temp name='none'
  8521.             // on PHP 4.1.2 on RAQ4.
  8522.             // So, we now also test for "name".
  8523.             //
  8524.         if (!isset($a_upload["tmp_name"]) || empty($a_upload["tmp_name"]) ||
  8525.             !isset($a_upload["name"]) || empty($a_upload["name"]))
  8526.             continue;
  8527.             //
  8528.             // ensure we don't move the file more than once
  8529.             //
  8530.         if (!isset($a_upload["saved_as"]) || empty($a_upload["saved_as"]))
  8531.             if (!IsUploadedFile($a_upload))
  8532.                 SendAlert(GetMessage(MSG_FILE_UPLOAD_ATTACK,
  8533.                                 array("NAME"=>$a_upload["name"],
  8534.                                         "TEMP"=>$a_upload["tmp_name"],
  8535.                                         "FLD"=>$m_file_key)));
  8536.             elseif (!SaveUploadedFile($a_upload,$s_prefix))
  8537.                 return (false);
  8538.     }
  8539.     return (true);
  8540. }
  8541.  
  8542.     //
  8543.     // Attach a file to the body of a MIME formatted email.  $a_lines is the
  8544.     // current body, and is modified to include the file.
  8545.     // $a_file_spec must have the following values (just like an uploaded
  8546.     // file specification):
  8547.     //      name        the name of the file
  8548.     //      type        the mime type
  8549.     //      tmp_name    the name of the temporary file
  8550.     //      size        the size of the temporary file
  8551.     //
  8552.     // Alternatively, you supply the following instead of tmp_name and size:
  8553.     //      data        the data to attach
  8554.     //
  8555. function AttachFile(&$a_lines,$s_att_boundary,$a_file_spec,$s_charset)
  8556. {
  8557.     $a_lines[] = "--$s_att_boundary".HEAD_CRLF;
  8558.         //
  8559.         // if a replacement name has been specified, use that, otherwise
  8560.         // use the original name
  8561.         //
  8562.     if (isset($a_file_spec["new_name"]))
  8563.         $s_file_name = $a_file_spec["new_name"];
  8564.     else
  8565.         $s_file_name = $a_file_spec["name"];
  8566.     $s_file_name = str_replace('"','',$s_file_name);
  8567.     $s_mime_type = $a_file_spec["type"];
  8568.             //
  8569.             // The following says that the data is encoded in
  8570.             // base64 and is an attachment and that once decoded the
  8571.             // character set of the decoded data is $s_charset.
  8572.             // (See RFC 1521 Section 5.)
  8573.             //
  8574.     $a_lines[] = "Content-Type: $s_mime_type; name=\"$s_file_name\"; charset=$s_charset".HEAD_CRLF;
  8575.     $a_lines[] = "Content-Transfer-Encoding: base64".HEAD_CRLF;
  8576.     $a_lines[] = "Content-Disposition: attachment; filename=\"$s_file_name\"".HEAD_CRLF;
  8577.     $a_lines[] = HEAD_CRLF;         // blank line
  8578.     if (isset($a_file_spec["tmp_name"]) && isset($a_file_spec["size"]))
  8579.     {
  8580.         $s_srce = $a_file_spec["tmp_name"];
  8581.             //
  8582.             // check if the file has been saved elsewhere
  8583.             //
  8584.         if (isset($a_file_spec["saved_as"]) && !empty($a_file_spec["saved_as"]))
  8585.             $s_srce = $a_file_spec["saved_as"];
  8586.         return (AddFile($a_lines,$s_srce,$a_file_spec["size"]));
  8587.     }
  8588.     if (!isset($a_file_spec["data"]))
  8589.     {
  8590.         SendAlert(GetMessage(MSG_ATTACH_DATA));
  8591.         return (false);
  8592.     }
  8593.     return (AddData($a_lines,$a_file_spec["data"]));
  8594. }
  8595.  
  8596.     //
  8597.     // Reformat the email to be in MIME format.
  8598.     // Process file attachments and and fill out any
  8599.     // specified HTML template.
  8600.     //
  8601. function MakeMimeMail(&$s_body,&$a_headers,$a_raw_fields,$s_template = "",
  8602.                     $s_missing = NULL,$b_no_plain = false,
  8603.                     $s_filter = "",$a_file_vars = array(),
  8604.                     $a_attach_spec = array())
  8605. {
  8606.     global  $FM_VERS,$aPHPVERSION;
  8607.     global  $SPECIAL_VALUES,$FILTER_ATTRIBS,$FILE_REPOSITORY;
  8608.  
  8609.     $s_charset = GetMailOption("CharSet");
  8610.     if (!isset($s_charset))
  8611.         $s_charset = "ISO-8859-1";
  8612.     $b_att = $b_html = false;
  8613.     $b_got_filter = (isset($s_filter) && !empty($s_filter));
  8614.     if (isset($s_template) && !empty($s_template))
  8615.     {
  8616.             //
  8617.             // need PHP 4.0.5 for the preg_replace_callback function
  8618.             //
  8619.         if (!IsPHPAtLeast("4.0.5"))
  8620.         {
  8621.             SendAlert(GetMessage(MSG_PHP_HTML_TEMPLATES,
  8622.                             array("PHPVERS"=>implode(".",$aPHPVERSION))));
  8623.             return (false);
  8624.         }
  8625.         $b_html = true;
  8626.     }
  8627.     if (count($a_file_vars) > 0)
  8628.     {
  8629.         if (!IsPHPAtLeast("4.0.3"))
  8630.         {
  8631.             SendAlert(GetMessage(MSG_PHP_FILE_UPLOADS,
  8632.                             array("PHPVERS"=>implode(".",$aPHPVERSION))));
  8633.             return (false);
  8634.         }
  8635.         if (!FILEUPLOADS)
  8636.             SendAlert(GetMessage(MSG_FILE_UPLOAD));
  8637.         elseif ($FILE_REPOSITORY === "")    // if storing on the server, don't attach
  8638.             foreach ($a_file_vars as $a_upload)
  8639.             {
  8640.                     //
  8641.                     // One customer reported:
  8642.                     //  Possible file upload attack detected: name='' temp name='none'
  8643.                     // on PHP 4.1.2 on RAQ4.
  8644.                     // So, we now also test for "name".
  8645.                     //
  8646.                 if (isset($a_upload["tmp_name"]) && !empty($a_upload["tmp_name"]) &&
  8647.                     isset($a_upload["name"]) && !empty($a_upload["name"]))
  8648.                 {
  8649.                     $b_att = true;
  8650.                     break;
  8651.                 }
  8652.             }
  8653.     }
  8654.         //
  8655.         // check for an internally-generated attachment
  8656.         //
  8657.     if (isset($a_attach_spec["Data"]))
  8658.         $b_att = true;
  8659.  
  8660.     $s_uniq = md5($s_body);
  8661.     $s_body_boundary = "BODY$s_uniq";
  8662.     $s_att_boundary = "PART$s_uniq";
  8663.     $a_headers['MIME-Version'] = "1.0 (produced by FormMail $FM_VERS from www.tectite.com)";
  8664.  
  8665.         //
  8666.         // if the filter strips formatting, then we'll only have plain text
  8667.         // to send, even after the template has been used
  8668.         //
  8669.     if ($b_got_filter && IsFilterAttribSet($s_filter,"Strips"))
  8670.             //
  8671.             // no HTML if the filter strips the formatting
  8672.             //
  8673.         $b_html = false;
  8674.     $a_new = array();
  8675.     if ($b_att)
  8676.     {
  8677.         $a_headers['Content-Type'] = "multipart/mixed; boundary=\"$s_att_boundary\"";
  8678.  
  8679.         MimePreamble($a_new);
  8680.             //
  8681.             // add the body of the email
  8682.             //
  8683.         $a_new[] = "--$s_att_boundary".HEAD_CRLF;
  8684.         if ($b_html)
  8685.         {
  8686.             $a_lines = $a_local_headers = array();
  8687.             if (!HTMLMail($a_lines,$a_local_headers,$s_body,$s_template,
  8688.                             $s_missing,($b_got_filter) ? $s_filter : "",
  8689.                             $s_body_boundary,$a_raw_fields,$b_no_plain))
  8690.                 return (false);
  8691.             $a_new = array_merge($a_new,ExpandMailHeadersArray($a_local_headers));
  8692.             $a_new[] = HEAD_CRLF;       // blank line after header
  8693.             $a_new = array_merge($a_new,$a_lines);
  8694.         }
  8695.         else
  8696.         {
  8697.             $a_new[] = "Content-Type: text/plain; charset=$s_charset".HEAD_CRLF;
  8698.             $a_new[] = HEAD_CRLF;       // blank line
  8699.                 //
  8700.                 // treat the body like one line, even though it isn't
  8701.                 //
  8702.             $a_new[] = $s_body;
  8703.         }
  8704.             //
  8705.             // now add the attachments or save to the $FILE_REPOSITORY
  8706.             //
  8707.         if (FILEUPLOADS && $FILE_REPOSITORY === "")
  8708.             foreach ($a_file_vars as $m_file_key=>$a_upload)
  8709.             {
  8710.                     //
  8711.                     // One customer reported:
  8712.                     //  Possible file upload attack detected: name='' temp name='none'
  8713.                     // on PHP 4.1.2 on RAQ4.
  8714.                     // So, we now also test for "name".
  8715.                     //
  8716.                 if (!isset($a_upload["tmp_name"]) || empty($a_upload["tmp_name"]) ||
  8717.                     !isset($a_upload["name"]) || empty($a_upload["name"]))
  8718.                     continue;
  8719.                 if (!IsUploadedFile($a_upload))
  8720.                 {
  8721.                     SendAlert(GetMessage(MSG_FILE_UPLOAD_ATTACK,
  8722.                                     array("NAME"=>$a_upload["name"],
  8723.                                           "TEMP"=>$a_upload["tmp_name"],
  8724.                                           "FLD"=>$m_file_key)));
  8725.                     continue;
  8726.                 }
  8727.                 if (MAX_FILE_UPLOAD_SIZE != 0 &&
  8728.                     $a_upload["size"] > MAX_FILE_UPLOAD_SIZE*1024)
  8729.                     UserError("upload_size",GetMessage(MSG_FILE_UPLOAD_SIZE,
  8730.                                               array("NAME"=>$a_upload["name"],
  8731.                                                     "SIZE"=>$a_upload["size"],
  8732.                                                     "MAX"=>MAX_FILE_UPLOAD_SIZE)));
  8733.                 if (!AttachFile($a_new,$s_att_boundary,$a_upload,$s_charset))
  8734.                     return (false);
  8735.             }
  8736.         if (isset($a_attach_spec["Data"]))
  8737.         {
  8738.                 //
  8739.                 // build a specification similar to a file upload
  8740.                 //
  8741.             $a_file_spec["name"] = isset($a_attach_spec["Name"]) ?
  8742.                                         $a_attach_spec["Name"] :
  8743.                                         "attachment.dat";
  8744.             $a_file_spec["type"] = isset($a_attach_spec["MIME"]) ?
  8745.                                         $a_attach_spec["MIME"] :
  8746.                                         "text/plain";
  8747.             $a_file_spec["data"] = $a_attach_spec["Data"];
  8748.             if (!AttachFile($a_new,$s_att_boundary,$a_file_spec,
  8749.                                 isset($a_attach_spec["CharSet"]) ?
  8750.                                 $a_attach_spec["CharSet"] :
  8751.                                 $s_charset))
  8752.                 return (false);
  8753.         }
  8754.         $a_new[] = "--$s_att_boundary--".HEAD_CRLF;     // the end
  8755.         $a_new[] = HEAD_CRLF;           // blank line
  8756.     }
  8757.     elseif ($b_html)
  8758.     {
  8759.         if (!HTMLMail($a_new,$a_headers,$s_body,$s_template,
  8760.                             $s_missing,($b_got_filter) ? $s_filter : "",
  8761.                             $s_body_boundary,$a_raw_fields,$b_no_plain))
  8762.             return (false);
  8763.     }
  8764.     else
  8765.     {
  8766.         $a_headers['Content-Type'] = SafeHeader("text/plain; charset=$s_charset");
  8767.             //
  8768.             // treat the body like one line, even though it isn't
  8769.             //
  8770.         $a_new[] = $s_body;
  8771.     }
  8772.  
  8773.     $s_body = JoinLines(BODY_LF,$a_new);
  8774.     return (true);
  8775. }
  8776.  
  8777.     //
  8778.     // to make a From line for the email
  8779.     //
  8780. function MakeFromLine($s_email,$s_name)
  8781. {
  8782.     $s_style = GetMailOption("FromLineStyle");
  8783.     $s_line = "";
  8784.     if (!isset($s_style))
  8785.         $s_style = "";
  8786.         //
  8787.         // the following From line styles are in accordance with RFC 822
  8788.         //
  8789.     switch ($s_style)
  8790.     {
  8791.     default:
  8792.     case "":
  8793.     case "default":
  8794.     case "AddrSpecName":
  8795.                 //
  8796.                 // this is the original From line style that FormMail produced
  8797.                 // e.g.
  8798.                 //      jack@nowhere.com (Jack Smith)
  8799.                 // this is an addr-spec with a trailing comment with the name
  8800.                 //
  8801.         if (!empty($s_email))
  8802.             $s_line .= SafeHeaderEmail($s_email)." ";
  8803.         if (!empty($s_name))
  8804.             $s_line .= "(".SafeHeaderComment($s_name).")";
  8805.         break;
  8806.     case "NameAddrSpec":
  8807.                 //
  8808.                 // email address as an addr-spec preceded by a comment with the name
  8809.                 // e.g.
  8810.                 //      (Jack Smith) jack@nowhere.com
  8811.                 //
  8812.         if (!empty($s_name))
  8813.             $s_line .= "(".SafeHeaderComment($s_name).") ";
  8814.         if (!empty($s_email))
  8815.             $s_line .= SafeHeaderEmail($s_email);
  8816.         break;
  8817.     case "RouteAddr":
  8818.                 //
  8819.                 // just the email address as a route-addr
  8820.                 // e.g.
  8821.                 //      <jack@nowhere.com>
  8822.                 //
  8823.         if (!empty($s_email))
  8824.             $s_line .= "<".SafeHeaderEmail($s_email).">";
  8825.         break;
  8826.     case "QuotedNameRouteAddr":
  8827.                 //
  8828.                 // email address as a route-addr preceded
  8829.                 // by the name of the user as a quoted string
  8830.                 // e.g.
  8831.                 //      "Jack Smith" <jack@nowhere.com>
  8832.                 //
  8833.         if (!empty($s_name))
  8834.             $s_line .= '"'.SafeHeaderQString($s_name).'" ';
  8835.         if (!empty($s_email))
  8836.             $s_line .= "<".SafeHeaderEmail($s_email).">";
  8837.         break;
  8838.     case "NameRouteAddr":
  8839.                 //
  8840.                 // email address as a route-addr preceded
  8841.                 // by the name of the user as words
  8842.                 // e.g.
  8843.                 //      Jack Smith <jack@nowhere.com>
  8844.                 //
  8845.         if (!empty($s_name))
  8846.             $s_line .= SafeHeaderWords($s_name).' ';
  8847.         if (!empty($s_email))
  8848.             $s_line .= "<".SafeHeaderEmail($s_email).">";
  8849.         break;
  8850.     }
  8851.     return ($s_line);
  8852. }
  8853.  
  8854.     //
  8855.     // Return two sets of plain text output: the filtered fields and the
  8856.     // non-filtered fields.
  8857.     //
  8858. function GetFilteredOutput($a_fld_order,$a_clean_fields,$s_filter,$a_filter_list)
  8859. {
  8860.         //
  8861.         // find the non-filtered fields and make unfiltered text from them
  8862.         //
  8863.     $a_unfiltered_list = array();
  8864.     $n_flds = count($a_fld_order);
  8865.     for ($ii = 0 ; $ii < $n_flds ; $ii++)
  8866.         if (!in_array($a_fld_order[$ii],$a_filter_list))
  8867.             $a_unfiltered_list[] = $a_fld_order[$ii];
  8868.     $s_unfiltered_results = MakeFieldOutput($a_unfiltered_list,$a_clean_fields);
  8869.         //
  8870.         // filter the specified fields only
  8871.         //
  8872.     $s_filtered_results = MakeFieldOutput($a_filter_list,$a_clean_fields);
  8873.     $s_filtered_results = Filter($s_filter,$s_filtered_results);
  8874.     return (array($s_unfiltered_results,$s_filtered_results));
  8875. }
  8876.  
  8877.     //
  8878.     // Make a plain text email body
  8879.     //
  8880. function MakePlainEmail($a_fld_order,$a_clean_fields,
  8881.                         $s_to,$s_cc,$s_bcc,$a_raw_fields,$s_filter,$a_filter_list)
  8882. {
  8883.     global  $SPECIAL_VALUES,$aPHPVERSION;
  8884.  
  8885.     $s_unfiltered_results = $s_filtered_results = "";
  8886.     $b_got_filter = (isset($s_filter) && !empty($s_filter));
  8887.     if ($b_got_filter)
  8888.         if (isset($a_filter_list) && count($a_filter_list) > 0)
  8889.             $b_limited_filter = true;
  8890.         else
  8891.             $b_limited_filter = false;
  8892.     $b_used_template = false;
  8893.     if (IsMailOptionSet("PlainTemplate"))
  8894.     {
  8895.             //
  8896.             // need PHP 4.0.5 for the preg_replace_callback function
  8897.             //
  8898.         if (!IsPHPAtLeast("4.0.5"))
  8899.             SendAlert(GetMessage(MSG_PHP_PLAIN_TEMPLATES,
  8900.                             array("PHPVERS"=>implode(".",$aPHPVERSION))));
  8901.         else
  8902.         {
  8903.             $s_template = GetMailOption("PlainTemplate");
  8904.             if (ProcessTemplate($s_template,$a_lines,$a_raw_fields,
  8905.                                 GetMailOption('TemplateMissing'),
  8906.                                 'SubstituteValuePlain'))
  8907.             {
  8908.                 $b_used_template = true;
  8909.                 $s_unfiltered_results = implode(BODY_LF,$a_lines);
  8910.                 if ($b_got_filter)
  8911.                 {
  8912.                         //
  8913.                         // with a limited filter, the template goes unfiltered
  8914.                         // and the named fields get filtered
  8915.                         //
  8916.                     if ($b_limited_filter)
  8917.                         list($s_discard,$s_filtered_results) =
  8918.                                     GetFilteredOutput($a_fld_order,$a_clean_fields,
  8919.                                             $s_filter,$a_filter_list);
  8920.                     else
  8921.                     {
  8922.                         $s_filtered_results = Filter($s_filter,$s_unfiltered_results);
  8923.                         $s_unfiltered_results = "";
  8924.                     }
  8925.                 }
  8926.             }
  8927.         }
  8928.     }
  8929.     if (!$b_used_template)
  8930.     {
  8931.         $res_hdr = "";
  8932.  
  8933.         if (IsMailOptionSet("DupHeader"))
  8934.         {
  8935.                 //
  8936.                 // write some standard mail headers
  8937.                 //
  8938.             $res_hdr = "To: $s_to".BODY_LF;
  8939.             if (!empty($s_cc))
  8940.                 $res_hdr .= "Cc: $s_cc".BODY_LF;
  8941.             if (!empty($SPECIAL_VALUES["email"]))
  8942.                 $res_hdr .= "From: ".MakeFromLine($SPECIAL_VALUES["email"],
  8943.                                         $SPECIAL_VALUES["realname"]).BODY_LF;
  8944.             $res_hdr .= BODY_LF;
  8945.             if (IsMailOptionSet("StartLine"))
  8946.                 $res_hdr .= "--START--".BODY_LF;        // signals the beginning of the text to filter
  8947.         }
  8948.  
  8949.             //
  8950.             // put the realname and the email address at the top of the results
  8951.             // (if not excluded)
  8952.             //
  8953.         if (!IsMailExcluded("realname"))
  8954.         {
  8955.             array_unshift($a_fld_order,"realname");
  8956.             $a_clean_fields["realname"] = $SPECIAL_VALUES["realname"];
  8957.         }
  8958.         if (!IsMailExcluded("email"))
  8959.         {
  8960.             array_unshift($a_fld_order,"email");
  8961.             $a_clean_fields["email"] = $SPECIAL_VALUES["email"];
  8962.         }
  8963.         if ($b_got_filter)
  8964.         {
  8965.             if ($b_limited_filter)
  8966.                 list($s_unfiltered_results,$s_filtered_results) =
  8967.                             GetFilteredOutput($a_fld_order,$a_clean_fields,
  8968.                                     $s_filter,$a_filter_list);
  8969.             else
  8970.             {
  8971.                     //
  8972.                     // make text output and filter it (filter all fields)
  8973.                     //
  8974.                 $s_filtered_results = MakeFieldOutput($a_fld_order,$a_clean_fields);
  8975.                 $s_filtered_results = Filter($s_filter,$s_filtered_results);
  8976.             }
  8977.         }
  8978.         else
  8979.         {
  8980. //SendAlert("There are ".count($a_fld_order)." fields in the order array");
  8981. //SendAlert("Here is the clean fields array:\r\n".var_export($a_clean_fields,true));
  8982.             $s_unfiltered_results = MakeFieldOutput($a_fld_order,$a_clean_fields);
  8983.         }
  8984.         $s_unfiltered_results = $res_hdr.$s_unfiltered_results;
  8985.     }
  8986.     $s_results = $s_unfiltered_results;
  8987.     if ($b_got_filter && !empty($s_filtered_results))
  8988.     {
  8989.         if (!empty($s_results))
  8990.             $s_results .= BODY_LF;
  8991.         $s_results .= $s_filtered_results;
  8992.     }
  8993.     return (array($s_results,$s_unfiltered_results,$s_filtered_results));
  8994. }
  8995.  
  8996.     //
  8997.     // Return the list of fields to be filtered, FALSE if no list provided.
  8998.     //
  8999. function GetFilterList()
  9000. {
  9001.     global  $SPECIAL_VALUES;
  9002.  
  9003.         //
  9004.         // no filter means no list of fields
  9005.         //
  9006.     if (!empty($SPECIAL_VALUES["filter"]))
  9007.         if (isset($SPECIAL_VALUES["filter_fields"]) && !empty($SPECIAL_VALUES["filter_fields"]))
  9008.             return (TrimArray(explode(",",$SPECIAL_VALUES["filter_fields"])));
  9009.     return (false);
  9010. }
  9011.  
  9012.     //
  9013.     // send the given results to the given email addresses
  9014.     //
  9015. function SendResults($a_fld_order,$a_clean_fields,$s_to,$s_cc,$s_bcc,$a_raw_fields)
  9016. {
  9017.     global  $SPECIAL_VALUES,$aFileVars,$FILE_REPOSITORY,$FIXED_SENDER;
  9018.  
  9019.         //
  9020.         // check for a filter and how to use it
  9021.         //
  9022.     $b_got_filter = (isset($SPECIAL_VALUES["filter"]) && !empty($SPECIAL_VALUES["filter"]));
  9023.     $b_filter_attach = false;
  9024.     $a_attach_spec = array();
  9025.     $s_filter = "";
  9026.     $a_filter_list = array();
  9027.     if ($b_got_filter)
  9028.     {
  9029.         $s_filter = $SPECIAL_VALUES["filter"];
  9030.         $a_filter_list = GetFilterList();
  9031.         if ($a_filter_list === false)
  9032.         {
  9033.                 //
  9034.                 // not a limited filter, so filter all fields
  9035.                 //
  9036.             $b_limited_filter = false;
  9037.             $a_filter_list = array();
  9038.         }
  9039.         else
  9040.             $b_limited_filter = true;
  9041.         $s_filter_attach_name = GetFilterOption("Attach");
  9042.         if (isset($s_filter_attach_name))
  9043.              if (!is_string($s_filter_attach_name) || empty($s_filter_attach_name))
  9044.                 SendAlert(GetMessage(MSG_ATTACH_NAME));
  9045.             else
  9046.             {
  9047.                 $b_filter_attach = true;
  9048.                 $a_attach_spec = array("Name"=>$s_filter_attach_name);
  9049.                 if (($s_mime = GetFilterAttrib($s_filter,"MIME")) !== false)
  9050.                     $a_attach_spec["MIME"] = $s_mime;
  9051.                     //
  9052.                     // Regarding the character set...
  9053.                     // A filter will not generally change the character set
  9054.                     // of the message, however, if it does, then we
  9055.                     // provide that information to the MIME encoder.
  9056.                     // Remember: this character set specification refers
  9057.                     // to the data *after* the effect of the filter
  9058.                     // has been reversed (e.g. an encrypted message
  9059.                     // in UTF-8 is in UTF-8 when it is decrypted).
  9060.                     //
  9061.                 if (($s_cset = GetFilterAttrib($s_filter,"CharSet")) !== false)
  9062.                     $a_attach_spec["CharSet"] = $s_cset;
  9063.             }
  9064.     }
  9065.  
  9066.         //
  9067.         // check the need for MIME formatted mail
  9068.         //
  9069.     $b_mime_mail = (IsMailOptionSet("HTMLTemplate") || count($aFileVars) > 0 ||
  9070.                     $b_filter_attach);
  9071.  
  9072.         //
  9073.         // create the email header lines - CC, BCC, From, and Reply-To
  9074.         //
  9075.     $a_headers = array();
  9076.     if (!empty($s_cc))
  9077.         $a_headers['Cc'] = SafeHeader($s_cc);
  9078.     if (!empty($SPECIAL_VALUES["replyto"]))
  9079.     {
  9080.             //
  9081.             // expand replyto list
  9082.             //
  9083.         CheckEmailAddress($SPECIAL_VALUES["replyto"],$s_list,$s_invalid,false);
  9084.         if (!empty($s_list))
  9085.             $a_headers['Reply-To'] = SafeHeader($s_list);
  9086.     }
  9087.         //
  9088.         // note that BCC is documented to not work prior to PHP 4.3
  9089.         //
  9090.     if (!empty($s_bcc))
  9091.     {
  9092.         global  $aPHPVERSION;
  9093.  
  9094.         if ($aPHPVERSION[0] < 4 || ($aPHPVERSION[0] == 4 && $aPHPVERSION[1] < 3))
  9095.             SendAlert(GetMessage(MSG_PHP_BCC,
  9096.                             array("PHPVERS"=>implode(".",$aPHPVERSION))));
  9097.         $a_headers['Bcc'] = SafeHeader($s_bcc);
  9098.     }
  9099.         //
  9100.         // create the From address
  9101.         //
  9102.         // Some servers won't let you set the email address to the
  9103.         // submitter of the form.  Therefore, use FromAddr if it's been
  9104.         // specified to set the sender and the "From" address.
  9105.         //
  9106.     $s_sender = GetMailOption("FromAddr");
  9107.     if (!isset($s_sender))
  9108.     {
  9109.         $s_sender = "";
  9110.         if (!empty($SPECIAL_VALUES["email"]))
  9111.             $a_headers['From'] = MakeFromLine($SPECIAL_VALUES["email"],
  9112.                                             $SPECIAL_VALUES["realname"]);
  9113.     }
  9114.     elseif ($s_sender !== "")
  9115.         $s_sender = $a_headers['From'] = SafeHeader(UnMangle($s_sender));
  9116.  
  9117.         /* 
  9118.          * Override sender if $FIXED_SENDER is set.
  9119.          */
  9120.     if ($FIXED_SENDER !== "")
  9121.         $s_sender = $FIXED_SENDER;
  9122.  
  9123.     if ($s_sender === "")
  9124.         if (SET_SENDER_FROM_EMAIL)
  9125.             $s_sender = $SPECIAL_VALUES["email"];
  9126.  
  9127.         //
  9128.         // special case: if there is only one non-special string value, then
  9129.         // format it as an email (unless an option says not to)
  9130.         //
  9131.     $a_keys = array_keys($a_raw_fields);
  9132.     if (count($a_keys) == 1 && is_string($a_raw_fields[$a_keys[0]]) &&
  9133.         !IsMailOptionSet("AlwaysList") && !IsMailOptionSet("DupHeader"))
  9134.     {
  9135.         if (IsMailExcluded($a_keys[0]))
  9136.             SendAlert("Exclusion of single field '".$a_keys[0]."' ignored");
  9137.         $s_value = $a_raw_fields[$a_keys[0]];
  9138.             //
  9139.             // replace carriage return/linefeeds with <br>
  9140.             //
  9141.         $s_value = str_replace("\r\n",'<br />',$s_value);
  9142.             //
  9143.             // replace lone linefeeds with <br>
  9144.             //
  9145.         $s_value = str_replace("\n",'<br />',$s_value);
  9146.             //
  9147.             // remove lone carriage returns
  9148.             //
  9149.         $s_value = str_replace("\r","",$s_value);
  9150.             //
  9151.             // replace all control chars with <br>
  9152.             //
  9153.         $s_value = preg_replace('/[[:cntrl:]]+/','<br />',$s_value);
  9154.             //
  9155.             // strip HTML (note that all the <br> above will now be
  9156.             // replaced with BODY_LF)
  9157.             //
  9158.         $s_value = StripHTML($s_value,BODY_LF);
  9159.  
  9160.         if ($b_mime_mail)
  9161.         {
  9162.             if ($b_got_filter)
  9163.             {
  9164.                     //
  9165.                     // filter the whole value (ignore filter_fields for this
  9166.                     // special case) if a filter has been specified
  9167.                     //
  9168.                 $s_results = Filter($s_filter,$s_value);
  9169.                 if ($b_filter_attach)
  9170.                 {
  9171.                     $a_attach_spec["Data"] = $s_results;
  9172.                         //
  9173.                         // KeepInLine keeps the filtered version inline as well
  9174.                         // as an attachment
  9175.                         //
  9176.                     if (!IsFilterOptionSet("KeepInLine"))
  9177.                         $s_results = "";
  9178.                     $s_filter = ""; // no more filtering
  9179.                 }
  9180.             }
  9181.             else
  9182.                 $s_results = $s_value;
  9183.  
  9184.                 //
  9185.                 // send this single value off to get formatted in a MIME
  9186.                 // email
  9187.                 //
  9188.             if (!MakeMimeMail($s_results,$a_headers,$a_raw_fields,
  9189.                                 GetMailOption('HTMLTemplate'),
  9190.                                 GetMailOption('TemplateMissing'),
  9191.                                 IsMailOptionSet("NoPlain"),
  9192.                                 $s_filter,$aFileVars,$a_attach_spec))
  9193.                 return (false);
  9194.         }
  9195.         elseif ($b_got_filter)
  9196.                 //
  9197.                 // filter the whole value (ignore filter_fields for this special case)
  9198.                 // if a filter has been specified
  9199.                 //
  9200.             $s_results = Filter($s_filter,$s_value);
  9201.         else
  9202.             $s_results = $s_value;
  9203.     }
  9204.     else
  9205.     {
  9206.         if ($b_mime_mail)
  9207.         {
  9208.                 //
  9209.                 // get the plain text version of the email then send it
  9210.                 // to get MIME formatted
  9211.                 //
  9212.             list($s_results,$s_unfiltered_results,$s_filtered_results) =
  9213.                             MakePlainEmail($a_fld_order,$a_clean_fields,
  9214.                                 $s_to,$s_cc,$s_bcc,$a_raw_fields,$s_filter,
  9215.                                 $a_filter_list);
  9216.             if ($b_filter_attach)
  9217.             {
  9218.                     //
  9219.                     // attached the filtered results
  9220.                     //
  9221.                 $a_attach_spec["Data"] = $s_filtered_results;
  9222.                     //
  9223.                     // KeepInLine keeps the filtered version inline as well
  9224.                     // as an attachment
  9225.                     //
  9226.                 if (!IsFilterOptionSet("KeepInLine"))
  9227.                         //
  9228.                         // put the unfiltered results in the body of the message
  9229.                         //
  9230.                     $s_results = $s_unfiltered_results;
  9231.                 $s_filter = ""; // no more filtering
  9232.             }
  9233.             if (!MakeMimeMail($s_results,$a_headers,$a_raw_fields,
  9234.                                 GetMailOption('HTMLTemplate'),
  9235.                                 GetMailOption('TemplateMissing'),
  9236.                                 IsMailOptionSet("NoPlain"),
  9237.                                 $s_filter,$aFileVars,$a_attach_spec))
  9238.                 return (false);
  9239.         }
  9240.         else
  9241.         {
  9242.             list($s_results,$s_unfiltered_results,$s_filtered_results) =
  9243.                             MakePlainEmail($a_fld_order,$a_clean_fields,
  9244.                                 $s_to,$s_cc,$s_bcc,$a_raw_fields,$s_filter,
  9245.                                 $a_filter_list);
  9246.             if (!$b_got_filter && IsMailOptionSet("CharSet"))
  9247.                     //
  9248.                     // sending plain text email, and the CharSet has been
  9249.                     // specified; include a header
  9250.                     //
  9251.                 $a_headers['Content-Type'] = "text/plain; charset=".SafeHeader(GetMailOption("CharSet"));
  9252.         }
  9253.     }
  9254.  
  9255.         //
  9256.         // append the environment variables report
  9257.         //
  9258.     if (isset($SPECIAL_VALUES["env_report"]) && !empty($SPECIAL_VALUES["env_report"]))
  9259.     {
  9260.         $s_results .= BODY_LF."==================================".BODY_LF;
  9261.         $s_results .= BODY_LF.GetEnvVars(TrimArray(explode(",",$SPECIAL_VALUES["env_report"])),BODY_LF);
  9262.     }
  9263.         //
  9264.         // now save uploaded files to the repository
  9265.         //
  9266.     if (FILEUPLOADS && $FILE_REPOSITORY !== "")
  9267.         if (!SaveAllFilesToRepository())
  9268.             return (false);
  9269.  
  9270.         //
  9271.         // send the mail - assumes the email addresses have already been checked
  9272.         //
  9273.     return (SendCheckedMail($s_to,$SPECIAL_VALUES["subject"],$s_results,
  9274.                                     $s_sender,$a_headers));
  9275. }
  9276.  
  9277.     //
  9278.     // append an entry to a log file
  9279.     //
  9280. function WriteLog($log_file)
  9281. {
  9282.     global  $SPECIAL_VALUES,$php_errormsg;
  9283.  
  9284. @   $log_fp = fopen($log_file,"a");
  9285.     if ($log_fp === false)
  9286.     {
  9287.         SendAlert(GetMessage(MSG_FILE_OPEN_ERROR,array("NAME"=>$log_file,
  9288.                                             "TYPE"=>"log",
  9289.                                             "ERROR"=>CheckString($php_errormsg))));
  9290.         return;
  9291.     }
  9292.     $date = gmdate("H:i:s d-M-y T");
  9293.     $entry = $date.":".$SPECIAL_VALUES["email"].",".
  9294.             $SPECIAL_VALUES["realname"].",".$SPECIAL_VALUES["subject"]."\n";
  9295.     fwrite($log_fp,$entry);
  9296.     fclose($log_fp);
  9297. }
  9298.  
  9299.     //
  9300.     // write the data to a comma-separated-values file
  9301.     //
  9302. function WriteCSVFile($s_csv_file,$a_vars)
  9303. {
  9304.     global  $SPECIAL_VALUES,$CSVSEP,$CSVINTSEP,$CSVQUOTE,$CSVOPEN,$CSVLINE;
  9305.  
  9306.         //
  9307.         // create an array of column values in the order specified
  9308.         // in $SPECIAL_VALUES["csvcolumns"]
  9309.         //
  9310.     $a_column_list = $SPECIAL_VALUES["csvcolumns"];
  9311.     if (!isset($a_column_list) || empty($a_column_list) || !is_string($a_column_list))
  9312.     {
  9313.         SendAlert(GetMessage(MSG_CSVCOLUMNS,array("VALUE"=>$a_column_list)));
  9314.         return;
  9315.     }
  9316.     if (!isset($s_csv_file) || empty($s_csv_file) || !is_string($s_csv_file))
  9317.     {
  9318.         SendAlert(GetMessage(MSG_CSVFILE,array("VALUE"=>$s_csv_file)));
  9319.         return;
  9320.     }
  9321.  
  9322. @   $fp = fopen($s_csv_file,"a".$CSVOPEN);
  9323.     if ($fp === false)
  9324.     {
  9325.         SendAlert(GetMessage(MSG_FILE_OPEN_ERROR,array("NAME"=>$s_csv_file,
  9326.                                             "TYPE"=>"CSV",
  9327.                                             "ERROR"=>CheckString($php_errormsg))));
  9328.         return;
  9329.     }
  9330.  
  9331.         //
  9332.         // convert the column list to an array, trim the names too
  9333.         //
  9334.     $a_column_list = TrimArray(explode(",",$a_column_list));
  9335.     $n_columns = count($a_column_list);
  9336.  
  9337.         //
  9338.         // if the file is currently empty, put the column names in the first line
  9339.         //
  9340.     if (filesize($s_csv_file) == 0)
  9341.     {
  9342.         for ($ii = 0 ; $ii < $n_columns ; $ii++)
  9343.         {
  9344.             fwrite($fp,$CSVQUOTE.$a_column_list[$ii].$CSVQUOTE);
  9345.             if ($ii < $n_columns-1)
  9346.                 fwrite($fp,"$CSVSEP");
  9347.         }
  9348.         fwrite($fp,$CSVLINE);
  9349.     }
  9350.  
  9351. //  $debug = "";
  9352. //  $debug .= "gpc -> ".get_magic_quotes_gpc()."\n";
  9353. //  $debug .= "runtime -> ".get_magic_quotes_runtime()."\n";
  9354.     for ($ii = 0 ; $ii < $n_columns ; $ii++)
  9355.     {
  9356.         $s_col_name = $a_column_list[$ii];
  9357.             //
  9358.             // columns can be missing from some form submission and present
  9359.             // from others
  9360.             //
  9361.         if (isset($a_vars[$s_col_name]))
  9362.             $m_value = $a_vars[$s_col_name];
  9363.         else
  9364.             $m_value = "";
  9365.  
  9366.         if (LIMITED_IMPORT)
  9367.                 //
  9368.                 // the target database doesn't understand escapes, so
  9369.                 // remove various things, including newlines and truncate
  9370.                 //
  9371.             $m_value = CleanValue($m_value);
  9372.         else
  9373.                 //
  9374.                 // the target database does understand escapes, so
  9375.                 // we have to slash any slashes
  9376.                 //
  9377.             $m_value = str_replace("\\","\\\\",$m_value);
  9378.             //
  9379.             // convert quotes, depending on the setting of $CSVQUOTE
  9380.             //
  9381.         switch ($CSVQUOTE)
  9382.         {
  9383.         case '"':
  9384.                     //
  9385.                     // convert double quotes in the data to single quotes
  9386.                     //
  9387.             $m_value = str_replace("\"","'",$m_value);
  9388.             break;
  9389.         case '\'':
  9390.                     //
  9391.                     // convert single quotes in the data to double quotes
  9392.                     //
  9393.             $m_value = str_replace("'","\"",$m_value);
  9394.             break;
  9395.         default:
  9396.                 //
  9397.                 // otherwise, leave the data unchanged
  9398.                 //
  9399.             break;
  9400.         }
  9401.             //
  9402.             // we handle arrays and strings
  9403.             //
  9404.         if (is_array($m_value))
  9405.                 //
  9406.                 // separate the values with the internal field separator
  9407.                 //
  9408.             $m_value = implode("$CSVINTSEP",$m_value);
  9409.  
  9410. //      $debug .= $a_column_list[$ii]." => ".$m_value."\n";
  9411.         fwrite($fp,$CSVQUOTE.$m_value.$CSVQUOTE);
  9412.         if ($ii < $n_columns-1)
  9413.             fwrite($fp,"$CSVSEP");
  9414.     }
  9415.     fwrite($fp,$CSVLINE);
  9416.     fclose($fp);
  9417. //  CreatePage($debug);
  9418. //  exit;
  9419. }
  9420.  
  9421. function CheckConfig()
  9422. {
  9423.     global  $TARGET_EMAIL,$CONFIG_CHECK;
  9424.  
  9425.     $a_mesgs = array();
  9426.     if (in_array("TARGET_EMAIL",$CONFIG_CHECK))
  9427.     {
  9428.             //
  9429.             // $TARGET_EMAIL values should begin with ^ and end with $
  9430.             //
  9431.         for ($ii = 0 ; $ii < count($TARGET_EMAIL) ; $ii++)
  9432.         {
  9433.             $s_pattern = $TARGET_EMAIL[$ii];
  9434.             if (substr($s_pattern,0,1) != '^')
  9435.                 $a_mesgs[] = GetMessage(MSG_TARG_EMAIL_PAT_START,
  9436.                                         array("PAT"=>$s_pattern));
  9437.             if (substr($s_pattern,-1) != '$')
  9438.                 $a_mesgs[] = GetMessage(MSG_TARG_EMAIL_PAT_END,
  9439.                                         array("PAT"=>$s_pattern));
  9440.         }
  9441.     }
  9442.     if (count($a_mesgs) > 0)
  9443.         SendAlert(GetMessage(MSG_CONFIG_WARN,
  9444.                         array("MESGS"=>implode("\n",$a_mesgs))),false,true);
  9445. }
  9446.  
  9447.     //
  9448.     // append an entry to the Auto Responder log file
  9449.     //
  9450. function WriteARLog($s_to,$s_subj,$s_info)
  9451. {
  9452.     global  $LOGDIR,$AUTORESPONDLOG,$aServerVars,$php_errormsg;
  9453.  
  9454.     if (!isset($LOGDIR) || !isset($AUTORESPONDLOG) ||
  9455.             empty($LOGDIR) || empty($AUTORESPONDLOG))
  9456.         return;
  9457.  
  9458.     $log_file = $LOGDIR."/".$AUTORESPONDLOG;
  9459. @   $log_fp = fopen($log_file,"a");
  9460.     if ($log_fp === false)
  9461.     {
  9462.         SendAlert(GetMessage(MSG_FILE_OPEN_ERROR,array("NAME"=>$log_file,
  9463.                                             "TYPE"=>"log",
  9464.                                             "ERROR"=>CheckString($php_errormsg))));
  9465.         return;
  9466.     }
  9467.     $a_entry = array();
  9468.     $a_entry[] = gmdate("H:i:s d-M-y T");       // date/time in GMT
  9469.     $a_entry[] = $aServerVars['REMOTE_ADDR'];   // remote IP address
  9470.     $a_entry[] = $s_to;                         // target email address
  9471.     $a_entry[] = $s_subj;                       // subject line
  9472.     $a_entry[] = $s_info;                       // information
  9473.  
  9474.     $s_log_entry = implode(",",$a_entry)."\n";
  9475.     fwrite($log_fp,$s_log_entry);
  9476.     fclose($log_fp);
  9477. }
  9478.  
  9479.     //
  9480.     // Send an email response to the user.
  9481.     //
  9482. function AutoRespond($s_to,$s_subj,$a_values)
  9483. {
  9484.     global  $aPHPVERSION,$SPECIAL_VALUES,$FROM_USER;
  9485.  
  9486.         //
  9487.         // need PHP 4.0.5 for the preg_replace_callback function
  9488.         //
  9489.     if (!IsPHPAtLeast("4.0.5"))
  9490.     {
  9491.         SendAlert(GetMessage(MSG_PHP_AUTORESP,
  9492.                         array("PHPVERS"=>implode(".",$aPHPVERSION))));
  9493.         return (false);
  9494.     }
  9495.  
  9496.     $a_headers = array();
  9497.     $s_mail_text = "";
  9498.     $s_from_addr = GetAROption("FromAddr");
  9499.  
  9500.     if (!isset($s_from_addr))
  9501.     {
  9502.         $s_from_addr = "";
  9503.         if (isset($FROM_USER) && !empty($FROM_USER))
  9504.         {
  9505.             if ($FROM_USER != "NONE")
  9506.                 $s_from_addr = $FROM_USER;
  9507.         }
  9508.         else
  9509.         {
  9510.             global  $SERVER;
  9511.  
  9512.             $s_from_addr = "FormMail@".$SERVER;
  9513.         }
  9514.     }
  9515.     else
  9516.         $s_from_addr = UnMangle($s_from_addr);
  9517.  
  9518.     if (!empty($s_from_addr))
  9519.         $a_headers['From'] = SafeHeader($s_from_addr);
  9520.  
  9521.     if (IsAROptionSet('PlainTemplate'))
  9522.     {
  9523.         $s_template = GetAROption("PlainTemplate");
  9524.         if (!ProcessTemplate($s_template,$a_lines,$a_values,
  9525.                                     GetAROption('TemplateMissing'),
  9526.                                     'SubstituteValuePlain'))
  9527.             return (false);
  9528.         $s_mail_text = implode(BODY_LF,$a_lines);
  9529.     }
  9530.     if (IsAROptionSet("HTMLTemplate"))
  9531.     {
  9532.         if (!MakeMimeMail($s_mail_text,$a_headers,$a_values,
  9533.                             GetAROption("HTMLTemplate"),
  9534.                             GetAROption('TemplateMissing')))
  9535.             return (false);
  9536.     }
  9537.     return (SendCheckedMail($s_to,$s_subj,$s_mail_text,$s_from_addr,$a_headers));
  9538. }
  9539.  
  9540. /*
  9541.  * The main logic starts here....
  9542.  */
  9543.  
  9544.     //
  9545.     // First, a special case; if formmail.php is called like this:
  9546.     //  http://.../formmail.php?testalert=1
  9547.     // it sends a test message to the default alert address with some
  9548.     // information about your PHP version and the DOCUMENT_ROOT.
  9549.     //
  9550. if (isset($aGetVars["testalert"]) && $aGetVars["testalert"] == 1)
  9551. {
  9552.     function ShowServerVar($s_name)
  9553.     {
  9554.         global  $aServerVars;
  9555.  
  9556.         return (isset($aServerVars[$s_name]) ? $aServerVars[$s_name] : "-not set-");
  9557.     }
  9558.     $sAlert = GetMessage(MSG_ALERT,
  9559.                 array("LANG"=>$sLangID,
  9560.                       "PHPVERS"=>implode(".",$aPHPVERSION),
  9561.                       "FM_VERS"=>$FM_VERS,
  9562.                       "SERVER"=>(IsServerWindows() ? "Windows" : "non-Windows"),
  9563.                       "DOCUMENT_ROOT"=>ShowServerVar('DOCUMENT_ROOT'),
  9564.                       "SCRIPT_FILENAME"=>ShowServerVar('SCRIPT_FILENAME'),
  9565.                       "PATH_TRANSLATED"=>ShowServerVar('PATH_TRANSLATED'),
  9566.                       "REAL_DOCUMENT_ROOT"=>CheckString($REAL_DOCUMENT_ROOT),
  9567.                      ));
  9568.  
  9569.     if (DEF_ALERT == "")
  9570.         echo "<p>".GetMessage(MSG_NO_DEF_ALERT)."</p>";
  9571.     elseif (SendAlert($sAlert,false,true))
  9572.         echo "<p>".GetMessage(MSG_TEST_SENT)."</p>";
  9573.     else
  9574.         echo "<p>".GetMessage(MSG_TEST_FAILED)."</p>";
  9575.     exit;
  9576. }
  9577.  
  9578. if (isset($aGetVars["testlang"]) && $aGetVars["testlang"] == 1)
  9579. {
  9580.     if (!IsPHPAtLeast("4.1.0"))
  9581.     {
  9582.     ?>
  9583.         <p>testlang feature only works with PHP version 4.1.0 or later</p>
  9584.     <?php
  9585.     }
  9586.     else
  9587.     {
  9588.         function ShowMessages()
  9589.         {
  9590.             global  $aMessages,$sLangID,$bShowMesgNumbers,$aGetVars,$sHTMLCharSet;
  9591.  
  9592.                 //
  9593.                 // force message numbers on unless "mnums=no"
  9594.                 //
  9595.             if (isset($aGetVars["mnums"]) && $aGetVars["mnums"] == "no")
  9596.                 $bShowMesgNumbers = false;
  9597.             else
  9598.                 $bShowMesgNumbers = true;
  9599.  
  9600.             LoadBuiltinLanguage();
  9601.  
  9602.             $s_def_lang = $sLangID;
  9603.             $a_def_mesgs = $aMessages;
  9604.  
  9605.             LoadLanguageFile();
  9606.  
  9607.             $s_active_lang = $sLangID;
  9608.             $a_active_mesgs = $aMessages;
  9609.  
  9610.             $a_list = get_defined_constants();
  9611.  
  9612.             echo "<html>\n";
  9613.             echo "<head>\n";
  9614.             if (isset($sHTMLCharSet) && $sHTMLCharSet !== "")
  9615.                 echo "<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=$sHTMLCharSet\">\n";
  9616.             echo "</head>\n";
  9617.             echo "<body>\n";
  9618.  
  9619.             echo "<table border=\"1\" cellpadding=\"10\" width=\"95%\">\n";
  9620.             echo "<tr>\n";
  9621.             echo "<th>\n";
  9622.             echo "Message Number";
  9623.             echo "</th>\n";
  9624.             echo "<th>\n";
  9625.             echo "$s_def_lang";
  9626.             echo "</th>\n";
  9627.             echo "<th>\n";
  9628.             echo "$s_active_lang";
  9629.             echo "</th>\n";
  9630.             echo "</tr>\n";
  9631.             foreach ($a_list as $s_name=>$i_value)
  9632.             {
  9633.                 if (substr($s_name,0,4) == "MSG_")
  9634.                 {
  9635.                         //
  9636.                         // some PHP constants begin with MSG_, so we try to skip them too
  9637.                         //
  9638.                     switch ($s_name)
  9639.                     {
  9640.                     case "MSG_IPC_NOWAIT":
  9641.                     case "MSG_EAGAIN":
  9642.                     case "MSG_ENOMSG":
  9643.                     case "MSG_NOERROR":
  9644.                     case "MSG_EXCEPT":
  9645.                     case "MSG_OOB":
  9646.                     case "MSG_PEEK":
  9647.                     case "MSG_DONTROUTE":
  9648.                     case "MSG_EOR":
  9649.                         continue 2;
  9650.                     }
  9651.                     if ($i_value >= 256)
  9652.                         continue;
  9653.                     echo "<tr>\n";
  9654.                     echo "<td valign=\"top\">\n";
  9655.                     echo "$s_name ($i_value)";
  9656.                     echo "</td>\n";
  9657.                     echo "<td valign=\"top\">\n";
  9658.                     $aMessages = $a_def_mesgs;
  9659.                     $s_def_msg = GetMessage((int) $i_value,array(),true,true);
  9660.                     echo nl2br(htmlentities($s_def_msg));       // English - don't need FixedHTMLEntities
  9661.                     echo "</td>\n";
  9662.                     echo "<td valign=\"top\">\n";
  9663.                     $aMessages = $a_active_mesgs;
  9664.                     $s_act_msg = GetMessage((int) $i_value,array(),true,true);
  9665.                     if ($s_def_msg == $s_act_msg)
  9666.                         echo "<i>identical</i>\n";
  9667.                     else
  9668.                         echo nl2br(FixedHTMLEntities($s_act_msg));
  9669.                     echo "</td>\n";
  9670.                     echo "</tr>\n";
  9671.                 }
  9672.             }
  9673.             echo "</table>\n";
  9674.  
  9675.             echo "</body>\n";
  9676.             echo "</html>\n";
  9677.         }
  9678.         ShowMessages();
  9679.     }
  9680.     exit;
  9681. }
  9682.  
  9683.     //
  9684.     // For saved files, add in the "new_name" values to the given
  9685.     // array.
  9686.     //
  9687. function    GetSavedFileNames($a_values)
  9688. {
  9689.     global  $aSessionVars;
  9690.  
  9691.     if (isset($aSessionVars["FormSavedFiles"]))
  9692.     {
  9693.         foreach ($aSessionVars["FormSavedFiles"] as $s_fld=>$a_upload)
  9694.         {
  9695.             if (isset($a_upload["name"]))
  9696.                 $a_values[$s_fld] = $a_upload["name"];
  9697.             if (isset($a_upload["new_name"]))
  9698.                 $a_values["name_of_$s_fld"] = $a_upload["new_name"];
  9699.         }
  9700.     }
  9701.     return ($a_values);
  9702. }
  9703.  
  9704.     //
  9705.     // Scan the Multi form sequence values and build up the values that
  9706.     // were submitted to the given form index.
  9707.     //
  9708. function GetMultiValues($a_form_list,$i_form_index,$a_order = array(),
  9709.                                             $a_clean = array(),
  9710.                                             $a_raw_data = array(),
  9711.                                             $a_all_data = array(),
  9712.                                             $a_file_data = array())
  9713. {
  9714.     $a_ret_clean = $a_ret_raw = $a_ret_all = $a_ret_files = array();
  9715.     for ($ii = 0 ; $ii < $i_form_index ; $ii++)
  9716.     {
  9717.             //
  9718.             // only add a field to the order if it's not already there
  9719.             //
  9720.         $a_form_order = $a_form_list[$ii]["ORDER"];
  9721.         $n_order = count($a_form_order);
  9722.         for ($jj = 0 ; $jj < $n_order ; $jj++)
  9723.         {
  9724.             if (array_search($a_form_order[$jj],$a_order) === false)
  9725.                 $a_order[] = $a_form_order[$jj];
  9726.         }
  9727.         $a_ret_clean = array_merge($a_ret_clean,$a_form_list[$ii]["CLEAN"]);
  9728.         $a_ret_raw = array_merge($a_ret_raw,$a_form_list[$ii]["RAWDATA"]);
  9729.         $a_ret_all = array_merge($a_ret_all,$a_form_list[$ii]["ALLDATA"]);
  9730.         $a_ret_files = array_merge($a_ret_files,$a_form_list[$ii]["FILES"]);
  9731.     }
  9732.         //
  9733.         // later values must take precedence to earlier values,
  9734.         // so merge in the passed-in data last
  9735.         //
  9736.     $a_ret_clean = array_merge($a_ret_clean,$a_clean);
  9737.     $a_ret_raw = array_merge($a_ret_raw,$a_raw_data);
  9738.     $a_ret_all = array_merge($a_ret_all,$a_all_data);
  9739.     $a_ret_files = array_merge($a_ret_files,$a_file_data);
  9740.     return (array($a_order,$a_ret_clean,$a_ret_raw,$a_ret_all,$a_ret_files));
  9741. }
  9742.  
  9743. $bMultiForm = false;
  9744.  
  9745.     //
  9746.     // Multi-page form sequencing is complicated....
  9747.     // Requirements:
  9748.     //      1. The first page in a multi-page form sequence must provide:
  9749.     //          - multi_start field set to 1
  9750.     //          - this_form field (it's own URL)
  9751.     //          - next_form field (multi-page form template name)
  9752.     //      2. Subsequent pages must provide either:
  9753.     //          next_form (the next template name in the sequence)
  9754.     //         OR
  9755.     //          good_url or good_template or neither; this terminates
  9756.     //          the multi-page processing and provides the final URL.
  9757.     // Logic:
  9758.     //      1. We create session variables to contain information about
  9759.     //         the sequence.
  9760.     //      2. On the first submission from the starting form, we record
  9761.     //         its "this_form" URL and the data submitted.
  9762.     //         We also create a URL (to FormMail) that will allow return
  9763.     //         to the *next* form in the sequence.
  9764.     //      3. On submission from other forms in the sequence, we record
  9765.     //         the data that was submitted so we can return to that
  9766.     //         form with the user's data re-filled into the form.
  9767.     //         We also create a URL (to FormMail) that will allow return
  9768.     //         to the *next* form in the sequence.
  9769.     //      4. A return URL contains "return=index" where index is the
  9770.     //         form sequence index number.  This is a URL to FormMail.
  9771.     //         FormMail gets the template name or URL (URL only for the
  9772.     //         starting form) and outputs the requested HTML form.  It also
  9773.     //         truncates the session data for forms after the returned-to
  9774.     //         one.
  9775.     //
  9776.  
  9777.     //
  9778.     // Return to a previous form in a sequence.
  9779.     //
  9780. function MultiFormReturn($i_return_to)
  9781. {
  9782.     global  $aSessionVars;
  9783.     global  $iFormIndex;
  9784.     global  $SessionAccessor;
  9785.  
  9786.     if (!isset($aSessionVars["FormList"]) ||
  9787.            !isset($aSessionVars["FormIndex"]) ||
  9788.             $i_return_to < 0 ||
  9789.             $i_return_to > $aSessionVars["FormIndex"])
  9790.         Error("cannot_return",GetMessage(MSG_CANNOT_RETURN,
  9791.                                 array("TO"=>$i_return_to,
  9792.                                     "TOPINDEX"=>(
  9793.                                         isset($aSessionVars["FormIndex"]) ?
  9794.                                         $aSessionVars["FormIndex"] :
  9795.                                         "<undefined>"))),
  9796.                                 false,false);
  9797.     assert($i_return_to < count($aSessionVars["FormList"]));
  9798.     $a_form_def = $aSessionVars["FormList"][$i_return_to];
  9799.     $aSessionVars["FormList"] = array_slice($aSessionVars["FormList"],0,$i_return_to+1);
  9800.     $aSessionVars["FormIndex"] = $iFormIndex = $i_return_to;
  9801.     if (isset($a_form_def["FORM"]))
  9802.     {
  9803.             //
  9804.             // get the values that were originally submitted to this form
  9805.             //
  9806.         list(,,$a_values,,) = GetMultiValues($aSessionVars["FormList"],$i_return_to);
  9807.             //
  9808.             // get the session values
  9809.             //
  9810.         $SessionAccessor->CopyIn($a_values,true);
  9811.         $a_lines = array();
  9812.             //
  9813.             // process the page as a template
  9814.             //
  9815.         if (ProcessMultiFormTemplate($a_form_def["FORM"],$a_values,$a_lines))
  9816.         {
  9817.             $n_lines = count($a_lines);
  9818.             $s_buf = "";
  9819.             for ($ii = 0 ; $ii < $n_lines ; $ii++)
  9820.             {
  9821.                 $s_buf .= $a_lines[$ii]."\n";
  9822.                 unset($a_lines[$ii]);       // free memory (hopefully)
  9823.             }
  9824.             unset($a_lines);       // free memory (hopefully)
  9825.                 //
  9826.                 // put in the values that the user previously submitted
  9827.                 // to this form
  9828.                 //
  9829.             echo SetPreviousValues($s_buf,$a_form_def["RAWDATA"]);
  9830.         }
  9831.         else
  9832.             Error("multi_form_failed",GetMessage(MSG_MULTIFORM_FAILED,
  9833.                                     array("NAME"=>$s_template)),false,false);
  9834.     }
  9835.     else
  9836.             //
  9837.             // we probably should include 
  9838.             //  $SessionAccessor->CopyIn(...,true);
  9839.             // at some stage in the future to get the session values....need to think about this
  9840.             // and run some case studies.
  9841.             //
  9842.         ProcessReturnToForm($a_form_def["URL"],$a_form_def["RAWDATA"],array("multi_start"));
  9843.     //echo "Returned to $i_return_to";
  9844. }
  9845.  
  9846.     //
  9847.     // Store any data just submitted and specified as "multi_keep".
  9848.     //
  9849. function MultiKeep()
  9850. {
  9851.     global  $SPECIAL_VALUES,$aSessionVars,$aRawDataValues;
  9852.  
  9853.     if (isset($SPECIAL_VALUES["multi_keep"]) &&
  9854.         !empty($SPECIAL_VALUES["multi_keep"]))
  9855.     {
  9856.         $a_list = TrimArray(explode(",",$SPECIAL_VALUES["multi_keep"]));
  9857.         if (!isset($aSessionVars["FormKeep"]))
  9858.             $aSessionVars["FormKeep"] = array();
  9859.             //
  9860.             // For each data field specified in "multi_keep" store its
  9861.             // value in the FormKeep session variable.
  9862.             // If a field is specified and does not exist in the
  9863.             // recent submission, its value is discarded.
  9864.             //
  9865.         foreach ($a_list as $s_fld_name)
  9866.             if (!empty($s_fld_name))
  9867.                 if (isset($aRawDataValues[$s_fld_name]))
  9868.                     $aSessionVars["FormKeep"][$s_fld_name] = $aRawDataValues[$s_fld_name];
  9869.                 else
  9870.                     unset($aSessionVars["FormKeep"][$s_fld_name]);
  9871.     }
  9872. }
  9873.  
  9874.     //
  9875.     // Perform Logic for Multi-Page form sequences
  9876.     //
  9877. function MultiFormLogic()
  9878. {
  9879.     global  $bMultiForm,$SPECIAL_VALUES,$aSessionVars,$aServerVars,$aFileVars;
  9880.     global  $sFormMailScript,$bGotGoBack,$bGotNextForm,$iFormIndex;
  9881.     global  $aFieldOrder,$aCleanedValues,$aRawDataValues,$aAllRawValues;
  9882.  
  9883.     if ($SPECIAL_VALUES["multi_start"] == 1)
  9884.     {
  9885.         if (empty($SPECIAL_VALUES["this_form"]))
  9886.             ErrorWithIgnore("need_this_form",GetMessage(MSG_NEED_THIS_FORM),false,false);
  9887.  
  9888.         $bMultiForm = true;
  9889.             //
  9890.             // Start of multi-page form sequence
  9891.             //
  9892.         $aSessionVars["FormList"] = array();
  9893.         $aSessionVars["FormList"][0] = array("URL"=>$SPECIAL_VALUES["this_form"],
  9894.                                             "ORDER"=>$aFieldOrder,
  9895.                                             "CLEAN"=>$aCleanedValues,
  9896.                                             "RAWDATA"=>$aRawDataValues,
  9897.                                             "ALLDATA"=>$aAllRawValues,
  9898.                                             "FILES"=>$aFileVars);
  9899.         $iFormIndex = $aSessionVars["FormIndex"] = 0;   // zero is the first form, which was
  9900.                                                         // just submitted
  9901.             //
  9902.             // this is a fresh session, so remove any remembered values
  9903.             //
  9904.         unset($aSessionVars["FormSavedFiles"]);
  9905.         unset($aSessionVars["FormKeep"]);
  9906.     }
  9907.     elseif (isset($aSessionVars["FormList"]))
  9908.         $bMultiForm = true;
  9909.  
  9910.     if ($bMultiForm)
  9911.     {
  9912.         if (isset($aServerVars["PHP_SELF"]) &&
  9913.             !empty($aServerVars["PHP_SELF"]) &&
  9914.             isset($aServerVars["SERVER_NAME"]) &&
  9915.             !empty($aServerVars["SERVER_NAME"]))
  9916.         {
  9917.             if (isset($aServerVars["SERVER_PORT"]) &&
  9918.                 $aServerVars["SERVER_PORT"] != 80)
  9919.             {
  9920.                 if ($aServerVars["SERVER_PORT"] == 443)     // SSL port
  9921.                         //
  9922.                         // just use https prefix
  9923.                         //
  9924.                     $sFormMailScript = "https://".$aServerVars["SERVER_NAME"].
  9925.                                                 $aServerVars["PHP_SELF"];
  9926.                 else
  9927.                         //
  9928.                         // use http with port number
  9929.                         //
  9930.                     $sFormMailScript = "http://".$aServerVars["SERVER_NAME"].
  9931.                                         ":".$aServerVars["SERVER_PORT"].
  9932.                                         $aServerVars["PHP_SELF"];
  9933.             }
  9934.             else
  9935.                 $sFormMailScript = "http://".$aServerVars["SERVER_NAME"].
  9936.                                         $aServerVars["PHP_SELF"];
  9937.             $iFormIndex = $aSessionVars["FormIndex"];
  9938.         }
  9939.         else
  9940.             Error("no_php_self",GetMessage(MSG_NO_PHP_SELF),false,false);
  9941.     }
  9942.  
  9943.         //
  9944.         // If we're going forward in a multi-page form sequence,
  9945.         // compute a URL to return to the form we're about to display.
  9946.         //
  9947.     if ($bMultiForm && !$bGotGoBack)
  9948.     {
  9949.             //
  9950.             // record the data that was just submitted by the previous form
  9951.             //
  9952.         $iFormIndex = $aSessionVars["FormIndex"];
  9953.         $aSessionVars["FormList"][$iFormIndex]["ORDER"] = $aFieldOrder;
  9954.         $aSessionVars["FormList"][$iFormIndex]["CLEAN"] = $aCleanedValues;
  9955.         $aSessionVars["FormList"][$iFormIndex]["RAWDATA"] = $aRawDataValues;
  9956.         $aSessionVars["FormList"][$iFormIndex]["ALLDATA"] = $aAllRawValues;
  9957.         if (count($aFileVars) > 0 && !FILEUPLOADS)
  9958.             SendAlert(GetMessage(MSG_FILE_UPLOAD));
  9959.         elseif (count($aFileVars) > 0 && !SaveAllUploadedFiles($aFileVars))
  9960.             Error("upload_save_failed",GetMessage(MSG_MULTI_UPLOAD),false,false);
  9961.         $aSessionVars["FormList"][$iFormIndex]["FILES"] = $aFileVars;
  9962.         $iFormIndex++;
  9963.         $s_url = GetReturnLink($sFormMailScript,$iFormIndex);
  9964.         $aSessionVars["FormList"][$iFormIndex] = array("URL"=>$s_url,
  9965.                                     "FORM"=>$SPECIAL_VALUES["next_form"],
  9966.                                     "ORDER"=>$aFieldOrder,
  9967.                                     "CLEAN"=>$aCleanedValues,
  9968.                                     "RAWDATA"=>$aRawDataValues,
  9969.                                     "ALLDATA"=>$aAllRawValues,
  9970.                                     "FILES"=>$aFileVars);
  9971.         $aSessionVars["FormIndex"] = $iFormIndex;
  9972.         MultiKeep();
  9973.     }
  9974. }
  9975.  
  9976.     //
  9977.     // Check for the MIME Attack
  9978.     //
  9979. function DetectMimeAttack($a_fields,&$s_attack,&$s_info,&$s_user_info)
  9980. {
  9981.         //
  9982.         // if any of the recipient fields contain "MIME-Version" or
  9983.         // "Content-Type" then this is the MIME attack
  9984.         // Now also checks the subject field.
  9985.         //
  9986.     $a_rec_flds = array("recipients","cc","bcc","replyto","subject");
  9987.     foreach ($a_rec_flds as $s_fld)
  9988.         if (isset($a_fields[$s_fld]))
  9989.         {
  9990.                 //
  9991.                 // some of the fields can be arrays
  9992.                 //
  9993.             if (is_array($a_fields[$s_fld]))
  9994.                 $s_data = implode(",",$a_fields[$s_fld]);
  9995.             else
  9996.                 $s_data = $a_fields[$s_fld];
  9997.             $s_data = strtolower($s_data);
  9998.             if (($i_mime = strpos($s_data,"mime-version")) !== false ||
  9999.                 ($i_cont = strpos($s_data,"content-type")) !== false)
  10000.             {
  10001.                 $s_attack = "MIME";
  10002.                 $s_info = GetMessage(MSG_ATTACK_MIME_INFO,
  10003.                             array("FLD"=>$s_fld,
  10004.                                   "CONTENT"=>($i_mime !== false) ?
  10005.                                                 "mime-version" :
  10006.                                                 "content-type"),false);
  10007.                 return (true);
  10008.             }
  10009.         }
  10010.     return (false);
  10011. }
  10012.  
  10013.     //
  10014.     // Strip common language sequences from the data
  10015.     // that might otherwise look like a junk attack.
  10016.     // We replace them with a space so that the stripping
  10017.     // cannot create more junk accidentally.
  10018.     //
  10019. function    AttackDetectionStripLang($s_data)
  10020. {
  10021.     global  $ATTACK_DETECTION_JUNK_LANG_STRIP;
  10022.  
  10023.     foreach ($ATTACK_DETECTION_JUNK_LANG_STRIP as $s_seq)
  10024.         $s_data = str_replace($s_seq," ",$s_data);
  10025.     return ($s_data);
  10026. }
  10027.  
  10028.     //
  10029.     // Find strings of $n_consec characters from the alphabet of $s_alpha
  10030.     // in $s_data.  Return the count of instances found.
  10031.     //
  10032. function    AttackDetectionFindJunk($s_data,$s_alpha,$n_consec,&$a_matches)
  10033. {
  10034.     $s_pat = "/[".preg_quote($s_alpha,"/")."]{"."$n_consec,$n_consec"."}/";
  10035.     if (($n_count = preg_match_all($s_pat,$s_data,$a_matches)) === false)
  10036.     {
  10037.         $n_count = 0;
  10038.         $a_matches = array();
  10039.     }
  10040.     else
  10041.         $a_matches = $a_matches[0];
  10042.     return ($n_count);
  10043. }
  10044.  
  10045.     //
  10046.     // Check for the Junk Attack
  10047.     //
  10048. function DetectJunkAttack($a_fields,&$s_attack,&$s_info,&$s_user_info)
  10049. {
  10050.         //
  10051.         // If any field contains junk data, trigger detection.
  10052.         //
  10053.     $n_count = 0;
  10054.     $a_matches = array();
  10055.     $a_user_matches = array();
  10056.     foreach ($a_fields as $s_fld=>$m_value)
  10057.     {
  10058.         if (IsSpecialField($s_fld) || IsSpecialMultiField($s_fld))
  10059.                 //
  10060.                 // skip special fields because they don't contain
  10061.                 // normal user input
  10062.                 //
  10063.             continue;
  10064.         if (isset($m_value) && !IsFieldEmpty($m_value))
  10065.         {
  10066.             if (!is_array($m_value))
  10067.                 $m_value = array($m_value);
  10068.             foreach ($m_value as $s_data)
  10069.             {
  10070.                 $s_orig_data = $s_data = strtolower($s_data);
  10071.                     //
  10072.                     // Strip out sequences that might be common to
  10073.                     // the user's language.
  10074.                     // For example, in English, there are a lot of common
  10075.                     // words that can easily be protected from our
  10076.                     // tests. For example, "thousandths" has 5 consecutive consonants
  10077.                     // but is a reasonable word.
  10078.                     // Similarly, "queue" has 4 consecutive vowels.
  10079.                     //
  10080.                 $s_data = AttackDetectionStripLang($s_data);
  10081.                     //
  10082.                     // Look for strings of too many vowels or too many consonants.
  10083.                     // For safety, we must detect more than one instance, because there
  10084.                     // are a lot of normal words that may be caught by this test.
  10085.                     // The number of instances is controlled by configuration.
  10086.                     //
  10087.                 $n_match = AttackDetectionFindJunk($s_data,ATTACK_DETECTION_JUNK_CONSONANTS,
  10088.                                                 ATTACK_DETECTION_JUNK_CONSEC_CONSONANTS,
  10089.                                                 $a_match_cons);
  10090.                 if ($n_match > 0)
  10091.                     $a_user_matches[] = $s_orig_data;
  10092.                 $n_count += $n_match;
  10093.                 $n_match = AttackDetectionFindJunk($s_data,ATTACK_DETECTION_JUNK_VOWELS,
  10094.                                                 ATTACK_DETECTION_JUNK_CONSEC_VOWELS,
  10095.                                                 $a_match_vow);
  10096.                 if ($n_match > 0)
  10097.                     $a_user_matches[] = $s_orig_data;
  10098.                 $n_count += $n_match;
  10099.                 if ($n_count >= ATTACK_DETECTION_JUNK_TRIGGER)
  10100.                 {
  10101.                     $a_matches = array_merge($a_matches,$a_match_cons,$a_match_vow);
  10102.                     $s_user_info = GetMessage(MSG_USER_ATTACK_JUNK,
  10103.                                         array("INPUT"=>implode(", ",$a_user_matches)),false);
  10104.                     $s_attack = "JUNK";
  10105.                     $s_info = GetMessage(MSG_ATTACK_JUNK_INFO,
  10106.                                 array("FLD"=>$s_fld,
  10107.                                       "JUNK"=>implode(" ",$a_matches)),false);
  10108.                     return (true);
  10109.                 }
  10110.             }
  10111.         }
  10112.     }
  10113.     return (false);
  10114. }
  10115.  
  10116.     //
  10117.     // Check for the duplicate data attack
  10118.     //
  10119. function DetectDupAttack($a_fields,&$s_attack,&$s_info,&$s_user_info)
  10120. {
  10121.         //
  10122.         // if any of the configured fields contain duplicate data,
  10123.         // then this lame attack has been detected
  10124.         //
  10125.     global  $ATTACK_DETECTION_DUPS;
  10126.  
  10127.     $a_data_map = array();
  10128.     foreach ($ATTACK_DETECTION_DUPS as $s_fld)
  10129.         if (isset($a_fields[$s_fld]) &&
  10130.             is_scalar($a_fields[$s_fld]) &&    // can only work with string data
  10131.             !empty($a_fields[$s_fld]))
  10132.         {
  10133.             $s_data = (string) $a_fields[$s_fld];
  10134.             if (isset($a_data_map[$s_data]))
  10135.             {
  10136.                     //
  10137.                     // duplicate found!
  10138.                     //
  10139.                 $s_attack = "Duplicate Fields";
  10140.                 $s_info = GetMessage(MSG_ATTACK_DUP_INFO,
  10141.                             array("FLD1"=>$a_data_map[$s_data],
  10142.                                   "FLD2"=>$s_fld),false);
  10143.                 $s_user_info = GetMessage(MSG_USER_ATTACK_DUP,array(),false);
  10144.                 return (true);
  10145.             }
  10146.             $a_data_map[$s_data] = $s_fld;
  10147.         }
  10148.     return (false);
  10149. }
  10150.  
  10151.     //
  10152.     // Check for the email addresses in specials attack
  10153.     //
  10154. function DetectSpecialsAttack($a_fields,&$s_attack,&$s_info,&$s_user_info)
  10155. {
  10156.     global  $ATTACK_DETECTION_SPECIALS_ONLY_EMAIL,
  10157.             $ATTACK_DETECTION_SPECIALS_ANY_EMAIL;
  10158.  
  10159.         //
  10160.         // look for email addresses in whole fields
  10161.         //
  10162.     foreach ($ATTACK_DETECTION_SPECIALS_ONLY_EMAIL as $s_fld)
  10163.     {
  10164.         if (isset($a_fields[$s_fld]) &&
  10165.             is_scalar($a_fields[$s_fld]) &&    // can only work with string data
  10166.             !empty($a_fields[$s_fld]))
  10167.         {
  10168.             $s_data = $a_fields[$s_fld];
  10169.             if (preg_match("/^\b[-a-z0-9._%]+@[-.%_a-z0-9]+\.[a-z]{2,9}\b$/i",
  10170.                             $s_data) === 1)
  10171.             {
  10172.                     //
  10173.                     // email address found in wrong field
  10174.                     //
  10175.                 $s_attack = "Special Fields Only";
  10176.                 $s_info = GetMessage(MSG_ATTACK_SPEC_INFO,
  10177.                             array("FLD"=>$s_fld),false);
  10178.                 return (true);
  10179.             }
  10180.         }
  10181.     }
  10182.         //
  10183.         // look for email addresses in any part of fields
  10184.         //
  10185.     foreach ($ATTACK_DETECTION_SPECIALS_ANY_EMAIL as $s_fld)
  10186.     {
  10187.         if (isset($a_fields[$s_fld]) &&
  10188.             is_scalar($a_fields[$s_fld]) &&    // can only work with string data
  10189.             !empty($a_fields[$s_fld]))
  10190.         {
  10191.             $s_data = $a_fields[$s_fld];
  10192.             if (preg_match("/\b[-a-z0-9._%]+@[-.%_a-z0-9]+\.[a-z]{2,9}\b/i",
  10193.                             $s_data) > 0)
  10194.             {
  10195.                     //
  10196.                     // email address found in wrong field
  10197.                     //
  10198.                 $s_attack = "Special Fields Any";
  10199.                 $s_info = GetMessage(MSG_ATTACK_SPEC_INFO,
  10200.                             array("FLD"=>$s_fld),false);
  10201.                 return (true);
  10202.             }
  10203.         }
  10204.     }
  10205.     return (false);
  10206. }
  10207.  
  10208.     //
  10209.     // Check for "many URLs in a field" and "many fields with URLs" attacks
  10210.     //
  10211. function DetectManyURLsAttack($a_fields,&$s_attack,&$s_info,&$s_user_info)
  10212. {
  10213.     global      $ATTACK_DETECTION_URL_PATTERNS;
  10214.  
  10215.     $a_fld_names = array();
  10216.         //
  10217.         // actual URL link patterns
  10218.         //
  10219.     $s_srch = '((\bhttps{0,1}:\/\/|<\s*a\s+href=["'."'".']{0,1})[-a-z0-9.]+\b)';
  10220.  
  10221.         //
  10222.         // now add configurable patterns
  10223.         //
  10224.     if (!empty($ATTACK_DETECTION_URL_PATTERNS) &&
  10225.         is_array($ATTACK_DETECTION_URL_PATTERNS))
  10226.     {
  10227.             //
  10228.             // escape / characters and build up a string
  10229.             // of alternate patterns
  10230.             //
  10231.         foreach ($ATTACK_DETECTION_URL_PATTERNS as $s_pat)
  10232.         {
  10233.             if ($s_pat == "")
  10234.                 continue;
  10235.             $s_srch .= "|".str_replace('/','\/',$s_pat);
  10236.         }
  10237.     }
  10238.  
  10239.     foreach ($a_fields as $s_fld=>$s_data)
  10240.     {
  10241.         if (IsSpecialField($s_fld) || IsSpecialMultiField($s_fld))
  10242.                 //
  10243.                 // skip special fields because some are supposed to
  10244.                 // have URLs in them
  10245.                 //
  10246.             continue;
  10247.         if (isset($s_data) &&
  10248.             is_scalar($s_data) &&    // can only work with string data
  10249.             !empty($s_data))
  10250.         {
  10251.             $n_match = preg_match_all("/$s_srch/msi",$s_data,$a_matches);
  10252.             if (!is_int($n_match))
  10253.                 $n_match = 0;
  10254.             /*
  10255.              * debugging code....
  10256.              if ($n_match > 0)
  10257.                 echo "Pattern is '".htmlentities($s_srch)."' with '".
  10258.                     htmlentities($s_data)."' field '$s_fld', matched=$n_match<br />";
  10259.              */
  10260.             if (ATTACK_DETECTION_MANY_URLS > 0)
  10261.                 if ($n_match >= ATTACK_DETECTION_MANY_URLS)
  10262.                 {
  10263.                     $s_attack = "Many URLS in a field";
  10264.                     $s_info = GetMessage(MSG_ATTACK_MANYURL_INFO,
  10265.                                 array("FLD"=>$s_fld,"NUM"=>($n_match)),false);
  10266.                     $s_user_info = GetMessage(MSG_USER_ATTACK_MANY_URLS,array(),false);
  10267.                     return (true);
  10268.                 }
  10269.             if ($n_match > 0)
  10270.                 $a_fld_names[] = $s_fld;
  10271.         }
  10272.     }
  10273.     if (ATTACK_DETECTION_MANY_URL_FIELDS > 0)
  10274.         if (count($a_fld_names) >= ATTACK_DETECTION_MANY_URL_FIELDS)
  10275.         {
  10276.             $s_attack = "Many fields with URLs";
  10277.             $s_info = GetMessage(MSG_ATTACK_MANYFIELDS_INFO,
  10278.                         array("FLDS"=>implode(",",$a_fld_names),
  10279.                                 "NUM"=>(count($a_fld_names))),false);
  10280.             $s_user_info = GetMessage(MSG_USER_ATTACK_MANY_URL_FIELDS,array(),false);
  10281.             return (true);
  10282.         }
  10283.     return (false);
  10284. }
  10285.  
  10286.     //
  10287.     // Detect annoying attacks and prevent them from sending spurious
  10288.     // alert messages.
  10289.     //
  10290. function DetectAttacks($a_fields)
  10291. {
  10292.     global      $ATTACK_DETECTION_DUPS,$ATTACK_DETECTION_REVERSE_CAPTCHA;
  10293.  
  10294.     $s_info = $s_attack = "";
  10295.     $b_attacked = false;
  10296.     $s_user_info = "";
  10297.     if (ATTACK_DETECTION_MIME)
  10298.         if (DetectMimeAttack($a_fields,$s_attack,$s_info,$s_user_info))
  10299.             $b_attacked = true;
  10300.     if (!$b_attacked && !empty($ATTACK_DETECTION_DUPS))
  10301.         if (DetectDupAttack($a_fields,$s_attack,$s_info,$s_user_info))
  10302.             $b_attacked = true;
  10303.     if (!$b_attacked && ATTACK_DETECTION_SPECIALS)
  10304.         if (DetectSpecialsAttack($a_fields,$s_attack,$s_info,$s_user_info))
  10305.             $b_attacked = true;
  10306.     if (!$b_attacked && (ATTACK_DETECTION_MANY_URLS ||
  10307.                         ATTACK_DETECTION_MANY_URL_FIELDS))
  10308.         if (DetectManyURLsAttack($a_fields,$s_attack,$s_info,$s_user_info))
  10309.             $b_attacked = true;
  10310.     if (ATTACK_DETECTION_JUNK)
  10311.         if (DetectJunkAttack($a_fields,$s_attack,$s_info,$s_user_info))
  10312.             $b_attacked = true;
  10313.  
  10314.     if (!$b_attacked && !empty($ATTACK_DETECTION_REVERSE_CAPTCHA))
  10315.             if (DetectRevCaptchaAttack($ATTACK_DETECTION_REVERSE_CAPTCHA,$a_fields,$s_attack,$s_info,$s_user_info))
  10316.                 $b_attacked = true;
  10317.  
  10318.     if ($b_attacked)
  10319.     {
  10320.         if (ALERT_ON_ATTACK_DETECTION)
  10321.             SendAlert(GetMessage(MSG_ATTACK_DETECTED,
  10322.                     array("ATTACK"=>$s_attack,
  10323.                           "INFO"=>$s_info,)),
  10324.                         false);
  10325.         if (ATTACK_DETECTION_URL !== "")
  10326.             Redirect(ATTACK_DETECTION_URL);
  10327.         else
  10328.         {
  10329.             global  $SERVER;
  10330.  
  10331.             CreatePage(GetMessage(MSG_ATTACK_PAGE,array("SERVER"=>$SERVER,"USERINFO"=>$s_user_info)));
  10332.         }
  10333.         exit;
  10334.     }
  10335. }
  10336.  
  10337.     //
  10338.     // Implement reverse captcha.  At least two fields must be provided.
  10339.     // At least one of the fields should have a non-empty value.
  10340.     //
  10341. function    DetectRevCaptchaAttack($a_revcap_spec,$a_form_data,&$s_attack,&$s_info,&$s_user_info)
  10342. {
  10343.     if (count($a_revcap_spec) < 2)
  10344.     {
  10345.         SendAlert(GetMessage(MSG_REV_CAP));
  10346.         return (false);
  10347.     }
  10348.         //
  10349.         // check the reverse captcha fields
  10350.         //
  10351.     $n_empty = $n_non_empty = 0;
  10352.     $b_attacked = false;
  10353.     $s_info = "";
  10354.     foreach ($a_revcap_spec as $s_fld_name=>$s_value)
  10355.     {
  10356.         if ($s_value === "")
  10357.         {
  10358.             $n_empty++;
  10359.             if (isset($a_form_data[$s_fld_name]) &&
  10360.                     $a_form_data[$s_fld_name] !== "")
  10361.             {
  10362.                 $b_attacked = true;
  10363.                 $s_info .= "\n".GetMessage(MSG_ATTACK_REV_CAP_INFO,
  10364.                             array("FLD"=>$s_fld_name,
  10365.                                     "CONTENT"=>$a_form_data[$s_fld_name]),false);
  10366.             }
  10367.         }
  10368.         else
  10369.         {
  10370.             $n_non_empty++;
  10371.             if (!isset($a_form_data[$s_fld_name]) ||
  10372.                     $a_form_data[$s_fld_name] !== $s_value)
  10373.             {
  10374.                 $b_attacked = true;
  10375.                 $s_info .= "\n".GetMessage(MSG_ATTACK_REV_CAP_INFO,
  10376.                             array("FLD"=>$s_fld_name,
  10377.                                     "CONTENT"=>
  10378.                                         isset($a_form_data[$s_fld_name]) ?
  10379.                                             $a_form_data[$s_fld_name] :
  10380.                                             ""),false);
  10381.             }
  10382.         }
  10383.     }
  10384.         //
  10385.         // check that the rev captcha specification is correct:
  10386.         //      at least two fields, at least one empty
  10387.         //      and at least one non-empty
  10388.         //
  10389.     if ($n_empty + $n_non_empty < 2 ||
  10390.         $n_empty == 0 || $n_non_empty == 0)
  10391.     {
  10392.         SendAlert(GetMessage(MSG_REV_CAP));
  10393.         return (false);
  10394.     }
  10395.     if ($b_attacked)
  10396.     {
  10397.         $s_attack = "Reverse Captcha";
  10398.         $s_user_info = GetMessage(MSG_USER_ATTACK_REV_CAP,array(),false);
  10399.     }
  10400.     return ($b_attacked);
  10401. }
  10402.  
  10403. /* 
  10404.  * Class:       SessionAccess
  10405.  * Description:     
  10406.  *  Implements access to the general PHP session.
  10407.  *  This provides a secure way of copy data to and from the
  10408.  *  user's PHP session.
  10409.  */
  10410. class   SessionAccess
  10411. {
  10412.     var     $_aAccessList;
  10413.  
  10414.     /*
  10415.      * Method:      SessionAccess ctor
  10416.      * Parameters:  $a_access_list      list of variables that can be accessed
  10417.      * Returns:     n/a
  10418.      * Description: 
  10419.      *  Constructs the object.
  10420.      */
  10421.     function    SessionAccess($a_access_list)
  10422.     {
  10423.         $this->_aAccessList = $a_access_list;
  10424.     }
  10425.  
  10426.     /*
  10427.      * Method:      SessionAccess::CopyIn
  10428.      * Parameters:  $a_vars     reference to an array of values (keyed on name)
  10429.      *              $b_overwrite_empty  if true, the session value will overwrite
  10430.      *                          an empty array variable
  10431.      * Returns:     int         number of values copied
  10432.      * Description: 
  10433.      *  Copies in the list of variables from the session to the given array.
  10434.      */
  10435.     function    CopyIn(&$a_vars,$b_overwrite_empty)
  10436.     {
  10437.         global      $aSessionVars;
  10438.  
  10439.         //$s_db = "Session CopyIn:\n";
  10440.         $n_copied = 0;
  10441.         foreach ($this->_aAccessList as $s_var_name)
  10442.             if (isset($aSessionVars[$s_var_name]))
  10443.                 if (!isset($a_vars[$s_var_name]) ||
  10444.                         ($b_overwrite_empty &&
  10445.                         IsFieldEmpty($a_vars[$s_var_name])))
  10446.                 {
  10447.                     $a_vars[$s_var_name] = $aSessionVars[$s_var_name];
  10448.                     //$s_db .= "$s_var_name='".$a_vars[$s_var_name]."'\n";
  10449.                     $n_copied++;
  10450.                 };
  10451.         //SendAlert($s_db);
  10452.         return ($n_copied);
  10453.     }
  10454.  
  10455.     /*
  10456.      * Method:      SessionAccess::CopyOut
  10457.      * Parameters:  $a_vars     reference to an array of values (keyed on name)
  10458.      *              $a_fields   an array of fields to copy
  10459.      * Returns:     int         number of values copied
  10460.      * Description: 
  10461.      *  Copies the variables from the given array into the session.
  10462.      *  The list of fields to copy is specified in _aAccessList.
  10463.      *  If $a_fields is provided, it contains a list of fields to copy, which
  10464.      *  limits the fields selected from _aAccessList, otherwise all fields
  10465.      *  listed in _aAccessList are copied.
  10466.      */
  10467.     function    CopyOut(&$a_vars,$a_fields = array())
  10468.     {
  10469.         global      $aSessionVars;
  10470.  
  10471.         //$s_db = "Session CopyOut:\n";
  10472.  
  10473.         $n_copied = 0;
  10474.         foreach ($this->_aAccessList as $s_var_name)
  10475.             if (isset($a_vars[$s_var_name]))
  10476.                 if (empty($a_fields) || in_array($s_var_name,$a_fields))
  10477.                 {
  10478.                     $aSessionVars[$s_var_name] = $a_vars[$s_var_name];
  10479.                     //$s_db .= "$s_var_name='".$aSessionVars[$s_var_name]."'\n";
  10480.                     $n_copied++;
  10481.                 };
  10482.         //SendAlert($s_db);
  10483.         return ($n_copied);
  10484.     }
  10485. };
  10486.  
  10487. $SessionAccessor = new SessionAccess($SESSION_ACCESS);
  10488.  
  10489. $bAdvTemplates = false;
  10490. if (ADVANCED_TEMPLATES &&
  10491.         (!empty($TEMPLATEDIR) || !empty($TEMPLATEURL) ||
  10492.         !empty($MULTIFORMDIR) || !empty($MULTIFORMURL)))
  10493.     $bAdvTemplates = true;
  10494.  
  10495. if (isset($aGetVars["return"]) && is_numeric($aGetVars["return"]))
  10496. {
  10497.         //
  10498.         // if advanced templates are in use, we will need them for
  10499.         // performing a multi-page form return
  10500.         //
  10501.     if ($bAdvTemplates)
  10502.     {
  10503.         $FMCTEMPLATE_PROC = true;
  10504.         if (!include_once("$MODULEDIR/$FMCOMPUTE"))
  10505.             Error("load_fmcompute",GetMessage(MSG_LOAD_FMCOMPUTE,
  10506.                             array("FILE"=>"$MODULEDIR/$FMCOMPUTE",
  10507.                                     "ERROR"=>$php_errormsg)),false,false);
  10508.     }
  10509.     MultiFormReturn($aGetVars["return"]);
  10510.     exit;
  10511. }
  10512.  
  10513.     //
  10514.     // Hook system: after initialization
  10515.     //
  10516. if ($HOOK_DIR !== "")
  10517.     if (!@include("$HOOK_DIR/fmhookpostinit.inc.php"))
  10518.         @include("$HOOK_DIR/fmhookpostinit.inc");
  10519.  
  10520.     //
  10521.     // check configuration values for potential security problems
  10522.     //
  10523. CheckConfig();
  10524.  
  10525.     //
  10526.     // otherwise, do the real processing of FormMail
  10527.     //
  10528. $aStrippedFormVars = $aAllRawValues = StripGPCArray($aFormVars);
  10529.  
  10530. if (ENABLE_ATTACK_DETECTION)
  10531.     DetectAttacks($aAllRawValues);
  10532.  
  10533.     //
  10534.     // Copy in configured session variables, overwriting any
  10535.     // fields that are empty.
  10536.     //
  10537. $SessionAccessor->CopyIn($aAllRawValues,true);
  10538. $SessionAccessor->CopyIn($aStrippedFormVars,true);
  10539.  
  10540.     //
  10541.     // process the options
  10542.     //
  10543. ProcessMailOptions($aAllRawValues);
  10544. ProcessCRMOptions($aAllRawValues);
  10545. ProcessAROptions($aAllRawValues);
  10546. ProcessFilterOptions($aAllRawValues);
  10547.  
  10548.     //
  10549.     // create any derived fields
  10550.     // NOTE: it's important that derivation occurs before cleaned values
  10551.     // are created.  If derivation occurred after cleaning or it created
  10552.     // fields that were assumed to be clean, then an attacked could create
  10553.     // forged email headers using derive_fields.  The code is safe with
  10554.     // the logic sequence below.
  10555.     //
  10556. $aAllRawValues = CreateDerived($aAllRawValues);
  10557.  
  10558. list($aFieldOrder,$aCleanedValues,$aRawDataValues) = ParseInput($aAllRawValues);
  10559.  
  10560.     //
  10561.     // if we're processing multi-forms, then merge in the raw data from previous
  10562.     // forms unless this is the first page of the form sequence
  10563.     //
  10564. if (isset($aSessionVars["FormList"]) && $SPECIAL_VALUES["multi_start"] != 1)
  10565. {
  10566.     list($aFieldOrder,$aCleanedValues,
  10567.             $aRawDataValues,$aAllRawValues,$aFileVars) = GetMultiValues(
  10568.                             $aSessionVars["FormList"],
  10569.                             $aSessionVars["FormIndex"],
  10570.                             $aFieldOrder,$aCleanedValues,
  10571.                             $aRawDataValues,$aAllRawValues,
  10572.                             $aFileVars);
  10573. }
  10574.  
  10575. if ($SPECIAL_VALUES["file_names"] !== "")
  10576.     list($aFieldOrder,$aCleanedValues,$aRawDataValues,$aAllRawValues,$aFileVars) =
  10577.             SetFileNames($SPECIAL_VALUES["file_names"],$aFieldOrder,
  10578.                     $aCleanedValues,$aRawDataValues,$aAllRawValues,$aFileVars);
  10579.  
  10580.     //
  10581.     // Hook system: after loading and processing data
  10582.     //
  10583. if ($HOOK_DIR !== "")
  10584.     if (!@include("$HOOK_DIR/fmhookload.inc.php"))
  10585.         @include("$HOOK_DIR/fmhookload.inc");
  10586.  
  10587. if ($FORM_INI_FILE !== "")
  10588. {
  10589.     ProcessFormIniFile($FORM_INI_FILE);
  10590.         //
  10591.         // Hook system: after processing INI file
  10592.         //
  10593.     if ($HOOK_DIR !== "")
  10594.         if (!@include("$HOOK_DIR/fmhookinifile.inc.php"))
  10595.             @include("$HOOK_DIR/fmhookinifile.inc");
  10596. }
  10597.  
  10598. $bDoneSomething = false;
  10599. if (DB_SEE_INPUT)
  10600. {
  10601.     /***
  10602.     echo "<pre>";
  10603.     print_r($aFormVars);
  10604.     print_r($aServerVars);
  10605.     echo "</pre>";
  10606.     exit;
  10607.     ****/
  10608.     CreatePage(implode("\n",$FORMATTED_INPUT));
  10609.     ZapSession();
  10610.     exit;
  10611. }
  10612.  
  10613. if (!empty($SPECIAL_VALUES["fmcompute"]) || $bAdvTemplates)
  10614. {
  10615.     $FM_UserErrors = array();
  10616.         //
  10617.         // Generalized interface between FMCompute and FormMail functions
  10618.         //
  10619.     function FM_CallFunction($s_func,$a_params,&$m_return,
  10620.                                 &$s_mesg,&$a_debug,&$a_alerts)
  10621.     {
  10622.         switch ($s_func)
  10623.         {
  10624.         case "FMFatalError":
  10625.             SendComputeAlerts();
  10626.             if (count($a_params) < 3)
  10627.                 Error("fmcompute_call",GetMessage(MSG_CALL_PARAM_COUNT,
  10628.                                         array("FUNC"=>$s_func,
  10629.                                             "COUNT"=>count($a_params))),
  10630.                                         false,false);
  10631.             else
  10632.                 Error("fmcompute_error",$a_params[0],$a_params[1],$a_params[2]);
  10633.             break;
  10634.  
  10635.         case "FMFatalUserError":
  10636.             SendComputeAlerts();
  10637.             if (count($a_params) < 1)
  10638.                 Error("fmcompute_call",GetMessage(MSG_CALL_PARAM_COUNT,
  10639.                                         array("FUNC"=>$s_func,
  10640.                                             "COUNT"=>count($a_params))),
  10641.                                         false,false);
  10642.             else
  10643.                 UserError("fmcompute_usererror",$a_params[0]);
  10644.             break;
  10645.  
  10646.         case "FMUserError":
  10647.             if (count($a_params) < 1)
  10648.             {
  10649.                 SendComputeAlerts();
  10650.                 Error("fmcompute_call",GetMessage(MSG_CALL_PARAM_COUNT,
  10651.                                         array("FUNC"=>$s_func,
  10652.                                             "COUNT"=>count($a_params))),
  10653.                                         false,false);
  10654.             }
  10655.             else
  10656.             {
  10657.                 global  $FM_UserErrors;
  10658.  
  10659.                 $FM_UserErrors[] = $a_params[0];
  10660.             }
  10661.             break;
  10662.  
  10663.         case "FMSaveAllFilesToRepository":
  10664.             if (count($a_params) != 0)
  10665.             {
  10666.                 SendComputeAlerts();
  10667.                 Error("fmcompute_call",GetMessage(MSG_CALL_PARAM_COUNT,
  10668.                                         array("FUNC"=>$s_func,
  10669.                                             "COUNT"=>count($a_params))),
  10670.                                         false,false);
  10671.             }
  10672.             else
  10673.                 $m_return = SaveAllFilesToRepository();
  10674.             break;
  10675.  
  10676.         case "FMDeleteFileFromRepository":
  10677.             if (count($a_params) != 1)
  10678.             {
  10679.                 SendComputeAlerts();
  10680.                 Error("fmcompute_call",GetMessage(MSG_CALL_PARAM_COUNT,
  10681.                                         array("FUNC"=>$s_func,
  10682.                                             "COUNT"=>count($a_params))),
  10683.                                         false,false);
  10684.             }
  10685.             else
  10686.                 $m_return = DeleteFileFromRepository($a_params[0]);
  10687.             break;
  10688.  
  10689.         case "FMNextNum":
  10690.             if (count($a_params) != 2)
  10691.             {
  10692.                 SendComputeAlerts();
  10693.                 Error("fmcompute_call",GetMessage(MSG_CALL_PARAM_COUNT,
  10694.                                         array("FUNC"=>$s_func,
  10695.                                             "COUNT"=>count($a_params))),
  10696.                                         false,false);
  10697.             }
  10698.             else
  10699.             {
  10700.                 $i_pad = $a_params[0];
  10701.                 $i_base = $a_params[1];
  10702.                 if ($i_base < 2 || $i_base > 36)
  10703.                     Error("fmcompute_call",GetMessage(MSG_CALL_INVALID_PARAM,
  10704.                                             array("FUNC"=>$s_func,
  10705.                                                 "PARAM"=>2,
  10706.                                                 "CORRECT"=>2...36)),
  10707.                                             false,false);
  10708.                 $m_return = GetNextNum($i_pad,$i_base);
  10709.             }
  10710.             break;
  10711.  
  10712.         default:
  10713.             $s_mesg = GetMessage(MSG_CALL_UNK_FUNC,array("FUNC"=>$s_func));
  10714.             return (false);
  10715.         }
  10716.         return (true);
  10717.     }
  10718.  
  10719.         //
  10720.         // register useful FormMail functions with FMCompute module
  10721.         //
  10722.     function RegisterFormMailFunctions(&$fmc)
  10723.     {
  10724.             //
  10725.             // Allows the user to call "Error" from within a computation
  10726.             //
  10727.         if (($s_msg = $fmc->RegisterExternalFunction("PHP","void",
  10728.                             "FMFatalError",
  10729.                             array("string","bool","bool"),
  10730.                             "FM_CallFunction")) !== true)
  10731.             Error("fmcompute_reg",GetMessage(MSG_REG_FMCOMPUTE,
  10732.                                     array("FUNC"=>"FMFatalError",
  10733.                                           "ERROR"=>$s_msg)),false,false);
  10734.             //
  10735.             // Allows the user to call "UserError" from within a computation
  10736.             //
  10737.         if (($s_msg = $fmc->RegisterExternalFunction("PHP","void",
  10738.                             "FMFatalUserError",
  10739.                             array("string"),
  10740.                             "FM_CallFunction")) !== true)
  10741.             Error("fmcompute_reg",GetMessage(MSG_REG_FMCOMPUTE,
  10742.                                     array("FUNC"=>"FMFatalUserError",
  10743.                                           "ERROR"=>$s_msg)),false,false);
  10744.  
  10745.             //
  10746.             // Allows the user to record an error to be displayed
  10747.             // from within a computation.
  10748.             //
  10749.         if (($s_msg = $fmc->RegisterExternalFunction("PHP","void",
  10750.                             "FMUserError",
  10751.                             array("string"),
  10752.                             "FM_CallFunction")) !== true)
  10753.             Error("fmcompute_reg",GetMessage(MSG_REG_FMCOMPUTE,
  10754.                                     array("FUNC"=>"FMUserError",
  10755.                                           "ERROR"=>$s_msg)),false,false);
  10756.  
  10757.             //
  10758.             // Saves files to the repository.
  10759.             //
  10760.         if (($s_msg = $fmc->RegisterExternalFunction("PHP","bool",
  10761.                             "FMSaveAllFilesToRepository",
  10762.                             array(),
  10763.                             "FM_CallFunction")) !== true)
  10764.             Error("fmcompute_reg",GetMessage(MSG_REG_FMCOMPUTE,
  10765.                                     array("FUNC"=>"FMSaveAllFilesToRepository",
  10766.                                           "ERROR"=>$s_msg)),false,false);
  10767.  
  10768.             //
  10769.             // Delete a file from the repository.
  10770.             //
  10771.         if (($s_msg = $fmc->RegisterExternalFunction("PHP","bool",
  10772.                             "FMDeleteFileFromRepository",
  10773.                             array("string"),
  10774.                             "FM_CallFunction")) !== true)
  10775.             Error("fmcompute_reg",GetMessage(MSG_REG_FMCOMPUTE,
  10776.                                     array("FUNC"=>"FMDeleteFileFromRepository",
  10777.                                           "ERROR"=>$s_msg)),false,false);
  10778.  
  10779.             //
  10780.             // Generate a Next Number
  10781.             //
  10782.         if (($s_msg = $fmc->RegisterExternalFunction("PHP","string",
  10783.                             "FMNextNum",
  10784.                             array("int","int"),
  10785.                             "FM_CallFunction")) !== true)
  10786.             Error("fmcompute_reg",GetMessage(MSG_REG_FMCOMPUTE,
  10787.                                     array("FUNC"=>"FMNextNum",
  10788.                                           "ERROR"=>$s_msg)),false,false);
  10789.  
  10790.     }
  10791.  
  10792.         //
  10793.         // load the fmcompute module
  10794.         //
  10795.     if (!empty($SPECIAL_VALUES["fmcompute"]))
  10796.     {
  10797.         $FMCOMPUTE_CLASS = true;
  10798.         $FMCOMPUTE_NODEBUG = true;
  10799.     }
  10800.     if ($bAdvTemplates)
  10801.         $FMCTEMPLATE_PROC = true;
  10802.     if (!include_once("$MODULEDIR/$FMCOMPUTE"))
  10803.         Error("load_fmcompute",GetMessage(MSG_LOAD_FMCOMPUTE,
  10804.                         array("FILE"=>"$MODULEDIR/$FMCOMPUTE",
  10805.                                 "ERROR"=>$php_errormsg)),false,false);
  10806.     if (!empty($SPECIAL_VALUES["fmcompute"]))
  10807.     {
  10808.         RegisterFormMailFunctions($FMCalc);
  10809.  
  10810.             //
  10811.             // if GeoIP support is specified, load that module now
  10812.             //
  10813.         if (!empty($GEOIP_LIC))
  10814.         {
  10815.             $FMMODULE_LOAD = true;      // signal module load
  10816.             if (!include_once("$MODULEDIR/$FMGEOIP"))
  10817.                 Error("load_module",GetMessage(MSG_LOAD_MODULE,
  10818.                                 array("FILE"=>"$MODULEDIR/$FMGEOIP",
  10819.                                         "ERROR"=>$php_errormsg)),false,false);
  10820.                 //
  10821.                 // load the license and register the module
  10822.                 //
  10823.             $GeoIP = new FMGeoIP($GEOIP_LIC);
  10824.             if (!$GeoIP->RegisterModule($FMCalc))
  10825.                 Error("reg_module",GetMessage(MSG_REGISTER_MODULE,
  10826.                                 array("NAME"=>"FMGeoIP",
  10827.                                        "ERROR"=>$GeoIP->GetError())),false,false);
  10828.         }
  10829.     }
  10830. }
  10831.  
  10832. if (isset($SPECIAL_VALUES["multi_go_back"]) && !empty($SPECIAL_VALUES["multi_go_back"]))
  10833. {
  10834.     if (!isset($aSessionVars["FormList"]) || $aSessionVars["FormIndex"] == 0)
  10835.         ErrorWithIgnore("go_back",GetMessage(MSG_GO_BACK),false,false);
  10836.     MultiKeep();        // store any "multi_keep" data just submitted
  10837.         //
  10838.         // save back to the session any variables that have been specified in
  10839.         // multi_keep
  10840.         //
  10841.     if (isset($SPECIAL_VALUES["multi_keep"]) && !empty($SPECIAL_VALUES["multi_keep"]))
  10842.         $SessionAccessor->CopyOut($aAllRawValues,$SPECIAL_VALUES["multi_keep"]);
  10843.     MultiFormReturn($aSessionVars["FormIndex"]-1);
  10844. //    echo "Form index = ".$aSessionVars["FormIndex"];
  10845.     exit;
  10846. }
  10847.  
  10848.     //
  10849.     // This is the check for spiders; I can't imagine a spider will
  10850.     // ever use the POST method.
  10851.     //
  10852. if ($bIsGetMethod && count($aFormVars) == 0)
  10853. {
  10854.     CreatePage(GetMessage(MSG_NO_DATA_PAGE));
  10855.     ZapSession();
  10856.     exit;
  10857. }
  10858.  
  10859.     //
  10860.     // Hook system: before performing required and conditions etc.
  10861.     //
  10862. if ($HOOK_DIR !== "")
  10863.     if (!@include("$HOOK_DIR/fmhookprechecks.inc.php"))
  10864.         @include("$HOOK_DIR/fmhookprechecks.inc");
  10865.  
  10866.     //
  10867.     // check for required fields
  10868.     //
  10869. if (!CheckRequired($SPECIAL_VALUES["required"],$aAllRawValues,$sMissing,$aMissingList))
  10870.     UserError("missing_fields",GetMessage(MSG_REQD_ERROR),$sMissing,$aMissingList);
  10871.  
  10872.     //
  10873.     // check complex conditions
  10874.     //
  10875. if (!CheckConditions($SPECIAL_VALUES["conditions"],$aAllRawValues,$sMissing,$aMissingList))
  10876.     UserError("failed_conditions",GetMessage(MSG_COND_ERROR),$sMissing,$aMissingList);
  10877.  
  10878.     //
  10879.     // check imgverify
  10880.     //
  10881. if (isset($SPECIAL_VALUES["imgverify"]) && $SPECIAL_VALUES["imgverify"] !== "")
  10882. {
  10883.         //
  10884.         // VerifyImgString is from Tectite's simple verifyimg.php CAPTCHA
  10885.         // turing_string is from Captcha Creator
  10886.         //
  10887.     if (!isset($aSessionVars["VerifyImgString"]) &&
  10888.         !isset($aSessionVars["turing_string"]))
  10889.         ErrorWithIgnore("verify_failed",GetMessage(MSG_VERIFY_MISSING),false);
  10890.         //
  10891.         // the user's entry must match the value in the session; allow
  10892.         // spaces in the user's input
  10893.         //
  10894.     if (isset($aSessionVars["VerifyImgString"]))
  10895.     {
  10896.         if (strtoupper(str_replace(" ","",$SPECIAL_VALUES["imgverify"])) !==
  10897.                     strtoupper($aSessionVars["VerifyImgString"]))
  10898.             UserError("img_verify",GetMessage(MSG_VERIFY_MATCH));
  10899.     }
  10900.     else
  10901.     {
  10902.         if (strtoupper(str_replace(" ","",$SPECIAL_VALUES["imgverify"])) !==
  10903.                     strtoupper($aSessionVars["turing_string"]))
  10904.             UserError("img_verify",GetMessage(MSG_VERIFY_MATCH)/*,
  10905.                         "imgverify='".$SPECIAL_VALUES["imgverify"]."' ".
  10906.                         "turing_string='".$aSessionVars["turing_string"]."'"*/);
  10907.     }
  10908. }
  10909.  
  10910.     //
  10911.     // Hook system: after performing required and conditions etc.
  10912.     //
  10913. if ($HOOK_DIR !== "")
  10914.     if (!@include("$HOOK_DIR/fmhookchecks.inc.php"))
  10915.         @include("$HOOK_DIR/fmhookchecks.inc");
  10916.  
  10917. if (!empty($SPECIAL_VALUES["fmmodules"]))
  10918. {
  10919.     $aModuleList = TrimArray(explode(",",$SPECIAL_VALUES["fmmodules"]));
  10920.     $FMMODULE_LOAD = true;      // signal module load
  10921.     foreach ($aModuleList as $sModule)
  10922.         if (!include_once("$MODULEDIR/$sModule"))
  10923.             Error("load_module",GetMessage(MSG_LOAD_MODULE,
  10924.                             array("FILE"=>"$MODULEDIR/$sModule",
  10925.                                     "ERROR"=>$php_errormsg)),false,false);
  10926. }
  10927.  
  10928. if (!empty($SPECIAL_VALUES["fmcompute"]))
  10929. {
  10930.         //
  10931.         // Callback function for preg_replace_callback to add line
  10932.         // numbers on each match
  10933.         //
  10934.     function AddLineNumbersCallback($a_matches)
  10935.     {
  10936.         global  $iAddLineNumbersCounter;
  10937.  
  10938.         return (sprintf("%d:",++$iAddLineNumbersCounter).$a_matches[0]);
  10939.     }
  10940.         //
  10941.         // Add line numbers to some code
  10942.         //
  10943.     function AddLineNumbers($s_code)
  10944.     {
  10945.         global  $iAddLineNumbersCounter;
  10946.  
  10947.         $iAddLineNumbersCounter = 0;
  10948.         return (preg_replace_callback('/^/m','AddLineNumbersCallback',$s_code));
  10949.     }
  10950.  
  10951.         //
  10952.         // Load some more code into FMCalc
  10953.         //
  10954.     function Load($s_code)
  10955.     {
  10956.         global  $FMCalc;
  10957.  
  10958.         $a_mesgs = array();
  10959.        // echo "Loading '$s_code'";
  10960.         if ($FMCalc->Parse($s_code,$a_mesgs) === false)
  10961.         {
  10962.             $s_msgs = "";
  10963.             foreach ($a_mesgs as $a_msg)
  10964.             {
  10965.                 $s_msgs .= "Line ".$a_msg["LINE"];
  10966.                 $s_msgs .= ", position ".$a_msg["CHAR"].": ";
  10967.                 $s_msgs .= $a_msg["MSG"]."\n";
  10968.             }
  10969.             Error("fmcompute_parse",GetMessage(MSG_COMP_PARSE,
  10970.                         array("CODE"=>AddLineNumbers($s_code),
  10971.                                 "ERRORS"=>$s_msgs)),false,false);
  10972.         }
  10973.     }
  10974.  
  10975.         //
  10976.         // Send any alerts found in FMCalc
  10977.         //
  10978.     function SendComputeAlerts()
  10979.     {
  10980.         global  $FMCalc;
  10981.  
  10982.         $a_alerts = $FMCalc->GetAlerts();
  10983.         if (count($a_alerts) > 0)
  10984.             SendAlert(GetMessage(MSG_COMP_ALERT,
  10985.                         array("ALERTS"=>implode("\n",StripHTML($a_alerts)))));
  10986.         $a_debug = $FMCalc->GetDebug();
  10987.         if (count($a_debug) > 0)
  10988.             SendAlert(GetMessage(MSG_COMP_DEBUG,
  10989.                         array("DEBUG"=>implode("\n",StripHTML($a_debug)))));
  10990.     }
  10991.         //
  10992.         // Perform the computations in FMCalc
  10993.         //
  10994.     function Compute(&$a_field_order,&$a_cleaned_values,&$a_raw_data_values,
  10995.                             &$a_values)
  10996.     {
  10997.         global  $FMCalc,$FM_UserErrors;
  10998.  
  10999.         $a_mesgs = array();
  11000.         $FM_UserErrors = array();
  11001.         if (($a_flds = $FMCalc->Execute($a_mesgs)) !== false)
  11002.         {
  11003.             SendComputeAlerts();
  11004.             foreach ($a_flds as $s_name=>$s_value)
  11005.             {
  11006.                 $a_values[$s_name] = $s_value;
  11007.                 ProcessField($s_name,$s_value,$a_field_order,
  11008.                                 $a_cleaned_values,$a_raw_data_values);
  11009.             }
  11010.             if (count($FM_UserErrors) > 0)
  11011.                 UserError("fmcompute_usererrors",GetMessage(MSG_USER_ERRORS),
  11012.                                 "",$FM_UserErrors);
  11013.         }
  11014.         else
  11015.         {
  11016.             SendComputeAlerts();
  11017.             Error("fmcompute_exec",GetMessage(MSG_COMP_EXEC,
  11018.                         array("ERRORS"=>implode("\n",$a_mesgs))),false,false);
  11019.         }
  11020.     }
  11021.  
  11022.         //
  11023.         // Register all fields; a future improvement should use a call-back
  11024.         // function so as not to copy all the data into the FMCompute object
  11025.         //
  11026.     function RegisterData($a_form_data,$a_file_vars)
  11027.     {
  11028.         global  $FMCalc;
  11029.  
  11030.         foreach ($a_form_data as $s_name=>$s_value)
  11031.             if (isset($s_name) && isset($s_value))
  11032.                 if (($s_msg = $FMCalc->RegisterExternalData("PHP","string",
  11033.                                                 $s_name,"c",$s_value)) !== true)
  11034.                     Error("fmcompute_regdata",GetMessage(MSG_COMP_REG_DATA,
  11035.                                 array("NAME"=>$s_name,"ERROR"=>$s_msg)),false,false);
  11036.  
  11037.         foreach ($a_file_vars as $s_fld_name=>$a_file_spec)
  11038.         {
  11039.             if (IsUploadedFile($a_file_spec))
  11040.             {
  11041.                 if (isset($a_file_spec["new_name"]))
  11042.                 {
  11043.                         //
  11044.                         // we ignore errors here, because name_of_ field often already
  11045.                         // exists from the above loop
  11046.                         //
  11047.                     $FMCalc->RegisterExternalData("PHP","string",
  11048.                                         "name_of_".$s_fld_name,"c",$a_file_spec["new_name"]);
  11049.                 }
  11050.                 $s_value = $a_file_spec["name"];
  11051.             }
  11052.             else
  11053.                 $s_value = "";
  11054.             if (($s_msg = $FMCalc->RegisterExternalData("PHP","string",
  11055.                                             $s_fld_name,"c",$s_value)) !== true)
  11056.                 Error("fmcompute_regdata",GetMessage(MSG_COMP_REG_DATA,
  11057.                             array("NAME"=>$s_fld_name,"ERROR"=>$s_msg)),false,false);
  11058.         }
  11059.     }
  11060.  
  11061.     /* 
  11062.      * Function:    MergeFileArrays
  11063.      * Parameters:  $a_new_files    the list of files just submitted by the form
  11064.      *              $a_saved_files  the list of files that have been previously saved (can be NULL)
  11065.      * Returns:     array           a merged array
  11066.      * Description:     
  11067.      *  Intelligently merges two arrays of file definitions.
  11068.      *  If a file has been newly uploaded, its definition takes precedence.
  11069.      */
  11070.     function    MergeFileArrays($a_new_files,$a_saved_files)
  11071.     {
  11072.         if (isset($a_saved_files))
  11073.             foreach ($a_saved_files as $s_key=>$a_def)
  11074.                 if (isset($a_new_files[$s_key]))
  11075.                 {
  11076.                     if (!IsUploadedFile($a_new_files[$s_key]))
  11077.                         $a_new_files[$s_key] = $a_def;
  11078.                 }
  11079.                 else
  11080.                     $a_new_files[$s_key] = $a_def;
  11081.         return ($a_new_files);
  11082.     }
  11083.     RegisterData($aAllRawValues,MergeFileArrays($aFileVars,$aSessionVars["FormSavedFiles"]));
  11084.         //
  11085.         // parse all fmcompute fields
  11086.         //
  11087.     if (is_array($SPECIAL_VALUES["fmcompute"]))
  11088.     {
  11089.         $nCompute = count($SPECIAL_VALUES["fmcompute"]);
  11090.         for ($iCompute = 0 ; $iCompute < $nCompute ; $iCompute++)
  11091.             Load($SPECIAL_VALUES["fmcompute"][$iCompute]);
  11092.     }
  11093.     else
  11094.         Load($SPECIAL_VALUES["fmcompute"]);
  11095.  
  11096.         //
  11097.         // run computations
  11098.         //
  11099.     Compute($aFieldOrder,$aCleanedValues,$aRawDataValues,$aAllRawValues);
  11100.         //
  11101.         // Hook system: after computations
  11102.         //
  11103.     if ($HOOK_DIR !== "")
  11104.         if (!@include("$HOOK_DIR/fmhookcompute.inc.php"))
  11105.             @include("$HOOK_DIR/fmhookcompute.inc");
  11106. }
  11107.  
  11108. $bGotGoBack = $bGotNextForm = $bGotGoodTemplate = $bGotGoodUrl = false;
  11109. if (isset($SPECIAL_VALUES["good_url"]) &&
  11110.     !empty($SPECIAL_VALUES["good_url"]))
  11111.     $bGotGoodUrl = true;
  11112.  
  11113. if (isset($SPECIAL_VALUES["good_template"]) &&
  11114.     !empty($SPECIAL_VALUES["good_template"]))
  11115.     $bGotGoodTemplate = true;
  11116.  
  11117. if (isset($SPECIAL_VALUES["next_form"]) &&
  11118.     !empty($SPECIAL_VALUES["next_form"]))
  11119.     $bGotNextForm = true;
  11120.  
  11121. if (isset($SPECIAL_VALUES["multi_go_back"]) &&
  11122.     !empty($SPECIAL_VALUES["multi_go_back"]))
  11123.     $bGotGoBack = true;
  11124.  
  11125.     //
  11126.     // it's not valid to specify "next_form" as well as "good_url" or
  11127.     // "good_template"; this is because it's ambiguous - do we go to the
  11128.     // next form or the final 'thank you' page?
  11129.     //
  11130. if ($bGotNextForm && ($bGotGoodTemplate || $bGotGoodUrl))
  11131.     ErrorWithIgnore("next_plus_good",GetMessage(MSG_NEXT_PLUS_GOOD,array("WHICH"=>
  11132.                                     ($bGotGoodUrl ? "good_url" :
  11133.                                     "good_template"))),false,false);
  11134.  
  11135. MultiFormLogic();
  11136.  
  11137.     //
  11138.     // Hook system: after multi-page form logic
  11139.     //
  11140. if ($HOOK_DIR !== "")
  11141.     if (!@include("$HOOK_DIR/fmhookmulti.inc.php"))
  11142.         @include("$HOOK_DIR/fmhookmulti.inc");
  11143.  
  11144.     //
  11145.     // write to the CSV database
  11146.     //
  11147. if (!empty($CSVDIR) && isset($SPECIAL_VALUES["csvfile"]) &&
  11148.                         !empty($SPECIAL_VALUES["csvfile"]))
  11149. {
  11150.         //
  11151.         // Hook system: before writing CSV file
  11152.         //
  11153.     if ($HOOK_DIR !== "")
  11154.         if (!@include("$HOOK_DIR/fmhookprecsv.inc.php"))
  11155.             @include("$HOOK_DIR/fmhookprecsv.inc");
  11156.     WriteCSVFile($CSVDIR."/".basename($SPECIAL_VALUES["csvfile"]),$aAllRawValues);
  11157.         //
  11158.         // Hook system: after writing CSV file
  11159.         //
  11160.     if ($HOOK_DIR !== "")
  11161.         if (!@include("$HOOK_DIR/fmhookpostcsv.inc.php"))
  11162.             @include("$HOOK_DIR/fmhookpostcsv.inc");
  11163.     $bDoneSomething = true;
  11164. }
  11165.  
  11166.     //
  11167.     // write to the log file
  11168.     //
  11169. if (!empty($LOGDIR) && isset($SPECIAL_VALUES["logfile"]) && !empty($SPECIAL_VALUES["logfile"]))
  11170. {
  11171.         //
  11172.         // Hook system: before writing log file
  11173.         //
  11174.     if ($HOOK_DIR !== "")
  11175.         if (!@include("$HOOK_DIR/fmhookprelog.inc.php"))
  11176.             @include("$HOOK_DIR/fmhookprelog.inc");
  11177.     WriteLog($LOGDIR."/".basename($SPECIAL_VALUES["logfile"]));
  11178.         //
  11179.         // Hook system: after writing log file
  11180.         //
  11181.     if ($HOOK_DIR !== "")
  11182.         if (!@include("$HOOK_DIR/fmhookpostlog.inc.php"))
  11183.             @include("$HOOK_DIR/fmhookpostlog.inc");
  11184.     $bDoneSomething = true;
  11185. }
  11186.  
  11187.     //
  11188.     // send to the CRM
  11189.     //
  11190. if (isset($SPECIAL_VALUES["crm_url"]) && isset($SPECIAL_VALUES["crm_spec"]) &&
  11191.     !empty($SPECIAL_VALUES["crm_url"]) && !empty($SPECIAL_VALUES["crm_spec"]))
  11192. {
  11193.     $sCRM = GetCRMURL($SPECIAL_VALUES["crm_spec"],$aAllRawValues,$SPECIAL_VALUES["crm_url"]);
  11194.     if (!empty($sCRM))
  11195.     {
  11196.         $aCRMReturnData = array();
  11197.             //
  11198.             // Hook system: before sending to CRM
  11199.             //
  11200.         if ($HOOK_DIR !== "")
  11201.             if (!@include("$HOOK_DIR/fmhookprecrm.inc.php"))
  11202.                 @include("$HOOK_DIR/fmhookprecrm.inc");
  11203.         if (!SendToCRM($sCRM,$aCRMReturnData))
  11204.         {
  11205.                 //
  11206.                 // CRM interface failed, check if the form wants an error
  11207.                 // displayed
  11208.                 //
  11209.             if (IsCRMOptionSet("ErrorOnFail"))
  11210.                 Error("crm_failed",GetMessage(MSG_CRM_FAILURE,
  11211.                                 array("URL"=>$sCRM,
  11212.                                     "DATA"=>GetObjectAsString($aCRMReturnData))),
  11213.                                 false,false);
  11214.         }
  11215.         else
  11216.                 //
  11217.                 // append the returned data to the raw data values of the form
  11218.                 //
  11219.             $aRawDataValues = array_merge($aRawDataValues,$aCRMReturnData);
  11220.             //
  11221.             // Hook system: after sending to CRM
  11222.             //
  11223.         if ($HOOK_DIR !== "")
  11224.             if (!@include("$HOOK_DIR/fmhookpostcrm.inc.php"))
  11225.                 @include("$HOOK_DIR/fmhookpostcrm.inc");
  11226.         $bDoneSomething = true;
  11227.     }
  11228. }
  11229.  
  11230.     //
  11231.     // Check obsolete SendMailFOption
  11232.     //
  11233. if (IsMailOptionSet("SendMailFOption"))
  11234.     SendAlert(GetMessage(MSG_FOPTION_WARN,array("LINE"=>SENDMAIL_F_OPTION_LINE)),
  11235.                 false,true);
  11236.  
  11237.     //
  11238.     // send email
  11239.     //
  11240. if (!isset($SPECIAL_VALUES["recipients"]) || empty($SPECIAL_VALUES["recipients"]))
  11241. {
  11242.         //
  11243.         // No recipients - don't email anyone...
  11244.         // If nothing has been done above (CSV, logging, or CRM),
  11245.         // then report an error.
  11246.         //
  11247.     if (!$bDoneSomething)
  11248.         if (!$bGotGoBack && !$bGotNextForm)
  11249.             ErrorWithIgnore("no_recipients",GetMessage(MSG_NO_ACTIONS));
  11250. }
  11251. else
  11252. {
  11253.         //
  11254.         // Hook system: before sending emails
  11255.         //
  11256.     if ($HOOK_DIR !== "")
  11257.         if (!@include("$HOOK_DIR/fmhookpreemail.inc.php"))
  11258.             @include("$HOOK_DIR/fmhookpreemail.inc");
  11259.     $s_invalid = $s_invalid_cc = $s_invalid_bcc = "";
  11260.     if (!CheckEmailAddress($SPECIAL_VALUES["recipients"],$s_valid_recipients,$s_invalid))
  11261.         ErrorWithIgnore("no_valid_recipients",GetMessage(MSG_NO_RECIP));
  11262.     else
  11263.     {
  11264.         $s_valid_cc = $s_valid_bcc = "";
  11265.  
  11266.             //
  11267.             // check CC and BCC addresses
  11268.             //
  11269.         if (isset($SPECIAL_VALUES["cc"]) && !empty($SPECIAL_VALUES["cc"]))
  11270.             CheckEmailAddress($SPECIAL_VALUES["cc"],$s_valid_cc,$s_invalid_cc);
  11271.         if (isset($SPECIAL_VALUES["bcc"]) && !empty($SPECIAL_VALUES["bcc"]))
  11272.             CheckEmailAddress($SPECIAL_VALUES["bcc"],$s_valid_bcc,$s_invalid_bcc);
  11273.  
  11274.             //
  11275.             // send an alert for invalid addresses
  11276.             //
  11277.         $s_error = "";
  11278.         if (!empty($s_invalid))
  11279.             $s_error .= "recipients: $s_invalid\r\n";
  11280.         if (!empty($s_invalid_cc))
  11281.             $s_error .= "cc: $s_invalid_cc\r\n";
  11282.         if (!empty($s_invalid_bcc))
  11283.             $s_error .= "bcc: $s_invalid_bcc\r\n";
  11284.         if (!empty($s_error))
  11285.             SendAlert(GetMessage(MSG_INV_EMAIL,array("ERRORS"=>$s_error)));
  11286.  
  11287.             //
  11288.             // send the actual results
  11289.             //
  11290.         if (!SendResults($aFieldOrder,$aCleanedValues,$s_valid_recipients,$s_valid_cc,
  11291.                             $s_valid_bcc,$aRawDataValues))
  11292.             Error("mail_failed",GetMessage(MSG_FAILED_SEND));
  11293.             //
  11294.             // Hook system: after sending emails
  11295.             //
  11296.         if ($HOOK_DIR !== "")
  11297.             if (!@include("$HOOK_DIR/fmhookpostemail.inc.php"))
  11298.                 @include("$HOOK_DIR/fmhookpostemail.inc");
  11299.     }
  11300. }
  11301.  
  11302.     //
  11303.     // if the user didn't enter the verification code,
  11304.     // just skip the autoresponse
  11305.     //
  11306. if (isset($SPECIAL_VALUES["arverify"]) && $SPECIAL_VALUES["arverify"] !== "")
  11307. {
  11308.     if (IsAROptionSet('HTMLTemplate') || IsAROptionSet('PlainTemplate'))
  11309.     {
  11310.         if (!isset($SPECIAL_VALUES["email"]) || empty($SPECIAL_VALUES["email"]))
  11311.             SendAlert(GetMessage(MSG_ARESP_EMAIL));
  11312.         else
  11313.         {
  11314.                 //
  11315.                 // Hook system: before sending auto response
  11316.                 //
  11317.             if ($HOOK_DIR !== "")
  11318.                 if (!@include("$HOOK_DIR/fmhookprearesp.inc.php"))
  11319.                     @include("$HOOK_DIR/fmhookprearesp.inc");
  11320.             $sAutoRespTo = $SPECIAL_VALUES["email"];
  11321.             if (IsAROptionSet('Subject'))
  11322.                 $sAutoRespSubj = GetAROption('Subject');
  11323.             else
  11324.                 $sAutoRespSubj = GetMessage(MSG_ARESP_SUBJ,array(),false);
  11325.  
  11326.                 //
  11327.                 // VerifyImgString is from Tectite's simple verifyimg.php CAPTCHA
  11328.                 // turing_string is from Captcha Creator
  11329.                 //
  11330.             if (!isset($aSessionVars["VerifyImgString"]) &&
  11331.                 !isset($aSessionVars["turing_string"]))
  11332.             {
  11333.                 WriteARLog($sAutoRespTo,$sAutoRespSubj,
  11334.                         GetMessage(MSG_LOG_NO_VERIMG,array(),false));
  11335.                 ErrorWithIgnore("verify_failed",GetMessage(MSG_ARESP_NO_AUTH),true);
  11336.             }
  11337.             $bARImgMatch = false;
  11338.                 //
  11339.                 // the user's entry must match the value in the session; allow
  11340.                 // spaces in the user's input
  11341.                 //
  11342.             if (isset($aSessionVars["VerifyImgString"]))
  11343.             {
  11344.                 if (strtoupper(str_replace(" ","",$SPECIAL_VALUES["arverify"])) ===
  11345.                             strtoupper($aSessionVars["VerifyImgString"]))
  11346.                     $bARImgMatch = true;
  11347.             }
  11348.             else
  11349.             {
  11350.                 if (strtoupper(str_replace(" ","",$SPECIAL_VALUES["arverify"])) ===
  11351.                             strtoupper($aSessionVars["turing_string"]))
  11352.                     $bARImgMatch = true;
  11353.             }
  11354.             if (!$bARImgMatch)
  11355.             {
  11356.                 WriteARLog($sAutoRespTo,$sAutoRespSubj,
  11357.                             GetMessage(MSG_LOG_NO_MATCH,array(),false));
  11358.                 UserError("ar_verify",GetMessage(MSG_ARESP_NO_MATCH));
  11359.             }
  11360.             elseif (!AutoRespond($sAutoRespTo,$sAutoRespSubj,$aRawDataValues))
  11361.             {
  11362.                 WriteARLog($sAutoRespTo,$sAutoRespSubj,
  11363.                             GetMessage(MSG_LOG_FAILED,array(),false));
  11364.                 SendAlert(GetMessage(MSG_ARESP_FAILED));
  11365.             }
  11366.             else
  11367.             {
  11368.                 WriteARLog($sAutoRespTo,$sAutoRespSubj,
  11369.                             GetMessage(MSG_LOG_OK,array(),false));
  11370.                     //
  11371.                     // Hook system: after sending auto response
  11372.                     //
  11373.                 if ($HOOK_DIR !== "")
  11374.                     if (!@include("$HOOK_DIR/fmhookpostaresp.inc.php"))
  11375.                         @include("$HOOK_DIR/fmhookpostaresp.inc");
  11376.             }
  11377.         }
  11378.     }
  11379. }
  11380.  
  11381. $SessionAccessor->CopyOut($aAllRawValues);
  11382.     //
  11383.     // multi-form processing
  11384.     //
  11385. if ($bGotNextForm)
  11386. {
  11387.     OutputMultiFormTemplate($SPECIAL_VALUES["next_form"],$aRawDataValues);
  11388. //    echo "Form index = ".$aSessionVars["FormIndex"];
  11389. }
  11390. else
  11391. {
  11392.         //
  11393.         // Hook system: before finishing
  11394.         //
  11395.     if ($HOOK_DIR !== "")
  11396.         if (!@include("$HOOK_DIR/fmhookprefinish.inc.php"))
  11397.             @include("$HOOK_DIR/fmhookprefinish.inc");
  11398.         //
  11399.         // redirect to the good URL page, or create a default page;
  11400.         // we're no longer processing a multi-page form sequence
  11401.         //
  11402.     unset($aSessionVars["FormList"]);
  11403.     unset($aSessionVars["FormIndex"]);
  11404.     unset($aSessionVars["FormKeep"]);
  11405.     if (!$bGotGoodUrl)
  11406.     {
  11407.         if ($bGotGoodTemplate)
  11408.             OutputTemplate($SPECIAL_VALUES["good_template"],$aRawDataValues);
  11409.         else
  11410.             CreatePage(GetMessage(MSG_THANKS_PAGE));
  11411.             //
  11412.             // Hook system: after finishing (before session is cleared)
  11413.             //
  11414.         if ($HOOK_DIR !== "")
  11415.             if (!@include("$HOOK_DIR/fmhookpostfinish.inc.php"))
  11416.                 @include("$HOOK_DIR/fmhookpostfinish.inc");
  11417.             //
  11418.             // everything's good, so we don't need the session any more
  11419.             //
  11420.         ZapSession();
  11421.     }
  11422.     else
  11423.             //
  11424.             // Note that a redirect terminates the script and prevents
  11425.             // the processing of fmhookpostfinish.inc.  Also, the session
  11426.             // is left intact (which the good_url can use).
  11427.             //
  11428.         Redirect($SPECIAL_VALUES["good_url"]);
  11429. }
  11430. ?>
  11431.