imapkit 4.0.3 → 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 +33 -74
- 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,202 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.default = oauthbearerPlugin;
|
|
4
|
+
exports.parseClientResponse = parseClientResponse;
|
|
5
|
+
/**
|
|
6
|
+
* @help Adds AUTH=OAUTHBEARER [RFC7628] capability
|
|
7
|
+
* @help Works with and without SASL-IR [RFC4959]
|
|
8
|
+
* @help Valid login info, same as for XOAUTH2:
|
|
9
|
+
* @help Username (authzid, optional): testuser
|
|
10
|
+
* @help Access Token: testtoken
|
|
11
|
+
*/
|
|
12
|
+
const KVSEP = '\x01';
|
|
13
|
+
const utf8 = new TextDecoder('utf-8', { fatal: true });
|
|
14
|
+
/**
|
|
15
|
+
* Parses an OAUTHBEARER client response (RFC 7628 section 3.1)
|
|
16
|
+
*
|
|
17
|
+
* client-resp = (gs2-header kvsep *kvpair kvsep) / kvsep
|
|
18
|
+
* kvpair = key "=" value kvsep
|
|
19
|
+
* key = 1*(ALPHA)
|
|
20
|
+
* value = *(VCHAR / SP / HTAB / CR / LF)
|
|
21
|
+
*
|
|
22
|
+
* and its GS2 header (RFC 5801 section 4)
|
|
23
|
+
*
|
|
24
|
+
* gs2-header = [gs2-nonstd-flag ","] gs2-cb-flag "," [gs2-authzid] ","
|
|
25
|
+
* gs2-cb-flag = ("p=" cb-name) / "n" / "y"
|
|
26
|
+
* gs2-authzid = "a=" saslname
|
|
27
|
+
*
|
|
28
|
+
* @param {Buffer} input Decoded client response
|
|
29
|
+
* @return {Object} `{ kvsepOnly }`, `{ error }` when the response breaks the grammar, or
|
|
30
|
+
* `{ channelBinding, authzid, pairs }` where pairs maps keys to values
|
|
31
|
+
*/
|
|
32
|
+
function parseClientResponse(input) {
|
|
33
|
+
const str = input.toString('binary');
|
|
34
|
+
if (str === KVSEP) {
|
|
35
|
+
return { kvsepOnly: true };
|
|
36
|
+
}
|
|
37
|
+
const header = str.match(/^(?:F,)?(n|y|p=[A-Za-z0-9.-]+),(?:a=([^,]+))?,/);
|
|
38
|
+
if (!header || str.charAt(header[0].length) !== KVSEP) {
|
|
39
|
+
return { error: 'Invalid GS2 header' };
|
|
40
|
+
}
|
|
41
|
+
let authzid = false;
|
|
42
|
+
if (header[2]) {
|
|
43
|
+
// saslname: "," and "=" are only allowed as "=2C" and "=3D", NUL is not allowed
|
|
44
|
+
if (/=(?!2C|3D)/.test(header[2]) || header[2].includes('\x00')) {
|
|
45
|
+
return { error: 'Invalid authorization identity' };
|
|
46
|
+
}
|
|
47
|
+
try {
|
|
48
|
+
authzid = utf8.decode(Buffer.from(header[2].replace(/=2C/g, ',').replace(/=3D/g, '='), 'binary'));
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return { error: 'Invalid UTF-8 in the authorization identity' };
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// *kvpair kvsep: every pair ends with a kvsep of its own, so the split ends with two empty parts
|
|
55
|
+
const parts = str.substr(header[0].length + 1).split(KVSEP);
|
|
56
|
+
if (parts.pop() !== '' || parts.pop() !== '') {
|
|
57
|
+
return { error: 'The client response must end with %x01' };
|
|
58
|
+
}
|
|
59
|
+
const pairs = Object.create(null);
|
|
60
|
+
for (const pair of parts) {
|
|
61
|
+
const match = pair.match(/^([A-Za-z]+)=([\x20-\x7e\t\r\n]*)$/);
|
|
62
|
+
if (!match) {
|
|
63
|
+
return { error: 'Invalid key/value pair' };
|
|
64
|
+
}
|
|
65
|
+
pairs[match[1]] = match[2];
|
|
66
|
+
}
|
|
67
|
+
return { channelBinding: header[1].charAt(0) === 'p', authzid, pairs };
|
|
68
|
+
}
|
|
69
|
+
function oauthbearerPlugin(server) {
|
|
70
|
+
server.registerCapability('AUTH=OAUTHBEARER', (connection) => connection.state === 'Not Authenticated');
|
|
71
|
+
const fail = (connection, parsed, data, command, text) => {
|
|
72
|
+
// RFC 5530 section 3: a rejected login is AUTHENTICATIONFAILED
|
|
73
|
+
connection.sendStatus(parsed, data, command, text, command === 'NO' && 'AUTHENTICATIONFAILED', 'AUTHENTICATE OAUTHBEARER FAILED');
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* Checks the client response. Returns the OAuth error status (RFC 6750 section 3.1) if the
|
|
77
|
+
* credentials are not accepted, or false if the user is logged in
|
|
78
|
+
*/
|
|
79
|
+
const checkCredentials = (request) => {
|
|
80
|
+
if (request.channelBinding) {
|
|
81
|
+
// RFC 5801 section 5: "p" asks for channel binding, which this mechanism does not support
|
|
82
|
+
return 'invalid_request';
|
|
83
|
+
}
|
|
84
|
+
const { auth, port } = request.pairs;
|
|
85
|
+
// port: a decimal positive integer string without leading zeros (RFC 7628 section 3.1)
|
|
86
|
+
if (typeof port === 'string' && !/^[1-9][0-9]*$/.test(port)) {
|
|
87
|
+
return 'invalid_request';
|
|
88
|
+
}
|
|
89
|
+
// RFC 6750 section 2.1: "Bearer" 1*SP b64token, the scheme name is case insensitive
|
|
90
|
+
const bearer = typeof auth === 'string' && auth.match(/^Bearer +([A-Za-z0-9\-._~+/]+=*)$/i);
|
|
91
|
+
if (!bearer) {
|
|
92
|
+
// an empty auth value is how a client asks for the error details (RFC 7628 section 4.3)
|
|
93
|
+
return auth === '' ? 'invalid_token' : 'invalid_request';
|
|
94
|
+
}
|
|
95
|
+
const token = bearer[1];
|
|
96
|
+
let username = request.authzid;
|
|
97
|
+
if (username === false) {
|
|
98
|
+
// without an authzid the token tells who the user is
|
|
99
|
+
username = Object.keys(server.users).find(name => {
|
|
100
|
+
const user = server.users[name];
|
|
101
|
+
return user && user.xoauth2 && user.xoauth2.accessToken === token;
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
const user = server.getUser(username);
|
|
105
|
+
if (!user || !user.xoauth2 || user.xoauth2.accessToken !== token) {
|
|
106
|
+
return 'invalid_token';
|
|
107
|
+
}
|
|
108
|
+
request.username = username;
|
|
109
|
+
return false;
|
|
110
|
+
};
|
|
111
|
+
// Decodes a base64 client response, sends BAD and returns false if it is not valid base64
|
|
112
|
+
const decode = (connection, parsed, data, input) => {
|
|
113
|
+
const decoded = connection.decodeSaslResponse(input);
|
|
114
|
+
if (!decoded) {
|
|
115
|
+
fail(connection, parsed, data, 'BAD', 'Invalid base64 in SASL response');
|
|
116
|
+
}
|
|
117
|
+
return decoded;
|
|
118
|
+
};
|
|
119
|
+
// Waits for the next client response line. "*" cancels the exchange, which RFC 3501 section 6.2.2
|
|
120
|
+
// answers with BAD
|
|
121
|
+
const readResponse = (connection, parsed, data, onResponse) => {
|
|
122
|
+
connection.inputHandler = (line) => {
|
|
123
|
+
connection.inputHandler = false;
|
|
124
|
+
if (line === '*') {
|
|
125
|
+
return fail(connection, parsed, data, 'BAD', 'Authentication cancelled');
|
|
126
|
+
}
|
|
127
|
+
const decoded = decode(connection, parsed, data, line);
|
|
128
|
+
if (decoded) {
|
|
129
|
+
onResponse(decoded);
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
};
|
|
133
|
+
// Handles the decoded client response, sent with SASL-IR or after the empty continuation request
|
|
134
|
+
const authenticate = (connection, parsed, data, decoded) => {
|
|
135
|
+
const request = parseClientResponse(decoded);
|
|
136
|
+
if (request.error) {
|
|
137
|
+
return fail(connection, parsed, data, 'BAD', request.error + ' in the OAUTHBEARER client response');
|
|
138
|
+
}
|
|
139
|
+
if (request.kvsepOnly) {
|
|
140
|
+
// RFC 7628 section 3.1: as the first message the server may fail without discovery information
|
|
141
|
+
return fail(connection, parsed, data, 'NO', 'SASL authentication failed');
|
|
142
|
+
}
|
|
143
|
+
const status = checkCredentials(request);
|
|
144
|
+
if (!status) {
|
|
145
|
+
connection.state = 'Authenticated';
|
|
146
|
+
connection.username = request.username;
|
|
147
|
+
return connection.sendStatus(parsed, data, 'OK', 'SASL authentication succeeded', false, 'AUTHENTICATE OAUTHBEARER SUCCESS');
|
|
148
|
+
}
|
|
149
|
+
// RFC 7628 section 3.2.2: the error result is a JSON document in a continuation request, the
|
|
150
|
+
// client MUST answer with a single %x01 or cancel, and the server then fails the exchange
|
|
151
|
+
readResponse(connection, parsed, data, (response) => {
|
|
152
|
+
if (response.toString('binary') !== KVSEP) {
|
|
153
|
+
return fail(connection, parsed, data, 'BAD', 'The client must answer the error result with a single %x01 (RFC 7628 section 3.2.3)');
|
|
154
|
+
}
|
|
155
|
+
fail(connection, parsed, data, 'NO', 'SASL authentication failed');
|
|
156
|
+
});
|
|
157
|
+
connection.send({
|
|
158
|
+
tag: '+',
|
|
159
|
+
attributes: [
|
|
160
|
+
{
|
|
161
|
+
type: 'ATOM',
|
|
162
|
+
value: Buffer.from(JSON.stringify({ status })).toString('base64')
|
|
163
|
+
}
|
|
164
|
+
]
|
|
165
|
+
}, 'AUTHENTICATE OAUTHBEARER CHALLENGE', parsed, data);
|
|
166
|
+
};
|
|
167
|
+
server.setCommandHandler('AUTHENTICATE OAUTHBEARER', (connection, parsed, data, callback) => {
|
|
168
|
+
const args = parsed.attributes || [];
|
|
169
|
+
if (!args.length) {
|
|
170
|
+
// without an initial response the client sends its response after an empty challenge
|
|
171
|
+
readResponse(connection, parsed, data, decoded => authenticate(connection, parsed, data, decoded));
|
|
172
|
+
connection.write('+ \r\n');
|
|
173
|
+
return callback();
|
|
174
|
+
}
|
|
175
|
+
if (args.length !== 1 || !args[0] || args[0].type !== 'ATOM') {
|
|
176
|
+
fail(connection, parsed, data, 'BAD', 'Invalid arguments for AUTHENTICATE OAUTHBEARER');
|
|
177
|
+
return callback();
|
|
178
|
+
}
|
|
179
|
+
// RFC 4959 section 3: an initial response is only allowed when SASL-IR is advertised
|
|
180
|
+
if (!server.capabilities['SASL-IR'] || !server.capabilities['SASL-IR'](connection)) {
|
|
181
|
+
fail(connection, parsed, data, 'BAD', 'SASL-IR must be enabled to send Initial Response with the request');
|
|
182
|
+
return callback();
|
|
183
|
+
}
|
|
184
|
+
const decoded = decode(connection, parsed, data, args[0].value);
|
|
185
|
+
if (decoded) {
|
|
186
|
+
authenticate(connection, parsed, data, decoded);
|
|
187
|
+
}
|
|
188
|
+
return callback();
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
{
|
|
192
|
+
const defaultExport = exports.default;
|
|
193
|
+
if (defaultExport && (typeof defaultExport === 'function' || typeof defaultExport === 'object')) {
|
|
194
|
+
for (const key of Object.keys(exports)) {
|
|
195
|
+
if (key !== 'default' && !(key in defaultExport)) {
|
|
196
|
+
defaultExport[key] = exports[key];
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
Object.defineProperty(defaultExport, 'default', { value: defaultExport, enumerable: false, writable: true, configurable: true });
|
|
200
|
+
module.exports = defaultExport;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { IMAPServer } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* @help Adds OBJECTID [RFC8474] capability
|
|
4
|
+
* @help MAILBOXID, EMAILID and THREADID values are generated (F1, M1, T1, ...)
|
|
5
|
+
* @help unless storage sets them for a mailbox ("MAILBOXID") or a message
|
|
6
|
+
* @help ("EMAILID", "THREADID"). Messages are threaded by their Message-ID,
|
|
7
|
+
* @help In-Reply-To and References headers across all mailboxes
|
|
8
|
+
*
|
|
9
|
+
* OBJECTID: https://www.rfc-editor.org/rfc/rfc8474.txt
|
|
10
|
+
*
|
|
11
|
+
* Additional response codes:
|
|
12
|
+
* - MAILBOXID for CREATE, SELECT and EXAMINE
|
|
13
|
+
*
|
|
14
|
+
* Additional STATUS items:
|
|
15
|
+
* - MAILBOXID
|
|
16
|
+
*
|
|
17
|
+
* Additional FETCH items:
|
|
18
|
+
* - EMAILID, THREADID
|
|
19
|
+
*
|
|
20
|
+
* Additional SEARCH keys:
|
|
21
|
+
* - EMAILID, THREADID
|
|
22
|
+
*/
|
|
23
|
+
export default function objectidPlugin(server: IMAPServer): void;
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.default = objectidPlugin;
|
|
4
|
+
const search_js_1 = require("../commands/handlers/search.js");
|
|
5
|
+
// RFC 8474 section 7: objectid = 1*255(ALPHA / DIGIT / "_" / "-"), case sensitive
|
|
6
|
+
const OBJECTID = /^[A-Za-z0-9_-]{1,255}$/;
|
|
7
|
+
// header fields that threading uses, in an unfolded header
|
|
8
|
+
const MESSAGE_ID_HEADER = /^Message-ID[ \t]*:(.*)$/im;
|
|
9
|
+
const REFERENCES_HEADER = /^References[ \t]*:(.*)$/im;
|
|
10
|
+
const IN_REPLY_TO_HEADER = /^In-Reply-To[ \t]*:(.*)$/im;
|
|
11
|
+
// uidvalidity a MAILBOXID was assigned for
|
|
12
|
+
const ASSIGNED_FOR = Symbol('mailboxid-uidvalidity');
|
|
13
|
+
/**
|
|
14
|
+
* @help Adds OBJECTID [RFC8474] capability
|
|
15
|
+
* @help MAILBOXID, EMAILID and THREADID values are generated (F1, M1, T1, ...)
|
|
16
|
+
* @help unless storage sets them for a mailbox ("MAILBOXID") or a message
|
|
17
|
+
* @help ("EMAILID", "THREADID"). Messages are threaded by their Message-ID,
|
|
18
|
+
* @help In-Reply-To and References headers across all mailboxes
|
|
19
|
+
*
|
|
20
|
+
* OBJECTID: https://www.rfc-editor.org/rfc/rfc8474.txt
|
|
21
|
+
*
|
|
22
|
+
* Additional response codes:
|
|
23
|
+
* - MAILBOXID for CREATE, SELECT and EXAMINE
|
|
24
|
+
*
|
|
25
|
+
* Additional STATUS items:
|
|
26
|
+
* - MAILBOXID
|
|
27
|
+
*
|
|
28
|
+
* Additional FETCH items:
|
|
29
|
+
* - EMAILID, THREADID
|
|
30
|
+
*
|
|
31
|
+
* Additional SEARCH keys:
|
|
32
|
+
* - EMAILID, THREADID
|
|
33
|
+
*/
|
|
34
|
+
function objectidPlugin(server) {
|
|
35
|
+
server.registerCapability('OBJECTID');
|
|
36
|
+
// kind (F, M or T) of every value ever used, generated values must not collide with them
|
|
37
|
+
const used = new Map();
|
|
38
|
+
const counters = { F: 0, M: 0, T: 0 };
|
|
39
|
+
// current owner of each MAILBOXID, RFC 8474 section 4: never two mailboxes at the same time
|
|
40
|
+
const mailboxOwners = new Map();
|
|
41
|
+
// THREADID by EMAILID, RFC 8474 section 5.2: the same EMAILID always has the same THREADID
|
|
42
|
+
const emailThreads = new Map();
|
|
43
|
+
// THREADID by Message-ID, for threading
|
|
44
|
+
const messageIdThreads = new Map();
|
|
45
|
+
// RFC 8474 section 8.1: the prefix keeps generated ids from starting with a digit or a dash
|
|
46
|
+
const generate = (prefix) => {
|
|
47
|
+
let id;
|
|
48
|
+
do {
|
|
49
|
+
id = prefix + ++counters[prefix];
|
|
50
|
+
} while (used.has(id));
|
|
51
|
+
used.set(id, prefix);
|
|
52
|
+
return id;
|
|
53
|
+
};
|
|
54
|
+
const checkValue = (value, what, owner) => {
|
|
55
|
+
if (typeof value !== 'string' || !OBJECTID.test(value)) {
|
|
56
|
+
throw new Error('Invalid ' + what + ' value ' + JSON.stringify(value) + ' in ' + owner);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
// RFC 8474 section 5.2: an id is used for one kind of object only
|
|
60
|
+
const checkUnique = (value, prefix) => {
|
|
61
|
+
if (used.has(value) && used.get(value) !== prefix) {
|
|
62
|
+
throw new Error('Object identifier ' + JSON.stringify(value) + ' is already used for another kind of object');
|
|
63
|
+
}
|
|
64
|
+
used.set(value, prefix);
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Returns the MAILBOXID of a mailbox. A mailbox that got a new UIDVALIDITY (re-created after
|
|
68
|
+
* DELETE) is a new mailbox and gets a new id (RFC 8474 section 4)
|
|
69
|
+
*/
|
|
70
|
+
const getMailboxId = (mailbox) => {
|
|
71
|
+
if (mailbox[ASSIGNED_FOR] === mailbox.uidvalidity && mailboxOwners.get(mailbox.MAILBOXID) === mailbox) {
|
|
72
|
+
return mailbox.MAILBOXID;
|
|
73
|
+
}
|
|
74
|
+
let id;
|
|
75
|
+
if (mailbox.MAILBOXID && mailbox[ASSIGNED_FOR] === undefined && !mailboxOwners.has(mailbox.MAILBOXID)) {
|
|
76
|
+
// value from storage
|
|
77
|
+
id = mailbox.MAILBOXID;
|
|
78
|
+
checkValue(id, 'MAILBOXID', 'mailbox ' + mailbox.path);
|
|
79
|
+
checkUnique(id, 'F');
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
// a new mailbox, or a copy of a deleted one (a \Noselect placeholder that is created again)
|
|
83
|
+
id = generate('F');
|
|
84
|
+
}
|
|
85
|
+
mailbox.MAILBOXID = id;
|
|
86
|
+
mailbox[ASSIGNED_FOR] = mailbox.uidvalidity;
|
|
87
|
+
mailboxOwners.set(id, mailbox);
|
|
88
|
+
return id;
|
|
89
|
+
};
|
|
90
|
+
// Assign ids when mailboxes are loaded or created. A \Noselect placeholder is not a mailbox
|
|
91
|
+
server.mailboxHandlers.push((server, mailbox) => {
|
|
92
|
+
if (mailbox.flags.indexOf('\\Noselect') >= 0) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (mailbox.MAILBOXID && mailbox[ASSIGNED_FOR] === undefined && mailboxOwners.has(mailbox.MAILBOXID)) {
|
|
96
|
+
// two mailboxes in storage with the same id
|
|
97
|
+
throw new Error('Duplicate MAILBOXID value ' + JSON.stringify(mailbox.MAILBOXID) + ' in mailbox ' + mailbox.path);
|
|
98
|
+
}
|
|
99
|
+
getMailboxId(mailbox);
|
|
100
|
+
});
|
|
101
|
+
server.messageHandlers.push((server, message, mailbox) => {
|
|
102
|
+
const owner = 'a message of mailbox ' + mailbox.path;
|
|
103
|
+
if (message.EMAILID) {
|
|
104
|
+
checkValue(message.EMAILID, 'EMAILID', owner);
|
|
105
|
+
checkUnique(message.EMAILID, 'M');
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
message.EMAILID = generate('M');
|
|
109
|
+
}
|
|
110
|
+
if (message.THREADID) {
|
|
111
|
+
checkValue(message.THREADID, 'THREADID', owner);
|
|
112
|
+
checkUnique(message.THREADID, 'T');
|
|
113
|
+
}
|
|
114
|
+
const threadOfEmail = emailThreads.get(message.EMAILID);
|
|
115
|
+
if (threadOfEmail && message.THREADID && message.THREADID !== threadOfEmail) {
|
|
116
|
+
throw new Error('Messages with EMAILID ' + JSON.stringify(message.EMAILID) + ' must have the same THREADID');
|
|
117
|
+
}
|
|
118
|
+
const ids = getThreadingIds(message.raw);
|
|
119
|
+
message.THREADID = message.THREADID || threadOfEmail || findThread(ids.references) || generate('T');
|
|
120
|
+
emailThreads.set(message.EMAILID, message.THREADID);
|
|
121
|
+
// later replies, and later messages with a common parent, join this thread
|
|
122
|
+
[ids.messageId].concat(ids.references).forEach(id => {
|
|
123
|
+
if (id && !messageIdThreads.has(id)) {
|
|
124
|
+
messageIdThreads.set(id, message.THREADID);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
// the nearest known parent decides the thread
|
|
129
|
+
const findThread = (references) => {
|
|
130
|
+
for (let i = references.length - 1; i >= 0; i--) {
|
|
131
|
+
if (messageIdThreads.has(references[i])) {
|
|
132
|
+
return messageIdThreads.get(references[i]);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return false;
|
|
136
|
+
};
|
|
137
|
+
// RFC 8474 section 5.1: the copy in the COPYUID pairing has the EMAILID of the source, after COPY as well as after MOVE
|
|
138
|
+
server.copyHandlers.push((server, source, copy) => {
|
|
139
|
+
if (source.EMAILID) {
|
|
140
|
+
copy.EMAILID = source.EMAILID;
|
|
141
|
+
copy.THREADID = source.THREADID;
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
// RFC 8474 section 4.3
|
|
145
|
+
server.allowedStatus.push('MAILBOXID');
|
|
146
|
+
server.statusHandlers.MAILBOXID = (connection, mailbox) => [{ type: 'ATOM', value: getMailboxId(mailbox) }];
|
|
147
|
+
// RFC 8474 section 5.3
|
|
148
|
+
server.fetchHandlers.EMAILID = (connection, message) => [{ type: 'ATOM', value: message.EMAILID }];
|
|
149
|
+
server.fetchHandlers.THREADID = (connection, message) => [{ type: 'ATOM', value: message.THREADID }];
|
|
150
|
+
// RFC 8474 section 6: search-key =/ "EMAILID" SP objectid / "THREADID" SP objectid
|
|
151
|
+
const objectIdArgument = (value) => {
|
|
152
|
+
if (!OBJECTID.test(value)) {
|
|
153
|
+
throw (0, search_js_1.badError)('Invalid object identifier');
|
|
154
|
+
}
|
|
155
|
+
return value;
|
|
156
|
+
};
|
|
157
|
+
const searchHandler = (name) => {
|
|
158
|
+
const handler = (connection, message, index, value) => message[name] === value;
|
|
159
|
+
handler.argumentTypes = () => [objectIdArgument];
|
|
160
|
+
server.searchHandlers[name] = handler;
|
|
161
|
+
};
|
|
162
|
+
searchHandler('EMAILID');
|
|
163
|
+
searchHandler('THREADID');
|
|
164
|
+
// resp-text-code =/ "MAILBOXID" SP "(" objectid ")"
|
|
165
|
+
const mailboxIdCode = (mailbox) => ({
|
|
166
|
+
type: 'SECTION',
|
|
167
|
+
section: [{ type: 'ATOM', value: 'MAILBOXID' }, [{ type: 'ATOM', value: getMailboxId(mailbox) }]]
|
|
168
|
+
});
|
|
169
|
+
server.outputHandlers.push((connection, response, description, parsed, data, extra) => {
|
|
170
|
+
// RFC 8474 section 4.1: MAILBOXID response code in the tagged OK of CREATE
|
|
171
|
+
if (description === 'CREATE' && response.command === 'OK' && extra) {
|
|
172
|
+
response.attributes = [mailboxIdCode(extra)].concat(response.attributes || []);
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
// RFC 8474 section 4.2: untagged OK with MAILBOXID on every successful SELECT and EXAMINE
|
|
176
|
+
if ((description === 'SELECT' || description === 'EXAMINE') &&
|
|
177
|
+
parsed &&
|
|
178
|
+
response.tag === parsed.tag &&
|
|
179
|
+
response.command === 'OK' &&
|
|
180
|
+
connection.selectedMailbox) {
|
|
181
|
+
connection.send({
|
|
182
|
+
tag: '*',
|
|
183
|
+
command: 'OK',
|
|
184
|
+
attributes: [mailboxIdCode(connection.selectedMailbox), { type: 'TEXT', value: 'Ok' }]
|
|
185
|
+
}, description + ' MAILBOXID', parsed, data);
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Reads the message ids that threading uses from the header of a message
|
|
191
|
+
*
|
|
192
|
+
* @param {String} raw Message source
|
|
193
|
+
* @return {Object} `{ messageId, references }`, references lists the ids of References and In-Reply-To, the parent last
|
|
194
|
+
*/
|
|
195
|
+
function getThreadingIds(raw) {
|
|
196
|
+
raw = raw || '';
|
|
197
|
+
const end = raw.search(/\r?\n\r?\n/);
|
|
198
|
+
// unfolded header lines
|
|
199
|
+
const header = (end >= 0 ? raw.substr(0, end) : raw).replace(/\r?\n(?=[ \t])/g, '');
|
|
200
|
+
const getIds = (regex) => {
|
|
201
|
+
const match = header.match(regex);
|
|
202
|
+
return match ? match[1].match(/<[^<>\s]+>/g) || [] : [];
|
|
203
|
+
};
|
|
204
|
+
return {
|
|
205
|
+
messageId: getIds(MESSAGE_ID_HEADER)[0] || false,
|
|
206
|
+
// In-Reply-To names the parent, which is also the last entry of References
|
|
207
|
+
references: getIds(REFERENCES_HEADER).concat(getIds(IN_REPLY_TO_HEADER))
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
{
|
|
211
|
+
const defaultExport = exports.default;
|
|
212
|
+
if (defaultExport && (typeof defaultExport === 'function' || typeof defaultExport === 'object')) {
|
|
213
|
+
for (const key of Object.keys(exports)) {
|
|
214
|
+
if (key !== 'default' && !(key in defaultExport)) {
|
|
215
|
+
defaultExport[key] = exports[key];
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
Object.defineProperty(defaultExport, 'default', { value: defaultExport, enumerable: false, writable: true, configurable: true });
|
|
219
|
+
module.exports = defaultExport;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @help Adds PARTIAL [RFC9394] capability, loads ESEARCH as well
|
|
3
|
+
* @help SEARCH RETURN (PARTIAL 1:100) or (PARTIAL -1:-100) returns a window of the results, FETCH and UID FETCH take a PARTIAL modifier
|
|
4
|
+
*/
|
|
5
|
+
import type { IMAPServer } from '../types.js';
|
|
6
|
+
export default function partialPlugin(server: IMAPServer): void;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @help Adds PARTIAL [RFC9394] capability, loads ESEARCH as well
|
|
4
|
+
* @help SEARCH RETURN (PARTIAL 1:100) or (PARTIAL -1:-100) returns a window of the results, FETCH and UID FETCH take a PARTIAL modifier
|
|
5
|
+
*/
|
|
6
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
+
};
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.default = partialPlugin;
|
|
11
|
+
const esearch_js_1 = __importDefault(require("./esearch.js"));
|
|
12
|
+
const esearch_js_2 = require("../esearch.js");
|
|
13
|
+
const isPartial = (item) => !!item && item.type === 'ATOM' && String(item.value).toUpperCase() === 'PARTIAL';
|
|
14
|
+
function partialPlugin(server) {
|
|
15
|
+
// the PARTIAL search return option is returned in an ESEARCH response (RFC 9394 section 3.1)
|
|
16
|
+
(0, esearch_js_1.default)(server);
|
|
17
|
+
server.registerCapability('PARTIAL');
|
|
18
|
+
server.partialRangeLast = true;
|
|
19
|
+
(0, esearch_js_2.registerPartialOption)(server);
|
|
20
|
+
// RFC 9394 section 3.3: fetch-modifier =/ modifier-partial. The grammar (RFC 4466 section 2.4) allows
|
|
21
|
+
// the modifier for FETCH as well as for UID FETCH. The modifier is taken off the list, CHANGEDSINCE of
|
|
22
|
+
// CONDSTORE then filters the messages in the range (RFC 9394 section 3.4)
|
|
23
|
+
const fetchWrapper = (prevHandler, connection, parsed, data, callback) => {
|
|
24
|
+
const modifiers = parsed.attributes && parsed.attributes[2];
|
|
25
|
+
if (Array.isArray(modifiers)) {
|
|
26
|
+
for (let i = 0; i < modifiers.length; i += 2) {
|
|
27
|
+
if (!isPartial(modifiers[i])) {
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
if (parsed.partialFetch) {
|
|
32
|
+
throw new Error('PARTIAL can be used only once');
|
|
33
|
+
}
|
|
34
|
+
parsed.partialFetch = (0, esearch_js_2.parsePartialRange)(modifiers[i + 1], true);
|
|
35
|
+
}
|
|
36
|
+
catch (E) {
|
|
37
|
+
connection.sendStatus(parsed, data, 'BAD', E.message, false, (parsed.command || '').toUpperCase() + ' FAILED');
|
|
38
|
+
return callback();
|
|
39
|
+
}
|
|
40
|
+
modifiers.splice(i, 2);
|
|
41
|
+
i -= 2;
|
|
42
|
+
}
|
|
43
|
+
if (!modifiers.length) {
|
|
44
|
+
parsed.attributes.splice(2, 1);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
prevHandler(connection, parsed, data, callback);
|
|
48
|
+
};
|
|
49
|
+
['FETCH', 'UID FETCH'].forEach(command => {
|
|
50
|
+
const prevHandler = server.getCommandHandler(command);
|
|
51
|
+
server.setCommandHandler(command, (connection, parsed, data, callback) => fetchWrapper(prevHandler, connection, parsed, data, callback));
|
|
52
|
+
});
|
|
53
|
+
// only the messages in the PARTIAL range of the messages that the sequence set matched are returned,
|
|
54
|
+
// checked before the other filters
|
|
55
|
+
server.fetchFilters.unshift((connection, message, parsed) => {
|
|
56
|
+
if (!parsed.partialFetch) {
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
if (!parsed.partialFetchSet) {
|
|
60
|
+
const isUid = (parsed.command || '').toUpperCase() === 'UID FETCH';
|
|
61
|
+
const range = connection.getMessageRange(parsed.attributes[0].value, isUid).map(item => item[1]);
|
|
62
|
+
parsed.partialFetchSet = new Set((0, esearch_js_2.selectPartial)(range, parsed.partialFetch));
|
|
63
|
+
}
|
|
64
|
+
return parsed.partialFetchSet.has(message);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
{
|
|
68
|
+
const defaultExport = exports.default;
|
|
69
|
+
if (defaultExport && (typeof defaultExport === 'function' || typeof defaultExport === 'object')) {
|
|
70
|
+
for (const key of Object.keys(exports)) {
|
|
71
|
+
if (key !== 'default' && !(key in defaultExport)) {
|
|
72
|
+
defaultExport[key] = exports[key];
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
Object.defineProperty(defaultExport, 'default', { value: defaultExport, enumerable: false, writable: true, configurable: true });
|
|
76
|
+
module.exports = defaultExport;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { MimeNode } from '../mimeparser.js';
|
|
2
|
+
import type { IMAPServer } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* @help Adds PREVIEW [RFC8970] capability
|
|
5
|
+
* @help Previews come from the first text/plain or text/html body part,
|
|
6
|
+
* @help or from the "preview" property of a message in storage.
|
|
7
|
+
* @help PREVIEW (LAZY) returns NIL until a preview has been generated
|
|
8
|
+
*
|
|
9
|
+
* PREVIEW: https://www.rfc-editor.org/rfc/rfc8970
|
|
10
|
+
*
|
|
11
|
+
* Message storage property:
|
|
12
|
+
* - preview: preview text to return instead of a generated one
|
|
13
|
+
*/
|
|
14
|
+
export default function previewPlugin(server: IMAPServer): void;
|
|
15
|
+
/**
|
|
16
|
+
* Generates the preview text of a message (RFC 8970 3.3) from the first text/plain or text/html part
|
|
17
|
+
*
|
|
18
|
+
* @param {Object} tree Root node of the MIME tree
|
|
19
|
+
* @return {String} Preview, an empty string if there is no text to show
|
|
20
|
+
*/
|
|
21
|
+
declare function generatePreview(tree: MimeNode): string;
|
|
22
|
+
/**
|
|
23
|
+
* Normalizes preview text: control characters are removed, whitespace runs become a single space (so there are no
|
|
24
|
+
* CR or LF characters) and the text is cut to at most `length` characters (code points, RFC 8970 3.3)
|
|
25
|
+
*
|
|
26
|
+
* @param {String} text Text
|
|
27
|
+
* @param {Number} length Maximum number of characters
|
|
28
|
+
* @return {String} Preview
|
|
29
|
+
*/
|
|
30
|
+
declare function finishPreview(text: string, length: number): string;
|
|
31
|
+
export { generatePreview, finishPreview };
|