@bobfrankston/rmfmail 1.0.467

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 (330) hide show
  1. package/README.md +429 -0
  2. package/bin/build-icon-ico.js +283 -0
  3. package/bin/lean-accounts.js +172 -0
  4. package/bin/mailx.js +1580 -0
  5. package/bin/mailx.js.map +1 -0
  6. package/bin/mailx.ts +1549 -0
  7. package/bin/postinstall.js +39 -0
  8. package/bin/postinstall.js.map +1 -0
  9. package/bin/postinstall.ts +41 -0
  10. package/bin/tsconfig.json +10 -0
  11. package/client/.gitattributes +10 -0
  12. package/client/.msger-window.json +1 -0
  13. package/client/android.html +226 -0
  14. package/client/app.js +3400 -0
  15. package/client/app.js.map +1 -0
  16. package/client/app.ts +3190 -0
  17. package/client/components/address-book.js +199 -0
  18. package/client/components/address-book.js.map +1 -0
  19. package/client/components/address-book.ts +204 -0
  20. package/client/components/alarms.js +299 -0
  21. package/client/components/alarms.js.map +1 -0
  22. package/client/components/alarms.ts +276 -0
  23. package/client/components/calendar-sidebar.js +508 -0
  24. package/client/components/calendar-sidebar.js.map +1 -0
  25. package/client/components/calendar-sidebar.ts +474 -0
  26. package/client/components/calendar.js +217 -0
  27. package/client/components/calendar.js.map +1 -0
  28. package/client/components/calendar.ts +211 -0
  29. package/client/components/context-menu.js +80 -0
  30. package/client/components/context-menu.js.map +1 -0
  31. package/client/components/context-menu.ts +95 -0
  32. package/client/components/folder-picker.js +119 -0
  33. package/client/components/folder-picker.js.map +1 -0
  34. package/client/components/folder-picker.ts +127 -0
  35. package/client/components/folder-tree.js +1093 -0
  36. package/client/components/folder-tree.js.map +1 -0
  37. package/client/components/folder-tree.ts +1069 -0
  38. package/client/components/message-list.js +1140 -0
  39. package/client/components/message-list.js.map +1 -0
  40. package/client/components/message-list.ts +1129 -0
  41. package/client/components/message-viewer.js +1291 -0
  42. package/client/components/message-viewer.js.map +1 -0
  43. package/client/components/message-viewer.ts +1257 -0
  44. package/client/components/outbox-view.js +104 -0
  45. package/client/components/outbox-view.js.map +1 -0
  46. package/client/components/outbox-view.ts +102 -0
  47. package/client/components/tasks.js +261 -0
  48. package/client/components/tasks.js.map +1 -0
  49. package/client/components/tasks.ts +234 -0
  50. package/client/compose/compose.css +560 -0
  51. package/client/compose/compose.html +52 -0
  52. package/client/compose/compose.js +1289 -0
  53. package/client/compose/compose.js.map +1 -0
  54. package/client/compose/compose.ts +1231 -0
  55. package/client/compose/editor.js +616 -0
  56. package/client/compose/editor.js.map +1 -0
  57. package/client/compose/editor.ts +599 -0
  58. package/client/compose/ghost-text.js +122 -0
  59. package/client/compose/ghost-text.js.map +1 -0
  60. package/client/compose/ghost-text.ts +140 -0
  61. package/client/favicon.svg +11 -0
  62. package/client/icon.ico +0 -0
  63. package/client/icon.png +0 -0
  64. package/client/index.html +230 -0
  65. package/client/lib/android-bootstrap.js +9 -0
  66. package/client/lib/android-bootstrap.js.map +1 -0
  67. package/client/lib/android-bootstrap.ts +9 -0
  68. package/client/lib/api-client.js +378 -0
  69. package/client/lib/api-client.js.map +1 -0
  70. package/client/lib/api-client.ts +439 -0
  71. package/client/lib/local-service.js +603 -0
  72. package/client/lib/local-service.js.map +1 -0
  73. package/client/lib/local-service.ts +646 -0
  74. package/client/lib/local-store.js +214 -0
  75. package/client/lib/local-store.js.map +1 -0
  76. package/client/lib/local-store.ts +283 -0
  77. package/client/lib/mailxapi.js +304 -0
  78. package/client/lib/message-state.js +132 -0
  79. package/client/lib/message-state.js.map +1 -0
  80. package/client/lib/message-state.ts +160 -0
  81. package/client/package.json +16 -0
  82. package/client/styles/components.css +2049 -0
  83. package/client/styles/layout.css +332 -0
  84. package/client/styles/variables.css +85 -0
  85. package/client/tsconfig.json +19 -0
  86. package/package.json +124 -0
  87. package/packages/mailx-api/.gitattributes +10 -0
  88. package/packages/mailx-api/index.d.ts +10 -0
  89. package/packages/mailx-api/index.d.ts.map +1 -0
  90. package/packages/mailx-api/index.js +322 -0
  91. package/packages/mailx-api/index.js.map +1 -0
  92. package/packages/mailx-api/index.ts +283 -0
  93. package/packages/mailx-api/package.json +27 -0
  94. package/packages/mailx-api/tsconfig.json +9 -0
  95. package/packages/mailx-api/tsconfig.tsbuildinfo +1 -0
  96. package/packages/mailx-compose/.gitattributes +10 -0
  97. package/packages/mailx-compose/index.d.ts +21 -0
  98. package/packages/mailx-compose/index.d.ts.map +1 -0
  99. package/packages/mailx-compose/index.js +61 -0
  100. package/packages/mailx-compose/index.js.map +1 -0
  101. package/packages/mailx-compose/index.ts +85 -0
  102. package/packages/mailx-compose/package.json +18 -0
  103. package/packages/mailx-compose/tsconfig.json +9 -0
  104. package/packages/mailx-core/index.d.ts +139 -0
  105. package/packages/mailx-core/index.d.ts.map +1 -0
  106. package/packages/mailx-core/index.js +403 -0
  107. package/packages/mailx-core/index.js.map +1 -0
  108. package/packages/mailx-core/index.ts +424 -0
  109. package/packages/mailx-core/ipc.d.ts +13 -0
  110. package/packages/mailx-core/ipc.d.ts.map +1 -0
  111. package/packages/mailx-core/ipc.js +56 -0
  112. package/packages/mailx-core/ipc.js.map +1 -0
  113. package/packages/mailx-core/ipc.ts +62 -0
  114. package/packages/mailx-core/package.json +18 -0
  115. package/packages/mailx-core/tsconfig.json +9 -0
  116. package/packages/mailx-host/.gitattributes +10 -0
  117. package/packages/mailx-host/index.d.ts +21 -0
  118. package/packages/mailx-host/index.d.ts.map +1 -0
  119. package/packages/mailx-host/index.js +29 -0
  120. package/packages/mailx-host/index.js.map +1 -0
  121. package/packages/mailx-host/index.ts +38 -0
  122. package/packages/mailx-host/package.json +23 -0
  123. package/packages/mailx-host/tsconfig.json +9 -0
  124. package/packages/mailx-host/types-shim.d.ts +14 -0
  125. package/packages/mailx-imap/.gitattributes +10 -0
  126. package/packages/mailx-imap/index.d.ts +442 -0
  127. package/packages/mailx-imap/index.d.ts.map +1 -0
  128. package/packages/mailx-imap/index.js +3684 -0
  129. package/packages/mailx-imap/index.js.map +1 -0
  130. package/packages/mailx-imap/index.ts +3652 -0
  131. package/packages/mailx-imap/package-lock.json +131 -0
  132. package/packages/mailx-imap/package.json +28 -0
  133. package/packages/mailx-imap/providers/gmail-api.d.ts +8 -0
  134. package/packages/mailx-imap/providers/gmail-api.d.ts.map +1 -0
  135. package/packages/mailx-imap/providers/gmail-api.js +8 -0
  136. package/packages/mailx-imap/providers/gmail-api.js.map +1 -0
  137. package/packages/mailx-imap/providers/gmail-api.ts +8 -0
  138. package/packages/mailx-imap/providers/outlook-api.ts +7 -0
  139. package/packages/mailx-imap/providers/types.d.ts +9 -0
  140. package/packages/mailx-imap/providers/types.d.ts.map +1 -0
  141. package/packages/mailx-imap/providers/types.js +9 -0
  142. package/packages/mailx-imap/providers/types.js.map +1 -0
  143. package/packages/mailx-imap/providers/types.ts +9 -0
  144. package/packages/mailx-imap/tsconfig.json +9 -0
  145. package/packages/mailx-imap/tsconfig.tsbuildinfo +1 -0
  146. package/packages/mailx-send/.gitattributes +10 -0
  147. package/packages/mailx-send/README.md +217 -0
  148. package/packages/mailx-send/cli-queue.d.ts +11 -0
  149. package/packages/mailx-send/cli-queue.d.ts.map +1 -0
  150. package/packages/mailx-send/cli-queue.js +59 -0
  151. package/packages/mailx-send/cli-queue.js.map +1 -0
  152. package/packages/mailx-send/cli-queue.ts +62 -0
  153. package/packages/mailx-send/cli-send.d.ts +17 -0
  154. package/packages/mailx-send/cli-send.d.ts.map +1 -0
  155. package/packages/mailx-send/cli-send.js +75 -0
  156. package/packages/mailx-send/cli-send.js.map +1 -0
  157. package/packages/mailx-send/cli-send.ts +83 -0
  158. package/packages/mailx-send/cli.d.ts +22 -0
  159. package/packages/mailx-send/cli.d.ts.map +1 -0
  160. package/packages/mailx-send/cli.js +115 -0
  161. package/packages/mailx-send/cli.js.map +1 -0
  162. package/packages/mailx-send/cli.ts +126 -0
  163. package/packages/mailx-send/index.d.ts +77 -0
  164. package/packages/mailx-send/index.d.ts.map +1 -0
  165. package/packages/mailx-send/index.js +264 -0
  166. package/packages/mailx-send/index.js.map +1 -0
  167. package/packages/mailx-send/index.ts +333 -0
  168. package/packages/mailx-send/mailsend/README.md +133 -0
  169. package/packages/mailx-send/mailsend/cli.d.ts +12 -0
  170. package/packages/mailx-send/mailsend/cli.d.ts.map +1 -0
  171. package/packages/mailx-send/mailsend/cli.js +70 -0
  172. package/packages/mailx-send/mailsend/cli.js.map +1 -0
  173. package/packages/mailx-send/mailsend/cli.ts +81 -0
  174. package/packages/mailx-send/mailsend/index.d.ts +77 -0
  175. package/packages/mailx-send/mailsend/index.d.ts.map +1 -0
  176. package/packages/mailx-send/mailsend/index.js +264 -0
  177. package/packages/mailx-send/mailsend/index.js.map +1 -0
  178. package/packages/mailx-send/mailsend/index.ts +333 -0
  179. package/packages/mailx-send/mailsend/package-lock.json +65 -0
  180. package/packages/mailx-send/mailsend/package.json +26 -0
  181. package/packages/mailx-send/mailsend/tsconfig.json +21 -0
  182. package/packages/mailx-send/package-lock.json +65 -0
  183. package/packages/mailx-send/package.json +37 -0
  184. package/packages/mailx-send/tsconfig.json +21 -0
  185. package/packages/mailx-server/.gitattributes +10 -0
  186. package/packages/mailx-server/index.d.ts +8 -0
  187. package/packages/mailx-server/index.d.ts.map +1 -0
  188. package/packages/mailx-server/index.js +397 -0
  189. package/packages/mailx-server/index.js.map +1 -0
  190. package/packages/mailx-server/index.ts +429 -0
  191. package/packages/mailx-server/package.json +28 -0
  192. package/packages/mailx-server/tsconfig.json +9 -0
  193. package/packages/mailx-server/tsconfig.tsbuildinfo +1 -0
  194. package/packages/mailx-service/google-sync.d.ts +96 -0
  195. package/packages/mailx-service/google-sync.d.ts.map +1 -0
  196. package/packages/mailx-service/google-sync.js +153 -0
  197. package/packages/mailx-service/google-sync.js.map +1 -0
  198. package/packages/mailx-service/google-sync.ts +238 -0
  199. package/packages/mailx-service/index.d.ts +366 -0
  200. package/packages/mailx-service/index.d.ts.map +1 -0
  201. package/packages/mailx-service/index.js +2589 -0
  202. package/packages/mailx-service/index.js.map +1 -0
  203. package/packages/mailx-service/index.ts +2512 -0
  204. package/packages/mailx-service/jsonrpc.d.ts +25 -0
  205. package/packages/mailx-service/jsonrpc.d.ts.map +1 -0
  206. package/packages/mailx-service/jsonrpc.js +238 -0
  207. package/packages/mailx-service/jsonrpc.js.map +1 -0
  208. package/packages/mailx-service/jsonrpc.ts +268 -0
  209. package/packages/mailx-service/package.json +22 -0
  210. package/packages/mailx-service/tsconfig.json +9 -0
  211. package/packages/mailx-settings/.gitattributes +10 -0
  212. package/packages/mailx-settings/cloud.d.ts +47 -0
  213. package/packages/mailx-settings/cloud.d.ts.map +1 -0
  214. package/packages/mailx-settings/cloud.js +408 -0
  215. package/packages/mailx-settings/cloud.js.map +1 -0
  216. package/packages/mailx-settings/cloud.ts +393 -0
  217. package/packages/mailx-settings/index.d.ts +140 -0
  218. package/packages/mailx-settings/index.d.ts.map +1 -0
  219. package/packages/mailx-settings/index.js +872 -0
  220. package/packages/mailx-settings/index.js.map +1 -0
  221. package/packages/mailx-settings/index.ts +908 -0
  222. package/packages/mailx-settings/package.json +20 -0
  223. package/packages/mailx-settings/tsconfig.json +9 -0
  224. package/packages/mailx-settings/tsconfig.tsbuildinfo +1 -0
  225. package/packages/mailx-store/.gitattributes +10 -0
  226. package/packages/mailx-store/db.d.ts +346 -0
  227. package/packages/mailx-store/db.d.ts.map +1 -0
  228. package/packages/mailx-store/db.js +1796 -0
  229. package/packages/mailx-store/db.js.map +1 -0
  230. package/packages/mailx-store/db.ts +2007 -0
  231. package/packages/mailx-store/file-store.d.ts +36 -0
  232. package/packages/mailx-store/file-store.d.ts.map +1 -0
  233. package/packages/mailx-store/file-store.js +80 -0
  234. package/packages/mailx-store/file-store.js.map +1 -0
  235. package/packages/mailx-store/file-store.ts +82 -0
  236. package/packages/mailx-store/index.d.ts +7 -0
  237. package/packages/mailx-store/index.d.ts.map +1 -0
  238. package/packages/mailx-store/index.js +7 -0
  239. package/packages/mailx-store/index.js.map +1 -0
  240. package/packages/mailx-store/index.ts +7 -0
  241. package/packages/mailx-store/package.json +19 -0
  242. package/packages/mailx-store/tsconfig.json +9 -0
  243. package/packages/mailx-store/tsconfig.tsbuildinfo +1 -0
  244. package/packages/mailx-store-web/android-bootstrap.d.ts +16 -0
  245. package/packages/mailx-store-web/android-bootstrap.d.ts.map +1 -0
  246. package/packages/mailx-store-web/android-bootstrap.js +1247 -0
  247. package/packages/mailx-store-web/android-bootstrap.js.map +1 -0
  248. package/packages/mailx-store-web/android-bootstrap.ts +1262 -0
  249. package/packages/mailx-store-web/db.d.ts +132 -0
  250. package/packages/mailx-store-web/db.d.ts.map +1 -0
  251. package/packages/mailx-store-web/db.js +642 -0
  252. package/packages/mailx-store-web/db.js.map +1 -0
  253. package/packages/mailx-store-web/db.ts +756 -0
  254. package/packages/mailx-store-web/gmail-api-web.d.ts +11 -0
  255. package/packages/mailx-store-web/gmail-api-web.d.ts.map +1 -0
  256. package/packages/mailx-store-web/gmail-api-web.js +11 -0
  257. package/packages/mailx-store-web/gmail-api-web.js.map +1 -0
  258. package/packages/mailx-store-web/gmail-api-web.ts +11 -0
  259. package/packages/mailx-store-web/imap-web-provider.d.ts +33 -0
  260. package/packages/mailx-store-web/imap-web-provider.d.ts.map +1 -0
  261. package/packages/mailx-store-web/imap-web-provider.js +140 -0
  262. package/packages/mailx-store-web/imap-web-provider.js.map +1 -0
  263. package/packages/mailx-store-web/imap-web-provider.ts +156 -0
  264. package/packages/mailx-store-web/index.d.ts +10 -0
  265. package/packages/mailx-store-web/index.d.ts.map +1 -0
  266. package/packages/mailx-store-web/index.js +10 -0
  267. package/packages/mailx-store-web/index.js.map +1 -0
  268. package/packages/mailx-store-web/index.ts +10 -0
  269. package/packages/mailx-store-web/main-thread-host.d.ts +15 -0
  270. package/packages/mailx-store-web/main-thread-host.d.ts.map +1 -0
  271. package/packages/mailx-store-web/main-thread-host.js +292 -0
  272. package/packages/mailx-store-web/main-thread-host.js.map +1 -0
  273. package/packages/mailx-store-web/main-thread-host.ts +322 -0
  274. package/packages/mailx-store-web/package.json +23 -0
  275. package/packages/mailx-store-web/provider-types.d.ts +7 -0
  276. package/packages/mailx-store-web/provider-types.d.ts.map +1 -0
  277. package/packages/mailx-store-web/provider-types.js +7 -0
  278. package/packages/mailx-store-web/provider-types.js.map +1 -0
  279. package/packages/mailx-store-web/provider-types.ts +7 -0
  280. package/packages/mailx-store-web/sql-wasm-esm.js +10 -0
  281. package/packages/mailx-store-web/sql.js.d.ts +29 -0
  282. package/packages/mailx-store-web/sync-manager.d.ts +68 -0
  283. package/packages/mailx-store-web/sync-manager.d.ts.map +1 -0
  284. package/packages/mailx-store-web/sync-manager.js +506 -0
  285. package/packages/mailx-store-web/sync-manager.js.map +1 -0
  286. package/packages/mailx-store-web/sync-manager.ts +508 -0
  287. package/packages/mailx-store-web/tsconfig.json +10 -0
  288. package/packages/mailx-store-web/web-jsonrpc.d.ts +20 -0
  289. package/packages/mailx-store-web/web-jsonrpc.d.ts.map +1 -0
  290. package/packages/mailx-store-web/web-jsonrpc.js +102 -0
  291. package/packages/mailx-store-web/web-jsonrpc.js.map +1 -0
  292. package/packages/mailx-store-web/web-jsonrpc.ts +116 -0
  293. package/packages/mailx-store-web/web-message-store.d.ts +16 -0
  294. package/packages/mailx-store-web/web-message-store.d.ts.map +1 -0
  295. package/packages/mailx-store-web/web-message-store.js +89 -0
  296. package/packages/mailx-store-web/web-message-store.js.map +1 -0
  297. package/packages/mailx-store-web/web-message-store.ts +97 -0
  298. package/packages/mailx-store-web/web-service.d.ts +111 -0
  299. package/packages/mailx-store-web/web-service.d.ts.map +1 -0
  300. package/packages/mailx-store-web/web-service.js +542 -0
  301. package/packages/mailx-store-web/web-service.js.map +1 -0
  302. package/packages/mailx-store-web/web-service.ts +616 -0
  303. package/packages/mailx-store-web/web-settings.d.ts +83 -0
  304. package/packages/mailx-store-web/web-settings.d.ts.map +1 -0
  305. package/packages/mailx-store-web/web-settings.js +491 -0
  306. package/packages/mailx-store-web/web-settings.js.map +1 -0
  307. package/packages/mailx-store-web/web-settings.ts +522 -0
  308. package/packages/mailx-store-web/worker-bundle.js +6838 -0
  309. package/packages/mailx-store-web/worker-entry.d.ts +8 -0
  310. package/packages/mailx-store-web/worker-entry.d.ts.map +1 -0
  311. package/packages/mailx-store-web/worker-entry.js +187 -0
  312. package/packages/mailx-store-web/worker-entry.js.map +1 -0
  313. package/packages/mailx-store-web/worker-entry.ts +215 -0
  314. package/packages/mailx-store-web/worker-tcp-transport.d.ts +28 -0
  315. package/packages/mailx-store-web/worker-tcp-transport.d.ts.map +1 -0
  316. package/packages/mailx-store-web/worker-tcp-transport.js +98 -0
  317. package/packages/mailx-store-web/worker-tcp-transport.js.map +1 -0
  318. package/packages/mailx-store-web/worker-tcp-transport.ts +101 -0
  319. package/packages/mailx-types/.gitattributes +10 -0
  320. package/packages/mailx-types/index.d.ts +319 -0
  321. package/packages/mailx-types/index.d.ts.map +1 -0
  322. package/packages/mailx-types/index.js +243 -0
  323. package/packages/mailx-types/index.js.map +1 -0
  324. package/packages/mailx-types/index.ts +498 -0
  325. package/packages/mailx-types/package.json +16 -0
  326. package/packages/mailx-types/tsconfig.json +9 -0
  327. package/packages/mailx-types/tsconfig.tsbuildinfo +1 -0
  328. package/todo.json +13 -0
  329. package/tsconfig.base.json +31 -0
  330. package/tsconfig.json +9 -0
@@ -0,0 +1,283 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Build client/icon.ico from client/icon.png with proper format coverage:
4
+ * - 16, 32, 48, 64, 128 px entries: BMP-DIB (BI_RGB) — required by the
5
+ * Windows Shell taskbar/AUMID code path. PNG-in-ICO at small sizes is
6
+ * silently rejected, leaving the taskbar showing the generic "document"
7
+ * icon (the bug behind "icon shows as a piece of paper").
8
+ * - 256 px entry: PNG (Vista+ accepts it; smaller file than the 256 KB
9
+ * a 256x256 BMP DIB would be).
10
+ *
11
+ * Run: node bin/build-icon-ico.js
12
+ *
13
+ * Source: client/icon.png. Re-run whenever the source PNG changes.
14
+ *
15
+ * Hand-rolled — no image deps available in the workspace. Decodes 8-bit
16
+ * RGBA / RGB non-interlaced PNG (which is what every standard tool emits),
17
+ * downsamples by box-averaging, encodes BMP DIBs with the trailing AND mask
18
+ * the ICO format requires.
19
+ */
20
+ import fs from "node:fs";
21
+ import path from "node:path";
22
+ import zlib from "node:zlib";
23
+
24
+ const root = path.resolve(import.meta.dirname, "..");
25
+ const src = path.join(root, "client", "icon.png");
26
+ const dst = path.join(root, "client", "icon.ico");
27
+
28
+ if (!fs.existsSync(src)) {
29
+ console.error(`build-icon-ico: source not found: ${src}`);
30
+ process.exit(1);
31
+ }
32
+
33
+ const pngBuf = fs.readFileSync(src);
34
+
35
+ // ── PNG decoder (8-bit RGBA / RGB, no interlace) ─────────────────────────
36
+ function decodePNG(buf) {
37
+ const sigExpected = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A];
38
+ if (buf.length < 8 || sigExpected.some((b, i) => buf[i] !== b)) {
39
+ throw new Error("not a PNG (bad signature)");
40
+ }
41
+ let pos = 8;
42
+ let width = 0, height = 0, bitDepth = 0, colorType = 0;
43
+ const idat = [];
44
+ while (pos < buf.length) {
45
+ const len = buf.readUInt32BE(pos); pos += 4;
46
+ const type = buf.toString("ascii", pos, pos + 4); pos += 4;
47
+ const data = buf.subarray(pos, pos + len); pos += len + 4; // skip CRC
48
+ if (type === "IHDR") {
49
+ width = data.readUInt32BE(0);
50
+ height = data.readUInt32BE(4);
51
+ bitDepth = data.readUInt8(8);
52
+ colorType = data.readUInt8(9);
53
+ if (data.readUInt8(12) !== 0) {
54
+ throw new Error("interlaced PNG not supported");
55
+ }
56
+ } else if (type === "IDAT") {
57
+ idat.push(data);
58
+ } else if (type === "IEND") {
59
+ break;
60
+ }
61
+ }
62
+ if (bitDepth !== 8 && bitDepth !== 16) {
63
+ throw new Error(`bit depth ${bitDepth} not supported (need 8 or 16)`);
64
+ }
65
+ if (colorType !== 6 && colorType !== 2) {
66
+ throw new Error(`color type ${colorType} not supported (need 2=RGB or 6=RGBA)`);
67
+ }
68
+ const samplesPerPixel = colorType === 6 ? 4 : 3;
69
+ const bytesPerSample = bitDepth / 8; // 1 or 2
70
+ const bpp = samplesPerPixel * bytesPerSample;
71
+ const inflated = zlib.inflateSync(Buffer.concat(idat));
72
+ const stride = width * bpp;
73
+ const rgba = Buffer.alloc(width * height * 4);
74
+ let inPos = 0;
75
+ let prev = Buffer.alloc(stride);
76
+ let cur = Buffer.alloc(stride);
77
+ for (let y = 0; y < height; y++) {
78
+ const filter = inflated.readUInt8(inPos); inPos += 1;
79
+ inflated.copy(cur, 0, inPos, inPos + stride); inPos += stride;
80
+ switch (filter) {
81
+ case 0: break; // None
82
+ case 1: // Sub
83
+ for (let x = bpp; x < stride; x++) cur[x] = (cur[x] + cur[x - bpp]) & 0xFF;
84
+ break;
85
+ case 2: // Up
86
+ for (let x = 0; x < stride; x++) cur[x] = (cur[x] + prev[x]) & 0xFF;
87
+ break;
88
+ case 3: // Avg
89
+ for (let x = 0; x < stride; x++) {
90
+ const left = x >= bpp ? cur[x - bpp] : 0;
91
+ cur[x] = (cur[x] + ((left + prev[x]) >> 1)) & 0xFF;
92
+ }
93
+ break;
94
+ case 4: { // Paeth
95
+ for (let x = 0; x < stride; x++) {
96
+ const a = x >= bpp ? cur[x - bpp] : 0;
97
+ const b = prev[x];
98
+ const c = x >= bpp ? prev[x - bpp] : 0;
99
+ const p = a + b - c;
100
+ const pa = Math.abs(p - a);
101
+ const pb = Math.abs(p - b);
102
+ const pc = Math.abs(p - c);
103
+ const pred = pa <= pb && pa <= pc ? a : pb <= pc ? b : c;
104
+ cur[x] = (cur[x] + pred) & 0xFF;
105
+ }
106
+ break;
107
+ }
108
+ default: throw new Error(`unknown PNG filter ${filter}`);
109
+ }
110
+ // 16-bit samples are big-endian; we keep only the high byte (eyeball-
111
+ // identical to dividing by 257 for icon use).
112
+ for (let x = 0; x < width; x++) {
113
+ const di = (y * width + x) * 4;
114
+ const si = x * bpp;
115
+ if (bitDepth === 8) {
116
+ rgba[di + 0] = cur[si + 0];
117
+ rgba[di + 1] = cur[si + 1];
118
+ rgba[di + 2] = cur[si + 2];
119
+ rgba[di + 3] = samplesPerPixel === 4 ? cur[si + 3] : 255;
120
+ } else {
121
+ rgba[di + 0] = cur[si + 0]; // hi byte of R
122
+ rgba[di + 1] = cur[si + 2]; // hi byte of G
123
+ rgba[di + 2] = cur[si + 4]; // hi byte of B
124
+ rgba[di + 3] = samplesPerPixel === 4 ? cur[si + 6] : 255;
125
+ }
126
+ }
127
+ const swap = prev; prev = cur; cur = swap;
128
+ }
129
+ return { width, height, rgba };
130
+ }
131
+
132
+ // ── Box-filter downsample (good enough for icon sizes) ───────────────────
133
+ function downsample(src, srcW, srcH, dstW, dstH) {
134
+ if (srcW === dstW && srcH === dstH) return Buffer.from(src);
135
+ const dst = Buffer.alloc(dstW * dstH * 4);
136
+ const sx = srcW / dstW;
137
+ const sy = srcH / dstH;
138
+ for (let y = 0; y < dstH; y++) {
139
+ const y0 = Math.floor(y * sy);
140
+ const y1 = Math.min(srcH, Math.ceil((y + 1) * sy));
141
+ for (let x = 0; x < dstW; x++) {
142
+ const x0 = Math.floor(x * sx);
143
+ const x1 = Math.min(srcW, Math.ceil((x + 1) * sx));
144
+ let r = 0, g = 0, b = 0, a = 0, n = 0;
145
+ for (let yy = y0; yy < y1; yy++) {
146
+ for (let xx = x0; xx < x1; xx++) {
147
+ const i = (yy * srcW + xx) * 4;
148
+ r += src[i]; g += src[i + 1]; b += src[i + 2]; a += src[i + 3];
149
+ n++;
150
+ }
151
+ }
152
+ const di = (y * dstW + x) * 4;
153
+ dst[di] = (r / n) | 0;
154
+ dst[di + 1] = (g / n) | 0;
155
+ dst[di + 2] = (b / n) | 0;
156
+ dst[di + 3] = (a / n) | 0;
157
+ }
158
+ }
159
+ return dst;
160
+ }
161
+
162
+ // ── BMP DIB encoder for ICO entries (32bpp BGRA + AND mask) ──────────────
163
+ function encodeDIB(rgba, w, h) {
164
+ const colorBytes = w * h * 4;
165
+ const maskRowSize = ((w + 31) >> 5) << 2; // 1bpp, 4-byte aligned
166
+ const maskBytes = maskRowSize * h;
167
+ const out = Buffer.alloc(40 + colorBytes + maskBytes);
168
+ // BITMAPINFOHEADER
169
+ out.writeUInt32LE(40, 0); // biSize
170
+ out.writeInt32LE(w, 4); // biWidth
171
+ out.writeInt32LE(h * 2, 8); // biHeight = 2*h (color + mask)
172
+ out.writeUInt16LE(1, 12); // biPlanes
173
+ out.writeUInt16LE(32, 14); // biBitCount
174
+ out.writeUInt32LE(0, 16); // biCompression (BI_RGB)
175
+ // remaining BITMAPINFOHEADER fields stay zero
176
+ // Color: 32bpp BGRA, bottom-up
177
+ let off = 40;
178
+ for (let y = h - 1; y >= 0; y--) {
179
+ for (let x = 0; x < w; x++) {
180
+ const i = (y * w + x) * 4;
181
+ out[off++] = rgba[i + 2]; // B
182
+ out[off++] = rgba[i + 1]; // G
183
+ out[off++] = rgba[i + 0]; // R
184
+ out[off++] = rgba[i + 3]; // A
185
+ }
186
+ }
187
+ // AND mask stays all-zero — alpha channel handles transparency. Required
188
+ // by ICO format though, so we allocate the bytes (already zeroed).
189
+ return out;
190
+ }
191
+
192
+ // ── ICO container ────────────────────────────────────────────────────────
193
+ function buildICO(entries) {
194
+ const dirSize = 6 + 16 * entries.length;
195
+ const dir = Buffer.alloc(dirSize);
196
+ dir.writeUInt16LE(0, 0); // reserved
197
+ dir.writeUInt16LE(1, 2); // type = icon
198
+ dir.writeUInt16LE(entries.length, 4); // count
199
+ let dataOff = dirSize;
200
+ for (let i = 0; i < entries.length; i++) {
201
+ const e = entries[i];
202
+ const o = 6 + i * 16;
203
+ dir.writeUInt8(e.size === 256 ? 0 : e.size, o);
204
+ dir.writeUInt8(e.size === 256 ? 0 : e.size, o + 1);
205
+ dir.writeUInt8(0, o + 2); // ncolors
206
+ dir.writeUInt8(0, o + 3); // reserved
207
+ dir.writeUInt16LE(1, o + 4); // planes
208
+ dir.writeUInt16LE(32, o + 6); // bpp
209
+ dir.writeUInt32LE(e.data.length, o + 8);
210
+ dir.writeUInt32LE(dataOff, o + 12);
211
+ dataOff += e.data.length;
212
+ }
213
+ return Buffer.concat([dir, ...entries.map(e => e.data)]);
214
+ }
215
+
216
+ // ── Main ─────────────────────────────────────────────────────────────────
217
+ const decoded = decodePNG(pngBuf);
218
+ console.log(`build-icon-ico: source ${decoded.width}x${decoded.height} ${decoded.rgba.length} bytes RGBA`);
219
+
220
+ const sizes = [16, 32, 48, 64, 128, 256];
221
+ const entries = [];
222
+ for (const sz of sizes) {
223
+ const scaled = downsample(decoded.rgba, decoded.width, decoded.height, sz, sz);
224
+ if (sz === 256) {
225
+ // 256x256 BMP would be 256KB — store as PNG instead. Vista+ Shell
226
+ // accepts PNG entries at >=96px; <96px still has to be BMP for the
227
+ // taskbar code path on older configs.
228
+ const pngEntry = encodePNGEntry(scaled, sz);
229
+ entries.push({ size: sz, data: pngEntry });
230
+ } else {
231
+ entries.push({ size: sz, data: encodeDIB(scaled, sz, sz) });
232
+ }
233
+ }
234
+
235
+ // Re-encode an RGBA buffer back to a PNG (used only for the 256x256 entry).
236
+ function encodePNGEntry(rgba, sz) {
237
+ function chunk(type, data) {
238
+ const len = Buffer.alloc(4);
239
+ len.writeUInt32BE(data.length, 0);
240
+ const head = Buffer.concat([Buffer.from(type, "ascii"), data]);
241
+ const crc = Buffer.alloc(4);
242
+ crc.writeInt32BE(crc32(head), 0);
243
+ return Buffer.concat([len, head, crc]);
244
+ }
245
+ const sig = Buffer.from([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]);
246
+ const ihdr = Buffer.alloc(13);
247
+ ihdr.writeUInt32BE(sz, 0);
248
+ ihdr.writeUInt32BE(sz, 4);
249
+ ihdr[8] = 8; // bit depth
250
+ ihdr[9] = 6; // RGBA
251
+ ihdr[10] = 0; // compression
252
+ ihdr[11] = 0; // filter
253
+ ihdr[12] = 0; // interlace
254
+ // Filter byte 0 (None) per scanline + RGBA pixels
255
+ const stride = sz * 4;
256
+ const filtered = Buffer.alloc(sz * (stride + 1));
257
+ for (let y = 0; y < sz; y++) {
258
+ filtered[y * (stride + 1)] = 0;
259
+ rgba.copy(filtered, y * (stride + 1) + 1, y * stride, y * stride + stride);
260
+ }
261
+ const idat = zlib.deflateSync(filtered, { level: 9 });
262
+ return Buffer.concat([sig, chunk("IHDR", ihdr), chunk("IDAT", idat), chunk("IEND", Buffer.alloc(0))]);
263
+ }
264
+
265
+ // Standard PNG-spec CRC32.
266
+ function crc32(buf) {
267
+ let c, table = crc32.table;
268
+ if (!table) {
269
+ table = crc32.table = new Int32Array(256);
270
+ for (let n = 0; n < 256; n++) {
271
+ c = n;
272
+ for (let k = 0; k < 8; k++) c = c & 1 ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1);
273
+ table[n] = c;
274
+ }
275
+ }
276
+ c = -1;
277
+ for (let i = 0; i < buf.length; i++) c = table[(c ^ buf[i]) & 0xFF] ^ (c >>> 8);
278
+ return c ^ -1;
279
+ }
280
+
281
+ const ico = buildICO(entries);
282
+ fs.writeFileSync(dst, ico);
283
+ console.log(`build-icon-ico: wrote ${dst} (${ico.length} bytes, sizes: ${sizes.join(", ")})`);
@@ -0,0 +1,172 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * lean-accounts.js — strip default-valued fields from an accounts.jsonc.
4
+ *
5
+ * Reads any accounts.jsonc (the one mailx writes when it bloats it with
6
+ * port: 993, tls: true, auth: "password", enabled: true, sig.html: false,
7
+ * etc.) and emits a compact form. Same logic as the Lean button in the
8
+ * config editor, but standalone so it works without mailx running.
9
+ *
10
+ * Usage:
11
+ * node lean-accounts.js <path> prints lean output to stdout
12
+ * node lean-accounts.js <path> --inplace overwrites the file
13
+ *
14
+ * Drops:
15
+ * - imap/smtp host/port/tls/auth that match the email's provider defaults
16
+ * - imap/smtp user when it equals the email
17
+ * - enabled: true (default)
18
+ * - sig.html: false (default)
19
+ * - per-account name when it matches the file-level "name"
20
+ *
21
+ * Promotes a shared "name" to file-level when every account has the same.
22
+ *
23
+ * Requires: jsonc-parser (any version that exports `parse` with comment+
24
+ * trailing-comma tolerance). The mailx repo's node_modules has it.
25
+ */
26
+
27
+ import fs from "node:fs";
28
+ import path from "node:path";
29
+ import { fileURLToPath, pathToFileURL } from "node:url";
30
+
31
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
32
+
33
+ // ── Provider defaults: same set mailx-settings uses ────────────────────────
34
+ const PROVIDERS = {
35
+ "gmail.com": {
36
+ label: "Gmail",
37
+ imap: { host: "imap.gmail.com", port: 993, tls: true, auth: "oauth2" },
38
+ smtp: { host: "smtp.gmail.com", port: 587, tls: true, auth: "oauth2" },
39
+ },
40
+ "googlemail.com": {
41
+ label: "Gmail",
42
+ imap: { host: "imap.gmail.com", port: 993, tls: true, auth: "oauth2" },
43
+ smtp: { host: "smtp.gmail.com", port: 587, tls: true, auth: "oauth2" },
44
+ },
45
+ "outlook.com": {
46
+ label: "Outlook",
47
+ imap: { host: "outlook.office365.com", port: 993, tls: true, auth: "oauth2" },
48
+ smtp: { host: "smtp.office365.com", port: 587, tls: true, auth: "oauth2" },
49
+ },
50
+ "hotmail.com": {
51
+ label: "Outlook",
52
+ imap: { host: "outlook.office365.com", port: 993, tls: true, auth: "oauth2" },
53
+ smtp: { host: "smtp.office365.com", port: 587, tls: true, auth: "oauth2" },
54
+ },
55
+ "yahoo.com": {
56
+ label: "Yahoo",
57
+ imap: { host: "imap.mail.yahoo.com", port: 993, tls: true, auth: "oauth2" },
58
+ smtp: { host: "smtp.mail.yahoo.com", port: 587, tls: true, auth: "oauth2" },
59
+ },
60
+ "icloud.com": {
61
+ label: "iCloud",
62
+ imap: { host: "imap.mail.me.com", port: 993, tls: true, auth: "oauth2" },
63
+ smtp: { host: "smtp.mail.me.com", port: 587, tls: true, auth: "oauth2" },
64
+ },
65
+ };
66
+
67
+ function denormalizeAccount(acct, globalName) {
68
+ const domain = (acct.email || "").split("@")[1]?.toLowerCase() || "";
69
+ const provider = PROVIDERS[domain];
70
+ const out = {};
71
+ out.id = acct.id;
72
+ if (acct.label && acct.label !== provider?.label && acct.label !== acct.id) out.label = acct.label;
73
+ out.email = acct.email;
74
+ if (acct.name && acct.name !== globalName) out.name = acct.name;
75
+ if (acct.primary) out.primary = true;
76
+ if (acct.primaryCalendar !== undefined) out.primaryCalendar = acct.primaryCalendar;
77
+ if (acct.primaryTasks !== undefined) out.primaryTasks = acct.primaryTasks;
78
+ if (acct.primaryContacts !== undefined) out.primaryContacts = acct.primaryContacts;
79
+
80
+ const imapOut = {};
81
+ if (acct.imap?.host && acct.imap.host !== provider?.imap.host) imapOut.host = acct.imap.host;
82
+ if (acct.imap?.user && acct.imap.user !== acct.email) imapOut.user = acct.imap.user;
83
+ if (acct.imap?.password) imapOut.password = acct.imap.password;
84
+ if (acct.imap?.port && acct.imap.port !== (provider?.imap.port ?? 993)) imapOut.port = acct.imap.port;
85
+ if (acct.imap?.tls !== undefined && acct.imap.tls !== (provider?.imap.tls ?? true)) imapOut.tls = acct.imap.tls;
86
+ if (acct.imap?.auth && acct.imap.auth !== (provider?.imap.auth ?? "password")) imapOut.auth = acct.imap.auth;
87
+ if (Object.keys(imapOut).length > 0) out.imap = imapOut;
88
+
89
+ const smtpOut = {};
90
+ if (acct.smtp?.host && acct.smtp.host !== provider?.smtp.host) smtpOut.host = acct.smtp.host;
91
+ if (acct.smtp?.user && acct.smtp.user !== acct.email && acct.smtp.user !== acct.imap?.user) smtpOut.user = acct.smtp.user;
92
+ if (acct.smtp?.password) smtpOut.password = acct.smtp.password;
93
+ if (acct.smtp?.port && acct.smtp.port !== (provider?.smtp.port ?? 587)) smtpOut.port = acct.smtp.port;
94
+ if (acct.smtp?.tls !== undefined && acct.smtp.tls !== (provider?.smtp.tls ?? true)) smtpOut.tls = acct.smtp.tls;
95
+ if (acct.smtp?.auth && acct.smtp.auth !== (provider?.smtp.auth ?? "password")) smtpOut.auth = acct.smtp.auth;
96
+ if (Object.keys(smtpOut).length > 0) out.smtp = smtpOut;
97
+
98
+ if (acct.defaultSend) out.defaultSend = true;
99
+ if (acct.enabled === false) out.enabled = false;
100
+ if (acct.relayDomains?.length > 0) out.relayDomains = acct.relayDomains;
101
+ if (acct.deliveredToPrefix?.length > 0) out.deliveredToPrefix = acct.deliveredToPrefix;
102
+ if (acct.identityDomains?.length > 0) out.identityDomains = acct.identityDomains;
103
+
104
+ const syncContactsDefault = provider?.imap.auth === "oauth2";
105
+ if (acct.syncContacts !== undefined && acct.syncContacts !== syncContactsDefault) {
106
+ out.syncContacts = acct.syncContacts;
107
+ }
108
+ if (acct.signature) out.signature = acct.signature;
109
+ if (acct.sig?.text) {
110
+ out.sig = acct.sig.html ? { text: acct.sig.text, html: true } : { text: acct.sig.text };
111
+ }
112
+ return out;
113
+ }
114
+
115
+ async function main() {
116
+ const args = process.argv.slice(2);
117
+ const inputPath = args.find(a => !a.startsWith("--"));
118
+ const inplace = args.includes("--inplace");
119
+ if (!inputPath) {
120
+ console.error("Usage: node lean-accounts.js <path-to-accounts.jsonc> [--inplace]");
121
+ process.exit(2);
122
+ }
123
+ if (!fs.existsSync(inputPath)) {
124
+ console.error(`File not found: ${inputPath}`);
125
+ process.exit(1);
126
+ }
127
+
128
+ // Resolve jsonc-parser from the local mailx repo's node_modules so the
129
+ // script doesn't require a global install. The repo root is two levels
130
+ // up from bin/ — and we walk up further if invoked from elsewhere.
131
+ let parseJsonc;
132
+ for (const dir of [
133
+ path.join(__dirname, "..", "node_modules", "jsonc-parser"),
134
+ path.join(__dirname, "..", "..", "node_modules", "jsonc-parser"),
135
+ path.join(process.cwd(), "node_modules", "jsonc-parser"),
136
+ ]) {
137
+ if (fs.existsSync(path.join(dir, "package.json"))) {
138
+ const mod = await import(pathToFileURL(path.join(dir, "lib", "esm", "main.js")).href).catch(() => null) ||
139
+ await import("jsonc-parser").catch(() => null);
140
+ if (mod) { parseJsonc = mod.parse; break; }
141
+ }
142
+ }
143
+ if (!parseJsonc) {
144
+ try { parseJsonc = (await import("jsonc-parser")).parse; }
145
+ catch { console.error("jsonc-parser not found. Install or run from inside the mailx repo."); process.exit(1); }
146
+ }
147
+
148
+ const raw = fs.readFileSync(inputPath, "utf-8");
149
+ const errors = [];
150
+ const cfg = parseJsonc(raw, errors, { allowTrailingComma: true });
151
+ if (errors.length) {
152
+ console.error(`JSONC parse error: ${errors.map(e => JSON.stringify(e)).join(", ")}`);
153
+ process.exit(1);
154
+ }
155
+
156
+ const accounts = cfg?.accounts || (Array.isArray(cfg) ? cfg : []);
157
+ // Promote shared name to file-level when every entry has the same.
158
+ const names = new Set(accounts.map(a => a.name).filter(Boolean));
159
+ const sharedName = names.size === 1 ? [...names][0] : cfg?.name;
160
+ const lean = accounts.map(a => denormalizeAccount(a, sharedName));
161
+ const payload = sharedName ? { name: sharedName, accounts: lean } : { accounts: lean };
162
+ const output = JSON.stringify(payload, null, 2) + "\n";
163
+
164
+ if (inplace) {
165
+ fs.writeFileSync(inputPath, output);
166
+ console.error(`Wrote lean ${inputPath}`);
167
+ } else {
168
+ process.stdout.write(output);
169
+ }
170
+ }
171
+
172
+ main().catch(e => { console.error(e); process.exit(1); });