| | |
| | | } |
| | | |
| | | $threading = (bool) $RCMAIL->storage->get_threading(); |
| | | $delimiter = $RCMAIL->storage->get_hierarchy_delimiter(); |
| | | |
| | | // set current mailbox and some other vars in client environment |
| | | $OUTPUT->set_env('mailbox', $mbox_name); |
| | | $OUTPUT->set_env('pagesize', $RCMAIL->storage->get_pagesize()); |
| | | $OUTPUT->set_env('delimiter', $RCMAIL->storage->get_hierarchy_delimiter()); |
| | | $OUTPUT->set_env('delimiter', $delimiter); |
| | | $OUTPUT->set_env('threading', $threading); |
| | | $OUTPUT->set_env('threads', $threading || $RCMAIL->storage->get_capability('THREAD')); |
| | | $OUTPUT->set_env('preview_pane_mark_read', $RCMAIL->config->get('preview_pane_mark_read', 0)); |
| | |
| | | 'movingmessage', 'copyingmessage', 'deletingmessage', 'markingmessage', |
| | | 'copy', 'move', 'quota'); |
| | | |
| | | $OUTPUT->set_pagetitle(rcmail_localize_foldername($RCMAIL->storage->mod_folder($mbox_name))); |
| | | $pagetitle = $RCMAIL->localize_foldername($RCMAIL->storage->mod_folder($mbox_name), true); |
| | | $pagetitle = str_replace($delimiter, " \xC2\xBB ", $pagetitle); |
| | | |
| | | $OUTPUT->set_pagetitle($pagetitle); |
| | | } |
| | | |
| | | /** |
| | |
| | | |
| | | $p += array('safe' => false, 'inline_html' => true); |
| | | |
| | | // special replacements (not properly handled by washtml class) |
| | | $html_search = array( |
| | | '/(<\/nobr>)(\s+)(<nobr>)/i', // space(s) between <NOBR> |
| | | '/<title[^>]*>[^<]*<\/title>/i', // PHP bug #32547 workaround: remove title tag |
| | | '/^(\0\0\xFE\xFF|\xFF\xFE\0\0|\xFE\xFF|\xFF\xFE|\xEF\xBB\xBF)/', // byte-order mark (only outlook?) |
| | | '/<html\s[^>]+>/i', // washtml/DOMDocument cannot handle xml namespaces |
| | | ); |
| | | $html_replace = array( |
| | | '\\1'.' '.'\\3', |
| | | '', |
| | | '', |
| | | '<html>', |
| | | ); |
| | | $html = preg_replace($html_search, $html_replace, trim($html)); |
| | | |
| | | // PCRE errors handling (#1486856), should we use something like for every preg_* use? |
| | | if ($html === null && ($preg_error = preg_last_error()) != PREG_NO_ERROR) { |
| | | $errstr = "Could not clean up HTML message! PCRE Error: $preg_error."; |
| | | |
| | | if ($preg_error == PREG_BACKTRACK_LIMIT_ERROR) |
| | | $errstr .= " Consider raising pcre.backtrack_limit!"; |
| | | if ($preg_error == PREG_RECURSION_LIMIT_ERROR) |
| | | $errstr .= " Consider raising pcre.recursion_limit!"; |
| | | |
| | | raise_error(array('code' => 620, 'type' => 'php', |
| | | 'line' => __LINE__, 'file' => __FILE__, |
| | | 'message' => $errstr), true, false); |
| | | return ''; |
| | | } |
| | | |
| | | // fix (unknown/malformed) HTML tags before "wash" |
| | | $html = preg_replace_callback('/(<[\/]*)([^\s>]+)/', 'rcmail_html_tag_callback', $html); |
| | | |
| | | // charset was converted to UTF-8 in rcube_storage::get_message_part(), |
| | | // change/add charset specification in HTML accordingly, |
| | | // washtml cannot work without that |
| | |
| | | if (!$rcount) { |
| | | $html = '<head>' . $meta . '</head>' . $html; |
| | | } |
| | | |
| | | // turn relative into absolute urls |
| | | $html = rcmail_resolve_base($html); |
| | | |
| | | // clean HTML with washhtml by Frederic Motte |
| | | $wash_opts = array( |
| | |
| | | $wash_opts['html_attribs'] = $p['html_attribs']; |
| | | |
| | | // initialize HTML washer |
| | | $washer = new washtml($wash_opts); |
| | | $washer = new rcube_washtml($wash_opts); |
| | | |
| | | if (!$p['skip_washer_form_callback']) |
| | | $washer->add_callback('form', 'rcmail_washtml_callback'); |
| | |
| | | + $p + array('safe' => false, 'plain' => false, 'inline_html' => true)); |
| | | |
| | | // convert html to text/plain |
| | | if ($data['type'] == 'html' && $data['plain']) { |
| | | $txt = new html2text($data['body'], false, true); |
| | | if ($data['plain'] && ($data['type'] == 'html' || $data['type'] == 'enriched')) { |
| | | if ($data['type'] == 'enriched') { |
| | | $data['body'] = rcube_enriched::to_html($data['body']); |
| | | } |
| | | $txt = new rcube_html2text($data['body'], false, true); |
| | | $body = $txt->get_text(); |
| | | $part->ctype_secondary = 'plain'; |
| | | } |
| | |
| | | |
| | | |
| | | /** |
| | | * Callback function for HTML tags fixing |
| | | */ |
| | | function rcmail_html_tag_callback($matches) |
| | | { |
| | | $tagname = $matches[2]; |
| | | |
| | | $tagname = preg_replace(array( |
| | | '/:.*$/', // Microsoft's Smart Tags <st1:xxxx> |
| | | '/[^a-z0-9_\[\]\!-]/i', // forbidden characters |
| | | ), '', $tagname); |
| | | |
| | | return $matches[1].$tagname; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * return table with message headers |
| | | */ |
| | | function rcmail_message_headers($attrib, $headers=null) |
| | |
| | | $headers_obj = $MESSAGE->headers; |
| | | $headers = get_object_vars($MESSAGE->headers); |
| | | } |
| | | else if (is_object($headers)) { |
| | | $headers_obj = $headers; |
| | | $headers = get_object_vars($headers_obj); |
| | | } |
| | | else { |
| | | $headers_obj = rcube_message_header::from_array($headers); |
| | | } |
| | | |
| | | // show these headers |
| | | $standard_headers = array('subject', 'from', 'to', 'cc', 'bcc', 'replyto', |
| | | $standard_headers = array('subject', 'from', 'sender', 'to', 'cc', 'bcc', 'replyto', |
| | | 'mail-reply-to', 'mail-followup-to', 'date', 'priority'); |
| | | $exclude_headers = $attrib['exclude'] ? explode(',', $attrib['exclude']) : array(); |
| | | $output_headers = array(); |
| | |
| | | if ($headers['mail-replyto'] != $headers['reply-to'] |
| | | && $headers['reply-to'] != $headers['from'] |
| | | ) { |
| | | $header_value = rcmail_address_string($value, $attrib['max'], true, $attrib['addicon'], $headers['charset'], $header_title); |
| | | $ishtml = true; |
| | | } |
| | | else |
| | | continue; |
| | | } |
| | | else if ($hkey == 'sender') { |
| | | if ($headers['sender'] != $headers['from']) { |
| | | $header_value = rcmail_address_string($value, $attrib['max'], true, $attrib['addicon'], $headers['charset'], $header_title); |
| | | $ishtml = true; |
| | | } |
| | |
| | | $out .= html::div('message-partheaders', rcmail_message_headers(sizeof($header_attrib) ? $header_attrib : null, $part->headers)); |
| | | } |
| | | else if ($part->type == 'content') { |
| | | // unsapported |
| | | // unsupported (e.g. encrypted) |
| | | if ($part->realtype) { |
| | | if ($part->realtype == 'multipart/encrypted') { |
| | | if ($part->realtype == 'multipart/encrypted' || $part->realtype == 'application/pkcs7-mime') { |
| | | $out .= html::span('part-notice', rcube_label('encryptedmessage')); |
| | | } |
| | | continue; |
| | |
| | | |
| | | // extract headers from message/rfc822 parts |
| | | if ($part->mimetype == 'message/rfc822') { |
| | | list($hdrs, $body) = explode("\r\n\r\n", $part->body, 2); |
| | | if ($hdrs && $body && preg_match('/^[\w-]+:\s/i', $hdrs)) { |
| | | $out .= html::div('message-partheaders', rcmail_message_headers(sizeof($header_attrib) ? $header_attrib : null, rcube_mime::parse_headers($hdrs))); |
| | | $part->body = $body; |
| | | $msgpart = rcube_mime::parse_message($part->body); |
| | | if (!empty($msgpart->headers)) { |
| | | $part = $msgpart; |
| | | $out .= html::div('message-partheaders', rcmail_message_headers(sizeof($header_attrib) ? $header_attrib : null, $part->headers)); |
| | | } |
| | | } |
| | | |
| | |
| | | $show_link = array( |
| | | 'href' => $MESSAGE->get_part_url($attach_prop->mime_id, false), |
| | | 'onclick' => sprintf( |
| | | 'return %s.command(\'load-attachment\',{part:\'%s\', mimetype:\'%s\'},this)', |
| | | 'return %s.command(\'load-attachment\',\'%s\',this)', |
| | | JS_OBJECT_NAME, |
| | | $attach_prop->mime_id, |
| | | $mimetype) |
| | | $attach_prop->mime_id) |
| | | ); |
| | | $out .= html::p('image-attachment', |
| | | html::a($show_link + array('class' => 'image-link', 'style' => sprintf('width:%dpx', $thumbnail_size)), |
| | |
| | | |
| | | // Content-Type: image/*... |
| | | if (preg_match($mime_regex, $part->mimetype)) { |
| | | return $part->mimetype; |
| | | return rcmail_fix_mimetype($part->mimetype); |
| | | } |
| | | |
| | | // Many clients use application/octet-stream, we'll detect mimetype |
| | |
| | | ) { |
| | | return $types[$extension]; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Convert all relative URLs according to a <base> in HTML |
| | | */ |
| | | function rcmail_resolve_base($body) |
| | | { |
| | | // check for <base href=...> |
| | | if (preg_match('!(<base.*href=["\']?)([hftps]{3,5}://[a-z0-9/.%-]+)!i', $body, $regs)) { |
| | | $replacer = new rcube_base_replacer($regs[2]); |
| | | $body = $replacer->replace($body); |
| | | } |
| | | |
| | | return $body; |
| | | } |
| | | |
| | | |
| | |
| | | $mailto = $part['mailto']; |
| | | $string = $part['string']; |
| | | |
| | | // phishing email prevention (#1488981), e.g. "valid@email.addr <phishing@email.addr>" |
| | | if ($name && $name != $mailto && strpos($name, '@')) { |
| | | $name = ''; |
| | | } |
| | | |
| | | // IDNA ASCII to Unicode |
| | | if ($name == $mailto) |
| | | $name = rcube_idn_to_utf8($name); |
| | |
| | | if ($addicon && $_SESSION['writeable_abook']) { |
| | | $address .= html::a(array( |
| | | 'href' => "#add", |
| | | 'onclick' => sprintf("return %s.command('add-contact','%s',this)", JS_OBJECT_NAME, $string), |
| | | 'onclick' => sprintf("return %s.command('add-contact','%s',this)", JS_OBJECT_NAME, JQ($string)), |
| | | 'title' => rcube_label('addtoaddressbook'), |
| | | 'class' => 'rcmaddcontact', |
| | | ), |
| | |
| | | $part = $MESSAGE->mime_parts[$part]; |
| | | $table = new html_table(array('cols' => 3)); |
| | | |
| | | $filename = $part->filename; |
| | | if (empty($filename) && $attach_prop->mimetype == 'text/html') { |
| | | $filename = rcube_label('htmlmessage'); |
| | | } |
| | | $filename = rcmail_attachment_name($part); |
| | | |
| | | if (!empty($filename)) { |
| | | $table->add('title', Q(rcube_label('filename'))); |
| | |
| | | |
| | | return $table->show($attrib); |
| | | } |
| | | |
| | | |
| | | |
| | | function rcmail_message_part_frame($attrib) |
| | |
| | | if ($message->headers->mdn_to && empty($message->headers->flags['MDNSENT']) && |
| | | ($RCMAIL->storage->check_permflag('MDNSENT') || $RCMAIL->storage->check_permflag('*'))) |
| | | { |
| | | $identity = $RCMAIL->user->get_identity(); |
| | | $sender = format_email_recipient($identity['email'], $identity['name']); |
| | | $identity = rcmail_identity_select($message); |
| | | $sender = format_email_recipient($identity['email'], $identity['name']); |
| | | $recipient = array_shift(rcube_mime::decode_address_list( |
| | | $message->headers->mdn_to, 1, true, $message->headers->charset)); |
| | | $mailto = $recipient['mailto']; |
| | | $mailto = $recipient['mailto']; |
| | | |
| | | $compose = new Mail_mime("\r\n"); |
| | | |
| | |
| | | if ($agent = $RCMAIL->config->get('useragent')) |
| | | $headers['User-Agent'] = $agent; |
| | | |
| | | if ($RCMAIL->config->get('mdn_use_from')) |
| | | $options['mdn_use_from'] = true; |
| | | |
| | | $body = rcube_label("yourmessage") . "\r\n\r\n" . |
| | | "\t" . rcube_label("to") . ': ' . rcube_mime::decode_mime_string($message->headers->to, $message->headers->charset) . "\r\n" . |
| | | "\t" . rcube_label("subject") . ': ' . $message->subject . "\r\n" . |
| | |
| | | $compose->setTXTBody(rc_wordwrap($body, 75, "\r\n")); |
| | | $compose->addAttachment($report, 'message/disposition-notification', 'MDNPart2.txt', false, '7bit', 'inline'); |
| | | |
| | | $sent = rcmail_deliver_message($compose, $identity['email'], $mailto, $smtp_error, $body_file); |
| | | $sent = rcmail_deliver_message($compose, $identity['email'], $mailto, $smtp_error, $body_file, $options); |
| | | |
| | | if ($sent) |
| | | { |
| | |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * Detect recipient identity from specified message |
| | | */ |
| | | function rcmail_identity_select($MESSAGE, $identities = null, $compose_mode = 'reply') |
| | | { |
| | | $a_recipients = array(); |
| | | $a_names = array(); |
| | | |
| | | if ($identities === null) { |
| | | $identities = rcmail::get_instance()->user->list_identities(null, true); |
| | | } |
| | | |
| | | // extract all recipients of the reply-message |
| | | if (is_object($MESSAGE->headers) && in_array($compose_mode, array('reply', 'forward'))) { |
| | | $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_names[] = $addr['name']; |
| | | } |
| | | } |
| | | |
| | | if (!empty($MESSAGE->headers->cc)) { |
| | | $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_names[] = $addr['name']; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | $from_idx = null; |
| | | $found_idx = null; |
| | | $default_identity = 0; // default identity is always first on the list |
| | | |
| | | // Select identity |
| | | foreach ($identities as $idx => $ident) { |
| | | // use From header |
| | | if (in_array($compose_mode, array('draft', 'edit'))) { |
| | | if ($MESSAGE->headers->from == $ident['ident']) { |
| | | $from_idx = $idx; |
| | | break; |
| | | } |
| | | } |
| | | // reply to yourself |
| | | else if ($compose_mode == 'reply' && $MESSAGE->headers->from == $ident['ident']) { |
| | | $from_idx = $idx; |
| | | break; |
| | | } |
| | | // use replied message recipients |
| | | else if (($found = array_search($ident['email_ascii'], $a_recipients)) !== false) { |
| | | if ($found_idx === null) { |
| | | $found_idx = $idx; |
| | | } |
| | | // match identity name |
| | | if ($a_names[$found] && $ident['name'] && $a_names[$found] == $ident['name']) { |
| | | $from_idx = $idx; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | | // If matching by name+address doesn't found any matches, get first found address (identity) |
| | | if ($from_idx === null) { |
| | | $from_idx = $found_idx; |
| | | } |
| | | |
| | | // Try Return-Path |
| | | if ($from_idx === null && ($return_path = $MESSAGE->headers->others['return-path'])) { |
| | | foreach ($identities as $idx => $ident) { |
| | | if (strpos($return_path, str_replace('@', '=', $ident['email_ascii']).'@') !== false) { |
| | | $from_idx = $idx; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | | // Fallback using Delivered-To |
| | | if ($from_idx === null && ($delivered_to = $MESSAGE->headers->others['delivered-to'])) { |
| | | foreach ($identities as $idx => $ident) { |
| | | if (in_array($ident['email_ascii'], (array)$delivered_to)) { |
| | | $from_idx = $idx; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | | // Fallback using Envelope-To |
| | | if ($from_idx === null && ($envelope_to = $MESSAGE->headers->others['envelope-to'])) { |
| | | foreach ($identities as $idx => $ident) { |
| | | if (in_array($ident['email_ascii'], (array)$envelope_to)) { |
| | | $from_idx = $idx; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | | return $identities[$from_idx !== null ? $from_idx : $default_identity]; |
| | | } |
| | | |
| | | // Fixes some content-type names |
| | | function rcmail_fix_mimetype($name) |
| | |
| | | if (preg_match('/^application\/pdf.+/', $name)) |
| | | $name = 'application/pdf'; |
| | | |
| | | // treat image/pjpeg as image/jpeg |
| | | else if (preg_match('/^image\/p?jpe?g$/', $name)) |
| | | $name = 'image/jpeg'; |
| | | |
| | | return $name; |
| | | } |
| | | |
| | | // return attachment filename, handle empty filename case |
| | | function rcmail_attachment_name($attachment, $display = false) |
| | | { |
| | | $filename = $attachment->filename; |
| | | |
| | | if ($filename === null || $filename === '') { |
| | | if ($attachment->mimetype == 'text/html') { |
| | | $filename = rcube_label('htmlmessage'); |
| | | } |
| | | else { |
| | | $ext = (array) rcube_mime::get_mime_extensions($attachment->mimetype); |
| | | $ext = array_shift($ext); |
| | | $filename = rcube_label('messagepart') . ' ' . $attachment->mime_id; |
| | | if ($ext) { |
| | | $filename .= '.' . $ext; |
| | | } |
| | | } |
| | | } |
| | | |
| | | $filename = preg_replace('[\r\n]', '', $filename); |
| | | |
| | | // Display smart names for some known mimetypes |
| | | if ($display) { |
| | | if (preg_match('/application\/(pgp|pkcs7)-signature/i', $attachment->mimetype)) { |
| | | $filename = rcube_label('digitalsig'); |
| | | } |
| | | } |
| | | |
| | | return $filename; |
| | | } |
| | | |
| | | function rcmail_search_filter($attrib) |
| | | { |
| | | global $OUTPUT, $CONFIG; |