imapkit 4.0.2 → 4.1.0
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.
- package/README.md +32 -19
- package/bin/imapkit.js +12 -16
- package/dist/cjs/addressparser.d.ts +21 -0
- package/dist/cjs/addressparser.js +277 -0
- package/dist/cjs/arguments.d.ts +31 -0
- package/{lib → dist/cjs}/arguments.js +9 -21
- package/dist/cjs/bodystructure.d.ts +25 -0
- package/dist/cjs/bodystructure.js +150 -0
- package/dist/cjs/cert.d.ts +2 -0
- package/dist/cjs/cert.js +7 -0
- package/dist/cjs/command-states.d.ts +36 -0
- package/dist/cjs/command-states.js +102 -0
- package/dist/cjs/commands/append.d.ts +88 -0
- package/dist/cjs/commands/append.js +299 -0
- package/dist/cjs/commands/capability.d.ts +2 -0
- package/dist/cjs/commands/capability.js +44 -0
- package/dist/cjs/commands/check.d.ts +2 -0
- package/dist/cjs/commands/check.js +28 -0
- package/dist/cjs/commands/close.d.ts +2 -0
- package/dist/cjs/commands/close.js +35 -0
- package/dist/cjs/commands/copy.d.ts +30 -0
- package/dist/cjs/commands/copy.js +107 -0
- package/dist/cjs/commands/create.d.ts +2 -0
- package/dist/cjs/commands/create.js +53 -0
- package/dist/cjs/commands/delete.d.ts +2 -0
- package/dist/cjs/commands/delete.js +63 -0
- package/dist/cjs/commands/examine.d.ts +2 -0
- package/dist/cjs/commands/examine.js +19 -0
- package/dist/cjs/commands/expunge.d.ts +2 -0
- package/dist/cjs/commands/expunge.js +32 -0
- package/dist/cjs/commands/fetch.d.ts +23 -0
- package/dist/cjs/commands/fetch.js +208 -0
- package/dist/cjs/commands/handlers/fetch.d.ts +12 -0
- package/dist/cjs/commands/handlers/fetch.js +195 -0
- package/dist/cjs/commands/handlers/flags.d.ts +17 -0
- package/dist/cjs/commands/handlers/flags.js +39 -0
- package/dist/cjs/commands/handlers/search.d.ts +85 -0
- package/dist/cjs/commands/handlers/search.js +504 -0
- package/dist/cjs/commands/handlers/status.d.ts +34 -0
- package/dist/cjs/commands/handlers/status.js +81 -0
- package/dist/cjs/commands/handlers/store.d.ts +3 -0
- package/dist/cjs/commands/handlers/store.js +117 -0
- package/dist/cjs/commands/index.d.ts +2 -0
- package/dist/cjs/commands/index.js +61 -0
- package/dist/cjs/commands/list.d.ts +2 -0
- package/dist/cjs/commands/list.js +86 -0
- package/dist/cjs/commands/login.d.ts +2 -0
- package/dist/cjs/commands/login.js +62 -0
- package/dist/cjs/commands/logout.d.ts +2 -0
- package/dist/cjs/commands/logout.js +40 -0
- package/dist/cjs/commands/lsub.d.ts +2 -0
- package/dist/cjs/commands/lsub.js +79 -0
- package/dist/cjs/commands/noop.d.ts +2 -0
- package/dist/cjs/commands/noop.js +28 -0
- package/dist/cjs/commands/rename.d.ts +2 -0
- package/dist/cjs/commands/rename.js +98 -0
- package/dist/cjs/commands/search.d.ts +10 -0
- package/dist/cjs/commands/search.js +71 -0
- package/dist/cjs/commands/select.d.ts +19 -0
- package/dist/cjs/commands/select.js +230 -0
- package/dist/cjs/commands/status.d.ts +2 -0
- package/dist/cjs/commands/status.js +57 -0
- package/dist/cjs/commands/store.d.ts +10 -0
- package/dist/cjs/commands/store.js +134 -0
- package/dist/cjs/commands/subscribe.d.ts +2 -0
- package/dist/cjs/commands/subscribe.js +51 -0
- package/dist/cjs/commands/uid-copy.d.ts +2 -0
- package/dist/cjs/commands/uid-copy.js +19 -0
- package/dist/cjs/commands/uid-fetch.d.ts +3 -0
- package/dist/cjs/commands/uid-fetch.js +17 -0
- package/dist/cjs/commands/uid-search.d.ts +3 -0
- package/dist/cjs/commands/uid-search.js +17 -0
- package/dist/cjs/commands/uid-store.d.ts +3 -0
- package/dist/cjs/commands/uid-store.js +17 -0
- package/dist/cjs/commands/unsubscribe.d.ts +2 -0
- package/dist/cjs/commands/unsubscribe.js +50 -0
- package/dist/cjs/dates.d.ts +64 -0
- package/dist/cjs/dates.js +124 -0
- package/dist/cjs/deflate-layer.d.ts +83 -0
- package/dist/cjs/deflate-layer.js +232 -0
- package/dist/cjs/encoded-words.d.ts +15 -0
- package/dist/cjs/encoded-words.js +85 -0
- package/dist/cjs/envelope.d.ts +33 -0
- package/dist/cjs/envelope.js +86 -0
- package/dist/cjs/esearch.d.ts +96 -0
- package/dist/cjs/esearch.js +190 -0
- package/dist/cjs/framing.d.ts +66 -0
- package/{lib → dist/cjs}/framing.js +9 -26
- package/dist/cjs/index.d.ts +9 -0
- package/dist/cjs/index.js +56 -0
- package/dist/cjs/list-extensions.d.ts +50 -0
- package/dist/cjs/list-extensions.js +35 -0
- package/dist/cjs/load-plugins.d.ts +21 -0
- package/dist/cjs/load-plugins.js +89 -0
- package/dist/cjs/mailbox-name.d.ts +26 -0
- package/dist/cjs/mailbox-name.js +127 -0
- package/dist/cjs/mimeparser.d.ts +137 -0
- package/dist/cjs/mimeparser.js +727 -0
- package/dist/cjs/mock-client.d.ts +39 -0
- package/dist/cjs/mock-client.js +236 -0
- package/dist/cjs/numbers.d.ts +28 -0
- package/dist/cjs/numbers.js +52 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/plugins/acl.d.ts +2 -0
- package/dist/cjs/plugins/acl.js +888 -0
- package/dist/cjs/plugins/appendlimit.d.ts +16 -0
- package/dist/cjs/plugins/appendlimit.js +87 -0
- package/dist/cjs/plugins/auth-plain.d.ts +2 -0
- package/dist/cjs/plugins/auth-plain.js +89 -0
- package/dist/cjs/plugins/binary.d.ts +30 -0
- package/dist/cjs/plugins/binary.js +247 -0
- package/dist/cjs/plugins/catenate.d.ts +14 -0
- package/dist/cjs/plugins/catenate.js +250 -0
- package/dist/cjs/plugins/compress.d.ts +7 -0
- package/dist/cjs/plugins/compress.js +79 -0
- package/dist/cjs/plugins/condstore.d.ts +5 -0
- package/dist/cjs/plugins/condstore.js +492 -0
- package/dist/cjs/plugins/context-search.d.ts +8 -0
- package/dist/cjs/plugins/context-search.js +304 -0
- package/dist/cjs/plugins/context-sort.d.ts +6 -0
- package/dist/cjs/plugins/context-sort.js +32 -0
- package/dist/cjs/plugins/create-special-use.d.ts +7 -0
- package/dist/cjs/plugins/create-special-use.js +101 -0
- package/dist/cjs/plugins/enable.d.ts +23 -0
- package/dist/cjs/plugins/enable.js +127 -0
- package/dist/cjs/plugins/esearch.d.ts +6 -0
- package/dist/cjs/plugins/esearch.js +142 -0
- package/dist/cjs/plugins/esort.d.ts +6 -0
- package/dist/cjs/plugins/esort.js +60 -0
- package/dist/cjs/plugins/id.d.ts +5 -0
- package/dist/cjs/plugins/id.js +123 -0
- package/dist/cjs/plugins/idle.d.ts +5 -0
- package/dist/cjs/plugins/idle.js +85 -0
- package/dist/cjs/plugins/imap4rev2.d.ts +6 -0
- package/dist/cjs/plugins/imap4rev2.js +184 -0
- package/dist/cjs/plugins/index.d.ts +2 -0
- package/dist/cjs/plugins/index.js +119 -0
- package/dist/cjs/plugins/list-extended.d.ts +2 -0
- package/dist/cjs/plugins/list-extended.js +235 -0
- package/dist/cjs/plugins/list-status.d.ts +6 -0
- package/dist/cjs/plugins/list-status.js +42 -0
- package/dist/cjs/plugins/literalminus.d.ts +8 -0
- package/dist/cjs/plugins/literalminus.js +32 -0
- package/dist/cjs/plugins/literalplus.d.ts +6 -0
- package/dist/cjs/plugins/literalplus.js +30 -0
- package/dist/cjs/plugins/logindisabled.d.ts +5 -0
- package/dist/cjs/plugins/logindisabled.js +54 -0
- package/dist/cjs/plugins/messagelimit.d.ts +19 -0
- package/dist/cjs/plugins/messagelimit.js +227 -0
- package/dist/cjs/plugins/metadata-server.d.ts +7 -0
- package/dist/cjs/plugins/metadata-server.js +24 -0
- package/dist/cjs/plugins/metadata.d.ts +11 -0
- package/dist/cjs/plugins/metadata.js +436 -0
- package/dist/cjs/plugins/move.d.ts +11 -0
- package/dist/cjs/plugins/move.js +96 -0
- package/dist/cjs/plugins/multiappend.d.ts +12 -0
- package/dist/cjs/plugins/multiappend.js +38 -0
- package/dist/cjs/plugins/multisearch.d.ts +6 -0
- package/dist/cjs/plugins/multisearch.js +263 -0
- package/dist/cjs/plugins/namespace.d.ts +5 -0
- package/dist/cjs/plugins/namespace.js +57 -0
- package/dist/cjs/plugins/notify.d.ts +2 -0
- package/dist/cjs/plugins/notify.js +628 -0
- package/dist/cjs/plugins/oauthbearer.d.ts +32 -0
- package/dist/cjs/plugins/oauthbearer.js +202 -0
- package/dist/cjs/plugins/objectid.d.ts +23 -0
- package/dist/cjs/plugins/objectid.js +221 -0
- package/dist/cjs/plugins/partial.d.ts +6 -0
- package/dist/cjs/plugins/partial.js +78 -0
- package/dist/cjs/plugins/preview.d.ts +31 -0
- package/dist/cjs/plugins/preview.js +378 -0
- package/dist/cjs/plugins/qresync.d.ts +11 -0
- package/dist/cjs/plugins/qresync.js +473 -0
- package/dist/cjs/plugins/quota.d.ts +18 -0
- package/dist/cjs/plugins/quota.js +254 -0
- package/dist/cjs/plugins/replace.d.ts +14 -0
- package/dist/cjs/plugins/replace.js +130 -0
- package/dist/cjs/plugins/sasl-ir.d.ts +5 -0
- package/dist/cjs/plugins/sasl-ir.js +24 -0
- package/dist/cjs/plugins/savedate.d.ts +17 -0
- package/dist/cjs/plugins/savedate.js +64 -0
- package/dist/cjs/plugins/savelimit.d.ts +10 -0
- package/dist/cjs/plugins/savelimit.js +30 -0
- package/dist/cjs/plugins/searchres.d.ts +6 -0
- package/dist/cjs/plugins/searchres.js +91 -0
- package/dist/cjs/plugins/sort-display.d.ts +11 -0
- package/dist/cjs/plugins/sort-display.js +37 -0
- package/dist/cjs/plugins/sort.d.ts +11 -0
- package/dist/cjs/plugins/sort.js +125 -0
- package/dist/cjs/plugins/special-use.d.ts +10 -0
- package/dist/cjs/plugins/special-use.js +95 -0
- package/dist/cjs/plugins/starttls.d.ts +5 -0
- package/dist/cjs/plugins/starttls.js +55 -0
- package/dist/cjs/plugins/status-size.d.ts +7 -0
- package/dist/cjs/plugins/status-size.js +30 -0
- package/dist/cjs/plugins/thread-orderedsubject.d.ts +11 -0
- package/dist/cjs/plugins/thread-orderedsubject.js +28 -0
- package/dist/cjs/plugins/thread-references.d.ts +11 -0
- package/dist/cjs/plugins/thread-references.js +28 -0
- package/dist/cjs/plugins/uidonly.d.ts +15 -0
- package/dist/cjs/plugins/uidonly.js +126 -0
- package/dist/cjs/plugins/uidplus.d.ts +15 -0
- package/dist/cjs/plugins/uidplus.js +119 -0
- package/dist/cjs/plugins/unauthenticate.d.ts +7 -0
- package/dist/cjs/plugins/unauthenticate.js +32 -0
- package/dist/cjs/plugins/unselect.d.ts +5 -0
- package/dist/cjs/plugins/unselect.js +36 -0
- package/dist/cjs/plugins/utf8-accept.d.ts +6 -0
- package/dist/cjs/plugins/utf8-accept.js +72 -0
- package/dist/cjs/plugins/x-gm-ext-1.d.ts +26 -0
- package/dist/cjs/plugins/x-gm-ext-1.js +422 -0
- package/dist/cjs/plugins/xoauth2.d.ts +2 -0
- package/dist/cjs/plugins/xoauth2.js +155 -0
- package/dist/cjs/plugins/xtoybird.d.ts +2 -0
- package/dist/cjs/plugins/xtoybird.js +236 -0
- package/dist/cjs/server.d.ts +876 -0
- package/dist/cjs/server.js +2597 -0
- package/dist/cjs/smtp-listener.d.ts +13 -0
- package/dist/cjs/smtp-listener.js +47 -0
- package/dist/cjs/sorting.d.ts +77 -0
- package/dist/cjs/sorting.js +290 -0
- package/dist/cjs/threading.d.ts +30 -0
- package/dist/cjs/threading.js +318 -0
- package/dist/cjs/types.d.ts +327 -0
- package/dist/cjs/types.js +3 -0
- package/dist/cjs/utf8-session.d.ts +17 -0
- package/dist/cjs/utf8-session.js +148 -0
- package/dist/cjs/vanished.d.ts +21 -0
- package/dist/cjs/vanished.js +55 -0
- package/dist/esm/addressparser.d.ts +21 -0
- package/{lib → dist/esm}/addressparser.js +102 -123
- package/dist/esm/arguments.d.ts +31 -0
- package/dist/esm/arguments.js +96 -0
- package/dist/esm/bodystructure.d.ts +25 -0
- package/{lib → dist/esm}/bodystructure.js +17 -33
- package/dist/esm/cert.d.ts +2 -0
- package/dist/esm/cert.js +4 -0
- package/dist/esm/command-states.d.ts +36 -0
- package/{lib → dist/esm}/command-states.js +4 -16
- package/dist/esm/commands/append.d.ts +88 -0
- package/{lib → dist/esm}/commands/append.js +47 -85
- package/dist/esm/commands/capability.d.ts +2 -0
- package/dist/esm/commands/capability.js +29 -0
- package/dist/esm/commands/check.d.ts +2 -0
- package/dist/esm/commands/check.js +13 -0
- package/dist/esm/commands/close.d.ts +2 -0
- package/dist/esm/commands/close.js +20 -0
- package/dist/esm/commands/copy.d.ts +30 -0
- package/{lib → dist/esm}/commands/copy.js +31 -55
- package/dist/esm/commands/create.d.ts +2 -0
- package/{lib → dist/esm}/commands/create.js +25 -39
- package/dist/esm/commands/delete.d.ts +2 -0
- package/{lib → dist/esm}/commands/delete.js +25 -41
- package/dist/esm/commands/examine.d.ts +2 -0
- package/dist/esm/commands/examine.js +4 -0
- package/dist/esm/commands/expunge.d.ts +2 -0
- package/dist/esm/commands/expunge.js +17 -0
- package/dist/esm/commands/fetch.d.ts +23 -0
- package/{lib → dist/esm}/commands/fetch.js +34 -75
- package/dist/esm/commands/handlers/fetch.d.ts +12 -0
- package/{lib → dist/esm}/commands/handlers/fetch.js +11 -42
- package/dist/esm/commands/handlers/flags.d.ts +17 -0
- package/{lib → dist/esm}/commands/handlers/flags.js +3 -11
- package/dist/esm/commands/handlers/search.d.ts +85 -0
- package/{lib → dist/esm}/commands/handlers/search.js +33 -71
- package/dist/esm/commands/handlers/status.d.ts +34 -0
- package/{lib → dist/esm}/commands/handlers/status.js +1 -9
- package/dist/esm/commands/handlers/store.d.ts +3 -0
- package/{lib → dist/esm}/commands/handlers/store.js +20 -44
- package/dist/esm/commands/index.d.ts +2 -0
- package/dist/esm/commands/index.js +55 -0
- package/dist/esm/commands/list.d.ts +2 -0
- package/dist/esm/commands/list.js +71 -0
- package/dist/esm/commands/login.d.ts +2 -0
- package/{lib → dist/esm}/commands/login.js +24 -44
- package/dist/esm/commands/logout.d.ts +2 -0
- package/dist/esm/commands/logout.js +25 -0
- package/dist/esm/commands/lsub.d.ts +2 -0
- package/dist/esm/commands/lsub.js +64 -0
- package/dist/esm/commands/noop.d.ts +2 -0
- package/dist/esm/commands/noop.js +13 -0
- package/dist/esm/commands/rename.d.ts +2 -0
- package/{lib → dist/esm}/commands/rename.js +32 -51
- package/dist/esm/commands/search.d.ts +10 -0
- package/dist/esm/commands/search.js +54 -0
- package/dist/esm/commands/select.d.ts +19 -0
- package/dist/esm/commands/select.js +214 -0
- package/dist/esm/commands/status.d.ts +2 -0
- package/{lib → dist/esm}/commands/status.js +18 -39
- package/dist/esm/commands/store.d.ts +10 -0
- package/{lib → dist/esm}/commands/store.js +39 -73
- package/dist/esm/commands/subscribe.d.ts +2 -0
- package/{lib → dist/esm}/commands/subscribe.js +22 -39
- package/dist/esm/commands/uid-copy.d.ts +2 -0
- package/dist/esm/commands/uid-copy.js +4 -0
- package/dist/esm/commands/uid-fetch.d.ts +3 -0
- package/dist/esm/commands/uid-fetch.js +3 -0
- package/dist/esm/commands/uid-search.d.ts +3 -0
- package/dist/esm/commands/uid-search.js +3 -0
- package/dist/esm/commands/uid-store.d.ts +3 -0
- package/dist/esm/commands/uid-store.js +3 -0
- package/dist/esm/commands/unsubscribe.d.ts +2 -0
- package/{lib → dist/esm}/commands/unsubscribe.js +22 -37
- package/dist/esm/dates.d.ts +64 -0
- package/{lib → dist/esm}/dates.js +6 -14
- package/dist/esm/deflate-layer.d.ts +83 -0
- package/{lib → dist/esm}/deflate-layer.js +9 -26
- package/dist/esm/encoded-words.d.ts +15 -0
- package/{lib → dist/esm}/encoded-words.js +9 -25
- package/dist/esm/envelope.d.ts +33 -0
- package/{lib → dist/esm}/envelope.js +8 -19
- package/dist/esm/esearch.d.ts +96 -0
- package/{lib → dist/esm}/esearch.js +12 -39
- package/dist/esm/framing.d.ts +66 -0
- package/dist/esm/framing.js +82 -0
- package/dist/esm/index.d.ts +9 -0
- package/dist/esm/index.js +6 -0
- package/dist/esm/list-extensions.d.ts +50 -0
- package/{lib → dist/esm}/list-extensions.js +1 -4
- package/dist/esm/load-plugins.d.ts +21 -0
- package/{lib → dist/esm}/load-plugins.js +9 -43
- package/dist/esm/mailbox-name.d.ts +26 -0
- package/{lib → dist/esm}/mailbox-name.js +5 -26
- package/dist/esm/mimeparser.d.ts +137 -0
- package/{lib → dist/esm}/mimeparser.js +74 -152
- package/dist/esm/mock-client.d.ts +39 -0
- package/{lib → dist/esm}/mock-client.js +26 -40
- package/dist/esm/numbers.d.ts +28 -0
- package/{lib → dist/esm}/numbers.js +1 -8
- package/dist/esm/package.json +3 -0
- package/dist/esm/plugins/acl.d.ts +2 -0
- package/{lib → dist/esm}/plugins/acl.js +146 -240
- package/dist/esm/plugins/appendlimit.d.ts +16 -0
- package/{lib → dist/esm}/plugins/appendlimit.js +5 -16
- package/dist/esm/plugins/auth-plain.d.ts +2 -0
- package/{lib → dist/esm}/plugins/auth-plain.js +11 -31
- package/dist/esm/plugins/binary.d.ts +30 -0
- package/{lib → dist/esm}/plugins/binary.js +17 -43
- package/dist/esm/plugins/catenate.d.ts +14 -0
- package/{lib → dist/esm}/plugins/catenate.js +19 -40
- package/dist/esm/plugins/compress.d.ts +7 -0
- package/dist/esm/plugins/compress.js +61 -0
- package/dist/esm/plugins/condstore.d.ts +5 -0
- package/{lib → dist/esm}/plugins/condstore.js +66 -152
- package/dist/esm/plugins/context-search.d.ts +8 -0
- package/{lib → dist/esm}/plugins/context-search.js +53 -88
- package/dist/esm/plugins/context-sort.d.ts +6 -0
- package/{lib → dist/esm}/plugins/context-sort.js +4 -9
- package/dist/esm/plugins/create-special-use.d.ts +7 -0
- package/{lib → dist/esm}/plugins/create-special-use.js +33 -55
- package/dist/esm/plugins/enable.d.ts +23 -0
- package/dist/esm/plugins/enable.js +111 -0
- package/dist/esm/plugins/esearch.d.ts +6 -0
- package/{lib → dist/esm}/plugins/esearch.js +13 -42
- package/dist/esm/plugins/esort.d.ts +6 -0
- package/{lib → dist/esm}/plugins/esort.js +7 -25
- package/dist/esm/plugins/id.d.ts +5 -0
- package/dist/esm/plugins/id.js +108 -0
- package/dist/esm/plugins/idle.d.ts +5 -0
- package/dist/esm/plugins/idle.js +70 -0
- package/dist/esm/plugins/imap4rev2.d.ts +6 -0
- package/{lib → dist/esm}/plugins/imap4rev2.js +24 -60
- package/dist/esm/plugins/index.d.ts +2 -0
- package/dist/esm/plugins/index.js +113 -0
- package/dist/esm/plugins/list-extended.d.ts +2 -0
- package/{lib → dist/esm}/plugins/list-extended.js +28 -66
- package/dist/esm/plugins/list-status.d.ts +6 -0
- package/{lib → dist/esm}/plugins/list-status.js +5 -12
- package/dist/esm/plugins/literalminus.d.ts +8 -0
- package/{lib → dist/esm}/plugins/literalminus.js +2 -5
- package/dist/esm/plugins/literalplus.d.ts +6 -0
- package/{lib → dist/esm}/plugins/literalplus.js +2 -5
- package/dist/esm/plugins/logindisabled.d.ts +5 -0
- package/dist/esm/plugins/logindisabled.js +39 -0
- package/dist/esm/plugins/messagelimit.d.ts +19 -0
- package/{lib → dist/esm}/plugins/messagelimit.js +18 -41
- package/dist/esm/plugins/metadata-server.d.ts +7 -0
- package/{lib → dist/esm}/plugins/metadata-server.js +3 -7
- package/dist/esm/plugins/metadata.d.ts +11 -0
- package/dist/esm/plugins/metadata.js +421 -0
- package/dist/esm/plugins/move.d.ts +11 -0
- package/{lib → dist/esm}/plugins/move.js +37 -66
- package/dist/esm/plugins/multiappend.d.ts +12 -0
- package/{lib → dist/esm}/plugins/multiappend.js +2 -5
- package/dist/esm/plugins/multisearch.d.ts +6 -0
- package/{lib → dist/esm}/plugins/multisearch.js +24 -48
- package/dist/esm/plugins/namespace.d.ts +5 -0
- package/dist/esm/plugins/namespace.js +42 -0
- package/dist/esm/plugins/notify.d.ts +2 -0
- package/{lib → dist/esm}/plugins/notify.js +90 -134
- package/dist/esm/plugins/oauthbearer.d.ts +32 -0
- package/{lib → dist/esm}/plugins/oauthbearer.js +18 -48
- package/dist/esm/plugins/objectid.d.ts +23 -0
- package/{lib → dist/esm}/plugins/objectid.js +21 -58
- package/dist/esm/plugins/partial.d.ts +6 -0
- package/{lib → dist/esm}/plugins/partial.js +7 -15
- package/dist/esm/plugins/preview.d.ts +31 -0
- package/{lib → dist/esm}/plugins/preview.js +28 -66
- package/dist/esm/plugins/qresync.d.ts +11 -0
- package/{lib → dist/esm}/plugins/qresync.js +64 -134
- package/dist/esm/plugins/quota.d.ts +18 -0
- package/{lib → dist/esm}/plugins/quota.js +89 -135
- package/dist/esm/plugins/replace.d.ts +14 -0
- package/{lib → dist/esm}/plugins/replace.js +21 -51
- package/dist/esm/plugins/sasl-ir.d.ts +5 -0
- package/{lib → dist/esm}/plugins/sasl-ir.js +3 -6
- package/dist/esm/plugins/savedate.d.ts +17 -0
- package/{lib → dist/esm}/plugins/savedate.js +5 -15
- package/dist/esm/plugins/savelimit.d.ts +10 -0
- package/{lib → dist/esm}/plugins/savelimit.js +3 -6
- package/dist/esm/plugins/searchres.d.ts +6 -0
- package/{lib → dist/esm}/plugins/searchres.js +13 -22
- package/dist/esm/plugins/sort-display.d.ts +11 -0
- package/{lib → dist/esm}/plugins/sort-display.js +6 -10
- package/dist/esm/plugins/sort.d.ts +11 -0
- package/{lib → dist/esm}/plugins/sort.js +24 -46
- package/dist/esm/plugins/special-use.d.ts +10 -0
- package/{lib → dist/esm}/plugins/special-use.js +9 -24
- package/dist/esm/plugins/starttls.d.ts +5 -0
- package/{lib → dist/esm}/plugins/starttls.js +20 -37
- package/dist/esm/plugins/status-size.d.ts +7 -0
- package/{lib → dist/esm}/plugins/status-size.js +4 -11
- package/dist/esm/plugins/thread-orderedsubject.d.ts +11 -0
- package/{lib → dist/esm}/plugins/thread-orderedsubject.js +3 -6
- package/dist/esm/plugins/thread-references.d.ts +11 -0
- package/{lib → dist/esm}/plugins/thread-references.js +3 -6
- package/dist/esm/plugins/uidonly.d.ts +15 -0
- package/{lib → dist/esm}/plugins/uidonly.js +11 -35
- package/dist/esm/plugins/uidplus.d.ts +15 -0
- package/{lib → dist/esm}/plugins/uidplus.js +25 -45
- package/dist/esm/plugins/unauthenticate.d.ts +7 -0
- package/dist/esm/plugins/unauthenticate.js +17 -0
- package/dist/esm/plugins/unselect.d.ts +5 -0
- package/dist/esm/plugins/unselect.js +21 -0
- package/dist/esm/plugins/utf8-accept.d.ts +6 -0
- package/{lib → dist/esm}/plugins/utf8-accept.js +10 -21
- package/dist/esm/plugins/x-gm-ext-1.d.ts +26 -0
- package/{lib → dist/esm}/plugins/x-gm-ext-1.js +48 -100
- package/dist/esm/plugins/xoauth2.d.ts +2 -0
- package/dist/esm/plugins/xoauth2.js +140 -0
- package/dist/esm/plugins/xtoybird.d.ts +2 -0
- package/dist/esm/plugins/xtoybird.js +218 -0
- package/dist/esm/server.d.ts +876 -0
- package/dist/esm/server.js +2543 -0
- package/dist/esm/smtp-listener.d.ts +13 -0
- package/{lib → dist/esm}/smtp-listener.js +5 -12
- package/dist/esm/sorting.d.ts +77 -0
- package/{lib → dist/esm}/sorting.js +40 -53
- package/dist/esm/threading.d.ts +30 -0
- package/{lib → dist/esm}/threading.js +29 -70
- package/dist/esm/types.d.ts +327 -0
- package/dist/esm/types.js +2 -0
- package/dist/esm/utf8-session.d.ts +17 -0
- package/{lib → dist/esm}/utf8-session.js +15 -25
- package/dist/esm/vanished.d.ts +21 -0
- package/{lib → dist/esm}/vanished.js +16 -21
- package/dist/plugin-help.json +298 -0
- package/package.json +54 -11
- package/lib/commands/capability.js +0 -47
- package/lib/commands/check.js +0 -21
- package/lib/commands/close.js +0 -30
- package/lib/commands/examine.js +0 -7
- package/lib/commands/expunge.js +0 -27
- package/lib/commands/list.js +0 -100
- package/lib/commands/logout.js +0 -41
- package/lib/commands/lsub.js +0 -87
- package/lib/commands/noop.js +0 -21
- package/lib/commands/search.js +0 -76
- package/lib/commands/select.js +0 -289
- package/lib/commands/uid copy.js +0 -7
- package/lib/commands/uid fetch.js +0 -5
- package/lib/commands/uid search.js +0 -5
- package/lib/commands/uid store.js +0 -5
- package/lib/plugins/compress.js +0 -76
- package/lib/plugins/enable.js +0 -155
- package/lib/plugins/id.js +0 -138
- package/lib/plugins/idle.js +0 -105
- package/lib/plugins/logindisabled.js +0 -50
- package/lib/plugins/metadata.js +0 -475
- package/lib/plugins/namespace.js +0 -67
- package/lib/plugins/unauthenticate.js +0 -28
- package/lib/plugins/unselect.js +0 -36
- package/lib/plugins/xoauth2.js +0 -188
- package/lib/plugins/xtoybird.js +0 -282
- package/lib/server.js +0 -2880
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @help Adds QRESYNC [RFC7162] capability, loads CONDSTORE and ENABLE as well
|
|
4
|
+
* @help After ENABLE QRESYNC: SELECT/EXAMINE (QRESYNC (...)), UID FETCH (CHANGEDSINCE n VANISHED),
|
|
5
|
+
* @help and VANISHED responses instead of EXPUNGE
|
|
6
|
+
*/
|
|
7
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
8
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
9
|
+
};
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.default = qresyncPlugin;
|
|
12
|
+
const fetch_js_1 = __importDefault(require("../commands/handlers/fetch.js"));
|
|
13
|
+
const vanished_js_1 = require("../vanished.js");
|
|
14
|
+
const numbers_js_1 = require("../numbers.js");
|
|
15
|
+
const arguments_js_1 = require("../arguments.js");
|
|
16
|
+
const enable_js_1 = require("./enable.js");
|
|
17
|
+
// commands that report expunged messages, their tagged OK carries the new HIGHESTMODSEQ (RFC 7162 sections 3.2.7
|
|
18
|
+
// and 3.2.9, RFC 6851 section 4.4). CLOSE MUST NOT (RFC 7162 section 3.2.8)
|
|
19
|
+
// REPLACE removes the replaced message as if with UID EXPUNGE (RFC 8508 section 4.5)
|
|
20
|
+
const EXPUNGING_COMMANDS = new Set(['EXPUNGE', 'UID EXPUNGE', 'MOVE', 'UID MOVE', 'REPLACE', 'UID REPLACE']);
|
|
21
|
+
function qresyncPlugin(server) {
|
|
22
|
+
server.registerCapability('QRESYNC');
|
|
23
|
+
(0, enable_js_1.registerEnable)(server, 'QRESYNC');
|
|
24
|
+
// RFC 8437 section 4.1: UNAUTHENTICATE ends what ENABLE QRESYNC enabled (the ENABLE plugin clears the list)
|
|
25
|
+
server.resetHandlers.push((connection) => {
|
|
26
|
+
connection.qresyncExpunged = false;
|
|
27
|
+
});
|
|
28
|
+
// mod-sequence each expunged message was removed with
|
|
29
|
+
const expungeModseq = new WeakMap();
|
|
30
|
+
const isQresync = (connection) => (0, enable_js_1.isEnabled)(connection, 'QRESYNC');
|
|
31
|
+
const { isEnabled: isCondstore, getHighestModseq } = server.condstore;
|
|
32
|
+
// Expunged UID ranges with their mod-sequences, oldest first (RFC 7162 section 5.3), and the mod-sequence after which
|
|
33
|
+
// all expunges are remembered. Messages missing from the initial storage were expunged at an unknown time
|
|
34
|
+
// before. The record belongs to one UIDVALIDITY, as nothing needs to be kept once it changes
|
|
35
|
+
const getExpunged = (mailbox, since) => {
|
|
36
|
+
if (!mailbox.qresyncExpunged || mailbox.qresyncExpunged.uidvalidity !== mailbox.uidvalidity) {
|
|
37
|
+
mailbox.qresyncExpunged = { uidvalidity: mailbox.uidvalidity, since: since || getHighestModseq(mailbox), list: [] };
|
|
38
|
+
}
|
|
39
|
+
return mailbox.qresyncExpunged;
|
|
40
|
+
};
|
|
41
|
+
// start remembering expunges for the mailboxes of the storage once their messages have mod-sequences
|
|
42
|
+
const indexFolders = server.indexFolders;
|
|
43
|
+
server.indexFolders = function (...args) {
|
|
44
|
+
const result = indexFolders.apply(this, args);
|
|
45
|
+
Object.keys(this.folderCache).forEach(path => getExpunged(this.folderCache[path]));
|
|
46
|
+
return result;
|
|
47
|
+
};
|
|
48
|
+
// CONDSTORE has already incremented HIGHESTMODSEQ for this removal, the expunged UIDs get that value
|
|
49
|
+
// (RFC 7162 section 3.2)
|
|
50
|
+
server.on('expunge', (mailbox, messages, connection) => {
|
|
51
|
+
const modseq = getHighestModseq(mailbox);
|
|
52
|
+
const list = getExpunged(mailbox, modseq - 1).list;
|
|
53
|
+
messages.forEach((message) => {
|
|
54
|
+
// consecutive UIDs expunged together are kept as one range, so the history stays small even in long test
|
|
55
|
+
// runs. It is never trimmed: the server keeps everything since it started (RFC 7162 section 5.3)
|
|
56
|
+
const last = list[list.length - 1];
|
|
57
|
+
if (last && last.modseq === modseq && last.to + 1 === message.uid) {
|
|
58
|
+
last.to = message.uid;
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
list.push({ from: message.uid, to: message.uid, modseq });
|
|
62
|
+
}
|
|
63
|
+
expungeModseq.set(message, modseq);
|
|
64
|
+
});
|
|
65
|
+
if (connection) {
|
|
66
|
+
connection.qresyncExpunged = true;
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
/**
|
|
70
|
+
* Lists the UIDs of a set that were expunged after a mod-sequence (RFC 7162 sections 3.2.5.1 and 3.2.6)
|
|
71
|
+
*
|
|
72
|
+
* @param {Object} mailbox Mailbox object
|
|
73
|
+
* @param {Array} messages Messages of the mailbox as the session sees them, these are not reported
|
|
74
|
+
* @param {Array} ranges Ascending UID ranges as [from, to] pairs
|
|
75
|
+
* @param {Number} modseq Mod-sequence the client knows
|
|
76
|
+
* @param {Number} [knownUpTo] The client knows about all expunges up to this UID (message sequence match data)
|
|
77
|
+
* @return {String} sequence set of the UIDs, empty if there are none
|
|
78
|
+
*/
|
|
79
|
+
const getVanished = (mailbox, messages, ranges, modseq, knownUpTo) => {
|
|
80
|
+
const { since, list } = getExpunged(mailbox);
|
|
81
|
+
let candidates;
|
|
82
|
+
if (modseq >= since) {
|
|
83
|
+
// all expunges after the client's mod-sequence are remembered. Message sequence match data only helps
|
|
84
|
+
// when they are not, so it is not used here (RFC 7162 section 5.3)
|
|
85
|
+
candidates = intersectRanges(mergeRanges(list.filter(entry => entry.modseq > modseq).map((entry) => [entry.from, entry.to])), ranges);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
// RFC 7162 section 3.2.6: for a mod-sequence older than the remembered expunges, the server MUST behave as
|
|
89
|
+
// if asked to report all expunged messages of the set: every UID below UIDNEXT that is not in the mailbox,
|
|
90
|
+
// except what the sequence match data shows the client knows
|
|
91
|
+
candidates = intersectRanges(ranges, [[(knownUpTo || 0) + 1, mailbox.uidnext - 1]]);
|
|
92
|
+
}
|
|
93
|
+
// messages the session still sees are left out, an expunge that the session has not been told about yet is
|
|
94
|
+
// reported with VANISHED without EARLIER
|
|
95
|
+
return subtractUids(candidates, messages)
|
|
96
|
+
.map(range => (range[0] === range[1] ? String(range[0]) : range[0] + ':' + range[1]))
|
|
97
|
+
.join(',');
|
|
98
|
+
};
|
|
99
|
+
const sendBad = (connection, parsed, data, callback, message) => {
|
|
100
|
+
connection.sendStatus(parsed, data, 'BAD', message, false, 'QRESYNC FAILED');
|
|
101
|
+
return callback();
|
|
102
|
+
};
|
|
103
|
+
// Wraps an existing command handler. Commands that are not available are left alone
|
|
104
|
+
const wrapHandler = (command, wrapper) => {
|
|
105
|
+
const prevHandler = server.getCommandHandler(command);
|
|
106
|
+
if (!prevHandler) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
server.setCommandHandler(command, (connection, parsed, data, callback) => wrapper(prevHandler, connection, parsed, data, callback));
|
|
110
|
+
};
|
|
111
|
+
// RFC 7162 section 3.2.5: SELECT/EXAMINE mailbox (QRESYNC (uidvalidity mod-sequence-value [known-uids] [seq-match-data]))
|
|
112
|
+
const selectWrapper = (prevHandler, connection, parsed, data, callback) => {
|
|
113
|
+
const params = parsed.attributes && parsed.attributes[1];
|
|
114
|
+
const isQresyncParam = (param) => (0, arguments_js_1.isAtom)(param, 'QRESYNC');
|
|
115
|
+
const position = Array.isArray(params) ? params.findIndex(isQresyncParam) : -1;
|
|
116
|
+
if (position < 0) {
|
|
117
|
+
return prevHandler(connection, parsed, data, callback);
|
|
118
|
+
}
|
|
119
|
+
if (!isQresync(connection)) {
|
|
120
|
+
return sendBad(connection, parsed, data, callback, 'QRESYNC parameter requires ENABLE QRESYNC');
|
|
121
|
+
}
|
|
122
|
+
if (params.findLastIndex(isQresyncParam) !== position) {
|
|
123
|
+
return sendBad(connection, parsed, data, callback, 'QRESYNC parameter can be used only once');
|
|
124
|
+
}
|
|
125
|
+
let qresync;
|
|
126
|
+
try {
|
|
127
|
+
qresync = parseQresyncParam(params[position + 1]);
|
|
128
|
+
}
|
|
129
|
+
catch (err) {
|
|
130
|
+
return sendBad(connection, parsed, data, callback, err.message);
|
|
131
|
+
}
|
|
132
|
+
params.splice(position, 2);
|
|
133
|
+
if (!params.length) {
|
|
134
|
+
parsed.attributes.splice(1, 1);
|
|
135
|
+
}
|
|
136
|
+
parsed.qresync = qresync;
|
|
137
|
+
prevHandler(connection, parsed, data, callback);
|
|
138
|
+
};
|
|
139
|
+
wrapHandler('SELECT', selectWrapper);
|
|
140
|
+
wrapHandler('EXAMINE', selectWrapper);
|
|
141
|
+
// RFC 7162 section 3.2.6: the VANISHED UID FETCH modifier
|
|
142
|
+
const fetchWrapper = (isUid, prevHandler, connection, parsed, data, callback) => {
|
|
143
|
+
const modifiers = parsed.attributes && parsed.attributes[2];
|
|
144
|
+
const isVanished = (modifier) => (0, arguments_js_1.isAtom)(modifier, 'VANISHED');
|
|
145
|
+
const position = Array.isArray(modifiers) ? modifiers.findIndex(isVanished) : -1;
|
|
146
|
+
if (position < 0) {
|
|
147
|
+
return prevHandler(connection, parsed, data, callback);
|
|
148
|
+
}
|
|
149
|
+
if (!isUid) {
|
|
150
|
+
return sendBad(connection, parsed, data, callback, 'VANISHED is only allowed with UID FETCH');
|
|
151
|
+
}
|
|
152
|
+
if (!isQresync(connection)) {
|
|
153
|
+
return sendBad(connection, parsed, data, callback, 'VANISHED requires ENABLE QRESYNC');
|
|
154
|
+
}
|
|
155
|
+
if (modifiers.findLastIndex(isVanished) !== position) {
|
|
156
|
+
return sendBad(connection, parsed, data, callback, 'VANISHED can be used only once');
|
|
157
|
+
}
|
|
158
|
+
if (!modifiers.some((modifier) => (0, arguments_js_1.isAtom)(modifier, 'CHANGEDSINCE'))) {
|
|
159
|
+
return sendBad(connection, parsed, data, callback, 'VANISHED requires CHANGEDSINCE');
|
|
160
|
+
}
|
|
161
|
+
modifiers.splice(position, 1);
|
|
162
|
+
parsed.qresyncVanished = true;
|
|
163
|
+
prevHandler(connection, parsed, data, callback);
|
|
164
|
+
};
|
|
165
|
+
wrapHandler('FETCH', fetchWrapper.bind(null, false));
|
|
166
|
+
wrapHandler('UID FETCH', fetchWrapper.bind(null, true));
|
|
167
|
+
// RFC 7162 section 3.2.10: after ENABLE QRESYNC, expunges are reported with VANISHED instead of EXPUNGE.
|
|
168
|
+
// Consecutive EXPUNGE notifications become one VANISHED response
|
|
169
|
+
server.connectionHandlers.push((connection) => {
|
|
170
|
+
const prepareNotifications = connection.prepareNotifications;
|
|
171
|
+
connection.prepareNotifications = function (queue) {
|
|
172
|
+
queue = prepareNotifications.call(this, queue);
|
|
173
|
+
return isQresync(this) ? (0, vanished_js_1.toVanished)(queue) : queue;
|
|
174
|
+
};
|
|
175
|
+
});
|
|
176
|
+
// Sends a VANISHED (EARLIER) response, if there is anything to report
|
|
177
|
+
const sendVanishedEarlier = (connection, uids, parsed, data) => {
|
|
178
|
+
if (!uids) {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
connection.send({
|
|
182
|
+
tag: '*',
|
|
183
|
+
command: 'VANISHED',
|
|
184
|
+
attributes: [[{ type: 'ATOM', value: 'EARLIER' }], { type: 'SEQUENCE', value: uids }]
|
|
185
|
+
}, 'VANISHED EARLIER', parsed, data);
|
|
186
|
+
};
|
|
187
|
+
// RFC 7162 section 3.2.5.1: after SELECT/EXAMINE (QRESYNC), expunges and flag changes since the given mod-sequence
|
|
188
|
+
const sendQresyncChanges = (connection, parsed, data) => {
|
|
189
|
+
// only called with a mailbox selected
|
|
190
|
+
const mailbox = connection.selectedMailbox;
|
|
191
|
+
const qresync = parsed.qresync;
|
|
192
|
+
if (qresync.uidvalidity !== mailbox.uidvalidity) {
|
|
193
|
+
// RFC 7162 section 3.2.5: ignore the remaining parameters if UIDVALIDITY does not match
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
// without known UIDs, the client is treated as if it sent 1:<UIDNEXT - 1>, nothing for an unused mailbox
|
|
197
|
+
const ranges = qresync.knownUids || (mailbox.uidnext > 1 ? [[1, mailbox.uidnext - 1]] : []);
|
|
198
|
+
// RFC 7162 section 3.2.5.2: the last pair of sequence number and UID that still match tells up to which
|
|
199
|
+
// UID the client knows about all expunges, the first pair that does not match ends the comparison
|
|
200
|
+
let knownUpTo = 0;
|
|
201
|
+
if (qresync.seqMatch) {
|
|
202
|
+
const uids = iterateRanges(qresync.seqMatch.uids);
|
|
203
|
+
for (const seq of iterateRanges(qresync.seqMatch.sequences)) {
|
|
204
|
+
const uid = uids.next().value;
|
|
205
|
+
const message = mailbox.messages[seq - 1];
|
|
206
|
+
if (!message || message.uid !== uid) {
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
knownUpTo = uid;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
// VANISHED (EARLIER) MUST come before the FETCH responses (RFC 7162 section 3.2.6)
|
|
213
|
+
sendVanishedEarlier(connection, getVanished(mailbox, mailbox.messages, ranges, qresync.modseq, knownUpTo), parsed, data);
|
|
214
|
+
const getFlags = server.fetchHandlers.FLAGS || fetch_js_1.default.FLAGS;
|
|
215
|
+
mailbox.messages.forEach((message, i) => {
|
|
216
|
+
if (message.MODSEQ <= qresync.modseq || !inRanges(ranges, message.uid)) {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
// flag changes MUST include the UID (RFC 7162 section 3.2.5.1)
|
|
220
|
+
connection.send({
|
|
221
|
+
tag: '*',
|
|
222
|
+
attributes: [
|
|
223
|
+
i + 1,
|
|
224
|
+
{ type: 'ATOM', value: 'FETCH' },
|
|
225
|
+
[
|
|
226
|
+
{ type: 'ATOM', value: 'UID' },
|
|
227
|
+
message.uid,
|
|
228
|
+
{ type: 'ATOM', value: 'FLAGS' },
|
|
229
|
+
getFlags(connection, message, { type: 'ATOM', value: 'FLAGS' }),
|
|
230
|
+
{ type: 'ATOM', value: 'MODSEQ' },
|
|
231
|
+
[message.MODSEQ]
|
|
232
|
+
]
|
|
233
|
+
]
|
|
234
|
+
}, 'QRESYNC FETCH', parsed, data, message);
|
|
235
|
+
});
|
|
236
|
+
};
|
|
237
|
+
const highestModseqCode = (modseq) => ({ type: 'SECTION', section: [{ type: 'ATOM', value: 'HIGHESTMODSEQ' }, modseq] });
|
|
238
|
+
server.outputHandlers.push((connection, response, description, parsed, data) => {
|
|
239
|
+
if (!parsed || !response || response.tag === '+') {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
const isTagged = response.tag !== '*' && response.tag === parsed.tag;
|
|
243
|
+
// UID FETCH (VANISHED): VANISHED (EARLIER) comes before the first FETCH response, or before the tagged OK
|
|
244
|
+
if (parsed.qresyncVanished && ((response.tag === '*' && description === 'UID FETCH') || (isTagged && response.command === 'OK'))) {
|
|
245
|
+
parsed.qresyncVanished = false;
|
|
246
|
+
// UID FETCH runs in the Selected state
|
|
247
|
+
const mailbox = connection.selectedMailbox;
|
|
248
|
+
const ranges = parseUidSet(parsed.attributes[0].value, mailbox.uidnext - 1);
|
|
249
|
+
if (ranges) {
|
|
250
|
+
sendVanishedEarlier(connection, getVanished(mailbox, connection.getSessionMessages(), ranges, parsed.changedsince), parsed, data);
|
|
251
|
+
}
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
if (!isTagged) {
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
if (parsed.qresync && response.command === 'OK' && (description === 'SELECT' || description === 'EXAMINE') && connection.selectedMailbox) {
|
|
258
|
+
sendQresyncChanges(connection, parsed, data);
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
const expunged = connection.qresyncExpunged;
|
|
262
|
+
connection.qresyncExpunged = false;
|
|
263
|
+
// HIGHESTMODSEQ in the tagged OK once messages were expunged, RFC 7162 sections 3.2.7 and 3.2.9 require it
|
|
264
|
+
// with QRESYNC enabled, RFC 6851 section 4.4 for MOVE
|
|
265
|
+
if (expunged &&
|
|
266
|
+
response.command === 'OK' &&
|
|
267
|
+
EXPUNGING_COMMANDS.has(String(parsed.command).toUpperCase()) &&
|
|
268
|
+
connection.selectedMailbox &&
|
|
269
|
+
isCondstore(connection)) {
|
|
270
|
+
const hasCode = response.attributes && response.attributes[0] && response.attributes[0].type === 'SECTION';
|
|
271
|
+
if (!hasCode) {
|
|
272
|
+
response.attributes = [highestModseqCode(getHighestModseq(connection.selectedMailbox))].concat(response.attributes || []);
|
|
273
|
+
}
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
// RFC 7162 section 3.2: while expunges are held back (FETCH, STORE, SEARCH), the client must not take a
|
|
277
|
+
// MODSEQ it got as the new HIGHESTMODSEQ, so tell it a value below the mod-sequence of the pending expunges
|
|
278
|
+
if (isCondstore(connection)) {
|
|
279
|
+
let lowest = 0;
|
|
280
|
+
connection.notificationQueue.forEach((notification) => {
|
|
281
|
+
const modseq = (0, vanished_js_1.isExpungeNotification)(notification) && notification.message && expungeModseq.get(notification.message);
|
|
282
|
+
if (modseq && (!lowest || modseq < lowest)) {
|
|
283
|
+
lowest = modseq;
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
if (lowest > 1) {
|
|
287
|
+
connection.send({
|
|
288
|
+
tag: '*',
|
|
289
|
+
command: 'OK',
|
|
290
|
+
attributes: [highestModseqCode(lowest - 1), { type: 'TEXT', value: 'Expunges not reported yet' }]
|
|
291
|
+
}, 'QRESYNC HIGHESTMODSEQ', parsed, data);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Parses a sequence set without "*" into [from, to] ranges as written
|
|
298
|
+
*
|
|
299
|
+
* @param {Object} value Parsed argument
|
|
300
|
+
* @param {String} name Name of the argument for the error message
|
|
301
|
+
* @return {Array} ranges
|
|
302
|
+
*/
|
|
303
|
+
function parseSequenceSet(value, name) {
|
|
304
|
+
if (!value || Array.isArray(value) || ['ATOM', 'SEQUENCE'].indexOf(value.type) < 0 || !(0, numbers_js_1.isSequenceSet)(value.value, true)) {
|
|
305
|
+
throw new Error('Invalid QRESYNC ' + name + ', a sequence set without "*" expected');
|
|
306
|
+
}
|
|
307
|
+
return value.value.split(',').map((part) => {
|
|
308
|
+
const range = part.split(':').map(Number);
|
|
309
|
+
return [range[0], range.length > 1 ? range[1] : range[0]];
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Parses the UID set of UID FETCH, "*" stands for the highest UID the mailbox may have used
|
|
314
|
+
*
|
|
315
|
+
* @param {String} value Sequence set
|
|
316
|
+
* @param {Number} star Value for "*"
|
|
317
|
+
* @return {Array|false} ranges ordered as [low, high], or false for other forms (e.g. "$" of SEARCHRES)
|
|
318
|
+
*/
|
|
319
|
+
function parseUidSet(value, star) {
|
|
320
|
+
if (!/^[\d*:,]+$/.test(String(value))) {
|
|
321
|
+
return false;
|
|
322
|
+
}
|
|
323
|
+
return mergeRanges(String(value)
|
|
324
|
+
.split(',')
|
|
325
|
+
.map(part => part.split(':').map(number => (number === '*' ? star : Number(number)))));
|
|
326
|
+
}
|
|
327
|
+
// Intersection of two lists of ascending, non-overlapping ranges
|
|
328
|
+
function intersectRanges(a, b) {
|
|
329
|
+
const result = [];
|
|
330
|
+
let i = 0;
|
|
331
|
+
let j = 0;
|
|
332
|
+
while (i < a.length && j < b.length) {
|
|
333
|
+
const from = Math.max(a[i][0], b[j][0]);
|
|
334
|
+
const to = Math.min(a[i][1], b[j][1]);
|
|
335
|
+
if (from <= to) {
|
|
336
|
+
result.push([from, to]);
|
|
337
|
+
}
|
|
338
|
+
if (a[i][1] < b[j][1]) {
|
|
339
|
+
i++;
|
|
340
|
+
}
|
|
341
|
+
else {
|
|
342
|
+
j++;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
return result;
|
|
346
|
+
}
|
|
347
|
+
// Removes the UIDs of messages (ordered by UID) from ascending ranges, walking both lists once
|
|
348
|
+
function subtractUids(ranges, messages) {
|
|
349
|
+
const result = [];
|
|
350
|
+
let i = 0;
|
|
351
|
+
ranges.forEach(([from, to]) => {
|
|
352
|
+
let next = from;
|
|
353
|
+
while (i < messages.length && messages[i].uid < from) {
|
|
354
|
+
i++;
|
|
355
|
+
}
|
|
356
|
+
for (; i < messages.length && messages[i].uid <= to; i++) {
|
|
357
|
+
if (messages[i].uid > next) {
|
|
358
|
+
result.push([next, messages[i].uid - 1]);
|
|
359
|
+
}
|
|
360
|
+
next = messages[i].uid + 1;
|
|
361
|
+
}
|
|
362
|
+
if (next <= to) {
|
|
363
|
+
result.push([next, to]);
|
|
364
|
+
}
|
|
365
|
+
});
|
|
366
|
+
return result;
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Orders the ends of every range and merges overlapping or adjacent ranges, so that a UID is listed once
|
|
370
|
+
*
|
|
371
|
+
* @param {Array} ranges List of [from, to] or [number] ranges
|
|
372
|
+
* @return {Array} ascending [low, high] ranges
|
|
373
|
+
*/
|
|
374
|
+
function mergeRanges(ranges) {
|
|
375
|
+
const sorted = ranges.map((range) => [Math.min(...range), Math.max(...range)]).sort((a, b) => a[0] - b[0]);
|
|
376
|
+
const result = [];
|
|
377
|
+
sorted.forEach(range => {
|
|
378
|
+
const last = result[result.length - 1];
|
|
379
|
+
if (last && range[0] <= last[1] + 1) {
|
|
380
|
+
last[1] = Math.max(last[1], range[1]);
|
|
381
|
+
}
|
|
382
|
+
else {
|
|
383
|
+
result.push(range);
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
return result;
|
|
387
|
+
}
|
|
388
|
+
// Lists the numbers of ascending ranges one by one
|
|
389
|
+
function* iterateRanges(ranges) {
|
|
390
|
+
for (const [from, to] of ranges) {
|
|
391
|
+
for (let i = from; i <= to; i++) {
|
|
392
|
+
yield i;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Checks that a sequence set lists its numbers in ascending order and counts them
|
|
398
|
+
*/
|
|
399
|
+
function countAscending(ranges, name) {
|
|
400
|
+
let last = 0;
|
|
401
|
+
let count = 0;
|
|
402
|
+
ranges.forEach(([from, to]) => {
|
|
403
|
+
if (from > to || from <= last) {
|
|
404
|
+
throw new Error('Invalid QRESYNC ' + name + ', numbers must be in ascending order');
|
|
405
|
+
}
|
|
406
|
+
last = to;
|
|
407
|
+
count += to - from + 1;
|
|
408
|
+
});
|
|
409
|
+
return count;
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Validates the value of the QRESYNC SELECT/EXAMINE parameter (RFC 7162 section 7):
|
|
413
|
+
* "(" uidvalidity SP mod-sequence-value [SP known-uids] [SP seq-match-data] ")"
|
|
414
|
+
*
|
|
415
|
+
* @param {Array} value Parsed parameter value
|
|
416
|
+
* @return {Object} `{ uidvalidity, modseq, knownUids, seqMatch }`
|
|
417
|
+
*/
|
|
418
|
+
function parseQresyncParam(value) {
|
|
419
|
+
if (!Array.isArray(value) || value.length < 2 || value.length > 4) {
|
|
420
|
+
throw new Error('QRESYNC expects (uidvalidity modseq [known-uids] [(known-sequence-set known-uid-set)])');
|
|
421
|
+
}
|
|
422
|
+
const [uidvalidity, modseq] = value;
|
|
423
|
+
// uidvalidity = nz-number
|
|
424
|
+
if (!(0, arguments_js_1.isAtom)(uidvalidity) || !(0, numbers_js_1.isNzNumber)(uidvalidity.value)) {
|
|
425
|
+
throw new Error('Invalid QRESYNC uidvalidity, a non-zero number expected');
|
|
426
|
+
}
|
|
427
|
+
// mod-sequence-value = 1*DIGIT, 1 <= n <= 9,223,372,036,854,775,807
|
|
428
|
+
if (!(0, arguments_js_1.isAtom)(modseq) || !(0, numbers_js_1.isNumber)(modseq.value, numbers_js_1.MAX_NUMBER64) || BigInt(modseq.value) < 1n) {
|
|
429
|
+
throw new Error('Invalid QRESYNC mod-sequence, a positive number expected');
|
|
430
|
+
}
|
|
431
|
+
const result = {
|
|
432
|
+
uidvalidity: Number(uidvalidity.value),
|
|
433
|
+
modseq: Number(modseq.value),
|
|
434
|
+
knownUids: false,
|
|
435
|
+
seqMatch: false
|
|
436
|
+
};
|
|
437
|
+
const rest = value.slice(2);
|
|
438
|
+
if (rest.length && !Array.isArray(rest[0])) {
|
|
439
|
+
result.knownUids = mergeRanges(parseSequenceSet(rest.shift(), 'known-uids'));
|
|
440
|
+
}
|
|
441
|
+
if (rest.length) {
|
|
442
|
+
const seqMatch = rest.shift();
|
|
443
|
+
if (!Array.isArray(seqMatch) || seqMatch.length !== 2 || rest.length) {
|
|
444
|
+
throw new Error('Invalid QRESYNC parameters, (known-sequence-set known-uid-set) expected last');
|
|
445
|
+
}
|
|
446
|
+
// RFC 7162 section 3.2.5.2: both sets MUST be in ascending order, the Nth number of one matches the Nth of the other
|
|
447
|
+
const sequences = parseSequenceSet(seqMatch[0], 'known-sequence-set');
|
|
448
|
+
const uids = parseSequenceSet(seqMatch[1], 'known-uid-set');
|
|
449
|
+
const count = countAscending(sequences, 'known-sequence-set');
|
|
450
|
+
if (countAscending(uids, 'known-uid-set') !== count) {
|
|
451
|
+
throw new Error('Invalid QRESYNC sets, known-sequence-set and known-uid-set must have as many numbers');
|
|
452
|
+
}
|
|
453
|
+
result.seqMatch = { sequences, uids };
|
|
454
|
+
}
|
|
455
|
+
return result;
|
|
456
|
+
}
|
|
457
|
+
function inRanges(ranges, uid) {
|
|
458
|
+
return ranges.some(range => uid >= range[0] && uid <= range[1]);
|
|
459
|
+
}
|
|
460
|
+
// RFC 7162 section 3.2.3: a QRESYNC server implements CONDSTORE and ENABLE, these are loaded first
|
|
461
|
+
qresyncPlugin.requires = ['ENABLE', 'CONDSTORE'];
|
|
462
|
+
{
|
|
463
|
+
const defaultExport = exports.default;
|
|
464
|
+
if (defaultExport && (typeof defaultExport === 'function' || typeof defaultExport === 'object')) {
|
|
465
|
+
for (const key of Object.keys(exports)) {
|
|
466
|
+
if (key !== 'default' && !(key in defaultExport)) {
|
|
467
|
+
defaultExport[key] = exports[key];
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
Object.defineProperty(defaultExport, 'default', { value: defaultExport, enumerable: false, writable: true, configurable: true });
|
|
471
|
+
module.exports = defaultExport;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { IMAPServer } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* @help Adds QUOTA [RFC9208] capability with the STORAGE, MESSAGE and MAILBOX
|
|
4
|
+
* @help resources and SETQUOTA. All personal mailboxes share one quota root, set
|
|
5
|
+
* @help with the "quota" server option, eg. {"root": "User quota",
|
|
6
|
+
* @help "STORAGE": 10240, "MESSAGE": 1000, "MAILBOX": 100, "soft": false}.
|
|
7
|
+
* @help STORAGE is in units of 1024 octets. Hard limits make APPEND, COPY, MOVE
|
|
8
|
+
* @help and CREATE fail with NO [OVERQUOTA], soft limits only send a warning
|
|
9
|
+
*
|
|
10
|
+
* QUOTA: https://www.rfc-editor.org/rfc/rfc9208.txt
|
|
11
|
+
*
|
|
12
|
+
* Additional commands:
|
|
13
|
+
* - GETQUOTA, GETQUOTAROOT, SETQUOTA
|
|
14
|
+
*
|
|
15
|
+
* Additional STATUS items:
|
|
16
|
+
* - DELETED, DELETED-STORAGE
|
|
17
|
+
*/
|
|
18
|
+
export default function quotaPlugin(server: IMAPServer): void;
|