summaryrefslogtreecommitdiff
path: root/program/steps/mail
diff options
context:
space:
mode:
Diffstat (limited to 'program/steps/mail')
-rw-r--r--program/steps/mail/attachments.inc5
-rw-r--r--program/steps/mail/compose.inc142
-rw-r--r--program/steps/mail/func.inc71
-rw-r--r--program/steps/mail/sendmail.inc44
-rw-r--r--program/steps/mail/show.inc5
5 files changed, 183 insertions, 84 deletions
diff --git a/program/steps/mail/attachments.inc b/program/steps/mail/attachments.inc
index f83f6892e..85aa9542b 100644
--- a/program/steps/mail/attachments.inc
+++ b/program/steps/mail/attachments.inc
@@ -118,9 +118,12 @@ if (is_array($_FILES['_attachments']['tmp_name'])) {
'alt' => rcube_label('delete')
));
}
- else {
+ else if ($COMPOSE['textbuttons']) {
$button = Q(rcube_label('delete'));
}
+ else {
+ $button = '';
+ }
$content = html::a(array(
'href' => "#delete",
diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc
index bce4fd313..646d2bcd1 100644
--- a/program/steps/mail/compose.inc
+++ b/program/steps/mail/compose.inc
@@ -54,30 +54,12 @@ if (!is_array($COMPOSE))
$COMPOSE_ID = uniqid(mt_rand());
$_SESSION['compose_data_'.$COMPOSE_ID] = array(
'id' => $COMPOSE_ID,
- 'param' => request2param(RCUBE_INPUT_GET),
+ 'param' => rcube_utils::request2param(RCUBE_INPUT_GET, 'task|action', true),
'mailbox' => $RCMAIL->storage->get_folder(),
);
$COMPOSE =& $_SESSION['compose_data_'.$COMPOSE_ID];
- // process values like "mailto:foo@bar.com?subject=new+message&cc=another"
- if ($COMPOSE['param']['to']) {
- // #1486037: remove "mailto:" prefix
- $COMPOSE['param']['to'] = preg_replace('/^mailto:/i', '', $COMPOSE['param']['to']);
- $mailto = explode('?', $COMPOSE['param']['to']);
- if (count($mailto) > 1) {
- $COMPOSE['param']['to'] = $mailto[0];
- parse_str($mailto[1], $query);
- foreach ($query as $f => $val)
- $COMPOSE['param'][$f] = $val;
- }
- }
-
- // select folder where to save the sent message
- $COMPOSE['param']['sent_mbox'] = $RCMAIL->config->get('sent_mbox');
-
- // pipe compose parameters thru plugins
- $plugin = $RCMAIL->plugins->exec_hook('message_compose', $COMPOSE);
- $COMPOSE['param'] = array_merge($COMPOSE['param'], $plugin['param']);
+ rcmail_process_compose_params($COMPOSE);
// add attachments listed by message_compose hook
if (is_array($plugin['attachments'])) {
@@ -149,6 +131,11 @@ if ($font && !is_array($font)) {
$OUTPUT->set_env('default_font', $font);
}
+// default font size for HTML editor
+if ($font_size = $RCMAIL->config->get('default_font_size')) {
+ $OUTPUT->set_env('default_font_size', $font_size);
+}
+
// get reference message and set compose mode
if ($msg_uid = $COMPOSE['param']['draft_uid']) {
$compose_mode = RCUBE_COMPOSE_DRAFT;
@@ -166,6 +153,8 @@ else if ($msg_uid = $COMPOSE['param']['forward_uid']) {
else if ($msg_uid = $COMPOSE['param']['uid']) {
$compose_mode = RCUBE_COMPOSE_EDIT;
}
+
+$COMPOSE['mode'] = $compose_mode;
$OUTPUT->set_env('compose_mode', $compose_mode);
$config_show_sig = $RCMAIL->config->get('show_sig', 1);
@@ -254,6 +243,14 @@ if (!empty($msg_uid) && empty($COMPOSE['as_attachment']))
}
else {
$MESSAGE = new stdClass();
+
+ // apply mailto: URL parameters
+ if (!empty($COMPOSE['param']['in-reply-to'])) {
+ $COMPOSE['reply_msgid'] = '<' . $COMPOSE['param']['in-reply-to'] . '>';
+ }
+ if (!empty($COMPOSE['param']['references'])) {
+ $COMPOSE['references'] = $COMPOSE['param']['references'];
+ }
}
$MESSAGE->compose = array();
@@ -378,7 +375,12 @@ foreach ($parts as $header) {
$mailto = format_email(rcube_idn_to_utf8($addr_part['mailto']));
if (!in_array($mailto, $a_recipients)
- && ($header == 'to' || empty($MESSAGE->compose['from_email']) || $mailto != $MESSAGE->compose['from_email'])
+ && (
+ $header == 'to'
+ || $compose_mode != RCUBE_COMPOSE_REPLY
+ || empty($MESSAGE->compose['from_email'])
+ || $mailto != $MESSAGE->compose['from_email']
+ )
) {
if ($addr_part['name'] && $addr_part['mailto'] != $addr_part['name'])
$string = format_email_recipient($mailto, $addr_part['name']);
@@ -403,6 +405,53 @@ $MESSAGE_BODY = rcmail_prepare_message_body();
/****** compose mode functions ********/
+// process compose request parameters
+function rcmail_process_compose_params(&$COMPOSE)
+{
+ if ($COMPOSE['param']['to']) {
+ $mailto = explode('?', $COMPOSE['param']['to'], 2);
+
+ // #1486037: remove "mailto:" prefix
+ $COMPOSE['param']['to'] = preg_replace('/^mailto:/i', '', $mailto[0]);
+
+ // Supported case-insensitive tokens in mailto URL
+ $url_tokens = array('to', 'cc', 'bcc', 'reply-to', 'in-reply-to', 'references', 'subject', 'body');
+
+ if (!empty($mailto[1])) {
+ parse_str($mailto[1], $query);
+ foreach ($query as $f => $val) {
+ if (($key = array_search(strtolower($f), $url_tokens)) !== false) {
+ $f = $url_tokens[$key];
+ }
+
+ // merge mailto: addresses with addresses from 'to' parameter
+ if ($f == 'to' && !empty($COMPOSE['param']['to'])) {
+ $to_addresses = rcube_mime::decode_address_list($COMPOSE['param']['to'], null, true, null, true);
+ $add_addresses = rcube_mime::decode_address_list($val, null, true);
+ foreach ($add_addresses as $addr) {
+ if (!in_array($addr['mailto'], $to_addresses)) {
+ $to_addresses[] = $addr['mailto'];
+ $COMPOSE['param']['to'] = (!empty($to_addresses) ? ', ' : '') . $addr['string'];
+ }
+ }
+ }
+ else {
+ $COMPOSE['param'][$f] = $val;
+ }
+ }
+ }
+ }
+
+ $RCMAIL = rcmail::get_instance();
+
+ // select folder where to save the sent message
+ $COMPOSE['param']['sent_mbox'] = $RCMAIL->config->get('sent_mbox');
+
+ // pipe compose parameters thru plugins
+ $plugin = $RCMAIL->plugins->exec_hook('message_compose', $COMPOSE);
+ $COMPOSE['param'] = array_merge($COMPOSE['param'], $plugin['param']);
+}
+
function rcmail_compose_headers($attrib)
{
global $MESSAGE;
@@ -804,29 +853,14 @@ function rcmail_compose_body($attrib)
// Set language list
if (!empty($CONFIG['enable_spellcheck'])) {
- $engine = $RCMAIL->config->get('spellcheck_engine','googie');
+ $engine = new rcube_spellchecker();
$dictionary = (bool) $RCMAIL->config->get('spellcheck_dictionary');
- $spellcheck_langs = (array) $RCMAIL->config->get('spellcheck_languages',
- array('da'=>'Dansk', 'de'=>'Deutsch', 'en' => 'English', 'es'=>'Español',
- 'fr'=>'Français', 'it'=>'Italiano', 'nl'=>'Nederlands', 'pl'=>'Polski',
- 'pt'=>'Português', 'ru'=>'Русский', 'fi'=>'Suomi', 'sv'=>'Svenska'));
-
- // googie works only with two-letter codes
- if ($engine == 'googie') {
- $lang = strtolower(substr($_SESSION['language'], 0, 2));
-
- $spellcheck_langs_googie = array();
- foreach ($spellcheck_langs as $key => $name)
- $spellcheck_langs_googie[strtolower(substr($key,0,2))] = $name;
- $spellcheck_langs = $spellcheck_langs_googie;
- }
- else {
- $lang = $_SESSION['language'];
+ $spellcheck_langs = $engine->languages();
+ $lang = $_SESSION['language'];
- // if not found in the list, try with two-letter code
- if (!$spellcheck_langs[$lang])
- $lang = strtolower(substr($lang, 0, 2));
- }
+ // if not found in the list, try with two-letter code
+ if (!$spellcheck_langs[$lang])
+ $lang = strtolower(substr($lang, 0, 2));
if (!$spellcheck_langs[$lang])
$lang = 'en';
@@ -1364,8 +1398,9 @@ function rcmail_compose_attachment_list($attrib)
if (!$attrib['id'])
$attrib['id'] = 'rcmAttachmentList';
- $out = "\n";
+ $out = "\n";
$jslist = array();
+ $button = '';
if (is_array($COMPOSE['attachments'])) {
if ($attrib['deleteicon']) {
@@ -1374,27 +1409,38 @@ function rcmail_compose_attachment_list($attrib)
'alt' => rcube_label('delete')
));
}
- else
+ else if (rcube_utils::get_boolean($attrib['textbuttons'])) {
$button = Q(rcube_label('delete'));
+ }
foreach ($COMPOSE['attachments'] as $id => $a_prop) {
if (empty($a_prop))
continue;
- $out .= html::tag('li', array('id' => 'rcmfile'.$id, 'class' => rcmail_filetype2classname($a_prop['mimetype'], $a_prop['name'])),
+ $out .= html::tag('li',
+ array(
+ 'id' => 'rcmfile'.$id,
+ 'class' => rcmail_filetype2classname($a_prop['mimetype'], $a_prop['name']),
+ 'onmouseover' => "rcube_webmail.long_subject_title_ex(this, 0)",
+ ),
html::a(array(
'href' => "#delete",
'title' => rcube_label('delete'),
'onclick' => sprintf("return %s.command('remove-attachment','rcmfile%s', this)", JS_OBJECT_NAME, $id),
- 'class' => 'delete'),
- $button) . Q($a_prop['name']));
+ 'class' => 'delete'
+ ),
+ $button
+ ) . Q($a_prop['name'])
+ );
- $jslist['rcmfile'.$id] = array('name' => $a_prop['name'], 'complete' => true, 'mimetype' => $a_prop['mimetype']);
+ $jslist['rcmfile'.$id] = array('name' => $a_prop['name'], 'complete' => true, 'mimetype' => $a_prop['mimetype']);
}
}
if ($attrib['deleteicon'])
$COMPOSE['deleteicon'] = $CONFIG['skin_path'] . $attrib['deleteicon'];
+ else if (rcube_utils::get_boolean($attrib['textbuttons']))
+ $COMPOSE['textbuttons'] = true;
if ($attrib['cancelicon'])
$OUTPUT->set_env('cancelicon', $CONFIG['skin_path'] . $attrib['cancelicon']);
if ($attrib['loadingicon'])
diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc
index 018a31b84..70441e0d7 100644
--- a/program/steps/mail/func.inc
+++ b/program/steps/mail/func.inc
@@ -1383,9 +1383,6 @@ function rcmail_alter_html_link($matches)
{
global $RCMAIL;
- // Support unicode/punycode in top-level domain part
- $EMAIL_PATTERN = '([a-z0-9][a-z0-9\-\.\+\_]*@[^&@"\'.][^@&"\']*\\.([^\\x00-\\x40\\x5b-\\x60\\x7b-\\x7f]{2,}|xn--[a-z0-9]{2,}))';
-
$tag = strtolower($matches[1]);
$attrib = parse_attrib_string($matches[2]);
$end = '>';
@@ -1400,12 +1397,36 @@ function rcmail_alter_html_link($matches)
$attrib['href'] = $RCMAIL->url(array('task' => 'utils', 'action' => 'modcss', 'u' => $tempurl, 'c' => $GLOBALS['rcmail_html_container_id']));
$end = ' />';
}
- else if (preg_match('/^mailto:'.$EMAIL_PATTERN.'(\?[^"\'>]+)?/i', $attrib['href'], $mailto)) {
- $attrib['href'] = $mailto[0];
- $attrib['onclick'] = sprintf(
- "return %s.command('compose','%s',this)",
- JS_OBJECT_NAME,
- JQ($mailto[1].$mailto[3]));
+ else if (preg_match('/^mailto:(.+)/i', $attrib['href'], $mailto)) {
+ list($mailto, $url) = explode('?', html_entity_decode($mailto[1], ENT_QUOTES, 'UTF-8'), 2);
+
+ $url = urldecode($url);
+ $mailto = urldecode($mailto);
+ $addresses = rcube_mime::decode_address_list($mailto, null, true);
+ $mailto = array();
+
+ // do sanity checks on recipients
+ foreach ($addresses as $idx => $addr) {
+ if (rcube_utils::check_email($addr['mailto'], false)) {
+ $addresses[$idx] = $addr['mailto'];
+ $mailto[] = $addr['string'];
+ }
+ else {
+ unset($addresses[$idx]);
+ }
+ }
+
+ if (!empty($addresses)) {
+ $attrib['href'] = 'mailto:' . implode(',', $addresses);
+ $attrib['onclick'] = sprintf(
+ "return %s.command('compose','%s',this)",
+ JS_OBJECT_NAME,
+ JQ(implode(',', $mailto) . ($url ? "?$url" : '')));
+ }
+ else {
+ $attrib['href'] = '#NOP';
+ $attrib['onclick'] = '';
+ }
}
else if (empty($attrib['href']) && !$attrib['name']) {
$attrib['href'] = './#NOP';
@@ -1470,15 +1491,13 @@ function rcmail_address_string($input, $max=null, $linked=false, $addicon=null,
$mailto = rcube_idn_to_utf8($mailto);
if ($PRINT_MODE) {
- $out .= ($out ? ', ' : '') . sprintf('%s &lt;%s&gt;', Q($name), $mailto);
- // for printing we display all addresses
- continue;
+ $address = sprintf('%s &lt;%s&gt;', Q($name), Q($mailto));
}
else if ($valid) {
if ($linked) {
$attrs = array(
'href' => 'mailto:' . $mailto,
- 'onclick' => sprintf("return %s.command('compose','%s',this)", JS_OBJECT_NAME, JQ($mailto)),
+ 'onclick' => sprintf("return %s.command('compose','%s',this)", JS_OBJECT_NAME, JQ(format_email_recipient($mailto, $name))),
'class' => "rcmContactAddress",
);
@@ -1536,6 +1555,15 @@ function rcmail_address_string($input, $max=null, $linked=false, $addicon=null,
}
if ($moreadrs) {
+ if ($PRINT_MODE) {
+ $out .= ' ' . html::a(array(
+ 'href' => '#more',
+ 'class' => 'morelink',
+ 'onclick' => '$(this).hide().next().show()',
+ ), Q(rcube_label(array('name' => 'andnmore', 'vars' => array('nr' => $moreadrs))))) .
+ html::span(array('style' => 'display:none'), join(', ', $allvalues));
+ }
+ else {
$out .= ' ' . html::a(array(
'href' => '#more',
'class' => 'morelink',
@@ -1545,6 +1573,7 @@ function rcmail_address_string($input, $max=null, $linked=false, $addicon=null,
JQ($title))
),
Q(rcube_label(array('name' => 'andnmore', 'vars' => array('nr' => $moreadrs)))));
+ }
}
return $out;
@@ -1730,7 +1759,7 @@ function rcmail_identity_select($MESSAGE, $identities = null, $compose_mode = 'r
$a_to = rcube_mime::decode_address_list($MESSAGE->headers->to, null, true, $MESSAGE->headers->charset);
foreach ($a_to as $addr) {
if (!empty($addr['mailto'])) {
- $a_recipients[] = format_email($addr['mailto']);
+ $a_recipients[] = strtolower($addr['mailto']);
$a_names[] = $addr['name'];
}
}
@@ -1739,7 +1768,7 @@ function rcmail_identity_select($MESSAGE, $identities = null, $compose_mode = 'r
$a_cc = rcube_mime::decode_address_list($MESSAGE->headers->cc, null, true, $MESSAGE->headers->charset);
foreach ($a_cc as $addr) {
if (!empty($addr['mailto'])) {
- $a_recipients[] = format_email($addr['mailto']);
+ $a_recipients[] = strtolower($addr['mailto']);
$a_names[] = $addr['name'];
}
}
@@ -1765,7 +1794,7 @@ function rcmail_identity_select($MESSAGE, $identities = null, $compose_mode = 'r
break;
}
// use replied message recipients
- else if (($found = array_search($ident['email_ascii'], $a_recipients)) !== false) {
+ else if (($found = array_search(strtolower($ident['email_ascii']), $a_recipients)) !== false) {
if ($found_idx === null) {
$found_idx = $idx;
}
@@ -1784,15 +1813,19 @@ function rcmail_identity_select($MESSAGE, $identities = null, $compose_mode = 'r
// Try Return-Path
if ($from_idx === null && ($return_path = $MESSAGE->headers->others['return-path'])) {
+ $return_path = array_map('strtolower', (array) $return_path);
+
foreach ($identities as $idx => $ident) {
// Return-Path header contains an email address, but on some mailing list
// it can be e.g. <pear-dev-return-55250-local=domain.tld@lists.php.net>
// where local@domain.tld is the address we're looking for (#1489241)
- $ident1 = $ident['email_ascii'];
+ $ident1 = strtolower($ident['email_ascii']);
$ident2 = str_replace('@', '=', $ident1);
+ $ident1 = '<' . $ident1 . '>';
+ $ident2 = '-' . $ident2 . '@';
- foreach ((array)$return_path as $path) {
- if (stripos($path, $ident1) !== false || stripos($path, $ident2)) {
+ foreach ($return_path as $path) {
+ if ($path == $ident1 || stripos($path, $ident2)) {
$from_idx = $idx;
break 2;
}
diff --git a/program/steps/mail/sendmail.inc b/program/steps/mail/sendmail.inc
index 1a92844c0..ccb8978be 100644
--- a/program/steps/mail/sendmail.inc
+++ b/program/steps/mail/sendmail.inc
@@ -414,9 +414,6 @@ if (!empty($headers['Reply-To'])) {
if (!empty($_POST['_followupto'])) {
$headers['Mail-Followup-To'] = rcmail_email_input_format(get_input_value('_followupto', RCUBE_INPUT_POST, TRUE, $message_charset));
}
-if (!empty($COMPOSE['reply_msgid'])) {
- $headers['In-Reply-To'] = $COMPOSE['reply_msgid'];
-}
// remember reply/forward UIDs in special headers
if (!empty($COMPOSE['reply_uid']) && $savedraft) {
@@ -426,6 +423,9 @@ else if (!empty($COMPOSE['forward_uid']) && $savedraft) {
$headers['X-Draft-Info'] = array('type' => 'forward', 'uid' => $COMPOSE['forward_uid']);
}
+if (!empty($COMPOSE['reply_msgid'])) {
+ $headers['In-Reply-To'] = $COMPOSE['reply_msgid'];
+}
if (!empty($COMPOSE['references'])) {
$headers['References'] = $COMPOSE['references'];
}
@@ -473,12 +473,19 @@ $isHtml = (bool) get_input_value('_is_html', RCUBE_INPUT_POST);
$message_body = get_input_value('_message', RCUBE_INPUT_POST, TRUE, $message_charset);
if ($isHtml) {
- $font = rcube_fontdefs($RCMAIL->config->get('default_font'));
- $bstyle = $font && is_string($font) ? " style='font-family: $font'" : '';
+ $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
- $message_body = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN">' .
- "\r\n<html><body$bstyle>\r\n" . $message_body;
+ $message_body = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN">'
+ . "\r\n<html><body" . (!empty($bstyle) ? " style='" . implode($bstyle, '; ') . "'" : '') . ">\r\n"
+ . $message_body;
}
if (!$savedraft) {
@@ -752,7 +759,7 @@ if ($store_target) {
if (PEAR::isError($msg))
raise_error(array('code' => 650, 'type' => 'php',
- 'file' => __FILE__, 'line' => __LINE__,
+ 'file' => __FILE__, 'line' => __LINE__,
'message' => "Could not create message: ".$msg->getMessage()),
TRUE, FALSE);
else {
@@ -823,15 +830,24 @@ if ($savedraft) {
// start the auto-save timer again
$OUTPUT->command('auto_save_start');
-
- $OUTPUT->send('iframe');
}
else {
+ $folders = array();
+
+ if ($COMPOSE['mode'] == 'reply' || $COMPOSE['mode'] == 'forward')
+ $folders[] = $COMPOSE['mailbox'];
+
rcmail_compose_cleanup($COMPOSE_ID);
if ($store_folder && !$saved)
- $OUTPUT->command('sent_successfully', 'error', rcube_label('errorsavingsent'));
- else
- $OUTPUT->command('sent_successfully', 'confirmation', rcube_label('messagesent'), $store_target);
- $OUTPUT->send('iframe');
+ $OUTPUT->command('sent_successfully', 'error', rcube_label('errorsavingsent'), $folders);
+ else {
+ if ($store_folder) {
+ $folders[] = $store_target;
+ }
+
+ $OUTPUT->command('sent_successfully', 'confirmation', rcube_label('messagesent'), $folders);
+ }
}
+
+$OUTPUT->send('iframe');
diff --git a/program/steps/mail/show.inc b/program/steps/mail/show.inc
index 59f4d55e1..9d85f9c8f 100644
--- a/program/steps/mail/show.inc
+++ b/program/steps/mail/show.inc
@@ -175,9 +175,9 @@ function rcmail_message_attachments($attrib)
$ol .= html::tag('li', null, Q(sprintf("%s (%s)", $filename, $size)));
}
else {
- if (mb_strlen($filename) > 50) {
+ if ($attrib['maxlength'] && mb_strlen($filename) > $attrib['maxlength']) {
$title = $filename;
- $filename = abbreviate_string($filename, 50);
+ $filename = abbreviate_string($filename, $attrib['maxlength']);
}
else {
$title = '';
@@ -190,6 +190,7 @@ function rcmail_message_attachments($attrib)
'href' => $MESSAGE->get_part_url($attach_prop->mime_id, false),
'onclick' => sprintf('return %s.command(\'load-attachment\',\'%s\',this)',
JS_OBJECT_NAME, $attach_prop->mime_id),
+ 'onmouseover' => $title ? '' : 'rcube_webmail.long_subject_title_ex(this, 0)',
'title' => Q($title),
), Q($filename));
$ol .= html::tag('li', array('class' => $class, 'id' => $id), $link);