2
* The contents of this file are subject to the Mozilla Public
3
* License Version 1.1 (the "MPL"); you may not use this file
4
* except in compliance with the MPL. You may obtain a copy of
5
* the MPL at http://www.mozilla.org/MPL/
7
* Software distributed under the MPL is distributed on an "AS
8
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
9
* implied. See the MPL for the specific language governing
10
* rights and limitations under the MPL.
12
* The Original Code is Enigmail.
14
* The Initial Developer of this code is Patrick Brunschwig.
15
* Portions created by Patrick Brunschwig <patrick.brunschwig@gmx.net>
16
* are Copyright (C) 2004-2005 Patrick Brunschwig.
17
* All Rights Reserved.
21
* Alternatively, the contents of this file may be used under the
22
* terms of the GNU General Public License (the "GPL"), in which case
23
* the provisions of the GPL are applicable instead of
24
* those above. If you wish to allow use of your version of this
25
* file only under the terms of the GPL and not to allow
26
* others to use your version of this file under the MPL, indicate
27
* your decision by deleting the provisions above and replace them
28
* with the notice and other provisions required by the GPL.
29
* If you do not delete the provisions above, a recipient
30
* may use your version of this file under either the MPL or the
34
// Uses: chrome://enigmail/content/enigmailCommon.js
36
// Initialize enigmailCommon
37
EnigInitCommon("enigmailSearchKey");
42
const ENIG_DEFAULT_HKP_PORT = "11371";
43
const ENIG_DEFAULT_LDAP_PORT = "389";
45
const ENIG_IMG_NOT_SELECTED = "chrome://enigmail/content/check0.png";
46
const ENIG_IMG_SELECTED = "chrome://enigmail/content/check1.png";
47
const ENIG_IMG_DISABLED = "chrome://enigmail/content/check2.png";
49
const ENIG_CONN_TYPE_HTTP = 1;
50
const ENIG_CONN_TYPE_GPGKEYS = 2;
52
const KEY_EXPIRED="e";
53
const KEY_REVOKED="r";
54
const KEY_INVALID="i";
55
const KEY_DISABLED="d";
56
const KEY_NOT_VALID=KEY_EXPIRED+KEY_REVOKED+KEY_INVALID+KEY_DISABLED;
59
return str.replace(/^(\s*)(.*)/, "$2").replace(/\s+$/,"");
64
window.arguments[RESULT].importedKeys=0;
66
var keyserver = window.arguments[INPUT].keyserver;
68
if (keyserver.search(/[a-zA-Z0-9\-\_\.]+:\/\//)==0) {
69
protocol=keyserver.replace(/^([a-zA-Z0-9\-\_\.]+)(:\/\/.*)/, "$1");
70
if (protocol.search(/hkp/i) >= 0) {
73
keyserver=keyserver.replace(/^[a-zA-Z0-9\-\_\.]+:\/\//, "");
82
port = ENIG_DEFAULT_HKP_PORT;
85
port = ENIG_DEFAULT_LDAP_PORT;
89
var m = keyserver.match(/^(.+)(:)(\d+)$/);
90
if (m && m.length==4) {
95
window.enigRequest = {
96
searchList: window.arguments[INPUT].searchList,
102
requestType: (EnigGetPref("useGpgKeysTool") ? ENIG_CONN_TYPE_GPGKEYS : ENIG_CONN_TYPE_HTTP),
103
gpgkeysRequest: null,
104
progressMeter: document.getElementById("dialog.progress"),
105
httpInProgress: false
108
window.enigRequest.progressMeter.mode="undetermined";
110
if (window.arguments[INPUT].searchList.length == 1 &&
111
window.arguments[INPUT].searchList[0].search(/^0x[A-Fa-f0-9]{8,16}$/) == 0) {
112
// shrink dialog and start download if just one key ID provided
114
window.enigRequest.dlKeyList = [ window.arguments[INPUT].searchList ];
115
document.getElementById("keySelGroup").setAttribute("collapsed", "true");
116
window.sizeToContent();
117
window.resizeBy(0, -320);
118
window.setTimeout(startDownload, 10);
121
switch (window.enigRequest.requestType) {
122
case ENIG_CONN_TYPE_HTTP:
123
enigNewHttpRequest(nsIEnigmail.SEARCH_KEY, enigScanKeys);
125
case ENIG_CONN_TYPE_GPGKEYS:
126
enigNewGpgKeysRequest(nsIEnigmail.SEARCH_KEY, enigScanKeys);
134
function onAccept () {
135
DEBUG_LOG("enigmailSearchKey.js: onAccept\n");
137
var keySelList = document.getElementById("enigmailKeySel");
138
var treeChildren=keySelList.getElementsByAttribute("id", "enigmailKeySelChildren")[0];
140
window.enigRequest.dlKeyList = [];
141
var item=treeChildren.firstChild;
143
var aRows = item.getElementsByAttribute("id","indicator")
146
if (elem.getAttribute("active") == "1") {
147
window.enigRequest.dlKeyList.push(item.getAttribute("id"));
150
item = item.nextSibling;
152
return startDownload();
156
function startDownload() {
157
DEBUG_LOG("enigmailSearchKey.js: startDownload\n");
158
if (window.enigRequest.dlKeyList.length>0) {
159
window.enigRequest.progressMeter.value = 0;
160
window.enigRequest.progressMeter.mode = "undetermined";
161
document.getElementById("progress.box").removeAttribute("hidden");
162
document.getElementById("dialog.accept").setAttribute("disabled", "true");
163
window.enigRequest.keyNum = 0;
164
window.enigRequest.errorTxt="";
165
switch (window.enigRequest.requestType) {
166
case ENIG_CONN_TYPE_HTTP:
167
enigNewHttpRequest(nsIEnigmail.DOWNLOAD_KEY, enigImportKeys);
169
case ENIG_CONN_TYPE_GPGKEYS:
170
enigNewGpgKeysRequest(nsIEnigmail.DOWNLOAD_KEY, enigImportKeys);
174
// do not yet close the window, so that we can display some progress info
182
function onCancel() {
183
if (window.enigRequest.httpInProgress) {
186
if ((typeof(window.enigHttpReq) == "object") &&
187
(window.enigHttpReq.readyState != 4)) {
188
window.enigHttpReq.abort();
190
window.enigRequest.httpInProgress=false;
191
if (window.enigRequest.gpgkeysRequest) {
192
enigGpgkeysCloseRequest();
201
function enigStatusError () {
202
DEBUG_LOG("enigmailSearchKey.js: enigStatusError\n");
203
window.enigRequest.httpInProgress=false;
204
EnigAlert(EnigGetString("noKeyserverConn", this.channel.originalURI.prePath));
208
function enigCloseDialog() {
209
document.getElementById("enigmailSearchKeyDlg").cancelDialog();
213
function enigStatusLoaded (event) {
214
DEBUG_LOG("enigmailSearchKey.js: enigStatusLoaded\n");
216
if (this.status == 200) {
217
// de-HTMLize the result
218
var htmlTxt = this.responseText.replace(/<([^<>]+)>/g, "");
220
this.requestCallbackFunc(ENIG_CONN_TYPE_HTTP, htmlTxt);
222
else if (this.status == 500 && this.statusText=="OK") {
223
this.requestCallbackFunc(ENIG_CONN_TYPE_HTTP, "no keys found");
225
else if (this.statusText!="OK") {
226
EnigAlert(EnigGetString("keyDownloadFailed", this.statusText));
234
function enigImportKeys (connType, txt, errorTxt) {
235
DEBUG_LOG("enigmailSearchKey.js: enigImportKeys\n");
237
window.enigRequest.keyNum++;
238
window.enigRequest.progressMeter.mode = "determined";
239
window.enigRequest.progressMeter.value = (100 * window.enigRequest.keyNum / window.enigRequest.dlKeyList.length).toFixed(0);
241
if (txt.search(/^\[GNUPG:\] IMPORT_RES/m) < 0) {
242
if (!enigImportHtmlKeys(txt)) return;
245
window.enigRequest.errorTxt +=errorTxt+"\n";
248
if (txt.search(/^\[GNUPG:\] IMPORT_RES/m) >= 0) {
249
window.arguments[RESULT].importedKeys++;
252
if (window.enigRequest.dlKeyList.length > window.enigRequest.keyNum) {
254
case ENIG_CONN_TYPE_HTTP:
255
enigNewHttpRequest(nsIEnigmail.DOWNLOAD_KEY, window.enigHttpReq.requestCallbackFunc);
257
case ENIG_CONN_TYPE_GPGKEYS:
258
enigNewGpgKeysRequest(nsIEnigmail.DOWNLOAD_KEY, window.enigRequest.callbackFunction);
262
else if (window.enigRequest.errorTxt) {
263
EnigLongAlert(window.enigRequest.errorTxt);
266
window.enigRequest.httpInProgress=false;
271
function enigImportHtmlKeys(txt) {
272
var errorMsgObj = new Object();
274
var enigmailSvc = GetEnigmailSvc();
278
var uiFlags = nsIEnigmail.UI_ALLOW_KEY_IMPORT;
279
var r = enigmailSvc.importKey(window, uiFlags, txt,
280
window.enigRequest.dlKeyList[window.enigRequest.keyNum-1],
282
if (errorMsgObj.value)
283
EnigAlert(errorMsgObj.value);
285
window.arguments[RESULT].importedKeys++;
292
function enigNewHttpRequest(requestType, requestCallbackFunc) {
293
DEBUG_LOG("enigmailSearchKey.js: enigNewHttpRequest\n");
295
switch (window.enigRequest.protocol) {
297
window.enigRequest.protocol = "http";
302
var msg=EnigGetString("protocolNotSupported", window.enigRequest.protocol);
303
if (! EnigGetPref("useGpgKeysTool"))
304
msg += " "+EnigGetString("gpgkeysDisabled");
310
var httpReq = new XMLHttpRequest();
312
switch (requestType) {
313
case nsIEnigmail.SEARCH_KEY:
314
var pubKey = escape("<"+trim(window.enigRequest.searchList[window.enigRequest.keyNum])+">");
315
reqCommand = window.enigRequest.protocol+"://"+window.enigRequest.keyserver+":"+window.enigRequest.port+"/pks/lookup?search="+pubKey+"&op=index";
317
case nsIEnigmail.DOWNLOAD_KEY:
318
var keyId = escape(trim(window.enigRequest.dlKeyList[window.enigRequest.keyNum]));
319
reqCommand = window.enigRequest.protocol+"://"+window.enigRequest.keyserver+":"+window.enigRequest.port+"/pks/lookup?search="+keyId+"&op=get";
322
EnigAlert("Unknown request type "+requestType);
326
window.enigRequest.httpInProgress=true;
327
httpReq.open("GET", reqCommand);
328
httpReq.onerror=enigStatusError;
329
httpReq.onload=enigStatusLoaded;
330
httpReq.requestCallbackFunc = requestCallbackFunc;
331
window.enigHttpReq = httpReq;
336
function enigScanKeys(connType, htmlTxt) {
337
DEBUG_LOG("enigmailSearchKey.js: enigScanKeys\n");
339
window.enigRequest.keyNum++;
340
window.enigRequest.progressMeter.mode = "determined";
341
window.enigRequest.progressMeter.value = (100 * window.enigRequest.keyNum / window.enigRequest.searchList.length).toFixed(0);
344
case ENIG_CONN_TYPE_HTTP:
345
// interpret HTML codes (e.g. <)
346
var domParser = new DOMParser();
347
// needs improvement: result is max. 4096 bytes long!
348
var htmlNode = domParser.parseFromString("<p>" + htmlTxt + "</p>", "text/xml");
350
if (htmlNode.firstChild.nodeName=="parsererror") {
351
EnigAlert("internalError");
354
enigScanHtmlKeys(htmlNode.firstChild.firstChild.data);
356
case ENIG_CONN_TYPE_GPGKEYS:
357
enigScanGpgKeys(EnigConvertGpgToUnicode(unescape(htmlTxt)));
360
ERROR_LOG("bizarre connType: "+connType+"\n");
363
if (window.enigRequest.searchList.length > window.enigRequest.keyNum) {
365
case ENIG_CONN_TYPE_HTTP:
366
enigNewHttpRequest(nsIEnigmail.SEARCH_KEY, window.enigHttpReq.requestCallbackFunc);
368
case ENIG_CONN_TYPE_GPGKEYS:
369
enigNewGpgKeysRequest(nsIEnigmail.SEARCH_KEY, window.enigRequest.callbackFunction);
374
window.enigRequest.httpInProgress=false;
375
enigPopulateList(window.enigRequest.keyList);
376
document.getElementById("progress.box").setAttribute("hidden", "true");
377
if (window.enigRequest.keyList.length == 0) {
378
EnigAlert(EnigGetString("noKeyFound"));
382
document.getElementById("dialog.accept").removeAttribute("disabled");
387
function enigScanHtmlKeys (txt) {
388
DEBUG_LOG("enigmailSearchKey.js: enigScanHtmlKeys\n");
390
var lines=txt.split(/(\n\r|\n|\r)/);
392
for (i=0; i<lines.length; i++) {
393
if (lines[i].search(/^\s*pub /)==0) {
396
// first, append prev. key to keylist
397
window.enigRequest.keyList.push(key);
400
var m=lines[i].match(/(\d+[a-zA-Z]?\/)([0-9a-fA-F]+)(\s+[\d\/\-\.]+\s+)(.*)/);
401
if (m && m.length>0 ) {
407
if (m[4].search(/.+<.+@.+>/)>=0) {
408
if (! ignoreUid(m[4])) key.uid.push(trim(m[4]));
410
else if (m[4].search(/key (revoked|expired|disabled)/i)>=0) {
411
DEBUG_LOG("revoked key id "+m[4]+"\n");
419
var uid = trim(lines[i]);
420
if (uid.length>0 && ! ignoreUid(uid))
426
// append prev. key to keylist
428
window.enigRequest.keyList.push(key);
433
function enigScanGpgKeys(txt) {
434
DEBUG_LOG("enigmailSearchKey.js: enigScanGpgKeys\n");
435
DEBUG_LOG("got text: "+txt+"\n");
437
var lines=txt.split(/(\r\n|\n|\r)/);
440
for (var i=0; i<lines.length; i++) {
441
if (outputType == 0 && lines[i].search(/^COUNT \d+\s*$/)==0) {
445
if (outputType == 0 && lines[i].search(/^pub:[\da-fA-F]{8}/)==0) {
448
if (outputType==1 && (lines[i].search(/^([a-fA-F0-9]{8}){1,2}:/))==0) {
449
// output from gpgkeys_* protocol version 0
451
var m=lines[i].split(/:/);
452
if (m && m.length>0 ) {
454
if (key.keyId == m[0]) {
455
if (! ignoreUid(m[i])) key.uid.push(trim(m[1]));
458
window.enigRequest.keyList.push(key);
463
var dat=new Date(m[3]*1000);
464
var month=String(dat.getMonth()+101).substr(1);
465
var day=String(dat.getDate()+100).substr(1);
468
created: dat.getFullYear()+"-"+month+"-"+day,
471
if (! ignoreUid(m[1])) key.uid.push(m[1]);
475
if (outputType==2 && (lines[i].search(/^pub:/))==0) {
476
// output from gpgkeys_* protocol version 1
478
m=lines[i].split(/:/);
479
if (m && m.length>1 ) {
481
window.enigRequest.keyList.push(key);
484
dat=new Date(m[4]*1000);
485
month=String(dat.getMonth()+101).substr(1);
486
day=String(dat.getDate()+100).substr(1);
489
created: dat.getFullYear()+"-"+month+"-"+day,
494
if (outputType==2 && (lines[i].search(/^uid:.+/))==0) {
495
// output from gpgkeys_* protocol version 1
497
m=lines[i].split(/:/);
498
if (m && m.length>1 ) {
499
if (key && ! ignoreUid(m[1])) key.uid.push(trim(m[1]));
504
// append prev. key to keylist
506
window.enigRequest.keyList.push(key);
510
// interaction with gpgkeys_xxx
512
function enigNewGpgKeysRequest(requestType, callbackFunction) {
513
DEBUG_LOG("enigmailSearchkey.js: enigNewGpgKeysRequest\n");
515
var enigmailSvc = GetEnigmailSvc();
517
EnigAlert(EnigGetString("accessError"));
521
window.enigRequest.callbackFunction = callbackFunction;
522
var requestObserver = new EnigRequestObserver(enigmailGpgkeysTerminate, null);
523
var errorMsgObj = new Object();
524
var ipcRequest = null;
525
window.enigRequest.gpgkeysRequest = null;
529
if (requestType == nsIEnigmail.SEARCH_KEY) {
530
var keyValue = window.enigRequest.searchList[window.enigRequest.keyNum];
533
keyValue = window.enigRequest.dlKeyList[window.enigRequest.keyNum];
536
ipcRequest = enigmailSvc.searchKey(requestType,
537
window.enigRequest.protocol,
538
window.enigRequest.keyserver,
539
window.enigRequest.port,
546
// calling gpgkeys_xxx failed, let's try builtin http variant
547
switch (window.enigRequest.protocol) {
551
window.enigRequest.requestType = ENIG_CONN_TYPE_HTTP;
552
enigNewHttpRequest(requestType, enigScanKeys);
555
EnigAlert(EnigGetString("gpgKeysFailed", window.enigRequest.protocol));
561
window.enigRequest.gpgkeysRequest = ipcRequest;
563
WRITE_LOG("enigmailSearchkey.js: Start: window.enigRequest.gpgkeysRequest = "+window.enigRequest.gpgkeysRequest+"\n");
568
function enigGpgkeysCloseRequest() {
569
DEBUG_LOG("enigmailSearchkey.js: CloseRequest\n");
571
if (window.enigRequest.gpgkeysRequest) {
573
var searchkeyProcess = window.enigRequest.gpgkeysRequest.pipeTransport;
574
if (searchkeyProcess)
575
searchkeyProcess.terminate();
578
window.enigRequest.gpgkeysRequest.close(true);
579
window.enigRequest.gpgkeysRequest = null;
583
function enigmailGpgkeysTerminate(terminateArg, ipcRequest) {
584
DEBUG_LOG("enigmailSearchkey.js: Terminate: "+ipcRequest+"\n");
586
var gpgkeysRequest = window.enigRequest.gpgkeysRequest;
587
var gpgkeysProcess = gpgkeysRequest.pipeTransport;
588
var enigmailSvc = GetEnigmailSvc();
590
var console = gpgkeysRequest.stdoutConsole;
597
console = console.QueryInterface(Components.interfaces.nsIPipeConsole);
601
ERROR_LOG("enigmailSearchkey.js: Terminate(): cannot join stdout\n");
604
if (console && console.hasNewData()) {
605
DEBUG_LOG("enigmailSearchkey.js: Terminate(): stdout.hasNewData\n");
606
txt = console.getData();
609
DEBUG_LOG("enigmailSearchkey.js: Terminate(): stdout - no data??\n");
610
txt = console.getData();
612
console = gpgkeysRequest.stderrConsole;
613
console = console.QueryInterface(Components.interfaces.nsIPipeConsole);
614
if (console && console.hasNewData()) {
615
DEBUG_LOG("enigmailSearchkey.js: Terminate(): stderr.hasNewData\n");
616
errorTxt = console.getData();
617
CONSOLE_LOG(errorTxt+"\n");
620
if (gpgkeysProcess && !gpgkeysProcess.isAttached()) {
621
gpgkeysProcess.terminate();
622
var exitCode = gpgkeysProcess.exitCode();
623
DEBUG_LOG("enigmailGpgkeysConsole: exitCode = "+exitCode+"\n");
625
exitCode = enigmailSvc.fixExitCode(exitCode, 0);
629
enigGpgkeysCloseRequest();
632
window.enigRequest.callbackFunction(ENIG_CONN_TYPE_GPGKEYS, txt, errorTxt);
640
function enigPopulateList(keyList) {
641
DEBUG_LOG("enigmailSearchKey.js: enigPopulateList\n");
643
var sortUsers = function (a,b) {
644
if (a.uid[0]<b.uid[0]) { return -1; } else {return 1; }
647
keyList.sort(sortUsers);
649
var treeList = document.getElementById("enigmailKeySel");
650
var treeChildren=treeList.getElementsByAttribute("id", "enigmailKeySelChildren")[0];
653
for (var i=0; i<keyList.length; i++) {
654
treeItem = enigUserSelCreateRow(keyList[i].keyId, false, keyList[i].uid[0], keyList[i].created, "");
655
if (keyList[i].uid.length>1) {
656
treeItem.setAttribute("container", "true");
657
var subChildren=document.createElement("treechildren");
658
for (j=1; j<keyList[i].uid.length; j++) {
659
var subItem=enigUserSelCreateRow(keyList[i].keyId, true, keyList[i].uid[j], "", "");
660
subChildren.appendChild(subItem);
662
treeItem.appendChild(subChildren);
664
treeChildren.appendChild(treeItem);
667
if (keyList.length == 1) {
668
// activate found item if just one key found
669
enigSetActive(treeItem.firstChild.firstChild, 1);
673
function enigUserSelCreateRow (keyId, subKey, userId, dateField, trustStatus) {
674
var selectCol=document.createElement("treecell");
675
selectCol.setAttribute("id", "indicator");
676
var expCol=document.createElement("treecell");
677
var userCol=document.createElement("treecell");
678
userCol.setAttribute("id", "name");
679
if (trustStatus.charAt(0)==KEY_EXPIRED) {
680
expCol.setAttribute("label", EnigGetString("selKeyExpired", dateField));
683
expCol.setAttribute("label", dateField);
686
expCol.setAttribute("id", "expiry");
687
userCol.setAttribute("label", userId);
688
var keyCol=document.createElement("treecell");
689
keyCol.setAttribute("id", "keyid");
691
enigSetActive(selectCol, -1);
692
keyCol.setAttribute("label", "");
695
enigSetActive(selectCol, 0);
696
keyCol.setAttribute("label", keyId.substr(-8));
700
var userRow=document.createElement("treerow");
701
userRow.appendChild(selectCol);
702
userRow.appendChild(userCol);
703
userRow.appendChild(expCol);
704
userRow.appendChild(keyCol);
705
var treeItem=document.createElement("treeitem");
706
treeItem.setAttribute("id", "0x"+keyId);
707
treeItem.appendChild(userRow);
711
function enigmailKeySelCallback(event) {
712
DEBUG_LOG("enigmailSearchKey.js: enigmailKeySelCallback\n");
714
var Tree = document.getElementById("enigmailKeySel");
718
Tree.treeBoxObject.getCellAt(event.clientX, event.clientY, row, col, elt);
723
var treeItem = Tree.contentView.getItemAtIndex(row.value);
724
Tree.currentItem=treeItem;
725
if (col.value.id != "selectionCol")
728
var aRows = treeItem.getElementsByAttribute("id","indicator")
732
if (elem.getAttribute("active") == "1") {
733
enigSetActive(elem, 0);
734
} else if (elem.getAttribute("active") == "0") {
735
enigSetActive(elem, 1);
740
// set the "active" flag and the corresponding image
741
function enigSetActive(element, status) {
744
element.setAttribute("active", status.toString());
749
element.setAttribute("src", ENIG_IMG_NOT_SELECTED);
752
element.setAttribute("src", ENIG_IMG_SELECTED);
755
element.setAttribute("src", ENIG_IMG_DISABLED);
758
element.setAttribute("active", -1);
762
function ignoreUid(uid) {
763
const ignoreList = "{Test 555 <sdfg@gga.com>}";
764
return (ignoreList.indexOf("{"+trim(uid)+"}") >= 0);