views_send.module in Views Send 6
Same filename and directory in other branches
The Views Send module.
Views Send allow sending mass mailing using Views Bulk Operations module.
File
views_send.moduleView source
<?php
/**
* @file
* The Views Send module.
*
* Views Send allow sending mass mailing using Views Bulk Operations module.
*
* @ingroup views_send
*/
/**
* E-mail priorities.
*/
define('VIEWS_SEND_PRIORITY_NONE', 0);
define('VIEWS_SEND_PRIORITY_HIGHEST', 1);
define('VIEWS_SEND_PRIORITY_HIGH', 2);
define('VIEWS_SEND_PRIORITY_NORMAL', 3);
define('VIEWS_SEND_PRIORITY_LOW', 4);
define('VIEWS_SEND_PRIORITY_LOWEST', 5);
/**
* Plain message format value.
*/
define('VIEWS_SEND_FORMAT_PLAIN', 'plain');
/**
* Capture PHP max_execution_time before drupal_cron_run().
* Workaround for Drupal 6.14. See http://drupal.org/node/584334
*/
define('VIEWS_SEND_MAX_EXECUTION_TIME', ini_get('max_execution_time'));
/**
* Token pattern.
*/
define('VIEWS_SEND_TOKEN_PATTERN', 'views-send-%s');
define('VIEWS_SEND_TOKEN_PREFIX', '[');
define('VIEWS_SEND_TOKEN_POSTFIX', ']');
/**
* Detect and store Mime Mail module presence.
*/
define('VIEWS_SEND_MIMEMAIL', module_exists('mimemail'));
// === Action implementation ===================================================
/**
* Implementation of hook_action_info()
*
* @see http://drupal.org/node/172152
*/
function views_send_action_info() {
return array(
'views_send_mail_action' => array(
'type' => 'system',
'description' => t('Send mass mail'),
'configurable' => TRUE,
'permissions' => array(
'mass mailing with views_send',
),
),
);
}
/**
* Configuration form for views_send_mail action.
*
* @see http://drupal.org/node/172152
*/
function views_send_mail_action_form($context) {
$display = $context['view']->name . ':' . $context['view']->current_display;
$form = array();
$form['display'] = array(
'#type' => 'value',
'#value' => $display,
);
$form['from'] = array(
'#type' => 'fieldset',
'#title' => t('Sender'),
'#collapsible' => TRUE,
'#collapsed' => FALSE,
);
$form['from']['views_send_from_name'] = array(
'#type' => 'textfield',
'#title' => t('Sender\'s name'),
'#description' => t("Enter the sender's human readable name."),
'#default_value' => variable_get('views_send_from_name_' . $display, variable_get('site_name', '')),
'#maxlen' => 255,
);
$form['from']['views_send_from_mail'] = array(
'#type' => 'textfield',
'#title' => t('Sender\'s e-mail'),
'#description' => t("Enter the sender's e-mail address."),
'#required' => TRUE,
'#default_value' => variable_get('views_send_from_mail_' . $display, variable_get('site_mail', ini_get('sendmail_from'))),
'#maxlen' => 255,
);
// The view needs to be executed, as we rely on the result set to
// retrieve the available fields
if (!$context['view']->executed) {
$context['view']
->execute();
}
$fields = _views_send_get_fields_and_tokens($context['view'], 'fields');
$tokens = _views_send_get_fields_and_tokens($context['view'], 'tokens');
$fields_name_text = _views_send_get_fields_and_tokens($context['view'], 'fields_name_text');
$fields_options = array_merge(array(
'' => '<' . t('select') . '>',
), $fields);
$form['views_send_tokens'] = array(
'#type' => 'value',
'#value' => $tokens,
);
$form['to'] = array(
'#type' => 'fieldset',
'#title' => t('Recipients'),
'#collapsible' => TRUE,
'#collapsed' => FALSE,
);
$form['to']['views_send_to_name'] = array(
'#type' => 'select',
'#title' => t('Field used for recipient\'s name'),
'#description' => t('Select which field from the current view will be used as recipient\'s name.'),
'#options' => $fields_options,
'#default_value' => variable_get('views_send_to_name_' . $display, ''),
);
$form['to']['views_send_to_mail'] = array(
'#type' => 'select',
'#title' => t('Field used for recipient\'s e-mail'),
'#description' => t('Select which field from the current view will be used as recipient\'s e-mail.'),
'#options' => $fields_options,
'#default_value' => variable_get('views_send_to_mail_' . $display, ''),
'#required' => TRUE,
);
$form['mail'] = array(
'#type' => 'fieldset',
'#title' => t('E-mail content'),
'#collapsible' => TRUE,
'#collapsed' => FALSE,
);
$form['mail']['views_send_subject'] = array(
'#type' => 'textfield',
'#title' => t('Subject'),
'#description' => t('Enter the e-mail\'s subject line.'),
'#maxlen' => 255,
'#required' => TRUE,
'#default_value' => variable_get('views_send_subject_' . $display, ''),
);
$form['mail']['views_send_message'] = array(
'#type' => 'textarea',
'#title' => t('Message'),
'#description' => t('Enter the body of the message. You can use the token replacements listed below.'),
'#required' => TRUE,
'#rows' => 10,
'#default_value' => variable_get('views_send_message_' . $display, ''),
);
$form['mail']['format'] = _views_send_filter_form(variable_get('views_send_message_format_' . $display, VIEWS_SEND_FORMAT_PLAIN));
$form['mail']['token'] = array(
'#type' => 'fieldset',
'#title' => t('Replacements'),
'#description' => t('You can use these token replacements in Subject or Message Body.'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
);
$form['mail']['token']['tokens'] = array(
'#type' => 'markup',
'#value' => theme('views_send_token_help', $fields_name_text),
);
if (VIEWS_SEND_MIMEMAIL && user_access('allow attachments with views_send')) {
// set the form encoding type
$form['#attributes']['enctype'] = "multipart/form-data";
// add a file upload file
$form['mail']['views_send_attachments'] = array(
'#type' => 'file',
'#title' => t('Attachment'),
'#description' => t('NB! The attached file is stored once per recipient in the database (before sending it).'),
);
}
$form['additional'] = array(
'#type' => 'fieldset',
'#title' => t('Additional e-mail options'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
);
$form['additional']['views_send_priority'] = array(
'#type' => 'select',
'#title' => t('Priority'),
'#options' => array(
VIEWS_SEND_PRIORITY_NONE => t('none'),
VIEWS_SEND_PRIORITY_HIGHEST => t('highest'),
VIEWS_SEND_PRIORITY_HIGH => t('high'),
VIEWS_SEND_PRIORITY_NORMAL => t('normal'),
VIEWS_SEND_PRIORITY_LOW => t('low'),
VIEWS_SEND_PRIORITY_LOWEST => t('lowest'),
),
'#description' => t('Note that email priority is ignored by a lot of email programs.'),
'#default_value' => variable_get('views_send_priority_' . $display, 0),
);
$form['additional']['views_send_receipt'] = array(
'#type' => 'checkbox',
'#title' => t('Request receipt'),
'#default_value' => variable_get('views_send_receipt_' . $display, 0),
'#description' => t('Request a Read Receipt from your e-mails. A lot of email programs ignore these so it is not a definitive indication of how many people have read your message.'),
);
$form['additional']['views_send_headers'] = array(
'#type' => 'textarea',
'#title' => t('Additional headers'),
'#description' => t("Additional headers to be send with the message. You'll have to enter one per line. Example:<pre>Reply-To: noreply@example.com\nX-MyCustomHeader: Whatever</pre>"),
'#rows' => 4,
'#default_value' => variable_get('views_send_headers_' . $display, ''),
);
$form['views_send_remember'] = array(
'#type' => 'checkbox',
'#title' => t('Remember these values for the next time a mass mail is sent. (The values are not stored per user.)'),
'#default_value' => variable_get('views_send_remember_' . $display, FALSE),
);
return $form;
}
/**
* Validation callback for views_send_mail action configuration form.
*
* @see http://drupal.org/node/172152
*/
function views_send_mail_action_validate($form, $form_state) {
$values =& $form_state['values'];
// Check if sender's e-mail is a valid one.
if (!valid_email_address(trim($values['views_send_from_mail']))) {
form_set_error('from_mail', t('The sender\'s e-mail is not a valid e-mail address: %mail', array(
'%mail' => trim($values['views_send_from_mail']),
)));
}
// Check in the column selected as e-mail contain valid e-mail values.
if (!empty($values['views_send_to_mail'])) {
$wrong_addresses = array();
/**
* "views_send_mail_action" was the only action configured and "Merge single
* action's form with node selection view" checkbox is checked. We are on
* first submit and the $form_state['storage'] is not populated yet.
*/
if ($values['step'] == VBO_STEP_SINGLE) {
// Get selection.
$plugin = $form['#plugin'];
$form_id = $values['form_id'];
$form_state['storage']['selection'] = _views_bulk_operations_get_selection($plugin, $form_state, $form_id);
$records =& $form_state['storage']['selection'];
}
else {
$records =& $form_state['storage']['selection'];
}
// When using the action in Rules nothing has been selected.
if (empty($records)) {
return;
}
$to_mail_field = $values["views_send_to_mail"];
foreach ($records as $record) {
$email = _views_send_get_from_views_result($record, $to_mail_field, 'email');
if (!valid_email_address(trim($email))) {
$wrong_addresses[] = trim($email);
}
}
if (count($wrong_addresses) > 0) {
if (count($wrong_addresses) == count($records)) {
$error_message = t("The field used for recipient's e-mail contains an invalid e-mail address in all selected rows. Maybe choose another field to act as recipient's e-mail?");
}
else {
$error_message = t("The field used for recipient's e-mail contains an invalid e-mail address in @wrong of @total selected rows. Choose another field to act as recipient's e-mail or return to the view and narrow the selection to a subset containing only valid addresses. Bad addresses:", array(
'@wrong' => count($wrong_addresses),
'@total' => count($records),
));
$error_message .= '<ul>';
foreach ($wrong_addresses as $rowid => $wrong_address) {
$error_message .= sprintf('<li>%s</li>', check_plain($wrong_address));
}
$error_message .= '</ul>';
}
form_set_error('views_send_to_mail', $error_message);
}
}
}
/**
* Action configuration submission callback.
*
* @see http://drupal.org/node/172152
*/
function views_send_mail_action_submit($form, &$form_state) {
$display = $form['display']['#value'];
$values =& $form_state['values'];
$return = array();
foreach ($values as $key => $value) {
$key = $key == 'format' ? 'views_send_message_format' : $key;
if (substr($key, 0, 11) == 'views_send_') {
if ($values['views_send_remember']) {
variable_set($key . '_' . $display, $value);
}
else {
variable_del($key . '_' . $display);
}
$return += array(
$key => $value,
);
}
}
// If a file was uploaded, process it.
if (VIEWS_SEND_MIMEMAIL && user_access('allow attachments with views_send') && isset($_FILES['files']) && is_uploaded_file($_FILES['files']['tmp_name']['views_send_attachments'])) {
// attempt to save the uploaded file
$dir = file_directory_path() . '/views_send_attachments';
$dest = file_check_directory($dir, FILE_CREATE_DIRECTORY);
$file = file_save_upload('views_send_attachments', array(), $dir);
// set error if file was not uploaded
if (!$file) {
//form_set_error('views_send_attachment', 'Error uploading file.');
}
else {
// set files to form_state, to process when form is submitted
// @todo: when we add a multifile formfield then loop through to add each file to attachments array
$file->filepath = base_path() . $file->filepath;
$file->list = true;
$return['views_send_attachments'][] = (array) $file;
}
}
return $return;
}
/**
* Main action callback.
*
* @see http://drupal.org/node/172152
*/
function views_send_mail_action($object, $context) {
global $user;
// From: parts.
$from_mail = trim($context['views_send_from_mail']);
$from_name = $context['views_send_from_name'];
// To: parts.
$to_mail = trim(_views_send_get_from_views_result($context['row'], $context['views_send_to_mail'], 'email'));
$to_name = _views_send_get_from_views_result($context['row'], $context['views_send_to_name']);
// Formatting using selected input format.
$subject = $context['views_send_subject'];
$body = $context['views_send_message_format'] == VIEWS_SEND_FORMAT_PLAIN ? $context['views_send_message'] : check_markup($context['views_send_message'], $context['views_send_message_format']);
// Populate row/context tokens.
$token_keys = $token_values = array();
foreach ($context['views_send_tokens'] as $field_key => $field_name) {
$token_keys[] = VIEWS_SEND_TOKEN_PREFIX . sprintf(VIEWS_SEND_TOKEN_PATTERN, $field_name) . VIEWS_SEND_TOKEN_POSTFIX;
$token_values[] = _views_send_get_from_views_result($context['row'], $field_key);
}
$subject = str_replace($token_keys, $token_values, $subject);
$body = str_replace($token_keys, $token_values, $body);
// Let Token module operate substitutions.
if (module_exists('token')) {
_views_send_normalize_context($context);
$subject = token_replace_multiple($subject, $context);
$body = token_replace_multiple($body, $context);
}
// Process PHP code when only plain format is available.
if (!VIEWS_SEND_MIMEMAIL && _views_send_allow_php() && $context['views_send_message_format'] == VIEWS_SEND_FORMAT_PLAIN) {
$body = drupal_eval($body);
}
// We transform receipt, priority in headers,
// merging them to the user defined headers.
$headers = _views_send_headers($context['views_send_receipt'], $context['views_send_priority'], $from_mail, $context['views_send_headers']);
$attachments = $context['views_send_attachments'] ? $context['views_send_attachments'] : array();
$format = $context['views_send_message_format'];
// All tokens replacements, PHP processing and formatting were done.
// We are performing now all usual mail processing, altering and preparing.
_views_send_prepare_mail($from_name, $from_mail, $to_name, $to_mail, $subject, $body, $headers, $format, $attachments);
// Queue the message to the spool table.
db_query("INSERT INTO {views_send_spool} (uid, timestamp, from_name, from_mail, to_name, to_mail, subject, body, headers) VALUES (%d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s')", $user->uid, time(), $from_name, $from_mail, $to_name, $to_mail, $subject, $body, serialize($headers));
}
// === Hook implementations ====================================================
/**
* Implementation of hook_menu().
*
* @see http://api.drupal.org/api/function/hook_menu/6
*/
function views_send_menu() {
$items = array();
$items['admin/settings/views_send'] = array(
'type' => MENU_NORMAL_ITEM,
'title' => 'Views Send',
'description' => 'Configure Views Send general options.',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'views_send_settings',
),
'access arguments' => array(
'administer views_send',
),
'file' => 'views_send.admin.inc',
);
return $items;
}
/**
* Implementation of hook_perm().
*
* @see http://api.drupal.org/api/function/hook_perm/6
*/
function views_send_perm() {
$perms = array(
'administer views_send',
'mass mailing with views_send',
);
if (VIEWS_SEND_MIMEMAIL) {
$perms[] = 'allow attachments with views_send';
}
return $perms;
}
/**
* Implementation of hook_theme().
*
* @see http://api.drupal.org/api/function/hook_theme/6
*/
function views_send_theme($existing, $type, $theme, $path) {
return array(
'views_send_token_help' => array(
'arguments' => array(
'tokens' => array(),
),
),
);
}
/**
* Implementation of hook_form_alter().
*
* We want to alter the confirmation form, just before processing the action, so the the user can preview the whole message berore sending it.
*
* @see http://api.drupal.org/api/function/hook_form_alter/6
*/
function views_send_form_alter(&$form, &$form_state, $form_id) {
if (strpos($form_id, 'views_bulk_operations_form') === 0 && $form_state['values']['step'] >= VBO_STEP_CONFIG && $form_state['storage']['operation']['key'] == 'views_send_mail_action') {
drupal_set_title(t('Review and confirm the message that is about to be sent'));
drupal_add_css(drupal_get_path('module', 'views_send') . '/views_send.css');
$args =& $form_state['storage']['operation_arguments'];
// Drop the confirmation form warning message.
unset($form['description']);
$form['#attributes']['class'] .= ' views-send-preview';
$form['from'] = array(
'#type' => 'item',
'#title' => t('From'),
'#value' => '<div class="views-send-preview-value">' . (empty($args['views_send_from_name']) ? $args['views_send_from_mail'] : $args['views_send_from_name'] . check_plain(' <' . $args['views_send_from_mail'] . '>')) . '</div>',
);
$recipients = array();
foreach ($form_state['storage']['selection'] as $oid => $row) {
$email = trim(_views_send_get_from_views_result($row, $args["views_send_to_mail"], 'email'));
$name = _views_send_get_from_views_result($row, $args["views_send_to_name"]);
$recipients[] = check_plain(empty($name) ? $email : $name . ' <' . $email . '>');
}
$preview_to = '';
if ($form_state['storage']['selectall'] && empty($recipients)) {
$preview_to = t('- All -');
}
else {
$preview_to = implode(', ', $recipients);
}
$form['to'] = array(
'#type' => 'item',
'#title' => t('To'),
'#value' => '<div id="views-send-preview-to" class="views-send-preview-value">' . $preview_to . '</div>',
);
$form['subject'] = array(
'#type' => 'item',
'#title' => t('Subject'),
'#value' => '<div class="views-send-preview-value">' . $args['views_send_subject'] . '</div>',
);
if ($args['views_send_message_format'] == VIEWS_SEND_FORMAT_PLAIN) {
$message = '<div style="white-space: pre;">' . $args['views_send_message'] . '</div>';
}
else {
$message = check_markup($args['views_send_message'], $args['views_send_message_format']);
}
$form['message'] = array(
'#type' => 'item',
'#title' => t('Message'),
'#value' => '<div id="views-send-preview-message" class="views-send-preview-value">' . $message . '</div>',
);
$headers = array();
foreach (_views_send_headers($args['views_send_receipt'], $args['views_send_priority'], $args['views_send_from_mail'], $args['views_send_headers']) as $key => $value) {
$headers[] = $key . ': ' . $value;
}
$form['headers'] = array(
'#type' => 'item',
'#title' => t('Headers'),
'#value' => '<div id="views-send-preview-headers" class="views-send-preview-value">' . implode('<br />', $headers) . '</div>',
);
if (VIEWS_SEND_MIMEMAIL && !empty($args['views_send_attachments']) && user_access('allow attachments with views_send')) {
foreach ($args['views_send_attachments'] as $attachment) {
$attachments[] = $attachment['filename'];
}
$form['attachments'] = array(
'#type' => 'item',
'#title' => t('Attachments'),
'#value' => '<div id="views-send-preview-attachments" class="views-send-preview-value">' . implode('<br />', $attachments) . '</div>',
);
}
$form['actions']['#weight'] = 100;
}
}
/**
* Implementation of hook_cron().
*
* @see http://api.drupal.org/api/function/hook_cron/6
*/
function views_send_cron() {
// Load cron functions.
module_load_include('cron.inc', 'views_send');
// Send pending messages from spool.
views_send_send_from_spool();
// Clear successful sent messages.
views_send_clear_spool();
}
/**
* Implementation of hook_mail().
*
* @see http://api.drupal.org/api/function/hook_mail/6
*/
function views_send_mail($key, &$message, $params) {
// This is a simple message send. User inputs the content directly.
if ($key == 'direct') {
// Set the subject.
$message['subject'] = $params['subject'];
// Set the body.
$message['body'] = $params['body'];
// Add additional headers.
$message['headers'] += $params['headers'];
}
elseif ($key == 'node') {
// Translations, theming, etc...
}
}
// === Helper functions ========================================================
/**
* This is a fork of filter_form() in order to allow adding the "Plain" option.
*
* @see http://api.drupal.org/api/function/filter_form/6
*
* @param
* The ID of the format that is currently selected.
*
* @return
* Form API array for the form element.
*/
function _views_send_filter_form($default_value) {
$form = array();
$parents = array(
'format',
);
// Format wrapper.
$form = array(
'#type' => 'fieldset',
'#title' => t('Message format'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#element_validate' => array(
'filter_form_validate',
),
);
$guidelines = array();
$guidelines[] = VIEWS_SEND_MIMEMAIL ? t('Messages will be send in plain format.') : t('Only plain format is available. If you want to format the message as HTML, you\'ll have to install and enable <a href="http://drupal.org/project/mimemail">Mime Mail</a> module.');
if (!VIEWS_SEND_MIMEMAIL && _views_send_allow_php()) {
$guidelines[] = t('You may post PHP code. You should include <?php ?> tags.');
}
$guidelines = count($guidelines) == 1 ? '<p>' . $guidelines[0] . '</p>' : theme('item_list', $guidelines);
$form[VIEWS_SEND_FORMAT_PLAIN] = array(
'#type' => 'radio',
'#title' => t('Plain'),
'#default_value' => VIEWS_SEND_MIMEMAIL ? $default_value : VIEWS_SEND_FORMAT_PLAIN,
'#return_value' => VIEWS_SEND_FORMAT_PLAIN,
'#parents' => $parents,
'#description' => $guidelines,
'#id' => form_clean_id('edit-' . implode('-', array_merge($parents, array(
VIEWS_SEND_FORMAT_PLAIN,
)))),
);
// If Mime Mail module is not present we allow only plain format.
if (!VIEWS_SEND_MIMEMAIL) {
return $form;
}
$formats = filter_formats();
$extra = theme('filter_tips_more_info');
// Multiple formats available: display radio buttons with tips.
foreach ($formats as $fid => $format) {
// Generate the parents as the autogenerator does, so we will have a
// unique id for each radio button.
$parents_for_id = array_merge($parents, array(
$format->format,
));
$form[$format->format] = array(
'#type' => 'radio',
'#title' => $format->name,
'#default_value' => $default_value,
'#return_value' => $format->format,
'#parents' => $parents,
'#description' => theme('filter_tips', _filter_tips($format->format, FALSE)),
'#id' => form_clean_id('edit-' . implode('-', $parents_for_id)),
);
}
$form[] = array(
'#value' => $extra,
);
return $form;
}
/**
* Build header array with priority and receipt confirmation settings.
*
* @param $receipt
* Boolean: If a receipt is requested.
* @param $priority
* Integer: The message priority.
* @param $from
* String: The sender's e-mail address.
*
* @return Header array with priority and receipt confirmation info
*/
function _views_send_headers($receipt, $priority, $from, $additional_headers) {
$headers = array();
// If receipt is requested, add headers.
if ($receipt) {
$headers['Disposition-Notification-To'] = $from;
$headers['X-Confirm-Reading-To'] = $from;
}
// Add priority if set.
switch ($priority) {
case VIEWS_SEND_PRIORITY_HIGHEST:
$headers['Priority'] = 'High';
$headers['X-Priority'] = '1';
$headers['X-MSMail-Priority'] = 'Highest';
break;
case VIEWS_SEND_PRIORITY_HIGH:
$headers['Priority'] = 'urgent';
$headers['X-Priority'] = '2';
$headers['X-MSMail-Priority'] = 'High';
break;
case VIEWS_SEND_PRIORITY_NORMAL:
$headers['Priority'] = 'normal';
$headers['X-Priority'] = '3';
$headers['X-MSMail-Priority'] = 'Normal';
break;
case VIEWS_SEND_PRIORITY_LOW:
$headers['Priority'] = 'non-urgent';
$headers['X-Priority'] = '4';
$headers['X-MSMail-Priority'] = 'Low';
break;
case VIEWS_SEND_PRIORITY_LOWEST:
$headers['Priority'] = 'non-urgent';
$headers['X-Priority'] = '5';
$headers['X-MSMail-Priority'] = 'Lowest';
break;
}
// Add general headers.
$headers['Precedence'] = 'bulk';
// Add additional headers.
$additional_headers = trim($additional_headers);
$additional_headers = str_replace("\r", "\n", $additional_headers);
$additional_headers = explode("\n", $additional_headers);
foreach ($additional_headers as $header) {
$header = trim($header);
if (!empty($header)) {
list($key, $value) = explode(': ', $header, 2);
$headers[$key] = trim($value);
}
}
return $headers;
}
/**
* Build a formatted e-mail address.
*/
function _views_send_format_address($mail, $name, $encode = TRUE) {
$name = trim($name);
// Do not format addres on Windows based PHP systems or when $name is empty.
return substr(PHP_OS, 0, 3) == 'WIN' || empty($name) ? $mail : '"' . ($encode ? mime_header_encode($name) : $name) . '" <' . $mail . '>';
}
/**
* Perform all alteration and preparation before spooling.
*
* @param $from_name
* String holding the Sender's name.
* @param $from_mail
* String holding the Sender's e-mail.
* @param $to_name
* String holding the Recipient's name.
* @param $to_mail
* String holding the Recipient's e-mail.
* @param $subject
* String with the e-mail subject. This argument can be altered here.
* @param $body
* Text with the e-mail body. This argument can be altered here.
* @param $headers
* Associative array with e-mail headers. This argument can be altered here.
* @param $format
* String with the e-mail format.
*/
function _views_send_prepare_mail($from_name, $from_mail, $to_name, $to_mail, &$subject, &$body, &$headers, $format, $attachments) {
/**
* TODO: In the future, this module will be able to send an existing node.
* $key will have to make the difference. A value when we pickup a node, other
* when user inputs the subject & body of the message.
*/
$key = 'direct';
// Build message parameters.
$params = array();
$params['from_name'] = $from_name;
$params['from_mail'] = $from_mail;
$params['from_formatted'] = _views_send_format_address($from_mail, $from_name);
$params['to_name'] = $to_name;
$params['to_mail'] = $to_mail;
$params['to_formatted'] = _views_send_format_address($to_mail, $to_name);
$params['subject'] = $subject;
$params['body'] = $body;
$params['headers'] = $headers;
// Call Drupal standard mail function, but without sending.
$mail = drupal_mail('views_send', $key, $params['to_formatted'], NULL, $params, $params['from_formatted'], FALSE);
// Add additional Mime Mail processing.
if (VIEWS_SEND_MIMEMAIL) {
$plain = $format == VIEWS_SEND_FORMAT_PLAIN;
$plain_text = $plain ? $mail['body'] : _views_send_html_to_text($mail['body'], TRUE);
$mail = mimemail($mail['from'], $mail['to'], $mail['subject'], $mail['body'], $plain, $mail['headers'], $plain_text, $attachments, 'views_send_' . $key, FALSE);
// From: header may be broken after mimemail_prepare().
$mail['headers']['From'] = _views_send_format_address($from_mail, $from_name);
// We want to spool the Subject decoded.
$mail['subject'] = mime_header_decode($mail['subject']);
}
$subject = $mail['subject'];
$body = $mail['body'];
$headers = $mail['headers'];
}
/**
* HTML to text conversion for HTML and special characters.
* Converts some special HTMLcharacters in addition to drupal_html_to_text().
* Inspired from Simplenews,
*
* @param $text
* String: Source text with HTML and special characters.
*
* @return
* String: Target text with HTML and special characters replaced.
*/
function _views_send_html_to_text($text) {
$pattern = '@<a[^>]+?href="([^"]*)"[^>]*?>(.+?)</a>@is';
$text = preg_replace_callback($pattern, '_views_send_absolute_mail_urls', $text);
// Replace some special characters before performing the drupal standard conversion.
$preg = _views_send_html_replace();
$text = preg_replace(array_keys($preg), array_values($preg), $text);
// Perform standard drupal html to text conversion.
return drupal_html_to_text($text);
}
/**
* Helper function for _views_send_html_to_text().
* Inspired from Simplenews.
*
* List of preg regular expression patterns to search for and replace with.
*/
function _views_send_html_replace() {
return array(
'/"/i' => '"',
'/>/i' => '>',
'/</i' => '<',
'/&/i' => '&',
'/©/i' => '(c)',
'/™/i' => '(tm)',
'/“/' => '"',
'/”/' => '"',
'/–/' => '-',
'/’/' => "'",
'/&/' => '&',
'/©/' => '(c)',
'/™/' => '(tm)',
'/—/' => '--',
'/“/' => '"',
'/”/' => '"',
'/•/' => '*',
'/®/i' => '(R)',
'/•/i' => '*',
'/€/i' => 'Euro ',
);
}
/**
* Helper function for _views_send_html_to_text().
* Replaces URLs with abolute URLs.
*
* Inspired from Simplenews.
*/
function _views_send_absolute_mail_urls($match) {
global $base_url, $base_path;
static $regexp;
$url = $label = '';
if ($match) {
if (empty($regexp)) {
$regexp = '@^' . preg_quote($base_path, '@') . '@';
}
list(, $url, $label) = $match;
$url = strpos($url, '://') ? $url : preg_replace($regexp, $base_url . '/', $url);
// If the link is formed by Drupal's URL filter, we only return the URL.
// The URL filter generates a label out of the original URL.
if (strpos($label, '...') === strlen($label) - 3) {
// Remove ellipsis from end of label.
$label = substr($label, 0, strlen($label) - 3);
}
if (strpos($url, $label) !== FALSE) {
return $url;
}
return $label . ' ' . $url;
}
}
/**
* Normalizing the context. If token_action.module is not enabled we'll have to
* normalize here. Otherwise use token_normalize_context().
*
* @see http://drupalcontrib.org/api/function/token_normalize_context/6
*/
function _views_send_normalize_context(&$context) {
if (function_exists('token_normalize_context')) {
token_normalize_context($context);
}
else {
$context['global'] = NULL;
if (empty($context['user']) && !empty($context['node'])) {
$context['user'] = user_load(array(
'uid' => $context['node']->uid,
));
}
if (empty($context['node']) && !empty($context['comment']) && !empty($context['comment']->nid)) {
$context['node'] = node_load($context['comment']->nid);
}
}
}
/**
* Find out if the current user is allowed to use the PHP filter.
*/
function _views_send_allow_php() {
static $allow_php;
if (!isset($allow_php)) {
$allow_php = FALSE;
$result = db_query("SELECT format FROM {filters} WHERE module = 'php'");
while ($row = db_fetch_object($result)) {
if (filter_access($row->format)) {
$allow_php = TRUE;
break;
}
}
}
return $allow_php;
}
// === Theming functions =======================================================
/**
* Theme the replacement tokens.
*
* @param $tokens:
* Keyed array with tokens as keys and description as values.
*
* @return
* A themed table wirh all tokens.
*/
function theme_views_send_token_help($fields) {
if (!module_exists('token')) {
$headers = array(
t('Token'),
t('Replacement value'),
);
$rows = array();
$rows[] = array(
array(
'data' => t('View row tokens'),
'class' => 'region',
'colspan' => 2,
),
);
foreach ($fields as $field => $title) {
$rows[] = array(
VIEWS_SEND_TOKEN_PREFIX . sprintf(VIEWS_SEND_TOKEN_PATTERN, $field) . VIEWS_SEND_TOKEN_POSTFIX,
$title,
);
}
$output = theme('table', $headers, $rows, array(
'class' => 'description',
));
}
else {
$output = theme('token_tree', 'all');
}
return $output;
}
if (module_exists('token')) {
/**
* Implements hook_token_list().
*/
function views_send_token_list($type = 'all') {
$tokencategory = 'views send';
if ($type == $tokencategory || $type == 'all') {
$fields_name_text = _views_send_get_fields_and_tokens(NULL, 'fields_name_text');
foreach ($fields_name_text as $field => $title) {
$tokens[$tokencategory][sprintf(VIEWS_SEND_TOKEN_PATTERN, $field)] = $title;
}
return $tokens;
}
}
}
/**
* Find the value for a given "field" in a Views result (row).
*
* If the "field" is a proper field, we check the raw array.
* First we look for "value" and then for a specific key if given.
* Then we check if there is just one key.
*/
function _views_send_get_from_views_result($views_result, $key, $extra_key = FALSE) {
$value = FALSE;
if (substr($key, 0, 6) == 'field_') {
// We don't know the table alias, just that it starts with
// or contains 'node_data_' and ends with the field key.
foreach ($views_result as $resultkey => $data) {
if (preg_match("/^(.*)node_data_(.*){$key}\$/", $resultkey)) {
$views_value = $data;
break;
}
}
// If the field is a plain string, just return it.
if (!is_array($views_value)) {
return $views_value;
}
// Abort immediately if the field is an empty array.
if (count($views_value) == 0) {
return FALSE;
}
// AFAICT the code below is never executed because Views 2 (on Drupal 6)
// doesn't have fields as arrays with 'raw' key.
if (isset($views_value[0]['raw']['value'])) {
$value = $views_value[0]['raw']['value'];
}
else {
if ($extra_key && isset($views_value[0]['raw'][$extra_key])) {
$value = $views_value[0]['raw'][$extra_key];
}
if (!$value && count($views_value[0]['raw']) == 1) {
$value = array_pop($views_value[0]['raw']);
}
}
}
else {
$value = $views_result->{$key};
}
return $value;
}
/**
* Generates and returns fields and tokens.
*/
function _views_send_get_fields_and_tokens($view, $type) {
static $return;
if (isset($return[$type])) {
return $return[$type];
}
if (!in_array($type, array(
'fields',
'tokens',
'fields_name_text',
)) || !$view) {
return array();
}
$fields = array();
$tokens = array();
$fields_name_text = array();
foreach ($view->field as $field_name => $field) {
if (!empty($field->content_field)) {
$field_key = $field_name;
$field_name = $field->content_field['field_name'];
}
elseif (property_exists($field, 'field_alias')) {
$field_key = $field->field_alias;
if ($field_key == 'unknown') {
$field_key = $field_name;
}
}
else {
$field_key = $field_name;
}
$field_text = $field
->label() . ' (' . $field_name . ')';
$fields[$field_key] = $field_text;
$tokens[$field_key] = $field_name;
$fields_name_text[$field_name] = $field_text;
}
$return = array();
$return['fields'] = $fields;
$return['tokens'] = $tokens;
$return['fields_name_text'] = $fields_name_text;
return $return[$type];
}
Functions
Name | Description |
---|---|
theme_views_send_token_help | Theme the replacement tokens. |
views_send_action_info | Implementation of hook_action_info() |
views_send_cron | Implementation of hook_cron(). |
views_send_form_alter | Implementation of hook_form_alter(). |
views_send_mail | Implementation of hook_mail(). |
views_send_mail_action | Main action callback. |
views_send_mail_action_form | Configuration form for views_send_mail action. |
views_send_mail_action_submit | Action configuration submission callback. |
views_send_mail_action_validate | Validation callback for views_send_mail action configuration form. |
views_send_menu | Implementation of hook_menu(). |
views_send_perm | Implementation of hook_perm(). |
views_send_theme | Implementation of hook_theme(). |
_views_send_absolute_mail_urls | Helper function for _views_send_html_to_text(). Replaces URLs with abolute URLs. |
_views_send_allow_php | Find out if the current user is allowed to use the PHP filter. |
_views_send_filter_form | This is a fork of filter_form() in order to allow adding the "Plain" option. |
_views_send_format_address | Build a formatted e-mail address. |
_views_send_get_fields_and_tokens | Generates and returns fields and tokens. |
_views_send_get_from_views_result | Find the value for a given "field" in a Views result (row). |
_views_send_headers | Build header array with priority and receipt confirmation settings. |
_views_send_html_replace | Helper function for _views_send_html_to_text(). Inspired from Simplenews. |
_views_send_html_to_text | HTML to text conversion for HTML and special characters. Converts some special HTMLcharacters in addition to drupal_html_to_text(). Inspired from Simplenews, |
_views_send_normalize_context | Normalizing the context. If token_action.module is not enabled we'll have to normalize here. Otherwise use token_normalize_context(). |
_views_send_prepare_mail | Perform all alteration and preparation before spooling. |
Constants
Name | Description |
---|---|
VIEWS_SEND_FORMAT_PLAIN | Plain message format value. |
VIEWS_SEND_MAX_EXECUTION_TIME | Capture PHP max_execution_time before drupal_cron_run(). Workaround for Drupal 6.14. See http://drupal.org/node/584334 |
VIEWS_SEND_MIMEMAIL | Detect and store Mime Mail module presence. |
VIEWS_SEND_PRIORITY_HIGH | |
VIEWS_SEND_PRIORITY_HIGHEST | |
VIEWS_SEND_PRIORITY_LOW | |
VIEWS_SEND_PRIORITY_LOWEST | |
VIEWS_SEND_PRIORITY_NONE | E-mail priorities. |
VIEWS_SEND_PRIORITY_NORMAL | |
VIEWS_SEND_TOKEN_PATTERN | Token pattern. |
VIEWS_SEND_TOKEN_POSTFIX | |
VIEWS_SEND_TOKEN_PREFIX |