Passed
Push — master ( be2d94...a4bbf8 )
by EMP
01:18
created

main.js ➔ displayMsg   F

Complexity

Conditions 14

Size

Total Lines 39
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 29
dl 0
loc 39
rs 3.6
c 0
b 0
f 0
cc 14

How to fix   Complexity   

Complexity

Complex classes like main.js ➔ displayMsg 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() {
1 ignored issue
show
Bug introduced by
The variable sodium seems to be never declared. If this is a global, consider adding a /** global: sodium */ 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...
4
5
const ae = new AllEars(function(ok) {
1 ignored issue
show
Bug introduced by
The variable AllEars seems to be never declared. If this is a global, consider adding a /** global: AllEars */ 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...
6
	if (ok) {
7
		document.getElementById("txt_skey").style.background = "#404b41";
8
		document.getElementById("txt_skey").maxLength = "64";
9
	} else {
10
		console.log("Failed to load All-Ears");
11
	}
12
});
13
14
let tab="inbox";
15
let page=0;
16
17
// Helper functions
18
function getCountryName(countryCode) {
19
	const opts = document.getElementById("gatekeeper_country");
20
21
	for (let i = 0; i < opts.length; i++) {
22
		if (opts[i].value === countryCode) {
23
			return opts[i].textContent;
24
		}
25
	}
26
27
	return "Unknown countrycode: " + countryCode;
28
}
29
30
function getCountryFlag(countryCode) {
31
	const regionalIndicator1 = 127462 + countryCode.codePointAt(0) - 65;
32
	const regionalIndicator2 = 127462 + countryCode.codePointAt(1) - 65;
33
	return "&#" + regionalIndicator1 + ";&#" + regionalIndicator2 + ";";
34
}
35
36
function displayMsg(isInt, num) {
37
	document.getElementById("midright").scroll(0, 0);
38
39
	const ts = isInt? ae.GetIntMsgTime(num) : ae.GetExtMsgTime(num);
40
41
	document.getElementById("btn_reply").disabled = false;
42
	document.getElementById("btn_reply").onclick = function() {
43
		document.getElementById("write_recv").value = isInt ? ae.GetIntMsgFrom(num) : ae.GetExtMsgFrom(num);
44
		document.getElementById("write_subj").value = "Re: " + (isInt ? ae.GetIntMsgTitle(num) : ae.GetExtMsgTitle(num));
45
		document.getElementById("btn_write").click();
46
	};
47
48
	document.getElementById("msg").hidden = false;
49
	document.getElementById("msg").getElementsByTagName("h1")[0].textContent = isInt ? ae.GetIntMsgTitle(num) : ae.GetExtMsgTitle(num);
50
	document.getElementById("msg").getElementsByTagName("pre")[0].textContent = isInt ? ae.GetIntMsgBody(num) : ae.GetExtMsgBody(num);
51
52
	document.getElementById("readmsg_to").textContent = isInt ? ae.GetIntMsgTo(num) : ae.GetExtMsgTo(num);
53
	document.getElementById("readmsg_date").textContent = new Date(ts * 1000).toISOString().slice(0, 16).replace("T", " ");
54
55
	if (!isInt) {
56
		const cc = ae.GetExtMsgCountry(num);
57
58
		document.getElementById("readmsg_greet").textContent = ae.GetExtMsgGreet(num);
59
		document.getElementById("readmsg_ip").textContent = ae.GetExtMsgIp(num);
60
		document.getElementById("readmsg_tls").textContent = ae.GetExtMsgTLS(num);
61
		document.getElementById("readmsg_country").innerHTML = getCountryFlag(cc) + " " + getCountryName(cc);
62
		document.getElementById("readmsg_envfrom").textContent = ae.GetExtMsgFrom(num);
63
64
		let flagText = "";
65
		if (!ae.GetExtMsgFlagPExt(num)) flagText += "<abbr title=\"The sender did not use the Extended (ESMTP) protocol\">SMTP</abbr> ";
66
		if (!ae.GetExtMsgFlagQuit(num)) flagText += "<abbr title=\"The sender did not issue the required QUIT command\">QUIT</abbr> ";
67
		if (ae.GetExtMsgFlagRare(num)) flagText += "<abbr title=\"The sender issued unusual command(s)\">RARE</abbr> ";
68
		if (ae.GetExtMsgFlagFail(num)) flagText += "<abbr title=\"The sender issued invalid command(s)\">FAIL</abbr> ";
69
		if (ae.GetExtMsgFlagPErr(num)) flagText += "<abbr title=\"The sender violated the protocol\">PROT</abbr> ";
70
		document.getElementById("readmsg_flags").innerHTML = flagText.trim();
71
	} else {
72
		document.getElementById("readmsg_from").textContent = ae.GetIntMsgFrom(num);
73
	}
74
}
75
76
// Interface
77
function addMsg(isInt, i) {
78
	const inbox = document.getElementById("tbl_inbox");
79
	const sent = document.getElementById("tbl_sent");
80
81
	const isSent = isInt? ae.GetIntMsgIsSent(i) : false;
82
	const table = isSent ? sent : inbox;
83
84
	const row = table.insertRow(-1);
85
	const cellTime = row.insertCell(-1);
86
	const cellSubj = row.insertCell(-1);
87
	const cellSnd1 = row.insertCell(-1);
88
	const cellSnd2 = row.insertCell(-1);
89
90
	const ts = isInt? ae.GetIntMsgTime(i) : ae.GetExtMsgTime(i);
91
	cellTime.setAttribute("data-ts", ts);
92
	cellTime.textContent = new Date(ts * 1000).toISOString().slice(0, 16).replace("T", " ");
93
94
	cellSubj.textContent = isInt? ae.GetIntMsgTitle(i) : ae.GetExtMsgTitle(i);
95
96
	if (isInt) {
97
		cellSnd1.textContent = ae.GetIntMsgFrom(i);
98
		cellSnd1.className = (ae.GetIntMsgFrom(i).length === 24) ? "mono" : "";
99
	} else {
100
		const from1 = ae.GetExtMsgFrom(i);
101
		const from2 = from1.substring(from1.indexOf("@") + 1);
102
		const cc = ae.GetExtMsgCountry(i);
103
104
		cellSnd1.textContent = from1.substring(0, from1.indexOf("@"));
105
		cellSnd2.innerHTML = "<abbr title=\"" + getCountryName(cc) + "\">" + getCountryFlag(cc) + "</abbr>";
106
107
		const fromText = document.createElement("span");
108
		fromText.textContent = " " + from2;
109
		cellSnd2.appendChild(fromText);
110
	}
111
112
//	divDel.innerHTML = "<input class=\"delMsg\" type=\"checkbox\" data-id=\"" + ae.GetIntMsgIdHex(i) + "\">";
113
114
	row.onclick = function() {
115
		displayMsg(isInt, i);
116
	};
117
/*
118
	cellDel.children[0].onchange = function() {
119
		if (!divDel.children[0].checked) {
120
			const checkboxes = elmt.getElementsByTagName("input");
121
			let checked = false;
122
123
			for (let j = 0; j < checkboxes.length; j++) {
124
				if (checkboxes[j].checked) {
125
					checked = true;
126
					break;
127
				}
128
			}
129
130
			if (!checked) {
131
				document.getElementById(isSent ? "btn_sentdel" : "btn_msgdel").hidden = true;
132
				return;
133
			}
134
		}
135
136
		document.getElementById(isSent? "btn_sentdel" : "btn_msgdel").hidden = false;
137
	};
138
*/
139
}
140
141
function addMessages() {
142
	const maxExt = ae.GetExtMsgCount();
143
	const maxInt = ae.GetIntMsgCount();
144
145
	let numExt = 0;
146
	let numInt = 0;
147
148
	for (let i = 0; i < (page * 20) + 20; i++) {
149
		const tsInt = (numInt < maxInt) ? ae.GetIntMsgTime(numInt) : 0;
150
		const tsExt = (numExt < maxExt) ? ae.GetExtMsgTime(numExt) : 0;
151
		if (tsInt === 0 && tsExt === 0) break;
152
153
		if (tsInt !== 0 && (tsExt === 0 || tsInt > tsExt)) {
154
			if (i < (page * 20)) {
155
				numInt++;
156
				continue;
157
			}
158
159
			addMsg(true, numInt);
160
			numInt++;
161
		} else if (tsExt !== 0) {
162
			if (i < (page * 20)) {
163
				numExt++;
164
				continue;
165
			}
166
167
			addMsg(false, numExt);
168
			numExt++;
169
		}
170
	}
171
}
172
173
function clearMessages() {
174
	document.getElementById("tbl_inbox").innerHTML = "";
175
//	document.getElementById("tbl_sentm").innerHTML = "";
176
//	document.getElementById("tbl_notes").innerHTML = "";
177
//	document.getElementById("tbl_files").innerHTML = "";
178
}
179
180
function updateAddressCounts() {
181
	document.getElementById("limit_normal").textContent = (ae.GetAddressCountNormal() + "/" + ae.GetAddressLimitNormal(ae.GetUserLevel())).padStart(ae.GetAddressLimitNormal(ae.GetUserLevel()) > 9 ? 5 : 1);
182
	document.getElementById("limit_shield").textContent = (ae.GetAddressCountShield() + "/" + ae.GetAddressLimitShield(ae.GetUserLevel())).padStart(ae.GetAddressLimitShield(ae.GetUserLevel()) > 9 ? 5 : 1);
183
	document.getElementById("limit_total").textContent = ((ae.GetAddressCountNormal() + ae.GetAddressCountShield()) + "/" + ae.GetAddrPerUser()).padStart(5);
184
}
185
186
function reloadInterface() {
187
	document.getElementById("div_begin").hidden = true;
188
	document.getElementById("div_main").style.display = "grid";
189
190
	// Contacts
191
	for (let i = 0; i < ae.GetContactCount(); i++) {
192
		addContact(
193
			ae.GetContactMail(i),
194
			ae.GetContactName(i),
195
			ae.GetContactNote(i)
196
		);
197
	}
198
199
	// Addresses
200
	for (let i = 0; i < ae.GetAddressCount(); i++) {
201
		addAddress(i);
202
	}
203
204
	document.getElementById("table_addrs").getElementsByTagName("caption")[0].textContent = "Level " + ae.GetUserLevel() + " User";
205
	updateAddressCounts();
206
}
207
208 View Code Duplication
function deleteAddress(addr) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
209
	let btns = document.getElementById("tbl_addrs").getElementsByTagName("button");
210
	for (let i = 0; i < btns.length; i++) btns[i].disabled = true;
211
212
	let addressToDelete = -1;
213
214
	for (let i = 0; i < ae.GetAddressCount(); i++) {
215
		if (addr === ae.GetAddress(i)) {
216
			addressToDelete = i;
217
			break;
218
		}
219
	}
220
221
	if (addressToDelete === -1) return;
222
223
	ae.Address_Delete(addressToDelete, function(success) {
224
		if (success) {
225
			document.getElementById("tbl_addrs").deleteRow(addressToDelete);
226
			document.getElementById("write_from").remove(addressToDelete);
227
			updateAddressCounts();
228
229
			if (ae.GetAddressCountNormal() < ae.GetAddressLimitNormal(ae.GetUserLevel())) document.getElementById("btn_address_create_normal").disabled = false;
230
			if (ae.GetAddressCountShield() < ae.GetAddressLimitShield(ae.GetUserLevel())) document.getElementById("btn_address_create_shield").disabled = false;
231
232
			ae.Private_Update(function(success2) {
233
				if (!success2) console.log("Failed to update the Private field");
234
235
				btns = document.getElementById("tbl_addrs").getElementsByTagName("button");
236
				for (let i = 0; i < btns.length; i++) btns[i].disabled = false;
237
			});
238
		} else {
239
			console.log("Failed to delete address");
240
241
			btns = document.getElementById("tbl_addrs").getElementsByTagName("button");
242
			for (let i = 0; i < btns.length; i++) btns[i].disabled = false;
243
		}
244
	});
245
}
246
247 View Code Duplication
function shieldMix(addr) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
248
	let newAddr = "";
249
250
	for (let i = 0; i < 24; i++) {
251
		switch (addr.charAt(i)) {
252
			case '1':
253
				newAddr += "1iIlL".charAt(Math.floor(Math.random() * 5));
254
				break;
255
			case '0':
256
				newAddr += "0oO".charAt(Math.floor(Math.random() * 3));
257
				break;
258
			case 'w':
259
				newAddr += "VvWw".charAt(Math.floor(Math.random() * 4));
260
				break;
261
			default:
262
				newAddr += (Math.random() > 0.5) ? addr.charAt(i) : addr.charAt(i).toUpperCase();
263
		}
264
	}
265
266
	return newAddr;
267
}
268
269
function addAddress(num) {
270
	const addrTable = document.getElementById("tbl_addrs");
271
	const row = addrTable.insertRow(-1);
272
	const cellAddr = row.insertCell(-1);
273
	const cellChk1 = row.insertCell(-1);
274
	const cellChk2 = row.insertCell(-1);
275
	const cellChk3 = row.insertCell(-1);
276
	const cellBtnD = row.insertCell(-1);
277
278
	cellAddr.textContent = ae.GetAddress(num);
279
	cellAddr.onclick = function() {
280
		if (cellAddr.textContent.length === 24)
281
			navigator.clipboard.writeText(shieldMix(cellAddr.textContent) + "@" + ae.GetDomain());
1 ignored issue
show
Bug introduced by
The variable navigator seems to be never declared. If this is a global, consider adding a /** global: navigator */ 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...
282
		else
283
			navigator.clipboard.writeText(cellAddr.textContent + "@" + ae.GetDomain());
284
	};
285
286
	cellChk1.innerHTML = ae.GetAddressAccExt(num) ? "<input type=\"checkbox\" checked=\"checked\">" : "<input type=\"checkbox\">";
287
	cellChk2.innerHTML = ae.GetAddressAccInt(num) ? "<input type=\"checkbox\" checked=\"checked\">" : "<input type=\"checkbox\">";
288
	cellChk3.innerHTML = ae.GetAddressUse_Gk(num) ? "<input type=\"checkbox\" checked=\"checked\">" : "<input type=\"checkbox\">";
289
290
	cellBtnD.innerHTML = "<button type=\"button\">X</button>";
291
	cellBtnD.onclick = function() {deleteAddress(cellAddr.textContent);};
292
293
	const opt = document.createElement("option");
294
	opt.value = cellAddr.textContent;
295
	opt.textContent = cellAddr.textContent + "@" + ae.GetDomain();
296
	document.getElementById("write_from").appendChild(opt);
297
}
298
299
document.getElementById("btn_updt").onclick = function() {
300
	const btn = this;
301
	btn.disabled = true;
302
	btn.blur();
303
304
	if (tab === "inbox") {
305
		ae.Message_Browse(0, function(successBrowse) {
306
			if (successBrowse) {
307
				clearMessages();
308
				addMessages();
309
				btn.disabled = false;
310
			} else {
311
				console.log("Failed to refresh");
312
				btn.disabled = false;
313
			}
314
		});
315
	}
316
};
317
318
function addContact(mail, name, note) {
319
	const tbl = document.getElementById("tbl_ctact");
320
	const row = tbl.insertRow(-1);
321
	const cellMail = row.insertCell(-1);
322
	const cellName = row.insertCell(-1);
323
	const cellNote = row.insertCell(-1);
324
	const cellBtnD = row.insertCell(-1);
325
326
	cellMail.textContent = mail;
327
	cellName.textContent = name;
328
	cellNote.textContent = note;
329
	cellBtnD.innerHTML = "<button type=\"button\">X</button>";
330
331
	cellMail.contentEditable = true;
332
	cellName.contentEditable = true;
333
	cellNote.contentEditable = true;
334
335
//	cellBtnD.onclick = 
336
}
337
338
document.getElementById("btn_newcontact").onclick = function() {
339
	addContact("", "", "");
340
}
341
342
// Tabs
343
function setupButtons() {
344
	switch(tab) {
345
		case "inbox":
346
		case "snbox":
347
			document.getElementById("btn_dele").disabled = false;
348
			document.getElementById("btn_left").disabled = false; // depends
349
			document.getElementById("btn_cent").disabled = true;
350
			document.getElementById("btn_rght").disabled = false;
351
			document.getElementById("btn_updt").disabled = false;
352
			break;
353
		case "write":
354
			document.getElementById("btn_dele").disabled = false; // depends
355
			document.getElementById("btn_left").disabled = false; // depends
356
			document.getElementById("btn_cent").disabled = true;
357
			document.getElementById("btn_rght").disabled = false;
358
			document.getElementById("btn_updt").disabled = true;
359
			break;
360
		case "notes":
361
			document.getElementById("btn_dele").disabled = true;
362
			document.getElementById("btn_left").disabled = false; // depends
363
			document.getElementById("btn_cent").disabled = true;
364
			document.getElementById("btn_rght").disabled = false; // depends
365
			document.getElementById("btn_updt").disabled = true; // depends
366
			break;
367
		case "prefs":
368
			document.getElementById("btn_dele").disabled = true;
369
			document.getElementById("btn_left").disabled = false; // depends
370
			document.getElementById("btn_cent").disabled = true;
371
			document.getElementById("btn_rght").disabled = false; // depends
372
			document.getElementById("btn_updt").disabled = true; // depends
373
			break;
374
	}
375
}
376
377
for (const btn1 of document.getElementById("main1").getElementsByClassName("top")[0].getElementsByTagName("button")) {
378
	btn1.onclick = function() {
379
		for (const btn2 of document.getElementById("main1").getElementsByClassName("top")[0].getElementsByTagName("button")) {
380
			const isMatch = (btn1 === btn2);
381
			btn2.disabled = isMatch;
382
			document.getElementById("div_" + btn2.id.slice(4)).hidden = !isMatch;
383
384
			if (isMatch) {
385
				tab = btn2.id.slice(4);
386
				setupButtons();
387
			}
388
		};
389
	};
390
};
391
392
function addressCreate(addr) {
393
	const btnN = document.getElementById("btn_address_create_normal");
394
	const btnS = document.getElementById("btn_address_create_shield");
395
	btnN.disabled = true;
396
	btnS.disabled = true;
397
398
	ae.Address_Create(addr, function(success1) {
399
		if (success1) {
400
			ae.Private_Update(function(success2) {
401
				addAddress(ae.GetAddressCount() - 1);
402
				if (addr !== "SHIELD") document.getElementById("txt_address_create_normal").value = "";
403
				updateAddressCounts();
404
405
				if (!success2) console.log("Failed to update the Private field");
406
407
				if (ae.GetAddressCountNormal() < ae.GetAddressLimitNormal(ae.GetUserLevel())) btnN.disabled = false;
408
				if (ae.GetAddressCountShield() < ae.GetAddressLimitShield(ae.GetUserLevel())) btnS.disabled = false;
409
			});
410
		} else {
411
			console.log("Failed to add address");
412
413
			if (ae.GetAddressCountNormal() < ae.GetAddressLimitNormal(ae.GetUserLevel())) btnN.disabled = false;
414
			if (ae.GetAddressCountShield() < ae.GetAddressLimitShield(ae.GetUserLevel())) btnS.disabled = false;
415
		}
416
	});
417
}
418
419
document.getElementById("btn_address_create_normal").onclick = function() {
420
	if (ae.GetAddressCountNormal() >= ae.GetAddressLimitNormal(ae.GetUserLevel())) return;
421
422
	const txtNewAddr = document.getElementById("txt_address_create_normal");
423
	if (!txtNewAddr.reportValidity()) return;
424
425
	addressCreate(txtNewAddr.value);
426
}
427
428
document.getElementById("btn_address_create_shield").onclick = function() {
429
	if (ae.GetAddressCountShield() >= ae.GetAddressLimitShield(ae.GetUserLevel())) return;
430
431
	addressCreate("SHIELD");
432
};
433
434
document.getElementById("txt_skey").onkeyup = function(event) {
435
	if (event.key === "Enter") {
436
		event.preventDefault();
437
		document.getElementById("btn_enter").click();
438
	}
439
};
440
441
document.getElementById("btn_enter").onclick = function() {
442
	const txtSkey = document.getElementById("txt_skey");
443
	if (!txtSkey.reportValidity()) return;
444
445
	const btn = this;
446
	btn.disabled = true;
447
	document.getElementById("txt_skey").style.background = "#111";
448
449
	ae.SetKeys(txtSkey.value, function(successSetKeys) {
450
		if (successSetKeys) {
451
			ae.Account_Browse(0, function(successBrowse) {
452
				if (successBrowse) {
453
					txtSkey.value = "";
454
					reloadInterface();
455
					document.getElementById("btn_updt").click();
456
				} else {
457
					console.log("Failed to enter");
458
					btn.disabled = false;
459
					document.getElementById("txt_skey").style.background = "#404b41";
460
					txtSkey.focus();
461
				}
462
			});
463
		} else {
464
			console.log("Invalid format for key");
465
			btn.disabled = false;
466
			document.getElementById("txt_skey").style.background = "#404b41";
467
			txtSkey.focus();
468
		}
469
	});
470
};
471
472
});
473