1
/* ***** BEGIN LICENSE BLOCK *****
2
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
4
* The contents of this file are subject to the Mozilla Public
5
* License Version 1.1 (the "MPL"); you may not use this file
6
* except in compliance with the MPL. You may obtain a copy of
7
* the MPL at http://www.mozilla.org/MPL/
9
* Software distributed under the MPL is distributed on an "AS
10
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11
* implied. See the MPL for the specific language governing
12
* rights and limitations under the MPL.
14
* The Original Code is Enigmail.
16
* The Initial Developer of the Original Code is Ramalingam Saravanan.
17
* Portions created by Ramalingam Saravanan <svn@xmlterm.org> are
18
* Copyright (C) 2001 Ramalingam Saravanan. All Rights Reserved.
21
* Patrick Brunschwig <patrick@mozilla-enigmail.org>
23
* Alternatively, the contents of this file may be used under the terms of
24
* either the GNU General Public License Version 2 or later (the "GPL"), or
25
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26
* in which case the provisions of the GPL or the LGPL are applicable instead
27
* of those above. If you wish to allow use of your version of this file only
28
* under the terms of either the GPL or the LGPL, and not to allow others to
29
* use your version of this file under the terms of the MPL, indicate your
30
* decision by deleting the provisions above and replace them with the notice
31
* and other provisions required by the GPL or the LGPL. If you do not delete
32
* the provisions above, a recipient may use your version of this file under
33
* the terms of any one of the MPL, the GPL or the LGPL.
34
* ***** END LICENSE BLOCK ***** */
36
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
40
Components.utils.import("resource:///modules/gloda/mimemsg.js");
44
Components.utils.import("resource://app/modules/gloda/mimemsg.js");
47
Components.utils.import("resource://enigmail/enigmailCommon.jsm");
48
Components.utils.import("resource://enigmail/commonFuncs.jsm");
49
Components.utils.import("resource://enigmail/mimeVerify.jsm");
51
if (! Enigmail) var Enigmail = {};
53
Enigmail.getEnigmailSvc = function ()
55
return EnigmailCommon.getService(window);
61
decryptedMessage: null,
68
removeListener: false,
69
enableExperiments: false,
70
headersList: ["content-type", "content-transfer-encoding",
71
"x-enigmail-version", "x-pgp-encoding-format" ],
73
messengerStartup: function ()
76
// private function to overwrite attributes
77
function overrideAttribute (elementIdList, attrName, prefix, suffix)
79
for (var index = 0; index < elementIdList.length; index++) {
80
var elementId = elementIdList[index];
81
var element = document.getElementById(elementId);
84
var oldValue = element.getAttribute(attrName);
85
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: overrideAttribute "+attrName+": oldValue="+oldValue+"\n");
86
var newValue = prefix+elementId+suffix;
88
element.setAttribute(attrName, newValue);
92
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: *** UNABLE to override id="+ elementId+"\n");
97
Enigmail.msg.messagePane = document.getElementById("messagepane");
99
if (Enigmail.msg.messagePane == null) return; // TB on Mac OS X calls this twice -- once far too early
101
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: Startup\n");
104
var viewSecurityCmd = document.getElementById("cmd_viewSecurityStatus");
105
if (viewSecurityCmd) {
106
viewSecurityCmd.setAttribute("oncommand", "Enigmail.msg.viewSecurityInfo(null, true);");
109
// Override print command
110
var printElementIds = ["cmd_print", "cmd_printpreview", "key_print", "button-print",
111
"mailContext-print", "mailContext-printpreview"];
113
overrideAttribute( printElementIds, "oncommand",
114
"Enigmail.msg.msgPrint('", "');");
116
Enigmail.msg.overrideLayoutChange();
118
Enigmail.msg.savedHeaders = null;
120
Enigmail.msg.decryptButton = document.getElementById("button-enigmail-decrypt");
122
// Need to add event listener to Enigmail.msg.messagePane to make it work
123
// Adding to msgFrame doesn't seem to work
124
Enigmail.msg.messagePane.addEventListener("unload", Enigmail.msg.messageFrameUnload.bind(Enigmail.msg), true);
126
// override double clicking attachments, but fall back to existing handler if present
127
var attListElem = document.getElementById("attachmentList");
129
var newHandler = "Enigmail.msg.enigAttachmentListClick('attachmentList', event)";
130
var oldHandler = attListElem.getAttribute("onclick");
132
newHandler = "if (!" + newHandler + ") {" + oldHandler + "}";
133
attListElem.setAttribute("onclick", newHandler);
136
var treeController = {
137
supportsCommand: function(command) {
138
// EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: treeCtrl: supportsCommand: "+command+"\n");
140
case "button_enigmail_decrypt":
145
isCommandEnabled: function(command) {
146
// EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: treeCtrl: isCommandEnabled: "+command+"\n");
148
if (gFolderDisplay.messageDisplay.visible) {
149
if (gFolderDisplay.selectedCount != 1) Enigmail.hdrView.statusBarHide();
150
return (gFolderDisplay.selectedCount == 1);
152
Enigmail.hdrView.statusBarHide();
157
doCommand: function(command) {
158
//EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: treeCtrl: doCommand: "+command+"\n");
161
onEvent: function(event) {
162
// EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: treeCtrl: onEvent: "+command+"\n");
167
top.controllers.appendController(treeController);
170
viewSecurityInfo: function (event, displaySmimeMsg)
172
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: viewSecurityInfo\n");
174
if (event && event.button != 0)
177
if (gSignatureStatus >= 0 || gEncryptionStatus >= 0) {
178
showMessageReadSecurityInfo();
181
if (Enigmail.msg.securityInfo)
182
this.viewOpenpgpInfo();
184
showMessageReadSecurityInfo();
188
viewOpenpgpInfo: function ()
190
if (Enigmail.msg.securityInfo) {
191
EnigmailCommon.longAlert(window, EnigmailCommon.getString("securityInfo")+Enigmail.msg.securityInfo.statusInfo);
196
messageReload: function (noShowReload)
198
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: this.messageReload: "+noShowReload+"\n");
200
Enigmail.msg.noShowReload = noShowReload;
206
reloadCompleteMsg: function ()
208
gDBView.reloadMessageWithAllParts();
212
setAttachmentReveal: function (attachmentList)
214
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: setAttachmentReveal\n");
216
var revealBox = document.getElementById("enigmailRevealAttachments");
217
revealBox.setAttribute("hidden", attachmentList == null ? "true" : "false");
221
messageCleanup: function () {
222
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: messageCleanup\n");
224
var enigmailBox = document.getElementById("enigmailBox");
226
if (enigmailBox && !enigmailBox.collapsed) {
227
enigmailBox.setAttribute("collapsed", "true");
229
var statusText = document.getElementById("expandedEnigmailStatusText");
235
this.setAttachmentReveal(null);
237
if (Enigmail.msg.createdURIs.length) {
238
// Cleanup messages belonging to this window (just in case)
239
var enigmailSvc = Enigmail.getEnigmailSvc();
241
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: Cleanup: Deleting messages\n");
242
for (var index=0; index < Enigmail.msg.createdURIs.length; index++) {
243
enigmailSvc.deleteMessageURI(Enigmail.msg.createdURIs[index]);
245
Enigmail.msg.createdURIs = [];
249
Enigmail.msg.decryptedMessage = null;
250
Enigmail.msg.securityInfo = null;
253
messageFrameUnload: function ()
255
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: messageFrameUnload\n");
257
if (Enigmail.msg.noShowReload) {
258
Enigmail.msg.noShowReload = false;
261
Enigmail.msg.savedHeaders = null;
263
Enigmail.msg.messageCleanup();
267
overrideLayoutChange: function ()
269
// Enigmail needs to listen to some layout changes in order to decrypt
270
// messages in case the user changes the layout
271
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: overrideLayoutChange\n");
272
var viewTypeElementIds = ["messagePaneVertical",
273
"messagePaneClassic",
276
for (i = 0; i < viewTypeElementIds.length; i++) {
277
var elementId = viewTypeElementIds[i];
278
var element = document.getElementById(elementId);
281
var oldValue = element.getAttribute("oncommand").replace(/;/g, "");
282
var arg=oldValue.replace(/^(.*)(\(.*\))/, "$2");
283
element.setAttribute("oncommand", "Enigmail.msg.changeMailLayout"+arg);
288
var toggleMsgPaneElementIds = ["cmd_toggleMessagePane"];
289
for (i = 0; i < toggleMsgPaneElementIds.length; i++) {
290
var elementId = toggleMsgPaneElementIds[i];
291
var element = document.getElementById(elementId);
294
element.setAttribute("oncommand", "Enigmail.msg.toggleMessagePane()");
300
changeMailLayout: function (viewType)
302
// call the original layout change 1st
303
ChangeMailLayout(viewType);
305
// This event requires that we re-subscribe to these events!
306
Enigmail.msg.messagePane.addEventListener("unload", Enigmail.msg.messageFrameUnload.bind(Enigmail.msg), true);
307
this.messageReload(false);
310
toggleMessagePane: function () {
311
Enigmail.hdrView.statusBarHide();
312
MsgToggleMessagePane(true);
314
var button=document.getElementById("button_enigmail_decrypt");
315
if (gFolderDisplay.messageDisplay.visible) {
316
button.removeAttribute("disabled");
319
button.setAttribute("disabled", "true");
323
getCurrentMsgUriSpec: function ()
326
if (gFolderDisplay.selectedMessages.length != 1)
329
var uriSpec = gFolderDisplay.selectedMessageUris[0];
330
//EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: getCurrentMsgUriSpec: uriSpec="+uriSpec+"\n");
340
getCurrentMsgUrl: function ()
342
var uriSpec = this.getCurrentMsgUriSpec();
343
return this.getUrlFromUriSpec(uriSpec);
346
getUrlFromUriSpec: function (uriSpec)
352
var msgService = messenger.messageServiceFromURI(uriSpec);
354
var urlObj = new Object();
355
msgService.GetUrlForUri(uriSpec, urlObj, msgWindow);
357
var url = urlObj.value;
359
if (url.scheme=="file") {
363
return url.QueryInterface(Components.interfaces.nsIMsgMailNewsUrl);
372
updateOptionsDisplay: function ()
374
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: updateOptionsDisplay: \n");
375
var optList = ["autoDecrypt"];
377
for (var j=0; j<optList.length; j++) {
378
var menuElement = document.getElementById("enigmail_"+optList[j]);
379
menuElement.setAttribute("checked", EnigmailCommon.getPref(optList[j]) ? "true" : "false");
381
menuElement = document.getElementById("enigmail_"+optList[j]+"2");
383
menuElement.setAttribute("checked", EnigmailCommon.getPref(optList[j]) ? "true" : "false");
386
optList = ["decryptverify", "importpublickey", "savedecrypted"];
387
for (j=0; j<optList.length; j++) {
388
menuElement = document.getElementById("enigmail_"+optList[j]);
389
if (Enigmail.msg.decryptButton && Enigmail.msg.decryptButton.disabled) {
390
menuElement.setAttribute("disabled", "true");
393
menuElement.removeAttribute("disabled");
396
menuElement = document.getElementById("enigmail_"+optList[j]+"2");
398
if (Enigmail.msg.decryptButton && Enigmail.msg.decryptButton.disabled) {
399
menuElement.setAttribute("disabled", "true");
402
menuElement.removeAttribute("disabled");
408
displayMainMenu: function(menuPopup) {
410
function traverseTree(currentElement, func)
414
func(currentElement);
415
if (currentElement.id)
416
EnigmailCommon.DEBUG_LOG("traverseTree: "+currentElement.id+"\n");
420
var currentElementChild=currentElement.childNodes[i];
421
while (currentElementChild)
423
// Recursively traverse the tree structure of the child node
424
traverseTree(currentElementChild, func);
426
currentElementChild=currentElement.childNodes[i];
431
var p = menuPopup.parentNode;
432
var a = document.getElementById("menu_EnigmailPopup");
433
var c = a.cloneNode(true);
434
p.removeChild(menuPopup);
437
traverseTree(c, function _updNode(node) {
438
if (node.id && node.id.length > 0) node.id += "2";
444
toggleAttribute: function (attrName)
446
EnigmailCommon.DEBUG_LOG("enigmailMsgessengerOverlay.js: toggleAttribute('"+attrName+"')\n");
448
var menuElement = document.getElementById("enigmail_"+attrName);
450
var oldValue = EnigmailCommon.getPref(attrName);
451
EnigmailCommon.setPref(attrName, !oldValue);
453
this.updateOptionsDisplay();
455
if (attrName == "autoDecrypt")
456
this.messageReload(false);
459
messageImport: function (event)
461
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: messageImport: "+event+"\n");
463
return this.messageParse(!event, true, "", this.getCurrentMsgUriSpec());
466
// callback function for automatic decryption
467
messageAutoDecrypt: function (event)
469
Enigmail.msg.messageDecrypt(event, true);
472
// analyse message header and decrypt/verify message
473
messageDecrypt: function (event, isAuto)
475
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: messageDecrypt: "+event+"\n");
482
let contentType = "text/plain";
483
if ('content-type' in currentHeaderData) contentType=currentHeaderData['content-type'].headerValue;
486
// don't parse message if we know it's a PGP/MIME message
487
if (((contentType.search(/^multipart\/signed(;|$)/i) == 0) && (contentType.search(/application\/pgp-signature/i)>0)) ||
488
((contentType.search(/^multipart\/encrypted(;|$)/i) == 0) && (contentType.search(/application\/pgp-encrypted/i)>0))) {
489
this.messageDecryptCb(event, isAuto, null);
494
if (gFolderDisplay.selectedMessageIsNews) throw "dummy"; // workaround for broken NNTP support in Gloda
495
MsgHdrToMimeMessage(gFolderDisplay.selectedMessage , cbObj, Enigmail.msg.msgDecryptMimeCb, true, {examineEncryptedParts: true, partsOnDemand: false});
498
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: enigMessageDecrypt: cannot use MsgHdrToMimeMessage\n");
499
this.messageDecryptCb(event, isAuto, null);
504
msgDecryptMimeCb: function (msg, mimeMsg)
506
// MsgHdrToMimeMessage is not on the main thread which may lead to problems with
507
// accessing DOM and debugging
509
EnigmailCommon.dispatchEvent(
511
var enigmailSvc=Enigmail.getEnigmailSvc();
512
if (!enigmailSvc) return;
514
var event = argList[0];
515
var isAuto = argList[1];
516
var mimeMsg = argList[2];
517
Enigmail.msg.messageDecryptCb(event, isAuto, mimeMsg);
518
}, 0, [this.event, this.isAuto, mimeMsg]);
521
enumerateMimeParts: function (mimePart, resultObj)
523
EnigmailCommon.DEBUG_LOG("enumerateMimeParts: "+mimePart.partName+" - "+mimePart.headers["content-type"]+"\n");
526
if (typeof(mimePart.contentType) == "string" &&
527
mimePart.contentType == "multipart/fake-container") {
528
// workaround for wrong content type of signed message
529
let signedPart = mimePart.parts[1];
530
if (typeof(signedPart.headers["content-type"][0]) == "string") {
531
if (signedPart.headers["content-type"][0].search(/application\/pgp-signature/i) >= 0) {
532
resultObj.signed=signedPart.partName.replace(/\.[0-9]+$/, "");
533
EnigmailCommon.DEBUG_LOG("enumerateMimeParts: found signed subpart "+resultObj.signed + "\n");
538
var ct = mimePart.headers["content-type"][0];
539
if (typeof(ct) == "string") {
540
if (ct.search(/multipart\/signed.*application\/pgp-signature/i) >= 0) {
541
resultObj.signed=mimePart.partName;
543
else if (ct.search(/application\/pgp-encrypted/i) >= 0)
544
resultObj.encrypted=mimePart.partName;
548
// catch exception if no headers or no content-type defined.
552
for (i in mimePart.parts) {
553
this.enumerateMimeParts(mimePart.parts[i], resultObj);
558
messageDecryptCb: function (event, isAuto, mimeMsg)
560
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: messageDecryptCb:\n");
565
var contentType = "";
567
if (mimeMsg == null) {
568
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: messageDecryptCb: mimeMsg is null\n");
570
contentType=currentHeaderData['content-type'].headerValue;
573
contentType = "text/plain";
576
headers: {'content-type': contentType },
577
contentType: contentType,
582
// Copy selected headers
583
Enigmail.msg.savedHeaders = {};
585
for (var index=0; index < Enigmail.msg.headersList.length; index++) {
586
var headerName = Enigmail.msg.headersList[index];
587
var headerValue = "";
589
if (mimeMsg.headers[headerName] != undefined) {
590
headerValue = mimeMsg.headers[headerName].toString();
593
Enigmail.msg.savedHeaders[headerName] = headerValue;
594
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: header "+headerName+": "+headerValue+"\n");
597
var embeddedSigned = null;
598
var embeddedEncrypted = null;
600
if (mimeMsg.parts != null && Enigmail.msg.savedHeaders["content-type"].search(/^multipart\/encrypted(;|$)/i) != 0) {
602
var resultObj={ encrypted: "", signed: "" };
603
this.enumerateMimeParts(mimeMsg, resultObj);
604
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: embedded objects: "+resultObj.encrypted+" / "+resultObj.signed+"\n");
606
// ignore mime parts on top level (regular messages)
607
if (resultObj.signed.indexOf(".") < 0) resultObj.signed = null;
608
if (resultObj.encrypted.indexOf(".") < 0) resultObj.encrypted = null;
610
if (resultObj.encrypted || resultObj.signed) {
611
let mailUrl = this.getCurrentMsgUrl();
613
if (resultObj.signed) embeddedSigned = mailUrl.spec+"?part="+resultObj.signed.replace(/\.\d+$/, "");
614
if (resultObj.encrypted) embeddedEncrypted = mailUrl.spec+"?part="+resultObj.encrypted.replace(/\.\d+$/, "");
619
var contentEncoding = "";
620
var xEnigmailVersion = "";
621
var msgUriSpec = this.getCurrentMsgUriSpec();
623
if (Enigmail.msg.savedHeaders) {
624
contentType = Enigmail.msg.savedHeaders["content-type"];
625
contentEncoding = Enigmail.msg.savedHeaders["content-transfer-encoding"];
626
xEnigmailVersion = Enigmail.msg.savedHeaders["x-enigmail-version"];
629
if (isAuto && (! EnigmailCommon.getPref("autoDecrypt"))) {
630
var signedMsg = ((contentType.search(/^multipart\/signed(;|$)/i) == 0) && (contentType.search(/application\/pgp-signature/i)>0));
631
var encrypedMsg = ((contentType.search(/^multipart\/encrypted(;|$)/i) == 0) && (contentType.search(/application\/pgp-encrypted/i)>0));
632
if (embeddedSigned || embeddedEncrypted ||
633
encrypedMsg || signedMsg) {
634
enigmailSvc = Enigmail.getEnigmailSvc();
639
((!encrypedMsg) && (embeddedSigned || embeddedEncrypted))) {
640
Enigmail.hdrView.updateHdrIcons(EnigmailCommon.POSSIBLE_PGPMIME, 0, "", "", "", EnigmailCommon.getString("possiblyPgpMime"));
646
if (contentType.search(/^multipart\/encrypted(;|$)/i) == 0) {
647
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: multipart/encrypted\n");
649
enigmailSvc = Enigmail.getEnigmailSvc();
654
if (((contentType.search(/^multipart\/encrypted(;|$)/i) == 0) ||
655
(embeddedEncrypted && contentType.search(/^multipart\/mixed(;|$)/i) == 0))
656
&& (!embeddedSigned)) {
658
enigmailSvc = Enigmail.getEnigmailSvc();
663
Enigmail.msg.messageReload(false);
665
else if (embeddedEncrypted && (! encrypedMsg)) {
666
var mailNewsUrl = this.getCurrentMsgUrl();
668
mailNewsUrl.spec = embeddedEncrypted;
669
Enigmail.msg.verifyEmbeddedMsg(window, mailNewsUrl, msgWindow, msgUriSpec, contentEncoding, event);
676
var tryVerify = false;
677
var enableSubpartTreatment = false;
678
// special treatment for embedded signed messages
679
if (embeddedSigned) {
680
if (contentType.search(/^multipart\/encrypted(;|$)/i) == 0) {
683
if (contentType.search(/^multipart\/mixed(;|$)/i) == 0) {
685
enableSubpartTreatment = true;
689
if ((contentType.search(/^multipart\/signed(;|$)/i) == 0) &&
690
(contentType.search(/application\/pgp-signature/i) >= 0)) {
695
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: messageDecryptCb: multipart/signed\n");
697
var mailNewsUrl = this.getCurrentMsgUrl();
699
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: messageDecryptCb: mailNewsUrl:"+mailNewsUrl+"\n");
700
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: messageDecryptCb: msgUriSpec:"+msgUriSpec+"\n");
701
if (embeddedSigned) {
702
mailNewsUrl.spec = embeddedSigned;
703
Enigmail.msg.verifyEmbeddedMsg(window, mailNewsUrl, msgWindow, msgUriSpec, contentEncoding, event);
706
var verifier = EnigmailVerify.newVerfier(false, mailNewsUrl);
707
verifier.startStreaming(window, msgWindow, msgUriSpec);
714
this.messageParse(!event, false, contentEncoding, msgUriSpec);
717
EnigmailCommon.writeException("enigmailMessengerOverlay.js: messageDecryptCb", ex);
722
messageParse: function (interactive, importOnly, contentEncoding, msgUriSpec)
724
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: messageParse: "+interactive+"\n");
725
var msgFrame = EnigmailCommon.getFrame(window, "messagepane");
726
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: msgFrame="+msgFrame+"\n");
728
var bodyElement = msgFrame.document.getElementsByTagName("body")[0];
729
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: bodyElement="+bodyElement+"\n");
731
var findStr = /* interactive ? null : */ "-----BEGIN PGP";
736
if (bodyElement.firstChild) {
737
let node = bodyElement.firstChild;
739
if (node.nodeName == "DIV") {
740
foundIndex = node.textContent.indexOf(findStr);
742
if (foundIndex >= 0) {
743
if (node.textContent.indexOf(findStr+" LICENSE AUTHORIZATION") == foundIndex)
746
if (foundIndex >= 0) {
751
node = node.nextSibling;
755
if (foundIndex >= 0) {
756
msgText = bodyElement.textContent;
764
var charset = msgWindow ? msgWindow.mailCharacterSet : "";
766
// Encode ciphertext to charset from unicode
767
msgText = EnigmailCommon.convertFromUnicode(msgText, charset);
769
var mozPlainText = bodyElement.innerHTML.search(/class=\"moz-text-plain\"/);
771
if ((mozPlainText >= 0) && (mozPlainText < 40)) {
772
// workaround for too much expanded emoticons in plaintext msg
773
var r = new RegExp(/( )(;-\)|:-\)|;\)|:\)|:-\(|:\(|:-\\|:-P|:-D|:-\[|:-\*|\>:o|8-\)|:-\$|:-X|\=-O|:-\!|O:-\)|:\'\()( )/g);
774
if (msgText.search(r) >= 0) {
775
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: messageParse: performing emoticons fixing\n");
776
msgText = msgText.replace(r, "$2");
780
// extract text preceeding and/or following armored block
784
head=msgText.substring(0,msgText.indexOf(findStr)).replace(/^[\n\r\s]*/,"");
785
head=head.replace(/[\n\r\s]*$/,"");
786
var endStart=msgText.indexOf("-----END PGP");
787
var nextLine=msgText.substring(endStart).search(/[\n\r]/);
789
tail=msgText.substring(endStart+nextLine).replace(/^[\n\r\s]*/,"");
793
//EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: msgText='"+msgText+"'\n");
795
var mailNewsUrl = this.getUrlFromUriSpec(msgUriSpec);
797
var urlSpec = mailNewsUrl ? mailNewsUrl.spec : "";
799
let retry = (charset != "UTF-8" ? 1 : 2);
801
Enigmail.msg.messageParseCallback(msgText, contentEncoding, charset, interactive,
802
importOnly, urlSpec, "", retry, head, tail,
807
messageParseCallback: function (msgText, contentEncoding, charset, interactive,
808
importOnly, messageUrl, signature, retry,
809
head, tail, msgUriSpec)
811
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: messageParseCallback: "+interactive+", "+interactive+", importOnly="+importOnly+", charset="+charset+", msgUrl="+messageUrl+", retry="+retry+", signature='"+signature+"'\n");
813
const nsIEnigmail = Components.interfaces.nsIEnigmail;
818
var enigmailSvc = Enigmail.getEnigmailSvc();
824
var newSignature = "";
827
var errorMsgObj = new Object();
828
var keyIdObj = new Object();
829
var blockSeparationObj = { value: "" };
834
var importFlags = nsIEnigmail.UI_INTERACTIVE;
835
exitCode = enigmailSvc.importKey(window, importFlags, msgText, "",
841
if (msgText.indexOf("\nCharset:") > 0) {
842
// Check if character set needs to be overridden
843
var startOffset = msgText.indexOf("-----BEGIN PGP ");
845
if (startOffset >= 0) {
846
var subText = msgText.substr(startOffset);
848
subText = subText.replace(/\r\n/g, "\n");
849
subText = subText.replace(/\r/g, "\n");
851
var endOffset = subText.search(/\n\n/);
853
subText = subText.substr(0,endOffset) + "\n";
855
var matches = subText.match(/\nCharset: *(.*) *\n/i);
856
if (matches && (matches.length > 1)) {
857
// Override character set
858
charset = matches[1];
859
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: messageParseCallback: OVERRIDING charset="+charset+"\n");
865
var exitCodeObj = new Object();
866
var statusFlagsObj = new Object();
867
var userIdObj = new Object();
868
var sigDetailsObj = new Object();
870
var signatureObj = new Object();
871
signatureObj.value = signature;
873
var uiFlags = interactive ? (nsIEnigmail.UI_INTERACTIVE |
874
nsIEnigmail.UI_ALLOW_KEY_IMPORT |
875
nsIEnigmail.UI_UNVERIFIED_ENC_OK) : 0;
878
plainText = enigmailSvc.decryptMessage(window, uiFlags, msgText,
879
signatureObj, exitCodeObj, statusFlagsObj,
880
keyIdObj, userIdObj, sigDetailsObj, errorMsgObj, blockSeparationObj);
882
//EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: messageParseCallback: plainText='"+plainText+"'\n");
884
exitCode = exitCodeObj.value;
885
newSignature = signatureObj.value;
887
if (plainText == "" && exitCode == 0) {
891
statusFlags = statusFlagsObj.value;
893
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: messageParseCallback: newSignature='"+newSignature+"'\n");
896
var errorMsg = errorMsgObj.value;
899
if (interactive && errorMsg)
900
EnigmailCommon.longAlert(window, errorMsg);
904
var displayedUriSpec = Enigmail.msg.getCurrentMsgUriSpec();
905
if (!msgUriSpec || (displayedUriSpec == msgUriSpec)) {
906
Enigmail.hdrView.updateHdrIcons(exitCode, statusFlags, keyIdObj.value, userIdObj.value, sigDetailsObj.value, errorMsg, null);
909
var noSecondTry = nsIEnigmail.GOOD_SIGNATURE |
910
nsIEnigmail.EXPIRED_SIGNATURE |
911
nsIEnigmail.EXPIRED_KEY_SIGNATURE |
912
nsIEnigmail.EXPIRED_KEY |
913
nsIEnigmail.REVOKED_KEY |
914
nsIEnigmail.NO_PUBKEY |
915
nsIEnigmail.NO_SECKEY |
916
nsIEnigmail.IMPORTED_KEY |
917
nsIEnigmail.MISSING_PASSPHRASE |
918
nsIEnigmail.BAD_PASSPHRASE |
919
nsIEnigmail.UNKNOWN_ALGO |
920
nsIEnigmail.DECRYPTION_OKAY |
921
nsIEnigmail.OVERFLOWED;
923
if ((exitCode !=0) && (! (statusFlags & noSecondTry))) {
924
// Bad signature/armor
926
msgText = EnigmailCommon.convertFromUnicode(msgText, "UTF-8");
927
Enigmail.msg.messageParseCallback(msgText, contentEncoding, charset,
928
interactive, importOnly, messageUrl,
929
signature, retry + 1,
930
head, tail, msgUriSpec);
933
else if (retry == 2) {
934
// Try to verify signature by accessing raw message text directly
935
// (avoid recursion by setting retry parameter to false on callback)
937
Enigmail.msg.msgDirectDecrypt(interactive, importOnly, contentEncoding, charset,
938
newSignature, 0, head, tail, msgUriSpec,
939
Enigmail.msg.messageParseCallback);
942
else if (retry == 3) {
943
msgText = EnigmailCommon.convertToUnicode(msgText, "UTF-8");
944
Enigmail.msg.messageParseCallback(msgText, contentEncoding, charset, interactive,
945
importOnly, messageUrl, null, retry + 1,
946
head, tail, msgUriSpec);
952
if (interactive && Enigmail.msg.securityInfo && Enigmail.msg.securityInfo.statusInfo)
953
EnigmailCommon.longAlert(window, Enigmail.msg.securityInfo.statusInfo);
958
plainText = EnigmailCommon.convertFromUnicode(EnigmailCommon.convertToUnicode(plainText, "UTF-8"), charset);
961
if (blockSeparationObj.value.indexOf(" ")>=0) {
962
var blocks = blockSeparationObj.value.split(/ /);
963
var blockInfo = blocks[0].split(/:/);
964
plainText = EnigmailCommon.convertFromUnicode(EnigmailCommon.getString("notePartEncrypted"), charset)
965
+ "\n\n" + plainText.substr(0, blockInfo[1]) + "\n\n" + EnigmailCommon.getString("noteCutMessage");
968
// Save decrypted message status, headers, and content
969
var headerList = {"subject":"", "from":"", "date":"", "to":"", "cc":""};
971
var index, headerName;
973
if (!gViewAllHeaders) {
974
for (index = 0; index < headerList.length; index++) {
975
headerList[index] = "";
979
for (index = 0; index < gExpandedHeaderList.length; index++) {
980
headerList[gExpandedHeaderList[index].name] = "";
983
for (headerName in currentHeaderData) {
984
headerList[headerName] = "";
988
for (headerName in headerList) {
989
if (currentHeaderData[headerName])
990
headerList[headerName] = currentHeaderData[headerName].headerValue;
994
if (headerList["cc"] == headerList["to"])
995
headerList["cc"] = "";
997
var hasAttachments = currentAttachments && currentAttachments.length;
998
var attachmentsEncrypted=true;
1000
for (index in currentAttachments) {
1001
if (! Enigmail.msg.checkEncryptedAttach(currentAttachments[index])) {
1002
if (!Enigmail.msg.checkSignedAttachment(currentAttachments, index)) attachmentsEncrypted=false;
1006
var msgRfc822Text = "";
1009
// print a warning if the signed or encrypted part doesn't start
1010
// quite early in the message
1011
matches=head.match(/(\n)/g);
1012
if (matches && matches.length >10) {
1013
msgRfc822Text=EnigmailCommon.convertFromUnicode(EnigmailCommon.getString("notePartEncrypted"), charset)+"\n\n";
1015
msgRfc822Text+=head+"\n\n";
1017
msgRfc822Text += EnigmailCommon.convertFromUnicode(EnigmailCommon.getString("beginPgpPart"), charset)+"\n\n";
1019
msgRfc822Text+=plainText;
1021
msgRfc822Text+="\n\n"+ EnigmailCommon.convertFromUnicode(EnigmailCommon.getString("endPgpPart"), charset)+"\n\n"+tail;
1024
Enigmail.msg.decryptedMessage = {url:messageUrl,
1026
headerList:headerList,
1027
hasAttachments:hasAttachments,
1028
attachmentsEncrypted:attachmentsEncrypted,
1030
plainText:msgRfc822Text};
1032
var msgFrame = EnigmailCommon.getFrame(window, "messagepane");
1033
var bodyElement = msgFrame.document.getElementsByTagName("body")[0];
1035
// don't display decrypted message if message selection has changed
1036
displayedUriSpec = Enigmail.msg.getCurrentMsgUriSpec();
1037
if (msgUriSpec && displayedUriSpec && (displayedUriSpec != msgUriSpec)) return;
1040
// Create and load one-time message URI
1041
var messageContent = Enigmail.msg.getDecryptedMessage("message/rfc822", false);
1043
Enigmail.msg.noShowReload = true;
1045
bodyElement = msgFrame.document.getElementsByTagName("body")[0];
1046
if (bodyElement.firstChild) {
1047
var node = bodyElement.firstChild;
1048
var foundIndex = -1;
1049
var findStr = "-----BEGIN PGP";
1052
if (node.nodeName == "DIV") {
1053
foundIndex = node.textContent.indexOf(findStr);
1055
if (foundIndex >= 0) {
1056
if (node.textContent.indexOf(findStr+" LICENSE AUTHORIZATION") == foundIndex)
1059
if (foundIndex >= 0) {
1060
node.innerHTML = EnigmailFuncs.formatPlaintextMsg(EnigmailCommon.convertToUnicode(messageContent, charset));
1064
node = node.nextSibling;
1067
// if no <DIV> node is found, try with <PRE> (bug 24762)
1068
node = bodyElement.firstChild;
1071
if (node.nodeName == "PRE") {
1072
foundIndex = node.textContent.indexOf(findStr);
1074
if (foundIndex >= 0) {
1075
if (node.textContent.indexOf(findStr+" LICENSE AUTHORIZATION") == foundIndex)
1078
if (foundIndex >= 0) {
1079
node.innerHTML = EnigmailFuncs.formatPlaintextMsg(EnigmailCommon.convertToUnicode(messageContent, charset));
1083
node = node.nextSibling;
1088
EnigmailCommon.ERROR_LOG("enigmailMessengerOverlay.js: no node found to replace message display\n");
1094
// check if an attachment could be signed
1095
checkSignedAttachment: function (attachmentObj, index)
1098
if (index != null) {
1099
attachmentList = attachmentObj;
1102
attachmentList=currentAttachments;
1103
for (var i=0; i < attachmentList.length; i++) {
1104
if (attachmentList[i].url == attachmentObj.url) {
1109
if (index == null) return false;
1115
var attName = this.getAttachmentName(attachmentList[index]).toLowerCase().replace(/\+/g, "\\+");
1117
// check if filename is a signature
1118
if ((this.getAttachmentName(attachmentList[index]).search(/\.(sig|asc)$/i) > 0) ||
1119
(attachmentList[index].contentType.match(/^application\/pgp\-signature/i))) {
1120
findFile = new RegExp(attName.replace(/\.(sig|asc)$/, ""));
1123
findFile = new RegExp(attName+".(sig|asc)$");
1126
for (i in attachmentList) {
1128
(this.getAttachmentName(attachmentList[i]).toLowerCase().search(findFile) == 0))
1135
// check if the attachment could be encrypted
1136
checkEncryptedAttach: function (attachment)
1138
return (this.getAttachmentName(attachment).match(/\.(gpg|pgp|asc)$/i) ||
1139
(attachment.contentType.match(/^application\/pgp(\-.*)?$/i)) &&
1140
(attachment.contentType.search(/^application\/pgp\-signature/i) < 0));
1143
getAttachmentName: function (attachment) {
1144
if (typeof(attachment.displayName) == "undefined") {
1146
return attachment.name;
1150
return attachment.displayName;
1153
escapeTextForHTML: function (text, hyperlink)
1155
// Escape special characters
1156
if (text.indexOf("&") > -1)
1157
text = text.replace(/&/g, "&");
1159
if (text.indexOf("<") > -1)
1160
text = text.replace(/</g, "<");
1162
if (text.indexOf(">") > -1)
1163
text = text.replace(/>/g, ">");
1165
if (text.indexOf("\"") > -1)
1166
text = text.replace(/"/g, """);
1171
// Hyperlink email addresses
1172
var addrs = text.match(/\b[A-Za-z0-9_+\-\.]+@[A-Za-z0-9\-\.]+\b/g);
1174
var newText, offset, loc;
1175
if (addrs && addrs.length) {
1179
for (var j=0; j < addrs.length; j++) {
1180
var addr = addrs[j];
1182
loc = text.indexOf(addr, offset);
1187
newText += text.substr(offset, loc-offset);
1189
// Strip any period off the end of address
1190
addr = addr.replace(/[\.]$/, "");
1195
newText += "<a href=\"mailto:"+addr+"\">" + addr + "</a>";
1197
offset = loc + addr.length;
1200
newText += text.substr(offset, text.length-offset);
1206
var urls = text.match(/\b(http|https|ftp):\S+\s/g);
1208
if (urls && urls.length) {
1212
for (var k=0; k < urls.length; k++) {
1215
loc = text.indexOf(url, offset);
1220
newText += text.substr(offset, loc-offset);
1222
// Strip delimiters off the end of URL
1223
url = url.replace(/\s$/, "");
1224
url = url.replace(/([\),\.']|>|")$/, "");
1229
newText += "<a href=\""+url+"\">" + url + "</a>";
1231
offset = loc + url.length;
1234
newText += text.substr(offset, text.length-offset);
1242
getDecryptedMessage: function (contentType, includeHeaders)
1244
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: getDecryptedMessage: "+contentType+", "+includeHeaders+"\n");
1246
if (!Enigmail.msg.decryptedMessage)
1247
return "No decrypted message found!\n";
1249
var enigmailSvc = Enigmail.getEnigmailSvc();
1253
var headerList = Enigmail.msg.decryptedMessage.headerList;
1255
var statusLine = Enigmail.msg.securityInfo ? Enigmail.msg.securityInfo.statusLine : "";
1257
var contentData = "";
1261
if (contentType == "message/rfc822") {
1264
if (includeHeaders) {
1267
var msg = gFolderDisplay.selectedMessage;
1269
msgHdr = { "From": msg.author,
1270
"Subject": msg.subject,
1271
"To": msg.recipients,
1273
"Date": EnigmailCommon.getDateTime(msg.dateInSeconds, true, true) };
1276
if(gFolderDisplay.selectedMessageIsNews) {
1277
if (typeof (currentHeaderData.newsgroups)) {
1278
msgHdr.Newsgroups = currentHeaderData.newsgroups.headerValue;
1282
for (headerName in msgHdr) {
1283
if (msgHdr[headerName] && msgHdr[headerName].length>0)
1284
contentData += headerName + ": " + msgHdr[headerName] + "\r\n";
1289
// the above seems to fail every now and then
1290
// so, here is the fallback
1291
for (headerName in headerList) {
1292
headerValue = headerList[headerName];
1293
contentData += headerName + ": " + headerValue + "\r\n";
1297
contentData += "Content-Type: text/plain";
1299
if (Enigmail.msg.decryptedMessage.charset) {
1300
contentData += "; charset="+Enigmail.msg.decryptedMessage.charset;
1303
contentData += "\r\n";
1306
contentData += "\r\n";
1308
if (Enigmail.msg.decryptedMessage.hasAttachments && (! Enigmail.msg.decryptedMessage.attachmentsEncrypted)) {
1309
contentData += EnigmailCommon.convertFromUnicode(EnigmailCommon.getString("enigContentNote"), Enigmail.msg.decryptedMessage.charset);
1312
contentData += Enigmail.msg.decryptedMessage.plainText;
1315
// text/html or text/plain
1317
if (contentType == "text/html") {
1318
contentData += "<meta http-equiv=\"Content-Type\" content=\"text/html; charset="+Enigmail.msg.decryptedMessage.charset+"\">\r\n";
1320
contentData += "<html><head></head><body>\r\n";
1324
if (contentType == "text/html") {
1325
contentData += "<b>"+EnigmailCommon.getString("enigHeader")+"</b> " +
1326
this.escapeTextForHTML(statusLine, false) + "<br>\r\n<hr>\r\n";
1328
contentData += EnigmailCommon.getString("enigHeader")+" " + statusLine + "\r\n\r\n";
1332
if (includeHeaders) {
1333
for (headerName in headerList) {
1334
headerValue = headerList[headerName];
1337
if (contentType == "text/html") {
1338
contentData += "<b>"+this.escapeTextForHTML(headerName, false)+":</b> "+
1339
this.escapeTextForHTML(headerValue, false)+"<br>\r\n";
1341
contentData += headerName + ": " + headerValue + "\r\n";
1347
if (contentType == "text/html") {
1348
contentData += "<pre>"+this.escapeTextForHTML(Enigmail.msg.decryptedMessage.plainText, false)+"</pre>\r\n";
1350
contentData += "</body></html>\r\n";
1354
contentData += "\r\n"+Enigmail.msg.decryptedMessage.plainText;
1357
if (!(EnigmailCommon.isDosLike())) {
1358
contentData = contentData.replace(/\r\n/g, "\n");
1366
msgDefaultPrint: function (elementId)
1368
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: this.msgDefaultPrint: "+elementId+"\n");
1370
goDoCommand(elementId.indexOf("printpreview")>=0 ? "cmd_printpreview" : "cmd_print");
1373
msgPrint: function (elementId)
1375
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: msgPrint: "+elementId+"\n");
1377
var contextMenu = (elementId.search("Context") > -1);
1379
if (!Enigmail.msg.decryptedMessage || typeof(Enigmail.msg.decryptedMessage) == "undefined") {
1380
this.msgDefaultPrint(elementId);
1384
var mailNewsUrl = this.getCurrentMsgUrl();
1387
this.msgDefaultPrint(elementId);
1391
if (Enigmail.msg.decryptedMessage.url != mailNewsUrl.spec) {
1392
Enigmail.msg.decryptedMessage = null;
1393
this.msgDefaultPrint(elementId);
1397
var enigmailSvc = Enigmail.getEnigmailSvc();
1399
this.msgDefaultPrint(elementId);
1403
// Note: Trying to print text/html content does not seem to work with
1405
var msgContent = this.getDecryptedMessage("message/rfc822", true);
1407
var uri = enigmailSvc.createMessageURI(Enigmail.msg.decryptedMessage.url,
1413
Enigmail.msg.createdURIs.push(uri);
1415
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: msgPrint: uri="+uri+"\n");
1417
var messageList = [uri];
1419
var printPreview = (elementId.indexOf("printpreview")>=0);
1421
window.openDialog("chrome://messenger/content/msgPrintEngine.xul",
1423
"chrome,dialog=no,all,centerscreen",
1424
1, messageList, statusFeedback,
1425
printPreview, Components.interfaces.nsIMsgPrintEngine.MNAB_PRINTPREVIEW_MSG,
1431
messageSave: function ()
1433
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: messageSave: \n");
1435
if (!Enigmail.msg.decryptedMessage) {
1436
EnigmailCommon.alert(window, EnigmailCommon.getString("noDecrypted"));
1440
var mailNewsUrl = this.getCurrentMsgUrl();
1443
EnigmailCommon.alert(window, EnigmailCommon.getString("noMessage"));
1447
if (Enigmail.msg.decryptedMessage.url != mailNewsUrl.spec) {
1448
Enigmail.msg.decryptedMessage = null;
1449
EnigmailCommon.alert(window, EnigmailCommon.getString("useButton"));
1453
var saveFile = EnigmailCommon.filePicker(window, EnigmailCommon.getString("saveHeader"),
1454
Enigmail.msg.lastSaveDir, true, "txt",
1455
null, ["Text files", "*.txt"]);
1456
if (!saveFile) return;
1458
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: messageSave: path="+saveFile.path+"\n");
1460
if (saveFile.parent)
1461
Enigmail.msg.lastSaveDir = EnigmailCommon.getFilePath(saveFile.parent);
1463
var textContent = this.getDecryptedMessage("text/plain", true);
1465
if (!Enigmail.msg.writeFileContents(saveFile.path, textContent, null)) {
1466
EnigmailCommon.alert(window, "Error in saving to file "+saveFile.path);
1473
msgDirectDecrypt: function (interactive, importOnly, contentEncoding, charset, signature,
1474
bufferSize, head, tail, msgUriSpec, callbackFunction)
1476
EnigmailCommon.WRITE_LOG("enigmailMessengerOverlay.js: msgDirectDecrypt: contentEncoding="+contentEncoding+", signature="+signature+"\n");
1477
var mailNewsUrl = this.getCurrentMsgUrl();
1481
var callbackArg = { interactive:interactive,
1482
importOnly:importOnly,
1483
contentEncoding:contentEncoding,
1485
messageUrl:mailNewsUrl.spec,
1486
msgUriSpec:msgUriSpec,
1487
signature:signature,
1491
callbackFunction: callbackFunction };
1493
var msgSvc = messenger.messageServiceFromURI(msgUriSpec);
1496
QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsIStreamListener]),
1497
onStartRequest: function() {
1499
this.inStream = Components.classes["@mozilla.org/scriptableinputstream;1"].
1500
createInstance(Components.interfaces.nsIScriptableInputStream);
1503
onDataAvailable: function(req, sup, stream, offset, count) {
1504
this.inStream.init(stream);
1505
this.data += this.inStream.read(count);
1507
onStopRequest: function() {
1508
var start = this.data.indexOf("-----BEGIN PGP");
1509
var end = this.data.indexOf("-----END PGP");
1511
if (start >= 0 && end > start) {
1512
var tStr = this.data.substr(end);
1513
var n = tStr.indexOf("\n");
1514
var r = tStr.indexOf("\r");
1516
if (n >= 0 && r >= 0) {
1517
lEnd = Math.min(r, n);
1529
callbackArg.data = this.data.substring(start, end+1);
1530
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: data: >"+callbackArg.data+"<\n");
1531
Enigmail.msg.msgDirectCallback(callbackArg);
1536
msgSvc.streamMessage(msgUriSpec,
1547
msgDirectCallback: function (callbackArg)
1549
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: msgDirectCallback: \n");
1551
var mailNewsUrl = Enigmail.msg.getCurrentMsgUrl();
1552
var urlSpec = mailNewsUrl ? mailNewsUrl.spec : "";
1553
var newBufferSize = 0;
1555
var l = urlSpec.length;
1557
if (urlSpec.substr(0, l) != callbackArg.messageUrl.substr(0, l)) {
1558
EnigmailCommon.ERROR_LOG("enigmailMessengerOverlay.js: msgDirectCallback: Message URL mismatch "+mailNewsUrl.spec+" vs. "+callbackArg.messageUrl+"\n");
1562
var msgText = callbackArg.data;
1563
msgText = EnigmailCommon.convertFromUnicode(msgText, "UTF-8");
1565
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: msgDirectCallback: msgText='"+msgText+"'\n");
1567
var f = function (argList) {
1568
var msgText = argList[0];
1569
var cb = argList[1];
1570
cb.callbackFunction(msgText, cb.contentEncoding,
1582
EnigmailCommon.dispatchEvent(f, 0, [msgText, callbackArg ]);
1586
verifyEmbeddedMsg: function (window, msgUrl, msgWindow, msgUriSpec, contentEncoding, event)
1588
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: verifyEmbeddedMsg: msgUrl"+msgUrl+"\n");
1590
var callbackArg = { data: "",
1593
msgWindow: msgWindow,
1594
msgUriSpec: msgUriSpec,
1595
contentEncoding: contentEncoding,
1598
var requestCallback = function _cb (data) {
1599
callbackArg.data = data;
1600
Enigmail.msg.verifyEmbeddedCallback(callbackArg);
1603
var bufferListener = EnigmailCommon.newStringStreamListener(requestCallback);
1605
var ioServ = Components.classes[EnigmailCommon.IOSERVICE_CONTRACTID].getService(Components.interfaces.nsIIOService);
1607
var channel = ioServ.newChannelFromURI(msgUrl);
1609
channel.asyncOpen(bufferListener, msgUrl);
1612
verifyEmbeddedCallback: function (callbackArg)
1614
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: verifyEmbeddedCallback: \n");
1616
if (callbackArg.data.length > 0) {
1617
let msigned=callbackArg.data.search(/content\-type:[ \t]*multipart\/signed/i);
1620
// Real multipart/signed message; let's try to verify it
1621
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: verifyEmbeddedCallback: detected multipart/signed. msigned: "+msigned+"\n");
1623
let enableSubpartTreatment=(msigned > 0);
1625
var verifier = EnigmailVerify.newVerfier(enableSubpartTreatment, callbackArg.mailNewsUrl);
1626
verifier.verifyData(callbackArg.window, callbackArg.msgWindow, callbackArg.msgUriSpec, callbackArg.data);
1633
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: verifyEmbeddedCallback: try inline PGP\n");
1635
Enigmail.msg.messageParse(!callbackArg.event, false, callbackArg.contentEncoding, callbackArg.msgUriSpec);
1639
revealAttachments: function (index)
1641
if (!index) index = 0;
1643
if (index < currentAttachments.length) {
1644
this.handleAttachment("revealName/"+index.toString(), currentAttachments[index]);
1649
// handle a selected attachment (decrypt & open or save)
1650
handleAttachmentSel: function (actionType)
1652
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: handleAttachmentSel: actionType="+actionType+"\n");
1655
var contextMenu = document.getElementById('attachmentItemContext');
1656
var selectedAttachments = contextMenu.attachments;
1658
if (! contextMenu) {
1660
contextMenu = document.getElementById('attachmentListContext');
1661
selectedAttachments = attachmentList.selectedItems;
1663
var anAttachment = selectedAttachments[0];
1665
switch (actionType) {
1666
case "saveAttachment":
1667
case "openAttachment":
1670
this.handleAttachment(actionType, anAttachment);
1673
this.verifyDetachedSignature(anAttachment);
1679
* save the original file plus the signature file to disk and then verify the signature
1681
verifyDetachedSignature: function (anAttachment)
1683
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: verifyDetachedSignature: url="+anAttachment.url+"\n");
1685
var enigmailSvc = Enigmail.getEnigmailSvc();
1686
if (! enigmailSvc) return;
1688
var origAtt, signatureAtt;
1690
if ((this.getAttachmentName(anAttachment).search(/\.sig$/i) > 0) ||
1691
(anAttachment.contentType.search(/^application\/pgp\-signature/i) == 0)) {
1692
// we have the .sig file; need to know the original file;
1694
signatureAtt = anAttachment;
1695
var origName = this.getAttachmentName(anAttachment).replace(/\.sig$/i, "");
1697
for (let i=0; i < currentAttachments.length; i++) {
1698
if (origName == this.getAttachmentName(currentAttachments[i])) {
1699
origAtt = currentAttachments[i];
1705
// we have a supposedly original file; need to know the .sig file;
1707
origAtt = anAttachment;
1708
var sigName = this.getAttachmentName(anAttachment)+".sig";
1710
for (let i=0; i < currentAttachments.length; i++) {
1711
if (sigName == this.getAttachmentName(currentAttachments[i])) {
1712
signatureAtt = currentAttachments[i];
1718
if (! signatureAtt) {
1719
EnigmailCommon.alert(window, EnigmailCommon.getString("attachment.noMatchToSignature", [ this.getAttachmentName(origAtt) ]));
1723
EnigmailCommon.alert(window, EnigmailCommon.getString("attachment.noMatchFromSignature", [ this.getAttachmentName(signatureAtt) ]));
1728
var tmpDir = EnigmailCommon.getTempDir();
1729
var outFile1, outFile2;
1730
outFile1 = Components.classes[EnigmailCommon.LOCAL_FILE_CONTRACTID].
1731
createInstance(EnigmailCommon.getLocalFileApi());
1732
outFile1.initWithPath(tmpDir);
1733
if (!(outFile1.isDirectory() && outFile1.isWritable())) {
1734
EnigmailCommon.alert(window, EnigmailCommon.getString("noTempDir"));
1737
outFile1.append(this.getAttachmentName(origAtt));
1738
outFile1.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0600);
1739
this.writeUrlToFile(origAtt.url, outFile1);
1741
outFile2 = Components.classes[EnigmailCommon.LOCAL_FILE_CONTRACTID].
1742
createInstance(EnigmailCommon.getLocalFileApi());
1743
outFile2.initWithPath(tmpDir);
1744
outFile2.append(this.getAttachmentName(signatureAtt));
1745
outFile2.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0600);
1746
this.writeUrlToFile(signatureAtt.url, outFile2);
1748
var statusFlagsObj = {};
1749
var errorMsgObj = {};
1750
var r = enigmailSvc.verifyAttachment(window, outFile1, outFile2, statusFlagsObj, errorMsgObj);
1753
EnigmailCommon.alert(window, EnigmailCommon.getString("signature.verifiedOK", [ this.getAttachmentName(origAtt) ]) +"\n\n"+ errorMsgObj.value);
1755
EnigmailCommon.alert(window, EnigmailCommon.getString("signature.verifyFailed", [ this.getAttachmentName(origAtt) ])+"\n\n"+
1758
outFile1.remove(false);
1759
outFile2.remove(false);
1762
writeUrlToFile: function(srcUrl, outFile) {
1763
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: writeUrlToFile: outFile="+outFile.path+"\n");
1764
var ioServ = Components.classes[EnigmailCommon.IOSERVICE_CONTRACTID].
1765
getService(Components.interfaces.nsIIOService);
1766
var msgUri = ioServ.newURI(srcUrl, null, null);
1767
var channel = ioServ.newChannelFromURI(msgUri);
1768
var istream = channel.open();
1770
var fstream = Components.classes["@mozilla.org/network/safe-file-output-stream;1"]
1771
.createInstance(Components.interfaces.nsIFileOutputStream);
1772
var buffer = Components.classes["@mozilla.org/network/buffered-output-stream;1"]
1773
.createInstance(Components.interfaces.nsIBufferedOutputStream);
1774
fstream.init(outFile, 0x04 | 0x08 | 0x20, 0600, 0); // write, create, truncate
1775
buffer.init(fstream, 8192);
1777
buffer.writeFrom(istream, istream.available());
1779
// Close the output streams
1780
if (buffer instanceof Components.interfaces.nsISafeOutputStream)
1785
if (fstream instanceof Components.interfaces.nsISafeOutputStream)
1790
// Close the input stream
1794
handleAttachment: function (actionType, anAttachment)
1796
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: handleAttachment: actionType="+actionType+", anAttachment(url)="+anAttachment.url+"\n");
1798
var argumentsObj = { actionType: actionType,
1799
attachment: anAttachment,
1800
forceBrowser: false,
1804
var f = function _cb(data) {
1805
argumentsObj.data = data;
1806
Enigmail.msg.decryptAttachmentCallback([argumentsObj]);
1809
var bufferListener = EnigmailCommon.newStringStreamListener(f);
1810
var ioServ = Components.classes[EnigmailCommon.IOSERVICE_CONTRACTID].getService(Components.interfaces.nsIIOService);
1811
var msgUri = ioServ.newURI(argumentsObj.attachment.url, null, null);
1813
var channel = ioServ.newChannelFromURI(msgUri);
1814
channel.asyncOpen(bufferListener, msgUri);
1817
setAttachmentName: function (attachment, newLabel, index)
1819
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: setAttachmentName ("+newLabel+"):\n");
1821
var attList=document.getElementById("attachmentList");
1823
var attNode = attList.firstChild;
1826
if (attNode.getAttribute("attachmentUrl") == attachment.url)
1827
attNode.setAttribute("label", newLabel);
1829
if (attNode.getAttribute("name") == attachment.name)
1830
attNode.setAttribute("name", newLabel);
1831
attNode=attNode.nextSibling;
1835
if (typeof(attachment.displayName) == "undefined") {
1836
attachment.name = newLabel;
1839
attachment.displayName = newLabel;
1841
if (index && index.length > 0) {
1842
this.revealAttachments(parseInt(index)+1);
1846
decryptAttachmentCallback: function (cbArray)
1848
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: decryptAttachmentCallback:\n");
1850
var callbackArg = cbArray[0];
1851
const nsIEnigmail = Components.interfaces.nsIEnigmail;
1853
var exitCodeObj = new Object();
1854
var statusFlagsObj = new Object();
1855
var errorMsgObj= new Object();
1856
var exitStatus = -1;
1858
var enigmailSvc = Enigmail.getEnigmailSvc();
1861
var rawFileName=Enigmail.msg.getAttachmentName(callbackArg.attachment).replace(/\.(asc|pgp|gpg)$/i,"");
1863
if (callbackArg.actionType != "importKey") {
1864
origFilename = EnigmailCommon.getAttachmentFileName(window, callbackArg.data);
1865
if (origFilename && origFilename.length > rawFileName.length) rawFileName = origFilename;
1868
if (callbackArg.actionType == "saveAttachment") {
1869
outFile = EnigmailCommon.filePicker(window, EnigmailCommon.getString("saveAttachmentHeader"),
1870
Enigmail.msg.lastSaveDir, true, "",
1872
if (! outFile) return;
1874
else if (callbackArg.actionType.substr(0,10) == "revealName") {
1875
if (origFilename && origFilename.length > 0) {
1876
Enigmail.msg.setAttachmentName(callbackArg.attachment, origFilename+".pgp", callbackArg.actionType.substr(11,10));
1878
Enigmail.msg.setAttachmentReveal(null);
1883
var tmpDir = EnigmailCommon.getTempDir();
1885
outFile = Components.classes[EnigmailCommon.LOCAL_FILE_CONTRACTID].createInstance(EnigmailCommon.getLocalFileApi());
1886
outFile.initWithPath(tmpDir);
1887
if (!(outFile.isDirectory() && outFile.isWritable())) {
1888
errorMsgObj.value=EnigmailCommon.getString("noTempDir");
1891
outFile.append(rawFileName);
1892
outFile.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0600);
1895
errorMsgObj.value=EnigmailCommon.getString("noTempDir");
1900
if (callbackArg.actionType == "importKey") {
1902
exitStatus = enigmailSvc.importKey(parent, 0, callbackArg.data, "", errorMsgObj);
1905
if (exitStatus == 0) {
1906
EnigmailCommon.longAlert(window, EnigmailCommon.getString("successKeyImport")+"\n\n"+errorMsgObj.value);
1909
EnigmailCommon.alert(window, EnigmailCommon.getString("failKeyImport")+"\n"+errorMsgObj.value);
1915
exitStatus=enigmailSvc.decryptAttachment(window, outFile,
1916
Enigmail.msg.getAttachmentName(callbackArg.attachment),
1918
exitCodeObj, statusFlagsObj,
1921
if ((! exitStatus) || exitCodeObj.value != 0) {
1923
if ((statusFlagsObj.value & nsIEnigmail.DECRYPTION_OKAY) &&
1924
(statusFlagsObj.value & nsIEnigmail.UNVERIFIED_SIGNATURE)) {
1926
if (callbackArg.actionType == "openAttachment") {
1927
exitStatus = EnigmailCommon.confirmDlg(window, EnigmailCommon.getString("decryptOkNoSig"), EnigmailCommon.getString("msgOvl.button.contAnyway"));
1930
EnigmailCommon.alert(window, EnigmailCommon.getString("decryptOkNoSig"));
1934
EnigmailCommon.alert(window, EnigmailCommon.getString("failedDecrypt")+"\n\n"+errorMsgObj.value);
1939
if (statusFlagsObj.value & nsIEnigmail.IMPORTED_KEY) {
1940
EnigmailCommon.longAlert(window, EnigmailCommon.getString("successKeyImport")+"\n\n"+errorMsgObj.value);
1942
else if (statusFlagsObj.value & nsIEnigmail.DISPLAY_MESSAGE) {
1943
HandleSelectedAttachments('open');
1945
else if ((statusFlagsObj.value & nsIEnigmail.DISPLAY_MESSAGE) ||
1946
(callbackArg.actionType == "openAttachment")) {
1947
var ioServ = Components.classes[EnigmailCommon.IOSERVICE_CONTRACTID].getService(Components.interfaces.nsIIOService);
1948
var outFileUri = ioServ.newFileURI(outFile);
1949
var fileExt = outFile.leafName.replace(/(.*\.)(\w+)$/, "$2");
1950
if (fileExt && ! callbackArg.forceBrowser) {
1951
var extAppLauncher = Components.classes[EnigmailCommon.MIME_CONTRACTID].getService(Components.interfaces.nsPIExternalAppLauncher);
1952
extAppLauncher.deleteTemporaryFileOnExit(outFile);
1955
var mimeService = Components.classes[EnigmailCommon.MIME_CONTRACTID].getService(Components.interfaces.nsIMIMEService);
1956
var fileMimeType = mimeService.getTypeFromFile(outFile);
1957
var fileMimeInfo = mimeService.getFromTypeAndExtension(fileMimeType, fileExt);
1959
fileMimeInfo.launchWithFile(outFile);
1962
// if the attachment file type is unknown, an exception is thrown,
1963
// so let it be handled by a browser window
1964
Enigmail.msg.loadExternalURL(outFileUri.asciiSpec);
1968
// open the attachment using an external application
1969
Enigmail.msg.loadExternalURL(outFileUri.asciiSpec);
1974
loadExternalURL: function (url) {
1975
if (EnigmailCommon.isSuite()) {
1976
Enigmail.msg.loadURLInNavigatorWindow(url, true);
1979
messenger.launchExternalURL(url);
1983
// retrieves the most recent navigator window (opens one if need be)
1984
loadURLInNavigatorWindow: function (url, aOpenFlag)
1986
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: loadURLInNavigatorWindow: "+url+", "+aOpenFlag+"\n");
1990
// if this is a browser window, just use it
1991
if ("document" in top) {
1992
var possibleNavigator = top.document.getElementById("main-window");
1993
if (possibleNavigator &&
1994
possibleNavigator.getAttribute("windowtype") == "navigator:browser")
1998
// if not, get the most recently used browser window
2001
wm = Components.classes["@mozilla.org/appshell/window-mediator;1"].getService(
2002
Components.interfaces.nsIWindowMediator);
2003
navWindow = wm.getMostRecentWindow("navigator:browser");
2008
if ("loadURI" in navWindow)
2009
navWindow.loadURI(url);
2011
navWindow._content.location.href = url;
2013
} else if (aOpenFlag) {
2014
// if no browser window available and it's ok to open a new one, do so
2015
navWindow = window.open(url, "Enigmail");
2018
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: loadURLInNavigatorWindow: navWindow="+navWindow+"\n");
2023
// handle double click events on Attachments
2024
enigAttachmentListClick: function (elementId, event)
2026
EnigmailCommon.DEBUG_LOG("enigmailMessengerOverlay.js: enigAttachmentListClick: event="+event+"\n");
2028
var attachment=event.target.attachment;
2029
if (this.checkEncryptedAttach(attachment)) {
2030
if (event.button == 0 && event.detail == 2) { // double click
2031
this.handleAttachment("openAttachment", attachment);
2032
event.stopPropagation();
2040
handleUnknownKey: function ()
2042
var pubKeyId = "0x" + Enigmail.msg.securityInfo.keyId.substr(8, 8);
2044
var mesg = EnigmailCommon.getString("pubKeyNeeded") + EnigmailCommon.getString("keyImport", [pubKeyId]);
2046
if (EnigmailCommon.confirmDlg(window, mesg, EnigmailCommon.getString("keyMan.button.import"))) {
2048
searchList : [ pubKeyId ]
2050
var resultObj = new Object();
2052
EnigmailFuncs.downloadKeys(window, inputObj, resultObj);
2054
if (resultObj.importedKeys > 0) {
2055
this.messageReload(false);
2060
createFileStream: function (filePath, permissions)
2062
const DEFAULT_FILE_PERMS = 0600;
2063
const WRONLY = 0x02;
2064
const CREATE_FILE = 0x08;
2065
const TRUNCATE = 0x20;
2068
var localFile = Components.classes[EnigmailCommon.LOCAL_FILE_CONTRACTID].
2069
createInstance(EnigmailCommon.getLocalFileApi());
2071
localFile.initWithPath(filePath);
2073
if (localFile.exists()) {
2075
if (localFile.isDirectory() || !localFile.isWritable())
2076
throw Components.results.NS_ERROR_FAILURE;
2079
permissions = localFile.permissions;
2083
permissions = DEFAULT_FILE_PERMS;
2085
var flags = WRONLY | CREATE_FILE | TRUNCATE;
2087
var fileStream = Components.classes["@mozilla.org/network/file-output-stream;1"].
2088
createInstance(Components.interfaces.nsIFileOutputStream);
2090
fileStream.init(localFile, flags, permissions, 0);
2095
EnigmailCommon.ERROR_LOG("enigmailMessengerOverlay.js: createFileStream: Failed to create "+filePath+"\n");
2100
writeFileContents: function (filePath, data, permissions)
2104
var fileOutStream = this.createFileStream(filePath, permissions);
2107
if (fileOutStream.write(data, data.length) != data.length)
2108
throw Components.results.NS_ERROR_FAILURE;
2110
fileOutStream.flush();
2112
fileOutStream.close();
2115
EnigmailCommon.ERROR_LOG("enigmailMessengerOverlay.js: writeFileContents: Failed to write to "+filePath+"\n");
2123
window.addEventListener("load", Enigmail.msg.messengerStartup.bind(Enigmail.msg), false);