imapkit 4.0.3 → 4.1.1

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 (485) hide show
  1. package/README.md +32 -19
  2. package/bin/imapkit.js +12 -16
  3. package/dist/cjs/addressparser.d.ts +21 -0
  4. package/dist/cjs/addressparser.js +271 -0
  5. package/dist/cjs/arguments.d.ts +31 -0
  6. package/{lib → dist/cjs}/arguments.js +9 -21
  7. package/dist/cjs/bodystructure.d.ts +25 -0
  8. package/dist/cjs/bodystructure.js +150 -0
  9. package/dist/cjs/cert.d.ts +2 -0
  10. package/dist/cjs/cert.js +7 -0
  11. package/dist/cjs/command-states.d.ts +36 -0
  12. package/dist/cjs/command-states.js +102 -0
  13. package/dist/cjs/commands/append.d.ts +88 -0
  14. package/dist/cjs/commands/append.js +299 -0
  15. package/dist/cjs/commands/capability.d.ts +2 -0
  16. package/dist/cjs/commands/capability.js +44 -0
  17. package/dist/cjs/commands/check.d.ts +2 -0
  18. package/dist/cjs/commands/check.js +28 -0
  19. package/dist/cjs/commands/close.d.ts +2 -0
  20. package/dist/cjs/commands/close.js +35 -0
  21. package/dist/cjs/commands/copy.d.ts +30 -0
  22. package/dist/cjs/commands/copy.js +107 -0
  23. package/dist/cjs/commands/create.d.ts +2 -0
  24. package/dist/cjs/commands/create.js +53 -0
  25. package/dist/cjs/commands/delete.d.ts +2 -0
  26. package/dist/cjs/commands/delete.js +63 -0
  27. package/dist/cjs/commands/examine.d.ts +2 -0
  28. package/dist/cjs/commands/examine.js +19 -0
  29. package/dist/cjs/commands/expunge.d.ts +2 -0
  30. package/dist/cjs/commands/expunge.js +32 -0
  31. package/dist/cjs/commands/fetch.d.ts +23 -0
  32. package/dist/cjs/commands/fetch.js +208 -0
  33. package/dist/cjs/commands/handlers/fetch.d.ts +12 -0
  34. package/dist/cjs/commands/handlers/fetch.js +195 -0
  35. package/dist/cjs/commands/handlers/flags.d.ts +17 -0
  36. package/dist/cjs/commands/handlers/flags.js +39 -0
  37. package/dist/cjs/commands/handlers/search.d.ts +85 -0
  38. package/dist/cjs/commands/handlers/search.js +504 -0
  39. package/dist/cjs/commands/handlers/status.d.ts +34 -0
  40. package/dist/cjs/commands/handlers/status.js +81 -0
  41. package/dist/cjs/commands/handlers/store.d.ts +3 -0
  42. package/dist/cjs/commands/handlers/store.js +117 -0
  43. package/dist/cjs/commands/index.d.ts +2 -0
  44. package/dist/cjs/commands/index.js +61 -0
  45. package/dist/cjs/commands/list.d.ts +2 -0
  46. package/dist/cjs/commands/list.js +86 -0
  47. package/dist/cjs/commands/login.d.ts +2 -0
  48. package/dist/cjs/commands/login.js +62 -0
  49. package/dist/cjs/commands/logout.d.ts +2 -0
  50. package/dist/cjs/commands/logout.js +40 -0
  51. package/dist/cjs/commands/lsub.d.ts +2 -0
  52. package/dist/cjs/commands/lsub.js +79 -0
  53. package/dist/cjs/commands/noop.d.ts +2 -0
  54. package/dist/cjs/commands/noop.js +28 -0
  55. package/dist/cjs/commands/rename.d.ts +2 -0
  56. package/dist/cjs/commands/rename.js +98 -0
  57. package/dist/cjs/commands/search.d.ts +10 -0
  58. package/dist/cjs/commands/search.js +71 -0
  59. package/dist/cjs/commands/select.d.ts +19 -0
  60. package/dist/cjs/commands/select.js +230 -0
  61. package/dist/cjs/commands/status.d.ts +2 -0
  62. package/dist/cjs/commands/status.js +57 -0
  63. package/dist/cjs/commands/store.d.ts +10 -0
  64. package/dist/cjs/commands/store.js +134 -0
  65. package/dist/cjs/commands/subscribe.d.ts +2 -0
  66. package/dist/cjs/commands/subscribe.js +51 -0
  67. package/dist/cjs/commands/uid-copy.d.ts +2 -0
  68. package/dist/cjs/commands/uid-copy.js +19 -0
  69. package/dist/cjs/commands/uid-fetch.d.ts +3 -0
  70. package/dist/cjs/commands/uid-fetch.js +17 -0
  71. package/dist/cjs/commands/uid-search.d.ts +3 -0
  72. package/dist/cjs/commands/uid-search.js +17 -0
  73. package/dist/cjs/commands/uid-store.d.ts +3 -0
  74. package/dist/cjs/commands/uid-store.js +17 -0
  75. package/dist/cjs/commands/unsubscribe.d.ts +2 -0
  76. package/dist/cjs/commands/unsubscribe.js +50 -0
  77. package/dist/cjs/dates.d.ts +64 -0
  78. package/dist/cjs/dates.js +124 -0
  79. package/dist/cjs/deflate-layer.d.ts +83 -0
  80. package/dist/cjs/deflate-layer.js +232 -0
  81. package/dist/cjs/encoded-words.d.ts +15 -0
  82. package/dist/cjs/encoded-words.js +85 -0
  83. package/dist/cjs/envelope.d.ts +33 -0
  84. package/dist/cjs/envelope.js +86 -0
  85. package/dist/cjs/esearch.d.ts +96 -0
  86. package/dist/cjs/esearch.js +190 -0
  87. package/dist/cjs/framing.d.ts +66 -0
  88. package/{lib → dist/cjs}/framing.js +9 -26
  89. package/dist/cjs/index.d.ts +9 -0
  90. package/dist/cjs/index.js +56 -0
  91. package/dist/cjs/list-extensions.d.ts +50 -0
  92. package/dist/cjs/list-extensions.js +35 -0
  93. package/dist/cjs/load-plugins.d.ts +21 -0
  94. package/dist/cjs/load-plugins.js +89 -0
  95. package/dist/cjs/mailbox-name.d.ts +26 -0
  96. package/dist/cjs/mailbox-name.js +127 -0
  97. package/dist/cjs/mimeparser.d.ts +137 -0
  98. package/dist/cjs/mimeparser.js +727 -0
  99. package/dist/cjs/mock-client.d.ts +39 -0
  100. package/dist/cjs/mock-client.js +236 -0
  101. package/dist/cjs/numbers.d.ts +28 -0
  102. package/dist/cjs/numbers.js +52 -0
  103. package/dist/cjs/package.json +3 -0
  104. package/dist/cjs/plugins/acl.d.ts +2 -0
  105. package/dist/cjs/plugins/acl.js +888 -0
  106. package/dist/cjs/plugins/appendlimit.d.ts +16 -0
  107. package/dist/cjs/plugins/appendlimit.js +87 -0
  108. package/dist/cjs/plugins/auth-plain.d.ts +2 -0
  109. package/dist/cjs/plugins/auth-plain.js +89 -0
  110. package/dist/cjs/plugins/binary.d.ts +30 -0
  111. package/dist/cjs/plugins/binary.js +247 -0
  112. package/dist/cjs/plugins/catenate.d.ts +14 -0
  113. package/dist/cjs/plugins/catenate.js +250 -0
  114. package/dist/cjs/plugins/compress.d.ts +7 -0
  115. package/dist/cjs/plugins/compress.js +79 -0
  116. package/dist/cjs/plugins/condstore.d.ts +5 -0
  117. package/dist/cjs/plugins/condstore.js +492 -0
  118. package/dist/cjs/plugins/context-search.d.ts +8 -0
  119. package/dist/cjs/plugins/context-search.js +304 -0
  120. package/dist/cjs/plugins/context-sort.d.ts +6 -0
  121. package/dist/cjs/plugins/context-sort.js +32 -0
  122. package/dist/cjs/plugins/create-special-use.d.ts +7 -0
  123. package/dist/cjs/plugins/create-special-use.js +101 -0
  124. package/dist/cjs/plugins/enable.d.ts +23 -0
  125. package/dist/cjs/plugins/enable.js +127 -0
  126. package/dist/cjs/plugins/esearch.d.ts +6 -0
  127. package/dist/cjs/plugins/esearch.js +142 -0
  128. package/dist/cjs/plugins/esort.d.ts +6 -0
  129. package/dist/cjs/plugins/esort.js +60 -0
  130. package/dist/cjs/plugins/id.d.ts +5 -0
  131. package/dist/cjs/plugins/id.js +123 -0
  132. package/dist/cjs/plugins/idle.d.ts +5 -0
  133. package/dist/cjs/plugins/idle.js +85 -0
  134. package/dist/cjs/plugins/imap4rev2.d.ts +6 -0
  135. package/dist/cjs/plugins/imap4rev2.js +184 -0
  136. package/dist/cjs/plugins/index.d.ts +2 -0
  137. package/dist/cjs/plugins/index.js +119 -0
  138. package/dist/cjs/plugins/list-extended.d.ts +2 -0
  139. package/dist/cjs/plugins/list-extended.js +235 -0
  140. package/dist/cjs/plugins/list-status.d.ts +6 -0
  141. package/dist/cjs/plugins/list-status.js +42 -0
  142. package/dist/cjs/plugins/literalminus.d.ts +8 -0
  143. package/dist/cjs/plugins/literalminus.js +32 -0
  144. package/dist/cjs/plugins/literalplus.d.ts +6 -0
  145. package/dist/cjs/plugins/literalplus.js +30 -0
  146. package/dist/cjs/plugins/logindisabled.d.ts +5 -0
  147. package/dist/cjs/plugins/logindisabled.js +54 -0
  148. package/dist/cjs/plugins/messagelimit.d.ts +19 -0
  149. package/dist/cjs/plugins/messagelimit.js +227 -0
  150. package/dist/cjs/plugins/metadata-server.d.ts +7 -0
  151. package/dist/cjs/plugins/metadata-server.js +24 -0
  152. package/dist/cjs/plugins/metadata.d.ts +11 -0
  153. package/dist/cjs/plugins/metadata.js +436 -0
  154. package/dist/cjs/plugins/move.d.ts +11 -0
  155. package/dist/cjs/plugins/move.js +96 -0
  156. package/dist/cjs/plugins/multiappend.d.ts +12 -0
  157. package/dist/cjs/plugins/multiappend.js +38 -0
  158. package/dist/cjs/plugins/multisearch.d.ts +6 -0
  159. package/dist/cjs/plugins/multisearch.js +263 -0
  160. package/dist/cjs/plugins/namespace.d.ts +5 -0
  161. package/dist/cjs/plugins/namespace.js +57 -0
  162. package/dist/cjs/plugins/notify.d.ts +2 -0
  163. package/dist/cjs/plugins/notify.js +628 -0
  164. package/dist/cjs/plugins/oauthbearer.d.ts +32 -0
  165. package/dist/cjs/plugins/oauthbearer.js +202 -0
  166. package/dist/cjs/plugins/objectid.d.ts +23 -0
  167. package/dist/cjs/plugins/objectid.js +221 -0
  168. package/dist/cjs/plugins/partial.d.ts +6 -0
  169. package/dist/cjs/plugins/partial.js +78 -0
  170. package/dist/cjs/plugins/preview.d.ts +31 -0
  171. package/dist/cjs/plugins/preview.js +378 -0
  172. package/dist/cjs/plugins/qresync.d.ts +11 -0
  173. package/dist/cjs/plugins/qresync.js +473 -0
  174. package/dist/cjs/plugins/quota.d.ts +18 -0
  175. package/dist/cjs/plugins/quota.js +254 -0
  176. package/dist/cjs/plugins/replace.d.ts +14 -0
  177. package/dist/cjs/plugins/replace.js +130 -0
  178. package/dist/cjs/plugins/sasl-ir.d.ts +5 -0
  179. package/dist/cjs/plugins/sasl-ir.js +24 -0
  180. package/dist/cjs/plugins/savedate.d.ts +17 -0
  181. package/dist/cjs/plugins/savedate.js +64 -0
  182. package/dist/cjs/plugins/savelimit.d.ts +10 -0
  183. package/dist/cjs/plugins/savelimit.js +30 -0
  184. package/dist/cjs/plugins/searchres.d.ts +6 -0
  185. package/dist/cjs/plugins/searchres.js +91 -0
  186. package/dist/cjs/plugins/sort-display.d.ts +11 -0
  187. package/dist/cjs/plugins/sort-display.js +37 -0
  188. package/dist/cjs/plugins/sort.d.ts +11 -0
  189. package/dist/cjs/plugins/sort.js +125 -0
  190. package/dist/cjs/plugins/special-use.d.ts +10 -0
  191. package/dist/cjs/plugins/special-use.js +95 -0
  192. package/dist/cjs/plugins/starttls.d.ts +5 -0
  193. package/dist/cjs/plugins/starttls.js +55 -0
  194. package/dist/cjs/plugins/status-size.d.ts +7 -0
  195. package/dist/cjs/plugins/status-size.js +30 -0
  196. package/dist/cjs/plugins/thread-orderedsubject.d.ts +11 -0
  197. package/dist/cjs/plugins/thread-orderedsubject.js +28 -0
  198. package/dist/cjs/plugins/thread-references.d.ts +11 -0
  199. package/dist/cjs/plugins/thread-references.js +28 -0
  200. package/dist/cjs/plugins/uidonly.d.ts +15 -0
  201. package/dist/cjs/plugins/uidonly.js +126 -0
  202. package/dist/cjs/plugins/uidplus.d.ts +15 -0
  203. package/dist/cjs/plugins/uidplus.js +119 -0
  204. package/dist/cjs/plugins/unauthenticate.d.ts +7 -0
  205. package/dist/cjs/plugins/unauthenticate.js +32 -0
  206. package/dist/cjs/plugins/unselect.d.ts +5 -0
  207. package/dist/cjs/plugins/unselect.js +36 -0
  208. package/dist/cjs/plugins/utf8-accept.d.ts +6 -0
  209. package/dist/cjs/plugins/utf8-accept.js +72 -0
  210. package/dist/cjs/plugins/x-gm-ext-1.d.ts +26 -0
  211. package/dist/cjs/plugins/x-gm-ext-1.js +422 -0
  212. package/dist/cjs/plugins/xoauth2.d.ts +2 -0
  213. package/dist/cjs/plugins/xoauth2.js +155 -0
  214. package/dist/cjs/plugins/xtoybird.d.ts +2 -0
  215. package/dist/cjs/plugins/xtoybird.js +236 -0
  216. package/dist/cjs/server.d.ts +876 -0
  217. package/dist/cjs/server.js +2597 -0
  218. package/dist/cjs/smtp-listener.d.ts +13 -0
  219. package/dist/cjs/smtp-listener.js +47 -0
  220. package/dist/cjs/sorting.d.ts +77 -0
  221. package/dist/cjs/sorting.js +290 -0
  222. package/dist/cjs/threading.d.ts +30 -0
  223. package/dist/cjs/threading.js +318 -0
  224. package/dist/cjs/types.d.ts +327 -0
  225. package/dist/cjs/types.js +3 -0
  226. package/dist/cjs/utf8-session.d.ts +17 -0
  227. package/dist/cjs/utf8-session.js +148 -0
  228. package/dist/cjs/vanished.d.ts +21 -0
  229. package/dist/cjs/vanished.js +55 -0
  230. package/dist/esm/addressparser.d.ts +21 -0
  231. package/{lib → dist/esm}/addressparser.js +106 -133
  232. package/dist/esm/arguments.d.ts +31 -0
  233. package/dist/esm/arguments.js +96 -0
  234. package/dist/esm/bodystructure.d.ts +25 -0
  235. package/{lib → dist/esm}/bodystructure.js +17 -33
  236. package/dist/esm/cert.d.ts +2 -0
  237. package/dist/esm/cert.js +4 -0
  238. package/dist/esm/command-states.d.ts +36 -0
  239. package/{lib → dist/esm}/command-states.js +4 -16
  240. package/dist/esm/commands/append.d.ts +88 -0
  241. package/{lib → dist/esm}/commands/append.js +47 -85
  242. package/dist/esm/commands/capability.d.ts +2 -0
  243. package/dist/esm/commands/capability.js +29 -0
  244. package/dist/esm/commands/check.d.ts +2 -0
  245. package/dist/esm/commands/check.js +13 -0
  246. package/dist/esm/commands/close.d.ts +2 -0
  247. package/dist/esm/commands/close.js +20 -0
  248. package/dist/esm/commands/copy.d.ts +30 -0
  249. package/{lib → dist/esm}/commands/copy.js +31 -55
  250. package/dist/esm/commands/create.d.ts +2 -0
  251. package/{lib → dist/esm}/commands/create.js +25 -39
  252. package/dist/esm/commands/delete.d.ts +2 -0
  253. package/{lib → dist/esm}/commands/delete.js +25 -41
  254. package/dist/esm/commands/examine.d.ts +2 -0
  255. package/dist/esm/commands/examine.js +4 -0
  256. package/dist/esm/commands/expunge.d.ts +2 -0
  257. package/dist/esm/commands/expunge.js +17 -0
  258. package/dist/esm/commands/fetch.d.ts +23 -0
  259. package/{lib → dist/esm}/commands/fetch.js +33 -74
  260. package/dist/esm/commands/handlers/fetch.d.ts +12 -0
  261. package/{lib → dist/esm}/commands/handlers/fetch.js +11 -42
  262. package/dist/esm/commands/handlers/flags.d.ts +17 -0
  263. package/{lib → dist/esm}/commands/handlers/flags.js +3 -11
  264. package/dist/esm/commands/handlers/search.d.ts +85 -0
  265. package/{lib → dist/esm}/commands/handlers/search.js +33 -71
  266. package/dist/esm/commands/handlers/status.d.ts +34 -0
  267. package/{lib → dist/esm}/commands/handlers/status.js +1 -9
  268. package/dist/esm/commands/handlers/store.d.ts +3 -0
  269. package/{lib → dist/esm}/commands/handlers/store.js +20 -44
  270. package/dist/esm/commands/index.d.ts +2 -0
  271. package/dist/esm/commands/index.js +55 -0
  272. package/dist/esm/commands/list.d.ts +2 -0
  273. package/dist/esm/commands/list.js +71 -0
  274. package/dist/esm/commands/login.d.ts +2 -0
  275. package/{lib → dist/esm}/commands/login.js +24 -44
  276. package/dist/esm/commands/logout.d.ts +2 -0
  277. package/dist/esm/commands/logout.js +25 -0
  278. package/dist/esm/commands/lsub.d.ts +2 -0
  279. package/dist/esm/commands/lsub.js +64 -0
  280. package/dist/esm/commands/noop.d.ts +2 -0
  281. package/dist/esm/commands/noop.js +13 -0
  282. package/dist/esm/commands/rename.d.ts +2 -0
  283. package/{lib → dist/esm}/commands/rename.js +32 -51
  284. package/dist/esm/commands/search.d.ts +10 -0
  285. package/dist/esm/commands/search.js +54 -0
  286. package/dist/esm/commands/select.d.ts +19 -0
  287. package/dist/esm/commands/select.js +214 -0
  288. package/dist/esm/commands/status.d.ts +2 -0
  289. package/{lib → dist/esm}/commands/status.js +18 -39
  290. package/dist/esm/commands/store.d.ts +10 -0
  291. package/{lib → dist/esm}/commands/store.js +39 -73
  292. package/dist/esm/commands/subscribe.d.ts +2 -0
  293. package/{lib → dist/esm}/commands/subscribe.js +22 -39
  294. package/dist/esm/commands/uid-copy.d.ts +2 -0
  295. package/dist/esm/commands/uid-copy.js +4 -0
  296. package/dist/esm/commands/uid-fetch.d.ts +3 -0
  297. package/dist/esm/commands/uid-fetch.js +3 -0
  298. package/dist/esm/commands/uid-search.d.ts +3 -0
  299. package/dist/esm/commands/uid-search.js +3 -0
  300. package/dist/esm/commands/uid-store.d.ts +3 -0
  301. package/dist/esm/commands/uid-store.js +3 -0
  302. package/dist/esm/commands/unsubscribe.d.ts +2 -0
  303. package/{lib → dist/esm}/commands/unsubscribe.js +22 -37
  304. package/dist/esm/dates.d.ts +64 -0
  305. package/{lib → dist/esm}/dates.js +6 -14
  306. package/dist/esm/deflate-layer.d.ts +83 -0
  307. package/{lib → dist/esm}/deflate-layer.js +9 -26
  308. package/dist/esm/encoded-words.d.ts +15 -0
  309. package/{lib → dist/esm}/encoded-words.js +9 -25
  310. package/dist/esm/envelope.d.ts +33 -0
  311. package/{lib → dist/esm}/envelope.js +8 -19
  312. package/dist/esm/esearch.d.ts +96 -0
  313. package/{lib → dist/esm}/esearch.js +12 -39
  314. package/dist/esm/framing.d.ts +66 -0
  315. package/dist/esm/framing.js +82 -0
  316. package/dist/esm/index.d.ts +9 -0
  317. package/dist/esm/index.js +6 -0
  318. package/dist/esm/list-extensions.d.ts +50 -0
  319. package/{lib → dist/esm}/list-extensions.js +1 -4
  320. package/dist/esm/load-plugins.d.ts +21 -0
  321. package/{lib → dist/esm}/load-plugins.js +9 -43
  322. package/dist/esm/mailbox-name.d.ts +26 -0
  323. package/{lib → dist/esm}/mailbox-name.js +5 -26
  324. package/dist/esm/mimeparser.d.ts +137 -0
  325. package/{lib → dist/esm}/mimeparser.js +74 -152
  326. package/dist/esm/mock-client.d.ts +39 -0
  327. package/{lib → dist/esm}/mock-client.js +26 -40
  328. package/dist/esm/numbers.d.ts +28 -0
  329. package/{lib → dist/esm}/numbers.js +1 -8
  330. package/dist/esm/package.json +3 -0
  331. package/dist/esm/plugins/acl.d.ts +2 -0
  332. package/{lib → dist/esm}/plugins/acl.js +146 -240
  333. package/dist/esm/plugins/appendlimit.d.ts +16 -0
  334. package/{lib → dist/esm}/plugins/appendlimit.js +5 -16
  335. package/dist/esm/plugins/auth-plain.d.ts +2 -0
  336. package/{lib → dist/esm}/plugins/auth-plain.js +11 -31
  337. package/dist/esm/plugins/binary.d.ts +30 -0
  338. package/{lib → dist/esm}/plugins/binary.js +17 -43
  339. package/dist/esm/plugins/catenate.d.ts +14 -0
  340. package/{lib → dist/esm}/plugins/catenate.js +19 -40
  341. package/dist/esm/plugins/compress.d.ts +7 -0
  342. package/dist/esm/plugins/compress.js +61 -0
  343. package/dist/esm/plugins/condstore.d.ts +5 -0
  344. package/{lib → dist/esm}/plugins/condstore.js +66 -152
  345. package/dist/esm/plugins/context-search.d.ts +8 -0
  346. package/{lib → dist/esm}/plugins/context-search.js +53 -88
  347. package/dist/esm/plugins/context-sort.d.ts +6 -0
  348. package/{lib → dist/esm}/plugins/context-sort.js +4 -9
  349. package/dist/esm/plugins/create-special-use.d.ts +7 -0
  350. package/{lib → dist/esm}/plugins/create-special-use.js +33 -55
  351. package/dist/esm/plugins/enable.d.ts +23 -0
  352. package/dist/esm/plugins/enable.js +111 -0
  353. package/dist/esm/plugins/esearch.d.ts +6 -0
  354. package/{lib → dist/esm}/plugins/esearch.js +13 -42
  355. package/dist/esm/plugins/esort.d.ts +6 -0
  356. package/{lib → dist/esm}/plugins/esort.js +7 -25
  357. package/dist/esm/plugins/id.d.ts +5 -0
  358. package/dist/esm/plugins/id.js +108 -0
  359. package/dist/esm/plugins/idle.d.ts +5 -0
  360. package/dist/esm/plugins/idle.js +70 -0
  361. package/dist/esm/plugins/imap4rev2.d.ts +6 -0
  362. package/{lib → dist/esm}/plugins/imap4rev2.js +24 -60
  363. package/dist/esm/plugins/index.d.ts +2 -0
  364. package/dist/esm/plugins/index.js +113 -0
  365. package/dist/esm/plugins/list-extended.d.ts +2 -0
  366. package/{lib → dist/esm}/plugins/list-extended.js +28 -66
  367. package/dist/esm/plugins/list-status.d.ts +6 -0
  368. package/{lib → dist/esm}/plugins/list-status.js +5 -12
  369. package/dist/esm/plugins/literalminus.d.ts +8 -0
  370. package/{lib → dist/esm}/plugins/literalminus.js +2 -5
  371. package/dist/esm/plugins/literalplus.d.ts +6 -0
  372. package/{lib → dist/esm}/plugins/literalplus.js +2 -5
  373. package/dist/esm/plugins/logindisabled.d.ts +5 -0
  374. package/dist/esm/plugins/logindisabled.js +39 -0
  375. package/dist/esm/plugins/messagelimit.d.ts +19 -0
  376. package/{lib → dist/esm}/plugins/messagelimit.js +18 -41
  377. package/dist/esm/plugins/metadata-server.d.ts +7 -0
  378. package/{lib → dist/esm}/plugins/metadata-server.js +3 -7
  379. package/dist/esm/plugins/metadata.d.ts +11 -0
  380. package/dist/esm/plugins/metadata.js +421 -0
  381. package/dist/esm/plugins/move.d.ts +11 -0
  382. package/{lib → dist/esm}/plugins/move.js +37 -66
  383. package/dist/esm/plugins/multiappend.d.ts +12 -0
  384. package/{lib → dist/esm}/plugins/multiappend.js +2 -5
  385. package/dist/esm/plugins/multisearch.d.ts +6 -0
  386. package/{lib → dist/esm}/plugins/multisearch.js +24 -48
  387. package/dist/esm/plugins/namespace.d.ts +5 -0
  388. package/dist/esm/plugins/namespace.js +42 -0
  389. package/dist/esm/plugins/notify.d.ts +2 -0
  390. package/{lib → dist/esm}/plugins/notify.js +90 -134
  391. package/dist/esm/plugins/oauthbearer.d.ts +32 -0
  392. package/{lib → dist/esm}/plugins/oauthbearer.js +18 -48
  393. package/dist/esm/plugins/objectid.d.ts +23 -0
  394. package/{lib → dist/esm}/plugins/objectid.js +21 -58
  395. package/dist/esm/plugins/partial.d.ts +6 -0
  396. package/{lib → dist/esm}/plugins/partial.js +7 -15
  397. package/dist/esm/plugins/preview.d.ts +31 -0
  398. package/{lib → dist/esm}/plugins/preview.js +28 -66
  399. package/dist/esm/plugins/qresync.d.ts +11 -0
  400. package/{lib → dist/esm}/plugins/qresync.js +64 -134
  401. package/dist/esm/plugins/quota.d.ts +18 -0
  402. package/{lib → dist/esm}/plugins/quota.js +89 -135
  403. package/dist/esm/plugins/replace.d.ts +14 -0
  404. package/{lib → dist/esm}/plugins/replace.js +21 -51
  405. package/dist/esm/plugins/sasl-ir.d.ts +5 -0
  406. package/{lib → dist/esm}/plugins/sasl-ir.js +3 -6
  407. package/dist/esm/plugins/savedate.d.ts +17 -0
  408. package/{lib → dist/esm}/plugins/savedate.js +5 -15
  409. package/dist/esm/plugins/savelimit.d.ts +10 -0
  410. package/{lib → dist/esm}/plugins/savelimit.js +3 -6
  411. package/dist/esm/plugins/searchres.d.ts +6 -0
  412. package/{lib → dist/esm}/plugins/searchres.js +13 -22
  413. package/dist/esm/plugins/sort-display.d.ts +11 -0
  414. package/{lib → dist/esm}/plugins/sort-display.js +6 -10
  415. package/dist/esm/plugins/sort.d.ts +11 -0
  416. package/{lib → dist/esm}/plugins/sort.js +24 -46
  417. package/dist/esm/plugins/special-use.d.ts +10 -0
  418. package/{lib → dist/esm}/plugins/special-use.js +9 -24
  419. package/dist/esm/plugins/starttls.d.ts +5 -0
  420. package/{lib → dist/esm}/plugins/starttls.js +20 -37
  421. package/dist/esm/plugins/status-size.d.ts +7 -0
  422. package/{lib → dist/esm}/plugins/status-size.js +4 -11
  423. package/dist/esm/plugins/thread-orderedsubject.d.ts +11 -0
  424. package/{lib → dist/esm}/plugins/thread-orderedsubject.js +3 -6
  425. package/dist/esm/plugins/thread-references.d.ts +11 -0
  426. package/{lib → dist/esm}/plugins/thread-references.js +3 -6
  427. package/dist/esm/plugins/uidonly.d.ts +15 -0
  428. package/{lib → dist/esm}/plugins/uidonly.js +11 -35
  429. package/dist/esm/plugins/uidplus.d.ts +15 -0
  430. package/{lib → dist/esm}/plugins/uidplus.js +25 -45
  431. package/dist/esm/plugins/unauthenticate.d.ts +7 -0
  432. package/dist/esm/plugins/unauthenticate.js +17 -0
  433. package/dist/esm/plugins/unselect.d.ts +5 -0
  434. package/dist/esm/plugins/unselect.js +21 -0
  435. package/dist/esm/plugins/utf8-accept.d.ts +6 -0
  436. package/{lib → dist/esm}/plugins/utf8-accept.js +10 -21
  437. package/dist/esm/plugins/x-gm-ext-1.d.ts +26 -0
  438. package/{lib → dist/esm}/plugins/x-gm-ext-1.js +48 -100
  439. package/dist/esm/plugins/xoauth2.d.ts +2 -0
  440. package/dist/esm/plugins/xoauth2.js +140 -0
  441. package/dist/esm/plugins/xtoybird.d.ts +2 -0
  442. package/dist/esm/plugins/xtoybird.js +218 -0
  443. package/dist/esm/server.d.ts +876 -0
  444. package/dist/esm/server.js +2543 -0
  445. package/dist/esm/smtp-listener.d.ts +13 -0
  446. package/{lib → dist/esm}/smtp-listener.js +5 -12
  447. package/dist/esm/sorting.d.ts +77 -0
  448. package/{lib → dist/esm}/sorting.js +40 -53
  449. package/dist/esm/threading.d.ts +30 -0
  450. package/{lib → dist/esm}/threading.js +29 -70
  451. package/dist/esm/types.d.ts +327 -0
  452. package/dist/esm/types.js +2 -0
  453. package/dist/esm/utf8-session.d.ts +17 -0
  454. package/{lib → dist/esm}/utf8-session.js +15 -25
  455. package/dist/esm/vanished.d.ts +21 -0
  456. package/{lib → dist/esm}/vanished.js +16 -21
  457. package/dist/plugin-help.json +298 -0
  458. package/package.json +55 -12
  459. package/lib/commands/capability.js +0 -47
  460. package/lib/commands/check.js +0 -21
  461. package/lib/commands/close.js +0 -30
  462. package/lib/commands/examine.js +0 -7
  463. package/lib/commands/expunge.js +0 -27
  464. package/lib/commands/list.js +0 -100
  465. package/lib/commands/logout.js +0 -41
  466. package/lib/commands/lsub.js +0 -87
  467. package/lib/commands/noop.js +0 -21
  468. package/lib/commands/search.js +0 -76
  469. package/lib/commands/select.js +0 -289
  470. package/lib/commands/uid copy.js +0 -7
  471. package/lib/commands/uid fetch.js +0 -5
  472. package/lib/commands/uid search.js +0 -5
  473. package/lib/commands/uid store.js +0 -5
  474. package/lib/plugins/compress.js +0 -76
  475. package/lib/plugins/enable.js +0 -155
  476. package/lib/plugins/id.js +0 -138
  477. package/lib/plugins/idle.js +0 -105
  478. package/lib/plugins/logindisabled.js +0 -50
  479. package/lib/plugins/metadata.js +0 -475
  480. package/lib/plugins/namespace.js +0 -67
  481. package/lib/plugins/unauthenticate.js +0 -28
  482. package/lib/plugins/unselect.js +0 -36
  483. package/lib/plugins/xoauth2.js +0 -188
  484. package/lib/plugins/xtoybird.js +0 -282
  485. package/lib/server.js +0 -2880
@@ -1,9 +1,6 @@
1
- 'use strict';
2
-
3
- const { badError } = require('../commands/handlers/search');
4
- const { parsePartialRange } = require('../esearch');
5
- const { MAX_NUMBER, isNzNumber } = require('../numbers');
6
-
1
+ import { badError } from '../commands/handlers/search.js';
2
+ import { parsePartialRange } from '../esearch.js';
3
+ import { MAX_NUMBER, isNzNumber } from '../numbers.js';
7
4
  /**
8
5
  * @help Adds MESSAGELIMIT [RFC9738] capability, advertised as MESSAGELIMIT=<n>
9
6
  * @help Server option "messageLimit" sets n (default 1000). FETCH, STORE, SEARCH, MOVE, UID EXPUNGE
@@ -14,17 +11,14 @@ const { MAX_NUMBER, isNzNumber } = require('../numbers');
14
11
  *
15
12
  * MESSAGELIMIT: https://www.rfc-editor.org/rfc/rfc9738
16
13
  */
17
-
18
14
  // RFC 9738 section 3: the advertised limit SHOULD NOT be lower than 1000
19
15
  const DEFAULT_LIMIT = 1000;
20
-
21
16
  // RFC 9738 section 3.1: commands that operate on the messages with the highest UIDs and return the MESSAGELIMIT response code.
22
17
  // EXPUNGE, CLOSE and STATUS UNSEEN MUST NOT be limited
23
18
  const PARTIAL_COMMANDS = new Set(['FETCH', 'UID FETCH', 'STORE', 'UID STORE', 'MOVE', 'UID MOVE', 'UID EXPUNGE']);
24
19
  const SEARCH_COMMANDS = new Set(['SEARCH', 'UID SEARCH']);
25
20
  // RFC 9738 section 3.3: SORT and THREAD can not be run on more messages than the limit
26
21
  const SORT_COMMANDS = new Set(['SORT', 'UID SORT', 'THREAD', 'UID THREAD']);
27
-
28
22
  /**
29
23
  * Reads the limit from the "messageLimit" server option
30
24
  *
@@ -45,7 +39,6 @@ function getLimit(server, name) {
45
39
  server.messageLimit = { name, limit };
46
40
  return limit;
47
41
  }
48
-
49
42
  /**
50
43
  * Refuses COPY and APPEND of more messages than the limit, shared with the SAVELIMIT plugin. COPY and
51
44
  * MULTIAPPEND APPEND are atomic, so nothing is copied or appended (RFC 9738 section 3.1)
@@ -70,14 +63,11 @@ function addSaveLimit(server, limit) {
70
63
  return false;
71
64
  });
72
65
  }
73
-
74
- module.exports = function (server) {
66
+ export default function messagelimitPlugin(server) {
75
67
  const limit = getLimit(server, 'MESSAGELIMIT');
76
68
  server.registerCapability('MESSAGELIMIT=' + limit);
77
69
  addSaveLimit(server, limit);
78
-
79
- const commandName = parsed => String(parsed.command || '').toUpperCase();
80
-
70
+ const commandName = (parsed) => String(parsed.command || '').toUpperCase();
81
71
  // FETCH, STORE, MOVE and UID EXPUNGE only operate on the messages with the highest UIDs, "the server is REQUIRED
82
72
  // to process messages from highest to lowest UID". COPY is refused by addSaveLimit instead
83
73
  server.rangeLimits.push((connection, parsed, range) => {
@@ -98,7 +88,6 @@ module.exports = function (server) {
98
88
  parsed.highestFirst = true;
99
89
  return range.filter(entry => !dropped.has(entry)).reverse();
100
90
  });
101
-
102
91
  // RFC 9738 section 3.1: with the PARTIAL FETCH modifier (RFC 9394 section 3.3), the PARTIAL range is the message
103
92
  // count, a larger range is refused without doing any work. The PARTIAL plugin answers an invalid modifier with BAD
104
93
  server.commandChecks.push((connection, parsed) => {
@@ -111,7 +100,8 @@ module.exports = function (server) {
111
100
  let range;
112
101
  try {
113
102
  range = position >= 0 && parsePartialRange(modifiers[position + 1], true);
114
- } catch {
103
+ }
104
+ catch {
115
105
  return false;
116
106
  }
117
107
  if (range && range.to - range.from + 1 > limit) {
@@ -119,13 +109,12 @@ module.exports = function (server) {
119
109
  }
120
110
  return false;
121
111
  });
122
-
123
112
  // RFC 9738 section 3.1: SEARCH counts the searched messages, not the matching ones. The messages a search
124
113
  // looks at are the ones its top level sequence set, UID, UIDAFTER and UIDBEFORE keys allow
125
114
  server.searchLimits.push((connection, messages, query) => {
126
115
  // the running command, SEARCH and SORT do not pass it to the search
127
116
  const parsed = connection._runningCommand && connection._runningCommand.parsed;
128
- const command = parsed && commandName(parsed);
117
+ const command = parsed ? commandName(parsed) : '';
129
118
  if (messages.length <= limit || (!SEARCH_COMMANDS.has(command) && !SORT_COMMANDS.has(command))) {
130
119
  return false;
131
120
  }
@@ -143,9 +132,8 @@ module.exports = function (server) {
143
132
  parsed.messageLimitUid = candidates[candidates.length - limit].uid;
144
133
  return candidates.slice(-limit);
145
134
  });
146
-
147
135
  // RFC 9738 section 3.2: UIDAFTER <uid> is "UID <uid>+1:*", UIDBEFORE <uid> is "UID 1:<uid>-1"
148
- const parseUniqueId = value => {
136
+ const parseUniqueId = (value) => {
149
137
  // uniqueid = nz-number
150
138
  if (!isNzNumber(value)) {
151
139
  throw badError('UIDAFTER and UIDBEFORE expect a UID');
@@ -158,7 +146,6 @@ module.exports = function (server) {
158
146
  uidBefore.argumentTypes = () => [parseUniqueId];
159
147
  server.searchHandlers.UIDAFTER = uidAfter;
160
148
  server.searchHandlers.UIDBEFORE = uidBefore;
161
-
162
149
  const outputHandler = (connection, response, description, parsed, data) => {
163
150
  // section 3.1 UID SEARCH example: the results go from the highest UID down, (MODSEQ n) of CONDSTORE stays last
164
151
  if (parsed && parsed.messageLimitUid && response.tag === '*' && response.command === 'SEARCH' && Array.isArray(response.attributes)) {
@@ -177,43 +164,35 @@ module.exports = function (server) {
177
164
  if (response.command !== 'OK') {
178
165
  return;
179
166
  }
180
-
181
167
  // resp-text-code =/ "MESSAGELIMIT" SP message-limit [SP uniqueid]
182
168
  const code = { type: 'SECTION', section: [{ type: 'ATOM', value: 'MESSAGELIMIT' }, limit, lastUid] };
183
169
  const attributes = response.attributes || [];
184
170
  if (attributes[0] && attributes[0].type === 'SECTION') {
185
171
  // RFC 9738 section 3.1: when the tagged OK carries another response code (EXPUNGEISSUED there, and here
186
172
  // also HIGHESTMODSEQ, MODIFIED), MESSAGELIMIT is sent in an untagged NO
187
- connection.send(
188
- {
189
- tag: '*',
190
- command: 'NO',
191
- attributes: [code, { type: 'TEXT', value: 'Only the last ' + limit + ' messages were processed' }]
192
- },
193
- 'MESSAGELIMIT',
194
- parsed,
195
- data
196
- );
173
+ connection.send({
174
+ tag: '*',
175
+ command: 'NO',
176
+ attributes: [code, { type: 'TEXT', value: 'Only the last ' + limit + ' messages were processed' }]
177
+ }, 'MESSAGELIMIT', parsed, data);
197
178
  return;
198
179
  }
199
180
  response.attributes = [code].concat(attributes);
200
181
  };
201
-
202
182
  // registered once every plugin is loaded, so that the response codes other plugins add to the tagged OK
203
183
  // are already there
204
184
  server.once('pluginsLoaded', () => server.outputHandlers.push(outputHandler));
205
- };
206
-
185
+ }
207
186
  /**
208
187
  * Checks if a message passes the keys of a search query that every match must pass: sequence sets,
209
188
  * UID, UIDAFTER and UIDBEFORE at the top level, or in parenthesized lists at the top level
210
189
  *
211
- * @param {Object} node AND node of the query tree, see commands/handlers/search.js
190
+ * @param {Object} node AND node of the query tree, see commands/handlers/search.ts
212
191
  * @param {Object} message Message
213
192
  * @return {Boolean} true if the message has to be searched
214
193
  */
215
194
  function isCandidate(node, message) {
216
- return node.args.every(arg => {
195
+ return node.args.every((arg) => {
217
196
  switch (arg.key) {
218
197
  case 'AND':
219
198
  return isCandidate(arg, message);
@@ -229,6 +208,4 @@ function isCandidate(node, message) {
229
208
  }
230
209
  });
231
210
  }
232
-
233
- module.exports.getLimit = getLimit;
234
- module.exports.addSaveLimit = addSaveLimit;
211
+ export { getLimit, addSaveLimit };
@@ -0,0 +1,7 @@
1
+ import type { IMAPServer } from '../types.js';
2
+ /**
3
+ * @help Adds METADATA-SERVER [RFC5464] capability, like METADATA but
4
+ * @help only for server annotations (mailbox name ""). With METADATA
5
+ * @help also loaded, only METADATA is advertised
6
+ */
7
+ export default function metadataServerPlugin(server: IMAPServer): void;
@@ -1,13 +1,9 @@
1
- 'use strict';
2
-
3
- const { setup } = require('./metadata');
4
-
1
+ import { setup } from './metadata.js';
5
2
  /**
6
3
  * @help Adds METADATA-SERVER [RFC5464] capability, like METADATA but
7
4
  * @help only for server annotations (mailbox name ""). With METADATA
8
5
  * @help also loaded, only METADATA is advertised
9
6
  */
10
-
11
- module.exports = function (server) {
7
+ export default function metadataServerPlugin(server) {
12
8
  setup(server, false);
13
- };
9
+ }
@@ -0,0 +1,11 @@
1
+ import type { IMAPServer } from '../types.js';
2
+ /**
3
+ * Sets up METADATA or METADATA-SERVER. With both plugins loaded, METADATA wins (RFC 5464 section 1:
4
+ * a server with mailbox annotations advertises METADATA)
5
+ *
6
+ * @param {Object} server IMAPServer instance
7
+ * @param {Boolean} mailboxes If true, mailbox annotations are supported, otherwise only server annotations
8
+ */
9
+ declare function setup(server: IMAPServer, mailboxes: boolean): void;
10
+ export default function metadataPlugin(server: IMAPServer): void;
11
+ export { setup };
@@ -0,0 +1,421 @@
1
+ import { states } from '../command-states.js';
2
+ import { isNumber } from '../numbers.js';
3
+ import { isAstring } from '../arguments.js';
4
+ import { registerEnable, isEnabled } from './enable.js';
5
+ /**
6
+ * @help Adds METADATA [RFC5464] capability (GETMETADATA and SETMETADATA)
7
+ * @help for server and mailbox annotations. Mailboxes take initial entries
8
+ * @help from a "metadata" object in storage, server entries come from the
9
+ * @help "metadata" option. Limits: "metadataMaxSize" (octets per value,
10
+ * @help default 65536), "metadataMaxEntries" (per mailbox and for the
11
+ * @help server, default 100). "metadataPrivate": false turns /private
12
+ * @help entries off. ENABLE METADATA turns on unsolicited METADATA responses
13
+ */
14
+ // Default limits, RFC 5464 section 4.1 requires at least 1024 octets and 10 entries
15
+ const DEFAULT_MAX_SIZE = 64 * 1024;
16
+ const DEFAULT_MAX_ENTRIES = 100;
17
+ // RFC 5464 section 3.2.1.1: /shared/admin is always read-only
18
+ const READ_ONLY_SERVER_ENTRIES = new Set(['/shared/admin']);
19
+ // RFC 6154 section 4: special-use attributes are tied to this mailbox entry
20
+ const SPECIAL_USE_ENTRY = '/private/specialuse';
21
+ /**
22
+ * Checks an entry name against RFC 5464 section 3.2
23
+ *
24
+ * @param {String} name Entry name as a binary string
25
+ * @param {Boolean} [isSet] If true, the name must be one that can hold a value (at least 2 components,
26
+ * at least 4 under /shared/vendor and /private/vendor). GETMETADATA also accepts the bare "/shared"
27
+ * and "/private" scopes, so a client can ask for everything with DEPTH infinity
28
+ * @return {String|Boolean} Description of the problem, or false if the name is valid
29
+ */
30
+ function checkEntryName(name, isSet) {
31
+ if (typeof name !== 'string' || name.charAt(0) !== '/') {
32
+ return 'Entry name must begin with "/"';
33
+ }
34
+ // "MUST NOT contain non-ASCII characters or characters with octet values in the range 0x00 to 0x19"
35
+ if (/[^\x20-\x7f]/.test(name)) {
36
+ return 'Entry name must not contain non-ASCII or control characters';
37
+ }
38
+ if (/[*%]/.test(name)) {
39
+ return 'Entry name must not contain "*" or "%"';
40
+ }
41
+ if (name.indexOf('//') >= 0) {
42
+ return 'Entry name must not contain consecutive "/" characters';
43
+ }
44
+ if (name.charAt(name.length - 1) === '/') {
45
+ return 'Entry name must not end with "/"';
46
+ }
47
+ const components = name.toLowerCase().substr(1).split('/');
48
+ if (components[0] !== 'private' && components[0] !== 'shared') {
49
+ return 'Entry name must begin with /private or /shared';
50
+ }
51
+ if (isSet && components.length < 2) {
52
+ return 'Entry name must have at least 2 components';
53
+ }
54
+ if (isSet && components[1] === 'vendor' && components.length < 4) {
55
+ return 'Vendor entry names must have at least 4 components';
56
+ }
57
+ return false;
58
+ }
59
+ /**
60
+ * Converts a value from storage or options to a binary string. A value with NUL is sent as a literal8
61
+ *
62
+ * @param {String} name Entry name, for error messages
63
+ * @param {*} value Entry value
64
+ * @return {String|null} Binary string, or null for no value
65
+ */
66
+ function normalizeValue(name, value) {
67
+ if (value === null || value === undefined) {
68
+ return null;
69
+ }
70
+ if (value instanceof Uint8Array) {
71
+ value = Buffer.from(value).toString('binary');
72
+ }
73
+ else if (typeof value === 'string') {
74
+ if (/[Ā-￿]/.test(value)) {
75
+ // characters outside Latin-1 can only come from a unicode string, so encode it as UTF-8
76
+ value = Buffer.from(value, 'utf-8').toString('binary');
77
+ }
78
+ }
79
+ else {
80
+ throw new Error('Invalid value for metadata entry ' + name + ', expecting a string');
81
+ }
82
+ return value;
83
+ }
84
+ /**
85
+ * Formats a mailbox name for a METADATA response. IMAPConnection#send converts the storage name for
86
+ * each session (UTF-8 with UTF8=ACCEPT) and quotes it when it is not an atom
87
+ *
88
+ * @param {String} name Mailbox name, "" for the server
89
+ * @return {Object} Response attribute
90
+ */
91
+ function mailboxAttribute(name) {
92
+ return { type: 'MAILBOX', value: name };
93
+ }
94
+ /**
95
+ * Sets up METADATA or METADATA-SERVER. With both plugins loaded, METADATA wins (RFC 5464 section 1:
96
+ * a server with mailbox annotations advertises METADATA)
97
+ *
98
+ * @param {Object} server IMAPServer instance
99
+ * @param {Boolean} mailboxes If true, mailbox annotations are supported, otherwise only server annotations
100
+ */
101
+ function setup(server, mailboxes) {
102
+ if (server.metadataState) {
103
+ // the other variant is already loaded, upgrade it if needed
104
+ if (mailboxes && !server.metadataState.mailboxes) {
105
+ server.metadataState.mailboxes = true;
106
+ delete server.capabilities['METADATA-SERVER'];
107
+ server.registerCapability('METADATA');
108
+ server.enableAvailable.splice(server.enableAvailable.indexOf('METADATA-SERVER'), 1, 'METADATA');
109
+ }
110
+ return;
111
+ }
112
+ // RFC 5464 section 5: SETMETADATA values can be literal8
113
+ server.parserOptions.literal8 = true;
114
+ const capability = mailboxes ? 'METADATA' : 'METADATA-SERVER';
115
+ server.registerCapability(capability);
116
+ // RFC 5464 section 4.1: unsolicited METADATA responses are only sent after ENABLE
117
+ registerEnable(server, capability);
118
+ const options = server.options;
119
+ const state = (server.metadataState = {
120
+ mailboxes,
121
+ maxSize: Number(options.metadataMaxSize) || DEFAULT_MAX_SIZE,
122
+ maxEntries: Number(options.metadataMaxEntries) || DEFAULT_MAX_ENTRIES,
123
+ allowPrivate: options.metadataPrivate !== false,
124
+ // server annotations, normalized on first use like mailbox annotations
125
+ server: { path: '', metadata: options.metadata }
126
+ });
127
+ // metadata objects that are already normalized
128
+ const normalized = new WeakSet();
129
+ /**
130
+ * Returns the stored entries of a mailbox or the server, as an object of lower case entry
131
+ * names (entry names are case-insensitive, RFC 5464 section 3.2) and binary string values
132
+ *
133
+ * @param {Object} holder Mailbox object or state.server
134
+ * @return {Object} Entries, replace them with setEntries instead of changing them
135
+ */
136
+ const getEntries = (holder) => {
137
+ if (!holder.metadata) {
138
+ return Object.create(null);
139
+ }
140
+ if (normalized.has(holder.metadata)) {
141
+ return holder.metadata;
142
+ }
143
+ // initial values from storage or options, never modify the caller's objects
144
+ const entries = Object.create(null);
145
+ const metadata = holder.metadata;
146
+ Object.keys(metadata).forEach(name => {
147
+ const error = checkEntryName(name, true);
148
+ if (error) {
149
+ throw new Error('Invalid metadata entry name ' + JSON.stringify(name) + ': ' + error);
150
+ }
151
+ const value = normalizeValue(name, metadata[name]);
152
+ if (value !== null) {
153
+ entries[name.toLowerCase()] = value;
154
+ }
155
+ });
156
+ return setEntries(holder, entries);
157
+ };
158
+ const setEntries = (holder, entries) => {
159
+ normalized.add(entries);
160
+ holder.metadata = entries;
161
+ return entries;
162
+ };
163
+ /**
164
+ * Returns entries that the server computes instead of storing them
165
+ *
166
+ * @param {Object} holder Mailbox object or state.server
167
+ * @return {Object} Entries, a null value means no value
168
+ */
169
+ const getComputedEntries = (holder) => {
170
+ const computed = Object.create(null);
171
+ if (holder.path && server.capabilities['SPECIAL-USE']) {
172
+ // RFC 6154 section 4: NIL or the special-use attributes separated by spaces, as in LIST responses
173
+ const specialUse = [].concat(holder['special-use'] || []);
174
+ computed[SPECIAL_USE_ENTRY] = specialUse.length ? specialUse.join(' ') : null;
175
+ }
176
+ return computed;
177
+ };
178
+ const isMetadataEnabled = (connection) => isEnabled(connection, state.mailboxes ? 'METADATA' : 'METADATA-SERVER');
179
+ /**
180
+ * Finds the annotation holder for a mailbox name argument, sends a NO if there is none
181
+ *
182
+ * @return {Object|Boolean} Mailbox object, state.server or false
183
+ */
184
+ const getHolder = (connection, parsed, data, name) => {
185
+ if (name === '') {
186
+ return state.server;
187
+ }
188
+ if (!state.mailboxes) {
189
+ connection.sendStatus(parsed, data, 'NO', 'Mailbox annotations are not supported, only server annotations');
190
+ return false;
191
+ }
192
+ // RFC 5464 section 3.3: only mailboxes that exist and are returned by LIST. Annotations
193
+ // on \Noselect mailboxes are allowed (section 4.1)
194
+ const mailbox = connection.server.getMailbox(name);
195
+ if (!mailbox || mailbox.flags.indexOf('\\NonExistent') >= 0) {
196
+ connection.sendStatus(parsed, data, 'NO', 'Mailbox does not exist', 'NONEXISTENT');
197
+ return false;
198
+ }
199
+ return mailbox;
200
+ };
201
+ const bad = (connection, parsed, data, text, callback) => {
202
+ connection.sendStatus(parsed, data, 'BAD', text);
203
+ return callback();
204
+ };
205
+ // RFC 5464 section 4.2, options before the mailbox name as corrected by errata 2785 and 2786:
206
+ // getmetadata = "GETMETADATA" [SP getmetadata-options] SP mailbox SP entries
207
+ server.setCommandHandler('GETMETADATA', (connection, parsed, data, callback) => {
208
+ const attrs = parsed.attributes || [];
209
+ const offset = Array.isArray(attrs[0]) ? 1 : 0;
210
+ let maxSize = false;
211
+ let depth = 0;
212
+ if (attrs.length !== offset + 2 || !isAstring(attrs[offset])) {
213
+ return bad(connection, parsed, data, 'GETMETADATA expects options, a mailbox name and entries', callback);
214
+ }
215
+ if (offset) {
216
+ // getmetadata-options = "(" getmetadata-option *(SP getmetadata-option) ")"
217
+ const list = attrs[0];
218
+ if (!list.length) {
219
+ return bad(connection, parsed, data, 'Empty option list', callback);
220
+ }
221
+ for (let i = 0; i < list.length; i += 2) {
222
+ const label = list[i] && list[i].type === 'ATOM' ? list[i].value.toUpperCase() : false;
223
+ const value = list[i + 1] && list[i + 1].type === 'ATOM' ? list[i + 1].value : false;
224
+ if (label === 'MAXSIZE') {
225
+ // maxsize-opt = "MAXSIZE" SP number
226
+ if (!isNumber(value)) {
227
+ return bad(connection, parsed, data, 'Invalid value for MAXSIZE', callback);
228
+ }
229
+ maxSize = Number(value);
230
+ }
231
+ else if (label === 'DEPTH') {
232
+ // scope-opt = "DEPTH" SP ("0" / "1" / "infinity")
233
+ if (!value || !/^(0|1|infinity)$/i.test(value)) {
234
+ return bad(connection, parsed, data, 'Invalid value for DEPTH', callback);
235
+ }
236
+ depth = value.toLowerCase() === 'infinity' ? Infinity : Number(value);
237
+ }
238
+ else {
239
+ return bad(connection, parsed, data, 'Unknown GETMETADATA option', callback);
240
+ }
241
+ }
242
+ }
243
+ // the mailbox position depends on the options, so the name is converted here, not by mailboxArguments
244
+ let mailboxName;
245
+ try {
246
+ mailboxName = connection.importMailboxName(attrs[offset].value);
247
+ }
248
+ catch (err) {
249
+ return bad(connection, parsed, data, err.message, callback);
250
+ }
251
+ // entries = entry / "(" entry *(SP entry) ")"
252
+ const entryAttrs = [].concat(attrs[offset + 1]);
253
+ if (!entryAttrs.length || !entryAttrs.every(isAstring)) {
254
+ return bad(connection, parsed, data, 'GETMETADATA expects an entry name or a list of entry names', callback);
255
+ }
256
+ for (const attr of entryAttrs) {
257
+ const error = checkEntryName(attr.value);
258
+ if (error) {
259
+ // RFC 5464 section 3.2: "Invalid entry names result in a BAD response"
260
+ return bad(connection, parsed, data, error, callback);
261
+ }
262
+ }
263
+ const holder = getHolder(connection, parsed, data, mailboxName);
264
+ if (!holder) {
265
+ return callback();
266
+ }
267
+ const all = Object.assign(Object.create(null), getEntries(holder), getComputedEntries(holder));
268
+ const names = depth
269
+ ? Object.keys(all)
270
+ .filter(name => all[name] !== null)
271
+ .sort()
272
+ : [];
273
+ // RFC 5464 section 4.2.2: the entry itself and the entries below it up to DEPTH
274
+ const found = new Map();
275
+ for (const attr of entryAttrs) {
276
+ const entry = attr.value.toLowerCase();
277
+ const value = all[entry] ?? null;
278
+ if (!depth || value !== null) {
279
+ // a requested entry without a value is returned as NIL
280
+ found.set(entry, value);
281
+ }
282
+ const prefix = entry + '/';
283
+ names.forEach(name => {
284
+ if (name.startsWith(prefix) && (depth === Infinity || name.indexOf('/', prefix.length) < 0)) {
285
+ found.set(name, all[name]);
286
+ }
287
+ });
288
+ }
289
+ // RFC 5464 section 4.2.1: larger values are left out, LONGENTRIES reports the biggest one
290
+ let longest = -1;
291
+ const pairs = [];
292
+ found.forEach((value, name) => {
293
+ if (maxSize !== false && value !== null && value.length > maxSize) {
294
+ longest = Math.max(longest, value.length);
295
+ return;
296
+ }
297
+ // RFC 5464 section 5: value = nstring / literal8, only binary data with NUL needs a literal8
298
+ pairs.push({ type: 'ATOM', value: name }, value === null ? null : { type: value.indexOf('\x00') >= 0 ? 'LITERAL8' : 'STRING', value });
299
+ });
300
+ if (pairs.length) {
301
+ connection.send({
302
+ tag: '*',
303
+ command: 'METADATA',
304
+ attributes: [mailboxAttribute(holder.path), pairs]
305
+ }, 'METADATA', parsed, data, holder);
306
+ }
307
+ connection.sendStatus(parsed, data, 'OK', 'GETMETADATA completed', longest >= 0 && ['METADATA', 'LONGENTRIES', longest]);
308
+ return callback();
309
+ }, { states: states.AUTHENTICATED });
310
+ // RFC 5464 section 4.3: setmetadata = "SETMETADATA" SP mailbox SP entry-values
311
+ server.setCommandHandler('SETMETADATA', (connection, parsed, data, callback) => {
312
+ const attrs = parsed.attributes || [];
313
+ if (attrs.length !== 2 || !isAstring(attrs[0]) || !Array.isArray(attrs[1])) {
314
+ return bad(connection, parsed, data, 'SETMETADATA expects a mailbox name and a list of entries and values', callback);
315
+ }
316
+ // entry-values = "(" entry-value *(SP entry-value) ")", entry-value = entry SP value
317
+ const list = attrs[1];
318
+ if (!list.length || list.length % 2) {
319
+ return bad(connection, parsed, data, 'SETMETADATA expects entry and value pairs', callback);
320
+ }
321
+ const changes = new Map();
322
+ for (let i = 0; i < list.length; i += 2) {
323
+ if (!isAstring(list[i])) {
324
+ return bad(connection, parsed, data, 'Entry name must be a string', callback);
325
+ }
326
+ const error = checkEntryName(list[i].value, true);
327
+ if (error) {
328
+ return bad(connection, parsed, data, error, callback);
329
+ }
330
+ // value = nstring / literal8, an atom is not a value
331
+ const value = list[i + 1];
332
+ if (value !== null && (!value || ['STRING', 'LITERAL', 'LITERAL8'].indexOf(value.type) < 0)) {
333
+ return bad(connection, parsed, data, 'Entry value must be a string, a literal, a literal8 or NIL', callback);
334
+ }
335
+ // RFC 5464 section 3.2: "Clients MUST use the CRLF (0x0D 0x0A) character octet sequence
336
+ // to represent line ends in a multi-line string value", binary data in a literal8 is not a string
337
+ if (value && value.type !== 'LITERAL8' && /\r(?!\n)|(?:^|[^\r])\n/.test(value.value)) {
338
+ return bad(connection, parsed, data, 'Line ends in a value must be CRLF', callback);
339
+ }
340
+ changes.set(list[i].value.toLowerCase(), value ? value.value : null);
341
+ }
342
+ const holder = getHolder(connection, parsed, data, attrs[0].value);
343
+ if (!holder) {
344
+ return callback();
345
+ }
346
+ const entries = getEntries(holder);
347
+ const computed = getComputedEntries(holder);
348
+ const fail = (text, code) => {
349
+ // RFC 5464 section 4.3: when one entry fails, no entry is changed
350
+ connection.sendStatus(parsed, data, 'NO', text, code);
351
+ return callback();
352
+ };
353
+ // changes go to a copy that replaces the entries once every check passed
354
+ const next = Object.assign(Object.create(null), entries);
355
+ const changed = [];
356
+ for (const [name, value] of changes) {
357
+ if ((!holder.path && READ_ONLY_SERVER_ENTRIES.has(name)) || name in computed) {
358
+ return fail('The ' + name + ' entry is read-only', 'CANNOT');
359
+ }
360
+ if (!state.allowPrivate && name.startsWith('/private/')) {
361
+ return fail('Private annotations are not supported', ['METADATA', 'NOPRIVATE']);
362
+ }
363
+ if (value !== null && value.length > state.maxSize) {
364
+ return fail('Value of ' + name + ' is too large', ['METADATA', 'MAXSIZE', state.maxSize]);
365
+ }
366
+ if ((entries[name] ?? null) !== value) {
367
+ changed.push(name);
368
+ }
369
+ if (value === null) {
370
+ delete next[name];
371
+ }
372
+ else {
373
+ next[name] = value;
374
+ }
375
+ }
376
+ // only adding entries can fail, even when the storage already holds more than the limit
377
+ const count = Object.keys(next).length;
378
+ if (count > state.maxEntries && count > Object.keys(entries).length) {
379
+ return fail('Too many annotations', ['METADATA', 'TOOMANY']);
380
+ }
381
+ setEntries(holder, next);
382
+ if (changed.length) {
383
+ // RFC 5464 section 4.4.2: unsolicited responses only list the entry names. Section 4.1:
384
+ // only sessions that used ENABLE METADATA (or METADATA-SERVER) get them
385
+ server.notify({
386
+ tag: '*',
387
+ command: 'METADATA',
388
+ attributes: [mailboxAttribute(holder.path)].concat(changed.map(name => ({ type: 'ATOM', value: name })))
389
+ }, false, connection, isMetadataEnabled);
390
+ }
391
+ connection.sendStatus(parsed, data, 'OK', 'SETMETADATA completed');
392
+ return callback();
393
+ },
394
+ // RFC 5464 section 5: values can be literal8, with or without BINARY
395
+ { states: states.AUTHENTICATED, mailboxArguments: [0], literal8: true });
396
+ server.outputHandlers.push((connection, response, description, parsed, data, extra) => {
397
+ if (response.command !== 'OK' || !parsed || !parsed.attributes) {
398
+ return;
399
+ }
400
+ if (description === 'RENAME' && extra && extra.path === 'INBOX') {
401
+ // RFC 5464 section 4.1: renaming INBOX copies its annotations, INBOX keeps them. Other
402
+ // mailboxes are moved as objects, so their annotations follow without any help
403
+ const target = connection.server.getMailbox(parsed.attributes[1].value);
404
+ if (target && target !== extra && extra.metadata) {
405
+ setEntries(target, Object.assign(Object.create(null), getEntries(extra)));
406
+ }
407
+ }
408
+ else if (description === 'DELETE') {
409
+ // RFC 5464 section 4.1: a mailbox created later with the same name must not inherit the
410
+ // annotations. A mailbox with children stays as a \Noselect placeholder
411
+ const placeholder = connection.server.getMailbox(parsed.attributes[0].value);
412
+ if (placeholder) {
413
+ delete placeholder.metadata;
414
+ }
415
+ }
416
+ });
417
+ }
418
+ export default function metadataPlugin(server) {
419
+ setup(server, true);
420
+ }
421
+ export { setup };
@@ -0,0 +1,11 @@
1
+ import type { IMAPServer } from '../types.js';
2
+ /**
3
+ * @help Adds MOVE [RFC6851] capability
4
+ *
5
+ * MOVE: http://tools.ietf.org/html/rfc6851
6
+ *
7
+ * Additional commands:
8
+ * - MOVE
9
+ * - UID MOVE
10
+ */
11
+ export default function movePlugin(server: IMAPServer): void;