From 2965a981b7ec22866fbdf2d567d87e2d068d3617 Mon Sep 17 00:00:00 2001 From: Thomas Bruederli <thomas@roundcube.net> Date: Fri, 31 Jul 2015 16:04:08 -0400 Subject: [PATCH] Allow to search and import missing PGP pubkeys from keyservers using Publickey.js --- program/steps/mail/compose.inc | 182 ++++++++++++++++++++++++++++++++------------- 1 files changed, 128 insertions(+), 54 deletions(-) diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc index 56bc9fb..9e1b988 100644 --- a/program/steps/mail/compose.inc +++ b/program/steps/mail/compose.inc @@ -53,13 +53,14 @@ } $COMPOSE_ID = uniqid(mt_rand()); + $params = rcube_utils::request2param(rcube_utils::INPUT_GET, 'task|action', true); + $_SESSION['compose_data_'.$COMPOSE_ID] = array( 'id' => $COMPOSE_ID, - 'param' => rcube_utils::request2param(rcube_utils::INPUT_GET, 'task|action', true), - 'mailbox' => $RCMAIL->storage->get_folder(), + 'param' => $params, + 'mailbox' => $params['mbox'] ?: $RCMAIL->storage->get_folder(), ); $COMPOSE =& $_SESSION['compose_data_'.$COMPOSE_ID]; - rcmail_process_compose_params($COMPOSE); // check if folder for saving sent messages exists and is subscribed (#1486802) @@ -82,7 +83,10 @@ 'messagesaved', 'converting', 'editorwarning', 'searching', 'uploading', 'uploadingmany', 'fileuploaderror', 'sendmessage', 'newresponse', 'responsename', 'responsetext', 'save', 'savingresponse', 'restoresavedcomposedata', 'restoremessage', 'delete', 'restore', 'ignore', - 'selectimportfile'); + 'selectimportfile', 'messageissent', 'loadingdata', 'nopubkeyfor', 'nopubkeyforsender', + 'encryptnoattachments','encryptedsendialog','searchpubkeyservers', 'importpubkeys', + 'encryptpubkeysfound', 'search', 'close', 'import', 'keyid', 'keylength', 'keyexpired', + 'keyrevoked'); $OUTPUT->set_pagetitle($RCMAIL->gettext('compose')); @@ -90,8 +94,10 @@ $OUTPUT->set_env('session_id', session_id()); $OUTPUT->set_env('mailbox', $RCMAIL->storage->get_folder()); $OUTPUT->set_env('top_posting', intval($RCMAIL->config->get('reply_mode')) > 0); +$OUTPUT->set_env('sig_below', $RCMAIL->config->get('sig_below')); $OUTPUT->set_env('recipients_separator', trim($RCMAIL->config->get('recipients_separator', ','))); $OUTPUT->set_env('save_localstorage', (bool)$RCMAIL->config->get('compose_save_localstorage')); +$OUTPUT->set_env('is_sent', false); $drafts_mbox = $RCMAIL->config->get('drafts_mbox'); $config_show_sig = $RCMAIL->config->get('show_sig', 1); @@ -131,8 +137,10 @@ $compose_mode = RCUBE_COMPOSE_EDIT; } -$COMPOSE['mode'] = $compose_mode; -$OUTPUT->set_env('compose_mode', $compose_mode); +if ($compose_mode) { + $COMPOSE['mode'] = $compose_mode; + $OUTPUT->set_env('compose_mode', $compose_mode); +} if ($compose_mode == RCUBE_COMPOSE_EDIT || $compose_mode == RCUBE_COMPOSE_DRAFT) { // don't add signature in draft/edit mode, we'll also not remove the old-one @@ -320,13 +328,18 @@ $fvalue = $mailfollowup; else if ($mailreplyto) $fvalue = $mailreplyto; - else if (!empty($MESSAGE->headers->replyto)) - $fvalue = $MESSAGE->headers->replyto; + else if (!empty($MESSAGE->headers->replyto)) { + $fvalue = $MESSAGE->headers->replyto; + $replyto = true; + } else if (!empty($MESSAGE->headers->from)) $fvalue = $MESSAGE->headers->from; // Reply to message sent by yourself (#1487074, #1489230) - if (!empty($ident) && in_array($ident['ident'], array($fvalue, $MESSAGE->headers->from))) { + // Reply-To address need to be unset (#1490233) + if (!empty($ident) && empty($replyto) + && in_array($ident['ident'], array($fvalue, $MESSAGE->headers->from)) + ) { $fvalue = $MESSAGE->headers->to; } } @@ -417,7 +430,8 @@ 'filedroparea' => 'compose_file_drop_area', 'priorityselector' => 'rcmail_priority_selector', 'editorselector' => 'rcmail_editor_selector', - 'receiptcheckbox' => 'rcmail_receipt_checkbox', + 'receiptcheckbox' => 'rcmail_mdn_checkbox', // deprecated + 'mdncheckbox' => 'rcmail_mdn_checkbox', 'dsncheckbox' => 'rcmail_dsn_checkbox', 'storetarget' => 'rcmail_store_target_selection', 'addressbooks' => 'rcmail_addressbook_list', @@ -438,6 +452,8 @@ // #1486037: remove "mailto:" prefix $COMPOSE['param']['to'] = preg_replace('/^mailto:/i', '', $mailto[0]); + // #1490346: decode the recipient address + $COMPOSE['param']['to'] = urldecode($COMPOSE['param']['to']); // Supported case-insensitive tokens in mailto URL $url_tokens = array('to', 'cc', 'bcc', 'reply-to', 'in-reply-to', 'references', 'subject', 'body'); @@ -600,8 +616,10 @@ if (count($MESSAGE->identities)) { $a_signatures = array(); $identities = array(); - $separator = intval($RCMAIL->config->get('reply_mode')) > 0 - && ($compose_mode == RCUBE_COMPOSE_REPLY || $compose_mode == RCUBE_COMPOSE_FORWARD) ? '---' : '-- '; + $top_posting = intval($RCMAIL->config->get('reply_mode')) > 0 + && !$RCMAIL->config->get('sig_below') + && ($compose_mode == RCUBE_COMPOSE_REPLY || $compose_mode == RCUBE_COMPOSE_FORWARD); + $separator = $top_posting ? '---' : '-- '; $field_attrib['onchange'] = rcmail_output::JS_OBJECT_NAME.".change_identity(this)"; $select_from = new html_select($field_attrib); @@ -616,21 +634,17 @@ $text = $html = $sql_arr['signature']; if ($sql_arr['html_signature']) { - $h2t = new rcube_html2text($sql_arr['signature'], false, true); + $h2t = new rcube_html2text($html, false, true); $text = trim($h2t->get_text()); } else { - $html = htmlentities($html, ENT_NOQUOTES, RCUBE_CHARSET); + $t2h = new rcube_text2html($text, false); + $html = $t2h->get_html(); } if (!preg_match('/^--[ -]\r?\n/m', $text)) { $text = $separator . "\n" . $text; $html = $separator . "<br>" . $html; - } - - if (!$sql_arr['html_signature']) { - $t2h = new rcube_text2html($sql_arr['signature'], false); - $html = $t2h->get_html(); } $a_signatures[$identity_id]['text'] = $text; @@ -644,6 +658,8 @@ if (!empty($sql_arr['bcc'])) { $identities[$identity_id]['bcc'] = $sql_arr['bcc']; } + + $identities[$identity_id]['email'] = $sql_arr['email']; } $out = $select_from->show($MESSAGE->compose['from']); @@ -736,6 +752,21 @@ } foreach ($MESSAGE->parts as $part) { + if ($part->realtype == 'multipart/encrypted') { + // find the encrypted message payload part + foreach ($MESSAGE->mime_parts as $mime_id => $mpart) { + if ($mpart->mimetype == 'application/octet-stream' || !empty($mpart->filename)) { + $RCMAIL->output->set_env('pgp_mime_message', array( + '_mbox' => $RCMAIL->storage->get_folder(), '_uid' => $MESSAGE->uid, '_part' => $mime_id, + )); + $RCMAIL->output->set_env('compose_mode', $compose_mode); + $MESSAGE->pgp_mime = true; + break; + } + } + continue; + } + // skip no-content and attachment parts (#1488557) if ($part->type != 'content' || !$part->size || $MESSAGE->is_attachment($part)) { continue; @@ -758,14 +789,21 @@ } // compose reply-body - if ($compose_mode == RCUBE_COMPOSE_REPLY) + if ($compose_mode == RCUBE_COMPOSE_REPLY) { $body = rcmail_create_reply_body($body, $isHtml); + + if ($MESSAGE->pgp_mime) { + $RCMAIL->output->set_env('compose_reply_header', rcmail_get_reply_header($MESSAGE)); + } + } // forward message body inline - else if ($compose_mode == RCUBE_COMPOSE_FORWARD) + else if ($compose_mode == RCUBE_COMPOSE_FORWARD) { $body = rcmail_create_forward_body($body, $isHtml); + } // load draft message body - else if ($compose_mode == RCUBE_COMPOSE_DRAFT || $compose_mode == RCUBE_COMPOSE_EDIT) + else if ($compose_mode == RCUBE_COMPOSE_DRAFT || $compose_mode == RCUBE_COMPOSE_EDIT) { $body = rcmail_create_draft_body($body, $isHtml); + } } else { // new message $isHtml = rcmail_compose_editor_mode(); @@ -778,12 +816,13 @@ unset($plugin); // add blocked.gif attachment (#1486516) - if ($isHtml && preg_match('#<img src="\./program/resources/blocked\.gif"#', $body)) { - if ($attachment = rcmail_save_image('program/resources/blocked.gif', 'image/gif')) { + if ($isHtml && preg_match('#<img src="program/resources/blocked\.gif"#', $body)) { + $content = $RCMAIL->get_resource_content('blocked.gif'); + if ($content && ($attachment = rcmail_save_image('blocked.gif', 'image/gif', $content))) { $COMPOSE['attachments'][$attachment['id']] = $attachment; $url = sprintf('%s&_id=%s&_action=display-attachment&_file=rcmfile%s', $RCMAIL->comm_path, $COMPOSE['id'], $attachment['id']); - $body = preg_replace('#\./program/resources/blocked\.gif#', $url, $body); + $body = preg_replace('#program/resources/blocked\.gif#', $url, $body); } } @@ -794,7 +833,7 @@ function rcmail_compose_part_body($part, $isHtml = false) { - global $RCMAIL, $MESSAGE, $LINE_LENGTH, $compose_mode; + global $RCMAIL, $COMPOSE, $MESSAGE, $LINE_LENGTH, $compose_mode; // Check if we have enough memory to handle the message in it // #1487424: we need up to 10x more memory than the body @@ -808,6 +847,14 @@ // message is cached but not exists (#1485443), or other error if ($body === false) { return ''; + } + + // register this part as pgp encrypted + if (strpos($body, 'BEGIN PGP MESSAGE') !== false) { + $MESSAGE->pgp_mime = true; + $RCMAIL->output->set_env('pgp_mime_message', array( + '_mbox' => $RCMAIL->storage->get_folder(), '_uid' => $MESSAGE->uid, '_part' => $part->mime_id, + )); } if ($isHtml) { @@ -949,7 +996,7 @@ "googie.setCurrentLanguage('%s');\n". "googie.setDecoration(false);\n". "googie.decorateTextarea('%s');\n", - $RCMAIL->output->get_skin_path(), + $RCMAIL->output->asset_url($RCMAIL->output->get_skin_path()), $RCMAIL->url(array('_task' => 'utils', '_action' => 'spell', '_remote' => 1)), !empty($dictionary) ? 'true' : 'false', rcube::JQ(rcube::Q($RCMAIL->gettext('checkspelling'))), @@ -976,16 +1023,7 @@ { global $RCMAIL, $MESSAGE, $LINE_LENGTH; - // build reply prefix - $from = array_pop(rcube_mime::decode_address_list($MESSAGE->get_header('from'), 1, false, $MESSAGE->headers->charset)); - $prefix = $RCMAIL->gettext(array( - 'name' => 'mailreplyintro', - 'vars' => array( - 'date' => $RCMAIL->format_date($MESSAGE->headers->date, $RCMAIL->config->get('date_long')), - 'sender' => $from['name'] ? $from['name'] : rcube_utils::idn_to_utf8($from['mailto']), - ) - )); - + $prefix = rcmail_get_reply_header($MESSAGE); $reply_mode = intval($RCMAIL->config->get('reply_mode')); if (!$bodyIsHtml) { @@ -1029,6 +1067,19 @@ return $prefix . $body . $suffix; } +function rcmail_get_reply_header($message) +{ + global $RCMAIL; + + $from = array_pop(rcube_mime::decode_address_list($message->get_header('from'), 1, false, $message->headers->charset)); + return $RCMAIL->gettext(array( + 'name' => 'mailreplyintro', + 'vars' => array( + 'date' => $RCMAIL->format_date($message->headers->date, $RCMAIL->config->get('date_long')), + 'sender' => $from['name'] ?: rcube_utils::idn_to_utf8($from['mailto']), + ) + )); +} function rcmail_create_forward_body($body, $bodyIsHtml) { @@ -1156,6 +1207,10 @@ $cid_map = array(); $messages = array(); + if ($message->pgp_mime) { + return $cid_map; + } + foreach ((array)$message->mime_parts as $pid => $part) { if ($part->disposition == 'attachment' || ($part->disposition == 'inline' && $bodyIsHtml) || $part->filename) { // skip parts that aren't valid attachments @@ -1222,6 +1277,11 @@ global $RCMAIL, $COMPOSE; $cid_map = array(); + + if ($message->pgp_mime) { + return $cid_map; + } + foreach ((array)$message->mime_parts as $pid => $part) { if (($part->content_id || $part->content_location) && $part->filename) { if ($attachment = rcmail_save_attachment($message, $pid)) { @@ -1248,6 +1308,10 @@ $storage = $RCMAIL->get_storage(); $names = array(); $refs = array(); + + if ($MESSAGE->pgp_mime) { + return; + } $loaded_attachments = array(); foreach ((array)$COMPOSE['attachments'] as $attachment) { @@ -1309,7 +1373,6 @@ } else { $data = $storage->get_raw_body($message->uid); - $curr_mem += $message->size; } $attachment = array( @@ -1398,18 +1461,31 @@ return false; } -function rcmail_save_image($path, $mimetype='') +function rcmail_save_image($path, $mimetype = '', $data = null) { global $COMPOSE; // handle attachments in memory - $data = file_get_contents($path); + if (empty($data)) { + $data = file_get_contents($path); + $is_file = true; + } + $name = rcmail_basename($path); + + if (empty($mimetype)) { + if ($is_file) { + $mimetype = rcube_mime::file_content_type($path, $name); + } + else { + $mimetype = rcube_mime::file_content_type($data, $name, 'application/octet-stream', true); + } + } $attachment = array( 'group' => $COMPOSE['id'], 'name' => $name, - 'mimetype' => $mimetype ? $mimetype : rcube_mime::file_content_type($path, $name), + 'mimetype' => $mimetype, 'data' => $data, 'size' => strlen($data), ); @@ -1493,15 +1569,14 @@ if (!$attrib['id']) $attrib['id'] = 'rcmAttachmentList'; - $out = "\n"; - $jslist = array(); - $button = ''; - $skin_path = $RCMAIL->config->get('skin_path'); + $out = "\n"; + $jslist = array(); + $button = ''; if (is_array($COMPOSE['attachments'])) { if ($attrib['deleteicon']) { $button = html::img(array( - 'src' => $skin_path . $attrib['deleteicon'], + 'src' => $RCMAIL->output->abs_url($attrib['deleteicon'], true), 'alt' => $RCMAIL->gettext('delete') )); } @@ -1540,13 +1615,13 @@ } if ($attrib['deleteicon']) - $COMPOSE['deleteicon'] = $skin_path . $attrib['deleteicon']; + $COMPOSE['deleteicon'] = $RCMAIL->output->abs_url($attrib['deleteicon'], true); else if (rcube_utils::get_boolean($attrib['textbuttons'])) $COMPOSE['textbuttons'] = true; if ($attrib['cancelicon']) - $OUTPUT->set_env('cancelicon', $skin_path . $attrib['cancelicon']); + $OUTPUT->set_env('cancelicon', $RCMAIL->output->abs_url($attrib['cancelicon'], true)); if ($attrib['loadingicon']) - $OUTPUT->set_env('loadingicon', $skin_path . $attrib['loadingicon']); + $OUTPUT->set_env('loadingicon', $RCMAIL->output->abs_url($attrib['loadingicon'], true)); $OUTPUT->set_env('attachments', $jslist); $OUTPUT->add_gui_object('attachmentlist', $attrib['id']); @@ -1642,7 +1717,7 @@ } -function rcmail_receipt_checkbox($attrib) +function rcmail_mdn_checkbox($attrib) { global $RCMAIL, $MESSAGE, $compose_mode; @@ -1652,13 +1727,13 @@ if (!isset($attrib['id'])) $attrib['id'] = 'receipt'; - $attrib['name'] = '_receipt'; + $attrib['name'] = '_mdn'; $attrib['value'] = '1'; $checkbox = new html_checkbox($attrib); - if (isset($_POST['_receipt'])) - $mdn_default = $_POST['_receipt']; + if (isset($_POST['_mdn'])) + $mdn_default = $_POST['_mdn']; else if (in_array($compose_mode, array(RCUBE_COMPOSE_DRAFT, RCUBE_COMPOSE_EDIT))) $mdn_default = (bool) $MESSAGE->headers->mdn_to; else @@ -1733,7 +1808,6 @@ 'noselection' => '- ' . $RCMAIL->gettext('dontsave') . ' -', 'folder_filter' => 'mail', 'folder_rights' => 'w', - 'realnames' => $RCMAIL->config->get('show_real_foldernames'), ))); return $select->show(isset($_POST['_store_target']) ? $_POST['_store_target'] : $COMPOSE['param']['sent_mbox'], $attrib); -- Gitblit v1.9.1