--- components/captcha.inc	Tue May 29 05:00:32 2007
+++ components/captcha.inc	Wed Jun 20 22:31:59 2007
@@ -1,148 +1,148 @@
-<?php
-// $Id: captcha.inc,v 1.11.2.2 2007/05/29 03:00:32 quicksketch Exp $
-/** 
- * function webform_edit_captcha
- * Create a set of form items to be displayed on the form for editing this component.
- * Use care naming the form items, as this correlates directly to the database schema.
- * The component "Name" and "Description" fields are added to every component type and
- * are not necessary to specify here (although they may be overridden if desired).
- * @returns An array of form items to be displayed on the edit component page
- **/
-function _webform_edit_captcha($currfield) {
-  if (!module_exists("captcha")) {
-    drupal_set_message(t("Using captcha components in webform requires the <a href='http://drupal.org/project/captcha'>Captcha</a> and <a href='http://drupal.org/node/52349'>Textimage</a> modules."), "error");
-  }
-  
-  $edit_fields = array();
-  $edit_fields['value'] = array();
-  $edit_fields['mandatory'] = array(
-    '#type' => 'hidden',
-    '#value' => 1,
-  );
-  $edit_fields['mandatory-display'] = array(
-    '#type' => 'checkbox',
-    '#title' => t("Mandatory"),
-    '#default_value' => TRUE,
-    '#attributes' => array('disabled' => 'disabled'),
-    '#description' => t('Captchas are always mandatory'),
-    '#weight' => 2,
-  );
-  return $edit_fields;
-}
-
-/** 
- * function webform_render_captcha
- * Build a form item array containing all the properties of this component
- * @param $component An array of information describing the component, directly correlating to the webform_component database schema
- * @returns An array of a form item to be displayed on the client-side webform
- **/
-function _webform_render_captcha($component) {
-  if (module_exists("captcha")) {
-    // Create a dummy form to pass to the captcha function
-    $dummy_form = array();
-    // Pass the form to the captcha rendering function
-    $captcha_type = variable_get("captcha_type", 'captcha');
-    
-    // Recursively check if captcha has already been answered in the POST array:
-    if (isset($_POST['edit']['submitted'])) {
-      $captcha_correct = _webform_render_captcha_check($component['cid'], $_POST['edit']['submitted']);
-    }
-    else {
-      $captcha_correct = false;
-    }
-    
-    if ($captcha_correct) {
-      return array(); // Do not render the captcha at all
-    }
-    else {
-      if (module_hook($captcha_type, 'captchachallenge')) {
-        call_user_func_array($captcha_type .'_captchachallenge', array(&$dummy_form, &$_SESSION['captcha']));   
-      }
-    }
-    // Set a custom validation function (defined below)
-    $dummy_form['captcha_response']['#validate'] = array("_webform_validate_captcha" => array());
-    // Extract the created captcha into formItem to be returned to webform
-    $form_item = $dummy_form['captcha_response'];
-    $form_item['#weight'] = $component['weight']; 
-    
-    // Override the default title if not the default math question (which is used as the title)
-    if ($captcha_type != 'captcha') {
-      $form_item['#title'] = htmlspecialchars($component['name'], ENT_QUOTES);
-    }
-    // Override the default captcha description if the user has defined something different
-    if (strlen(trim($component['extra']['description'])) > 0) {
-      $form_item['#description'] = _webform_filtervalues($component['extra']['description']);
-    }
-    
-    // Wrap in a div
-    $form_item['#prefix'] = '<div class="webform-component-'. $component['type'] .'" id="webform-component-'. $component['form_key'] .'">'. $form_item['#prefix'];
-    $form_item['#suffix'] .= "</div>";
-  }
-  else {
-    drupal_set_message(t("Unable to render captcha field because the captcha module is not available."), "error");
-  }
-  return $form_item;
-}
-/**
- * Helper function for rendering the captcha. The standard captcha module always places
- * the captcha on the root level of the form, since we can place captcha inside any
- * fieldset in webform, we need to do a recursive check for the field, see if was answered
- * correctly and return the result.
- *
- * @param string $captcha_field_name
- * @param array $fieldset
- * @return boolean 
- */
-function _webform_render_captcha_check($captcha_field_name, $fieldset) {
-  foreach ($fieldset as $key => $value) {
-    if ($key == $captcha_field_name) {
-      return _webform_validate_captcha($value);
-    }
-    if (is_array($value)) {
-      _webform_render_captcha_check($captcha_field_name, $value);
-    }
-  }
-  return true; // No captcha at all in the array
-}
-
-function _webform_validate_captcha($captcha_response) {
-  // This function copied directly from the captcha module.
-  // The below line is commented out to require every submission to use a captcha,
-  // no caching correct answers allowed, lest one real user enter the captcha
-  // and then send a bot to churn out spam.
-
-  //if ($_SESSION['captcha_correct']) return TRUE; // Potentially Dangerous
-  if (is_array($captcha_response)) $captcha_response = $captcha_response['#value'];
-  if (trim($captcha_response) == '') return FALSE;
-
-  global $user;
-  $captcha_type = variable_get("captcha_type", NULL);
-  $trigger = NULL;
-
-  if (module_hook($captcha_type, 'captchavalidate')) {
-    call_user_func_array($captcha_type .'_captchavalidate', array(&$captcha_response, &$_SESSION['captcha_correct']));
-  }
-  
-  return $_SESSION['captcha_correct'];
-}
-
-function _webform_help_captcha($section) {
-  switch ($section) {
-    case 'admin/settings/webform#captcha_description':
-      $output = t("Require a question to prove the user is human. Requires <a href='http://drupal.org/project/captcha'>Captcha</a> module.");
-      break;
-  }
-  return $output;
-}
-
-/** 
- * function _webform_submission_display_captcha
- * Display the result of a captcha submission. The output of this function will be displayed under the "results" tab then "submissions"
- * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
- * @param $component An array of information describing the component, directly correlating to the webform_component database schema
- * @returns Textual output formatted for human reading.
- **/
-function _webform_submission_display_captcha($component, $data) {
-  $form_item = array();
-  return $form_item;
-}
+<?php
+// $Id: captcha.inc,v 1.11.2.2 2007/05/29 03:00:32 quicksketch Exp $
+/** 
+ * function webform_edit_captcha
+ * Create a set of form items to be displayed on the form for editing this component.
+ * Use care naming the form items, as this correlates directly to the database schema.
+ * The component "Name" and "Description" fields are added to every component type and
+ * are not necessary to specify here (although they may be overridden if desired).
+ * @returns An array of form items to be displayed on the edit component page
+ **/
+function _webform_edit_captcha($currfield) {
+  if (!module_exists("captcha")) {
+    drupal_set_message(t("Using captcha components in webform requires the <a href='http://drupal.org/project/captcha'>Captcha</a> and <a href='http://drupal.org/node/52349'>Textimage</a> modules."), "error");
+  }
+  
+  $edit_fields = array();
+  $edit_fields['value'] = array();
+  $edit_fields['mandatory'] = array(
+    '#type' => 'hidden',
+    '#value' => 1,
+  );
+  $edit_fields['mandatory-display'] = array(
+    '#type' => 'checkbox',
+    '#title' => t("Mandatory"),
+    '#default_value' => TRUE,
+    '#attributes' => array('disabled' => 'disabled'),
+    '#description' => t('Captchas are always mandatory'),
+    '#weight' => 2,
+  );
+  return $edit_fields;
+}
+
+/** 
+ * function webform_render_captcha
+ * Build a form item array containing all the properties of this component
+ * @param $component An array of information describing the component, directly correlating to the webform_component database schema
+ * @returns An array of a form item to be displayed on the client-side webform
+ **/
+function _webform_render_captcha($component) {
+  if (module_exists("captcha")) {
+    // Create a dummy form to pass to the captcha function
+    $dummy_form = array();
+    // Pass the form to the captcha rendering function
+    $captcha_type = variable_get("captcha_type", 'captcha');
+    
+    // Recursively check if captcha has already been answered in the POST array:
+    if (isset($_POST['edit']['submitted'])) {
+      $captcha_correct = _webform_render_captcha_check($component['cid'], $_POST['edit']['submitted']);
+    }
+    else {
+      $captcha_correct = false;
+    }
+    
+    if ($captcha_correct) {
+      return array(); // Do not render the captcha at all
+    }
+    else {
+      if (module_hook($captcha_type, 'captchachallenge')) {
+        call_user_func_array($captcha_type .'_captchachallenge', array(&$dummy_form, &$_SESSION['captcha']));   
+      }
+    }
+    // Set a custom validation function (defined below)
+    $dummy_form['captcha_response']['#validate'] = array("_webform_validate_captcha" => array());
+    // Extract the created captcha into formItem to be returned to webform
+    $form_item = $dummy_form['captcha_response'];
+    $form_item['#weight'] = $component['weight']; 
+    
+    // Override the default title if not the default math question (which is used as the title)
+    if ($captcha_type != 'captcha') {
+      $form_item['#title'] = htmlspecialchars($component['name'], ENT_QUOTES);
+    }
+    // Override the default captcha description if the user has defined something different
+    if (strlen(trim($component['extra']['description'])) > 0) {
+      $form_item['#description'] = _webform_filtervalues($component['extra']['description']);
+    }
+    
+    // Wrap in a div
+    $form_item['#prefix'] = '<div class="webform-component-'. $component['type'] .'" id="webform-component-'. $component['form_key'] .'">'. $form_item['#prefix'];
+    $form_item['#suffix'] .= "</div>";
+  }
+  else {
+    drupal_set_message(t("Unable to render captcha field because the captcha module is not available."), "error");
+  }
+  return $form_item;
+}
+/**
+ * Helper function for rendering the captcha. The standard captcha module always places
+ * the captcha on the root level of the form, since we can place captcha inside any
+ * fieldset in webform, we need to do a recursive check for the field, see if was answered
+ * correctly and return the result.
+ *
+ * @param string $captcha_field_name
+ * @param array $fieldset
+ * @return boolean 
+ */
+function _webform_render_captcha_check($captcha_field_name, $fieldset) {
+  foreach ($fieldset as $key => $value) {
+    if ($key == $captcha_field_name) {
+      return _webform_validate_captcha($value);
+    }
+    if (is_array($value)) {
+      _webform_render_captcha_check($captcha_field_name, $value);
+    }
+  }
+  return true; // No captcha at all in the array
+}
+
+function _webform_validate_captcha($captcha_response) {
+  // This function copied directly from the captcha module.
+  // The below line is commented out to require every submission to use a captcha,
+  // no caching correct answers allowed, lest one real user enter the captcha
+  // and then send a bot to churn out spam.
+
+  //if ($_SESSION['captcha_correct']) return TRUE; // Potentially Dangerous
+  if (is_array($captcha_response)) $captcha_response = $captcha_response['#value'];
+  if (trim($captcha_response) == '') return FALSE;
+
+  global $user;
+  $captcha_type = variable_get("captcha_type", NULL);
+  $trigger = NULL;
+
+  if (module_hook($captcha_type, 'captchavalidate')) {
+    call_user_func_array($captcha_type .'_captchavalidate', array(&$captcha_response, &$_SESSION['captcha_correct']));
+  }
+  
+  return $_SESSION['captcha_correct'];
+}
+
+function _webform_help_captcha($section) {
+  switch ($section) {
+    case 'admin/settings/webform#captcha_description':
+      $output = t("Require a question to prove the user is human. Requires <a href='http://drupal.org/project/captcha'>Captcha</a> module.");
+      break;
+  }
+  return $output;
+}
+
+/** 
+ * function _webform_submission_display_captcha
+ * Display the result of a captcha submission. The output of this function will be displayed under the "results" tab then "submissions"
+ * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
+ * @param $component An array of information describing the component, directly correlating to the webform_component database schema
+ * @returns Textual output formatted for human reading.
+ **/
+function _webform_submission_display_captcha($component, $data, $enabled) {
+  $form_item = array();
+  return $form_item;
+}
--- components/date.inc	Wed Jun 13 02:47:20 2007
+++ components/date.inc	Wed Jun 20 22:31:59 2007
@@ -1,298 +1,298 @@
-<?php
-// $Id: date.inc,v 1.13.2.8 2007/06/13 00:47:19 quicksketch Exp $
-/** 
- * function webform_edit_date
- * Create a set of form items to be displayed on the form for editing this component.
- * Use care naming the form items, as this correlates directly to the database schema.
- * The component "Name" and "Description" fields are added to every component type and
- * are not necessary to specify here (although they may be overridden if desired).
- * @returns An array of form items to be displayed on the edit component page
- **/
-function _webform_edit_date($currfield) {
-  $edit_fields = array();
-  $edit_fields['value'] = array(
-    '#type' => 'textfield',
-    '#title' => t("Default value"),
-    '#default_value' => $currfield['default'],
-    '#description' => t('The default value of the field.') .'<br />'. t('Accepts any date in any <a href="http://www.gnu.org/software/tar/manual/html_node/tar_109.html">GNU Date Input Format</a>. Strings such as today, +2 months, and Dec 9 2004 are all valid.') .'<br />'. webform_help('webform/helptext#variables'),
-    '#size' => 60,
-    '#maxlength' => 127,
-    '#weight' => 0,
-  );
-  $edit_fields['extra']['timezone'] = array(
-    '#type' => 'radios',
-    '#title' => t("Timezone"),
-    '#default_value' => empty($currfield['extra']['timezone']) ? "site" : $currfield['extra']['timezone'],
-    '#description' => t('Adjust the date according to a specific timezone. Website timezone is defined in the <a href="%settings">Site Settings</a> and is the default.', array('%settings' => url('admin/settings'))),
-    '#options' => array('site' => 'Website Timezone', 'user' => 'User Timezone', 'gmt' => 'GMT'),
-    '#weight' => 0,
-  );
-  $edit_fields['extra']['check_daylight_savings'] = array(
-    '#type' => 'checkbox',
-    '#title' => t("Observe Daylight Savings"),
-    '#default_value' => $currfield['extra']['check_daylight_savings'],
-    '#checked_value' => 1,
-    '#description' => t('Automatically adjust the time during daylight savings.'),
-    '#weight' => 1,
-  );
-
-  return $edit_fields;
-}
-
-/** 
- * function webform_render_date
- * Build a form item array containing all the properties of this component
- * @param $component An array of information describing the component, directly correlating to the webform_component database schema
- * @returns An array of a form item to be displayed on the client-side webform
- **/
-function _webform_render_date($component) {
-  if (strlen($component['value']) > 0) {
-    // Calculate the timestamp in GMT
-    $timestamp = strtotime(_webform_filtervalues($component['value']));
-    
-    if ($component['extra']['timezone'] == "user") {
-      // Use the users timezone
-      global $user;
-      $timestamp += (int)$user->timezone;
-    }
-    elseif ($component['extra']['timezone'] == "gmt") {
-      // Use GMT
-      $timestamp += 0;
-    }
-    else {
-      // Use the Drupal site time
-      $timestamp += variable_get('date_default_timezone', 0);
-    }
-    
-    // Check for daylight savings time
-    if ($component['extra']['check_daylight_savings'] && date("I")) {
-      $timestamp += 3600;
-    }
-    
-    $year = gmdate('Y', $timestamp);
-    $month = gmdate('n', $timestamp);
-    $day = gmdate('j', $timestamp);
-  }
-  $months = array("" => t("month"), 1 => t('January'), t('February'), t('March'), t('April'), t('May'), t('June'), t('July'), t('August'), t('September'), t('October'), t('November'), t('December'));
-  $days = array("" => t("day"));
-  for ($i = 1; $i <= 31; $i++) $days[$i] = $i;
-  
-  $form_item = array(
-    '#type' => 'fieldset',
-    '#title' => htmlspecialchars($component['name'], ENT_QUOTES),
-    '#weight' => $component['weight'],
-    '#description' => _webform_filtervalues($component['extra']['description']),
-    '#prefix' => '<div class="webform-component-'. $component['type'] .' container-inline" id="webform-component-'. $component['form_key'] .'">',
-    '#suffix' => '</div>',
-  );
-  if ($component['mandatory']) {
-    $form_item['#title'] .= '<span class="form-required" title="'. t("This field is required.") .'">*</span>';
-  }
-  
-  $form_item['month'] = array(
-    '#type' => 'select',
-    '#default_value' => $month,
-    '#options' => $months,
-    '#validate' => array('webform_validate_date' => array('month', $component['name'], $component['form_key'], $component['mandatory'])),
-    );
-  $form_item['day'] = array(
-    '#type' => 'select',
-    '#default_value' => $day,
-    '#options' => $days,
-    '#validate' => array('webform_validate_date' => array('day', $component['name'], $component['form_key'], $component['mandatory'])),
-    );
-  $form_item['year'] = array(
-    '#type' => 'textfield',
-    '#default_value' => $year,
-    '#maxlength' => 4,
-    '#size' => 4,
-    '#validate' => array('webform_validate_date' => array('year', $component['name'], $component['form_key'], $component['mandatory'])),
-    );
-    
-  return $form_item;
-}
-
-function webform_validate_date($field, $field_name, $component_name, $component_key, $mandatory) {
-  static $complete_date;
-
-  switch ($field_name) {
-    case 'month':
-      $complete_date['month'] = $field['#value'];
-      break;
-    case 'day':
-      $complete_date['day'] = $field['#value'];
-      break;
-    case 'year':
-      $complete_date['year'] = $field['#value'];
-      break;
-  }
-  
-  // Check if the user filled the required fields
-  if (!is_numeric($field['#value']) && $mandatory) {
-    form_set_error(t("@type %name field required", array('@type' => $component_name, '%name' => $field_name)));
-    return false;
-  }
-  
-  // Check for a valid date
-  if ( (isset($complete_date['month']) &&
-        isset($complete_date['day']) &&
-        isset($complete_date['year'])) &&
-       ($complete_date['month'] !== "" ||
-        $complete_date['day']   !== "" ||
-        $complete_date['year']  !== "")
-     ) { 
-    if (!checkdate((int)$complete_date['month'], (int)$complete_date['day'], (int)$complete_date['year'])) {
-      form_set_error($component_key .']['. $field_name, t("Entered %name is not a valid date.", array('%name' => $component_name)));
-      $complete_date = array();
-      return false;
-    }
-
-    $complete_date = array();
-  }
-}
-
-/** 
- * function _webform_submission_data_date
- * Display the result of a textfield submission. The output of this function will be displayed under the "results" tab then "submissions"
- * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
- * @param $component An array of information describing the component, directly correlating to the webform_component database schema
- * @returns Textual output formatted for human reading.
- **/
-function _webform_submission_display_date($data, $component) {
-  $form_item = _webform_render_date($component);
-  $form_item['month']['#default_value'] = $data['value']['0'];
-  $form_item['day']['#default_value']   = $data['value']['1'];
-  $form_item['year']['#default_value']  = $data['value']['2'];
-  $form_item['month']['#attributes']    = array("disabled" => "disabled");
-  $form_item['day']['#attributes']      = array("disabled" => "disabled");
-  $form_item['year']['#attributes']     = array("disabled" => "disabled");
-  return $form_item;
-}
-
-/**
- * theme_webform_mail_date
- * Format the output of emailed data for this component
- *
- * @param mixed $data A string or array of the submitted data
- * @param array $component An array of information describing the component, directly correlating to the webform_component database schema
- * @returns string Textual output to be included in the email
- */
-function theme_webform_mail_date($data, $component) {
-  $output = $component['name'] .":";
-  if ($data['month'] && $data['day']) {
-    $timestamp = strtotime($data['month'] ."/". $data['day'] ."/". $data['year']);
-    $output .= " ". format_date($timestamp, "custom", 'F j, Y', 0);
-  }
-  return $output;
-}
-
-/** 
- * function _webform_help_date
- * Module specific instance of hook_help
- **/
-function _webform_help_date($section) {
-  switch ($section) {
-    case 'admin/settings/webform#date_description':
-      $output = t("Presents month, day, and year fields.");
-      break;
-  }
-  return $output;
-}
-
-/** 
- * function _webform_analysis_view_date
- * Calculate and returns statistics about results for this component from all submission to this webform. The output of this function will be displayed under the "results" tab then "analysis"
- * @param $component An array of information describing the component, directly correlating to the webform_component database schema
- * @returns An array of data rows, each containing a statistic for this component's submissions.
- **/
-function _webform_analysis_rows_date($component) {  
-  $query = 'SELECT no,data '.
-    ' FROM {webform_submitted_data} '.
-    ' WHERE nid = %d '.
-    ' AND  cid = %d '.
-    ' ORDER BY sid,no ASC ';
-
-  $result = db_query($query, $component['nid'], $component['cid']);
-  // build an array of timestamps from entered values
-  $timestamps = array();
-  $submissions = 1;
-  while ($row = db_fetch_array($result)) {
-    if ($row['no'] == '0') {
-      $submissions++;
-      $month = $row['data'];
-      if ($row = db_fetch_array($result)) {
-        if ($row['no'] == '1') {
-          $day = $row['data'];
-          if ($row = db_fetch_array($result)) {
-            if ($row['no'] == '2') {
-              $year = $row['data'];
-              // Build the full timestamp
-              if (strlen($month) > 0  && strlen($day) > 0  && strlen($year) > 0 ) {
-                $timestamp = strtotime($month ."/". $day ."/". $year);
-                // Add usefull information about this date into an array
-                $timestamps[$timestamp] = array(
-                  date("l", $timestamp), // Day of the week (Monday, Tuesday, etc.)
-                  date("F", $timestamp), // Full Month name (January, February, etc.)
-                  $year, // Year
-                  $day,  // Day of the month (1,2,...,31)
-                );
-              }
-            }
-          }
-        }
-      }
-    }    
-  }
-  
-  // Display stats
-  // TODO: display date statistics in javascript tabs
-  $nonblanks = count($timestamps);
-  $rows[0] = array( t('Left Blank'), ($submissions - $nonblanks));
-  $rows[1] = array( t('User entered value'), $nonblanks);
-  return $rows;
-}
-
-/** 
- * function _webform_table_data_date
- * Return the result of this component's submission for display in a table. The output of this function will be displayed under the "results" tab then "table"
- * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
- * @returns Textual output formatted for human reading.
- **/
-function _webform_table_data_date($data) {
-  if (strlen($data['value']['0']) > 0 && strlen($data['value']['1']) > 0 && strlen($data['value']['2']) > 0) {
-    return check_plain($data['value']['0'] ."/". $data['value']['1'] ."/". $data['value']['2']);
-  }
-  else {
-    return "";
-  }
-}
-
-
-/** 
- * function _webform_csv_headers_date
- * Return the header information for this component to be displayed in a comma seperated value file. The output of this function will be displayed under the "results" tab then "download"
- * @param $component An array of information describing the component, directly correlating to the webform_component database schema
- * @returns An array of data to be displayed in the first three rows of a CSV file, not including either prefixed or trailing commas
- **/
-function _webform_csv_headers_date($component) {
-  $header = array();
-  $header[0] = '';
-  $header[1] = '';
-  $header[2] = $component['name'];
-  return $header;
-}
-
-/** 
- * function _webform_csv_data_date
- * Return the result of a textfield submission. The output of this function will be displayed under the "results" tab then "submissions"
- * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
- * @returns Textual output formatted for CSV, not including either prefixed or trailing commas
- **/
-function _webform_csv_data_date($data) {
-  if (strlen($data['value']['0']) > 0 && strlen($data['value']['1']) > 0 && strlen($data['value']['2']) > 0) {
-    return $data['value']['0'] ."/". $data['value']['1'] ."/". $data['value']['2'];
-  }
-  else {
-    return "";
-  }
-}
+<?php
+// $Id: date.inc,v 1.13.2.8 2007/06/13 00:47:19 quicksketch Exp $
+/** 
+ * function webform_edit_date
+ * Create a set of form items to be displayed on the form for editing this component.
+ * Use care naming the form items, as this correlates directly to the database schema.
+ * The component "Name" and "Description" fields are added to every component type and
+ * are not necessary to specify here (although they may be overridden if desired).
+ * @returns An array of form items to be displayed on the edit component page
+ **/
+function _webform_edit_date($currfield) {
+  $edit_fields = array();
+  $edit_fields['value'] = array(
+    '#type' => 'textfield',
+    '#title' => t("Default value"),
+    '#default_value' => $currfield['default'],
+    '#description' => t('The default value of the field.') .'<br />'. t('Accepts any date in any <a href="http://www.gnu.org/software/tar/manual/html_node/tar_109.html">GNU Date Input Format</a>. Strings such as today, +2 months, and Dec 9 2004 are all valid.') .'<br />'. webform_help('webform/helptext#variables'),
+    '#size' => 60,
+    '#maxlength' => 127,
+    '#weight' => 0,
+  );
+  $edit_fields['extra']['timezone'] = array(
+    '#type' => 'radios',
+    '#title' => t("Timezone"),
+    '#default_value' => empty($currfield['extra']['timezone']) ? "site" : $currfield['extra']['timezone'],
+    '#description' => t('Adjust the date according to a specific timezone. Website timezone is defined in the <a href="%settings">Site Settings</a> and is the default.', array('%settings' => url('admin/settings'))),
+    '#options' => array('site' => 'Website Timezone', 'user' => 'User Timezone', 'gmt' => 'GMT'),
+    '#weight' => 0,
+  );
+  $edit_fields['extra']['check_daylight_savings'] = array(
+    '#type' => 'checkbox',
+    '#title' => t("Observe Daylight Savings"),
+    '#default_value' => $currfield['extra']['check_daylight_savings'],
+    '#checked_value' => 1,
+    '#description' => t('Automatically adjust the time during daylight savings.'),
+    '#weight' => 1,
+  );
+
+  return $edit_fields;
+}
+
+/** 
+ * function webform_render_date
+ * Build a form item array containing all the properties of this component
+ * @param $component An array of information describing the component, directly correlating to the webform_component database schema
+ * @returns An array of a form item to be displayed on the client-side webform
+ **/
+function _webform_render_date($component) {
+  if (strlen($component['value']) > 0) {
+    // Calculate the timestamp in GMT
+    $timestamp = strtotime(_webform_filtervalues($component['value']));
+    
+    if ($component['extra']['timezone'] == "user") {
+      // Use the users timezone
+      global $user;
+      $timestamp += (int)$user->timezone;
+    }
+    elseif ($component['extra']['timezone'] == "gmt") {
+      // Use GMT
+      $timestamp += 0;
+    }
+    else {
+      // Use the Drupal site time
+      $timestamp += variable_get('date_default_timezone', 0);
+    }
+    
+    // Check for daylight savings time
+    if ($component['extra']['check_daylight_savings'] && date("I")) {
+      $timestamp += 3600;
+    }
+    
+    $year = gmdate('Y', $timestamp);
+    $month = gmdate('n', $timestamp);
+    $day = gmdate('j', $timestamp);
+  }
+  $months = array("" => t("month"), 1 => t('January'), t('February'), t('March'), t('April'), t('May'), t('June'), t('July'), t('August'), t('September'), t('October'), t('November'), t('December'));
+  $days = array("" => t("day"));
+  for ($i = 1; $i <= 31; $i++) $days[$i] = $i;
+  
+  $form_item = array(
+    '#type' => 'fieldset',
+    '#title' => htmlspecialchars($component['name'], ENT_QUOTES),
+    '#weight' => $component['weight'],
+    '#description' => _webform_filtervalues($component['extra']['description']),
+    '#prefix' => '<div class="webform-component-'. $component['type'] .' container-inline" id="webform-component-'. $component['form_key'] .'">',
+    '#suffix' => '</div>',
+  );
+  if ($component['mandatory']) {
+    $form_item['#title'] .= '<span class="form-required" title="'. t("This field is required.") .'">*</span>';
+  }
+  
+  $form_item['month'] = array(
+    '#type' => 'select',
+    '#default_value' => $month,
+    '#options' => $months,
+    '#validate' => array('webform_validate_date' => array('month', $component['name'], $component['form_key'], $component['mandatory'])),
+    );
+  $form_item['day'] = array(
+    '#type' => 'select',
+    '#default_value' => $day,
+    '#options' => $days,
+    '#validate' => array('webform_validate_date' => array('day', $component['name'], $component['form_key'], $component['mandatory'])),
+    );
+  $form_item['year'] = array(
+    '#type' => 'textfield',
+    '#default_value' => $year,
+    '#maxlength' => 4,
+    '#size' => 4,
+    '#validate' => array('webform_validate_date' => array('year', $component['name'], $component['form_key'], $component['mandatory'])),
+    );
+    
+  return $form_item;
+}
+
+function webform_validate_date($field, $field_name, $component_name, $component_key, $mandatory) {
+  static $complete_date;
+
+  switch ($field_name) {
+    case 'month':
+      $complete_date['month'] = $field['#value'];
+      break;
+    case 'day':
+      $complete_date['day'] = $field['#value'];
+      break;
+    case 'year':
+      $complete_date['year'] = $field['#value'];
+      break;
+  }
+  
+  // Check if the user filled the required fields
+  if (!is_numeric($field['#value']) && $mandatory) {
+    form_set_error(t("@type %name field required", array('@type' => $component_name, '%name' => $field_name)));
+    return false;
+  }
+  
+  // Check for a valid date
+  if ( (isset($complete_date['month']) &&
+        isset($complete_date['day']) &&
+        isset($complete_date['year'])) &&
+       ($complete_date['month'] !== "" ||
+        $complete_date['day']   !== "" ||
+        $complete_date['year']  !== "")
+     ) { 
+    if (!checkdate((int)$complete_date['month'], (int)$complete_date['day'], (int)$complete_date['year'])) {
+      form_set_error($component_key .']['. $field_name, t("Entered %name is not a valid date.", array('%name' => $component_name)));
+      $complete_date = array();
+      return false;
+    }
+
+    $complete_date = array();
+  }
+}
+
+/** 
+ * function _webform_submission_data_date
+ * Display the result of a textfield submission. The output of this function will be displayed under the "results" tab then "submissions"
+ * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
+ * @param $component An array of information describing the component, directly correlating to the webform_component database schema
+ * @returns Textual output formatted for human reading.
+ **/
+function _webform_submission_display_date($data, $component, $enabled) {
+  $form_item = _webform_render_date($component);
+  $form_item['month']['#default_value'] = $data['value']['0'];
+  $form_item['day']['#default_value']   = $data['value']['1'];
+  $form_item['year']['#default_value']  = $data['value']['2'];
+  $form_item['month']['#disabled'] = !$enabled;
+  $form_item['day']['#disabled'] = !$enabled;
+  $form_item['year']['#disabled'] = !$enabled;
+  return $form_item;
+}
+
+/**
+ * theme_webform_mail_date
+ * Format the output of emailed data for this component
+ *
+ * @param mixed $data A string or array of the submitted data
+ * @param array $component An array of information describing the component, directly correlating to the webform_component database schema
+ * @returns string Textual output to be included in the email
+ */
+function theme_webform_mail_date($data, $component) {
+  $output = $component['name'] .":";
+  if ($data['month'] && $data['day']) {
+    $timestamp = strtotime($data['month'] ."/". $data['day'] ."/". $data['year']);
+    $output .= " ". format_date($timestamp, "custom", 'F j, Y', 0);
+  }
+  return $output;
+}
+
+/** 
+ * function _webform_help_date
+ * Module specific instance of hook_help
+ **/
+function _webform_help_date($section) {
+  switch ($section) {
+    case 'admin/settings/webform#date_description':
+      $output = t("Presents month, day, and year fields.");
+      break;
+  }
+  return $output;
+}
+
+/** 
+ * function _webform_analysis_view_date
+ * Calculate and returns statistics about results for this component from all submission to this webform. The output of this function will be displayed under the "results" tab then "analysis"
+ * @param $component An array of information describing the component, directly correlating to the webform_component database schema
+ * @returns An array of data rows, each containing a statistic for this component's submissions.
+ **/
+function _webform_analysis_rows_date($component) {  
+  $query = 'SELECT no,data '.
+    ' FROM {webform_submitted_data} '.
+    ' WHERE nid = %d '.
+    ' AND  cid = %d '.
+    ' ORDER BY sid,no ASC ';
+
+  $result = db_query($query, $component['nid'], $component['cid']);
+  // build an array of timestamps from entered values
+  $timestamps = array();
+  $submissions = 1;
+  while ($row = db_fetch_array($result)) {
+    if ($row['no'] == '0') {
+      $submissions++;
+      $month = $row['data'];
+      if ($row = db_fetch_array($result)) {
+        if ($row['no'] == '1') {
+          $day = $row['data'];
+          if ($row = db_fetch_array($result)) {
+            if ($row['no'] == '2') {
+              $year = $row['data'];
+              // Build the full timestamp
+              if (strlen($month) > 0  && strlen($day) > 0  && strlen($year) > 0 ) {
+                $timestamp = strtotime($month ."/". $day ."/". $year);
+                // Add usefull information about this date into an array
+                $timestamps[$timestamp] = array(
+                  date("l", $timestamp), // Day of the week (Monday, Tuesday, etc.)
+                  date("F", $timestamp), // Full Month name (January, February, etc.)
+                  $year, // Year
+                  $day,  // Day of the month (1,2,...,31)
+                );
+              }
+            }
+          }
+        }
+      }
+    }    
+  }
+  
+  // Display stats
+  // TODO: display date statistics in javascript tabs
+  $nonblanks = count($timestamps);
+  $rows[0] = array( t('Left Blank'), ($submissions - $nonblanks));
+  $rows[1] = array( t('User entered value'), $nonblanks);
+  return $rows;
+}
+
+/** 
+ * function _webform_table_data_date
+ * Return the result of this component's submission for display in a table. The output of this function will be displayed under the "results" tab then "table"
+ * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
+ * @returns Textual output formatted for human reading.
+ **/
+function _webform_table_data_date($data) {
+  if (strlen($data['value']['0']) > 0 && strlen($data['value']['1']) > 0 && strlen($data['value']['2']) > 0) {
+    return check_plain($data['value']['0'] ."/". $data['value']['1'] ."/". $data['value']['2']);
+  }
+  else {
+    return "";
+  }
+}
+
+
+/** 
+ * function _webform_csv_headers_date
+ * Return the header information for this component to be displayed in a comma seperated value file. The output of this function will be displayed under the "results" tab then "download"
+ * @param $component An array of information describing the component, directly correlating to the webform_component database schema
+ * @returns An array of data to be displayed in the first three rows of a CSV file, not including either prefixed or trailing commas
+ **/
+function _webform_csv_headers_date($component) {
+  $header = array();
+  $header[0] = '';
+  $header[1] = '';
+  $header[2] = $component['name'];
+  return $header;
+}
+
+/** 
+ * function _webform_csv_data_date
+ * Return the result of a textfield submission. The output of this function will be displayed under the "results" tab then "submissions"
+ * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
+ * @returns Textual output formatted for CSV, not including either prefixed or trailing commas
+ **/
+function _webform_csv_data_date($data) {
+  if (strlen($data['value']['0']) > 0 && strlen($data['value']['1']) > 0 && strlen($data['value']['2']) > 0) {
+    return $data['value']['1'] ."/". $data['value']['0'] ."/". $data['value']['2'];
+  }
+  else {
+    return "";
+  }
+}
--- components/email.inc	Wed Jun 13 04:27:38 2007
+++ components/email.inc	Wed Jun 20 22:31:59 2007
@@ -1,182 +1,182 @@
-<?php
-// $Id: email.inc,v 1.16.2.4 2007/06/13 02:27:37 quicksketch Exp $
-/** 
- * function webform_edit_email
- * Create a set of form items to be displayed on the form for editing this component.
- * Use care naming the form items, as this correlates directly to the database schema.
- * The component "Name" and "Description" fields are added to every component type and
- * are not necessary to specify here (although they may be overridden if desired).
- * @returns An array of form items to be displayed on the edit component page
- **/
-function _webform_edit_email($currfield) {
-  $edit_fields = array();
-  $edit_fields['extra']['width'] = array(
-    '#type' => 'textfield',
-    '#title' => t("Width"),
-    '#default_value' => $currfield['extra']['width'],
-    '#description' => t('Width of the textfield.'),
-    '#size' => 5,
-    '#maxlength' => 10,
-  );
-  $edit_fields['value'] = array(
-    '#type' => 'checkbox',
-    '#title' => t("User email as default"),
-    '#default_value' => $currfield['default'],
-    '#return_value' => 'user email',
-    '#description' => t('Set the default value of this field to the user email, if he/she is logged in.'),
-  );
-  $edit_fields['extra']['carboncopy'] = array(
-    '#type' => 'checkbox',
-    '#title' => t("CC submission to this email"),
-    '#return_value' => 'Y',
-    '#default_value' => ($currfield['extra']['carboncopy']=='Y'?TRUE:FALSE),
-    '#description' => t('Check this option if the email specified in this component should get a CC submission.') .' '.
-                      t('Note that this opens the risk that the form can be used to send emails to any address and might be missused as a spam gateway.'),
-  );
-  $edit_fields['extra']['attributes']['disabled'] = array(
-    '#type' => 'checkbox',
-    '#title' => t("Disabled"),
-    '#return_value' => 'disabled',
-    '#description' => t('Make this field non-editable. Useful for setting an unchangeable default value.'),
-    '#weight' => 3,
-    '#default_value' => $currfield['extra']['attributes']['disabled'],
-  );
-  return $edit_fields;
-}
-
-/** 
- * function webform_render_email
- * Build a form item array containing all the properties of this component
- * @param $component An array of information describing the component, directly correlating to the webform_component database schema
- * @returns An array of a form item to be displayed on the client-side webform
- **/
-function _webform_render_email($component) {
-  global $user;
-  $form_item = array(
-    '#type'          => 'textfield',
-    '#title'         => htmlspecialchars($component['name'], ENT_QUOTES),
-    '#required'      => $component['mandatory'],
-    '#weight'        => $component['weight'],
-    '#description'   => _webform_filtervalues($component['extra']['description']),
-    '#attributes'    => $component['extra']['attributes'],
-    '#prefix'        => '<div class="webform-component-'. $component['type'] .'" id="webform-component-'. $component['form_key'] .'">',
-    '#suffix'        => '</div>',
-    '#validate'      => array('_webform_validate_email' => array('submitted]['. $component['cid'])),
-  );
-  
-  // Fill in the user's email address if available
-  if ($user->uid && $user->mail && $component['value'] == 'user email') {
-    $form_item['#default_value'] = $user->mail;
-  }
-  
-  // Change the 'width' option to the correct 'size' option
-  if ($component['extra']['width'] > 0) {
-    $form_item['#size'] = $component['extra']['width'];
-  }
-    
-  return $form_item;
-}
-
-/** 
- * function webform_validate_email
- * A Drupal Forms API Validation function. Validates the entered values from email components on the client-side form.
- * @param $formelement An array of information describing the component, directly correlating to the webform_component database schema
- * @returns True if successful, calls a form_set_error on the field if the email is not valid.
- **/
-function _webform_validate_email($formelement, $name) {
-  if (!empty($formelement['#value']) && !valid_email_address($formelement['#value'])) {
-    form_set_error($name, t("'%value' is not a valid email address", array('%value' => $formelement['#value'])));
-  }
-}
-
-/** 
- * function _webform_submission_data_email
- * Display the result of a textfield submission. The output of this function will be displayed under the "results" tab then "submissions"
- * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
- * @param $component An array of information describing the component, directly correlating to the webform_component database schema
- * @returns Textual output formatted for human reading.
- **/
-function _webform_submission_display_email($data, $component) {
-  $form_item = _webform_render_email($component);
-  $form_item['#default_value'] = $data['value']['0'];
-  $form_item['#attributes']    = array("disabled" => "disabled");
-  return $form_item;
-}
-
-/** 
- * function _webform_help_email
- * Module specific instance of hook_help
- **/
-function _webform_help_email($section) {
-  switch ($section) {
-    case 'admin/settings/webform#email_description':
-      $output = t("A textfield that automatically fills in logged-in users e-mail.");
-      break;
-  }
-  return $output;
-}
-
-/** 
- * function _webform_analysis_view_email
- * Calculate and returns statistics about results for this component from all submission to this webform. The output of this function will be displayed under the "results" tab then "analysis"
- * @param $component An array of information describing the component, directly correlating to the webform_component database schema
- * @returns An array of data rows, each containing a statistic for this component's submissions.
- **/
-function _webform_analysis_rows_email($component) {  
-  $query = 'SELECT data '.
-    ' FROM {webform_submitted_data} '.
-    ' WHERE nid = %d '.
-    ' AND cid = %d';
-  $nonblanks = 0;
-  $submissions = 0;
-  $wordcount = 0;
-
-  $result = db_query($query, $component['nid'], $component['cid']);
-  while ($data = db_fetch_array($result)) {
-    if ( strlen(trim($data['data'])) > 0 ) {
-      $nonblanks++;
-      $wordcount += str_word_count(trim($data['data']));
-    }
-    $submissions++;
-  }
-  
-  $rows[0] = array(t('Left Blank'), ($submissions - $nonblanks));
-  $rows[1] = array(t('User entered value'), $nonblanks);
-  $rows[2] = array(t('Average submission length in words (ex blanks)'), ($nonblanks !=0 ? number_format($wordcount/$nonblanks, 2) : '0'));
-  return $rows;
-}
-
-/** 
- * function _webform_table_data_email
- * Return the result of this component's submission for display in a table. The output of this function will be displayed under the "results" tab then "table"
- * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
- * @returns Textual output formatted for human reading.
- **/
-function _webform_table_data_email($data) {
-  return check_plain(empty($data['value']['0']) ? "" : $data['value']['0']);
-}
-
-
-/** 
- * function _webform_csv_headers_email
- * Return the header information for this component to be displayed in a comma seperated value file. The output of this function will be displayed under the "results" tab then "download"
- * @param $component An array of information describing the component, directly correlating to the webform_component database schema
- * @returns An array of data to be displayed in the first three rows of a CSV file, not including either prefixed or trailing commas
- **/
-function _webform_csv_headers_email($component) {
-  $header = array();
-  $header[0] = '';
-  $header[1] = '';
-  $header[2] = $component['name'];
-  return $header;
-}
-
-/** 
- * function _webform_csv_data_email
- * Return the result of a textfield submission. The output of this function will be displayed under the "results" tab then "submissions"
- * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
- * @returns Textual output formatted for CSV, not including either prefixed or trailing commas
- **/
-function _webform_csv_data_email($data) {
-  return empty($data['value']['0']) ? "" : $data['value']['0'];
-}
+<?php
+// $Id: email.inc,v 1.16.2.4 2007/06/13 02:27:37 quicksketch Exp $
+/** 
+ * function webform_edit_email
+ * Create a set of form items to be displayed on the form for editing this component.
+ * Use care naming the form items, as this correlates directly to the database schema.
+ * The component "Name" and "Description" fields are added to every component type and
+ * are not necessary to specify here (although they may be overridden if desired).
+ * @returns An array of form items to be displayed on the edit component page
+ **/
+function _webform_edit_email($currfield) {
+  $edit_fields = array();
+  $edit_fields['extra']['width'] = array(
+    '#type' => 'textfield',
+    '#title' => t("Width"),
+    '#default_value' => $currfield['extra']['width'],
+    '#description' => t('Width of the textfield.'),
+    '#size' => 5,
+    '#maxlength' => 10,
+  );
+  $edit_fields['value'] = array(
+    '#type' => 'checkbox',
+    '#title' => t("User email as default"),
+    '#default_value' => $currfield['default'],
+    '#return_value' => 'user email',
+    '#description' => t('Set the default value of this field to the user email, if he/she is logged in.'),
+  );
+  $edit_fields['extra']['carboncopy'] = array(
+    '#type' => 'checkbox',
+    '#title' => t("CC submission to this email"),
+    '#return_value' => 'Y',
+    '#default_value' => ($currfield['extra']['carboncopy']=='Y'?TRUE:FALSE),
+    '#description' => t('Check this option if the email specified in this component should get a CC submission.') .' '.
+                      t('Note that this opens the risk that the form can be used to send emails to any address and might be missused as a spam gateway.'),
+  );
+  $edit_fields['extra']['attributes']['disabled'] = array(
+    '#type' => 'checkbox',
+    '#title' => t("Disabled"),
+    '#return_value' => 'disabled',
+    '#description' => t('Make this field non-editable. Useful for setting an unchangeable default value.'),
+    '#weight' => 3,
+    '#default_value' => $currfield['extra']['attributes']['disabled'],
+  );
+  return $edit_fields;
+}
+
+/** 
+ * function webform_render_email
+ * Build a form item array containing all the properties of this component
+ * @param $component An array of information describing the component, directly correlating to the webform_component database schema
+ * @returns An array of a form item to be displayed on the client-side webform
+ **/
+function _webform_render_email($component) {
+  global $user;
+  $form_item = array(
+    '#type'          => 'textfield',
+    '#title'         => htmlspecialchars($component['name'], ENT_QUOTES),
+    '#required'      => $component['mandatory'],
+    '#weight'        => $component['weight'],
+    '#description'   => _webform_filtervalues($component['extra']['description']),
+    '#attributes'    => $component['extra']['attributes'],
+    '#prefix'        => '<div class="webform-component-'. $component['type'] .'" id="webform-component-'. $component['form_key'] .'">',
+    '#suffix'        => '</div>',
+    '#validate'      => array('_webform_validate_email' => array('submitted]['. $component['cid'])),
+  );
+  
+  // Fill in the user's email address if available
+  if ($user->uid && $user->mail && $component['value'] == 'user email') {
+    $form_item['#default_value'] = $user->mail;
+  }
+  
+  // Change the 'width' option to the correct 'size' option
+  if ($component['extra']['width'] > 0) {
+    $form_item['#size'] = $component['extra']['width'];
+  }
+    
+  return $form_item;
+}
+
+/** 
+ * function webform_validate_email
+ * A Drupal Forms API Validation function. Validates the entered values from email components on the client-side form.
+ * @param $formelement An array of information describing the component, directly correlating to the webform_component database schema
+ * @returns True if successful, calls a form_set_error on the field if the email is not valid.
+ **/
+function _webform_validate_email($formelement, $name) {
+  if (!empty($formelement['#value']) && !valid_email_address($formelement['#value'])) {
+    form_set_error($name, t("'%value' is not a valid email address", array('%value' => $formelement['#value'])));
+  }
+}
+
+/** 
+ * function _webform_submission_data_email
+ * Display the result of a textfield submission. The output of this function will be displayed under the "results" tab then "submissions"
+ * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
+ * @param $component An array of information describing the component, directly correlating to the webform_component database schema
+ * @returns Textual output formatted for human reading.
+ **/
+function _webform_submission_display_email($data, $component, $enabled) {
+  $form_item = _webform_render_email($component);
+  $form_item['#default_value'] = $data['value']['0'];
+  $form_item['#disabled'] = !$enabled;
+  return $form_item;
+}
+
+/** 
+ * function _webform_help_email
+ * Module specific instance of hook_help
+ **/
+function _webform_help_email($section) {
+  switch ($section) {
+    case 'admin/settings/webform#email_description':
+      $output = t("A textfield that automatically fills in logged-in users e-mail.");
+      break;
+  }
+  return $output;
+}
+
+/** 
+ * function _webform_analysis_view_email
+ * Calculate and returns statistics about results for this component from all submission to this webform. The output of this function will be displayed under the "results" tab then "analysis"
+ * @param $component An array of information describing the component, directly correlating to the webform_component database schema
+ * @returns An array of data rows, each containing a statistic for this component's submissions.
+ **/
+function _webform_analysis_rows_email($component) {  
+  $query = 'SELECT data '.
+    ' FROM {webform_submitted_data} '.
+    ' WHERE nid = %d '.
+    ' AND cid = %d';
+  $nonblanks = 0;
+  $submissions = 0;
+  $wordcount = 0;
+
+  $result = db_query($query, $component['nid'], $component['cid']);
+  while ($data = db_fetch_array($result)) {
+    if ( strlen(trim($data['data'])) > 0 ) {
+      $nonblanks++;
+      $wordcount += str_word_count(trim($data['data']));
+    }
+    $submissions++;
+  }
+  
+  $rows[0] = array(t('Left Blank'), ($submissions - $nonblanks));
+  $rows[1] = array(t('User entered value'), $nonblanks);
+  $rows[2] = array(t('Average submission length in words (ex blanks)'), ($nonblanks !=0 ? number_format($wordcount/$nonblanks, 2) : '0'));
+  return $rows;
+}
+
+/** 
+ * function _webform_table_data_email
+ * Return the result of this component's submission for display in a table. The output of this function will be displayed under the "results" tab then "table"
+ * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
+ * @returns Textual output formatted for human reading.
+ **/
+function _webform_table_data_email($data) {
+  return check_plain(empty($data['value']['0']) ? "" : $data['value']['0']);
+}
+
+
+/** 
+ * function _webform_csv_headers_email
+ * Return the header information for this component to be displayed in a comma seperated value file. The output of this function will be displayed under the "results" tab then "download"
+ * @param $component An array of information describing the component, directly correlating to the webform_component database schema
+ * @returns An array of data to be displayed in the first three rows of a CSV file, not including either prefixed or trailing commas
+ **/
+function _webform_csv_headers_email($component) {
+  $header = array();
+  $header[0] = '';
+  $header[1] = '';
+  $header[2] = $component['name'];
+  return $header;
+}
+
+/** 
+ * function _webform_csv_data_email
+ * Return the result of a textfield submission. The output of this function will be displayed under the "results" tab then "submissions"
+ * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
+ * @returns Textual output formatted for CSV, not including either prefixed or trailing commas
+ **/
+function _webform_csv_data_email($data) {
+  return empty($data['value']['0']) ? "" : $data['value']['0'];
+}
--- components/file.inc	Wed Jun 13 01:58:36 2007
+++ components/file.inc	Wed Jun 20 22:31:59 2007
@@ -1,382 +1,382 @@
-<?php
-// $Id: file.inc,v 1.2.2.8 2007/06/12 23:58:35 quicksketch Exp $
-/** 
- * function webform_edit_file
- * Create a set of form items to be displayed on the form for editing this component.
- * Use care naming the form items, as this correlates directly to the database schema.
- * The component "Name" and "Description" fields are added to every component type and
- * are not necessary to specify here (although they may be overridden if desired).
- * @returns An array of form items to be displayed on the edit component page
- **/
-function _webform_edit_file($currfield) {
-    $edit_fields = array();
-    $edit_fields['#theme'] = 'webform_edit_file';
-    $edit_fields['extra']['filtering'] = array(
-      '#type' => 'fieldset',
-      '#collapsible' => true,
-      '#collapsed' => false,
-      '#title' => t('Upload Filtering'),
-      '#description' => t('Select the types of uploads you would like to allow.'),
-    );
-    $edit_fields['extra']['filtering']['types']['webimages'] = array(
-      '#type' => 'checkboxes',
-      '#title' => t('Web Images'),
-      '#options' => drupal_map_assoc(array('gif', 'jpg', 'png')),
-      '#default_value' => isset($currfield['extra']['filtering']['types']) ? $currfield['extra']['filtering']['types']['webimages'] : array('jpg', 'gif', 'png'),
-    );
-    $edit_fields['extra']['filtering']['types']['desktopimages'] = array(
-      '#type' => 'checkboxes',
-      '#title' => t('Desktop Images'),
-      '#options' => drupal_map_assoc(array('bmp', 'eps', 'tif', 'pict', 'psd')),
-      '#default_value' => $currfield['extra']['filtering']['types']['desktopimages'],
-    );
-    $edit_fields['extra']['filtering']['types']['documents'] = array(
-      '#type' => 'checkboxes',
-      '#title' => t('Documents'),
-      '#options' => drupal_map_assoc(array('doc', 'html', 'odf', 'pdf', 'ppt', 'xls', 'xml')),
-      '#default_value' => $currfield['extra']['filtering']['types']['documents'],
-    );
-    $edit_fields['extra']['filtering']['types']['media'] = array(
-      '#type' => 'checkboxes',
-      '#title' => t('Media'),
-      '#options' => drupal_map_assoc(array('avi', 'mov', 'mp3', 'ogg', 'wav')),
-      '#default_value' => $currfield['extra']['filtering']['types']['media'],
-    );
-    $edit_fields['extra']['filtering']['types']['archives'] = array(
-      '#type' => 'checkboxes',
-      '#title' => t('Archives'),
-      '#options' => drupal_map_assoc(array('bz2', 'dmg', 'gz', 'jar', 'rar', 'sit', 'tar', 'zip')),
-      '#default_value' => $currfield['extra']['filtering']['types']['archives'],
-    );
-    $edit_fields['extra']['filtering']['addextensions'] = array(
-      '#type' => 'textfield',
-      '#title' => t("Additional Extensions"),
-      '#default_value' => $currfield['extra']['filtering']['addextensions'],
-      '#description' => t('Enter a list of additional file extensions for this upload field, seperated by commas.<br /> Entered extensions will be appended to checked items above.'),
-      '#size' => 60,
-      '#weight' => 3,
-      '#default_value' => $currfield['extra']['filtering']['addextensions'],
-    );
-    $edit_fields['extra']['filtering']['size'] = array(
-      '#type' => 'textfield',
-      '#title' => t("Max Upload Size"),
-      '#default_value' => $currfield['extra']['filtering']['size'],
-      '#description' => t('Enter the max file size a user may upload (in KB).'),
-      '#size' => 10,
-      '#weight' => 3,
-      '#default_value' => strlen($currfield['extra']['filtering']['size']) == 0 ? 800 : $currfield['extra']['filtering']['size'],
-    );
-    $edit_fields['extra']['savelocation'] = array(
-      '#type' => 'textfield',
-      '#title' => t("Upload Directory"),
-      '#default_value' => $currfield['extra']['savelocation'],
-      '#description' => "<div style='display: block'>". t('Webform uploads are always saved in the site files directory. You may optionally specify a subfolder to store your files.') ."</div>",
-      '#weight' => 3,
-      '#validate' => array('_webform_edit_file_check_directory'), // TODO: Get this validation working
-      '#after_build' => array('_webform_edit_file_check_directory'),
-    );
-    return $edit_fields;
-}
-
-function _webform_edit_file_check_directory($form_element) {
-  $destination_dir = variable_get('file_directory_path', 'files') ."/webform/". $form_element['#value'];
-  file_check_directory($destination_dir, FILE_CREATE_DIRECTORY, 'savelocation');
-  return $form_element;
-}
-
-function theme_webform_edit_file($form) {
-  // Add a little javascript to check all the items in one type
-  $javascript = '
-    <script type="text/javascript">
-      function check_category_boxes () {
-        var checkValue = !document.getElementById("edit-field-extra-filtering-types-"+arguments[0]+"-"+arguments[1]).checked;
-        for(var i=1; i < arguments.length; i++) {
-          document.getElementById("edit-field-extra-filtering-types-"+arguments[0]+"-"+arguments[i]).checked = checkValue;
-        }
-      }
-  </script>
- ';
-  drupal_set_html_head($javascript);
-  
-  // Format the components into a table
-  $per_row = 4;
-  $rows = array();
-  foreach (element_children($form['extra']['filtering']['types']) as $key => $filtergroup) {
-    $row = array();
-    $first_row = count($rows);
-    if ($form['extra']['filtering']['types'][$filtergroup]['#type'] == 'checkboxes') {
-      // Add the title
-      $row[] = $form['extra']['filtering']['types'][$filtergroup]['#title'];
-      $row[] = "&nbsp;";
-      // Convert the checkboxes into individual form-items
-      $checkboxes = expand_checkboxes($form['extra']['filtering']['types'][$filtergroup]);
-      // Render the checkboxes in two rows
-      $checkcount = 0;
-      $jsboxes = "";
-      foreach ($checkboxes as $key => $checkbox) {
-        if ($checkbox['#type'] == 'checkbox') {
-          $checkcount++;
-          $jsboxes .= "'". $checkbox['#return_value'] ."',";
-          if ($checkcount <= $per_row) {
-            $row[] = array('data' => drupal_render($checkbox));
-          }
-          elseif ($checkcount == $per_row+1) {
-            $rows[] = array('data' => $row, 'style' => 'border-bottom: none;');
-            $row = array(array('data' => '&nbsp;'), array('data' => '&nbsp;'));
-            $row[] = array('data' => drupal_render($checkbox));
-          }
-          else {
-            $row[] = array('data' => drupal_render($checkbox));
-          }
-        }
-      }
-      // Pretty up the table a little bit
-      $current_cell   = $checkcount % $per_row;
-      if ($current_cell   > 0) {
-        $colspan = $per_row - $current_cell   + 1;
-        $row[$current_cell  +1]['colspan'] = $colspan;
-      }
-      // Add the javascript links
-      $jsboxes = substr($jsboxes, 0, strlen($jsboxes) - 1);
-      $rows[] = array('data' => $row);
-      $select_link = ' <a href="javascript:check_category_boxes(\''. $filtergroup .'\','. $jsboxes .')">(select)</a>';
-      $rows[$first_row]['data'][1] = array('data' => $select_link, 'width' => 40);
-      unset($form['extra']['filtering']['types'][$filtergroup]);
-    }
-    elseif ($filtergroup != 'size') {
-      // Add other fields to the table (ie. additional extensions)
-      $row[] = $form['extra']['filtering']['types'][$filtergroup]['#title'];
-      unset($form['extra']['filtering']['types'][$filtergroup]['#title']);
-      $row[] = array(
-        'data' => drupal_render($form['extra']['filtering']['types'][$filtergroup]),
-        'colspan' => $per_row+1,
-      );
-      unset($form['extra']['filtering']['types'][$filtergroup]);
-      $rows[] = array('data' => $row);
-    }
-  }
-  $header = array(array('data' => t('Category'), 'colspan' => '2'), array('data' => t('Types'), 'colspan' => $per_row));
-  //unset($form['extra']['filtering']['types']);
-  
-  // Create the table inside the form
-  $form['extra']['filtering']['types']['table'] = array(
-    '#value' => theme('table', $header, $rows)
-  );
-  
-  $output = drupal_render($form);
-  
-  // Prefix the upload location field with the default path for webform
-  $output = str_replace("Upload Directory: </label>", "Upload Directory: </label>". variable_get('file_directory_path', 'files') ."/webform/", $output);
-  
-  return $output;
-}
-
-/** 
- * function webform_render_file
- * Build a form item array containing all the properties of this component
- * @param $component An array of information describing the component, directly correlating to the webform_component database schema
- * @returns An array of a form item to be displayed on the client-side webform
- **/
-function _webform_render_file($component) {
-  $form_item = array(
-    '#type'          => $component['type'],
-    '#title'         => htmlspecialchars($component['name'], ENT_QUOTES),
-    //'#required'      => $component['mandatory'], // Drupal core bug with required file uploads
-    '#weight'        => $component['weight'],
-    '#description'   => _webform_filtervalues($component['extra']['description']),
-    '#attributes'    => $component['extra']['attributes'],
-  '#tree'          => false, // file_check_upload assumes a flat $_FILES structure
-  '#validate'      => array(
-                        '_webform_validate_file' => array($component['cid'], $component['name'], $component['extra']['filtering']),
-                        '_webform_required_file' => array($component['cid'], $component['name'], $component['mandatory']), // Custom required routine
-                      ),
-  '#prefix'        => '<div class="webform-component-'. $component['type'] .'" id="webform-component-'. $component['form_key'] .'">',
-  '#suffix'        => '</div>',
-  );
-  
-  return $form_item;
-}
-
-function _webform_required_file($formelement, $cid, $fieldname, $required = false) {
-  if (empty($_FILES['files']['name'][$cid]) && $required) {
-    form_set_error($fieldname, t('%fieldname field is required.', array('%fieldname' => $fieldname)));
-  }
-}
-
-function _webform_validate_file($formelement, $cid, $fieldname, $filters) {
-  if (empty($_FILES['files']['name'][$cid])) {
-    return;
-  }
-  
-  // Build a list of extensions
-  foreach ($filters['types'] as $filtertype) {
-    foreach ($filtertype as $extension) {
-      $extensions[] = $extension;
-    }
-  }
-  $extras = str_replace(" ", "", $filters['addextensions']);
-  if (!empty($extras)) {
-    $extensions = array_merge($extensions, explode(",", $extras));
-  }
-  
-  // Build a human readable list of extensions:
-  if (count($extensions) > 1) {
-    for ($n=0; $n < count($extensions) - 1; $n++) {
-      $extension_list .= $extensions[$n] .", ";
-    }
-    $extension_list .= "or ". $extensions[count($extensions)-1];
-  }
-  else {
-    $extension_list = $extensions[0];
-  }
-
-  $dot = strrpos($_FILES['files']['name'][$cid], '.');
-  $extension = strtolower(substr($_FILES['files']['name'][$cid], $dot+1));
-  if (!in_array($extension, $extensions)) {
-    form_set_error($cid, t("Files with the '%ext' extension are not allowed, please upload a file with a %exts extension.", array('%ext' => $extension, '%exts' => $extension_list)));
-  }
-  
-  // Now let's check the file size (limit is set in KB)
-  if ($_FILES['files']['size'][$cid] > $filters['size']*1024) {
-    form_set_error($cid, t("The file '%filename' is too large (%filesize KB). Please upload a file %maxsize KB or smaller.", array('%filename' => $_FILES['files']['name'][$cid], '%filesize' => (int)($_FILES['files']['size'][$cid]/1024), '%maxsize' => $filters['size'])));
-  }
-}
-
-/** 
- * function webform_submit_file
- * Perform additional server-side processing on the submitted data, such as managing an uploaded file
- * @param $data The POST data associated with the component
- * @param $component An array of information describing the component, directly correlating to the webform_component database schema
- * @returns Nothing
- **/
-function _webform_submit_file(&$data, $component) {
-  if ($file = file_check_upload($component['cid'])) {
-    $upload_dir = variable_get('file_directory_path', 'files') ."/webform/". $component['extra']['savelocation'];
-    if (file_check_directory($upload_dir, FILE_CREATE_DIRECTORY)) {
-      $file_saved = file_save_upload($component['cid'], variable_get('file_directory_path', 'files') ."/webform/". $component['extra']['savelocation']);
-      if (!$file_saved) {
-        drupal_set_message(t("The uploaded file %filename was unable to be saved. The destination directory may not be writable.", array('%filename' => $data)), "error");
-        $data = serialize(array('error' => 'Error while uploading file'));
-      }
-      else {
-        $data = serialize((array)$file_saved);
-      }
-    }
-    else {
-      drupal_set_message(t("The uploaded file %filename was unable to be saved. The destination directory does not exist.", array('%filename' => $data), "error"));
-    }
-  }
-}
-
-
-/**
- * theme_webform_mail_file
- * Format the output of emailed data for this component
- *
- * @param mixed $data A string or array of the submitted data
- * @param array $component An array of information describing the component, directly correlating to the webform_component database schema
- * @returns string Textual output to be included in the email
- */
-function theme_webform_mail_file($data, $component) {
-  $file = unserialize($data);
-  $output = $component['name'] .": ". file_create_url($file['filepath']) ."\n";
-  return $output;
-}
-
-/** 
- * function _webform_submission_display_file
- * Display the result of a file submission. The output of this function will be displayed under the "results" tab then "submissions"
- * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
- * @param $component An array of information describing the component, directly correlating to the webform_component database schema
- * @returns Textual output formatted for human reading.
- **/
-function _webform_submission_display_file($data, $component) {
-  $filedata = unserialize($data['value'][0]);
-  $form_item = _webform_render_file($component);
-  $form_item['#type'] = 'textfield';
-  $form_item['#default_value'] = empty($filedata['filepath']) ? $filedata['error'] : $filedata['filepath'];
-  if ($filedata['filename']) {
-    $form_item['#suffix'] = ' <a href="'. base_path() . $filedata['filepath'] .'">Download '. $filedata['filename'] .'</a><br /><br />';
-  }
-  $form_item['#attributes'] = array("disabled" => "disabled");
-  return $form_item;
-}
-
-/** 
- * function _webform_analysis_view_file
- * Calculate and returns statistics about results for this component from all submission to this webform. The output of this function will be displayed under the "results" tab then "analysis"
- * @param $component An array of information describing the component, directly correlating to the webform_component database schema
- * @returns An array of data rows, each containing a statistic for this component's submissions.
- **/
-function _webform_analysis_rows_file($component) {  
-  $query = 'SELECT data '.
-    ' FROM {webform_submitted_data} '.
-    ' WHERE nid = %d '.
-    ' AND cid = %d';
-  $nonblanks = 0;
-  $submissions = 0;
-  $wordcount = 0;
-
-  $result = db_query($query, $component['nid'], $component['cid']);
-  while ($data = db_fetch_array($result)) {
-    $filedata = unserialize($data['data']);
-    if ($filedata['filesize']) {
-      $nonblanks++;
-      $sizetotal += $filedata['filesize'];
-    }
-    $submissions++;
-  }
-  
-  $rows[0] = array(t('Left Blank'), ($submissions - $nonblanks));
-  $rows[1] = array(t('User uploaded file'), $nonblanks);
-  $rows[2] = array(t('Average uploaded file size'), ($sizetotal !=0 ? (int)(($sizetotal/$nonblanks)/1024) ." KB" : '0'));
-  return $rows;
-}
-
-/** 
- * function _webform_table_data_file
- * Return the result of this component's submission for display in a table. The output of this function will be displayed under the "results" tab then "table"
- * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
- * @returns Textual output formatted for human reading.
- **/
-function _webform_table_data_file($data) {
-  $filedata = unserialize($data['value']['0']);
-  if (!empty($filedata['filename'])) {
-    $output = '<a href="'. base_path() . $filedata['filepath'] .'">'. $filedata['filename'] .'</a>';
-    $output .= " (". (int)($filedata['filesize']/1024) ." KB)";
-  }
-  elseif (!empty($filedata['error'])) {
-    $output = $filedata['error'];
-  }
-  else {
-    $output = "";
-  }
-  return $output;
-}
-
-
-/** 
- * function _webform_csv_headers_file
- * Return the header information for this component to be displayed in a comma seperated value file. The output of this function will be displayed under the "results" tab then "download"
- * @param $component An array of information describing the component, directly correlating to the webform_component database schema
- * @returns An array of data to be displayed in the first three rows of a CSV file, not including either prefixed or trailing commas
- **/
-function _webform_csv_headers_file($component) {
-  $header = array();
-  $header[0] = '';
-  $header[1] = $component['name'];
-  $header[2] = 'Name\,Filesize (KB)';
-  return $header;
-}
-
-/** 
- * function _webform_csv_data_file
- * Return the result of a file submission. The output of this function will be displayed under the "results" tab then "submissions"
- * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
- * @returns Textual output formatted for CSV, not including either prefixed or trailing commas
- **/
-function _webform_csv_data_file($data) {
-  $filedata = unserialize($data['value']['0']);
-  return empty($filedata['filename']) ? '\,' : $filedata['filename'] .'\,'. (int)($filedata['filesize']/1024);
-}
-
+<?php
+// $Id: file.inc,v 1.2.2.8 2007/06/12 23:58:35 quicksketch Exp $
+/** 
+ * function webform_edit_file
+ * Create a set of form items to be displayed on the form for editing this component.
+ * Use care naming the form items, as this correlates directly to the database schema.
+ * The component "Name" and "Description" fields are added to every component type and
+ * are not necessary to specify here (although they may be overridden if desired).
+ * @returns An array of form items to be displayed on the edit component page
+ **/
+function _webform_edit_file($currfield) {
+    $edit_fields = array();
+    $edit_fields['#theme'] = 'webform_edit_file';
+    $edit_fields['extra']['filtering'] = array(
+      '#type' => 'fieldset',
+      '#collapsible' => true,
+      '#collapsed' => false,
+      '#title' => t('Upload Filtering'),
+      '#description' => t('Select the types of uploads you would like to allow.'),
+    );
+    $edit_fields['extra']['filtering']['types']['webimages'] = array(
+      '#type' => 'checkboxes',
+      '#title' => t('Web Images'),
+      '#options' => drupal_map_assoc(array('gif', 'jpg', 'png')),
+      '#default_value' => isset($currfield['extra']['filtering']['types']) ? $currfield['extra']['filtering']['types']['webimages'] : array('jpg', 'gif', 'png'),
+    );
+    $edit_fields['extra']['filtering']['types']['desktopimages'] = array(
+      '#type' => 'checkboxes',
+      '#title' => t('Desktop Images'),
+      '#options' => drupal_map_assoc(array('bmp', 'eps', 'tif', 'pict', 'psd')),
+      '#default_value' => $currfield['extra']['filtering']['types']['desktopimages'],
+    );
+    $edit_fields['extra']['filtering']['types']['documents'] = array(
+      '#type' => 'checkboxes',
+      '#title' => t('Documents'),
+      '#options' => drupal_map_assoc(array('doc', 'html', 'odf', 'pdf', 'ppt', 'xls', 'xml')),
+      '#default_value' => $currfield['extra']['filtering']['types']['documents'],
+    );
+    $edit_fields['extra']['filtering']['types']['media'] = array(
+      '#type' => 'checkboxes',
+      '#title' => t('Media'),
+      '#options' => drupal_map_assoc(array('avi', 'mov', 'mp3', 'ogg', 'wav')),
+      '#default_value' => $currfield['extra']['filtering']['types']['media'],
+    );
+    $edit_fields['extra']['filtering']['types']['archives'] = array(
+      '#type' => 'checkboxes',
+      '#title' => t('Archives'),
+      '#options' => drupal_map_assoc(array('bz2', 'dmg', 'gz', 'jar', 'rar', 'sit', 'tar', 'zip')),
+      '#default_value' => $currfield['extra']['filtering']['types']['archives'],
+    );
+    $edit_fields['extra']['filtering']['addextensions'] = array(
+      '#type' => 'textfield',
+      '#title' => t("Additional Extensions"),
+      '#default_value' => $currfield['extra']['filtering']['addextensions'],
+      '#description' => t('Enter a list of additional file extensions for this upload field, seperated by commas.<br /> Entered extensions will be appended to checked items above.'),
+      '#size' => 60,
+      '#weight' => 3,
+      '#default_value' => $currfield['extra']['filtering']['addextensions'],
+    );
+    $edit_fields['extra']['filtering']['size'] = array(
+      '#type' => 'textfield',
+      '#title' => t("Max Upload Size"),
+      '#default_value' => $currfield['extra']['filtering']['size'],
+      '#description' => t('Enter the max file size a user may upload (in KB).'),
+      '#size' => 10,
+      '#weight' => 3,
+      '#default_value' => strlen($currfield['extra']['filtering']['size']) == 0 ? 800 : $currfield['extra']['filtering']['size'],
+    );
+    $edit_fields['extra']['savelocation'] = array(
+      '#type' => 'textfield',
+      '#title' => t("Upload Directory"),
+      '#default_value' => $currfield['extra']['savelocation'],
+      '#description' => "<div style='display: block'>". t('Webform uploads are always saved in the site files directory. You may optionally specify a subfolder to store your files.') ."</div>",
+      '#weight' => 3,
+      '#validate' => array('_webform_edit_file_check_directory'), // TODO: Get this validation working
+      '#after_build' => array('_webform_edit_file_check_directory'),
+    );
+    return $edit_fields;
+}
+
+function _webform_edit_file_check_directory($form_element) {
+  $destination_dir = variable_get('file_directory_path', 'files') ."/webform/". $form_element['#value'];
+  file_check_directory($destination_dir, FILE_CREATE_DIRECTORY, 'savelocation');
+  return $form_element;
+}
+
+function theme_webform_edit_file($form) {
+  // Add a little javascript to check all the items in one type
+  $javascript = '
+    <script type="text/javascript">
+      function check_category_boxes () {
+        var checkValue = !document.getElementById("edit-field-extra-filtering-types-"+arguments[0]+"-"+arguments[1]).checked;
+        for(var i=1; i < arguments.length; i++) {
+          document.getElementById("edit-field-extra-filtering-types-"+arguments[0]+"-"+arguments[i]).checked = checkValue;
+        }
+      }
+  </script>
+ ';
+  drupal_set_html_head($javascript);
+  
+  // Format the components into a table
+  $per_row = 4;
+  $rows = array();
+  foreach (element_children($form['extra']['filtering']['types']) as $key => $filtergroup) {
+    $row = array();
+    $first_row = count($rows);
+    if ($form['extra']['filtering']['types'][$filtergroup]['#type'] == 'checkboxes') {
+      // Add the title
+      $row[] = $form['extra']['filtering']['types'][$filtergroup]['#title'];
+      $row[] = "&nbsp;";
+      // Convert the checkboxes into individual form-items
+      $checkboxes = expand_checkboxes($form['extra']['filtering']['types'][$filtergroup]);
+      // Render the checkboxes in two rows
+      $checkcount = 0;
+      $jsboxes = "";
+      foreach ($checkboxes as $key => $checkbox) {
+        if ($checkbox['#type'] == 'checkbox') {
+          $checkcount++;
+          $jsboxes .= "'". $checkbox['#return_value'] ."',";
+          if ($checkcount <= $per_row) {
+            $row[] = array('data' => drupal_render($checkbox));
+          }
+          elseif ($checkcount == $per_row+1) {
+            $rows[] = array('data' => $row, 'style' => 'border-bottom: none;');
+            $row = array(array('data' => '&nbsp;'), array('data' => '&nbsp;'));
+            $row[] = array('data' => drupal_render($checkbox));
+          }
+          else {
+            $row[] = array('data' => drupal_render($checkbox));
+          }
+        }
+      }
+      // Pretty up the table a little bit
+      $current_cell   = $checkcount % $per_row;
+      if ($current_cell   > 0) {
+        $colspan = $per_row - $current_cell   + 1;
+        $row[$current_cell  +1]['colspan'] = $colspan;
+      }
+      // Add the javascript links
+      $jsboxes = substr($jsboxes, 0, strlen($jsboxes) - 1);
+      $rows[] = array('data' => $row);
+      $select_link = ' <a href="javascript:check_category_boxes(\''. $filtergroup .'\','. $jsboxes .')">(select)</a>';
+      $rows[$first_row]['data'][1] = array('data' => $select_link, 'width' => 40);
+      unset($form['extra']['filtering']['types'][$filtergroup]);
+    }
+    elseif ($filtergroup != 'size') {
+      // Add other fields to the table (ie. additional extensions)
+      $row[] = $form['extra']['filtering']['types'][$filtergroup]['#title'];
+      unset($form['extra']['filtering']['types'][$filtergroup]['#title']);
+      $row[] = array(
+        'data' => drupal_render($form['extra']['filtering']['types'][$filtergroup]),
+        'colspan' => $per_row+1,
+      );
+      unset($form['extra']['filtering']['types'][$filtergroup]);
+      $rows[] = array('data' => $row);
+    }
+  }
+  $header = array(array('data' => t('Category'), 'colspan' => '2'), array('data' => t('Types'), 'colspan' => $per_row));
+  //unset($form['extra']['filtering']['types']);
+  
+  // Create the table inside the form
+  $form['extra']['filtering']['types']['table'] = array(
+    '#value' => theme('table', $header, $rows)
+  );
+  
+  $output = drupal_render($form);
+  
+  // Prefix the upload location field with the default path for webform
+  $output = str_replace("Upload Directory: </label>", "Upload Directory: </label>". variable_get('file_directory_path', 'files') ."/webform/", $output);
+  
+  return $output;
+}
+
+/** 
+ * function webform_render_file
+ * Build a form item array containing all the properties of this component
+ * @param $component An array of information describing the component, directly correlating to the webform_component database schema
+ * @returns An array of a form item to be displayed on the client-side webform
+ **/
+function _webform_render_file($component) {
+  $form_item = array(
+    '#type'          => $component['type'],
+    '#title'         => htmlspecialchars($component['name'], ENT_QUOTES),
+    //'#required'      => $component['mandatory'], // Drupal core bug with required file uploads
+    '#weight'        => $component['weight'],
+    '#description'   => _webform_filtervalues($component['extra']['description']),
+    '#attributes'    => $component['extra']['attributes'],
+  '#tree'          => false, // file_check_upload assumes a flat $_FILES structure
+  '#validate'      => array(
+                        '_webform_validate_file' => array($component['cid'], $component['name'], $component['extra']['filtering']),
+                        '_webform_required_file' => array($component['cid'], $component['name'], $component['mandatory']), // Custom required routine
+                      ),
+  '#prefix'        => '<div class="webform-component-'. $component['type'] .'" id="webform-component-'. $component['form_key'] .'">',
+  '#suffix'        => '</div>',
+  );
+  
+  return $form_item;
+}
+
+function _webform_required_file($formelement, $cid, $fieldname, $required = false) {
+  if (empty($_FILES['files']['name'][$cid]) && $required) {
+    form_set_error($fieldname, t('%fieldname field is required.', array('%fieldname' => $fieldname)));
+  }
+}
+
+function _webform_validate_file($formelement, $cid, $fieldname, $filters) {
+  if (empty($_FILES['files']['name'][$cid])) {
+    return;
+  }
+  
+  // Build a list of extensions
+  foreach ($filters['types'] as $filtertype) {
+    foreach ($filtertype as $extension) {
+      $extensions[] = $extension;
+    }
+  }
+  $extras = str_replace(" ", "", $filters['addextensions']);
+  if (!empty($extras)) {
+    $extensions = array_merge($extensions, explode(",", $extras));
+  }
+  
+  // Build a human readable list of extensions:
+  if (count($extensions) > 1) {
+    for ($n=0; $n < count($extensions) - 1; $n++) {
+      $extension_list .= $extensions[$n] .", ";
+    }
+    $extension_list .= "or ". $extensions[count($extensions)-1];
+  }
+  else {
+    $extension_list = $extensions[0];
+  }
+
+  $dot = strrpos($_FILES['files']['name'][$cid], '.');
+  $extension = strtolower(substr($_FILES['files']['name'][$cid], $dot+1));
+  if (!in_array($extension, $extensions)) {
+    form_set_error($cid, t("Files with the '%ext' extension are not allowed, please upload a file with a %exts extension.", array('%ext' => $extension, '%exts' => $extension_list)));
+  }
+  
+  // Now let's check the file size (limit is set in KB)
+  if ($_FILES['files']['size'][$cid] > $filters['size']*1024) {
+    form_set_error($cid, t("The file '%filename' is too large (%filesize KB). Please upload a file %maxsize KB or smaller.", array('%filename' => $_FILES['files']['name'][$cid], '%filesize' => (int)($_FILES['files']['size'][$cid]/1024), '%maxsize' => $filters['size'])));
+  }
+}
+
+/** 
+ * function webform_submit_file
+ * Perform additional server-side processing on the submitted data, such as managing an uploaded file
+ * @param $data The POST data associated with the component
+ * @param $component An array of information describing the component, directly correlating to the webform_component database schema
+ * @returns Nothing
+ **/
+function _webform_submit_file(&$data, $component) {
+  if ($file = file_check_upload($component['cid'])) {
+    $upload_dir = variable_get('file_directory_path', 'files') ."/webform/". $component['extra']['savelocation'];
+    if (file_check_directory($upload_dir, FILE_CREATE_DIRECTORY)) {
+      $file_saved = file_save_upload($component['cid'], variable_get('file_directory_path', 'files') ."/webform/". $component['extra']['savelocation']);
+      if (!$file_saved) {
+        drupal_set_message(t("The uploaded file %filename was unable to be saved. The destination directory may not be writable.", array('%filename' => $data)), "error");
+        $data = serialize(array('error' => 'Error while uploading file'));
+      }
+      else {
+        $data = serialize((array)$file_saved);
+      }
+    }
+    else {
+      drupal_set_message(t("The uploaded file %filename was unable to be saved. The destination directory does not exist.", array('%filename' => $data), "error"));
+    }
+  }
+}
+
+
+/**
+ * theme_webform_mail_file
+ * Format the output of emailed data for this component
+ *
+ * @param mixed $data A string or array of the submitted data
+ * @param array $component An array of information describing the component, directly correlating to the webform_component database schema
+ * @returns string Textual output to be included in the email
+ */
+function theme_webform_mail_file($data, $component) {
+  $file = unserialize($data);
+  $output = $component['name'] .": ". file_create_url($file['filepath']) ."\n";
+  return $output;
+}
+
+/** 
+ * function _webform_submission_display_file
+ * Display the result of a file submission. The output of this function will be displayed under the "results" tab then "submissions"
+ * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
+ * @param $component An array of information describing the component, directly correlating to the webform_component database schema
+ * @returns Textual output formatted for human reading.
+ **/
+function _webform_submission_display_file($data, $component, $enabled) {
+  $filedata = unserialize($data['value'][0]);
+  $form_item = _webform_render_file($component);
+  $form_item['#type'] = 'textfield';
+  $form_item['#default_value'] = empty($filedata['filepath']) ? $filedata['error'] : $filedata['filepath'];
+  if ($filedata['filename']) {
+    $form_item['#suffix'] = ' <a href="'. base_path() . $filedata['filepath'] .'">Download '. $filedata['filename'] .'</a><br /><br />';
+  }
+  $form_item['#disabled'] = !$enabled;
+  return $form_item;
+}
+
+/** 
+ * function _webform_analysis_view_file
+ * Calculate and returns statistics about results for this component from all submission to this webform. The output of this function will be displayed under the "results" tab then "analysis"
+ * @param $component An array of information describing the component, directly correlating to the webform_component database schema
+ * @returns An array of data rows, each containing a statistic for this component's submissions.
+ **/
+function _webform_analysis_rows_file($component) {  
+  $query = 'SELECT data '.
+    ' FROM {webform_submitted_data} '.
+    ' WHERE nid = %d '.
+    ' AND cid = %d';
+  $nonblanks = 0;
+  $submissions = 0;
+  $wordcount = 0;
+
+  $result = db_query($query, $component['nid'], $component['cid']);
+  while ($data = db_fetch_array($result)) {
+    $filedata = unserialize($data['data']);
+    if ($filedata['filesize']) {
+      $nonblanks++;
+      $sizetotal += $filedata['filesize'];
+    }
+    $submissions++;
+  }
+  
+  $rows[0] = array(t('Left Blank'), ($submissions - $nonblanks));
+  $rows[1] = array(t('User uploaded file'), $nonblanks);
+  $rows[2] = array(t('Average uploaded file size'), ($sizetotal !=0 ? (int)(($sizetotal/$nonblanks)/1024) ." KB" : '0'));
+  return $rows;
+}
+
+/** 
+ * function _webform_table_data_file
+ * Return the result of this component's submission for display in a table. The output of this function will be displayed under the "results" tab then "table"
+ * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
+ * @returns Textual output formatted for human reading.
+ **/
+function _webform_table_data_file($data) {
+  $filedata = unserialize($data['value']['0']);
+  if (!empty($filedata['filename'])) {
+    $output = '<a href="'. base_path() . $filedata['filepath'] .'">'. $filedata['filename'] .'</a>';
+    $output .= " (". (int)($filedata['filesize']/1024) ." KB)";
+  }
+  elseif (!empty($filedata['error'])) {
+    $output = $filedata['error'];
+  }
+  else {
+    $output = "";
+  }
+  return $output;
+}
+
+
+/** 
+ * function _webform_csv_headers_file
+ * Return the header information for this component to be displayed in a comma seperated value file. The output of this function will be displayed under the "results" tab then "download"
+ * @param $component An array of information describing the component, directly correlating to the webform_component database schema
+ * @returns An array of data to be displayed in the first three rows of a CSV file, not including either prefixed or trailing commas
+ **/
+function _webform_csv_headers_file($component) {
+  $header = array();
+  $header[0] = '';
+  $header[1] = $component['name'];
+  $header[2] = 'Name\,Filesize (KB)';
+  return $header;
+}
+
+/** 
+ * function _webform_csv_data_file
+ * Return the result of a file submission. The output of this function will be displayed under the "results" tab then "submissions"
+ * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
+ * @returns Textual output formatted for CSV, not including either prefixed or trailing commas
+ **/
+function _webform_csv_data_file($data) {
+  $filedata = unserialize($data['value']['0']);
+  return empty($filedata['filename']) ? '\,' : $filedata['filename'] .'\,'. (int)($filedata['filesize']/1024);
+}
+
--- components/hidden.inc	Mon May 28 00:45:20 2007
+++ components/hidden.inc	Wed Jun 20 22:31:59 2007
@@ -1,139 +1,139 @@
-<?php
-// $Id: hidden.inc,v 1.11.2.1 2007/05/27 22:45:20 quicksketch Exp $
-/** 
- * function webform_edit_hidden
- * Create a set of form items to be displayed on the form for editing this component.
- * Use care naming the form items, as this correlates directly to the database schema.
- * The component "Name" and "Description" fields are added to every component type and
- * are not necessary to specify here (although they may be overridden if desired).
- * @returns An array of form items to be displayed on the edit component page
- **/
-function _webform_edit_hidden($currfield) {
-  $edit_fields = array();
-  $edit_fields['value'] = array(
-    '#type' => 'textfield',
-    '#title' => t("Default value"),
-    '#default_value' => $currfield['default'],
-    '#description' => t('The default value of the field.') .'<br />'. webform_help('webform/helptext#variables'),
-    '#size' => 60,
-    '#maxlength' => 127,
-    '#weight' => 0,
-  );
-  $edit_fields['mandatory'] = array(
-    '#type' => 'hidden',
-    '#value' => 1,
-  );
-  $edit_fields['extra']['description'] = array(); // Hide the description box
-  return $edit_fields;
-}
-
-/** 
- * function webform_render_hidden
- * Build a form item array containing all the properties of this component
- * @param $component An array of information describing the component, directly correlating to the webform_component database schema
- * @returns An array of a form item to be displayed on the client-side webform
- **/
-function _webform_render_hidden($component) {
-  $form_item = array(
-    '#type'          => 'hidden',
-    '#value'          => _webform_filtervalues($component['value']),
-    '#weight'        => $component['weight'],
-  );
-  
-  return $form_item;
-}
-
-/** 
- * function _webform_submission_data_hidden
- * Display the result of a textfield submission. The output of this function will be displayed under the "results" tab then "submissions"
- * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
- * @param $component An array of information describing the component, directly correlating to the webform_component database schema
- * @returns Textual output formatted for human reading.
- **/
-function _webform_submission_display_hidden($data, $component) {
-  $form_item = _webform_render_hidden($component);
-  $form_item['#value']         = $data['value']['0'];
-  $form_item['#type']          = 'textfield';
-  $form_item['#title']         = htmlspecialchars($component['name'], ENT_QUOTES) ." (hidden)";
-  $form_item['#attributes']    = array("disabled" => "disabled");
-  return $form_item;
-}
-
-/** 
- * function _webform_help_hidden
- * Module specific instance of hook_help
- **/
-function _webform_help_hidden($section) {
-  switch ($section) {
-    case 'admin/settings/webform#hidden_description':
-      $output = t("Create a field which is not visible to the user, but is recorded with the submission.");
-      break;
-  }
-  return $output;
-}
-
-/** 
- * function _webform_analysis_view_hidden
- * Calculate and returns statistics about results for this component from all submission to this webform. The output of this function will be displayed under the "results" tab then "analysis"
- * @param $component An array of information describing the component, directly correlating to the webform_component database schema
- * @returns An array of data rows, each containing a statistic for this component's submissions.
- **/
-function _webform_analysis_rows_hidden($component) {  
-  $query = 'SELECT data '.
-    ' FROM {webform_submitted_data} '.
-    ' WHERE nid = %d '.
-    ' AND cid = %d';
-  $nonblanks = 0;
-  $submissions = 0;
-  $wordcount = 0;
-
-  $result = db_query($query, $component['nid'], $component['cid']);
-  while ($data = db_fetch_array($result)) {
-    if ( strlen(trim($data['data'])) > 0 ) {
-      $nonblanks++;
-      $wordcount += str_word_count(trim($data['data']));
-    }
-    $submissions++;
-  }
-  
-  $rows[0] = array( t('Empty'), ($submissions - $nonblanks));
-  $rows[1] = array( t('Non-empty'), $nonblanks);
-  $rows[2] = array( t('Average submission length in words (ex blanks)'), 
-                    ($nonblanks !=0 ? number_format($wordcount/$nonblanks, 2) : '0'));
-  return $rows;
-}
-
-/** 
- * function _webform_table_data_hidden
- * Return the result of this component's submission for display in a table. The output of this function will be displayed under the "results" tab then "table"
- * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
- * @returns Textual output formatted for human reading.
- **/
-function _webform_table_data_hidden($data) {
-  return check_plain(empty($data['value']['0']) ? "" : $data['value']['0']);
-}
-
-
-/** 
- * function _webform_csv_headers_hidden
- * Return the header information for this component to be displayed in a comma seperated value file. The output of this function will be displayed under the "results" tab then "download"
- * @param $component An array of information describing the component, directly correlating to the webform_component database schema
- * @returns An array of data to be displayed in the first three rows of a CSV file, not including either prefixed or trailing commas
- **/
-function _webform_csv_headers_hidden($component) {
-  $header = array();
-  $header[0] = '';
-  $header[1] = '';
-  $header[2] = $component['name'];
-  return $header;
-}
-
-/** 
- * function _webform_csv_data_hidden
- * Return the result of a textfield submission. The output of this function will be displayed under the "results" tab then "submissions"
- * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
- * @returns Textual output formatted for CSV, not including either prefixed or trailing commas
- **/
-function _webform_csv_data_hidden($data) {
-  return empty($data['value']['0']) ? "" : $data['value']['0'];
-}
+<?php
+// $Id: hidden.inc,v 1.11.2.1 2007/05/27 22:45:20 quicksketch Exp $
+/** 
+ * function webform_edit_hidden
+ * Create a set of form items to be displayed on the form for editing this component.
+ * Use care naming the form items, as this correlates directly to the database schema.
+ * The component "Name" and "Description" fields are added to every component type and
+ * are not necessary to specify here (although they may be overridden if desired).
+ * @returns An array of form items to be displayed on the edit component page
+ **/
+function _webform_edit_hidden($currfield) {
+  $edit_fields = array();
+  $edit_fields['value'] = array(
+    '#type' => 'textfield',
+    '#title' => t("Default value"),
+    '#default_value' => $currfield['default'],
+    '#description' => t('The default value of the field.') .'<br />'. webform_help('webform/helptext#variables'),
+    '#size' => 60,
+    '#maxlength' => 127,
+    '#weight' => 0,
+  );
+  $edit_fields['mandatory'] = array(
+    '#type' => 'hidden',
+    '#value' => 1,
+  );
+  $edit_fields['extra']['description'] = array(); // Hide the description box
+  return $edit_fields;
+}
+
+/** 
+ * function webform_render_hidden
+ * Build a form item array containing all the properties of this component
+ * @param $component An array of information describing the component, directly correlating to the webform_component database schema
+ * @returns An array of a form item to be displayed on the client-side webform
+ **/
+function _webform_render_hidden($component) {
+  $form_item = array(
+    '#type'          => 'hidden',
+    '#value'          => _webform_filtervalues($component['value']),
+    '#weight'        => $component['weight'],
+  );
+  
+  return $form_item;
+}
+
+/** 
+ * function _webform_submission_data_hidden
+ * Display the result of a textfield submission. The output of this function will be displayed under the "results" tab then "submissions"
+ * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
+ * @param $component An array of information describing the component, directly correlating to the webform_component database schema
+ * @returns Textual output formatted for human reading.
+ **/
+function _webform_submission_display_hidden($data, $component, $enabled) {
+  $form_item = _webform_render_hidden($component);
+  $form_item['#value']         = $data['value']['0'];
+  $form_item['#type']          = 'textfield';
+  $form_item['#title']         = htmlspecialchars($component['name'], ENT_QUOTES) ." (hidden)";
+  $form_item['#disabled'] = !$enabled;
+  return $form_item;
+}
+
+/** 
+ * function _webform_help_hidden
+ * Module specific instance of hook_help
+ **/
+function _webform_help_hidden($section) {
+  switch ($section) {
+    case 'admin/settings/webform#hidden_description':
+      $output = t("Create a field which is not visible to the user, but is recorded with the submission.");
+      break;
+  }
+  return $output;
+}
+
+/** 
+ * function _webform_analysis_view_hidden
+ * Calculate and returns statistics about results for this component from all submission to this webform. The output of this function will be displayed under the "results" tab then "analysis"
+ * @param $component An array of information describing the component, directly correlating to the webform_component database schema
+ * @returns An array of data rows, each containing a statistic for this component's submissions.
+ **/
+function _webform_analysis_rows_hidden($component) {  
+  $query = 'SELECT data '.
+    ' FROM {webform_submitted_data} '.
+    ' WHERE nid = %d '.
+    ' AND cid = %d';
+  $nonblanks = 0;
+  $submissions = 0;
+  $wordcount = 0;
+
+  $result = db_query($query, $component['nid'], $component['cid']);
+  while ($data = db_fetch_array($result)) {
+    if ( strlen(trim($data['data'])) > 0 ) {
+      $nonblanks++;
+      $wordcount += str_word_count(trim($data['data']));
+    }
+    $submissions++;
+  }
+  
+  $rows[0] = array( t('Empty'), ($submissions - $nonblanks));
+  $rows[1] = array( t('Non-empty'), $nonblanks);
+  $rows[2] = array( t('Average submission length in words (ex blanks)'), 
+                    ($nonblanks !=0 ? number_format($wordcount/$nonblanks, 2) : '0'));
+  return $rows;
+}
+
+/** 
+ * function _webform_table_data_hidden
+ * Return the result of this component's submission for display in a table. The output of this function will be displayed under the "results" tab then "table"
+ * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
+ * @returns Textual output formatted for human reading.
+ **/
+function _webform_table_data_hidden($data) {
+  return check_plain(empty($data['value']['0']) ? "" : $data['value']['0']);
+}
+
+
+/** 
+ * function _webform_csv_headers_hidden
+ * Return the header information for this component to be displayed in a comma seperated value file. The output of this function will be displayed under the "results" tab then "download"
+ * @param $component An array of information describing the component, directly correlating to the webform_component database schema
+ * @returns An array of data to be displayed in the first three rows of a CSV file, not including either prefixed or trailing commas
+ **/
+function _webform_csv_headers_hidden($component) {
+  $header = array();
+  $header[0] = '';
+  $header[1] = '';
+  $header[2] = $component['name'];
+  return $header;
+}
+
+/** 
+ * function _webform_csv_data_hidden
+ * Return the result of a textfield submission. The output of this function will be displayed under the "results" tab then "submissions"
+ * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
+ * @returns Textual output formatted for CSV, not including either prefixed or trailing commas
+ **/
+function _webform_csv_data_hidden($data) {
+  return empty($data['value']['0']) ? "" : $data['value']['0'];
+}
--- components/select.inc	Mon Jun 11 15:07:12 2007
+++ components/select.inc	Wed Jun 20 22:33:44 2007
@@ -1,411 +1,411 @@
-<?php
-// $Id: select.inc,v 1.18.2.9 2007/06/11 13:07:11 quicksketch Exp $
-/** 
- * function webform_edit_select
- * Create a set of form items to be displayed on the form for editing this component.
- * Use care naming the form items, as this correlates directly to the database schema.
- * The component "Name" and "Description" fields are added to every component type and
- * are not necessary to specify here (although they may be overridden if desired).
- * @returns An array of form items to be displayed on the edit component page
- **/
-function _webform_edit_select($currfield) {
-  $edit_fields = array();
-  $edit_fields['extra']['items'] = array(
-    '#type' => 'textarea',
-    '#title' => t("Options"),
-    '#default_value' => $currfield['extra']['items'],
-    '#description' => t('A list of selectable options. One option per line. Key-value pairs may be entered seperated by pipes. i.e. safe_key|Some readable option') .'<br />'. webform_help('webform/helptext#variables'),
-    '#cols' => 60,
-    '#rows' => 5,
-    '#weight' => -2,
-    '#required' => TRUE,
-  );
-  $edit_fields['value'] = array(
-    '#type' => 'textfield',
-    '#title' => t("Default value"),
-    '#default_value' => $currfield['default'],
-    '#description' => t('The default value of the field. For multiple selects use commas to separate multiple defaults.') .'<br />'. webform_help('webform/helptext#variables'),
-    '#size' => 60,
-    '#maxlength' => 256,
-    '#weight' => 0,
-  );
-  $edit_fields['extra']['multiple'] = array(
-    '#type' => 'checkbox',
-    '#title' => t("Multiple"),
-    '#return_value' => 'Y',
-    '#default_value' => ($currfield['extra']['multiple']=='Y'?TRUE:FALSE),
-    '#description' => t('Check this option if the user should be allowed to choose multiple values.'),
-  );
-  $edit_fields['extra']['aslist'] = array(
-    '#type' => 'checkbox',
-    '#title' => t("Listbox"),
-    '#return_value' => 'Y',
-    '#default_value' => ($currfield['extra']['aslist']=='Y'?TRUE:FALSE),
-    '#description' => t('Check this option if you want the select component to be of listbox type instead of radiobuttons or checkboxes.'),
-  );
-  return $edit_fields;
-}
-
-function _webform_edit_validate_select($form_values) {
-  $rows = explode("\n", _webform_filtervalues($form_values['extra']['items'], FALSE));
-  foreach ($rows as $row) {
-    $row = trim($row);
-    if (preg_match('/^(.+)?\|(.*)$/', $row, $matches)) {
-      if (preg_match('/ |"/', $matches[1])) {
-        form_set_error('field][extra][items', t('The options for this select contain illegal characters (quotes or spaces). Specify your options as <em>safe_value_no_spaces</em>|<em>The Real Value</em>.'));
-        return false;
-      }
-    }
-  }
-  return true;
-}
-
-/** 
- * function webform_render_select
- * Build a form item array containing all the properties of this component
- * @param $component An array of information describing the component, directly correlating to the webform_component database schema
- * @returns An array of a form item to be displayed on the client-side webform
- **/
-function _webform_render_select($component) {
-  $form_item = array(
-    '#title'         => htmlspecialchars($component['name'], ENT_QUOTES),
-    '#required'      => $component['mandatory'],
-    '#weight'        => $component['weight'],
-    '#description'   => _webform_filtervalues($component['extra']['description']),
-    '#prefix'        => '<div class="webform-component-'. $component['type'] .'" id="webform-component-'. $component['form_key'] .'">',
-    '#suffix'        => '</div>',
-  );
-  
-  // Convert the user-entered options list into an array
-  $default_value = _webform_filtervalues($component['value']);
-  $rows = explode("\n", _webform_filtervalues($component['extra']['items'], FALSE));
-
-  if ($component['extra']['aslist'] == 'Y' && $component['extra']['multiple'] != 'Y') {
-    $options = array('' => t('select...'));
-  }
-  else {
-    $options = array();
-  }
-
-  foreach ($rows as $row) {
-    $row = trim($row);
-    if (preg_match('/^([^"|]+)\|(.*)$/', $row, $matches)) {
-      $options[$matches[1]] = $matches[2];
-    }
-    else {
-      $options[_webform_safe_name($row)] = $row;
-    } 
-  }
-
-  // Set the component options
-  $form_item['#options'] = $options;
-  
-  // Set the default value
-  if ($default_value) {
-    // Convert default value to a list if necessary
-    if ($component['extra']['multiple'] == 'Y') {
-      if (strpos($default_value, ',')) {
-        $varray = explode(',', $default_value);
-        foreach ($varray as $key => $v) {
-          if (array_key_exists(_webform_safe_name($v), $options)) {
-            $form_item['#default_value'][] = _webform_safe_name($v);
-          }
-          else {
-            $form_item['#default_value'][] = $v;
-          }
-        }
-      }
-      else {
-        if (array_key_exists(_webform_safe_name($default_value), $options)) {
-          $form_item['#default_value'] = _webform_safe_name($default_value);
-        }
-        else {
-          $form_item['#default_value'] = $default_value;
-        }
-      }
-    }
-    else {
-      if (array_key_exists(_webform_safe_name($default_value), $options)) {
-        $form_item['#default_value'] = _webform_safe_name($default_value);
-      }
-      else {
-        $form_item['#default_value'] = $default_value;
-      }
-    }
-  }
-  
-  if ($component['extra']['aslist'] == 'Y') {
-    // Set display as a select list:
-    $form_item['#type'] = 'select';
-    if ($component['extra']['multiple'] == 'Y') {
-      $form_item['#multiple'] = TRUE;
-    }
-  }
-  else {
-    if ($component['extra']['multiple'] == 'Y') {
-      // Set display as a checkbox set
-      $form_item['#type'] = 'checkboxes';
-      
-    }
-    else {
-      // Set display as a radio set
-      $form_item['#type'] = 'radios';
-    }
-  }
-  return $form_item;
-}
-
-
-/** 
- * function _webform_submission_display_select
- * Display the result of a textfield submission. The output of this function will be displayed under the "results" tab then "submissions"
- * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
- * @param $component An array of information describing the component, directly correlating to the webform_component database schema
- * @returns Textual output formatted for human reading.
- **/
-function _webform_submission_display_select($data, $component) {
-  $form_item = _webform_render_select($component);
-  if ($component['extra']['multiple'] == 'Y') {
-    // Set the value as an array
-    foreach ((array)$data['value'] as $key => $value) {
-      if (array_key_exists(_webform_safe_name($value), $form_item['#options'])) {
-        $form_item['#default_value'][] = _webform_safe_name($value);
-      }
-      else {
-        $form_item['#default_value'][] = $value;
-      }
-    }
-  }
-  else {
-    // Set the value as a single string
-    foreach ((array)$data['value'] as $value) {
-      if ($value !== '0') {
-        if (array_key_exists(_webform_safe_name($value), $form_item['#options'])) {
-          $form_item['#default_value'] = _webform_safe_name($value);
-        }
-        else {
-          $form_item['#default_value'] = $value;
-        }
-        break;
-      }
-    }
-  }
-  $form_item['#attributes'] = array("disabled" => "disabled");
-  return $form_item;
-}
-
-
-/** 
- * function webform_submit_select
- * Translates the submitted 'safe' form values back into their un-edited original form
- * @param $data The POST data associated with the component
- * @param $component An array of information describing the component, directly correlating to the webform_component database schema
- * @returns Nothing
- **/
-function _webform_submit_select(&$data, $component) {
-  $value = _webform_filtervalues($component['value']);
-  $rows = explode("\n", _webform_filtervalues($component['extra']['items']));
-
-  foreach ($rows as $row) {
-    $row = trim($row);
-    if (preg_match('/^([^"|]+)\|(.*)$/', $row, $matches)) {
-      $options[$matches[1]] = $matches[1];
-    }
-    else {
-      $options[_webform_safe_name($row)] = $row;
-    } 
-  }
-
-  if (is_array($data)) {
-    foreach ($data as $key => $value) {
-      if ($value) {
-        $data[$key] = $options[$key];
-      }
-    }
-  }
-  elseif (!empty($data)) {
-    $data = $options[$data];
-  }
-}
-
-/**
- * theme_webform_mail_select
- * Format the output of emailed data for this component
- *
- * @param mixed $data A string or array of the submitted data
- * @param array $component An array of information describing the component, directly correlating to the webform_component database schema
- * @returns string Textual output to be included in the email
- */
-function theme_webform_mail_select($data, $component) {
-  // Convert submitted 'safe' values to un-edited, original form
-  $rows = explode("\n", _webform_filtervalues($component['extra']['items']));
-  $options = array();
-  
-  foreach ($rows as $row) {
-    $row = trim($row);
-    if (preg_match('/^([^"|]+)\|(.*)$/', $row, $matches)) {
-      $options[$matches[1]] = $matches[2];
-    }
-    else {
-      $options[_webform_safe_name($row)] = $row;
-    }
-  }
-  // Generate the output
-  if ($component['extra']['multiple']) {
-    $output = $component['name'] .":\n";
-    foreach ($data as $value) {
-      if ($value) {
-        if ($options[$value]) {
-          $output .= "    â€¢ ". $options[$value] ."\n";
-        }
-        else {
-          $output .= "    â€¢ ". $options[_webform_safe_name($value)] ."\n";
-        }
-      }
-    }
-  }
-  else {
-    $output = $component['name'] .": ". $data ."\n";
-  }
-  return $output;
-}
-
-/** 
- * function _webform_help_select
- * Module specific instance of hook_help
- **/
-function _webform_help_select($section) {
-  switch ($section) {
-    case 'admin/settings/webform#select_description':
-      $output = t("Allows creation of checkboxes, radio buttons, or select menus.");
-      break;
-  }
-  return $output;
-}
-
-/** 
- * function _webform_analysis_view_select
- * Calculate and returns statistics about results for this component from all submission to this webform. The output of this function will be displayed under the "results" tab then "analysis"
- * @param $component An array of information describing the component, directly correlating to the webform_component database schema
- * @returns An array of data rows, each containing a statistic for this component's submissions.
- **/
-function _webform_analysis_rows_select($component) {
-  $component['extra'] = unserialize($component['extra']);
-  $rows = explode("\n", _webform_filtervalues($component['extra']['items']));
-  $options = array();
-  
-  foreach ($rows as $row) {
-    $row = trim($row);
-    if (preg_match('/^([^"|]+)\|(.*)$/', $row, $matches)) {
-      $options[$matches[1]] = $matches[2];
-    }
-    else {
-      $options[_webform_safe_name($row)] = $row;
-    } 
-  }
-
-  $query = 'SELECT data, count(data) as datacount '.
-    ' FROM {webform_submitted_data} '.
-    ' WHERE nid = %d '.
-    ' AND cid = %d '.
-    " AND data != '0' AND data != '' ".
-    ' GROUP BY data ';
-  $result = db_query($query, $component['nid'], $component['cid']);
-  $rows = array();
-  while ($data = db_fetch_array($result)) {
-    if ($options[$data['data']]) {
-      $display_option = $options[$data['data']];
-    }
-    else {
-      $display_option = $data['data'];
-    }
-    $rows[] = array($display_option, $data['datacount']);
-  }
-  return $rows;
-}
-
-/** 
- * function _webform_table_data_select
- * Return the result of this component's submission for display in a table. The output of this function will be displayed under the "results" tab then "table"
- * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
- * @returns Textual output formatted for human reading.
- **/
-function _webform_table_data_select($data) {
-  // Set the value as a single string
-  if (is_array($data['value'])) {
-    foreach ($data['value'] as $value) {
-      if ($value !== '0') {
-        $output .= check_plain($value) ."<br />";
-      }
-    }
-  }
-  else {
-    $output = check_plain(empty($data['value']['0']) ? "" : $data['value']['0']);
-  }
-  return $output;
-}
-
-
-/** 
- * function _webform_csv_headers_select
- * Return the header information for this component to be displayed in a comma seperated value file. The output of this function will be displayed under the "results" tab then "download"
- * @param $component An array of information describing the component, directly correlating to the webform_component database schema
- * @returns An array of data to be displayed in the first three rows of a CSV file, not including either prefixed or trailing commas
- **/
-function _webform_csv_headers_select($component) {
-  $header = array();
-  $header[0] = '';
-  
-  if ($component['extra']['multiple']) {
-    $header[1] = $component['name'];
-    $items = split("\n", $component['extra']['items']);
-    foreach ($items as $item) {
-      $header[2] .= "\,". $item;
-    }
-    // Remove the preceding extra comma
-    $header[2] = substr($header[2], 2);
-  }
-  else {
-    $header[2] = $component['name'];
-  }
-  return $header;
-}
-
-/** 
- * function _webform_csv_data_select
- * Return the result of a textfield submission. The output of this function will be displayed under the "results" tab then "submissions"
- * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
- * @returns Textual output formatted for CSV, not including either prefixed or trailing commas
- **/
-function _webform_csv_data_select($data, $component) {
-  $value = _webform_filtervalues($component['value']);
-  $rows = explode("\n", _webform_filtervalues($component['extra']['items']));
-  $options = array();
-  
-  foreach ($rows as $row) {
-    $row = trim($row);
-    if (preg_match('/^([^"|]+)\|(.*)$/', $row, $matches)) {
-      $options[$matches[1]] = $matches[2];
-    }
-    else {
-      $options[_webform_safe_name($row)] = $row;
-    } 
-  }
-  
-  if ($component['extra']['multiple']) {
-    foreach ($options as $key => $item) {
-      if (in_array($key, (array)$data['value']) === true) {
-        $output .= '\,Yes';
-      }
-      else {
-        $output .= '\,No';
-      }
-    }
-    // Remove the preceding extra comma
-   $output = substr($output, 2);
-  }
-  else {
-    $output = $data['value'][0];
-  }
-  return $output;
-}
+<?php
+// $Id: select.inc,v 1.18.2.9 2007/06/11 13:07:11 quicksketch Exp $
+/** 
+ * function webform_edit_select
+ * Create a set of form items to be displayed on the form for editing this component.
+ * Use care naming the form items, as this correlates directly to the database schema.
+ * The component "Name" and "Description" fields are added to every component type and
+ * are not necessary to specify here (although they may be overridden if desired).
+ * @returns An array of form items to be displayed on the edit component page
+ **/
+function _webform_edit_select($currfield) {
+  $edit_fields = array();
+  $edit_fields['extra']['items'] = array(
+    '#type' => 'textarea',
+    '#title' => t("Options"),
+    '#default_value' => $currfield['extra']['items'],
+    '#description' => t('A list of selectable options. One option per line. Key-value pairs may be entered seperated by pipes. i.e. safe_key|Some readable option') .'<br />'. webform_help('webform/helptext#variables'),
+    '#cols' => 60,
+    '#rows' => 5,
+    '#weight' => -2,
+    '#required' => TRUE,
+  );
+  $edit_fields['value'] = array(
+    '#type' => 'textfield',
+    '#title' => t("Default value"),
+    '#default_value' => $currfield['default'],
+    '#description' => t('The default value of the field. For multiple selects use commas to separate multiple defaults.') .'<br />'. webform_help('webform/helptext#variables'),
+    '#size' => 60,
+    '#maxlength' => 256,
+    '#weight' => 0,
+  );
+  $edit_fields['extra']['multiple'] = array(
+    '#type' => 'checkbox',
+    '#title' => t("Multiple"),
+    '#return_value' => 'Y',
+    '#default_value' => ($currfield['extra']['multiple']=='Y'?TRUE:FALSE),
+    '#description' => t('Check this option if the user should be allowed to choose multiple values.'),
+  );
+  $edit_fields['extra']['aslist'] = array(
+    '#type' => 'checkbox',
+    '#title' => t("Listbox"),
+    '#return_value' => 'Y',
+    '#default_value' => ($currfield['extra']['aslist']=='Y'?TRUE:FALSE),
+    '#description' => t('Check this option if you want the select component to be of listbox type instead of radiobuttons or checkboxes.'),
+  );
+  return $edit_fields;
+}
+
+function _webform_edit_validate_select($form_values) {
+  $rows = explode("\n", _webform_filtervalues($form_values['extra']['items'], FALSE));
+  foreach ($rows as $row) {
+    $row = trim($row);
+    if (preg_match('/^(.+)?\|(.*)$/', $row, $matches)) {
+      if (preg_match('/ |"/', $matches[1])) {
+        form_set_error('field][extra][items', t('The options for this select contain illegal characters (quotes or spaces). Specify your options as <em>safe_value_no_spaces</em>|<em>The Real Value</em>.'));
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+/** 
+ * function webform_render_select
+ * Build a form item array containing all the properties of this component
+ * @param $component An array of information describing the component, directly correlating to the webform_component database schema
+ * @returns An array of a form item to be displayed on the client-side webform
+ **/
+function _webform_render_select($component) {
+  $form_item = array(
+    '#title'         => htmlspecialchars($component['name'], ENT_QUOTES),
+    '#required'      => $component['mandatory'],
+    '#weight'        => $component['weight'],
+    '#description'   => _webform_filtervalues($component['extra']['description']),
+    '#prefix'        => '<div class="webform-component-'. $component['type'] .'" id="webform-component-'. $component['form_key'] .'">',
+    '#suffix'        => '</div>',
+  );
+  
+  // Convert the user-entered options list into an array
+  $default_value = _webform_filtervalues($component['value']);
+  $rows = explode("\n", _webform_filtervalues($component['extra']['items'], FALSE));
+
+  if ($component['extra']['aslist'] == 'Y' && $component['extra']['multiple'] != 'Y') {
+    $options = array('' => t('select...'));
+  }
+  else {
+    $options = array();
+  }
+
+  foreach ($rows as $row) {
+    $row = trim($row);
+    if (preg_match('/^([^"|]+)\|(.*)$/', $row, $matches)) {
+      $options[$matches[1]] = $matches[2];
+    }
+    else {
+      $options[_webform_safe_name($row)] = $row;
+    } 
+  }
+
+  // Set the component options
+  $form_item['#options'] = $options;
+  
+  // Set the default value
+  if ($default_value) {
+    // Convert default value to a list if necessary
+    if ($component['extra']['multiple'] == 'Y') {
+      if (strpos($default_value, ',')) {
+        $varray = explode(',', $default_value);
+        foreach ($varray as $key => $v) {
+          if (array_key_exists(_webform_safe_name($v), $options)) {
+            $form_item['#default_value'][] = _webform_safe_name($v);
+          }
+          else {
+            $form_item['#default_value'][] = $v;
+          }
+        }
+      }
+      else {
+        if (array_key_exists(_webform_safe_name($default_value), $options)) {
+          $form_item['#default_value'] = _webform_safe_name($default_value);
+        }
+        else {
+          $form_item['#default_value'] = $default_value;
+        }
+      }
+    }
+    else {
+      if (array_key_exists(_webform_safe_name($default_value), $options)) {
+        $form_item['#default_value'] = _webform_safe_name($default_value);
+      }
+      else {
+        $form_item['#default_value'] = $default_value;
+      }
+    }
+  }
+  
+  if ($component['extra']['aslist'] == 'Y') {
+    // Set display as a select list:
+    $form_item['#type'] = 'select';
+    if ($component['extra']['multiple'] == 'Y') {
+      $form_item['#multiple'] = TRUE;
+    }
+  }
+  else {
+    if ($component['extra']['multiple'] == 'Y') {
+      // Set display as a checkbox set
+      $form_item['#type'] = 'checkboxes';
+      
+    }
+    else {
+      // Set display as a radio set
+      $form_item['#type'] = 'radios';
+    }
+  }
+  return $form_item;
+}
+
+
+/** 
+ * function _webform_submission_display_select
+ * Display the result of a textfield submission. The output of this function will be displayed under the "results" tab then "submissions"
+ * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
+ * @param $component An array of information describing the component, directly correlating to the webform_component database schema
+ * @returns Textual output formatted for human reading.
+ **/
+function _webform_submission_display_select($data, $component, $enabled) {
+  $form_item = _webform_render_select($component);
+  if ($component['extra']['multiple'] == 'Y') {
+    // Set the value as an array
+    foreach ((array)$data['value'] as $key => $value) {
+      if (array_key_exists(_webform_safe_name($value), $form_item['#options'])) {
+        $form_item['#default_value'][] = _webform_safe_name($value);
+      }
+      else {
+        $form_item['#default_value'][] = $value;
+      }
+    }
+  }
+  else {
+    // Set the value as a single string
+    foreach ((array)$data['value'] as $value) {
+      if ($value !== '0') {
+        if (array_key_exists(_webform_safe_name($value), $form_item['#options'])) {
+          $form_item['#default_value'] = _webform_safe_name($value);
+        }
+        else {
+          $form_item['#default_value'] = $value;
+        }
+        break;
+      }
+    }
+  }
+  $form_item['#disabled'] = !$enabled;
+  return $form_item;
+}
+
+
+/** 
+ * function webform_submit_select
+ * Translates the submitted 'safe' form values back into their un-edited original form
+ * @param $data The POST data associated with the component
+ * @param $component An array of information describing the component, directly correlating to the webform_component database schema
+ * @returns Nothing
+ **/
+function _webform_submit_select(&$data, $component) {
+  $value = _webform_filtervalues($component['value']);
+  $rows = explode("\n", _webform_filtervalues($component['extra']['items']));
+
+  foreach ($rows as $row) {
+    $row = trim($row);
+    if (preg_match('/^([^"|]+)\|(.*)$/', $row, $matches)) {
+      $options[$matches[1]] = $matches[1];
+    }
+    else {
+      $options[_webform_safe_name($row)] = $row;
+    } 
+  }
+
+  if (is_array($data)) {
+    foreach ($data as $key => $value) {
+      if ($value) {
+        $data[$key] = $options[$key];
+      }
+    }
+  }
+  elseif (!empty($data)) {
+    $data = $options[$data];
+  }
+}
+
+/**
+ * theme_webform_mail_select
+ * Format the output of emailed data for this component
+ *
+ * @param mixed $data A string or array of the submitted data
+ * @param array $component An array of information describing the component, directly correlating to the webform_component database schema
+ * @returns string Textual output to be included in the email
+ */
+function theme_webform_mail_select($data, $component) {
+  // Convert submitted 'safe' values to un-edited, original form
+  $rows = explode("\n", _webform_filtervalues($component['extra']['items']));
+  $options = array();
+  
+  foreach ($rows as $row) {
+    $row = trim($row);
+    if (preg_match('/^([^"|]+)\|(.*)$/', $row, $matches)) {
+      $options[$matches[1]] = $matches[2];
+    }
+    else {
+      $options[_webform_safe_name($row)] = $row;
+    }
+  }
+  // Generate the output
+  if ($component['extra']['multiple']) {
+    $output = $component['name'] .":\n";
+    foreach ($data as $value) {
+      if ($value) {
+        if ($options[$value]) {
+          $output .= "    â€¢ ". $options[$value] ."\n";
+        }
+        else {
+          $output .= "    â€¢ ". $options[_webform_safe_name($value)] ."\n";
+        }
+      }
+    }
+  }
+  else {
+    $output = $component['name'] .": ". $data ."\n";
+  }
+  return $output;
+}
+
+/** 
+ * function _webform_help_select
+ * Module specific instance of hook_help
+ **/
+function _webform_help_select($section) {
+  switch ($section) {
+    case 'admin/settings/webform#select_description':
+      $output = t("Allows creation of checkboxes, radio buttons, or select menus.");
+      break;
+  }
+  return $output;
+}
+
+/** 
+ * function _webform_analysis_view_select
+ * Calculate and returns statistics about results for this component from all submission to this webform. The output of this function will be displayed under the "results" tab then "analysis"
+ * @param $component An array of information describing the component, directly correlating to the webform_component database schema
+ * @returns An array of data rows, each containing a statistic for this component's submissions.
+ **/
+function _webform_analysis_rows_select($component) {
+  $component['extra'] = unserialize($component['extra']);
+  $rows = explode("\n", _webform_filtervalues($component['extra']['items']));
+  $options = array();
+  
+  foreach ($rows as $row) {
+    $row = trim($row);
+    if (preg_match('/^([^"|]+)\|(.*)$/', $row, $matches)) {
+      $options[$matches[1]] = $matches[2];
+    }
+    else {
+      $options[_webform_safe_name($row)] = $row;
+    } 
+  }
+
+  $query = 'SELECT data, count(data) as datacount '.
+    ' FROM {webform_submitted_data} '.
+    ' WHERE nid = %d '.
+    ' AND cid = %d '.
+    " AND data != '0' AND data != '' ".
+    ' GROUP BY data ';
+  $result = db_query($query, $component['nid'], $component['cid']);
+  $rows = array();
+  while ($data = db_fetch_array($result)) {
+    if ($options[$data['data']]) {
+      $display_option = $options[$data['data']];
+    }
+    else {
+      $display_option = $data['data'];
+    }
+    $rows[] = array($display_option, $data['datacount']);
+  }
+  return $rows;
+}
+
+/** 
+ * function _webform_table_data_select
+ * Return the result of this component's submission for display in a table. The output of this function will be displayed under the "results" tab then "table"
+ * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
+ * @returns Textual output formatted for human reading.
+ **/
+function _webform_table_data_select($data) {
+  // Set the value as a single string
+  if (is_array($data['value'])) {
+    foreach ($data['value'] as $value) {
+      if ($value !== '0') {
+        $output .= check_plain($value) ."<br />";
+      }
+    }
+  }
+  else {
+    $output = check_plain(empty($data['value']['0']) ? "" : $data['value']['0']);
+  }
+  return $output;
+}
+
+
+/** 
+ * function _webform_csv_headers_select
+ * Return the header information for this component to be displayed in a comma seperated value file. The output of this function will be displayed under the "results" tab then "download"
+ * @param $component An array of information describing the component, directly correlating to the webform_component database schema
+ * @returns An array of data to be displayed in the first three rows of a CSV file, not including either prefixed or trailing commas
+ **/
+function _webform_csv_headers_select($component) {
+  $header = array();
+  $header[0] = '';
+  
+  if ($component['extra']['multiple']) {
+    $header[1] = $component['name'];
+    $items = split("\n", $component['extra']['items']);
+    foreach ($items as $item) {
+      $header[2] .= "\,". $item;
+    }
+    // Remove the preceding extra comma
+    $header[2] = substr($header[2], 2);
+  }
+  else {
+    $header[2] = $component['name'];
+  }
+  return $header;
+}
+
+/** 
+ * function _webform_csv_data_select
+ * Return the result of a textfield submission. The output of this function will be displayed under the "results" tab then "submissions"
+ * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
+ * @returns Textual output formatted for CSV, not including either prefixed or trailing commas
+ **/
+function _webform_csv_data_select($data, $component) {
+  $value = _webform_filtervalues($component['value']);
+  $rows = explode("\n", _webform_filtervalues($component['extra']['items']));
+  $options = array();
+  
+  foreach ($rows as $row) {
+    $row = trim($row);
+    if (preg_match('/^([^"|]+)\|(.*)$/', $row, $matches)) {
+      $options[$matches[1]] = $matches[2];
+    }
+    else {
+      $options[_webform_safe_name($row)] = $row;
+    } 
+  }
+  
+  if ($component['extra']['multiple']) {
+    foreach ($options as $key => $item) {
+      if (in_array($key, (array)$data['value']) === true) {
+        $output .= '\,Yes';
+      }
+      else {
+        $output .= '\,No';
+      }
+    }
+    // Remove the preceding extra comma
+   $output = substr($output, 2);
+  }
+  else {
+    $output = $data['value'][0];
+  }
+  return $output;
+}
--- components/textarea.inc	Tue May 29 05:00:32 2007
+++ components/textarea.inc	Wed Jun 20 22:31:59 2007
@@ -1,169 +1,169 @@
-<?php
-// $Id: textarea.inc,v 1.11.2.2 2007/05/29 03:00:32 quicksketch Exp $
-/** 
- * function webform_edit_textarea
- * Create a set of form items to be displayed on the form for editing this component.
- * Use care naming the form items, as this correlates directly to the database schema.
- * The component "Name" and "Description" fields are added to every component type and
- * are not necessary to specify here (although they may be overridden if desired).
- * @returns An array of form items to be displayed on the edit component page
- **/
-function _webform_edit_textarea($currfield) {
-  $edit_fields = array();
-  $edit_fields['value'] = array(
-    '#type' => 'textarea',
-    '#title' => t("Default value"),
-    '#default_value' => $currfield['default'],
-    '#description' => t('The default value of the field.') .'<br />'. webform_help('webform/helptext#variables'),
-    '#cols' => 60,
-    '#rows' => 5,
-    '#weight' => 0,
-  );
-  $edit_fields['extra']['cols'] = array(
-    '#type' => 'textfield',
-    '#title' => t("Width"),
-    '#default_value' => $currfield['extra']['cols'],
-    '#description' => t('Width of the textfield.'),
-    '#size' => 5,
-    '#maxlength' => 10,
-  );
-  $edit_fields['extra']['rows'] = array(
-    '#type' => 'textfield',
-    '#title' => t("Height"),
-    '#default_value' => $currfield['extra']['rows'],
-    '#description' => t('Height of the textfield.'),
-    '#size' => 5,
-    '#maxlength' => 10,
-  );
-  $edit_fields['extra']['attributes']['disabled'] = array(
-    '#type' => 'checkbox',
-    '#title' => t("Disabled"),
-    '#return_value' => 'disabled',
-    '#description' => t('Make this field non-editable. Useful for setting an unchangeable default value.'),
-    '#weight' => 3,
-    '#default_value' => $currfield['extra']['attributes']['disabled'],
-  );
-  return $edit_fields;
-}
-
-/** 
- * function webform_render_textarea
- * Build a form item array containing all the properties of this component
- * @param $component An array of information describing the component, directly correlating to the webform_component database schema
- * @returns An array of a form item to be displayed on the client-side webform
- **/
-function _webform_render_textarea($component) {
-  $form_item = array(
-    '#type'          => "textarea",
-    '#title'         => htmlspecialchars($component['name'], ENT_QUOTES),
-    '#default_value' => _webform_filtervalues($component['value']),
-    '#required'      => $component['mandatory'],
-    '#weight'        => $component['weight'],
-    '#description'   => _webform_filtervalues($component['extra']['description']),
-    '#rows'          => $component['extra']['rows'],
-    '#cols'          => $component['extra']['cols'],
-    '#attributes'    => $component['extra']['attributes'],
-    '#prefix'        => '<div class="webform-component-'. $component['type'] .'" id="webform-component-'. $component['form_key'] .'">',
-    '#suffix'        => '</div>',
-  );
-  if ($component['extra']['rows'] > 0) {
-    $form_item['#rows'] = $component['extra']['rows'];
-  }
-  if ($component['extra']['cols'] > 0) {
-    $form_item['#cols'] = $component['extra']['cols'];
-  }
-
-  return $form_item;
-}
-
-/** 
- * function _webform_submission_data_textarea
- * Display the result of a textfield submission. The output of this function will be displayed under the "results" tab then "submissions"
- * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
- * @param $component An array of information describing the component, directly correlating to the webform_component database schema
- * @returns Textual output formatted for human reading.
- **/
-function _webform_submission_display_textarea($data, $component) {
-  $form_item = _webform_render_textarea($component);
-  $form_item['#default_value'] = $data['value']['0'];
-  $form_item['#attributes']    = array("disabled" => "disabled");
-  return $form_item;
-}
-
-/** 
- * function _webform_help_textarea
- * Module specific instance of hook_help
- **/
-function _webform_help_textarea($section) {
-  switch ($section) {
-    case 'admin/settings/webform#textarea_description':
-      $output = t("A large text area that allows for multiple lines of input.");
-      break;
-  }
-  return $output;
-}
-
-/** 
- * function _webform_analysis_view_textarea
- * Calculate and returns statistics about results for this component from all submission to this webform. The output of this function will be displayed under the "results" tab then "analysis"
- * @param $component An array of information describing the component, directly correlating to the webform_component database schema
- * @returns An array of data rows, each containing a statistic for this component's submissions.
- **/
-function _webform_analysis_rows_textarea($component) {  
-  $query = 'SELECT data '.
-    ' FROM {webform_submitted_data} '.
-    ' WHERE nid = %d '.
-    ' AND cid = %d';
-  $nonblanks = 0;
-  $submissions = 0;
-  $wordcount = 0;
-
-  $result = db_query($query, $component['nid'], $component['cid']);
-  while ($data = db_fetch_array($result)) {
-    if ( strlen(trim($data['data'])) > 0 ) {
-      $nonblanks++;
-      $wordcount += str_word_count(trim($data['data']));
-    }
-    $submissions++;
-  }
-  
-  $rows[0] = array(t('Left Blank'), ($submissions - $nonblanks));
-  $rows[1] = array(t('User entered value'), $nonblanks);
-  $rows[2] = array(t('Average submission length in words (ex blanks)'), ($nonblanks != 0 ? number_format($wordcount/$nonblanks, 2) : '0'));
-  return $rows;
-}
-
-/** 
- * function _webform_table_data_textarea
- * Return the result of this component's submission for display in a table. The output of this function will be displayed under the "results" tab then "table"
- * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
- * @returns Textual output formatted for human reading.
- **/
-function _webform_table_data_textarea($data) {
-  return empty($data['value']['0']) ? "" : check_markup($data['value']['0'], FILTER_HTML_STRIP, FALSE);
-}
-
-
-/** 
- * function _webform_csv_headers_textarea
- * Return the header information for this component to be displayed in a comma seperated value file. The output of this function will be displayed under the "results" tab then "download"
- * @param $component An array of information describing the component, directly correlating to the webform_component database schema
- * @returns An array of data to be displayed in the first three rows of a CSV file, not including either prefixed or trailing commas
- **/
-function _webform_csv_headers_textarea($component) {
-  $header = array();
-  $header[0] = '';
-  $header[1] = '';
-  $header[2] = $component['name'];
-  return $header;
-}
-
-/** 
- * function _webform_csv_data_textarea
- * Return the result of a textfield submission. The output of this function will be displayed under the "results" tab then "submissions"
- * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
- * @returns Textual output formatted for CSV, not including either prefixed or trailing commas
- **/
-function _webform_csv_data_textarea($data) {
-  return empty($data['value']['0']) ? "" : $data['value']['0'];
-}
+<?php
+// $Id: textarea.inc,v 1.11.2.2 2007/05/29 03:00:32 quicksketch Exp $
+/** 
+ * function webform_edit_textarea
+ * Create a set of form items to be displayed on the form for editing this component.
+ * Use care naming the form items, as this correlates directly to the database schema.
+ * The component "Name" and "Description" fields are added to every component type and
+ * are not necessary to specify here (although they may be overridden if desired).
+ * @returns An array of form items to be displayed on the edit component page
+ **/
+function _webform_edit_textarea($currfield) {
+  $edit_fields = array();
+  $edit_fields['value'] = array(
+    '#type' => 'textarea',
+    '#title' => t("Default value"),
+    '#default_value' => $currfield['default'],
+    '#description' => t('The default value of the field.') .'<br />'. webform_help('webform/helptext#variables'),
+    '#cols' => 60,
+    '#rows' => 5,
+    '#weight' => 0,
+  );
+  $edit_fields['extra']['cols'] = array(
+    '#type' => 'textfield',
+    '#title' => t("Width"),
+    '#default_value' => $currfield['extra']['cols'],
+    '#description' => t('Width of the textfield.'),
+    '#size' => 5,
+    '#maxlength' => 10,
+  );
+  $edit_fields['extra']['rows'] = array(
+    '#type' => 'textfield',
+    '#title' => t("Height"),
+    '#default_value' => $currfield['extra']['rows'],
+    '#description' => t('Height of the textfield.'),
+    '#size' => 5,
+    '#maxlength' => 10,
+  );
+  $edit_fields['extra']['attributes']['disabled'] = array(
+    '#type' => 'checkbox',
+    '#title' => t("Disabled"),
+    '#return_value' => 'disabled',
+    '#description' => t('Make this field non-editable. Useful for setting an unchangeable default value.'),
+    '#weight' => 3,
+    '#default_value' => $currfield['extra']['attributes']['disabled'],
+  );
+  return $edit_fields;
+}
+
+/** 
+ * function webform_render_textarea
+ * Build a form item array containing all the properties of this component
+ * @param $component An array of information describing the component, directly correlating to the webform_component database schema
+ * @returns An array of a form item to be displayed on the client-side webform
+ **/
+function _webform_render_textarea($component) {
+  $form_item = array(
+    '#type'          => "textarea",
+    '#title'         => htmlspecialchars($component['name'], ENT_QUOTES),
+    '#default_value' => _webform_filtervalues($component['value']),
+    '#required'      => $component['mandatory'],
+    '#weight'        => $component['weight'],
+    '#description'   => _webform_filtervalues($component['extra']['description']),
+    '#rows'          => $component['extra']['rows'],
+    '#cols'          => $component['extra']['cols'],
+    '#attributes'    => $component['extra']['attributes'],
+    '#prefix'        => '<div class="webform-component-'. $component['type'] .'" id="webform-component-'. $component['form_key'] .'">',
+    '#suffix'        => '</div>',
+  );
+  if ($component['extra']['rows'] > 0) {
+    $form_item['#rows'] = $component['extra']['rows'];
+  }
+  if ($component['extra']['cols'] > 0) {
+    $form_item['#cols'] = $component['extra']['cols'];
+  }
+
+  return $form_item;
+}
+
+/** 
+ * function _webform_submission_data_textarea
+ * Display the result of a textfield submission. The output of this function will be displayed under the "results" tab then "submissions"
+ * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
+ * @param $component An array of information describing the component, directly correlating to the webform_component database schema
+ * @returns Textual output formatted for human reading.
+ **/
+function _webform_submission_display_textarea($data, $component, $enabled) {
+  $form_item = _webform_render_textarea($component);
+  $form_item['#default_value'] = $data['value']['0'];
+  $form_item['#disabled'] = !$enabled;
+  return $form_item;
+}
+
+/** 
+ * function _webform_help_textarea
+ * Module specific instance of hook_help
+ **/
+function _webform_help_textarea($section) {
+  switch ($section) {
+    case 'admin/settings/webform#textarea_description':
+      $output = t("A large text area that allows for multiple lines of input.");
+      break;
+  }
+  return $output;
+}
+
+/** 
+ * function _webform_analysis_view_textarea
+ * Calculate and returns statistics about results for this component from all submission to this webform. The output of this function will be displayed under the "results" tab then "analysis"
+ * @param $component An array of information describing the component, directly correlating to the webform_component database schema
+ * @returns An array of data rows, each containing a statistic for this component's submissions.
+ **/
+function _webform_analysis_rows_textarea($component) {  
+  $query = 'SELECT data '.
+    ' FROM {webform_submitted_data} '.
+    ' WHERE nid = %d '.
+    ' AND cid = %d';
+  $nonblanks = 0;
+  $submissions = 0;
+  $wordcount = 0;
+
+  $result = db_query($query, $component['nid'], $component['cid']);
+  while ($data = db_fetch_array($result)) {
+    if ( strlen(trim($data['data'])) > 0 ) {
+      $nonblanks++;
+      $wordcount += str_word_count(trim($data['data']));
+    }
+    $submissions++;
+  }
+  
+  $rows[0] = array(t('Left Blank'), ($submissions - $nonblanks));
+  $rows[1] = array(t('User entered value'), $nonblanks);
+  $rows[2] = array(t('Average submission length in words (ex blanks)'), ($nonblanks != 0 ? number_format($wordcount/$nonblanks, 2) : '0'));
+  return $rows;
+}
+
+/** 
+ * function _webform_table_data_textarea
+ * Return the result of this component's submission for display in a table. The output of this function will be displayed under the "results" tab then "table"
+ * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
+ * @returns Textual output formatted for human reading.
+ **/
+function _webform_table_data_textarea($data) {
+  return empty($data['value']['0']) ? "" : check_markup($data['value']['0'], FILTER_HTML_STRIP, FALSE);
+}
+
+
+/** 
+ * function _webform_csv_headers_textarea
+ * Return the header information for this component to be displayed in a comma seperated value file. The output of this function will be displayed under the "results" tab then "download"
+ * @param $component An array of information describing the component, directly correlating to the webform_component database schema
+ * @returns An array of data to be displayed in the first three rows of a CSV file, not including either prefixed or trailing commas
+ **/
+function _webform_csv_headers_textarea($component) {
+  $header = array();
+  $header[0] = '';
+  $header[1] = '';
+  $header[2] = $component['name'];
+  return $header;
+}
+
+/** 
+ * function _webform_csv_data_textarea
+ * Return the result of a textfield submission. The output of this function will be displayed under the "results" tab then "submissions"
+ * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
+ * @returns Textual output formatted for CSV, not including either prefixed or trailing commas
+ **/
+function _webform_csv_data_textarea($data) {
+  return empty($data['value']['0']) ? "" : $data['value']['0'];
+}
--- components/textfield.inc	Wed Jun 13 04:25:58 2007
+++ components/textfield.inc	Wed Jun 20 22:31:59 2007
@@ -1,170 +1,170 @@
-<?php
-// $Id: textfield.inc,v 1.11.2.4 2007/06/13 02:25:57 quicksketch Exp $
-/** 
- * function webform_edit_textfield
- * Create a set of form items to be displayed on the form for editing this component.
- * Use care naming the form items, as this correlates directly to the database schema.
- * The component "Name" and "Description" fields are added to every component type and
- * are not necessary to specify here (although they may be overridden if desired).
- * @returns An array of form items to be displayed on the edit component page
- **/
-function _webform_edit_textfield($currfield) {
-  $edit_fields = array();
-  $edit_fields['value'] = array(
-    '#type' => 'textfield',
-    '#title' => t("Default value"),
-    '#default_value' => $currfield['default'],
-    '#description' => t('The default value of the field.') .'<br />'. webform_help('webform/helptext#variables'),
-    '#size' => 60,
-    '#maxlength' => 127,
-    '#weight' => 0,
-  );
-  $edit_fields['extra']['width'] = array(
-    '#type' => 'textfield',
-    '#title' => t("Width"),
-    '#default_value' => $currfield['extra']['width'],
-    '#description' => t('Width of the textfield.'),
-    '#size' => 5,
-    '#maxlength' => 10,
-    '#weight' => 0,
-  );
-  $edit_fields['extra']['maxlength'] = array(
-    '#type' => 'textfield',
-    '#title' => t("Maxlength"),
-    '#default_value' => $currfield['extra']['maxlength'],
-    '#description' => t('Maxlength of the textfield.'),
-    '#size' => 5,
-    '#maxlength' => 10,
-    '#weight' => 0,
-  );
-  $edit_fields['extra']['attributes']['disabled'] = array(
-    '#type' => 'checkbox',
-    '#title' => t("Disabled"),
-    '#return_value' => 'disabled',
-    '#description' => t('Make this field non-editable. Useful for setting an unchangeable default value.'),
-    '#weight' => 3,
-    '#default_value' => $currfield['extra']['attributes']['disabled'],
-  );
-  return $edit_fields;
-}
-
-/** 
- * function webform_render_textfield
- * Build a form item array containing all the properties of this component
- * @param $component An array of information describing the component, directly correlating to the webform_component database schema
- * @returns An array of a form item to be displayed on the client-side webform
- **/
-function _webform_render_textfield($component) {
-  $form_item = array(
-    '#type'          => $component['type'],
-    '#title'         => htmlspecialchars($component['name'], ENT_QUOTES),
-    '#default_value' => _webform_filtervalues($component['value']),
-    '#required'      => $component['mandatory'],
-    '#weight'        => $component['weight'],
-    '#description'   => _webform_filtervalues($component['extra']['description']),
-    '#attributes'    => $component['extra']['attributes'],
-    '#prefix'        => '<div class="webform-component-'. $component['type'] .'" id="webform-component-'. $component['form_key'] .'">',
-    '#suffix'        => '</div>',
-  );
-  // Change the 'width' option to the correct 'size' option
-  if ($component['extra']['width'] > 0) {
-    $form_item['#size'] = $component['extra']['width'];
-  }
-  if ($component['extra']['maxlength'] > 0) {
-    $form_item['#maxlength'] = $component['extra']['maxlength'];
-  }
-  
-  return $form_item;
-}
-
-/** 
- * function _webform_submission_display_textfield
- * Display the result of a textfield submission. The output of this function will be displayed under the "results" tab then "submissions"
- * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
- * @param $component An array of information describing the component, directly correlating to the webform_component database schema
- * @returns Textual output formatted for human reading.
- **/
-function _webform_submission_display_textfield($data, $component) {
-  $form_item = _webform_render_textfield($component);
-  $form_item['#default_value'] = $data['value']['0'];
-  $form_item['#disabled'] = TRUE;
-  return $form_item;
-}
-
-/** 
- * function _webform_help_textfield
- * Module specific instance of hook_help
- **/
-function _webform_help_textfield($section) {
-  switch ($section) {
-    case 'admin/settings/webform#textfield_description':
-      $output = t("Basic textfield type.");
-      break;
-  }
-  return $output;
-}
-
-/** 
- * function _webform_analysis_view_textfield
- * Calculate and returns statistics about results for this component from all submission to this webform. The output of this function will be displayed under the "results" tab then "analysis"
- * @param $component An array of information describing the component, directly correlating to the webform_component database schema
- * @returns An array of data rows, each containing a statistic for this component's submissions.
- **/
-function _webform_analysis_rows_textfield($component) {  
-  $query = 'SELECT data '.
-    ' FROM {webform_submitted_data} '.
-    ' WHERE nid = %d '.
-    '  AND cid = %d';
-  $nonblanks = 0;
-  $submissions = 0;
-  $wordcount = 0;
-
-  $result = db_query($query, $component['nid'], $component['cid']);
-  while ($data = db_fetch_array($result)) {
-    if ( strlen(trim($data['data'])) > 0 ) {
-      $nonblanks++;
-      $wordcount += str_word_count(trim($data['data']));
-    }
-    $submissions++;
-  }
-  
-  $rows[0] = array(t('Left Blank'), ($submissions - $nonblanks));
-  $rows[1] = array(t('User entered value'), $nonblanks);
-  $rows[2] = array(t('Average submission length in words (ex blanks)'), ($nonblanks != 0 ? number_format($wordcount/$nonblanks, 2) : '0'));
-  return $rows;
-}
-
-/** 
- * function _webform_table_data_textfield
- * Return the result of this component's submission for display in a table. The output of this function will be displayed under the "results" tab then "table"
- * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
- * @returns Textual output formatted for human reading.
- **/
-function _webform_table_data_textfield($data) {
-  return check_plain(empty($data['value']['0']) ? "" : $data['value']['0']);
-}
-
-
-/** 
- * function _webform_csv_headers_textfield
- * Return the header information for this component to be displayed in a comma seperated value file. The output of this function will be displayed under the "results" tab then "download"
- * @param $component An array of information describing the component, directly correlating to the webform_component database schema
- * @returns An array of data to be displayed in the first three rows of a CSV file, not including either prefixed or trailing commas
- **/
-function _webform_csv_headers_textfield($component) {
-  $header = array();
-  $header[0] = '';
-  $header[1] = '';
-  $header[2] = $component['name'];
-  return $header;
-}
-
-/** 
- * function _webform_csv_data_textfield
- * Return the result of a textfield submission. The output of this function will be displayed under the "results" tab then "submissions"
- * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
- * @returns Textual output formatted for CSV, not including either prefixed or trailing commas
- **/
-function _webform_csv_data_textfield($data) {
-  return empty($data['value']['0']) ? "" : $data['value']['0'];
-}
+<?php
+// $Id: textfield.inc,v 1.11.2.4 2007/06/13 02:25:57 quicksketch Exp $
+/** 
+ * function webform_edit_textfield
+ * Create a set of form items to be displayed on the form for editing this component.
+ * Use care naming the form items, as this correlates directly to the database schema.
+ * The component "Name" and "Description" fields are added to every component type and
+ * are not necessary to specify here (although they may be overridden if desired).
+ * @returns An array of form items to be displayed on the edit component page
+ **/
+function _webform_edit_textfield($currfield) {
+  $edit_fields = array();
+  $edit_fields['value'] = array(
+    '#type' => 'textfield',
+    '#title' => t("Default value"),
+    '#default_value' => $currfield['default'],
+    '#description' => t('The default value of the field.') .'<br />'. webform_help('webform/helptext#variables'),
+    '#size' => 60,
+    '#maxlength' => 127,
+    '#weight' => 0,
+  );
+  $edit_fields['extra']['width'] = array(
+    '#type' => 'textfield',
+    '#title' => t("Width"),
+    '#default_value' => $currfield['extra']['width'],
+    '#description' => t('Width of the textfield.'),
+    '#size' => 5,
+    '#maxlength' => 10,
+    '#weight' => 0,
+  );
+  $edit_fields['extra']['maxlength'] = array(
+    '#type' => 'textfield',
+    '#title' => t("Maxlength"),
+    '#default_value' => $currfield['extra']['maxlength'],
+    '#description' => t('Maxlength of the textfield.'),
+    '#size' => 5,
+    '#maxlength' => 10,
+    '#weight' => 0,
+  );
+  $edit_fields['extra']['attributes']['disabled'] = array(
+    '#type' => 'checkbox',
+    '#title' => t("Disabled"),
+    '#return_value' => 'disabled',
+    '#description' => t('Make this field non-editable. Useful for setting an unchangeable default value.'),
+    '#weight' => 3,
+    '#default_value' => $currfield['extra']['attributes']['disabled'],
+  );
+  return $edit_fields;
+}
+
+/** 
+ * function webform_render_textfield
+ * Build a form item array containing all the properties of this component
+ * @param $component An array of information describing the component, directly correlating to the webform_component database schema
+ * @returns An array of a form item to be displayed on the client-side webform
+ **/
+function _webform_render_textfield($component) {
+  $form_item = array(
+    '#type'          => $component['type'],
+    '#title'         => htmlspecialchars($component['name'], ENT_QUOTES),
+    '#default_value' => _webform_filtervalues($component['value']),
+    '#required'      => $component['mandatory'],
+    '#weight'        => $component['weight'],
+    '#description'   => _webform_filtervalues($component['extra']['description']),
+    '#attributes'    => $component['extra']['attributes'],
+    '#prefix'        => '<div class="webform-component-'. $component['type'] .'" id="webform-component-'. $component['form_key'] .'">',
+    '#suffix'        => '</div>',
+  );
+  // Change the 'width' option to the correct 'size' option
+  if ($component['extra']['width'] > 0) {
+    $form_item['#size'] = $component['extra']['width'];
+  }
+  if ($component['extra']['maxlength'] > 0) {
+    $form_item['#maxlength'] = $component['extra']['maxlength'];
+  }
+  
+  return $form_item;
+}
+
+/** 
+ * function _webform_submission_display_textfield
+ * Display the result of a textfield submission. The output of this function will be displayed under the "results" tab then "submissions"
+ * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
+ * @param $component An array of information describing the component, directly correlating to the webform_component database schema
+ * @returns Textual output formatted for human reading.
+ **/
+function _webform_submission_display_textfield($data, $component, $enabled) {
+  $form_item = _webform_render_textfield($component);
+  $form_item['#default_value'] = $data['value']['0'];
+  $form_item['#disabled'] = !$enabled;
+  return $form_item;
+}
+
+/** 
+ * function _webform_help_textfield
+ * Module specific instance of hook_help
+ **/
+function _webform_help_textfield($section) {
+  switch ($section) {
+    case 'admin/settings/webform#textfield_description':
+      $output = t("Basic textfield type.");
+      break;
+  }
+  return $output;
+}
+
+/** 
+ * function _webform_analysis_view_textfield
+ * Calculate and returns statistics about results for this component from all submission to this webform. The output of this function will be displayed under the "results" tab then "analysis"
+ * @param $component An array of information describing the component, directly correlating to the webform_component database schema
+ * @returns An array of data rows, each containing a statistic for this component's submissions.
+ **/
+function _webform_analysis_rows_textfield($component) {  
+  $query = 'SELECT data '.
+    ' FROM {webform_submitted_data} '.
+    ' WHERE nid = %d '.
+    '  AND cid = %d';
+  $nonblanks = 0;
+  $submissions = 0;
+  $wordcount = 0;
+
+  $result = db_query($query, $component['nid'], $component['cid']);
+  while ($data = db_fetch_array($result)) {
+    if ( strlen(trim($data['data'])) > 0 ) {
+      $nonblanks++;
+      $wordcount += str_word_count(trim($data['data']));
+    }
+    $submissions++;
+  }
+  
+  $rows[0] = array(t('Left Blank'), ($submissions - $nonblanks));
+  $rows[1] = array(t('User entered value'), $nonblanks);
+  $rows[2] = array(t('Average submission length in words (ex blanks)'), ($nonblanks != 0 ? number_format($wordcount/$nonblanks, 2) : '0'));
+  return $rows;
+}
+
+/** 
+ * function _webform_table_data_textfield
+ * Return the result of this component's submission for display in a table. The output of this function will be displayed under the "results" tab then "table"
+ * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
+ * @returns Textual output formatted for human reading.
+ **/
+function _webform_table_data_textfield($data) {
+  return check_plain(empty($data['value']['0']) ? "" : $data['value']['0']);
+}
+
+
+/** 
+ * function _webform_csv_headers_textfield
+ * Return the header information for this component to be displayed in a comma seperated value file. The output of this function will be displayed under the "results" tab then "download"
+ * @param $component An array of information describing the component, directly correlating to the webform_component database schema
+ * @returns An array of data to be displayed in the first three rows of a CSV file, not including either prefixed or trailing commas
+ **/
+function _webform_csv_headers_textfield($component) {
+  $header = array();
+  $header[0] = '';
+  $header[1] = '';
+  $header[2] = $component['name'];
+  return $header;
+}
+
+/** 
+ * function _webform_csv_data_textfield
+ * Return the result of a textfield submission. The output of this function will be displayed under the "results" tab then "submissions"
+ * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
+ * @returns Textual output formatted for CSV, not including either prefixed or trailing commas
+ **/
+function _webform_csv_data_textfield($data) {
+  return empty($data['value']['0']) ? "" : $data['value']['0'];
+}
--- components/time.inc	Tue May 29 05:00:32 2007
+++ components/time.inc	Wed Jun 20 22:31:59 2007
@@ -1,310 +1,310 @@
-<?php
-// $Id: time.inc,v 1.14.2.3 2007/05/29 03:00:32 quicksketch Exp $
-/** 
- * function webform_edit_time
- * Create a set of form items to be displayed on the form for editing this component.
- * Use care naming the form items, as this correlates directly to the database schema.
- * The component "Name" and "Description" fields are added to every component type and
- * are not necessary to specify here (although they may be overridden if desired).
- * @returns An array of form items to be displayed on the edit component page
- **/
-function _webform_edit_time($currfield) {
-  $edit_fields = array();
-  $edit_fields['value'] = array(
-    '#type' => 'textfield',
-    '#title' => t("Default value"),
-    '#default_value' => $currfield['default'],
-    '#description' => t('The default value of the field.') .'<br />'. t('Accepts a time in any <a href="http://www.gnu.org/software/tar/manual/html_node/tar_109.html">GNU Date Input Format</a>. Strings such as now, +2 hours, and 10:30pm are all valid.'),
-    '#size' => 60,
-    '#maxlength' => 127,
-    '#weight' => 0,
-    '#validate' => array('webform_validate_time_string' => array()),
-  );
-  $edit_fields['extra']['timezone'] = array(
-    '#type' => 'radios',
-    '#title' => t("Timezone"),
-    '#default_value' => empty($currfield['extra']['timezone']) ? "site" : $currfield['extra']['timezone'],
-    '#description' => t('Adjust the time according to a specific timezone. Website timezone is defined in the <a href="%settings">Site Settings</a> and is the default.', array('%settings' => url('admin/settings'))),
-    '#options' => array('site' => 'Website Timezone', 'user' => 'User Timezone', 'gmt' => 'GMT'),
-    '#weight' => 0,
-  );
-$edit_fields['extra']['check_daylight_savings'] = array(
-  '#type' => 'checkbox',
-  '#title' => t("Observe Daylight Savings"),
-  '#default_value' => $currfield['extra']['check_daylight_savings'],
-  '#checked_value' => 1,
-  '#description' => t('Automatically adjust the time during daylight savings.'),
-  '#weight' => 1,
-);
-  $edit_fields['extra']['hourformat'] = array(
-    '#type' => 'radios',
-    '#title' => t("Time Format"),
-    '#default_value' => isset($currfield['extra']['hourformat']) ? $currfield['extra']['hourformat'] : '12-hour',
-    '#description' => t('Format the display of the time in 12 or 24 hours.'),
-    '#options' => array('12-hour' => '12-hour (am/pm)', '24-hour' => '24-hour'),
-    '#weight' => 2,
-  );
-  return $edit_fields;
-}
-
-/** 
- * function webform_render_time
- * Build a form item array containing all the properties of this component
- * @param $component An array of information describing the component, directly correlating to the webform_component database schema
- * @returns An array of a form item to be displayed on the client-side webform
- **/
-function _webform_render_time($component) {
-  if (strlen($component['value']) > 0) {
-    // Calculate the timestamp in GMT
-    $timestamp = strtotime($component['value']);
-    if ($component['extra']['timezone'] == "user") {
-      // Use the users timezone
-      global $user;
-      $timestamp += (int)$user->timezone;
-    }
-    elseif ($component['extra']['timezone'] == "gmt") {
-      // Use GMT
-      $timestamp += 0;
-    }
-    else {
-      // Use the Drupal site time
-      $timestamp += (int)variable_get('date_default_timezone', 0);
-    }
-  
-    // Check for daylight savings time
-    if ($component['extra']['check_daylight_savings'] && date("I")) {
-      $timestamp += 3600;
-    }
-  }
-
-  if ($component['extra']['hourformat'] == '12-hour') {
-    $first_hour = 1;
-    $last_hour = 12;
-    $hour_format = 'g';
-  }
-  else {
-    $first_hour = 0;
-    $last_hour = 23;
-    $hour_format = 'G';
-  }
-
-  if (strlen($component['value']) > 0) {
-    $hour = gmdate($hour_format, $timestamp);
-    $minute = gmdate('i', $timestamp);
-    $am_pm = gmdate('a', $timestamp);
-  }
-
-  // Generate the choices for drop-down selects
-  $hours[""] = t("hour");
-  $minutes[""] = t("minute");
-  for ($i = $first_hour; $i <= $last_hour; $i++) $hours[$i] = $i;
-  for ($i = 0; $i <= 59; $i++) $minutes[$i < 10 ? "0$i" : $i] = $i < 10 ? "0$i" : $i;
-  $am_pms = array('am' => t('am'), 'pm' => t('pm'));
-
-  $form_item['#type'] = 'fieldset';
-  $form_item['#title'] = htmlspecialchars($component['name'], ENT_QUOTES);
-  if ($component['mandatory']) {
-    $form_item['#title'] .= '<span class="form-required" title="'. t("This field is required.") .'">*</span>';
-  }
-  $form_item['#weight'] = $component['weight'];
-  $form_item['#description'] = _webform_filtervalues($component['extra']['description']);
-  $form_item['#prefix'] = '<div class="webform-component-'. $component['type'] .' container-inline" id="webform-component-'. $component['form_key'] .'">';
-  $form_item['#suffix'] = '</div>';
-  $form_item['hour'] = array(
-    '#prefix' => '',
-    '#type' => 'select',
-    '#default_value' => $hour,
-    '#options' => $hours,
-    '#validate' => array('webform_validate_time' => array('hour', $component['name'], $component['mandatory'])),
-    );
-  $form_item['minute'] = array(
-    '#prefix' => ':',
-    '#type' => 'select',
-    '#default_value' => $minute,
-    '#options' => $minutes,
-    '#validate' => array('webform_validate_time' => array('minute', $component['name'], $component['mandatory'])),
-    );
-  if ($component['extra']['hourformat'] == '12-hour') {
-    $form_item['ampm'] = array(
-      '#type' => 'radios',
-      '#default_value' => $am_pm,
-      '#options' => $am_pms,
-      );
-  }
-  
-  return $form_item;
-}
-
-function webform_validate_time($field, $field_name, $component_name, $mandatory) {
-  if (!is_numeric($field['#value']) && $mandatory) {
-    form_set_error($field_name, $component_name ." ". $field_name ." ". t(" field is required"));
-    return false;
-  }
-}
-
-/** 
- * function _webform_submission_data_time
- * Display the result of a textfield submission. The output of this function will be displayed under the "results" tab then "submissions"
- * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
- * @param $component An array of information describing the component, directly correlating to the webform_component database schema
- * @returns Textual output formatted for human reading.
- **/
-function _webform_submission_display_time($data, $component) {
-  $form_item = _webform_render_time($component);
-  $form_item['minute']['#default_value']   = $data['value']['1'];
-  $form_item['minute']['#attributes']      = array("disabled" => "disabled");
-  $form_item['hour']['#attributes']        = array("disabled" => "disabled");
-  $form_item['ampm']['#attributes']        = array("disabled" => "disabled");
-  
-  // Match the hourly data to the hour format
-  $timestamp = strtotime($data['value']['0'] .":". $data['value']['1'] . $data['value']['2']);
-  if ($component['extra']['hourformat'] == "24-hour") {
-    $form_item['hour']['#default_value'] = date("H", $timestamp);
-  }
-  else {
-    $form_item['hour']['#default_value'] = date("g", $timestamp);
-    $form_item['ampm']['#default_value'] = $data['value']['2'];
-  }
-  return $form_item;
-}
-
-/**
- * theme_webform_mail_time
- * Format the output of emailed data for this component
- *
- * @param mixed $data A string or array of the submitted data
- * @param array $component An array of information describing the component, directly correlating to the webform_component database schema
- * @returns string Textual output to be included in the email
- */
-function theme_webform_mail_time($data, $component) {
-  $output = $component['name'] .":";
-  if ($data['hour'] && $data['minute']) {
-    if ($component['extra']['hourformat'] == "24-hour") {
-      $output .= " ". $data['hour'] .":". $data['minute'];
-    }
-    else {
-      $output .= " ". $data['hour'] .":". $data['minute'] ." ". $data['ampm'];
-    }
-  }
-  return $output;
-}
-
-/** 
- * function _webform_help_time
- * Module specific instance of hook_help
- **/
-function _webform_help_time($section) {
-  switch ($section) {
-    case 'admin/settings/webform#time_description':
-      $output = t("Presents the user with hour and minute fields. Optional am/pm fields.");
-      break;
-  }
-  return $output;
-}
-
-/** 
- * function _webform_analysis_view_time
- * Calculate and returns statistics about results for this component from all submission to this webform. The output of this function will be displayed under the "results" tab then "analysis"
- * @param $component An array of information describing the component, directly correlating to the webform_component database schema
- * @returns An array of data rows, each containing a statistic for this component's submissions.
- **/
-function _webform_analysis_rows_time($component) {  
-  $query = 'SELECT no,data '.
-    ' FROM {webform_submitted_data} '.
-    ' WHERE nid = %d '.
-    ' AND  cid = %d '.
-    ' ORDER BY sid,no ASC ';
-
-  $result = db_query($query, $component['nid'], $component['cid']);
-  // build an array of timestamps from entered values
-  $timestamps = array();
-  $submissions = 1;
-  while ($row = db_fetch_array($result)) {
-    if ($row['no'] == '0') {
-      $submissions++;
-      $hour = $row['data'];
-      if ($row = db_fetch_array($result)) {
-        if ($row['no'] == '1') {
-          $minute = $row['data'];
-          if ($row = db_fetch_array($result)) {
-            if ($row['no'] == '2') {
-              $ampm = $row['data'];
-              // Build the full timestamp
-              if (strlen($hour) > 0 && strlen($minute) > 0 ) {
-                $timestamps[] = strtotime($hour .":". $minute .' '. $ampm);
-              }
-            }
-            else {
-              // Build military time
-              $timestamps[] = strtotime($hour .":". $minute);
-            }
-          }
-        }
-      }
-    }    
-  }
-  
-  // Display stats
-  // TODO: display date statistics in javascript tabs
-  $nonblanks = count($timestamps);
-  $rows[0] = array(t('Left Blank'), ($submissions - $nonblanks));
-  $rows[1] = array(t('User entered value'), $nonblanks);
-  return $rows;
-}
-
-/** 
- * function _webform_table_data_time
- * Return the result of this component's submission for display in a table. The output of this function will be displayed under the "results" tab then "table"
- * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
- * @returns Textual output formatted for human reading.
- **/
-function _webform_table_data_time($data, $component) {
-  if (strlen($data['value']['0']) > 0 && strlen($data['value']['1']) > 0) {
-    $timestamp = strtotime($data['value']['0'] .":". $data['value']['1'] . $data['value']['2']);
-    if ($component['extra']['hourformat'] == '24-hour') {
-      return check_plain(date("H:i", $timestamp));
-    }
-    else {
-      return check_plain(date("g:i a", $timestamp));
-    }
-  }
-  else {
-    return "";
-  }
-}
-
-
-/** 
- * function _webform_csv_headers_time
- * Return the header information for this component to be displayed in a comma seperated value file. The output of this function will be displayed under the "results" tab then "download"
- * @param $component An array of information describing the component, directly correlating to the webform_component database schema
- * @returns An array of data to be displayed in the first three rows of a CSV file, not including either prefixed or trailing commas
- **/
-function _webform_csv_headers_time($component) {
-  $header = array();
-  $header[0] = '';
-  $header[1] = '';
-  $header[2] = $component['name'];
-  return $header;
-}
-
-/** 
- * function _webform_csv_data_time
- * Return the result of a textfield submission. The output of this function will be displayed under the "results" tab then "submissions"
- * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
- * @returns Textual output formatted for CSV, not including either prefixed or trailing commas
- **/
-function _webform_csv_data_time($data, $component) {
-  if (strlen($data['value']['0']) > 0 && strlen($data['value']['1']) > 0) {
-    $timestamp = strtotime($data['value']['0'] .":". $data['value']['1'] . $data['value']['2']);
-    if ($component['extra']['hourformat'] == '24-hour') {
-      return date("H:i", $timestamp);
-    }
-    else {
-      return date("g:i a", $timestamp);
-    }
-  }
-  else {
-    return "";
-  }
-}
+<?php
+// $Id: time.inc,v 1.14.2.3 2007/05/29 03:00:32 quicksketch Exp $
+/** 
+ * function webform_edit_time
+ * Create a set of form items to be displayed on the form for editing this component.
+ * Use care naming the form items, as this correlates directly to the database schema.
+ * The component "Name" and "Description" fields are added to every component type and
+ * are not necessary to specify here (although they may be overridden if desired).
+ * @returns An array of form items to be displayed on the edit component page
+ **/
+function _webform_edit_time($currfield) {
+  $edit_fields = array();
+  $edit_fields['value'] = array(
+    '#type' => 'textfield',
+    '#title' => t("Default value"),
+    '#default_value' => $currfield['default'],
+    '#description' => t('The default value of the field.') .'<br />'. t('Accepts a time in any <a href="http://www.gnu.org/software/tar/manual/html_node/tar_109.html">GNU Date Input Format</a>. Strings such as now, +2 hours, and 10:30pm are all valid.'),
+    '#size' => 60,
+    '#maxlength' => 127,
+    '#weight' => 0,
+    '#validate' => array('webform_validate_time_string' => array()),
+  );
+  $edit_fields['extra']['timezone'] = array(
+    '#type' => 'radios',
+    '#title' => t("Timezone"),
+    '#default_value' => empty($currfield['extra']['timezone']) ? "site" : $currfield['extra']['timezone'],
+    '#description' => t('Adjust the time according to a specific timezone. Website timezone is defined in the <a href="%settings">Site Settings</a> and is the default.', array('%settings' => url('admin/settings'))),
+    '#options' => array('site' => 'Website Timezone', 'user' => 'User Timezone', 'gmt' => 'GMT'),
+    '#weight' => 0,
+  );
+$edit_fields['extra']['check_daylight_savings'] = array(
+  '#type' => 'checkbox',
+  '#title' => t("Observe Daylight Savings"),
+  '#default_value' => $currfield['extra']['check_daylight_savings'],
+  '#checked_value' => 1,
+  '#description' => t('Automatically adjust the time during daylight savings.'),
+  '#weight' => 1,
+);
+  $edit_fields['extra']['hourformat'] = array(
+    '#type' => 'radios',
+    '#title' => t("Time Format"),
+    '#default_value' => isset($currfield['extra']['hourformat']) ? $currfield['extra']['hourformat'] : '12-hour',
+    '#description' => t('Format the display of the time in 12 or 24 hours.'),
+    '#options' => array('12-hour' => '12-hour (am/pm)', '24-hour' => '24-hour'),
+    '#weight' => 2,
+  );
+  return $edit_fields;
+}
+
+/** 
+ * function webform_render_time
+ * Build a form item array containing all the properties of this component
+ * @param $component An array of information describing the component, directly correlating to the webform_component database schema
+ * @returns An array of a form item to be displayed on the client-side webform
+ **/
+function _webform_render_time($component) {
+  if (strlen($component['value']) > 0) {
+    // Calculate the timestamp in GMT
+    $timestamp = strtotime($component['value']);
+    if ($component['extra']['timezone'] == "user") {
+      // Use the users timezone
+      global $user;
+      $timestamp += (int)$user->timezone;
+    }
+    elseif ($component['extra']['timezone'] == "gmt") {
+      // Use GMT
+      $timestamp += 0;
+    }
+    else {
+      // Use the Drupal site time
+      $timestamp += (int)variable_get('date_default_timezone', 0);
+    }
+  
+    // Check for daylight savings time
+    if ($component['extra']['check_daylight_savings'] && date("I")) {
+      $timestamp += 3600;
+    }
+  }
+
+  if ($component['extra']['hourformat'] == '12-hour') {
+    $first_hour = 1;
+    $last_hour = 12;
+    $hour_format = 'g';
+  }
+  else {
+    $first_hour = 0;
+    $last_hour = 23;
+    $hour_format = 'G';
+  }
+
+  if (strlen($component['value']) > 0) {
+    $hour = gmdate($hour_format, $timestamp);
+    $minute = gmdate('i', $timestamp);
+    $am_pm = gmdate('a', $timestamp);
+  }
+
+  // Generate the choices for drop-down selects
+  $hours[""] = t("hour");
+  $minutes[""] = t("minute");
+  for ($i = $first_hour; $i <= $last_hour; $i++) $hours[$i] = $i;
+  for ($i = 0; $i <= 59; $i++) $minutes[$i < 10 ? "0$i" : $i] = $i < 10 ? "0$i" : $i;
+  $am_pms = array('am' => t('am'), 'pm' => t('pm'));
+
+  $form_item['#type'] = 'fieldset';
+  $form_item['#title'] = htmlspecialchars($component['name'], ENT_QUOTES);
+  if ($component['mandatory']) {
+    $form_item['#title'] .= '<span class="form-required" title="'. t("This field is required.") .'">*</span>';
+  }
+  $form_item['#weight'] = $component['weight'];
+  $form_item['#description'] = _webform_filtervalues($component['extra']['description']);
+  $form_item['#prefix'] = '<div class="webform-component-'. $component['type'] .' container-inline" id="webform-component-'. $component['form_key'] .'">';
+  $form_item['#suffix'] = '</div>';
+  $form_item['hour'] = array(
+    '#prefix' => '',
+    '#type' => 'select',
+    '#default_value' => $hour,
+    '#options' => $hours,
+    '#validate' => array('webform_validate_time' => array('hour', $component['name'], $component['mandatory'])),
+    );
+  $form_item['minute'] = array(
+    '#prefix' => ':',
+    '#type' => 'select',
+    '#default_value' => $minute,
+    '#options' => $minutes,
+    '#validate' => array('webform_validate_time' => array('minute', $component['name'], $component['mandatory'])),
+    );
+  if ($component['extra']['hourformat'] == '12-hour') {
+    $form_item['ampm'] = array(
+      '#type' => 'radios',
+      '#default_value' => $am_pm,
+      '#options' => $am_pms,
+      );
+  }
+  
+  return $form_item;
+}
+
+function webform_validate_time($field, $field_name, $component_name, $mandatory) {
+  if (!is_numeric($field['#value']) && $mandatory) {
+    form_set_error($field_name, $component_name ." ". $field_name ." ". t(" field is required"));
+    return false;
+  }
+}
+
+/** 
+ * function _webform_submission_data_time
+ * Display the result of a textfield submission. The output of this function will be displayed under the "results" tab then "submissions"
+ * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
+ * @param $component An array of information describing the component, directly correlating to the webform_component database schema
+ * @returns Textual output formatted for human reading.
+ **/
+function _webform_submission_display_time($data, $component, $enabled) {
+  $form_item = _webform_render_time($component);
+  $form_item['minute']['#default_value']   = $data['value']['1'];
+  $form_item['minute']['#disabled'] = !$enabled;
+  $form_item['hour']['#disabled'] = !$enabled;
+  $form_item['ampm']['#disabled'] = !$enabled;
+  
+  // Match the hourly data to the hour format
+  $timestamp = strtotime($data['value']['0'] .":". $data['value']['1'] . $data['value']['2']);
+  if ($component['extra']['hourformat'] == "24-hour") {
+    $form_item['hour']['#default_value'] = date("H", $timestamp);
+  }
+  else {
+    $form_item['hour']['#default_value'] = date("g", $timestamp);
+    $form_item['ampm']['#default_value'] = $data['value']['2'];
+  }
+  return $form_item;
+}
+
+/**
+ * theme_webform_mail_time
+ * Format the output of emailed data for this component
+ *
+ * @param mixed $data A string or array of the submitted data
+ * @param array $component An array of information describing the component, directly correlating to the webform_component database schema
+ * @returns string Textual output to be included in the email
+ */
+function theme_webform_mail_time($data, $component) {
+  $output = $component['name'] .":";
+  if ($data['hour'] && $data['minute']) {
+    if ($component['extra']['hourformat'] == "24-hour") {
+      $output .= " ". $data['hour'] .":". $data['minute'];
+    }
+    else {
+      $output .= " ". $data['hour'] .":". $data['minute'] ." ". $data['ampm'];
+    }
+  }
+  return $output;
+}
+
+/** 
+ * function _webform_help_time
+ * Module specific instance of hook_help
+ **/
+function _webform_help_time($section) {
+  switch ($section) {
+    case 'admin/settings/webform#time_description':
+      $output = t("Presents the user with hour and minute fields. Optional am/pm fields.");
+      break;
+  }
+  return $output;
+}
+
+/** 
+ * function _webform_analysis_view_time
+ * Calculate and returns statistics about results for this component from all submission to this webform. The output of this function will be displayed under the "results" tab then "analysis"
+ * @param $component An array of information describing the component, directly correlating to the webform_component database schema
+ * @returns An array of data rows, each containing a statistic for this component's submissions.
+ **/
+function _webform_analysis_rows_time($component) {  
+  $query = 'SELECT no,data '.
+    ' FROM {webform_submitted_data} '.
+    ' WHERE nid = %d '.
+    ' AND  cid = %d '.
+    ' ORDER BY sid,no ASC ';
+
+  $result = db_query($query, $component['nid'], $component['cid']);
+  // build an array of timestamps from entered values
+  $timestamps = array();
+  $submissions = 1;
+  while ($row = db_fetch_array($result)) {
+    if ($row['no'] == '0') {
+      $submissions++;
+      $hour = $row['data'];
+      if ($row = db_fetch_array($result)) {
+        if ($row['no'] == '1') {
+          $minute = $row['data'];
+          if ($row = db_fetch_array($result)) {
+            if ($row['no'] == '2') {
+              $ampm = $row['data'];
+              // Build the full timestamp
+              if (strlen($hour) > 0 && strlen($minute) > 0 ) {
+                $timestamps[] = strtotime($hour .":". $minute .' '. $ampm);
+              }
+            }
+            else {
+              // Build military time
+              $timestamps[] = strtotime($hour .":". $minute);
+            }
+          }
+        }
+      }
+    }    
+  }
+  
+  // Display stats
+  // TODO: display date statistics in javascript tabs
+  $nonblanks = count($timestamps);
+  $rows[0] = array(t('Left Blank'), ($submissions - $nonblanks));
+  $rows[1] = array(t('User entered value'), $nonblanks);
+  return $rows;
+}
+
+/** 
+ * function _webform_table_data_time
+ * Return the result of this component's submission for display in a table. The output of this function will be displayed under the "results" tab then "table"
+ * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
+ * @returns Textual output formatted for human reading.
+ **/
+function _webform_table_data_time($data, $component) {
+  if (strlen($data['value']['0']) > 0 && strlen($data['value']['1']) > 0) {
+    $timestamp = strtotime($data['value']['0'] .":". $data['value']['1'] . $data['value']['2']);
+    if ($component['extra']['hourformat'] == '24-hour') {
+      return check_plain(date("H:i", $timestamp));
+    }
+    else {
+      return check_plain(date("g:i a", $timestamp));
+    }
+  }
+  else {
+    return "";
+  }
+}
+
+
+/** 
+ * function _webform_csv_headers_time
+ * Return the header information for this component to be displayed in a comma seperated value file. The output of this function will be displayed under the "results" tab then "download"
+ * @param $component An array of information describing the component, directly correlating to the webform_component database schema
+ * @returns An array of data to be displayed in the first three rows of a CSV file, not including either prefixed or trailing commas
+ **/
+function _webform_csv_headers_time($component) {
+  $header = array();
+  $header[0] = '';
+  $header[1] = '';
+  $header[2] = $component['name'];
+  return $header;
+}
+
+/** 
+ * function _webform_csv_data_time
+ * Return the result of a textfield submission. The output of this function will be displayed under the "results" tab then "submissions"
+ * @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
+ * @returns Textual output formatted for CSV, not including either prefixed or trailing commas
+ **/
+function _webform_csv_data_time($data, $component) {
+  if (strlen($data['value']['0']) > 0 && strlen($data['value']['1']) > 0) {
+    $timestamp = strtotime($data['value']['0'] .":". $data['value']['1'] . $data['value']['2']);
+    if ($component['extra']['hourformat'] == '24-hour') {
+      return date("H:i", $timestamp);
+    }
+    else {
+      return date("g:i a", $timestamp);
+    }
+  }
+  else {
+    return "";
+  }
+}
--- webform.inc	Tue Jun 12 05:02:44 2007
+++ webform.inc	Wed Jun 20 22:31:59 2007
@@ -1,305 +1,306 @@
-<?php
-// $Id: webform.inc,v 1.48.2.12 2007/06/12 03:02:44 quicksketch Exp $
-
-/** 
- * This file includes helper functions for webform.module
- *
- *
- * @author Pontus Ullgren <ullgren@user.sourceforge.net>
- * @package module_webform
- * @copyright Pontus Ullgren 2004
- **/
-
-/* Creates a list of all webforms avaliable on this site.
- */
-function _webform_page() {
-  $header = array(
-    t('Title'), 
-    array('data' => t('View'), 'colspan' => '4'),
-    array('data' => t('Operations'), 'colspan' => '2')
-  );
-
-  $result = db_query("SELECT nid, title FROM {node} WHERE type='webform'");
-   
-  while ($node = db_fetch_object($result)) {
-    $rows[] = array(
-      l($node->title, 'node/'. $node->nid),
-      l(t('submissions'), 'node/'. $node->nid .'/results'),
-      l(t('analysis'), 'node/'. $node->nid .'/results/analysis'),
-      l(t('table'), 'node/'. $node->nid .'/results/table'),
-      l(t('download'), 'node/'. $node->nid .'/results/download'),
-      l(t('edit'), 'node/'. $node->nid .'/edit'),
-      l(t('clear'), 'node/'. $node->nid .'/results/clear'),
-    );
-  }
-  
-  $content = theme('table', $header, $rows);
-  drupal_set_title($node->title);
-  return $content;
-} // end function _webform_page
-
-/**
- * Delete all submission for a form.
- * @param $nid
- *   ID  of node for which to clear submissions.
- */
-function _webform_results_clear($nid) {
-  drupal_set_title(t("Clear Form Submissions"));
-  
-  $form = array();
-  $form['nid'] = array('#type' => 'value', '#value' => $nid);
-  $question = t("Are you sure you want to delete all submissions for this form?");
-  
-  return confirm_form($form, $question, 'node/'. $nid .'/results', NULL, t('Clear'), t('Cancel'));
-} // end function _webform_results_clear
-
-function _webform_results_clear_submit($form_id, $form_values) {
-  db_query('DELETE FROM {webform_submitted_data} WHERE nid = %d', $form_values['nid']);
-  db_query('DELETE FROM {webform_submissions} WHERE nid = %d', $form_values['nid']);
-
-  $node = node_load(array('nid' => $form_values['nid']));
-  $title = $node->title;
-
-  $message = t('Webform %title entries cleared.', array('%title' => $title));
-  drupal_set_message($message);
-  watchdog('webform', $message, WATCHDOG_NOTICE);
-  drupal_goto('admin/content/webform'); 
-}
-
-/**
- * Delete one form submission
- * @param $nid
- *   ID of node for which this webform was submitted
- * @param $sid
- *   ID  of submission to be deleted (from webform_submitted_data)
- */
-function _webform_submission_delete($nid, $sid) {
-  drupal_set_title(t("Delete Form Submission"));
-
-  $form = array();
-  $form['nid'] = array('#type' => 'value', '#value' => $nid);
-  $form['sid'] = array('#type' => 'value', '#value' => $sid);
-  $question = t("Are you sure you want to delete this submission?");
-
-  return confirm_form($form, $question, 'node/'. $nid .'/results', NULL, t('Delete'), t('Cancel'));
-} // end function _webform_submission_delete
-
-function _webform_submission_delete_submit($form_id, $form_values) {
-  $nid = $form_values['nid'];
-  $sid = $form_values['sid'];
-
-  db_query('DELETE FROM {webform_submitted_data} WHERE nid = %d AND sid = %d', $nid, $sid);
-  db_query('DELETE FROM {webform_submissions} WHERE nid = %d AND sid = %d', $nid, $sid);
-
-  drupal_set_message(t("Submission deleted"));
-  drupal_goto('node/'. $nid .'/results');
-} // end function _webform_submission_delete_submit
-
-/**
- * Return all the submissions for a particular node
- * @param $nid
- *   The node ID for which submissions are being fetched.
- * @param $header
- *   If the results of this fetch will be used in a sortable table, pass the
- *   array header of the table.
- */
-function _webform_fetch_submissions($nid, $header = NULL) {
-  
-  $query = 'SELECT s.sid, s.uid, s.submitted, s.remote_addr, sd.cid, sd.no, sd.data, u.name, u.mail, u.status '. 
-           'FROM {webform_submissions} s '. 
-           'LEFT JOIN {webform_submitted_data} sd ON sd.sid = s.sid '.
-           'LEFT JOIN {users} u ON u.uid = s.uid '.
-           'WHERE sd.nid = %d';
-  
-  if (is_array($header)) {
-    $query .= tablesort_sql($header);
-  }
-
-  $res = db_query($query, $nid);
-  $submissions = array();
-  $previous = array();
-  
-  // Outer loop: iterate for each submission
-  while ($row = db_fetch_object($res)) {
-    if ($row->sid != $previous) {
-      $submissions[$row->sid]->sid = $row->sid;
-      $submissions[$row->sid]->submitted = $row->submitted;
-      $submissions[$row->sid]->remote_addr = $row->remote_addr;
-      $submissions[$row->sid]->uid = $row->uid;
-      $submissions[$row->sid]->name = $row->name;
-      $submissions[$row->sid]->status = $row->status;
-    }
-    $submissions[$row->sid]->data[$row->cid]['value'][$row->no] = $row->data;
-    $previous = $row->sid;
-  }
- 
-  return $submissions;
-} // end function _webform_fetch_submissions
-
-/** 
- * This function is used to fetch a specified submission.
- */
-function _webform_fetch_submission($sid, $nid) {
-  
-  $submission = array();
-
-  $query = 'SELECT sd.nid, sd.sid, s.submitted, sd.cid, sd.no, sd.data '. 
-           'FROM {webform_submitted_data} as sd '. 
-           'LEFT JOIN {webform_submissions} as s on (sd.sid = s.sid) '. 
-           'WHERE sd.sid = %d AND s.nid = %d';
-
-  $res = db_query($query, $sid, $nid);
-  $recs = db_num_rows($res);
-  if ($recs >= 1) {
-    $row = db_fetch_array($res);
-    $submission['nid'] = $row['nid'];
-    $submission['sid'] = $row['sid'];
-    $submission['submitted'] = $row['submitted'];
-
-    while ($row) {
-      $submission['data'][$row['cid']]['value'][$row['no']] = $row['data'];
-      $row = db_fetch_array($res);
-    }
-    
-  }
-  return $submission;
-} // end function _webform_fetch_submission
-
-
-function theme_webform_create_mailmessage($form_values, $node, $sid) {
-  global $user, $baseurl;
-  $message .=  t('Submitted on') .' '. format_date(time(), 'small') ."\n";
-  $ip_address = $_SERVER['REMOTE_ADDR'];
-  
-  if ($user->uid) {
-    $message .= t('Submitted by user') .": $user->name [$ip_address]\n";
-  }
-  else {
-    $message .= t('Submitted by anonymous user') .": [$ip_address]\n";
-  }
-
-  $message .= "\n";
-  $message .= t('Submitted values are');
-  $message .= theme('webform_mail_fields', '', $form_values['submitted_tree'], $node);
-  
-  $message .= "\n\n";
-  $message .= t("The results of this submission may be viewed at:\n");
-  $message .= "http://". $_SERVER['HTTP_HOST'] . $baseurl . url('node/'.$node->nid, "sid=". $sid);
-  
-  
-  if (variable_get('webform_debug', 0) == 2) {
-    $message .= "\n";
-    $message .= "DEBUG INFO\n";
-    $message .= "==========\n";
-    $message .= "\$form_values are\n";
-    $message .= print_r($form_values, true);
-    $message .= "\$node is\n";
-    $message .= print_r($node, true);
-    $message .= "\$_SERVER is\n";
-    $message .= print_r($_SERVER, true);
-    $message .= "\n";
-    $message .= "\$_POST is\n";
-    $message .= print_r($_POST, true);
-  }
-
-  return $message;
-}
-
-function theme_webform_mail_fields($key, $value, $node, $indent = "") {
-  // First check for component-level themes.
-  $themed_output = theme("webform_mail_". $node->webformcomponents[$key]['type'], $value, $node->webformcomponents[$key]);
-  if ($themed_output) {
-    // Indent the output and add to message.
-    $message .= $indent;
-    $themed_output = rtrim($themed_output, "\n");
-    $message .= str_replace("\n", "\n". $indent, $themed_output);
-    $message .= "\n";
-  }
-  // Generic output for single values.
-  elseif (!is_array($value)) {
-    // Note that newlines cannot be preceeded by spaces to display properly in some clients.
-    if ($node->webformcomponents[$key]['name']) {
-      // If text is more than 60 characters, put it on a new line with space after.
-      $long = (strlen($indent . $node->webformcomponents[$key]['name'] . $value)) > 60;
-      $message .= $indent . $node->webformcomponents[$key]['name'] .":". (empty($value) ? "\n" : ($long ? "\n$value\n\n" : " $value\n"));
-    }
-  }
-  // Else use a generic output for arrays.
-  else {
-    $message .= $indent . $node->webformcomponents[$key]['name'] .":\n";
-    foreach ($value as $k => $v) {
-      $message .= theme('webform_mail_fields', $k, $v, $node, $indent ."  ");
-    }
-  }
-  return ($message);
-}
-
-
-function _webform_submission_spam_check($to, $subject, $message, $from, $headers = array()) {
-  $headers = implode('\n', $headers);
-  // Check if they are attempting to spam using a bcc or content type hack
-  if (preg_match('/(b?cc\s?:)|(content\-type:)/i', $to ."\n". $subject ."\n". $from ."\n". $headers)) {
-    return true; // Possible spam attempt
-  }  
-  return false; // Not spam
-}
-
-function _webform_submission_limit_check($node, $form_values) {
-  global $user, $db_type;
-
-  // check if submission limiting is enabled
-  if ($node->submit_limit == '-1') {
-    return false; // No check enabled
-  }
-  
-  // Retrieve submission data for this IP address or username from the database
-  $query = "SELECT submitted, uid, remote_addr ". 
-           "FROM {webform_submissions} ". 
-           "WHERE (( 0 = %d AND remote_addr = '%s') OR uid = %d )". 
-           "AND submitted > %d AND nid = %d";
-  
-  // Fetch all the entries from the database within the submit interval with this username and IP
-  $result = db_query($query, $user->uid, $_SERVER['REMOTE_ADDR'], $user->uid, time() - $node->submit_interval, $node->nid);
-  $num_submissions_database = db_num_rows($result);
-  
-  // Double check the submission history from the users machine using cookies
-  if (variable_get("webform_use_cookies", 0)) {
-    $cookie_name = 'webform-'. $node->nid;
-    
-    if (isset($_COOKIE[$cookie_name]) && is_array($_COOKIE[$cookie_name])) {
-      foreach ($_COOKIE[$cookie_name] as $key => $timestamp) {
-        if ($timestamp <= time() - $node->submit_interval) {
-          // Remove the cookie if past the required time interval
-          setcookie($cookie_name ."[". $key ."]", "", 0);
-        }
-      }
-      // Count the number of submissions recorded in cookies
-      $num_submissions_cookie = count($_COOKIE[$cookie_name]);
-    }
-    else {
-      $num_submissions_cookie = 0;
-    }
-  }
-  
-  if ($num_submissions_database >= $node->submit_limit || $num_submissions_cookie >= $node->submit_limit) {
-    // Limit exceeded
-    return $num_submissions_database; 
-  }
-  else {
-    // Increment a cookie for triple recording of the submission
-    if (variable_get("webform_use_cookies", 0)) {
-      $attempted_key = 0;
-      if ($num_submissions_cookie > 0) {
-        while (array_key_exists($attempted_key, $_COOKIE[$cookie_name])) {
-          $attempted_key++;
-        }
-      }
-      // Set a cookie including the server's submission time
-      // The cookie expires in the length of the interval plus a day to compensate for different timezones
-      setcookie($cookie_name ."[". $attempted_key ."]", time(), time() + $node->submit_interval + 86400);
-    }
-    
-    // Limit not exceeded
-    return false;
-  }
-}
+<?php
+// $Id: webform.inc,v 1.48.2.12 2007/06/12 03:02:44 quicksketch Exp $
+
+/** 
+ * This file includes helper functions for webform.module
+ *
+ *
+ * @author Pontus Ullgren <ullgren@user.sourceforge.net>
+ * @package module_webform
+ * @copyright Pontus Ullgren 2004
+ **/
+
+/* Creates a list of all webforms avaliable on this site.
+ */
+function _webform_page() {
+  $header = array(
+    t('Title'), 
+    array('data' => t('View'), 'colspan' => '4'),
+    array('data' => t('Operations'), 'colspan' => '2')
+  );
+
+  $result = db_query("SELECT nid, title FROM {node} WHERE type='webform'");
+   
+  while ($node = db_fetch_object($result)) {
+    $rows[] = array(
+      l($node->title, 'node/'. $node->nid),
+      l(t('submissions'), 'node/'. $node->nid .'/results'),
+      l(t('analysis'), 'node/'. $node->nid .'/results/analysis'),
+      l(t('table'), 'node/'. $node->nid .'/results/table'),
+      l(t('download'), 'node/'. $node->nid .'/results/download'),
+      l(t('edit'), 'node/'. $node->nid .'/edit'),
+      l(t('clear'), 'node/'. $node->nid .'/results/clear'),
+    );
+  }
+  
+  $content = theme('table', $header, $rows);
+  drupal_set_title($node->title);
+  return $content;
+} // end function _webform_page
+
+/**
+ * Delete all submission for a form.
+ * @param $nid
+ *   ID  of node for which to clear submissions.
+ */
+function _webform_results_clear($nid) {
+  drupal_set_title(t("Clear Form Submissions"));
+  
+  $form = array();
+  $form['nid'] = array('#type' => 'value', '#value' => $nid);
+  $question = t("Are you sure you want to delete all submissions for this form?");
+  
+  return confirm_form($form, $question, 'node/'. $nid .'/results', NULL, t('Clear'), t('Cancel'));
+} // end function _webform_results_clear
+
+function _webform_results_clear_submit($form_id, $form_values) {
+  db_query('DELETE FROM {webform_submitted_data} WHERE nid = %d', $form_values['nid']);
+  db_query('DELETE FROM {webform_submissions} WHERE nid = %d', $form_values['nid']);
+
+  $node = node_load(array('nid' => $form_values['nid']));
+  $title = $node->title;
+
+  $message = t('Webform %title entries cleared.', array('%title' => $title));
+  drupal_set_message($message);
+  watchdog('webform', $message, WATCHDOG_NOTICE);
+  drupal_goto('admin/content/webform'); 
+}
+
+/**
+ * Delete one form submission
+ * @param $nid
+ *   ID of node for which this webform was submitted
+ * @param $sid
+ *   ID  of submission to be deleted (from webform_submitted_data)
+ */
+function _webform_submission_delete($nid, $sid) {
+  drupal_set_title(t("Delete Form Submission"));
+
+  $form = array();
+  $form['nid'] = array('#type' => 'value', '#value' => $nid);
+  $form['sid'] = array('#type' => 'value', '#value' => $sid);
+  $question = t("Are you sure you want to delete this submission?");
+
+  return confirm_form($form, $question, 'node/'. $nid .'/results', NULL, t('Delete'), t('Cancel'));
+} // end function _webform_submission_delete
+
+function _webform_submission_delete_submit($form_id, $form_values) {
+  $nid = $form_values['nid'];
+  $sid = $form_values['sid'];
+
+  db_query('DELETE FROM {webform_submitted_data} WHERE nid = %d AND sid = %d', $nid, $sid);
+  db_query('DELETE FROM {webform_submissions} WHERE nid = %d AND sid = %d', $nid, $sid);
+
+  drupal_set_message(t("Submission deleted"));
+  drupal_goto('node/'. $nid .'/results');
+} // end function _webform_submission_delete_submit
+
+/**
+ * Return all the submissions for a particular node
+ * @param $nid
+ *   The node ID for which submissions are being fetched.
+ * @param $header
+ *   If the results of this fetch will be used in a sortable table, pass the
+ *   array header of the table.
+ */
+function _webform_fetch_submissions($nid, $header = NULL) {
+  
+  $query = 'SELECT s.sid, s.uid, s.submitted, s.remote_addr, sd.cid, sd.no, sd.data, u.name, u.mail, u.status '. 
+           'FROM {webform_submissions} s '. 
+           'LEFT JOIN {webform_submitted_data} sd ON sd.sid = s.sid '.
+           'LEFT JOIN {users} u ON u.uid = s.uid '.
+           'WHERE sd.nid = %d';
+  
+  if (is_array($header)) {
+    $query .= tablesort_sql($header);
+  }
+
+  $res = db_query($query, $nid);
+  $submissions = array();
+  $previous = array();
+  
+  // Outer loop: iterate for each submission
+  while ($row = db_fetch_object($res)) {
+    if ($row->sid != $previous) {
+      $submissions[$row->sid]->sid = $row->sid;
+      $submissions[$row->sid]->submitted = $row->submitted;
+      $submissions[$row->sid]->remote_addr = $row->remote_addr;
+      $submissions[$row->sid]->uid = $row->uid;
+      $submissions[$row->sid]->name = $row->name;
+      $submissions[$row->sid]->status = $row->status;
+    }
+    $submissions[$row->sid]->data[$row->cid]['value'][$row->no] = $row->data;
+    $previous = $row->sid;
+  }
+ 
+  return $submissions;
+} // end function _webform_fetch_submissions
+
+/** 
+ * This function is used to fetch a specified submission.
+ */
+function _webform_fetch_submission($sid, $nid) {
+  
+  $submission = array();
+
+  $query = 'SELECT sd.nid, sd.sid, s.submitted, s.uid, sd.cid, sd.no, sd.data '.
+           'FROM {webform_submitted_data} as sd '. 
+           'LEFT JOIN {webform_submissions} as s on (sd.sid = s.sid) '. 
+           'WHERE sd.sid = %d AND s.nid = %d';
+
+  $res = db_query($query, $sid, $nid);
+  $recs = db_num_rows($res);
+  if ($recs >= 1) {
+    $row = db_fetch_array($res);
+    $submission['nid'] = $row['nid'];
+    $submission['sid'] = $row['sid'];
+    $submission['uid'] = $row['uid'];
+    $submission['submitted'] = $row['submitted'];
+
+    while ($row) {
+      $submission['data'][$row['cid']]['value'][$row['no']] = $row['data'];
+      $row = db_fetch_array($res);
+    }
+    
+  }
+  return $submission;
+} // end function _webform_fetch_submission
+
+
+function theme_webform_create_mailmessage($form_values, $node, $sid) {
+  global $user, $baseurl;
+  $message .=  t('Submitted on') .' '. format_date(time(), 'small') ."\n";
+  $ip_address = $_SERVER['REMOTE_ADDR'];
+  
+  if ($user->uid) {
+    $message .= t('Submitted by user') .": $user->name [$ip_address]\n";
+  }
+  else {
+    $message .= t('Submitted by anonymous user') .": [$ip_address]\n";
+  }
+
+  $message .= "\n";
+  $message .= t('Submitted values are');
+  $message .= theme('webform_mail_fields', '', $form_values['submitted_tree'], $node);
+  
+  $message .= "\n\n";
+  $message .= t("The results of this submission may be viewed at:\n");
+  $message .= "http://". $_SERVER['HTTP_HOST'] . $baseurl . url('node/'.$node->nid, "sid=". $sid);
+  
+  
+  if (variable_get('webform_debug', 0) == 2) {
+    $message .= "\n";
+    $message .= "DEBUG INFO\n";
+    $message .= "==========\n";
+    $message .= "\$form_values are\n";
+    $message .= print_r($form_values, true);
+    $message .= "\$node is\n";
+    $message .= print_r($node, true);
+    $message .= "\$_SERVER is\n";
+    $message .= print_r($_SERVER, true);
+    $message .= "\n";
+    $message .= "\$_POST is\n";
+    $message .= print_r($_POST, true);
+  }
+
+  return $message;
+}
+
+function theme_webform_mail_fields($key, $value, $node, $indent = "") {
+  // First check for component-level themes.
+  $themed_output = theme("webform_mail_". $node->webformcomponents[$key]['type'], $value, $node->webformcomponents[$key]);
+  if ($themed_output) {
+    // Indent the output and add to message.
+    $message .= $indent;
+    $themed_output = rtrim($themed_output, "\n");
+    $message .= str_replace("\n", "\n". $indent, $themed_output);
+    $message .= "\n";
+  }
+  // Generic output for single values.
+  elseif (!is_array($value)) {
+    // Note that newlines cannot be preceeded by spaces to display properly in some clients.
+    if ($node->webformcomponents[$key]['name']) {
+      // If text is more than 60 characters, put it on a new line with space after.
+      $long = (strlen($indent . $node->webformcomponents[$key]['name'] . $value)) > 60;
+      $message .= $indent . $node->webformcomponents[$key]['name'] .":". (empty($value) ? "\n" : ($long ? "\n$value\n\n" : " $value\n"));
+    }
+  }
+  // Else use a generic output for arrays.
+  else {
+    $message .= $indent . $node->webformcomponents[$key]['name'] .":\n";
+    foreach ($value as $k => $v) {
+      $message .= theme('webform_mail_fields', $k, $v, $node, $indent ."  ");
+    }
+  }
+  return ($message);
+}
+
+
+function _webform_submission_spam_check($to, $subject, $message, $from, $headers = array()) {
+  $headers = implode('\n', $headers);
+  // Check if they are attempting to spam using a bcc or content type hack
+  if (preg_match('/(b?cc\s?:)|(content\-type:)/i', $to ."\n". $subject ."\n". $from ."\n". $headers)) {
+    return true; // Possible spam attempt
+  }  
+  return false; // Not spam
+}
+
+function _webform_submission_limit_check($node, $form_values) {
+  global $user, $db_type;
+
+  // check if submission limiting is enabled
+  if ($node->submit_limit == '-1') {
+    return false; // No check enabled
+  }
+  
+  // Retrieve submission data for this IP address or username from the database
+  $query = "SELECT submitted, uid, remote_addr ". 
+           "FROM {webform_submissions} ". 
+           "WHERE (( 0 = %d AND remote_addr = '%s') OR uid = %d )". 
+           "AND submitted > %d AND nid = %d";
+  
+  // Fetch all the entries from the database within the submit interval with this username and IP
+  $result = db_query($query, $user->uid, $_SERVER['REMOTE_ADDR'], $user->uid, time() - $node->submit_interval, $node->nid);
+  $num_submissions_database = db_num_rows($result);
+  
+  // Double check the submission history from the users machine using cookies
+  if (variable_get("webform_use_cookies", 0)) {
+    $cookie_name = 'webform-'. $node->nid;
+    
+    if (isset($_COOKIE[$cookie_name]) && is_array($_COOKIE[$cookie_name])) {
+      foreach ($_COOKIE[$cookie_name] as $key => $timestamp) {
+        if ($timestamp <= time() - $node->submit_interval) {
+          // Remove the cookie if past the required time interval
+          setcookie($cookie_name ."[". $key ."]", "", 0);
+        }
+      }
+      // Count the number of submissions recorded in cookies
+      $num_submissions_cookie = count($_COOKIE[$cookie_name]);
+    }
+    else {
+      $num_submissions_cookie = 0;
+    }
+  }
+  
+  if ($num_submissions_database >= $node->submit_limit || $num_submissions_cookie >= $node->submit_limit) {
+    // Limit exceeded
+    return $num_submissions_database; 
+  }
+  else {
+    // Increment a cookie for triple recording of the submission
+    if (variable_get("webform_use_cookies", 0)) {
+      $attempted_key = 0;
+      if ($num_submissions_cookie > 0) {
+        while (array_key_exists($attempted_key, $_COOKIE[$cookie_name])) {
+          $attempted_key++;
+        }
+      }
+      // Set a cookie including the server's submission time
+      // The cookie expires in the length of the interval plus a day to compensate for different timezones
+      setcookie($cookie_name ."[". $attempted_key ."]", time(), time() + $node->submit_interval + 86400);
+    }
+    
+    // Limit not exceeded
+    return false;
+  }
+}
--- webform.module	Wed Jun 13 02:47:20 2007
+++ webform.module	Wed Jun 20 22:31:59 2007
@@ -1,1701 +1,1779 @@
-<?php
-
-// $Id: webform.module,v 1.113.2.38 2007/06/13 00:47:19 quicksketch Exp $
-
-/**
- * This module provides a simple way to create forms and questionnaires.
- * The development of this module was sponsered by F Industri AB, Open
- * Source City and Karlstad University Library.
- *
- * @author Pontus Ullgren <ullgren@user.sourceforge.net>
- * @author Nathan Haug <nate at lullabot dot com>
- * @package module_webform
- * @copyright Pontus Ullgren 2003-2005
- **/
-
-/** 
- * Hook Help - used to retrieve help texts and general infomation about the module
- * @param section specifies the section to display help for.
- * @return a formated string containing the help output.
- **/
-function webform_help($section= "admin/help#webform") {
-  $output= "";
-  switch ($section) {
-    case 'admin/settings/webform' :
-      $output = t("Webforms are forms and questionnaires. To add one select <strong>create content -&gt; webform</strong>. Below you can set different security and debug options.");
-      break;
-    case 'admin/help#webform' :
-      $output = t("<p>This module lets you create forms or questionnaires and define their content. Submissions from these forms are stored in the database and optionally also sent by e-mail to a predefined address.</p>
-      <p>Here is how to create one:</p>
-      <ul>
-       <li>Go to Create Content and add a webform</li>
-       <li>Add a description to be displayed as a teaser and above the actual form.</li>
-       <li>Add a confirmation message or redirect node that is to be displayed after successful submission.</li>
-       <li>Add one or more components to your form.</li>
-       <li>Optionally add an e-mail address to which submissions will be sent. If no email address is specified, no e-mail will be sent when submissions are made through the form.</li>
-       <li>Optionally select an e-mail (or hidden) component that will be used to populate the return e-mail address on any sent e-mail.</li>
-       <li>Optionally select a textfield (or hidden) component that will be used to populate the subject e-mail field on any sent e-mail.</li>
-      </ul>
-      <p>Help on adding and configuring the components will be shown after you add your first component.</p>
-      <p>The content of submitted forms is stored in the database table <i>webform_submitted_data</i> as key-value pairs.</p>
-      ");
-      break;
-    case 'node/add#webform' :
-      $output = t("A webform can be a questionnaires, contact or request forms. It can be used to let visitors make contact, register for a event or to enable a complex survey.");
-      break;
-    case 'webform/helptext#variables' :
-      $output = t('Available variables are: %username, %useremail, %site, %date.');
-      $output .= ' '. t('You can also use %server[key] to add any of the special PHP <a href="http://www.php.net/reserved.variables#reserved.variables.server">$_SERVER</a> variables and %get[key] to create prefilled forms from the <a href="http://www.php.net/reserved.variables#reserved.variables.get">URL</a> (e.g. %server[HTTP_USER_AGENT] or %get[id]).');
-      if (module_exists('profile')) {
-        $output .= ' '. t('If you are using the profiles module, you can also access all profile data using the syntax %profile[form_name]. If you for example have a profile value named profile_city, add the varible %profile[profile_city].');
-      }
-      break;
-  }
-  // Call help hooks in plugins:
-  $components = _webform_load_components();
-  foreach ($components as $component) {
-    $help_function = "_webform_help_". $component;
-    if (function_exists($help_function)) {
-      $output .= $help_function($section);
-    }
-  }
-  return $output;
-}
-
-function webform_perm() {
-  return array("create webforms", "edit own webforms", "edit webforms", "access webform results", "clear webform results", "use PHP for additional processing");
-}
-
-/**
- * Implementation of hook_node_info().
- */
-function webform_node_info() {
-  return array(
-    'webform' => array(
-      'name' => t('Webform'),
-      'module' => 'webform',
-      'description' => t('Create a new form or questionnaire accessible to users. Submission results and statistics are recorded and accessible to privileged users.'),
-    )
-  );
-}
-
-function webform_access($op, $node) {
-  global $user;
-
-  switch ($op) {
-    case "create":
-      return user_access("create webforms");
-    case "update":
-    case "delete":
-      return user_access("edit webforms") || (user_access("edit own webforms") && ($user->uid == $node->uid));
-  }
-}
-
-function webform_insert($node) {
-  global $user;
-  // Correctly set the submission limits
-  if ($_POST['enforce_limit'] === 'no') {
-    $node->submit_limit = '-1';
-    $node->submit_interval = '157784630'; // 5 years, close enough to 'ever'
-  }
-  
-  // Re-add existing components from the POST array
-  if (isset($_POST['webformcomponents'])) {
-    unset($node->webformcomponents);
-    $node->webformcomponents = _webform_components_decode($_POST['webformcomponents']);
-  }
-  
-  // Insert the Webform
-  db_query("INSERT INTO {webform} (nid, confirmation, redirect_post, submit_limit, submit_interval, email, email_from_name, email_from_address, email_subject, additional_validate, additional_submit) VALUES (%d, '%s', %d, %d, %d, '%s', '%s', '%s', '%s', '%s', '%s')", $node->nid, $node->confirmation, $node->redirect_post, $node->submit_limit, $node->submit_interval, $node->email, $node->email_from_name, $node->email_from_address, $node->email_subject, $node->additional_validate, $node->additional_submit);
-
-  // Insert the components into the database
-  if (is_array($node->webformcomponents) && !empty($node->webformcomponents)) {
-    foreach ($node->webformcomponents as $cid => $component) {   
-      db_query("INSERT INTO {webform_component} (nid, cid, pid, form_key, name, type, value, extra, mandatory, weight) VALUES (%d, %d, %d, '%s', '%s', '%s', '%s', '%s', %d, %d)",
-        $node->nid, $cid, $component['parent'], $component['form_key'], $component['name'], $component['type'], $component['value'], serialize($component['extra']), ($component['mandatory'] ? 1 : 0), $component['weight']
-      );
-    }
-  }
-}
-
-function webform_update($node) {  
-  // Update the webform by deleting existing data and replacing with the new
-  db_query("DELETE FROM {webform} WHERE nid = %d", $node->nid);
-  db_query("DELETE FROM {webform_component} WHERE nid = %d", $node->nid);
-  webform_insert($node);
-}
-
-function webform_delete(& $node) {
-  // delete 
-  db_query("DELETE FROM {webform} WHERE nid = %d", $node->nid);
-  db_query("DELETE FROM {webform_component} WHERE nid = %d", $node->nid);
-  watchdog('webform', 'webform "'. $node->title .'" deleted', WATCHDOG_NOTICE);
-}
-
-function webform_load($node) {
-  // load 
-  $page= db_fetch_object(db_query("SELECT * FROM {webform} WHERE nid = %d", $node->nid));
-  $result= db_query('SELECT * FROM {webform_component} WHERE nid = %d ORDER BY weight, name', $node->nid);
-  while ($c= db_fetch_array($result)) {
-    $page->webformcomponents[$c['cid']]['cid']= $c['cid'];
-    $page->webformcomponents[$c['cid']]['form_key']= $c['form_key'] ? $c['form_key'] : $c['cid'];
-    $page->webformcomponents[$c['cid']]['name']= $c['name'];
-    $page->webformcomponents[$c['cid']]['type']= $c['type'];
-    $page->webformcomponents[$c['cid']]['value']= $c['value'];
-    $page->webformcomponents[$c['cid']]['extra']= unserialize($c['extra']);
-    $page->webformcomponents[$c['cid']]['mandatory']= $c['mandatory'];
-    $page->webformcomponents[$c['cid']]['parent']= $c['pid'];
-    $page->webformcomponents[$c['cid']]['weight']= $c['weight'];
-  }
-  return $page;
-}
-
-function webform_admin_settings() {
-
-  $form['components'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Available Components'),
-    '#collapsible' => TRUE,
-    '#collapsed' => FALSE,
-    '#description' => t('Below is a list of supported field types available for webform. You may disable any of these components by unchecking its corresponding box. Only checked components will be available in existing or new webforms.'),
-  );
-  
-  // Add each component to the form:
-  $component_types = _webform_load_components(true);
-  foreach ($component_types as $component_name => $component_trans_name) {
-    $form['components']['webform_enable_'. $component_name] = array(
-      '#title' => $component_trans_name,
-      '#description' => module_invoke('webform', 'help', 'admin/settings/webform#'. $component_name .'_description'),
-      '#type' => 'checkbox',
-      '#checked_value' => 1,
-      '#default_value' => variable_get('webform_enable_'. $component_name, 1),
-    );
-  }
-  
-  $form['email'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Default E-mail Values'),
-    '#collapsible' => TRUE,
-    '#collapsed' => FALSE,
-  );
-
-  $form['email']['webform_default_from_email']  = array(
-    '#type' => 'textfield',
-    '#title' => t("From e-mail address"),
-    '#default_value' => variable_get('webform_default_from_email', variable_get('site_mail', ini_get('sendmail_from'))),
-    '#description' => t('Default sender address. This may be the E-mail address of the maintainer of your forms. This is also used for Reply-To, Return-Path and Errors-To.'),
-  );
-
-  $form['email']['webform_default_from_name']  = array(
-    '#type' => 'textfield',
-    '#title' => t("From Name"),
-    '#default_value' => variable_get('webform_default_from_name', variable_get('site_name', '')),
-    '#description' => t('Default sender name which is displayed together with the E-mail address.'),
-  );
-
-  $form['email']['webform_default_subject']  = array(
-    '#type' => 'textfield',
-    '#title' => t("Default Subject"),
-    '#default_value' => variable_get('webform_default_subject', t('Form submission from: ')),
-    '#description' => t('Default Subject. If not other stated in the form configuration this is appended to your form title. If you have e.g. defined "Your " (note the space) as a default subject and a form titled with "Order" the e-mail subject will be "Your Order".'),
-  );
-
-  $form['advanced'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Advanced Options'),
-    '#collapsible' => TRUE,
-    '#collapsed' => TRUE,
-  );
-  
-  $form['advanced']['webform_use_cookies']  = array(
-    '#type' => 'checkbox',
-    '#checked_value' => 1,
-    '#title' => t("Allow Cookies for Tracking Submissions"),
-    '#default_value' => variable_get("webform_use_cookies", 0), 
-    '#description' => t('<a href="http://www.wikipedia.org/wiki/HTTP_cookie">Cookies</a> can be used to help prevent the same user from repeatedly submitting a webform. This feature is not needed for limiting submissions per user, though it can increase accuracy in some situations. Besides cookies, webform also uses IP addresses and site usernames to prevent repeated submissions.'),
-  );
-
-  $form['advanced']['webform_debug']  = array(
-    '#type' => 'select',
-    '#title' => t("Webforms Debug"),
-    '#default_value' => variable_get("webform_debug", 0), 
-    '#options' => array(0 => t("OFF"), 1 => t("Log submissions"), 2 => t("Full debug")), 
-    '#description' => t('Set this option to "Log submissions" to log all submissions in the watchdog. Set it to "Full debug" to print debug info on submission. You probably want to leave this option on "OFF".')
-  );
-  return system_settings_form($form);
-} // end function webform_admin_settings
-
-function theme_webform_admin_settings($form) {
-  // Format the components into a table
-  foreach (element_children($form['components']) as $key) {  
-    $row = array();
-    $row[] = $form['components'][$key]['#title'];
-    $row[] = $form['components'][$key]['#description'];
-    unset($form['components'][$key]['#title']);
-    unset($form['components'][$key]['#description']);
-    $row[] = array('data' => drupal_render($form['components'][$key]), 'align' => 'center');
-    $rows[] = $row;
-  }
-  $header = array(t('Name'), t('Description'), t('Enabled'));
-  
-  // Create the table inside the form
-  $form['components']['table'] = array(
-    '#value' => theme('table', $header, $rows)
-  );
-  
-  $output = drupal_render($form);
-  return $output;
-}
-
-/**
- * Implementation of hook_menu().
- */
-function webform_menu($may_cache) {
-  global $user;
-  
-  $items = array();
-  if ($may_cache) {
-    // Submissions listing 
-    $items[]= array(
-      'path' => 'admin/content/webform',
-      'title' => t('Webforms'),
-      'callback' => 'webform_page',
-      'access' => user_access('access webform results'),
-      'description' => t('View and edit all the available webforms on your site.'),
-      'type' => MENU_NORMAL_ITEM,
-    );
-    
-    // Admin Settings
-    $items[]= array(
-      'path' => 'admin/settings/webform',
-      'title' => t('Webform'),
-      'callback' => 'drupal_get_form',
-      'callback arguments' => 'webform_admin_settings',
-      'access' => user_access('administer site configuration'),
-      'description' => t('Global configuration of webform functionality.'),
-      'type' => MENU_NORMAL_ITEM,
-    );
-        
-    return $items;
-  }
-
-  if (arg(0) == 'node' && is_numeric(arg(1))) {
-    $node = node_load(arg(1));
-    if ($node->nid && $node->type == 'webform') {
-      $items[]= array('path' => 'node/'. $node->nid .'/done', 'title' => t('webform'),
-                       'callback' => '_webform_confirmation', 'callback arguments' => array(arg(1)),
-                       'access' => true,
-                       'type' => MENU_CALLBACK); 
-      $items[]= array('path' => 'node/'. $node->nid .'/results', 'title' => t('Results'), 
-                       'callback' => 'webform_results',
-                       'access' => user_access('access webform results'), 
-                       'type' => MENU_LOCAL_TASK, 'weight' => 2);
-      $items[]= array('path' => 'node/'. $node->nid .'/results/submissions', 'title' => t('submissions'),
-                       'callback' => 'webform_results',
-                       'access' => user_access('access webform results'),
-                       'weight' => 4,
-                       'type' => MENU_DEFAULT_LOCAL_TASK);
-      $items[]= array('path' => 'node/'. $node->nid .'/results/analysis', 'title' => t('analysis'),
-                       'callback' => 'webform_results',
-                       'access' => user_access('access webform results'),
-                       'weight' => 5,
-                       'type' => MENU_LOCAL_TASK);
-      $items[]= array('path' => 'node/'. $node->nid .'/results/table', 'title' => t('table'), 
-                       'callback' => 'webform_results',
-                       'access' => user_access('access webform results'), 
-                       'weight' => 6,
-                       'type' => MENU_LOCAL_TASK);
-      $items[]= array('path' => 'node/'. $node->nid .'/results/download', 'title' => t('download'), 
-                       'callback' => 'webform_results',
-                       'access' => user_access('access webform results'),
-                       'weight' => 7,
-                       'type' => MENU_LOCAL_TASK);
-      $items[]= array('path' => 'node/'. $node->nid .'/results/clear', 'title' => t('clear'), 
-                       'callback' => 'webform_results',
-                       'access' => user_access('clear webform results'),
-                       'weight' => 8,
-                       'type' => MENU_LOCAL_TASK);
-      $items[]= array('path' => 'node/'. $node->nid .'/results/delete', 'title' => t('webform'),
-                       'callback' => 'webform_results',
-                       'access' => user_access('clear webform results'),
-                       'type' => MENU_CALLBACK); 
-    }
-  }
-
-  return $items;
-}
-
-
-/** 
- * Implementation of hook_link().
- * Always add a "view form" link
- **/
-function webform_link($type, $node= 0, $main= 0) {
-  if ($node->type == 'webform') {
-    if ($main == 1) {
-      $links['webform_goto'] = array(
-        'title' => t('Go to form'),
-        'href' => "node/$node->nid",
-        'attributes' => array('title' => t('View this form.'), 'class' => 'read-more')
-      );
-    }
-  }
-  return $links;
-}
-
-/** 
- * Implementation of hook_prepare().
- * This function is called before the display of webform_form(). Rather than
- * a typical usage of hook_prepare, in webform it is used to update the contents
- * of the $node object after changes have been made to the node, such as adding a
- * new component or deleting an existing component. The node is altered as necessary,
- * then the user is returned to the display of webform_form() with the changes visible.
- * The changes to the node are not permanent until the user submits the form.
- **/
-function webform_prepare(&$node) {
-
-  $op = $_POST['op'];
-
-  switch ($op) {
-    case t('Delete Selected'):
-      // Re-add existing components
-      if (isset($_POST['webformcomponents'])) {
-        $node->webformcomponents = _webform_components_decode($_POST['webformcomponents']);
-      }
-      // Delete an existing component
-      $delete_cid = $_POST['selected_component'];
-      if (is_array($node->webformcomponents)) {
-        $new_parent = $node->webformcomponents[$delete_cid]['parent'];
-        // Fix-up any children of the deleted component
-        foreach ($node->webformcomponents as $cid => $component) {
-          if ($component['parent'] == $delete_cid) {
-            $node->webformcomponents[$cid]['parent'] = $new_parent;
-          }
-        }
-        unset($node->webformcomponents[$delete_cid]);
-      }
-      break;
-      
-    case t('Done'):
-      // Overwrite the database components with any saved in the POST array
-      if (isset($_POST['node']['webformcomponents'])) {
-        $node->webformcomponents = _webform_components_decode($_POST['node']['webformcomponents']);
-        unset($_POST['node']['webformcomponents']);
-      }
-      
-      // Add saved values of the node
-      $old_edit = (array)$node;
-      $new_edit = (array)$_POST['node'];
-      
-      $edit = array_merge($old_edit, $new_edit);
-      $node = (object)$edit;
-          
-      // Validate the field form
-      webform_edit_field_form_validate($_POST['field']);
-      $errors = form_get_errors();
-      if (!empty($errors)) {
-        $node->webformcomponents[$node->selected_component] = $_POST['field'];
-        $_POST = $_POST['node'];
-        $_POST['op'] = $op = t('Edit Selected');
-        $output = drupal_get_form('webform_edit_field_form', $node);
-        print theme('page', $output);
-        exit();
-      }
-      else {
-        // Add the component changes/additions to the node components
-        $cid = $_POST['field']['key'];
-        if (isset($_POST['field']) && is_array($_POST['field'])) {
-          unset($node->webformcomponents[$cid]);
-          foreach ($_POST['field'] as $key => $value) {
-            $node->webformcomponents[$cid][$key] = $value;
-          }
-          unset($_POST['field']);
-        }
-      }
-      
-      // Display editted message
-      drupal_set_message(t('The form component has been changed. Remember to press Submit on the bottom of this form to save your changes.'));
-      break;
-    case t('Preview'):
-      if (isset($_POST['webformcomponents'])) {
-        $node->webformcomponents = _webform_components_decode($_POST['webformcomponents']);
-      }
-      break;
-  } // end switch
-  
-  // Make sure the submission limiter is correctly set
-  if ($_POST['enforce_limit'] === 'no') {
-    $node->submit_limit = '-1';
-    $node->submit_interval = '157784630'; // 5 years, close enough to 'ever'
-  }
-}
-
-/** 
- * Implementation of hook_validate().
- * This function is called after the user clicks any button displayed in webform_form().
- * Rather than a typical usage of validation, in webform this is used to perform various
- * actions without kicking the user out of the 'edit' tab. For instance, webform detects
- * the when the buttons "Add" or "Edit Selected" are clicked, and then direct the user
- * to a form for editing a component.
- **/
-function webform_validate(&$node) {
-  $op = $_POST['op'];
-  $node->webformcomponents = _webform_components_decode($_POST['webformcomponents']);
-
-  switch ($op) {
-    // Intercept these buttons and redirect:
-    case t('Add'):
-      $errors = form_get_errors();
-      if (empty($errors)) {
-        $output = drupal_get_form('webform_edit_field_form', $node);
-        print theme('page', $output);
-        exit();
-      }
-      break;
-
-    case t('Edit Selected'):
-      $errors = form_get_errors();
-      if (empty($errors)) {
-        $output = drupal_get_form('webform_edit_field_form', $node);
-        print theme('page', $output);
-        exit();
-      }
-      break;
-    case t('Delete Selected'):
-      // We have to throw a form error for Drupal to stop form processing
-      // The 'selected_component' field item is a radio button, which shouldn't
-      // show a red border of any sort when an error is flagged on it
-      if ($_POST['selected_component']) {
-        form_set_error('selected_component', t("Field deleted, form must be submitted to save changes"));
-      }
-      else {
-        form_set_error('selected_component', t("A component must be selected to delete"));
-      }
-      break;
-    // Standard form checking:
-    case t('Submit'):
-    case t('Preview'):
-      // Make sure the submission limiter is correctly set
-      if ($_POST['enforce_limit'] === 'yes') {
-        if (!is_numeric($_POST['submit_limit'])) {
-          form_set_error('submit_limit', t('Submission limit must be a number'));
-        }
-      }
-      break;
-  }
-}
-
-/** 
- * Implementation of hook_form()
- * Creates the standard form for editing or creating a webform.
- **/
-function webform_form(&$node, &$param) {
-  /* Start Edit Form */
-  $form['webform'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Webform Settings'),
-    '#collapsible' => TRUE,
-    '#collapsed' => FALSE,
-    '#weight' => -4);
-  
-  $form['webform']['title'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Title'),
-    '#default_value' => $node->title,
-    '#maxlength' => 128,
-    '#required' => TRUE,
-  );
-  
-  $form['webform']['body'] = array(
-    '#type' => 'textarea',
-    '#title' => t('Description'),
-    '#description' => t('Text to be shown as teaser and before the form.'),
-    '#default_value' => $node->body,
-    '#cols' => 40,
-    '#rows' => 10,
-    '#required' => TRUE,
-  );
-  
-  $form['webform']['confirmation'] = array(
-    '#type' => 'textarea',
-    '#title' => t("Confirmation message or redirect URL"),
-    '#description' => t("Message to be shown upon successful submission or a path to a redirect page. Redirect pages must start with <em>http://</em> for external sites or <em>internal:</em> for an internal path. i.e. <em>http://www.example.com</em> or <em>internal:node/10</em>"),
-    '#default_value' => $node->confirmation,
-    '#cols' => 40,
-    '#rows' => 10,
-    '#required' => TRUE,
-  );
-  
-  $form['webform']['format'] = filter_form($node->format);
-  /* End Edit Form */
-  
-  /* Start Components Form */
-  $form['components'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Components'),
-    '#collapsible' => TRUE,
-    '#collapsed' => FALSE,
-    '#weight' => -3);
-  
-  if (is_array($node->webformcomponents) && !empty($node->webformcomponents)) {
-    $options = array();
-    foreach ($node->webformcomponents as $cid => $component) {  
-      $options[$cid] = htmlspecialchars($component['name'], ENT_QUOTES);
-    }
-    
-    if ($node->selected_component > 0) {
-        $default_value = $node->selected_component;
-    }
-    else {
-        $comp_keys = array_keys($node->webformcomponents);
-        $default_value = array_shift($comp_keys);
-    }
-    
-    $form['components']['selected_component'] = array(
-      '#type' => 'radios',
-      '#options' => $options,
-      '#default_value' => $default_value,
-      '#DANGEROUS_SKIP_CHECK' => TRUE,
-    );
-    $form['components']['delete_component'] = array(
-      '#type' => 'submit',
-      '#value' => t('Delete Selected'),
-      '#weight' => 2,
-    );
-    $form['components']['edit_component'] = array(
-      '#type' => 'submit',
-      '#value' => t('Edit Selected'),
-      '#weight' => 2,
-    );
-  }
-
-  $component_types =  _webform_load_components();
-  natcasesort($component_types);
-  $form['components']['webform_newfield_type'] = array(
-    '#type' => 'select',
-    '#title' => t('Add a new component'),
-    '#default_value' => $node->webform_newfield_type,
-    '#options' => $component_types,
-    '#description' => t('Each component adds a new field to the form. Any number components (even of the same type) may be added to the form. Select a component type to add above.'),
-    '#weight' => 3,
-  );
-  $form['components']['add_component'] = array(
-    '#type' => 'submit',
-    '#value' => t('Add'),
-    '#weight' => 4,
-  );
-  /* End Components Form */
-  
-  /* Start E-mail Settings Form */
-  $form['mailsettings'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Mail Settings'),
-    '#collapsible' => TRUE,
-    '#collapsed' => FALSE,
-    '#weight' => -2,
-  );
-  
-  $form['mailsettings']['email'] = array(
-    '#type' => 'textfield',
-    '#title' => t("E-mail to address"),
-    '#default_value' => $node->email,
-    '#description' => t('Form submissions will be e-mailed to this address. Leave blank for none.'),
-  );
-  
-  // Build arrays of possible return email addresses and email subject lines from elements on the form
-  $possible_email_from_name = array('default' => variable_get('webform_default_from_name', variable_get('site_name', '')) .' ['. t('Default') .']', 'none' => '['. t('None') .']');
-  $possible_email_from_address = array('default' => variable_get('webform_default_from_email', variable_get('site_mail', ini_get('sendmail_from'))) .' ['. t('Default') .']', 'none' => '['. t('None') .']');
-  $possible_email_subject = array('default' => variable_get('webform_default_subject', t('Form submission from: ') . t('$title')) .' ['. t('Default') .']', 'none' => '['. t('None') .']');
-  
-  if (is_array($node->webformcomponents) && !empty ($node->webformcomponents)) {
-    foreach ($node->webformcomponents as $cid => $component) {
-      $type = $component['type'];
-      if (in_array($type, array('textfield', 'hidden', 'select'))) {
-        $possible_email_from_name[$component['name']] = $component['name'];
-        $possible_email_subject[$component['name']] = $component['name'];
-      }
-      if (in_array($type, array('email', 'hidden', 'select'))) {
-        $possible_email_from_address[$component['name']] = $component['name'];
-      }
-    }
-  }
-  
-  $form['mailsettings']['email_from_name'] = array(
-    '#type' => 'select',
-    '#title' => t('E-mail from name'),
-    '#default_value' => $node->email_from_name,
-    '#options' => $possible_email_from_name,
-    '#description' => t('After adding components to this form, any textfield or hidden form element may be selected as the sender\'s name for e-mails.'),
-    '#weight' => 6,
-    '#DANGEROUS_SKIP_CHECK' => TRUE,
-  );
-  $form['mailsettings']['email_from_address'] = array(
-    '#type' => 'select',
-    '#title' => t('E-mail from address'),
-    '#default_value' => $node->email_from_address,
-    '#options' => $possible_email_from_address,
-    '#description' => t('After adding components to this form, any e-mail or hidden form element may be selected as the sender\'s address for e-mails.'),
-    '#weight' => 7,
-    '#DANGEROUS_SKIP_CHECK' => TRUE,
-  );
-  $form['mailsettings']['email_subject'] = array(
-    '#type' => 'select',
-    '#title' => t('E-mail subject'),
-    '#default_value' => $node->email_subject,
-    '#options' => $possible_email_subject,
-    '#description' => t('After adding components to this form, any textfield or hidden form element may be selected as the subject line for e-mails.'),
-    '#weight' => 8,
-    '#DANGEROUS_SKIP_CHECK' => TRUE,
-  );
-  
-  /* End mail settings form */
-  
-  /* Start advanced settings form */
-  $form['advanced'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Advanced Settings'),
-    '#collapsible' => TRUE,
-    '#collapsed' => TRUE,
-    '#weight' => -1);
-  
-  
-  $form['advanced']['submitlimit'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Limit the number of submission a user may send within a specified time period.'),
-    '#prefix' => '<div class="container-inline">',
-    '#suffix' => '</div>',
-  );
-  
-  $form['advanced']['submitlimit']['unlimited'] = array(
-    '#name' => 'enforce_limit', // Override the naming scheme to force these radios into the same group
-    '#type' => 'radio',
-    '#return_value' => 'no',
-    '#title' => t('Unlimited'),
-    '#default_value' => ($node->submit_limit > 0 ? false : 'no'),
-    '#parents' => array('advanced', 'submitlimit'), // If we don't specify the parent, the forms API will think this is an illegal posting
-  );
-
-  $form['advanced']['submitlimit']['limited'] = array(
-    '#name' => 'enforce_limit', // Override the naming scheme to force these radios into the same group
-    '#type' => 'radio',
-    '#return_value' => 'yes',
-    '#prefix' => '<br />',
-    '#suffix' => t('Limit to '),
-    '#default_value' => ($node->submit_limit > 0 ? 'yes' : false),
-    '#parents' => array('advanced', 'submitlimit'), // If we don't specify the parent, the forms API will think this is an illegal posting
-  );
-  $form['advanced']['submitlimit']['submit_limit'] = array(
-    '#type' => 'textfield',
-    '#maxlength' => 2,
-    '#size' => 2,
-    '#suffix' => ' '. t('submission(s)') .' ',
-    '#default_value' => ($node->submit_limit > 0 ? $node->submit_limit : ""),
-    '#attributes' => array(
-      'style' => 'width: 2em; display: inline;',
-      'onchange' => "javascript: document.getElementsByName('edit[enforce_limit]').item(1).checked = true;",
-      'onclick' => "javascript: document.getElementsByName('edit[enforce_limit]').item(1).checked = true;"
-    ),
-  );
-  
-  $form['advanced']['submitlimit']['submit_interval'] = array(
-    '#type' => 'select',
-    '#options' => array(
-      '157784630' => t('ever'), // 5 years
-      '1600' => t('every hour'),
-      '86400' => t('every day'),
-      '604800' => t('every week'),
-    ),
-    '#default_value' => $node->submit_interval,
-    '#attributes' => array(
-      'onchange' => "javascript: document.getElementsByName('edit[enforce_limit]').item(1).checked = true;",
-      'onclick' => "javascript: document.getElementsByName('edit[enforce_limit]').item(1).checked = true;"
-    ),
-  );
-  
-  if (user_access('use PHP for additional processing')) {
-    $form['advanced']['additional_validate'] = array(
-      '#type' => 'textarea',
-      '#title' => 'Additional Validation',
-      '#description' => t('Enter PHP code to preform additional validation for this form. Include the &lt;?php ?&gt; tags. $form_id and $form_values are available variables. If validation fails, use the form_set_error function to prevent the form from being submitted. Use the same syntax as a _validate function used in the <a href="http://api.drupal.org/api/4.7/file/developer/topics/forms_api.html">Forms API</a>.'),
-      '#default_value' => $node->additional_validate,
-      '#cols' => 40,
-      '#rows' => 10,
-    );
-    
-    $form['advanced']['additional_submit'] = array(
-      '#type' => 'textarea',
-      '#title' => 'Additional Processing',
-      '#description' => t('Enter PHP code to preform additional processing for this form (after the validation). Include the &lt;?php ?&gt; tags. $form_id and $form_values are available variables, use the same syntax as a _submit function used in the <a href="http://api.drupal.org/api/4.7/file/developer/topics/forms_api.html">Forms API</a>.'),
-      '#default_value' => $node->additional_submit,
-      '#cols' => 40,
-      '#rows' => 10,
-    );
-  }
-  else {
-    $form['advanced']['additional_validate'] = array(
-      '#type' => 'value',
-      '#value' => $node->additional_validate,
-    );
-    
-    $form['advanced']['additional_submit'] = array(
-      '#type' => 'value',
-      '#value' => $node->additional_submit,
-    );
-  }
-  $form['advanced']['redirect_post'] = array(
-    '#type' => 'checkbox',
-    '#title' => t("Redirect POST Values"),
-    '#description' => t("Forward the contents of the POST array to the redirect URL. Use this option for custom processing of the form information. No processing will be done by webform. The confirmation option above MUST be a full redirect URL for this option to have an effect."),
-    '#default_value' => $node->redirect_post,
-  );
-  
-  /* End Advanced Settings Form */
-  
-  // Add hidden form elements containing the contents of the components
-  if (is_array($node->webformcomponents) && !empty($node->webformcomponents)) {
-    $form['webformcomponents'] = array(
-      '#type' => 'fieldset',
-      '#tree' => TRUE,
-      '#attributes' => array('style' => 'display: none;'),
-    );
-    foreach ($node->webformcomponents as $cid => $component) {
-    // Create a hidden field with the component's values
-      $form['webformcomponents'][$cid] = array(
-        '#type' => 'hidden',
-        '#value' => base64_encode(serialize($component)),
-      );
-    }
-  }
-  
-  // Create our forms and display the output:
-  return $form;
-}
-
-/**
- * Theme the node form. Use a standard Drupal table to organize the components fieldset
- *
- * @param array $form
- * @return string Formatted HTML form, ready for display
- */
-function theme_webform_node_form($form) {
-  $node = $form['#node'];
-  $rows = array();
-  if (is_array($node->webformcomponents) && !empty($node->webformcomponents)) {
-    $component_tree = array();
-    $page_count = 1;
-    _webform_components_tree_build($node->webformcomponents, $component_tree, 0, $page_count);
-    $component_tree = _webform_components_tree_sort($component_tree);
-    // Build the table rows
-    function _webform_add_rows($cid, $component, $level, &$form, &$rows) { 
-      // Create presentable values
-      if (strlen($component['value']) > 30) {
-        $component['value'] = htmlspecialchars(substr($component['value'], 0, 30), ENT_QUOTES);
-        $component['value'] .= "...";
-      }
-      
-      // Add padding to the radio label
-      $form['components']['selected_component'][$cid]['#title'] = '<span style="padding-left: '. ($level * 15) .'px; padding-right: 20px;">'. $form['components']['selected_component'][$cid]['#title'] .'</span>';
-      
-      // Add each component to a table row
-      $rows[] = array(
-        drupal_render($form['components']['selected_component'][$cid]),
-        $component['type'],
-        ($component['value'] == "") ? "-" : $component['value'],
-        ($component['mandatory'] == 1) ? "Y" : "N" ,
-        $component['weight'],
-      );
-      if (is_array($component['children'])) {
-        foreach ($component['children'] as $cid => $component) {
-          _webform_add_rows($cid, $component, $level + 1, $form, $rows);
-        }
-      }
-    }
-    foreach ($component_tree['children'] as $cid => $component) {
-      _webform_add_rows($cid, $component, 0, $form, $rows);
-    }
-  }
-  else {
-    $rows[] = array(NULL, array('data' => t("No Components, add a component below."), 'colspan' => 5));
-  }
-
-  $headers = array(
-    array('data' => t('Name'), 'style' => 'padding-left: 30px'),
-    t('Type'),
-    t('Value'),
-    t('Mandatory'),
-    t('Weight'),
-  );
-  $component_table .= theme('table', $headers, $rows);
-
-  $form['components']['table'] = array(
-    '#value' => $component_table,
-  );
-  return drupal_render($form);
-}
-
-function webform_edit_field_form(&$node) {
-  // This is the information about the current field.
-  $currfield = array();
-
-  if ($_POST['op'] == t('Edit Selected')) {
-    // Check to make sure a valid component id was selected
-    $cid = $_POST['selected_component'];
-    $component = $node->webformcomponents[$cid];
-    if (empty($component)) {
-      drupal_set_message(t('Component not found'), 'error');
-      drupal_set_title("Webform Error");
-      return array();
-    }
-    // We are editing a existing field.
-    // Fetch all filed data into the $currfield object.
-    $currfield['key'] = $cid;
-    $currfield['form_key'] = $component['form_key'] ? $component['form_key'] : $cid;
-    $currfield['type'] = $component['type'];
-    $currfield['name'] = $component['name'];
-    $currfield['default'] = $component['value'];
-    $currfield['parent'] = $component['parent'];
-    $currfield['weight'] = $component['weight'];
-    $currfield['mandatory'] = $component['mandatory'];
-    $currfield['extra'] = $component['extra'];
-    drupal_set_title("Edit component: ". $currfield['name'] ." (". $currfield['type'] .")");
-  }
-  else {
-    // Check to make sure a valid component type was selected
-    $component_types =  _webform_load_components();
-    $new_component_type = $_POST['webform_newfield_type'];
-    if (empty($new_component_type) || !key_exists($new_component_type, $component_types)) {
-      drupal_set_message(t('Unknown component type %component', array('%component' => $new_component_type)), 'error');
-      drupal_set_title("Webform Error");
-      print theme('page', "");
-      return;
-    }
-    // We are editing a new field.
-    $currfield['key'] = time();
-    $currfield['form_key'] = $currfield['key'];
-    $currfield['type'] = $_POST['webform_newfield_type'];
-    $currfield['name'] = $currfield['type'] ."_". $currfield['key'];
-    drupal_set_title(t("Add new %type component", array('%type' => $currfield['type'])));
-  }
-  
-  // Construct the form:
-  $form = array();
-  
-  // Print the correct field type specification
-  // We always need: name and description.
-  $form['field'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Field Details'),
-    '#collapsible' => FALSE,
-    '#collapsed' => FALSE,
-    '#weight' => 5,
-    '#tree' => TRUE,
-  );
-  
-  
-  $form['field']['type'] = array(
-    '#type' => 'hidden',
-    '#value' => $currfield['type'],
-  );
-  $form['field']['key'] = array(
-    '#type' => 'hidden',
-    '#value' => $currfield['key'],
-  );
-  $form['field']['form_key'] = array(
-    '#type' => 'textfield',
-    '#default_value' => $currfield['form_key'],
-    '#title' => t('Field Key'),
-    '#description' => t('Enter a machine readable key for this form element. May contain only alphanumeric characters and underscores. This key will be used as the name attribute of the form element.'),
-    '#required' => TRUE,
-    '#weight' => -2,
-  );
-  $form['field']['name'] = array(
-    '#type' => 'textfield',
-    '#default_value' => $currfield['name'],
-    '#title' => t("Label"),
-    '#description' => t('This is used as a descriptive label when displaying this form element.'),
-    '#required' => TRUE,
-    '#weight' => -1,
-  );
-  $form['field']['extra']['description'] = array(
-    '#type' => 'textfield',
-    '#default_value' => $currfield['extra']['description'],
-    '#title' => t("Description"),
-    '#maxlength' => '512',
-    '#description' => t('A short description of the field used as help for the user when he/she uses the form.') .'<br />'. webform_help('webform/helptext#variables'),
-    '#weight' => -1,
-  );
-  
-  $form['field']['mandatory'] = array(
-    '#type' => 'checkbox',
-    '#title' => t("Mandatory"),
-    '#default_value' => ($currfield['mandatory'] == '1' ? TRUE : FALSE),
-    '#description' => t('Check this option if the user must enter a value.'),
-    '#weight' => 2,
-  );
-  
-  if (variable_get('webform_enable_fieldset', true) && is_array($node->webformcomponents)) {
-    $options = array('0' => t('Root'));
-    foreach ($node->webformcomponents as $thiscid => $value) {
-      if ($value['type'] == 'fieldset' && $thiscid != $cid) {
-        $options[$thiscid] = htmlspecialchars($value['name'], ENT_QUOTES);
-      }
-    }
-    $form['field']['parent'] = array(
-      '#type' => 'select',
-      '#title' => t("Parent Fieldset"),
-      '#default_value' => $currfield['parent'],
-      '#description' => t('Optional. You may organize your form by placing this component inside inside another fieldset.'),
-      '#options' => $options,
-      '#weight' => 2,
-    );
-  }
-  
-  $form['field']['weight'] = array(
-    '#type' => 'weight',
-    '#delta' => count($_POST['webformcomponents']) > 10 ? count($_POST['webformcomponents']) : 10,
-    '#title' => t("Weight"),
-    '#default_value' => $currfield['weight'],
-    '#description' => t('Optional. In the menu, the heavier items will sink and the lighter items will be positioned nearer the top.'),
-    '#weight' => 2,
-  );
-
-  // Add the fields specific to this component type:  
-  _webform_load_components(); // Load all component types
-  $edit_function = "_webform_edit_". $currfield['type'];
-  $additional_form_elements = array();
-  if (function_exists($edit_function)) {
-    $additional_form_elements = $edit_function($currfield); // Call the component render function
-  }
-  else {
-    drupal_set_message(t("The webform component of type @type does not have an edit function defined.", array('@type' => $currfield['type'])));
-  }
-
-  // Merge the additional fields with the current fields:
-  $extra_fields_copy = $form['field']['extra'];
-  $form['field'] = array_merge($form['field'], $additional_form_elements);
-  $form['field']['extra'] = array_merge((array)$extra_fields_copy, (array)$additional_form_elements['extra']);
-  
-  // Add the submit button
-  $form['field']['submit'] = array(
-    '#type' => 'submit',
-    '#value' => t("Done"),
-    '#weight' => 3,
-  );
-
-  // Create hidden form elements to restore all the settings on the node edit form
-  $form['node'] = array(
-    '#tree' => TRUE,
-  );
-
-  // Recursively create hidden form elements for all fields on the node form
-  function _webform_edit_field_form_hiddens(&$form, $key, $value) {
-    if (is_array($value)) {
-      foreach ($value as $k => $v) {
-        _webform_edit_field_form_hiddens($form[$key], $k, $v);
-      }
-    }
-    else {
-      $form[$key] = array(
-        '#type' => 'hidden',
-        '#value' => $value
-      );
-    }
-  }
-  _webform_edit_field_form_hiddens($form, 'node', $_POST);
-
-  return $form;
-}
-
-/**
- * Field name validation for the webform unique key. Must be alphanumeric.
- */
-function webform_edit_field_form_validate($form_values) {
-  if (!preg_match('!^[a-z0-9_]+$!', $form_values['form_key'])) {
-    form_set_error('field][form_key', t('The field name %field_name is invalid.', array('%field_name' => $form_values['form_key'])));
-  }
-
-  // Let the field do any additional validation.
-  _webform_load_components($form_values['type']);
-  $validate_function = '_webform_edit_validate_'. $form_values['type'];
-  if (function_exists($validate_function)) {
-    $validate_function($form_values);
-  }
-}
-
-/**
- * Implementation of hook_forms(). All webform_client_form forms share the same form handler
- */
-function webform_forms() {
-  global $_webform_form_list;
-
-  if (is_array($_webform_form_list)) {
-    foreach ($_webform_form_list as $form_id) {
-      $forms['webform_client_form_'. $form_id]['callback'] = 'webform_client_form';
-    }
-  }
-  return $forms;
-}
-
-function webform_view(&$node, $teaser = 0, $page = 0) {
-  // If a teaser, do not display the form
-  if ($teaser) {
-    $node->content['teaser'] = array('#value' => check_markup($node->teaser, $node->format, FALSE));
-    return $node;
-  }
-  
-  include_once(drupal_get_path('module', 'webform') ."/webform.inc");
-  
-  $sid_to_display = check_plain($_GET['sid']); // Will be NULL if no sid
-  $submission = array();
-  $preview = false;
-  $node->webformcomponents = _webform_components_decode($node->webformcomponents);
-  
-  if ($_POST['op'] == t('Preview')) {
-    webform_prepare($node);
-  }
-
-  if ($sid_to_display && is_numeric($sid_to_display)) {
-    if (user_access('access webform results')) {
-      drupal_set_title('Submission #'. $sid_to_display);
-      $node->body = "";
-      $submission = _webform_fetch_submission($sid_to_display, $node->nid);
-    }
-    else {
-      $sid_to_display = NULL; // This user is not allowed to access a submitted node. Deny the attempt without alert.
-      watchdog('webform', t('Unauthorized webform access attempt by %name.', array('%name' => $user->name)), WATCHDOG_WARNING); // and log the attempt
-    }
-  }
-  
-  global $_webform_form_list;
-  $_webform_form_list[] = $node->nid;
-  $output = drupal_get_form('webform_client_form_'. $node->nid, $node, $submission);
-
-  // Remove the surrounding <form> tag if this is a preview
-  if ($preview) {
-    $output = preg_replace('/<\/?form[^>]*>/', '', $output);
-  }
-  
-  $node->content['body'] = array('#value' => check_markup($node->body, $node->format, FALSE));
-  $node->content['webform'] = array('#value' => $output, '#weight' => 10);
-  
-  return $node;
-} // end webform_view
-
-/**
- * Client form generation function. If this is displaying an existing
- * submission, pass in the $submission variable with the contents of the
- * submission to be displayed.
- */
-function webform_client_form(&$node, $submission = array(), $form_values = NULL) {
-  global $user;
-  
-  _webform_load_components(); // Load all the components
-  
-  if ($_POST['op'] == t('Preview')) {
-    $preview = true;
-  }
-  
-  if (module_exists('profile')) {
-    profile_load_profile($user);
-  }
-  
-  if ($node->redirect_post && valid_url(trim($node->confirmation), true)) {
-    $form['#action'] = trim($node->confirmation);
-  }
-  
-  // Add a theme function for this form
-  $form['#theme'] = 'webform_form_'. $node->nid;
-  // Set the encoding type (necessary for file uploads)
-  $form['#attributes']['enctype'] = 'multipart/form-data';
-  $form['#base'] = 'webform_client_form';
-  
-  if (is_array($node->webformcomponents) && !empty($node->webformcomponents)) {
-    // Prepare a new form array
-    $form['submitted'] = array(
-      '#tree' => TRUE
-    );
-    $form['details'] = array(
-      '#tree' => true,
-    );
-    
-    // Put the components into a tree structure
-    $component_tree = array();
-    $page_count = 1;
-    _webform_components_tree_build($node->webformcomponents, $component_tree, 0, $page_count);
-
-    if (!$preview && empty($submission)) {
-      if ($page_count > 1) {
-        $next_page = t('Next Page >');
-        $prev_page = t('< Previous Page');
-        if (isset($form_values)) {
-          $page_num = $form_values['details']['page_num'];
-          if ($form_values['op'] == $prev_page && $page_num > 1) {
-            $page_num--;
-          }
-          else if ($form_values['op'] == $next_page && $page_num < $page_count) {
-            $page_num++;
-          }
-        }
-        else {
-          $page_num = 1;
-        }
-  
-        $form['#multistep'] = TRUE;
-        $form['#redirect'] = FALSE;
-  
-        $form['details']['page_num'] = array(
-          '#type'      => 'hidden',
-          '#value'     => $page_num,
-        );
-        // Add the submit button(s)
-        if ($page_num > 1) {
-          $form['submitbutton_prev'] = array(
-            '#type' => 'submit',
-            '#value' => $prev_page,
-            '#weight' => 1000,
-          );
-        }
-        if ($page_num == $page_count) {
-          $form['submitbutton'] = array(
-            '#type' => 'submit',
-            '#value' => t('Submit'),
-            '#weight' => 1001,
-          );
-        }
-        else if ($page_num < $page_count) {
-          $form['submitbutton_next'] = array(
-            '#type' => 'submit',
-            '#value' => $next_page,
-            '#weight' => 1001,
-          );
-        }
-      }
-      else {
-        $page_num = 1;
-        // Add the submit button
-        $form['submitbutton'] = array(
-          '#type' => 'submit',
-          '#value' => t('Submit'),
-          '#weight' => 1000,
-        );
-      }
-    }
-
-    // Recursively add components to the form
-    foreach ($component_tree['children'] as $cid => $component) {
-      _webform_client_form_add_component($cid, $component, $form['submitted'], $form, $submission, $page_num);
-    }
-    // Do not display the submit button if this is a preview or submission view
-    if (!$preview && empty($submission)) {
-      // Additional hidden elements   
-      // Email subject and sender
-      $form['details']['email_subject'] = array(
-        '#type'      => 'hidden',
-        '#value'     => $node->email_subject,
-      );
-      $form['details']['email_from_name'] = array(
-        '#type'      => 'hidden',
-        '#value'     => $node->email_from_name,
-      );
-      $form['details']['email_from_address'] = array(
-        '#type'      => 'hidden',
-        '#value'     => $node->email_from_address,
-      );
-      $form['details']['nid'] = array(
-        '#type'      => 'value',
-        '#value'     => $node->nid,
-      );
-    }
-  }
-  
-  return $form;
-}
-
-function _webform_client_form_add_component($cid, $component, &$parent_fieldset, &$form, $submission, $page_num) {
-  // Load with submission information if necessary
-  if (!empty($submission)) {
-    // This component is display only, with the value set according information
-    // previously submitted in the submission numbered $sid_to_display
-    $display_function = "_webform_submission_display_". $component['type'];
-    if (function_exists($display_function)) {
-      $parent_fieldset[$component['form_key']] = $display_function($submission['data'][$cid], $component);
-    }
-  }
-  else if ($component['page_num'] == $page_num) {
-    // Add this user-defined field to the form (with all the values that are always available)      
-    $render_function = "_webform_render_". $component['type'];
-    if (function_exists($render_function)) {
-      $parent_fieldset[$component['form_key']] = $render_function($component); // Call the component render function
-    }
-    else {
-      drupal_set_message(t("The webform component @type is not able to be displayed", array('@type' => $component['type'])));
-    }
-  }
-  
-  if (is_array($component['children'])) {
-    foreach ($component['children'] as $scid => $subcomponent) {
-      _webform_client_form_add_component($scid, $subcomponent, $parent_fieldset[$component['form_key']], $form, $submission, $page_num);
-    }
-  }
-}
-
-function webform_client_form_validate($form_id, $form_values) {
-  global $user, $base_url;
-  include_once(drupal_get_path('module', 'webform') ."/webform.inc");
-  $node = node_load(array('nid' => $form_values['details']['nid']));
-
-  // Flatten trees within the submission
-  $form_values['submitted_tree'] = $form_values['submitted'];
-  _webform_client_form_submit_flatten($node, $form_values['submitted'], $form_values['submitted']);
-
-  // Verify that this submission is within the submission limits on this form
-  if ($violation_count = _webform_submission_limit_check ($node, $form_values)) {
-    // If the webform is being swamped by repeated entries, limit the messages in watchdog
-    if ($violation_count < 21) {
-      if ($user->uid > 0) {
-        watchdog('webform', t('The authenticated user <a href="%user_url">%username</a> attempted to submit more entries than allowed on the <a href="%webform_url">%webform_title</a> webform',
-                              array(
-                                '%user_url' => url('user/'. $user->uid),
-                                '%username' => $user->name,
-                                '%webform_url' => url('node/'. $node->nid),
-                                '%webform_title' => $node->title,
-                              )), WATCHDOG_WARNING);
-      }
-      else {
-        watchdog('webform', t('An anonymous user with IP address %ip attempted to submit more entries than allowed on the <a href="%webform_url">%webform_title</a> webform',
-                              array(
-                                '%ip' => $_SERVER['REMOTE_ADDR'],
-                                '%webform_url' => url('node/'. $node->nid),
-                                '%webform_title' => $node->title,
-                              )), WATCHDOG_WARNING);
-      }
-    }
-    form_set_error('', t("You have submitted the maximum number of entries. Check submission guidelines."));
-  }
-  
-  if (trim($node->additional_validate)) {
-    // We use eval here (rather than drupal_eval) because the user needs access to local variables
-    eval("?>".$node->additional_validate);
-  }
-}
-
-function webform_client_form_submit($form_id, $form_values) {
-  global $user, $base_url;
-  include_once (drupal_get_path('module', 'webform')."/webform.inc");
-  $node = node_load(array('nid'=>$form_values['details']['nid']));
-  $session_key = 'webform_form_'.$node->nid;
-
-  if ($form_values['op'] != t('Submit')) {
-    // This is a multi-page form that is not yet complete.
-    // Copy values stored during previous steps into $_POST because they are needed in form_builder() to repopulate the form.
-    if (is_array($_SESSION[$session_key])) {
-      foreach ($_SESSION[$session_key] as $key => $val) {
-        $_POST['submitted'][$key] = $val;
-      }
-    }
-
-    // Store values from an intermediate stage of a multistep form in $_SESSION
-    if (is_array($form_values['submitted'])) {
-      foreach ($form_values['submitted'] as $key => $val) {
-        $_SESSION[$session_key][$key] = $val;
-      }
-    }
-    return;
-  }
-
-  $form_values['submitted_tree'] = $form_values['submitted'];
-  if (is_array($_SESSION[$session_key])) {
-    // Merge any submission data stored in $_SESSION for multistep forms
-    foreach ($_SESSION[$session_key] as $key => $val) {
-      $form_values['submitted'][$key] = $val;
-    }
-    unset($_SESSION[$session_key]);
-  }
-
-  // Flatten trees within the submission
-  _webform_client_form_submit_flatten($node, $form_values['submitted'], $form_values['submitted']);
-
-  // Process post-submission data if necessary in the components
-  _webform_load_components();
-  foreach ($node->webformcomponents as $cid => $component) {
-    $submit_function = "_webform_submit_".$component['type'];
-    if (function_exists($submit_function)) {
-      $submit_function($form_values['submitted'][$cid], $component); // Call the component process submission function
-    }
-  }
-
-  // Perform additional submit processing
-  if (trim($node->additional_submit)) {
-    // We use eval here (rather than drupal_eval) because the user needs access to local variables
-    eval("?>".$node->additional_submit);
-  }
-  
-  // Save the submission to the database
-  $sid = _webform_save_submission($node, $form_values['submitted']);
-  
-  // Check if this form is sending an email
-  if (isset ($node->email)) {
-    $node->email = strip_tags($node->email);
-    if (!empty ($node->email)) {
-    
-      // Create a themed message for mailing
-      // Check for a node-specific message:
-      $message = theme("webform_create_mailmessage_$node->nid", $form_values, $node, $sid);
-      if (!$message) {
-        // Otherwise use the generic form:
-        $message = theme("webform_create_mailmessage", $form_values, $node, $sid);
-      }
-      
-      // Build arrays of possible return email addresses and email subject lines from elements on the form
-      
-      // Default values:
-      $email_from_name = variable_get('webform_default_from_name', variable_get('site_name', ''));
-      $email_from_address = variable_get('webform_default_from_email', variable_get('site_mail', ini_get('sendmail_from')));
-      $email_subject_string = variable_get('webform_default_subject', t('Form submission from: ')) . ' ' . $node->title;
-      $headers = array();
-
-      // Check for empty values
-      if (strcmp('none', $node->email_from_name)) {
-        $email_from_name = '';
-      }
-      if (strcmp('none', $node->email_from_address)) {
-        $email_from_address = '';
-      }
-      if (strcmp('none', $node->email_subject)) {
-        $email_subject_string = '';
-      }
-
-      // Search for user set FROM and SUBJECT fields
-      if (is_array($node->webformcomponents) && !empty ($node->webformcomponents)) {
-        foreach ($node->webformcomponents as $cid => $component) {
-          $type = $component['type'];
-          // Find and set a custom FROM: field
-          if ($type == 'email' || $type == 'hidden') {
-            if ($component['name'] == $node->email_from_address) {
-              $email_from_address = $form_values['submitted'][$cid];
-            }
-          }
-          // Find and set a custom SUBJECT: field
-          if ($type == 'textfield' || $type == 'hidden') {
-            if ($component['name'] == $node->email_from_name) {
-              $email_from_name = strip_tags($form_values['submitted'][$cid]);
-            }
-            if ($component['name'] == $node->email_subject) {
-              $email_subject_string = strip_tags($form_values['submitted'][$cid]);
-            }
-          }
-          if ($type == 'email' && $component['extra']['carboncopy'] == 'Y' ) {
-            $headers['Cc'] = $form_values['submitted'][$cid];
-          }
-        }
-      }
-      
-      // Assemble the FROM string
-      if (strlen($email_from_name) > 0) {
-        $email_from_string = $email_from_name . ' <' . $email_from_address . '>';
-      }
-      else {
-        $email_from_string = $email_from_address;
-      }
-
-      // Verify that this submission is not attempting to send any spam hacks
-      if (_webform_submission_spam_check($node->email, $email_subject_string, $message, $email_from_string, $headers)) {
-        watchdog('webform', t('Possible spam attempt from ').$_SERVER['REMOTE_ADDR']."<br />\n".nl2br(htmlentities($message)), WATCHDOG_WARNING);
-        drupal_set_message(t("Illegal information. Data not submitted."), 'error');
-        return false;
-      }
-      // Additional headers
-      $headers['X-Mailer'] = 'Drupal Webform (PHP/' . phpversion() . ')';
-    
-      // Mail the webform results
-      drupal_mail('webform-submission', $node->email, $email_subject_string, $message, $email_from_string, $headers);
-      
-      // Debugging output
-      if (variable_get('webform_debug', 0) >= 2) {
-        drupal_set_message("E-mail Headers: <pre>". print_r($headers, true) ."</pre>To: " . $node->email . "<br />From: " . htmlentities($email_from_string) . "<br />Subject: " . $email_subject_string . "<br />E-mail Body: <pre>".$message."</pre>");
-      }
-    }
-  }
-   
-  if (variable_get('webform_debug', 0) >= 1) {
-    watchdog('webform', t('Submission posted to %title', array('%title' => $node->title)) . l(t('Results'), 'node/'.$node->nid, NULL, 'sid='.$sid)."<br />\n".nl2br(htmlentities($message)), WATCHDOG_NOTICE);
-  }
-  
-  // Check confirmation field to see if redirect should be to another node or a message
-  if (valid_url(trim($node->confirmation), true)) {
-    return trim($node->confirmation);
-  }
-  elseif (preg_match('/^internal:/', $node->confirmation)) {
-    $path = preg_replace('/^internal:/', '', $node->confirmation);
-    return array($path, 'sid=' . $sid);
-  }
-  else {
-    return array('node/'.$node->nid.'/done', 'sid=' . $sid);
-  }
-} // end webform_client_form_submit
-
-/**
- * Flattens a submitted form back into a single array representation (rather than nested fields)
- */
-function _webform_client_form_submit_flatten($node, $fieldset, &$form) {
-  if (is_array($fieldset)) {
-    foreach ($fieldset as $form_key => $value) {
-      $cid = webform_get_cid($node, $form_key);
-      if (is_array($value) && $node->webformcomponents[$cid]['type'] == 'fieldset') {
-        _webform_client_form_submit_flatten($node, $value, $form);
-        unset($form[$form_key]);
-        unset($form[$cid]);
-      }
-      else {
-        // the order here is significant!
-        unset($form[$form_key]);
-        $form[$cid] = $value;
-      }
-    }
-  }
-}
-
-/**
- * Prints the confirmation message after a successful submission.
- */
-function _webform_confirmation($nid) {
-  if ($node = node_load(array('nid' => $nid))) {
-    if (node_access('view', $node)) {
-      drupal_set_title($node->title);
-      return theme('webform_confirmation', $node);
-    }
-    else {
-      drupal_access_denied();
-    }
-  }
-  else {
-    drupal_set_message(t("No node with the id '%nid' could be found", array('%nid'=>$nid)));
-    drupal_not_found();
-  }
-} // end _webform_confirmation
-
-/**
- * Themable function for webform submission confirmation
- */
-function theme_webform_confirmation($node) {
-  $node->body = check_markup($node->confirmation, $node->format, FALSE);
-  $node->links['webform_back'] = array(
-    'href' => 'node/'.$node->nid,
-    'title' => t('Go back to the form'),
-  );
-  return theme('node', $node, FALSE, TRUE);
-}
-
-/** 
- * Filters all special chars
- **/
-function _webform_filtervalues($string, $strict = TRUE) {
-  global $user;
-
-  $find= array('%username', '%useremail', '%site', '%date');
-  $replace= array($user->name, $user->mail, variable_get('site_name', 'drupal'), format_date(time(), 'large'));
-
-  if (module_exists('profile')) {
-    foreach ($user as $k => $v) {
-      // Special case for dates
-      $find[]= "%profile[$k]";
-      if (is_array($v) && $v['year']) {
-        $replace[] = format_date(strtotime($v['month'] .'/'. $v['day'] .'/'. $v['year']), 'custom', 'F j, Y', '0');
-      }
-      else {
-        $replace[] = $v;
-      }
-    }
-  }
-  foreach ($_SERVER as $k => $v) {
-    $find[]= "%server[$k]";
-    $replace[]= $v;
-  }
-  foreach ($_GET as $k => $v) {
-    $find[] = "%get[$k]";
-    $replace[] = $v;
-  }
-  foreach ($_POST as $k => $v) {
-    $find[] = "%post[$k]";
-    $replace[] = $v;
-  }
-  $string= str_replace($find, $replace, $string);
-
-  if (module_exists('profile')) {
-    // Clean up any unused %profile stuff
-    $string= preg_replace('/\%profile\[\w+\]/', '', $string);
-  }
-  // Clean up any unused %post and %get stuff
-  $string= preg_replace('/\%get\[\w+\]/', '', $string);
-  $string= preg_replace('/\%post\[\w+\]/', '', $string);
-  // Clean up any unused %system stuff
-  $string= preg_replace('/\%server\[\w+\]/', '', $string);
-
-  if ($strict) {
-    return filter_xss($string);
-  }
-  else {
-    return $string;
-  }
-} // end _webform_filtervalues
-
-function _webform_save_submission($node, $submitted) {
-  global $user;
-
-  $sid = db_next_id('{webform_submissions}_sid');
-  
-  db_query("INSERT INTO {webform_submissions} (nid, sid, uid, submitted, remote_addr) "." VALUES (%d, %d, %d, %d, '%s')", $node->nid, $sid, $user->uid, time(), $_SERVER['REMOTE_ADDR']);
-
-  foreach ($submitted as $cid => $value) {
-    if (is_array($value)) {
-      $delta = 0;
-      foreach ($value as $k => $v) {
-        db_query("INSERT INTO {webform_submitted_data} (nid, sid, cid, no, data) "."VALUES (%d, %d, %d, %d, '%s')", $node->nid, $sid, $cid, $delta, $v);
-        $delta++;
-      }
-    }
-    else {
-      db_query("INSERT INTO {webform_submitted_data} (nid, sid, cid, no, data) "."VALUES (%d, %d, %d, %d, '%s')", $node->nid, $sid, $cid, 0, $value);
-    }
-  }
-  
-  return $sid;
-}
-
-function webform_page() {
-  include_once (drupal_get_path('module', 'webform')."/webform.inc");
-  return _webform_page();
-}
-
-/**
- * function webform_results() is an allocator function that builds the page
- * under the 'Results' sub menu The function uses the URL tail to nominate
- * internal content.
- */
-function webform_results() {
-  include_once (drupal_get_path('module', 'webform')."/webform.inc");
-  include_once (drupal_get_path('module', 'webform')."/webform_report.inc");
-
-  $nid= arg(1);
-  $node= node_load(array('nid' => $nid));
-
-  $title= $node->title;
-  drupal_set_title($title);
-
-  if (arg(2) == 'results') {
-
-    switch (arg(3)) {
-      case 'analysis' :
-        $content= _webform_results_analysis($nid);
-        break;
-      case 'clear' :
-        $content= drupal_get_form('_webform_results_clear', $nid);
-        break;
-      case 'delete' :
-        $sid= arg(4);
-        $content= drupal_get_form('_webform_submission_delete', $nid, $sid);
-        break;
-      case 'table' :
-        $content= _webform_results_table($nid);
-        break;
-      case 'download' :
-        $content= _webform_results_download($nid);
-        break;
-      case 'submissions' :
-      default :
-        $content= _webform_results_submissions($nid);
-        break;
-    }
-
-    return $content;
-  }
-}
-
-function webform_get_cid($node, $form_key) {
-  foreach ($node->webformcomponents as $cid => $component) {
-    if ($component['form_key'] == $form_key) {
-      return $cid;
-    }
-  }
-}
-
-function _webform_safe_name($name) {
-  $new = drupal_strtolower(trim($name));
-  $new = str_replace(' ', '_', $new);
-  $new = preg_replace('/[^a-z0-9_]/', '', $new);
-  // If the string contains NO safe characters, base64 encode the answer
-  if ($new == '') {
-    $new = base64_encode($name);
-  }
-  return $new;
-}
-
-function _webform_components_decode($components) {
-  if (is_array($components)) {
-    foreach ($components as $cid => $value) {
-      if (is_string($value)) {
-        $components[$cid] = unserialize(base64_decode($value));
-      }
-    }
-  }
-  return $components;
-}
-
-/**
- * Convert an array of components into a tree
- */
-function _webform_components_tree_build($src, &$tree, $parent, &$page_count) {
-  foreach ($src as $cid => $component) {
-    if ($component['parent'] == $parent) {
-      _webform_components_tree_build($src, $component, $cid, $page_count);
-      $tree['children'][$cid] = $component;
-      $tree['children'][$cid]['page_num'] = $page_count;
-      if ($component['type'] == 'pagebreak') {
-        $page_count++;
-      }
-    }
-  }
-  return $tree;
-}
-
-/**
- * Helper for the uasort in webform_tree_sort()
- */
-function _webform_components_sort($a, $b) {
-  if ($a['weight'] == $b['weight']) {
-    return strcasecmp($a['name'], $b['name']);
-  }
-  return ($a['weight'] < $b['weight']) ? -1 : 1;
-}
-
-
-/**
- * Sort each level of a component tree by weight and name
- */
-function _webform_components_tree_sort($tree) {
-  if (is_array($tree['children'])) {
-    uasort($tree['children'], "_webform_components_sort");
-    foreach ($tree['children'] as $cid => $component) {
-      $return[$cid] = _webform_components_tree_sort($component);
-    }
-    $tree['children'] = $return;
-  }
-  return $tree;
-}
-
-function _webform_load_components($return_all = false) {
-  static $component_list;
-  
-  if (!isset($component_list)) {
-    $component_list = array();
-    $path = drupal_get_path('module', 'webform')."/components";
-    $files = file_scan_directory($path, '^.*\.inc$');
-    foreach ($files as $filename => $file) {
-      if ($return_all || variable_get('webform_enable_'.$file->name, 1)) {
-        include_once($filename);
-        $component_list[$file->name] = t($file->name);
-      }
-    }
-  }
-  return $component_list;
-}
+<?php
+
+// $Id: webform.module,v 1.113.2.38 2007/06/13 00:47:19 quicksketch Exp $
+
+/**
+ * This module provides a simple way to create forms and questionnaires.
+ * The development of this module was sponsered by ?F Industri AB, Open
+ * Source City and Karlstad University Library.
+ *
+ * @author Pontus Ullgren <ullgren@user.sourceforge.net>
+ * @author Nathan Haug <nate at lullabot dot com>
+ * @package module_webform
+ * @copyright Pontus Ullgren 2003-2005
+ **/
+
+/** 
+ * Hook Help - used to retrieve help texts and general infomation about the module
+ * @param section specifies the section to display help for.
+ * @return a formated string containing the help output.
+ **/
+function webform_help($section= "admin/help#webform") {
+  $output= "";
+  switch ($section) {
+    case 'admin/settings/webform' :
+      $output = t("Webforms are forms and questionnaires. To add one select <strong>create content -&gt; webform</strong>. Below you can set different security and debug options.");
+      break;
+    case 'admin/help#webform' :
+      $output = t("<p>This module lets you create forms or questionnaires and define their content. Submissions from these forms are stored in the database and optionally also sent by e-mail to a predefined address.</p>
+      <p>Here is how to create one:</p>
+      <ul>
+       <li>Go to Create Content and add a webform</li>
+       <li>Add a description to be displayed as a teaser and above the actual form.</li>
+       <li>Add a confirmation message or redirect node that is to be displayed after successful submission.</li>
+       <li>Add one or more components to your form.</li>
+       <li>Optionally add an e-mail address to which submissions will be sent. If no email address is specified, no e-mail will be sent when submissions are made through the form.</li>
+       <li>Optionally select an e-mail (or hidden) component that will be used to populate the return e-mail address on any sent e-mail.</li>
+       <li>Optionally select a textfield (or hidden) component that will be used to populate the subject e-mail field on any sent e-mail.</li>
+      </ul>
+      <p>Help on adding and configuring the components will be shown after you add your first component.</p>
+      <p>The content of submitted forms is stored in the database table <i>webform_submitted_data</i> as key-value pairs.</p>
+      ");
+      break;
+    case 'node/add#webform' :
+      $output = t("A webform can be a questionnaires, contact or request forms. It can be used to let visitors make contact, register for a event or to enable a complex survey.");
+      break;
+    case 'webform/helptext#variables' :
+      $output = t('Available variables are: %username, %useremail, %site, %date.');
+      $output .= ' '. t('You can also use %server[key] to add any of the special PHP <a href="http://www.php.net/reserved.variables#reserved.variables.server">$_SERVER</a> variables and %get[key] to create prefilled forms from the <a href="http://www.php.net/reserved.variables#reserved.variables.get">URL</a> (e.g. %server[HTTP_USER_AGENT] or %get[id]).');
+      if (module_exists('profile')) {
+        $output .= ' '. t('If you are using the profiles module, you can also access all profile data using the syntax %profile[form_name]. If you for example have a profile value named profile_city, add the varible %profile[profile_city].');
+      }
+      break;
+  }
+  // Call help hooks in plugins:
+  $components = _webform_load_components();
+  foreach ($components as $component) {
+    $help_function = "_webform_help_". $component;
+    if (function_exists($help_function)) {
+      $output .= $help_function($section);
+    }
+  }
+  return $output;
+}
+
+function webform_perm() {
+  return array("create webforms", "edit own webforms", "edit webforms", "access webform results", "clear webform results", "edit own webform submissions", "edit webform submissions", "use PHP for additional processing");
+}
+
+/**
+ * Implementation of hook_node_info().
+ */
+function webform_node_info() {
+  return array(
+    'webform' => array(
+      'name' => t('Webform'),
+      'module' => 'webform',
+      'description' => t('Create a new form or questionnaire accessible to users. Submission results and statistics are recorded and accessible to privileged users.'),
+    )
+  );
+}
+
+function webform_access($op, $node) {
+  global $user;
+
+  switch ($op) {
+    case "create":
+      return user_access("create webforms");
+    case "edit":
+    	return user_access("edit webform submissions") || (user_access("edit own webform submissions") && ($user->uid == $node->uid));
+    case "update":
+    case "delete":
+      return user_access("edit webforms") || (user_access("edit own webforms") && ($user->uid == $node->uid));
+  }
+}
+
+function webform_insert($node) {
+  global $user;
+  // Correctly set the submission limits
+  if ($_POST['enforce_limit'] === 'no') {
+    $node->submit_limit = '-1';
+    $node->submit_interval = '157784630'; // 5 years, close enough to 'ever'
+  }
+  
+  // Re-add existing components from the POST array
+  if (isset($_POST['webformcomponents'])) {
+    unset($node->webformcomponents);
+    $node->webformcomponents = _webform_components_decode($_POST['webformcomponents']);
+  }
+  
+  // Insert the Webform
+  db_query("INSERT INTO {webform} (nid, confirmation, redirect_post, submit_limit, submit_interval, email, email_from_name, email_from_address, email_subject, additional_validate, additional_submit) VALUES (%d, '%s', %d, %d, %d, '%s', '%s', '%s', '%s', '%s', '%s')", $node->nid, $node->confirmation, $node->redirect_post, $node->submit_limit, $node->submit_interval, $node->email, $node->email_from_name, $node->email_from_address, $node->email_subject, $node->additional_validate, $node->additional_submit);
+
+  // Insert the components into the database
+  if (is_array($node->webformcomponents) && !empty($node->webformcomponents)) {
+    foreach ($node->webformcomponents as $cid => $component) {   
+      db_query("INSERT INTO {webform_component} (nid, cid, pid, form_key, name, type, value, extra, mandatory, weight) VALUES (%d, %d, %d, '%s', '%s', '%s', '%s', '%s', %d, %d)",
+        $node->nid, $cid, $component['parent'], $component['form_key'], $component['name'], $component['type'], $component['value'], serialize($component['extra']), ($component['mandatory'] ? 1 : 0), $component['weight']
+      );
+    }
+  }
+}
+
+function webform_update($node) {  
+  // Update the webform by deleting existing data and replacing with the new
+  db_query("DELETE FROM {webform} WHERE nid = %d", $node->nid);
+  db_query("DELETE FROM {webform_component} WHERE nid = %d", $node->nid);
+  webform_insert($node);
+}
+
+function webform_delete(& $node) {
+  // delete 
+  db_query("DELETE FROM {webform} WHERE nid = %d", $node->nid);
+  db_query("DELETE FROM {webform_component} WHERE nid = %d", $node->nid);
+  watchdog('webform', 'webform "'. $node->title .'" deleted', WATCHDOG_NOTICE);
+}
+
+function webform_load($node) {
+  // load 
+  $page= db_fetch_object(db_query("SELECT * FROM {webform} WHERE nid = %d", $node->nid));
+  $result= db_query('SELECT * FROM {webform_component} WHERE nid = %d ORDER BY weight, name', $node->nid);
+  while ($c= db_fetch_array($result)) {
+    $page->webformcomponents[$c['cid']]['cid']= $c['cid'];
+    $page->webformcomponents[$c['cid']]['form_key']= $c['form_key'] ? $c['form_key'] : $c['cid'];
+    $page->webformcomponents[$c['cid']]['name']= $c['name'];
+    $page->webformcomponents[$c['cid']]['type']= $c['type'];
+    $page->webformcomponents[$c['cid']]['value']= $c['value'];
+    $page->webformcomponents[$c['cid']]['extra']= unserialize($c['extra']);
+    $page->webformcomponents[$c['cid']]['mandatory']= $c['mandatory'];
+    $page->webformcomponents[$c['cid']]['parent']= $c['pid'];
+    $page->webformcomponents[$c['cid']]['weight']= $c['weight'];
+  }
+  return $page;
+}
+
+function webform_admin_settings() {
+
+  $form['components'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Available Components'),
+    '#collapsible' => TRUE,
+    '#collapsed' => FALSE,
+    '#description' => t('Below is a list of supported field types available for webform. You may disable any of these components by unchecking its corresponding box. Only checked components will be available in existing or new webforms.'),
+  );
+  
+  // Add each component to the form:
+  $component_types = _webform_load_components(true);
+  foreach ($component_types as $component_name => $component_trans_name) {
+    $form['components']['webform_enable_'. $component_name] = array(
+      '#title' => $component_trans_name,
+      '#description' => module_invoke('webform', 'help', 'admin/settings/webform#'. $component_name .'_description'),
+      '#type' => 'checkbox',
+      '#checked_value' => 1,
+      '#default_value' => variable_get('webform_enable_'. $component_name, 1),
+    );
+  }
+  
+  $form['email'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Default E-mail Values'),
+    '#collapsible' => TRUE,
+    '#collapsed' => FALSE,
+  );
+
+  $form['email']['webform_default_from_email']  = array(
+    '#type' => 'textfield',
+    '#title' => t("From e-mail address"),
+    '#default_value' => variable_get('webform_default_from_email', variable_get('site_mail', ini_get('sendmail_from'))),
+    '#description' => t('Default sender address. This may be the E-mail address of the maintainer of your forms. This is also used for Reply-To, Return-Path and Errors-To.'),
+  );
+
+  $form['email']['webform_default_from_name']  = array(
+    '#type' => 'textfield',
+    '#title' => t("From Name"),
+    '#default_value' => variable_get('webform_default_from_name', variable_get('site_name', '')),
+    '#description' => t('Default sender name which is displayed together with the E-mail address.'),
+  );
+
+  $form['email']['webform_default_subject']  = array(
+    '#type' => 'textfield',
+    '#title' => t("Default Subject"),
+    '#default_value' => variable_get('webform_default_subject', t('Form submission from: ')),
+    '#description' => t('Default Subject. If not other stated in the form configuration this is appended to your form title. If you have e.g. defined "Your " (note the space) as a default subject and a form titled with "Order" the e-mail subject will be "Your Order".'),
+  );
+
+  $form['advanced'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Advanced Options'),
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+  );
+  
+  $form['advanced']['webform_use_cookies']  = array(
+    '#type' => 'checkbox',
+    '#checked_value' => 1,
+    '#title' => t("Allow Cookies for Tracking Submissions"),
+    '#default_value' => variable_get("webform_use_cookies", 0), 
+    '#description' => t('<a href="http://www.wikipedia.org/wiki/HTTP_cookie">Cookies</a> can be used to help prevent the same user from repeatedly submitting a webform. This feature is not needed for limiting submissions per user, though it can increase accuracy in some situations. Besides cookies, webform also uses IP addresses and site usernames to prevent repeated submissions.'),
+  );
+
+  $form['advanced']['webform_debug']  = array(
+    '#type' => 'select',
+    '#title' => t("Webforms Debug"),
+    '#default_value' => variable_get("webform_debug", 0), 
+    '#options' => array(0 => t("OFF"), 1 => t("Log submissions"), 2 => t("Full debug")), 
+    '#description' => t('Set this option to "Log submissions" to log all submissions in the watchdog. Set it to "Full debug" to print debug info on submission. You probably want to leave this option on "OFF".')
+  );
+  return system_settings_form($form);
+} // end function webform_admin_settings
+
+function theme_webform_admin_settings($form) {
+  // Format the components into a table
+  foreach (element_children($form['components']) as $key) {  
+    $row = array();
+    $row[] = $form['components'][$key]['#title'];
+    $row[] = $form['components'][$key]['#description'];
+    unset($form['components'][$key]['#title']);
+    unset($form['components'][$key]['#description']);
+    $row[] = array('data' => drupal_render($form['components'][$key]), 'align' => 'center');
+    $rows[] = $row;
+  }
+  $header = array(t('Name'), t('Description'), t('Enabled'));
+  
+  // Create the table inside the form
+  $form['components']['table'] = array(
+    '#value' => theme('table', $header, $rows)
+  );
+  
+  $output = drupal_render($form);
+  return $output;
+}
+
+/**
+ * Implementation of hook_menu().
+ */
+function webform_menu($may_cache) {
+  global $user;
+  
+  $items = array();
+  if ($may_cache) {
+    // Submissions listing 
+    $items[]= array(
+      'path' => 'admin/content/webform',
+      'title' => t('Webforms'),
+      'callback' => 'webform_page',
+      'access' => user_access('access webform results'),
+      'description' => t('View and edit all the available webforms on your site.'),
+      'type' => MENU_NORMAL_ITEM,
+    );
+    
+    // Admin Settings
+    $items[]= array(
+      'path' => 'admin/settings/webform',
+      'title' => t('Webform'),
+      'callback' => 'drupal_get_form',
+      'callback arguments' => 'webform_admin_settings',
+      'access' => user_access('administer site configuration'),
+      'description' => t('Global configuration of webform functionality.'),
+      'type' => MENU_NORMAL_ITEM,
+    );
+        
+    return $items;
+  }
+
+  if (arg(0) == 'node' && is_numeric(arg(1))) {
+    $node = node_load(arg(1));
+    if ($node->nid && $node->type == 'webform') {
+      $items[]= array('path' => 'node/'. $node->nid .'/done', 'title' => t('webform'),
+                       'callback' => '_webform_confirmation', 'callback arguments' => array(arg(1)),
+                       'access' => true,
+                       'type' => MENU_CALLBACK); 
+      $items[]= array('path' => 'node/'. $node->nid .'/results', 'title' => t('Results'), 
+                       'callback' => 'webform_results',
+                       'access' => user_access('access webform results'), 
+                       'type' => MENU_LOCAL_TASK, 'weight' => 2);
+      $items[]= array('path' => 'node/'. $node->nid .'/results/submissions', 'title' => t('submissions'),
+                       'callback' => 'webform_results',
+                       'access' => user_access('access webform results'),
+                       'weight' => 4,
+                       'type' => MENU_DEFAULT_LOCAL_TASK);
+      $items[]= array('path' => 'node/'. $node->nid .'/results/analysis', 'title' => t('analysis'),
+                       'callback' => 'webform_results',
+                       'access' => user_access('access webform results'),
+                       'weight' => 5,
+                       'type' => MENU_LOCAL_TASK);
+      $items[]= array('path' => 'node/'. $node->nid .'/results/table', 'title' => t('table'), 
+                       'callback' => 'webform_results',
+                       'access' => user_access('access webform results'), 
+                       'weight' => 6,
+                       'type' => MENU_LOCAL_TASK);
+      $items[]= array('path' => 'node/'. $node->nid .'/results/download', 'title' => t('download'), 
+                       'callback' => 'webform_results',
+                       'access' => user_access('access webform results'),
+                       'weight' => 7,
+                       'type' => MENU_LOCAL_TASK);
+      $items[]= array('path' => 'node/'. $node->nid .'/results/clear', 'title' => t('clear'), 
+                       'callback' => 'webform_results',
+                       'access' => user_access('clear webform results'),
+                       'weight' => 8,
+                       'type' => MENU_LOCAL_TASK);
+      $items[]= array('path' => 'node/'. $node->nid .'/results/edit', 'title' => t('webform'),
+                       'callback' => 'webform_results',
+                       //access checking is done in the function called by the webform_results function,
+                       //so just grant access here to avoid redundant code...
+                       'access' => true,
+                       'type' => MENU_CALLBACK);
+      $items[]= array('path' => 'node/'. $node->nid .'/results/delete', 'title' => t('webform'),
+                       'callback' => 'webform_results',
+                       'access' => user_access('clear webform results'),
+                       'type' => MENU_CALLBACK); 
+    }
+  }
+
+  return $items;
+}
+
+
+/** 
+ * Implementation of hook_link().
+ * Always add a "view form" link
+ **/
+function webform_link($type, $node= 0, $main= 0) {
+  if ($node->type == 'webform') {
+    if ($main == 1) {
+      $links['webform_goto'] = array(
+        'title' => t('Go to form'),
+        'href' => "node/$node->nid",
+        'attributes' => array('title' => t('View this form.'), 'class' => 'read-more')
+      );
+    }
+  }
+  return $links;
+}
+
+/** 
+ * Implementation of hook_prepare().
+ * This function is called before the display of webform_form(). Rather than
+ * a typical usage of hook_prepare, in webform it is used to update the contents
+ * of the $node object after changes have been made to the node, such as adding a
+ * new component or deleting an existing component. The node is altered as necessary,
+ * then the user is returned to the display of webform_form() with the changes visible.
+ * The changes to the node are not permanent until the user submits the form.
+ **/
+function webform_prepare(&$node) {
+
+  $op = $_POST['op'];
+
+  switch ($op) {
+    case t('Delete Selected'):
+      // Re-add existing components
+      if (isset($_POST['webformcomponents'])) {
+        $node->webformcomponents = _webform_components_decode($_POST['webformcomponents']);
+      }
+      // Delete an existing component
+      $delete_cid = $_POST['selected_component'];
+      if (is_array($node->webformcomponents)) {
+        $new_parent = $node->webformcomponents[$delete_cid]['parent'];
+        // Fix-up any children of the deleted component
+        foreach ($node->webformcomponents as $cid => $component) {
+          if ($component['parent'] == $delete_cid) {
+            $node->webformcomponents[$cid]['parent'] = $new_parent;
+          }
+        }
+        unset($node->webformcomponents[$delete_cid]);
+      }
+      break;
+      
+    case t('Done'):
+      // Overwrite the database components with any saved in the POST array
+      if (isset($_POST['node']['webformcomponents'])) {
+        $node->webformcomponents = _webform_components_decode($_POST['node']['webformcomponents']);
+        unset($_POST['node']['webformcomponents']);
+      }
+      
+      // Add saved values of the node
+      $old_edit = (array)$node;
+      $new_edit = (array)$_POST['node'];
+      
+      $edit = array_merge($old_edit, $new_edit);
+      $node = (object)$edit;
+          
+      // Validate the field form
+      webform_edit_field_form_validate($_POST['field']);
+      $errors = form_get_errors();
+      if (!empty($errors)) {
+        $node->webformcomponents[$node->selected_component] = $_POST['field'];
+        $_POST = $_POST['node'];
+        $_POST['op'] = $op = t('Edit Selected');
+        $output = drupal_get_form('webform_edit_field_form', $node);
+        print theme('page', $output);
+        exit();
+      }
+      else {
+        // Add the component changes/additions to the node components
+        $cid = $_POST['field']['key'];
+        if (isset($_POST['field']) && is_array($_POST['field'])) {
+          unset($node->webformcomponents[$cid]);
+          foreach ($_POST['field'] as $key => $value) {
+            $node->webformcomponents[$cid][$key] = $value;
+          }
+          unset($_POST['field']);
+        }
+      }
+      
+      // Display editted message
+      drupal_set_message(t('The form component has been changed. Remember to press Submit on the bottom of this form to save your changes.'));
+      break;
+    case t('Preview'):
+      if (isset($_POST['webformcomponents'])) {
+        $node->webformcomponents = _webform_components_decode($_POST['webformcomponents']);
+      }
+      break;
+  } // end switch
+  
+  // Make sure the submission limiter is correctly set
+  if ($_POST['enforce_limit'] === 'no') {
+    $node->submit_limit = '-1';
+    $node->submit_interval = '157784630'; // 5 years, close enough to 'ever'
+  }
+}
+
+/** 
+ * Implementation of hook_validate().
+ * This function is called after the user clicks any button displayed in webform_form().
+ * Rather than a typical usage of validation, in webform this is used to perform various
+ * actions without kicking the user out of the 'edit' tab. For instance, webform detects
+ * the when the buttons "Add" or "Edit Selected" are clicked, and then direct the user
+ * to a form for editing a component.
+ **/
+function webform_validate(&$node) {
+  $op = $_POST['op'];
+  $node->webformcomponents = _webform_components_decode($_POST['webformcomponents']);
+
+  switch ($op) {
+    // Intercept these buttons and redirect:
+    case t('Add'):
+      $errors = form_get_errors();
+      if (empty($errors)) {
+        $output = drupal_get_form('webform_edit_field_form', $node);
+        print theme('page', $output);
+        exit();
+      }
+      break;
+
+    case t('Edit Selected'):
+      $errors = form_get_errors();
+      if (empty($errors)) {
+        $output = drupal_get_form('webform_edit_field_form', $node);
+        print theme('page', $output);
+        exit();
+      }
+      break;
+    case t('Delete Selected'):
+      // We have to throw a form error for Drupal to stop form processing
+      // The 'selected_component' field item is a radio button, which shouldn't
+      // show a red border of any sort when an error is flagged on it
+      if ($_POST['selected_component']) {
+        form_set_error('selected_component', t("Field deleted, form must be submitted to save changes"));
+      }
+      else {
+        form_set_error('selected_component', t("A component must be selected to delete"));
+      }
+      break;
+    // Standard form checking:
+    case t('Submit'):
+    case t('Preview'):
+      // Make sure the submission limiter is correctly set
+      if ($_POST['enforce_limit'] === 'yes') {
+        if (!is_numeric($_POST['submit_limit'])) {
+          form_set_error('submit_limit', t('Submission limit must be a number'));
+        }
+      }
+      break;
+  }
+}
+
+/** 
+ * Implementation of hook_form()
+ * Creates the standard form for editing or creating a webform.
+ **/
+function webform_form(&$node, &$param) {
+  /* Start Edit Form */
+  $form['webform'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Webform Settings'),
+    '#collapsible' => TRUE,
+    '#collapsed' => FALSE,
+    '#weight' => -4);
+  
+  $form['webform']['title'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Title'),
+    '#default_value' => $node->title,
+    '#maxlength' => 128,
+    '#required' => TRUE,
+  );
+  
+  $form['webform']['body'] = array(
+    '#type' => 'textarea',
+    '#title' => t('Description'),
+    '#description' => t('Text to be shown as teaser and before the form.'),
+    '#default_value' => $node->body,
+    '#cols' => 40,
+    '#rows' => 10,
+    '#required' => TRUE,
+  );
+  
+  $form['webform']['confirmation'] = array(
+    '#type' => 'textarea',
+    '#title' => t("Confirmation message or redirect URL"),
+    '#description' => t("Message to be shown upon successful submission or a path to a redirect page. Redirect pages must start with <em>http://</em> for external sites or <em>internal:</em> for an internal path. i.e. <em>http://www.example.com</em> or <em>internal:node/10</em>"),
+    '#default_value' => $node->confirmation,
+    '#cols' => 40,
+    '#rows' => 10,
+    '#required' => TRUE,
+  );
+  
+  $form['webform']['format'] = filter_form($node->format);
+  /* End Edit Form */
+  
+  /* Start Components Form */
+  $form['components'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Components'),
+    '#collapsible' => TRUE,
+    '#collapsed' => FALSE,
+    '#weight' => -3);
+  
+  if (is_array($node->webformcomponents) && !empty($node->webformcomponents)) {
+    $options = array();
+    foreach ($node->webformcomponents as $cid => $component) {  
+      $options[$cid] = htmlspecialchars($component['name'], ENT_QUOTES);
+    }
+    
+    if ($node->selected_component > 0) {
+        $default_value = $node->selected_component;
+    }
+    else {
+        $comp_keys = array_keys($node->webformcomponents);
+        $default_value = array_shift($comp_keys);
+    }
+    
+    $form['components']['selected_component'] = array(
+      '#type' => 'radios',
+      '#options' => $options,
+      '#default_value' => $default_value,
+      '#DANGEROUS_SKIP_CHECK' => TRUE,
+    );
+    $form['components']['delete_component'] = array(
+      '#type' => 'submit',
+      '#value' => t('Delete Selected'),
+      '#weight' => 2,
+    );
+    $form['components']['edit_component'] = array(
+      '#type' => 'submit',
+      '#value' => t('Edit Selected'),
+      '#weight' => 2,
+    );
+  }
+
+  $component_types =  _webform_load_components();
+  natcasesort($component_types);
+  $form['components']['webform_newfield_type'] = array(
+    '#type' => 'select',
+    '#title' => t('Add a new component'),
+    '#default_value' => $node->webform_newfield_type,
+    '#options' => $component_types,
+    '#description' => t('Each component adds a new field to the form. Any number components (even of the same type) may be added to the form. Select a component type to add above.'),
+    '#weight' => 3,
+  );
+  $form['components']['add_component'] = array(
+    '#type' => 'submit',
+    '#value' => t('Add'),
+    '#weight' => 4,
+  );
+  /* End Components Form */
+  
+  /* Start E-mail Settings Form */
+  $form['mailsettings'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Mail Settings'),
+    '#collapsible' => TRUE,
+    '#collapsed' => FALSE,
+    '#weight' => -2,
+  );
+  
+  $form['mailsettings']['email'] = array(
+    '#type' => 'textfield',
+    '#title' => t("E-mail to address"),
+    '#default_value' => $node->email,
+    '#description' => t('Form submissions will be e-mailed to this address. Leave blank for none.'),
+  );
+  
+  // Build arrays of possible return email addresses and email subject lines from elements on the form
+  $possible_email_from_name = array('default' => variable_get('webform_default_from_name', variable_get('site_name', '')) .' ['. t('Default') .']', 'none' => '['. t('None') .']');
+  $possible_email_from_address = array('default' => variable_get('webform_default_from_email', variable_get('site_mail', ini_get('sendmail_from'))) .' ['. t('Default') .']', 'none' => '['. t('None') .']');
+  $possible_email_subject = array('default' => variable_get('webform_default_subject', t('Form submission from: ') . t('$title')) .' ['. t('Default') .']', 'none' => '['. t('None') .']');
+  
+  if (is_array($node->webformcomponents) && !empty ($node->webformcomponents)) {
+    foreach ($node->webformcomponents as $cid => $component) {
+      $type = $component['type'];
+      if (in_array($type, array('textfield', 'hidden', 'select'))) {
+        $possible_email_from_name[$component['name']] = $component['name'];
+        $possible_email_subject[$component['name']] = $component['name'];
+      }
+      if (in_array($type, array('email', 'hidden', 'select'))) {
+        $possible_email_from_address[$component['name']] = $component['name'];
+      }
+    }
+  }
+  
+  $form['mailsettings']['email_from_name'] = array(
+    '#type' => 'select',
+    '#title' => t('E-mail from name'),
+    '#default_value' => $node->email_from_name,
+    '#options' => $possible_email_from_name,
+    '#description' => t('After adding components to this form, any textfield or hidden form element may be selected as the sender\'s name for e-mails.'),
+    '#weight' => 6,
+    '#DANGEROUS_SKIP_CHECK' => TRUE,
+  );
+  $form['mailsettings']['email_from_address'] = array(
+    '#type' => 'select',
+    '#title' => t('E-mail from address'),
+    '#default_value' => $node->email_from_address,
+    '#options' => $possible_email_from_address,
+    '#description' => t('After adding components to this form, any e-mail or hidden form element may be selected as the sender\'s address for e-mails.'),
+    '#weight' => 7,
+    '#DANGEROUS_SKIP_CHECK' => TRUE,
+  );
+  $form['mailsettings']['email_subject'] = array(
+    '#type' => 'select',
+    '#title' => t('E-mail subject'),
+    '#default_value' => $node->email_subject,
+    '#options' => $possible_email_subject,
+    '#description' => t('After adding components to this form, any textfield or hidden form element may be selected as the subject line for e-mails.'),
+    '#weight' => 8,
+    '#DANGEROUS_SKIP_CHECK' => TRUE,
+  );
+  
+  /* End mail settings form */
+  
+  /* Start advanced settings form */
+  $form['advanced'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Advanced Settings'),
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+    '#weight' => -1);
+  
+  
+  $form['advanced']['submitlimit'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Limit the number of submission a user may send within a specified time period.'),
+    '#prefix' => '<div class="container-inline">',
+    '#suffix' => '</div>',
+  );
+  
+  $form['advanced']['submitlimit']['unlimited'] = array(
+    '#name' => 'enforce_limit', // Override the naming scheme to force these radios into the same group
+    '#type' => 'radio',
+    '#return_value' => 'no',
+    '#title' => t('Unlimited'),
+    '#default_value' => ($node->submit_limit > 0 ? false : 'no'),
+    '#parents' => array('advanced', 'submitlimit'), // If we don't specify the parent, the forms API will think this is an illegal posting
+  );
+
+  $form['advanced']['submitlimit']['limited'] = array(
+    '#name' => 'enforce_limit', // Override the naming scheme to force these radios into the same group
+    '#type' => 'radio',
+    '#return_value' => 'yes',
+    '#prefix' => '<br />',
+    '#suffix' => t('Limit to '),
+    '#default_value' => ($node->submit_limit > 0 ? 'yes' : false),
+    '#parents' => array('advanced', 'submitlimit'), // If we don't specify the parent, the forms API will think this is an illegal posting
+  );
+  $form['advanced']['submitlimit']['submit_limit'] = array(
+    '#type' => 'textfield',
+    '#maxlength' => 2,
+    '#size' => 2,
+    '#suffix' => ' '. t('submission(s)') .' ',
+    '#default_value' => ($node->submit_limit > 0 ? $node->submit_limit : ""),
+    '#attributes' => array(
+      'style' => 'width: 2em; display: inline;',
+      'onchange' => "javascript: document.getElementsByName('edit[enforce_limit]').item(1).checked = true;",
+      'onclick' => "javascript: document.getElementsByName('edit[enforce_limit]').item(1).checked = true;"
+    ),
+  );
+  
+  $form['advanced']['submitlimit']['submit_interval'] = array(
+    '#type' => 'select',
+    '#options' => array(
+      '157784630' => t('ever'), // 5 years
+      '1600' => t('every hour'),
+      '86400' => t('every day'),
+      '604800' => t('every week'),
+    ),
+    '#default_value' => $node->submit_interval,
+    '#attributes' => array(
+      'onchange' => "javascript: document.getElementsByName('edit[enforce_limit]').item(1).checked = true;",
+      'onclick' => "javascript: document.getElementsByName('edit[enforce_limit]').item(1).checked = true;"
+    ),
+  );
+  
+  if (user_access('use PHP for additional processing')) {
+    $form['advanced']['additional_validate'] = array(
+      '#type' => 'textarea',
+      '#title' => 'Additional Validation',
+      '#description' => t('Enter PHP code to preform additional validation for this form. Include the &lt;?php ?&gt; tags. $form_id and $form_values are available variables. If validation fails, use the form_set_error function to prevent the form from being submitted. Use the same syntax as a _validate function used in the <a href="http://api.drupal.org/api/4.7/file/developer/topics/forms_api.html">Forms API</a>.'),
+      '#default_value' => $node->additional_validate,
+      '#cols' => 40,
+      '#rows' => 10,
+    );
+    
+    $form['advanced']['additional_submit'] = array(
+      '#type' => 'textarea',
+      '#title' => 'Additional Processing',
+      '#description' => t('Enter PHP code to preform additional processing for this form (after the validation). Include the &lt;?php ?&gt; tags. $form_id and $form_values are available variables, use the same syntax as a _submit function used in the <a href="http://api.drupal.org/api/4.7/file/developer/topics/forms_api.html">Forms API</a>.'),
+      '#default_value' => $node->additional_submit,
+      '#cols' => 40,
+      '#rows' => 10,
+    );
+  }
+  else {
+    $form['advanced']['additional_validate'] = array(
+      '#type' => 'value',
+      '#value' => $node->additional_validate,
+    );
+    
+    $form['advanced']['additional_submit'] = array(
+      '#type' => 'value',
+      '#value' => $node->additional_submit,
+    );
+  }
+  $form['advanced']['redirect_post'] = array(
+    '#type' => 'checkbox',
+    '#title' => t("Redirect POST Values"),
+    '#description' => t("Forward the contents of the POST array to the redirect URL. Use this option for custom processing of the form information. No processing will be done by webform. The confirmation option above MUST be a full redirect URL for this option to have an effect."),
+    '#default_value' => $node->redirect_post,
+  );
+  
+  /* End Advanced Settings Form */
+  
+  // Add hidden form elements containing the contents of the components
+  if (is_array($node->webformcomponents) && !empty($node->webformcomponents)) {
+    $form['webformcomponents'] = array(
+      '#type' => 'fieldset',
+      '#tree' => TRUE,
+      '#attributes' => array('style' => 'display: none;'),
+    );
+    foreach ($node->webformcomponents as $cid => $component) {
+    // Create a hidden field with the component's values
+      $form['webformcomponents'][$cid] = array(
+        '#type' => 'hidden',
+        '#value' => base64_encode(serialize($component)),
+      );
+    }
+  }
+  
+  // Create our forms and display the output:
+  return $form;
+}
+
+/**
+ * Theme the node form. Use a standard Drupal table to organize the components fieldset
+ *
+ * @param array $form
+ * @return string Formatted HTML form, ready for display
+ */
+function theme_webform_node_form($form) {
+  $node = $form['#node'];
+  $rows = array();
+  if (is_array($node->webformcomponents) && !empty($node->webformcomponents)) {
+    $component_tree = array();
+    $page_count = 1;
+    _webform_components_tree_build($node->webformcomponents, $component_tree, 0, $page_count);
+    $component_tree = _webform_components_tree_sort($component_tree);
+    // Build the table rows
+    function _webform_add_rows($cid, $component, $level, &$form, &$rows) { 
+      // Create presentable values
+      if (strlen($component['value']) > 30) {
+        $component['value'] = htmlspecialchars(substr($component['value'], 0, 30), ENT_QUOTES);
+        $component['value'] .= "...";
+      }
+      
+      // Add padding to the radio label
+      $form['components']['selected_component'][$cid]['#title'] = '<span style="padding-left: '. ($level * 15) .'px; padding-right: 20px;">'. $form['components']['selected_component'][$cid]['#title'] .'</span>';
+      
+      // Add each component to a table row
+      $rows[] = array(
+        drupal_render($form['components']['selected_component'][$cid]),
+        $component['type'],
+        ($component['value'] == "") ? "-" : $component['value'],
+        ($component['mandatory'] == 1) ? "Y" : "N" ,
+        $component['weight'],
+      );
+      if (is_array($component['children'])) {
+        foreach ($component['children'] as $cid => $component) {
+          _webform_add_rows($cid, $component, $level + 1, $form, $rows);
+        }
+      }
+    }
+    foreach ($component_tree['children'] as $cid => $component) {
+      _webform_add_rows($cid, $component, 0, $form, $rows);
+    }
+  }
+  else {
+    $rows[] = array(NULL, array('data' => t("No Components, add a component below."), 'colspan' => 5));
+  }
+
+  $headers = array(
+    array('data' => t('Name'), 'style' => 'padding-left: 30px'),
+    t('Type'),
+    t('Value'),
+    t('Mandatory'),
+    t('Weight'),
+  );
+  $component_table .= theme('table', $headers, $rows);
+
+  $form['components']['table'] = array(
+    '#value' => $component_table,
+  );
+  return drupal_render($form);
+}
+
+function webform_edit_field_form(&$node) {
+  // This is the information about the current field.
+  $currfield = array();
+
+  if ($_POST['op'] == t('Edit Selected')) {
+    // Check to make sure a valid component id was selected
+    $cid = $_POST['selected_component'];
+    $component = $node->webformcomponents[$cid];
+    if (empty($component)) {
+      drupal_set_message(t('Component not found'), 'error');
+      drupal_set_title("Webform Error");
+      return array();
+    }
+    // We are editing a existing field.
+    // Fetch all filed data into the $currfield object.
+    $currfield['key'] = $cid;
+    $currfield['form_key'] = $component['form_key'] ? $component['form_key'] : $cid;
+    $currfield['type'] = $component['type'];
+    $currfield['name'] = $component['name'];
+    $currfield['default'] = $component['value'];
+    $currfield['parent'] = $component['parent'];
+    $currfield['weight'] = $component['weight'];
+    $currfield['mandatory'] = $component['mandatory'];
+    $currfield['extra'] = $component['extra'];
+    drupal_set_title("Edit component: ". $currfield['name'] ." (". $currfield['type'] .")");
+  }
+  else {
+    // Check to make sure a valid component type was selected
+    $component_types =  _webform_load_components();
+    $new_component_type = $_POST['webform_newfield_type'];
+    if (empty($new_component_type) || !key_exists($new_component_type, $component_types)) {
+      drupal_set_message(t('Unknown component type %component', array('%component' => $new_component_type)), 'error');
+      drupal_set_title("Webform Error");
+      print theme('page', "");
+      return;
+    }
+    // We are editing a new field.
+    $currfield['key'] = time();
+    $currfield['form_key'] = $currfield['key'];
+    $currfield['type'] = $_POST['webform_newfield_type'];
+    $currfield['name'] = $currfield['type'] ."_". $currfield['key'];
+    drupal_set_title(t("Add new %type component", array('%type' => $currfield['type'])));
+  }
+  
+  // Construct the form:
+  $form = array();
+  
+  // Print the correct field type specification
+  // We always need: name and description.
+  $form['field'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Field Details'),
+    '#collapsible' => FALSE,
+    '#collapsed' => FALSE,
+    '#weight' => 5,
+    '#tree' => TRUE,
+  );
+  
+  
+  $form['field']['type'] = array(
+    '#type' => 'hidden',
+    '#value' => $currfield['type'],
+  );
+  $form['field']['key'] = array(
+    '#type' => 'hidden',
+    '#value' => $currfield['key'],
+  );
+  $form['field']['form_key'] = array(
+    '#type' => 'textfield',
+    '#default_value' => $currfield['form_key'],
+    '#title' => t('Field Key'),
+    '#description' => t('Enter a machine readable key for this form element. May contain only alphanumeric characters and underscores. This key will be used as the name attribute of the form element.'),
+    '#required' => TRUE,
+    '#weight' => -2,
+  );
+  $form['field']['name'] = array(
+    '#type' => 'textfield',
+    '#default_value' => $currfield['name'],
+    '#title' => t("Label"),
+    '#description' => t('This is used as a descriptive label when displaying this form element.'),
+    '#required' => TRUE,
+    '#weight' => -1,
+  );
+  $form['field']['extra']['description'] = array(
+    '#type' => 'textfield',
+    '#default_value' => $currfield['extra']['description'],
+    '#title' => t("Description"),
+    '#maxlength' => '512',
+    '#description' => t('A short description of the field used as help for the user when he/she uses the form.') .'<br />'. webform_help('webform/helptext#variables'),
+    '#weight' => -1,
+  );
+  
+  $form['field']['mandatory'] = array(
+    '#type' => 'checkbox',
+    '#title' => t("Mandatory"),
+    '#default_value' => ($currfield['mandatory'] == '1' ? TRUE : FALSE),
+    '#description' => t('Check this option if the user must enter a value.'),
+    '#weight' => 2,
+  );
+  
+  if (variable_get('webform_enable_fieldset', true) && is_array($node->webformcomponents)) {
+    $options = array('0' => t('Root'));
+    foreach ($node->webformcomponents as $thiscid => $value) {
+      if ($value['type'] == 'fieldset' && $thiscid != $cid) {
+        $options[$thiscid] = htmlspecialchars($value['name'], ENT_QUOTES);
+      }
+    }
+    $form['field']['parent'] = array(
+      '#type' => 'select',
+      '#title' => t("Parent Fieldset"),
+      '#default_value' => $currfield['parent'],
+      '#description' => t('Optional. You may organize your form by placing this component inside inside another fieldset.'),
+      '#options' => $options,
+      '#weight' => 2,
+    );
+  }
+  
+  $form['field']['weight'] = array(
+    '#type' => 'weight',
+    '#delta' => count($_POST['webformcomponents']) > 10 ? count($_POST['webformcomponents']) : 10,
+    '#title' => t("Weight"),
+    '#default_value' => $currfield['weight'],
+    '#description' => t('Optional. In the menu, the heavier items will sink and the lighter items will be positioned nearer the top.'),
+    '#weight' => 2,
+  );
+
+  // Add the fields specific to this component type:  
+  _webform_load_components(); // Load all component types
+  $edit_function = "_webform_edit_". $currfield['type'];
+  $additional_form_elements = array();
+  if (function_exists($edit_function)) {
+    $additional_form_elements = $edit_function($currfield); // Call the component render function
+  }
+  else {
+    drupal_set_message(t("The webform component of type @type does not have an edit function defined.", array('@type' => $currfield['type'])));
+  }
+
+  // Merge the additional fields with the current fields:
+  $extra_fields_copy = $form['field']['extra'];
+  $form['field'] = array_merge($form['field'], $additional_form_elements);
+  $form['field']['extra'] = array_merge((array)$extra_fields_copy, (array)$additional_form_elements['extra']);
+  
+  // Add the submit button
+  $form['field']['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t("Done"),
+    '#weight' => 3,
+  );
+
+  // Create hidden form elements to restore all the settings on the node edit form
+  $form['node'] = array(
+    '#tree' => TRUE,
+  );
+
+  // Recursively create hidden form elements for all fields on the node form
+  function _webform_edit_field_form_hiddens(&$form, $key, $value) {
+    if (is_array($value)) {
+      foreach ($value as $k => $v) {
+        _webform_edit_field_form_hiddens($form[$key], $k, $v);
+      }
+    }
+    else {
+      $form[$key] = array(
+        '#type' => 'hidden',
+        '#value' => $value
+      );
+    }
+  }
+  _webform_edit_field_form_hiddens($form, 'node', $_POST);
+
+  return $form;
+}
+
+/**
+ * Field name validation for the webform unique key. Must be alphanumeric.
+ */
+function webform_edit_field_form_validate($form_values) {
+  if (!preg_match('!^[a-z0-9_]+$!', $form_values['form_key'])) {
+    form_set_error('field][form_key', t('The field name %field_name is invalid.', array('%field_name' => $form_values['form_key'])));
+  }
+
+  // Let the field do any additional validation.
+  _webform_load_components($form_values['type']);
+  $validate_function = '_webform_edit_validate_'. $form_values['type'];
+  if (function_exists($validate_function)) {
+    $validate_function($form_values);
+  }
+}
+
+/**
+ * Implementation of hook_forms(). All webform_client_form forms share the same form handler
+ */
+function webform_forms() {
+  global $_webform_form_list;
+
+  if (is_array($_webform_form_list)) {
+    foreach ($_webform_form_list as $form_id) {
+      $forms['webform_client_form_'. $form_id]['callback'] = 'webform_client_form';
+    }
+  }
+  return $forms;
+}
+
+function webform_view(&$node, $teaser = 0, $page = 0) {
+  // If a teaser, do not display the form
+  if ($teaser) {
+    $node->content['teaser'] = array('#value' => check_markup($node->teaser, $node->format, FALSE));
+    return $node;
+  }
+  
+  include_once(drupal_get_path('module', 'webform') ."/webform.inc");
+  
+  $sid_to_display = check_plain($_GET['sid']); // Will be NULL if no sid
+  $submission = array();
+  $preview = false;
+  $node->webformcomponents = _webform_components_decode($node->webformcomponents);
+  
+  if ($_POST['op'] == t('Preview')) {
+    webform_prepare($node);
+  }
+
+  if ($sid_to_display && is_numeric($sid_to_display)) {
+    if (user_access('access webform results')) {
+      drupal_set_title('Submission #'. $sid_to_display);
+      $node->body = "";
+      $submission = _webform_fetch_submission($sid_to_display, $node->nid);
+    }
+    else {
+      $sid_to_display = NULL; // This user is not allowed to access a submitted node. Deny the attempt without alert.
+      watchdog('webform', t('Unauthorized webform access attempt by %name.', array('%name' => $user->name)), WATCHDOG_WARNING); // and log the attempt
+    }
+  }
+  
+  global $_webform_form_list;
+  $_webform_form_list[] = $node->nid;
+  $output = drupal_get_form('webform_client_form_'. $node->nid, $node, $submission);
+
+  // Remove the surrounding <form> tag if this is a preview
+  if ($preview) {
+    $output = preg_replace('/<\/?form[^>]*>/', '', $output);
+  }
+  
+  $node->content['body'] = array('#value' => check_markup($node->body, $node->format, FALSE));
+  $node->content['webform'] = array('#value' => $output, '#weight' => 10);
+  
+  return $node;
+} // end webform_view
+
+// Display the webform for editing existing submission data.
+function webform_submission_edit(&$node, $sid) {
+  global $user;
+
+  include_once (drupal_get_path('module', 'webform')."/webform.inc");
+
+  $submission = array();
+  $node->webformcomponents = _webform_components_decode($node->webformcomponents);
+  $submission = _webform_fetch_submission($sid, $node->nid);
+  if ($sid && is_numeric($sid)) {
+    if (user_access("edit webform submissions") || (user_access("edit own webform submissions") && ($user->uid == $submission['uid']))) {
+      drupal_set_title('Submission #'.$sid);
+      $node->body = "";
+
+      global $_webform_form_list;
+      $_webform_form_list[] = $node->nid;
+      return drupal_get_form('webform_client_form_'. $node->nid, $node, $submission, null, true);
+    } else {
+      $sid = NULL; // This user is not allowed to access a submitted node. Deny the attempt without alert.
+      watchdog('webform', t('Unauthorized webform access attempt', array ('%name' => "<em>$user->name</em>")), WATCHDOG_WARNING); // and log the attempt
+      return drupal_access_denied();
+    }
+  }
+
+
+//  return drupal_get_form('webform_client_form', $node, $submission, null, true);
+} // end webform_submission_edit
+
+
+/**
+ * Client form generation function. If this is displaying an existing
+ * submission, pass in the $submission variable with the contents of the
+ * submission to be displayed.
+ */
+function webform_client_form(&$node, $submission = array(), $form_values = NULL, $enabled = false) {
+  global $user;
+  
+  _webform_load_components(); // Load all the components
+  
+  if ($_POST['op'] == t('Preview')) {
+    $preview = true;
+  }
+  
+  if (module_exists('profile')) {
+    profile_load_profile($user);
+  }
+  
+  if ($node->redirect_post && valid_url(trim($node->confirmation), true)) {
+    $form['#action'] = trim($node->confirmation);
+  }
+  
+  // Add a theme function for this form
+  $form['#theme'] = 'webform_form_'. $node->nid;
+  // Set the encoding type (necessary for file uploads)
+  $form['#attributes']['enctype'] = 'multipart/form-data';
+  $form['#base'] = 'webform_client_form';
+  
+  if (is_array($node->webformcomponents) && !empty($node->webformcomponents)) {
+    // Prepare a new form array
+    $form['submitted'] = array(
+      '#tree' => TRUE
+    );
+    $form['details'] = array(
+      '#tree' => true,
+    );
+    
+    // Put the components into a tree structure
+    $component_tree = array();
+    $page_count = 1;
+    _webform_components_tree_build($node->webformcomponents, $component_tree, 0, $page_count);
+
+    if ((!$preview && empty($submission)) || ($enabled)) {
+      if ($page_count > 1) {
+        $next_page = t('Next Page >');
+        $prev_page = t('< Previous Page');
+        if (isset($form_values)) {
+          $page_num = $form_values['details']['page_num'];
+          if ($form_values['op'] == $prev_page && $page_num > 1) {
+            $page_num--;
+          }
+          else if ($form_values['op'] == $next_page && $page_num < $page_count) {
+            $page_num++;
+          }
+        }
+        else {
+          $page_num = 1;
+        }
+  
+        $form['#multistep'] = TRUE;
+        $form['#redirect'] = FALSE;
+  
+        $form['details']['page_num'] = array(
+          '#type'      => 'hidden',
+          '#value'     => $page_num,
+        );
+        // Add the submit button(s)
+        if ($page_num > 1) {
+          $form['submitbutton_prev'] = array(
+            '#type' => 'submit',
+            '#value' => $prev_page,
+            '#weight' => 1000,
+          );
+        }
+        if ($page_num == $page_count) {
+          $form['submitbutton'] = array(
+            '#type' => 'submit',
+            '#value' => t('Submit'),
+            '#weight' => 1001,
+          );
+        }
+        else if ($page_num < $page_count) {
+          $form['submitbutton_next'] = array(
+            '#type' => 'submit',
+            '#value' => $next_page,
+            '#weight' => 1001,
+          );
+        }
+      }
+      else {
+        $page_num = 1;
+        // Add the submit button
+        $form['submitbutton'] = array(
+          '#type' => 'submit',
+          '#value' => t('Submit'),
+          '#weight' => 1000,
+        );
+      }
+    }
+
+    // Recursively add components to the form
+    foreach ($component_tree['children'] as $cid => $component) {
+      _webform_client_form_add_component($cid, $component, $form['submitted'], $form, $submission, $page_num, $enabled);
+    }
+    // Do not display the submit button if this is a preview or submission view
+    if ((!$preview && empty($submission)) || ($enabled)) {
+      // Additional hidden elements   
+      // Email subject and sender
+      $form['details']['email_subject'] = array(
+        '#type'      => 'hidden',
+        '#value'     => $node->email_subject,
+      );
+      $form['details']['email_from_name'] = array(
+        '#type'      => 'hidden',
+        '#value'     => $node->email_from_name,
+      );
+      $form['details']['email_from_address'] = array(
+        '#type'      => 'hidden',
+        '#value'     => $node->email_from_address,
+      );
+      $form['details']['nid'] = array(
+        '#type'      => 'value',
+        '#value'     => $node->nid,
+      );
+      // set this flag to be able to determine if the displayed submission
+      // is a new one or an exisiting one being updated
+      $form['details']['sid'] = array(
+        '#type'      => 'value',
+        '#value'     => $submission['sid'],
+      );
+    }
+  }
+  
+  return $form;
+}
+
+function _webform_client_form_add_component($cid, $component, &$parent_fieldset, &$form, $submission, $page_num, $enabled) {
+  // Load with submission information if necessary
+  if (!empty($submission)) {
+    // This component is display only, with the value set according information
+    // previously submitted in the submission numbered $sid_to_display
+    $display_function = "_webform_submission_display_". $component['type'];
+    if (function_exists($display_function)) {
+      $parent_fieldset[$component['form_key']] = $display_function($submission['data'][$cid], $component, $enabled);
+    }
+  }
+  else if ($component['page_num'] == $page_num) {
+    // Add this user-defined field to the form (with all the values that are always available)      
+    $render_function = "_webform_render_". $component['type'];
+    if (function_exists($render_function)) {
+      $parent_fieldset[$component['form_key']] = $render_function($component); // Call the component render function
+    }
+    else {
+      drupal_set_message(t("The webform component @type is not able to be displayed", array('@type' => $component['type'])));
+    }
+  }
+  
+  if (is_array($component['children'])) {
+    foreach ($component['children'] as $scid => $subcomponent) {
+      _webform_client_form_add_component($scid, $subcomponent, $parent_fieldset[$component['form_key']], $form, $submission, $page_num, $enabled);
+    }
+  }
+}
+
+function webform_client_form_validate($form_id, $form_values) {
+  global $user, $base_url;
+  include_once(drupal_get_path('module', 'webform') ."/webform.inc");
+  $node = node_load(array('nid' => $form_values['details']['nid']));
+
+  // Flatten trees within the submission
+  $form_values['submitted_tree'] = $form_values['submitted'];
+  _webform_client_form_submit_flatten($node, $form_values['submitted'], $form_values['submitted']);
+
+  // Verify that this submission is within the submission limits on this form
+  if ($violation_count = _webform_submission_limit_check ($node, $form_values)) {
+    // If the webform is being swamped by repeated entries, limit the messages in watchdog
+    if ($violation_count < 21) {
+      if ($user->uid > 0) {
+        watchdog('webform', t('The authenticated user <a href="%user_url">%username</a> attempted to submit more entries than allowed on the <a href="%webform_url">%webform_title</a> webform',
+                              array(
+                                '%user_url' => url('user/'. $user->uid),
+                                '%username' => $user->name,
+                                '%webform_url' => url('node/'. $node->nid),
+                                '%webform_title' => $node->title,
+                              )), WATCHDOG_WARNING);
+      }
+      else {
+        watchdog('webform', t('An anonymous user with IP address %ip attempted to submit more entries than allowed on the <a href="%webform_url">%webform_title</a> webform',
+                              array(
+                                '%ip' => $_SERVER['REMOTE_ADDR'],
+                                '%webform_url' => url('node/'. $node->nid),
+                                '%webform_title' => $node->title,
+                              )), WATCHDOG_WARNING);
+      }
+    }
+    form_set_error('', t("You have submitted the maximum number of entries. Check submission guidelines."));
+  }
+  
+  if (trim($node->additional_validate)) {
+    // We use eval here (rather than drupal_eval) because the user needs access to local variables
+    eval("?>".$node->additional_validate);
+  }
+}
+
+function webform_client_form_submit($form_id, $form_values) {
+  global $user, $base_url;
+  include_once (drupal_get_path('module', 'webform')."/webform.inc");
+  $node = node_load(array('nid'=>$form_values['details']['nid']));
+  $session_key = 'webform_form_'.$node->nid;
+
+  if ($form_values['op'] != t('Submit')) {
+    // This is a multi-page form that is not yet complete.
+    // Copy values stored during previous steps into $_POST because they are needed in form_builder() to repopulate the form.
+    if (is_array($_SESSION[$session_key])) {
+      foreach ($_SESSION[$session_key] as $key => $val) {
+        $_POST['submitted'][$key] = $val;
+      }
+    }
+
+    // Store values from an intermediate stage of a multistep form in $_SESSION
+    if (is_array($form_values['submitted'])) {
+      foreach ($form_values['submitted'] as $key => $val) {
+        $_SESSION[$session_key][$key] = $val;
+      }
+    }
+    return;
+  }
+
+  $form_values['submitted_tree'] = $form_values['submitted'];
+  if (is_array($_SESSION[$session_key])) {
+    // Merge any submission data stored in $_SESSION for multistep forms
+    foreach ($_SESSION[$session_key] as $key => $val) {
+      $form_values['submitted'][$key] = $val;
+    }
+    unset($_SESSION[$session_key]);
+  }
+
+  // Flatten trees within the submission
+  _webform_client_form_submit_flatten($node, $form_values['submitted'], $form_values['submitted']);
+
+  // Process post-submission data if necessary in the components
+  _webform_load_components();
+  foreach ($node->webformcomponents as $cid => $component) {
+    $submit_function = "_webform_submit_".$component['type'];
+    if (function_exists($submit_function)) {
+      $submit_function($form_values['submitted'][$cid], $component); // Call the component process submission function
+    }
+  }
+
+  // Perform additional submit processing
+  if (trim($node->additional_submit)) {
+    // We use eval here (rather than drupal_eval) because the user needs access to local variables
+    eval("?>".$node->additional_submit);
+  }
+  
+  // Save the submission to the database
+  if (!$form_values['details']['sid']) {
+  	// no sid was found thus insert it in the datatabase
+  $sid = _webform_save_submission($node, $form_values['submitted']);
+  } else {
+  	// sid was found thus update the existing sid in the datatbase
+    $sid = _webform_update_submission($node, $form_values['details']['sid'], $form_values['submitted']);
+  }
+  // Check if this form is sending an email
+  if (isset ($node->email)) {
+    $node->email = strip_tags($node->email);
+    if (!empty ($node->email)) {
+    
+      // Create a themed message for mailing
+      // Check for a node-specific message:
+      $message = theme("webform_create_mailmessage_$node->nid", $form_values, $node, $sid);
+      if (!$message) {
+        // Otherwise use the generic form:
+        $message = theme("webform_create_mailmessage", $form_values, $node, $sid);
+      }
+      
+      // Build arrays of possible return email addresses and email subject lines from elements on the form
+      
+      // Default values:
+      $email_from_name = variable_get('webform_default_from_name', variable_get('site_name', ''));
+      $email_from_address = variable_get('webform_default_from_email', variable_get('site_mail', ini_get('sendmail_from')));
+      $email_subject_string = variable_get('webform_default_subject', t('Form submission from: ')) . ' ' . $node->title;
+      $headers = array();
+
+      // Check for empty values
+      if (strcmp('none', $node->email_from_name)) {
+        $email_from_name = '';
+      }
+      if (strcmp('none', $node->email_from_address)) {
+        $email_from_address = '';
+      }
+      if (strcmp('none', $node->email_subject)) {
+        $email_subject_string = '';
+      }
+
+      // Search for user set FROM and SUBJECT fields
+      if (is_array($node->webformcomponents) && !empty ($node->webformcomponents)) {
+        foreach ($node->webformcomponents as $cid => $component) {
+          $type = $component['type'];
+          // Find and set a custom FROM: field
+          if ($type == 'email' || $type == 'hidden') {
+            if ($component['name'] == $node->email_from_address) {
+              $email_from_address = $form_values['submitted'][$cid];
+            }
+          }
+          // Find and set a custom SUBJECT: field
+          if ($type == 'textfield' || $type == 'hidden') {
+            if ($component['name'] == $node->email_from_name) {
+              $email_from_name = strip_tags($form_values['submitted'][$cid]);
+            }
+            if ($component['name'] == $node->email_subject) {
+              $email_subject_string = strip_tags($form_values['submitted'][$cid]);
+            }
+          }
+          if ($type == 'email' && $component['extra']['carboncopy'] == 'Y' ) {
+            $headers['Cc'] = $form_values['submitted'][$cid];
+          }
+        }
+      }
+      
+      // Assemble the FROM string
+      if (strlen($email_from_name) > 0) {
+        $email_from_string = $email_from_name . ' <' . $email_from_address . '>';
+      }
+      else {
+        $email_from_string = $email_from_address;
+      }
+
+      // Verify that this submission is not attempting to send any spam hacks
+      if (_webform_submission_spam_check($node->email, $email_subject_string, $message, $email_from_string, $headers)) {
+        watchdog('webform', t('Possible spam attempt from ').$_SERVER['REMOTE_ADDR']."<br />\n".nl2br(htmlentities($message)), WATCHDOG_WARNING);
+        drupal_set_message(t("Illegal information. Data not submitted."), 'error');
+        return false;
+      }
+      // Additional headers
+      $headers['X-Mailer'] = 'Drupal Webform (PHP/' . phpversion() . ')';
+    
+      // Mail the webform results
+      drupal_mail('webform-submission', $node->email, $email_subject_string, $message, $email_from_string, $headers);
+      
+      // Debugging output
+      if (variable_get('webform_debug', 0) >= 2) {
+        drupal_set_message("E-mail Headers: <pre>". print_r($headers, true) ."</pre>To: " . $node->email . "<br />From: " . htmlentities($email_from_string) . "<br />Subject: " . $email_subject_string . "<br />E-mail Body: <pre>".$message."</pre>");
+      }
+    }
+  }
+   
+  if (variable_get('webform_debug', 0) >= 1) {
+    watchdog('webform', t('Submission posted to %title', array('%title' => $node->title)) . l(t('Results'), 'node/'.$node->nid, NULL, 'sid='.$sid)."<br />\n".nl2br(htmlentities($message)), WATCHDOG_NOTICE);
+  }
+  
+  // Check confirmation field to see if redirect should be to another node or a message
+  if (valid_url(trim($node->confirmation), true)) {
+    return trim($node->confirmation);
+  }
+  elseif (preg_match('/^internal:/', $node->confirmation)) {
+    $path = preg_replace('/^internal:/', '', $node->confirmation);
+    return array($path, 'sid=' . $sid);
+  }
+  else {
+    return array('node/'.$node->nid.'/done', 'sid=' . $sid);
+  }
+} // end webform_client_form_submit
+
+/**
+ * Flattens a submitted form back into a single array representation (rather than nested fields)
+ */
+function _webform_client_form_submit_flatten($node, $fieldset, &$form) {
+  if (is_array($fieldset)) {
+    foreach ($fieldset as $form_key => $value) {
+      $cid = webform_get_cid($node, $form_key);
+      if (is_array($value) && $node->webformcomponents[$cid]['type'] == 'fieldset') {
+        _webform_client_form_submit_flatten($node, $value, $form);
+        unset($form[$form_key]);
+        unset($form[$cid]);
+      }
+      else {
+        // the order here is significant!
+        unset($form[$form_key]);
+        $form[$cid] = $value;
+      }
+    }
+  }
+}
+
+/**
+ * Prints the confirmation message after a successful submission.
+ */
+function _webform_confirmation($nid) {
+  if ($node = node_load(array('nid' => $nid))) {
+    if (node_access('view', $node)) {
+      drupal_set_title($node->title);
+      return theme('webform_confirmation', $node);
+    }
+    else {
+      drupal_access_denied();
+    }
+  }
+  else {
+    drupal_set_message(t("No node with the id '%nid' could be found", array('%nid'=>$nid)));
+    drupal_not_found();
+  }
+} // end _webform_confirmation
+
+/**
+ * Themable function for webform submission confirmation
+ */
+function theme_webform_confirmation($node) {
+  $node->body = check_markup($node->confirmation, $node->format, FALSE);
+  $node->links['webform_back'] = array(
+    'href' => 'node/'.$node->nid,
+    'title' => t('Go back to the form'),
+  );
+  return theme('node', $node, FALSE, TRUE);
+}
+
+/** 
+ * Filters all special chars
+ **/
+function _webform_filtervalues($string, $strict = TRUE) {
+  global $user;
+
+  $find= array('%username', '%useremail', '%site', '%date');
+  $replace= array($user->name, $user->mail, variable_get('site_name', 'drupal'), format_date(time(), 'large'));
+
+  if (module_exists('profile')) {
+    foreach ($user as $k => $v) {
+      // Special case for dates
+      $find[]= "%profile[$k]";
+      if (is_array($v) && $v['year']) {
+        $replace[] = format_date(strtotime($v['month'] .'/'. $v['day'] .'/'. $v['year']), 'custom', 'F j, Y', '0');
+      }
+      else {
+        $replace[] = $v;
+      }
+    }
+  }
+  foreach ($_SERVER as $k => $v) {
+    $find[]= "%server[$k]";
+    $replace[]= $v;
+  }
+  foreach ($_GET as $k => $v) {
+    $find[] = "%get[$k]";
+    $replace[] = $v;
+  }
+  foreach ($_POST as $k => $v) {
+    $find[] = "%post[$k]";
+    $replace[] = $v;
+  }
+  $string= str_replace($find, $replace, $string);
+
+  if (module_exists('profile')) {
+    // Clean up any unused %profile stuff
+    $string= preg_replace('/\%profile\[\w+\]/', '', $string);
+  }
+  // Clean up any unused %post and %get stuff
+  $string= preg_replace('/\%get\[\w+\]/', '', $string);
+  $string= preg_replace('/\%post\[\w+\]/', '', $string);
+  // Clean up any unused %system stuff
+  $string= preg_replace('/\%server\[\w+\]/', '', $string);
+
+  if ($strict) {
+    return filter_xss($string);
+  }
+  else {
+    return $string;
+  }
+} // end _webform_filtervalues
+
+function _webform_save_submission($node, $submitted) {
+  global $user;
+
+  $sid = db_next_id('{webform_submissions}_sid');
+  
+  db_query("INSERT INTO {webform_submissions} (nid, sid, uid, submitted, remote_addr) "." VALUES (%d, %d, %d, %d, '%s')", $node->nid, $sid, $user->uid, time(), $_SERVER['REMOTE_ADDR']);
+
+  foreach ($submitted as $cid => $value) {
+    if (is_array($value)) {
+      $delta = 0;
+      foreach ($value as $k => $v) {
+        db_query("INSERT INTO {webform_submitted_data} (nid, sid, cid, no, data) "."VALUES (%d, %d, %d, %d, '%s')", $node->nid, $sid, $cid, $delta, $v);
+        $delta++;
+      }
+    }
+    else {
+      db_query("INSERT INTO {webform_submitted_data} (nid, sid, cid, no, data) "."VALUES (%d, %d, %d, %d, '%s')", $node->nid, $sid, $cid, 0, $value);
+    }
+  }
+  
+  return $sid;
+}
+
+function _webform_update_submission($node, $sid, $submitted) {
+  global $user;
+
+  //update submission by first deleting and then readding it to the database
+  db_query("DELETE FROM {webform_submissions} WHERE sid = %d", $sid);
+  db_query("INSERT INTO {webform_submissions} (nid, sid, uid, submitted, remote_addr) "." VALUES (%d, %d, %d, %d, '%s')", $node->nid, $sid, $user->uid, time(), $_SERVER['REMOTE_ADDR']);
+
+  // update the submission data by first removing all this submissions data
+  db_query("DELETE FROM {webform_submitted_data} WHERE sid = %d", $sid);
+  // and then re-ad it to the database
+  foreach ($submitted as $cid => $value) {
+    if (is_array($value)) {
+      $delta = 0;
+      foreach ($value as $k => $v) {
+        db_query("INSERT INTO {webform_submitted_data} (nid, sid, cid, no, data) "."VALUES (%d, %d, %d, %d, '%s')", $node->nid, $sid, $cid, $delta, $v);
+        $delta++;
+      }
+    }
+    else {
+      db_query("INSERT INTO {webform_submitted_data} (nid, sid, cid, no, data) "."VALUES (%d, %d, %d, %d, '%s')", $node->nid, $sid, $cid, 0, $value);
+    }
+  }
+
+  return $sid;
+}
+
+function webform_page() {
+  include_once (drupal_get_path('module', 'webform')."/webform.inc");
+  return _webform_page();
+}
+
+/**
+ * function webform_results() is an allocator function that builds the page
+ * under the 'Results' sub menu The function uses the URL tail to nominate
+ * internal content.
+ */
+function webform_results() {
+  include_once (drupal_get_path('module', 'webform')."/webform.inc");
+  include_once (drupal_get_path('module', 'webform')."/webform_report.inc");
+
+  $nid= arg(1);
+  $node= node_load(array('nid' => $nid));
+
+  $title= $node->title;
+  drupal_set_title($title);
+
+  if (arg(2) == 'results') {
+
+    switch (arg(3)) {
+      case 'analysis' :
+        $content= _webform_results_analysis($nid);
+        break;
+      case 'clear' :
+        $content= drupal_get_form('_webform_results_clear', $nid);
+        break;
+      case 'delete' :
+        $sid= arg(4);
+        $content= drupal_get_form('_webform_submission_delete', $nid, $sid);
+        break;
+      case 'edit' :
+      	$sid= arg(4);
+      	$content= webform_submission_edit($node, $sid);
+      	break;
+      case 'table' :
+        $content= _webform_results_table($nid);
+        break;
+      case 'download' :
+        $content= _webform_results_download($nid);
+        break;
+      case 'submissions' :
+      default :
+        $content= _webform_results_submissions($nid);
+        break;
+    }
+
+    return $content;
+  }
+}
+
+function webform_get_cid($node, $form_key) {
+  foreach ($node->webformcomponents as $cid => $component) {
+    if ($component['form_key'] == $form_key) {
+      return $cid;
+    }
+  }
+}
+
+function _webform_safe_name($name) {
+  $new = drupal_strtolower(trim($name));
+  $new = str_replace(' ', '_', $new);
+  $new = preg_replace('/[^a-z0-9_]/', '', $new);
+  // If the string contains NO safe characters, base64 encode the answer
+  if ($new == '') {
+    $new = base64_encode($name);
+  }
+  return $new;
+}
+
+function _webform_components_decode($components) {
+  if (is_array($components)) {
+    foreach ($components as $cid => $value) {
+      if (is_string($value)) {
+        $components[$cid] = unserialize(base64_decode($value));
+      }
+    }
+  }
+  return $components;
+}
+
+/**
+ * Convert an array of components into a tree
+ */
+function _webform_components_tree_build($src, &$tree, $parent, &$page_count) {
+  foreach ($src as $cid => $component) {
+    if ($component['parent'] == $parent) {
+      _webform_components_tree_build($src, $component, $cid, $page_count);
+      $tree['children'][$cid] = $component;
+      $tree['children'][$cid]['page_num'] = $page_count;
+      if ($component['type'] == 'pagebreak') {
+        $page_count++;
+      }
+    }
+  }
+  return $tree;
+}
+
+/**
+ * Helper for the uasort in webform_tree_sort()
+ */
+function _webform_components_sort($a, $b) {
+  if ($a['weight'] == $b['weight']) {
+    return strcasecmp($a['name'], $b['name']);
+  }
+  return ($a['weight'] < $b['weight']) ? -1 : 1;
+}
+
+
+/**
+ * Sort each level of a component tree by weight and name
+ */
+function _webform_components_tree_sort($tree) {
+  if (is_array($tree['children'])) {
+    uasort($tree['children'], "_webform_components_sort");
+    foreach ($tree['children'] as $cid => $component) {
+      $return[$cid] = _webform_components_tree_sort($component);
+    }
+    $tree['children'] = $return;
+  }
+  return $tree;
+}
+
+function _webform_load_components($return_all = false) {
+  static $component_list;
+  
+  if (!isset($component_list)) {
+    $component_list = array();
+    $path = drupal_get_path('module', 'webform')."/components";
+    $files = file_scan_directory($path, '^.*\.inc$');
+    foreach ($files as $filename => $file) {
+      if ($return_all || variable_get('webform_enable_'.$file->name, 1)) {
+        include_once($filename);
+        $component_list[$file->name] = t($file->name);
+      }
+    }
+  }
+  return $component_list;
+}
--- webform_report.inc	Mon May 28 21:40:54 2007
+++ webform_report.inc	Wed Jun 20 22:33:44 2007
@@ -1,273 +1,280 @@
-<?php
-// $Id: webform_report.inc,v 1.15.2.3 2007/05/28 19:40:54 quicksketch Exp $
-
-/** 
- * This file includes helper functions for creating reports for webform.module
- *
- * @author Pontus Ullgren <ullgren@user.sourceforge.net>
- * @package module_webform
- * @copyright Pontus Ullgren 2004
- **/
-
-/**
- * Database accessor function which to returns lists of submissions for a given
- * form.
- * @param  integer $nid the node id of the webform
- */
-function _webform_results_submissions($nid) {
-  $header = theme('webform_results_submissions_header', $nid);
-  $submissions = _webform_fetch_submissions($nid, $header);  
-  return theme('webform_results_submissions', $nid, $submissions);
-}
-
-/**
- * Theme the header of the submissions table. This is done in it's own function
- * so that webform can retrieve the header and use it for sorting the results.
- */
-function theme_webform_results_submissions_header($nid) {
-  return array(
-    array('data' => t('#'), 'field' => 'sid', 'sort' => 'asc'),
-    array('data' => t('Submitted'), 'field' => 'submitted'),
-    array('data' => t('User'), 'field' => 'name'),
-    array('data' => t('IP Address'), 'field' => 'remote_addr'),
-    array('data' => t('Operations'), 'colspan' => user_access('clear webform results') ? '3' : '2'),
-  );
-}
-
-/**
- * Theme the submissions tab of the webform results page.
- * @param $nid
- *   The nid of the node whose results are being displayed.
- * @param $submissions
- *   An array of all submissions for this webform.
- */
-function theme_webform_results_submissions($nid, $submissions) {
-  
-  // This header has to be generated seperately so we can add the SQL necessary
-  // to sort the results.
-  $header = theme('webform_results_submissions_header', $nid);
-  
-  $rows = array();
-  foreach ($submissions as $sid => $submission) {
-    $row = array(
-      $sid,
-      format_date($submission->submitted, 'small'),
-      theme('username', $submission),
-      $submission->remote_addr,
-      l(t('View'), "node/$nid", NULL, "sid=". $submission->sid, NULL, FALSE),
-    );
-    
-    if (user_access('clear webform results')) {
-      $row[] = l(t('Delete'), "node/$nid/results/delete/". $submission->sid, NULL, NULL, NULL, FALSE);
-    }
-    $rows[] = $row;
-  }
-  
-  return theme('table', $header, $rows);
-}
-
-/**
- * This function creates a table for all submissions.
- *   @param integer $nid The node ID of the node to show results for.
- */
-function _webform_results_table($nid) {
-  include_once(drupal_get_path('module', 'webform') ."/webform.inc");
-  // Load Components
-  _webform_load_components();
-
-  // Get all the component cid and names for the node
-  $query = 'SELECT cid, name, type, extra FROM {webform_component} WHERE nid = %d ORDER BY weight, name';
-  $res = db_query($query, $nid);
-  while ($component = db_fetch_array($res)) {
-    $components[] = $component;
-  }
-
-  // Get all the submissions for the node
-  $header = theme('webform_results_table_header', $nid);
-  $submissions = _webform_fetch_submissions($nid, $header);
-  
-  return theme('webform_results_table', $nid, $components, $submissions);
-} // end function _webform_results_table($nid)
-
-
-function theme_webform_results_table_header($nid) {
-  return array(
-    array('data' => t('#'), 'field' => 'sid', 'sort' => 'asc'),
-    array('data' => t('Submitted'), 'field' => 'submitted'),
-    array('data' => t('User'), 'field' => 'name'),
-    array('data' => t('IP Address'), 'field' => 'remote_addr'),
-  );
-}
-
-/**
- * Theme the results table displaying all the submissions for a particular node.
- * @param $nid
- *   The nid of the node whose results are being displayed.
- * @param $components
- *   An associative array of the components for this webform.
- * @param $submissions
- *   An array of all submissions for this webform.
- */
-function theme_webform_results_table($nid, $components, $submissions) {
-  $header = array();
-  $rows = array();
-  $cell = array();
-
-  // This header has to be generated seperately so we can add the SQL necessary
-  // to sort the results.
-  $header = theme('webform_results_table_header', $nid);
-
-  // Generate a row for each submission
-  foreach ($submissions as $sid => $submission) {
-    $cell[] = l($sid, 'node/'. $nid, NULL, "sid=". $sid);
-    $cell[] = format_date($submission->submitted, "small");
-    $cell[] = theme('username', $submission);
-    $cell[] = $submission->remote_addr;
-    $component_headers = array();
-
-    // Generate a cell for each component
-    foreach ($components as $component) {
-      $component['extra'] = unserialize($component['extra']);
-      $table_function = "_webform_table_data_". $component['type'];
-      if (function_exists($table_function)) {
-        $submission_output = $table_function($submission->data[$component['cid']], $component);
-        if ($submission_output !== NULL) {
-          $component_headers[] = $component['name'];
-          $cell[] = $submission_output;
-        }
-      }
-    }
-    
-    $rows[] = $cell;
-    unset($cell);
-  }
-  if (!empty($component_headers)) {
-    $header = array_merge($header, $component_headers);
-  }
-
-  return theme('table', $header, $rows);
-}
-
-function _webform_results_download($nid) {
-  include_once(drupal_get_path('module', 'webform') ."/webform.inc");
-
-/*
- * The CSV requires that the data be presented in a flat file.  In order 
- * to maximize useability to the Excel community and minimize subsequent 
- * stats or spreadsheet programming this program extracts data from the 
- * various records for a given session and presents them as a single file 
- * where each row represents a single record.
- * The structure of the file is:
- *   Heading Line 1: Gives group overviews padded by empty cells to the 
- *                   next group.  A group may be a question and corresponds 
- *                   to a component in the webform philosophy. Each group 
- *                   overview will have a fixed number of columns beneath it.
- *   Heading line 2: gives column headings
- *   Data line 1 .....
- *   Data line 2 .....
- *   
- * An example of this format is given below.  Note the columns have had spaces 
- * added so the columns line up.  This is not the case with actual file where 
- * a column may be null.  Note also, that multiple choice questions as produced
- * by checkboxes or radio buttons have been presented as "yes" or "no" and the
- * actual choice text is retained only in the header line 2.
- * Data from text boxes and input fields are written out in the body of the table.
- *
- *   Submission Details,    ,   ,      ,Question 1,        ,        ,..,        ,Question 2,        ,        ,..,        ,Question n
- *   timestamp         ,time,SID,userid,Choice 1  ,Choice 2,Choice 3,..,Choice n,Choice 1  ,Choice 2,Choice 3,..,Choice n,Comment
- *   21 Feb 2005       ,1835,23 ,34    ,Yes       ,No      ,No      ,..,No      ,Yes       ,Yes     ,Yes     ,..,Yes     ,My comment
- *   23 Feb 2005       ,1125,24 ,89    ,Yes       ,Yes     ,No      ,..,No      ,Yes       ,Yes     ,Yes     ,..,Yes     ,Hello
- *   ...............................................................................................................
- *   27 Feb 2005       ,1035,56 ,212   ,Yes       ,No      ,No      ,..,No      ,Yes       ,No      ,Yes     ,..,Yes     ,How is this?
- */
-  $node = node_load(array('nid' => $nid));
-
-  $file_name = tempnam(variable_get('file_directory_temp', FILE_DIRECTORY_TEMP), 'webform');
-  $handle = @fopen($file_name, 'w'); // The @ suppresses errors
-  $header[0] .= $node->title .",,,,";
-  $header[1] .= "Submission Details,,,,";
-  $header[2] .= "Serial,SID,Time,UID,Username";
-  // Compile header information
-  _webform_load_components(); // Load all components
-  if (is_array($node->webformcomponents)) {
-    foreach ($node->webformcomponents as $cid => $component) {
-      $csv_header_function   = "_webform_csv_headers_". $component['type'];
-      if (function_exists($csv_header_function)) {
-        // Let each component determine its headers
-        $component_header = $csv_header_function($component);
-        $header[0] .= ',"'. str_replace(array('"', '\,'), array('""', '","'), $component_header[0]) .'"';
-        $header[1] .= ',"'. str_replace(array('"', '\,'), array('""', '","'), $component_header[1]) .'"';
-        $header[2] .= ',"'. str_replace(array('"', '\,'), array('""', '","'), $component_header[2]) .'"';
-      }
-    }
-  }
-  
-  // Write header information
-  $file_record = $header[0] ."\n". $header[1] ."\n". $header[2] ."\n";
-  @fwrite($handle, $file_record);
-
-  // Get all the submissions for the node
-  $submissions = _webform_fetch_submissions($nid);
-  
-  // Generate a row for each submission
-  $rowcount = 0;
-  foreach ($submissions as $sid => $submission) {
-    $row = ++$rowcount .",". $sid .",\"". format_date($submission->submitted, 'small') ."\",". $submission->uid .",\"". $submission->name ."\"";
-    foreach ($node->webformcomponents as $cid => $component) {      
-      $csv_data_function   = "_webform_csv_data_". $component['type'];
-      if (function_exists($csv_data_function)) {
-        // Let each component add its data
-        $row .= ',"'. str_replace(array('"', '\,'), array('""', '","'), $csv_data_function($submission->data[$cid], $component)) .'"';
-      }
-    }
-    // Write data from submissions
-    @fwrite($handle, $row ."\n");
-  }
-  // Close the file 
-  @fclose($handle);
-
-  drupal_set_header("Content-type: text/csv; charset=utf-8");
-  drupal_set_header("Content-Disposition: attachment; filename=". preg_replace('/\.$/', '', str_replace(' ', '_', $node->title)) .".csv");
-
-  @readfile($file_name);  // The @ makes it silent
-  @unlink($file_name);  // Clean up, the @ makes it silent
-  exit(0);
-} // end function _webform_results_download
-
-/* _webform_results_analysis - Provides simple analysis of a series of webform submission.
- * @return to stdio a themeatic HTML rendering of the page.
- */
-function _webform_results_analysis($nid) {
-  
-  $query = 'SELECT nid, cid, name, type, value, extra '.
-    ' FROM {webform_component} '.
-    ' WHERE nid = %d '.
-    ' ORDER BY weight, name';
-
-  $components = db_query($query, $nid);
-
-  $rows = array();
-  $question_number = 0;
-
-  $headers = array(
-    t('Q'),
-    array('data' => t('responses'), 'colspan' => '10')
-  );
-
-  _webform_load_components(); // Load all component types
-  while ($component = db_fetch_array($components)) {
-    $question_number++;
-    
-    // Do component specific call
-    $analysis_function = "_webform_analysis_rows_". $component['type'];
-    if (function_exists($analysis_function)) {
-      $crows = $analysis_function($component);       
-      if (is_array($crows)) {
-        $row[0] = array('data' => '<strong>'. $question_number .'</strong>', 'rowspan' => count($crows) + 1, 'valign' => 'top');
-        $row[1] = array('data' => '<strong>'. $component['name'] .'</strong>', 'colspan' => '10');
-        $rows = array_merge($rows, array_merge(array($row), $crows));
-      }
-    }
-  }
-  return theme('table', $headers, $rows);
-}
+<?php
+// $Id: webform_report.inc,v 1.15.2.3 2007/05/28 19:40:54 quicksketch Exp $
+
+/** 
+ * This file includes helper functions for creating reports for webform.module
+ *
+ * @author Pontus Ullgren <ullgren@user.sourceforge.net>
+ * @package module_webform
+ * @copyright Pontus Ullgren 2004
+ **/
+
+/**
+ * Database accessor function which to returns lists of submissions for a given
+ * form.
+ * @param  integer $nid the node id of the webform
+ */
+function _webform_results_submissions($nid) {
+  $header = theme('webform_results_submissions_header', $nid);
+  $submissions = _webform_fetch_submissions($nid, $header);  
+  return theme('webform_results_submissions', $nid, $submissions);
+}
+
+/**
+ * Theme the header of the submissions table. This is done in it's own function
+ * so that webform can retrieve the header and use it for sorting the results.
+ */
+function theme_webform_results_submissions_header($nid) {
+  return array(
+    array('data' => t('#'), 'field' => 'sid', 'sort' => 'asc'),
+    array('data' => t('Submitted'), 'field' => 'submitted'),
+    array('data' => t('User'), 'field' => 'name'),
+    array('data' => t('IP Address'), 'field' => 'remote_addr'),
+    array('data' => t('Operations'), 'colspan' => user_access('clear webform results') ? '3' : '2'),
+  );
+}
+
+/**
+ * Theme the submissions tab of the webform results page.
+ * @param $nid
+ *   The nid of the node whose results are being displayed.
+ * @param $submissions
+ *   An array of all submissions for this webform.
+ */
+function theme_webform_results_submissions($nid, $submissions) {
+global $user;
+  
+  // This header has to be generated seperately so we can add the SQL necessary
+  // to sort the results.
+  $header = theme('webform_results_submissions_header', $nid);
+  
+  $rows = array();
+  foreach ($submissions as $sid => $submission) {
+    $row = array(
+      $sid,
+      format_date($submission->submitted, 'small'),
+      theme('username', $submission),
+      $submission->remote_addr,
+      l(t('View'), "node/$nid", NULL, "sid=". $submission->sid, NULL, FALSE),
+    );
+    
+    if ((user_access("edit own webform submissions") && ($user->uid == $submission->uid)) || user_access("edit webform submissions")) {
+	  $row[] = l(t('Edit'),"node/$nid/results/edit/".$submission->sid, NULL, NULL, NULL, FALSE);
+	} else {
+	  $row[] = t('Edit');
+	}
+
+    if (user_access('clear webform results')) {
+      $row[] = l(t('Delete'), "node/$nid/results/delete/". $submission->sid, NULL, NULL, NULL, FALSE);
+    }
+    $rows[] = $row;
+  }
+  
+  return theme('table', $header, $rows);
+}
+
+/**
+ * This function creates a table for all submissions.
+ *   @param integer $nid The node ID of the node to show results for.
+ */
+function _webform_results_table($nid) {
+  include_once(drupal_get_path('module', 'webform') ."/webform.inc");
+  // Load Components
+  _webform_load_components();
+
+  // Get all the component cid and names for the node
+  $query = 'SELECT cid, name, type, extra FROM {webform_component} WHERE nid = %d ORDER BY weight, name';
+  $res = db_query($query, $nid);
+  while ($component = db_fetch_array($res)) {
+    $components[] = $component;
+  }
+
+  // Get all the submissions for the node
+  $header = theme('webform_results_table_header', $nid);
+  $submissions = _webform_fetch_submissions($nid, $header);
+  
+  return theme('webform_results_table', $nid, $components, $submissions);
+} // end function _webform_results_table($nid)
+
+
+function theme_webform_results_table_header($nid) {
+  return array(
+    array('data' => t('#'), 'field' => 'sid', 'sort' => 'asc'),
+    array('data' => t('Submitted'), 'field' => 'submitted'),
+    array('data' => t('User'), 'field' => 'name'),
+    array('data' => t('IP Address'), 'field' => 'remote_addr'),
+  );
+}
+
+/**
+ * Theme the results table displaying all the submissions for a particular node.
+ * @param $nid
+ *   The nid of the node whose results are being displayed.
+ * @param $components
+ *   An associative array of the components for this webform.
+ * @param $submissions
+ *   An array of all submissions for this webform.
+ */
+function theme_webform_results_table($nid, $components, $submissions) {
+  $header = array();
+  $rows = array();
+  $cell = array();
+
+  // This header has to be generated seperately so we can add the SQL necessary
+  // to sort the results.
+  $header = theme('webform_results_table_header', $nid);
+
+  // Generate a row for each submission
+  foreach ($submissions as $sid => $submission) {
+    $cell[] = l($sid, 'node/'. $nid, NULL, "sid=". $sid);
+    $cell[] = format_date($submission->submitted, "small");
+    $cell[] = theme('username', $submission);
+    $cell[] = $submission->remote_addr;
+    $component_headers = array();
+
+    // Generate a cell for each component
+    foreach ($components as $component) {
+      $component['extra'] = unserialize($component['extra']);
+      $table_function = "_webform_table_data_". $component['type'];
+      if (function_exists($table_function)) {
+        $submission_output = $table_function($submission->data[$component['cid']], $component);
+        if ($submission_output !== NULL) {
+          $component_headers[] = $component['name'];
+          $cell[] = $submission_output;
+        }
+      }
+    }
+    
+    $rows[] = $cell;
+    unset($cell);
+  }
+  if (!empty($component_headers)) {
+    $header = array_merge($header, $component_headers);
+  }
+
+  return theme('table', $header, $rows);
+}
+
+function _webform_results_download($nid) {
+  include_once(drupal_get_path('module', 'webform') ."/webform.inc");
+
+/*
+ * The CSV requires that the data be presented in a flat file.  In order 
+ * to maximize useability to the Excel community and minimize subsequent 
+ * stats or spreadsheet programming this program extracts data from the 
+ * various records for a given session and presents them as a single file 
+ * where each row represents a single record.
+ * The structure of the file is:
+ *   Heading Line 1: Gives group overviews padded by empty cells to the 
+ *                   next group.  A group may be a question and corresponds 
+ *                   to a component in the webform philosophy. Each group 
+ *                   overview will have a fixed number of columns beneath it.
+ *   Heading line 2: gives column headings
+ *   Data line 1 .....
+ *   Data line 2 .....
+ *   
+ * An example of this format is given below.  Note the columns have had spaces 
+ * added so the columns line up.  This is not the case with actual file where 
+ * a column may be null.  Note also, that multiple choice questions as produced
+ * by checkboxes or radio buttons have been presented as "yes" or "no" and the
+ * actual choice text is retained only in the header line 2.
+ * Data from text boxes and input fields are written out in the body of the table.
+ *
+ *   Submission Details,    ,   ,      ,Question 1,        ,        ,..,        ,Question 2,        ,        ,..,        ,Question n
+ *   timestamp         ,time,SID,userid,Choice 1  ,Choice 2,Choice 3,..,Choice n,Choice 1  ,Choice 2,Choice 3,..,Choice n,Comment
+ *   21 Feb 2005       ,1835,23 ,34    ,Yes       ,No      ,No      ,..,No      ,Yes       ,Yes     ,Yes     ,..,Yes     ,My comment
+ *   23 Feb 2005       ,1125,24 ,89    ,Yes       ,Yes     ,No      ,..,No      ,Yes       ,Yes     ,Yes     ,..,Yes     ,Hello
+ *   ...............................................................................................................
+ *   27 Feb 2005       ,1035,56 ,212   ,Yes       ,No      ,No      ,..,No      ,Yes       ,No      ,Yes     ,..,Yes     ,How is this?
+ */
+  $node = node_load(array('nid' => $nid));
+
+  $file_name = tempnam(variable_get('file_directory_temp', FILE_DIRECTORY_TEMP), 'webform');
+  $handle = @fopen($file_name, 'w'); // The @ suppresses errors
+  $header[0] .= $node->title .",,,,";
+  $header[1] .= "Submission Details,,,,";
+  $header[2] .= "Serial,SID,Time,UID,Username";
+  // Compile header information
+  _webform_load_components(); // Load all components
+  if (is_array($node->webformcomponents)) {
+    foreach ($node->webformcomponents as $cid => $component) {
+      $csv_header_function   = "_webform_csv_headers_". $component['type'];
+      if (function_exists($csv_header_function)) {
+        // Let each component determine its headers
+        $component_header = $csv_header_function($component);
+        $header[0] .= ',"'. str_replace(array('"', '\,'), array('""', '","'), $component_header[0]) .'"';
+        $header[1] .= ',"'. str_replace(array('"', '\,'), array('""', '","'), $component_header[1]) .'"';
+        $header[2] .= ',"'. str_replace(array('"', '\,'), array('""', '","'), $component_header[2]) .'"';
+      }
+    }
+  }
+  
+  // Write header information
+  $file_record = $header[0] ."\n". $header[1] ."\n". $header[2] ."\n";
+  @fwrite($handle, $file_record);
+
+  // Get all the submissions for the node
+  $submissions = _webform_fetch_submissions($nid);
+  
+  // Generate a row for each submission
+  $rowcount = 0;
+  foreach ($submissions as $sid => $submission) {
+    $row = ++$rowcount .",". $sid .",\"". format_date($submission->submitted, 'small') ."\",". $submission->uid .",\"". $submission->name ."\"";
+    foreach ($node->webformcomponents as $cid => $component) {      
+      $csv_data_function   = "_webform_csv_data_". $component['type'];
+      if (function_exists($csv_data_function)) {
+        // Let each component add its data
+        $row .= ',"'. str_replace(array('"', '\,'), array('""', '","'), $csv_data_function($submission->data[$cid], $component)) .'"';
+      }
+    }
+    // Write data from submissions
+    @fwrite($handle, $row ."\n");
+  }
+  // Close the file 
+  @fclose($handle);
+
+  drupal_set_header("Content-type: text/csv; charset=utf-8");
+  drupal_set_header("Content-Disposition: attachment; filename=". preg_replace('/\.$/', '', str_replace(' ', '_', $node->title)) .".csv");
+
+  @readfile($file_name);  // The @ makes it silent
+  @unlink($file_name);  // Clean up, the @ makes it silent
+  exit(0);
+} // end function _webform_results_download
+
+/* _webform_results_analysis - Provides simple analysis of a series of webform submission.
+ * @return to stdio a themeatic HTML rendering of the page.
+ */
+function _webform_results_analysis($nid) {
+  
+  $query = 'SELECT nid, cid, name, type, value, extra '.
+    ' FROM {webform_component} '.
+    ' WHERE nid = %d '.
+    ' ORDER BY weight, name';
+
+  $components = db_query($query, $nid);
+
+  $rows = array();
+  $question_number = 0;
+
+  $headers = array(
+    t('Q'),
+    array('data' => t('responses'), 'colspan' => '10')
+  );
+
+  _webform_load_components(); // Load all component types
+  while ($component = db_fetch_array($components)) {
+    $question_number++;
+    
+    // Do component specific call
+    $analysis_function = "_webform_analysis_rows_". $component['type'];
+    if (function_exists($analysis_function)) {
+      $crows = $analysis_function($component);       
+      if (is_array($crows)) {
+        $row[0] = array('data' => '<strong>'. $question_number .'</strong>', 'rowspan' => count($crows) + 1, 'valign' => 'top');
+        $row[1] = array('data' => '<strong>'. $component['name'] .'</strong>', 'colspan' => '10');
+        $rows = array_merge($rows, array_merge(array($row), $crows));
+      }
+    }
+  }
+  return theme('table', $headers, $rows);
+}
