@bobfrankston/rmfmail 1.2.87 → 1.2.96

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 (82) hide show
  1. package/client/android-bootstrap.bundle.js +65 -15
  2. package/client/android-bootstrap.bundle.js.map +2 -2
  3. package/client/app.bundle.js +378 -286
  4. package/client/app.bundle.js.map +4 -4
  5. package/client/app.js +23 -1
  6. package/client/app.js.map +1 -1
  7. package/client/app.ts +20 -1
  8. package/client/components/address-book.js +5 -1
  9. package/client/components/address-book.js.map +1 -1
  10. package/client/components/address-book.ts +5 -1
  11. package/client/components/folder-tree.js +31 -6
  12. package/client/components/folder-tree.js.map +1 -1
  13. package/client/components/folder-tree.ts +29 -5
  14. package/client/components/message-list.js +164 -54
  15. package/client/components/message-list.js.map +1 -1
  16. package/client/components/message-list.ts +159 -51
  17. package/client/components/message-viewer.js +7 -0
  18. package/client/components/message-viewer.js.map +1 -1
  19. package/client/components/message-viewer.ts +7 -0
  20. package/client/compose/compose.bundle.js +4 -4
  21. package/client/compose/compose.bundle.js.map +2 -2
  22. package/client/index.html +4 -0
  23. package/client/lib/api-client.js +4 -4
  24. package/client/lib/api-client.js.map +1 -1
  25. package/client/lib/api-client.ts +4 -4
  26. package/client/lib/mailxapi.js +4 -4
  27. package/client/styles/components.css +20 -0
  28. package/package.json +9 -9
  29. package/packages/mailx-imap/index.d.ts +17 -0
  30. package/packages/mailx-imap/index.d.ts.map +1 -1
  31. package/packages/mailx-imap/index.js +86 -4
  32. package/packages/mailx-imap/index.js.map +1 -1
  33. package/packages/mailx-imap/index.ts +85 -4
  34. package/packages/mailx-imap/package-lock.json +2 -2
  35. package/packages/mailx-imap/package.json +1 -1
  36. package/packages/mailx-service/index.d.ts +2 -2
  37. package/packages/mailx-service/index.d.ts.map +1 -1
  38. package/packages/mailx-service/index.js +6 -4
  39. package/packages/mailx-service/index.js.map +1 -1
  40. package/packages/mailx-service/index.ts +7 -5
  41. package/packages/mailx-service/jsonrpc.js +2 -2
  42. package/packages/mailx-service/jsonrpc.js.map +1 -1
  43. package/packages/mailx-service/jsonrpc.ts +2 -2
  44. package/packages/mailx-service/sync-queue.d.ts +3 -0
  45. package/packages/mailx-service/sync-queue.d.ts.map +1 -1
  46. package/packages/mailx-service/sync-queue.js +30 -11
  47. package/packages/mailx-service/sync-queue.js.map +1 -1
  48. package/packages/mailx-service/sync-queue.ts +34 -9
  49. package/packages/mailx-service/sync-worker.js +51 -0
  50. package/packages/mailx-service/sync-worker.js.map +1 -1
  51. package/packages/mailx-service/sync-worker.ts +45 -0
  52. package/packages/mailx-settings/package.json +1 -1
  53. package/packages/mailx-store/db.d.ts +10 -1
  54. package/packages/mailx-store/db.d.ts.map +1 -1
  55. package/packages/mailx-store/db.js +68 -7
  56. package/packages/mailx-store/db.js.map +1 -1
  57. package/packages/mailx-store/db.ts +70 -8
  58. package/packages/mailx-store/package.json +1 -1
  59. package/packages/mailx-store/store.d.ts +1 -1
  60. package/packages/mailx-store/store.d.ts.map +1 -1
  61. package/packages/mailx-store/store.js +2 -2
  62. package/packages/mailx-store/store.js.map +1 -1
  63. package/packages/mailx-store/store.ts +2 -2
  64. package/packages/mailx-store-web/imap-web-provider.d.ts +7 -0
  65. package/packages/mailx-store-web/imap-web-provider.d.ts.map +1 -1
  66. package/packages/mailx-store-web/imap-web-provider.js +12 -0
  67. package/packages/mailx-store-web/imap-web-provider.js.map +1 -1
  68. package/packages/mailx-store-web/imap-web-provider.ts +15 -0
  69. package/packages/mailx-store-web/package.json +1 -1
  70. package/packages/mailx-store-web/sync-manager.d.ts.map +1 -1
  71. package/packages/mailx-store-web/sync-manager.js +12 -0
  72. package/packages/mailx-store-web/sync-manager.js.map +1 -1
  73. package/packages/mailx-store-web/sync-manager.ts +12 -0
  74. package/packages/mailx-store-web/web-service.d.ts.map +1 -1
  75. package/packages/mailx-store-web/web-service.js +53 -19
  76. package/packages/mailx-store-web/web-service.js.map +1 -1
  77. package/packages/mailx-store-web/web-service.ts +60 -20
  78. package/packages/mailx-types/index.d.ts +5 -1
  79. package/packages/mailx-types/index.d.ts.map +1 -1
  80. package/packages/mailx-types/index.js.map +1 -1
  81. package/packages/mailx-types/index.ts +5 -1
  82. package/packages/mailx-types/package.json +1 -1
@@ -5951,6 +5951,7 @@ var WebMailxService = class {
5951
5951
  }
5952
5952
  // ── Send ──
5953
5953
  async send(msg) {
5954
+ console.log(`[send] from=${msg?.from} to=${(msg?.to || []).length} subject="${msg?.subject || ""}" attachments=${Array.isArray(msg?.attachments) ? msg.attachments.length : 0}`);
5954
5955
  const settings = await loadSettings();
5955
5956
  const account = settings.accounts.find((a) => a.id === msg.from);
5956
5957
  if (!account)
@@ -5978,10 +5979,10 @@ var WebMailxService = class {
5978
5979
  msg.references?.length ? `References: ${msg.references.join(" ")}` : null,
5979
5980
  `MIME-Version: 1.0`
5980
5981
  ].filter((h) => h !== null);
5981
- let rawMessage;
5982
- if (hasHtml) {
5983
- const altBoundary = `mailx_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
5984
- const body = `--${altBoundary}\r
5982
+ const makeInner = () => {
5983
+ if (hasHtml) {
5984
+ const altBoundary = `mailx_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
5985
+ const body = `--${altBoundary}\r
5985
5986
  Content-Type: text/plain; charset=UTF-8\r
5986
5987
  Content-Transfer-Encoding: quoted-printable\r
5987
5988
  \r
@@ -5993,22 +5994,50 @@ Content-Transfer-Encoding: quoted-printable\r
5993
5994
  ${htmlEncoded}\r
5994
5995
  --${altBoundary}--\r
5995
5996
  `;
5997
+ return { headers: [`Content-Type: multipart/alternative; boundary="${altBoundary}"`], body };
5998
+ }
5999
+ return {
6000
+ headers: [`Content-Type: text/plain; charset=UTF-8`, `Content-Transfer-Encoding: quoted-printable`],
6001
+ body: textEncoded
6002
+ };
6003
+ };
6004
+ const atts = Array.isArray(msg.attachments) ? msg.attachments : [];
6005
+ let rawMessage;
6006
+ if (atts.length > 0) {
6007
+ const wrap76 = (s) => s.match(/.{1,76}/g)?.join("\r\n") || s;
6008
+ const mixedBoundary = `mailxmix_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
6009
+ const inner = makeInner();
6010
+ const parts = [];
6011
+ parts.push(`--${mixedBoundary}\r
6012
+ ` + inner.headers.join("\r\n") + `\r
6013
+ \r
6014
+ ` + inner.body);
6015
+ for (const att of atts) {
6016
+ const filename = (att.filename || "attachment").replace(/[\r\n"]/g, "_");
6017
+ const mime = att.mimeType || "application/octet-stream";
6018
+ const wrapped = wrap76(att.dataBase64 || "");
6019
+ parts.push(`--${mixedBoundary}\r
6020
+ Content-Type: ${mime}; name="${filename}"\r
6021
+ Content-Disposition: attachment; filename="${filename}"\r
6022
+ Content-Transfer-Encoding: base64\r
6023
+ \r
6024
+ ${wrapped}\r
6025
+ `);
6026
+ }
5996
6027
  const headers = [
5997
6028
  ...envelope,
5998
- `Content-Type: multipart/alternative; boundary="${altBoundary}"`
6029
+ `Content-Type: multipart/mixed; boundary="${mixedBoundary}"`
5999
6030
  ].join("\r\n");
6000
6031
  rawMessage = `${headers}\r
6001
6032
  \r
6002
- ${body}`;
6033
+ ${parts.join("")}--${mixedBoundary}--\r
6034
+ `;
6003
6035
  } else {
6004
- const headers = [
6005
- ...envelope,
6006
- `Content-Type: text/plain; charset=UTF-8`,
6007
- `Content-Transfer-Encoding: quoted-printable`
6008
- ].join("\r\n");
6036
+ const inner = makeInner();
6037
+ const headers = [...envelope, ...inner.headers].join("\r\n");
6009
6038
  rawMessage = `${headers}\r
6010
6039
  \r
6011
- ${textEncoded}`;
6040
+ ${inner.body}`;
6012
6041
  }
6013
6042
  await this.syncManager.queueOutgoingLocal(account.id, rawMessage);
6014
6043
  for (const addr of msg.to)
@@ -6725,11 +6754,14 @@ var GmailApiProvider = class _GmailApiProvider {
6725
6754
  const inReplyTo = getHeader(headers, "In-Reply-To") || "";
6726
6755
  const referencesRaw = getHeader(headers, "References") || "";
6727
6756
  const references = referencesRaw.trim() ? referencesRaw.split(/\s+/).filter((r) => r.startsWith("<") && r.endsWith(">")) : [];
6757
+ const internalMs = msg.internalDate ? new Date(Number(msg.internalDate)) : null;
6758
+ const headerMs = dateRaw ? new Date(dateRaw) : null;
6728
6759
  return {
6729
6760
  uid: idToUid(msg.id),
6730
6761
  messageId,
6731
6762
  providerId: msg.id,
6732
- date: dateRaw ? new Date(dateRaw) : msg.internalDate ? new Date(Number(msg.internalDate)) : null,
6763
+ date: internalMs ?? headerMs,
6764
+ sentDate: headerMs ?? internalMs ?? void 0,
6733
6765
  subject,
6734
6766
  from: parseAddressList(fromRaw),
6735
6767
  to: parseAddressList(toRaw),
@@ -7378,8 +7410,8 @@ function parseEnvelope(envStr) {
7378
7410
  result.to = parseAddressList2(tokens[5]);
7379
7411
  result.cc = parseAddressList2(tokens[6]);
7380
7412
  result.bcc = parseAddressList2(tokens[7]);
7381
- result.inReplyTo = unquote(tokens[8]);
7382
- result.messageId = unquote(tokens[9]);
7413
+ result.inReplyTo = unquote(tokens[8]).trim();
7414
+ result.messageId = unquote(tokens[9]).trim();
7383
7415
  }
7384
7416
  } catch {
7385
7417
  }
@@ -8144,6 +8176,10 @@ var NativeImapClient = class {
8144
8176
  return parseSearchResponse(r.text);
8145
8177
  }
8146
8178
  }
8179
+ const tagged = responses.find((r) => r.tag === tag);
8180
+ if (!tagged || tagged.type !== "OK") {
8181
+ throw new Error(`SEARCH failed: ${tagged ? `${tagged.type} ${tagged.text || ""}` : "no tagged response"}`);
8182
+ }
8147
8183
  return [];
8148
8184
  }
8149
8185
  /** Set flags on a message */
@@ -8831,6 +8867,7 @@ var NativeImapClient = class {
8831
8867
  if (envMatch) {
8832
8868
  const env = parseEnvelope(envMatch[1]);
8833
8869
  msg.date = msg.date || env.date;
8870
+ msg.sentDate = env.date || void 0;
8834
8871
  msg.subject = env.subject;
8835
8872
  msg.messageId = env.messageId;
8836
8873
  msg.from = env.from;
@@ -8873,6 +8910,7 @@ var FetchedMessage = class {
8873
8910
  uid;
8874
8911
  flags;
8875
8912
  date;
8913
+ sentDate;
8876
8914
  subject;
8877
8915
  messageId;
8878
8916
  from;
@@ -9407,6 +9445,18 @@ var ImapWebProvider = class {
9407
9445
  async getUids(folder) {
9408
9446
  return this.withRetry(() => this.client.getUids(folder), `getUids(${folder})`);
9409
9447
  }
9448
+ /** APPEND a raw message to this account's Sent folder. Used by the
9449
+ * Android send path after a successful SMTP delivery — without it a
9450
+ * phone-sent message never got a Sent copy on IMAP accounts (Gmail's
9451
+ * API self-files; SMTP does not). Resolves the Sent path from the
9452
+ * special-folder map (populated by listFolders; refreshed here if the
9453
+ * cache is cold). Returns the appended UID when the server reports it. */
9454
+ async appendToSent(raw) {
9455
+ if (!this.specialFolders.sent)
9456
+ await this.listFolders();
9457
+ const sentPath = this.specialFolders.sent || "Sent";
9458
+ return this.withRetry(() => this.client.appendMessage(sentPath, raw, ["\\Seen"]), `appendToSent(${sentPath})`);
9459
+ }
9410
9460
  async close() {
9411
9461
  try {
9412
9462
  await this.client.logout();