View source
<?php
function mailhandler_cron() {
module_load_include('inc', 'mailhandler', 'mailhandler.retrieve');
$result = db_query('SELECT * FROM {mailhandler} WHERE enabled = 1 ORDER BY mail');
while ($mailbox = db_fetch_array($result)) {
mailhandler_node_process_mailbox($mailbox, 'auto', variable_get('mailhandler_max_retrieval', 0), array());
}
}
function mailhandler_perm() {
return array(
'administer mailhandler',
);
}
function mailhandler_menu() {
$items = array();
$items['admin/content/mailhandler'] = array(
'title' => 'Mailhandler Mailboxes',
'description' => 'Manage mailboxes and retrieve messages.',
'page callback' => 'mailhandler_list_mailboxes',
'access arguments' => array(
'administer mailhandler',
),
'file' => 'mailhandler.admin.inc',
);
$items['admin/content/mailhandler/list'] = array(
'title' => 'List',
'description' => 'Manage mailboxes and retrieve messages.',
'type' => MENU_DEFAULT_LOCAL_TASK,
'access arguments' => array(
'administer mailhandler',
),
'weight' => -10,
);
$items['admin/content/mailhandler/add'] = array(
'title' => 'Add mailbox',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'mailhandler_add_edit_mailbox',
NULL,
),
'access arguments' => array(
'administer mailhandler',
),
'type' => MENU_LOCAL_TASK,
'file' => 'mailhandler.admin.inc',
);
$items['admin/content/mailhandler/clone/%'] = array(
'title' => 'Add mailbox',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'mailhandler_add_edit_mailbox',
4,
TRUE,
),
'access arguments' => array(
'administer mailhandler',
),
'type' => MENU_CALLBACK,
'file' => 'mailhandler.admin.inc',
);
$items['admin/content/mailhandler/retrieve/%mailhandler_mailbox'] = array(
'title' => 'Retrieve',
'page callback' => 'mailhandler_node_process_mailbox',
'page arguments' => array(
4,
'ui',
(string) variable_get('mailhandler_max_retrieval', 0),
),
'access arguments' => array(
'administer mailhandler',
),
'type' => MENU_CALLBACK,
'file' => 'mailhandler.retrieve.inc',
);
$items['admin/content/mailhandler/edit/%'] = array(
'title' => 'Edit mailbox',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'mailhandler_add_edit_mailbox',
4,
),
'access arguments' => array(
'administer mailhandler',
),
'type' => MENU_CALLBACK,
'file' => 'mailhandler.admin.inc',
);
$items['admin/content/mailhandler/delete/%'] = array(
'title' => 'Delete mailbox',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'mailhandler_admin_delete_confirm',
4,
),
'access arguments' => array(
'administer mailhandler',
),
'type' => MENU_CALLBACK,
'file' => 'mailhandler.admin.inc',
);
$items['admin/settings/mailhandler'] = array(
'title' => 'Mailhandler Settings',
'description' => t('Set the default content type for incoming messages and set the cron limit.'),
'page callback' => 'drupal_get_form',
'page arguments' => array(
'mailhandler_admin_settings',
),
'access arguments' => array(
'administer mailhandler',
),
'file' => 'mailhandler.admin.inc',
);
return $items;
}
function mailhandler_mailbox_load($mid) {
return db_fetch_array(db_query("SELECT * FROM {mailhandler} WHERE mid = %d", $mid));
}
function mailhandler_help($path = 'admin/help#mailhandler', $arg) {
$output = '';
$commands[] = array(
'command' => 'taxonomy: [term1, term2]',
'description' => t('Use this to add the terms <em>term1</em> and <em>term2</em> to the node.<br />
Both of the terms should already exist. In case they do not exist already, they will be quietly ommitted'),
);
$commands[] = array(
'command' => 'taxonomy[v]: [term1, term2]',
'description' => t('Similar to the above: adds the terms <em>term1</em> and <em>term2</em> to the node, but uses the vocabulary with the vocabulary id <em>v</em>. For example <em>taxonomy[3]</em> will chose only terms from the vocabulary which id is 3.<br />
In case some of the terms do not exist already, the behavior will depend on whether the vocabulary is a free tagging vocabulary or not. If it is a free tagging vocabulary, the term will be added, otherwise, it will be quietly ommitted'),
);
$commands_list = '<dl>';
foreach ($commands as $command) {
$commands_list .= '<dt>' . $command['command'] . '</dt>';
$commands_list .= '<dl>' . $command['description'] . '</dl>';
}
$commands_list .= '</dl>';
switch ($path) {
case 'admin/help#mailhandler':
$output = '<p>' . t('The mailhandler module allows registered users to create or edit nodes and comments via e-mail. Users may post taxonomy terms, teasers, and other post attributes using the mail commands capability. This module is useful because e-mail is the preferred method of communication by community members.') . '</p>';
$output .= '<p>' . t('The mailhandler module requires the use of a custom mailbox. Administrators can add mailboxes that should be customized to meet the needs of a mailing list. This mailbox will then be checked on every cron job. Administrators may also initiate a manual retrieval of messages.') . '</p>';
$output .= '<p>' . t('This is particularly useful when you want multiple sets of default commands. For example , if you want to authenticate based on a non-standard mail header like Sender: which is useful for accepting submissions from a listserv. Authentication is usually based on the From: e-mail address. Administrators can edit the individual mailboxes when they administer mailhandler.') . '</p>';
$output .= t('<p>You can</p>
<ul>
<li><a href="@run-cron">run cron</a> to retrieve messages from all cron enabled mailboxes.</li>
<li>list mailboxes at <a href="@admin-mailhandler">Administer >> Content management >> Mailhandler</a>.</li>
<li>add a mailbox at <a href="@admin-mailhandler-add">Administer >> Content management >> Mailhandler >> Add mailbox.</a></li>
<li>set default commands, (password, type, taxonomy, promote, status), for how to work with incoming mail at <a href="%admin-mailhandler">Administer >> Content management >> Mailhandler</a> and select <strong>edit</strong> for the email address being handled. Set commands in the default command field.</li>
<li>post email, such as from a mailing list, to a forum by adding the term id (number found in the URL) to the default commands using <strong>tid: #</strong>.</li>
<li>alter mailhandler settings (default content type and cron threshold) at <a href="@admin-mailhandler-settings">Administer >> Site configuration >> Mailhandler</a>.</li>
</ul>', array(
'@run-cron' => url('admin/logs/status/run-cron'),
'@admin-mailhandler-add' => url('admin/content/mailhandler/add'),
'@admin-mailhandler' => url('admin/content/mailhandler'),
'@admin-mailhandler-settings' => url('admin/settings/mailhandler'),
));
$output .= '<h3 id="commands">' . t('Useful Commands') . '</h3>';
$output .= $commands_list;
$output .= '<p>' . t('For more information please read the configuration and customization handbook <a href="@mailhandler">Mailhandler page</a>.', array(
'@mailhandler' => url('http://www.drupal.org/handbook/modules/mailhandler', array(
'absolute' => TRUE,
)),
)) . '</p>';
return $output;
case 'admin/content/mailhandler':
return t('The mailhandler module allows registered users to create or edit nodes and comments via email. Authentication is usually based on the From: email address. There is also an email filter that can be used to prettify incoming email. Users may post taxonomy terms, teasers, and other node parameters using the Command capability.');
case 'admin/content/mailhandler/add':
return t('Add a mailbox whose mail you wish to import into Drupal. Can be IMAP, POP3, or local folder.');
case 'admin/content/mailhandler/edit/%':
return t('Edit the mailbox whose mail you wish to import into Drupal. Can be IMAP, POP3, or local folder.');
case 'admin/settings/mailhandler':
return t('The mailhandler module allows registered users to create or edit nodes and comments via e-mail.');
}
}
function mailhandler_get_mailbox($mid) {
return db_fetch_array(db_query("SELECT * FROM {mailhandler} WHERE mid = %d", $mid));
}
function mailhandler_default_type() {
$default_type = variable_get('mailhandler_default_type', NULL);
$available_types = node_get_types('names');
if ($default_type && array_key_exists($default_type, $available_types)) {
return $default_type;
}
if (array_key_exists('blog', $available_types)) {
$default_type = 'blog';
}
else {
if (array_key_exists('story', $available_types)) {
$default_type = 'story';
}
else {
if (array_key_exists('page', $available_types)) {
$default_type = 'page';
}
else {
$default_type = key($available_types);
}
}
}
return $default_type;
}
function mailhandler_node_process_mailbox($mailbox = FALSE, $mode = FALSE, $limit = FALSE, $messages = array()) {
if (empty($messages)) {
if ($mode == 'ui') {
mailhandler_retrieve($mailbox, $mode, $limit);
}
else {
if ($messages = mailhandler_retrieve($mailbox, $mode, $limit)) {
foreach ($messages as $message) {
mailhandler_node_process_message($message['header'], $message['origbody'], $message['mailbox'], $message['mimeparts']);
}
}
}
}
else {
foreach ($messages as $message) {
mailhandler_node_process_message($message['header'], $message['origbody'], $message['mailbox'], $message['mimeparts']);
}
}
}
function mailhandler_mailhandler_batch_results($results) {
mailhandler_node_process_mailbox(FALSE, FALSE, FALSE, $results);
return $results;
}
function mailhandler_node_process_message($header, $origbody, $mailbox, $mimeparts) {
mailhandler_switch_user();
$node = mailhandler_node_prepare_message($header, $origbody, $mailbox);
if (!($node = mailhandler_mailhandler_authenticate('execute', $mailbox['authentication'], array(
$node,
$header,
$origbody,
$mailbox,
)))) {
watchdog('mailhandler', 'Message failed authentication', array(), WATCHDOG_ERROR);
return FALSE;
}
$node->mimeparts = $mimeparts;
mailhandler_switch_user($node->uid);
foreach (module_list() as $name) {
if (module_hook($name, 'mailhandler')) {
$function = $name . '_mailhandler';
if (!($node = $function($node, $result, $i, $header, $mailbox))) {
break;
}
}
}
if ($node) {
if ($node->type == 'comment') {
$nid = mailhandler_comment_submit($node, $header, $mailbox, $origbody);
$type = 'comment';
}
else {
$nid = mailhandler_node_submit($node, $header, $mailbox, $origbody);
$type = 'node';
}
}
foreach (module_list() as $name) {
if (module_hook($name, 'mailhandler_post_save')) {
$function = $name . '_mailhandler_post_save';
$function($nid, $type);
}
}
mailhandler_switch_user();
$context['results'][] = $mailbox['mail'];
mailhandler_switch_user();
}
function mailhandler_node_prepare_message($header, $body, $mailbox) {
$node = new stdClass();
$node->pass = NULL;
$sep = $mailbox['sigseparator'];
if (!empty($header->references)) {
$threading = substr(strrchr($header->references, '<'), 0);
}
else {
if (!empty($header->in_reply_to)) {
$threading = str_replace(strstr($header->in_reply_to, '>'), '>', $header->in_reply_to);
}
}
if (isset($threading) && ($threading = rtrim(ltrim($threading, '<'), '>'))) {
if ($threading) {
$node->threading = $threading;
}
parse_str($threading, $tmp);
if ($tmp['host']) {
$tmp['host'] = ltrim($tmp['host'], '@');
}
foreach ($tmp as $key => $value) {
$node->{$key} = $value;
}
}
if ($mailbox['commands']) {
$body = trim($mailbox['commands']) . "\n" . $body;
}
if ($commands = mailhandler_commands_parse($body, $sep)) {
foreach ($commands['commands'] as $command) {
if ($command[0] == 'type') {
$node->type = $command[1];
}
}
}
if (!isset($node->type)) {
$node->type = mailhandler_default_type();
}
require_once drupal_get_path('module', 'node') . '/node.pages.inc';
node_object_prepare($node);
$node->uid = 0;
if ($node->type == 'comment') {
unset($node->status);
}
if (!empty($commands['commands'])) {
mailhandler_node_process_message_commands($node, $commands['commands']);
}
$tmp = array_slice($commands['lines'], $commands['endcommands'], $commands['i'] - $commands['endcommands']);
$type = node_get_types('type', $node->type);
if ($type->has_body) {
$node->body = implode("\n", $tmp);
}
if (empty($node->teaser)) {
$node->teaser = node_teaser($node->body);
}
$subjectarr = imap_mime_header_decode($header->subject);
if (empty($subjectarr)) {
$node->title = truncate_utf8(trim(decode_entities(strip_tags(check_markup($node->body)))), 29, TRUE);
}
else {
for ($i = 0; $i < count($subjectarr); $i++) {
if ($subjectarr[$i]->charset != 'default') {
$node->title .= drupal_convert_to_utf8($subjectarr[$i]->text, $subjectarr[$i]->charset);
}
else {
$node->title .= $subjectarr[$i]->text;
}
}
}
$node->date = $node->changed = format_date($header->udate, 'custom', 'Y-m-d H:i:s O');
$node->format = $mailbox['format'];
if (isset($node->nid) && !empty($node->nid) && $node->type != 'comment') {
$vid = db_result(db_query('SELECT n.vid FROM {node} n WHERE n.nid = %d', $node->nid));
if ($vid) {
$node->revision = $node->vid = $vid;
}
}
return $node;
}
function mailhandler_comment_submit($node, $header, $mailbox, $origbody) {
global $user;
if (!$node->subject) {
$node->subject = $node->title;
}
$node->comment = $node->body;
if (property_exists($node, 'status')) {
$node->status == 1 ? $node->status = 0 : ($node->status = 1);
}
$node->timestamp = $node->created;
$edit = (array) $node;
$cid = comment_save($edit);
if (!$cid && $mailbox['replies']) {
list($fromaddress, $fromname) = mailhandler_get_fromaddress($header, $mailbox);
$error_text = t('Sorry, your comment experienced an error and was not posted. Possible reasons are that you have insufficient permission to post comments or the node is no longer open for comments.');
$params = array(
'body' => $origbody,
'error_messages' => array(),
'error_text' => $error_text,
'from' => $fromaddress,
'header' => $header,
'node' => $node,
);
drupal_mail('mailhandler', 'mailhandler_error_comment', $fromaddress, user_preferred_language($user), $params);
watchdog('mailhandler', 'Comment submission failure: %subject.', array(
'%subject' => $edit['subject'],
), WATCHDOG_ERROR);
}
return $cid;
}
function mailhandler_node_submit($node, $header, $mailbox, $origbody) {
global $user;
list($fromaddress, $fromname) = mailhandler_get_fromaddress($header, $mailbox);
form_set_error(NULL, '', TRUE);
node_validate($node);
if (!($error_messages = form_set_error())) {
$node = node_submit($node);
if (!empty($node->nid)) {
if (node_access('update', $node)) {
node_save($node);
watchdog('mailhandler', 'Updated %title by %from.', array(
'%title' => $node->title,
'%from' => $fromaddress,
));
}
else {
$error_text = t('The e-mail address !from may not update !type items.', array(
'!from' => $fromaddress,
'!type' => $node->type,
));
watchdog('mailhandler', 'Node submission failure: %from may not update %type items.', array(
'%from' => $fromaddress,
'%type' => $node->type,
), WATCHDOG_WARNING);
}
}
else {
$account = user_load($node->uid);
if (node_access('create', $node, $account)) {
node_save($node);
watchdog('mailhandler', 'Added %title by %from.', array(
'%title' => $node->title,
'%from' => $fromaddress,
));
}
else {
$error_text = t('The e-mail address !from may not create !type items.', array(
'!from' => $fromaddress,
'!type' => $node->type,
));
watchdog('mailhandler', 'Node submission failure: %from may not create %type items.', array(
'%from' => $fromaddress,
'%type' => $node->type,
), WATCHDOG_WARNING);
}
}
if (!isset($error_text)) {
return $node;
}
}
else {
$error_text = t('Your submission is invalid:');
watchdog('mailhandler', 'Node submission failure: validation error.', array(), WATCHDOG_WARNING);
}
if (isset($error_text)) {
if ($mailbox['replies']) {
$params = array(
'body' => $origbody,
'error_messages' => $error_messages,
'error_text' => $error_text,
'from' => $fromaddress,
'header' => $header,
'node' => $node,
);
drupal_mail('mailhandler', 'mailhandler_error_node', $fromaddress, user_preferred_language($user), $params);
}
}
return FALSE;
}
function mailhandler_term_map(&$term, $index = array(), $vid = FALSE) {
if ($vid) {
$and = 'AND vid =' . db_escape_string($vid);
}
$term = db_result(db_query("SELECT tid FROM {term_data} WHERE LOWER('%s') LIKE LOWER(name) {$and}", trim($term)));
}
function mailhandler_node_process_message_commands(&$node, $commands) {
if (module_exists('taxonomy')) {
$vocabs = taxonomy_get_vocabularies($node->type);
$node->taxonomy = array();
foreach ($commands as $data) {
if (substr($data[1], 0, 1) == '[' && substr($data[1], -1, 1) == ']') {
$data[1] = rtrim(ltrim($data[1], '['), ']');
$data[1] = explode(",", $data[1]);
foreach ($data[1] as $key => $value) {
$data_tmp = explode(":", $value, 2);
if (isset($data_tmp[1])) {
unset($data[1][$key]);
$data_tmp[0] = trim($data_tmp[0]);
$data[1][$data_tmp[0]] = $data_tmp[1];
}
}
}
$data[0] = strtolower(str_replace(' ', '_', $data[0]));
if ($data[0] == 'taxonomy' && !is_numeric($data[1][0])) {
array_walk($data[1], 'mailhandler_term_map');
$term = taxonomy_get_term($data[1][0]);
if (array_key_exists($term->vid, $vocabs)) {
$node->taxonomy = array_merge($node->taxonomy, $data[1]);
}
unset($data[0]);
}
else {
if (substr($data[0], 0, 9) == 'taxonomy[' && substr($data[0], -1, 1) == ']') {
$vid = substr($data[0], 9, -1);
$vocabulary = taxonomy_vocabulary_load($vid);
if (!in_array($node->type, $vocabulary->nodes)) {
unset($data[0]);
}
else {
if (!$vocabulary->tags) {
array_walk($data[1], 'mailhandler_term_map', $vid);
$node->taxonomy = array_merge($node->taxonomy, $data[1]);
unset($data[0]);
}
else {
if ($vocabulary->tags) {
$node->taxonomy['tags'][$vid] = implode(',', $data[1]);
unset($data[0]);
}
}
}
}
}
if (!empty($data[0])) {
$node->{$data}[0] = $data[1];
}
}
}
else {
watchdog('mailhandler', 'Unable to process commands. Taxonomy module must be enabled for Mailhandler command processing to work.');
}
}
function mailhandler_mail($key, &$message, $params) {
$variables = array(
'!body' => $params['body'],
'!from' => $params['from'],
'!site_name' => variable_get('site_name', 'Drupal'),
'!subject' => $params['header']->subject,
'!type' => $params['node']->type,
);
$message['subject'] = t('Email submission to !site_name failed - !subject', $variables);
$message['body'][] = $params['error_text'];
foreach ($params['error_messages'] as $key => $error) {
$message['body'][$key] = decode_entities(strip_tags($error));
}
$message['body'][] = t("You sent:\n\nFrom: !from\nSubject: !subject\nBody:\n!body", $variables);
}
function mailhandler_mailhandler_authenticate_info() {
$info = array(
'mailhandler_default' => array(
'title' => 'Mailhandler Default',
'description' => 'Checks whether the sender matches a valid user in the database',
'callback' => 'mailhandler_authenticate_default',
'module' => 'mailhandler',
'extension' => NULL,
'basename' => NULL,
),
);
if (module_exists('tokenauth')) {
$info += array(
'mailhandler_tokenauth' => array(
'title' => 'Mailhandler Tokenauth',
'description' => 'Authenticate messages based on users token from Tokenauth module',
'callback' => 'mailhandler_authenticate_tokenauth',
'module' => 'mailhandler',
'extension' => NULL,
'basename' => NULL,
),
);
}
return $info;
}
function mailhandler_authenticate_default($node, $header, $origbody, $mailbox) {
list($fromaddress, $fromname) = mailhandler_get_fromaddress($header, $mailbox);
if ($from_user = mailhandler_user_load($fromaddress, $node->pass, $mailbox)) {
$node->uid = $from_user->uid;
$node->name = $from_user->name;
}
else {
if (function_exists('mailalias_user') && ($from_user = mailhandler_user_load_alias($fromaddress, $node, $mailbox))) {
$node->uid = $from_user->uid;
$node->name = $from_user->name;
}
else {
$node->uid = 0;
$node->name = $fromname;
}
}
return $node;
}
function mailhandler_authenticate_tokenauth($node, $header, $origbody, $mailbox) {
if (module_exists('tokenauth')) {
list($fromaddress, $fromname) = mailhandler_get_fromaddress($header, $mailbox);
if (($from_user = mailhandler_user_load($fromaddress, $node->pass, $mailbox)) && strpos($header->to[0]->mailbox, tokenauth_get_token($from_user->uid)) !== FALSE) {
$node->uid = $from_user->uid;
$node->name = $from_user->name;
}
else {
if (function_exists('mailalias_user') && ($from_user = mailhandler_user_load_alias($fromaddress, $node, $mailbox)) && strpos($header->to[0]->mailbox, tokenauth_get_token($from_user->uid)) !== FALSE) {
$node->uid = $from_user->uid;
$node->name = $from_user->name;
}
else {
$node->uid = 0;
$node->name = $fromname;
}
}
}
return $node;
}
function mailhandler_get_fromaddress($header, $mailbox) {
if (($fromheader = strtolower($mailbox['fromheader'])) && isset($header->{$fromheader})) {
$from = $header->{$fromheader};
}
else {
$from = $header->from;
}
return array(
$from[0]->mailbox . '@' . $from[0]->host,
isset($from[0]->personal) ? $from[0]->personal : '',
);
}
function mailhandler_user_load($mail, $pass, $mailbox) {
if ($mailbox['security'] == 1) {
if (!($account = user_load(array(
'mail' => $mail,
'pass' => $pass,
)))) {
watchdog('mailhandler', 'Wrong password used in message commands for %address', array(
'%address' => $mail,
), WATCHDOG_NOTICE);
}
return $account;
}
else {
return user_load(array(
'mail' => $mail,
));
}
}
function mailhandler_user_load_alias($fromaddress, $node, $mailbox) {
$result = db_query("SELECT mail FROM {users} WHERE data LIKE '%%%s%%'", $fromaddress);
while ($alias = db_result($result)) {
if ($from_user = mailhandler_user_load($alias, $node->pass, $mailbox)) {
return $from_user;
break;
}
}
return FALSE;
}