@bobfrankston/rmfmail 1.2.263 → 1.2.268

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 (38) hide show
  1. package/TODO.md +1 -0
  2. package/client/android-bootstrap.bundle.js +32 -0
  3. package/client/android-bootstrap.bundle.js.map +2 -2
  4. package/client/app.bundle.js +51 -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 +11 -4
  13. package/client/components/message-viewer.js.map +1 -1
  14. package/client/components/message-viewer.ts +10 -3
  15. package/client/compose/compose.bundle.js +16 -5
  16. package/client/compose/compose.bundle.js.map +2 -2
  17. package/client/compose/compose.js +5 -6
  18. package/client/compose/compose.js.map +1 -1
  19. package/client/compose/compose.ts +5 -4
  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 +9 -9
  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-store-web/package.json +1 -1
  32. package/packages/mailx-types/index.d.ts +51 -0
  33. package/packages/mailx-types/index.d.ts.map +1 -1
  34. package/packages/mailx-types/index.js +72 -0
  35. package/packages/mailx-types/index.js.map +1 -1
  36. package/packages/mailx-types/index.ts +72 -0
  37. package/packages/mailx-types/package.json +1 -1
  38. /package/packages/mailx-imap/{node_modules.npmglobalize-stash-88864 → node_modules.npmglobalize-stash-83744}/.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 || [];
@@ -5599,7 +5629,13 @@ var init_message_list = __esm({
5599
5629
  if (showToInsteadOfFrom && msg.to?.length) {
5600
5630
  from.textContent = msg.to.map((a) => a.name || a.address).join(", ");
5601
5631
  } else {
5602
- from.textContent = msg.from.name || msg.from.address;
5632
+ const fromName2 = msg.from.name || msg.from.address;
5633
+ const fromClaim = displayNameClaimsOtherAddress(msg.from.name || "", msg.from.address || "");
5634
+ from.textContent = fromClaim ? `${fromName2} \u2014 actually ${msg.from.address}` : fromName2;
5635
+ if (fromClaim) {
5636
+ from.classList.add("ml-from-spoofed");
5637
+ from.title = `Display name claims ${fromClaim}, but the message is from ${msg.from.address}`;
5638
+ }
5603
5639
  }
5604
5640
  if (showAccountTag && accountId) {
5605
5641
  const tag = document.createElement("span");
@@ -5636,7 +5672,7 @@ var init_message_list = __esm({
5636
5672
  });
5637
5673
  subject.prepend(threadPill);
5638
5674
  }
5639
- if (msg.preview) {
5675
+ if (msg.preview && !isJunkPreviewText(msg.preview)) {
5640
5676
  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
5677
  const preview = document.createElement("span");
5642
5678
  preview.className = "ml-preview";
@@ -9880,6 +9916,9 @@ async function openCompose(mode, overrideMsg, overrideAccountId) {
9880
9916
  }
9881
9917
  frame = showComposeOverlay(composeTitle);
9882
9918
  }
9919
+ handOffComposeInit(frame, init);
9920
+ }
9921
+ function handOffComposeInit(frame, init) {
9883
9922
  const initJson = JSON.stringify(init);
9884
9923
  try {
9885
9924
  sessionStorage.setItem("composeInit", initJson);
@@ -10611,7 +10650,7 @@ document.getElementById("rail-inbox")?.addEventListener("click", () => {
10611
10650
  inbox?.click();
10612
10651
  });
10613
10652
  document.getElementById("rail-unified")?.addEventListener("click", () => {
10614
- const unified = document.querySelector(".folder-tree .all-inboxes") || document.getElementById("ft-all-inboxes");
10653
+ const unified = document.querySelector(".folder-tree .all-inboxes");
10615
10654
  unified?.click();
10616
10655
  });
10617
10656
  document.getElementById("rail-contacts")?.addEventListener("click", async () => {
@@ -10807,8 +10846,7 @@ document.addEventListener("mailx-share-intent", ((e) => {
10807
10846
  if (Array.isArray(detail.attachments) && detail.attachments.length) {
10808
10847
  init.attachments = detail.attachments.filter((a) => a?.filename && a?.dataBase64);
10809
10848
  }
10810
- sessionStorage.setItem("composeInit", JSON.stringify(init));
10811
- showComposeOverlay(init.subject || "Compose");
10849
+ handOffComposeInit(showComposeOverlay(init.subject || "Compose"), init);
10812
10850
  }));
10813
10851
  var searchTimeout;
10814
10852
  var searchInput = document.getElementById("search-input");
@@ -11098,11 +11136,6 @@ window.addEventListener("message", (e) => {
11098
11136
  }
11099
11137
  return;
11100
11138
  }
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
11139
  if (e.data?.type === "linkClick" && e.data.url) {
11107
11140
  const url = e.data.url;
11108
11141
  console.log(`[android-link] parent got linkClick \u2192 ${url}`);
@@ -11121,10 +11154,6 @@ window.addEventListener("message", (e) => {
11121
11154
  }
11122
11155
  return;
11123
11156
  }
11124
- if (e.data?.type === "previewToggleFullscreen") {
11125
- toggleFullscreenPreview();
11126
- return;
11127
- }
11128
11157
  if (e.data?.type === "previewContextMenu") {
11129
11158
  let iframeRect = null;
11130
11159
  for (const f of Array.from(document.querySelectorAll("iframe"))) {
@@ -11146,84 +11175,6 @@ window.addEventListener("message", (e) => {
11146
11175
  );
11147
11176
  return;
11148
11177
  }
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
11178
  if (e.data?.type === "mailx-send-error") {
11228
11179
  const statusSync = document.getElementById("status-sync");
11229
11180
  if (statusSync) {
@@ -11730,11 +11681,7 @@ async function openComposeFromMailto(m) {
11730
11681
  references: m.inReplyTo ? [m.inReplyTo] : [],
11731
11682
  accounts: accounts.map((a) => ({ id: a.id, name: a.name, email: a.email, signature: a.signature, sig: a.sig }))
11732
11683
  };
11733
- sessionStorage.setItem("composeInit", JSON.stringify(init));
11734
- try {
11735
- frame?.contentWindow?.postMessage({ type: "compose-init-ready" }, "*");
11736
- } catch {
11737
- }
11684
+ handOffComposeInit(frame, init);
11738
11685
  }
11739
11686
  async function openComposeFromShare(s) {
11740
11687
  const accountsP = getAccounts();
@@ -11767,11 +11714,7 @@ async function openComposeFromShare(s) {
11767
11714
  attachments: s.attachments,
11768
11715
  accounts: accounts.map((a) => ({ id: a.id, name: a.name, email: a.email, signature: a.signature, sig: a.sig }))
11769
11716
  };
11770
- sessionStorage.setItem("composeInit", JSON.stringify(init));
11771
- try {
11772
- frame?.contentWindow?.postMessage({ type: "compose-init-ready" }, "*");
11773
- } catch {
11774
- }
11717
+ handOffComposeInit(frame, init);
11775
11718
  }
11776
11719
  window.addEventListener("keydown", (e) => {
11777
11720
  if (!e.ctrlKey || e.altKey || e.metaKey) return;
@@ -12251,9 +12194,10 @@ document.addEventListener("keydown", (e) => {
12251
12194
  bd.remove();
12252
12195
  closed = true;
12253
12196
  }
12254
- const themeSub = document.getElementById("theme-submenu");
12197
+ const themeSub = document.getElementById("theme-submenu-popout");
12255
12198
  if (themeSub && !themeSub.hidden) {
12256
12199
  themeSub.hidden = true;
12200
+ document.getElementById("theme-submenu-toggle")?.setAttribute("aria-expanded", "false");
12257
12201
  closed = true;
12258
12202
  }
12259
12203
  if (closed) {
@@ -13689,8 +13633,7 @@ document.addEventListener("mailx-popout-message", (async (e) => {
13689
13633
  }
13690
13634
  if (loaded.length) init.attachments = loaded;
13691
13635
  }
13692
- sessionStorage.setItem("composeInit", JSON.stringify(init));
13693
- showComposeOverlay(msg.subject ? `Edit: ${msg.subject}` : "Edit draft");
13636
+ handOffComposeInit(showComposeOverlay(msg.subject ? `Edit: ${msg.subject}` : "Edit draft"), init);
13694
13637
  return;
13695
13638
  }
13696
13639
  const { spawnDesktopPopout: spawnDesktopPopout2 } = await Promise.resolve().then(() => (init_message_viewer(), message_viewer_exports));