Passed
Push — master ( af9535...602bb6 )
by EMP
01:29
created

main.js ➔ showFiles   F

Complexity

Conditions 33

Size

Total Lines 150
Code Lines 100

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 33
eloc 100
dl 0
loc 150
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like main.js ➔ showFiles often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
"use strict";
2
3
sodium.ready.then(function() {
4
5
let isReady = true;
6
let vaultOk = null;
7
8
const vault = new PostVault(function(ok) {
0 ignored issues
show
Bug introduced by
The variable PostVault seems to be never declared. If this is a global, consider adding a /** global: PostVault */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
9
	if (ok) vaultOk = false;
10
});
11
12
const ae = new AllEars(function(ok) {
13
	if (!ok) {
14
		document.getElementById("greeting").textContent = "Failed loading All-Ears";
15
		return;
16
	}
17
18
	try {
19
		if (localStorage.greeting) {
20
			document.getElementById("greeting").textContent = localStorage.greeting;
21
			document.getElementById("txt_pg").value = localStorage.greeting;
22
		} else localStorage.greeting = document.getElementById("greeting").textContent;
23
	} catch(e) {
24
		document.getElementById("btn_pg").disabled = true;
25
		document.getElementById("txt_pg").disabled = true;
26
		document.getElementById("txt_pg").className = "ita";
27
		document.getElementById("txt_pg").value = "LocalStorage inaccessible";
28
	}
29
30
	document.getElementById("txt_skey").maxLength = "64";
31
});
32
33
function TabState(cur, max, btnDele, btnUpdt) {
34
	this.cur = cur;
35
	this.max = max;
36
	this.btnDele = btnDele;
37
	this.btnUpdt = btnUpdt;
38
}
39
40
const tabs = [
41
	new TabState(0, 0, false, true), // Inbox
42
	new TabState(0, 0, false, false), // Outbx
43
	new TabState(0, 1, true,  false), // Write
44
	new TabState(0, 2, false, false), // Notes
45
	new TabState(0, 2, false, false) // Tools
46
];
47
48
function MsgInfo(msgIdHex, msgType, msgNum) {
49
	this.idHex = msgIdHex;
50
	this.type = msgType;
51
	this.num = msgNum;
52
}
53
54
let msgDisplay = new MsgInfo(null, null, null);
55
let showHeaders = false;
56
let rowsPerPage = 0;
57
58
let tab = 0;
59
const TAB_INBOX = 0;
60
const TAB_DRBOX = 1;
61
const TAB_WRITE = 2;
62
const TAB_NOTES = 3;
63
const TAB_TOOLS = 4;
64
65
// Helper functions
66
function errorDialog(err, focusAfter) {
67
	if (typeof(err) !== "number" || err < 1) return;
68
69
	let btnDisable = [];
70
	const buttons = document.querySelectorAll("nav > button");
71
	buttons.forEach(function(btn) {
72
		btnDisable.push(btn.disabled);
73
		btn.disabled = true;
74
	});
75
76
	const errMsg = ae.getErrorMessage(err);
77
78
	const dlg = document.querySelector("dialog");
79
	dlg.children[0].style.height = getComputedStyle(document.querySelector("#main1 > div[class='mid']")).height;
80
	dlg.querySelector("h1").textContent = "ERROR 0x" + err.toString(16).padStart(2, "0").toUpperCase();
81
	dlg.querySelector("p").textContent = (typeof(errMsg) === "string") ? errMsg : errMsg[1];
82
	dlg.show();
83
84
	document.querySelector("dialog > div").onclick = function() {
85
		buttons.forEach(function(btn, i) {btn.disabled = btnDisable[i];});
86
		dlg.close();
87
		if (focusAfter) focusAfter.focus();
88
	};
89
90
	document.onkeyup = function(event) {
91
		document.onkeyup = null;
92
		event.preventDefault();
93
94
		buttons.forEach(function(btn, i) {btn.disabled = btnDisable[i];});
95
		dlg.close();
96
		if (focusAfter) focusAfter.focus();
97
	};
98
}
99
100
function getCountryFlag(countryCode) {
101
	return (!countryCode || countryCode.length !== 2 || countryCode === "??") ? "❔" : sodium.to_string(new Uint8Array([
102
		240, 159, 135, 166 + countryCode.codePointAt(0) - 65,
103
		240, 159, 135, 166 + countryCode.codePointAt(1) - 65
104
	]));
105
}
106
107
function getClockIcon(d) {
108
	const h24 = d.getUTCHours();
109
	let h12 = (h24 === 0 ? 12 : ((h24 > 12) ? h24 - 12 : h24));
110
111
	const m60 = (d.getUTCMinutes() * 60) + d.getUTCSeconds();
112
	let m30 = 0;
113
	if (m60 <= 900) { // <= 15: round down to this hour
114
		m30 = 0;
115
	} else if (m60 > 900 && m60 < 2700) { // 15..45: round to half-past this hour
116
		m30 = 12;
117
	} else { // >= 45: round up to next hour
118
		h12++;
119
		m30 = 0;
120
	}
121
122
	return String.fromCodePoint((128335 + h12) + m30);
123
}
124
125
function clearDisplay() {
126
	document.getElementById("btn_mnext").disabled = true;
127
	document.getElementById("btn_mprev").disabled = true;
128
	document.getElementById("readmsg_export").hidden = true;
129
130
	const el = document.querySelector("#readmsg_main > img, #readmsg_main > audio, #readmsg_main > video, #readmsg_main > embed, #readmsg_main > iframe");
131
	if (!el) return;
132
	if (el.src) URL.revokeObjectURL(el.src);
133
	el.remove();
134
}
135
136
function clearMsgFlags() {
137
	document.getElementById("readmsg_flags").children[0].replaceChildren();
138
}
139
140
function addMsgFlag(abbr, abbrTitle) {
141
	const parent = document.getElementById("readmsg_flags").children[0];
142
143
	const el = document.createElement("abbr");
144
	el.title = abbrTitle;
145
	el.textContent = abbr;
146
147
	parent.appendChild(document.createTextNode(" "));
148
	parent.appendChild(el);
149
}
150
151
function displayFile(isHistory, num, showNext) {
152
	if (num < 0 || num >= ae.getUplMsgCount()) return;
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
153
154
	const fileType = ae.getUplMsgType(num);
155
	if (!fileType) {
156
		if (isHistory) return;
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
157
		if (showNext === true) return displayFile(false, num + 1, true);
158
		if (showNext === false) return displayFile(false, num - 1, false);
159
		ae.downloadUplMsg(num); return;
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
160
	}
161
162
	clearDisplay();
163
	document.querySelector("article").scroll(0, 0);
164
	document.querySelector("article").setAttribute("data-msgid", ae.getUplMsgIdHex(num));
165
166
	document.getElementById("btn_mdele").disabled = false;
167
	document.getElementById("btn_msave").disabled = false;
168
	document.getElementById("btn_reply").disabled = true;
169
170
	document.getElementById("btn_msave").onclick = function() {ae.downloadUplMsg(num);};
171
172
	document.getElementById("readmsg_info").hidden = true;
173
	document.querySelector("#readmsg_main > h1").textContent = ae.getUplMsgTitle(num);
174
175
	msgDisplay = new MsgInfo(ae.getUplMsgIdHex(num), "upl", num);
176
	if (!isHistory) history.pushState({tab: tab, page: tabs[tab].cur, msg: msgDisplay}, null);
177
178
	document.getElementById("main2").hidden = false;
179
	document.getElementById("main1").hidden = !window.matchMedia("(min-width: 80em)").matches;
180
181
	document.getElementById("btn_mnext").disabled = (num === ae.getUplMsgCount() - 1);
182
	document.getElementById("btn_mprev").disabled = (num === 0);
183
	document.getElementById("btn_mnext").onclick = function() {displayFile(false, num + 1, true);};
184
	document.getElementById("btn_mprev").onclick = function() {displayFile(false, num - 1, false);};
185
186
	if (fileType === "text") {
187
		document.querySelector("#readmsg_main > pre").hidden = false;
188
		try {
189
			document.querySelector("#readmsg_main > pre").textContent = sodium.to_string(ae.getUplMsgBody(num));
190
		} catch(e) {
191
			document.querySelector("#readmsg_main > pre").textContent = "Failed decoding body: " + e.message;
192
		}
193
		return;
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
194
	}
195
196
	document.querySelector("#readmsg_main > pre").hidden = true;
197
	let el;
198
199
	switch (fileType) {
200
		case "image": {
201
			el = document.createElement("img");
202
			el.src = URL.createObjectURL(new Blob([ae.getUplMsgBody(num).buffer]));
203
			el.onclick = function() {
204
				if (!document.fullscreen)
205
					this.requestFullscreen();
206
				else
207
					document.exitFullscreen();
208
			};
209
		break;}
210
211
		case "audio":
212
		case "video": {
213
			el = document.createElement(fileType);
214
			el.controls = "controls";
215
			el.src = URL.createObjectURL(new Blob([ae.getUplMsgBody(num).buffer]));
216
		break;}
217
218
		case "pdf": {
219
			el = document.createElement("embed");
220
			el.type = "application/pdf";
221
			el.src = URL.createObjectURL(new Blob([ae.getUplMsgBody(num).buffer], {type: "application/pdf"}));
222
		break;}
223
224
		case "html": {
225
			el = document.createElement("iframe");
226
			el.allow = "vertical-scroll";
227
			el.sandbox = "";
228
			el.referrerPolicy = "no-referrer";
229
230
			try {
231
				const sanBody = document.createElement("body");
232
				sanBody.setHTML(sodium.to_string(ae.getUplMsgBody(num).buffer), {sanitizer: new Sanitizer({
0 ignored issues
show
Bug introduced by
The variable Sanitizer seems to be never declared. If this is a global, consider adding a /** global: Sanitizer */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
233
					"allowElements": [
234
						"a","div","p",
235
						"h1","h2","h3","h4","h5","h6",
236
						"em","strong","b","i","u"
237
					],
238
					'allowAttributes': {
239
						"href": ["*"]
240
					}
241
				})});
242
243
				el.srcdoc =
244
				"<html>" +
245
					"<head>" +
246
						"<style>" +
247
							"html, body {background: #080a08; color: #fff; scrollbar-color: #222 #333;}\n" +
248
							"body {opacity:0.55;}\n" +
249
							"body > *:first-child {margin-top: 0; padding-top: 0;}\n" +
250
							"a {color: #fff;}\n" +
251
							"button, input, select, textarea {background: #000; color: #fff;}\n" +
252
						"</style>" +
253
					"</head>" +
254
					sanBody.outerHTML +
255
				"</html>";
256
			} catch(e) {
257
				el.srcdoc = "<!doctype html><html><head><style>body {background: #080a08; color: #fff; opacity:0.55;} h1 {margin: 0;}</style><body><h1>Error</h1><p>" + e.message + "</p></body></html>";
258
			}
259
		break;}
260
261
		case "svg": {
262
			el = document.createElement("iframe");
263
			el.allow = "";
264
			el.sandbox = "";
265
			el.referrerPolicy = "no-referrer";
266
			el.srcdoc = "<!doctype><html><head><style>body,html,svg {margin: 0; padding: 0; border: 0; height: 100%; width: 100%; display: block; background: #080a08;}</style></head><body>" + sodium.to_string(ae.getUplMsgBody(num).buffer) + "</body></html>";
267
		break;}
268
269
		default: return;
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
270
	}
271
272
	document.getElementById("readmsg_main").appendChild(el);
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
273
}
274
275
document.getElementById("btn_leave").onclick = function() {
276
	document.getElementById("main2").hidden = true;
277
	document.getElementById("main1").hidden = false;
278
};
279
280
function displayMsg(isHistory, isInt, num) {
281
	clearDisplay();
282
	document.getElementById("btn_mdele").disabled = false;
283
284
	document.querySelector("article").scroll(0, 0);
285
	document.querySelector("article").setAttribute("data-msgid", isInt? ae.getIntMsgIdHex(num) : ae.getExtMsgIdHex(num));
286
287
	document.getElementById("btn_msave").disabled = false;
288
	document.getElementById("btn_msave").onclick = function() {displayExport(false, isInt, num);};
289
290
	const ts = isInt? ae.getIntMsgTime(num) : ae.getExtMsgTime(num);
291
292
	if (!isInt || (ae.getIntMsgFrom(num) !== "public" && ae.getIntMsgFrom(num) !== "system")) {
293
		document.getElementById("btn_reply").disabled = false;
294
295
		document.getElementById("btn_reply").onclick = function() {
296
			document.getElementById("write_recv").value = isInt? ae.getIntMsgFrom(num) : ae.getExtMsgReplyAddress(num);
297
			document.getElementById("write_subj").value = isInt? ae.getIntMsgTitle(num) : ae.getExtMsgTitle(num);
298
			if (!document.getElementById("write_subj").value.startsWith("Re:")) document.getElementById("write_subj").value = "Re: " + document.getElementById("write_subj").value;
299
			document.querySelector("#write2_pkey > input").value = isInt? ae.getIntMsgApk(num) : "";
300
301
			document.getElementById("write_recv").readOnly = !isInt;
302
			document.getElementById("write_subj").readOnly = !isInt;
303
			document.getElementById("write_subj").setAttribute("data-replyid", isInt? "" : ae.getExtMsgHdrId(num));
304
305
			tabs[TAB_WRITE].cur = 0;
306
			document.getElementById("btn_write").disabled = false;
307
			document.getElementById("btn_write").click();
308
			document.getElementById("write_body").focus();
309
310
			for (const opt of document.getElementById("write_from").options) {
311
				if (opt.value === (isInt ? ae.getIntMsgTo(num) : ae.getExtMsgEnvTo(num).split("@")[0].toLowerCase())) {
312
					opt.selected = true;
313
				}
314
			}
315
		};
316
	} else {
317
		document.getElementById("btn_reply").disabled = true;
318
	}
319
320
	document.getElementById("readmsg_info").hidden = false;
321
	document.querySelector("#readmsg_main > pre").hidden = false;
322
323
	document.getElementById("readmsg_envto").textContent = isInt ? "" : ae.getExtMsgEnvTo(num);
324
	document.getElementById("readmsg_hdrto").textContent = isInt ? ae.getIntMsgTo(num) : (ae.getExtMsgHdrTo(num));
325
	if(!isInt && ae.getExtMsgDnTo(num)) {
326
		const span = document.createElement("span");
327
		span.className = "sans";
328
		span.textContent = " • " + ae.getExtMsgDnTo(num);
329
		document.getElementById("readmsg_hdrto").appendChild(span);
330
	}
331
332
	const tzOs = new Date().getTimezoneOffset();
333
	const msgDate = new Date((ts * 1000) + (tzOs * -60000));
334
	document.getElementById("readmsg_date").children[0].textContent = getClockIcon(msgDate);
335
	document.getElementById("readmsg_date").children[1].dateTime = new Date(ts * 1000).toISOString();
336
337
	if (isInt) {
338
		document.querySelector("#readmsg_main > h1").textContent = ae.getIntMsgTitle(num);
339
		document.querySelector("#readmsg_main > pre").textContent = ae.getIntMsgBody(num);
340
341
		document.getElementById("readmsg_date").children[1].textContent = msgDate.toISOString().slice(0, 19).replace("T", " ");
342
343
		document.getElementById("readmsg_ip").style.visibility = "hidden";
344
		document.getElementById("readmsg_rdns").style.visibility = "hidden";
345
		document.getElementById("readmsg_dkim").style.visibility = "hidden";
346
		document.getElementById("readmsg_greet").style.visibility = "hidden";
347
		document.getElementById("readmsg_cert").style.visibility = "hidden";
348
		document.getElementById("readmsg_envfrom").style.visibility = "hidden";
349
		document.getElementById("readmsg_envto").style.visibility = "hidden";
350
351
		if (ae.getIntMsgFrom(num) !== "system" && ae.getIntMsgFrom(num) !== "public") {
352
			document.getElementById("readmsg_tls").style.visibility = "visible";
353
			document.getElementById("readmsg_tls").children[0].textContent = ae.getIntMsgApk(num);
354
		} else document.getElementById("readmsg_tls").style.visibility = "hidden";
355
356
		let symbol = document.createElement("span");
357
		if      (ae.getIntMsgLevel(num) === 3 && ae.getIntMsgFrom(num) === "system") {symbol.title = "System message"; symbol.textContent = "🅢";}
358
		else if (ae.getIntMsgLevel(num) === 3 && ae.getIntMsgFrom(num) === "public") {symbol.title = "Public announcement"; symbol.textContent = "🅟";}
359
		else if (ae.getIntMsgLevel(num) === 3) {symbol.title = "Administrator"; symbol.textContent = "🅐";}
360
		else if (ae.getIntMsgLevel(num) === 2) {symbol.title = "Level 2";  symbol.textContent = "➋";}
361
		else if (ae.getIntMsgLevel(num) === 1) {symbol.title = "Level 1";  symbol.textContent = "➊";}
362
		else if (ae.getIntMsgLevel(num) === 0) {symbol.title = "Level 0";  symbol.textContent = "🄌";}
363
		else {symbol.title = "Invalid level"; symbol.textContent = "⚠";}
364
365
		document.getElementById("readmsg_hdrfrom").replaceChildren(symbol, document.createTextNode(" " + ae.getIntMsgFrom(num)));
366
367
		clearMsgFlags();
368
		if (!ae.getIntMsgFlagVPad(num)) addMsgFlag("PAD", "Invalid padding");
369
		if (!ae.getIntMsgFlagVSig(num)) addMsgFlag("SIG", "Invalid signature");
370
		if ( ae.getIntMsgFlagE2ee(num)) addMsgFlag("E2EE", "End-to-end encrypted");
371
	} else {
372
		const headers = document.createElement("p");
373
		headers.textContent = ae.getExtMsgHeaders(num);
374
		headers.className = "mono";
375
		headers.hidden = !showHeaders;
376
377
		const body = document.createElement("p");
378
		body.innerHTML = ae.getExtMsgBody(num, false);
379
380
		document.querySelector("#readmsg_main > pre").replaceChildren(headers, body);
381
382
		const h1 = document.querySelector("#readmsg_main > h1");
383
		h1.textContent = ae.getExtMsgTitle(num);
384
		h1.style.cursor = headers.textContent? "pointer" : "";
385
		h1.onclick = function() {
386
			if (!headers.textContent) return;
387
			showHeaders = !showHeaders;
388
			headers.hidden = !showHeaders;
389
		};
390
391
		let hdrSecs = Math.abs(ae.getExtMsgHdrTime(num));
392
		let hdrTime = "";
393
		if (hdrSecs >= 3600) {
394
			const hdrHours = Math.floor(hdrSecs / 3600);
395
			hdrTime += hdrHours.toString() + "h ";
396
			hdrSecs -= hdrHours * 3600;
397
		}
398
		if (hdrSecs >= 60) {
399
			const hdrMins = Math.floor(hdrSecs / 60);
400
			hdrTime += hdrMins.toString() + "m ";
401
			hdrSecs -= hdrMins * 60;
402
		}
403
		hdrTime += hdrSecs + "s";
404
405
		const hdrTz = (ae.getExtMsgHdrTz(num) >= 0 ? "+" : "-") + Math.floor(Math.abs(ae.getExtMsgHdrTz(num)) / 60).toString().padStart(2, "0") + (Math.abs(ae.getExtMsgHdrTz(num)) % 60).toString().padStart(2, "0");
406
407
		let spans = [document.createElement("span"), document.createElement("span"), document.createElement("span")];
408
		spans[0].textContent = msgDate.toISOString().slice(0, 19).replace("T", " ");
409
		spans[1].className = "sans";
410
		spans[1].textContent = " • ";
411
		spans[2].textContent = hdrTz + " " + ((ae.getExtMsgHdrTime(num) >= 0) ? "+" : "-") + hdrTime;
412
		document.getElementById("readmsg_date").children[1].replaceChildren(...spans);
413
414
		document.getElementById("readmsg_ip").style.visibility = "visible";
415
		document.getElementById("readmsg_rdns").style.visibility = "visible";
416
		document.getElementById("readmsg_dkim").style.visibility = "visible";
417
		document.getElementById("readmsg_greet").style.visibility = "visible";
418
		document.getElementById("readmsg_tls").style.visibility = "visible";
419
		document.getElementById("readmsg_cert").style.visibility = "visible";
420
		document.getElementById("readmsg_envfrom").style.visibility = "visible";
421
		document.getElementById("readmsg_envto").style.visibility = "visible";
422
423
		// DKIM
424
		let dkim = "";
425
		if (ae.getExtMsgDkim(num)) {
426
			[ // Look for a matching domain in this order
427
				ae.getExtMsgHdrFrom(num).split("@")[1],
428
				ae.getExtMsgEnvFrom(num).split("@")[1],
429
				ae.getExtMsgRdns(num),
430
				ae.getExtMsgGreet(num),
431
				ae.getExtMsgTlsDomain(num)
432
			].forEach(function(dom) {
433
				if (dkim) return;
434
				for (let i = 0; i < ae.getExtMsgDkim(num).domain.length; i++) {
435
					if (ae.getExtMsgDkim(num).domain[i] === dom) {
436
						dkim = dom + " ✓";
437
						return;
438
					}
439
				}
440
			});
441
442
			if (!dkim) dkim = ae.getExtMsgDkim(num).domain[0]; // Default to first signature domain
443
		}
444
445
		if (ae.getExtMsgFlagDkFl(num)) dkim += " (fail)";
446
447
		// Left side
448
		document.getElementById("readmsg_country").textContent = getCountryFlag(ae.getExtMsgCcode(num));
449
		document.getElementById("readmsg_country").title = ae.getExtMsgCname(num);
450
		document.getElementById("readmsg_ip").children[1].textContent = ae.getExtMsgIp(num) + (ae.getExtMsgFlagIpBl(num) ? " ❗" : "");
451
		document.getElementById("readmsg_ip").children[2].textContent = " • " + ae.getExtMsgAuSys(num);
452
		document.getElementById("readmsg_tls").children[0].textContent = ae.getExtMsgTLS(num);
453
454
		// Right side
455
		document.getElementById("readmsg_greet").children[0].textContent = ae.getExtMsgGreet(num) + (ae.getExtMsgFlagGrDm(num) ? " ✓" : "");
456
		document.getElementById("readmsg_rdns").children[0].textContent = ae.getExtMsgRdns(num) + (ae.getExtMsgGreet(num).toLowerCase() === ae.getExtMsgRdns(num).toLowerCase() ? " ✓" : "");
457
		document.getElementById("readmsg_cert").children[0].textContent = ae.getExtMsgTlsDomain(num) ? (ae.getExtMsgTlsDomain(num) + " ✓") : "";
458
		document.getElementById("readmsg_dkim").children[0].textContent = dkim;
459
		document.getElementById("readmsg_envfrom").textContent = ae.getExtMsgEnvFrom(num);
460
		document.getElementById("readmsg_hdrfrom").textContent = ae.getExtMsgHdrFrom(num);
461
		if (ae.getExtMsgDnFrom(num)) {
462
			const span = document.createElement("span");
463
			span.className = "sans";
464
			span.textContent = " • " + ae.getExtMsgDnFrom(num);
465
			document.getElementById("readmsg_hdrfrom").appendChild(span);
466
		}
467
468
		clearMsgFlags();
469
		if (!ae.getExtMsgFlagVPad(num)) addMsgFlag("PAD", "Invalid padding");
470
		if (!ae.getExtMsgFlagVSig(num)) addMsgFlag("SIG", "Invalid signature");
471
		if (!ae.getExtMsgFlagPExt(num)) addMsgFlag("SMTP", "The sender did not use the Extended (ESMTP) protocol");
472
		if ( ae.getExtMsgFlagRare(num)) addMsgFlag("RARE", "The sender issued unusual command(s)");
473
		if ( ae.getExtMsgFlagFail(num)) addMsgFlag("FAIL", "The sender issued invalid command(s)");
474
		if ( ae.getExtMsgFlagPErr(num)) addMsgFlag("PROT", "The sender violated the protocol");
475
	}
476
477
	document.getElementById("readmsg_main").hidden = false;
478
	document.getElementById("main2").hidden = false;
479
	document.getElementById("main1").hidden = !window.matchMedia("(min-width: 80em)").matches;
480
481
	msgDisplay = new MsgInfo(isInt? ae.getIntMsgIdHex(num) : ae.getExtMsgIdHex(num), isInt? "int" : "ext", num);
482
	if (!isHistory) history.pushState({tab: tab, page: tabs[tab].cur, msg: msgDisplay}, null);
483
}
484
485
function displayExport(isHistory, isInt, num) {
486
	clearDisplay();
487
	document.getElementById("readmsg_main").hidden = true;
488
	document.getElementById("readmsg_export").hidden = false;
489
	document.getElementById("btn_msave").blur();
490
	document.getElementById("btn_msave").disabled = true;
491
	document.getElementById("btn_reply").disabled = true;
492
	document.getElementById("btn_mdele").disabled = true;
493
494
//	document.querySelector("#readmsg_export > div:nth-child(1)").onclick = function() {};
495
	document.querySelector("#readmsg_export > div:nth-child(2)").onclick = function() {if (isInt) {ae.downloadIntMsg(num);} else {ae.downloadExtMsg(num);} displayMsg(false, isInt, num);};
496
	document.querySelector("#readmsg_export > div:nth-child(3)").onclick = function() {if (isInt) {ae.htmlIntMsg(num, true);} else {ae.htmlExtMsg(num, true);} displayMsg(false, isInt, num);};
497
	document.querySelector("#readmsg_export > div:nth-child(4)").onclick = function() {if (isInt) {ae.txtIntMsg(num, true);} else {ae.txtExtMsg(num, true);} displayMsg(false, isInt, num);};
498
	document.querySelector("#readmsg_export > div:nth-child(5)").onclick = function() {if (isInt) {ae.printIntMsg(num);} else {ae.printExtMsg(num);} displayMsg(false, isInt, num);};
499
	document.querySelector("#readmsg_export > div:nth-child(6)").onclick = function() {navigator.clipboard.writeText(isInt? ae.txtIntMsg(num, false) : ae.txtExtMsg(num, false)); displayMsg(false, isInt, num);};
500
501
	msgDisplay = new MsgInfo(isInt? ae.getIntMsgIdHex(num) : ae.getExtMsgIdHex(num), isInt? "int_exp" : "ext_exp", num);
502
	if (!isHistory) history.pushState({tab: tab, page: tabs[tab].cur, msg: msgDisplay}, null);
503
}
504
505
function displayOutMsg(isHistory, num) {
506
	clearDisplay();
507
	document.querySelector("article").scroll(0, 0);
508
	document.querySelector("article").setAttribute("data-msgid", ae.getOutMsgIdHex(num));
509
510
	document.getElementById("btn_mdele").disabled = false;
511
	document.getElementById("btn_msave").disabled = true;
512
	document.getElementById("btn_reply").disabled = true;
513
514
	document.getElementById("readmsg_info").hidden = false;
515
	document.querySelector("#readmsg_main > pre").hidden = false;
516
517
	document.querySelector("#readmsg_main > h1").textContent = ae.getOutMsgSubj(num);
518
	document.querySelector("#readmsg_main > pre").textContent = ae.getOutMsgBody(num);
519
520
	document.getElementById("readmsg_dkim").style.visibility    = "hidden";
521
	document.getElementById("readmsg_hdrto").style.visibility   = "visible";
522
	document.getElementById("readmsg_hdrfrom").style.visibility = "visible";
523
	document.getElementById("readmsg_envto").style.visibility   = "visible";
524
	document.getElementById("readmsg_envfrom").style.visibility = "hidden";
525
526
	document.getElementById("readmsg_hdrfrom").textContent = ae.getOutMsgFrom(num);
527
528
	document.getElementById("readmsg_envto").textContent = ae.getOutMsgMxDom(num);
529
	document.getElementById("readmsg_hdrto").textContent = ae.getOutMsgTo(num);
530
531
	const ts = ae.getOutMsgTime(num);
532
	const tzOs = new Date().getTimezoneOffset();
533
	document.getElementById("readmsg_date").children[1].textContent = new Date((ts * 1000) + (tzOs * -60000)).toISOString().slice(0, 19).replace("T", " ");
534
535
	const isInt = ae.getOutMsgIsInt(num);
536
	document.getElementById("readmsg_ip").style.visibility    = isInt? "hidden" : "visible";
537
	document.getElementById("readmsg_rdns").style.visibility  = /*isInt?*/ "hidden" /*: "visible"*/; // TODO
538
	document.getElementById("readmsg_tls").style.visibility   = /*isInt?*/ "hidden" /*: "visible"*/; // TODO
539
	document.getElementById("readmsg_cert").style.visibility  = /*isInt?*/ "hidden" /*: "visible"*/; // TODO
540
	document.getElementById("readmsg_greet").style.visibility = isInt? "hidden" : "visible";
541
542
	if (!isInt) {
543
		document.getElementById("readmsg_ip").children[1].textContent = ae.getOutMsgIp(num);
544
		document.getElementById("readmsg_country").textContent = getCountryFlag(ae.getOutMsgCcode(num));
545
		document.getElementById("readmsg_country").title = ae.getOutMsgCname(num);
546
//		document.getElementById("readmsg_tls").children[0].textContent = ae.getOutMsgTLS(num);
547
		document.getElementById("readmsg_greet").children[0].textContent = ae.getOutMsgGreet(num);
548
	}
549
550
	clearMsgFlags();
551
	if (!ae.getOutMsgFlagVPad(num)) addMsgFlag("PAD", "Invalid padding");
552
	if (!ae.getOutMsgFlagVSig(num)) addMsgFlag("SIG", "Invalid signature");
553
	if ( ae.getOutMsgFlagE2ee(num)) addMsgFlag("E2EE", "End-to-end encrypted");
554
555
	document.getElementById("main2").hidden = false;
556
	document.getElementById("main1").hidden = !window.matchMedia("(min-width: 80em)").matches;
557
558
	msgDisplay = new MsgInfo(ae.getOutMsgIdHex(num), "out", num);
559
	if (!isHistory) history.pushState({tab: tab, page: tabs[tab].cur, msg: msgDisplay}, null);
560
}
561
562
function updateAddressButtons() {
563
	const limitReached = (ae.getAddressCountNormal() + ae.getAddressCountShield() >= 31);
564
	document.getElementById("btn_address_create_normal").disabled = (limitReached || ae.getAddressCountNormal() >= ae.getLimitNormalA(ae.getOwnLevel()));
565
	document.getElementById("btn_address_create_shield").disabled = (limitReached || ae.getAddressCountShield() >= ae.getLimitShieldA(ae.getOwnLevel()));
566
}
567
568
function updateAddressCounts() {
569
	document.querySelector("#tbd_accs > tr > td:nth-child(3)").textContent = ae.getAddressCountNormal();
570
	document.querySelector("#tbd_accs > tr > td:nth-child(4)").textContent = ae.getAddressCountShield();
571
572
	document.getElementById("limit_normal").textContent = (ae.getAddressCountNormal() + "/" + ae.getLimitNormalA(ae.getOwnLevel())).padStart(ae.getLimitNormalA(ae.getOwnLevel()) > 9 ? 5 : 1);
573
	document.getElementById("limit_shield").textContent = (ae.getAddressCountShield() + "/" + ae.getLimitShieldA(ae.getOwnLevel())).padStart(ae.getLimitShieldA(ae.getOwnLevel()) > 9 ? 5 : 1);
574
	document.getElementById("limit_total").textContent = ((ae.getAddressCountNormal() + ae.getAddressCountShield()) + "/" + ae.getAddrPerUser()).padStart(5);
575
576
	updateAddressButtons();
577
}
578
579
function addOwnAccount() {
580
	const row = document.getElementById("tbd_accs").insertRow(-1);
581
582
	let cell;
583
	cell = row.insertCell(-1); cell.textContent = ae.getOwnUpk();
584
	cell = row.insertCell(-1); cell.textContent = Math.round(ae.getTotalMsgBytes() / 1048576); // MiB
585
	cell = row.insertCell(-1); cell.textContent = ae.getAddressCountNormal();
586
	cell = row.insertCell(-1); cell.textContent = ae.getAddressCountShield();
587
588
	cell = row.insertCell(-1);
589
	let btn = document.createElement("button");
590
	btn.type = "button";
591
	btn.textContent = "+";
592
	btn.disabled = true;
593
	cell.appendChild(btn);
594
595
	cell = row.insertCell(-1); cell.textContent = ae.getOwnLevel();
596
597
	cell = row.insertCell(-1);
598
	btn = document.createElement("button");
599
	btn.type = "button";
600
	btn.textContent = "−";
601
	btn.disabled = true;
602
	btn.id = "btn_lowme";
603
	btn.onclick = function() {
604
		const newLevel = parseInt(row.cells[5].textContent, 10) - 1;
605
		ae.Account_Update(ae.getOwnUpk(), newLevel, function(error) {
606
			if (error === 0) {
607
				row.cells[5].textContent = newLevel;
608
				if (newLevel === 0) {document.getElementById("btn_lowme").disabled = true;}
609
			} else errorDialog(error);
610
		});
611
	};
612
	cell.appendChild(btn);
613
614
	cell = row.insertCell(-1);
615
	btn = document.createElement("button");
616
	btn.type = "button";
617
	btn.textContent = "X";
618
	btn.disabled = true;
619
	btn.id = "btn_delme";
620
	btn.onclick = function() {
621
		ae.Account_Delete(ae.getOwnUpk(), function(error) {
622
			if (error === 0) {
623
				row.remove();
624
				document.getElementById("fs_users").disabled = true;
625
			} else errorDialog(error);
626
		});
627
	};
628
	cell.appendChild(btn);
629
}
630
631
function adjustLevel(pubkey, level, c) {
632
	const fs = document.getElementById("tbl_accs");
633
	fs.disabled = true;
634
635
	ae.Account_Update(pubkey, level, function(error) {
636
		fs.disabled = false;
637
638
		if (error === 0) {
639
			c[4].children[0].disabled = (level === 3);
640
			c[5].textContent = level;
641
			c[6].children[0].disabled = (level === 0);
642
		} else errorDialog(error);
643
	});
644
}
645
646
function addMsg(isInt, i) {
647
	const row = document.getElementById("tbl_inbox").insertRow(-1);
648
	row.setAttribute("data-msgid", isInt? ae.getIntMsgIdHex(i) : ae.getExtMsgIdHex(i));
649
650
	const ts = isInt? ae.getIntMsgTime(i) : ae.getExtMsgTime(i);
651
	const el = document.createElement("time");
652
	el.dateTime = new Date(ts * 1000).toISOString();
653
	el.textContent = new Date((ts * 1000) + (new Date().getTimezoneOffset() * -60000)).toISOString().slice(0, 10);
654
	let cell = row.insertCell(-1);
655
	cell.appendChild(el);
656
657
	cell = row.insertCell(-1);
658
	cell.textContent = isInt? ae.getIntMsgTitle(i) : ae.getExtMsgTitle(i);
659
	if (!cell.textContent) cell.textContent = "(fail)";
660
661
	if (isInt) {
662
		cell = row.insertCell(-1);
663
		cell.textContent = ae.getIntMsgFrom(i);
664
		cell.className = (ae.getIntMsgFrom(i).length === 16) ? "mono" : "";
665
	} else {
666
		let from1 = ae.getExtMsgHdrFrom(i);
667
		if (!from1) from1 = ae.getExtMsgEnvFrom(i);
668
		const from2 = from1.substring(from1.indexOf("@") + 1);
669
		cell = row.insertCell(-1);
670
		cell.textContent = from1.substring(0, from1.indexOf("@"));
671
672
		const flag = document.createElement("abbr");
673
		flag.textContent = getCountryFlag(ae.getExtMsgCcode(i));
674
		flag.title = ae.getExtMsgCname(i);
675
676
		const fromText = document.createElement("span");
677
		fromText.textContent = " " + from2;
678
679
		cell = row.insertCell(-1);
680
		cell.appendChild(flag);
681
		cell.appendChild(fromText);
682
	}
683
684
	row.onclick = function() {
685
		displayMsg(false, isInt, i);
686
	};
687
}
688
689
function getRowsPerPage(tbl) {
690
	tbl.replaceChildren();
691
	const row = tbl.insertRow(-1);
692
	const cell = row.insertCell(-1);
693
	cell.textContent = "0";
694
	const rowsPerPage = Math.floor(getComputedStyle(tbl).height.replace("px", "") / getComputedStyle(tbl.getElementsByTagName("tr")[0]).height.replace("px", ""));
695
	tbl.replaceChildren();
696
	return rowsPerPage;
697
}
698
699
function showInbox() {
700
	const tbl = document.getElementById("tbl_inbox");
701
	if (!document.getElementById("main1").hidden) rowsPerPage = getRowsPerPage(tbl);
702
703
	const maxExt = ae.getExtMsgCount();
704
	const maxInt = ae.getIntMsgCount();
705
	const loadMore = ae.getReadyMsgBytes() < ae.getTotalMsgBytes();
706
707
	if (maxExt + maxInt > 0) {
708
		tabs[TAB_INBOX].max = Math.floor((maxExt + maxInt - (loadMore? 0 : 1)) / rowsPerPage);
709
		document.getElementById("btn_rght").disabled = (tabs[TAB_INBOX].cur >= tabs[TAB_INBOX].max);
710
		tbl.replaceChildren();
711
712
		let skipMsgs = rowsPerPage * tabs[TAB_INBOX].cur;
713
		let numExt = 0;
714
		let numInt = 0;
715
		let numAdd = 0;
716
717
		while (numAdd < rowsPerPage) {
718
			const tsInt = (numInt < maxInt) ? ae.getIntMsgTime(numInt) : -1;
719
			const tsExt = (numExt < maxExt) ? ae.getExtMsgTime(numExt) : -1;
720
			if (tsInt === -1 && tsExt === -1) break;
721
722
			if (tsInt !== -1 && (tsExt === -1 || tsInt > tsExt)) {
723
				if (skipMsgs > 0) skipMsgs--; else {addMsg(true, numInt); numAdd++;}
724
				numInt++;
725
			} else if (tsExt !== -1) {
726
				if (skipMsgs > 0) skipMsgs--; else {addMsg(false, numExt); numAdd++;}
727
				numExt++;
728
			}
729
		}
730
	} else {
731
		tabs[TAB_INBOX].max = 0;
732
	}
733
734
	if (loadMore && tabs[TAB_INBOX].cur >= tabs[TAB_INBOX].max) {
735
		const row = tbl.insertRow(-1);
736
		const cell = row.insertCell(-1);
737
		cell.textContent = "Load more (" + Math.round((ae.getTotalMsgBytes() - ae.getReadyMsgBytes()) / 1024) + " KiB left)";
738
739
		row.onclick = function() {
740
			tbl.style.opacity = 0.5;
741
742
			ae.Message_Browse(false, false, function(errorBrowse) {
743
				tbl.style.opacity = 1;
744
745
				if (errorBrowse !== 0) {
746
					errorDialog(errorBrowse);
747
					return;
748
				}
749
750
				showInbox();
751
			});
752
		};
753
	}
754
}
755
756
function showDrbox() {
757
	const tbl = document.getElementById("tbl_drbox");
758
	if (!document.getElementById("main1").hidden) rowsPerPage = getRowsPerPage(tbl);
759
760
	const drCount = ae.getOutMsgCount();
761
	const loadMore = ae.getReadyMsgBytes() < ae.getTotalMsgBytes();
762
763
	if (drCount > 0) {
764
		tabs[TAB_DRBOX].max = Math.floor((drCount - (loadMore? 0 : 1)) / rowsPerPage);
765
		document.getElementById("btn_rght").disabled = (tabs[TAB_DRBOX].cur >= tabs[TAB_DRBOX].max);
766
		tbl.replaceChildren();
767
768
		let skipMsgs = rowsPerPage * tabs[TAB_DRBOX].cur;
769
		let numAdd = 0;
770
771
		for (let i = 0; numAdd < rowsPerPage && i < drCount; i++) {
772
			if (skipMsgs > 0) {
773
				skipMsgs--;
774
				continue;
775
			}
776
777
			const row = tbl.insertRow(-1);
778
			row.setAttribute("data-msgid", ae.getOutMsgIdHex(i));
779
780
			let cell;
781
			cell = row.insertCell(-1); cell.textContent = new Date(ae.getOutMsgTime(i) * 1000).toISOString().slice(0, 10);
782
			cell = row.insertCell(-1); cell.textContent = ae.getOutMsgSubj(i);
783
			row.onclick = function() {displayOutMsg(false, i);};
784
785
			numAdd++;
786
		}
787
	} else {
788
		tabs[TAB_DRBOX].max = 0;
789
	}
790
791
	if (loadMore && tabs[TAB_DRBOX].cur >= tabs[TAB_DRBOX].max) {
792
		const row = tbl.insertRow(-1);
793
		const cell = row.insertCell(-1);
794
		cell.textContent = "Load more (" + Math.round((ae.getTotalMsgBytes() - ae.getReadyMsgBytes()) / 1024) + " KiB left)";
795
796
		row.onclick = function() {
797
			tbl.style.opacity = 0.5;
798
799
			ae.Message_Browse(false, false, function(errorBrowse) {
800
				tbl.style.opacity = 1;
801
802
				if (errorBrowse !== 0) {
803
					errorDialog(errorBrowse);
804
					return;
805
				}
806
807
				showDrbox();
808
			});
809
		};
810
	}
811
}
812
813
function showFiles() {
814
	const tbl = document.getElementById("tbl_files");
815
	if (!document.getElementById("main1").hidden) rowsPerPage = getRowsPerPage(tbl);
816
817
	const msgCount = ae.getUplMsgCount() + (vaultOk? vault.getFileCount() : 0);
818
	const loadMore = (ae.getReadyMsgBytes() < ae.getTotalMsgBytes()) || (vaultOk === false);
819
820
	if (msgCount > 0) {
821
		tabs[TAB_NOTES].max = 2 + Math.floor((msgCount - (loadMore? 0 : 1)) / rowsPerPage);
822
		document.getElementById("btn_rght").disabled = (tabs[TAB_NOTES].cur >= tabs[TAB_NOTES].max);
823
		tbl.replaceChildren();
824
825
		let skipMsgs = rowsPerPage * (tabs[TAB_NOTES].cur - 2);
826
		let numAdd = 0;
827
828
		for (let i = 0; numAdd < rowsPerPage && i < ae.getUplMsgCount(); i++) {
829
			if (skipMsgs > 0) {
830
				skipMsgs--;
831
				continue;
832
			}
833
834
			const row = tbl.insertRow(-1);
835
			row.setAttribute("data-msgid", ae.getUplMsgIdHex(i));
836
			row.className = "rowfile";
837
838
			let cell = row.insertCell(-1);
839
			cell.textContent = new Date(ae.getUplMsgTime(i) * 1000).toISOString().slice(0, 10);
840
			cell.onclick = function() {displayFile(false, i, null);};
841
842
			cell = row.insertCell(-1);
843
			cell.textContent = (ae.getUplMsgBytes(i) / 1024).toFixed(0).padStart(4, " ");
844
			cell.onclick = function() {displayFile(false, i, null);};
845
846
			cell = row.insertCell(-1);
847
			const parentNum = ae.getUplMsgParent(i);
848
			if (typeof(parentNum) === "number") {
849
				cell.textContent = ae.getExtMsgTitle(parentNum);
850
				cell.onclick = function() {displayMsg(false, false, parentNum);};
851
			} else if (parentNum === false) {
852
				cell.textContent = "Upload";
853
			} else {
854
				cell.textContent = "Unknown";
855
			}
856
857
			cell = row.insertCell(-1);
858
			cell.textContent = ae.getUplMsgTitle(i);
859
			cell.onclick = function() {displayFile(false, i, null);};
860
861
			cell = row.insertCell(-1);
862
			const btn = document.createElement("button");
863
			btn.setAttribute("data-msgid", ae.getUplMsgIdHex(i));
864
			btn.type = "button";
865
			btn.textContent = "X";
866
			btn.onclick = function() {
867
				ae.Message_Delete(this.getAttribute("data-msgid"), function(error) {
868
					if (error === 0) showFiles();
869
					else errorDialog(error);
870
				});
871
			};
872
			cell.appendChild(btn);
873
874
			numAdd++;
875
		}
876
877
		if (vaultOk) {
878
			for (let i = 0; numAdd < rowsPerPage && i < 256; i++) {
879
				if (vault.getFileSize(i) < 1) continue;
880
881
				if (skipMsgs > 0) {
882
					skipMsgs--;
883
					continue;
884
				}
885
886
				const row = tbl.insertRow(-1);
887
				row.setAttribute("data-msgid", i);
888
				row.className = "rowfile";
889
890
				let cell = row.insertCell(-1);
891
				cell.textContent = new Date(vault.getFileTime(i) * 1000).toISOString().slice(0, 10);
892
893
				cell = row.insertCell(-1);
894
				cell.textContent = (vault.getFileSize(i) / 1024).toFixed(0).padStart(4, " ");
895
896
				cell = row.insertCell(-1);
897
				cell.textContent = "Vault";
898
899
				cell = row.insertCell(-1);
900
				cell.textContent = vault.getFileName(i);
901
				cell.onclick = function() {vault.downloadFile(i);};
902
903
				cell = row.insertCell(-1);
904
				const btn = document.createElement("button");
905
				btn.type = "button";
906
				btn.textContent = "X";
907
				btn.onclick = function() {
908
					vault.deleteFile(i, function(error) {
909
						if (error === 0) showFiles();
910
						else errorDialog(error);
911
					});
912
				};
913
				cell.appendChild(btn);
914
915
				numAdd++;
916
			}
917
		}
918
	} else {
919
		tabs[TAB_NOTES].max = (vaultOk === false) ? 3 : 2;
920
	}
921
922
	if (loadMore && tabs[TAB_NOTES].cur >= tabs[TAB_NOTES].max) {
923
		const row = tbl.insertRow(-1);
924
		row.className = "rowfilex";
925
926
		let cell = row.insertCell(-1);
927
		if (ae.getReadyMsgBytes() < ae.getTotalMsgBytes()) {
928
			cell.textContent = "Load more (" + Math.round((ae.getTotalMsgBytes() - ae.getReadyMsgBytes()) / 1024) + " KiB left)";
929
			cell.onclick = function() {
930
				tbl.style.opacity = 0.5;
931
932
				ae.Message_Browse(false, false, function(errorBrowse) {
933
					tbl.style.opacity = 1;
934
935
					if (errorBrowse !== 0) {
936
						errorDialog(errorBrowse);
937
						return;
938
					}
939
940
					showFiles();
941
				});
942
			};
943
		}
944
945
		cell = row.insertCell(-1);
946
		if (vaultOk === false) {
947
			cell.textContent = "Open PostVault";
948
			cell.onclick = function() {
949
				tbl.style.opacity = 0.5;
950
951
				vault.getInfo(function() {
952
					tbl.style.opacity = 1;
953
954
					// TODO check for error
955
956
					vaultOk = true;
957
					showFiles();
958
				});
959
			};
960
		}
961
	}
962
}
963
964
function addAccountToTable(i) {
965
	const row = document.getElementById("tbd_accs").insertRow(-1);
966
	let cell;
967
	cell = row.insertCell(-1); cell.textContent = ae.admin_getUserUpk(i);
968
	cell = row.insertCell(-1); cell.textContent = Math.round(ae.admin_getUserKib(i) / 1024);
969
	cell = row.insertCell(-1); cell.textContent = ae.admin_getUserNrm(i);
970
	cell = row.insertCell(-1); cell.textContent = ae.admin_getUserShd(i);
971
972
	cell = row.insertCell(-1);
973
	let btn = document.createElement("button");
974
	btn.type = "button";
975
	btn.textContent = "+";
976
	btn.disabled = (ae.admin_getUserLvl(i) === 3);
977
	btn.onclick = function() {const c = this.parentElement.parentElement.cells; adjustLevel(c[0].textContent, parseInt(c[5].textContent, 10) + 1, c);};
978
	cell.appendChild(btn);
979
980
	cell = row.insertCell(-1); cell.textContent = ae.admin_getUserLvl(i);
981
982
	cell = row.insertCell(-1);
983
	btn = document.createElement("button");
984
	btn.type = "button";
985
	btn.textContent = "−";
986
	btn.disabled = (ae.admin_getUserLvl(i) === 0);
987
	btn.onclick = function() {const c = this.parentElement.parentElement.cells; adjustLevel(c[0].textContent, parseInt(c[5].textContent, 10) - 1, c);};
988
	cell.appendChild(btn);
989
990
	cell = row.insertCell(-1);
991
	btn = document.createElement("button");
992
	btn.type = "button";
993
	btn.textContent = "X";
994
	btn.onclick = function() {
995
		const tr = this.parentElement.parentElement;
996
		ae.Account_Delete(tr.cells[0].textContent, function(error) {
997
			if (error === 0) tr.remove(); else errorDialog(error);
998
		});
999
	};
1000
	cell.appendChild(btn);
1001
}
1002
1003
function updateLimits() {
1004
	const tbl = document.querySelector("#tbl_limits > tbody");
1005
1006
	if (ae.isUserAdmin()) {
1007
		for (let i = 0; i < 4; i++) {
1008
			tbl.rows[i].cells[1].children[0].value = ae.getLimitStorage(i);
1009
			tbl.rows[i].cells[2].children[0].value = ae.getLimitNormalA(i);
1010
			tbl.rows[i].cells[3].children[0].value = ae.getLimitShieldA(i);
1011
		}
1012
	} else {
1013
		const lvl = ae.getOwnLevel();
1014
		tbl.rows[lvl].cells[1].children[0].value = ae.getLimitStorage(lvl);
1015
		tbl.rows[lvl].cells[2].children[0].value = ae.getLimitNormalA(lvl);
1016
		tbl.rows[lvl].cells[3].children[0].value = ae.getLimitShieldA(lvl);
1017
	}
1018
}
1019
1020
function deleteAddress(addr) {
1021
	const buttons = document.querySelectorAll("#tbl_addrs button");
1022
	buttons.forEach(function(btn) {btn.disabled = true;});
1023
1024
	let addressToDelete = -1;
1025
	for (let i = 0; i < ae.getAddressCount(); i++) {
1026
		if (addr === ae.getAddress(i)) {
1027
			addressToDelete = i;
1028
			break;
1029
		}
1030
	}
1031
1032
	if (addressToDelete === -1) return;
1033
1034
	ae.Address_Delete(addressToDelete, function(error1) {
1035
		if (error1 !== 0) {
1036
			buttons.forEach(function(btn) {btn.disabled = false;});
1037
			errorDialog(error1);
1038
			return;
1039
		}
1040
1041
		document.getElementById("tbl_addrs").deleteRow(addressToDelete);
1042
		document.getElementById("write_from").remove(addressToDelete);
1043
1044
		if (ae.getAddressCountNormal() > 0) {
1045
			const apkList = document.getElementById("getapk_addr");
1046
			for (let i = 0; i < apkList.children.length; i++) {
1047
				if (apkList.children[i].value === addr) {
1048
					apkList.remove(i);
1049
					break;
1050
				}
1051
			}
1052
		} else {
1053
			document.getElementById("getapk_addr").replaceChildren();
1054
			document.getElementById("btn_getapk").disabled = true;
1055
		}
1056
1057
		updateAddressCounts();
1058
1059
		ae.Private_Update(function(error2) {
1060
			buttons.forEach(function(btn) {btn.disabled = false;});
1061
			if (error2) errorDialog(error2);
1062
		});
1063
	});
1064
}
1065
1066
function addAddress(num) {
1067
	const addrTable = document.getElementById("tbl_addrs");
1068
	const row = addrTable.insertRow(-1);
1069
	const addr = ae.getAddress(num);
1070
1071
	let cell = row.insertCell(-1);
1072
	cell.textContent = addr;
1073
	cell.onclick = function() {navigator.clipboard.writeText(((this.textContent.length === 16) ? ae.shieldMix(this.textContent) : this.textContent) + "@" + ae.getDomainEml());};
1074
1075
	cell = row.insertCell(-1);
1076
	let el = document.createElement("input");
1077
	el.type = "checkbox";
1078
	el.checked = ae.getAddressAccInt(num);
1079
	cell.appendChild(el);
1080
1081
	cell = row.insertCell(-1);
1082
	el = document.createElement("input");
1083
	el.type = "checkbox";
1084
	el.checked = ae.getAddressAccExt(num);
1085
	cell.appendChild(el);
1086
1087
	cell = row.insertCell(-1);
1088
	el = document.createElement("input");
1089
	el.type = "checkbox";
1090
	el.checked = ae.getAddressAllVer(num);
1091
	cell.appendChild(el);
1092
1093
	cell = row.insertCell(-1);
1094
	el = document.createElement("input");
1095
	el.type = "checkbox";
1096
	el.checked = ae.getAddressAttach(num);
1097
	cell.appendChild(el);
1098
1099
	cell = row.insertCell(-1);
1100
	el = document.createElement("input");
1101
	el.type = "checkbox";
1102
	el.checked = ae.getAddressSecure(num);
1103
	cell.appendChild(el);
1104
1105
	cell = row.insertCell(-1);
1106
	el = document.createElement("input");
1107
	el.type = "checkbox";
1108
	el.checked = ae.getAddressOrigin(num);
1109
	cell.appendChild(el);
1110
1111
	cell = row.insertCell(-1);
1112
	el = document.createElement("button");
1113
	el.type = "button";
1114
	el.textContent = "X";
1115
	el.onclick = function() {deleteAddress(addr);};
1116
	cell.appendChild(el);
1117
1118
	el = document.createElement("option");
1119
	el.value = addr;
1120
	el.textContent = addr + "@" + ae.getDomainEml();
1121
	document.getElementById("write_from").appendChild(el);
1122
1123
	if (addr.length !== 16) {
1124
		el = document.createElement("option");
1125
		el.value = addr;
1126
		el.textContent = addr;
1127
		document.getElementById("getapk_addr").appendChild(el);
1128
	}
1129
}
1130
1131
function clearWrite() {
1132
	setTab(false, TAB_WRITE, 0);
1133
1134
	document.querySelector("#write2_pkey > input").value = "";
1135
	document.getElementById("write_body").value = "";
1136
	document.getElementById("write_subj").value = "";
1137
	document.getElementById("write_subj").readOnly = false;
1138
	document.getElementById("write_subj").setAttribute("data-replyid", "");
1139
	document.getElementById("write_recv").value = "";
1140
	document.getElementById("write_recv").readOnly = false;
1141
	document.getElementById("write_recv").focus();
1142
}
1143
1144
// Interface
1145
if (window.matchMedia("(prefers-color-scheme: light)").matches) document.querySelector("head > meta[name='theme-color']").content = "#eef";
1146
window.matchMedia("(prefers-color-scheme: light)").onchange = function() {document.querySelector("head > meta[name='theme-color']").content = window.matchMedia("(prefers-color-scheme: light)").matches? "#eef" : "#001";};
1147
1148
document.getElementById("btn_dele").onclick = function() {
1149
	this.blur();
1150
1151
	if (tab === TAB_WRITE) clearWrite();
1152
};
1153
1154
document.getElementById("btn_updt").onclick = function() {
1155
	const btn = this;
1156
	btn.disabled = true;
1157
	btn.blur();
1158
1159
	if (tab === TAB_INBOX) {
1160
		document.getElementById("tbl_inbox").style.opacity = 0.5;
1161
1162
		ae.Message_Browse(true, false, function(error) {
1163
			btn.disabled = false;
1164
			document.getElementById("tbl_inbox").style.opacity = 1;
1165
1166
			if (error === 0) {
1167
				showInbox();
1168
			} else {
1169
				errorDialog(error);
1170
			}
1171
		});
1172
	}
1173
};
1174
1175
document.getElementById("btn_mdele").onclick = function() {
1176
	const delId = document.querySelector("article").getAttribute("data-msgid");
1177
	if (!delId) return;
1178
1179
	const btn = this;
1180
	btn.blur();
1181
	btn.disabled = true;
1182
1183
	ae.Message_Delete(delId, function(error) {
1184
		if (error !== 0) {
1185
			btn.disabled = false;
1186
			errorDialog(error);
1187
			return;
1188
		}
1189
1190
		switch (tab) {
1191
			case TAB_INBOX: showInbox(); break;
1192
			case TAB_DRBOX: showDrbox(); break;
1193
			case TAB_NOTES: showFiles(); break;
1194
		}
1195
	});
1196
};
1197
1198
function refreshContactList() {
1199
	let opts = [];
1200
1201
	for (let i = 0; i < ae.getContactCount(); i++) {
1202
		const el = document.createElement("option");
1203
		el.value = ae.getContactMail(i);
1204
		opts.push(el);
1205
	}
1206
1207
	if (ae.isUserAdmin()) {
1208
		const el = document.createElement("option");
1209
		el.value = "public";
1210
		opts.push(el);
1211
	}
1212
1213
	document.getElementById("contact_emails").replaceChildren(...opts);
1214
}
1215
1216
function addContact(mail, name, note) {
1217
	const tbl = document.getElementById("tbl_ctact");
1218
	const row = tbl.insertRow(-1);
1219
1220
	let cell = row.insertCell(-1);
1221
	cell.autocapitalize = "off";
1222
	cell.contentEditable = true;
1223
	cell.inputMode = "email";
1224
	cell.spellcheck = false;
1225
	cell.textContent = mail;
1226
1227
	cell = row.insertCell(-1);
1228
	cell.autocapitalize = "words";
1229
	cell.contentEditable = true;
1230
	cell.spellcheck = false;
1231
	cell.textContent = name;
1232
1233
	cell = row.insertCell(-1);
1234
	cell.autocapitalize = "off";
1235
	cell.contentEditable = true;
1236
	cell.spellcheck = false;
1237
	cell.textContent = note;
1238
1239
	cell = row.insertCell(-1);
1240
	const el = document.createElement("button");
1241
	el.type = "button";
1242
	el.textContent = "X";
1243
	el.onclick = function() {row.remove();};
1244
	cell.appendChild(el);
1245
}
1246
1247
function addContacts() {
1248
	for (let i = 0; i < ae.getContactCount(); i++) {
1249
		addContact(
1250
			ae.getContactMail(i),
1251
			ae.getContactName(i),
1252
			ae.getContactNote(i)
1253
		);
1254
	}
1255
1256
	refreshContactList();
1257
}
1258
1259
function addAddresses() {
1260
	for (let i = 0; i < ae.getAddressCount(); i++) {
1261
		addAddress(i);
1262
	}
1263
1264
	document.getElementById("btn_getapk").disabled = (ae.getAddressCountNormal() < 1);
1265
}
1266
1267
function reloadAccount() {
1268
	updateLimits();
1269
	addOwnAccount();
1270
	addContacts();
1271
	addAddresses();
1272
	updateAddressCounts();
1273
1274
	document.getElementById("fs_admin").disabled = !ae.isUserAdmin();
1275
	document.getElementById("txt_notepad").value = ae.getPrivateExtra();
1276
}
1277
1278
document.getElementById("btn_newcontact").onclick = function() {
1279
	addContact("", "", "");
1280
};
1281
1282
document.getElementById("btn_savecontacts").onclick = function() {
1283
	while (ae.getContactCount() > 0) {
1284
		ae.deleteContact(0);
1285
	}
1286
1287
	for (const row of document.getElementById("tbl_ctact").rows) {
1288
		ae.addContact(row.cells[0].textContent, row.cells[1].textContent, row.cells[2].textContent);
1289
	}
1290
1291
	refreshContactList();
1292
1293
	const btn = this;
1294
	btn.disabled = true;
1295
1296
	ae.Private_Update(function(error) {
1297
		btn.disabled = false;
1298
		if (error) errorDialog(error);
1299
	});
1300
};
1301
1302
function writeVerify() {
1303
	if (
1304
	   !document.getElementById("write_recv").reportValidity()
1305
	|| !document.getElementById("write_subj").reportValidity()
1306
	|| !document.getElementById("write_body").reportValidity()
1307
	) return false;
1308
1309
	document.getElementById("div_write_1").hidden = true;
1310
	document.getElementById("div_write_2").hidden = false;
1311
1312
	document.getElementById("write2_recv").textContent = document.getElementById("write_recv").value;
1313
	document.getElementById("write2_subj").textContent = document.getElementById("write_subj").value;
1314
	document.getElementById("write2_rply").textContent = document.getElementById("write_subj").getAttribute("data-replyid");
1315
	document.getElementById("write2_body").textContent = document.getElementById("write_body").value;
1316
1317
	if (document.getElementById("write_recv").value.indexOf("@") >= 0) {
1318
		document.getElementById("write2_from").textContent = document.getElementById("write_from").value + "@" + ae.getDomainEml();
1319
		document.getElementById("write2_pkey").hidden = true;
1320
	} else {
1321
		document.getElementById("write2_from").textContent = document.getElementById("write_from").value;
1322
		document.getElementById("write2_pkey").hidden = (document.getElementById("write_recv").value === "public");
1323
	}
1324
1325
	document.querySelector("#write2_send > button").disabled = false;
1326
	document.getElementById("write2_btntxt").textContent = (document.getElementById("write_recv").value === "public") ? "Make" : "Send to";
1327
	return true;
1328
}
1329
1330
function setTab(isHistory, tabNum, pageNum) {
1331
	tab = tabNum;
1332
	if (pageNum !== -1) tabs[tab].cur = pageNum;
1333
1334
	document.querySelectorAll("#main1 > nav:first-of-type > button").forEach(function(btn, i) {
1335
		document.querySelectorAll("#main1 > .mid > div")[i].hidden = (tab !== i);
1336
		btn.disabled = (tab === i);
1337
	});
1338
1339
	const bigScreen = window.matchMedia("(min-width: 80em)").matches;
1340
	document.getElementById("main2").hidden = !bigScreen;
1341
	document.getElementById("btn_leave").disabled = bigScreen;
1342
1343
	switch (tab) {
1344
		case TAB_INBOX: showInbox(); break;
1345
		case TAB_DRBOX: showDrbox(); break;
1346
1347
		case TAB_WRITE:
1348
			if (tabs[tab].cur === 0) {
1349
				document.getElementById("div_write_1").hidden = false;
1350
				document.getElementById("div_write_2").hidden = true;
1351
				document.getElementById("write_recv").focus();
1352
			} else if (!writeVerify()) {
1353
				tabs[TAB_WRITE].cur = 0;
1354
				return;
1355
			}
1356
		break;
1357
1358
		case TAB_NOTES:
1359
			switch (tabs[tab].cur) {
1360
				case 0:
1361
					document.getElementById("div_notes").children[0].hidden = false;
1362
					document.getElementById("div_notes").children[1].hidden = true;
1363
					document.getElementById("div_notes").children[2].hidden = true;
1364
				break;
1365
1366
				case 1:
1367
					document.getElementById("div_notes").children[0].hidden = true;
1368
					document.getElementById("div_notes").children[1].hidden = false;
1369
					document.getElementById("div_notes").children[2].hidden = true;
1370
1371
					document.querySelector("#div_notepad meter").value = ae.getPrivateExtraSpace() / ae.getPrivateExtraSpaceMax();
1372
				break;
1373
1374
				case 2:
1375
					document.getElementById("div_notes").children[0].hidden = true;
1376
					document.getElementById("div_notes").children[1].hidden = true;
1377
					document.getElementById("div_notes").children[2].hidden = false;
0 ignored issues
show
introduced by
This node falls through to the next case due to this statement. Please add a comment either directly below this line or between the cases to explain.
Loading history...
1378
1379
				default:
1380
					showFiles();
1381
			}
1382
		break;
1383
1384
		case TAB_TOOLS:
1385
			for (let i = 0; i <= tabs[tab].max; i++) {
1386
				document.getElementById("div_tools").children[i].hidden = (i !== tabs[tab].cur);
1387
			}
1388
		break;
1389
	}
1390
1391
	document.getElementById("btn_dele").disabled = !tabs[tab].btnDele;
1392
	document.getElementById("btn_left").disabled = (tabs[tab].cur === 0);
1393
	document.getElementById("btn_rght").disabled = (tabs[tab].cur === tabs[tab].max);
1394
	document.getElementById("btn_updt").disabled = !tabs[tab].btnUpdt;
1395
1396
	if (!isHistory) history.pushState({tab: tab, page: tabs[tab].cur, msg: msgDisplay}, null);
1397
}
1398
1399
window.onpopstate = function(event) {
1400
	if (!isReady || !event.state) return;
1401
	setTab(true, event.state.tab, event.state.page);
1402
	msgDisplay = event.state.msg;
1403
1404
	if (msgDisplay) {
1405
		switch (msgDisplay.type) {
1406
			case "ext": displayMsg(true, false, msgDisplay.num); break;
1407
			case "int": displayMsg(true, true, msgDisplay.num); break;
1408
			case "out": displayOutMsg(true, msgDisplay.num); break;
1409
			case "upl": displayFile(true, msgDisplay.num, null); break;
1410
			case "ext_exp": displayExport(true, false, msgDisplay.num); break;
1411
			case "int_exp": displayExport(true, true, msgDisplay.num); break;
1412
		}
1413
	}
1414
};
1415
1416
document.querySelectorAll("#main1 > nav:first-of-type > button").forEach(function(btn, i) {
1417
	btn.onclick = function() {setTab(false, i, -1);};
1418
});
1419
1420
document.getElementById("btn_left").onclick = function() {
1421
	setTab(false, tab, tabs[tab].cur - 1);
1422
};
1423
1424
document.getElementById("btn_rght").onclick = function() {
1425
	setTab(false, tab, tabs[tab].cur + 1);
1426
};
1427
1428
function addressCreate(addr) {
1429
	document.getElementById("btn_address_create_normal").disabled = true;
1430
	document.getElementById("btn_address_create_shield").disabled = true;
1431
1432
	ae.Address_Create(addr, function(error1) {
1433
		if (error1 !== 0) {
1434
			updateAddressButtons();
1435
			errorDialog(error1, (addr !== "SHIELD") ? document.getElementById("txt_address_create_normal") : null);
1436
			return;
1437
		}
1438
1439
		ae.Private_Update(function(error2) {
1440
			updateAddressCounts();
1441
1442
			addAddress(ae.getAddressCount() - 1);
1443
			if (addr !== "SHIELD") {
1444
				document.getElementById("btn_getapk").disabled = false;
1445
				document.getElementById("txt_address_create_normal").value = "";
1446
				document.getElementById("txt_address_create_normal").focus();
1447
			}
1448
1449
			if (error2 !== 0) errorDialog(error2, (addr !== "SHIELD") ? document.getElementById("txt_address_create_normal") : null);
1450
		});
1451
	});
1452
}
1453
1454
document.getElementById("btn_address_create_normal").onclick = function() {
1455
	if (ae.getAddressCountNormal() >= ae.getLimitNormalA(ae.getOwnLevel()) || ae.getAddressCountNormal() + ae.getAddressCountShield() >= 31) return;
1456
1457
	const txtNewAddr = document.getElementById("txt_address_create_normal");
1458
	if (!txtNewAddr.reportValidity()) return;
1459
1460
	addressCreate(txtNewAddr.value);
1461
};
1462
1463
document.getElementById("txt_address_create_normal").onkeyup = function() {
1464
	if (event.key !== "Enter") return;
0 ignored issues
show
Bug introduced by
The variable event seems to be never declared. If this is a global, consider adding a /** global: event */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1465
	event.preventDefault();
1466
	document.getElementById("btn_address_create_normal").click();
1467
};
1468
1469
document.getElementById("btn_address_create_shield").onclick = function() {
1470
	if (ae.getAddressCountShield() >= ae.getLimitShieldA(ae.getOwnLevel()) || ae.getAddressCountNormal() + ae.getAddressCountShield() >= 31) return;
1471
1472
	addressCreate("SHIELD");
1473
};
1474
1475
document.getElementById("btn_address_update").onclick = function() {
1476
	const btn = this;
1477
	btn.disabled = true;
1478
1479
	const rows = document.getElementById("tbl_addrs").rows;
1480
1481
	for (let i = 0; i < rows.length; i++) {
1482
		ae.setAddressAccInt(i, rows[i].getElementsByTagName("input")[0].checked);
1483
		ae.setAddressAccExt(i, rows[i].getElementsByTagName("input")[1].checked);
1484
		ae.setAddressAllVer(i, rows[i].getElementsByTagName("input")[2].checked);
1485
		ae.setAddressAttach(i, rows[i].getElementsByTagName("input")[3].checked);
1486
		ae.setAddressSecure(i, rows[i].getElementsByTagName("input")[4].checked);
1487
		ae.setAddressOrigin(i, rows[i].getElementsByTagName("input")[5].checked);
1488
	}
1489
1490
	ae.Address_Update(function(error) {
1491
		btn.disabled = false;
1492
		if (error) errorDialog(error);
1493
	});
1494
};
1495
1496
1497
document.getElementById("txt_reg").onkeyup = function(event) {
1498
	if (event.key !== "Enter") return;
1499
	event.preventDefault();
1500
	document.getElementById("btn_reg").click();
1501
};
1502
1503
document.getElementById("btn_reg").onclick = function() {
1504
	const btn = document.getElementById("btn_reg");
1505
	const txt = document.getElementById("txt_reg");
1506
	if (!txt.reportValidity()) return;
1507
	btn.disabled = true;
1508
1509
	ae.Account_Create(txt.value, function(error) {
1510
		if (error === 0) {
1511
			addAccountToTable(ae.admin_getUserNum() - 1);
1512
			txt.value = "";
1513
		} else errorDialog(error);
1514
1515
		btn.disabled = false;
1516
	});
1517
};
1518
1519
document.getElementById("chk_dng_usr").onclick = function() {
1520
	document.getElementById("btn_lowme").disabled = !this.checked || (ae.getOwnLevel() === 0);
1521
	document.getElementById("btn_erame").disabled = !this.checked;
1522
	document.getElementById("btn_delme").disabled = !this.checked;
1523
};
1524
1525
document.getElementById("btn_erame").onclick = function() {
1526
	ae.Message_Delete("ALL", function(error) {
1527
		if (error === 0) {
1528
			document.getElementById("chk_dng_usr").checked = false;
1529
			document.getElementById("chk_dng_usr").onclick();
1530
		} else errorDialog(error);
1531
	});
1532
};
1533
1534
document.getElementById("btn_notepad_restore").onclick = function() {
1535
	document.getElementById("txt_notepad").value = ae.getPrivateExtra();
1536
	document.getElementById("btn_notepad_savepad").disabled = true;
1537
	document.getElementById("txt_notepad").oninput = function() {
1538
		this.oninput = null;
1539
		document.getElementById("btn_notepad_savepad").disabled = false;
1540
		document.getElementById("btn_notepad_savepad").textContent = "Save";
1541
	};
1542
};
1543
1544
document.getElementById("txt_notepad").oninput = function() {
1545
	document.getElementById("btn_notepad_savepad").disabled = false;
1546
};
1547
1548
document.getElementById("btn_notepad_savepad").onclick = function() {
1549
	const btn = this;
1550
	btn.disabled = true;
1551
1552
	const error = ae.setPrivateExtra(document.getElementById("txt_notepad").value);
1553
	if (error !== 0) {
1554
		btn.disabled = false;
1555
		errorDialog(error);
1556
		return;
1557
	}
1558
1559
	ae.Private_Update(function(error2) {
1560
		if (error2 !== 0) {
1561
			btn.disabled = false;
1562
			errorDialog(error2);
1563
		} else {
1564
			document.querySelector("#div_notepad meter").value = ae.getPrivateExtraSpace() / ae.getPrivateExtraSpaceMax();
1565
			btn.textContent = "Saved";
1566
			document.getElementById("txt_notepad").oninput = function() {
1567
				this.oninput = null;
1568
				btn.textContent = "Save";
1569
				btn.disabled = false;
1570
			};
1571
		}
1572
	});
1573
};
1574
1575
document.getElementById("btn_notepad_saveupl").onclick = function() {
1576
	const np = document.getElementById("txt_notepad");
1577
	np.disabled = true;
1578
1579
	let fname = prompt("Save as...", "Untitled");
0 ignored issues
show
Debugging Code Best Practice introduced by
The prompt UI element is often considered obtrusive and is generally only used as a temporary measure. Consider replacing it with another UI element.
Loading history...
1580
	if (!fname.endsWith(".txt")) fname += ".txt";
1581
1582
	ae.Message_Upload(fname, np.value, function(error) {
1583
		if (error === 0) {
1584
			np.value = "";
1585
			showFiles();
1586
			document.getElementById("tbd_accs").children[0].children[1].textContent = Math.round(ae.getTotalMsgBytes() / 1024 / 1024);
1587
		} else errorDialog(error);
1588
1589
		np.disabled = false;
1590
	});
1591
};
1592
1593
document.getElementById("btn_upload").onclick = function() {
1594
	const btn = this;
1595
	const fileSelector = document.createElement("input");
1596
	fileSelector.type = "file";
1597
	fileSelector.click();
1598
1599
	fileSelector.onchange = function() {
1600
		btn.disabled = true;
1601
1602
		const reader = new FileReader();
1603
		reader.onload = function() {
1604
			if (vaultOk) { // Vault opened -> upload to PostVault
1605
				vault.uploadFile(fileSelector.files[0].name, new Uint8Array(reader.result), function(status) {
1606
					if (status === 0) {
1607
						showFiles();
1608
					} // TODO else show error
1609
1610
					btn.disabled = false;
1611
				});
1612
			} else { // No vault access -> upload to All-Ears
1613
				ae.Message_Upload(fileSelector.files[0].name, new Uint8Array(reader.result), function(status) {
1614
					if (status === 0) {
1615
						showFiles();
1616
						document.getElementById("tbd_accs").children[0].children[1].textContent = Math.round(ae.getTotalMsgBytes() / 1024 / 1024);
1617
					} else errorDialog(error);
0 ignored issues
show
Bug introduced by
The variable error seems to be never declared. If this is a global, consider adding a /** global: error */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1618
1619
					btn.disabled = false;
1620
				});
1621
			}
1622
		};
1623
1624
		reader.readAsArrayBuffer(fileSelector.files[0]);
1625
	};
1626
};
1627
1628
document.getElementById("btn_pg").onclick = function() {
1629
//	localStorage.greeting = document.getElementById("txt_pg").value;
1630
};
1631
1632
document.querySelector("#write2_send > button").onclick = function() {
1633
	const btn = this;
1634
	btn.disabled = true;
1635
1636
	// Public announcement
1637
	if (document.getElementById("write2_recv").textContent === "public") {
1638
		ae.Message_Public(document.getElementById("write_subj").value, document.getElementById("write_body").value, function(error) {
1639
			if (error !== 0) {
1640
				document.getElementById("write2_btntxt").textContent = "Retry making";
1641
				btn.disabled = false;
1642
				errorDialog(error);
1643
				return;
1644
			}
1645
1646
			clearWrite();
1647
			displayMsg(false, true, 0);
1648
		});
1649
1650
		return;
1651
	}
1652
1653
	// Email or internal message
1654
	let apk = null;
1655
	if (document.getElementById("write2_recv").textContent.indexOf("@") === -1) {
1656
		const elApk = document.querySelector("#write2_pkey > input");
1657
		if (!elApk.reportValidity()) {
1658
			btn.disabled = false;
1659
			return;
1660
		}
1661
1662
		try {apk = sodium.from_base64(elApk.value, sodium.base64_variants.ORIGINAL_NO_PADDING);}
1663
		catch(e) {
1664
			errorDialog(1); // Invalid input
1665
			btn.disabled = false;
1666
			return;
1667
		}
1668
	}
1669
1670
	document.getElementById("write2_btntxt").textContent = "Sending to";
1671
1672
	ae.Message_Create(
1673
		document.getElementById("write_subj").value,
1674
		document.getElementById("write_body").value,
1675
		document.getElementById("write_from").value,
1676
		document.getElementById("write_recv").value,
1677
		document.getElementById("write_subj").getAttribute("data-replyid"),
1678
		apk,
1679
		function(error) {
1680
			if (error !== 0) {
1681
				errorDialog(error);
1682
				document.getElementById("write2_btntxt").textContent = "Retry sending to";
1683
				btn.disabled = false;
1684
				return;
1685
			}
1686
1687
			showDrbox();
1688
			clearWrite();
1689
			displayOutMsg(false, 0);
1690
		}
1691
	);
1692
};
1693
1694
document.getElementById("btn_sender").onclick = function() {
1695
	ae.Message_Sender(document.getElementById("txt_sender_hash").value, Date.parse(document.getElementById("txt_sender_date").value) / 1000, function(error, result) {
1696
		if (error !== 0) {
1697
			errorDialog(error);
1698
			return;
1699
		}
1700
1701
		document.getElementById("txt_sender_res").value = result;
1702
	});
1703
};
1704
1705
document.getElementById("btn_limits").onclick = function() {
1706
	const btn = this;
1707
	btn.disabled = true;
1708
1709
	const mib = [parseInt(document.getElementById("lim_mib0").value, 10), parseInt(document.getElementById("lim_mib1").value, 10), parseInt(document.getElementById("lim_mib2").value, 10), parseInt(document.getElementById("lim_mib3").value, 10)];
1710
	const nrm = [parseInt(document.getElementById("lim_nrm0").value, 10), parseInt(document.getElementById("lim_nrm1").value, 10), parseInt(document.getElementById("lim_nrm2").value, 10), parseInt(document.getElementById("lim_nrm3").value, 10)];
1711
	const shd = [parseInt(document.getElementById("lim_shd0").value, 10), parseInt(document.getElementById("lim_shd1").value, 10), parseInt(document.getElementById("lim_shd2").value, 10), parseInt(document.getElementById("lim_shd3").value, 10)];
1712
1713
	ae.Setting_Update(mib, nrm, shd, function(error) {
1714
		btn.disabled = false;
1715
1716
		if (error !== 0) {
1717
			errorDialog(error);
1718
		} else {
1719
			updateAddressCounts();
1720
		}
1721
	});
1722
};
1723
1724
document.getElementById("btn_getapk").onclick = function() {
1725
	document.getElementById("getapk_result").textContent = ae.getOwnApk(document.getElementById("getapk_addr").value);
1726
};
1727
1728
document.getElementById("txt_skey").onfocus = function() {
1729
//	document.getElementById("greeting").textContent = localStorage.greeting;
1730
};
1731
1732
document.getElementById("txt_skey").onkeyup = function(event) {
1733
	if (event.key !== "Enter") return;
1734
	event.preventDefault();
1735
	document.getElementById("btn_enter").click();
1736
};
1737
1738
document.getElementById("btn_enter").onclick = function() {
1739
	const txtSkey = document.getElementById("txt_skey");
1740
1741
	if (txtSkey.value === "") {
1742
		ae.reset();
1743
		document.getElementById("greeting").textContent = "Data cleared";
1744
		return;
1745
	}
1746
1747
	if (!txtSkey.reportValidity()) return;
1748
1749
	const btn = this;
1750
	btn.disabled = true;
1751
1752
	document.getElementById("txt_skey").disabled = true;
1753
1754
	ae.setKeys(txtSkey.value, function(successSetKeys) {
1755
		if (!successSetKeys) {
1756
			document.getElementById("txt_skey").disabled = false;
1757
			txtSkey.focus();
1758
1759
			document.getElementById("greeting").textContent = "SetKeys failed";
1760
			btn.disabled = false;
1761
			return;
1762
		}
1763
1764
		if (vaultOk === false) {
1765
			vault.setKeys(txtSkey.value, function(successPv) {
1766
				if (!successPv) vaultOk = null;
1767
			});
1768
		}
1769
1770
		document.body.style.cursor = "wait";
1771
		document.getElementById("greeting").textContent = "Connecting...";
1772
1773
		ae.Message_Browse(false, true, function(statusBrowse) {
1774
			document.body.style.cursor = "";
1775
1776
			if (statusBrowse !== 0 && statusBrowse !== 0x09) {
1777
				document.getElementById("greeting").textContent = ae.getErrorMessage(statusBrowse) + " (0x" + statusBrowse.toString(16).padStart(2, "0").toUpperCase() + ")";
1778
				document.getElementById("txt_skey").disabled = false;
1779
				btn.disabled = false;
1780
				btn.focus();
1781
				return;
1782
			}
1783
1784
			txtSkey.value = "";
1785
			document.getElementById("div_begin").hidden = true;
1786
			document.getElementById("div_main").hidden = false;
1787
			isReady = true;
1788
			reloadAccount();
1789
			history.replaceState({tab: 0, page: 0, msg: msgDisplay}, null);
1790
			setTab(true, 0, 0);
1791
1792
			if (statusBrowse !== 0) errorDialog(statusBrowse);
1793
			if (!ae.isUserAdmin()) return;
1794
1795
			ae.Account_Browse(function(statusAcc) {
1796
				if (statusAcc === 0) {
1797
					for (let i = 0; i < ae.admin_getUserNum(); i++) {addAccountToTable(i);}
1798
					updateLimits();
1799
				} else {
1800
					errorDialog(statusAcc);
1801
				}
1802
			});
1803
		});
1804
	});
1805
};
1806
1807
});
1808