Index: webform.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/webform/webform.module,v retrieving revision 1.131 diff -u -r1.131 webform.module --- webform.module 16 Jun 2009 12:39:04 -0000 1.131 +++ webform.module 17 Jun 2009 22:33:14 -0000 @@ -122,9 +122,38 @@ 'access callback' => 'node_access', 'access arguments' => array('update', 1), 'file' => 'includes/webform.pages.inc', + 'weight' => 2, + 'type' => MENU_LOCAL_TASK, + ); + + // Node e-mail forms. + $items['node/%webform_menu/webform/emails'] = array( + 'title' => 'E-mails', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('webform_emails_form', 1), + 'access callback' => 'node_access', + 'access arguments' => array('update', 1), + 'file' => 'includes/webform.emails.inc', 'weight' => 1, 'type' => MENU_LOCAL_TASK, ); + $items['node/%webform_menu/webform/emails/%webform_menu_email'] = array( + 'title' => 'Edit e-mail settings', + 'load arguments' => array(1), + 'page arguments' => array('webform_email_edit_form', 1, 4), + 'access callback' => 'node_access', + 'access arguments' => array('update', 1), + 'file' => 'includes/webform.emails.inc', + 'type' => MENU_LOCAL_TASK, + ); + $items['node/%webform_menu/webform/emails/%webform_menu_email/delete'] = array( + 'title' => 'Delete e-mail settings', + 'load arguments' => array(1), + 'page arguments' => array('webform_email_delete_form', 1, 4), + 'access callback' => 'node_access', + 'access arguments' => array('update', 1), + 'type' => MENU_LOCAL_TASK, + ); // Node component forms. $items['node/%webform_menu/webform/components/%webform_menu_component'] = array( @@ -304,6 +333,38 @@ return $component; } + +/** + * Menu loader callback. Load a webform e-mail if the given eid is a valid. + */ +function webform_menu_email_load($eid, $nid) { + module_load_include('inc', 'webform', 'includes/webform.emails'); + $node = node_load($nid); + if ($eid == 'new') { + $email = array( + 'email' => '', + 'subject' => 'default', + 'from_name' => 'default', + 'from_address' => 'default', + 'template' => 'default', + ); + if (isset($_GET['option']) && isset($_GET['email'])) { + $type = $_GET['option']; + if ($type == 'custom') { + $email['email'] = $_GET['email']; + } + elseif ($type == 'component' && isset($node->webform['components'][$_GET['email']])) { + $email['email'] = $_GET['email']; + } + } + } + else { + $email = isset($node->webform['emails'][$eid]) ? $node->webform['emails'][$eid] : FALSE; + } + + return $email; +} + function webform_submission_access($node, $submission, $op = 'view', $account = NULL) { global $user; $account = isset($account) ? $account : $user; @@ -351,14 +412,6 @@ 'template' => 'templates/webform-form', 'pattern' => 'webform_form_[0-9]+', ), - 'webform_mail_components_form' => array( - 'arguments' => array('form' => NULL), - 'file' => 'includes/webform.pages.inc', - ), - 'webform_mail_settings_form' => array( - 'arguments' => array('form' => NULL), - 'file' => 'includes/webform.pages.inc', - ), 'webform_advanced_submit_limit_form' => array( 'arguments' => array('form' => NULL), 'file' => 'includes/webform.pages.inc', @@ -389,6 +442,19 @@ 'webform_token_help' => array( 'arguments' => array(), ), + // webform.emails.inc. + 'webform_emails_form' => array( + 'arguments' => array('form' => NULL), + 'file' => 'includes/webform.emails.inc', + ), + 'webform_email_add_form' => array( + 'arguments' => array('form' => NULL), + 'file' => 'includes/webform.emails.inc', + ), + 'webform_email_edit_form' => array( + 'arguments' => array('form' => NULL), + 'file' => 'includes/webform.emails.inc', + ), // webform_components.inc. 'webform_components_form' => array( 'arguments' => array('form' => NULL), @@ -550,6 +616,12 @@ while ($role = db_fetch_object($result)) { $additions->webform['roles'][] = $role->rid; } + + $additions->webform['emails'] = array(); + $result = db_query('SELECT * FROM {webform_emails} WHERE nid = %d', $node->nid); + while ($email = db_fetch_array($result)) { + $additions->webform['emails'][$email['eid']] = $email; + } } else { $additions->webform = array( @@ -559,13 +631,10 @@ 'submit_text' => '', 'submit_limit' => -1, 'submit_interval' => -1, - 'email' => '', - 'email_from_name' => 'default', - 'email_from_address' => 'default', - 'email_subject' => 'default', 'additional_validate' => '', 'additional_submit' => '', 'roles' => array(1, 2), + 'emails' => array(), ); } @@ -931,6 +1000,17 @@ '#description' => t('Cookies 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_email_address_format'] = array( + '#type' => 'radios', + '#title' => t('E-mail address format'), + '#options' => array( + 'long' => t('Long format: "Example Name" <name@example.com>'), + 'short' => t('Short format: name@example.com'), + ), + '#default_value' => variable_get('webform_email_address_format', 'long'), + '#description' => t('Most servers support the "long" format which will allow for more friendly From addresses in e-mails sent. However many Windows-based servers are unable to send in the long format. Change this option if experiencing problems sending e-mails with Webform.'), + ); + $form['advanced']['webform_export_format'] = array( '#type' => 'radios', '#title' => t('Default export format'), @@ -1347,24 +1427,6 @@ $form_state['values']['submitted_tree'] = $form_state['values']['submitted']; $form_state['values']['submitted'] = _webform_client_form_submit_flatten($node, $form_state['values']['submitted']); - // Convert additional email addresses into actual values. - foreach ($node->webform['additional_emails'] as $cid => $value) { - if (is_array($form_state['values']['submitted'][$cid])) { - $node->webform['additional_emails'][$cid] = array(); - foreach ($form_state['values']['submitted'][$cid] as $submitted_value) { - if ($submitted_value) { - $node->webform['additional_emails'][$cid][] = $submitted_value; - } - } - } - else { - $node->webform['additional_emails'][$cid] = $form_state['values']['submitted'][$cid]; - } - if (empty($node->webform['additional_emails'][$cid])) { - unset($node->webform['additional_emails'][$cid]); - } - } - // Perform additional submit processing. if (trim($node->webform['additional_submit'])) { // Support for Drupal 5 validation code. @@ -1396,104 +1458,89 @@ $sid = $form_state['values']['details']['sid']; // Check if this form is sending an email. - if ((!empty($node->webform['email']) || !empty($node->webform['additional_emails'])) && $form_state['values']['details']['is_new']) { + if ($form_state['values']['details']['is_new']) { + // Create a themed message for mailing. + foreach ($node->webform['emails'] as $eid => $email) { + $cid = is_numeric($email['email']) && isset($node->webform['components'][$email['email']]) ? $email['email'] : 'custom'; - // Set values for the name, address, and subject for the email. - $email_from_name = $node->webform['email_from_name']; - $email_from_address = $node->webform['email_from_address']; - $email_subject = $node->webform['email_subject']; - foreach (array('from_name', 'from_address', 'subject') as $field) { - if ($node->webform['email_'. $field] == 'default') { - ${'email_'. $field} = _webform_filter_values(webform_variable_get('webform_default_'. $field), $node, $form_state['values']['submitted']); - } - elseif (is_numeric($node->webform['email_'. $field])) { - if (is_array($form_state['values']['submitted'][${'email_'. $field}])) { - $values = array(); - foreach ($form_state['values']['submitted'][${'email_'. $field}] as $key => $value) { - $values[] = _webform_filter_values($value, $node, $form_state['values']['submitted']); - } - ${'email_'. $field} = implode(', ', $values); - } - else { - ${'email_'. $field} = _webform_filter_values($form_state['values']['submitted'][${'email_'. $field}], $node, $form_state['values']['submitted']); - } + // Pass through the theme layer if using the default template. + if ($email['template'] == 'default') { + $email['message'] = theme(array('webform_mail_'. $node->nid, 'webform_mail', 'webform_mail_message'), $form_state['values'], $node, $sid, $cid); } else { - ${'email_'. $field} = _webform_filter_values(${'email_'. $field}, $node, $form_state['values']['submitted']); + $email['message'] = $email['template']; } - } - // Create a themed message for mailing. - // Check for a node-specific message: - $emails = $node->webform['additional_emails']; - if ($node->webform['email']) { - $emails['default'] = $node->webform['email']; - } - $messages = array(); - $headers = array(); - $froms = array(); - $subjects = array(); - foreach ($emails as $cid => $email) { - $messages[$cid] = theme(array('webform_mail_'. $node->nid, 'webform_mail', 'webform_mail_message'), $form_state['values'], $node, $sid, $cid); - $headers[$cid] = theme(array('webform_mail_headers_'. $node->nid, 'webform_mail_headers'), $form_state['values'], $node, $sid, $cid); + // Replace tokens in the message. + $email['message'] = _webform_filter_values($email['message'], $node, $form_state['values'], FALSE); + + // Build the e-mail headers. + $email['headers'] = theme(array('webform_mail_headers_'. $node->nid, 'webform_mail_headers'), $form_state['values'], $node, $sid, $cid); // Assemble the FROM string. - if (isset($headers[$cid]['From'])) { - $froms[$cid] = $headers[$cid]['From']; - unset($headers[$cid]['From']); - } - elseif (drupal_strlen($email_from_name) > 0) { - $froms[$cid] = '"'. mime_header_encode($email_from_name) .'" <'. $email_from_address .'>'; + if (isset($email['headers']['From'])) { + // If a header From is already set, don't override it. + $email['from'] = $email['headers']['From']; + unset($email['headers']['From']); } else { - $froms[$cid] = $email_from_address; + $email['from'] = webform_format_email_address($email['from_address'], $email['from_name'], $node, $form_state['values']); } // Update the subject if set in the themed headers. - if (isset($headers[$cid]['Subject'])) { - $subjects[$cid] = $headers[$cid]['Subject']; - unset($headers[$cid]['Subject']); + if (isset($email['headers']['Subject'])) { + $email['headers']['subject'] = $email['headers']['Subject']; + unset($email['headers']['Subject']); } else { - $subjects[$cid] = $email_subject; + $email['subject'] = webform_format_email_subject($email['subject'], $node, $form_state['values']); } // Update the to e-mail if set in the themed headers. if (isset($headers[$cid]['To'])) { - $emails[$cid] = $headers[$cid]['To']; + $email['email'] = $headers[$cid]['To']; unset($headers[$cid]['To']); } - } - // Verify that this submission is not attempting to send any spam hacks. - if (_webform_submission_spam_check($emails['default'], $subjects['default'], $froms['default'], $headers['default'])) { - watchdog('webform', 'Possible spam attempt from @remote_addr'."
\n". nl2br(htmlentities($messages['default'])), array('@remote_add' => ip_address())); - drupal_set_message(t('Illegal information. Data not submitted.'), 'error'); - return FALSE; - } - - // Mail the webform results. - foreach ($emails as $cid => $address) { - // In the case of checkboxes or multiple select, multiple e-mails may need - // to be sent out. - if (is_array($address)) { - foreach ($address as $single_address) { - drupal_mail('webform', 'submission', $single_address, user_preferred_language($user), array('message' => $messages[$cid], 'subject' => $subjects[$cid], 'headers' => $headers[$cid]), $froms[$cid]); - - // Debugging output for email. - if (variable_get('webform_debug', 0) >= 2) { - drupal_set_message('E-mail Headers:
'. htmlentities(print_r($headers[$cid], TRUE)) .'
To: '. $single_address .'
From: '. htmlentities($froms[$cid]) .'
Subject: '. $subjects[$cid] .'
E-mail Body:
'. $messages[$cid] .'
'); + // Generate the list of addresses that this e-mail will be sent to. + $addresses = array_filter(explode(',', $email['email'])); + $addresses_final = array(); + foreach ($addresses as $address) { + $address = trim($address); + + // After filtering e-mail addresses with component values, a single value + // might contain multiple addresses (such as from checkboxes or selects). + $address = webform_format_email_address($address, NULL, $node, $form_state['values'], TRUE, FALSE, 'short'); + + if (is_array($address)) { + foreach ($address as $new_address) { + if (valid_email_address($new_address)) { + $addresses_final[] = $new_address; + } } } + elseif (valid_email_address($address)) { + $addresses_final[] = $address; + } } - else { - drupal_mail('webform', 'submission', $address, user_preferred_language($user), array('message' => $messages[$cid], 'subject' => $subjects[$cid], 'headers' => $headers[$cid]), $froms[$cid]); + // Mail the webform results. + foreach ($addresses_final as $address) { + // Verify that this submission is not attempting to send any spam hacks. + if (_webform_submission_spam_check($address, $email['subject'], $email['from'], $email['headers'])) { + watchdog('webform', 'Possible spam attempt from @remote_addr'."
\n". nl2br(htmlentities($email['message'])), array('@remote_add' => ip_address())); + drupal_set_message(t('Illegal information. Data not submitted.'), 'error'); + return FALSE; + } + + drupal_mail('webform', 'submission', $address, user_preferred_language($user), array('message' => $email['message'], 'subject' => $email['subject'], 'headers' => $email['headers']), $email['from']); + // Debugging output for email. if (variable_get('webform_debug', 0) >= 2) { - drupal_set_message('E-mail Headers:
'. htmlentities(print_r($headers[$cid], TRUE)) .'
To: '. $address .'
From: '. htmlentities($froms[$cid]) .'
Subject: '. $subjects[$cid] .'
E-mail Body:
'. $messages[$cid] .'
'); + drupal_set_message('E-mail Headers:
'. check_plain(print_r($headers[$cid], TRUE)) .'
To: '. check_plain($address) .'
From: '. check_plain($email['from']) .'
Subject: '. check_plain($email['subject']) .'
E-mail Body:
'. check_plain($email['message']) .'
'); } } + } } @@ -1730,46 +1777,71 @@ */ function _webform_filter_values($string, $node = NULL, $submission = NULL, $strict = TRUE) { global $user; + static $find, $replace; // Setup default token replacements. - $find = array('%site', '%date'); - $replace = array(variable_get('site_name', 'drupal'), format_date(time(), 'large')); + if (!isset($find)) { + $find = array('%site', '%date'); + $replace = array(variable_get('site_name', 'drupal'), format_date(time(), 'large')); + } // Node replacements. - if (isset($node)) { - $find[] = '%title'; - $replace[] = $node->title; + if (isset($node) && !in_array('%title', $find)) { + $find['%title'] = '%title'; + $replace['%title'] = $node->title; } // Submission replacements. - if (isset($submission)) { - foreach ($submission as $cid => $value) { - $find[] = '%cid['. $cid .']'; + if (isset($submission) && !in_array('%email_values', $find)) { + foreach ($submission['submitted'] as $cid => $value) { + // Find by CID. + $find[] = '%cid[' . $cid . ']'; + $replace[] = $value; + + // Find by form key. + $find[] = '%value[' . $node->webform['components'][$cid]['form_key'] . ']'; + $find[] = '%label[' . $node->webform['components'][$cid]['form_key'] . ']'; $replace[] = $value; + $replace[] = $node->webform['components'][$cid]['name']; } - } - // User replacements. - $find[] = '%username'; - $find[] = '%useremail'; - $replace[] = isset($user->name) ? $user->name : ''; - $replace[] = isset($user->mail) ? $user->mail : ''; - if ($user->uid && module_exists('profile')) { - profile_load_profile($user); + // The entire form tree: + $find[] = '%email_values'; + $replace[] = theme('webform_mail_fields', 0, $submission['submitted_tree'], $node); + + // Submission edit URL. + $find[] = '%submission_url'; + $replace[] = url('node/'. $node->nid .'/submission/'. $submission['details']['sid'], array('absolute' => TRUE)); } // Provide a list of candidates for token replacement. - $tokens = array( - '%server' => $_SERVER, + // Note these tokens are not cached as they may change frequently. + $special_tokens = array( '%session' => $_SESSION, '%cookie' => $_COOKIE, '%get' => $_GET, '%post' => $_POST, '%request' => $_REQUEST, - '%profile' => $user, ); - foreach ($tokens as $token => $variable) { + // User replacements. + if (!in_array('%username', $find)) { + $find[] = '%username'; + $find[] = '%useremail'; + $find[] = '%ip_address'; + $replace[] = isset($user->name) ? $user->name : ''; + $replace[] = isset($user->mail) ? $user->mail : ''; + $replace[] = ip_address(); + if ($user->uid && module_exists('profile')) { + profile_load_profile($user); + } + $special_tokens['%profile'] = $user; + + // Doesn't really belong here with user things, but works. + $special_tokens['%server'] = $_SERVER; + } + + foreach ($special_tokens as $token => $variable) { if (strpos($string, $token) !== FALSE) { foreach ($variable as $key => $value) { $find[] = $token .'['. $key .']'; @@ -1788,18 +1860,18 @@ $string = str_replace($find, $replace, $string); // Clean up any unused tokens. - foreach (array_keys($tokens) as $token) { + foreach (array_keys($special_tokens) as $token) { $string = preg_replace('/\\'. $token .'\[\w+\]/', '', $string); } - return $strict ? filter_xss($string) : $string; + return $strict ? check_plain($string) : $string; } /** * Filters all special tokens provided by webform, and allows basic layout in descriptions. */ function _webform_filter_descriptions($string, $node = NULL, $submission = NULL, $strict = TRUE) { - return check_markup(_webform_filter_values($string, $node = NULL, $submission = NULL, $strict = TRUE)); + return check_markup(_webform_filter_values($string, $node, $submission, $strict)); } /** @@ -1878,28 +1950,57 @@ return $result; } -function theme_webform_token_help() { - $tokens = array( +function theme_webform_token_help($node = NULL) { + $basic_tokens = array( '%username', '%useremail', + '%ip_address', '%site', '%date', + ); + + $special_tokens = array( '%server['. t('key') .']', '%session['. t('key') .']', '%get['. t('key') .']', '%post['. t('key') .']', '%request['. t('key') .']', ); + if (module_exists('profile')) { - $tokens[] = '%profile['. t('key') .']'; + $special_tokens[] = '%profile['. t('key') .']'; + } + + if (isset($node)) { + $submission_keys = array(); + foreach ($node->webform['components'] as $cid => $component) { + if (!in_array($component['type'], array('markup', 'fieldset', 'pagebreak'))) { + $submission_keys[] = $component['form_key']; + } + } + if (!empty($submission_keys)) { + $submission_tokens = array( + '%email_values', + '%submission_url', + '%label[key]', + '%value[key]', + t('Where the key may be any of the following components (do not include quotes):') . theme('item_list', $submission_keys), + ); + } } $output = ''; - $output .= t('You may use special tokens in this field that will be replaced with dynamic values.'); - $output .= theme('item_list', $tokens); - $output .= t('You can use %server[key] to add any of the special PHP $_SERVER variables, %session[key] to add any of the special PHP $_SESSION variables and %get[key] to create prefilled forms from the URL. %cookie, %request and %post also work with their respective PHP variables. For example %server[HTTP_USER_AGENT], %session[id], or %get[q].'); + $output .= '

' . t('You may use special tokens in this field that will be replaced with dynamic values.') . '

'; + + if (!empty($submission_tokens)) { + $output .= theme('item_list', $submission_tokens, t('Component variables')); + } + + $output .= theme('item_list', $basic_tokens, t('Basic variables')); + $output .= theme('item_list', $special_tokens, t('Special variables')); + $output .= '

' . t('You can use %server[key] to add any of the special PHP $_SERVER variables, %session[key] to add any of the special PHP $_SESSION variables and %get[key] to create prefilled forms from the URL. %cookie, %request and %post also work with their respective PHP variables. For example %server[HTTP_USER_AGENT], %session[id], or %get[q].') . '

'; 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 variable %profile[profile_city].'); + $output .= '

'. t('If you are using the Profile 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 variable %profile[profile_city].') . '

'; } $fieldset = array( @@ -1933,6 +2034,108 @@ } /** + * Given an email address and a name, format an e-mail address. + * + * @param $address + * The e-mail address. + * @param $name + * The name to be used in the formatted address. + * @param $node + * The webform node if replacements will be done. + * @param $submission + * The webform submission values if replacements will be done. + * @param $encode + * Encode the text for use in an e-mail. + * @param $single + * Force a single value to be returned, even if a component expands to + * multiple addresses. This is useful to ensure a single e-mail will be + * returned for the "From" address. + * @param $format + * The e-mail format, defaults to the site-wide setting. May be either "short" + * or "long". + */ +function webform_format_email_address($address, $name, $node = NULL, $submission = NULL, $encode = TRUE, $single = TRUE, $format = NULL) { + if (!isset($format)) { + $format = variable_get('webform_email_address_format', 'long'); + } + + if ($name == 'default') { + $name = webform_variable_get('webform_default_from_name'); + } + elseif (is_numeric($name) && isset($node->webform['components'][$name])) { + if (isset($submission['submitted'][$name])) { + $name = $submission['submitted'][$name]; + } + else { + $name = t('Value of !component', array('!component' => $node->webform['components'][$name]['name'])); + } + } + + if ($address == 'default') { + $address = webform_variable_get('webform_default_from_address'); + } + elseif (is_numeric($address) && isset($node->webform['components'][$address])) { + if (isset($submission['submitted'][$address])) { + $address = $submission['submitted'][$address]; + } + else { + $address = t('Value of "!component"', array('!component' => $node->webform['components'][$address]['name'])); + } + } + + // Convert arrays into a single value for From values. + if ($single) { + $address = is_array($address) ? reset($address) : $address; + $name = is_array($name) ? reset($name) : $name; + } + + // Address may be an array if a component value was used on checkboxes. + if (is_array($address)) { + foreach ($address as $key => $individual_address) { + $address[$key] = _webform_filter_values($individual_address, $node, $submission, FALSE); + } + } + else { + $address = _webform_filter_values($address, $node, $submission, FALSE); + } + + if ($format == 'long' && isset($name)) { + $name = _webform_filter_values($name, $node, $submission, FALSE); + if ($encode) { + $name = mime_header_encode($name); + } + return '"' . $name . '" <' . $address . '>'; + } + else { + return $address; + } +} + +/** + * Given an email subject, format it with any needed replacements. + */ +function webform_format_email_subject($subject, $node = NULL, $submission = NULL) { + if ($subject == 'default') { + $subject = webform_variable_get('webform_default_subject'); + } + elseif (is_numeric($subject) && isset($node->webform['components'][$subject])) { + if (isset($submission['submitted'][$subject])) { + $subject = $submission['submitted'][$subject]; + } + else { + $subject = t('Value of "!component"', array('!component' => $node->webform['components'][$subject]['name'])); + } + } + + // Convert arrays to strings (may happen if checkboxes are used as the value). + if (is_array($subject)) { + $subject = reset($subject); + } + + return _webform_filter_values($subject, $node, $submission, FALSE); +} + +/** * Given a set of components, determine which one are appropriate for a * particular use, such as an email address or subject. * Index: webform.install =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/webform/webform.install,v retrieving revision 1.25 diff -u -r1.25 webform.install --- webform.install 16 Jun 2009 12:39:03 -0000 1.25 +++ webform.install 17 Jun 2009 22:33:13 -0000 @@ -16,7 +16,7 @@ 'description' => 'Table for storing additional properties for webform nodes.', 'fields' => array( 'nid' => array( - 'description' => 'The node identifier of a webform', + 'description' => 'The node identifier of a webform.', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, @@ -57,26 +57,6 @@ 'not null' => TRUE, 'default' => -1, ), - 'email' => array( - 'description' => 'The primary e-mail address for receiving submission results.', - 'type' => 'varchar', - 'length' => 255, - ), - 'email_from_name' => array( - 'description' => 'The name of the sender in sent submission e-mails.', - 'type' => 'varchar', - 'length' => 255, - ), - 'email_from_address' => array( - 'description' => 'The address of the sender in sent submission e-mails.', - 'type' => 'varchar', - 'length' => 255, - ), - 'email_subject' => array( - 'description' => 'The subject of sent submission e-mails', - 'type' => 'varchar', - 'length' => 255, - ), 'additional_validate' => array( 'description' => 'PHP code for additional functionality when validating a form.', 'type' => 'text', @@ -95,7 +75,7 @@ 'description' => 'Stores information about components for webform nodes.', 'fields' => array( 'nid' => array( - 'description' => 'The node identifier of a webform', + 'description' => 'The node identifier of a webform.', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, @@ -167,6 +147,56 @@ 'primary key' => array('nid', 'cid'), ); + $schema['webform_emails'] = array( + 'description' => 'Holds information regarding e-mails that should be sent upon submitting a webform', + 'fields' => array( + 'nid' => array( + 'description' => 'The node identifier of a webform.', + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0, + ), + 'eid' => array( + 'description' => 'The e-mail identifier for this row\'s settings.', + 'type' => 'int', + 'unsigned' => TRUE, + 'size' => 'small', + 'not null' => TRUE, + 'default' => 0, + ), + 'email' => array( + 'description' => 'The e-mail address that will be sent to upon submission. This may be an e-mail address, the special key "default" or a numeric value. If a numeric value is used, the value of a component will be substituted on submission.', + 'type' => 'text', + 'not null' => FALSE, + ), + 'subject' => array( + 'description' => 'The e-mail subject that will be used. This may be a string, the special key "default" or a numeric value. If a numeric value is used, the value of a component will be substituted on submission.', + 'type' => 'varchar', + 'length' => '255', + 'not null' => FALSE, + ), + 'from_name' => array( + 'description' => 'The e-mail "from" name that will be used. This may be a string, the special key "default" or a numeric value. If a numeric value is used, the value of a component will be substituted on submission.', + 'type' => 'varchar', + 'length' => '255', + 'not null' => FALSE, + ), + 'from_address' => array( + 'description' => 'The e-mail "from" e-mail address that will be used. This may be a string, the special key "default" or a numeric value. If a numeric value is used, the value of a component will be substituted on submission.', + 'type' => 'varchar', + 'length' => '255', + 'not null' => FALSE, + ), + 'template' => array( + 'description' => 'A template that will be used for the sent e-mail. This may be a string or the special key "default", which will use the template provided by the theming layer.', + 'type' => 'text', + 'not null' => FALSE, + ) + ), + 'primary key' => array('nid', 'eid'), + ); + $schema['webform_roles'] = array( 'description' => 'Holds access information regarding which roles are allowed to submit which webform nodes. Does not prevent access to the webform node entirely, use the {node_access} table for that purpose.', 'fields' => array( @@ -198,7 +228,7 @@ 'not null' => TRUE, ), 'nid' => array( - 'description' => 'The node identifier of a webform', + 'description' => 'The node identifier of a webform.', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, @@ -233,7 +263,7 @@ 'description' => 'Stores all submitted field data for webform submissions.', 'fields' => array( 'nid' => array( - 'description' => 'The node identifier of a webform', + 'description' => 'The node identifier of a webform.', 'type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, @@ -1042,6 +1072,96 @@ } /** + * Convert node-level e-mail settings to new webform_emails table. + */ +function webform_update_6302() { + $ret = array(); + + // Safety check to prevent recreating the webform_emails table. + if (db_table_exists('webform_emails')) { + return $ret; + } + + $table = array( + 'fields' => array( + 'nid' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0, + ), + 'eid' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'size' => 'small', + 'not null' => TRUE, + 'default' => 0, + ), + 'email' => array( + 'type' => 'text', + 'not null' => FALSE, + ), + 'subject' => array( + 'type' => 'varchar', + 'length' => '255', + 'not null' => FALSE, + ), + 'from_name' => array( + 'type' => 'varchar', + 'length' => '255', + 'not null' => FALSE, + ), + 'from_address' => array( + 'type' => 'varchar', + 'length' => '255', + 'not null' => FALSE, + ), + 'template' => array( + 'type' => 'text', + 'not null' => FALSE, + ) + ), + 'primary key' => array('nid', 'eid'), + ); + + db_create_table($ret, 'webform_emails', $table); + + // Move over data from the webform table. + $result = db_query("SELECT w.nid, w.email, w.email_from_name, w.email_from_address, w.email_subject, wc.cid, wc.extra FROM {webform} w LEFT JOIN {webform_component} wc ON w.nid = wc.nid AND type IN ('select', 'hidden', 'email') ORDER BY nid"); + $nid = 0; + while ($row = db_fetch_object($result)) { + // Insert an e-mail settings row for the default e-mail. + if ($row->nid != $nid) { + $nid = $row->nid; + $eid = 0; + if (!empty($row->email)) { + $eid++; + db_query("INSERT INTO {webform_emails} (nid, eid, email, subject, from_name, from_address, template) VALUES (%d, %d, '%s', '%s', '%s', '%s', 'default')", $nid, $eid, $row->email, $row->email_subject, $row->email_from_name, $row->email_from_address); + } + } + + // Check for an e-mail based on a component. + if ($row->extra) { + $extra = unserialize($row->extra); + if ($extra['email']) { + $eid++; + unset($extra['email']); + db_query("INSERT INTO {webform_emails} (nid, eid, email, subject, from_name, from_address, template) VALUES (%d, %d, '%s', '%s', '%s', '%s', 'default')", $nid, $eid, $row->cid, $row->email_subject, $row->email_from_name, $row->email_from_address); + db_query("UPDATE {webform_component} SET extra = '%s' WHERE nid = %d AND cid = %d", serialize($extra), $row->nid, $row->cid); + } + } + } + + // Remove columns from webform table. + db_drop_field($ret, 'webform', 'email'); + db_drop_field($ret, 'webform', 'email_from_name'); + db_drop_field($ret, 'webform', 'email_from_address'); + db_drop_field($ret, 'webform', 'email_subject'); + + return $ret; +} + +/** * Recursively delete all files and folders in the specified filepath, then * delete the containing folder. * Index: webform.js =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/webform/webform.js,v retrieving revision 1.4 diff -u -r1.4 webform.js --- webform.js 7 May 2009 22:38:13 -0000 1.4 +++ webform.js 17 Jun 2009 22:33:13 -0000 @@ -9,6 +9,8 @@ Drupal.webform.defaultValues(context); // On click or change, make a parent radio button selected. Drupal.webform.setActive(context); + // Update the template select list upon changing a template. + Drupal.webform.updateTemplate(context); } Drupal.webform = new Object(); @@ -39,6 +41,32 @@ }; Drupal.webform.setActive = function(context) { - var setActive = function() { $('.form-radio', $(this).parent().parent()).attr('checked', true); }; + var setActive = function() { + $('.form-radio', $(this).parent().parent()).attr('checked', true); + }; $('.webform-set-active', context).click(setActive).change(setActive); }; + +Drupal.webform.updateTemplate = function(context) { + var defaultTemplate = $('#edit-templates-default').val(); + var $templateSelect = $('#webform-template-fieldset select', context); + var $templateTextarea = $('#webform-template-fieldset textarea', context); + + var updateTemplateSelect = function() { + if ($(this).val() == defaultTemplate) { + $templateSelect.val('default'); + } + else { + $templateSelect.val('custom'); + } + } + + var updateTemplateText = function() { + if ($(this).val() == 'default') { + $templateTextarea.val(defaultTemplate); + } + } + + $templateTextarea.keyup(updateTemplateSelect); + $templateSelect.change(updateTemplateText); +} Index: components/hidden.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/webform/components/hidden.inc,v retrieving revision 1.13 diff -u -r1.13 hidden.inc --- components/hidden.inc 7 May 2009 22:38:14 -0000 1.13 +++ components/hidden.inc 17 Jun 2009 22:33:14 -0000 @@ -17,7 +17,6 @@ 'weight' => 0, 'value' => '', 'extra' => array( - 'email' => 0, ), ); } @@ -46,13 +45,6 @@ '#type' => 'hidden', '#value' => 1, ); - $edit_fields['extra']['email'] = array( - '#type' => 'checkbox', - '#title' => t('E-mail a submission copy'), - '#return_value' => 1, - '#default_value' => $currfield['extra']['email'], - '#description' => t('Check this option if this component contains an e-mail address that should get a copy of the submission. Emails are sent individually so other emails will not be shown to the recipient.'), - ); $edit_fields['extra']['description'] = array(); // Hide the description box. return $edit_fields; } Index: components/select.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/webform/components/select.inc,v retrieving revision 1.23 diff -u -r1.23 select.inc --- components/select.inc 7 May 2009 22:38:14 -0000 1.23 +++ components/select.inc 17 Jun 2009 22:33:14 -0000 @@ -20,7 +20,6 @@ 'value' => '', 'extra' => array( 'items' => '', - 'email' => 0, 'multiple' => NULL, 'aslist' => NULL, 'description' => '', @@ -73,14 +72,7 @@ '#default_value' => $currfield['extra']['aslist'], '#description' => t('Check this option if you want the select component to be of listbox type instead of radiobuttons or checkboxes.'), ); - $edit_fields['extra']['email'] = array( - '#type' => 'checkbox', - '#title' => t('E-mail a submission copy'), - '#return_value' => 1, - '#default_value' => $currfield['extra']['email'], - '#description' => t('Check this option if this component contains an e-mail address that should get a copy of the submission. Emails are sent individually so other emails will not be shown to the recipient.') .' '. - t('To use the option with a select component, you must use key-value pairs seperated by pipes. i.e. user@example.com|Sample user.'), - ); + return $edit_fields; } Index: components/email.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/webform/components/email.inc,v retrieving revision 1.20 diff -u -r1.20 email.inc --- components/email.inc 7 May 2009 22:38:14 -0000 1.20 +++ components/email.inc 17 Jun 2009 22:33:14 -0000 @@ -21,7 +21,6 @@ 'extra' => array( 'width' => '', 'disabled' => 0, - 'email' => 0, 'description' => '', 'attributes' => array(), ), @@ -66,13 +65,6 @@ '#size' => 5, '#maxlength' => 10, ); - $edit_fields['extra']['email'] = array( - '#type' => 'checkbox', - '#title' => t('E-mail a submission copy'), - '#return_value' => 1, - '#default_value' => $currfield['extra']['email'], - '#description' => t('Check this option if this component contains an e-mail address that should get a copy of the submission. Emails are sent individually so other emails will not be shown to the recipient.'), - ); $edit_fields['extra']['disabled'] = array( '#type' => 'checkbox', '#title' => t('Disabled'), Index: templates/webform-mail.tpl.php =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/webform/templates/webform-mail.tpl.php,v retrieving revision 1.1 diff -u -r1.1 webform-mail.tpl.php --- templates/webform-mail.tpl.php 22 May 2009 03:11:18 -0000 1.1 +++ templates/webform-mail.tpl.php 17 Jun 2009 22:33:15 -0000 @@ -23,23 +23,19 @@ * logic on CIDs you can customize various e-mails. */ ?> - format_date(time(), 'small'))) ?> + uid): ?> - $user->name, '@ip_address' => $ip_address)) ?> + - $ip_address)) ?> + : - +%email_values -nid .'/submission/'. $sid, array('absolute' => TRUE)) ?> + +%submission_url Index: includes/webform.pages.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/webform/includes/webform.pages.inc,v retrieving revision 1.2 diff -u -r1.2 webform.pages.inc --- includes/webform.pages.inc 16 Jun 2009 14:42:13 -0000 1.2 +++ includes/webform.pages.inc 17 Jun 2009 22:33:15 -0000 @@ -92,97 +92,6 @@ ); /* End per-role submission control */ - /* Start E-mail Settings Form */ - $form['mail_settings'] = array( - '#type' => 'fieldset', - '#title' => t('Mail settings'), - '#collapsible' => TRUE, - '#collapsed' => FALSE, - '#weight' => -2, - '#theme' => 'webform_mail_settings_form', - ); - - $form['mail_settings']['email'] = array( - '#type' => 'textfield', - '#title' => t('E-mail to address'), - '#maxlength' => 255, - '#default_value' => $node->webform['email'], - '#description' => t('Form submissions will be e-mailed to this address. Leave blank for none. Multiple e-mail addresses may be separated by commas.'), - ); - - $form['mail_settings']['email_components'] = array( - '#type' => 'fieldset', - '#collapsible' => TRUE, - '#collapsed' => TRUE, - '#theme' => 'webform_mail_components_form', - '#title' => t('Conditional e-mail recipients'), - '#description' => t('The settings below allow you to send e-mails to multiple recipients based off the value of a component.'), - '#node' => $node, - ); - - $options = _webform_component_options($node->webform['components'], 'email'); - $default_value = array(); - if (is_array($node->webform['components'])) { - foreach ($node->webform['components'] as $cid => $component) { - if (isset($component['extra']['email']) && $component['extra']['email']) { - $default_value[] = $cid; - } - } - } - $form['mail_settings']['email_components']['email_components'] = array( - '#type' => 'checkboxes', - '#options' => $options, - '#default_value' => $default_value, - '#parents' => array('email_components'), - ); - - foreach (array('from_name', 'from_address', 'subject') as $field) { - switch ($field) { - case 'from_name': - $default_value = _webform_filter_values(webform_variable_get('webform_default_from_name'), $node); - $title = t('E-mail from name'); - $description = t('After adding components to this form any email, select, or hidden form element may be selected as the sender\'s name for e-mails.'); - break; - case 'from_address': - $default_value = _webform_filter_values(webform_variable_get('webform_default_from_address'), $node); - $title = t('E-mail from address'); - $description = t('After adding components to this form any textfield, select, or hidden form element may be selected as the sender\'s e-mail address.'); - break; - case 'subject': - $default_value = _webform_filter_values(webform_variable_get('webform_default_subject'), $node); - $title = t('E-mail subject'); - $description = t('After adding components to this form any textfield, select, or hidden form element may be selected as the subject for e-mails.'); - break; - } - - $form['mail_settings']['email_'. $field .'_option'] = array( - '#title' => $title, - '#type' => 'radios', - '#default_value' => is_numeric($node->webform['email_'. $field]) ? 'component' : ((empty($default_value) || ($node->webform['email_'. $field] != 'default' && isset($node->webform['email_'. $field]))) ? 'custom' : 'default'), - '#description' => $description, - ); - if (!empty($default_value)) { - $form['mail_settings']['email_'. $field .'_option']['#options']['default'] = $default_value; - } - $form['mail_settings']['email_'. $field .'_option']['#options']['custom'] = 'custom'; - $form['mail_settings']['email_'. $field .'_option']['#options']['component'] = 'component'; - - $form['mail_settings']['email_'. $field .'_custom'] = array( - '#type' => 'textfield', - '#size' => 40, - '#default_value' => (!is_numeric($node->webform['email_'. $field]) && $node->webform['email_'. $field] != 'default') ? $node->webform['email_'. $field] : NULL, - ); - $options = _webform_component_options($node->webform['components'], $field == 'from_address' ? 'email' : 'string'); - $form['mail_settings']['email_'. $field .'_component'] = array( - '#type' => 'select', - '#default_value' => is_numeric($node->webform['email_'. $field]) ? $node->webform['email_'. $field] : NULL, - '#options' => empty($options) ? array('' => 'No available components') : $options, - '#disabled' => empty($options) ? TRUE : FALSE, - '#weight' => 6, - ); - } - /* End mail settings form */ - /* Start advanced settings form */ $form['advanced'] = array( '#type' => 'fieldset', @@ -278,25 +187,6 @@ // Save roles. $node->webform['roles'] = $form_state['values']['roles']; - // Save e-mail. - $node->webform['email'] = $form_state['values']['email']; - - // Add the conditional e-mail recipients to components. - foreach ($form_state['values']['email_components'] as $cid => $checked) { - $node->webform['components'][$cid]['extra']['email'] = $checked; - } - - // Merge the e-mail name, address, and subject options into single values. - foreach (array('from_name', 'from_address', 'subject') as $field) { - $option = $form_state['values']['email_'. $field .'_option']; - if ($option == 'default') { - $node->webform['email_'. $field] = 'default'; - } - else { - $node->webform['email_'. $field] = $form_state['values']['email_'. $field .'_'. $option]; - } - } - // Set the Show complete form in teaser setting. $node->webform['teaser'] = $form_state['values']['teaser']; @@ -321,61 +211,6 @@ } /** - * Theme the component options for sending e-mails. - */ -function theme_webform_mail_components_form($form) { - drupal_add_css(drupal_get_path('module', 'webform') .'/webform.css'); - $node = $form['#node']; - $header = array( - array('data' => t('To'), 'class' => 'webform-checkbox'), - t('Name'), - t('Type'), - ); - $rows = array(); - foreach (element_children($form['email_components']) as $cid) { - $title = $form['email_components'][$cid]['#title']; - unset($form['email_components'][$cid]['#title']); - $rows[] = array( - array('data' => drupal_render($form['email_components'][$cid]), 'class' => 'webform-checkbox'), - $title, - $node->webform['components'][$cid]['type'], - ); - } - if (empty($rows)) { - $rows[] = array(array('colspan' => 5, 'data' => t('No components yet in this webform.'))); - } - - $form['#children'] = theme('table', $header, $rows); - return drupal_render($form); -} - -/** - * Theme the Webform mail settings section of the node form. - */ -function theme_webform_mail_settings_form($form) { - drupal_add_js(drupal_get_path('module', 'webform') .'/webform.js'); - - // Loop through fields, rendering them into radio button options. - foreach (array('from_name', 'from_address', 'subject') as $field) { - foreach (array('custom' => t('Custom'), 'component' => t('Component')) as $option => $title) { - $form['email_'. $field .'_'. $option]['#attributes']['class'] = 'webform-set-active'; - $form['email_'. $field .'_option'][$option]['#title'] = $title .': '. drupal_render($form['email_'. $field .'_'. $option]); - } - // For spacing consitency, every option is wrapped in container-inline. - foreach (element_children($form['email_'. $field .'_option']) as $option) { - $form['email_'. $field .'_option'][$option]['#prefix'] = '
'; - $form['email_'. $field .'_option'][$option]['#suffix'] = '
'; - } - // Wrap the default option in a placeholder tag.. - if (isset($form['email_'. $field .'_option']['#options']['default'])) { - $form['email_'. $field .'_option']['default']['#title'] = t('Default') .': '. theme('placeholder', $form['email_'. $field .'_option']['default']['#title']); - } - } - - return drupal_render($form); -} - -/** * Theme the submit limit fieldset on the webform node form. */ function theme_webform_advanced_submit_limit_form($form) { Index: includes/webform.emails.inc =================================================================== RCS file: includes/webform.emails.inc diff -N includes/webform.emails.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ includes/webform.emails.inc 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,465 @@ + + */ + +/** + * Overview form of all components for this webform. + */ +function webform_emails_form($form_state, $node) { + $form = array( + '#tree' => TRUE, + '#node' => $node, + 'components' => array(), + ); + + $form['nid'] = array( + '#type' => 'value', + '#value' => $node->nid, + ); + + foreach ($node->webform['emails'] as $eid => $email) { + $email_addresses = array_filter(explode(',', check_plain($email['email']))); + foreach ($email_addresses as $key => $email_address) { + $email_addresses[$key] = webform_format_email_address($email_address, NULL, $node, NULL, FALSE); + } + + $form['emails'][$eid]['email'] = array( + '#value' => implode('
', $email_addresses), + ); + $form['emails'][$eid]['subject'] = array( + '#value' => check_plain(webform_format_email_subject($email['subject'], $node)), + ); + $form['emails'][$eid]['from'] = array( + '#value' => check_plain(webform_format_email_address($email['from_address'], $email['from_name'], $node, NULL, FALSE)), + ); + } + + $form['add'] = array( + '#theme' => 'webform_email_add_form', + '#tree' => FALSE, + ); + + $form['add']['email_option'] = array( + '#type' => 'radios', + '#options' => array( + 'custom' => t('Address'), + 'component' => t('Component value'), + ), + '#default_value' => 'custom', + ); + + $form['add']['email_custom'] = array( + '#type' => 'textfield', + '#size' => 24, + ); + + $form['add']['email_component'] = array( + '#type' => 'select', + '#options' => _webform_component_options($node->webform['components'], 'email'), + ); + + $form['add_button'] = array( + '#type' => 'submit', + '#value' => t('Add'), + '#weight' => 45, + ); + + $form['#validate'] = array('webform_email_address_validate'); + + return $form; +} + +/** + * Theme the node components form. Use a table to organize the components. + * + * @param $form + * The form array. + * @return + * Formatted HTML form, ready for display. + */ +function theme_webform_emails_form($form) { + // Add CSS to display submission info. Don't preprocess because this CSS file is used rarely. + drupal_add_css(drupal_get_path('module', 'webform') .'/webform.css', 'module', 'all', FALSE); + drupal_add_js(drupal_get_path('module', 'webform') .'/webform.js', 'module', 'header', FALSE, TRUE, FALSE); + + $node = $form['#node']; + + $headers = array(t('E-mail to'), t('Subject'), t('From'), array('data' => t('Operations'), 'colspan' => 2)); + $rows = array(); + + if (!empty($form['emails'])) { + foreach (element_children($form['emails']) as $eid) { + // Add each component to a table row. + $rows[] = array( + drupal_render($form['emails'][$eid]['email']), + drupal_render($form['emails'][$eid]['subject']), + drupal_render($form['emails'][$eid]['from']), + l(t('Edit'), 'node/'. $node->nid .'/webform/emails/'. $eid), + l(t('Delete'), 'node/'. $node->nid .'/webform/emails/'. $eid .'/delete'), + ); + } + } + else { + $rows[] = array(array('data' => t('Currently not sending e-mails, add an e-mail recipient below.'), 'colspan' => 5)); + } + + // Add a row containing form elements for a new item. + $row_data = array( + array('colspan' => 3, 'data' => drupal_render($form['add'])), + array('colspan' => 2, 'data' => drupal_render($form['add_button'])), + ); + $rows[] = array('data' => $row_data, 'class' => 'webform-add-form'); + + $output = ''; + $output .= theme('table', $headers, $rows, array('id' => 'webform-emails')); + $output .= drupal_render($form); + return $output; +} + +/** + * Theme the add new e-mail settings form on the node/x/webform/emails page. + */ +function theme_webform_email_add_form($form) { + // Add a default value to the custom e-mail textfield. + $form['email_custom']['#value'] = t('email@example.com'); + $form['email_custom']['#attributes']['class'] = 'webform-set-active webform-default-value'; + $form['email_option']['custom']['#title'] = $form['email_option']['custom']['#title'] .': '. drupal_render($form['email_custom']); + + // Render the component value. + $form['email_component']['#attributes']['class'] = 'webform-set-active'; + $form['email_option']['component']['#title'] = $form['email_option']['component']['#title'] .': '. drupal_render($form['email_component']); + + // For spacing consistency, every option is wrapped in container-inline. + foreach (element_children($form['email_option']) as $option) { + $form['email_option'][$option]['#prefix'] = '
'; + $form['email_option'][$option]['#suffix'] = '
'; + } + + return drupal_render($form); +} + +/** + * Submit handler for webform_emails_form(). + */ +function webform_emails_form_submit($form, &$form_state) { + if ($form_state['values']['email_option'] == 'custom') { + $email = $form_state['values']['email_custom']; + } + else { + $email = $form_state['values']['email_component']; + } + $form_state['redirect'] = array('node/'. $form['#node']->nid .'/webform/emails/new', 'option='. urlencode($form_state['values']['email_option']) .'&email='. urlencode(trim($email))); +} + +/** + * Form for configuring an e-mail setting and template. + */ +function webform_email_edit_form($form_state, &$node, $email = array()) { + $form = array( + '#tree' => TRUE, + ); + $form['nid'] = array( + '#type' => 'value', + '#value' => $node->nid, + ); + $form['eid'] = array( + '#type' => 'value', + '#value' => isset($email['eid']) ? $email['eid'] : NULL, + ); + + // All these fields work essentially the same, with a radio button set, + // a textfield for custom values, and a select list for a component. + foreach (array('email', 'subject', 'from_address', 'from_name') as $field) { + switch ($field) { + case 'email': + $default_value = NULL; + $title = t('E-mail to address'); + $description = t('Form submissions will be e-mailed to this address. Any email, select, or hidden form element may be selected as the recipient address. Multiple e-mail addresses may be separated by commas.'); + break; + case 'subject': + $default_value = _webform_filter_values(webform_variable_get('webform_default_subject'), $node); + $title = t('E-mail subject'); + $description = t('Aany textfield, select, or hidden form element may be selected as the subject for e-mails.'); + break; + case 'from_address': + $default_value = _webform_filter_values(webform_variable_get('webform_default_from_address'), $node); + $title = t('E-mail from address'); + $description = t('Any email, select, or hidden form element may be selected as the sender\'s e-mail address.'); + break; + case 'from_name': + $default_value = _webform_filter_values(webform_variable_get('webform_default_from_name'), $node); + $title = t('E-mail from name'); + $description = t('Any textfield, select, or hidden form element may be selected as the sender\'s name for e-mails.'); + break; + } + + $form[$field . '_option'] = array( + '#title' => $title, + '#type' => 'radios', + '#default_value' => is_numeric($email[$field]) ? 'component' : ((empty($default_value) || ($email[$field] != 'default' && isset($email[$field]))) ? 'custom' : 'default'), + '#description' => $description, + ); + if (!empty($default_value)) { + $form[$field . '_option']['#options']['default'] = $default_value; + } + $form[$field . '_option']['#options']['custom'] = 'custom'; + $form[$field . '_option']['#options']['component'] = 'component'; + + $form[$field . '_custom'] = array( + '#type' => 'textfield', + '#size' => 40, + '#default_value' => (!is_numeric($email[$field]) && $email[$field] != 'default') ? $email[$field] : NULL, + ); + $options = _webform_component_options($node->webform['components'], $field == 'from_address' || $field == 'email' ? 'email' : 'string'); + $form[$field . '_component'] = array( + '#type' => 'select', + '#default_value' => is_numeric($email[$field]) ? $email[$field] : NULL, + '#options' => empty($options) ? array('' => 'No available components') : $options, + '#disabled' => empty($options) ? TRUE : FALSE, + '#weight' => 6, + ); + } + + // Do not show the "E-mail from name" if using the short e-mail format. + if (variable_get('webform_email_address_format', 'long') == 'short') { + $form['from_name_option']['#access'] = FALSE; + $form['from_name_custom']['#access'] = FALSE; + $form['from_name_component']['#access'] = FALSE; + } + + // Add the template fieldset. + $form['template'] = array( + '#type' => 'fieldset', + '#title' => t('E-mail template'), + '#collapsible' => TRUE, + '#collapsed' => !empty($email['cid']) && empty($email['template']), + '#description' => t('An e-mail template can customize the display of e-mails.'), + '#weight' => 15, + '#tree' => FALSE, + '#attributes' => array('id' => 'webform-template-fieldset'), + ); + + $default_template = theme(array('webform_mail_'. $node->nid, 'webform_mail', 'webform_mail_message'), array(), $node, 0, 'default'); + $template = $email['template'] == 'default' ? $default_template : $email['template']; + $form['template']['template'] = array( + '#type' => 'textarea', + '#rows' => max(10, min(20, count(explode("\n", $template)))), + '#description' => theme('webform_token_help', $node), + '#default_value' => $template, + ); + + $form['template']['template_option'] = array( + '#type' => 'select', + '#options' => array( + 'default' => t('Default template'), + 'custom' => t('Custom template'), + ), + '#description' => t('Warning: Changing will immediately update the textarea above.'), + ); + + // TODO: Allow easy re-use of existing templates. + $form['templates']['#tree'] = TRUE; + $form['templates']['default'] = array( + '#type' => 'textarea', + '#value' => $default_template, + '#attributes' => array('style' => 'display: none'), + '#resizable' => FALSE, + ); + + // Add the submit button. + $form['submit'] = array( + '#type' => 'submit', + '#value' => t('Save e-mail settings'), + '#weight' => 20, + ); + + $form['#validate'] = array('webform_email_address_validate', 'webform_email_edit_form_validate'); + + return $form; +} + +/** + * Theme the Webform mail settings section of the node form. + */ +function theme_webform_email_edit_form($form) { + drupal_add_js(drupal_get_path('module', 'webform') . '/webform.js'); + + // Loop through fields, rendering them into radio button options. + foreach (array('email', 'subject', 'from_address', 'from_name') as $field) { + foreach (array('custom' => t('Custom'), 'component' => t('Component')) as $option => $title) { + $form[$field . '_' . $option]['#attributes']['class'] = 'webform-set-active'; + $form[$field .'_option'][$option]['#title'] = $title .': '. drupal_render($form[$field . '_' . $option]); + } + // For spacing consistency, every option is wrapped in container-inline. + foreach (element_children($form[$field . '_option']) as $option) { + $form[$field . '_option'][$option]['#prefix'] = '
'; + $form[$field . '_option'][$option]['#suffix'] = '
'; + } + // Wrap the default option in a placeholder tag.. + if (isset($form[$field .'_option']['#options']['default'])) { + $form[$field . '_option']['default']['#title'] = t('Default') .': '. theme('placeholder', $form[$field . '_option']['default']['#title']); + } + } + + $details = ''; + $details .= drupal_render($form['subject_option']); + $details .= drupal_render($form['from_address_option']); + $details .= drupal_render($form['from_name_option']); + $form['details'] = array( + '#type' => 'fieldset', + '#title' => t('E-mail header details'), + '#weight' => 10, + '#children' => $details, + '#collapsible' => FALSE, + ); + + return drupal_render($form); +} + +/** + * Validate handler for webform_email_edit_form() and webform_emails_form(). + */ +function webform_email_address_validate($form, &$form_state) { + if ($form_state['values']['email_option'] == 'custom') { + $email = trim($form_state['values']['email_custom']); + if (empty($email)) { + form_set_error('email_custom', t('When adding a new custom e-mail, the e-mail field is required.')); + } + else { + $emails = array_filter(explode(',', $email)); + foreach ($emails as $email) { + if (!valid_email_address(trim($email))) { + form_set_error('email_custom', t('The entered e-mail address "@email" does not appear valid.', array('@email' => $email))); + } + } + } + } +} + +/** + * Validate handler for webform_email_edit_form(). + */ +function webform_email_edit_form_validate($form, &$form_state) { + if ($form_state['values']['from_address_option'] == 'custom' && !valid_email_address($form_state['values']['from_address_custom'])) { + form_set_error('from_address_custom', t('The entered e-mail address "@email" does not appear valid.', array('@email' => $form_state['values']['from_address_custom']))); + } +} + +/** + * Submit handler for webform_email_edit_form(). + */ +function webform_email_edit_form_submit($form, &$form_state) { + // Merge the e-mail, name, address, and subject options into single values. + $email = array( + 'eid' => $form_state['values']['eid'], + 'nid' => $form_state['values']['nid'], + ); + + foreach (array('email', 'from_name', 'from_address', 'subject') as $field) { + $option = $form_state['values'][$field .'_option']; + if ($option == 'default') { + $email[$field] = 'default'; + } + else { + $email[$field] = $form_state['values'][$field .'_'. $option]; + } + } + + // Ensure templates are unaffected by differences in line breaks. + $form_state['values']['template'] = str_replace(array("\r", "\n"), array('', "\n"), $form_state['values']['template']); + $form_state['values']['templates']['default'] = str_replace(array("\r", "\n"), array('', "\n"), $form_state['values']['templates']['default']); + + // Set the template value. + // TODO: Support reuse of templates. + if (strcmp(trim($form_state['values']['templates']['default']), trim($form_state['values']['template'])) == 0) { + $email['template'] = 'default'; + } + else { + $email['template'] = $form_state['values']['template']; + } + + if (empty($form_state['values']['eid'])) { + drupal_set_message(t('Email settings added.')); + $cid = webform_email_insert($email); + } + else { + drupal_set_message(t('Email settings updated.')); + webform_email_update($email); + } + + $form_state['redirect'] = array('node/'. $form_state['values']['nid'] .'/webform/emails'); +} + +/** + * Form for deleting an e-mail setting. + */ +function webform_email_delete_form($form_state, $node, $email) { + $eid = $email['eid']; + + $form = array(); + $form['node'] = array( + '#type' => 'value', + '#value' => $node, + ); + $form['email'] = array( + '#type' => 'value', + '#value' => $email, + ); + + $question = t('Delete e-mail settings?'); + if (is_numeric($email['email'])) { + $description = t('This will immediately delete the e-mail settings based on the @component component.', array('@component' => $email['email'])); + } + else { + $description = t('This will immediately delete the e-mail settings sending to the @address address.', array('@address' => $email['email'])); + } + + return confirm_form($form, $question, 'node/'. $node->nid .'/webform/emails', $description, t('Delete')); +} + +/** + * Submit handler for webform_component_delete_form(). + */ +function webform_email_delete_form_submit($form, &$form_state) { + drupal_set_message(t('E-mail settings deleted.')); + webform_component_delete($form_state['values']['node'], $form_state['values']['email']); + $form_state['redirect'] = 'node/'. $form_state['values']['node']->nid .'/webform/emails'; +} + +/** + * Insert a new e-mail setting into the database. + * + * @param $email + * An array of settings for sending an e-mail. + */ +function webform_email_insert($email) { + db_lock_table('webform_emails'); + $email['eid'] = isset($email['eid']) ? $email['eid'] : db_result(db_query('SELECT MAX(eid) FROM {webform_emails} WHERE nid = %d', $email['nid'])) + 1; + db_query("INSERT INTO {webform_emails} (nid, eid, email, subject, from_name, from_address, template) VALUES (%d, %d, '%s', '%s', '%s', '%s', '%s')", $email['nid'], $email['eid'], $email['email'], $email['subject'], $email['from_name'], $email['from_address'], $email['template']); + db_unlock_tables(); + return $email['eid']; +} + +/** + * Update an existing e-mail setting with new values. + * + * @param $email + * An array of settings for sending an e-mail containing a nid, eid, and all + * other fields from the e-mail form. + */ +function webform_email_update($email) { + return db_query("UPDATE {webform_emails} SET email = '%s', subject = '%s', from_name = '%s', from_address = '%s', template = '%s' WHERE nid = %d AND eid = %d", $email['email'], $email['subject'], $email['from_name'], $email['from_address'], $email['template'], $email['nid'], $email['eid']); +} + +/** + * Delete an e-mail setting. + */ +function webform_email_delete($node, $email) { + db_query('DELETE FROM {webform_emails} WHERE nid = %d AND eid = %d', $node->nid, $email['edit']); +}