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
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const { getPendingTarget } = require('../commands/append');
|
|
9
|
-
const { isAstring } = require('../arguments');
|
|
10
|
-
|
|
1
|
+
import { states } from '../command-states.js';
|
|
2
|
+
import { normalizeSystemFlag, checkSystemFlags } from '../commands/handlers/flags.js';
|
|
3
|
+
import builtinStoreHandlers from '../commands/handlers/store.js';
|
|
4
|
+
import { getListExtensions } from '../list-extensions.js';
|
|
5
|
+
import { beginSelect } from '../commands/select.js';
|
|
6
|
+
import { getPendingTarget } from '../commands/append.js';
|
|
7
|
+
import { isAstring } from '../arguments.js';
|
|
11
8
|
/**
|
|
12
9
|
* @help Adds ACL [RFC4314] capability with RIGHTS=texk
|
|
13
10
|
* @help The owner (server option "aclOwner", default "testuser")
|
|
@@ -26,7 +23,6 @@ const { isAstring } = require('../arguments');
|
|
|
26
23
|
*
|
|
27
24
|
* Users other than the owner can only do what their rights allow (RFC 4314 section 4).
|
|
28
25
|
*/
|
|
29
|
-
|
|
30
26
|
// RFC 4314 section 2.1, in the order they are listed in responses
|
|
31
27
|
const RIGHTS = 'lrswipkxtea';
|
|
32
28
|
const ALL_RIGHTS = new Set(RIGHTS);
|
|
@@ -41,7 +37,6 @@ const FLAG_RIGHTS = ['s', 'w', 't'];
|
|
|
41
37
|
// RFC 4314 section 4: MYRIGHTS needs any of these
|
|
42
38
|
const ANY_RIGHTS = ['l', 'r', 'i', 'k', 'x', 'a'];
|
|
43
39
|
const STORE_ITEMS = ['FLAGS', '+FLAGS', '-FLAGS', 'FLAGS.SILENT', '+FLAGS.SILENT', '-FLAGS.SILENT'];
|
|
44
|
-
|
|
45
40
|
/**
|
|
46
41
|
* Formats an astring for a response. The compiler sends an ATOM value that is not a valid atom as a
|
|
47
42
|
* quoted string or a literal, only a leading "\\" (allowed for flags) and NIL have to be kept away from it
|
|
@@ -55,7 +50,6 @@ function astring(value) {
|
|
|
55
50
|
// an atom NIL would read back as NIL, not as an identifier
|
|
56
51
|
return value && value.charAt(0) !== '\\' && !/^NIL$/i.test(value) ? { type: 'ATOM', value } : value;
|
|
57
52
|
}
|
|
58
|
-
|
|
59
53
|
/**
|
|
60
54
|
* Creates an error that is answered with BAD
|
|
61
55
|
*
|
|
@@ -67,7 +61,6 @@ function badInput(message) {
|
|
|
67
61
|
err.imapResponse = 'BAD';
|
|
68
62
|
return err;
|
|
69
63
|
}
|
|
70
|
-
|
|
71
64
|
/**
|
|
72
65
|
* Parses a rights string, the virtual "c" and "d" rights are expanded (RFC 4314 section 2.1.1)
|
|
73
66
|
*
|
|
@@ -80,17 +73,19 @@ function parseRights(value) {
|
|
|
80
73
|
for (const chr of value) {
|
|
81
74
|
if (ALL_RIGHTS.has(chr)) {
|
|
82
75
|
rights.add(chr);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
|
|
76
|
+
}
|
|
77
|
+
else if (Object.hasOwn(VIRTUAL_RIGHTS, chr)) {
|
|
78
|
+
VIRTUAL_RIGHTS[chr].split('').forEach((right) => rights.add(right));
|
|
79
|
+
}
|
|
80
|
+
else if (/^[A-Z]$/.test(chr)) {
|
|
86
81
|
throw badInput('Uppercase rights are not allowed');
|
|
87
|
-
}
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
88
84
|
throw badInput('The ' + (/^[\x21-\x7e]$/.test(chr) ? chr + ' ' : '') + 'right is not supported');
|
|
89
85
|
}
|
|
90
86
|
}
|
|
91
87
|
return rights;
|
|
92
88
|
}
|
|
93
|
-
|
|
94
89
|
/**
|
|
95
90
|
* Builds the attributes of an ACL, LISTRIGHTS or MYRIGHTS response. The mailbox name is a MAILBOX
|
|
96
91
|
* attribute, so each session gets it in the form it uses (modified UTF-7, or UTF-8 after ENABLE
|
|
@@ -101,9 +96,8 @@ function parseRights(value) {
|
|
|
101
96
|
* @return {Array} Response attributes
|
|
102
97
|
*/
|
|
103
98
|
function mailboxResponse(mailbox, values) {
|
|
104
|
-
return [{ type: 'MAILBOX', value: mailbox.path }].concat(values.map(astring));
|
|
99
|
+
return [{ type: 'MAILBOX', value: mailbox.path }].concat(values.map(value => astring(value)));
|
|
105
100
|
}
|
|
106
|
-
|
|
107
101
|
/**
|
|
108
102
|
* Formats rights for ACL and MYRIGHTS responses. "c" and "d" are added when any of their
|
|
109
103
|
* member rights is set (RFC 4314 section 2.1.1)
|
|
@@ -116,13 +110,12 @@ function formatRights(rights) {
|
|
|
116
110
|
.filter(right => rights.has(right))
|
|
117
111
|
.join('');
|
|
118
112
|
Object.keys(VIRTUAL_RIGHTS).forEach(virtual => {
|
|
119
|
-
if (VIRTUAL_RIGHTS[virtual].split('').some(right => rights.has(right))) {
|
|
113
|
+
if (VIRTUAL_RIGHTS[virtual].split('').some((right) => rights.has(right))) {
|
|
120
114
|
result += virtual;
|
|
121
115
|
}
|
|
122
116
|
});
|
|
123
117
|
return result;
|
|
124
118
|
}
|
|
125
|
-
|
|
126
119
|
/**
|
|
127
120
|
* Checks an identifier argument. RFC 4314 section 3 asks for SASLprep, which is not implemented,
|
|
128
121
|
* but an identifier that SASLprep would refuse (control characters, invalid UTF-8) or that is
|
|
@@ -145,16 +138,12 @@ function identifierError(identifier) {
|
|
|
145
138
|
}
|
|
146
139
|
return false;
|
|
147
140
|
}
|
|
148
|
-
|
|
149
|
-
module.exports = function (server) {
|
|
141
|
+
export default function aclPlugin(server) {
|
|
150
142
|
server.registerCapability('ACL');
|
|
151
143
|
// RFC 4314 section 5.1.1: the rights not defined in RFC 2086, MUST include "t", "e", "x" and "k"
|
|
152
144
|
server.registerCapability('RIGHTS=texk');
|
|
153
|
-
|
|
154
145
|
const owner = typeof server.options.aclOwner === 'string' ? server.options.aclOwner : 'testuser';
|
|
155
|
-
|
|
156
|
-
const isOwner = connection => connection.username === owner;
|
|
157
|
-
|
|
146
|
+
const isOwner = (connection) => connection.username === owner;
|
|
158
147
|
/**
|
|
159
148
|
* Returns the ACL of a mailbox as a Map of identifier to a Set of rights. The ACL from the
|
|
160
149
|
* storage (an object of identifier to rights string) is converted on first use
|
|
@@ -162,14 +151,15 @@ module.exports = function (server) {
|
|
|
162
151
|
* @param {Object} mailbox Mailbox object
|
|
163
152
|
* @return {Map}
|
|
164
153
|
*/
|
|
165
|
-
const getAcl = mailbox => {
|
|
154
|
+
const getAcl = (mailbox) => {
|
|
166
155
|
if (!(mailbox.acl instanceof Map)) {
|
|
167
156
|
const acl = new Map();
|
|
168
157
|
const source = mailbox.acl && typeof mailbox.acl === 'object' ? mailbox.acl : {};
|
|
169
158
|
Object.keys(source).forEach(identifier => {
|
|
170
159
|
try {
|
|
171
160
|
acl.set(identifier, parseRights(String(source[identifier])));
|
|
172
|
-
}
|
|
161
|
+
}
|
|
162
|
+
catch (err) {
|
|
173
163
|
// not a client error, so this is answered with NO [SERVERBUG]
|
|
174
164
|
throw new Error('Invalid ACL in storage for ' + mailbox.path + ': ' + err.message, { cause: err });
|
|
175
165
|
}
|
|
@@ -178,7 +168,6 @@ module.exports = function (server) {
|
|
|
178
168
|
}
|
|
179
169
|
return mailbox.acl;
|
|
180
170
|
};
|
|
181
|
-
|
|
182
171
|
/**
|
|
183
172
|
* Returns the rights a user has on a mailbox. The owner has all rights, other users get the
|
|
184
173
|
* union of the rights of their own identifier and "anyone", minus the negative rights of
|
|
@@ -197,14 +186,12 @@ module.exports = function (server) {
|
|
|
197
186
|
acl = acl || getAcl(mailbox);
|
|
198
187
|
const identifiers = ['anyone'].concat(typeof username === 'string' && username ? username : []);
|
|
199
188
|
const rights = new Set();
|
|
200
|
-
identifiers.forEach(identifier => (acl.get(identifier) || []).forEach(right => rights.add(right)));
|
|
201
|
-
identifiers.forEach(identifier => (acl.get('-' + identifier) || []).forEach(right => rights.delete(right)));
|
|
189
|
+
identifiers.forEach(identifier => (acl.get(identifier) || []).forEach((right) => rights.add(right)));
|
|
190
|
+
identifiers.forEach(identifier => (acl.get('-' + identifier) || []).forEach((right) => rights.delete(right)));
|
|
202
191
|
return rights;
|
|
203
192
|
};
|
|
204
|
-
|
|
205
193
|
// for plugins that report only what a user may see (e.g. NOTIFY)
|
|
206
194
|
server.acl = { getRights, isOwner };
|
|
207
|
-
|
|
208
195
|
// Tells plugins that the ACL of a mailbox changed, with an `acl` event `(mailbox, previousAcl)`
|
|
209
196
|
const changeAcl = (mailbox, change) => {
|
|
210
197
|
const acl = getAcl(mailbox);
|
|
@@ -212,7 +199,6 @@ module.exports = function (server) {
|
|
|
212
199
|
change(acl);
|
|
213
200
|
server.emit('acl', mailbox, previous);
|
|
214
201
|
};
|
|
215
|
-
|
|
216
202
|
// CATENATE (RFC 4469 section 5): reading a message through an IMAP URL needs the "r" right, a
|
|
217
203
|
// mailbox without "l" is reported like one that does not exist (RFC 4314 section 6)
|
|
218
204
|
server.urlAccessChecks.push((connection, mailbox) => {
|
|
@@ -222,20 +208,17 @@ module.exports = function (server) {
|
|
|
222
208
|
}
|
|
223
209
|
return false;
|
|
224
210
|
});
|
|
225
|
-
|
|
226
211
|
// MULTISEARCH (RFC 7377 section 2.2): searching needs "r", and "l" for a mailbox that the client did not name.
|
|
227
212
|
// Other mailboxes are left out without an error
|
|
228
213
|
server.searchAccessChecks.push((connection, mailbox, named) => {
|
|
229
214
|
const rights = getRights(connection, mailbox);
|
|
230
215
|
return rights.has('r') && (named || rights.has('l'));
|
|
231
216
|
});
|
|
232
|
-
|
|
233
217
|
// Rights on the selected mailbox are taken when it is selected (RFC 4314 section 5.1.1 allows caching
|
|
234
218
|
// them), so the FLAGS and PERMANENTFLAGS a session got stay correct until the next SELECT
|
|
235
|
-
const getSelectedRights = connection => connection.aclRights || ALL_RIGHTS;
|
|
236
|
-
|
|
219
|
+
const getSelectedRights = (connection) => connection.aclRights || ALL_RIGHTS;
|
|
237
220
|
// RFC 4314 section 4: "t" for \Deleted, "s" for \Seen and "w" for all other flags
|
|
238
|
-
const flagRight = flag => {
|
|
221
|
+
const flagRight = (flag) => {
|
|
239
222
|
flag = normalizeSystemFlag(flag);
|
|
240
223
|
if (flag === '\\Deleted') {
|
|
241
224
|
return 't';
|
|
@@ -245,24 +228,19 @@ module.exports = function (server) {
|
|
|
245
228
|
}
|
|
246
229
|
return 'w';
|
|
247
230
|
};
|
|
248
|
-
|
|
249
|
-
const flagValue = flag => (typeof flag === 'string' ? flag : String((flag && flag.value) || ''));
|
|
250
|
-
|
|
231
|
+
// flags are strings or parsed atoms
|
|
232
|
+
const flagValue = (flag) => (typeof flag === 'string' ? flag : String((flag && flag.value) || ''));
|
|
251
233
|
const canSetFlag = (rights, flag) => rights.has(flagRight(flagValue(flag)));
|
|
252
|
-
|
|
253
234
|
const mailboxArgument = (parsed, position) => {
|
|
254
235
|
const attr = (parsed.attributes || [])[position];
|
|
255
236
|
return isAstring(attr) ? attr.value : false;
|
|
256
237
|
};
|
|
257
|
-
|
|
258
238
|
// the mailbox named by an argument, false if there is no such mailbox or the argument is invalid
|
|
259
239
|
const argumentMailbox = (parsed, position) => {
|
|
260
240
|
const name = mailboxArgument(parsed, position);
|
|
261
241
|
return (name !== false && server.getMailbox(name)) || false;
|
|
262
242
|
};
|
|
263
|
-
|
|
264
243
|
const sendNoPerm = (connection, parsed, data, description) => connection.sendStatus(parsed, data, 'NO', 'Permission denied', 'NOPERM', description);
|
|
265
|
-
|
|
266
244
|
/**
|
|
267
245
|
* Refuses a command for lack of rights. Without the "l" right the user gets the same error
|
|
268
246
|
* as for a mailbox that does not exist, so the existence of the mailbox is not disclosed
|
|
@@ -271,20 +249,21 @@ module.exports = function (server) {
|
|
|
271
249
|
const sendDenied = (connection, parsed, data, rights, description, notFound) => {
|
|
272
250
|
if (rights.has('l')) {
|
|
273
251
|
sendNoPerm(connection, parsed, data, description);
|
|
274
|
-
}
|
|
252
|
+
}
|
|
253
|
+
else if (notFound === 'TRYCREATE') {
|
|
275
254
|
connection.sendStatus(parsed, data, 'NO', 'Target mailbox does not exist', 'TRYCREATE', description);
|
|
276
|
-
}
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
277
257
|
connection.sendStatus(parsed, data, 'NO', 'Mailbox does not exist', 'NONEXISTENT', description);
|
|
278
258
|
}
|
|
279
259
|
};
|
|
280
|
-
|
|
281
260
|
/**
|
|
282
261
|
* Finds the nearest existing parent of a mailbox name (RFC 4314 section 4, CREATE)
|
|
283
262
|
*
|
|
284
263
|
* @param {String} path Mailbox path
|
|
285
264
|
* @return {Object|Boolean} parent mailbox or false if there is none
|
|
286
265
|
*/
|
|
287
|
-
const getParent = path => {
|
|
266
|
+
const getParent = (path) => {
|
|
288
267
|
for (let parent = server.getParentPath(path); parent; parent = server.getParentPath(parent)) {
|
|
289
268
|
const mailbox = server.getMailbox(parent);
|
|
290
269
|
if (mailbox) {
|
|
@@ -293,7 +272,6 @@ module.exports = function (server) {
|
|
|
293
272
|
}
|
|
294
273
|
return false;
|
|
295
274
|
};
|
|
296
|
-
|
|
297
275
|
// Checks for the ACL commands, true if the command can go ahead
|
|
298
276
|
const checkAclCommand = (connection, parsed, data, mailbox, isAllowed) => {
|
|
299
277
|
if (!mailbox) {
|
|
@@ -302,14 +280,12 @@ module.exports = function (server) {
|
|
|
302
280
|
}
|
|
303
281
|
const rights = getRights(connection, mailbox);
|
|
304
282
|
if (!isAllowed(rights)) {
|
|
305
|
-
sendDenied(connection, parsed, data, rights
|
|
283
|
+
sendDenied(connection, parsed, data, rights);
|
|
306
284
|
return false;
|
|
307
285
|
}
|
|
308
286
|
return true;
|
|
309
287
|
};
|
|
310
|
-
|
|
311
|
-
const hasAdmin = rights => rights.has('a');
|
|
312
|
-
|
|
288
|
+
const hasAdmin = (rights) => rights.has('a');
|
|
313
289
|
/**
|
|
314
290
|
* Validates the arguments of an ACL command: `count` astrings, the first one a mailbox name and
|
|
315
291
|
* the second one (if any) an identifier
|
|
@@ -335,7 +311,6 @@ module.exports = function (server) {
|
|
|
335
311
|
}
|
|
336
312
|
return true;
|
|
337
313
|
};
|
|
338
|
-
|
|
339
314
|
// RFC 4314 section 2: an implementation MAY force rights to always be granted to an identifier
|
|
340
315
|
const refuseOwnerIdentifier = (connection, parsed, data) => {
|
|
341
316
|
const identifier = parsed.attributes[1].value;
|
|
@@ -345,28 +320,17 @@ module.exports = function (server) {
|
|
|
345
320
|
connection.sendStatus(parsed, data, 'NO', 'Rights of the mailbox owner can not be changed', 'CANNOT');
|
|
346
321
|
return true;
|
|
347
322
|
};
|
|
348
|
-
|
|
349
323
|
const aclCommand = (count, handler) => (connection, parsed, data, callback) => {
|
|
350
324
|
if (checkArguments(connection, parsed, data, count)) {
|
|
351
325
|
handler(connection, parsed, data, server.getMailbox(parsed.attributes[0].value));
|
|
352
326
|
}
|
|
353
327
|
callback();
|
|
354
328
|
};
|
|
355
|
-
|
|
356
329
|
const aclOptions = { states: states.AUTHENTICATED, mailboxArguments: [0] };
|
|
357
330
|
// RFC 4314 section 7: identifier and mod-rights are astrings
|
|
358
331
|
const identifierOptions = Object.assign({ astringArguments: [1] }, aclOptions);
|
|
359
|
-
|
|
360
332
|
// RFC 4314 section 3.8: myrights-data = "MYRIGHTS" SP mailbox SP rights
|
|
361
|
-
const sendMyRights = (connection, mailbox, parsed, data) =>
|
|
362
|
-
connection.send(
|
|
363
|
-
{ tag: '*', command: 'MYRIGHTS', attributes: mailboxResponse(mailbox, [formatRights(getRights(connection, mailbox))]) },
|
|
364
|
-
'MYRIGHTS',
|
|
365
|
-
parsed,
|
|
366
|
-
data,
|
|
367
|
-
mailbox
|
|
368
|
-
);
|
|
369
|
-
|
|
333
|
+
const sendMyRights = (connection, mailbox, parsed, data) => connection.send({ tag: '*', command: 'MYRIGHTS', attributes: mailboxResponse(mailbox, [formatRights(getRights(connection, mailbox))]) }, 'MYRIGHTS', parsed, data, mailbox);
|
|
370
334
|
// RFC 8440 section 3: the MYRIGHTS return option of an extended LIST. The registry is shared with
|
|
371
335
|
// LIST-EXTENDED, which accepts the option only when it is loaded, in any load order
|
|
372
336
|
const listExtensions = getListExtensions(server);
|
|
@@ -380,107 +344,81 @@ module.exports = function (server) {
|
|
|
380
344
|
}
|
|
381
345
|
}
|
|
382
346
|
};
|
|
383
|
-
|
|
384
347
|
// RFC 4314 section 3.1
|
|
385
|
-
server.setCommandHandler(
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
changeAcl(mailbox, acl => {
|
|
400
|
-
const current = new Set(acl.get(identifier) || []);
|
|
401
|
-
if (mode === '+') {
|
|
402
|
-
rights.forEach(right => current.add(right));
|
|
403
|
-
} else if (mode === '-') {
|
|
404
|
-
rights.forEach(right => current.delete(right));
|
|
405
|
-
}
|
|
406
|
-
const updated = mode ? current : rights;
|
|
407
|
-
if (updated.size) {
|
|
408
|
-
acl.set(identifier, updated);
|
|
409
|
-
} else {
|
|
410
|
-
acl.delete(identifier);
|
|
411
|
-
}
|
|
412
|
-
});
|
|
413
|
-
connection.sendStatus(parsed, data, 'OK', 'Setacl complete');
|
|
414
|
-
}),
|
|
415
|
-
Object.assign({ astringArguments: [1, 2] }, aclOptions)
|
|
416
|
-
);
|
|
417
|
-
|
|
418
|
-
// RFC 4314 section 3.2
|
|
419
|
-
server.setCommandHandler(
|
|
420
|
-
'DELETEACL',
|
|
421
|
-
aclCommand(2, (connection, parsed, data, mailbox) => {
|
|
422
|
-
if (!checkAclCommand(connection, parsed, data, mailbox, hasAdmin) || refuseOwnerIdentifier(connection, parsed, data)) {
|
|
423
|
-
return;
|
|
348
|
+
server.setCommandHandler('SETACL', aclCommand(3, (connection, parsed, data, mailbox) => {
|
|
349
|
+
const identifier = parsed.attributes[1].value;
|
|
350
|
+
const modification = parsed.attributes[2].value;
|
|
351
|
+
const mode = /^[+-]/.test(modification) ? modification.charAt(0) : '';
|
|
352
|
+
// an unrecognized right MUST cause BAD, before anything else is checked
|
|
353
|
+
const rights = parseRights(modification.substr(mode.length));
|
|
354
|
+
if (!checkAclCommand(connection, parsed, data, mailbox, hasAdmin) || refuseOwnerIdentifier(connection, parsed, data)) {
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
changeAcl(mailbox, acl => {
|
|
358
|
+
const current = new Set(acl.get(identifier) || []);
|
|
359
|
+
if (mode === '+') {
|
|
360
|
+
rights.forEach(right => current.add(right));
|
|
424
361
|
}
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
}),
|
|
428
|
-
identifierOptions
|
|
429
|
-
);
|
|
430
|
-
|
|
431
|
-
// RFC 4314 sections 3.3 and 3.6
|
|
432
|
-
server.setCommandHandler(
|
|
433
|
-
'GETACL',
|
|
434
|
-
aclCommand(1, (connection, parsed, data, mailbox) => {
|
|
435
|
-
if (!checkAclCommand(connection, parsed, data, mailbox, hasAdmin)) {
|
|
436
|
-
return;
|
|
362
|
+
else if (mode === '-') {
|
|
363
|
+
rights.forEach(right => current.delete(right));
|
|
437
364
|
}
|
|
438
|
-
const
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
});
|
|
442
|
-
connection.send({ tag: '*', command: 'ACL', attributes: mailboxResponse(mailbox, attributes) }, 'ACL', parsed, data, mailbox);
|
|
443
|
-
connection.sendStatus(parsed, data, 'OK', 'Getacl complete');
|
|
444
|
-
}),
|
|
445
|
-
aclOptions
|
|
446
|
-
);
|
|
447
|
-
|
|
448
|
-
// RFC 4314 sections 3.4 and 3.7
|
|
449
|
-
server.setCommandHandler(
|
|
450
|
-
'LISTRIGHTS',
|
|
451
|
-
aclCommand(2, (connection, parsed, data, mailbox) => {
|
|
452
|
-
if (!checkAclCommand(connection, parsed, data, mailbox, hasAdmin)) {
|
|
453
|
-
return;
|
|
365
|
+
const updated = mode ? current : rights;
|
|
366
|
+
if (updated.size) {
|
|
367
|
+
acl.set(identifier, updated);
|
|
454
368
|
}
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
let attributes;
|
|
458
|
-
if (identifier === owner) {
|
|
459
|
-
// the owner always has every right, nothing is optional
|
|
460
|
-
attributes = [identifier, formatRights(ALL_RIGHTS)];
|
|
461
|
-
} else {
|
|
462
|
-
// nothing is granted always, every right can be granted on its own, including the virtual ones
|
|
463
|
-
attributes = [identifier, ''].concat(RIGHTS.split(''), Object.keys(VIRTUAL_RIGHTS));
|
|
369
|
+
else {
|
|
370
|
+
acl.delete(identifier);
|
|
464
371
|
}
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
)
|
|
470
|
-
|
|
372
|
+
});
|
|
373
|
+
connection.sendStatus(parsed, data, 'OK', 'Setacl complete');
|
|
374
|
+
}), Object.assign({ astringArguments: [1, 2] }, aclOptions));
|
|
375
|
+
// RFC 4314 section 3.2
|
|
376
|
+
server.setCommandHandler('DELETEACL', aclCommand(2, (connection, parsed, data, mailbox) => {
|
|
377
|
+
if (!checkAclCommand(connection, parsed, data, mailbox, hasAdmin) || refuseOwnerIdentifier(connection, parsed, data)) {
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
changeAcl(mailbox, acl => acl.delete(parsed.attributes[1].value));
|
|
381
|
+
connection.sendStatus(parsed, data, 'OK', 'Deleteacl complete');
|
|
382
|
+
}), identifierOptions);
|
|
383
|
+
// RFC 4314 sections 3.3 and 3.6
|
|
384
|
+
server.setCommandHandler('GETACL', aclCommand(1, (connection, parsed, data, mailbox) => {
|
|
385
|
+
if (!checkAclCommand(connection, parsed, data, mailbox, hasAdmin)) {
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
const attributes = [owner, formatRights(ALL_RIGHTS)];
|
|
389
|
+
getAcl(mailbox).forEach((rights, identifier) => {
|
|
390
|
+
attributes.push(identifier, formatRights(rights));
|
|
391
|
+
});
|
|
392
|
+
connection.send({ tag: '*', command: 'ACL', attributes: mailboxResponse(mailbox, attributes) }, 'ACL', parsed, data, mailbox);
|
|
393
|
+
connection.sendStatus(parsed, data, 'OK', 'Getacl complete');
|
|
394
|
+
}), aclOptions);
|
|
395
|
+
// RFC 4314 sections 3.4 and 3.7
|
|
396
|
+
server.setCommandHandler('LISTRIGHTS', aclCommand(2, (connection, parsed, data, mailbox) => {
|
|
397
|
+
if (!checkAclCommand(connection, parsed, data, mailbox, hasAdmin)) {
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
// the identifier is sent back in the same form as the client used
|
|
401
|
+
const identifier = parsed.attributes[1].value;
|
|
402
|
+
let attributes;
|
|
403
|
+
if (identifier === owner) {
|
|
404
|
+
// the owner always has every right, nothing is optional
|
|
405
|
+
attributes = [identifier, formatRights(ALL_RIGHTS)];
|
|
406
|
+
}
|
|
407
|
+
else {
|
|
408
|
+
// nothing is granted always, every right can be granted on its own, including the virtual ones
|
|
409
|
+
attributes = [identifier, ''].concat(RIGHTS.split(''), Object.keys(VIRTUAL_RIGHTS));
|
|
410
|
+
}
|
|
411
|
+
connection.send({ tag: '*', command: 'LISTRIGHTS', attributes: mailboxResponse(mailbox, attributes) }, 'LISTRIGHTS', parsed, data, mailbox);
|
|
412
|
+
connection.sendStatus(parsed, data, 'OK', 'Listrights complete');
|
|
413
|
+
}), identifierOptions);
|
|
471
414
|
// RFC 4314 sections 3.5 and 3.8
|
|
472
|
-
server.setCommandHandler(
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
connection.sendStatus(parsed, data, 'OK', 'Myrights complete');
|
|
480
|
-
}),
|
|
481
|
-
aclOptions
|
|
482
|
-
);
|
|
483
|
-
|
|
415
|
+
server.setCommandHandler('MYRIGHTS', aclCommand(1, (connection, parsed, data, mailbox) => {
|
|
416
|
+
if (!checkAclCommand(connection, parsed, data, mailbox, (rights) => ANY_RIGHTS.some(right => rights.has(right)))) {
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
sendMyRights(connection, mailbox, parsed, data);
|
|
420
|
+
connection.sendStatus(parsed, data, 'OK', 'Myrights complete');
|
|
421
|
+
}), aclOptions);
|
|
484
422
|
// Enforcement (RFC 4314 section 4). Commands are wrapped once every plugin is loaded, so that
|
|
485
423
|
// the commands of every plugin (MOVE, UID EXPUNGE, ...) are covered whatever the load order is
|
|
486
424
|
const wrappers = {};
|
|
@@ -499,7 +437,6 @@ module.exports = function (server) {
|
|
|
499
437
|
});
|
|
500
438
|
}
|
|
501
439
|
});
|
|
502
|
-
|
|
503
440
|
// Return options of an extended LIST (LIST-STATUS, LIST-MYRIGHTS) add responses for the listed
|
|
504
441
|
// mailboxes, so they skip the mailboxes that are not listed for the user. STATUS also needs "r"
|
|
505
442
|
// (RFC 5819 section 2: the STATUS response MUST NOT be returned if the mailbox can not be selected)
|
|
@@ -520,7 +457,6 @@ module.exports = function (server) {
|
|
|
520
457
|
}
|
|
521
458
|
};
|
|
522
459
|
});
|
|
523
|
-
|
|
524
460
|
// RFC 4314 section 4: STORE changes only the flags the user has rights for
|
|
525
461
|
STORE_ITEMS.forEach(item => {
|
|
526
462
|
const prevHandler = server.storeHandlers[item] || builtinStoreHandlers[item];
|
|
@@ -531,8 +467,8 @@ module.exports = function (server) {
|
|
|
531
467
|
}
|
|
532
468
|
flags = [].concat(flags);
|
|
533
469
|
// invalid flags are still refused with BAD, even if the user could not set them anyway
|
|
534
|
-
flags.forEach(flag => checkSystemFlags(connection, normalizeSystemFlag(flagValue(flag))));
|
|
535
|
-
let allowed = flags.filter(flag => canSetFlag(rights, flag));
|
|
470
|
+
flags.forEach((flag) => checkSystemFlags(connection, normalizeSystemFlag(flagValue(flag))));
|
|
471
|
+
let allowed = flags.filter((flag) => canSetFlag(rights, flag));
|
|
536
472
|
if (item.charAt(0) !== '+' && item.charAt(0) !== '-') {
|
|
537
473
|
// replacing the flags keeps the ones the user can not change
|
|
538
474
|
allowed = message.flags.filter(flag => !canSetFlag(rights, flag)).concat(allowed);
|
|
@@ -541,9 +477,7 @@ module.exports = function (server) {
|
|
|
541
477
|
};
|
|
542
478
|
});
|
|
543
479
|
};
|
|
544
|
-
|
|
545
480
|
server.once('pluginsLoaded', wrapCommands);
|
|
546
|
-
|
|
547
481
|
const selectWrapper = (prevHandler, connection, parsed, data, callback) => {
|
|
548
482
|
const mailbox = argumentMailbox(parsed, 0);
|
|
549
483
|
if (!mailbox) {
|
|
@@ -567,31 +501,25 @@ module.exports = function (server) {
|
|
|
567
501
|
};
|
|
568
502
|
wrappers.SELECT = selectWrapper;
|
|
569
503
|
wrappers.EXAMINE = selectWrapper;
|
|
570
|
-
|
|
571
504
|
// Checks that the user has a right on the mailbox named by an argument. Unknown mailboxes and
|
|
572
505
|
// invalid arguments are left to the command handler
|
|
573
506
|
const hasMailboxRight = (right, position, notFound) => (connection, parsed, data) => {
|
|
574
507
|
const mailbox = argumentMailbox(parsed, position);
|
|
575
508
|
const rights = mailbox && getRights(connection, mailbox);
|
|
576
509
|
if (rights && !rights.has(right)) {
|
|
577
|
-
sendDenied(connection, parsed, data, rights,
|
|
510
|
+
sendDenied(connection, parsed, data, rights, undefined, notFound);
|
|
578
511
|
return false;
|
|
579
512
|
}
|
|
580
513
|
return true;
|
|
581
514
|
};
|
|
582
|
-
|
|
583
515
|
const requireRight = (right, position, notFound) => {
|
|
584
516
|
const check = hasMailboxRight(right, position, notFound);
|
|
585
|
-
return (prevHandler, connection, parsed, data, callback) =>
|
|
586
|
-
check(connection, parsed, data) ? prevHandler(connection, parsed, data, callback) : callback();
|
|
517
|
+
return (prevHandler, connection, parsed, data, callback) => check(connection, parsed, data) ? prevHandler(connection, parsed, data, callback) : callback();
|
|
587
518
|
};
|
|
588
|
-
|
|
589
519
|
wrappers.STATUS = requireRight('r', 0);
|
|
590
520
|
// SUBSCRIBE checks that the mailbox exists, so it needs "l". UNSUBSCRIBE needs no rights
|
|
591
521
|
wrappers.SUBSCRIBE = requireRight('l', 0);
|
|
592
|
-
|
|
593
522
|
wrappers.DELETE = requireRight('x', 0);
|
|
594
|
-
|
|
595
523
|
// CREATE needs "k" on the nearest existing parent, a mailbox at the top level can not be created
|
|
596
524
|
const checkCreateRight = (connection, parsed, data, path) => {
|
|
597
525
|
const parent = getParent(path);
|
|
@@ -601,7 +529,6 @@ module.exports = function (server) {
|
|
|
601
529
|
}
|
|
602
530
|
return true;
|
|
603
531
|
};
|
|
604
|
-
|
|
605
532
|
wrappers.CREATE = (prevHandler, connection, parsed, data, callback) => {
|
|
606
533
|
const name = mailboxArgument(parsed, 0);
|
|
607
534
|
if (name !== false && !checkCreateRight(connection, parsed, data, name)) {
|
|
@@ -609,7 +536,6 @@ module.exports = function (server) {
|
|
|
609
536
|
}
|
|
610
537
|
return prevHandler(connection, parsed, data, callback);
|
|
611
538
|
};
|
|
612
|
-
|
|
613
539
|
// RENAME needs "x" on the mailbox and "k" on the new parent
|
|
614
540
|
const hasRenameRight = hasMailboxRight('x', 0);
|
|
615
541
|
wrappers.RENAME = (prevHandler, connection, parsed, data, callback) => {
|
|
@@ -622,7 +548,6 @@ module.exports = function (server) {
|
|
|
622
548
|
}
|
|
623
549
|
return prevHandler(connection, parsed, data, callback);
|
|
624
550
|
};
|
|
625
|
-
|
|
626
551
|
// APPEND needs "i", and only the flags the user has rights for are stored
|
|
627
552
|
wrappers.APPEND = (prevHandler, connection, parsed, data, callback) => {
|
|
628
553
|
const mailbox = argumentMailbox(parsed, 0);
|
|
@@ -635,18 +560,18 @@ module.exports = function (server) {
|
|
|
635
560
|
return callback();
|
|
636
561
|
}
|
|
637
562
|
const flags = parsed.attributes[1];
|
|
638
|
-
if (Array.isArray(flags) && flags.every(flag => flag && flag.type === 'ATOM')) {
|
|
563
|
+
if (Array.isArray(flags) && flags.every((flag) => flag && flag.type === 'ATOM')) {
|
|
639
564
|
try {
|
|
640
|
-
flags.forEach(flag => checkSystemFlags(connection, normalizeSystemFlag(flag.value)));
|
|
565
|
+
flags.forEach((flag) => checkSystemFlags(connection, normalizeSystemFlag(flag.value)));
|
|
641
566
|
// the server MUST NOT fail APPEND for flags the user can not set
|
|
642
|
-
parsed.attributes[1] = flags.filter(flag => canSetFlag(rights, flag));
|
|
643
|
-
}
|
|
567
|
+
parsed.attributes[1] = flags.filter((flag) => canSetFlag(rights, flag));
|
|
568
|
+
}
|
|
569
|
+
catch {
|
|
644
570
|
// invalid flags are refused with BAD by the APPEND handler
|
|
645
571
|
}
|
|
646
572
|
}
|
|
647
573
|
return prevHandler(connection, parsed, data, callback);
|
|
648
574
|
};
|
|
649
|
-
|
|
650
575
|
// the refusal for a target mailbox without "i", see sendDenied
|
|
651
576
|
const insertRefusal = (connection, mailbox) => {
|
|
652
577
|
const rights = mailbox ? getRights(connection, mailbox) : false;
|
|
@@ -657,11 +582,10 @@ module.exports = function (server) {
|
|
|
657
582
|
? { command: 'NO', code: 'NOPERM', text: 'Permission denied' }
|
|
658
583
|
: { command: 'NO', code: 'TRYCREATE', text: 'Target mailbox does not exist' };
|
|
659
584
|
};
|
|
660
|
-
|
|
661
585
|
// COPY and MOVE need "i" on the target, MOVE also needs what UID STORE \Deleted and UID EXPUNGE
|
|
662
586
|
// need on the source, "t" and "e" (RFC 6851 section 4.2)
|
|
663
587
|
const requireInsert = requireRight('i', 1, 'TRYCREATE');
|
|
664
|
-
const copyWrapper = isMove => (prevHandler, connection, parsed, data, callback) => {
|
|
588
|
+
const copyWrapper = (isMove) => (prevHandler, connection, parsed, data, callback) => {
|
|
665
589
|
const command = parsed.command.toUpperCase();
|
|
666
590
|
if (isMove && !connection.readOnly) {
|
|
667
591
|
const rights = getSelectedRights(connection);
|
|
@@ -676,7 +600,6 @@ module.exports = function (server) {
|
|
|
676
600
|
wrappers['UID COPY'] = copyWrapper(false);
|
|
677
601
|
wrappers.MOVE = copyWrapper(true);
|
|
678
602
|
wrappers['UID MOVE'] = copyWrapper(true);
|
|
679
|
-
|
|
680
603
|
// RFC 8508 section 4.1: REPLACE needs the rights of UID STORE (\Deleted, "t") and UID EXPUNGE ("e") on the
|
|
681
604
|
// selected mailbox, and of APPEND ("i") on the target. A read-only session is refused by the command handler
|
|
682
605
|
const replaceRefusal = (connection, mailbox) => {
|
|
@@ -696,7 +619,6 @@ module.exports = function (server) {
|
|
|
696
619
|
};
|
|
697
620
|
wrappers.REPLACE = replaceWrapper;
|
|
698
621
|
wrappers['UID REPLACE'] = replaceWrapper;
|
|
699
|
-
|
|
700
622
|
// The message literal of APPEND and REPLACE is refused before it is sent when the user may not add messages to the
|
|
701
623
|
// target, with the same answer as after the literal. A mailbox the user can not see ("l") is refused like a
|
|
702
624
|
// missing one, which the core literal filter refuses before the literal too, so the transcripts do not tell
|
|
@@ -712,11 +634,10 @@ module.exports = function (server) {
|
|
|
712
634
|
}
|
|
713
635
|
return command === 'APPEND' ? insertRefusal(connection, mailbox) : replaceRefusal(connection, mailbox);
|
|
714
636
|
});
|
|
715
|
-
|
|
716
637
|
// RFC 5464 section 3.3: mailbox annotations need "l" and any of "r", "s", "w", "i" or "p". Server
|
|
717
638
|
// annotations (the empty mailbox name) are not covered by mailbox ACLs
|
|
718
639
|
const METADATA_RIGHTS = ['r', 's', 'w', 'i', 'p'];
|
|
719
|
-
const canUseMetadata = rights => rights.has('l') && METADATA_RIGHTS.some(right => rights.has(right));
|
|
640
|
+
const canUseMetadata = (rights) => rights.has('l') && METADATA_RIGHTS.some(right => rights.has(right));
|
|
720
641
|
const metadataWrapper = (prevHandler, connection, parsed, data, callback) => {
|
|
721
642
|
const args = parsed.attributes || [];
|
|
722
643
|
// GETMETADATA takes its options before the mailbox name (RFC 5464 errata 2785)
|
|
@@ -725,7 +646,7 @@ module.exports = function (server) {
|
|
|
725
646
|
if (mailbox && mailboxArgument(parsed, position) !== '') {
|
|
726
647
|
const rights = getRights(connection, mailbox);
|
|
727
648
|
if (!canUseMetadata(rights)) {
|
|
728
|
-
sendDenied(connection, parsed, data, rights
|
|
649
|
+
sendDenied(connection, parsed, data, rights);
|
|
729
650
|
return callback();
|
|
730
651
|
}
|
|
731
652
|
}
|
|
@@ -733,7 +654,6 @@ module.exports = function (server) {
|
|
|
733
654
|
};
|
|
734
655
|
wrappers.GETMETADATA = metadataWrapper;
|
|
735
656
|
wrappers.SETMETADATA = metadataWrapper;
|
|
736
|
-
|
|
737
657
|
// Unsolicited METADATA responses (RFC 5464 section 4.4.2) only go to sessions that could read the
|
|
738
658
|
// annotations of the mailbox. Server annotations have an empty mailbox name
|
|
739
659
|
server.notifyFilters.push((connection, notification) => {
|
|
@@ -746,7 +666,6 @@ module.exports = function (server) {
|
|
|
746
666
|
const mailbox = typeof path === 'string' && path !== '' && server.getMailbox(path);
|
|
747
667
|
return !mailbox || canUseMetadata(getRights(connection, mailbox));
|
|
748
668
|
});
|
|
749
|
-
|
|
750
669
|
// RFC 9208 section 6: GETQUOTA needs no rights. GETQUOTAROOT needs "r" for the MESSAGE and STORAGE
|
|
751
670
|
// resources, which tell about the messages of the mailbox, only MAILBOX needs no right. Without "r"
|
|
752
671
|
// (or for a mailbox that does not exist, so nothing is disclosed) the QUOTA responses only list MAILBOX
|
|
@@ -757,7 +676,6 @@ module.exports = function (server) {
|
|
|
757
676
|
}
|
|
758
677
|
return prevHandler(connection, parsed, data, callback);
|
|
759
678
|
};
|
|
760
|
-
|
|
761
679
|
// RFC 9208 section 6: SETQUOTA needs "a". The quota root is not a mailbox, so the user needs "a" on
|
|
762
680
|
// every mailbox the quota root applies to (all personal mailboxes)
|
|
763
681
|
wrappers.SETQUOTA = (prevHandler, connection, parsed, data, callback) => {
|
|
@@ -774,7 +692,6 @@ module.exports = function (server) {
|
|
|
774
692
|
}
|
|
775
693
|
return prevHandler(connection, parsed, data, callback);
|
|
776
694
|
};
|
|
777
|
-
|
|
778
695
|
// EXPUNGE needs "e". In a read-only session the command handler refuses it already
|
|
779
696
|
const expungeWrapper = (prevHandler, connection, parsed, data, callback) => {
|
|
780
697
|
if (!connection.readOnly && !getSelectedRights(connection).has('e')) {
|
|
@@ -785,13 +702,11 @@ module.exports = function (server) {
|
|
|
785
702
|
};
|
|
786
703
|
wrappers.EXPUNGE = expungeWrapper;
|
|
787
704
|
wrappers['UID EXPUNGE'] = expungeWrapper;
|
|
788
|
-
|
|
789
705
|
// UNAUTHENTICATE (RFC 8437): rights of the previous user must not stay with the session
|
|
790
|
-
server.resetHandlers.push(connection => {
|
|
706
|
+
server.resetHandlers.push((connection) => {
|
|
791
707
|
connection.aclRights = null;
|
|
792
708
|
});
|
|
793
|
-
|
|
794
|
-
server.connectionHandlers.push(connection => {
|
|
709
|
+
server.connectionHandlers.push((connection) => {
|
|
795
710
|
// A FETCH that implies setting \Seen MUST NOT set it without "s", and without "e" CLOSE MUST
|
|
796
711
|
// close the mailbox without expunging (RFC 4314 section 4)
|
|
797
712
|
const canSetSeen = connection.canSetSeen;
|
|
@@ -799,7 +714,6 @@ module.exports = function (server) {
|
|
|
799
714
|
connection.canSetSeen = () => canSetSeen.call(connection) && getSelectedRights(connection).has('s');
|
|
800
715
|
connection.canExpunge = () => canExpunge.call(connection) && getSelectedRights(connection).has('e');
|
|
801
716
|
});
|
|
802
|
-
|
|
803
717
|
// STORE needs the right of at least one of the flags it changes, it SHOULD NOT fail otherwise.
|
|
804
718
|
// The flags themselves are filtered by the store handlers
|
|
805
719
|
const storeWrapper = (prevHandler, connection, parsed, data, callback) => {
|
|
@@ -821,14 +735,16 @@ module.exports = function (server) {
|
|
|
821
735
|
const flags = [].concat(args[args.length - 1] || []);
|
|
822
736
|
try {
|
|
823
737
|
flags.forEach(flag => checkSystemFlags(connection, normalizeSystemFlag(flagValue(flag))));
|
|
824
|
-
}
|
|
738
|
+
}
|
|
739
|
+
catch {
|
|
825
740
|
// invalid flags are refused with BAD by the STORE handler
|
|
826
741
|
return prevHandler(connection, parsed, data, callback);
|
|
827
742
|
}
|
|
828
743
|
let allowed;
|
|
829
744
|
if (item.charAt(0) === '+' || item.charAt(0) === '-') {
|
|
830
745
|
allowed = !flags.length || flags.some(flag => canSetFlag(rights, flag));
|
|
831
|
-
}
|
|
746
|
+
}
|
|
747
|
+
else {
|
|
832
748
|
// replacing the flags changes every flag the user has rights for
|
|
833
749
|
allowed = FLAG_RIGHTS.some(right => rights.has(right));
|
|
834
750
|
}
|
|
@@ -840,28 +756,21 @@ module.exports = function (server) {
|
|
|
840
756
|
};
|
|
841
757
|
wrappers.STORE = storeWrapper;
|
|
842
758
|
wrappers['UID STORE'] = storeWrapper;
|
|
843
|
-
|
|
844
759
|
// Checks if an extended LIST command asks for the STATUS return option (RFC 5819)
|
|
845
|
-
const hasStatusReturnOption = parsed => {
|
|
760
|
+
const hasStatusReturnOption = (parsed) => {
|
|
846
761
|
const args = (parsed && parsed.attributes) || [];
|
|
847
|
-
return args.some(
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
Array.isArray(args[i + 1]) &&
|
|
853
|
-
args[i + 1].some(option => option && option.type === 'ATOM' && /^STATUS$/i.test(option.value))
|
|
854
|
-
);
|
|
762
|
+
return args.some((arg, i) => arg &&
|
|
763
|
+
arg.type === 'ATOM' &&
|
|
764
|
+
/^RETURN$/i.test(arg.value) &&
|
|
765
|
+
Array.isArray(args[i + 1]) &&
|
|
766
|
+
args[i + 1].some((option) => option && option.type === 'ATOM' && /^STATUS$/i.test(option.value)));
|
|
855
767
|
};
|
|
856
|
-
|
|
857
768
|
// Checks if any mailbox below a mailbox is visible to the user
|
|
858
|
-
const hasVisibleChildren = (connection, mailbox) => server.hasDescendant(mailbox.path, child => getRights(connection, child).has('l'));
|
|
859
|
-
|
|
769
|
+
const hasVisibleChildren = (connection, mailbox) => server.hasDescendant(mailbox.path, (child) => getRights(connection, child).has('l'));
|
|
860
770
|
server.outputHandlers.push((connection, response, description, parsed, data, extra) => {
|
|
861
771
|
if (isOwner(connection)) {
|
|
862
772
|
return;
|
|
863
773
|
}
|
|
864
|
-
|
|
865
774
|
if ((description === 'LIST ITEM' || description === 'LSUB ITEM') && extra && extra.path) {
|
|
866
775
|
// LIST and LSUB need "l", the mailbox is left out without it and never answered with NO
|
|
867
776
|
if (!getRights(connection, extra).has('l')) {
|
|
@@ -873,20 +782,19 @@ module.exports = function (server) {
|
|
|
873
782
|
return;
|
|
874
783
|
}
|
|
875
784
|
response.attributes[0] = flags.slice();
|
|
876
|
-
const index = flags.findIndex(flag => flag && flag.value === '\\HasChildren');
|
|
785
|
+
const index = flags.findIndex((flag) => flag && flag.value === '\\HasChildren');
|
|
877
786
|
if (index >= 0 && !hasVisibleChildren(connection, extra)) {
|
|
878
787
|
// children that the user can not see do not count (RFC 3348 section 4)
|
|
879
788
|
response.attributes[0][index] = { type: 'ATOM', value: '\\HasNoChildren' };
|
|
880
789
|
}
|
|
881
790
|
// RFC 5819 section 2: a mailbox that gets no STATUS response because it can not be selected
|
|
882
791
|
// (no "r" right) MUST be listed with \Noselect
|
|
883
|
-
const isSelectable = !flags.some(flag => flag && /^\\(Noselect|NonExistent)$/i.test(flag.value));
|
|
792
|
+
const isSelectable = !flags.some((flag) => flag && /^\\(Noselect|NonExistent)$/i.test(flag.value));
|
|
884
793
|
if (isSelectable && hasStatusReturnOption(parsed) && !getRights(connection, extra).has('r')) {
|
|
885
794
|
response.attributes[0].push({ type: 'ATOM', value: '\\Noselect' });
|
|
886
795
|
}
|
|
887
796
|
return;
|
|
888
797
|
}
|
|
889
|
-
|
|
890
798
|
if (description === 'QUOTA' && parsed && parsed.aclQuotaMailboxOnly && Array.isArray(response.attributes[1])) {
|
|
891
799
|
// quota-resource = resource-name SP resource-usage SP resource-limit
|
|
892
800
|
const list = response.attributes[1];
|
|
@@ -899,36 +807,35 @@ module.exports = function (server) {
|
|
|
899
807
|
// quota-list needs at least one resource, so without a MAILBOX limit there is no QUOTA response
|
|
900
808
|
if (filtered.length) {
|
|
901
809
|
response.attributes[1] = filtered;
|
|
902
|
-
}
|
|
810
|
+
}
|
|
811
|
+
else {
|
|
903
812
|
response.skipResponse = true;
|
|
904
813
|
}
|
|
905
814
|
return;
|
|
906
815
|
}
|
|
907
|
-
|
|
908
816
|
if (description === 'SELECT PERMANENTFLAGS') {
|
|
909
817
|
// RFC 4314 section 5.1.1: PERMANENTFLAGS MUST reflect the rights of the user
|
|
910
818
|
const section = response.attributes[0] && response.attributes[0].section;
|
|
911
819
|
const rights = getSelectedRights(connection);
|
|
912
820
|
if (section && Array.isArray(section[1])) {
|
|
913
|
-
section[1] = section[1].filter(flag => (flag.value === '\\*' ? rights.has('w') : canSetFlag(rights, flag)));
|
|
821
|
+
section[1] = section[1].filter((flag) => (flag.value === '\\*' ? rights.has('w') : canSetFlag(rights, flag)));
|
|
914
822
|
}
|
|
915
823
|
return;
|
|
916
824
|
}
|
|
917
|
-
|
|
918
825
|
if (extra && extra.targetUids && extra.mailbox && /^(UID )?(COPY|MOVE COPYUID)$/.test(description)) {
|
|
919
826
|
// RFC 4314 section 4: the copies only keep the flags the user has rights for in the target
|
|
920
827
|
const rights = getRights(connection, extra.mailbox);
|
|
921
828
|
const uids = new Set(extra.targetUids);
|
|
922
|
-
extra.mailbox.messages.forEach(message => {
|
|
829
|
+
extra.mailbox.messages.forEach((message) => {
|
|
923
830
|
if (uids.has(message.uid)) {
|
|
924
|
-
message.flags = message.flags.filter(flag => canSetFlag(rights, flag));
|
|
831
|
+
message.flags = message.flags.filter((flag) => canSetFlag(rights, flag));
|
|
925
832
|
}
|
|
926
833
|
});
|
|
927
834
|
}
|
|
928
835
|
});
|
|
929
|
-
|
|
930
836
|
// The DELETE command MUST delete the ACL of the mailbox (RFC 4314 section 4), this matters when a
|
|
931
837
|
// \Noselect placeholder stays for the children of the mailbox
|
|
838
|
+
// DELETE and CREATE are core commands, so the handlers exist
|
|
932
839
|
const prevDelete = server.getCommandHandler('DELETE');
|
|
933
840
|
server.setCommandHandler('DELETE', (connection, parsed, data, callback) => {
|
|
934
841
|
const mailbox = argumentMailbox(parsed, 0);
|
|
@@ -940,7 +847,6 @@ module.exports = function (server) {
|
|
|
940
847
|
callback();
|
|
941
848
|
});
|
|
942
849
|
});
|
|
943
|
-
|
|
944
850
|
// A new mailbox inherits the ACL of its parent (RFC 4314 section 4, CREATE SHOULD)
|
|
945
851
|
const prevCreate = server.getCommandHandler('CREATE');
|
|
946
852
|
server.setCommandHandler('CREATE', (connection, parsed, data, callback) => {
|
|
@@ -950,15 +856,15 @@ module.exports = function (server) {
|
|
|
950
856
|
.filter(path => !existing.has(path))
|
|
951
857
|
.sort((a, b) => a.length - b.length)
|
|
952
858
|
.forEach(path => {
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
859
|
+
const parent = getParent(path);
|
|
860
|
+
const mailbox = server.folderCache[path];
|
|
861
|
+
if (parent && parent !== mailbox) {
|
|
862
|
+
const acl = new Map();
|
|
863
|
+
getAcl(parent).forEach((rights, identifier) => acl.set(identifier, new Set(rights)));
|
|
864
|
+
mailbox.acl = acl;
|
|
865
|
+
}
|
|
866
|
+
});
|
|
961
867
|
callback();
|
|
962
868
|
});
|
|
963
869
|
});
|
|
964
|
-
}
|
|
870
|
+
}
|