diff --git a/program/js/app.js b/program/js/app.js index 36694b29d..09baeabea 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -3396,8 +3396,7 @@ function rcube_webmail() type: 'GET', url: this.url('get', { '_mbox': this.env.mailbox, '_uid': this.env.uid, '_part': this.env.pgp_mime_part }), error: function(o, status, err) { - ref.hide_message(msgkey); - ref.http_error(o, status, err, lock); + ref.http_error(o, status, err, msgid); }, success: function(data) { ref.mailvelope_display_container(selector, data, keyring, msgid); @@ -3406,11 +3405,31 @@ function rcube_webmail() } } else if (action == 'compose' && window.mailvelope) { - this.enable_command('compose-encrypted', true); + if (this.env.pgp_mime_message) { + // fetch PGP/Mime part and open load into Mailvelope editor + var lock = this.set_busy(true, this.get_label('loadingdata')); + $.ajax({ + type: 'GET', + url: this.url('get', this.env.pgp_mime_message), + error: function(o, status, err) { + ref.http_error(o, status, err, lock); + ref.enable_command('compose-encrypted', true); + }, + success: function(data) { + ref.set_busy(false, null, lock); + ref.compose_encrypted({ quotedMail: data }); + ref.enable_command('compose-encrypted', true); + } + }); + } + else { + // enable encrypted compose toggle + this.enable_command('compose-encrypted', true); + } } }; - // handler for the 'compose-encrypt' command + // handler for the 'compose-encrypted' command this.compose_encrypted = function(props) { var container = $('#' + this.env.composebody).parent(); @@ -3429,6 +3448,14 @@ function rcube_webmail() // embed Mailvelope editor container else { var options = { predefinedText: $('#' + this.env.composebody).val() }; + if (props.quotedMail) { + options = { quotedMail: props.quotedMail, quotedMailIndent: false }; + } + if (this.env.compose_mode == 'reply') { + options.quotedMailIndent = true; + options.quotedMailHeader = this.env.compose_reply_header; + } + mailvelope.createEditorContainer('#' + container.attr('id'), ref.mailvelope_keyring, options).then(function(editor) { ref.mailvelope_editor = editor; ref.compose_skip_unsavedcheck = true; @@ -3436,6 +3463,15 @@ function rcube_webmail() container.addClass('mailvelope'); $('#' + ref.env.composebody).hide(); + + // notify user about loosing attachments + if (ref.env.attachments && !$.isEmptyObject(ref.env.attachments)) { + alert(ref.get_label('encryptnoattachments')); + + $.each(ref.env.attachments, function(name, attach) { + ref.remove_from_attachment_list(name); + }); + } }).catch(function(err) { console.error(err); }); diff --git a/program/localization/en_US/messages.inc b/program/localization/en_US/messages.inc index be8a0d8f7..acb42823c 100644 --- a/program/localization/en_US/messages.inc +++ b/program/localization/en_US/messages.inc @@ -59,6 +59,7 @@ $messages['encryptedmessage'] = 'This is an encrypted message and can not be dis $messages['externalmessagedecryption'] = 'This is an encrypted message and can be decrypted with your browser extension.'; $messages['nopubkeyfor'] = 'No valid public key found for $email'; $messages['nopubkeyforsender'] = 'No valid public key found for your sender identity. Do you want to encrypt the message for the recipients only?'; +$messages['encryptnoattachments'] = 'Alraady uploaded attachments cannot be encrypted. Please re-add them in the encryption editor.'; $messages['nocontactsfound'] = 'No contacts found.'; $messages['contactnotfound'] = 'The requested contact was not found.'; $messages['contactsearchonly'] = 'Enter some search terms to find contacts'; diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc index 1896e93d2..6989c3a8e 100644 --- a/program/steps/mail/compose.inc +++ b/program/steps/mail/compose.inc @@ -83,7 +83,8 @@ $OUTPUT->add_label('nosubject', 'nosenderwarning', 'norecipientwarning', 'nosubj 'messagesaved', 'converting', 'editorwarning', 'searching', 'uploading', 'uploadingmany', 'fileuploaderror', 'sendmessage', 'newresponse', 'responsename', 'responsetext', 'save', 'savingresponse', 'restoresavedcomposedata', 'restoremessage', 'delete', 'restore', 'ignore', - 'selectimportfile', 'messageissent', 'nopubkeyfor', 'nopubkeyforsender'); + 'selectimportfile', 'messageissent', 'loadingdata', 'nopubkeyfor', 'nopubkeyforsender', + 'encryptnoattachments'); $OUTPUT->set_pagetitle($RCMAIL->gettext('compose')); @@ -749,6 +750,21 @@ function rcmail_prepare_message_body() } 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; @@ -771,14 +787,21 @@ function rcmail_prepare_message_body() } // 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(); @@ -808,7 +831,7 @@ function rcmail_prepare_message_body() 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 @@ -824,6 +847,14 @@ function rcmail_compose_part_body($part, $isHtml = 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) { if ($part->ctype_secondary == 'html') { } @@ -990,16 +1021,7 @@ function rcmail_create_reply_body($body, $bodyIsHtml) { 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) { @@ -1043,6 +1065,19 @@ function rcmail_create_reply_body($body, $bodyIsHtml) 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) { @@ -1170,6 +1205,10 @@ function rcmail_write_compose_attachments(&$message, $bodyIsHtml) $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 @@ -1236,6 +1275,11 @@ function rcmail_write_inline_attachments(&$message) 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)) { @@ -1263,6 +1307,10 @@ function rcmail_write_forward_attachments() $names = array(); $refs = array(); + if ($MESSAGE->pgp_mime) { + return; + } + $loaded_attachments = array(); foreach ((array)$COMPOSE['attachments'] as $attachment) { $loaded_attachments[$attachment['name'] . $attachment['mimetype']] = $attachment; diff --git a/skins/larry/images/buttons.png b/skins/larry/images/buttons.png index 713ac169a..bd3e29d89 100644 Binary files a/skins/larry/images/buttons.png and b/skins/larry/images/buttons.png differ diff --git a/skins/larry/mail.css b/skins/larry/mail.css index 9d8ddcead..47d2f4806 100644 --- a/skins/larry/mail.css +++ b/skins/larry/mail.css @@ -1302,6 +1302,11 @@ div.message-partheaders .headers-table td.header { bottom: 42px; } +#composebodycontainer.mailvelope { + right: 0; + z-index: 10; +} + #composebodycontainer.mailvelope > iframe[scrolling='no'] { position: relative; top: -12px; diff --git a/skins/larry/styles.css b/skins/larry/styles.css index e418e0a98..581c2567a 100644 --- a/skins/larry/styles.css +++ b/skins/larry/styles.css @@ -2160,6 +2160,14 @@ ul.proplist li { background-position: center -1932px; } +.toolbar a.button.encrypt { + background-position: center -2025px; +} + +.toolbar a.button.encrypt.selected { + background-position: center -2065px; +} + a.menuselector { display: inline-block; border: 1px solid #ababab;