diff --git a/package/enigmail.js b/package/enigmail.js index 1e0f4706..6dffedc7 100644 --- a/package/enigmail.js +++ b/package/enigmail.js @@ -1,5636 +1,5625 @@ /* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "MPL"); you may not use this file * except in compliance with the MPL. You may obtain a copy of * the MPL at http://www.mozilla.org/MPL/ * * Software distributed under the MPL is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the MPL for the specific language governing * rights and limitations under the MPL. * * The Original Code is Enigmail. * * The Initial Developer of the Original Code is Ramalingam Saravanan. * Portions created by Ramalingam Saravanan are * Copyright (C) 2001 Ramalingam Saravanan. All Rights Reserved. * * Contributor(s): * Patrick Brunschwig * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License (the "GPL"), in which case * the provisions of the GPL are applicable instead of * those above. If you wish to allow use of your version of this * file only under the terms of the GPL and not to allow * others to use your version of this file under the MPL, indicate * your decision by deleting the provisions above and replace them * with the notice and other provisions required by the GPL. * If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. */ // Maximum size of message directly processed by Enigmail const MSG_BUFFER_SIZE = 98304; // 96 kB const MAX_MSG_BUFFER_SIZE = 512000 // slightly less than 512 kB const ERROR_BUFFER_SIZE = 16384; // 16 kB const PGP_BATCH_OPTS = " +batchmode +force"; const GPG_BATCH_OPTS = " --batch --no-tty --status-fd 2"; const gDummyPKCS7 = 'Content-Type: multipart/mixed;\r\n boundary="------------060503030402050102040303\r\n\r\nThis is a multi-part message in MIME format.\r\n--------------060503030402050102040303\r\nContent-Type: application/x-pkcs7-mime\r\nContent-Transfer-Encoding: 8bit\r\n\r\n\r\n--------------060503030402050102040303\r\nContent-Type: application/x-enigmail-dummy\r\nContent-Transfer-Encoding: 8bit\r\n\r\n\r\n--------------060503030402050102040303--\r\n'; /* Implementations supplied by this module */ const NS_ENIGMAIL_CONTRACTID = "@mozdev.org/enigmail/enigmail;1"; const NS_PGP_MODULE_CONTRACTID = "@mozilla.org/mimecth/pgp;1"; const NS_ENIGMAILPROTOCOLHANDLER_CONTRACTID = "@mozilla.org/network/protocol;1?name=enigmail"; const NS_ENIGMAIL_CID = Components.ID("{847b3a01-7ab1-11d4-8f02-006008948af5}"); const NS_ENIGMAILPROTOCOLHANDLER_CID = Components.ID("{847b3a11-7ab1-11d4-8f02-006008948af5}"); const NS_PGP_MODULE_CID = Components.ID("{847b3af1-7ab1-11d4-8f02-006008948af5}"); const NS_ENIGMSGCOMPOSE_CID = Components.ID("{847b3a21-7ab1-11d4-8f02-006008948af5}"); const NS_ENIGMSGCOMPOSEFACTORY_CID = Components.ID("{847b3a22-7ab1-11d4-8f02-006008948af5}"); const NS_ENIGCLINE_SERVICE_CID = Components.ID("{847b3ab1-7ab1-11d4-8f02-006008948af5}"); // Contract IDs and CIDs used by this module const NS_IPCSERVICE_CONTRACTID = "@mozilla.org/process/ipc-service;1"; const NS_IPCBUFFER_CONTRACTID = "@mozilla.org/process/ipc-buffer;1"; const NS_PIPECONSOLE_CONTRACTID = "@mozilla.org/process/pipe-console;1"; const NS_PIPETRANSPORT_CONTRACTID="@mozilla.org/process/pipe-transport;1"; const NS_PROCESSINFO_CONTRACTID = "@mozilla.org/xpcom/process-info;1"; const NS_MSGCOMPOSESECURE_CONTRACTID = "@mozilla.org/messengercompose/composesecure;1"; const NS_ENIGMSGCOMPOSE_CONTRACTID = "@mozilla.org/enigmail/composesecure;1"; const NS_ENIGMSGCOMPOSEFACTORY_CONTRACTID = "@mozilla.org/enigmail/composesecure-factory;1"; const NS_ENIGMIMESERVICE_CONTRACTID = "@mozdev.org/enigmail/enigmimeservice;1"; const NS_SIMPLEURI_CONTRACTID = "@mozilla.org/network/simple-uri;1"; const NS_TIMER_CONTRACTID = "@mozilla.org/timer;1"; const NS_OBSERVERSERVICE_CONTRACTID = "@mozilla.org/observer-service;1"; const NS_PROMPTSERVICE_CONTRACTID = "@mozilla.org/embedcomp/prompt-service;1"; const ASS_CONTRACTID = "@mozilla.org/appshell/appShellService;1"; const WMEDIATOR_CONTRACTID = "@mozilla.org/rdf/datasource;1?name=window-mediator"; const NS_IOSERVICE_CONTRACTID = "@mozilla.org/network/io-service;1"; const NS_ISCRIPTABLEUNICODECONVERTER_CONTRACTID = "@mozilla.org/intl/scriptableunicodeconverter"; const NS_SCRIPTABLEINPUTSTREAM_CONTRACTID = "@mozilla.org/scriptableinputstream;1" const ENIG_STRINGBUNDLE_CONTRACTID = "@mozilla.org/intl/stringbundle;1"; const NS_PREFS_SERVICE_CID = "@mozilla.org/preferences-service;1"; const NS_DOMPARSER_CONTRACTID = "@mozilla.org/xmlextras/domparser;1"; const NS_DOMSERIALIZER_CONTRACTID = "@mozilla.org/xmlextras/xmlserializer;1"; const NS_CATMAN_CONTRACTID = "@mozilla.org/categorymanager;1"; const NS_CLINE_SERVICE_CONTRACTID = "@mozilla.org/commandlinehandler/general-startup;1?type=pgpkeyman"; // Interfaces const nsISupports = Components.interfaces.nsISupports; const nsIObserver = Components.interfaces.nsIObserver; const nsILocalFile = Components.interfaces.nsILocalFile; const nsIProtocolHandler = Components.interfaces.nsIProtocolHandler; const nsIIPCService = Components.interfaces.nsIIPCService; const nsIPipeConsole = Components.interfaces.nsIPipeConsole; const nsIProcessInfo = Components.interfaces.nsIProcessInfo; const nsIEnigmail = Components.interfaces.nsIEnigmail; //const nsIPGPModule = Components.interfaces.nsIPGPModule; //const nsIPGPMsgBody = Components.interfaces.nsIPGPMsgBody; //const nsIPGPMsgHeader = Components.interfaces.nsIPGPMsgHeader; const nsIEnigStrBundle = Components.interfaces.nsIStringBundleService; const nsICmdLineHandler = Components.interfaces.nsICmdLineHandler; const nsICategoryManager = Components.interfaces.nsICategoryManager; const nsIWindowWatcher = Components.interfaces.nsIWindowWatcher; const NS_XPCOM_SHUTDOWN_OBSERVER_ID = "xpcom-shutdown"; /////////////////////////////////////////////////////////////////////////////// // Global variables const GPG_COMMENT_OPT = "Using GnuPG with %s - http://enigmail.mozdev.org"; var gLogLevel = 3; // Output only errors/warnings by default var gEnigmailSvc = null; // Global Enigmail Service var gCachedPassphrase = null; // Cached passphrase var gCacheTimer = null; // Cache timer var gXULOwner = null; // Global XUL owner var gEnvList = []; // Global environment list var gEnigStrBundle; // Global string bundle // GPG status flags mapping (see doc/DETAILS file in the GnuPG distribution) var gStatusFlags = {GOODSIG: nsIEnigmail.GOOD_SIGNATURE, BADSIG: nsIEnigmail.BAD_SIGNATURE, ERRSIG: nsIEnigmail.UNVERIFIED_SIGNATURE, EXPSIG: nsIEnigmail.EXPIRED_SIGNATURE, REVKEYSIG: nsIEnigmail.GOOD_SIGNATURE, EXPKEYSIG: nsIEnigmail.EXPIRED_KEY_SIGNATURE, KEYEXPIRED: nsIEnigmail.EXPIRED_KEY, KEYREVOKED: nsIEnigmail.REVOKED_KEY, NO_PUBKEY: nsIEnigmail.NO_PUBKEY, NO_SECKEY: nsIEnigmail.NO_SECKEY, IMPORTED: nsIEnigmail.IMPORTED_KEY, INV_RECP: nsIEnigmail.INVALID_RECIPIENT, MISSING_PASSPHRASE: nsIEnigmail.MISSING_PASSPHRASE, BAD_PASSPHRASE: nsIEnigmail.BAD_PASSPHRASE, BADARMOR: nsIEnigmail.BAD_ARMOR, NODATA: nsIEnigmail.NODATA, DECRYPTION_FAILED: nsIEnigmail.DECRYPTION_FAILED, DECRYPTION_OKAY: nsIEnigmail.DECRYPTION_OKAY, TRUST_UNDEFINED: nsIEnigmail.UNTRUSTED_IDENTITY, TRUST_NEVER: nsIEnigmail.UNTRUSTED_IDENTITY, TRUST_MARGINAL: nsIEnigmail.UNTRUSTED_IDENTITY, TRUST_FULLY: nsIEnigmail.TRUSTED_IDENTITY, TRUST_ULTIMATE: nsIEnigmail.TRUSTED_IDENTITY, CARDCTRL: nsIEnigmail.NO_SC_AVAILABLE }; /////////////////////////////////////////////////////////////////////////////// // File read/write operations const NS_LOCAL_FILE_CONTRACTID = "@mozilla.org/file/local;1"; const NS_LOCALFILEOUTPUTSTREAM_CONTRACTID = "@mozilla.org/network/file-output-stream;1"; const NS_RDONLY = 0x01; const NS_WRONLY = 0x02; const NS_CREATE_FILE = 0x08; const NS_TRUNCATE = 0x20; const DEFAULT_FILE_PERMS = 0600; const GET_BOOL = "GET_BOOL"; const GET_LINE = "GET_LINE"; const GET_HIDDEN = "GET_HIDDEN"; const BUTTON_POS_0 = 1; const BUTTON_POS_1 = 1 << 8; const BUTTON_POS_2 = 1 << 16; var gMimeHashAlgorithms = ["md5", "sha1", "ripemd160", "sha256", "sha384", "sha512"]; function CreateFileStream(filePath, permissions) { //DEBUG_LOG("enigmail.js: CreateFileStream: file="+filePath+"\n"); try { var localFile = Components.classes[NS_LOCAL_FILE_CONTRACTID].createInstance(Components.interfaces.nsILocalFile); localFile.initWithPath(filePath); if (localFile.exists()) { if (localFile.isDirectory() || !localFile.isWritable()) throw Components.results.NS_ERROR_FAILURE; if (!permissions) permissions = localFile.permissions; } if (!permissions) permissions = DEFAULT_FILE_PERMS; var flags = NS_WRONLY | NS_CREATE_FILE | NS_TRUNCATE; var fileStream = Components.classes[NS_LOCALFILEOUTPUTSTREAM_CONTRACTID].createInstance(Components.interfaces.nsIFileOutputStream); fileStream.init(localFile, flags, permissions, 0); return fileStream; } catch (ex) { ERROR_LOG("enigmail.js: CreateFileStream: Failed to create "+filePath+"\n"); return null; } } function WriteFileContents(filePath, data, permissions) { DEBUG_LOG("enigmail.js: WriteFileContents: file="+filePath+"\n"); try { var fileOutStream = CreateFileStream(filePath, permissions); if (data.length) { if (fileOutStream.write(data, data.length) != data.length) throw Components.results.NS_ERROR_FAILURE; fileOutStream.flush(); } fileOutStream.close(); } catch (ex) { ERROR_LOG("enigmail.js: WriteFileContents: Failed to write to "+filePath+"\n"); return false; } return true; } // Pack/unpack: Network (big-endian) byte order function pack(value, bytes) { var str = ''; var mask = 0xff; for (var j=0; j < bytes; j++) { str = String.fromCharCode( (value & mask) >> j*8 ) + str; mask <<= 8; } return str; } function unpack(str) { var len = str.length; var value = 0; for (var j=0; j < len; j++) { value <<= 8; value |= str.charCodeAt(j); } return value; } const hexTable = "0123456789abcdef"; function bytesToHex(str) { var len = str.length; var hex = ''; for (var j=0; j < len; j++) { var charCode = str.charCodeAt(j); hex += hexTable.charAt((charCode & 0xf0) >> 4) + hexTable.charAt((charCode & 0x0f)); } return hex; } function hexToBytes(hex) { hex = hex.toLowerCase(); var bytes = (1+hex.length)/2; var str = ''; for (var j=0; j < bytes; j++) { var loc1 = hexTable.indexOf(hex.charAt(2*j)); var loc2 = 0; if ((2*j+1) < hex.length) loc2 = hexTable.indexOf(hex.charAt(2*j+1)); if (loc1 < 0) loc1 = 0; if (loc2 < 0) loc2 = 0; str += String.fromCharCode((loc1 << 4) + loc2); } return str; } /////////////////////////////////////////////////////////////////////////////// function WRITE_LOG(str) { function f00(val, digits) { return ("0000"+val.toString()).substr(-digits); } var d = new Date(); var datStr=d.getFullYear()+"-"+f00(d.getMonth()+1, 2)+"-"+f00(d.getDate(),2)+" "+f00(d.getHours(),2)+":"+f00(d.getMinutes(),2)+":"+f00(d.getSeconds(),2)+"."+f00(d.getMilliseconds(),3)+" "; if (gLogLevel >= 4) dump(datStr+str); if (gEnigmailSvc && gEnigmailSvc.logFileStream) { gEnigmailSvc.logFileStream.write(datStr, datStr.length); gEnigmailSvc.logFileStream.write(str, str.length); //gEnigmailSvc.logFileStream.flush(); } } function DEBUG_LOG(str) { if ((gLogLevel >= 4) || (gEnigmailSvc && gEnigmailSvc.logFileStream)) WRITE_LOG(str); } function WARNING_LOG(str) { if (gLogLevel >= 3) WRITE_LOG(str); if (gEnigmailSvc && gEnigmailSvc.console) gEnigmailSvc.console.write(str); } function ERROR_LOG(str) { if (gLogLevel >= 2) WRITE_LOG(str); if (gEnigmailSvc && gEnigmailSvc.console) gEnigmailSvc.console.write(str); } function CONSOLE_LOG(str) { if (gLogLevel >= 3) WRITE_LOG(str); if (gEnigmailSvc && gEnigmailSvc.console) gEnigmailSvc.console.write(str); } /////////////////////////////////////////////////////////////////////////////// var EnigModuleObj = { registerSelf: function (compRegistrar, moduleFile, registryLocation, componentType) { WRITE_LOG("enigmail.js: Registering components\n"); compRegistrar = compRegistrar.QueryInterface(Components.interfaces.nsIComponentRegistrar); compRegistrar.registerFactoryLocation(NS_ENIGMAIL_CID, "Enigmail", NS_ENIGMAIL_CONTRACTID, moduleFile, registryLocation, componentType); compRegistrar.registerFactoryLocation(NS_ENIGMAILPROTOCOLHANDLER_CID, "Enigmail Protocol Handler", NS_ENIGMAILPROTOCOLHANDLER_CONTRACTID, moduleFile, registryLocation, componentType); compRegistrar.registerFactoryLocation(NS_PGP_MODULE_CID, "PGP Module", NS_PGP_MODULE_CONTRACTID, moduleFile, registryLocation, componentType); compRegistrar.registerFactoryLocation(NS_ENIGCLINE_SERVICE_CID, "Enigmail Key Management CommandLine Service", NS_CLINE_SERVICE_CONTRACTID, moduleFile, registryLocation, componentType); var catman = Components.classes[NS_CATMAN_CONTRACTID].getService(nsICategoryManager); catman.addCategoryEntry("command-line-argument-handlers", "Enigmail Key Management command line handler", NS_CLINE_SERVICE_CONTRACTID, true, true); WRITE_LOG("enigmail.js: Registered components\n"); }, unregisterSelf: function(compRegistrar, moduleFile, registryLocation) { DEBUG_LOG("enigmail.js: unregisterSelf\n"); compRegistrar = compRegistrar.QueryInterface(Components.interfaces.nsIComponentRegistrar); compRegistrar.unregisterFactoryLocation(NS_ENIGCLINE_SERVICE_CID, moduleFile); var catman = Components.classes[NS_CATMAN_CONTRACTID] .getService(nsICategoryManager); catman.deleteCategoryEntry("command-line-argument-handlers", NS_CLINE_SERVICE_CONTRACTID, true); }, getClassObject: function (compRegistrar, cid, iid) { DEBUG_LOG("enigmail.js: getClassObject: cid="+cid+"\n"); if (!iid.equals(Components.interfaces.nsIFactory)) throw Components.results.NS_ERROR_NOT_IMPLEMENTED; if (gEnigmailSvc == null) { // Create Enigmail Service (delay initialization) gEnigmailSvc = new Enigmail(false); } if (cid.equals(NS_ENIGCLINE_SERVICE_CID)) return EnigCLineFactory; if (cid.equals(NS_ENIGMAIL_CID)) { return new EnigmailFactory(); } if (cid.equals(NS_ENIGMAILPROTOCOLHANDLER_CID)) { return new EnigmailProtocolHandlerFactory(); } if (cid.equals(NS_PGP_MODULE_CID)) { return new PGPModuleFactory(); } return null; }, canUnload: function(compRegistrar) { DEBUG_LOG("enigmail.js: canUnload:\n"); return true; } }; /* Module entry point */ function NSGetModule(compRegistrar, moduleFile) { DEBUG_LOG("enigmail.js: NSGetModule:\n"); return EnigModuleObj; } /////////////////////////////////////////////////////////////////////////////// function EnigmailFactory() { } EnigmailFactory.prototype = { QueryInterface: function (iid) { //DEBUG_LOG("EnigmailFactory.QueryInterface:"+iid+"\n"); if (!iid.equals(Components.interfaces.nsIFactory) && !iid.equals(nsISupports)) throw Components.results.NS_ERROR_NO_INTERFACE; return this; }, createInstance: function (outer, iid) { //DEBUG_LOG("EnigmailFactory.createInstance:\n"); if (!gEnigmailSvc) throw Components.results.NS_ERROR_NOT_D; return gEnigmailSvc; } } function PGPModuleFactory() { } PGPModuleFactory.prototype = { QueryInterface: function (iid) { //DEBUG_LOG("PGPModuleFactory.QueryInterface:"+iid+"\n"); if (!iid.equals(Components.interfaces.nsIFactory) && !iid.equals(nsISupports)) throw Components.results.NS_ERROR_NO_INTERFACE; return this; }, createInstance: function (outer, iid) { DEBUG_LOG("PGPModuleFactory.createInstance:\n"); return new PGPModule(); } } function PGPMsgHeader(aTo, aCc, aBcc) { this.to = aTo; this.cc = aCc; this.bcc = aBcc; } PGPMsgHeader.prototype = { to: "", cc: "", bcc: "", QueryInterface: function (iid) { DEBUG_LOG("PGPMsgHeader.QueryInterface:\n"); if (!iid.equals(nsIPGPMsgHeader) && !iid.equals(nsISupports)) throw Components.results.NS_ERROR_NO_INTERFACE; return this; } } /* function PGPMsgBody(aBody) { this.body = aBody; } PGPMsgBody.prototype = { body: "", QueryInterface: function (iid) { DEBUG_LOG("PGPMsgBody.QueryInterface:\n"); if (!iid.equals(nsIPGPMsgBody) && !iid.equals(nsISupports)) throw Components.results.NS_ERROR_NO_INTERFACE; return this; } } function PGPModule() { } PGPModule.prototype = { QueryInterface: function (iid) { DEBUG_LOG("PGPModule.QueryInterface:\n"); if (!iid.equals(nsIPGPModule) && !iid.equals(nsISupports)) throw Components.results.NS_ERROR_NO_INTERFACE; return this; }, // void SetEncrypt(in boolean aEncrypt, in long aFlags, // [retval] out long aNewFlags); SetEncrypt: function (aEncrypt, aFlags, aNewFlags) { DEBUG_LOG("PGPModule.SetEncrypt:\n"); return 0; }, // void SetSign(in boolean aSign, in long aFlags, // [retval] out long aNewFlags); SetSign: function (aSign, aFlags, aNewFlags) { DEBUG_LOG("PGPModule.SetSign:\n"); return 0; }, // void SetPGPMIME(in boolean aMime, in long aFlags, // [retval] out long aNewFlags); SetPGPMIME: function (aMime, Flags, aNewFlags) { DEBUG_LOG("PGPModule.SetPGPMIME:\n"); return 0; }, // nsISupports CreateMsgHeader(in string aTo, in string aCc, in string aBcc); CreateMsgHeader: function (aTo, aCc, aBcc) { DEBUG_LOG("PGPModuleCreateMsgHeader.:\n"); return new PGPMsgHeader(aTo, aCc, aBcc); }, //nsISupports CreateMsgBody(in string aBody); CreateMsgBody: function (aBody) { DEBUG_LOG("PGPModule.CreateMsgBody: "+aBody+"\n"); return new PGPMsgBody(aBody); }, // string GetStringFromMsgBody(in nsISupports aMsgBody); GetStringFromMsgBody: function (aMsgBody) { DEBUG_LOG("PGPModule.GetStringFromMsgBody:\n"); aMsgBody = aMsgBody.QueryInterface(nsIPGPMsgBody); return aMsgBody.body; }, // void EncryptSign(in long aFlags, in nsISupports aMsgHeader, // in nsISupports aOrigBody, // [retval] out nsISupports aNewBody); EncryptSign: function (aFlags, aMsgHeader, aOrigBody, aNewBody) { DEBUG_LOG("PGPModule.EncryptSign:\n"); aMsgHeader = aMsgHeader.QueryInterface(nsIPGPMsgHeader); aOrigBody = aOrigBody.QueryInterface(nsIPGPMsgBody); DEBUG_LOG("PGPModule.EncryptSign: aMsgHeader.to="+aMsgHeader.to+"\n"); DEBUG_LOG("PGPModule.EncryptSign: aOrigBody.body="+aOrigBody.body+"\n"); DEBUG_LOG("PGPModule.EncryptSign: aNewBody="+aNewBody+"\n"); var exitCodeObj = new Object(); var statusFlagsObj = new Object(); var errorMsgObj = new Object(); var encryptFlags = nsIEnigmail.SEND_SIGNED | nsIEnigmail.SEND_ENCRYPTED; var cipherText = gEnigmailSvc.encryptMessage(null, 0, aOrigBody.body, "", aMsgHeader.to, encryptFlags, exitCodeObj, statusFlagsObj, errorMsgObj); return new PGPMsgBody(cipherText); }, // void DecryptVerify(in nsISupports aOrigBody, // [retval] out nsISupports aNewBody) DecryptVerify: function (aOrigBody, aNewBody) { DEBUG_LOG("PGPModule.DecryptVerify:\n"); aOrigBody = aOrigBody.QueryInterface(nsIPGPMsgBody); DEBUG_LOG("PGPModule.DecryptVerify: aOrigBody.body="+aOrigBody.body+"\n"); var exitCodeObj = new Object(); var errorMsgObj = new Object(); var signatureObj = new Object(); var statusFlagsObj = new Object(); var keyIdObj = new Object(); var userIdObj = new Object(); var plainText = gEnigmailSvc.decryptMessage(null, 0, aOrigBody.body, signatureObj, exitCodeObj, statusFlagsObj, keyIdObj, userIdObj, errorMsgObj); return new PGPMsgBody(plainText); }, // void FreeMsgHeader(in nsISupports aMsgHeader); FreeMsgHeader: function (aMsgHeader) { DEBUG_LOG("PGPModule.FreeMsgHeader:\n"); }, // void FreeMsgBody(in nsISupports aMsgBody); FreeMsgBody: function (aMsgBody) { DEBUG_LOG("PGPModule.FreeMsgBody:\n"); }, // void FindHeader(in string aHeaderBuffer, in string aHeaderStr, // out long aHeaderStartOffset, out long aHeaderLength, // [retval] out long aBufferEndOffset); FindHeader: function (aHeaderBuffer, aHeaderStr, aHeaderStartOffset, aHeaderLength, aBufferEndOffset) { DEBUG_LOG("PGPModule.FindHeader:\n"); DEBUG_LOG("PGPModule.EncryptSign: aHeaderBuffer="+aHeaderBuffer+"\n"); for (var k in aHeaderStartOffset) DEBUG_LOG("PGPModule.EncryptSign: k="+k+"\n"); DEBUG_LOG("PGPModule.EncryptSign: aHeaderStartOffset="+aHeaderStartOffset+"\n"); DEBUG_LOG("PGPModule.EncryptSign: aHeaderLength="+aHeaderLength+"\n"); DEBUG_LOG("PGPModule.EncryptSign: aBufferEndOffset="+aBufferEndOffset+"\n"); aHeaderStartOffset.value = 0; aHeaderLength.value = 0; aBufferEndOffset.value = 0; }, // boolean ContainsPGPContent(in string aBuffer); ContainsPGPContent: function (aBuffer) { DEBUG_LOG("PGPModule.ContainsPGPContent:\n"); return false; } } */ /////////////////////////////////////////////////////////////////////////////// // Utility functions /////////////////////////////////////////////////////////////////////////////// function isAbsolutePath(filePath, isDosLike) { // Check if absolute path if (isDosLike) { return (filePath.search(/^\w+:\\/) == 0); } else { return (filePath.search(/^\//) == 0) } } function ResolvePath(filePath, envPath, isDosLike) { DEBUG_LOG("enigmail.js: ResolvePath: filePath="+filePath+"\n"); if (isAbsolutePath(filePath, isDosLike)) return filePath; if (!envPath) return null; var pathDirs = envPath.split(isDosLike ? ";" : ":"); for (var j=0; j=0) { var ch=text.substr(a,2).toSource().substr(13,8).replace(/\\x/g, "\\u00"); var newCh=EnigConvertToUnicode(EnigConvertToUnicode(ch, "x-u-escaped"), "utf-8"); if (newCh != ch) { //dump(ch+"\n"); var r=new RegExp(text.substr(a, 2), "g"); text=text.replace(r, newCh); } b=a+2; a=text.substr(b+2).search(/[\x80-\xFF]{2}/); if (a>=0) { a += b+2; } } a=text.search(/\\x3a/i); if (a>0) { text = text.replace(/\\x3a/ig, "\\e3A"); } a=text.search(/\\x/); while (a>=0) { ch=text.substr(a,4).replace(/\\x/g, "\\u00"); newCh=EnigConvertToUnicode(ch, "x-u-escaped"); if (newCh != ch) { r=new RegExp("\\"+text.substr(a, 4), "g"); text=text.replace(r, newCh); } a=text.search(/\\x/); } } return text; } /////////////////////////////////////////////////////////////////////////////// // Enigmail protocol handler /////////////////////////////////////////////////////////////////////////////// function EnigmailProtocolHandler() { } EnigmailProtocolHandler.prototype.scheme = "enigmail"; EnigmailProtocolHandler.prototype.defaultPort = -1; EnigmailProtocolHandler.prototype.QueryInterface = function (iid) { DEBUG_LOG("enigmail.js: EnigmailProtocolHandler.QueryInterface\n"); if (!iid.equals(nsIProtocolHandler) && !iid.equals(nsISupports)) throw Components.results.NS_ERROR_NO_INTERFACE; return this; } EnigmailProtocolHandler.prototype.newURI = function (aSpec, originCharset, aBaseURI) { DEBUG_LOG("enigmail.js: EnigmailProtocolHandler.newURI: aSpec='"+aSpec+"'\n"); var uri = Components.classes[NS_SIMPLEURI_CONTRACTID].createInstance(Components.interfaces.nsIURI); uri.spec = aSpec; return uri; } EnigmailProtocolHandler.prototype.newChannel = function (aURI) { DEBUG_LOG("enigmail.js: EnigmailProtocolHandler.newChannel: URI='"+aURI.spec+"'\n"); var messageId = ExtractMessageId(aURI.spec); if (messageId) { // Handle enigmail:message?id=... if (!gEnigmailSvc) throw Components.results.NS_ERROR_FAILURE; var contentType, contentCharset, contentData; if (gEnigmailSvc._messageIdList[messageId]) { var messageUriObj = gEnigmailSvc._messageIdList[messageId]; contentType = messageUriObj.contentType; contentCharset = messageUriObj.contentCharset; contentData = messageUriObj.contentData; DEBUG_LOG("enigmail.js: EnigmailProtocolHandler.newChannel: messageURL="+messageUriObj.originalUrl+", "+contentType+", "+contentCharset+"\n"); if (!messageUriObj.persist) delete gEnigmailSvc._messageIdList[messageId]; } else { contentType = "text/plain"; contentCharset = ""; contentData = "Enigmail error: invalid URI "+aURI.spec; } var channel = gEnigmailSvc.ipcService.newStringChannel(aURI, contentType, "UTF-8", contentData); return channel; } if (aURI.spec == aURI.scheme+":dummy") { // Dummy PKCS7 content (to access mimeEncryptedClass) channel = gEnigmailSvc.ipcService.newStringChannel(aURI, "message/rfc822", "", gDummyPKCS7); return channel; } var winName, spec; if (aURI.spec == "about:"+aURI.scheme) { // About Enigmail winName = "about:"+enigmail; spec = "chrome://enigmail/content/enigmailAbout.xul"; } else if (aURI.spec == aURI.scheme+":console") { // Display enigmail console messages winName = "enigmail:console"; spec = "chrome://enigmail/content/enigmailConsole.xul"; } else if (aURI.spec == aURI.scheme+":keygen") { // Display enigmail key generation console winName = "enigmail:keygen"; spec = "chrome://enigmail/content/enigmailKeygen.xul"; } else { // Display Enigmail about page winName = "about:enigmail"; spec = "chrome://enigmail/content/enigmailAbout.xul"; } var windowManager = Components.classes[WMEDIATOR_CONTRACTID].getService(Components.interfaces.nsIWindowMediator); var recentWin = windowManager.getMostRecentWindow(winName); dump("recentWin="+recentWin+"\n"); if (recentWin) { recentWin.focus(); } else { var appShellSvc = Components.classes[ASS_CONTRACTID].getService(Components.interfaces.nsIAppShellService); var domWin = appShellSvc.hiddenDOMWindow; domWin.open(spec, "_blank", "chrome,menubar,toolbar,resizable"); } throw Components.results.NS_ERROR_FAILURE; } function EnigmailProtocolHandlerFactory() { } EnigmailProtocolHandlerFactory.prototype = { QueryInterface: function (iid) { //DEBUG_LOG("EnigmailProtocolHandlerFactory.QueryInterface:"+iid+"\n"); if (!iid.equals(Components.interfaces.nsIFactory) && !iid.equals(nsISupports)) throw Components.results.NS_ERROR_NO_INTERFACE; return this; }, createInstance: function (outer, iid) { DEBUG_LOG("enigmail.js: EnigmailProtocolHandlerFactory.createInstance\n"); if (outer != null) throw Components.results.NS_ERROR_NO_AGGREGATION; if (!iid.equals(nsIProtocolHandler) && !iid.equals(nsISupports)) throw Components.results.NS_ERROR_INVALID_ARG; return new EnigmailProtocolHandler(); } } /////////////////////////////////////////////////////////////////////////////// // Enigmail encryption/decryption service /////////////////////////////////////////////////////////////////////////////// function GetXULOwner () { if (gXULOwner) return gXULOwner; // Open temporary XUL channel var ioServ = Components.classes[NS_IOSERVICE_CONTRACTID].getService(Components.interfaces.nsIIOService); var temChannel = ioServ.newChannel("chrome://enigmail/content/dummy.xul", "", null); // Get owner of XUL channel gXULOwner = temChannel.owner; // Release channel temChannel = null; DEBUG_LOG("enigmail.js: GetXULOwner: gXULOwner="+gXULOwner+"\n"); return gXULOwner; } function GetPassphrase(domWindow, passwdObj, useAgentObj, agentVersion) { DEBUG_LOG("enigmail.js: GetPassphrase:\n"); useAgentObj.value = false; try { var noPassphrase = gEnigmailSvc.prefBranch.getBoolPref("noPassphrase"); var useAgent = gEnigmailSvc.prefBranch.getBoolPref("useGpgAgent"); useAgentObj.value = useAgent; if (noPassphrase || useAgent) { passwdObj.value = ""; return true; } } catch(ex) {} if (gEnigmailSvc.haveCachedPassphrase()) { passwdObj.value = gCachedPassphrase; return true; } // Obtain password interactively var checkObj = new Object(); if (agentVersion>="1.4") { var promptMsg = EnigGetString("enterPassOrPin"); } else { promptMsg = EnigGetString("enterPass",gEnigmailSvc.agentType.toUpperCase()); } passwdObj.value = ""; checkObj.value = true; var maxIdleMinutes = gEnigmailSvc.getMaxIdleMinutes(); var checkMsg = (maxIdleMinutes>0) ? EnigGetString("rememberPass",maxIdleMinutes) : ""; var success; var promptService = Components.classes[NS_PROMPTSERVICE_CONTRACTID].getService(Components.interfaces.nsIPromptService); success = promptService.promptPassword(domWindow, EnigGetString("Enigmail"), promptMsg, passwdObj, checkMsg, checkObj); if (!success) return false; DEBUG_LOG("enigmail.js: GetPassphrase: got passphrase\n"); // Remember passphrase only if necessary if (checkObj.value && (maxIdleMinutes > 0)) gEnigmailSvc.setCachedPassphrase(passwdObj.value); return true; } function Enigmail(registeringModule) { DEBUG_LOG("enigmail.js: Enigmail: START "+registeringModule+"\n"); this.registeringModule = registeringModule; DEBUG_LOG("enigmail.js: Enigmail: END\n"); } Enigmail.prototype.registeringModule = false; Enigmail.prototype.initialized = false; Enigmail.prototype.initializationAttempted = false; Enigmail.prototype.initializationError = ""; Enigmail.prototype.composeSecure = false; Enigmail.prototype.logFileStream = null; Enigmail.prototype.isUnix = false; Enigmail.prototype.isWin32 = false; Enigmail.prototype.isOs2 = false; Enigmail.prototype.isDosLike = false; Enigmail.prototype.ipcService = null; Enigmail.prototype.prefBranch = null; Enigmail.prototype.console = null; Enigmail.prototype.keygenProcess = null; Enigmail.prototype.keygenConsole = null; Enigmail.prototype.quoteSign = ""; Enigmail.prototype.agentType = ""; Enigmail.prototype.agentPath = ""; Enigmail.prototype.agentVersion = ""; Enigmail.prototype.userIdList = null; Enigmail.prototype.rulesList = null; Enigmail.prototype._lastActiveTime = 0; Enigmail.prototype._messageIdList = {}; Enigmail.prototype.QueryInterface = function (iid) { //DEBUG_LOG("Enigmail.QueryInterface:\n"); if (!iid.equals(nsIEnigmail) && !iid.equals(nsIObserver) && !iid.equals(nsISupports)) throw Components.results.NS_ERROR_NO_INTERFACE; return this; } Enigmail.prototype.observe = function (aSubject, aTopic, aData) { DEBUG_LOG("enigmail.js: Enigmail.observe: topic='"+aTopic+"' \n"); if (aTopic == "timer-callback") { // Cause cached password to expire, if need be if (!this.haveCachedPassphrase()) { // No cached password; cancel repeating timer if (gCacheTimer) gCacheTimer.cancel(); } } else if (aTopic == NS_XPCOM_SHUTDOWN_OBSERVER_ID) { // XPCOM shutdown this.finalize(); // Reset mail.show_headers pref try { var prefSvc = Components.classes[NS_PREFS_SERVICE_CID] .getService(Components.interfaces.nsIPrefService); var prefRoot = prefSvc.getBranch(null); var prefValue = 1; try { prefValue = this.prefBranch.getIntPref("show_headers"); } catch (ex) {} prefRoot.setIntPref("mail.show_headers", prefValue); prefSvc.savePrefFile(null); } catch (ex) {} } } Enigmail.prototype.alertMsg = function (domWindow, mesg) { var promptService = Components.classes[NS_PROMPTSERVICE_CONTRACTID].getService(Components.interfaces.nsIPromptService); return promptService.alert(domWindow, EnigGetString("enigAlert"), mesg); } Enigmail.prototype.confirmMsg = function (domWindow, mesg) { var dummy={}; var promptService = Components.classes[NS_PROMPTSERVICE_CONTRACTID].getService(Components.interfaces.nsIPromptService); var buttonPressed = promptService.confirmEx(domWindow, EnigGetString("enigConfirm"), mesg, (promptService.BUTTON_TITLE_YES * BUTTON_POS_0) + (promptService.BUTTON_TITLE_NO * BUTTON_POS_1), null, null, null, null, dummy); return (buttonPressed==0); // promptService.confirm(domWindow, EnigGetString("enigConfirm"), mesg); } Enigmail.prototype.promptValue = function (domWindow, mesg, valueObj) { var promptService = Components.classes[NS_PROMPTSERVICE_CONTRACTID].getService(Components.interfaces.nsIPromptService); var checkObj = new Object(); return promptService.prompt(domWindow, EnigGetString("enigPrompt"), mesg, valueObj, "", checkObj); } Enigmail.prototype.errorMsg = function (domWindow, mesg) { var promptService = Components.classes[NS_PROMPTSERVICE_CONTRACTID].getService(Components.interfaces.nsIPromptService); return promptService.alert(domWindow, EnigGetString("enigError"), mesg); } Enigmail.prototype.getMaxIdleMinutes = function () { var maxIdleMinutes = 5; try { maxIdleMinutes = this.prefBranch.getIntPref("maxIdleMinutes"); } catch (ex) { } return maxIdleMinutes; } Enigmail.prototype.getLogDirectoryPrefix = function () { var logDirectory = ""; try { logDirectory = this.prefBranch.getCharPref("logDirectory"); } catch (ex) { } if (!logDirectory) return ""; var dirPrefix = logDirectory + (this.isDosLike ? "\\" : "/"); return dirPrefix; } Enigmail.prototype.stillActive = function () { DEBUG_LOG("enigmail.js: Enigmail.stillActive: \n"); // Update last active time var curDate = new Date(); this._lastActiveTime = curDate.getTime(); // DEBUG_LOG("enigmail.js: Enigmail.stillActive: _lastActiveTime="+this._lastActiveTime+"\n"); } Enigmail.prototype.clearCachedPassphrase = function () { DEBUG_LOG("enigmail.js: Enigmail.clearCachedPassphrase: \n"); gCachedPassphrase = null; } Enigmail.prototype.setCachedPassphrase = function (passphrase) { DEBUG_LOG("enigmail.js: Enigmail.setCachedPassphrase: \n"); gCachedPassphrase = passphrase; this.stillActive(); var maxIdleMinutes = this.getMaxIdleMinutes(); if (this.haveCachedPassphrase() && (maxIdleMinutes > 0)) { // Start timer if (gCacheTimer) gCacheTimer.cancel(); var delayMillisec = maxIdleMinutes*60*1000; if (Components.interfaces.nsITimer) { // Use nsITimer: Post 1.2a mozilla trunk const nsITimer = Components.interfaces.nsITimer; gCacheTimer = Components.classes[NS_TIMER_CONTRACTID].createInstance(nsITimer); if (!gCacheTimer) { ERROR_LOG("enigmail.js: Enigmail.setCachedPassphrase: Error - failed to create timer\n"); throw Components.results.NS_ERROR_FAILURE; } gCacheTimer.init(this, delayMillisec, nsITimer.TYPE_REPEATING_SLACK); } else { // Use nsIScriptableTimer: Stable Mozilla 1.0 branch const nsIScriptableTimer = Components.interfaces.nsIScriptableTimer; gCacheTimer = Components.classes[NS_TIMER_CONTRACTID].createInstance(nsIScriptableTimer); if (!gCacheTimer) { ERROR_LOG("enigmail.js: Enigmail.setCachedPassphrase: Error - failed to create scriptable timer\n"); throw Components.results.NS_ERROR_FAILURE; } gCacheTimer.init(this, delayMillisec, nsIScriptableTimer.PRIORITY_NORMAL, nsIScriptableTimer.TYPE_REPEATING_SLACK); } DEBUG_LOG("enigmail.js: Enigmail.setCachedPassphrase: gCacheTimer="+gCacheTimer+"\n"); } } Enigmail.prototype.haveCachedPassphrase = function () { DEBUG_LOG("enigmail.js: Enigmail.haveCachedPassphrase: \n"); var havePassphrase = ((typeof gCachedPassphrase) == "string"); if (!havePassphrase) return false; var curDate = new Date(); var currentTime = curDate.getTime(); var maxIdleMinutes = this.getMaxIdleMinutes(); var delayMillisec = maxIdleMinutes*60*1000; var expired = ((currentTime - this._lastActiveTime) >= delayMillisec); // DEBUG_LOG("enigmail.js: Enigmail.haveCachedPassphrase: ") // DEBUG_LOG("currentTime="+currentTime+", _lastActiveTime="+this._lastActiveTime+", expired="+expired+"\n"); if (expired) { // Too much idle time; forget cached password gCachedPassphrase = null; havePassphrase = false; WRITE_LOG("enigmail.js: Enigmail.haveCachedPassphrase: CACHE IDLED OUT\n"); } return havePassphrase; } Enigmail.prototype.finalize = function () { DEBUG_LOG("enigmail.js: Enigmail.finalize:\n"); if (!this.initialized) return; if (this.logFileStream) { this.logFileStream.close(); this.logFileStream = null; } if (this.console) { this.console.close(); this.console = null; } gLogLevel = 3; this.initializationError = ""; this.initializationAttempted = false; this.initialized = false; } Enigmail.prototype.mimeInitialized = function () { var enigMimeService = Components.classes[NS_ENIGMIMESERVICE_CONTRACTID].getService(Components.interfaces.nsIEnigMimeService); var value = enigMimeService.initialized; DEBUG_LOG("enigmail.js: Enigmail.mimeInitialized: "+value+"\n"); return value; } Enigmail.prototype.initialize = function (domWindow, version, prefBranch) { this.initializationAttempted = true; this.prefBranch = prefBranch; DEBUG_LOG("enigmail.js: Enigmail.initialize: START\n"); if (this.initialized) return; try { var enigMsgComposeFactory = Components.classes[NS_ENIGMSGCOMPOSEFACTORY_CONTRACTID].createInstance(Components.interfaces.nsIFactory); var compMgr = Components.manager.QueryInterface(Components.interfaces.nsIComponentRegistrar); compMgr.registerFactory(NS_ENIGMSGCOMPOSE_CID, "Enig Msg Compose", NS_MSGCOMPOSESECURE_CONTRACTID, enigMsgComposeFactory); var msgComposeSecureCID = compMgr.contractIDToCID(NS_MSGCOMPOSESECURE_CONTRACTID); this.composeSecure = (msgComposeSecureCID.toString() == NS_ENIGMSGCOMPOSE_CID); } catch (ex) {} var ioServ = Components.classes[NS_IOSERVICE_CONTRACTID].getService(Components.interfaces.nsIIOService); try { var httpHandler = ioServ.getProtocolHandler("http"); httpHandler = httpHandler.QueryInterface(Components.interfaces.nsIHttpProtocolHandler); } catch (ex) { httpHandler = domWindow.navigator; } this.oscpu = httpHandler.oscpu; this.platform = httpHandler.platform; if (httpHandler.vendor) { this.vendor = httpHandler.vendor; } else { this.vendor = "Mozilla"; } this.isUnix = (this.platform.search(/X11/i) == 0); this.isWin32 = (this.platform.search(/Win/i) == 0); this.isOs2 = (this.platform.search(/OS\/2/i) == 0); if (this.isOs2) { this.quoteSign="\\\""; } else { this.quoteSign="'"; } this.isDosLike = (this.isWin32 || this.isOs2); var prefix = this.getLogDirectoryPrefix(); if (prefix) { gLogLevel = 5; this.logFileStream = CreateFileStream(prefix+"enigdbug.txt"); DEBUG_LOG("enigmail.js: Logging debug output to "+prefix+"enigdbug.txt\n"); } this.version = version; DEBUG_LOG("enigmail.js: Enigmail version "+this.version+"\n"); DEBUG_LOG("enigmail.js: OS/CPU="+this.oscpu+"\n"); DEBUG_LOG("enigmail.js: Platform="+this.platform+"\n"); DEBUG_LOG("enigmail.js: composeSecure="+this.composeSecure+"\n"); var processInfo; try { processInfo = Components.classes[NS_PROCESSINFO_CONTRACTID].getService(nsIProcessInfo); } catch (ex) { this.initializationError = EnigGetString("enigmimeNotAvail"); ERROR_LOG("enigmail.js: Enigmail.initialize: Error - "+this.initializationError+"\n"); throw Components.results.NS_ERROR_FAILURE; } this.processInfo = processInfo; var nspr_log_modules = processInfo.getEnv("NSPR_LOG_MODULES"); var matches = nspr_log_modules.match(/enigmail:(\d+)/); if (matches && (matches.length > 1)) { gLogLevel = matches[1]; WARNING_LOG("enigmail.js: Enigmail: gLogLevel="+gLogLevel+"\n"); } // Initialize global environment variables list var passEnv = [ "PGPPATH", "GNUPGHOME", "ALLUSERSPROFILE", "APPDATA", "BEGINLIBPATH", "COMMONPROGRAMFILES", "COMSPEC", "DISPLAY", "ENIGMAIL_PASS_ENV", "ENDLIBPATH", "HOME", "HOMEDRIVE", "HOMEPATH", "LANG", "LANGUAGE", "LC_ALL", "LC_COLLATE", "LC_CTYPE", "LC_MESSAGES", "LC_MONETARY", "LC_NUMERIC", "LC_TIME", "LOCPATH", "LOGNAME", "LD_LIBRARY_PATH", "MOZILLA_FIVE_HOME", "NLSPATH", "PATH", "PATHEXT", "PROGRAMFILES", "PWD", "SHELL", "SYSTEMDRIVE", "SYSTEMROOT", "TEMP", "TMP", "TMPDIR", "TZ", "TZDIR", "UNIXROOT", "USER", "USERPROFILE", "WINDIR" ]; try { var useAgent=this.prefBranch.getBoolPref("useGpgAgent"); if (useAgent) { passEnv.push("GPG_AGENT_INFO"); } } catch (ex) {} var passList = this.processInfo.getEnv("ENIGMAIL_PASS_ENV"); if (passList) { var passNames = passList.split(":"); for (var k=0; k -1) { - agentType = "gpg"; - - } else if (agentPath.search(/pgp[^\/\\]*$/i) > -1) { - agentType = "pgp"; - - } else { - this.initializationError = "Cannot determine agent type (GPG/PGP) from executable filename "+agentPath; - ERROR_LOG("enigmail.js: Enigmail.initialize: Error - "+this.initializationError+"\n"); - throw Components.results.NS_ERROR_FAILURE; - } - } else { - // Resolve relative path using PATH environment variable - var envPath = this.processInfo.getEnv("PATH"); - - for (var index=0; index "+command.replace(/\\\\/g, "\\")+"\n"); var outStr = outStrObj.value; if (errStrObj.value) outStr += errStrObj.value; CONSOLE_LOG(outStr+"\n"); var versionParts = outStr.replace(/[\r\n].*/g,"").split(/ /); var gpgVersion = versionParts[versionParts.length-1] this.agentVersion = gpgVersion; // check GnuPG version number var evalVersion = this.agentVersion.match(/^\d+\.\d+/) if (evalVersion && evalVersion[0]<"1.2") { this.alertMsg(domWindow, EnigGetString("oldGpgVersion", gpgVersion)); throw Components.results.NS_ERROR_FAILURE; } } Enigmail.prototype.getAgentPath = function () { var p = ""; try { p=this.prefBranch.getCharPref("agentAdditionalParam").replace(/([\\\`])/g, "\\$1"); } catch (ex) {} return this.agentPath + " --charset utf8 " + p; } Enigmail.prototype.passwdCommand = function () { var command; try { var gpgVersion = this.agentVersion.match(/^\d+\.\d+/); if (this.prefBranch.getBoolPref("useGpgAgent")) { command = " --use-agent " } else { command = " --passphrase-fd 0"; if (gpgVersion && gpgVersion[0] >= "1.1") { command += " --no-use-agent "; } } } catch (ex) {} return command; } Enigmail.prototype.fixExitCode = function (exitCode, statusFlags) { if ((this.agentType == "gpg") && (exitCode == 256)) { WARNING_LOG("enigmail.js: Enigmail.fixExitCode: Using gpg and exit code is 256. You seem to use cygwin-gpg, activating countermeasures.\n"); if (statusFlags & (nsIEnigmail.BAD_PASSPHRASE | nsIEnigmail.UNVERIFIED_SIGNATURE)) { WARNING_LOG("enigmail.js: Enigmail.fixExitCode: Changing exitCode 256->2\n"); exitCode = 2; } else { WARNING_LOG("enigmail.js: Enigmail.fixExitCode: Changing exitCode 256->0\n"); exitCode = 0; } } if (((this.agentVersion >= "1.3") && (this.agentVersion < "1.4.1" )) && (this.isDosLike)) { if ((exitCode == 2) && (!(statusFlags & (nsIEnigmail.BAD_PASSPHRASE | nsIEnigmail.UNVERIFIED_SIGNATURE | nsIEnigmail.MISSING_PASSPHRASE | nsIEnigmail.BAD_ARMOR | nsIEnigmail.DECRYPTION_INCOMPLETE | nsIEnigmail.DECRYPTION_FAILED | nsIEnigmail.NO_PUBKEY | nsIEnigmail.NO_SECKEY)))) { WARNING_LOG("enigmail.js: Enigmail.fixExitCode: Using gpg version "+this.agentVersion+", activating countermeasures for file renaming bug.\n"); exitCode = 0; } } return exitCode; } Enigmail.prototype.execCmd = function (command, passphrase, input, exitCodeObj, statusFlagsObj, statusMsgObj, errorMsgObj) { WRITE_LOG("enigmail.js: Enigmail.execCmd: command = "+command+"\n"); if ((typeof input) != "string") input = ""; var prependPassphrase = ((typeof passphrase) == "string"); var envList = []; envList = envList.concat(gEnvList); var preInput; if (prependPassphrase) { envList.push("PGPPASSFD=0"); preInput = passphrase; input = "\n" + input; } else { preInput = ""; } var prefix = this.getLogDirectoryPrefix(); if (prefix && (gLogLevel >= 4)) { if (prependPassphrase) { // Obscure passphrase WriteFileContents(prefix+"eniginp.txt", ""+input); } else { WriteFileContents(prefix+"eniginp.txt", input); } WriteFileContents(prefix+"enigcmd.txt", command.replace(/\\\\/g, "\\")+"\n"); WriteFileContents(prefix+"enigenv.txt", envList.join(",")+"\n"); DEBUG_LOG("enigmail.js: Enigmail.execCmd: copied command line/env/input to files "+prefix+"enigcmd.txt/enigenv.txt/eniginp.txt\n"); } var outObj = new Object(); var errObj = new Object(); var outLenObj = new Object(); var errLenObj = new Object(); CONSOLE_LOG("\nenigmail> "+command.replace(/\\\\/g, "\\")+"\n"); try { var useShell = false; exitCodeObj.value = gEnigmailSvc.ipcService.execPipe(command, useShell, preInput, input, input.length, envList, envList.length, outObj, outLenObj, errObj, errLenObj); } catch (ex) { exitCodeObj.value = -1; } var outputData = ""; var errOutput = ""; if (outObj.value) outputData = outObj.value; if (errObj.value) errOutput = errObj.value; if (prefix && (gLogLevel >= 4)) { WriteFileContents(prefix+"enigout.txt", outputData); WriteFileContents(prefix+"enigerr.txt", errOutput); DEBUG_LOG("enigmail.js: Enigmail.execCmd: copied command out/err data to files "+prefix+"enigout.txt/enigerr.txt\n"); } DEBUG_LOG("enigmail.js: Enigmail.execCmd: exitCode = "+exitCodeObj.value+"\n"); DEBUG_LOG("enigmail.js: Enigmail.execCmd: errOutput = "+errOutput+"\n"); /* var errLines = errOutput.split(/\r?\n/); // Discard last null string, if any if ((errLines.length > 1) && !errLines[errLines.length-1]) errLines.pop(); var errArray = new Array(); var statusArray = new Array(); var statusPat = /^\[GNUPG:\] /; var statusFlags = 0; for (var j=0; j 1)) { var flag = gStatusFlags[matches[1]]; if (flag == nsIEnigmail.NODATA) { // Recognize only "NODATA 1" if (statusLine.search(/NODATA 1\b/) < 0) flag = 0; } if (flag) statusFlags |= flag; //DEBUG_LOG("enigmail.js: Enigmail.execCmd: status match "+matches[1]+"\n"); } } else { errArray.push(errLines[j]); } } statusFlagsObj.value = statusFlags; statusMsgObj.value = statusArray.join("\n"); errorMsgObj.value = errArray.join("\n"); */ errorMsgObj.value = this.parseErrorOutput(errOutput, statusFlagsObj, statusMsgObj); exitCodeObj.value = this.fixExitCode(exitCodeObj.value, statusFlagsObj.value); CONSOLE_LOG(errorMsgObj.value+"\n"); //DEBUG_LOG("enigmail.js: Enigmail.execCmd: statusFlags = "+bytesToHex(pack(statusFlagsObj.value,4))+"\n"); //DEBUG_LOG("enigmail.js: Enigmail.execCmd: statusMsg = "+statusMsgObj.value+"\n"); this.stillActive(); return outputData; } Enigmail.prototype.execStart = function (command, needPassphrase, domWindow, prompter, listener, noProxy, statusFlagsObj) { WRITE_LOG("enigmail.js: Enigmail.execStart: command = "+command+", needPassphrase="+needPassphrase+", domWindow="+domWindow+", prompter="+prompter+", listener="+listener+", noProxy="+noProxy+"\n"); statusFlagsObj.value = 0; var envList = []; envList = envList.concat(gEnvList); var passphrase = null; var useAgentObj = {value: false}; if (needPassphrase) { command += this.passwdCommand(); var passwdObj = new Object(); if (!GetPassphrase(domWindow, passwdObj, useAgentObj, this.agentVersion)) { ERROR_LOG("enigmail.js: Enigmail.execStart: Error - no passphrase supplied\n"); statusFlagsObj.value |= nsIEnigmail.MISSING_PASSPHRASE; return null; } passphrase = passwdObj.value; } var prefix = this.getLogDirectoryPrefix(); if (prefix && (gLogLevel >= 4)) { WriteFileContents(prefix+"enigcmd.txt", command.replace(/\\\\/g, "\\")+"\n"); WriteFileContents(prefix+"enigenv.txt", envList.join(",")+"\n"); DEBUG_LOG("enigmail.js: Enigmail.execStart: copied command line/env to files "+prefix+"enigcmd.txt/enigenv.txt\n"); } CONSOLE_LOG("\nenigmail> "+command.replace(/\\\\/g, "\\")+"\n"); var pipetrans = Components.classes[NS_PIPETRANSPORT_CONTRACTID].createInstance(); pipetrans = pipetrans.QueryInterface(Components.interfaces.nsIPipeTransport); DEBUG_LOG("enigmail.js: Enigmail.execStart: pipetrans = " + pipetrans + "\n"); try { var ipcBuffer = Components.classes[NS_IPCBUFFER_CONTRACTID].createInstance(Components.interfaces.nsIIPCBuffer); ipcBuffer.open(ERROR_BUFFER_SIZE, false); var mergeStderr = false; pipetrans.initCommand(command, envList, envList.length, 0, "", noProxy, mergeStderr, ipcBuffer); if (listener) { pipetrans.asyncRead(listener, null, 0, -1, 0); } if (needPassphrase && ! useAgentObj.value) { // Write to child STDIN // (ignore errors, because child may have exited already, closing STDIN) try { if (passphrase) { pipetrans.writeSync(passphrase, passphrase.length); } pipetrans.writeSync("\n", 1); } catch (ex) {} } return pipetrans; } catch (ex) { CONSOLE_LOG("enigmail.js: Enigmail.execStart: Error - Failed to start PipeTransport\n"); return null; } } Enigmail.prototype.parseErrorOutput = function (errOutput, statusFlagsObj, statusMsgObj) { WRITE_LOG("enigmail.js: Enigmail.parseErrorOutput:\n"); var errLines = errOutput.split(/\r?\n/); // Discard last null string, if any if ((errLines.length > 1) && !errLines[errLines.length-1]) errLines.pop(); var errArray = new Array(); var statusArray = new Array(); var errCode = 0; var statusPat = /^\[GNUPG:\] /; var statusFlags = 0; for (var j=0; j 1)) { var flag = gStatusFlags[matches[1]]; if (flag == nsIEnigmail.NODATA) { // Recognize only "NODATA 1" if (statusLine.search(/NODATA 1\b/) < 0) flag = 0; } else if (flag == nsIEnigmail.NO_SC_AVAILABLE) { var a = statusLine.split(/ +/); errCode = Number(a[1]); } if (flag) statusFlags |= flag; //DEBUG_LOG("enigmail.js: Enigmail.parseErrorOutput: status match '+matches[1]+"\n"); } } else { errArray.push(errLines[j]); } } statusFlagsObj.value = statusFlags; statusMsgObj.value = statusArray.join("\n"); var errorMsg = errArray.join("\n"); if ((statusFlags & nsIEnigmail.NO_SC_AVAILABLE) && errCode >0) { switch (errCode) { case 4: errorMsg = EnigGetString("sc.noCardAvailable"); break; case 5: errorMsg = EnigGetString("sc.noReaderAvailable"); break; } } DEBUG_LOG("enigmail.js: Enigmail.parseErrorOutput: statusFlags = "+bytesToHex(pack(statusFlags,4))+"\n"); //DEBUG_LOG("enigmail.js: Enigmail.parseErrorOutput: statusMsg = "+statusMsgObj.value+"\n"); return errorMsg; } Enigmail.prototype.execEnd = function (pipeTransport, statusFlagsObj, statusMsgObj, cmdLineObj, errorMsgObj) { WRITE_LOG("enigmail.js: Enigmail.execEnd: \n"); // Extract command line try { var request = pipeTransport.QueryInterface(Components.interfaces.nsIRequest); cmdLineObj.value = request.name; } catch (ex) { cmdLineObj.value = "unknown-command"; } // Extract exit code and error output from pipeTransport var exitCode = pipeTransport.exitCode(); var errListener = pipeTransport.console; var errOutput = errListener.getData(); // Terminate pipeTransport errListener.shutdown(); pipeTransport.terminate(); var prefix = this.getLogDirectoryPrefix(); if (prefix && (gLogLevel >= 4)) { WriteFileContents(prefix+"enigerr.txt", errOutput); DEBUG_LOG("enigmail.js: Enigmail.execEnd: copied command err output to file "+prefix+"enigerr.txt\n"); } DEBUG_LOG("enigmail.js: Enigmail.execEnd: exitCode = "+exitCode+"\n"); DEBUG_LOG("enigmail.js: Enigmail.execEnd: errOutput = "+errOutput+"\n"); /* var errLines = errOutput.split(/\r?\n/); // Discard last null string, if any if ((errLines.length > 1) && !errLines[errLines.length-1]) errLines.pop(); var errArray = new Array(); var statusArray = new Array(); var statusPat = /^\[GNUPG:\] /; var statusFlags = 0; for (var j=0; j 1)) { var flag = gStatusFlags[matches[1]]; if (flag == nsIEnigmail.NODATA) { // Recognize only "NODATA 1" if (statusLine.search(/NODATA 1\b/) < 0) flag = 0; } if (flag) statusFlags |= flag; //DEBUG_LOG("enigmail.js: Enigmail.execEnd: status match '+matches[1]+"\n"); } } else { errArray.push(errLines[j]); } } statusFlagsObj.value = statusFlags; statusMsgObj.value = statusArray.join("\n"); errorMsgObj.value = errArray.join("\n"); if (statusFlags & nsIEnigmail.NO_SC_AVAILABLE) { errorMsgObj.value = EnigGetString("noCardAvailable"); } */ errorMsgObj.value = this.parseErrorOutput(errOutput, statusFlagsObj, statusMsgObj); if (errOutput.search(/jpeg image of size \d+/)>-1) { statusFlags |= nsIEnigmail.PHOTO_AVAILABLE; } CONSOLE_LOG(errorMsgObj.value+"\n"); //DEBUG_LOG("enigmail.js: Enigmail.execEnd: statusFlags = "+bytesToHex(pack(statusFlags,4))+"\n"); //DEBUG_LOG("enigmail.js: Enigmail.execEnd: statusMsg = "+statusMsgObj.value+"\n"); this.stillActive(); return exitCode; } // Remove all quoted strings (and angle brackets) from a list of email // addresses, returning a list of pure email address function EnigStripEmail(mailAddrs) { var qStart, qEnd; while ((qStart = mailAddrs.indexOf('"')) != -1) { qEnd = mailAddrs.indexOf('"', qStart+1); if (qEnd == -1) { ERROR_LOG("enigmail.js: EnigStripEmail: Unmatched quote in mail address: "+mailAddrs+"\n"); mailAddrs=mailAddrs.replace(/\"/g, ""); break; } mailAddrs = mailAddrs.substring(0,qStart) + mailAddrs.substring(qEnd+1); } // Eliminate all whitespace, just to be safe mailAddrs = mailAddrs.replace(/\s+/g,""); // Extract pure e-mail address list (stripping out angle brackets) mailAddrs = mailAddrs.replace(/(^|,)[^,]*<([^>]+)>[^,]*/g,"$1$2"); return mailAddrs; } Enigmail.prototype.stripWhitespace = function(sendFlags) { var stripThem=false; if ((sendFlags & nsIEnigmail.SEND_SIGNED) && (!(sendFlags & nsIEnigmail.SEND_ENCRYPTED))) { if (this.agentVersion >= "1.4.0" && this.agentVersion < "1.4.1") { stripThem = true; } } return stripThem; } Enigmail.prototype.encryptMessage = function (parent, uiFlags, plainText, fromMailAddr, toMailAddr, sendFlags, exitCodeObj, statusFlagsObj, errorMsgObj) { DEBUG_LOG("enigmail.js: Enigmail.encryptMessage: "+plainText.length+" bytes from "+fromMailAddr+" to "+toMailAddr+" ("+sendFlags+")\n"); exitCodeObj.value = -1; statusFlagsObj.value = 0; errorMsgObj.value = ""; var hashAlgo = gMimeHashAlgorithms[this.prefBranch.getIntPref("mimeHashAlgorithm")]; if (!plainText) { DEBUG_LOG("enigmail.js: Enigmail.encryptMessage: NO ENCRYPTION!\n"); exitCodeObj.value = 0; return plainText; } if (!this.initialized) { errorMsgObj.value = EnigGetString("notInit"); return ""; } var defaultSend = sendFlags & nsIEnigmail.SEND_DEFAULT; var signMsg = sendFlags & nsIEnigmail.SEND_SIGNED; var encryptMsg = sendFlags & nsIEnigmail.SEND_ENCRYPTED; if (encryptMsg) { // First convert all linebreaks to newlines plainText = plainText.replace(/\r\n/g, "\n"); plainText = plainText.replace(/\r/g, "\n"); // Using platform-specific linebreaks confuses some windows mail clients, // so we convert everything to windows like good old PGP worked anyway. plainText = plainText.replace(/\n/g, "\r\n"); } var noProxy = true; var startErrorMsgObj = new Object(); var ipcBuffer = Components.classes[NS_IPCBUFFER_CONTRACTID].createInstance(Components.interfaces.nsIIPCBuffer); var bufferSize = ((plainText.length + 20000)/1024).toFixed(0)*1024; if (MSG_BUFFER_SIZE > bufferSize) bufferSize=MSG_BUFFER_SIZE; ipcBuffer.open(bufferSize, false); var pipeTrans = this.encryptMessageStart(parent, null, uiFlags, fromMailAddr, toMailAddr, hashAlgo, sendFlags, ipcBuffer, noProxy, startErrorMsgObj); if (!pipeTrans) { errorMsgObj.value = startErrorMsgObj.value; return ""; } // Write to child STDIN // (ignore errors, because child may have exited already, closing STDIN) try { pipeTrans.writeSync(plainText, plainText.length); } catch (ex) {} // Wait for child STDOUT to close pipeTrans.join(); var cipherText = ipcBuffer.getData(); ipcBuffer.shutdown(); var exitCode = this.encryptMessageEnd(parent, null, uiFlags, sendFlags, plainText.length, pipeTrans, statusFlagsObj, errorMsgObj); exitCodeObj.value = exitCode; if ((exitCodeObj.value == 0) && !cipherText) exitCodeObj.value = -1; if (exitCodeObj.value == 0) { // Normal return return cipherText; } // Error processing ERROR_LOG("enigmail.js: Enigmail.encryptMessage: Error in command execution\n"); return ""; } Enigmail.prototype.encryptMessageEnd = function (parent, prompter, uiFlags, sendFlags, outputLen, pipeTransport, statusFlagsObj, errorMsgObj) { DEBUG_LOG("enigmail.js: Enigmail.encryptMessageEnd: uiFlags="+uiFlags+", sendFlags="+bytesToHex(pack(sendFlags,4))+", outputLen="+outputLen+", pipeTransport="+pipeTransport+"\n"); var pgpMime = uiFlags & nsIEnigmail.UI_PGP_MIME; statusFlagsObj.value = 0; errorMsgObj.value = ""; if (!this.initialized) { errorMsgObj.value = EnigGetString("notInit"); return -1; } // Terminate job and parse error output var statusMsgObj = new Object(); var cmdLineObj = new Object(); var cmdErrorMsgObj = new Object(); var exitCode = this.execEnd(pipeTransport, statusFlagsObj, statusMsgObj, cmdLineObj, cmdErrorMsgObj); var statusMsg = statusMsgObj.value; exitCode = this.fixExitCode(exitCode, statusFlagsObj.value); if ((exitCode == 0) && !outputLen) { exitCode = -1; } if (exitCode == 0) { // Normal return errorMsgObj.value = cmdErrorMsgObj.value; return 0; } // Error processing ERROR_LOG("enigmail.js: Enigmail.encryptMessageEnd: Error in command execution\n"); var defaultSend = sendFlags & nsIEnigmail.SEND_DEFAULT; var signMsg = sendFlags & nsIEnigmail.SEND_SIGNED; var encryptMsg = sendFlags & nsIEnigmail.SEND_ENCRYPTED; if ( (statusFlagsObj.value & nsIEnigmail.BAD_PASSPHRASE) || ((this.agentType == "pgp") && signMsg && (exitCode != 21)) ) { // "Unremember" passphrase on error return this.clearCachedPassphrase(); } if (statusFlagsObj.value & nsIEnigmail.BAD_PASSPHRASE) { errorMsgObj.value = EnigGetString("badPhrase"); } else if (statusFlagsObj.value & nsIEnigmail.INVALID_RECIPIENT) { errorMsgObj.value = statusMsg; } else { errorMsgObj.value = EnigGetString("badCommand"); } if (cmdErrorMsgObj.value) { errorMsgObj.value += "\n\n" + this.agentType + " "+EnigGetString("cmdLine"); errorMsgObj.value += "\n" + cmdLineObj.value; errorMsgObj.value += "\n" + cmdErrorMsgObj.value; } if (pgpMime && errorMsgObj.value) { if (prompter) prompter.alert(EnigGetString("enigAlert"), errorMsgObj.value); else this.alertMsg(parent, errorMsgObj.value); } return exitCode; } var gPGPHashNum = {md5:1, sha1:2, ripemd160:3, sha256:4, sha384:5, sha512:6}; Enigmail.prototype.getEncryptCommand = function (fromMailAddr, toMailAddr, hashAlgorithm, sendFlags, isAscii, errorMsgObj) { try { fromMailAddr = EnigStripEmail(fromMailAddr); toMailAddr = EnigStripEmail(toMailAddr); } catch (ex) { errorMsgObj.value = EnigGetString("invalidEmail"); return null; } var defaultSend = sendFlags & nsIEnigmail.SEND_DEFAULT; var signMsg = sendFlags & nsIEnigmail.SEND_SIGNED; var encryptMsg = sendFlags & nsIEnigmail.SEND_ENCRYPTED; var usePgpMime = sendFlags & nsIEnigmail.SEND_PGP_MIME; var useDefaultComment = false; try { useDefaultComment = this.prefBranch.getBoolPref("useDefaultComment") } catch(ex) { } var hushMailSupport = false; try { hushMailSupport = this.prefBranch.getBoolPref("hushMailSupport") } catch(ex) { } var detachedSig = usePgpMime && signMsg && !encryptMsg; var toAddrList = toMailAddr.split(/\s*,\s*/); var k; var encryptCommand = this.getAgentPath(); encryptCommand += GPG_BATCH_OPTS; if (!useDefaultComment) encryptCommand += " --comment "+this.quoteSign+GPG_COMMENT_OPT.replace(/\%s/, this.vendor)+this.quoteSign; /* if (usePgpMime && (! encryptMsg)) { if (this.agentVersion >= "1.4.1") { //encryptCommand += " --rfc2440-dshaw" } } */ var angledFromMailAddr = ((fromMailAddr.search(/^0x/) == 0) || hushMailSupport) ? fromMailAddr : "<" + fromMailAddr + ">"; angledFromMailAddr = angledFromMailAddr.replace(/([\"\'\`])/g, "\\$1"); if (signMsg && hashAlgorithm) { encryptCommand += " --digest-algo "+hashAlgorithm; } if (encryptMsg) { if (isAscii) encryptCommand += " -a"; encryptCommand += " -e"; if (signMsg) encryptCommand += " -s"; if (sendFlags & nsIEnigmail.SEND_ALWAYS_TRUST) { if (this.agentVersion >= "1.4") { encryptCommand += " --trust-model always" } else { encryptCommand += " --always-trust"; } } if ((sendFlags & nsIEnigmail.SEND_ENCRYPT_TO_SELF) && fromMailAddr) encryptCommand += " --encrypt-to " + angledFromMailAddr; for (k=0; k"; } } else if (detachedSig) { encryptCommand += " -s -b -t"; if (isAscii) encryptCommand += " -a"; } else if (signMsg) { encryptCommand += " --clearsign"; } if (fromMailAddr) { encryptCommand += " -u " + angledFromMailAddr; } return encryptCommand; } Enigmail.prototype.encryptMessageStart = function (parent, prompter, uiFlags, fromMailAddr, toMailAddr, hashAlgorithm, sendFlags, listener, noProxy, errorMsgObj) { DEBUG_LOG("enigmail.js: Enigmail.encryptMessageStart: prompter="+prompter+", uiFlags="+uiFlags+", from "+fromMailAddr+" to "+toMailAddr+", hashAlgorithm="+hashAlgorithm+" ("+bytesToHex(pack(sendFlags,4))+")\n"); var pgpMime = uiFlags & nsIEnigmail.UI_PGP_MIME; if (uiFlags & nsIEnigmail.UI_RESTORE_STRICTLY_MIME) { try { var prefSvc = Components.classes[NS_PREFS_SERVICE_CID] .getService(Components.interfaces.nsIPrefService); var prefRoot = prefSvc.getBranch(null); prefRoot.setBoolPref("mail.strictly_mime", false); DEBUG_LOG("enigmail.js: Enigmail.encryptMessageStart: disabled quoted-printable\n"); } catch (ex) {} } errorMsgObj.value = ""; if (!sendFlags) { DEBUG_LOG("enigmail.js: Enigmail.encryptMessageStart: NO ENCRYPTION!\n"); errorMsgObj.value = EnigGetString("notRequired"); return null; } if (!this.initialized) { errorMsgObj.value = EnigGetString("notInit"); return null; } if (this.keygenProcess) { errorMsgObj.value = EnigGetString("notComplete"); return null; } var encryptCommand = this.getEncryptCommand(fromMailAddr, toMailAddr, hashAlgorithm, sendFlags, true, errorMsgObj); if (! encryptCommand) return null; var signMsg = sendFlags & nsIEnigmail.SEND_SIGNED; var statusFlagsObj = new Object(); var pipetrans = this.execStart(encryptCommand, signMsg, parent, prompter, listener, noProxy, statusFlagsObj); if (statusFlagsObj.value & nsIEnigmail.MISSING_PASSPHRASE) { ERROR_LOG("enigmail.js: Enigmail.encryptMessageStart: Error - no passphrase supplied\n"); errorMsgObj.value = EnigGetString("noPassphrase"); } if (pgpMime && errorMsgObj.value) { if (prompter) prompter.alert(EnigGetString("enigAlert"), errorMsgObj.value); else this.alertMsg(parent, errorMsgObj.value); } return pipetrans; } // Locates STRing in TEXT occurring only at the beginning of a line function IndexOfArmorDelimiter(text, str, offset) { //DEBUG_LOG("enigmail.js: IndexOfArmorDelimiter: "+str+", "+offset+"\n"); while (offset < text.length) { var loc = text.indexOf(str, offset); if ((loc < 1) || (text.charAt(loc-1) == "\n")) return loc; offset = loc + str.length; } return -1; } // Locates offsets bracketing PGP armored block in text, // starting from given offset, and returns block type string. // beginIndex = offset of first character of block // endIndex = offset of last character of block (newline) // If block is not found, the null string is returned; Enigmail.prototype.locateArmoredBlock = function (text, offset, indentStr, beginIndexObj, endIndexObj, indentStrObj) { DEBUG_LOG("enigmail.js: Enigmail.locateArmoredBlock: "+offset+", '"+indentStr+"'\n"); beginIndexObj.value = -1; endIndexObj.value = -1; var beginIndex = IndexOfArmorDelimiter(text, indentStr+"-----BEGIN PGP ", offset); if (beginIndex == -1) { var blockStart=text.indexOf("-----BEGIN PGP ") if (blockStart>=0) { var indentStart=text.search(/\n.*\-\-\-\-\-BEGIN PGP /)+1; indentStrObj.value=text.substring(indentStart, blockStart); indentStr=indentStrObj.value; beginIndex = IndexOfArmorDelimiter(text, indentStr+"-----BEGIN PGP ", offset); } } if (beginIndex == -1) return ""; // Locate newline at end of armor header offset = text.indexOf("\n", beginIndex); if (offset == -1) return ""; var endIndex = IndexOfArmorDelimiter(text, indentStr+"-----END PGP ", offset); if (endIndex == -1) return ""; // Locate newline at end of PGP block endIndex = text.indexOf("\n", endIndex); if (endIndex == -1) { // No terminating newline endIndex = text.length - 1; } var blockHeader = text.substr(beginIndex, offset-beginIndex+1); var blockRegex = new RegExp("^" + indentStr + "-----BEGIN PGP (.*)-----\\s*\\r?\\n"); var matches = blockHeader.match(blockRegex); var blockType = ""; if (matches && (matches.length > 1)) { blockType = matches[1]; DEBUG_LOG("enigmail.js: Enigmail.locateArmoredBlock: blockType="+blockType+"\n"); } if (blockType == "UNVERIFIED MESSAGE") { // Skip any unverified message block return this.locateArmoredBlock(text, endIndex+1, indentStr, beginIndexObj, endIndexObj, indentStrObj); } beginIndexObj.value = beginIndex; endIndexObj.value = endIndex; return blockType; } Enigmail.prototype.extractSignaturePart = function (signatureBlock, part) { DEBUG_LOG("enigmail.js: Enigmail.extractSignaturePart: part="+part+"\n"); // Search for blank line var offset = signatureBlock.search(/\n\s*\r?\n/); if (offset == -1) return ""; offset = signatureBlock.indexOf("\n", offset+1); if (offset == -1) return ""; var beginIndex = signatureBlock.indexOf("-----BEGIN PGP SIGNATURE-----", offset+1); if (beginIndex == -1) return ""; if (part == nsIEnigmail.SIGNATURE_TEXT) { var signedText = signatureBlock.substr(offset+1, beginIndex-offset-1); // Unescape leading dashes signedText = signedText.replace(/^- -/, "-"); signedText = signedText.replace(/\n- -/g, "\n-"); signedText = signedText.replace(/\r- -/g, "\r-"); return signedText; } // Locate newline at end of armor header offset = signatureBlock.indexOf("\n", beginIndex); if (offset == -1) return ""; var endIndex = signatureBlock.indexOf("-----END PGP SIGNATURE-----", offset); if (endIndex == -1) return ""; var signBlock = signatureBlock.substr(offset, endIndex-offset); // Search for blank line var armorIndex = signBlock.search(/\n\s*\r?\n/); if (armorIndex == -1) return ""; if (part == nsIEnigmail.SIGNATURE_HEADERS) { return signBlock.substr(1, armorIndex); } armorIndex = signBlock.indexOf("\n", armorIndex+1); if (armorIndex == -1) return ""; if (part == nsIEnigmail.SIGNATURE_ARMOR) { var armorData = signBlock.substr(armorIndex, endIndex-armorIndex); armorData = armorData.replace(/\s*/g, ""); return armorData; } return ""; } Enigmail.prototype.decryptMessage = function (parent, uiFlags, cipherText, signatureObj, exitCodeObj, statusFlagsObj, keyIdObj, userIdObj, sigDetailsObj, errorMsgObj) { DEBUG_LOG("enigmail.js: Enigmail.decryptMessage: "+cipherText.length+" bytes, "+uiFlags+"\n"); if (! cipherText) return ""; var interactive = uiFlags & nsIEnigmail.UI_INTERACTIVE; var allowImport = uiFlags & nsIEnigmail.UI_ALLOW_KEY_IMPORT; var unverifiedEncryptedOK = uiFlags & nsIEnigmail.UI_UNVERIFIED_ENC_OK; var oldSignature = signatureObj.value; DEBUG_LOG("enigmail.js: Enigmail.decryptMessage: oldSignature="+oldSignature+"\n"); signatureObj.value = ""; exitCodeObj.value = -1; statusFlagsObj.value = 0; keyIdObj.value = ""; userIdObj.value = ""; errorMsgObj.value = ""; var beginIndexObj = new Object(); var endIndexObj = new Object(); var indentStrObj = new Object(); var blockType = this.locateArmoredBlock(cipherText, 0, "", beginIndexObj, endIndexObj, indentStrObj); if (!blockType || blockType == "SIGNATURE") { errorMsgObj.value = EnigGetString("noPGPblock"); statusFlagsObj.value |= nsIEnigmail.DISPLAY_MESSAGE; return ""; } var publicKey = (blockType == "PUBLIC KEY BLOCK"); var verifyOnly = (blockType == "SIGNED MESSAGE"); var pgpBlock = cipherText.substr(beginIndexObj.value, endIndexObj.value - beginIndexObj.value + 1); if (indentStrObj.value) { RegExp.multiline = true; var indentRegexp = new RegExp("^"+indentStrObj.value, "g"); pgpBlock = pgpBlock.replace(indentRegexp, ""); RegExp.multiline = false; } var head = cipherText.substr(0, beginIndexObj.value); var tail = cipherText.substr(endIndexObj.value+1, cipherText.length - endIndexObj.value - 1); if (publicKey) { if (!allowImport) { errorMsgObj.value = EnigGetString("decryptToImport"); statusFlagsObj.value |= nsIEnigmail.DISPLAY_MESSAGE; statusFlagsObj.value |= nsIEnigmail.INLINE_KEY; return ""; } // Import public key var importFlags = nsIEnigmail.UI_INTERACTIVE; exitCodeObj.value = this.importKey(parent, importFlags, pgpBlock, "", errorMsgObj); if (exitCodeObj.value == 0) { statusFlagsObj.value |= nsIEnigmail.IMPORTED_KEY; } return ""; } var newSignature = ""; if (verifyOnly) { newSignature = this.extractSignaturePart(pgpBlock, nsIEnigmail.SIGNATURE_ARMOR); if (oldSignature && (newSignature != oldSignature)) { ERROR_LOG("enigmail.js: Enigmail.decryptMessage: Error - signature mismatch "+newSignature+"\n"); errorMsgObj.value = EnigGetString("sigMismatch"); statusFlagsObj.value |= nsIEnigmail.DISPLAY_MESSAGE; return ""; } } var noOutput = false; var noProxy = true; var startErrorMsgObj = new Object(); var readBytes = MSG_BUFFER_SIZE; if (verifyOnly && pgpBlock.length > MSG_BUFFER_SIZE) { readBytes = ((pgpBlock.length+1500)/1024).toFixed(0)*1024; } if (readBytes > MAX_MSG_BUFFER_SIZE) { errorMsgObj.value = EnigGetString("messageSizeError"); statusFlagsObj.value |= nsIEnigmail.OVERFLOWED; exitCodeObj.value = 1; return ""; } const maxTries = 2; var tryCount = 0; while (tryCount < maxTries) { tryCount++; var ipcBuffer = Components.classes[NS_IPCBUFFER_CONTRACTID].createInstance(Components.interfaces.nsIIPCBuffer); ipcBuffer.open(readBytes, false); var pipeTrans = this.decryptMessageStart(parent, null, verifyOnly, noOutput, ipcBuffer, noProxy, startErrorMsgObj); if (!pipeTrans) { errorMsgObj.value = startErrorMsgObj.value; statusFlagsObj.value |= nsIEnigmail.DISPLAY_MESSAGE; return ""; } // Write to child STDIN // (ignore errors, because child may have exited already, closing STDIN) try { pipeTrans.writeSync(pgpBlock, pgpBlock.length); } catch (ex) {} // Wait for child STDOUT to close pipeTrans.join(); var overflowed = ipcBuffer.overflowed; var plainText = ipcBuffer.getData(); if (ipcBuffer.overflowed && plainText.length < ipcBuffer.totalBytes) { readBytes = ((ipcBuffer.totalBytes+1500)/1024).toFixed(0)*1024; WRITE_LOG("enigmail.js: Enigmail.decryptMessage: decrypted text too big for standard buffer, retrying with buffer size="+readBytes+"\n"); } else { tryCount = maxTries; } ipcBuffer.shutdown(); ipcBuffer = null; // make sure the object gets freed var exitCode = this.decryptMessageEnd(uiFlags, plainText.length, pipeTrans, verifyOnly, noOutput, statusFlagsObj, keyIdObj, userIdObj, sigDetailsObj, errorMsgObj); exitCodeObj.value = exitCode; } if ((head.search(/\S/) >= 0) || (tail.search(/\S/) >= 0)) { statusFlagsObj.value |= nsIEnigmail.PARTIALLY_PGP; } if (exitCodeObj.value == 0) { // Normal return var doubleDashSeparator = false; try { doubleDashSeparator = this.prefBranch.getBoolPref("doubleDashSeparator") } catch(ex) { } if (doubleDashSeparator && (plainText.search(/(\r|\n)-- +(\r|\n)/) < 0) ) { // Workaround for MsgCompose stripping trailing spaces from sig separator plainText = plainText.replace(/(\r|\n)--(\r|\n)/, "$1-- $2"); } statusFlagsObj.value |= nsIEnigmail.DISPLAY_MESSAGE; if (verifyOnly && indentStrObj.value) { RegExp.multiline = true; plainText = plainText.replace(/^/g, indentStrObj.value) RegExp.multiline = false; } return plainText; } var pubKeyId = keyIdObj.value; if (statusFlagsObj.value & nsIEnigmail.BAD_SIGNATURE) { if (verifyOnly && indentStrObj.value) { // Probably replied message that could not be verified errorMsgObj.value = EnigGetString("unverifiedReply")+"\n\n"+errorMsgObj.value; return ""; } // Return bad signature (for checking later) signatureObj.value = newSignature; } else if (pubKeyId && (statusFlagsObj.value & nsIEnigmail.UNVERIFIED_SIGNATURE)) { var innerKeyBlock; if (verifyOnly) { // Search for indented public key block in signed message var innerBlockType = this.locateArmoredBlock(pgpBlock, 0, "- ", beginIndexObj, endIndexObj, indentStrObj); if (innerBlockType == "PUBLIC KEY BLOCK") { innerKeyBlock = pgpBlock.substr(beginIndexObj.value, endIndexObj.value - beginIndexObj.value + 1); innerKeyBlock = innerKeyBlock.replace(/- -----/g, "-----"); statusFlagsObj.value |= nsIEnigmail.INLINE_KEY; DEBUG_LOG("enigmail.js: Enigmail.decryptMessage: innerKeyBlock found\n"); } } if (allowImport) { var importedKey = false; if (innerKeyBlock) { var importErrorMsgObj = new Object(); var importFlags2 = nsIEnigmail.UI_INTERACTIVE; var exitStatus = this.importKey(parent, importFlags2, innerKeyBlock, pubKeyId, importErrorMsgObj); importedKey = (exitStatus == 0); if (exitStatus > 0) { this.alertMsg(parent, EnigGetString("cantImport")+importErrorMsgObj.value); } } if (importedKey) { // Recursive call; note that nsIEnigmail.UI_ALLOW_KEY_IMPORT is unset // to break the recursion var uiFlagsDeep = interactive ? nsIEnigmail.UI_INTERACTIVE : 0; signatureObj.value = ""; return this.decryptMessage(parent, uiFlagsDeep, pgpBlock, signatureObj, exitCodeObj, statusFlagsObj, keyIdObj, userIdObj, sigDetailsObj, errorMsgObj); } } if (plainText && !unverifiedEncryptedOK) { // Append original PGP block to unverified message plainText = "-----BEGIN PGP UNVERIFIED MESSAGE-----\r\n" + plainText + "-----END PGP UNVERIFIED MESSAGE-----\r\n\r\n" + pgpBlock; } } return verifyOnly ? "" : plainText; } Enigmail.prototype.decryptMessageStart = function (parent, prompter, verifyOnly, noOutput, listener, noProxy, errorMsgObj) { DEBUG_LOG("enigmail.js: Enigmail.decryptMessageStart: prompter="+prompter+", verifyOnly="+verifyOnly+", noOutput="+noOutput+"\n"); if (!this.initialized) { errorMsgObj.value = EnigGetString("notInit"); return null; } if (this.keygenProcess) { errorMsgObj.value = EnigGetString("notComplete"); return null; } var decryptCommand = this.getAgentPath(); if (this.agentType == "pgp") { decryptCommand += PGP_BATCH_OPTS + " -ft"; } else if (noOutput) { decryptCommand += GPG_BATCH_OPTS + " --verify"; } else { decryptCommand += GPG_BATCH_OPTS + " -d"; } var statusFlagsObj = new Object(); var pipetrans = this.execStart(decryptCommand, !verifyOnly, parent, prompter, listener, noProxy, statusFlagsObj); if (statusFlagsObj.value & nsIEnigmail.MISSING_PASSPHRASE) { ERROR_LOG("enigmail.js: Enigmail.decryptMessageStart: Error - no passphrase supplied\n"); errorMsgObj.value = EnigGetString("noPassphrase"); return null; } return pipetrans; } Enigmail.prototype.decryptMessageEnd = function (uiFlags, outputLen, pipeTransport, verifyOnly, noOutput, statusFlagsObj, keyIdObj, userIdObj, sigDetailsObj, errorMsgObj) { DEBUG_LOG("enigmail.js: Enigmail.decryptMessageEnd: uiFlags="+uiFlags+", outputLen="+outputLen+", pipeTransport="+pipeTransport+", verifyOnly="+verifyOnly+", noOutput="+noOutput+"\n"); var interactive = uiFlags & nsIEnigmail.UI_INTERACTIVE; var pgpMime = uiFlags & nsIEnigmail.UI_PGP_MIME; var allowImport = uiFlags & nsIEnigmail.UI_ALLOW_KEY_IMPORT; var unverifiedEncryptedOK = uiFlags & nsIEnigmail.UI_UNVERIFIED_ENC_OK; statusFlagsObj.value = 0; errorMsgObj.value = ""; if (!this.initialized) { errorMsgObj.value = EnigGetString("notInit"); return -1; } // Terminate job and parse error output var statusMsgObj = new Object(); var cmdLineObj = new Object(); var cmdErrorMsgObj = new Object(); var exitCode = this.execEnd(pipeTransport, statusFlagsObj, statusMsgObj, cmdLineObj, cmdErrorMsgObj); if (pgpMime) { statusFlagsObj.value |= verifyOnly ? nsIEnigmail.PGP_MIME_SIGNED : nsIEnigmail.PGP_MIME_ENCRYPTED; } var statusMsg = statusMsgObj.value; exitCode = this.fixExitCode(exitCode, statusFlagsObj.value); if ((exitCode == 0) && !noOutput && !outputLen) { exitCode = -1; } if (exitCode == 0) { // Normal return var errLines, goodSignPat, badSignPat, keyExpPat; if (statusMsg) { errLines = statusMsg.split(/\r?\n/); goodSignPat = /GOODSIG (\w{16}) (.*)$/i; badSignPat = /BADSIG (\w{16}) (.*)$/i; keyExpPat = /EXPKEYSIG (\w{16}) (.*)$/i revKeyPat = /REVKEYSIG (\w{16}) (.*)$/i; validSigPat = /VALIDSIG (\w+) (.*) (\d+) (.*)/i; } else { errLines = cmdErrorMsgObj.value.split(/\r?\n/); goodSignPat = /Good signature from (user )?"(.*)"\.?/i; badSignPat = /BAD signature from (user )?"(.*)"\.?/i; keyExpPat = /This key has expired/i; revKeyPat = /This key has been revoked/i; validSigPat = /dummy-not-used/i; } errorMsgObj.value = ""; var matches; var signed = false; var goodSignature; var userId = ""; var keyId = ""; var sigDetails = ""; for (j=0; j 2)) { signed = true; goodSignature = false; userId = matches[2]; keyId = matches[1]; break; } matches = errLines[j].match(revKeyPat); if (matches && (matches.length > 2)) { signed = true; goodSignature = true; userId = matches[2]; keyId = matches[1]; break; } matches = errLines[j].match(goodSignPat); if (matches && (matches.length > 2)) { signed = true; goodSignature = true; userId = matches[2]; keyId = matches[1]; break; } matches = errLines[j].match(keyExpPat); if (matches && (matches.length > 2)) { signed = true; goodSignature = true; userId = matches[2]; keyId = matches[1]; break; } } if (goodSignature) { for (var j=0; j 2)) { sigDetails = errLines[j].substr(9); break; } } } try { if (userId && keyId && this.prefBranch.getBoolPref("displaySecondaryUid")) { uids = this.getKeyDetails(keyId, true); if (uids) { userId = uids; } } } catch (ex) {} if (userId) { userId = EnigConvertToUnicode(userId, "UTF-8"); } userIdObj.value = userId; keyIdObj.value = keyId; sigDetailsObj.value = sigDetails; if (signed) { var trustPrefix = ""; if (statusFlagsObj.value & nsIEnigmail.UNTRUSTED_IDENTITY) { trustPrefix += EnigGetString("prefUntrusted")+" "; } if (statusFlagsObj.value & nsIEnigmail.REVOKED_KEY) { trustPrefix += EnigGetString("prefRevoked")+" "; } if (statusFlagsObj.value & nsIEnigmail.EXPIRED_KEY_SIGNATURE) { trustPrefix += EnigGetString("prefExpiredKey")+" "; } else if (statusFlagsObj.value & nsIEnigmail.EXPIRED_SIGNATURE) { trustPrefix += EnigGetString("prefExpired")+" "; } if (goodSignature) { errorMsgObj.value = trustPrefix + EnigGetString("prefGood",userId) /* + ", " + EnigGetString("keyId") + " 0x" + keyId.substring(8,16); */ if (this.agentType != "gpg") { // Trust all good signatures, if not GPG statusFlagsObj.value |= nsIEnigmail.GOOD_SIGNATURE | nsIEnigmail.TRUSTED_IDENTITY; } } else { errorMsgObj.value = trustPrefix + EnigGetString("prefBad",userId) /*+ ", " + EnigGetString("keyId") + " 0x" + keyId.substring(8,16); */ if (!exitCode) exitCode = 1; if (this.agentType != "gpg") statusFlagsObj.value |= nsIEnigmail.BAD_SIGNATURE; } } if (!verifyOnly && (this.agentType != "gpg")) { statusFlagsObj.value |= nsIEnigmail.DECRYPTION_OKAY; } return exitCode; } if ( (statusFlagsObj.value & nsIEnigmail.BAD_PASSPHRASE) || ((this.agentType == "pgp") && !verifyOnly && (exitCode != 30)) ) { // "Unremember" passphrase on decryption failure this.clearCachedPassphrase(); } var pubKeyId; if (statusFlagsObj.value & nsIEnigmail.UNVERIFIED_SIGNATURE) { // Unverified signature var matchb = statusMsg.match(/(^|\n)NO_PUBKEY (\w{8})(\w{8})/); if (matchb && (matchb.length > 3)) { pubKeyId = "0x" + matchb[3]; DEBUG_LOG("enigmail.js: Enigmail.decryptMessageEnd: NO_PUBKEY "+pubKeyId+"\n"); keyIdObj.value = matchb[2]+matchb[3]; } if (statusFlagsObj.value & nsIEnigmail.DECRYPTION_OKAY) { exitCode=0; } } if (this.agentType != "gpg") { // Not GPG if (verifyOnly) { // Assume bad signature is reason for failure statusFlagsObj.value |= nsIEnigmail.BAD_SIGNATURE; } else { statusFlagsObj.value |= outputLen ? nsIEnigmail.DECRYPTION_OKAY : nsIEnigmail.DECRYPTION_FAILED; } } if (exitCode != 0) { // Error processing ERROR_LOG("enigmail.js: Enigmail.decryptMessageEnd: Error in command execution\n"); } if (cmdErrorMsgObj.value) { errorMsgObj.value = this.agentType + " " + EnigGetString("cmdLine"); errorMsgObj.value += "\n" + cmdLineObj.value; errorMsgObj.value += "\n" + cmdErrorMsgObj.value; } return exitCode; } // ExitCode == 0 => success // ExitCode > 0 => error // ExitCode == -1 => Cancelled by user Enigmail.prototype.receiveKey = function (recvFlags, keyserver, keyId, requestObserver, errorMsgObj) { DEBUG_LOG("enigmail.js: Enigmail.receiveKey: "+keyId+"\n"); if (!this.initialized) { errorMsgObj.value = EnigGetString("notInit"); return null; } if (this.agentType != "gpg") { errorMsgObj.value = EnigGetString("failOnlyGPG"); return null; } if (!keyserver) { errorMsgObj.value = EnigGetString("failNoServer"); return null; } if (!keyId && ! (recvFlags & nsIEnigmail.REFRESH_KEY)) { errorMsgObj.value = EnigGetString("failNoID"); return null; } var envList = []; envList = envList.concat(gEnvList); var proxyHost = null; try { if (this.prefBranch.getBoolPref("respectHttpProxy")) { // determine proxy host var prefsSvc = Components.classes[NS_PREFS_SERVICE_CID].getService(Components.interfaces.nsIPrefService); var prefRoot = prefsSvc.getBranch(null); var useProxy = prefRoot.getIntPref("network.proxy.type"); if (useProxy==1) { var proxyHostName = prefRoot.getCharPref("network.proxy.http"); var proxyHostPort = prefRoot.getIntPref("network.proxy.http_port"); var noProxy = prefRoot.getCharPref("network.proxy.no_proxies_on").split(/[ ,]/); for (var i=0; i=0) { i=noProxy.length+1; proxyHostName=null; } } if (proxyHostName && proxyHostPort) { proxyHost="http://"+proxyHostName+":"+proxyHostPort } } } } catch (ex) {} var command = this.getAgentPath(); if (! (recvFlags & nsIEnigmail.SEARCH_KEY)) command += GPG_BATCH_OPTS; if (proxyHost) { command += " --keyserver-options honor-http-proxy"; envList.push("http_proxy="+proxyHost); } command += " --keyserver " + keyserver; if (recvFlags & nsIEnigmail.DOWNLOAD_KEY) { command += " --recv-keys " + keyId; } else if (recvFlags & nsIEnigmail.SEARCH_KEY) { command += " --search-keys " + keyId; } else if (recvFlags & nsIEnigmail.UPLOAD_KEY) { command += " --send-keys " + keyId; } else if (recvFlags & nsIEnigmail.REFRESH_KEY) { command += " --refresh-keys"; } var exitCodeObj = new Object(); var statusFlagsObj = new Object(); var statusMsgObj = new Object(); var cmdLineObj = new Object(); CONSOLE_LOG("enigmail> "+command.replace(/\\\\/g, "\\")+"\n"); var pipeConsole = Components.classes[NS_PIPECONSOLE_CONTRACTID].createInstance(Components.interfaces.nsIPipeConsole); // Create joinable console pipeConsole.open(20, 80, true); var ipcRequest = null; try { ipcRequest = gEnigmailSvc.ipcService.execAsync(command, false, "", "", 0, envList, envList.length, pipeConsole, pipeConsole, requestObserver); } catch (ex) { ERROR_LOG("enigmail.js: Enigmail.receiveKey: execAsync failed\n"); } if (!ipcRequest) { ERROR_LOG("enigmail.js: Enigmail.receiveKey: execAsync failed somehow\n"); return null; } return ipcRequest; } Enigmail.prototype.searchKey = function (recvFlags, protocol, keyserver, port, keyValue, requestObserver, errorMsgObj) { DEBUG_LOG("enigmail.js: Enigmail.searchKey: "+keyValue+"\n"); if (!this.initialized) { errorMsgObj.value = EnigGetString("notInit"); return null; } if (this.agentType != "gpg") { errorMsgObj.value = EnigGetString("failOnlyGPG"); return null; } if (!keyserver) { errorMsgObj.value = EnigGetString("failNoServer"); return null; } if (!keyValue) { errorMsgObj.value = EnigGetString("failNoID"); return null; } var envList = []; envList = envList.concat(gEnvList); var proxyHost = null; if (protocol=="hkp") { try { if (this.prefBranch.getBoolPref("respectHttpProxy")) { // determine proxy host var prefsSvc = Components.classes[NS_PREFS_SERVICE_CID].getService(Components.interfaces.nsIPrefService); var prefRoot = prefsSvc.getBranch(null); var useProxy = prefRoot.getIntPref("network.proxy.type"); if (useProxy==1) { var proxyHostName = prefRoot.getCharPref("network.proxy.http"); var proxyHostPort = prefRoot.getIntPref("network.proxy.http_port"); var noProxy = prefRoot.getCharPref("network.proxy.no_proxies_on").split(/[ ,]/); for (var i=0; i=0) { i=noProxy.length+1; proxyHostName=null; } } if (proxyHostName && proxyHostPort) { proxyHost="http://"+proxyHostName+":"+proxyHostPort } } } } catch (ex) {} } var baseCommand = "gpgkeys_" + protocol; if (this.isDosLike) { baseCommand+=".exe"; } var baseDir = Components.classes[NS_LOCAL_FILE_CONTRACTID].createInstance(nsILocalFile); baseDir.initWithPath(this.agentPath); var command = null; // try to locate gpgkeys_* if (baseDir) baseDir = baseDir.parent; if (baseDir) { var theCommand=baseDir.clone(); // first the same dir as gpg executable theCommand.append(baseCommand); if (theCommand.exists() && theCommand.isExecutable()) command = theCommand.path; if (! command) { // then lib theCommand.append("lib"); theCommand.append(baseCommand); if (theCommand.exists() && theCommand.isExecutable()) command = theCommand.path; } if (!command) { if (baseDir.parent) { baseDir=baseDir.parent; theCommand=baseDir.clone(); // then ..\lib\gnupg or ../lib/gnupg theCommand.append("lib"); theCommand.append("gnupg"); theCommand.append(baseCommand); if (theCommand.exists() && theCommand.isExecutable()) { command = theCommand.path; } else { theCommand=baseDir.clone(); // then ..\libexec\gnupg or ../libexec/gnupg theCommand.append("libexec"); theCommand.append("gnupg"); theCommand.append(baseCommand); if (theCommand.exists() && theCommand.isExecutable()) command = theCommand.path; } } } } if (! command) { // no gpgkeys_* found return null; } command=command.replace(/\\\\/g, "\\").replace(/\\/g, "\\\\"); // call gpgkeys to check the version number var outObj = new Object(); var outLenObj = new Object(); var errObj = new Object(); var errLenObj = new Object(); var testCmd = command + " -V" CONSOLE_LOG("\nenigmail> "+testCmd.replace(/\\\\/g, "\\")+"\n"); try { var exitCode = this.ipcService.execPipe(testCmd, false, "", "", 0, envList, envList.length, outObj, outLenObj, errObj, errLenObj); } catch (ex) { CONSOLE_LOG(testCmd.replace(/\\\\/g, "\\")+" failed\n"); return null; } if (exitCode !=0) { CONSOLE_LOG(testCmd.replace(/\\\\/g, "\\")+" not found\n"); return null; } CONSOLE_LOG(outObj.value+"\n"); var ver = outObj.value.split(/[\n\r]+/); if (Number(ver[0])==0 || Number(ver[0])==1) { var inputData="VERSION "+ver[0]+"\nHOST "+keyserver+"\nPORT "+port+"\n"; } else { return null; } if (proxyHost) { inputData+="OPTION honor-http-proxy\n"; envList.push("http_proxy="+proxyHost); } if (recvFlags & nsIEnigmail.SEARCH_KEY) { inputData+="COMMAND search\n\n"+keyValue+"\n\n"; } else if (recvFlags & nsIEnigmail.DOWNLOAD_KEY) { inputData+="COMMAND get\n\n+"+keyValue+"\n\n"; } var pipeConsole = Components.classes[NS_PIPECONSOLE_CONTRACTID].createInstance(Components.interfaces.nsIPipeConsole); // Create joinable console pipeConsole.open(5000, 0, true); var errorConsole = Components.classes[NS_PIPECONSOLE_CONTRACTID].createInstance(Components.interfaces.nsIPipeConsole); errorConsole.open(20, 0, true); CONSOLE_LOG("enigmail> "+command.replace(/\\\\/g, "\\")+"\n"); var ipcRequest = null; try { ipcRequest = gEnigmailSvc.ipcService.execAsync(command, false, "", inputData, inputData.length, envList, envList.length, pipeConsole, errorConsole, requestObserver); } catch (ex) { ERROR_LOG("enigmail.js: Enigmail.searchKey: execAsync failed\n"); } if (!ipcRequest) { ERROR_LOG("enigmail.js: Enigmail.searchKey: execAsync failed somehow\n"); return null; } return ipcRequest; } Enigmail.prototype.extractKey = function (parent, exportFlags, userId, outputFile, exitCodeObj, errorMsgObj) { DEBUG_LOG("enigmail.js: Enigmail.extractKey: "+userId+"\n"); if (!this.initialized) { errorMsgObj.value = EnigGetString("notInit"); return ""; } var command = this.getAgentPath(); command += GPG_BATCH_OPTS + " -a --export "; command += userId; var statusFlagsObj = new Object(); var statusMsgObj = new Object(); var cmdErrorMsgObj = new Object(); var keyBlock = this.execCmd(command, null, "", exitCodeObj, statusFlagsObj, statusMsgObj, cmdErrorMsgObj); if ((exitCodeObj.value == 0) && !keyBlock) exitCodeObj.value = -1; if (exitCodeObj.value != 0) { errorMsgObj.value = EnigGetString("failKeyExtract"); if (cmdErrorMsgObj.value) { errorMsgObj.value += "\n" + command; errorMsgObj.value += "\n" + cmdErrorMsgObj.value; } return ""; } if (exportFlags & nsIEnigmail.EXTRACT_SECRET_KEY) { command = this.getAgentPath(); command += GPG_BATCH_OPTS + " -a --export-secret-keys "; command += userId; var secKeyBlock = this.execCmd(command, null, "", exitCodeObj, statusFlagsObj, statusMsgObj, cmdErrorMsgObj); if ((exitCodeObj.value == 0) && !secKeyBlock) exitCodeObj.value = -1; if (exitCodeObj.value != 0) { errorMsgObj.value = EnigGetString("failKeyExtract"); if (cmdErrorMsgObj.value) { errorMsgObj.value += "\n" + command; errorMsgObj.value += "\n" + cmdErrorMsgObj.value; } return ""; } if (keyBlock.substr(-1,1).search(/[\r\n]/)<0) keyBlock += "\n" keyBlock+=secKeyBlock; } if (outputFile) { if (! WriteFileContents(outputFile, keyBlock, DEFAULT_FILE_PERMS)) { exitCodeObj.value = -1; errorMsgObj.value = EnigGetString("fileWriteFailed", outputFile); } return ""; } return keyBlock; } // ExitCode == 0 => success // ExitCode > 0 => error // ExitCode == -1 => Cancelled by user Enigmail.prototype.importKey = function (parent, uiFlags, msgText, keyId, errorMsgObj) { DEBUG_LOG("enigmail.js: Enigmail.importKey: id="+keyId+", "+uiFlags+"\n"); if (!this.initialized) { errorMsgObj.value = EnigGetString("notInit"); return 1; } var beginIndexObj = new Object(); var endIndexObj = new Object(); var indentStrObj = new Object(); var blockType = this.locateArmoredBlock(msgText, 0, "", beginIndexObj, endIndexObj, indentStrObj); if (!blockType) { errorMsgObj.value = EnigGetString("noPGPblock"); return 1; } if (blockType != "PUBLIC KEY BLOCK") { errorMsgObj.value = EnigGetString("notFirstBlock"); return 1; } var pgpBlock = msgText.substr(beginIndexObj.value, endIndexObj.value - beginIndexObj.value + 1); var interactive = uiFlags & nsIEnigmail.UI_INTERACTIVE; if (interactive) { var confirmMsg = EnigGetString("importKeyConfirm"); if (!this.confirmMsg(parent, confirmMsg)) { errorMsgObj.value = EnigGetString("failCancel"); return -1; } } var command = this.getAgentPath(); if (this.agentType == "pgp") { command += PGP_BATCH_OPTS + " -ft -ka"; } else { command += GPG_BATCH_OPTS + " --import"; } var exitCodeObj = new Object(); var statusFlagsObj = new Object(); var statusMsgObj = new Object(); var output = this.execCmd(command, null, pgpBlock, exitCodeObj, statusFlagsObj, statusMsgObj, errorMsgObj); var statusMsg = statusMsgObj.value; var pubKeyId; if (exitCodeObj.value == 0) { // Normal return this.invalidateUserIdList(); if (statusMsg && (statusMsg.search("IMPORTED ") > -1)) { var matches = statusMsg.match(/(^|\n)IMPORTED (\w{8})(\w{8})/); if (matches && (matches.length > 3)) { pubKeyId = "0x" + matches[3]; DEBUG_LOG("enigmail.js: Enigmail.importKey: IMPORTED "+pubKeyId+"\n"); } } } return exitCodeObj.value; } Enigmail.prototype.importKeyFromFile = function (parent, fileName, errorMsgObj) { DEBUG_LOG("enigmail.js: Enigmail.importKeyFromFile: fileName="+fileName+"\n"); if (!this.initialized) { errorMsgObj.value = EnigGetString("notInit"); return 1; } fileName=fileName.replace(/\\/g, "\\\\"); var command = this.getAgentPath(); command += GPG_BATCH_OPTS + " --import '"+fileName+"'"; var statusFlagsObj = new Object(); var statusMsgObj = new Object(); var exitCodeObj = new Object(); var output = this.execCmd(command, null, "", exitCodeObj, statusFlagsObj, statusMsgObj, errorMsgObj); var statusMsg = statusMsgObj.value; var pubKeyId; if (exitCodeObj.value == 0) { // Normal return this.invalidateUserIdList(); if (statusMsg && (statusMsg.search("IMPORTED ") > -1)) { var matches = statusMsg.match(/(^|\n)IMPORTED (\w{8})(\w{8})/); if (matches && (matches.length > 3)) { pubKeyId = "0x" + matches[3]; DEBUG_LOG("enigmail.js: Enigmail.importKey: IMPORTED "+pubKeyId+"\n"); } } errorMsgObj.value = EnigConvertGpgToUnicode(errorMsgObj.value); } return exitCodeObj.value; } Enigmail.prototype.generateKey = function (parent, name, comment, email, expiryDate, keyLength, passphrase, requestObserver) { WRITE_LOG("enigmail.js: Enigmail.generateKey: \n"); if (this.keygenProcess || (this.agentType != "gpg")) throw Components.results.NS_ERROR_FAILURE; var pipeConsole = Components.classes[NS_PIPECONSOLE_CONTRACTID].createInstance(Components.interfaces.nsIPipeConsole); // Create joinable console pipeConsole.open(100, 80, true); var command = this.getAgentPath() + GPG_BATCH_OPTS + " --gen-key"; pipeConsole.write(command.replace(/\\\\/g, "\\")+"\n"); CONSOLE_LOG(command.replace(/\\\\/g, "\\")+"\n"); var inputData = "%echo Generating a standard key\nKey-Type: DSA\nKey-Length: 1024\nSubkey-Type: ELG-E\n"; inputData += "Subkey-Length: "+keyLength+"\n"; - inputData += "Name-Real: "+EnigConvertFromUnicode(name)+"\n"; + inputData += "Name-Real: "+name+"\n"; if (comment) - inputData += "Name-Comment: "+EnigConvertFromUnicode(comment)+"\n"; + inputData += "Name-Comment: "+comment+"\n"; inputData += "Name-Email: "+email+"\n"; inputData += "Expire-Date: "+String(expiryDate)+"\n"; pipeConsole.write(EnigConvertToUnicode(inputData, "utf-8")+"\n"); CONSOLE_LOG(inputData+" \n"); if (passphrase.length) inputData += "Passphrase: "+passphrase+"\n"; inputData += "%commit\n%echo done\n"; var ipcRequest = null; try { var useShell = false; ipcRequest = gEnigmailSvc.ipcService.execAsync(command, useShell, "", inputData, inputData.length, [], 0, pipeConsole, pipeConsole, requestObserver); } catch (ex) { } if (!ipcRequest) { ERROR_LOG("enigmail.js: Enigmail.generateKey: execAsync failed\n"); return null; } this.keygenRequest = ipcRequest; DEBUG_LOG("enigmail.js: Enigmail.generateKey: ipcRequest = "+ipcRequest+"\n"); return ipcRequest; } Enigmail.prototype.createMessageURI = function (originalUrl, contentType, contentCharset, contentData, persist) { DEBUG_LOG("enigmail.js: Enigmail.createMessageURI: "+originalUrl+ ", "+contentType+", "+contentCharset+"\n"); var messageId = "msg" + Math.floor(Math.random()*1.0e9); this._messageIdList[messageId] = {originalUrl:originalUrl, contentType:contentType, contentCharset:contentCharset, contentData:contentData, persist:persist}; return "enigmail:message?id="+messageId; } function ExtractMessageId(uri) { var messageId = ""; var matches = uri.match(/^enigmail:message\?id=(.+)/); if (matches && (matches.length > 1)) { messageId = matches[1]; } return messageId; } Enigmail.prototype.deleteMessageURI = function (uri) { DEBUG_LOG("enigmail.js: Enigmail.deleteMessageURI: "+uri+"\n"); var messageId = ExtractMessageId(uri); if (!messageId) return false; return (delete this._messageIdList[messageId]); } function IPCContext() { } IPCContext.prototype = { command: "", pipeTransport: null, stdoutConsole: null, stderrConsole: null, QueryInterface: function (iid) { if (!iid.equals(Components.interfaces.nsIIPCContext) && !iid.equals(Components.interfaces.nsISupports)) throw Components.results.NS_ERROR_NO_INTERFACE; return this; } } const ENIGMAIL_PANEL_URL = "chrome://enigmail/content/enigmailPanel.xul"; Enigmail.prototype.selectPanel = function (url) { WRITE_LOG("enigmail.js: Enigmail.selectPanel: "+url+"\n"); var wm = Components.classes[WMEDIATOR_CONTRACTID].getService(Components.interfaces.nsIWindowMediator); var navWindowList = wm.getEnumerator("navigator:browser"); var retval = false; while (navWindowList.hasMoreElements()) { var navWindow =navWindowList.getNext(); DEBUG_LOG("enigmail.js: navWindow="+navWindow+"\n"); var href = navWindow._content.location.href; DEBUG_LOG("enigmail.js: href="+href+"\n"); if (href.toLowerCase().indexOf(url.toLowerCase()) != 0) continue; var enigmailPanel = navWindow.document.getElementById("urn:sidebar:3rdparty-panel:"+ENIGMAIL_PANEL_URL); DEBUG_LOG("enigmail.js: panel="+enigmailPanel+"\n"); if (!enigmailPanel) { // Add panel enigmailAddPanel(); enigmailPanel = navWindow.document.getElementById("urn:sidebar:3rdparty-panel:"+ENIGMAIL_PANEL_URL); DEBUG_LOG("enigmail.js: panel="+enigmailPanel+"\n"); if (!enigmailPanel) { DEBUG_LOG("enigmail.js: Added panel not found in document!\n"); return false; } } navWindow.SidebarSelectPanel(enigmailPanel, true, true); retval = true; } return retval; } // Chrome sidebar panel adding code function enigmailAddPanel() { DEBUG_LOG("enigmail.js: Adding Enigmail panel\n"); var sidebarObj = new chromeSidebar(); sidebarObj.addPanel("Enigmail", ENIGMAIL_PANEL_URL, ""); } const PANELS_RDF_FILE = "UPnls"; /* directory services property to find panels.rdf */ const CONTAINER_CONTRACTID = "@mozilla.org/rdf/container;1"; const DIR_SERV_CONTRACTID = "@mozilla.org/file/directory_service;1" const NETSEARCH_CONTRACTID = "@mozilla.org/rdf/datasource;1?name=internetsearch" const RDF_CONTRACTID = "@mozilla.org/rdf/rdf-service;1"; const nsIRDFService = Components.interfaces.nsIRDFService; const nsIRDFContainer = Components.interfaces.nsIRDFContainer; const nsIRDFRemoteDataSource = Components.interfaces.nsIRDFRemoteDataSource; function chromeSidebar() { this.rdf = Components.classes[RDF_CONTRACTID].getService(nsIRDFService); this.datasource_uri = getSidebarDatasourceURI(PANELS_RDF_FILE); DEBUG_LOG("enigmail.js: datasource_uri is" + this.datasource_uri + "\n"); this.resource = 'urn:sidebar:current-panel-list'; this.datasource = this.rdf.GetDataSource(this.datasource_uri); } chromeSidebar.prototype.nc = "http://home.netscape.com/NC-rdf#"; function sidebarURLSecurityCheck(url) { if (url.search(/(^chrome:|^http:|^ftp:|^https:)/) == -1) throw "Script attempted to add sidebar panel from illegal source"; } chromeSidebar.prototype.isPanel = function (aContentURL) { var container = Components.classes[CONTAINER_CONTRACTID].createInstance(nsIRDFContainer); /* Create a resource for the new panel and add it to the list */ var panel_resource = this.rdf.GetResource("urn:sidebar:3rdparty-panel:" + aContentURL); return (container.IndexOf(panel_resource) != -1); } /* decorate prototype to provide ``class'' methods and property accessors */ chromeSidebar.prototype.addPanel = function (aTitle, aContentURL, aCustomizeURL) { DEBUG_LOG("enigmail.js: addPanel(" + aTitle + ", " + aContentURL + ", " + aCustomizeURL + ")" + "\n"); sidebarURLSecurityCheck(aContentURL); // Create a "container" wrapper around the current panels to // manipulate the RDF:Seq more easily. var panel_list = this.datasource.GetTarget(this.rdf.GetResource(this.resource), this.rdf.GetResource(chromeSidebar.prototype.nc+"panel-list"), true); if (panel_list) { panel_list.QueryInterface(Components.interfaces.nsIRDFResource); } else { // Datasource is busted. Start over. DEBUG_LOG("enigmail.js: Sidebar datasource is busted\n"); } var container = Components.classes[CONTAINER_CONTRACTID].createInstance(nsIRDFContainer); container.Init(this.datasource, panel_list); /* Create a resource for the new panel and add it to the list */ var panel_resource = this.rdf.GetResource("urn:sidebar:3rdparty-panel:" + aContentURL); var panel_index = container.IndexOf(panel_resource); if (panel_index != -1) { DEBUG_LOG("enigmail.js: addPanel(): panel already in list"+"\n"); return; } /* Now make some sidebar-ish assertions about it... */ this.datasource.Assert(panel_resource, this.rdf.GetResource(this.nc + "title"), this.rdf.GetLiteral(aTitle), true); this.datasource.Assert(panel_resource, this.rdf.GetResource(this.nc + "content"), this.rdf.GetLiteral(aContentURL), true); if (aCustomizeURL) this.datasource.Assert(panel_resource, this.rdf.GetResource(this.nc + "customize"), this.rdf.GetLiteral(aCustomizeURL), true); container.AppendElement(panel_resource); // Use an assertion to pass a "refresh" event to all the sidebars. // They use observers to watch for this assertion (in sidebarOverlay.js). this.datasource.Assert(this.rdf.GetResource(this.resource), this.rdf.GetResource(this.nc + "refresh"), this.rdf.GetLiteral("true"), true); this.datasource.Unassert(this.rdf.GetResource(this.resource), this.rdf.GetResource(this.nc + "refresh"), this.rdf.GetLiteral("true")); /* Write the modified panels out. */ this.datasource.QueryInterface(nsIRDFRemoteDataSource).Flush(); DEBUG_LOG("enigmail.js: Panel successfully added to sidebar\n"); } function getSidebarDatasourceURI(panels_file_id) { try { /* use the fileLocator to look in the profile directory * to find 'panels.rdf', which is the * database of the user's currently selected panels. */ var directory_service = Components.classes[DIR_SERV_CONTRACTID].getService(); if (directory_service) directory_service = directory_service.QueryInterface(Components.interfaces.nsIProperties); /* if /panels.rdf doesn't exist, get will copy *bin/defaults/profile/panels.rdf to /panels.rdf */ var sidebar_file = directory_service.get(panels_file_id, Components.interfaces.nsIFile); if (!sidebar_file.exists()) { /* this should not happen, as GetFileLocation() should copy * defaults/panels.rdf to the users profile directory */ DEBUG_LOG("enigmail.js: sidebar file does not exist" + "\n"); return null; } DEBUG_LOG("enigmail.js: sidebar uri is " + sidebar_file.URL + "\n"); return sidebar_file.URL; } catch (ex) { /* this should not happen */ DEBUG_LOG("enigmail.js: caught " + ex + " getting sidebar datasource uri" + "\n"); return null; } } // retrieves a localized string from the enigmail.properties stringbundle function EnigGetString(aStr) { var restCount = arguments.length - 1; if(!gEnigStrBundle) { try { var strBundleService = Components.classes[ENIG_STRINGBUNDLE_CONTRACTID].getService(); strBundleService = strBundleService.QueryInterface(nsIEnigStrBundle); gEnigStrBundle = strBundleService.createBundle("chrome://enigmail/locale/enigmail.properties"); } catch (ex) { ERROR_LOG("enigmailCommon.js: Error in instantiating stringBundleService\n"); } } if(gEnigStrBundle) { try { if(restCount > 0) { var subPhrases = new Array(); for (var i = 1; i < arguments.length; i++) { subPhrases.push(arguments[i]); } return gEnigStrBundle.formatStringFromName(aStr, subPhrases, subPhrases.length); } else { return gEnigStrBundle.GetStringFromName(aStr); } } catch (ex) { ERROR_LOG("enigmailCommon.js: Error in querying stringBundleService for string '"+aStr+"'\n"); } } return null; } Enigmail.prototype.invalidateUserIdList = function () { // clean the userIdList to force reloading the list at next usage this.userIdList= null; } // returns the output of -with-colons --list[-secret]-keys Enigmail.prototype.getUserIdList = function (secretOnly, refresh, exitCodeObj, statusFlagsObj, errorMsgObj) { if (secretOnly || refresh || this.userIdList == null) { var gpgCommand = this.getAgentPath() + GPG_BATCH_OPTS; if (secretOnly) { gpgCommand += " --with-fingerprint --fixed-list-mode --with-colons --list-secret-keys"; } else { gpgCommand += " --with-fingerprint --fixed-list-mode --with-colons --list-keys"; } if (!this.initialized) { errorMsgObj.value = EnigGetString("notInit"); return ""; } statusFlagsObj.value = 0; var statusMsgObj = new Object(); var cmdErrorMsgObj = new Object(); var listText = this.execCmd(gpgCommand, null, "", exitCodeObj, statusFlagsObj, statusMsgObj, cmdErrorMsgObj); if (exitCodeObj.value != 0) { errorMsgObj.value = EnigGetString("badCommand"); if (cmdErrorMsgObj.value) { errorMsgObj.value += "\n" + gpgCommand; errorMsgObj.value += "\n" + cmdErrorMsgObj.value; } return ""; } listText=EnigConvertGpgToUnicode(listText).replace(/(\r\n|\r)/g, "\n"); if (secretOnly) { return listText; } this.userIdList = listText; } else { exitCodeObj.value=0; statusFlagsObj.value=0; errorMsgObj.value=""; } return this.userIdList; } // returns the output of -with-colons --list-sig Enigmail.prototype.getKeySig = function (keyId, exitCodeObj, errorMsgObj) { var gpgCommand = this.getAgentPath() + GPG_BATCH_OPTS + " --fixed-list-mode --with-colons --with-fingerprint --list-sig "+keyId; if (!this.initialized) { errorMsgObj.value = EnigGetString("notInit"); return ""; } var statusFlagsObj = new Object(); var statusMsgObj = new Object(); var cmdErrorMsgObj = new Object(); var listText = this.execCmd(gpgCommand, null, "", exitCodeObj, statusFlagsObj, statusMsgObj, cmdErrorMsgObj); if (exitCodeObj.value != 0) { errorMsgObj.value = EnigGetString("badCommand"); if (cmdErrorMsgObj.value) { errorMsgObj.value += "\n" + gpgCommand; errorMsgObj.value += "\n" + cmdErrorMsgObj.value; } return ""; } return listText; } // get key details. // if uidOnly is true, returns just a list of uid's Enigmail.prototype.getKeyDetails = function (keyId, uidOnly) { var gpgCommand = this.getAgentPath() + GPG_BATCH_OPTS gpgCommand += " --fixed-list-mode --with-colons --list-keys " + keyId; var statusMsgObj = new Object(); var cmdErrorMsgObj = new Object(); var statusFlagsObj = new Object(); var exitCodeObj = new Object(); var listText = this.execCmd(gpgCommand, null, "", exitCodeObj, statusFlagsObj, statusMsgObj, cmdErrorMsgObj); if (exitCodeObj.value != 0) { return ""; } listText=EnigConvertGpgToUnicode(listText).replace(/(\r\n|\r)/g, "\n"); if (uidOnly) { var userList=""; var keyArr=listText.split(/\n/); for (var i=0; i 0) { pipeTrans.writeSync(passphrase, passphrase.length); } pipeTrans.writeSync("\n", 1); } pipeTrans.writeSync(byteData, dataLength.value); } catch (ex) { return false; } // Wait for child STDOUT to close pipeTrans.join(); exitCodeObj.value = pipeTrans.exitCode(); var statusMsgObj = new Object(); var cmdLineObj = new Object(); try { this.execEnd(pipeTrans, statusFlagsObj, statusMsgObj, cmdLineObj, errorMsgObj); } catch (ex) {}; return true; } Enigmail.prototype.getCardStatus = function(exitCodeObj, errorMsgObj) { var command = this.getAgentPath(); command += " --status-fd 2 --fixed-list-mode --with-colons --card-status"; var statusMsgObj = new Object(); var statusFlagsObj = new Object(); var outputTxt = this.execCmd(command, null, "", exitCodeObj, statusFlagsObj, statusMsgObj, errorMsgObj); if ((exitCodeObj.value == 0) && !outputTxt) { exitCodeObj.value = -1; return ""; } return outputTxt; } Enigmail.prototype.showKeyPhoto = function(keyId, exitCodeObj, errorMsgObj) { var command = this.getAgentPath(); command += " --batch --no-tty --status-fd 1 --attribute-fd 1"; command += " --fixed-list-mode --list-keys "+keyId; var statusMsgObj = new Object(); var statusFlagsObj = new Object(); var outputTxt = this.execCmd(command, null, "", exitCodeObj, statusFlagsObj, statusMsgObj, errorMsgObj); if ((exitCodeObj.value == 0) && !outputTxt) { exitCodeObj.value = -1; return ""; } if (this.agentVersion<"1.5" && this.isDosLike) { // workaround for error in gpg outputTxt=outputTxt.replace(/\r\n/g, "\n"); } var startIndex=0; var nextIndex=outputTxt.indexOf("[GNUPG:]",startIndex); var imgSize=-1; while (nextIndex>=0 && startIndex < outputTxt.length && startIndex>=0) { var matches = outputTxt.substring(startIndex).match(/ATTRIBUTE ([A-F\d]+) (\d+) (\d+) (\d+) (\d+) (\d+) (\d+) (\d+)/); if (matches && matches[3]=="1") { // attribute is an image imgSize=Number(matches[2]) break; } startIndex=nextIndex+1; nextIndex=outputTxt.indexOf("[GNUPG:]",startIndex); } if (imgSize>=0) { startIndex = outputTxt.substring(nextIndex).search(/[\n\r]\[GNUPG:\] ATTRIBUTE /)+nextIndex+5; var cr = outputTxt.substring(startIndex).search(/[\r\n]/); // increase cr by 1 if CRLF if (outputTxt.charAt(startIndex+cr)=="\r" && outputTxt.charAt(startIndex+cr+1)=="\n") cr++; var pictureData = outputTxt.substring(startIndex+cr+1+16, startIndex+cr+1+imgSize); if (! pictureData.length) return ""; try { var flags = NS_WRONLY | NS_CREATE_FILE | NS_TRUNCATE; var ds = Components.classes[DIR_SERV_CONTRACTID].getService(); var dsprops = ds.QueryInterface(Components.interfaces.nsIProperties); var picFile = dsprops.get("TmpD", Components.interfaces.nsIFile); picFile.append(keyId+".jpg"); picFile.createUnique(picFile.NORMAL_FILE_TYPE, DEFAULT_FILE_PERMS); var fileStream = Components.classes[NS_LOCALFILEOUTPUTSTREAM_CONTRACTID].createInstance(Components.interfaces.nsIFileOutputStream); fileStream.init(picFile, flags, DEFAULT_FILE_PERMS, 0); if (fileStream.write(pictureData, pictureData.length) != pictureData.length) throw Components.results.NS_ERROR_FAILURE; fileStream.flush(); fileStream.close(); } catch (ex) { exitCodeObj.value = -1; return ""; } } return picFile.path; } // Methods for handling Per-Recipient Rules Enigmail.prototype.getRulesFile = function () { DEBUG_LOG("enigmail.js: getRulesFile\n"); var ds = Components.classes[DIR_SERV_CONTRACTID].getService(); var dsprops = ds.QueryInterface(Components.interfaces.nsIProperties); var rulesFile = dsprops.get("ProfD", Components.interfaces.nsILocalFile); rulesFile.append("pgprules.xml"); return rulesFile; } Enigmail.prototype.loadRulesFile = function () { DEBUG_LOG("enigmail.js: loadRulesFile\n"); var flags = NS_RDONLY; var rulesFile = this.getRulesFile(); if (rulesFile.exists()) { var ioServ = Components.classes[NS_IOSERVICE_CONTRACTID].getService(Components.interfaces.nsIIOService); if (!ioServ) throw Components.results.NS_ERROR_FAILURE; var fileURI = ioServ.newFileURI(rulesFile); var fileChannel = ioServ.newChannel(fileURI.asciiSpec, null, null); var rawInStream = fileChannel.open(); var scriptableInStream = Components.classes[NS_SCRIPTABLEINPUTSTREAM_CONTRACTID].createInstance(Components.interfaces.nsIScriptableInputStream); scriptableInStream.init(rawInStream); var available = scriptableInStream.available() var fileContents = scriptableInStream.read(available); scriptableInStream.close(); if (fileContents.length==0 || fileContents.search(/^\s*$/)==0) { return false; } var domParser=Components.classes[NS_DOMPARSER_CONTRACTID].createInstance(Components.interfaces.nsIDOMParser); this.rulesList = domParser.parseFromString(fileContents, "text/xml"); return true; } return false; } Enigmail.prototype.saveRulesFile = function () { DEBUG_LOG("enigmail.js: saveRulesFile\n"); var flags = NS_WRONLY | NS_CREATE_FILE | NS_TRUNCATE; var domSerializer=Components.classes[NS_DOMSERIALIZER_CONTRACTID].createInstance(Components.interfaces.nsIDOMSerializer); var rulesFile = this.getRulesFile(); if (rulesFile) { if (this.rulesList) { // the rule list is not empty -> write into file return WriteFileContents(rulesFile.path, domSerializer.serializeToString(this.rulesList.firstChild), DEFAULT_FILE_PERMS); } else { // empty rule list -> delete rules file try { rulesFile.remove(false); } catch (ex) {} return true; } } else return false; } Enigmail.prototype.getRulesData = function (rulesListObj) { DEBUG_LOG("enigmail.js: getRulesData\n"); var ret=true; if (! this.rulesList) { ret=this.loadRulesFile(); } if (this.rulesList) { rulesListObj.value = this.rulesList; return ret; } rulesListObj.value = null; return false; } Enigmail.prototype.addRule = function (appendToEnd, toAddress, keyList, sign, encrypt, pgpMime, flags) { DEBUG_LOG("enigmail.js: addRule\n"); if (! this.rulesList) { var domParser=Components.classes[NS_DOMPARSER_CONTRACTID].createInstance(Components.interfaces.nsIDOMParser); this.rulesList = domParser.parseFromString("", "text/xml"); } var negate = (flags & 1); var rule=this.rulesList.createElement("pgpRule"); rule.setAttribute("email", toAddress); rule.setAttribute("keyId", keyList); rule.setAttribute("sign", sign); rule.setAttribute("encrypt", encrypt); rule.setAttribute("pgpMime", pgpMime); rule.setAttribute("negateRule", flags); var origFirstChild = this.rulesList.firstChild.firstChild; if (origFirstChild && (! appendToEnd)) { this.rulesList.firstChild.insertBefore(rule, origFirstChild); this.rulesList.firstChild.insertBefore(this.rulesList.createTextNode(this.isDosLike ? "\r\n" : "\n"), origFirstChild); } else { this.rulesList.firstChild.appendChild(rule); this.rulesList.firstChild.appendChild(this.rulesList.createTextNode(this.isDosLike ? "\r\n" : "\n")); } } Enigmail.prototype.clearRules = function () { this.rulesList = null; } function KeyEditor(pipeTrans, reqObserver) { this._pipeTrans = pipeTrans; this._reqObserver = reqObserver; } KeyEditor.prototype = { _pipeTrans: null, _txt: null, _req: null, nextLine: function() { return this._txt; }, writeLine: function (inputData) { this._pipeTrans.writeSync(inputData+"\n", inputData.length+1); }, nextLine: function() { var txt=""; while (txt.indexOf("[GNUPG:]") < 0) { txt = this._pipeTrans.readLine(-1); if (this._reqObserver) { var newTxt = this._reqObserver.onDataAvailable(txt); if (newTxt) { txt = newTxt; } } } this._txt = txt; return this._txt; }, doCheck: function(inputType, promptVal) { var a=this._txt.split(/ /); return ((a[1] == inputType) && (a[2] == promptVal)) }, getText: function() { return this._txt; }, keyEditorMainLoop: function (callbackFunc, inputData, errorMsgObj) { // main method that loops over the requests & responses of the // GnuPG key editor var txt=""; var r = { quitNow: false, exitCode: -1 }; errorMsgObj.value=EnigGetString("undefinedError"); while (! r.quitNow) { while ((txt.indexOf("[GNUPG:] GET_") < 0) && (! r.quitNow)) { try { txt = this.nextLine(); DEBUG_LOG(txt+"\n"); if (txt.indexOf("KEYEXPIRED") > 0) { errorMsgObj.value=EnigGetString("noSignKeyExpired"); r.exitCode=-1; } if (txt.indexOf("[GNUPG:] BAD_PASSPHRASE")>=0) { r.exitCode=-2; } if (txt.indexOf("[GNUPG:] NO_CARD_AVAILABLE")>=0) { errorMsgObj.value=EnigGetString("noCardAvailable"); r.exitCode=-3; } if (txt.indexOf("[GNUPG:] ENIGMAIL_FAILURE")==0) { r.exitCode = -3; r.quitNow = true; errorMsgObj.value = txt.substr(26); } if (txt.indexOf("[GNUPG:] ALREADY_SIGNED")>=0) { errorMsgObj.value=EnigGetString("keyAlreadySigned"); r.exitCode=-1; } } catch (ex) { txt=""; r.quitNow=true; } } if (! r.quitNow) { if (callbackFunc) { callbackFunc(inputData, this, r); if (r.exitCode == 0) { this.writeLine(r.writeTxt); } else { errorMsgObj.value = r.errorMsg; } } else { r.quitNow=true; r.exitCode = 0; } } if (! r.quitNow) { try{ txt = this.nextLine(); DEBUG_LOG(txt+"\n"); } catch(ex) { r.quitNow=true; } } } try { this.writeLine("save"); txt = this.nextLine(); DEBUG_LOG(txt+"\n"); } catch (ex) { DEBUG_LOG("no more data\n"); } return r.exitCode; }, QueryInterface: function (iid) { if (!iid.equals(Components.interfaces.nsISupports)) throw Components.results.NS_ERROR_NO_INTERFACE; return this; } } Enigmail.prototype.signKey = function (parent, userId, keyId, signLocally, trustLevel, errorMsgObj) { DEBUG_LOG("enigmail.js: Enigmail.signKey: trustLevel="+trustLevel+", userId="+userId+", keyId="+keyId+"\n"); var r = this.editKey(parent, true, userId, keyId, (signLocally ? "lsign" : "sign"), { trustLevel: trustLevel}, signKeyCallback, null, errorMsgObj); this.stillActive(); return r; } Enigmail.prototype.setKeyTrust = function (parent, keyId, trustLevel, errorMsgObj) { DEBUG_LOG("enigmail.js: Enigmail.setKeyTrust: trustLevel="+trustLevel+", keyId="+keyId+"\n"); return this.editKey(parent, false, null, keyId, "trust", { trustLevel: trustLevel}, keyTrustCallback, null, errorMsgObj); } Enigmail.prototype.genRevokeCert = function (parent, keyId, outFile, reasonCode, reasonText, errorMsgObj) { DEBUG_LOG("enigmail.js: Enigmail.genRevokeCert: keyId="+keyId+"\n"); var r= this.editKey(parent, true, null, keyId, "revoke", { outFile: outFile, reasonCode: reasonCode, reasonText: EnigConvertFromUnicode(reasonText) }, revokeCertCallback, null, errorMsgObj); this.stillActive(); return r; } Enigmail.prototype.addUid = function (parent, keyId, name, email, comment, errorMsgObj) { DEBUG_LOG("enigmail.js: Enigmail.addUid: keyId="+keyId+", name="+name+", email="+email+"\n"); var r= this.editKey(parent, true, null, keyId, "adduid", { email: email, - name: EnigConvertFromUnicode(name), - comment: EnigConvertFromUnicode(comment), + name: name, + comment: comment, nameAsked: 0, emailAsked: 0 }, addUidCallback, null, errorMsgObj); this.stillActive(); return r; } Enigmail.prototype.deleteKey = function (parent, keyId, deleteSecretKey, errorMsgObj) { DEBUG_LOG("enigmail.js: Enigmail.addUid: keyId="+keyId+", deleteSecretKey="+deleteSecretKey+"\n"); var cmd = (deleteSecretKey ? "--delete-secret-and-public-key" : "--delete-key"); var r= this.editKey(parent, false, null, keyId, cmd, {}, deleteKeyCallback, null, errorMsgObj); this.stillActive(); return r; } Enigmail.prototype.revokeSubkey = function (parent, keyId, subkeys, reasonCode, reasonText, errorMsgObj) { DEBUG_LOG("enigmail.js: Enigmail.revokeSubkey: keyId="+keyId+"\n"); var r= this.editKey(parent, true, null, keyId, "", { step: 0, subkeys: subkeys.split(/,/), reasonCode: reasonCode, reasonText: EnigConvertFromUnicode(reasonText) }, revokeSubkeyCallback, null, errorMsgObj); this.stillActive(); return r; } Enigmail.prototype.enableDisableKey = function (parent, keyId, disableKey, errorMsgObj) { DEBUG_LOG("enigmail.js: Enigmail.addUid: keyId="+keyId+", disableKey="+disableKey+"\n"); var cmd = (disableKey ? "disable" : "enable"); var r= this.editKey(parent, false, null, keyId, cmd, {}, null, null, errorMsgObj); this.stillActive(); return r; } Enigmail.prototype.setPrimaryUid = function (parent, keyId, idNumber, errorMsgObj) { DEBUG_LOG("enigmail.js: Enigmail.setPrimaryUid: keyId="+keyId+", idNumber="+idNumber+"\n"); var r = this.editKey(parent, true, null, keyId, "", { idNumber: idNumber, step: 0 }, setPrimaryUidCallback, null, errorMsgObj); this.stillActive(); return r; } Enigmail.prototype.deleteUid = function (parent, keyId, idNumber, errorMsgObj) { DEBUG_LOG("enigmail.js: Enigmail.deleteUid: keyId="+keyId+", idNumber="+idNumber+"\n"); var r = this.editKey(parent, true, null, keyId, "", { idNumber: idNumber, step: 0 }, deleteUidCallback, null, errorMsgObj); this.stillActive(); return r; } Enigmail.prototype.revokeUid = function (parent, keyId, idNumber, errorMsgObj) { DEBUG_LOG("enigmail.js: Enigmail.revokeUid: keyId="+keyId+", idNumber="+idNumber+"\n"); var r = this.editKey(parent, true, null, keyId, "", { idNumber: idNumber, step: 0 }, revokeUidCallback, null, errorMsgObj); this.stillActive(); return r; } function enigCardAdminObserver(guiObserver, isDosLike) { this._guiObserver = guiObserver; this.isDosLike = isDosLike; } enigCardAdminObserver.prototype = { _guiObserver: null, _failureCode: 0, QueryInterface : function(iid) { if (iid.equals(Components.interfaces.nsIEnigMimeReadCallback) || iid.equals(Components.interfaces.nsISupports) ) return this; throw Components.results.NS_NOINTERFACE; }, onDataAvailable: function (data) { var ret=""; DEBUG_LOG("enigmail.js: enigCardAdminObserver.onDataAvailable: data="+data+"\n"); if (this.isDosLike && data.indexOf("[GNUPG:] BACKUP_KEY_CREATED") == 0) { data=data.replace(/\//g, "\\"); } if (this._failureCode) { ret = "[GNUPG:] ENIGMAIL_FAILURE "+data; } if (data.indexOf("[GNUPG:] SC_OP_FAILURE")>=0) { this._failureCode = 1; } if (this._guiObserver) { this._guiObserver.onDataAvailable(data); } return ret; } } Enigmail.prototype.genCardKey = function (parent, name, email, comment, expiry, backupPasswd, requestObserver, errorMsgObj) { DEBUG_LOG("enigmail.js: Enigmail.genCardKey: \n"); var generateObserver = new enigCardAdminObserver(requestObserver, this.isDosLike); var r = this.editKey(parent, false, null, "", "--with-colons --card-edit", { step: 0, name: EnigConvertFromUnicode(name), email: email, comment: EnigConvertFromUnicode(comment), expiry: expiry, backupPasswd: backupPasswd, backupKey: (backupPasswd.length > 0 ? "Y" : "N"), parent: parent }, genCardKeyCallback, generateObserver, errorMsgObj); return r; } Enigmail.prototype.cardAdminData = function (parent, name, firstname, lang, sex, url, login, forcepin, errorMsgObj) { DEBUG_LOG("enigmail.js: Enigmail.cardAdminData: parent="+parent+", name="+name+", firstname="+firstname+", lang="+lang+", sex="+sex+", url="+url+", login="+login+", forcepin="+forcepin+"\n"); var adminObserver = new enigCardAdminObserver(null, this.isDosLike); var r = this.editKey(parent, false, null, "", "--with-colons --card-edit", { step: 0, - name: EnigConvertFromUnicode(name), - firstname: EnigConvertFromUnicode(firstname), + name: name, + firstname: firstname, lang: lang, sex: sex, url: url, login: login, forcepin: forcepin }, cardAdminDataCallback, adminObserver, errorMsgObj); return r; } Enigmail.prototype.cardChangePin = function (parent, action, oldPin, newPin, adminPin, pinObserver, errorMsgObj) { DEBUG_LOG("enigmail.js: Enigmail.cardChangePin: parent="+parent+", action="+action+"\n"); var adminObserver = new enigCardAdminObserver(pinObserver, this.isDosLike); var r = this.editKey(parent, false, null, "", "--with-colons --card-edit", { step: 0, pinStep: 0, action: action, oldPin: oldPin, newPin: newPin, adminPin: adminPin }, cardChangePinCallback, adminObserver, errorMsgObj); return r; } Enigmail.prototype.editKey = function (parent, needPassphrase, userId, keyId, editCmd, inputData, callbackFunc, requestObserver, errorMsgObj) { DEBUG_LOG("enigmail.js: Enigmail.editKey: parent="+parent+", editCmd="+editCmd+"\n"); if (!this.initialized) { errorMsgObj.value = EnigGetString("notInit"); return -1; } if (this.agentType != "gpg") { errorMsgObj.value = EnigGetString("failOnlyGPG"); return -1; } errorMsgObj.value = ""; var command = this.getAgentPath(); var statusFlags = new Object(); var passphrase = ""; var useAgentObj = new Object(); if (needPassphrase) { command += this.passwdCommand(); var passwdObj = new Object(); if (!GetPassphrase(parent, passwdObj, useAgentObj, this.agentVersion)) { ERROR_LOG("enigmail.js: Enigmail.execStart: Error - no passphrase supplied\n"); errorMsgObj.value = EnigGetString("noPassphrase"); return -1; } passphrase = passwdObj.value; } else { useAgentObj.value = true; } command += " --no-tty --status-fd 1 --logger-fd 1 --command-fd 0" if (userId) command += " -u " + userId; if (editCmd == "revoke") { // escape backslashes and ' characters command += " -a -o "+this.quoteSign; command += inputData.outFile.replace(/([\\\"\'\`])/g, "\\$1"); //replace(/\\/g, "\\\\").replace(/'/g, "\\'"); command += this.quoteSign+" --gen-revoke " + keyId; } else if (editCmd.indexOf("--")==0) { command += " "+editCmd + " " + keyId; } else { command += " --ask-cert-level --edit-key " + keyId + " " + editCmd; } command = command.replace(/ *$/, ""); var pipeTrans = this.execStart(command, false, parent, null, null, true, statusFlags); if (! pipeTrans) return -1; if (! useAgentObj.value) { try { if (passphrase) { pipeTrans.writeSync(passphrase, passphrase.length); } pipeTrans.writeSync("\n", 1); } catch (ex) {} } var returnCode=-1; try { var keyEdit = new KeyEditor(pipeTrans, requestObserver); returnCode = keyEdit.keyEditorMainLoop(callbackFunc, inputData, errorMsgObj); } catch (ex) { DEBUG_LOG("enigmail.js: Enigmail.editKey: caught exception from writing to pipeTrans\n"); } var thread=Components.classes["@mozilla.org/thread;1"].getService(Components.interfaces.nsIThread); thread=thread.currentThread; var exitCode = -1; switch(returnCode) { case 0: for (var retryCount = 100; retryCount > 0; retryCount--) { if (pipeTrans.isAttached()) { DEBUG_LOG("enigmail.js: Enigmail.editKey: sleeping 100 ms\n"); thread.sleep(100); // sleep 100 ms before retrying } else { retryCount = -1; } } try{ exitCode = pipeTrans.exitCode(); } catch (ex) { DEBUG_LOG("enigmail.js: Enigmail.editKey: caught exception from pipeTrans\n"); } break; case -2: errorMsgObj.value=EnigGetString("badPhrase"); this.clearCachedPassphrase(); default: exitCode = returnCode; } DEBUG_LOG("enigmail.js: Enigmail.editKey: GnuPG terminated with code="+exitCode+"\n"); return exitCode; } function signKeyCallback(inputData, keyEdit, ret) { ret.writeTxt = ""; ret.errorMsg = ""; if (keyEdit.doCheck(GET_BOOL, "sign_uid.okay" )) { ret.exitCode = 0; ret.writeTxt = "Y"; } else if (keyEdit.doCheck(GET_BOOL, "keyedit.sign_all.okay" )) { ret.exitCode = 0; ret.writeTxt = "Y"; } else if (keyEdit.doCheck(GET_LINE, "sign_uid.expire" )) { ret.exitCode = 0; ret.writeTxt = "0"; } else if (keyEdit.doCheck(GET_LINE, "trustsig_prompt.trust_value" )) { ret.exitCode = 0; ret.writeTxt = "0"; } else if (keyEdit.doCheck(GET_LINE, "trustsig_prompt.trust_depth" )) { ret.exitCode = 0; ret.writeTxt = "";} else if (keyEdit.doCheck(GET_LINE, "trustsig_prompt.trust_regexp" )) { ret.exitCode = 0; ret.writeTxt = "0";} else if (keyEdit.doCheck(GET_LINE, "siggen.valid" )) { ret.exitCode = 0; ret.writeTxt = "0"; } else if (keyEdit.doCheck(GET_BOOL, "sign_uid.local_promote_okay" )) { ret.exitCode = 0; ret.writeTxt = "Y"; } else if (keyEdit.doCheck(GET_LINE, "sign_uid.class" )) { ret.exitCode = 0; ret.writeTxt = inputData.trustLevel; } else if (keyEdit.doCheck(GET_HIDDEN, "passphrase.adminpin.ask")) { GetPin(inputData.parent, EnigGetString("enterAdminPin"), ret); } else if (keyEdit.doCheck(GET_HIDDEN, "passphrase.pin.ask")) { GetPin(inputData.parent, EnigGetString("enterCardPin"), ret); } else if (keyEdit.doCheck(GET_LINE, "keyedit.prompt")) { ret.quitNow = true; } else { ret.quitNow=true; ERROR_LOG("Unknown command prompt: "+keyEdit.getText()+"\n"); ret.exitCode=-1; } } function keyTrustCallback(inputData, keyEdit, ret) { ret.writeTxt = ""; ret.errorMsg = ""; if (keyEdit.doCheck(GET_LINE, "edit_ownertrust.value" )) { ret.exitCode = 0; ret.writeTxt = inputData.trustLevel; } else if (keyEdit.doCheck(GET_BOOL, "edit_ownertrust.set_ultimate.okay")) { ret.exitCode = 0; ret.writeTxt = "Y"; } else if (keyEdit.doCheck(GET_LINE, "keyedit.prompt")) { ret.quitNow = true; } else if (keyEdit.doCheck(GET_HIDDEN, "passphrase.adminpin.ask")) { GetPin(inputData.parent, EnigGetString("enterAdminPin"), ret); } else if (keyEdit.doCheck(GET_HIDDEN, "passphrase.pin.ask")) { GetPin(inputData.parent, EnigGetString("enterCardPin"), ret); } else { ret.quitNow=true; ERROR_LOG("Unknown command prompt: "+keyEdit.getText()+"\n"); ret.exitCode=-1; } } function addUidCallback(inputData, keyEdit, ret) { ret.writeTxt = ""; ret.errorMsg = ""; if (keyEdit.doCheck(GET_LINE, "keygen.name" )) { ++inputData.nameAsked; if (inputData.nameAsked==1) { ret.exitCode = 0; ret.writeTxt = inputData.name; } else { ret.exitCode=-1; ret.quitNow=true; ret.errorMsg="Invalid name (too short)"; } } else if (keyEdit.doCheck(GET_LINE, "keygen.email")) { ++inputData.emailAsked; if (inputData.emailAsked==1) { ret.exitCode = 0; ret.writeTxt = inputData.email; } else { ret.exitCode=-1; ret.quitNow=true; ret.errorMsg="Invalid email"; } } else if (keyEdit.doCheck(GET_LINE, "keygen.comment")) { ret.exitCode = 0; if (inputData.comment) { ret.writeTxt = inputData.comment; } else { ret.writeTxt=""; } } else if (keyEdit.doCheck(GET_LINE, "keyedit.prompt")) { ret.quitNow = true; } else if (keyEdit.doCheck(GET_HIDDEN, "passphrase.adminpin.ask")) { GetPin(inputData.parent, EnigGetString("enterAdminPin"), ret); } else if (keyEdit.doCheck(GET_HIDDEN, "passphrase.pin.ask")) { GetPin(inputData.parent, EnigGetString("enterCardPin"), ret); } else { ret.quitNow=true; ERROR_LOG("Unknown command prompt: "+keyEdit.getText()+"\n"); ret.exitCode=-1; } } function revokeCertCallback(inputData, keyEdit, ret) { ret.writeTxt = ""; ret.errorMsg = ""; if (keyEdit.doCheck(GET_LINE, "ask_revocation_reason.code" )) { ret.exitCode = 0; ret.writeTxt = inputData.reasonCode; } else if (keyEdit.doCheck(GET_LINE, "ask_revocation_reason.text" )) { ret.exitCode = 0; ret.writeTxt = ""; } else if (keyEdit.doCheck(GET_BOOL, "gen_revoke.okay")) { ret.exitCode = 0; ret.writeTxt = "Y"; } else if (keyEdit.doCheck(GET_BOOL, "ask_revocation_reason.okay" )) { ret.exitCode = 0; ret.writeTxt = "Y"; } else if (keyEdit.doCheck(GET_BOOL, "openfile.overwrite.okay" )) { ret.exitCode = 0; ret.writeTxt = "Y"; } else if (keyEdit.doCheck(GET_HIDDEN, "passphrase.adminpin.ask")) { GetPin(inputData.parent, EnigGetString("enterAdminPin"), ret); } else if (keyEdit.doCheck(GET_HIDDEN, "passphrase.pin.ask")) { GetPin(inputData.parent, EnigGetString("enterCardPin"), ret); } else if (keyEdit.doCheck(GET_LINE, "keyedit.prompt")) { ret.quitNow = true; } else { ret.quitNow=true; ERROR_LOG("Unknown command prompt: "+keyEdit.getText()+"\n"); ret.exitCode=-1; } } function revokeSubkeyCallback(inputData, keyEdit, ret) { ret.writeTxt = ""; ret.errorMsg = ""; if (keyEdit.doCheck(GET_LINE, "keyedit.prompt")) { if (inputData.step < inputData.subkeys.length) { ret.exitCode = 0; ret.writeTxt = "key "+inputData.subkeys[inputData.step]; ++inputData.step; } else if (inputData.step == inputData.subkeys.length) { ret.exitCode = 0; ret.writeTxt = "revkey"; ++inputData.step; } else { if (inputData.step == (inputData.subkeys.length+1)) { ret.exitCode = 0; } else { ret.exitCode = -1; } ret.quitNow = true; } } else if (keyEdit.doCheck(GET_BOOL, "keyedit.revoke.subkey.okay")) { ret.exitCode = 0; ret.writeTxt = "Y"; } else if (keyEdit.doCheck(GET_LINE, "ask_revocation_reason.code" )) { ret.exitCode = 0; ret.writeTxt = inputData.reasonCode; } else if (keyEdit.doCheck(GET_LINE, "ask_revocation_reason.text" )) { ret.exitCode = 0; ret.writeTxt = ""; } else if (keyEdit.doCheck(GET_BOOL, "ask_revocation_reason.okay" )) { ++inputData.step; ret.exitCode = 0; ret.writeTxt = "Y"; } else if (keyEdit.doCheck(GET_HIDDEN, "passphrase.adminpin.ask")) { GetPin(inputData.parent, EnigGetString("enterAdminPin"), ret); } else if (keyEdit.doCheck(GET_HIDDEN, "passphrase.pin.ask")) { GetPin(inputData.parent, EnigGetString("enterCardPin"), ret); } else { ret.quitNow=true; ERROR_LOG("Unknown command prompt: "+keyEdit.getText()+"\n"); ret.exitCode=-1; } } function setPrimaryUidCallback(inputData, keyEdit, ret) { ret.writeTxt = ""; ret.errorMsg = ""; if (keyEdit.doCheck(GET_LINE, "keyedit.prompt" )) { ++inputData.step; switch (inputData.step) { case 1: ret.exitCode = 0; ret.writeTxt = "uid "+inputData.idNumber; break; case 2: ret.exitCode = 0; ret.writeTxt = "primary"; break; case 3: ret.exitCode = 0; ret.quitNow=true; break; default: ret.exitCode = -1; ret.quitNow=true; } } else { ret.quitNow=true; ERROR_LOG("Unknown command prompt: "+keyEdit.getText()+"\n"); ret.exitCode=-1; } } function deleteUidCallback(inputData, keyEdit, ret) { ret.writeTxt = ""; ret.errorMsg = ""; if (keyEdit.doCheck(GET_LINE, "keyedit.prompt" )) { ++inputData.step; switch (inputData.step) { case 1: ret.exitCode = 0; ret.writeTxt = "uid "+inputData.idNumber; break; case 2: ret.exitCode = 0; ret.writeTxt = "deluid"; break; case 4: ret.exitCode = 0; ret.quitNow=true; break; default: ret.exitCode = -1; ret.quitNow=true; } } else if (keyEdit.doCheck(GET_BOOL, "keyedit.remove.uid.okay" )) { ++inputData.step; ret.exitCode = 0; ret.writeTxt = "Y"; } else if (keyEdit.doCheck(GET_HIDDEN, "passphrase.adminpin.ask")) { GetPin(inputData.parent, EnigGetString("enterAdminPin"), ret); } else if (keyEdit.doCheck(GET_HIDDEN, "passphrase.pin.ask")) { GetPin(inputData.parent, EnigGetString("enterCardPin"), ret); } else { ret.quitNow=true; ERROR_LOG("Unknown command prompt: "+keyEdit.getText()+"\n"); ret.exitCode=-1; } } function revokeUidCallback(inputData, keyEdit, ret) { ret.writeTxt = ""; ret.errorMsg = ""; if (keyEdit.doCheck(GET_LINE, "keyedit.prompt" )) { ++inputData.step; switch (inputData.step) { case 1: ret.exitCode = 0; ret.writeTxt = "uid "+inputData.idNumber; break; case 2: ret.exitCode = 0; ret.writeTxt = "revuid"; break; case 7: ret.exitCode = 0; ret.quitNow=true; break; default: ret.exitCode = -1; ret.quitNow=true; } } else if (keyEdit.doCheck(GET_BOOL, "keyedit.revoke.uid.okay" )) { ++inputData.step; ret.exitCode = 0; ret.writeTxt = "Y"; } else if (keyEdit.doCheck(GET_LINE, "ask_revocation_reason.code")) { ++inputData.step; ret.exitCode = 0; ret.writeTxt = "0"; // no reason specified } else if (keyEdit.doCheck(GET_LINE, "ask_revocation_reason.text")) { ++inputData.step; ret.exitCode = 0; ret.writeTxt = ""; } else if (keyEdit.doCheck(GET_BOOL, "ask_revocation_reason.okay")) { ++inputData.step; ret.exitCode = 0; ret.writeTxt = "Y"; } else if (keyEdit.doCheck(GET_HIDDEN, "passphrase.adminpin.ask")) { GetPin(inputData.parent, EnigGetString("enterAdminPin"), ret); } else if (keyEdit.doCheck(GET_HIDDEN, "passphrase.pin.ask")) { GetPin(inputData.parent, EnigGetString("enterCardPin"), ret); } else { ret.quitNow=true; ERROR_LOG("Unknown command prompt: "+keyEdit.getText()+"\n"); ret.exitCode=-1; } } function deleteKeyCallback(inputData, keyEdit, ret) { ret.writeTxt = ""; ret.errorMsg = ""; if (keyEdit.doCheck(GET_BOOL, "delete_key.secret.okay")) { ret.exitCode = 0; ret.writeTxt = "Y"; } else if (keyEdit.doCheck(GET_BOOL, "keyedit.remove.subkey.okay")) { ret.exitCode = 0; ret.writeTxt = "Y"; } else if (keyEdit.doCheck(GET_BOOL, "delete_key.okay" )) { ret.exitCode = 0; ret.writeTxt = "Y"; } else if (keyEdit.doCheck(GET_HIDDEN, "passphrase.adminpin.ask")) { GetPin(inputData.parent, EnigGetString("enterAdminPin"), ret); } else if (keyEdit.doCheck(GET_HIDDEN, "passphrase.pin.ask")) { GetPin(inputData.parent, EnigGetString("enterCardPin"), ret); } else { ret.quitNow=true; ERROR_LOG("Unknown command prompt: "+keyEdit.getText()+"\n"); ret.exitCode=-1; } } function GetPin(domWindow, promptMsg, ret) { DEBUG_LOG("enigmail.js: GetPin: \n"); var passwdObj = {value: ""}; var dummyObj = {}; var success = false; var promptService = Components.classes[NS_PROMPTSERVICE_CONTRACTID].getService(Components.interfaces.nsIPromptService); success = promptService.promptPassword(domWindow, EnigGetString("Enigmail"), promptMsg, passwdObj, null, dummyObj); if (!success) { ret.errorMsg = EnigGetString("noPassphrase"); ret.quitNow=true; return false; } DEBUG_LOG("enigmail.js: GetPin: got pin\n"); ret.writeTxt = passwdObj.value; return true; } function genCardKeyCallback(inputData, keyEdit, ret) { ret.writeTxt = ""; ret.errorMsg = ""; var pinObj={}; if (keyEdit.doCheck(GET_LINE, "cardedit.prompt")) { if (inputData.step == 0) { ret.exitCode = 0; ret.writeTxt = "admin"; } else if (inputData.step == 1) { ret.exitCode = 0; ret.writeTxt = "generate"; } else { ret.exitCode = 0; ret.quitNow=true; ret.writeTxt = "quit"; } ++inputData.step; } else if (keyEdit.doCheck(GET_LINE, "cardedit.genkeys.backup_enc") || keyEdit.doCheck(GET_BOOL, "cardedit.genkeys.backup_enc")) { ret.exitCode = 0; ret.writeTxt = inputData.backupKey; } else if (keyEdit.doCheck(GET_BOOL, "cardedit.genkeys.replace_keys")) { ret.exitCode = 0; ret.writeTxt = "Y"; } else if (keyEdit.doCheck(GET_HIDDEN, "passphrase.adminpin.ask")) { GetPin(inputData.parent, EnigGetString("enterAdminPin"), ret); } else if (keyEdit.doCheck(GET_HIDDEN, "passphrase.pin.ask")) { GetPin(inputData.parent, EnigGetString("enterCardPin"), ret); } else if (keyEdit.doCheck(GET_HIDDEN, "passphrase.enter")) { ret.exitCode = 0; ret.writeTxt = inputData.backupPasswd; } else if (keyEdit.doCheck(GET_LINE, "keygen.valid")) { ret.exitCode = 0; ret.writeTxt = inputData.expiry; } else if (keyEdit.doCheck(GET_LINE, "keygen.name")) { ret.exitCode = 0; ret.writeTxt = inputData.name; } else if (keyEdit.doCheck(GET_LINE, "keygen.email")) { ret.exitCode = 0; ret.writeTxt = inputData.email; } else if (keyEdit.doCheck(GET_LINE, "keygen.comment")) { ret.exitCode = 0; if (inputData.comment) { ret.writeTxt = inputData.comment; } else { ret.writeTxt=""; } } else { ret.quitNow=true; ERROR_LOG("Unknown command prompt: "+keyEdit.getText()+"\n"); ret.exitCode=-1; } } function cardAdminDataCallback(inputData, keyEdit, ret) { ret.writeTxt = ""; ret.errorMsg = ""; var pinObj={}; if (keyEdit.doCheck(GET_LINE, "cardedit.prompt")) { ++inputData.step; ret.exitCode = 0; switch(inputData.step) { case 1: ret.writeTxt = "admin"; break; case 2: ret.writeTxt = "name"; break; case 3: ret.writeTxt = "lang"; break; case 4: ret.writeTxt = "sex"; break; case 5: ret.writeTxt = "url"; break; case 6: ret.writeTxt = "login"; break; case 7: if (inputData.forcepin != 0) { ret.writeTxt = "forcesig"; break; } default: ret.writeTxt = "quit"; ret.quitNow=true; break; } } else if (keyEdit.doCheck(GET_HIDDEN, "passphrase.adminpin.ask")) { GetPin(inputData.parent, EnigGetString("enterAdminPin"), ret); } else if (keyEdit.doCheck(GET_HIDDEN, "passphrase.pin.ask")) { GetPin(inputData.parent, EnigGetString("enterCardPin"), ret); } else if (keyEdit.doCheck(GET_LINE, "keygen.smartcard.surname")) { ret.exitCode = 0; ret.writeTxt = inputData.firstname; } else if (keyEdit.doCheck(GET_LINE, "keygen.smartcard.givenname")) { ret.exitCode = 0; ret.writeTxt = inputData.name; } else if (keyEdit.doCheck(GET_LINE, "cardedit.change_sex")) { ret.exitCode = 0; ret.writeTxt = inputData.sex; } else if (keyEdit.doCheck(GET_LINE, "cardedit.change_lang")) { ret.exitCode = 0; ret.writeTxt = inputData.lang; } else if (keyEdit.doCheck(GET_LINE, "cardedit.change_url")) { ret.exitCode = 0; ret.writeTxt = inputData.url; } else if (keyEdit.doCheck(GET_LINE, "cardedit.change_login")) { ret.exitCode = 0; ret.writeTxt = inputData.login; } else { ret.quitNow=true; ERROR_LOG("Unknown command prompt: "+keyEdit.getText()+"\n"); ret.exitCode=-1; } } function cardChangePinCallback(inputData, keyEdit, ret) { ret.writeTxt = ""; ret.errorMsg = ""; if (keyEdit.doCheck(GET_LINE, "cardedit.prompt")) { ++inputData.step; ret.exitCode=0; switch (inputData.step) { case 1: ret.writeTxt = "admin"; break; case 2: ret.writeTxt = "passwd"; break; default: ret.writeTxt = "quit"; ret.exitCode = 0; ret.quitNow=true; break; } } else if (keyEdit.doCheck(GET_HIDDEN, "passphrase.adminpin.ask")) { ret.exitCode=0; ret.writeTxt = inputData.adminPin; } else if (keyEdit.doCheck(GET_HIDDEN, "passphrase.pin.ask")) { ret.exitCode=0; ret.writeTxt = inputData.oldPin; } else if (keyEdit.doCheck(GET_HIDDEN, "passphrase.pin.new.ask") || keyEdit.doCheck(GET_HIDDEN, "passphrase.pin.repeat") || keyEdit.doCheck(GET_HIDDEN, "passphrase.adminpin.new.ask")) { ret.exitCode = 0; ret.writeTxt = inputData.newPin; } else if (keyEdit.doCheck(GET_LINE, "cardutil.change_pin.menu")) { ret.exitCode=0; ++inputData.pinStep; if (inputData.pinStep == 1) { ret.writeTxt = inputData.action.toString(); } else { ret.writeTxt = "Q"; } } else { ret.exitCode=-1; ret.quitNow=true; ERROR_LOG("Unknown command prompt: "+keyEdit.getText()+"\n"); } } /* Command Line handler service */ function EnigCLineService() {} EnigCLineService.prototype = { /* nsISupports */ QueryInterface : function handler_QI(iid) { if (iid.equals(nsISupports)) return this; if (nsICmdLineHandler && iid.equals(nsICmdLineHandler)) return this; if (nsICommandLineHandler && iid.equals(nsICommandLineHandler)) return this; throw Components.results.NS_ERROR_NO_INTERFACE; }, commandLineArgument: "-pgpkeyman", prefNameForStartup: "general.startup.pgpkeyman", chromeUrlForTask: "chrome://enigmail/content/enigmailKeyManager.xul", helpText: "Start with OpenPGP key manager", helpInfo : " -pgpkeyman Open the OpenPGP key manager", handlesArgs: false, defaultArgs: "", openWindowWithArgs: false } /* factory for command line handler service (EnigCLineService) */ var EnigCLineFactory = { createInstance : function (outer, iid) { if (outer != null) throw Components.results.NS_ERROR_NO_AGGREGATION; if (!iid.equals(nsICmdLineHandler) && !iid.equals(nsISupports)) throw Components.results.NS_ERROR_INVALID_ARG; return new EnigCLineService().QueryInterface(iid); } } diff --git a/public/nsIEnigMimeService.idl b/public/nsIEnigMimeService.idl index 68c8b034..67520e86 100644 --- a/public/nsIEnigMimeService.idl +++ b/public/nsIEnigMimeService.idl @@ -1,104 +1,107 @@ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "MPL"); you may not use this file except in * compliance with the MPL. You may obtain a copy of the MPL at * http://www.mozilla.org/MPL/ * * Software distributed under the MPL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the MPL * for the specific language governing rights and limitations under the * MPL. * * The Original Code is Enigmail. * * The Initial Developer of the Original Code is * Ramalingam Saravanan * Portions created by the Initial Developer are Copyright (C) 2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): + * Patrick Brunschwig * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "nsISupports.idl" interface nsIDOMNode; /** * EnigMime service */ [scriptable, uuid(847b3a40-7ab1-11d4-8f02-006008948af5)] interface nsIEnigMimeService : nsISupports { void init(); readonly attribute boolean initialized; readonly attribute string version; AString getPlainText(in nsIDOMNode domNode, in wstring findStr); void rememberEncrypted(in AUTF8String uri); void forgetEncrypted(in AUTF8String uri); boolean isEncrypted(in AUTF8String uri); + + AString getGpgPathFromRegistry(); }; %{C++ #define NS_ENIGMIMESERVICE_CONTRACTID "@mozdev.org/enigmail/enigmimeservice;1" #define NS_ENIGMIMESERVICE_CLASSNAME "Enigmail Mime Service" #define APPLICATION_XENIGMAIL_DUMMY "application/x-enigmail-dummy" #define MULTIPART_ENCRYPTED "multipart/encrypted" #define APPLICATION_PGP "application/pgp" #define NS_ENIGDUMMYHANDLER_CONTRACTID "@mozilla.org/mimecth;1?type=" APPLICATION_XENIGMAIL_DUMMY #define NS_ENIGENCRYPTEDHANDLER_CONTRACTID "@mozilla.org/mimecth;1?type=" MULTIPART_ENCRYPTED #define NS_ENIGPGPHANDLER_CONTRACTID "@mozilla.org/mimecth;1?type=" APPLICATION_PGP #define NS_ENIGCONTENTHANDLER_CLASSNAME "Enigmail Content Handler" #define NS_ENIGCONTENTHANDLERFACTORY_CONTRACTID "@mozilla.org/enigmail/contenthandler-factory;1" #define NS_ENIGCONTENTHANDLERFACTORY_CLASSNAME "Enigmail Content Handler Factory" #define NS_ENIGMIMESERVICE_CID \ { /* 847b3a41-7ab1-11d4-8f02-006008948af5 */ \ 0x847b3a41, 0x7ab1, 0x11d4, \ {0x8f, 0x02, 0x00, 0x60, 0x08, 0x94, 0x8a, 0xf5} } #define NS_ENIGCONTENTHANDLER_CID \ { /* 847b3a51-7ab1-11d4-8f02-006008948af5 */ \ 0x847b3a51, 0x7ab1, 0x11d4, \ {0x8f, 0x02, 0x00, 0x60, 0x08, 0x94, 0x8a, 0xf5} } #define NS_ENIGCONTENTHANDLERFACTORY_CID \ { /* 847b3a52-7ab1-11d4-8f02-006008948af5 */ \ 0x847b3a52, 0x7ab1, 0x11d4, \ {0x8f, 0x02, 0x00, 0x60, 0x08, 0x94, 0x8a, 0xf5} } %} ////////////////////////////////////////////////////////////////////////////// diff --git a/src/nsEnigMimeService.cpp b/src/nsEnigMimeService.cpp index 5ed958dc..1a52cb72 100644 --- a/src/nsEnigMimeService.cpp +++ b/src/nsEnigMimeService.cpp @@ -1,291 +1,318 @@ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "MPL"); you may not use this file except in * compliance with the MPL. You may obtain a copy of the MPL at * http://www.mozilla.org/MPL/ * * Software distributed under the MPL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the MPL * for the specific language governing rights and limitations under the * MPL. * * The Original Code is Enigmail. * * The Initial Developer of the Original Code is * Ramalingam Saravanan * Portions created by the Initial Developer are Copyright (C) 2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Patrick Brunschwig * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ // Logging of debug output // The following define statement should occur before any include statements #define FORCE_PR_LOG /* Allow logging even in release build */ #define MOZILLA_INTERNAL_API #include "mimeenig.h" #include "nsEnigModule.h" #include "nsEnigMimeService.h" #include "nspr.h" #include "nsString.h" #include "nsCOMPtr.h" #include "nsIDOMNode.h" #include "nsIDOMText.h" #include "nsIThread.h" #include "nsIComponentManager.h" #include "nsIComponentRegistrar.h" #include "nsIGenericFactory.h" #include "nsEnigContentHandler.h" #include "nsReadableUtils.h" #undef MOZILLA_INTERNAL_API NS_GENERIC_FACTORY_CONSTRUCTOR(nsEnigContentHandler) #ifdef PR_LOGGING PRLogModuleInfo* gEnigMimeServiceLog = NULL; #endif #define ERROR_LOG(args) PR_LOG(gEnigMimeServiceLog,PR_LOG_ERROR,args) #define WARNING_LOG(args) PR_LOG(gEnigMimeServiceLog,PR_LOG_WARNING,args) #define DEBUG_LOG(args) PR_LOG(gEnigMimeServiceLog,PR_LOG_DEBUG,args) // nsEnigMimeService implementation // nsISupports implementation NS_IMPL_THREADSAFE_ISUPPORTS1(nsEnigMimeService, nsIEnigMimeService) // nsEnigMimeService implementation nsEnigMimeService::nsEnigMimeService() : mDummyHandler(PR_FALSE), mInitialized(PR_FALSE) { nsresult rv; NS_INIT_ISUPPORTS(); #ifdef PR_LOGGING if (gEnigMimeServiceLog == nsnull) { gEnigMimeServiceLog = PR_NewLogModule("nsEnigMimeService"); } #endif #ifdef FORCE_PR_LOG nsCOMPtr myThread; rv = nsIThread::GetCurrent(getter_AddRefs(myThread)); DEBUG_LOG(("nsEnigMimeService:: <<<<<<<<< CTOR(%p): myThread=%p\n", this, myThread.get())); #endif static const nsModuleComponentInfo info = { NS_ENIGCONTENTHANDLER_CLASSNAME, NS_ENIGCONTENTHANDLER_CID, NS_ENIGDUMMYHANDLER_CONTRACTID, nsEnigContentHandlerConstructor, }; // Create a generic factory for the dummy content handler nsCOMPtr factory; rv = NS_NewGenericFactory(getter_AddRefs(factory), &info); if (NS_SUCCEEDED(rv)) { // Register factory for dummy handler nsCOMPtr registrar; rv = NS_GetComponentRegistrar(getter_AddRefs(registrar)); if (NS_FAILED(rv)) return; rv = registrar->RegisterFactory(info.mCID, info.mDescription, info.mContractID, factory); if (NS_SUCCEEDED(rv)) { mDummyHandler = PR_TRUE; } } } nsEnigMimeService::~nsEnigMimeService() { nsresult rv; #ifdef FORCE_PR_LOG nsCOMPtr myThread; rv = nsIThread::GetCurrent(getter_AddRefs(myThread)); DEBUG_LOG(("nsEnigMimeService:: >>>>>>>>> DTOR(%p): myThread=%p\n", this, myThread.get())); #endif } /////////////////////////////////////////////////////////////////////////////// // nsIEnigMimeService methods: /////////////////////////////////////////////////////////////////////////////// NS_IMETHODIMP nsEnigMimeService::Init() { nsresult rv; DEBUG_LOG(("nsEnigContenthandler::Init:\n")); if (!mimeEncryptedClassP) { ERROR_LOG(("nsEnigContenthandler::Init: ERROR mimeEncryptedClassPis null\n")); return NS_ERROR_FAILURE; } if (!mDummyHandler) { ERROR_LOG(("nsEnigContenthandler::Init: ERROR content handler for %s not initialized\n", APPLICATION_XENIGMAIL_DUMMY)); return NS_ERROR_FAILURE; } static const nsModuleComponentInfo info = { NS_ENIGCONTENTHANDLER_CLASSNAME, NS_ENIGCONTENTHANDLER_CID, NS_ENIGENCRYPTEDHANDLER_CONTRACTID, nsEnigContentHandlerConstructor, }; // Create a generic factory for the content handler nsCOMPtr factory; rv = NS_NewGenericFactory(getter_AddRefs(factory), &info); if (NS_FAILED(rv)) return rv; nsCOMPtr registrar; rv = NS_GetComponentRegistrar(getter_AddRefs(registrar)); if (NS_FAILED(rv)) return rv; // Register factory rv = registrar->RegisterFactory(info.mCID, info.mDescription, info.mContractID, factory); if (NS_FAILED(rv)) return rv; DEBUG_LOG(("nsEnigMimeService::Init: registered %s\n", info.mContractID)); mInitialized = PR_TRUE; return NS_OK; } NS_IMETHODIMP nsEnigMimeService::GetInitialized(PRBool *_retval) { if (!_retval) return NS_ERROR_NULL_POINTER; *_retval = mInitialized; DEBUG_LOG(("nsEnigMimeService::GetInitialized: %d\n", (int) mInitialized)); return NS_OK; } NS_IMETHODIMP nsEnigMimeService::GetVersion(char **_retval) { *_retval = nsCRT::strdup(ENIGMIME_VERSION); if (!*_retval) return NS_ERROR_OUT_OF_MEMORY; DEBUG_LOG(("nsEnigMimeService::GetVersion: %s\n", *_retval)); return NS_OK; } NS_IMETHODIMP nsEnigMimeService::GetPlainText(nsIDOMNode* domNode, const PRUnichar* findStr, nsAString& text) { nsresult rv; nsAutoString outStr; //DEBUG_LOG(("nsEnigMimeService::GetPlainText:\n")); PRUint16 nodeType; rv = domNode->GetNodeType(&nodeType); if (NS_FAILED(rv)) return rv; if (nodeType == nsIDOMNode::TEXT_NODE) { // Text node nsCOMPtr domText( do_QueryInterface(domNode) ); rv = domText->GetData(outStr); if (NS_FAILED(rv)) return rv; } else { // Iterate over all child nodes nsCOMPtr child; rv = domNode->GetFirstChild(getter_AddRefs(child)); if (NS_FAILED(rv)) return NS_OK; while (child) { nsAutoString temStr; rv = GetPlainText(child, nsnull, temStr); if (NS_FAILED(rv)) return rv; outStr.Append(temStr); nsCOMPtr temp = child; rv = temp->GetNextSibling(getter_AddRefs(child)); if (NS_FAILED(rv)) break; } } if (outStr.FindChar(0xA0) >= 0) { // Replace non-breaking spaces with plain spaces outStr.ReplaceChar(0xA0, ' '); } if (findStr && nsCharTraits::length(findStr) && (outStr.Find(findStr) < 0) ) { // Substring not found; return empty string outStr.Truncate(0); } text = outStr; return NS_OK; } NS_IMETHODIMP nsEnigMimeService::RememberEncrypted(const nsACString & uri) { // Assuming duplicates are allowed. mEncryptedURIs.AppendCString(nsCString(uri)); return NS_OK; } NS_IMETHODIMP nsEnigMimeService::ForgetEncrypted(const nsACString & uri) { // Assuming, this will only remove one copy of the string, if the array // contains multiple copies of the same string. mEncryptedURIs.RemoveCString(nsCString(uri)); return NS_OK; } NS_IMETHODIMP nsEnigMimeService::IsEncrypted(const nsACString & uri, PRBool *_retval) { *_retval = (mEncryptedURIs.IndexOf(nsCString(uri)) != -1); return NS_OK; } + +NS_IMETHODIMP +nsEnigMimeService::GetGpgPathFromRegistry(nsAString& retval) { + +#ifdef XP_WIN + HKEY key; + DWORD type, length; + unsigned char gpgProg[MAX_PATH]; + + if (::RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\GNU\\GNUPG", 0, KEY_READ, &key) != ERROR_SUCCESS) { + return NS_ERROR_FAILURE; + } + + if (::RegQueryValueEx(key, "Install Directory", 0, &type, gpgProg, &length) != ERROR_SUCCESS) { + return NS_ERROR_FAILURE; + } + // printf("length: %d\nstring: %s\n", length, gpgProg); + nsAutoString gpgPath; + gpgPath.AssignWithConversion((char*)gpgProg); + retval = gpgPath; + return NS_OK; + +#else + return NS_ERROR_FAILURE; +#endif + +} diff --git a/src/nsEnigMimeService.h b/src/nsEnigMimeService.h index 407e901b..9e2ca2e5 100644 --- a/src/nsEnigMimeService.h +++ b/src/nsEnigMimeService.h @@ -1,65 +1,69 @@ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "MPL"); you may not use this file except in * compliance with the MPL. You may obtain a copy of the MPL at * http://www.mozilla.org/MPL/ * * Software distributed under the MPL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the MPL * for the specific language governing rights and limitations under the * MPL. * * The Original Code is Enigmail. * * The Initial Developer of the Original Code is * Ramalingam Saravanan * Portions created by the Initial Developer are Copyright (C) 2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Patrick Brunschwig * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #ifndef _nsEnigMimeService_h_ #define _nsEnigMimeService_h_ #include "nsIEnigMimeService.h" #include "nsCOMPtr.h" #include "nsVoidArray.h" +#ifdef XP_WIN +#include +#endif + class nsEnigMimeService : public nsIEnigMimeService { public: NS_DECL_ISUPPORTS NS_DECL_NSIENIGMIMESERVICE nsEnigMimeService(); virtual ~nsEnigMimeService(); // Define a Create method to be used with a factory: static NS_METHOD Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); protected: PRBool mDummyHandler; PRBool mInitialized; nsCStringArray mEncryptedURIs; }; #endif