@bobfrankston/rmfmail 1.2.263 → 1.2.270

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/TODO.md +1 -0
  2. package/client/android-bootstrap.bundle.js +34 -1
  3. package/client/android-bootstrap.bundle.js.map +2 -2
  4. package/client/app.bundle.js +54 -108
  5. package/client/app.bundle.js.map +3 -3
  6. package/client/app.js +59 -116
  7. package/client/app.js.map +1 -1
  8. package/client/app.ts +64 -93
  9. package/client/components/message-list.js +18 -3
  10. package/client/components/message-list.js.map +1 -1
  11. package/client/components/message-list.ts +18 -3
  12. package/client/components/message-viewer.js +14 -4
  13. package/client/components/message-viewer.js.map +1 -1
  14. package/client/components/message-viewer.ts +13 -3
  15. package/client/compose/compose.bundle.js +17 -6
  16. package/client/compose/compose.bundle.js.map +2 -2
  17. package/client/compose/compose.js +13 -7
  18. package/client/compose/compose.js.map +1 -1
  19. package/client/compose/compose.ts +13 -5
  20. package/client/lib/rmf-tiny.js +15 -1
  21. package/client/package.json +1 -1
  22. package/client/styles/components.css +9 -0
  23. package/docs/thundermail-jmap.md +291 -0
  24. package/package.json +11 -11
  25. package/packages/mailx-imap/index.d.ts.map +1 -1
  26. package/packages/mailx-imap/index.js +17 -1
  27. package/packages/mailx-imap/index.js.map +1 -1
  28. package/packages/mailx-imap/index.ts +17 -1
  29. package/packages/mailx-imap/package-lock.json +2 -2
  30. package/packages/mailx-imap/package.json +1 -1
  31. package/packages/mailx-settings/docs/thundermail-jmap.md +291 -0
  32. package/packages/mailx-settings/index.d.ts +1 -0
  33. package/packages/mailx-settings/index.d.ts.map +1 -1
  34. package/packages/mailx-settings/index.js +1 -0
  35. package/packages/mailx-settings/index.js.map +1 -1
  36. package/packages/mailx-settings/index.ts +1 -0
  37. package/packages/mailx-settings/package.json +1 -1
  38. package/packages/mailx-store/package.json +1 -1
  39. package/packages/mailx-store-web/package.json +1 -1
  40. package/packages/mailx-store-web/web-settings.d.ts +1 -0
  41. package/packages/mailx-store-web/web-settings.d.ts.map +1 -1
  42. package/packages/mailx-store-web/web-settings.js +1 -0
  43. package/packages/mailx-store-web/web-settings.js.map +1 -1
  44. package/packages/mailx-store-web/web-settings.ts +1 -0
  45. package/packages/mailx-types/index.d.ts +59 -1
  46. package/packages/mailx-types/index.d.ts.map +1 -1
  47. package/packages/mailx-types/index.js +72 -0
  48. package/packages/mailx-types/index.js.map +1 -1
  49. package/packages/mailx-types/index.ts +80 -1
  50. package/packages/mailx-types/package.json +1 -1
  51. /package/packages/mailx-imap/{node_modules.npmglobalize-stash-88864 → node_modules.npmglobalize-stash-18100}/.package-lock.json +0 -0
@@ -1368,6 +1368,35 @@ function _set(msg, flag, state) {
1368
1368
  const next = state ? [...msg.flags || [], flag] : (msg.flags || []).filter((f) => f !== flag);
1369
1369
  msg.flags = next;
1370
1370
  }
1371
+ function isJunkPreviewText(s) {
1372
+ const t = (s || "").replace(/\s+/g, " ").trim().toLowerCase();
1373
+ if (!t)
1374
+ return true;
1375
+ return t === "undefined" || t === "null" || t === "nan" || t === "[object object]";
1376
+ }
1377
+ function displayNameClaimsOtherAddress(name, address) {
1378
+ const n = (name || "").trim();
1379
+ if (!n)
1380
+ return null;
1381
+ const real = (address || "").trim().toLowerCase();
1382
+ const m = n.match(/[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/g);
1383
+ if (!m)
1384
+ return null;
1385
+ for (const claimed of m) {
1386
+ if (claimed.toLowerCase() !== real)
1387
+ return claimed;
1388
+ }
1389
+ return null;
1390
+ }
1391
+ function formatSender(addr) {
1392
+ const address = (addr?.address || "").trim();
1393
+ const name = (addr?.name || "").trim();
1394
+ if (!name)
1395
+ return { text: address, claimed: null };
1396
+ if (name.toLowerCase() === address.toLowerCase())
1397
+ return { text: address, claimed: null };
1398
+ return { text: `${name} <${address}>`, claimed: displayNameClaimsOtherAddress(name, address) };
1399
+ }
1371
1400
  var _SEEN, _FLAGGED, _DRAFT, seenOf, flaggedOf, draftOf, setSeen, setFlagged;
1372
1401
  var init_mailx_types = __esm({
1373
1402
  "packages/mailx-types/index.js"() {
@@ -3241,9 +3270,10 @@ ${escapeText(reputationBlind)}"` : ""}>${reputationText}</div>` : "") + `<div cl
3241
3270
  }
3242
3271
  }
3243
3272
  function formatAddr(addr) {
3244
- if (addr.name)
3245
- return `${addr.name} <${addr.address}>`;
3246
- return addr.address;
3273
+ const { text, claimed } = formatSender(addr);
3274
+ if (!claimed)
3275
+ return text;
3276
+ return `${text} \u2014 display name claims ${claimed}`;
3247
3277
  }
3248
3278
  function setRecipientLine(toEl, to, cc, deliveredTo) {
3249
3279
  const toList = to || [];
@@ -3463,6 +3493,9 @@ ${csp}
3463
3493
  html { height: 100%; overflow-y: auto; overflow-x: hidden; }
3464
3494
  body {
3465
3495
  font-family: system-ui, sans-serif;
3496
+ /* 17.5px x the 1.15 default preview zoom = ~20.1px effective, which is
3497
+ what COMPOSE_FONT_DEFAULT_PX (compose.ts) is set to match. Change one
3498
+ and change the other, or reading and writing drift apart again. */
3466
3499
  font-size: 17.5px;
3467
3500
  line-height: 1.5;
3468
3501
  color: #1a1a2e;
@@ -5599,7 +5632,13 @@ var init_message_list = __esm({
5599
5632
  if (showToInsteadOfFrom && msg.to?.length) {
5600
5633
  from.textContent = msg.to.map((a) => a.name || a.address).join(", ");
5601
5634
  } else {
5602
- from.textContent = msg.from.name || msg.from.address;
5635
+ const fromName2 = msg.from.name || msg.from.address;
5636
+ const fromClaim = displayNameClaimsOtherAddress(msg.from.name || "", msg.from.address || "");
5637
+ from.textContent = fromClaim ? `${fromName2} \u2014 actually ${msg.from.address}` : fromName2;
5638
+ if (fromClaim) {
5639
+ from.classList.add("ml-from-spoofed");
5640
+ from.title = `Display name claims ${fromClaim}, but the message is from ${msg.from.address}`;
5641
+ }
5603
5642
  }
5604
5643
  if (showAccountTag && accountId) {
5605
5644
  const tag = document.createElement("span");
@@ -5636,7 +5675,7 @@ var init_message_list = __esm({
5636
5675
  });
5637
5676
  subject.prepend(threadPill);
5638
5677
  }
5639
- if (msg.preview) {
5678
+ if (msg.preview && !isJunkPreviewText(msg.preview)) {
5640
5679
  const cleaned = msg.preview.replace(/data:image\/[a-z0-9.+-]+;base64,[A-Za-z0-9+/=\s]+/gi, "[image]").replace(/[A-Za-z0-9+/=]{200,}/g, "[image]");
5641
5680
  const preview = document.createElement("span");
5642
5681
  preview.className = "ml-preview";
@@ -9880,6 +9919,9 @@ async function openCompose(mode, overrideMsg, overrideAccountId) {
9880
9919
  }
9881
9920
  frame = showComposeOverlay(composeTitle);
9882
9921
  }
9922
+ handOffComposeInit(frame, init);
9923
+ }
9924
+ function handOffComposeInit(frame, init) {
9883
9925
  const initJson = JSON.stringify(init);
9884
9926
  try {
9885
9927
  sessionStorage.setItem("composeInit", initJson);
@@ -10611,7 +10653,7 @@ document.getElementById("rail-inbox")?.addEventListener("click", () => {
10611
10653
  inbox?.click();
10612
10654
  });
10613
10655
  document.getElementById("rail-unified")?.addEventListener("click", () => {
10614
- const unified = document.querySelector(".folder-tree .all-inboxes") || document.getElementById("ft-all-inboxes");
10656
+ const unified = document.querySelector(".folder-tree .all-inboxes");
10615
10657
  unified?.click();
10616
10658
  });
10617
10659
  document.getElementById("rail-contacts")?.addEventListener("click", async () => {
@@ -10807,8 +10849,7 @@ document.addEventListener("mailx-share-intent", ((e) => {
10807
10849
  if (Array.isArray(detail.attachments) && detail.attachments.length) {
10808
10850
  init.attachments = detail.attachments.filter((a) => a?.filename && a?.dataBase64);
10809
10851
  }
10810
- sessionStorage.setItem("composeInit", JSON.stringify(init));
10811
- showComposeOverlay(init.subject || "Compose");
10852
+ handOffComposeInit(showComposeOverlay(init.subject || "Compose"), init);
10812
10853
  }));
10813
10854
  var searchTimeout;
10814
10855
  var searchInput = document.getElementById("search-input");
@@ -11098,11 +11139,6 @@ window.addEventListener("message", (e) => {
11098
11139
  }
11099
11140
  return;
11100
11141
  }
11101
- if (e.data?.type === "openLink" && e.data.url) {
11102
- const api = window.mailxapi;
11103
- if (api?.openExternal) api.openExternal(e.data.url);
11104
- else window.open(e.data.url, "_blank", "noopener,noreferrer");
11105
- }
11106
11142
  if (e.data?.type === "linkClick" && e.data.url) {
11107
11143
  const url = e.data.url;
11108
11144
  console.log(`[android-link] parent got linkClick \u2192 ${url}`);
@@ -11121,10 +11157,6 @@ window.addEventListener("message", (e) => {
11121
11157
  }
11122
11158
  return;
11123
11159
  }
11124
- if (e.data?.type === "previewToggleFullscreen") {
11125
- toggleFullscreenPreview();
11126
- return;
11127
- }
11128
11160
  if (e.data?.type === "previewContextMenu") {
11129
11161
  let iframeRect = null;
11130
11162
  for (const f of Array.from(document.querySelectorAll("iframe"))) {
@@ -11146,84 +11178,6 @@ window.addEventListener("message", (e) => {
11146
11178
  );
11147
11179
  return;
11148
11180
  }
11149
- if (e.data?.type === "linkContextMenu") {
11150
- let iframeRect = null;
11151
- for (const f of Array.from(document.querySelectorAll("iframe"))) {
11152
- if (f.contentWindow === e.source) {
11153
- iframeRect = f.getBoundingClientRect();
11154
- break;
11155
- }
11156
- }
11157
- const x = (iframeRect?.left || 0) + (e.data.x || 0);
11158
- const y = (iframeRect?.top || 0) + (e.data.y || 0);
11159
- const url = e.data.url || "";
11160
- const guessName = (() => {
11161
- try {
11162
- const u = new URL(url);
11163
- const last = u.pathname.split("/").pop() || "";
11164
- return last && last.includes(".") ? last : "";
11165
- } catch {
11166
- return "";
11167
- }
11168
- })();
11169
- const items = [
11170
- { label: "Open in browser", action: () => {
11171
- window.open(url, "_blank", "noopener,noreferrer");
11172
- } },
11173
- { label: guessName ? `Save "${guessName}"\u2026` : "Save link as\u2026", action: () => {
11174
- const a = document.createElement("a");
11175
- a.href = url;
11176
- if (guessName) a.download = guessName;
11177
- else a.download = "";
11178
- a.style.display = "none";
11179
- document.body.appendChild(a);
11180
- a.click();
11181
- setTimeout(() => a.remove(), 1e3);
11182
- } },
11183
- { label: "Copy URL", action: async () => {
11184
- try {
11185
- await navigator.clipboard.writeText(url);
11186
- } catch {
11187
- prompt("URL:", url);
11188
- }
11189
- } },
11190
- { label: "Copy link text", action: async () => {
11191
- try {
11192
- await navigator.clipboard.writeText(e.data.text || url);
11193
- } catch {
11194
- prompt("Text:", e.data.text || url);
11195
- }
11196
- } }
11197
- ];
11198
- const menu = document.createElement("div");
11199
- menu.style.cssText = `position:fixed;z-index:2400;background:var(--color-bg);border:1px solid var(--color-border);border-radius:6px;box-shadow:0 4px 16px rgba(0,0,0,0.2);padding:4px 0;font-size:13px;min-width:180px;`;
11200
- menu.style.left = `${Math.min(x, window.innerWidth - 200)}px`;
11201
- menu.style.top = `${Math.min(y, window.innerHeight - 200)}px`;
11202
- menu.addEventListener("mousedown", (ev) => ev.stopPropagation());
11203
- for (const it of items) {
11204
- const row = document.createElement("div");
11205
- row.textContent = it.label;
11206
- row.style.cssText = `padding:6px 12px;cursor:pointer;`;
11207
- row.addEventListener("mouseenter", () => row.style.background = "var(--color-bg-hover)");
11208
- row.addEventListener("mouseleave", () => row.style.background = "");
11209
- row.addEventListener("click", () => {
11210
- menu.remove();
11211
- it.action();
11212
- });
11213
- menu.appendChild(row);
11214
- }
11215
- document.body.appendChild(menu);
11216
- const dismiss = () => {
11217
- menu.remove();
11218
- document.removeEventListener("mousedown", dismiss);
11219
- document.removeEventListener("keydown", dismiss);
11220
- };
11221
- setTimeout(() => {
11222
- document.addEventListener("mousedown", dismiss);
11223
- document.addEventListener("keydown", dismiss);
11224
- }, 0);
11225
- return;
11226
- }
11227
11181
  if (e.data?.type === "mailx-send-error") {
11228
11182
  const statusSync = document.getElementById("status-sync");
11229
11183
  if (statusSync) {
@@ -11730,11 +11684,7 @@ async function openComposeFromMailto(m) {
11730
11684
  references: m.inReplyTo ? [m.inReplyTo] : [],
11731
11685
  accounts: accounts.map((a) => ({ id: a.id, name: a.name, email: a.email, signature: a.signature, sig: a.sig }))
11732
11686
  };
11733
- sessionStorage.setItem("composeInit", JSON.stringify(init));
11734
- try {
11735
- frame?.contentWindow?.postMessage({ type: "compose-init-ready" }, "*");
11736
- } catch {
11737
- }
11687
+ handOffComposeInit(frame, init);
11738
11688
  }
11739
11689
  async function openComposeFromShare(s) {
11740
11690
  const accountsP = getAccounts();
@@ -11767,11 +11717,7 @@ async function openComposeFromShare(s) {
11767
11717
  attachments: s.attachments,
11768
11718
  accounts: accounts.map((a) => ({ id: a.id, name: a.name, email: a.email, signature: a.signature, sig: a.sig }))
11769
11719
  };
11770
- sessionStorage.setItem("composeInit", JSON.stringify(init));
11771
- try {
11772
- frame?.contentWindow?.postMessage({ type: "compose-init-ready" }, "*");
11773
- } catch {
11774
- }
11720
+ handOffComposeInit(frame, init);
11775
11721
  }
11776
11722
  window.addEventListener("keydown", (e) => {
11777
11723
  if (!e.ctrlKey || e.altKey || e.metaKey) return;
@@ -12251,9 +12197,10 @@ document.addEventListener("keydown", (e) => {
12251
12197
  bd.remove();
12252
12198
  closed = true;
12253
12199
  }
12254
- const themeSub = document.getElementById("theme-submenu");
12200
+ const themeSub = document.getElementById("theme-submenu-popout");
12255
12201
  if (themeSub && !themeSub.hidden) {
12256
12202
  themeSub.hidden = true;
12203
+ document.getElementById("theme-submenu-toggle")?.setAttribute("aria-expanded", "false");
12257
12204
  closed = true;
12258
12205
  }
12259
12206
  if (closed) {
@@ -13689,8 +13636,7 @@ document.addEventListener("mailx-popout-message", (async (e) => {
13689
13636
  }
13690
13637
  if (loaded.length) init.attachments = loaded;
13691
13638
  }
13692
- sessionStorage.setItem("composeInit", JSON.stringify(init));
13693
- showComposeOverlay(msg.subject ? `Edit: ${msg.subject}` : "Edit draft");
13639
+ handOffComposeInit(showComposeOverlay(msg.subject ? `Edit: ${msg.subject}` : "Edit draft"), init);
13694
13640
  return;
13695
13641
  }
13696
13642
  const { spawnDesktopPopout: spawnDesktopPopout2 } = await Promise.resolve().then(() => (init_message_viewer(), message_viewer_exports));