Show spam aliases #
This commit is contained in:
93
data/web/rc/program/steps/mail/addcontact.inc
Normal file
93
data/web/rc/program/steps/mail/addcontact.inc
Normal file
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
+-----------------------------------------------------------------------+
|
||||
| program/steps/mail/addcontact.inc |
|
||||
| |
|
||||
| This file is part of the Roundcube Webmail client |
|
||||
| Copyright (C) 2005-2013, The Roundcube Dev Team |
|
||||
| |
|
||||
| Licensed under the GNU General Public License version 3 or |
|
||||
| any later version with exceptions for skins & plugins. |
|
||||
| See the README file for a full license statement. |
|
||||
| |
|
||||
| PURPOSE: |
|
||||
| Add the submitted contact to the users address book |
|
||||
| |
|
||||
+-----------------------------------------------------------------------+
|
||||
| Author: Thomas Bruederli <roundcube@gmail.com> |
|
||||
+-----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
// only process ajax requests
|
||||
if (!$OUTPUT->ajax_call) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get default addressbook
|
||||
$CONTACTS = $RCMAIL->get_address_book(-1, true);
|
||||
|
||||
if (!empty($_POST['_address']) && is_object($CONTACTS)) {
|
||||
$address = rcube_utils::get_input_value('_address', rcube_utils::INPUT_POST, true);
|
||||
$contact_arr = rcube_mime::decode_address_list($address, 1, false);
|
||||
|
||||
if (!empty($contact_arr[1]['mailto'])) {
|
||||
$contact = array(
|
||||
'email' => $contact_arr[1]['mailto'],
|
||||
'name' => $contact_arr[1]['name'],
|
||||
);
|
||||
|
||||
// Validity checks
|
||||
if (empty($contact['email'])) {
|
||||
$OUTPUT->show_message('errorsavingcontact', 'error');
|
||||
$OUTPUT->send();
|
||||
}
|
||||
|
||||
$email = rcube_utils::idn_to_ascii($contact['email']);
|
||||
if (!rcube_utils::check_email($email, false)) {
|
||||
$OUTPUT->show_message('emailformaterror', 'error', array('email' => $contact['email']));
|
||||
$OUTPUT->send();
|
||||
}
|
||||
|
||||
$contact['email'] = rcube_utils::idn_to_utf8($contact['email']);
|
||||
|
||||
$contact = $RCMAIL->plugins->exec_hook('contact_displayname', $contact);
|
||||
|
||||
if (empty($contact['firstname']) || empty($contact['surname'])) {
|
||||
$contact['name'] = rcube_addressbook::compose_display_name($contact);
|
||||
}
|
||||
|
||||
// validate contact record
|
||||
if (!$CONTACTS->validate($contact, true)) {
|
||||
$error = $CONTACTS->get_error();
|
||||
// TODO: show dialog to complete record
|
||||
// if ($error['type'] == rcube_addressbook::ERROR_VALIDATE) { }
|
||||
|
||||
$OUTPUT->show_message($error['message'] ?: 'errorsavingcontact', 'error');
|
||||
$OUTPUT->send();
|
||||
}
|
||||
|
||||
// check for existing contacts
|
||||
$existing = $CONTACTS->search('email', $contact['email'], 1, false);
|
||||
|
||||
if ($done = $existing->count) {
|
||||
$OUTPUT->show_message('contactexists', 'warning');
|
||||
}
|
||||
else {
|
||||
$plugin = $RCMAIL->plugins->exec_hook('contact_create', array('record' => $contact, 'source' => null));
|
||||
$contact = $plugin['record'];
|
||||
|
||||
$done = !$plugin['abort'] ? $CONTACTS->insert($contact) : $plugin['result'];
|
||||
|
||||
if ($done) {
|
||||
$OUTPUT->show_message('addedsuccessfully', 'confirmation');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$done) {
|
||||
$OUTPUT->show_message($plugin['message'] ?: 'errorsavingcontact', 'error');
|
||||
}
|
||||
|
||||
$OUTPUT->send();
|
291
data/web/rc/program/steps/mail/attachments.inc
Normal file
291
data/web/rc/program/steps/mail/attachments.inc
Normal file
@@ -0,0 +1,291 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
+-----------------------------------------------------------------------+
|
||||
| program/steps/mail/attachments.inc |
|
||||
| |
|
||||
| This file is part of the Roundcube Webmail client |
|
||||
| Copyright (C) 2005-2013, The Roundcube Dev Team |
|
||||
| |
|
||||
| Licensed under the GNU General Public License version 3 or |
|
||||
| any later version with exceptions for skins & plugins. |
|
||||
| See the README file for a full license statement. |
|
||||
| |
|
||||
| PURPOSE: |
|
||||
| Upload, remove, display attachments in compose form |
|
||||
| |
|
||||
+-----------------------------------------------------------------------+
|
||||
| Author: Thomas Bruederli <roundcube@gmail.com> |
|
||||
+-----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
// Upload progress update
|
||||
if (!empty($_GET['_progress'])) {
|
||||
$RCMAIL->upload_progress();
|
||||
}
|
||||
|
||||
$COMPOSE_ID = rcube_utils::get_input_value('_id', rcube_utils::INPUT_GPC);
|
||||
$COMPOSE = null;
|
||||
|
||||
if ($COMPOSE_ID && $_SESSION['compose_data_' . $COMPOSE_ID]) {
|
||||
$SESSION_KEY = 'compose_data_' . $COMPOSE_ID;
|
||||
$COMPOSE =& $_SESSION[$SESSION_KEY];
|
||||
}
|
||||
|
||||
if (!$COMPOSE) {
|
||||
die("Invalid session var!");
|
||||
}
|
||||
|
||||
$file_id = rcube_utils::get_input_value('_file', rcube_utils::INPUT_GPC);
|
||||
$file_id = preg_replace('/^rcmfile/', '', $file_id) ?: 'unknown';
|
||||
|
||||
// remove an attachment
|
||||
if ($RCMAIL->action == 'remove-attachment') {
|
||||
if ($attachment = $COMPOSE['attachments'][$file_id]) {
|
||||
$attachment = $RCMAIL->plugins->exec_hook('attachment_delete', $attachment);
|
||||
}
|
||||
|
||||
if ($attachment['status']) {
|
||||
if (is_array($COMPOSE['attachments'][$file_id])) {
|
||||
$RCMAIL->session->remove($SESSION_KEY . '.attachments.' . $file_id);
|
||||
$OUTPUT->command('remove_from_attachment_list', "rcmfile$file_id");
|
||||
}
|
||||
}
|
||||
|
||||
$OUTPUT->send();
|
||||
exit;
|
||||
}
|
||||
|
||||
// rename an attachment
|
||||
if ($RCMAIL->action == 'rename-attachment') {
|
||||
$filename = rcube_utils::get_input_value('_name', rcube_utils::INPUT_POST);
|
||||
$filename = trim($filename);
|
||||
|
||||
if (strlen($filename)
|
||||
&& ($attachment = $COMPOSE['attachments'][$file_id])
|
||||
&& is_array($attachment)
|
||||
) {
|
||||
$attachment['name'] = $filename;
|
||||
$RCMAIL->session->remove($SESSION_KEY . '.attachments. ' . $file_id);
|
||||
$RCMAIL->session->append($SESSION_KEY . '.attachments', $attachment['id'], $attachment);
|
||||
$OUTPUT->command('rename_attachment_handler', "rcmfile$file_id", $filename);
|
||||
}
|
||||
|
||||
$OUTPUT->send();
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($RCMAIL->action == 'display-attachment') {
|
||||
$RCMAIL->display_uploaded_file($COMPOSE['attachments'][$file_id]);
|
||||
exit;
|
||||
}
|
||||
|
||||
/***** attachment upload action *****/
|
||||
|
||||
// clear all stored output properties (like scripts and env vars)
|
||||
$OUTPUT->reset();
|
||||
|
||||
$uploadid = rcube_utils::get_input_value('_uploadid', rcube_utils::INPUT_GPC);
|
||||
$uri = rcube_utils::get_input_value('_uri', rcube_utils::INPUT_POST);
|
||||
|
||||
// handle dropping a reference to an attachment part of some message
|
||||
if ($uri) {
|
||||
$url = parse_url($uri);
|
||||
parse_str($url['query'], $params);
|
||||
|
||||
if (strlen($params['_mbox']) && $params['_uid'] && $params['_part']) {
|
||||
// @TODO: at some point we might support drag-n-drop between
|
||||
// two different accounts on the same server, for now make sure
|
||||
// this is the same server and the same user
|
||||
list($host, $port) = explode(':', $_SERVER['HTTP_HOST']);
|
||||
if ($host == $url['host'] && $port == $url['port']
|
||||
&& $RCMAIL->get_user_name() == rawurldecode($url['user'])
|
||||
) {
|
||||
$message = new rcube_message($params['_uid'], $params['_mbox']);
|
||||
|
||||
if ($message && !empty($message->headers)) {
|
||||
$attachment = rcmail_save_attachment($message, $params['_part'], $COMPOSE_ID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$plugin = $RCMAIL->plugins->exec_hook('attachment_from_uri', array(
|
||||
'attachment' => $attachment, 'uri' => $uri, 'compose_id' => $COMPOSE_ID));
|
||||
|
||||
if ($plugin['attachment']) {
|
||||
rcmail_attachment_success($plugin['attachment'], $uploadid);
|
||||
}
|
||||
else {
|
||||
$OUTPUT->command('display_message', $RCMAIL->gettext('filelinkerror'), 'error');
|
||||
$OUTPUT->command('remove_from_attachment_list', $uploadid);
|
||||
}
|
||||
|
||||
$OUTPUT->send();
|
||||
return;
|
||||
}
|
||||
|
||||
// handle file(s) upload
|
||||
if (is_array($_FILES['_attachments']['tmp_name'])) {
|
||||
$multiple = count($_FILES['_attachments']['tmp_name']) > 1;
|
||||
$errors = array();
|
||||
|
||||
foreach ($_FILES['_attachments']['tmp_name'] as $i => $filepath) {
|
||||
// Process uploaded attachment if there is no error
|
||||
$err = $_FILES['_attachments']['error'][$i];
|
||||
|
||||
if (!$err) {
|
||||
$filename = $_FILES['_attachments']['name'][$i];
|
||||
$filesize = $_FILES['_attachments']['size'][$i];
|
||||
$filetype = rcube_mime::file_content_type($filepath, $filename, $_FILES['_attachments']['type'][$i]);
|
||||
|
||||
if ($err = rcmail_check_message_size($filesize, $filetype)) {
|
||||
if (!in_array($err, $errors)) {
|
||||
$OUTPUT->command('display_message', $err, 'error');
|
||||
$OUTPUT->command('remove_from_attachment_list', $uploadid);
|
||||
$errors[] = $err;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
$attachment = $RCMAIL->plugins->exec_hook('attachment_upload', array(
|
||||
'path' => $filepath,
|
||||
'name' => $filename,
|
||||
'size' => $filesize,
|
||||
'mimetype' => $filetype,
|
||||
'group' => $COMPOSE_ID,
|
||||
));
|
||||
}
|
||||
|
||||
if (!$err && $attachment['status'] && !$attachment['abort']) {
|
||||
// store new attachment in session
|
||||
unset($attachment['status'], $attachment['abort']);
|
||||
$RCMAIL->session->append($SESSION_KEY . '.attachments', $attachment['id'], $attachment);
|
||||
|
||||
rcmail_attachment_success($attachment, $uploadid);
|
||||
}
|
||||
else { // upload failed
|
||||
if ($err == UPLOAD_ERR_INI_SIZE || $err == UPLOAD_ERR_FORM_SIZE) {
|
||||
$size = $RCMAIL->show_bytes(rcube_utils::max_upload_size());
|
||||
$msg = $RCMAIL->gettext(array('name' => 'filesizeerror', 'vars' => array('size' => $size)));
|
||||
}
|
||||
else if ($attachment['error']) {
|
||||
$msg = $attachment['error'];
|
||||
}
|
||||
else {
|
||||
$msg = $RCMAIL->gettext('fileuploaderror');
|
||||
}
|
||||
|
||||
if ($attachment['error'] || $err != UPLOAD_ERR_NO_FILE) {
|
||||
if (!in_array($msg, $errors)) {
|
||||
$OUTPUT->command('display_message', $msg, 'error');
|
||||
$OUTPUT->command('remove_from_attachment_list', $uploadid);
|
||||
$errors[] = $msg;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
// if filesize exceeds post_max_size then $_FILES array is empty,
|
||||
// show filesizeerror instead of fileuploaderror
|
||||
if ($maxsize = ini_get('post_max_size')) {
|
||||
$msg = $RCMAIL->gettext(array(
|
||||
'name' => 'filesizeerror',
|
||||
'vars' => array('size' => $RCMAIL->show_bytes(parse_bytes($maxsize)))
|
||||
));
|
||||
}
|
||||
else {
|
||||
$msg = $RCMAIL->gettext('fileuploaderror');
|
||||
}
|
||||
|
||||
$OUTPUT->command('display_message', $msg, 'error');
|
||||
$OUTPUT->command('remove_from_attachment_list', $uploadid);
|
||||
}
|
||||
|
||||
// send html page with JS calls as response
|
||||
$OUTPUT->command('auto_save_start', false);
|
||||
$OUTPUT->send('iframe');
|
||||
|
||||
|
||||
function rcmail_attachment_success($attachment, $uploadid)
|
||||
{
|
||||
global $RCMAIL, $COMPOSE;
|
||||
|
||||
$id = $attachment['id'];
|
||||
|
||||
if (($icon = $COMPOSE['deleteicon']) && is_file($icon)) {
|
||||
$button = html::img(array(
|
||||
'src' => $icon,
|
||||
'alt' => $RCMAIL->gettext('delete')
|
||||
));
|
||||
}
|
||||
else if ($COMPOSE['textbuttons']) {
|
||||
$button = rcube::Q($RCMAIL->gettext('delete'));
|
||||
}
|
||||
else {
|
||||
$button = '';
|
||||
}
|
||||
|
||||
$link_content = sprintf('%s <span class="attachment-size"> (%s)</span>',
|
||||
rcube::Q($attachment['name']), $RCMAIL->show_bytes($attachment['size']));
|
||||
|
||||
$content_link = html::a(array(
|
||||
'href' => "#load",
|
||||
'class' => 'filename',
|
||||
'onclick' => sprintf("return %s.command('load-attachment','rcmfile%s', this, event)", rcmail_output::JS_OBJECT_NAME, $id),
|
||||
), $link_content);
|
||||
|
||||
$delete_link = html::a(array(
|
||||
'href' => "#delete",
|
||||
'onclick' => sprintf("return %s.command('remove-attachment','rcmfile%s', this, event)", rcmail_output::JS_OBJECT_NAME, $id),
|
||||
'title' => $RCMAIL->gettext('delete'),
|
||||
'class' => 'delete',
|
||||
'aria-label' => $RCMAIL->gettext('delete') . ' ' . $attachment['name'],
|
||||
), $button);
|
||||
|
||||
$content = $COMPOSE['icon_pos'] == 'left' ? $delete_link.$content_link : $content_link.$delete_link;
|
||||
|
||||
$RCMAIL->output->command('add2attachment_list', "rcmfile$id", array(
|
||||
'html' => $content,
|
||||
'name' => $attachment['name'],
|
||||
'mimetype' => $attachment['mimetype'],
|
||||
'classname' => rcube_utils::file2class($attachment['mimetype'], $attachment['name']),
|
||||
'complete' => true), $uploadid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the attached file will fit in message size limit.
|
||||
* Calculates size of all attachments and compares with the limit.
|
||||
*
|
||||
* @param int $filesize File size
|
||||
* @param string $filetype File mimetype
|
||||
*
|
||||
* @return string Error message if the limit is exceeded
|
||||
*/
|
||||
function rcmail_check_message_size($filesize, $filetype)
|
||||
{
|
||||
global $RCMAIL, $COMPOSE;
|
||||
|
||||
$limit = parse_bytes($RCMAIL->config->get('max_message_size'));
|
||||
$size = 10 * 1024; // size of message body
|
||||
|
||||
if (!$limit) {
|
||||
return;
|
||||
}
|
||||
|
||||
// add size of already attached files
|
||||
foreach ((array) $COMPOSE['attachments'] as $att) {
|
||||
// All attachments are base64-encoded except message/rfc822 (see sendmail.inc)
|
||||
$multip = $att['mimetype'] == 'message/rfc822' ? 1 : 1.33;
|
||||
$size += $att['size'] * $multip;
|
||||
}
|
||||
|
||||
// add size of the new attachment
|
||||
$multip = $filetype == 'message/rfc822' ? 1 : 1.33;
|
||||
$size += $filesize * $multip;
|
||||
|
||||
if ($size > $limit) {
|
||||
$limit = $RCMAIL->show_bytes($limit);
|
||||
return $RCMAIL->gettext(array('name' => 'msgsizeerror', 'vars' => array('size' => $limit)));
|
||||
}
|
||||
}
|
194
data/web/rc/program/steps/mail/autocomplete.inc
Normal file
194
data/web/rc/program/steps/mail/autocomplete.inc
Normal file
@@ -0,0 +1,194 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
+-----------------------------------------------------------------------+
|
||||
| program/steps/mail/autocomplete.inc |
|
||||
| |
|
||||
| This file is part of the Roundcube Webmail client |
|
||||
| Copyright (C) 2008-2013, Roundcube Dev Team |
|
||||
| Copyright (C) 2011-2013, Kolab Systems AG |
|
||||
| |
|
||||
| Licensed under the GNU General Public License version 3 or |
|
||||
| any later version with exceptions for skins & plugins. |
|
||||
| See the README file for a full license statement. |
|
||||
| |
|
||||
| PURPOSE: |
|
||||
| Perform a search on configured address books for the address |
|
||||
| autocompletion of the message compose screen |
|
||||
+-----------------------------------------------------------------------+
|
||||
| Author: Thomas Bruederli <roundcube@gmail.com> |
|
||||
+-----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
if ($RCMAIL->action == 'group-expand') {
|
||||
$abook = $RCMAIL->get_address_book(rcube_utils::get_input_value('_source', rcube_utils::INPUT_GPC));
|
||||
if ($gid = rcube_utils::get_input_value('_gid', rcube_utils::INPUT_GPC)) {
|
||||
$abook->set_group($gid);
|
||||
$abook->set_pagesize(1000); // TODO: limit number of group members by config
|
||||
|
||||
$separator = trim($RCMAIL->config->get('recipients_separator', ',')) . ' ';
|
||||
$result = $abook->list_records($RCMAIL->config->get('contactlist_fields'));
|
||||
$members = array();
|
||||
|
||||
while ($result && ($sql_arr = $result->iterate())) {
|
||||
$emails = (array) $abook->get_col_values('email', $sql_arr, true);
|
||||
if (!empty($emails) && ($email = array_shift($emails))) {
|
||||
$members[] = format_email_recipient($email, rcube_addressbook::compose_list_name($sql_arr));
|
||||
}
|
||||
}
|
||||
|
||||
$OUTPUT->command('replace_group_recipients', $gid, join($separator, array_unique($members)));
|
||||
}
|
||||
|
||||
$OUTPUT->send();
|
||||
}
|
||||
|
||||
|
||||
$MAXNUM = (int) $RCMAIL->config->get('autocomplete_max', 15);
|
||||
$mode = (int) $RCMAIL->config->get('addressbook_search_mode');
|
||||
$single = (bool) $RCMAIL->config->get('autocomplete_single');
|
||||
$search = rcube_utils::get_input_value('_search', rcube_utils::INPUT_GPC, true);
|
||||
$source = rcube_utils::get_input_value('_source', rcube_utils::INPUT_GPC);
|
||||
$reqid = rcube_utils::get_input_value('_reqid', rcube_utils::INPUT_GPC);
|
||||
|
||||
if (strlen($source)) {
|
||||
$book_types = array($source);
|
||||
}
|
||||
else {
|
||||
$book_types = (array) $RCMAIL->config->get('autocomplete_addressbooks', 'sql');
|
||||
}
|
||||
|
||||
$contacts = array();
|
||||
if (!empty($book_types) && strlen($search)) {
|
||||
$sort_keys = array();
|
||||
$books_num = count($book_types);
|
||||
$search_lc = mb_strtolower($search);
|
||||
$mode |= rcube_addressbook::SEARCH_GROUPS;
|
||||
|
||||
foreach ($book_types as $abook_id) {
|
||||
$abook = $RCMAIL->get_address_book($abook_id);
|
||||
$abook->set_pagesize($MAXNUM);
|
||||
|
||||
if ($result = $abook->search($RCMAIL->config->get('contactlist_fields'), $search, $mode, true, true, 'email')) {
|
||||
while ($sql_arr = $result->iterate()) {
|
||||
// Contact can have more than one e-mail address
|
||||
$email_arr = (array)$abook->get_col_values('email', $sql_arr, true);
|
||||
$email_cnt = count($email_arr);
|
||||
$idx = 0;
|
||||
|
||||
foreach ($email_arr as $email) {
|
||||
if (empty($email)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$name = rcube_addressbook::compose_list_name($sql_arr);
|
||||
$contact = format_email_recipient($email, $name);
|
||||
|
||||
// skip entries that don't match
|
||||
if ($email_cnt > 1 && strpos(mb_strtolower($contact), $search_lc) === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$index = $contact;
|
||||
|
||||
// skip duplicates
|
||||
if (empty($contacts[$index])) {
|
||||
$contact = array(
|
||||
'name' => $contact,
|
||||
'type' => $sql_arr['_type'],
|
||||
'id' => $sql_arr['ID'],
|
||||
'source' => $abook_id,
|
||||
);
|
||||
|
||||
if (($display = rcube_addressbook::compose_search_name($sql_arr, $email, $name)) && $display != $contact['name']) {
|
||||
$contact['display'] = $display;
|
||||
}
|
||||
|
||||
$contacts[$index] = $contact;
|
||||
$sort_keys[$index] = sprintf('%s %03d', $contact['display'] ?: $name, $idx++);
|
||||
|
||||
if (count($contacts) >= $MAXNUM) {
|
||||
break 2;
|
||||
}
|
||||
}
|
||||
|
||||
// skip redundant entries (show only first email address)
|
||||
if ($single) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// also list matching contact groups
|
||||
if ($abook->groups && count($contacts) < $MAXNUM) {
|
||||
foreach ($abook->list_groups($search, $mode) as $group) {
|
||||
$abook->reset();
|
||||
$abook->set_group($group['ID']);
|
||||
|
||||
$group_prop = $abook->get_group($group['ID']);
|
||||
|
||||
// group (distribution list) with email address(es)
|
||||
if ($group_prop['email']) {
|
||||
$idx = 0;
|
||||
foreach ((array)$group_prop['email'] as $email) {
|
||||
$index = format_email_recipient($email, $group['name']);
|
||||
|
||||
if (empty($contacts[$index])) {
|
||||
$sort_keys[$index] = sprintf('%s %03d', $group['name'] , $idx++);
|
||||
$contacts[$index] = array(
|
||||
'name' => $index,
|
||||
'email' => $email,
|
||||
'type' => 'group',
|
||||
'id' => $group['ID'],
|
||||
'source' => $abook_id,
|
||||
);
|
||||
|
||||
if (count($contacts) >= $MAXNUM) {
|
||||
break 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// show group with count
|
||||
else if (($result = $abook->count()) && $result->count) {
|
||||
if (empty($contacts[$group['name']])) {
|
||||
$sort_keys[$group['name']] = $group['name'];
|
||||
$contacts[$group['name']] = array(
|
||||
'name' => $group['name'] . ' (' . intval($result->count) . ')',
|
||||
'type' => 'group',
|
||||
'id' => $group['ID'],
|
||||
'source' => $abook_id,
|
||||
);
|
||||
|
||||
if (count($contacts) >= $MAXNUM) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (count($contacts)) {
|
||||
// sort contacts index
|
||||
asort($sort_keys, SORT_LOCALE_STRING);
|
||||
// re-sort contacts according to index
|
||||
foreach ($sort_keys as $idx => $val) {
|
||||
$sort_keys[$idx] = $contacts[$idx];
|
||||
}
|
||||
$contacts = array_values($sort_keys);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Allow autocomplete result optimization via plugin
|
||||
$pluginResult = $RCMAIL->plugins->exec_hook('contacts_autocomplete_after', array(
|
||||
'search' => $search,
|
||||
'contacts' => $contacts, // Provide already-found contacts to plugin if they are required
|
||||
));
|
||||
$contacts = $pluginResult['contacts'];
|
||||
|
||||
|
||||
$OUTPUT->command('ksearch_query_results', $contacts, $search, $reqid);
|
||||
$OUTPUT->send();
|
157
data/web/rc/program/steps/mail/check_recent.inc
Normal file
157
data/web/rc/program/steps/mail/check_recent.inc
Normal file
@@ -0,0 +1,157 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
+-----------------------------------------------------------------------+
|
||||
| program/steps/mail/check_recent.inc |
|
||||
| |
|
||||
| This file is part of the Roundcube Webmail client |
|
||||
| Copyright (C) 2005-2014, The Roundcube Dev Team |
|
||||
| |
|
||||
| Licensed under the GNU General Public License version 3 or |
|
||||
| any later version with exceptions for skins & plugins. |
|
||||
| See the README file for a full license statement. |
|
||||
| |
|
||||
| PURPOSE: |
|
||||
| Check for recent messages, in all mailboxes |
|
||||
| |
|
||||
+-----------------------------------------------------------------------+
|
||||
| Author: Thomas Bruederli <roundcube@gmail.com> |
|
||||
+-----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
// If there's no folder or messages list, there's nothing to update
|
||||
// This can happen on 'refresh' request
|
||||
if (empty($_POST['_folderlist']) && empty($_POST['_list'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$trash = $RCMAIL->config->get('trash_mbox');
|
||||
$current = $RCMAIL->storage->get_folder();
|
||||
$check_all = $RCMAIL->action != 'refresh' || (bool)$RCMAIL->config->get('check_all_folders');
|
||||
$page = $RCMAIL->storage->get_page();
|
||||
$page_size = $RCMAIL->storage->get_pagesize();
|
||||
|
||||
$search_request = rcube_utils::get_input_value('_search', rcube_utils::INPUT_GPC);
|
||||
if ($search_request && $_SESSION['search_request'] != $search_request) {
|
||||
$search_request = null;
|
||||
}
|
||||
|
||||
// list of folders to check
|
||||
if ($check_all) {
|
||||
$a_mailboxes = $RCMAIL->storage->list_folders_subscribed('', '*', 'mail');
|
||||
}
|
||||
else if ($search_request && is_object($_SESSION['search'][1])) {
|
||||
$a_mailboxes = (array) $_SESSION['search'][1]->get_parameters('MAILBOX');
|
||||
}
|
||||
else {
|
||||
$a_mailboxes = (array) $current;
|
||||
if ($current != 'INBOX') {
|
||||
$a_mailboxes[] = 'INBOX';
|
||||
}
|
||||
}
|
||||
|
||||
// Control folders list from a plugin
|
||||
$plugin = $RCMAIL->plugins->exec_hook('check_recent', array('folders' => $a_mailboxes, 'all' => $check_all));
|
||||
$a_mailboxes = $plugin['folders'];
|
||||
|
||||
// check recent/unseen counts
|
||||
foreach ($a_mailboxes as $mbox_name) {
|
||||
$is_current = $mbox_name == $current || ($search_request && is_object($_SESSION['search'][1]) && in_array($mbox_name, (array)$_SESSION['search'][1]->get_parameters('MAILBOX')));
|
||||
if ($is_current) {
|
||||
// Synchronize mailbox cache, handle flag changes
|
||||
$RCMAIL->storage->folder_sync($mbox_name);
|
||||
}
|
||||
|
||||
// Get mailbox status
|
||||
$status = $RCMAIL->storage->folder_status($mbox_name, $diff);
|
||||
|
||||
if ($status & 1) {
|
||||
// trigger plugin hook
|
||||
$RCMAIL->plugins->exec_hook('new_messages',
|
||||
array('mailbox' => $mbox_name, 'is_current' => $is_current, 'diff' => $diff));
|
||||
}
|
||||
|
||||
rcmail_send_unread_count($mbox_name, true, null,
|
||||
(!$is_current && ($status & 1)) ? 'recent' : '');
|
||||
|
||||
if ($status && $is_current) {
|
||||
// refresh saved search set
|
||||
if ($search_request && isset($_SESSION['search'])) {
|
||||
unset($search_request); // only do this once
|
||||
$_SESSION['search'] = $RCMAIL->storage->refresh_search();
|
||||
if ($_SESSION['search'][1]->multi) {
|
||||
$mbox_name = '';
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($_POST['_quota'])) {
|
||||
$OUTPUT->command('set_quota', $RCMAIL->quota_content(null, $mbox_name));
|
||||
}
|
||||
|
||||
$OUTPUT->set_env('exists', $RCMAIL->storage->count($mbox_name, 'EXISTS', true));
|
||||
|
||||
// "No-list" mode, don't get messages
|
||||
if (empty($_POST['_list'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// get overall message count; allow caching because rcube_storage::folder_status()
|
||||
// did a refresh but only in list mode
|
||||
$list_mode = $RCMAIL->storage->get_threading() ? 'THREADS' : 'ALL';
|
||||
$all_count = $RCMAIL->storage->count($mbox_name, $list_mode, $list_mode == 'THREADS', false);
|
||||
|
||||
// check current page if we're not on the first page
|
||||
if ($all_count && $page > 1) {
|
||||
$remaining = $all_count - $page_size * ($page - 1);
|
||||
if ($remaining <= 0) {
|
||||
$page -= 1;
|
||||
$RCMAIL->storage->set_page($page);
|
||||
$_SESSION['page'] = $page;
|
||||
}
|
||||
}
|
||||
|
||||
$OUTPUT->set_env('messagecount', $all_count);
|
||||
$OUTPUT->set_env('pagecount', ceil($all_count/$page_size));
|
||||
$OUTPUT->command('set_rowcount', rcmail_get_messagecount_text($all_count), $mbox_name);
|
||||
$OUTPUT->set_env('current_page', $all_count ? $page : 1);
|
||||
|
||||
// remove old rows (and clear selection if new list is empty)
|
||||
$OUTPUT->command('message_list.clear', $all_count ? false : true);
|
||||
|
||||
if ($all_count) {
|
||||
$a_headers = $RCMAIL->storage->list_messages($mbox_name, null, rcmail_sort_column(), rcmail_sort_order());
|
||||
// add message rows
|
||||
rcmail_js_message_list($a_headers, false);
|
||||
// remove messages that don't exists from list selection array
|
||||
$OUTPUT->command('update_selection');
|
||||
}
|
||||
}
|
||||
// handle flag updates
|
||||
else if ($is_current && ($uids = rcube_utils::get_input_value('_uids', rcube_utils::INPUT_GPC)) && empty($search_request)) {
|
||||
$data = $RCMAIL->storage->folder_data($mbox_name);
|
||||
|
||||
if (empty($_SESSION['list_mod_seq']) || $_SESSION['list_mod_seq'] != $data['HIGHESTMODSEQ']) {
|
||||
$flags = $RCMAIL->storage->list_flags($mbox_name, explode(',', $uids), $_SESSION['list_mod_seq']);
|
||||
foreach ($flags as $idx => $row) {
|
||||
$flags[$idx] = array_change_key_case(array_map('intval', $row));
|
||||
}
|
||||
|
||||
// remember last HIGHESTMODSEQ value (if supported)
|
||||
if (!empty($data['HIGHESTMODSEQ'])) {
|
||||
$_SESSION['list_mod_seq'] = $data['HIGHESTMODSEQ'];
|
||||
}
|
||||
|
||||
$RCMAIL->output->set_env('recent_flags', $flags);
|
||||
}
|
||||
}
|
||||
|
||||
// set trash folder state
|
||||
if ($mbox_name === $trash) {
|
||||
$OUTPUT->command('set_trash_count', $RCMAIL->storage->count($mbox_name, 'EXISTS', true));
|
||||
}
|
||||
}
|
||||
|
||||
// trigger refresh hook
|
||||
$RCMAIL->plugins->exec_hook('refresh', array());
|
||||
|
||||
$OUTPUT->send();
|
1896
data/web/rc/program/steps/mail/compose.inc
Normal file
1896
data/web/rc/program/steps/mail/compose.inc
Normal file
File diff suppressed because it is too large
Load Diff
62
data/web/rc/program/steps/mail/copy.inc
Normal file
62
data/web/rc/program/steps/mail/copy.inc
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
+-----------------------------------------------------------------------+
|
||||
| program/steps/mail/copy.inc |
|
||||
| |
|
||||
| This file is part of the Roundcube Webmail client |
|
||||
| Copyright (C) 2005-2014, The Roundcube Dev Team |
|
||||
| |
|
||||
| Licensed under the GNU General Public License version 3 or |
|
||||
| any later version with exceptions for skins & plugins. |
|
||||
| See the README file for a full license statement. |
|
||||
| |
|
||||
| PURPOSE: |
|
||||
| Copy the submitted messages to a specific mailbox |
|
||||
| |
|
||||
+-----------------------------------------------------------------------+
|
||||
| Author: Aleksander Machniak <alec@alec.pl> |
|
||||
+-----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
// only process ajax requests
|
||||
if (!$OUTPUT->ajax_call) {
|
||||
return;
|
||||
}
|
||||
|
||||
// copy messages
|
||||
if (!empty($_POST['_uid']) && strlen($_POST['_target_mbox'])) {
|
||||
$target = rcube_utils::get_input_value('_target_mbox', rcube_utils::INPUT_POST, true);
|
||||
$sources = array();
|
||||
|
||||
foreach (rcmail::get_uids(null, null, $multifolder) as $mbox => $uids) {
|
||||
if ($mbox === $target) {
|
||||
$copied++;
|
||||
}
|
||||
else {
|
||||
$copied += (int)$RCMAIL->storage->copy_message($uids, $target, $mbox);
|
||||
$sources[] = $mbox;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$copied) {
|
||||
// send error message
|
||||
$RCMAIL->display_server_error('errorcopying');
|
||||
$OUTPUT->send();
|
||||
exit;
|
||||
}
|
||||
else {
|
||||
$OUTPUT->show_message('messagecopied', 'confirmation');
|
||||
}
|
||||
|
||||
rcmail_send_unread_count($target, true);
|
||||
|
||||
$OUTPUT->command('set_quota', $RCMAIL->quota_content(null, $multifolder ? $sources[0] : 'INBOX'));
|
||||
}
|
||||
// unknown action or missing query param
|
||||
else {
|
||||
$OUTPUT->show_message('internalerror', 'error');
|
||||
}
|
||||
|
||||
// send response
|
||||
$OUTPUT->send();
|
87
data/web/rc/program/steps/mail/folders.inc
Normal file
87
data/web/rc/program/steps/mail/folders.inc
Normal file
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
+-----------------------------------------------------------------------+
|
||||
| program/steps/mail/folders.inc |
|
||||
| |
|
||||
| This file is part of the Roundcube Webmail client |
|
||||
| Copyright (C) 2005-2013, The Roundcube Dev Team |
|
||||
| |
|
||||
| Licensed under the GNU General Public License version 3 or |
|
||||
| any later version with exceptions for skins & plugins. |
|
||||
| See the README file for a full license statement. |
|
||||
| |
|
||||
| PURPOSE: |
|
||||
| Implement folder operations line EXPUNGE and Clear |
|
||||
| |
|
||||
+-----------------------------------------------------------------------+
|
||||
| Author: Thomas Bruederli <roundcube@gmail.com> |
|
||||
+-----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
// only process ajax requests
|
||||
if (!$OUTPUT->ajax_call) {
|
||||
return;
|
||||
}
|
||||
|
||||
$mbox = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST, true);
|
||||
|
||||
// send EXPUNGE command
|
||||
if ($RCMAIL->action == 'expunge') {
|
||||
$success = $RCMAIL->storage->expunge_folder($mbox);
|
||||
|
||||
// reload message list if current mailbox
|
||||
if ($success) {
|
||||
$OUTPUT->show_message('folderexpunged', 'confirmation');
|
||||
|
||||
if (!empty($_REQUEST['_reload'])) {
|
||||
$OUTPUT->command('set_quota', $RCMAIL->quota_content(null, $mbox));
|
||||
$OUTPUT->command('message_list.clear');
|
||||
$RCMAIL->action = 'list';
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$RCMAIL->display_server_error();
|
||||
}
|
||||
}
|
||||
// clear mailbox
|
||||
else if ($RCMAIL->action == 'purge') {
|
||||
$delimiter = $RCMAIL->storage->get_hierarchy_delimiter();
|
||||
$trash_mbox = $RCMAIL->config->get('trash_mbox');
|
||||
$junk_mbox = $RCMAIL->config->get('junk_mbox');
|
||||
$trash_regexp = '/^' . preg_quote($trash_mbox . $delimiter, '/') . '/';
|
||||
$junk_regexp = '/^' . preg_quote($junk_mbox . $delimiter, '/') . '/';
|
||||
|
||||
// we should only be purging trash and junk (or their subfolders)
|
||||
if ($mbox == $trash_mbox || $mbox == $junk_mbox
|
||||
|| preg_match($trash_regexp, $mbox) || preg_match($junk_regexp, $mbox)
|
||||
) {
|
||||
$success = $RCMAIL->storage->clear_folder($mbox);
|
||||
|
||||
if ($success) {
|
||||
$OUTPUT->show_message('folderpurged', 'confirmation');
|
||||
|
||||
if (!empty($_REQUEST['_reload'])) {
|
||||
$OUTPUT->set_env('messagecount', 0);
|
||||
$OUTPUT->set_env('pagecount', 0);
|
||||
$OUTPUT->set_env('exists', 0);
|
||||
$OUTPUT->command('message_list.clear');
|
||||
$OUTPUT->command('set_rowcount', rcmail_get_messagecount_text(), $mbox);
|
||||
$OUTPUT->command('set_unread_count', $mbox, 0);
|
||||
$OUTPUT->command('set_quota', $RCMAIL->quota_content(null, $mbox));
|
||||
rcmail_set_unseen_count($mbox, 0);
|
||||
|
||||
// set trash folder state
|
||||
if ($mbox === $trash_mbox) {
|
||||
$OUTPUT->command('set_trash_count', 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
$RCMAIL->display_server_error();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$OUTPUT->send();
|
2369
data/web/rc/program/steps/mail/func.inc
Normal file
2369
data/web/rc/program/steps/mail/func.inc
Normal file
File diff suppressed because it is too large
Load Diff
730
data/web/rc/program/steps/mail/get.inc
Normal file
730
data/web/rc/program/steps/mail/get.inc
Normal file
@@ -0,0 +1,730 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
+-----------------------------------------------------------------------+
|
||||
| program/steps/mail/get.inc |
|
||||
| |
|
||||
| This file is part of the Roundcube Webmail client |
|
||||
| Copyright (C) 2005-2016, The Roundcube Dev Team |
|
||||
| |
|
||||
| Licensed under the GNU General Public License version 3 or |
|
||||
| any later version with exceptions for skins & plugins. |
|
||||
| See the README file for a full license statement. |
|
||||
| |
|
||||
| PURPOSE: |
|
||||
| Delivering a specific uploaded file or mail message attachment |
|
||||
| |
|
||||
+-----------------------------------------------------------------------+
|
||||
| Author: Thomas Bruederli <roundcube@gmail.com> |
|
||||
| Author: Aleksander Machniak <alec@alec.pl> |
|
||||
+-----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
|
||||
// show loading page
|
||||
if (!empty($_GET['_preload'])) {
|
||||
unset($_GET['_preload']);
|
||||
unset($_GET['_safe']);
|
||||
|
||||
$url = $RCMAIL->url($_GET + array('_mimewarning' => 1, '_embed' => 1));
|
||||
$message = $RCMAIL->gettext('loadingdata');
|
||||
|
||||
header('Content-Type: text/html; charset=' . RCUBE_CHARSET);
|
||||
print "<html>\n<head>\n"
|
||||
. '<meta http-equiv="refresh" content="0; url='.rcube::Q($url).'">' . "\n"
|
||||
. '<meta http-equiv="content-type" content="text/html; charset='.RCUBE_CHARSET.'">' . "\n"
|
||||
. "</head>\n<body>\n$message\n</body>\n</html>";
|
||||
exit;
|
||||
}
|
||||
|
||||
$attachment = new rcmail_attachment_handler;
|
||||
$mimetype = $attachment->mimetype;
|
||||
$filename = $attachment->filename;
|
||||
|
||||
// show part page
|
||||
if (!empty($_GET['_frame'])) {
|
||||
$OUTPUT->set_pagetitle($filename);
|
||||
|
||||
// register UI objects
|
||||
$OUTPUT->add_handlers(array(
|
||||
'messagepartframe' => 'rcmail_message_part_frame',
|
||||
'messagepartcontrols' => 'rcmail_message_part_controls',
|
||||
));
|
||||
|
||||
$part_id = rcube_utils::get_input_value('_part', rcube_utils::INPUT_GET);
|
||||
$uid = rcube_utils::get_input_value('_uid', rcube_utils::INPUT_GET);
|
||||
|
||||
// message/rfc822 preview (Note: handle also multipart/ parts, they can
|
||||
// come from Enigma, which replaces message/rfc822 with real mimetype)
|
||||
if ($part_id && ($mimetype == 'message/rfc822' || strpos($mimetype, 'multipart/') === 0)) {
|
||||
$uid = preg_replace('/\.[0-9.]+/', '', $uid);
|
||||
$uid .= '.' . $part_id;
|
||||
|
||||
$OUTPUT->set_env('is_message', true);
|
||||
}
|
||||
|
||||
$OUTPUT->set_env('mailbox', $RCMAIL->storage->get_folder());
|
||||
$OUTPUT->set_env('uid', $uid);
|
||||
$OUTPUT->set_env('part', $part_id);
|
||||
$OUTPUT->set_env('filename', $filename);
|
||||
$OUTPUT->set_env('mimetype', $mimetype);
|
||||
|
||||
$OUTPUT->send('messagepart');
|
||||
exit;
|
||||
}
|
||||
|
||||
// render thumbnail of an image attachment
|
||||
if (!empty($_GET['_thumb']) && $attachment->is_valid()) {
|
||||
$thumbnail_size = $RCMAIL->config->get('image_thumbnail_size', 240);
|
||||
$temp_dir = $RCMAIL->config->get('temp_dir');
|
||||
$file_ident = $attachment->ident;
|
||||
$cache_basename = $temp_dir . '/' . md5($file_ident . ':' . $RCMAIL->user->ID . ':' . $thumbnail_size);
|
||||
$cache_file = $cache_basename . '.thumb';
|
||||
|
||||
// render thumbnail image if not done yet
|
||||
if (!is_file($cache_file) && $attachment->body_to_file($orig_name = $cache_basename . '.tmp')) {
|
||||
$image = new rcube_image($orig_name);
|
||||
|
||||
if ($imgtype = $image->resize($thumbnail_size, $cache_file, true)) {
|
||||
$mimetype = 'image/' . $imgtype;
|
||||
unlink($orig_name);
|
||||
}
|
||||
else {
|
||||
// Resize failed, we need to check the file mimetype
|
||||
// So, we do not exit here, but goto generic file body handler below
|
||||
$_GET['_thumb'] = 0;
|
||||
$_REQUEST['_embed'] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($_GET['_thumb'])) {
|
||||
if (is_file($cache_file)) {
|
||||
$RCMAIL->output->future_expire_header(3600);
|
||||
header('Content-Type: ' . $mimetype);
|
||||
header('Content-Length: ' . filesize($cache_file));
|
||||
readfile($cache_file);
|
||||
}
|
||||
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle attachment body (display or download)
|
||||
if (empty($_GET['_thumb']) && $attachment->is_valid()) {
|
||||
// require CSRF protected url for downloads
|
||||
if (!empty($_GET['_download'])) {
|
||||
$RCMAIL->request_security_check(rcube_utils::INPUT_GET);
|
||||
}
|
||||
|
||||
$extensions = rcube_mime::get_mime_extensions($mimetype);
|
||||
|
||||
// compare file mimetype with the stated content-type headers and file extension to avoid malicious operations
|
||||
if (!empty($_REQUEST['_embed']) && empty($_REQUEST['_nocheck'])) {
|
||||
$file_extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
|
||||
|
||||
// 1. compare filename suffix with expected suffix derived from mimetype
|
||||
$valid = $file_extension && in_array($file_extension, (array)$extensions) || empty($extensions) || !empty($_REQUEST['_mimeclass']);
|
||||
|
||||
// 2. detect the real mimetype of the attachment part and compare it with the stated mimetype and filename extension
|
||||
if ($valid || !$file_extension || $mimetype == 'application/octet-stream' || stripos($mimetype, 'text/') === 0) {
|
||||
$tmp_body = $attachment->body(2048);
|
||||
|
||||
// detect message part mimetype
|
||||
$real_mimetype = rcube_mime::file_content_type($tmp_body, $filename, $mimetype, true, true);
|
||||
list($real_ctype_primary, $real_ctype_secondary) = explode('/', $real_mimetype);
|
||||
|
||||
// accept text/plain with any extension
|
||||
if ($real_mimetype == 'text/plain' && $real_mimetype == $mimetype) {
|
||||
$valid_extension = true;
|
||||
}
|
||||
// ignore differences in text/* mimetypes. Filetype detection isn't very reliable here
|
||||
else if ($real_ctype_primary == 'text' && strpos($mimetype, $real_ctype_primary) === 0) {
|
||||
$real_mimetype = $mimetype;
|
||||
$valid_extension = true;
|
||||
}
|
||||
// ignore filename extension if mimeclass matches (#1489029)
|
||||
else if (!empty($_REQUEST['_mimeclass']) && $real_ctype_primary == $_REQUEST['_mimeclass']) {
|
||||
$valid_extension = true;
|
||||
}
|
||||
else {
|
||||
// get valid file extensions
|
||||
$extensions = rcube_mime::get_mime_extensions($real_mimetype);
|
||||
$valid_extension = !$file_extension || empty($extensions) || in_array($file_extension, (array)$extensions);
|
||||
}
|
||||
|
||||
// fix mimetype for images wrongly declared as octet-stream
|
||||
if ($mimetype == 'application/octet-stream' && strpos($real_mimetype, 'image/') === 0 && $valid_extension) {
|
||||
$mimetype = $real_mimetype;
|
||||
}
|
||||
// fix mimetype for images with wrong mimetype
|
||||
else if (strpos($real_mimetype, 'image/') === 0 && strpos($mimetype, 'image/') === 0) {
|
||||
$mimetype = $real_mimetype;
|
||||
}
|
||||
|
||||
// "fix" real mimetype the same way the original is before comparison
|
||||
$real_mimetype = rcmail_fix_mimetype($real_mimetype);
|
||||
|
||||
$valid = $real_mimetype == $mimetype && $valid_extension;
|
||||
}
|
||||
else {
|
||||
$real_mimetype = $mimetype;
|
||||
}
|
||||
|
||||
// show warning if validity checks failed
|
||||
if (!$valid) {
|
||||
// send blocked.gif for expected images
|
||||
if (empty($_REQUEST['_mimewarning']) && strpos($mimetype, 'image/') === 0) {
|
||||
// Do not cache. Failure might be the result of a misconfiguration, thus real content should be returned once fixed.
|
||||
$content = $RCMAIL->get_resource_content('blocked.gif');
|
||||
$OUTPUT->nocacheing_headers();
|
||||
header("Content-Type: image/gif");
|
||||
header("Content-Transfer-Encoding: binary");
|
||||
header("Content-Length: " . strlen($content));
|
||||
echo $content;
|
||||
}
|
||||
else { // html warning with a button to load the file anyway
|
||||
$OUTPUT = new rcmail_html_page();
|
||||
$OUTPUT->write(html::tag('html', null, html::tag('body', 'embed',
|
||||
html::div(array('class' => 'rcmail-inline-message rcmail-inline-warning'),
|
||||
$RCMAIL->gettext(array(
|
||||
'name' => 'attachmentvalidationerror',
|
||||
'vars' => array(
|
||||
'expected' => $mimetype . ($file_extension ? " (.$file_extension)" : ''),
|
||||
'detected' => $real_mimetype . ($extensions[0] ? " (.$extensions[0])" : ''),
|
||||
)
|
||||
))
|
||||
. html::p(array('class' => 'rcmail-inline-buttons'),
|
||||
html::tag('button', array(
|
||||
'onclick' => "location.href='" . $RCMAIL->url(array_merge($_GET, array('_nocheck' => 1))) . "'"
|
||||
),
|
||||
$RCMAIL->gettext('showanyway'))
|
||||
)
|
||||
))));
|
||||
}
|
||||
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
// TIFF/WEBP to JPEG conversion, if needed
|
||||
foreach (array('tiff', 'webp') as $type) {
|
||||
$img_support = !empty($_SESSION['browser_caps']) && !empty($_SESSION['browser_caps'][$type]);
|
||||
if (!empty($_REQUEST['_embed']) && !$img_support
|
||||
&& $attachment->image_type() == 'image/' . $type
|
||||
&& rcube_image::is_convertable('image/' . $type)
|
||||
) {
|
||||
$convert2jpeg = true;
|
||||
$mimetype = 'image/jpeg';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$browser = $RCMAIL->output->browser;
|
||||
list($ctype_primary, $ctype_secondary) = explode('/', $mimetype);
|
||||
|
||||
if (!empty($_GET['_download']) && $ctype_primary == 'text') {
|
||||
header("Content-Type: text/$ctype_secondary; charset=" . $attachment->charset);
|
||||
}
|
||||
else {
|
||||
header("Content-Type: $mimetype");
|
||||
header("Content-Transfer-Encoding: binary");
|
||||
}
|
||||
|
||||
// deliver part content
|
||||
if ($mimetype == 'text/html' && empty($_GET['_download'])) {
|
||||
// Check if we have enough memory to handle the message in it
|
||||
// #1487424: we need up to 10x more memory than the body
|
||||
if (!rcube_utils::mem_check($attachment->size * 10)) {
|
||||
$out = '<html><body>'
|
||||
. $RCMAIL->gettext('messagetoobig'). ' '
|
||||
. html::a($RCMAIL->url(array_merge($_GET, array('download' => 1))), $RCMAIL->gettext('download'))
|
||||
. '</body></html>';
|
||||
}
|
||||
else {
|
||||
// render HTML body
|
||||
$out = $attachment->html();
|
||||
|
||||
// insert remote objects warning into HTML body
|
||||
if ($REMOTE_OBJECTS) {
|
||||
$body_start = 0;
|
||||
if ($body_pos = strpos($out, '<body')) {
|
||||
$body_start = strpos($out, '>', $body_pos) + 1;
|
||||
}
|
||||
|
||||
$out = substr($out, 0, $body_start)
|
||||
. html::div(array('class' => 'rcmail-inline-message rcmail-inline-warning'),
|
||||
rcube::Q($RCMAIL->gettext('blockedimages')) . ' ' .
|
||||
html::tag('button',
|
||||
array('onclick' => "location.href='" . $RCMAIL->url(array_merge($_GET, array('_safe' => 1))) . "'"),
|
||||
rcube::Q($RCMAIL->gettext('showimages')))
|
||||
)
|
||||
. substr($out, $body_start);
|
||||
}
|
||||
}
|
||||
|
||||
$OUTPUT = new rcmail_html_page();
|
||||
$OUTPUT->write($out);
|
||||
exit;
|
||||
}
|
||||
|
||||
// don't kill the connection if download takes some more time
|
||||
@set_time_limit(3600);
|
||||
|
||||
$filename = $browser->ie ? rawurlencode($filename) : addcslashes($filename, '"');
|
||||
$disposition = !empty($_GET['_download']) ? 'attachment' : 'inline';
|
||||
|
||||
// add filename extension if missing
|
||||
if (!pathinfo($filename, PATHINFO_EXTENSION) && ($extensions = rcube_mime::get_mime_extensions($mimetype))) {
|
||||
$filename .= '.' . $extensions[0];
|
||||
}
|
||||
|
||||
header("Content-Disposition: $disposition; filename=\"$filename\"");
|
||||
|
||||
// handle tiff to jpeg conversion
|
||||
if (!empty($convert2jpeg)) {
|
||||
$temp_dir = unslashify($RCMAIL->config->get('temp_dir'));
|
||||
$file_path = tempnam($temp_dir, 'rcmAttmnt');
|
||||
|
||||
// convert image to jpeg and send it to the browser
|
||||
if ($attachment->body_to_file($file_path)) {
|
||||
$image = new rcube_image($file_path);
|
||||
if ($image->convert(rcube_image::TYPE_JPG, $file_path)) {
|
||||
header("Content-Length: " . filesize($file_path));
|
||||
readfile($file_path);
|
||||
}
|
||||
unlink($file_path);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$attachment->output($mimetype);
|
||||
}
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
// if we arrive here, the requested part was not found
|
||||
header('HTTP/1.1 404 Not Found');
|
||||
exit;
|
||||
|
||||
|
||||
/**
|
||||
* Attachment properties table
|
||||
*/
|
||||
function rcmail_message_part_controls($attrib)
|
||||
{
|
||||
global $attachment, $RCMAIL;
|
||||
|
||||
if (!$attachment->is_valid()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$table = new html_table(array('cols' => 2));
|
||||
|
||||
$table->add('title', rcube::Q($RCMAIL->gettext('namex')).':');
|
||||
$table->add('header', rcube::Q($attachment->filename));
|
||||
|
||||
$table->add('title', rcube::Q($RCMAIL->gettext('type')).':');
|
||||
$table->add('header', rcube::Q($attachment->mimetype));
|
||||
|
||||
$table->add('title', rcube::Q($RCMAIL->gettext('size')).':');
|
||||
$table->add('header', rcube::Q($attachment->size()));
|
||||
|
||||
return $table->show($attrib);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attachment preview frame
|
||||
*/
|
||||
function rcmail_message_part_frame($attrib)
|
||||
{
|
||||
global $RCMAIL;
|
||||
|
||||
if ($RCMAIL->output->get_env('is_message')) {
|
||||
$attrib['src'] = $RCMAIL->url(array(
|
||||
'task' => 'mail',
|
||||
'action' => 'preview',
|
||||
'uid' => $RCMAIL->output->get_env('uid'),
|
||||
'mbox' => $RCMAIL->output->get_env('mailbox'),
|
||||
'framed' => 1,
|
||||
));
|
||||
}
|
||||
else {
|
||||
$mimetype = $RCMAIL->output->get_env('mimetype');
|
||||
$frame_replace = strpos($mimetype, 'text/') === 0 ? '_embed=' : '_preload=';
|
||||
$attrib['src'] = './?' . str_replace('_frame=', $frame_replace, $_SERVER['QUERY_STRING']);
|
||||
}
|
||||
|
||||
$RCMAIL->output->add_gui_object('messagepartframe', $attrib['id']);
|
||||
|
||||
return html::iframe($attrib);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper class with unified access to attachment properties and body
|
||||
*
|
||||
* Unified for message parts as well as uploaded attachments
|
||||
*/
|
||||
class rcmail_attachment_handler
|
||||
{
|
||||
public $filename;
|
||||
public $size;
|
||||
public $mimetype;
|
||||
public $ident;
|
||||
public $charset = RCUBE_CHARSET;
|
||||
|
||||
private $message;
|
||||
private $part;
|
||||
private $upload;
|
||||
private $body;
|
||||
private $body_file;
|
||||
private $download = false;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
* Reads request parameters and initializes attachment/part props.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
ob_end_clean();
|
||||
|
||||
$part_id = rcube_utils::get_input_value('_part', rcube_utils::INPUT_GET);
|
||||
$file_id = rcube_utils::get_input_value('_file', rcube_utils::INPUT_GET);
|
||||
$compose_id = rcube_utils::get_input_value('_id', rcube_utils::INPUT_GET);
|
||||
$uid = rcube_utils::get_input_value('_uid', rcube_utils::INPUT_GET);
|
||||
$rcube = rcube::get_instance();
|
||||
|
||||
$this->download = !empty($_GET['_download']);
|
||||
|
||||
// similar code as in program/steps/mail/show.inc
|
||||
if (!empty($uid)) {
|
||||
$rcube->config->set('prefer_html', true);
|
||||
$this->message = new rcube_message($uid, null, intval($_GET['_safe']));
|
||||
|
||||
if ($this->part = $this->message->mime_parts[$part_id]) {
|
||||
$this->filename = rcmail_attachment_name($this->part);
|
||||
$this->mimetype = $this->part->mimetype;
|
||||
$this->size = $this->part->size;
|
||||
$this->ident = $this->message->headers->messageID . ':' . $this->part->mime_id . ':' . $this->size . ':' . $this->mimetype;
|
||||
$this->charset = $this->part->charset ?: RCUBE_CHARSET;
|
||||
|
||||
if (empty($_GET['_frame'])) {
|
||||
// allow post-processing of the attachment body
|
||||
$plugin = $rcube->plugins->exec_hook('message_part_get', array(
|
||||
'uid' => $uid,
|
||||
'id' => $this->part->mime_id,
|
||||
'mimetype' => $this->mimetype,
|
||||
'part' => $this->part,
|
||||
'download' => $this->download,
|
||||
));
|
||||
|
||||
if ($plugin['abort']) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// overwrite modified vars from plugin
|
||||
$this->mimetype = $plugin['mimetype'];
|
||||
|
||||
if ($plugin['body']) {
|
||||
$this->body = $plugin['body'];
|
||||
$this->size = strlen($this->body);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ($file_id && $compose_id) {
|
||||
$file_id = preg_replace('/^rcmfile/', '', $file_id);
|
||||
|
||||
if (($compose = $_SESSION['compose_data_' . $compose_id])
|
||||
&& ($this->upload = $compose['attachments'][$file_id])
|
||||
) {
|
||||
$this->filename = $this->upload['name'];
|
||||
$this->mimetype = $this->upload['mimetype'];
|
||||
$this->size = $this->upload['size'];
|
||||
$this->ident = sprintf('%s:%s%s', $compose_id, $file_id, $this->size);
|
||||
$this->charset = $this->upload['charset'] ?: RCUBE_CHARSET;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($this->part) && empty($this->upload)) {
|
||||
header('HTTP/1.1 404 Not Found');
|
||||
exit;
|
||||
}
|
||||
|
||||
// check connection status
|
||||
self::check_storage_status();
|
||||
|
||||
$this->mimetype = rcmail_fix_mimetype($this->mimetype);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove temp files, etc.
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
if ($this->body_file) {
|
||||
@unlink($this->body_file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the object is a message part not uploaded file
|
||||
*
|
||||
* @return bool True if the object is a meesage part
|
||||
*/
|
||||
public function is_message_part()
|
||||
{
|
||||
return !empty($this->message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Object/request status
|
||||
*
|
||||
* @return bool Status
|
||||
*/
|
||||
public function is_valid()
|
||||
{
|
||||
return !empty($this->part) || !empty($this->upload);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return attachment/part mimetype if this is an image
|
||||
* of supported type.
|
||||
*
|
||||
* @return string Image mimetype
|
||||
*/
|
||||
public function image_type()
|
||||
{
|
||||
$part = (object) array(
|
||||
'filename' => $this->filename,
|
||||
'mimetype' => $this->mimetype,
|
||||
);
|
||||
|
||||
return rcmail_part_image_type($part);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formatted attachment/part size (with units)
|
||||
*
|
||||
* @return string Attachment/part size (with units)
|
||||
*/
|
||||
public function size()
|
||||
{
|
||||
$part = $this->part ?: ((object) array('size' => $this->size, 'exact_size' => true));
|
||||
return rcube::get_instance()->message_part_size($part);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns, prints or saves the attachment/part body
|
||||
*/
|
||||
public function body($size = null, $fp = null)
|
||||
{
|
||||
// we may have the body in memory or file already
|
||||
if ($this->body !== null) {
|
||||
if ($fp == -1) {
|
||||
echo $size ? substr($this->body, 0, $size) : $this->body;
|
||||
}
|
||||
else if ($fp) {
|
||||
$result = fwrite($fp, $size ? substr($this->body, $size) : $this->body) !== false;
|
||||
}
|
||||
else {
|
||||
$result = $size ? substr($this->body, 0, $size) : $this->body;
|
||||
}
|
||||
}
|
||||
else if ($this->body_file) {
|
||||
if ($size) {
|
||||
$result = file_get_contents($this->body_file, false, null, 0, $size);
|
||||
}
|
||||
else {
|
||||
$result = file_get_contents($this->body_file);
|
||||
}
|
||||
|
||||
if ($fp == -1) {
|
||||
echo $result;
|
||||
}
|
||||
else if ($fp) {
|
||||
$result = fwrite($fp, $result) !== false;
|
||||
}
|
||||
}
|
||||
else if ($this->message) {
|
||||
$result = $this->message->get_part_body($this->part->mime_id, false, 0, $fp);
|
||||
|
||||
// check connection status
|
||||
if (!$fp && $this->size && empty($result)) {
|
||||
self::check_storage_status();
|
||||
}
|
||||
}
|
||||
else if ($this->upload) {
|
||||
// This hook retrieves the attachment contents from the file storage backend
|
||||
$attachment = rcube::get_instance()->plugins->exec_hook('attachment_get', $this->upload);
|
||||
|
||||
if ($fp && $fp != -1) {
|
||||
if ($attachment['data']) {
|
||||
$result = fwrite($fp, $size ? substr($attachment['data'], 0, $size) : $attachment['data']) !== false;
|
||||
}
|
||||
else if ($attachment['path']) {
|
||||
if ($fh = fopen($attachment['path'], 'rb')) {
|
||||
$result = stream_copy_to_stream($fh, $fp, $size ? $size : -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
$data = $attachment['data'];
|
||||
if (!$data && $attachment['path']) {
|
||||
$data = file_get_contents($attachment['path']);
|
||||
}
|
||||
|
||||
if ($fp == -1) {
|
||||
echo $size ? substr($data, 0, $size) : $data;
|
||||
}
|
||||
else {
|
||||
$result = $size ? substr($data, 0, $size) : $data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the body to a file
|
||||
*
|
||||
* @param string $filename File name with path
|
||||
*
|
||||
* @return bool True on success, False on failure
|
||||
*/
|
||||
public function body_to_file($filename)
|
||||
{
|
||||
if ($filename && $this->size && ($fp = fopen($filename, 'w'))) {
|
||||
$this->body(0, $fp);
|
||||
$this->body_file = $filename;
|
||||
fclose($fp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Output attachment body with content filtering
|
||||
*/
|
||||
public function output($mimetype)
|
||||
{
|
||||
if (!$this->size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$secure = stripos($mimetype, 'image/') === false || $this->download;
|
||||
|
||||
// Remove <script> in SVG images
|
||||
if (!$secure && stripos($mimetype, 'image/svg') === 0) {
|
||||
if (!$this->body) {
|
||||
$this->body = $this->body();
|
||||
if (empty($this->body)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
echo self::svg_filter($this->body);
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->body !== null && !$this->download) {
|
||||
header("Content-Length: " . strlen($this->body));
|
||||
echo $this->body;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Don't be tempted to set Content-Length to $part->d_parameters['size'] (#1490482)
|
||||
// RFC2183 says "The size parameter indicates an approximate size"
|
||||
|
||||
return $this->body(0, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns formatted HTML if the attachment is HTML
|
||||
*/
|
||||
public function html()
|
||||
{
|
||||
list($type, $subtype) = explode($this->mimetype, '/');
|
||||
$part = (object) array(
|
||||
'charset' => $this->charset,
|
||||
'ctype_secondary' => $subtype,
|
||||
);
|
||||
|
||||
// get part body if not available
|
||||
// fix formatting and charset
|
||||
$body = rcube_message::format_part_body($this->body(), $part);
|
||||
|
||||
// show images?
|
||||
$is_safe = $this->is_safe();
|
||||
|
||||
return rcmail_wash_html($body, array('safe' => $is_safe, 'inline_html' => false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove <script> in SVG images
|
||||
*/
|
||||
public static function svg_filter($body)
|
||||
{
|
||||
// clean SVG with washtml
|
||||
$wash_opts = array(
|
||||
'show_washed' => false,
|
||||
'allow_remote' => false,
|
||||
'charset' => RCUBE_CHARSET,
|
||||
'html_elements' => array('title'),
|
||||
// 'blocked_src' => 'program/resources/blocked.gif',
|
||||
);
|
||||
|
||||
// initialize HTML washer
|
||||
$washer = new rcube_washtml($wash_opts);
|
||||
|
||||
// allow CSS styles, will be sanitized by rcmail_washtml_callback()
|
||||
$washer->add_callback('style', 'rcmail_washtml_callback');
|
||||
|
||||
return $washer->wash($body);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles nicely storage connection errors
|
||||
*/
|
||||
public static function check_storage_status()
|
||||
{
|
||||
$error = rcmail::get_instance()->storage->get_error_code();
|
||||
|
||||
// Check if we have a connection error
|
||||
if ($error == rcube_imap_generic::ERROR_BAD) {
|
||||
ob_end_clean();
|
||||
|
||||
// Get action is often executed simultanously.
|
||||
// Some servers have MAXPERIP or other limits.
|
||||
// To workaround this we'll wait for some time
|
||||
// and try again (once).
|
||||
// Note: Random sleep interval is used to minimize concurency
|
||||
// in getting message parts
|
||||
|
||||
if (!isset($_GET['_redirected'])) {
|
||||
usleep(rand(10,30)*100000); // 1-3 sec.
|
||||
header('Location: ' . $_SERVER['REQUEST_URI'] . '&_redirected=1');
|
||||
}
|
||||
else {
|
||||
rcube::raise_error(array(
|
||||
'code' => 500, 'file' => __FILE__, 'line' => __LINE__,
|
||||
'message' => 'Unable to get/display message part. IMAP connection error'),
|
||||
true, true);
|
||||
}
|
||||
|
||||
// Don't kill session, just quit (#1486995)
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
public function is_safe()
|
||||
{
|
||||
if ($this->message) {
|
||||
return rcmail_check_safe($this->message);
|
||||
}
|
||||
|
||||
return !empty($_GET['_safe']);
|
||||
}
|
||||
}
|
56
data/web/rc/program/steps/mail/getunread.inc
Normal file
56
data/web/rc/program/steps/mail/getunread.inc
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
+-----------------------------------------------------------------------+
|
||||
| program/steps/mail/getunread.inc |
|
||||
| |
|
||||
| This file is part of the Roundcube Webmail client |
|
||||
| Copyright (C) 2005-2013, The Roundcube Dev Team |
|
||||
| |
|
||||
| Licensed under the GNU General Public License version 3 or |
|
||||
| any later version with exceptions for skins & plugins. |
|
||||
| See the README file for a full license statement. |
|
||||
| |
|
||||
| PURPOSE: |
|
||||
| Check all mailboxes for unread messages and update GUI |
|
||||
| |
|
||||
+-----------------------------------------------------------------------+
|
||||
| Author: Thomas Bruederli <roundcube@gmail.com> |
|
||||
+-----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
$a_folders = $RCMAIL->storage->list_folders_subscribed('', '*', 'mail');
|
||||
|
||||
if (!empty($a_folders)) {
|
||||
$current = $RCMAIL->storage->get_folder();
|
||||
$inbox = ($current == 'INBOX');
|
||||
$trash = $RCMAIL->config->get('trash_mbox');
|
||||
$check_all = (bool)$RCMAIL->config->get('check_all_folders');
|
||||
|
||||
foreach ($a_folders as $mbox) {
|
||||
$unseen_old = rcmail_get_unseen_count($mbox);
|
||||
|
||||
if (!$check_all && $unseen_old !== null && $mbox != $current) {
|
||||
$unseen = $unseen_old;
|
||||
}
|
||||
else {
|
||||
$unseen = $RCMAIL->storage->count($mbox, 'UNSEEN', $unseen_old === null);
|
||||
}
|
||||
|
||||
// call it always for current folder, so it can update counter
|
||||
// after possible message status change when opening a message
|
||||
// not in preview frame
|
||||
if ($unseen || $unseen_old === null || $mbox == $current) {
|
||||
$OUTPUT->command('set_unread_count', $mbox, $unseen, $inbox && $mbox_row == 'INBOX');
|
||||
}
|
||||
|
||||
rcmail_set_unseen_count($mbox, $unseen);
|
||||
|
||||
// set trash folder state
|
||||
if ($mbox === $trash) {
|
||||
$OUTPUT->command('set_trash_count', $RCMAIL->storage->count($mbox, 'EXISTS'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$OUTPUT->send();
|
56
data/web/rc/program/steps/mail/headers.inc
Normal file
56
data/web/rc/program/steps/mail/headers.inc
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
+-----------------------------------------------------------------------+
|
||||
| program/steps/mail/headers.inc |
|
||||
| |
|
||||
| This file is part of the Roundcube Webmail client |
|
||||
| Copyright (C) 2005-2016, The Roundcube Dev Team |
|
||||
| |
|
||||
| Licensed under the GNU General Public License version 3 or |
|
||||
| any later version with exceptions for skins & plugins. |
|
||||
| See the README file for a full license statement. |
|
||||
| |
|
||||
| PURPOSE: |
|
||||
| Fetch message headers in raw format for display |
|
||||
| |
|
||||
+-----------------------------------------------------------------------+
|
||||
| Author: Aleksander Machniak <alec@alec.pl> |
|
||||
+-----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
if ($uid = rcube_utils::get_input_value('_uid', rcube_utils::INPUT_POST)) {
|
||||
if ($pos = strpos($uid, '.')) {
|
||||
$message = new rcube_message($uid);
|
||||
$source = $message->get_part_body(substr($uid, $pos + 1));
|
||||
$source = substr($source, 0, strpos($source, "\r\n\r\n"));
|
||||
}
|
||||
else {
|
||||
$source = $RCMAIL->storage->get_raw_headers($uid);
|
||||
}
|
||||
|
||||
if ($source !== false) {
|
||||
$source = trim(rcube_charset::clean($source));
|
||||
$source = htmlspecialchars($source);
|
||||
$source = preg_replace(
|
||||
array(
|
||||
'/\n[\t\s]+/',
|
||||
'/^([a-z0-9_:-]+)/im',
|
||||
'/\r?\n/'
|
||||
),
|
||||
array(
|
||||
"\n ",
|
||||
'<font class="bold">\1</font>',
|
||||
'<br />'
|
||||
), $source);
|
||||
|
||||
$OUTPUT->command('set_headers', $source);
|
||||
}
|
||||
else {
|
||||
$RCMAIL->output->show_message('messageopenerror', 'error');
|
||||
}
|
||||
|
||||
$OUTPUT->send();
|
||||
}
|
||||
|
||||
exit;
|
197
data/web/rc/program/steps/mail/import.inc
Normal file
197
data/web/rc/program/steps/mail/import.inc
Normal file
@@ -0,0 +1,197 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
+-----------------------------------------------------------------------+
|
||||
| program/steps/mail/import.inc |
|
||||
| |
|
||||
| This file is part of the Roundcube Webmail client |
|
||||
| Copyright (C) 2005-2014, The Roundcube Dev Team |
|
||||
| |
|
||||
| Licensed under the GNU General Public License version 3 or |
|
||||
| any later version with exceptions for skins & plugins. |
|
||||
| See the README file for a full license statement. |
|
||||
| |
|
||||
| PURPOSE: |
|
||||
| Save the uploaded file(s) as messages to the current IMAP folder |
|
||||
| |
|
||||
+-----------------------------------------------------------------------+
|
||||
| Author: Thomas Bruederli <roundcube@gmail.com> |
|
||||
| Author: Aleksander Machniak <alec@alec.pl> |
|
||||
+-----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
// clear all stored output properties (like scripts and env vars)
|
||||
$OUTPUT->reset();
|
||||
|
||||
if (is_array($_FILES['_file'])) {
|
||||
$imported = 0;
|
||||
$folder = $RCMAIL->storage->get_folder();
|
||||
|
||||
foreach ((array)$_FILES['_file']['tmp_name'] as $i => $filepath) {
|
||||
// Process uploaded file if there is no error
|
||||
$err = $_FILES['_file']['error'][$i];
|
||||
|
||||
if (!$err) {
|
||||
// check file content type first
|
||||
$ctype = rcube_mime::file_content_type($filepath, $_FILES['_file']['name'][$i], $_FILES['_file']['type'][$i]);
|
||||
list($mtype_primary, $mtype_secondary) = explode('/', $ctype);
|
||||
|
||||
if (in_array($ctype, array('application/zip', 'application/x-zip'))) {
|
||||
$filepath = rcmail_zip_extract($filepath);
|
||||
if (empty($filepath)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (!in_array($mtype_primary, array('text', 'message'))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ((array) $filepath as $file) {
|
||||
// read the first few lines to detect header-like structure
|
||||
$fp = fopen($file, 'r');
|
||||
do {
|
||||
$line = fgets($fp);
|
||||
}
|
||||
while ($line !== false && trim($line) == '');
|
||||
|
||||
if (!preg_match('/^From .+/', $line) && !preg_match('/^[a-z-_]+:\s+.+/i', $line)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$message = $lastline = '';
|
||||
fseek($fp, 0);
|
||||
|
||||
while (($line = fgets($fp)) !== false) {
|
||||
// importing mbox file, split by From - lines
|
||||
if ($lastline === '' && strncmp($line, 'From ', 5) === 0 && strlen($line) > 5) {
|
||||
if (!empty($message)) {
|
||||
$imported += (int) rcmail_save_message($folder, $message);
|
||||
}
|
||||
|
||||
$message = $line;
|
||||
$lastline = '';
|
||||
continue;
|
||||
}
|
||||
|
||||
$message .= $line;
|
||||
$lastline = rtrim($line);
|
||||
}
|
||||
|
||||
if (!empty($message)) {
|
||||
$imported += (int) rcmail_save_message($folder, $message);
|
||||
}
|
||||
|
||||
// remove temp files extracted from zip
|
||||
if (is_array($filepath)) {
|
||||
unlink($file);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ($err == UPLOAD_ERR_INI_SIZE || $err == UPLOAD_ERR_FORM_SIZE) {
|
||||
$size = $RCMAIL->show_bytes(rcube_utils::max_upload_size());
|
||||
$msg = $RCMAIL->gettext(array('name' => 'filesizeerror', 'vars' => array('size' => $size)));
|
||||
|
||||
$OUTPUT->command('display_message', $msg, 'error');
|
||||
}
|
||||
else if ($err) {
|
||||
$OUTPUT->show_message('fileuploaderror', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
if ($imported) {
|
||||
$OUTPUT->show_message($RCMAIL->gettext(array('name' => 'importmessagesuccess', 'nr' => $imported, 'vars' => array('nr' => $imported))), 'confirmation');
|
||||
$OUTPUT->command('command', 'list');
|
||||
}
|
||||
else {
|
||||
$OUTPUT->show_message('importmessageerror', 'error');
|
||||
}
|
||||
}
|
||||
else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
// if filesize exceeds post_max_size then $_FILES array is empty,
|
||||
// show filesizeerror instead of fileuploaderror
|
||||
if ($maxsize = ini_get('post_max_size'))
|
||||
$msg = $RCMAIL->gettext(array('name' => 'filesizeerror', 'vars' => array('size' => $RCMAIL->show_bytes(parse_bytes($maxsize)))));
|
||||
else
|
||||
$msg = $RCMAIL->gettext('fileuploaderror');
|
||||
|
||||
$OUTPUT->command('display_message', $msg, 'error');
|
||||
}
|
||||
|
||||
// send html page with JS calls as response
|
||||
$OUTPUT->send('iframe');
|
||||
|
||||
|
||||
function rcmail_zip_extract($path)
|
||||
{
|
||||
if (!class_exists('ZipArchive', false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$rcmail = rcmail::get_instance();
|
||||
$temp_dir = $rcmail->config->get('temp_dir');
|
||||
$zip = new ZipArchive;
|
||||
$files = array();
|
||||
|
||||
if ($zip->open($path)) {
|
||||
for ($i = 0; $i < $zip->numFiles; $i++) {
|
||||
$entry = $zip->getNameIndex($i);
|
||||
$tmpfname = tempnam($temp_dir, 'zipimport');
|
||||
|
||||
if (copy("zip://$path#$entry", $tmpfname)) {
|
||||
$ctype = rcube_mime::file_content_type($tmpfname, $entry);
|
||||
list($mtype_primary, $mtype_secondary) = explode('/', $ctype);
|
||||
|
||||
if (in_array($mtype_primary, array('text', 'message'))) {
|
||||
$files[] = $tmpfname;
|
||||
}
|
||||
else {
|
||||
unlink($tmpfname);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$zip->close();
|
||||
}
|
||||
|
||||
return $files;
|
||||
}
|
||||
|
||||
function rcmail_save_message($folder, &$message)
|
||||
{
|
||||
if (strncmp($message, 'From ', 5) === 0) {
|
||||
// Extract the mbox from_line
|
||||
$pos = strpos($message, "\n");
|
||||
$from = substr($message, 0, $pos);
|
||||
$message = substr($message, $pos + 1);
|
||||
|
||||
// Read the received date, support only known date formats
|
||||
|
||||
// RFC4155: "Sat Jan 3 01:05:34 1996"
|
||||
$mboxdate_rx = '/^([a-z]{3} [a-z]{3} [0-9 ][0-9] [0-9]{2}:[0-9]{2}:[0-9]{2} [0-9]{4})/i';
|
||||
// Roundcube/Zipdownload: "12-Dec-2016 10:56:33 +0100"
|
||||
$imapdate_rx = '/^([0-9]{1,2}-[a-z]{3}-[0-9]{4} [0-9]{2}:[0-9]{2}:[0-9]{2} [0-9+-]{5})/i';
|
||||
|
||||
if (($pos = strpos($from, ' ', 6)) && ($dt_str = substr($from, $pos + 1))
|
||||
&& (preg_match($mboxdate_rx, $dt_str, $m) || preg_match($imapdate_rx, $dt_str, $m))
|
||||
) {
|
||||
try {
|
||||
$date = new DateTime($m[0], new DateTimeZone('UTC'));
|
||||
}
|
||||
catch (Exception $e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// unquote ">From " lines in message body
|
||||
$message = preg_replace('/\n>([>]*)From /', "\n\\1From ", $message);
|
||||
$message = rtrim($message);
|
||||
$rcmail = rcmail::get_instance();
|
||||
|
||||
if ($rcmail->storage->save_message($folder, $message, '', false, array(), $date)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
rcube::raise_error("Failed to import message to $folder", true, false);
|
||||
return false;
|
||||
}
|
147
data/web/rc/program/steps/mail/list.inc
Normal file
147
data/web/rc/program/steps/mail/list.inc
Normal file
@@ -0,0 +1,147 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
+-----------------------------------------------------------------------+
|
||||
| program/steps/mail/list.inc |
|
||||
| |
|
||||
| This file is part of the Roundcube Webmail client |
|
||||
| Copyright (C) 2005-2014, The Roundcube Dev Team |
|
||||
| |
|
||||
| Licensed under the GNU General Public License version 3 or |
|
||||
| any later version with exceptions for skins & plugins. |
|
||||
| See the README file for a full license statement. |
|
||||
| |
|
||||
| PURPOSE: |
|
||||
| Send message list to client (as remote response) |
|
||||
| |
|
||||
+-----------------------------------------------------------------------+
|
||||
| Author: Thomas Bruederli <roundcube@gmail.com> |
|
||||
+-----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
if (!$OUTPUT->ajax_call) {
|
||||
return;
|
||||
}
|
||||
|
||||
$save_arr = array();
|
||||
$dont_override = (array) $RCMAIL->config->get('dont_override');
|
||||
|
||||
// is there a sort type for this request?
|
||||
if ($sort = rcube_utils::get_input_value('_sort', rcube_utils::INPUT_GET)) {
|
||||
// yes, so set the sort vars
|
||||
list($sort_col, $sort_order) = explode('_', $sort);
|
||||
|
||||
// set session vars for sort (so next page and task switch know how to sort)
|
||||
if (!in_array('message_sort_col', $dont_override)) {
|
||||
$_SESSION['sort_col'] = $save_arr['message_sort_col'] = $sort_col;
|
||||
}
|
||||
if (!in_array('message_sort_order', $dont_override)) {
|
||||
$_SESSION['sort_order'] = $save_arr['message_sort_order'] = $sort_order;
|
||||
}
|
||||
}
|
||||
|
||||
// register layout change
|
||||
if ($layout = rcube_utils::get_input_value('_layout', rcube_utils::INPUT_GET)) {
|
||||
$OUTPUT->set_env('layout', $layout);
|
||||
$save_arr['layout'] = $layout;
|
||||
// force header replace on layout change
|
||||
$cols = $_SESSION['list_attrib']['columns'];
|
||||
}
|
||||
// is there a set of columns for this request?
|
||||
else if ($cols = rcube_utils::get_input_value('_cols', rcube_utils::INPUT_GET)) {
|
||||
$_SESSION['list_attrib']['columns'] = explode(',', $cols);
|
||||
if (!in_array('list_cols', $dont_override)) {
|
||||
$save_arr['list_cols'] = explode(',', $cols);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($save_arr)) {
|
||||
$RCMAIL->user->save_prefs($save_arr);
|
||||
}
|
||||
|
||||
$mbox_name = $RCMAIL->storage->get_folder();
|
||||
$threading = (bool) $RCMAIL->storage->get_threading();
|
||||
|
||||
// Synchronize mailbox cache, handle flag changes
|
||||
$RCMAIL->storage->folder_sync($mbox_name);
|
||||
|
||||
// fetch message headers
|
||||
if ($count = $RCMAIL->storage->count($mbox_name, $threading ? 'THREADS' : 'ALL', !empty($_REQUEST['_refresh']))) {
|
||||
$a_headers = $RCMAIL->storage->list_messages($mbox_name, NULL, rcmail_sort_column(), rcmail_sort_order());
|
||||
}
|
||||
|
||||
// update search set (possible change of threading mode)
|
||||
if (!empty($_REQUEST['_search']) && isset($_SESSION['search'])
|
||||
&& $_SESSION['search_request'] == $_REQUEST['_search']
|
||||
) {
|
||||
$search_request = $_REQUEST['_search'];
|
||||
$_SESSION['search'] = $RCMAIL->storage->get_search_set();
|
||||
}
|
||||
// remove old search data
|
||||
else if (empty($_REQUEST['_search']) && isset($_SESSION['search'])) {
|
||||
$RCMAIL->session->remove('search');
|
||||
}
|
||||
|
||||
rcmail_list_pagetitle();
|
||||
|
||||
// update mailboxlist
|
||||
if (empty($search_request)) {
|
||||
rcmail_send_unread_count($mbox_name, !empty($_REQUEST['_refresh']), empty($a_headers) ? 0 : null);
|
||||
}
|
||||
|
||||
// update message count display
|
||||
$pages = ceil($count/$RCMAIL->storage->get_pagesize());
|
||||
$page = $count ? $RCMAIL->storage->get_page() : 1;
|
||||
$exists = $RCMAIL->storage->count($mbox_name, 'EXISTS', true);
|
||||
|
||||
$OUTPUT->set_env('messagecount', $count);
|
||||
$OUTPUT->set_env('pagecount', $pages);
|
||||
$OUTPUT->set_env('threading', $threading);
|
||||
$OUTPUT->set_env('current_page', $page);
|
||||
$OUTPUT->set_env('exists', $exists);
|
||||
$OUTPUT->command('set_rowcount', rcmail_get_messagecount_text($count), $mbox_name);
|
||||
|
||||
// remove old message rows if commanded by the client
|
||||
if (!empty($_REQUEST['_clear'])) {
|
||||
$OUTPUT->command('clear_message_list');
|
||||
}
|
||||
|
||||
// add message rows
|
||||
rcmail_js_message_list($a_headers, false, $cols);
|
||||
|
||||
if (isset($a_headers) && count($a_headers)) {
|
||||
if ($search_request) {
|
||||
$OUTPUT->show_message('searchsuccessful', 'confirmation', array('nr' => $count));
|
||||
}
|
||||
|
||||
// remember last HIGHESTMODSEQ value (if supported)
|
||||
// we need it for flag updates in check-recent
|
||||
$data = $RCMAIL->storage->folder_data($mbox_name);
|
||||
if (!empty($data['HIGHESTMODSEQ'])) {
|
||||
$_SESSION['list_mod_seq'] = $data['HIGHESTMODSEQ'];
|
||||
}
|
||||
}
|
||||
else {
|
||||
// handle IMAP errors (e.g. #1486905)
|
||||
if ($err_code = $RCMAIL->storage->get_error_code()) {
|
||||
$RCMAIL->display_server_error();
|
||||
}
|
||||
else if ($search_request) {
|
||||
$OUTPUT->show_message('searchnomatch', 'notice');
|
||||
}
|
||||
else {
|
||||
$OUTPUT->show_message('nomessagesfound', 'notice');
|
||||
}
|
||||
}
|
||||
|
||||
// set trash folder state
|
||||
if ($mbox_name === $RCMAIL->config->get('trash_mbox')) {
|
||||
$OUTPUT->command('set_trash_count', $exists);
|
||||
}
|
||||
|
||||
if ($page == 1) {
|
||||
$OUTPUT->command('set_quota', $RCMAIL->quota_content(null, $multifolder ? 'INBOX' : $mbox_name));
|
||||
}
|
||||
|
||||
// send response
|
||||
$OUTPUT->send();
|
126
data/web/rc/program/steps/mail/list_contacts.inc
Normal file
126
data/web/rc/program/steps/mail/list_contacts.inc
Normal file
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
+-----------------------------------------------------------------------+
|
||||
| program/steps/mail/list_contacts.inc |
|
||||
| |
|
||||
| This file is part of the Roundcube Webmail client |
|
||||
| Copyright (C) 2012-2014, The Roundcube Dev Team |
|
||||
| |
|
||||
| Licensed under the GNU General Public License version 3 or |
|
||||
| any later version with exceptions for skins & plugins. |
|
||||
| See the README file for a full license statement. |
|
||||
| |
|
||||
| PURPOSE: |
|
||||
| Send contacts list to client (as remote response) |
|
||||
| |
|
||||
+-----------------------------------------------------------------------+
|
||||
| Author: Thomas Bruederli <roundcube@gmail.com> |
|
||||
+-----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
$afields = $RCMAIL->config->get('contactlist_fields');
|
||||
$addr_sort_col = $RCMAIL->config->get('addressbook_sort_col', 'name');
|
||||
$page_size = $RCMAIL->config->get('addressbook_pagesize', $RCMAIL->config->get('pagesize', 50));
|
||||
$list_page = max(1, intval($_GET['_page']));
|
||||
$jsresult = array();
|
||||
|
||||
// Use search result
|
||||
if (!empty($_REQUEST['_search']) && isset($_SESSION['search'][$_REQUEST['_search']])) {
|
||||
$search = (array)$_SESSION['search'][$_REQUEST['_search']];
|
||||
$sparam = $_SESSION['search_params']['id'] == $_REQUEST['_search'] ? $_SESSION['search_params']['data'] : array();
|
||||
|
||||
// get records from all sources
|
||||
foreach ($search as $s => $set) {
|
||||
$CONTACTS = $RCMAIL->get_address_book($s);
|
||||
|
||||
// list matching groups of this source (on page one)
|
||||
if ($sparam[1] && $CONTACTS->groups && $list_page == 1) {
|
||||
$jsresult += rcmail_compose_contact_groups($CONTACTS, $s, $sparam[1], (int)$RCMAIL->config->get('addressbook_search_mode'));
|
||||
}
|
||||
|
||||
// reset page
|
||||
$CONTACTS->set_page(1);
|
||||
$CONTACTS->set_pagesize(9999);
|
||||
$CONTACTS->set_search_set($set);
|
||||
|
||||
// get records
|
||||
$result = $CONTACTS->list_records($afields);
|
||||
|
||||
while ($row = $result->next()) {
|
||||
$row['sourceid'] = $s;
|
||||
$key = rcube_addressbook::compose_contact_key($row, $addr_sort_col);
|
||||
$records[$key] = $row;
|
||||
}
|
||||
unset($result);
|
||||
}
|
||||
|
||||
// sort the records
|
||||
ksort($records, SORT_LOCALE_STRING);
|
||||
|
||||
// create resultset object
|
||||
$count = count($records);
|
||||
$first = ($list_page-1) * $page_size;
|
||||
$result = new rcube_result_set($count, $first);
|
||||
|
||||
// we need only records for current page
|
||||
if ($page_size < $count) {
|
||||
$records = array_slice($records, $first, $page_size);
|
||||
}
|
||||
|
||||
$result->records = array_values($records);
|
||||
}
|
||||
// list contacts from selected source
|
||||
else {
|
||||
$source = rcube_utils::get_input_value('_source', rcube_utils::INPUT_GPC);
|
||||
$CONTACTS = $RCMAIL->get_address_book($source);
|
||||
|
||||
if ($CONTACTS && $CONTACTS->ready) {
|
||||
// set list properties
|
||||
$CONTACTS->set_pagesize($page_size);
|
||||
$CONTACTS->set_page($list_page);
|
||||
|
||||
if ($group_id = rcube_utils::get_input_value('_gid', rcube_utils::INPUT_GPC)) {
|
||||
$CONTACTS->set_group($group_id);
|
||||
}
|
||||
// list groups of this source (on page one)
|
||||
else if ($CONTACTS->groups && $CONTACTS->list_page == 1) {
|
||||
$jsresult = rcmail_compose_contact_groups($CONTACTS, $source);
|
||||
}
|
||||
|
||||
// get contacts for this user
|
||||
$result = $CONTACTS->list_records($afields);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($result) && !$result->count && $result->searchonly) {
|
||||
$OUTPUT->show_message('contactsearchonly', 'notice');
|
||||
}
|
||||
else if (!empty($result) && $result->count > 0) {
|
||||
// create javascript list
|
||||
while ($row = $result->next()) {
|
||||
$name = rcube_addressbook::compose_list_name($row);
|
||||
|
||||
// add record for every email address of the contact
|
||||
$emails = $CONTACTS->get_col_values('email', $row, true);
|
||||
foreach ($emails as $i => $email) {
|
||||
$row_id = $row['ID'].'-'.$i;
|
||||
$jsresult[$row_id] = format_email_recipient($email, $name);
|
||||
$classname = $row['_type'] == 'group' ? 'group' : 'person';
|
||||
$keyname = $row['_type'] == 'group' ? 'contactgroup' : 'contact';
|
||||
|
||||
$OUTPUT->command('add_contact_row', $row_id, array(
|
||||
$keyname => html::a(array('title' => $email), rcube::Q($name ?: $email) .
|
||||
($name && count($emails) > 1 ? ' ' . html::span('email', rcube::Q($email)) : '')
|
||||
)), $classname);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// update env
|
||||
$OUTPUT->set_env('contactdata', $jsresult);
|
||||
$OUTPUT->set_env('pagecount', ceil($result->count / $page_size));
|
||||
$OUTPUT->command('set_page_buttons');
|
||||
|
||||
// send response
|
||||
$OUTPUT->send();
|
173
data/web/rc/program/steps/mail/mark.inc
Normal file
173
data/web/rc/program/steps/mail/mark.inc
Normal file
@@ -0,0 +1,173 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
+-----------------------------------------------------------------------+
|
||||
| program/steps/mail/mark.inc |
|
||||
| |
|
||||
| This file is part of the Roundcube Webmail client |
|
||||
| Copyright (C) 2005-2014, The Roundcube Dev Team |
|
||||
| |
|
||||
| Licensed under the GNU General Public License version 3 or |
|
||||
| any later version with exceptions for skins & plugins. |
|
||||
| See the README file for a full license statement. |
|
||||
| |
|
||||
| PURPOSE: |
|
||||
| Mark the submitted messages with the specified flag |
|
||||
| |
|
||||
+-----------------------------------------------------------------------+
|
||||
| Author: Thomas Bruederli <roundcube@gmail.com> |
|
||||
+-----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
// only process ajax requests
|
||||
if (!$OUTPUT->ajax_call) {
|
||||
return;
|
||||
}
|
||||
|
||||
$threading = (bool) $RCMAIL->storage->get_threading();
|
||||
$skip_deleted = (bool) $RCMAIL->config->get('skip_deleted');
|
||||
$read_deleted = (bool) $RCMAIL->config->get('read_when_deleted');
|
||||
|
||||
$a_flags_map = array(
|
||||
'undelete' => 'UNDELETED',
|
||||
'delete' => 'DELETED',
|
||||
'read' => 'SEEN',
|
||||
'unread' => 'UNSEEN',
|
||||
'flagged' => 'FLAGGED',
|
||||
'unflagged' => 'UNFLAGGED',
|
||||
);
|
||||
|
||||
$_uids = rcube_utils::get_input_value('_uid', rcube_utils::INPUT_POST);
|
||||
$flag = rcube_utils::get_input_value('_flag', rcube_utils::INPUT_POST);
|
||||
$folders = rcube_utils::get_input_value('_folders', rcube_utils::INPUT_POST);
|
||||
$mbox = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST);
|
||||
|
||||
if ($_uids && $flag) {
|
||||
$flag = $a_flags_map[$flag] ?: strtoupper($flag);
|
||||
|
||||
if ($flag == 'DELETED' && $skip_deleted && $_POST['_from'] != 'show') {
|
||||
// count messages before changing anything
|
||||
$old_count = $RCMAIL->storage->count(NULL, $threading ? 'THREADS' : 'ALL');
|
||||
$old_pages = ceil($old_count / $RCMAIL->storage->get_pagesize());
|
||||
}
|
||||
|
||||
if ($folders == 'all') {
|
||||
$mboxes = $RCMAIL->storage->list_folders_subscribed('', '*', 'mail');
|
||||
$input = array_combine($mboxes, array_fill(0, count($mboxes), '*'));
|
||||
}
|
||||
else if ($folders == 'sub') {
|
||||
$delim = $RCMAIL->storage->get_hierarchy_delimiter();
|
||||
$mboxes = $RCMAIL->storage->list_folders_subscribed($mbox . $delim, '*', 'mail');
|
||||
array_unshift($mboxes, $mbox);
|
||||
$input = array_combine($mboxes, array_fill(0, count($mboxes), '*'));
|
||||
}
|
||||
else if ($folders == 'cur') {
|
||||
$input = array($mbox => '*');
|
||||
}
|
||||
else {
|
||||
$input = rcmail::get_uids();
|
||||
}
|
||||
|
||||
foreach ($input as $mbox => $uids) {
|
||||
$marked += (int)$RCMAIL->storage->set_flag($uids, $flag, $mbox);
|
||||
$count += count($uids);
|
||||
}
|
||||
|
||||
if (!$marked) {
|
||||
// send error message
|
||||
if ($_POST['_from'] != 'show') {
|
||||
$OUTPUT->command('list_mailbox');
|
||||
}
|
||||
|
||||
$RCMAIL->display_server_error('errormarking');
|
||||
$OUTPUT->send();
|
||||
exit;
|
||||
}
|
||||
else if (empty($_POST['_quiet'])) {
|
||||
$OUTPUT->show_message('messagemarked', 'confirmation');
|
||||
}
|
||||
|
||||
if ($flag == 'DELETED' && $read_deleted && !empty($_POST['_ruid'])) {
|
||||
$ruids = rcube_utils::get_input_value('_ruid', rcube_utils::INPUT_POST);
|
||||
foreach (rcmail::get_uids($ruids) as $mbox => $uids) {
|
||||
$read += (int)$RCMAIL->storage->set_flag($uids, 'SEEN', $mbox);
|
||||
}
|
||||
|
||||
if ($read && !$skip_deleted) {
|
||||
$OUTPUT->command('flag_deleted_as_read', $ruids);
|
||||
}
|
||||
}
|
||||
|
||||
if ($flag == 'SEEN' || $flag == 'UNSEEN' || ($flag == 'DELETED' && !$skip_deleted)) {
|
||||
foreach ($input as $mbox => $uids) {
|
||||
rcmail_send_unread_count($mbox);
|
||||
}
|
||||
|
||||
$OUTPUT->set_env('last_flag', $flag);
|
||||
}
|
||||
else if ($flag == 'DELETED' && $skip_deleted) {
|
||||
if ($_POST['_from'] == 'show') {
|
||||
if ($next = rcube_utils::get_input_value('_next_uid', rcube_utils::INPUT_GPC))
|
||||
$OUTPUT->command('show_message', $next);
|
||||
else
|
||||
$OUTPUT->command('command', 'list');
|
||||
}
|
||||
else {
|
||||
$search_request = rcube_utils::get_input_value('_search', rcube_utils::INPUT_GPC);
|
||||
|
||||
// refresh saved search set after moving some messages
|
||||
if ($search_request && $RCMAIL->storage->get_search_set()) {
|
||||
$_SESSION['search'] = $RCMAIL->storage->refresh_search();
|
||||
}
|
||||
|
||||
$msg_count = $RCMAIL->storage->count(NULL, $threading ? 'THREADS' : 'ALL');
|
||||
$page_size = $RCMAIL->storage->get_pagesize();
|
||||
$page = $RCMAIL->storage->get_page();
|
||||
$pages = ceil($msg_count / $page_size);
|
||||
$nextpage_count = $old_count - $page_size * $page;
|
||||
$remaining = $msg_count - $page_size * ($page - 1);
|
||||
|
||||
// jump back one page (user removed the whole last page)
|
||||
if ($page > 1 && $remaining == 0) {
|
||||
$page -= 1;
|
||||
$RCMAIL->storage->set_page($page);
|
||||
$_SESSION['page'] = $page;
|
||||
$jump_back = true;
|
||||
}
|
||||
|
||||
// update message count display
|
||||
$OUTPUT->set_env('messagecount', $msg_count);
|
||||
$OUTPUT->set_env('current_page', $page);
|
||||
$OUTPUT->set_env('pagecount', $pages);
|
||||
|
||||
// update mailboxlist
|
||||
$mbox = $RCMAIL->storage->get_folder();
|
||||
$unseen_count = $msg_count ? $RCMAIL->storage->count($mbox, 'UNSEEN') : 0;
|
||||
$old_unseen = rcmail_get_unseen_count($mbox);
|
||||
|
||||
if ($old_unseen != $unseen_count) {
|
||||
$OUTPUT->command('set_unread_count', $mbox, $unseen_count, ($mbox == 'INBOX'));
|
||||
rcmail_set_unseen_count($mbox, $unseen_count);
|
||||
}
|
||||
|
||||
$OUTPUT->command('set_rowcount', rcmail_get_messagecount_text($msg_count), $mbox);
|
||||
|
||||
if ($threading) {
|
||||
$count = rcube_utils::get_input_value('_count', rcube_utils::INPUT_POST);
|
||||
}
|
||||
|
||||
// add new rows from next page (if any)
|
||||
if ($old_count && $_uids != '*' && ($jump_back || $nextpage_count > 0)) {
|
||||
$a_headers = $RCMAIL->storage->list_messages($mbox, NULL,
|
||||
rcmail_sort_column(), rcmail_sort_order(), $jump_back ? NULL : $count);
|
||||
|
||||
rcmail_js_message_list($a_headers, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
$OUTPUT->show_message('internalerror', 'error');
|
||||
}
|
||||
|
||||
$OUTPUT->send();
|
179
data/web/rc/program/steps/mail/move_del.inc
Normal file
179
data/web/rc/program/steps/mail/move_del.inc
Normal file
@@ -0,0 +1,179 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
+-----------------------------------------------------------------------+
|
||||
| program/steps/mail/move_del.inc |
|
||||
| |
|
||||
| This file is part of the Roundcube Webmail client |
|
||||
| Copyright (C) 2005-2014, The Roundcube Dev Team |
|
||||
| |
|
||||
| Licensed under the GNU General Public License version 3 or |
|
||||
| any later version with exceptions for skins & plugins. |
|
||||
| See the README file for a full license statement. |
|
||||
| |
|
||||
| PURPOSE: |
|
||||
| Move the submitted messages to a specific mailbox or delete them |
|
||||
| |
|
||||
+-----------------------------------------------------------------------+
|
||||
| Author: Thomas Bruederli <roundcube@gmail.com> |
|
||||
+-----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
// only process ajax requests
|
||||
if (!$OUTPUT->ajax_call) {
|
||||
return;
|
||||
}
|
||||
|
||||
// count messages before changing anything
|
||||
$threading = (bool) $RCMAIL->storage->get_threading();
|
||||
$trash = $RCMAIL->config->get('trash_mbox');
|
||||
$sources = array();
|
||||
|
||||
if ($_POST['_from'] != 'show') {
|
||||
$old_count = $RCMAIL->storage->count(NULL, $threading ? 'THREADS' : 'ALL');
|
||||
$old_pages = ceil($old_count / $RCMAIL->storage->get_pagesize());
|
||||
}
|
||||
|
||||
// move messages
|
||||
if ($RCMAIL->action == 'move' && !empty($_POST['_uid']) && strlen($_POST['_target_mbox'])) {
|
||||
$target = rcube_utils::get_input_value('_target_mbox', rcube_utils::INPUT_POST, true);
|
||||
$success = true;
|
||||
|
||||
foreach (rcmail::get_uids(null, null, $multifolder) as $mbox => $uids) {
|
||||
if ($mbox === $target) {
|
||||
$count += count($uids);
|
||||
}
|
||||
else if ($RCMAIL->storage->move_message($uids, $target, $mbox)) {
|
||||
$count += count($uids);
|
||||
$sources[] = $mbox;
|
||||
}
|
||||
else {
|
||||
$success = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$success) {
|
||||
// send error message
|
||||
if ($_POST['_from'] != 'show')
|
||||
$OUTPUT->command('list_mailbox');
|
||||
$RCMAIL->display_server_error('errormoving', null, $target == $trash ? 'delete' : '');
|
||||
$OUTPUT->send();
|
||||
}
|
||||
else {
|
||||
$OUTPUT->show_message($target == $trash ? 'messagemovedtotrash' : 'messagemoved', 'confirmation');
|
||||
}
|
||||
|
||||
if (!empty($_POST['_refresh'])) {
|
||||
// FIXME: send updated message rows instead of reloading the entire list
|
||||
$OUTPUT->command('refresh_list');
|
||||
}
|
||||
else {
|
||||
$addrows = true;
|
||||
}
|
||||
}
|
||||
// delete messages
|
||||
else if ($RCMAIL->action == 'delete' && !empty($_POST['_uid'])) {
|
||||
foreach (rcmail::get_uids(null, null, $multifolder) as $mbox => $uids) {
|
||||
$del += (int)$RCMAIL->storage->delete_message($uids, $mbox);
|
||||
$count += count($uids);
|
||||
$sources[] = $mbox;
|
||||
}
|
||||
|
||||
if (!$del) {
|
||||
// send error message
|
||||
if ($_POST['_from'] != 'show')
|
||||
$OUTPUT->command('list_mailbox');
|
||||
$RCMAIL->display_server_error('errordeleting');
|
||||
$OUTPUT->send();
|
||||
}
|
||||
else {
|
||||
$OUTPUT->show_message('messagedeleted', 'confirmation');
|
||||
}
|
||||
|
||||
$addrows = true;
|
||||
}
|
||||
// unknown action or missing query param
|
||||
else {
|
||||
$OUTPUT->show_message('internalerror', 'error');
|
||||
$OUTPUT->send();
|
||||
}
|
||||
|
||||
$search_request = rcube_utils::get_input_value('_search', rcube_utils::INPUT_GPC);
|
||||
|
||||
// refresh saved search set after moving some messages
|
||||
if ($search_request && $RCMAIL->storage->get_search_set()) {
|
||||
$_SESSION['search'] = $RCMAIL->storage->refresh_search();
|
||||
}
|
||||
|
||||
if ($_POST['_from'] == 'show') {
|
||||
if ($next = rcube_utils::get_input_value('_next_uid', rcube_utils::INPUT_GPC)) {
|
||||
$OUTPUT->command('show_message', $next);
|
||||
}
|
||||
else {
|
||||
$OUTPUT->command('command', 'list');
|
||||
}
|
||||
|
||||
$OUTPUT->send();
|
||||
}
|
||||
|
||||
$mbox = $RCMAIL->storage->get_folder();
|
||||
$msg_count = $RCMAIL->storage->count(NULL, $threading ? 'THREADS' : 'ALL');
|
||||
$exists = $RCMAIL->storage->count($mbox, 'EXISTS', true);
|
||||
$page_size = $RCMAIL->storage->get_pagesize();
|
||||
$page = $RCMAIL->storage->get_page();
|
||||
$pages = ceil($msg_count / $page_size);
|
||||
$nextpage_count = $old_count - $page_size * $page;
|
||||
$remaining = $msg_count - $page_size * ($page - 1);
|
||||
|
||||
// jump back one page (user removed the whole last page)
|
||||
if ($page > 1 && $remaining == 0) {
|
||||
$page -= 1;
|
||||
$RCMAIL->storage->set_page($page);
|
||||
$_SESSION['page'] = $page;
|
||||
$jump_back = true;
|
||||
}
|
||||
|
||||
// update message count display
|
||||
$OUTPUT->set_env('messagecount', $msg_count);
|
||||
$OUTPUT->set_env('current_page', $page);
|
||||
$OUTPUT->set_env('pagecount', $pages);
|
||||
$OUTPUT->set_env('exists', $exists);
|
||||
|
||||
// update mailboxlist
|
||||
$unseen_count = $msg_count ? $RCMAIL->storage->count($mbox, 'UNSEEN') : 0;
|
||||
$old_unseen = rcmail_get_unseen_count($mbox);
|
||||
|
||||
if ($old_unseen != $unseen_count) {
|
||||
$OUTPUT->command('set_unread_count', $mbox, $unseen_count, ($mbox == 'INBOX'));
|
||||
rcmail_set_unseen_count($mbox, $unseen_count);
|
||||
}
|
||||
|
||||
if ($RCMAIL->action == 'move' && strlen($target)) {
|
||||
rcmail_send_unread_count($target, true);
|
||||
}
|
||||
|
||||
$OUTPUT->command('set_quota', $RCMAIL->quota_content(null, $multifolder ? $sources[0] : 'INBOX'));
|
||||
$OUTPUT->command('set_rowcount', rcmail_get_messagecount_text($msg_count), $mbox);
|
||||
|
||||
if ($threading) {
|
||||
$count = rcube_utils::get_input_value('_count', rcube_utils::INPUT_POST);
|
||||
}
|
||||
|
||||
// add new rows from next page (if any)
|
||||
if ($addrows && $count && $uids != '*' && ($jump_back || $nextpage_count > 0)) {
|
||||
$a_headers = $RCMAIL->storage->list_messages($mbox, NULL,
|
||||
rcmail_sort_column(), rcmail_sort_order(), $jump_back ? NULL : $count);
|
||||
|
||||
rcmail_js_message_list($a_headers, false);
|
||||
}
|
||||
|
||||
// set trash folder state
|
||||
if ($mbox === $trash) {
|
||||
$OUTPUT->command('set_trash_count', $exists);
|
||||
}
|
||||
else if ($target !== null && $target === $trash) {
|
||||
$OUTPUT->command('set_trash_count', $RCMAIL->storage->count($trash, 'EXISTS', true));
|
||||
}
|
||||
|
||||
// send response
|
||||
$OUTPUT->send();
|
66
data/web/rc/program/steps/mail/pagenav.inc
Normal file
66
data/web/rc/program/steps/mail/pagenav.inc
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
+-----------------------------------------------------------------------+
|
||||
| program/steps/mail/pagenav.inc |
|
||||
| |
|
||||
| This file is part of the Roundcube Webmail client |
|
||||
| Copyright (C) 2005-2016, The Roundcube Dev Team |
|
||||
| |
|
||||
| Licensed under the GNU General Public License version 3 or |
|
||||
| any later version with exceptions for skins & plugins. |
|
||||
| See the README file for a full license statement. |
|
||||
| |
|
||||
| PURPOSE: |
|
||||
| Updates message page navigation controls |
|
||||
| |
|
||||
+-----------------------------------------------------------------------+
|
||||
| Author: Aleksander Machniak <alec@alec.pl> |
|
||||
+-----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
$uid = rcube_utils::get_input_value('_uid', rcube_utils::INPUT_GET);
|
||||
$index = $RCMAIL->storage->index(null, rcmail_sort_column(), rcmail_sort_order());
|
||||
$cnt = $index->count_messages();
|
||||
|
||||
if ($cnt && ($pos = $index->exists($uid, true)) !== false) {
|
||||
$prev = $pos ? $index->get_element($pos-1) : 0;
|
||||
$first = $pos ? $index->get_element('FIRST') : 0;
|
||||
$next = $pos < $cnt-1 ? $index->get_element($pos+1) : 0;
|
||||
$last = $pos < $cnt-1 ? $index->get_element('LAST') : 0;
|
||||
}
|
||||
else {
|
||||
// error, this will at least disable page navigation
|
||||
$OUTPUT->command('set_rowcount', '');
|
||||
$OUTPUT->send();
|
||||
}
|
||||
|
||||
// Set UIDs and activate navigation buttons
|
||||
if ($prev) {
|
||||
$OUTPUT->set_env('prev_uid', $prev);
|
||||
$OUTPUT->command('enable_command', 'previousmessage', 'firstmessage', true);
|
||||
}
|
||||
|
||||
if ($next) {
|
||||
$OUTPUT->set_env('next_uid', $next);
|
||||
$OUTPUT->command('enable_command', 'nextmessage', 'lastmessage', true);
|
||||
}
|
||||
|
||||
if ($first) {
|
||||
$OUTPUT->set_env('first_uid', $first);
|
||||
}
|
||||
|
||||
if ($last) {
|
||||
$OUTPUT->set_env('last_uid', $last);
|
||||
}
|
||||
|
||||
// Don't need a real messages count value
|
||||
$OUTPUT->set_env('messagecount', 1);
|
||||
|
||||
// Set rowcount text
|
||||
$OUTPUT->command('set_rowcount', $RCMAIL->gettext(array(
|
||||
'name' => 'messagenrof',
|
||||
'vars' => array('nr' => $pos+1, 'count' => $cnt)
|
||||
)));
|
||||
|
||||
$OUTPUT->send();
|
248
data/web/rc/program/steps/mail/search.inc
Normal file
248
data/web/rc/program/steps/mail/search.inc
Normal file
@@ -0,0 +1,248 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
+-----------------------------------------------------------------------+
|
||||
| steps/mail/search.inc |
|
||||
| |
|
||||
| This file is part of the Roundcube Webmail client |
|
||||
| Copyright (C) 2005-2013, The Roundcube Dev Team |
|
||||
| |
|
||||
| Licensed under the GNU General Public License version 3 or |
|
||||
| any later version with exceptions for skins & plugins. |
|
||||
| See the README file for a full license statement. |
|
||||
| |
|
||||
| PURPOSE: |
|
||||
| Mail messages search action |
|
||||
+-----------------------------------------------------------------------+
|
||||
| Author: Benjamin Smith <defitro@gmail.com> |
|
||||
| Thomas Bruederli <roundcube@gmail.com> |
|
||||
+-----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
$REMOTE_REQUEST = TRUE;
|
||||
|
||||
@set_time_limit(170); // extend default max_execution_time to ~3 minutes
|
||||
|
||||
// reset list_page and old search results
|
||||
$RCMAIL->storage->set_page(1);
|
||||
$RCMAIL->storage->set_search_set(NULL);
|
||||
$_SESSION['page'] = 1;
|
||||
|
||||
// using encodeURI with javascript "should" give us
|
||||
// a correctly encoded query string
|
||||
$imap_charset = RCUBE_CHARSET;
|
||||
|
||||
// get search string
|
||||
$str = rcube_utils::get_input_value('_q', rcube_utils::INPUT_GET, true);
|
||||
$mbox = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_GET, true);
|
||||
$filter = rcube_utils::get_input_value('_filter', rcube_utils::INPUT_GET);
|
||||
$headers = rcube_utils::get_input_value('_headers', rcube_utils::INPUT_GET);
|
||||
$scope = rcube_utils::get_input_value('_scope', rcube_utils::INPUT_GET);
|
||||
$interval = rcube_utils::get_input_value('_interval', rcube_utils::INPUT_GET);
|
||||
$continue = rcube_utils::get_input_value('_continue', rcube_utils::INPUT_GET);
|
||||
$subject = array();
|
||||
|
||||
$filter = trim($filter);
|
||||
$search_request = md5($mbox.$scope.$interval.$filter.$str);
|
||||
|
||||
// add list filter string
|
||||
$search_str = $filter && $filter != 'ALL' ? $filter : '';
|
||||
|
||||
// Check the search string for type of search
|
||||
if (preg_match("/^from:.*/i", $str)) {
|
||||
list(,$srch) = explode(":", $str);
|
||||
$subject['from'] = "HEADER FROM";
|
||||
}
|
||||
else if (preg_match("/^to:.*/i", $str)) {
|
||||
list(,$srch) = explode(":", $str);
|
||||
$subject['to'] = "HEADER TO";
|
||||
}
|
||||
else if (preg_match("/^cc:.*/i", $str)) {
|
||||
list(,$srch) = explode(":", $str);
|
||||
$subject['cc'] = "HEADER CC";
|
||||
}
|
||||
else if (preg_match("/^bcc:.*/i", $str)) {
|
||||
list(,$srch) = explode(":", $str);
|
||||
$subject['bcc'] = "HEADER BCC";
|
||||
}
|
||||
else if (preg_match("/^subject:.*/i", $str)) {
|
||||
list(,$srch) = explode(":", $str);
|
||||
$subject['subject'] = "HEADER SUBJECT";
|
||||
}
|
||||
else if (preg_match("/^body:.*/i", $str)) {
|
||||
list(,$srch) = explode(":", $str);
|
||||
$subject['body'] = "BODY";
|
||||
}
|
||||
else if (strlen(trim($str))) {
|
||||
if ($headers) {
|
||||
foreach (explode(',', $headers) as $header) {
|
||||
if ($header == 'text') {
|
||||
// #1488208: get rid of other headers when searching by "TEXT"
|
||||
$subject = array('text' => 'TEXT');
|
||||
break;
|
||||
}
|
||||
else {
|
||||
$subject[$header] = ($header != 'body' ? 'HEADER ' : '') . strtoupper($header);
|
||||
}
|
||||
}
|
||||
|
||||
// save search modifiers for the current folder to user prefs
|
||||
$mkey = $scope == 'all' ? '*' : $mbox;
|
||||
$search_mods = rcmail_search_mods();
|
||||
$search_mods[$mkey] = array_fill_keys(array_keys($subject), 1);
|
||||
|
||||
$RCMAIL->user->save_prefs(array('search_mods' => $search_mods));
|
||||
}
|
||||
else {
|
||||
// search in subject by default
|
||||
$subject['subject'] = 'HEADER SUBJECT';
|
||||
}
|
||||
}
|
||||
|
||||
$search = isset($srch) ? trim($srch) : trim($str);
|
||||
|
||||
if ($search_interval = rcmail_search_interval_criteria($interval)) {
|
||||
$search_str .= ' ' . $search_interval;
|
||||
}
|
||||
|
||||
if (!empty($subject)) {
|
||||
$search_str .= str_repeat(' OR', count($subject)-1);
|
||||
foreach ($subject as $sub) {
|
||||
$search_str .= ' ' . $sub . ' ' . rcube_imap_generic::escape($search);
|
||||
}
|
||||
}
|
||||
|
||||
$search_str = trim($search_str);
|
||||
$sort_column = rcmail_sort_column();
|
||||
|
||||
// set message set for already stored (but incomplete) search request
|
||||
if (!empty($continue) && isset($_SESSION['search']) && $_SESSION['search_request'] == $continue) {
|
||||
$RCMAIL->storage->set_search_set($_SESSION['search']);
|
||||
$search_str = $_SESSION['search'][0];
|
||||
}
|
||||
|
||||
// execute IMAP search
|
||||
if ($search_str) {
|
||||
// search all, current or subfolders folders
|
||||
if ($scope == 'all') {
|
||||
$mboxes = $RCMAIL->storage->list_folders_subscribed('', '*', 'mail', null, true);
|
||||
natcasesort($mboxes); // we want natural alphabetic sorting of folders in the result set
|
||||
}
|
||||
else if ($scope == 'sub') {
|
||||
$delim = $RCMAIL->storage->get_hierarchy_delimiter();
|
||||
$mboxes = $RCMAIL->storage->list_folders_subscribed($mbox . $delim, '*', 'mail');
|
||||
array_unshift($mboxes, $mbox);
|
||||
}
|
||||
|
||||
if ($scope != 'all') {
|
||||
// Remember current folder, it can change in meantime (plugins)
|
||||
// but we need it to e.g. recognize Sent folder to handle From/To column later
|
||||
$RCMAIL->output->set_env('mailbox', $mbox);
|
||||
}
|
||||
|
||||
$result = $RCMAIL->storage->search($mboxes, $search_str, $imap_charset, $sort_column);
|
||||
}
|
||||
|
||||
// save search results in session
|
||||
if (!is_array($_SESSION['search'])) {
|
||||
$_SESSION['search'] = array();
|
||||
}
|
||||
|
||||
if ($search_str) {
|
||||
$_SESSION['search'] = $RCMAIL->storage->get_search_set();
|
||||
$_SESSION['last_text_search'] = $str;
|
||||
}
|
||||
$_SESSION['search_request'] = $search_request;
|
||||
$_SESSION['search_scope'] = $scope;
|
||||
$_SESSION['search_interval'] = $interval;
|
||||
$_SESSION['search_filter'] = $filter;
|
||||
|
||||
// Get the headers
|
||||
if (!$result->incomplete) {
|
||||
$result_h = $RCMAIL->storage->list_messages($mbox, 1, $sort_column, rcmail_sort_order());
|
||||
}
|
||||
|
||||
// Make sure we got the headers
|
||||
if (!empty($result_h)) {
|
||||
$count = $RCMAIL->storage->count($mbox, $RCMAIL->storage->get_threading() ? 'THREADS' : 'ALL');
|
||||
|
||||
rcmail_js_message_list($result_h, false);
|
||||
|
||||
if ($search_str) {
|
||||
$OUTPUT->show_message('searchsuccessful', 'confirmation', array('nr' => $RCMAIL->storage->count(NULL, 'ALL')));
|
||||
}
|
||||
|
||||
// remember last HIGHESTMODSEQ value (if supported)
|
||||
// we need it for flag updates in check-recent
|
||||
if ($mbox !== null) {
|
||||
$data = $RCMAIL->storage->folder_data($mbox);
|
||||
if (!empty($data['HIGHESTMODSEQ'])) {
|
||||
$_SESSION['list_mod_seq'] = $data['HIGHESTMODSEQ'];
|
||||
}
|
||||
}
|
||||
}
|
||||
// handle IMAP errors (e.g. #1486905)
|
||||
else if ($err_code = $RCMAIL->storage->get_error_code()) {
|
||||
$count = 0;
|
||||
$RCMAIL->display_server_error();
|
||||
}
|
||||
// advice the client to re-send the (cross-folder) search request
|
||||
else if ($result->incomplete) {
|
||||
$count = 0; // keep UI locked
|
||||
$OUTPUT->command('continue_search', $search_request);
|
||||
}
|
||||
else {
|
||||
$count = 0;
|
||||
$OUTPUT->show_message('searchnomatch', 'notice');
|
||||
$OUTPUT->set_env('multifolder_listing', (bool)$result->multi);
|
||||
if ($result->multi && $scope == 'all') {
|
||||
$OUTPUT->command('select_folder', '');
|
||||
}
|
||||
}
|
||||
|
||||
// update message count display
|
||||
$OUTPUT->set_env('search_request', $search_str ? $search_request : '');
|
||||
$OUTPUT->set_env('search_filter', $_SESSION['search_filter']);
|
||||
$OUTPUT->set_env('threading', $RCMAIL->storage->get_threading());
|
||||
$OUTPUT->set_env('messagecount', $count);
|
||||
$OUTPUT->set_env('pagecount', ceil($count/$RCMAIL->storage->get_pagesize()));
|
||||
$OUTPUT->set_env('exists', $mbox === null ? 0 : $RCMAIL->storage->count($mbox, 'EXISTS'));
|
||||
$OUTPUT->command('set_rowcount', rcmail_get_messagecount_text($count, 1), $mbox);
|
||||
|
||||
rcmail_list_pagetitle();
|
||||
|
||||
// update unseen messages count
|
||||
if (empty($search_str)) {
|
||||
rcmail_send_unread_count($mbox, false, empty($result_h) ? 0 : null);
|
||||
}
|
||||
|
||||
if (!$result->incomplete) {
|
||||
$OUTPUT->command('set_quota', $RCMAIL->quota_content(null, $result->multi ? 'INBOX' : $mbox));
|
||||
}
|
||||
|
||||
$OUTPUT->send();
|
||||
|
||||
|
||||
// Creates BEFORE/SINCE search criteria from the specified interval
|
||||
// Interval can be: 1W, 1M, 1Y, -1W, -1M, -1Y
|
||||
function rcmail_search_interval_criteria($interval)
|
||||
{
|
||||
if (empty($interval)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($interval[0] == '-') {
|
||||
$search = 'BEFORE';
|
||||
$interval = substr($interval, 1);
|
||||
}
|
||||
else {
|
||||
$search = 'SINCE';
|
||||
}
|
||||
|
||||
$date = new DateTime('now');
|
||||
$interval = new DateInterval('P' . $interval);
|
||||
|
||||
$date->sub($interval);
|
||||
|
||||
return $search . ' ' . $date->format('j-M-Y');
|
||||
}
|
121
data/web/rc/program/steps/mail/search_contacts.inc
Normal file
121
data/web/rc/program/steps/mail/search_contacts.inc
Normal file
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
+-----------------------------------------------------------------------+
|
||||
| program/steps/mail/search_contacts.inc |
|
||||
| |
|
||||
| This file is part of the Roundcube Webmail client |
|
||||
| Copyright (C) 2013-2014, The Roundcube Dev Team |
|
||||
| |
|
||||
| Licensed under the GNU General Public License version 3 or |
|
||||
| any later version with exceptions for skins & plugins. |
|
||||
| See the README file for a full license statement. |
|
||||
| |
|
||||
| PURPOSE: |
|
||||
| Search contacts from the adress book widget |
|
||||
| |
|
||||
+-----------------------------------------------------------------------+
|
||||
| Author: Thomas Bruederli <roundcube@gmail.com> |
|
||||
+-----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
$search = rcube_utils::get_input_value('_q', rcube_utils::INPUT_GPC, true);
|
||||
$sources = $RCMAIL->get_address_sources();
|
||||
$search_mode = (int) $RCMAIL->config->get('addressbook_search_mode');
|
||||
$addr_sort_col = $RCMAIL->config->get('addressbook_sort_col', 'name');
|
||||
$afields = $RCMAIL->config->get('contactlist_fields');
|
||||
$page_size = $RCMAIL->config->get('addressbook_pagesize', $RCMAIL->config->get('pagesize', 50));
|
||||
$records = array();
|
||||
$search_set = array();
|
||||
$jsresult = array();
|
||||
$search_mode |= rcube_addressbook::SEARCH_GROUPS;
|
||||
|
||||
foreach ($sources as $s) {
|
||||
$source = $RCMAIL->get_address_book($s['id']);
|
||||
$source->set_page(1);
|
||||
$source->set_pagesize(9999);
|
||||
|
||||
// list matching groups of this source
|
||||
if ($source->groups) {
|
||||
$jsresult += rcmail_compose_contact_groups($source, $s['id'], $search, $search_mode);
|
||||
}
|
||||
|
||||
// get contacts count
|
||||
$result = $source->search($afields, $search, $search_mode, true, true, 'email');
|
||||
|
||||
if (!$result->count) {
|
||||
continue;
|
||||
}
|
||||
|
||||
while ($row = $result->next()) {
|
||||
$row['sourceid'] = $s['id'];
|
||||
$key = rcube_addressbook::compose_contact_key($row, $addr_sort_col);
|
||||
$records[$key] = $row;
|
||||
}
|
||||
|
||||
$search_set[$s['id']] = $source->get_search_set();
|
||||
unset($result);
|
||||
}
|
||||
|
||||
$group_count = count($jsresult);
|
||||
|
||||
// sort the records
|
||||
ksort($records, SORT_LOCALE_STRING);
|
||||
|
||||
// create resultset object
|
||||
$count = count($records);
|
||||
$result = new rcube_result_set($count);
|
||||
|
||||
// select the requested page
|
||||
if ($page_size < $count) {
|
||||
$records = array_slice($records, $result->first, $page_size);
|
||||
}
|
||||
|
||||
$result->records = array_values($records);
|
||||
|
||||
if (!empty($result) && $result->count > 0) {
|
||||
// create javascript list
|
||||
while ($row = $result->next()) {
|
||||
$name = rcube_addressbook::compose_list_name($row);
|
||||
$classname = $row['_type'] == 'group' ? 'group' : 'person';
|
||||
$keyname = $row['_type'] == 'group' ? 'contactgroup' : 'contact';
|
||||
|
||||
// add record for every email address of the contact
|
||||
// (same as in list_contacts.inc)
|
||||
$emails = $source->get_col_values('email', $row, true);
|
||||
foreach ($emails as $i => $email) {
|
||||
$row_id = $row['ID'].'-'.$i;
|
||||
$jsresult[$row_id] = format_email_recipient($email, $name);
|
||||
$title = rcube_addressbook::compose_search_name($row, $email, $name);
|
||||
|
||||
$OUTPUT->command('add_contact_row', $row_id, array(
|
||||
$keyname => html::a(array('title' => $title), rcube::Q($name ?: $email) .
|
||||
($name && count($emails) > 1 ? ' ' . html::span('email', rcube::Q($email)) : '')
|
||||
)), $classname);
|
||||
}
|
||||
}
|
||||
|
||||
// search request ID
|
||||
$search_request = md5('composeaddr' . $search);
|
||||
|
||||
// save search settings in session
|
||||
$_SESSION['search'][$search_request] = $search_set;
|
||||
$_SESSION['search_params'] = array('id' => $search_request, 'data' => array($afields, $search));
|
||||
|
||||
$OUTPUT->show_message('contactsearchsuccessful', 'confirmation', array('nr' => $result->count));
|
||||
|
||||
$OUTPUT->set_env('search_request', $search_request);
|
||||
$OUTPUT->set_env('source', '');
|
||||
$OUTPUT->command('unselect_directory');
|
||||
}
|
||||
else if (!$group_count) {
|
||||
$OUTPUT->show_message('nocontactsfound', 'notice');
|
||||
}
|
||||
|
||||
// update env
|
||||
$OUTPUT->set_env('contactdata', $jsresult);
|
||||
$OUTPUT->set_env('pagecount', ceil($result->count / $page_size));
|
||||
$OUTPUT->command('set_page_buttons');
|
||||
|
||||
// send response
|
||||
$OUTPUT->send();
|
963
data/web/rc/program/steps/mail/sendmail.inc
Normal file
963
data/web/rc/program/steps/mail/sendmail.inc
Normal file
@@ -0,0 +1,963 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
+-----------------------------------------------------------------------+
|
||||
| program/steps/mail/sendmail.inc |
|
||||
| |
|
||||
| This file is part of the Roundcube Webmail client |
|
||||
| Copyright (C) 2005-2013, The Roundcube Dev Team |
|
||||
| |
|
||||
| Licensed under the GNU General Public License version 3 or |
|
||||
| any later version with exceptions for skins & plugins. |
|
||||
| See the README file for a full license statement. |
|
||||
| |
|
||||
| PURPOSE: |
|
||||
| Compose a new mail message with all headers and attachments |
|
||||
| and send it using the PEAR::Net_SMTP class or with PHP mail() |
|
||||
| |
|
||||
+-----------------------------------------------------------------------+
|
||||
| Author: Thomas Bruederli <roundcube@gmail.com> |
|
||||
+-----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
// remove all scripts and act as called in frame
|
||||
$OUTPUT->reset();
|
||||
$OUTPUT->framed = TRUE;
|
||||
|
||||
$saveonly = !empty($_GET['_saveonly']);
|
||||
$savedraft = !empty($_POST['_draft']) && !$saveonly;
|
||||
$sendmail_delay = (int) $RCMAIL->config->get('sendmail_delay');
|
||||
$drafts_mbox = $RCMAIL->config->get('drafts_mbox');
|
||||
|
||||
$COMPOSE_ID = rcube_utils::get_input_value('_id', rcube_utils::INPUT_GPC);
|
||||
$COMPOSE =& $_SESSION['compose_data_'.$COMPOSE_ID];
|
||||
|
||||
/****** checks ********/
|
||||
|
||||
if (!isset($COMPOSE['id'])) {
|
||||
rcube::raise_error(array('code' => 500, 'type' => 'php',
|
||||
'file' => __FILE__, 'line' => __LINE__,
|
||||
'message' => "Invalid compose ID"), true, false);
|
||||
|
||||
$OUTPUT->show_message('internalerror', 'error');
|
||||
$OUTPUT->send('iframe');
|
||||
}
|
||||
|
||||
if (!$savedraft) {
|
||||
if (empty($_POST['_to']) && empty($_POST['_cc']) && empty($_POST['_bcc']) && $_POST['_message']) {
|
||||
$OUTPUT->show_message('sendingfailed', 'error');
|
||||
$OUTPUT->send('iframe');
|
||||
}
|
||||
|
||||
if ($sendmail_delay) {
|
||||
$wait_sec = time() - $sendmail_delay - intval($RCMAIL->config->get('last_message_time'));
|
||||
if ($wait_sec < 0) {
|
||||
$OUTPUT->show_message('senttooquickly', 'error', array('sec' => $wait_sec * -1));
|
||||
$OUTPUT->send('iframe');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/****** compose message ********/
|
||||
|
||||
// set default charset
|
||||
$message_charset = isset($_POST['_charset']) ? $_POST['_charset'] : $OUTPUT->get_charset();
|
||||
|
||||
$EMAIL_FORMAT_ERROR = NULL;
|
||||
$RECIPIENT_COUNT = 0;
|
||||
|
||||
$mailto = rcmail_email_input_format(rcube_utils::get_input_value('_to', rcube_utils::INPUT_POST, TRUE, $message_charset), true);
|
||||
$mailcc = rcmail_email_input_format(rcube_utils::get_input_value('_cc', rcube_utils::INPUT_POST, TRUE, $message_charset), true);
|
||||
$mailbcc = rcmail_email_input_format(rcube_utils::get_input_value('_bcc', rcube_utils::INPUT_POST, TRUE, $message_charset), true);
|
||||
|
||||
if ($EMAIL_FORMAT_ERROR && !$savedraft) {
|
||||
$OUTPUT->show_message('emailformaterror', 'error', array('email' => $EMAIL_FORMAT_ERROR));
|
||||
$OUTPUT->send('iframe');
|
||||
}
|
||||
|
||||
if (empty($mailto) && !empty($mailcc)) {
|
||||
$mailto = $mailcc;
|
||||
$mailcc = null;
|
||||
}
|
||||
else if (empty($mailto)) {
|
||||
$mailto = 'undisclosed-recipients:;';
|
||||
}
|
||||
|
||||
// Get sender name and address...
|
||||
$from = rcube_utils::get_input_value('_from', rcube_utils::INPUT_POST, true, $message_charset);
|
||||
// ... from identity...
|
||||
if (is_numeric($from)) {
|
||||
if (is_array($identity_arr = rcmail_get_identity($from))) {
|
||||
if ($identity_arr['mailto'])
|
||||
$from = $identity_arr['mailto'];
|
||||
if ($identity_arr['string'])
|
||||
$from_string = $identity_arr['string'];
|
||||
}
|
||||
else {
|
||||
$from = null;
|
||||
}
|
||||
}
|
||||
// ... if there is no identity record, this might be a custom from
|
||||
else if (($from_string = rcmail_email_input_format($from))
|
||||
&& preg_match('/(\S+@\S+)/', $from_string, $m)
|
||||
) {
|
||||
$from = trim($m[1], '<>');
|
||||
}
|
||||
// ... otherwise it's empty or invalid
|
||||
else {
|
||||
$from = null;
|
||||
}
|
||||
|
||||
// check 'From' address (identity may be incomplete)
|
||||
if (!$savedraft && !$saveonly && empty($from)) {
|
||||
$OUTPUT->show_message('nofromaddress', 'error');
|
||||
$OUTPUT->send('iframe');
|
||||
}
|
||||
|
||||
if (!$from_string && $from) {
|
||||
$from_string = $from;
|
||||
}
|
||||
|
||||
if (empty($COMPOSE['param']['message-id'])) {
|
||||
$COMPOSE['param']['message-id'] = $RCMAIL->gen_message_id($from);
|
||||
}
|
||||
$message_id = $COMPOSE['param']['message-id'];
|
||||
|
||||
// compose headers array
|
||||
$headers = array();
|
||||
|
||||
// if configured, the Received headers goes to top, for good measure
|
||||
if ($RCMAIL->config->get('http_received_header')) {
|
||||
$nldlm = "\r\n\t";
|
||||
$http_header = 'from ';
|
||||
|
||||
// FROM/VIA
|
||||
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
|
||||
$hosts = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'], 2);
|
||||
$http_header .= rcmail_received_host($hosts[0]) . $nldlm . ' via ';
|
||||
}
|
||||
|
||||
$http_header .= rcmail_received_host($_SERVER['REMOTE_ADDR']);
|
||||
|
||||
// BY
|
||||
$http_header .= $nldlm . 'by ' . $_SERVER['HTTP_HOST'];
|
||||
|
||||
// WITH
|
||||
$http_header .= $nldlm . 'with HTTP (' . $_SERVER['SERVER_PROTOCOL']
|
||||
. ' ' . $_SERVER['REQUEST_METHOD'] . '); ' . date('r');
|
||||
|
||||
$headers['Received'] = wordwrap($http_header, 69, $nldlm);
|
||||
}
|
||||
|
||||
$headers['Date'] = $RCMAIL->user_date();
|
||||
$headers['From'] = rcube_charset::convert($from_string, RCUBE_CHARSET, $message_charset);
|
||||
$headers['To'] = $mailto;
|
||||
|
||||
// additional recipients
|
||||
if (!empty($mailcc)) {
|
||||
$headers['Cc'] = $mailcc;
|
||||
}
|
||||
if (!empty($mailbcc)) {
|
||||
$headers['Bcc'] = $mailbcc;
|
||||
}
|
||||
|
||||
if (($max_recipients = (int) $RCMAIL->config->get('max_recipients')) > 0) {
|
||||
if ($RECIPIENT_COUNT > $max_recipients) {
|
||||
$OUTPUT->show_message('toomanyrecipients', 'error', array('max' => $max_recipients));
|
||||
$OUTPUT->send('iframe');
|
||||
}
|
||||
}
|
||||
|
||||
$dont_override = (array) $RCMAIL->config->get('dont_override');
|
||||
$mdn_enabled = in_array('mdn_default', $dont_override) ? $RCMAIL->config->get('mdn_default') : !empty($_POST['_mdn']);
|
||||
$dsn_enabled = in_array('dsn_default', $dont_override) ? $RCMAIL->config->get('dsn_default') : !empty($_POST['_dsn']);
|
||||
$subject = trim(rcube_utils::get_input_value('_subject', rcube_utils::INPUT_POST, TRUE, $message_charset));
|
||||
|
||||
if (strlen($subject)) {
|
||||
$headers['Subject'] = $subject;
|
||||
}
|
||||
if (!empty($identity_arr['organization'])) {
|
||||
$headers['Organization'] = $identity_arr['organization'];
|
||||
}
|
||||
if ($hdr = rcube_utils::get_input_value('_replyto', rcube_utils::INPUT_POST, TRUE, $message_charset)) {
|
||||
$headers['Reply-To'] = rcmail_email_input_format($hdr);
|
||||
}
|
||||
if (!empty($headers['Reply-To'])) {
|
||||
$headers['Mail-Reply-To'] = $headers['Reply-To'];
|
||||
}
|
||||
if ($hdr = rcube_utils::get_input_value('_followupto', rcube_utils::INPUT_POST, TRUE, $message_charset)) {
|
||||
$headers['Mail-Followup-To'] = rcmail_email_input_format($hdr);
|
||||
}
|
||||
|
||||
// remember reply/forward UIDs in special headers
|
||||
if ($savedraft) {
|
||||
// Note: We ignore <UID>.<PART> forwards/replies here
|
||||
if (($uid = $COMPOSE['reply_uid']) && !preg_match('/^\d+\.[0-9.]+$/', $uid)) {
|
||||
$headers['X-Draft-Info'] = array('type' => 'reply', 'uid' => $uid);
|
||||
}
|
||||
else if (!empty($COMPOSE['forward_uid'])
|
||||
&& ($uid = rcube_imap_generic::compressMessageSet($COMPOSE['forward_uid']))
|
||||
&& !preg_match('/^\d+[0-9.]+$/', $uid)
|
||||
) {
|
||||
$headers['X-Draft-Info'] = array('type' => 'forward', 'uid' => $uid);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($COMPOSE['reply_msgid'])) {
|
||||
$headers['In-Reply-To'] = $COMPOSE['reply_msgid'];
|
||||
}
|
||||
if (!empty($COMPOSE['references'])) {
|
||||
$headers['References'] = $COMPOSE['references'];
|
||||
}
|
||||
|
||||
if (!empty($_POST['_priority'])) {
|
||||
$priority = intval($_POST['_priority']);
|
||||
$a_priorities = array(1 => 'highest', 2 => 'high', 4 => 'low', 5 => 'lowest');
|
||||
|
||||
if ($str_priority = $a_priorities[$priority]) {
|
||||
$headers['X-Priority'] = sprintf("%d (%s)", $priority, ucfirst($str_priority));
|
||||
}
|
||||
}
|
||||
|
||||
if ($mdn_enabled) {
|
||||
$headers['Return-Receipt-To'] = $from_string;
|
||||
$headers['Disposition-Notification-To'] = $from_string;
|
||||
}
|
||||
|
||||
// additional headers
|
||||
$headers['Message-ID'] = $message_id;
|
||||
$headers['X-Sender'] = $from;
|
||||
|
||||
if (is_array($headers['X-Draft-Info'])) {
|
||||
$headers['X-Draft-Info'] = rcmail_draftinfo_encode($headers['X-Draft-Info'] + array('folder' => $COMPOSE['mailbox']));
|
||||
}
|
||||
if ($hdr = $RCMAIL->config->get('useragent')) {
|
||||
$headers['User-Agent'] = $hdr;
|
||||
}
|
||||
|
||||
// exec hook for header checking and manipulation
|
||||
// Depracated: use message_before_send hook instead
|
||||
$data = $RCMAIL->plugins->exec_hook('message_outgoing_headers', array('headers' => $headers));
|
||||
|
||||
// sending aborted by plugin
|
||||
if ($data['abort'] && !$savedraft) {
|
||||
$OUTPUT->show_message($data['message'] ?: 'sendingfailed');
|
||||
$OUTPUT->send('iframe');
|
||||
}
|
||||
else {
|
||||
$headers = $data['headers'];
|
||||
}
|
||||
|
||||
$isHtml = (bool) rcube_utils::get_input_value('_is_html', rcube_utils::INPUT_POST);
|
||||
|
||||
// fetch message body
|
||||
$message_body = rcube_utils::get_input_value('_message', rcube_utils::INPUT_POST, TRUE, $message_charset);
|
||||
|
||||
if (isset($_POST['_pgpmime'])) {
|
||||
$pgp_mime = rcube_utils::get_input_value('_pgpmime', rcube_utils::INPUT_POST);
|
||||
$isHtml = false;
|
||||
$message_body = '';
|
||||
|
||||
// clear unencrypted attachments
|
||||
foreach ((array) $COMPOSE['attachments'] as $attach) {
|
||||
$RCMAIL->plugins->exec_hook('attachment_delete', $attach);
|
||||
}
|
||||
|
||||
$COMPOSE['attachments'] = array();
|
||||
}
|
||||
|
||||
if ($isHtml) {
|
||||
$bstyle = array();
|
||||
|
||||
if ($font_size = $RCMAIL->config->get('default_font_size')) {
|
||||
$bstyle[] = 'font-size: ' . $font_size;
|
||||
}
|
||||
if ($font_family = $RCMAIL->config->get('default_font')) {
|
||||
$bstyle[] = 'font-family: ' . rcmail::font_defs($font_family);
|
||||
}
|
||||
|
||||
// append doctype and html/body wrappers
|
||||
$bstyle = !empty($bstyle) ? (" style='" . implode($bstyle, '; ') . "'") : '';
|
||||
$message_body = '<html><head>'
|
||||
. '<meta http-equiv="Content-Type" content="text/html; charset=' . $message_charset . '" /></head>'
|
||||
. "<body" . $bstyle . ">\r\n" . $message_body;
|
||||
}
|
||||
|
||||
if (!$savedraft) {
|
||||
if ($isHtml) {
|
||||
$b_style = 'padding: 0 0.4em; border-left: #1010ff 2px solid; margin: 0';
|
||||
$pre_style = 'margin: 0; padding: 0; font-family: monospace';
|
||||
|
||||
$message_body = preg_replace(
|
||||
array(
|
||||
// remove empty signature div
|
||||
'/<div id="_rc_sig">( )?<\/div>[\s\r\n]*$/',
|
||||
// remove signature's div ID
|
||||
'/\s*id="_rc_sig"/',
|
||||
// add inline css for blockquotes and container
|
||||
'/<blockquote>/',
|
||||
'/<div class="pre">/',
|
||||
// convert TinyMCE's new-line sequences (#1490463)
|
||||
'/<p> <\/p>/',
|
||||
),
|
||||
array(
|
||||
'',
|
||||
'',
|
||||
'<blockquote type="cite" style="'.$b_style.'">',
|
||||
'<div class="pre" style="'.$pre_style.'">',
|
||||
'<p><br /></p>',
|
||||
),
|
||||
$message_body);
|
||||
}
|
||||
|
||||
// Check spelling before send
|
||||
if ($RCMAIL->config->get('spellcheck_before_send') && $RCMAIL->config->get('enable_spellcheck')
|
||||
&& empty($COMPOSE['spell_checked']) && !empty($message_body)
|
||||
) {
|
||||
$message_body = str_replace("\r\n", "\n", $message_body);
|
||||
$spellchecker = new rcube_spellchecker(rcube_utils::get_input_value('_lang', rcube_utils::INPUT_GPC));
|
||||
$spell_result = $spellchecker->check($message_body, $isHtml);
|
||||
|
||||
$COMPOSE['spell_checked'] = true;
|
||||
|
||||
if (!$spell_result) {
|
||||
if ($isHtml) {
|
||||
$result['words'] = $spellchecker->get();
|
||||
$result['dictionary'] = (bool) $RCMAIL->config->get('spellcheck_dictionary');
|
||||
}
|
||||
else {
|
||||
$result = $spellchecker->get_xml();
|
||||
}
|
||||
|
||||
$OUTPUT->show_message('mispellingsfound', 'error');
|
||||
$OUTPUT->command('spellcheck_resume', $result);
|
||||
$OUTPUT->send('iframe');
|
||||
}
|
||||
}
|
||||
|
||||
// generic footer for all messages
|
||||
if ($footer = rcmail_generic_message_footer($isHtml)) {
|
||||
$footer = rcube_charset::convert($footer, RCUBE_CHARSET, $message_charset);
|
||||
$message_body .= "\r\n" . $footer;
|
||||
}
|
||||
}
|
||||
|
||||
if ($isHtml) {
|
||||
$message_body .= "\r\n</body></html>\r\n";
|
||||
}
|
||||
|
||||
// sort attachments to make sure the order is the same as in the UI (#1488423)
|
||||
if ($files = rcube_utils::get_input_value('_attachments', rcube_utils::INPUT_POST)) {
|
||||
$files = explode(',', $files);
|
||||
$files = array_flip($files);
|
||||
foreach ($files as $idx => $val) {
|
||||
$files[$idx] = $COMPOSE['attachments'][$idx];
|
||||
unset($COMPOSE['attachments'][$idx]);
|
||||
}
|
||||
|
||||
$COMPOSE['attachments'] = array_merge(array_filter($files), $COMPOSE['attachments']);
|
||||
}
|
||||
|
||||
// set line length for body wrapping
|
||||
$LINE_LENGTH = $RCMAIL->config->get('line_length', 72);
|
||||
|
||||
// Since we can handle big messages with disk usage, we need more time to work
|
||||
@set_time_limit(0);
|
||||
|
||||
// create PEAR::Mail_mime instance
|
||||
$MAIL_MIME = new Mail_mime("\r\n");
|
||||
|
||||
// Check if we have enough memory to handle the message in it
|
||||
// It's faster than using files, so we'll do this if we only can
|
||||
if (is_array($COMPOSE['attachments']) && ($mem_limit = parse_bytes(ini_get('memory_limit')))) {
|
||||
$memory = 0;
|
||||
foreach ($COMPOSE['attachments'] as $id => $attachment) {
|
||||
$memory += $attachment['size'];
|
||||
}
|
||||
|
||||
// Yeah, Net_SMTP needs up to 12x more memory, 1.33 is for base64
|
||||
if (!rcube_utils::mem_check($memory * 1.33 * 12)) {
|
||||
$MAIL_MIME->setParam('delay_file_io', true);
|
||||
}
|
||||
}
|
||||
|
||||
// For HTML-formatted messages, construct the MIME message with both
|
||||
// the HTML part and the plain-text part
|
||||
if ($isHtml) {
|
||||
$plugin = $RCMAIL->plugins->exec_hook('message_outgoing_body',
|
||||
array('body' => $message_body, 'type' => 'html', 'message' => $MAIL_MIME));
|
||||
|
||||
$MAIL_MIME->setHTMLBody($plugin['body']);
|
||||
|
||||
$plainTextPart = $RCMAIL->html2text($plugin['body'], array('width' => 0, 'charset' => $message_charset));
|
||||
$plainTextPart = rcube_mime::wordwrap($plainTextPart, $LINE_LENGTH, "\r\n", false, $message_charset);
|
||||
$plainTextPart = wordwrap($plainTextPart, 998, "\r\n", true);
|
||||
|
||||
// There's no sense to use multipart/alternative if the text/plain
|
||||
// part would be blank. Completely blank text/plain part may confuse
|
||||
// some mail clients (#5283)
|
||||
if (strlen(trim($plainTextPart)) > 0) {
|
||||
// make sure all line endings are CRLF (#1486712)
|
||||
$plainTextPart = preg_replace('/\r?\n/', "\r\n", $plainTextPart);
|
||||
|
||||
$plugin = $RCMAIL->plugins->exec_hook('message_outgoing_body',
|
||||
array('body' => $plainTextPart, 'type' => 'alternative', 'message' => $MAIL_MIME));
|
||||
|
||||
// add a plain text version of the e-mail as an alternative part.
|
||||
$MAIL_MIME->setTXTBody($plugin['body']);
|
||||
}
|
||||
|
||||
// Extract image Data URIs into message attachments (#1488502)
|
||||
rcmail_extract_inline_images($MAIL_MIME, $from);
|
||||
}
|
||||
else {
|
||||
$plugin = $RCMAIL->plugins->exec_hook('message_outgoing_body',
|
||||
array('body' => $message_body, 'type' => 'plain', 'message' => $MAIL_MIME));
|
||||
|
||||
$message_body = $plugin['body'];
|
||||
|
||||
// compose format=flowed content if enabled
|
||||
if ($flowed = ($savedraft || $RCMAIL->config->get('send_format_flowed', true)))
|
||||
$message_body = rcube_mime::format_flowed($message_body, min($LINE_LENGTH+2, 79), $message_charset);
|
||||
else
|
||||
$message_body = rcube_mime::wordwrap($message_body, $LINE_LENGTH, "\r\n", false, $message_charset);
|
||||
|
||||
$message_body = wordwrap($message_body, 998, "\r\n", true);
|
||||
|
||||
$MAIL_MIME->setTXTBody($message_body, false, true);
|
||||
}
|
||||
|
||||
// add stored attachments, if any
|
||||
if (is_array($COMPOSE['attachments'])) {
|
||||
foreach ($COMPOSE['attachments'] as $id => $attachment) {
|
||||
// This hook retrieves the attachment contents from the file storage backend
|
||||
$attachment = $RCMAIL->plugins->exec_hook('attachment_get', $attachment);
|
||||
|
||||
if ($isHtml) {
|
||||
$dispurl = '/[\'"]\S+display-attachment\S+file=rcmfile' . preg_quote($attachment['id']) . '[\'"]/';
|
||||
$message_body = $MAIL_MIME->getHTMLBody();
|
||||
$is_inline = preg_match($dispurl, $message_body);
|
||||
}
|
||||
else {
|
||||
$is_inline = false;
|
||||
}
|
||||
|
||||
// inline image
|
||||
if ($is_inline) {
|
||||
// Mail_Mime does not support many inline attachments with the same name (#1489406)
|
||||
// we'll generate cid: urls here to workaround this
|
||||
$cid = preg_replace('/[^0-9a-zA-Z]/', '', uniqid(time(), true));
|
||||
if (preg_match('#(@[0-9a-zA-Z\-\.]+)#', $from, $matches)) {
|
||||
$cid .= $matches[1];
|
||||
}
|
||||
else {
|
||||
$cid .= '@localhost';
|
||||
}
|
||||
|
||||
$message_body = preg_replace($dispurl, '"cid:' . $cid . '"', $message_body);
|
||||
|
||||
$MAIL_MIME->setHTMLBody($message_body);
|
||||
|
||||
if ($attachment['data'])
|
||||
$MAIL_MIME->addHTMLImage($attachment['data'], $attachment['mimetype'], $attachment['name'], false, $cid);
|
||||
else
|
||||
$MAIL_MIME->addHTMLImage($attachment['path'], $attachment['mimetype'], $attachment['name'], true, $cid);
|
||||
}
|
||||
else {
|
||||
$ctype = str_replace('image/pjpeg', 'image/jpeg', $attachment['mimetype']); // #1484914
|
||||
$file = $attachment['data'] ?: $attachment['path'];
|
||||
$folding = (int) $RCMAIL->config->get('mime_param_folding');
|
||||
|
||||
$MAIL_MIME->addAttachment($file,
|
||||
$ctype,
|
||||
$attachment['name'],
|
||||
$attachment['data'] ? false : true,
|
||||
$ctype == 'message/rfc822' ? '8bit' : 'base64',
|
||||
'attachment',
|
||||
$attachment['charset'],
|
||||
'', '',
|
||||
$folding ? 'quoted-printable' : NULL,
|
||||
$folding == 2 ? 'quoted-printable' : NULL,
|
||||
'', RCUBE_CHARSET
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// choose transfer encoding for plain/text body
|
||||
if (preg_match('/[^\x00-\x7F]/', $MAIL_MIME->getTXTBody())) {
|
||||
$text_charset = $message_charset;
|
||||
$transfer_encoding = $RCMAIL->config->get('force_7bit') ? 'quoted-printable' : '8bit';
|
||||
}
|
||||
else {
|
||||
$text_charset = 'US-ASCII';
|
||||
$transfer_encoding = '7bit';
|
||||
}
|
||||
|
||||
if ($flowed) {
|
||||
$text_charset .= ";\r\n format=flowed";
|
||||
}
|
||||
|
||||
// compose PGP/Mime message
|
||||
if ($pgp_mime) {
|
||||
$MAIL_MIME->addAttachment(new Mail_mimePart('Version: 1', array(
|
||||
'content_type' => 'application/pgp-encrypted',
|
||||
'description' => 'PGP/MIME version identification',
|
||||
)));
|
||||
|
||||
$MAIL_MIME->addAttachment(new Mail_mimePart($pgp_mime, array(
|
||||
'content_type' => 'application/octet-stream',
|
||||
'filename' => 'encrypted.asc',
|
||||
'disposition' => 'inline',
|
||||
)));
|
||||
|
||||
$MAIL_MIME->setContentType('multipart/encrypted', array('protocol' => 'application/pgp-encrypted'));
|
||||
$MAIL_MIME->setParam('preamble', 'This is an OpenPGP/MIME encrypted message (RFC 2440 and 3156)');
|
||||
}
|
||||
|
||||
// encoding settings for mail composing
|
||||
$MAIL_MIME->setParam('text_encoding', $transfer_encoding);
|
||||
$MAIL_MIME->setParam('html_encoding', 'quoted-printable');
|
||||
$MAIL_MIME->setParam('head_encoding', 'quoted-printable');
|
||||
$MAIL_MIME->setParam('head_charset', $message_charset);
|
||||
$MAIL_MIME->setParam('html_charset', $message_charset);
|
||||
$MAIL_MIME->setParam('text_charset', $text_charset);
|
||||
|
||||
// pass headers to message object
|
||||
$MAIL_MIME->headers($headers);
|
||||
|
||||
// This hook allows to modify the message before send or save action
|
||||
$plugin = $RCMAIL->plugins->exec_hook('message_ready', array('message' => $MAIL_MIME));
|
||||
$MAIL_MIME = $plugin['message'];
|
||||
|
||||
// Begin SMTP Delivery Block
|
||||
if (!$savedraft && !$saveonly) {
|
||||
// Handle Delivery Status Notification request
|
||||
$smtp_opts['dsn'] = $dsn_enabled;
|
||||
|
||||
$sent = $RCMAIL->deliver_message($MAIL_MIME, $from, $mailto,
|
||||
$smtp_error, $mailbody_file, $smtp_opts, true);
|
||||
|
||||
// return to compose page if sending failed
|
||||
if (!$sent) {
|
||||
// remove temp file
|
||||
if ($mailbody_file) {
|
||||
unlink($mailbody_file);
|
||||
}
|
||||
|
||||
if ($smtp_error && is_string($smtp_error)) {
|
||||
$OUTPUT->show_message($smtp_error, 'error');
|
||||
}
|
||||
else if ($smtp_error && !empty($smtp_error['label'])) {
|
||||
$OUTPUT->show_message($smtp_error['label'], 'error', $smtp_error['vars']);
|
||||
}
|
||||
else {
|
||||
$OUTPUT->show_message('sendingfailed', 'error');
|
||||
}
|
||||
|
||||
$OUTPUT->send('iframe');
|
||||
}
|
||||
|
||||
// save message sent time
|
||||
if ($sendmail_delay) {
|
||||
$RCMAIL->user->save_prefs(array('last_message_time' => time()));
|
||||
}
|
||||
|
||||
// set replied/forwarded flag
|
||||
if ($COMPOSE['reply_uid']) {
|
||||
foreach (rcmail::get_uids($COMPOSE['reply_uid'], $COMPOSE['mailbox']) as $mbox => $uids) {
|
||||
// skip <UID>.<PART> replies
|
||||
if (!preg_match('/^\d+\.[0-9.]+$/', implode(',', (array) $uids))) {
|
||||
$RCMAIL->storage->set_flag($uids, 'ANSWERED', $mbox);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ($COMPOSE['forward_uid']) {
|
||||
foreach (rcmail::get_uids($COMPOSE['forward_uid'], $COMPOSE['mailbox']) as $mbox => $uids) {
|
||||
// skip <UID>.<PART> forwards
|
||||
if (!preg_match('/^\d+\.[0-9.]+$/', implode(',', (array) $uids))) {
|
||||
$RCMAIL->storage->set_flag($uids, 'FORWARDED', $mbox);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Determine which folder to save message
|
||||
if ($savedraft) {
|
||||
$store_target = $drafts_mbox;
|
||||
}
|
||||
else if (!$RCMAIL->config->get('no_save_sent_messages')) {
|
||||
if (isset($_POST['_store_target'])) {
|
||||
$store_target = rcube_utils::get_input_value('_store_target', rcube_utils::INPUT_POST);
|
||||
}
|
||||
else {
|
||||
$store_target = $RCMAIL->config->get('sent_mbox');
|
||||
}
|
||||
}
|
||||
|
||||
if ($store_target) {
|
||||
// check if folder is subscribed
|
||||
if ($RCMAIL->storage->folder_exists($store_target, true)) {
|
||||
$store_folder = true;
|
||||
}
|
||||
// folder may be existing but not subscribed (#1485241)
|
||||
else if (!$RCMAIL->storage->folder_exists($store_target)) {
|
||||
$store_folder = $RCMAIL->storage->create_folder($store_target, true);
|
||||
}
|
||||
else if ($RCMAIL->storage->subscribe($store_target)) {
|
||||
$store_folder = true;
|
||||
}
|
||||
|
||||
// append message to sent box
|
||||
if ($store_folder) {
|
||||
// message body in file
|
||||
if ($mailbody_file || $MAIL_MIME->getParam('delay_file_io')) {
|
||||
$headers = $MAIL_MIME->txtHeaders();
|
||||
|
||||
// file already created
|
||||
if ($mailbody_file) {
|
||||
$msg = $mailbody_file;
|
||||
}
|
||||
else {
|
||||
$temp_dir = $RCMAIL->config->get('temp_dir');
|
||||
$mailbody_file = tempnam($temp_dir, 'rcmMsg');
|
||||
$msg = $MAIL_MIME->saveMessageBody($mailbody_file);
|
||||
|
||||
if (!is_a($msg, 'PEAR_Error')) {
|
||||
$msg = $mailbody_file;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
$msg = $MAIL_MIME->getMessage();
|
||||
$headers = '';
|
||||
}
|
||||
|
||||
if (is_a($msg, 'PEAR_Error')) {
|
||||
rcube::raise_error(array('code' => 650, 'type' => 'php',
|
||||
'file' => __FILE__, 'line' => __LINE__,
|
||||
'message' => "Could not create message: ".$msg->getMessage()),
|
||||
true, false);
|
||||
}
|
||||
else {
|
||||
$saved = $RCMAIL->storage->save_message($store_target, $msg, $headers,
|
||||
$mailbody_file ? true : false, array('SEEN'));
|
||||
}
|
||||
|
||||
if ($mailbody_file) {
|
||||
unlink($mailbody_file);
|
||||
$mailbody_file = null;
|
||||
}
|
||||
}
|
||||
|
||||
// raise error if saving failed
|
||||
if (!$saved) {
|
||||
rcube::raise_error(array('code' => 800, 'type' => 'imap',
|
||||
'file' => __FILE__, 'line' => __LINE__,
|
||||
'message' => "Could not save message in $store_target"), true, false);
|
||||
|
||||
if ($savedraft) {
|
||||
$RCMAIL->display_server_error('errorsaving');
|
||||
|
||||
// start the auto-save timer again
|
||||
$OUTPUT->command('auto_save_start');
|
||||
$OUTPUT->send('iframe');
|
||||
}
|
||||
}
|
||||
}
|
||||
// remove temp file
|
||||
else if ($mailbody_file) {
|
||||
unlink($mailbody_file);
|
||||
}
|
||||
|
||||
// delete previous saved draft
|
||||
$old_id = rcube_utils::get_input_value('_draft_saveid', rcube_utils::INPUT_POST);
|
||||
if ($old_id && ($sent || $saved)) {
|
||||
$deleted = $RCMAIL->storage->delete_message($old_id, $drafts_mbox);
|
||||
|
||||
// raise error if deletion of old draft failed
|
||||
if (!$deleted) {
|
||||
rcube::raise_error(array('code' => 800, 'type' => 'imap',
|
||||
'file' => __FILE__, 'line' => __LINE__,
|
||||
'message' => "Could not delete message from $drafts_mbox"), true, false);
|
||||
}
|
||||
}
|
||||
|
||||
if ($savedraft) {
|
||||
// remember new draft-uid ($saved could be an UID or true/false here)
|
||||
if ($saved && is_bool($saved)) {
|
||||
$index = $RCMAIL->storage->search_once($drafts_mbox, 'HEADER Message-ID ' . $message_id);
|
||||
$saved = @max($index->get());
|
||||
}
|
||||
|
||||
if ($saved) {
|
||||
$plugin = $RCMAIL->plugins->exec_hook('message_draftsaved',
|
||||
array('msgid' => $message_id, 'uid' => $saved, 'folder' => $store_target));
|
||||
|
||||
// display success
|
||||
$OUTPUT->show_message($plugin['message'] ?: 'messagesaved', 'confirmation');
|
||||
|
||||
// update "_draft_saveid" and the "cmp_hash" to prevent "Unsaved changes" warning
|
||||
$COMPOSE['param']['draft_uid'] = $plugin['uid'];
|
||||
$OUTPUT->command('set_draft_id', $plugin['uid']);
|
||||
$OUTPUT->command('compose_field_hash', true);
|
||||
}
|
||||
|
||||
// start the auto-save timer again
|
||||
$OUTPUT->command('auto_save_start');
|
||||
}
|
||||
else {
|
||||
// Collect folders which could contain the composed message,
|
||||
// we'll refresh the list if currently opened folder is one of them (#1490238)
|
||||
$folders = array();
|
||||
|
||||
if (!$saveonly) {
|
||||
if (in_array($COMPOSE['mode'], array('reply', 'forward', 'draft'))) {
|
||||
$folders[] = $COMPOSE['mailbox'];
|
||||
}
|
||||
if (!empty($COMPOSE['param']['draft_uid']) && $drafts_mbox) {
|
||||
$folders[] = $drafts_mbox;
|
||||
}
|
||||
}
|
||||
|
||||
if ($store_folder && !$saved) {
|
||||
$params = $saveonly ? null : array('prefix' => true);
|
||||
$RCMAIL->display_server_error('errorsavingsent', null, null, $params);
|
||||
if ($saveonly) {
|
||||
$OUTPUT->send('iframe');
|
||||
}
|
||||
|
||||
$save_error = true;
|
||||
}
|
||||
else {
|
||||
rcmail_compose_cleanup($COMPOSE_ID);
|
||||
$OUTPUT->command('remove_compose_data', $COMPOSE_ID);
|
||||
|
||||
if ($store_folder) {
|
||||
$folders[] = $store_target;
|
||||
}
|
||||
}
|
||||
|
||||
$msg = $RCMAIL->gettext($saveonly ? 'successfullysaved' : 'messagesent');
|
||||
|
||||
$OUTPUT->command('sent_successfully', 'confirmation', $msg, $folders, $save_error);
|
||||
}
|
||||
|
||||
$OUTPUT->send('iframe');
|
||||
|
||||
|
||||
/****** message sending functions ********/
|
||||
|
||||
function rcmail_received_host($host)
|
||||
{
|
||||
$hostname = gethostbyaddr($host);
|
||||
|
||||
$result = rcmail_encrypt_host($hostname);
|
||||
|
||||
if ($host != $hostname) {
|
||||
$result .= ' (' . rcmail_encrypt_host($host) . ')';
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// encrypt host IP or hostname for Received header
|
||||
function rcmail_encrypt_host($host)
|
||||
{
|
||||
global $RCMAIL;
|
||||
|
||||
if ($RCMAIL->config->get('http_received_header_encrypt')) {
|
||||
return $RCMAIL->encrypt($host);
|
||||
}
|
||||
|
||||
if (!preg_match('/[^0-9:.]/', $host)) {
|
||||
return "[$host]";
|
||||
}
|
||||
|
||||
return $host;
|
||||
}
|
||||
|
||||
// get identity record
|
||||
function rcmail_get_identity($id)
|
||||
{
|
||||
global $RCMAIL, $message_charset;
|
||||
|
||||
if ($sql_arr = $RCMAIL->user->get_identity($id)) {
|
||||
$out = $sql_arr;
|
||||
|
||||
if ($message_charset != RCUBE_CHARSET) {
|
||||
foreach ($out as $k => $v) {
|
||||
$out[$k] = rcube_charset::convert($v, RCUBE_CHARSET, $message_charset);
|
||||
}
|
||||
}
|
||||
|
||||
$out['mailto'] = $sql_arr['email'];
|
||||
$out['string'] = format_email_recipient($sql_arr['email'], $sql_arr['name']);
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract image attachments from HTML content (data URIs)
|
||||
*/
|
||||
function rcmail_extract_inline_images($mime_message, $from)
|
||||
{
|
||||
$body = $mime_message->getHTMLBody();
|
||||
$offset = 0;
|
||||
$list = array();
|
||||
$domain = 'localhost';
|
||||
$regexp = '#img[^>]+src=[\'"](data:([^;]*);base64,([a-z0-9+/=\r\n]+))([\'"])#i';
|
||||
|
||||
if (preg_match_all($regexp, $body, $matches, PREG_OFFSET_CAPTURE)) {
|
||||
// get domain for the Content-ID, must be the same as in Mail_Mime::get()
|
||||
if (preg_match('#@([0-9a-zA-Z\-\.]+)#', $from, $m)) {
|
||||
$domain = $m[1];
|
||||
}
|
||||
|
||||
foreach ($matches[1] as $idx => $m) {
|
||||
$data = preg_replace('/\r\n/', '', $matches[3][$idx][0]);
|
||||
$data = base64_decode($data);
|
||||
|
||||
if (empty($data)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$hash = md5($data) . '@' . $domain;
|
||||
$mime_type = $matches[2][$idx][0];
|
||||
$name = $list[$hash];
|
||||
|
||||
if (empty($mime_type)) {
|
||||
$mime_type = rcube_mime::image_content_type($data);
|
||||
}
|
||||
|
||||
// add the image to the MIME message
|
||||
if (!$name) {
|
||||
$ext = preg_replace('#^[^/]+/#', '', $mime_type);
|
||||
$name = substr($hash, 0, 8) . '.' . $ext;
|
||||
$list[$hash] = $name;
|
||||
|
||||
$mime_message->addHTMLImage($data, $mime_type, $name, false, $hash);
|
||||
}
|
||||
|
||||
$body = substr_replace($body, $name, $m[1] + $offset, strlen($m[0]));
|
||||
$offset += strlen($name) - strlen($m[0]);
|
||||
}
|
||||
}
|
||||
|
||||
$mime_message->setHTMLBody($body);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse and cleanup email address input (and count addresses)
|
||||
*
|
||||
* @param string Address input
|
||||
* @param boolean Do count recipients (saved in global $RECIPIENT_COUNT)
|
||||
* @param boolean Validate addresses (errors saved in global $EMAIL_FORMAT_ERROR)
|
||||
* @return string Canonical recipients string separated by comma
|
||||
*/
|
||||
function rcmail_email_input_format($mailto, $count=false, $check=true)
|
||||
{
|
||||
global $RCMAIL, $EMAIL_FORMAT_ERROR, $RECIPIENT_COUNT;
|
||||
|
||||
// simplified email regexp, supporting quoted local part
|
||||
$email_regexp = '(\S+|("[^"]+"))@\S+';
|
||||
|
||||
$delim = trim($RCMAIL->config->get('recipients_separator', ','));
|
||||
$regexp = array("/[,;$delim]\s*[\r\n]+/", '/[\r\n]+/', "/[,;$delim]\s*\$/m", '/;/', '/(\S{1})(<'.$email_regexp.'>)/U');
|
||||
$replace = array($delim.' ', ', ', '', $delim, '\\1 \\2');
|
||||
|
||||
// replace new lines and strip ending ', ', make address input more valid
|
||||
$mailto = trim(preg_replace($regexp, $replace, $mailto));
|
||||
$items = rcube_utils::explode_quoted_string($delim, $mailto);
|
||||
$result = array();
|
||||
|
||||
foreach ($items as $item) {
|
||||
$item = trim($item);
|
||||
// address in brackets without name (do nothing)
|
||||
if (preg_match('/^<'.$email_regexp.'>$/', $item)) {
|
||||
$item = rcube_utils::idn_to_ascii(trim($item, '<>'));
|
||||
$result[] = $item;
|
||||
}
|
||||
// address without brackets and without name (add brackets)
|
||||
else if (preg_match('/^'.$email_regexp.'$/', $item)) {
|
||||
$item = rcube_utils::idn_to_ascii($item);
|
||||
$result[] = $item;
|
||||
}
|
||||
// address with name (handle name)
|
||||
else if (preg_match('/<*'.$email_regexp.'>*$/', $item, $matches)) {
|
||||
$address = $matches[0];
|
||||
$name = trim(str_replace($address, '', $item));
|
||||
if ($name[0] == '"' && $name[count($name)-1] == '"') {
|
||||
$name = substr($name, 1, -1);
|
||||
}
|
||||
$name = stripcslashes($name);
|
||||
$address = rcube_utils::idn_to_ascii(trim($address, '<>'));
|
||||
$result[] = format_email_recipient($address, $name);
|
||||
$item = $address;
|
||||
}
|
||||
else if (trim($item)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// check address format
|
||||
$item = trim($item, '<>');
|
||||
if ($item && $check && !rcube_utils::check_email($item)) {
|
||||
$EMAIL_FORMAT_ERROR = $item;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ($count) {
|
||||
$RECIPIENT_COUNT += count($result);
|
||||
}
|
||||
|
||||
return implode(', ', $result);
|
||||
}
|
||||
|
||||
|
||||
function rcmail_generic_message_footer($isHtml)
|
||||
{
|
||||
global $RCMAIL;
|
||||
|
||||
if ($isHtml && ($file = $RCMAIL->config->get('generic_message_footer_html'))) {
|
||||
$html_footer = true;
|
||||
}
|
||||
else {
|
||||
$file = $RCMAIL->config->get('generic_message_footer');
|
||||
$html_footer = false;
|
||||
}
|
||||
|
||||
if ($file && realpath($file)) {
|
||||
// sanity check
|
||||
if (!preg_match('/\.(php|ini|conf)$/', $file) && strpos($file, '/etc/') === false) {
|
||||
$footer = file_get_contents($file);
|
||||
if ($isHtml && !$html_footer) {
|
||||
$t2h = new rcube_text2html($footer, false);
|
||||
$footer = $t2h->get_html();
|
||||
}
|
||||
return $footer;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* clear message composing settings
|
||||
*/
|
||||
function rcmail_compose_cleanup($id)
|
||||
{
|
||||
if (!isset($_SESSION['compose_data_'.$id])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$rcmail = rcmail::get_instance();
|
||||
$rcmail->plugins->exec_hook('attachments_cleanup', array('group' => $id));
|
||||
$rcmail->session->remove('compose_data_'.$id);
|
||||
|
||||
$_SESSION['last_compose_session'] = $id;
|
||||
}
|
43
data/web/rc/program/steps/mail/sendmdn.inc
Normal file
43
data/web/rc/program/steps/mail/sendmdn.inc
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
+-----------------------------------------------------------------------+
|
||||
| program/steps/mail/sendmdn.inc |
|
||||
| |
|
||||
| This file is part of the Roundcube Webmail client |
|
||||
| Copyright (C) 2008-2013, The Roundcube Dev Team |
|
||||
| |
|
||||
| Licensed under the GNU General Public License version 3 or |
|
||||
| any later version with exceptions for skins & plugins. |
|
||||
| See the README file for a full license statement. |
|
||||
| |
|
||||
| PURPOSE: |
|
||||
| Send a message disposition notification for a specific mail |
|
||||
| |
|
||||
+-----------------------------------------------------------------------+
|
||||
| Author: Thomas Bruederli <roundcube@gmail.com> |
|
||||
+-----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
// only process ajax requests
|
||||
if (!$OUTPUT->ajax_call) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!empty($_POST['_uid'])) {
|
||||
$sent = rcmail_send_mdn(rcube_utils::get_input_value('_uid', rcube_utils::INPUT_POST), $smtp_error);
|
||||
}
|
||||
|
||||
// show either confirm or error message
|
||||
if ($sent) {
|
||||
$OUTPUT->set_env('mdn_request', false);
|
||||
$OUTPUT->show_message('receiptsent', 'confirmation');
|
||||
}
|
||||
else if ($smtp_error) {
|
||||
$OUTPUT->show_message($smtp_error['label'], 'error', $smtp_error['vars']);
|
||||
}
|
||||
else {
|
||||
$OUTPUT->show_message('errorsendingreceipt', 'error');
|
||||
}
|
||||
|
||||
$OUTPUT->send();
|
346
data/web/rc/program/steps/mail/show.inc
Normal file
346
data/web/rc/program/steps/mail/show.inc
Normal file
@@ -0,0 +1,346 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
+-----------------------------------------------------------------------+
|
||||
| program/steps/mail/show.inc |
|
||||
| |
|
||||
| This file is part of the Roundcube Webmail client |
|
||||
| Copyright (C) 2005-2013, The Roundcube Dev Team |
|
||||
| |
|
||||
| Licensed under the GNU General Public License version 3 or |
|
||||
| any later version with exceptions for skins & plugins. |
|
||||
| See the README file for a full license statement. |
|
||||
| |
|
||||
| PURPOSE: |
|
||||
| Display a mail message similar as a usual mail application does |
|
||||
| |
|
||||
+-----------------------------------------------------------------------+
|
||||
| Author: Thomas Bruederli <roundcube@gmail.com> |
|
||||
+-----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
$PRINT_MODE = $RCMAIL->action == 'print';
|
||||
|
||||
// Read browser capabilities and store them in session
|
||||
if ($caps = rcube_utils::get_input_value('_caps', rcube_utils::INPUT_GET)) {
|
||||
$browser_caps = array();
|
||||
foreach (explode(',', $caps) as $cap) {
|
||||
$cap = explode('=', $cap);
|
||||
$browser_caps[$cap[0]] = $cap[1];
|
||||
}
|
||||
$_SESSION['browser_caps'] = $browser_caps;
|
||||
}
|
||||
|
||||
$msg_id = rcube_utils::get_input_value('_uid', rcube_utils::INPUT_GET);
|
||||
$uid = preg_replace('/\.[0-9.]+$/', '', $msg_id);
|
||||
$mbox_name = $RCMAIL->storage->get_folder();
|
||||
|
||||
// similar code as in program/steps/mail/get.inc
|
||||
if ($uid) {
|
||||
// set message format (need to be done before rcube_message construction)
|
||||
if (!empty($_GET['_format'])) {
|
||||
$prefer_html = $_GET['_format'] == 'html';
|
||||
$RCMAIL->config->set('prefer_html', $prefer_html);
|
||||
$_SESSION['msg_formats'][$mbox_name.':'.$uid] = $prefer_html;
|
||||
}
|
||||
else if (isset($_SESSION['msg_formats'][$mbox_name.':'.$uid])) {
|
||||
$RCMAIL->config->set('prefer_html', $_SESSION['msg_formats'][$mbox_name.':'.$uid]);
|
||||
}
|
||||
|
||||
$MESSAGE = new rcube_message($msg_id, $mbox_name, intval($_GET['_safe']));
|
||||
|
||||
// if message not found (wrong UID)...
|
||||
if (empty($MESSAGE->headers)) {
|
||||
rcmail_message_error($uid);
|
||||
}
|
||||
|
||||
// show images?
|
||||
rcmail_check_safe($MESSAGE);
|
||||
|
||||
// set message charset as default
|
||||
if (!empty($MESSAGE->headers->charset)) {
|
||||
$RCMAIL->storage->set_charset($MESSAGE->headers->charset);
|
||||
}
|
||||
|
||||
$OUTPUT->set_pagetitle(abbreviate_string($MESSAGE->subject, 128, '...', true));
|
||||
|
||||
// set message environment
|
||||
$OUTPUT->set_env('uid', $msg_id);
|
||||
$OUTPUT->set_env('safemode', $MESSAGE->is_safe);
|
||||
$OUTPUT->set_env('message_context', $MESSAGE->context);
|
||||
$OUTPUT->set_env('sender', $MESSAGE->sender['string']);
|
||||
$OUTPUT->set_env('mailbox', $mbox_name);
|
||||
$OUTPUT->set_env('username', $RCMAIL->get_user_name());
|
||||
$OUTPUT->set_env('permaurl', $RCMAIL->url(array('_action' => 'show', '_uid' => $msg_id, '_mbox' => $mbox_name)));
|
||||
|
||||
if ($MESSAGE->headers->get('list-post', false)) {
|
||||
$OUTPUT->set_env('list_post', true);
|
||||
}
|
||||
|
||||
// set environment
|
||||
$OUTPUT->set_env('delimiter', $RCMAIL->storage->get_hierarchy_delimiter());
|
||||
$OUTPUT->set_env('mimetypes', rcmail_supported_mimetypes());
|
||||
|
||||
// set configuration
|
||||
$RCMAIL->set_env_config(array('delete_junk', 'flag_for_deletion', 'read_when_deleted',
|
||||
'skip_deleted', 'display_next', 'forward_attachment'));
|
||||
|
||||
// set special folders
|
||||
foreach (array('drafts', 'trash', 'junk') as $mbox) {
|
||||
if ($folder = $RCMAIL->config->get($mbox . '_mbox')) {
|
||||
$OUTPUT->set_env($mbox . '_mailbox', $folder);
|
||||
}
|
||||
}
|
||||
|
||||
if ($MESSAGE->has_html_part()) {
|
||||
$prefer_html = $RCMAIL->config->get('prefer_html');
|
||||
$OUTPUT->set_env('optional_format', $prefer_html ? 'text' : 'html');
|
||||
}
|
||||
|
||||
if (!$OUTPUT->ajax_call) {
|
||||
$OUTPUT->add_label('checkingmail', 'deletemessage', 'movemessagetotrash',
|
||||
'movingmessage', 'deletingmessage', 'markingmessage', 'replyall', 'replylist');
|
||||
}
|
||||
|
||||
// check for unset disposition notification
|
||||
if ($MESSAGE->headers->mdn_to
|
||||
&& $MESSAGE->context === null
|
||||
&& empty($MESSAGE->headers->flags['MDNSENT'])
|
||||
&& empty($MESSAGE->headers->flags['SEEN'])
|
||||
&& ($RCMAIL->storage->check_permflag('MDNSENT') || $RCMAIL->storage->check_permflag('*'))
|
||||
&& $mbox_name != $RCMAIL->config->get('drafts_mbox')
|
||||
&& $mbox_name != $RCMAIL->config->get('sent_mbox')
|
||||
) {
|
||||
$mdn_cfg = intval($RCMAIL->config->get('mdn_requests'));
|
||||
|
||||
if ($mdn_cfg == 1 || (($mdn_cfg == 3 || $mdn_cfg == 4) && rcmail_contact_exists($MESSAGE->sender['mailto']))) {
|
||||
// Send MDN
|
||||
if (rcmail_send_mdn($MESSAGE, $smtp_error))
|
||||
$OUTPUT->show_message('receiptsent', 'confirmation');
|
||||
else if ($smtp_error)
|
||||
$OUTPUT->show_message($smtp_error['label'], 'error', $smtp_error['vars']);
|
||||
else
|
||||
$OUTPUT->show_message('errorsendingreceipt', 'error');
|
||||
}
|
||||
else if ($mdn_cfg != 2 && $mdn_cfg != 4) {
|
||||
// Ask user
|
||||
$OUTPUT->add_label('mdnrequest');
|
||||
$OUTPUT->set_env('mdn_request', true);
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($MESSAGE->headers->flags['SEEN']) && $MESSAGE->context === null) {
|
||||
$v = intval($RCMAIL->config->get('mail_read_time'));
|
||||
if ($v > 0) {
|
||||
$OUTPUT->set_env('mail_read_time', $v);
|
||||
}
|
||||
else if ($v == 0) {
|
||||
$RCMAIL->output->command('set_unread_message', $MESSAGE->uid, $mbox_name);
|
||||
$RCMAIL->plugins->exec_hook('message_read', array(
|
||||
'uid' => $MESSAGE->uid,
|
||||
'mailbox' => $mbox_name,
|
||||
'message' => $MESSAGE,
|
||||
));
|
||||
|
||||
$set_seen_flag = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$OUTPUT->add_handlers(array(
|
||||
'messageattachments' => 'rcmail_message_attachments',
|
||||
'mailboxname' => 'rcmail_mailbox_name_display',
|
||||
'messageobjects' => 'rcmail_message_objects',
|
||||
'contactphoto' => 'rcmail_message_contactphoto',
|
||||
));
|
||||
|
||||
|
||||
if ($RCMAIL->action == 'print' && $OUTPUT->template_exists('messageprint'))
|
||||
$OUTPUT->send('messageprint', false);
|
||||
else if ($RCMAIL->action == 'preview' && $OUTPUT->template_exists('messagepreview'))
|
||||
$OUTPUT->send('messagepreview', false);
|
||||
else
|
||||
$OUTPUT->send('message', false);
|
||||
|
||||
|
||||
// mark message as read
|
||||
if (!empty($set_seen_flag)) {
|
||||
if ($RCMAIL->storage->set_flag($MESSAGE->uid, 'SEEN', $mbox_name)) {
|
||||
if ($count = rcmail_get_unseen_count($mbox_name)) {
|
||||
rcmail_set_unseen_count($mbox_name, $count - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit;
|
||||
|
||||
|
||||
function rcmail_message_attachments($attrib)
|
||||
{
|
||||
global $PRINT_MODE, $MESSAGE, $RCMAIL;
|
||||
|
||||
$out = $ol = '';
|
||||
$attachments = array();
|
||||
|
||||
if (sizeof($MESSAGE->attachments)) {
|
||||
foreach ($MESSAGE->attachments as $attach_prop) {
|
||||
$filename = rcmail_attachment_name($attach_prop, true);
|
||||
$filesize = $RCMAIL->message_part_size($attach_prop);
|
||||
|
||||
if ($PRINT_MODE) {
|
||||
$ol .= html::tag('li', array('id' => 'attach' . $attach_prop->mime_id),
|
||||
rcube::Q(sprintf("%s (%s)", $filename, $filesize)));
|
||||
}
|
||||
else {
|
||||
if ($attrib['maxlength'] && mb_strlen($filename) > $attrib['maxlength']) {
|
||||
$title = $filename;
|
||||
$filename = abbreviate_string($filename, $attrib['maxlength']);
|
||||
}
|
||||
else {
|
||||
$title = '';
|
||||
}
|
||||
|
||||
$size = ' ' . html::span('attachment-size', '(' . rcube::Q($filesize) . ')');
|
||||
$mimetype = rcmail_fix_mimetype($attach_prop->mimetype);
|
||||
$class = rcube_utils::file2class($mimetype, $filename);
|
||||
$id = 'attach' . $attach_prop->mime_id;
|
||||
$link = html::a(array(
|
||||
'href' => $MESSAGE->get_part_url($attach_prop->mime_id, false),
|
||||
'onclick' => sprintf('return %s.command(\'load-attachment\',\'%s\',this)',
|
||||
rcmail_output::JS_OBJECT_NAME, $attach_prop->mime_id),
|
||||
'onmouseover' => $title ? '' : 'rcube_webmail.long_subject_title_ex(this, 0)',
|
||||
'title' => $title,
|
||||
), rcube::Q($filename) . $size);
|
||||
|
||||
$ol .= html::tag('li', array('class' => $class, 'id' => $id), $link);
|
||||
|
||||
$attachments[$attach_prop->mime_id] = $mimetype;
|
||||
}
|
||||
}
|
||||
|
||||
$out = html::tag('ul', $attrib, $ol, html::$common_attrib);
|
||||
|
||||
$RCMAIL->output->set_env('attachments', $attachments);
|
||||
$RCMAIL->output->add_gui_object('attachments', $attrib['id']);
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
function rcmail_remote_objects_msg()
|
||||
{
|
||||
global $MESSAGE, $RCMAIL;
|
||||
|
||||
$attrib['id'] = 'remote-objects-message';
|
||||
$attrib['class'] = 'notice';
|
||||
$attrib['style'] = 'display: none';
|
||||
|
||||
$msg = rcube::Q($RCMAIL->gettext('blockedimages')) . ' ';
|
||||
$msg .= html::a(array(
|
||||
'href' => "#loadimages",
|
||||
'onclick' => rcmail_output::JS_OBJECT_NAME.".command('load-images')"
|
||||
),
|
||||
rcube::Q($RCMAIL->gettext('showimages')));
|
||||
|
||||
// add link to save sender in addressbook and reload message
|
||||
if ($MESSAGE->sender['mailto'] && $RCMAIL->config->get('show_images') == 1) {
|
||||
$msg .= ' ' . html::a(array(
|
||||
'href' => "#alwaysload",
|
||||
'onclick' => rcmail_output::JS_OBJECT_NAME.".command('always-load')",
|
||||
'style' => "white-space:nowrap"
|
||||
),
|
||||
rcube::Q($RCMAIL->gettext(array('name' => 'alwaysshow', 'vars' => array('sender' => $MESSAGE->sender['mailto'])))));
|
||||
}
|
||||
|
||||
$RCMAIL->output->add_gui_object('remoteobjectsmsg', $attrib['id']);
|
||||
|
||||
return html::div($attrib, $msg);
|
||||
}
|
||||
|
||||
function rcmail_message_buttons()
|
||||
{
|
||||
global $RCMAIL, $MESSAGE;
|
||||
|
||||
$delim = $RCMAIL->storage->get_hierarchy_delimiter();
|
||||
$dbox = $RCMAIL->config->get('drafts_mbox');
|
||||
|
||||
// the message is not a draft
|
||||
if ($MESSAGE->folder != $dbox && strpos($MESSAGE->folder, $dbox.$delim) !== 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$attrib['id'] = 'message-buttons';
|
||||
$attrib['class'] = 'notice';
|
||||
|
||||
$msg = rcube::Q($RCMAIL->gettext('isdraft')) . ' ';
|
||||
$msg .= html::a(array(
|
||||
'href' => "#edit",
|
||||
'onclick' => rcmail_output::JS_OBJECT_NAME.".command('edit')"
|
||||
),
|
||||
rcube::Q($RCMAIL->gettext('edit')));
|
||||
|
||||
return html::div($attrib, $msg);
|
||||
}
|
||||
|
||||
function rcmail_message_objects($attrib)
|
||||
{
|
||||
global $RCMAIL, $MESSAGE;
|
||||
|
||||
if (!$attrib['id'])
|
||||
$attrib['id'] = 'message-objects';
|
||||
|
||||
$content = array(
|
||||
rcmail_message_buttons(),
|
||||
rcmail_remote_objects_msg(),
|
||||
);
|
||||
|
||||
$plugin = $RCMAIL->plugins->exec_hook('message_objects',
|
||||
array('content' => $content, 'message' => $MESSAGE));
|
||||
|
||||
$content = implode("\n", $plugin['content']);
|
||||
|
||||
return html::div($attrib, $content);
|
||||
}
|
||||
|
||||
function rcmail_contact_exists($email)
|
||||
{
|
||||
global $RCMAIL;
|
||||
|
||||
if ($email) {
|
||||
// @TODO: search in all address books?
|
||||
$CONTACTS = $RCMAIL->get_address_book(-1, true);
|
||||
|
||||
if (is_object($CONTACTS)) {
|
||||
$existing = $CONTACTS->search('email', $email, 1, false);
|
||||
if ($existing->count) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function rcmail_message_contactphoto($attrib)
|
||||
{
|
||||
global $RCMAIL, $MESSAGE;
|
||||
|
||||
$placeholder = $attrib['placeholder'] ? $RCMAIL->output->abs_url($attrib['placeholder'], true) : null;
|
||||
$placeholder = $RCMAIL->output->asset_url($placeholder ?: 'program/resources/blank.gif');
|
||||
|
||||
if ($MESSAGE->sender) {
|
||||
$photo_img = $RCMAIL->url(array(
|
||||
'_task' => 'addressbook',
|
||||
'_action' => 'photo',
|
||||
'_email' => $MESSAGE->sender['mailto'],
|
||||
));
|
||||
|
||||
$attrib['onerror'] = "this.src = '$placeholder'";
|
||||
}
|
||||
else {
|
||||
$photo_img = $placeholder;
|
||||
}
|
||||
|
||||
return html::img(array('src' => $photo_img, 'alt' => $RCMAIL->gettext('contactphoto')) + $attrib);
|
||||
}
|
83
data/web/rc/program/steps/mail/viewsource.inc
Normal file
83
data/web/rc/program/steps/mail/viewsource.inc
Normal file
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
+-----------------------------------------------------------------------+
|
||||
| program/steps/mail/viewsource.inc |
|
||||
| |
|
||||
| This file is part of the Roundcube Webmail client |
|
||||
| Copyright (C) 2005-2016, The Roundcube Dev Team |
|
||||
| |
|
||||
| Licensed under the GNU General Public License version 3 or |
|
||||
| any later version with exceptions for skins & plugins. |
|
||||
| See the README file for a full license statement. |
|
||||
| |
|
||||
| PURPOSE: |
|
||||
| Display a mail message similar as a usual mail application does |
|
||||
| |
|
||||
+-----------------------------------------------------------------------+
|
||||
| Author: Thomas Bruederli <roundcube@gmail.com> |
|
||||
+-----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
if (!empty($_GET['_save'])) {
|
||||
$RCMAIL->request_security_check(rcube_utils::INPUT_GET);
|
||||
}
|
||||
|
||||
ob_end_clean();
|
||||
|
||||
// similar code as in program/steps/mail/get.inc
|
||||
if ($uid = rcube_utils::get_input_value('_uid', rcube_utils::INPUT_GET)) {
|
||||
if ($pos = strpos($uid, '.')) {
|
||||
$message = new rcube_message($uid);
|
||||
$headers = $message->headers;
|
||||
$part_id = substr($uid, $pos + 1);
|
||||
}
|
||||
else {
|
||||
$headers = $RCMAIL->storage->get_message_headers($uid);
|
||||
}
|
||||
|
||||
$charset = $headers->charset ?: $RCMAIL->config->get('default_charset');
|
||||
|
||||
header("Content-Type: text/plain; charset={$charset}");
|
||||
|
||||
if (!empty($_GET['_save'])) {
|
||||
$browser = $RCMAIL->output->browser;
|
||||
$subject = rcube_mime::decode_header($headers->subject, $headers->charset);
|
||||
$filename = rcmail_filename_from_subject(mb_substr($subject, 0, 128));
|
||||
$filename = ($filename ?: $uid) . '.eml';
|
||||
$filename = $browser->ie ? rawurlencode($filename) : addcslashes($filename, '"');
|
||||
|
||||
header("Content-Length: {$headers->size}");
|
||||
header("Content-Disposition: attachment; filename=\"$filename\"");
|
||||
}
|
||||
|
||||
if (isset($message)) {
|
||||
$message->get_part_body($part_id, empty($_GET['_save']), 0, -1);
|
||||
}
|
||||
else {
|
||||
$RCMAIL->storage->print_raw_body($uid, empty($_GET['_save']));
|
||||
}
|
||||
}
|
||||
else {
|
||||
rcube::raise_error(array(
|
||||
'code' => 500,
|
||||
'type' => 'php',
|
||||
'file' => __FILE__,
|
||||
'line' => __LINE__,
|
||||
'message' => "Message UID $uid not found"
|
||||
),
|
||||
true, true);
|
||||
}
|
||||
|
||||
exit;
|
||||
|
||||
|
||||
/**
|
||||
* Helper function to convert message subject into filename
|
||||
*/
|
||||
function rcmail_filename_from_subject($str)
|
||||
{
|
||||
$str = preg_replace('/[:\t\n\r\0\x0B\/]+\s*/', ' ', $str);
|
||||
|
||||
return trim($str, " \t\n\r\0\x0B./_");
|
||||
}
|
Reference in New Issue
Block a user