imapflow 1.7.8 → 2.0.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/CHANGELOG.md +20 -0
- package/README.md +8 -2
- package/dist/cjs/charsets.d.ts +1 -0
- package/dist/cjs/charsets.js +294 -0
- package/dist/cjs/commands/append.d.ts +22 -0
- package/dist/cjs/commands/append.js +151 -0
- package/dist/cjs/commands/authenticate.d.ts +24 -0
- package/dist/cjs/commands/authenticate.js +223 -0
- package/dist/cjs/commands/capability.d.ts +8 -0
- package/dist/cjs/commands/capability.js +32 -0
- package/dist/cjs/commands/close.d.ts +8 -0
- package/dist/cjs/commands/close.js +39 -0
- package/dist/cjs/commands/compress.d.ts +8 -0
- package/dist/cjs/commands/compress.js +56 -0
- package/dist/cjs/commands/copy.d.ts +13 -0
- package/dist/cjs/commands/copy.js +44 -0
- package/dist/cjs/commands/copyuid-parser.d.ts +11 -0
- package/dist/cjs/commands/copyuid-parser.js +32 -0
- package/dist/cjs/commands/create.d.ts +11 -0
- package/dist/cjs/commands/create.js +80 -0
- package/dist/cjs/commands/delete.d.ts +11 -0
- package/dist/cjs/commands/delete.js +40 -0
- package/dist/cjs/commands/enable.d.ts +9 -0
- package/dist/cjs/commands/enable.js +61 -0
- package/dist/cjs/commands/esearch-parser.d.ts +17 -0
- package/dist/cjs/commands/esearch-parser.js +91 -0
- package/dist/cjs/commands/expunge.d.ts +12 -0
- package/dist/cjs/commands/expunge.js +60 -0
- package/dist/cjs/commands/fetch.d.ts +30 -0
- package/dist/cjs/commands/fetch.js +241 -0
- package/dist/cjs/commands/id.d.ts +10 -0
- package/dist/cjs/commands/id.js +80 -0
- package/dist/cjs/commands/idle.d.ts +9 -0
- package/dist/cjs/commands/idle.js +347 -0
- package/dist/cjs/commands/list.d.ts +16 -0
- package/dist/cjs/commands/list.js +518 -0
- package/dist/cjs/commands/login.d.ts +11 -0
- package/dist/cjs/commands/login.js +42 -0
- package/dist/cjs/commands/logout.d.ts +8 -0
- package/dist/cjs/commands/logout.js +47 -0
- package/dist/cjs/commands/move.d.ts +13 -0
- package/dist/cjs/commands/move.js +57 -0
- package/dist/cjs/commands/namespace.d.ts +25 -0
- package/dist/cjs/commands/namespace.js +139 -0
- package/dist/cjs/commands/noop.d.ts +8 -0
- package/dist/cjs/commands/noop.js +22 -0
- package/dist/cjs/commands/quota.d.ts +10 -0
- package/dist/cjs/commands/quota.js +119 -0
- package/dist/cjs/commands/rename.d.ts +12 -0
- package/dist/cjs/commands/rename.js +48 -0
- package/dist/cjs/commands/search.d.ts +15 -0
- package/dist/cjs/commands/search.js +228 -0
- package/dist/cjs/commands/select.d.ts +25 -0
- package/dist/cjs/commands/select.js +250 -0
- package/dist/cjs/commands/starttls.d.ts +8 -0
- package/dist/cjs/commands/starttls.js +30 -0
- package/dist/cjs/commands/status-fields.d.ts +14 -0
- package/dist/cjs/commands/status-fields.js +61 -0
- package/dist/cjs/commands/status.d.ts +12 -0
- package/dist/cjs/commands/status.js +108 -0
- package/dist/cjs/commands/store.d.ts +19 -0
- package/dist/cjs/commands/store.js +93 -0
- package/dist/cjs/commands/subscribe.d.ts +9 -0
- package/dist/cjs/commands/subscribe.js +31 -0
- package/dist/cjs/commands/unsubscribe.d.ts +9 -0
- package/dist/cjs/commands/unsubscribe.js +31 -0
- package/dist/cjs/connection-deadline.d.ts +49 -0
- package/dist/cjs/connection-deadline.js +91 -0
- package/dist/cjs/errors.d.ts +83 -0
- package/dist/cjs/errors.js +13 -0
- package/dist/cjs/handler/imap-compiler.d.ts +24 -0
- package/dist/cjs/handler/imap-compiler.js +285 -0
- package/dist/cjs/handler/imap-formal-syntax.d.ts +28 -0
- package/dist/cjs/handler/imap-formal-syntax.js +121 -0
- package/dist/cjs/handler/imap-handler.d.ts +9 -0
- package/dist/cjs/handler/imap-handler.js +10 -0
- package/dist/cjs/handler/imap-parser.d.ts +16 -0
- package/dist/cjs/handler/imap-parser.js +90 -0
- package/dist/cjs/handler/imap-stream.d.ts +181 -0
- package/dist/cjs/handler/imap-stream.js +446 -0
- package/dist/cjs/handler/limits.d.ts +25 -0
- package/dist/cjs/handler/limits.js +51 -0
- package/dist/cjs/handler/parser-instance.d.ts +68 -0
- package/dist/cjs/handler/parser-instance.js +223 -0
- package/dist/cjs/handler/token-parser.d.ts +91 -0
- package/dist/cjs/handler/token-parser.js +673 -0
- package/dist/cjs/handler/types.d.ts +91 -0
- package/dist/cjs/handler/types.js +4 -0
- package/dist/cjs/imap-commands.d.ts +16 -0
- package/dist/cjs/imap-commands.js +74 -0
- package/dist/cjs/imap-flow.d.ts +676 -0
- package/dist/cjs/imap-flow.js +3949 -0
- package/dist/cjs/jp-decoder.d.ts +12 -0
- package/dist/cjs/jp-decoder.js +79 -0
- package/dist/cjs/limited-passthrough.d.ts +25 -0
- package/dist/cjs/limited-passthrough.js +54 -0
- package/dist/cjs/logger.d.ts +3 -0
- package/dist/cjs/logger.js +11 -0
- package/dist/cjs/package-info.d.ts +3 -0
- package/dist/cjs/package-info.js +7 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/proxy-connection.d.ts +33 -0
- package/dist/cjs/proxy-connection.js +392 -0
- package/dist/cjs/search-compiler.d.ts +34 -0
- package/dist/cjs/search-compiler.js +476 -0
- package/dist/cjs/special-use.d.ts +22 -0
- package/dist/cjs/special-use.js +911 -0
- package/dist/cjs/tools.d.ts +427 -0
- package/dist/cjs/tools.js +1496 -0
- package/{lib/imap-flow.d.ts → dist/cjs/types.d.ts} +386 -516
- package/dist/cjs/types.js +5 -0
- package/dist/esm/charsets.d.ts +1 -0
- package/{lib → dist/esm}/charsets.js +1 -6
- package/dist/esm/commands/append.d.ts +22 -0
- package/{lib → dist/esm}/commands/append.js +22 -52
- package/dist/esm/commands/authenticate.d.ts +24 -0
- package/{lib → dist/esm}/commands/authenticate.js +62 -87
- package/dist/esm/commands/capability.d.ts +8 -0
- package/{lib → dist/esm}/commands/capability.js +6 -9
- package/dist/esm/commands/close.d.ts +8 -0
- package/{lib → dist/esm}/commands/close.js +6 -10
- package/dist/esm/commands/compress.d.ts +8 -0
- package/{lib → dist/esm}/commands/compress.js +7 -11
- package/dist/esm/commands/copy.d.ts +13 -0
- package/{lib → dist/esm}/commands/copy.js +12 -20
- package/dist/esm/commands/copyuid-parser.d.ts +11 -0
- package/{lib → dist/esm}/commands/copyuid-parser.js +9 -15
- package/dist/esm/commands/create.d.ts +11 -0
- package/{lib → dist/esm}/commands/create.js +13 -27
- package/dist/esm/commands/delete.d.ts +11 -0
- package/{lib → dist/esm}/commands/delete.js +9 -14
- package/dist/esm/commands/enable.d.ts +9 -0
- package/{lib → dist/esm}/commands/enable.js +23 -30
- package/dist/esm/commands/esearch-parser.d.ts +17 -0
- package/dist/esm/commands/esearch-parser.js +88 -0
- package/dist/esm/commands/expunge.d.ts +12 -0
- package/{lib → dist/esm}/commands/expunge.js +17 -22
- package/dist/esm/commands/fetch.d.ts +30 -0
- package/{lib → dist/esm}/commands/fetch.js +32 -64
- package/dist/esm/commands/id.d.ts +10 -0
- package/{lib → dist/esm}/commands/id.js +17 -23
- package/dist/esm/commands/idle.d.ts +9 -0
- package/{lib → dist/esm}/commands/idle.js +47 -81
- package/dist/esm/commands/list.d.ts +16 -0
- package/{lib → dist/esm}/commands/list.js +56 -121
- package/dist/esm/commands/login.d.ts +11 -0
- package/{lib → dist/esm}/commands/login.js +10 -15
- package/dist/esm/commands/logout.d.ts +8 -0
- package/{lib → dist/esm}/commands/logout.js +9 -11
- package/dist/esm/commands/move.d.ts +13 -0
- package/{lib → dist/esm}/commands/move.js +13 -21
- package/dist/esm/commands/namespace.d.ts +25 -0
- package/{lib → dist/esm}/commands/namespace.js +34 -44
- package/dist/esm/commands/noop.d.ts +8 -0
- package/{lib → dist/esm}/commands/noop.js +6 -7
- package/dist/esm/commands/quota.d.ts +10 -0
- package/{lib → dist/esm}/commands/quota.js +18 -36
- package/dist/esm/commands/rename.d.ts +12 -0
- package/{lib → dist/esm}/commands/rename.js +10 -15
- package/dist/esm/commands/search.d.ts +15 -0
- package/{lib → dist/esm}/commands/search.js +36 -135
- package/dist/esm/commands/select.d.ts +25 -0
- package/{lib → dist/esm}/commands/select.js +33 -64
- package/dist/esm/commands/starttls.d.ts +8 -0
- package/{lib → dist/esm}/commands/starttls.js +6 -8
- package/dist/esm/commands/status-fields.d.ts +14 -0
- package/{lib → dist/esm}/commands/status-fields.js +5 -16
- package/dist/esm/commands/status.d.ts +12 -0
- package/{lib → dist/esm}/commands/status.js +18 -29
- package/dist/esm/commands/store.d.ts +19 -0
- package/{lib → dist/esm}/commands/store.js +24 -37
- package/dist/esm/commands/subscribe.d.ts +9 -0
- package/{lib → dist/esm}/commands/subscribe.js +8 -12
- package/dist/esm/commands/unsubscribe.d.ts +9 -0
- package/{lib → dist/esm}/commands/unsubscribe.js +8 -12
- package/dist/esm/connection-deadline.d.ts +49 -0
- package/{lib → dist/esm}/connection-deadline.js +14 -25
- package/dist/esm/errors.d.ts +83 -0
- package/dist/esm/errors.js +9 -0
- package/dist/esm/handler/imap-compiler.d.ts +24 -0
- package/{lib → dist/esm}/handler/imap-compiler.js +22 -80
- package/dist/esm/handler/imap-formal-syntax.d.ts +28 -0
- package/dist/esm/handler/imap-formal-syntax.js +117 -0
- package/dist/esm/handler/imap-handler.d.ts +9 -0
- package/dist/esm/handler/imap-handler.js +9 -0
- package/dist/esm/handler/imap-parser.d.ts +16 -0
- package/{lib → dist/esm}/handler/imap-parser.js +31 -44
- package/dist/esm/handler/imap-stream.d.ts +181 -0
- package/{lib → dist/esm}/handler/imap-stream.js +29 -121
- package/dist/esm/handler/limits.d.ts +25 -0
- package/{lib → dist/esm}/handler/limits.js +13 -22
- package/dist/esm/handler/parser-instance.d.ts +68 -0
- package/{lib → dist/esm}/handler/parser-instance.js +19 -47
- package/dist/esm/handler/token-parser.d.ts +91 -0
- package/{lib → dist/esm}/handler/token-parser.js +71 -155
- package/dist/esm/handler/types.d.ts +91 -0
- package/dist/esm/handler/types.js +3 -0
- package/dist/esm/imap-commands.d.ts +16 -0
- package/dist/esm/imap-commands.js +67 -0
- package/dist/esm/imap-flow.d.ts +676 -0
- package/{lib → dist/esm}/imap-flow.js +761 -1789
- package/dist/esm/jp-decoder.d.ts +12 -0
- package/{lib → dist/esm}/jp-decoder.js +6 -21
- package/dist/esm/limited-passthrough.d.ts +25 -0
- package/{lib → dist/esm}/limited-passthrough.js +7 -20
- package/dist/esm/logger.d.ts +3 -0
- package/dist/esm/logger.js +4 -0
- package/dist/esm/package-info.d.ts +3 -0
- package/dist/esm/package-info.js +4 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/proxy-connection.d.ts +33 -0
- package/{lib → dist/esm}/proxy-connection.js +56 -127
- package/dist/esm/search-compiler.d.ts +34 -0
- package/{lib → dist/esm}/search-compiler.js +54 -110
- package/dist/esm/special-use.d.ts +22 -0
- package/dist/esm/special-use.js +907 -0
- package/dist/esm/tools.d.ts +427 -0
- package/dist/esm/tools.js +1446 -0
- package/dist/esm/types.d.ts +828 -0
- package/dist/esm/types.js +4 -0
- package/package.json +60 -20
- package/.gitattributes +0 -1
- package/.github/CODE_OF_CONDUCT.md +0 -76
- package/.github/FUNDING.yml +0 -4
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -40
- package/.github/ISSUE_TEMPLATE/feature_request.md +0 -19
- package/.github/contributing.md +0 -17
- package/.github/workflows/release.yaml +0 -36
- package/.github/workflows/stale.yml +0 -29
- package/.github/workflows/test.yml +0 -51
- package/.ncurc.js +0 -4
- package/.prettierignore +0 -4
- package/.prettierrc.js +0 -8
- package/.release-please-manifest.json +0 -3
- package/CLAUDE.md +0 -104
- package/Gruntfile.js +0 -23
- package/eslint.config.js +0 -45
- package/lib/handler/imap-formal-syntax.js +0 -189
- package/lib/handler/imap-handler.js +0 -17
- package/lib/imap-commands.js +0 -45
- package/lib/logger.js +0 -5
- package/lib/special-use.js +0 -923
- package/lib/tools.js +0 -1612
- package/release-please-config.json +0 -10
- package/test/authentication-test.js +0 -101
- package/test/auto-idle-test.js +0 -470
- package/test/bodystructure-test.js +0 -899
- package/test/charsets-test.js +0 -161
- package/test/commands-branches-test.js +0 -1095
- package/test/commands-integration-test.js +0 -11124
- package/test/commands-test.js +0 -73
- package/test/connection-edge-cases-test.js +0 -1828
- package/test/connection-test.js +0 -162
- package/test/copyuid-parser-test.js +0 -173
- package/test/fetch-generator-test.js +0 -218
- package/test/fixtures/fake-timers.js +0 -115
- package/test/fixtures/serialized-mimetorture.js +0 -2738
- package/test/fixtures/test-client.js +0 -101
- package/test/fixtures/test-tls.js +0 -8
- package/test/handler-branches-test.js +0 -310
- package/test/idle-polling-test.js +0 -518
- package/test/imap-compiler-test.js +0 -809
- package/test/imap-flow-compress-test.js +0 -166
- package/test/imap-flow-coverage-test.js +0 -612
- package/test/imap-flow-fetch-download-test.js +0 -909
- package/test/imap-flow-internals-test.js +0 -725
- package/test/imap-flow-methods-test.js +0 -889
- package/test/imap-flow-proxy-paths-test.js +0 -366
- package/test/imap-flow-secure-test.js +0 -573
- package/test/imap-flow-server-test.js +0 -1474
- package/test/imap-formal-syntax-test.js +0 -293
- package/test/imap-parser-test.js +0 -1474
- package/test/imap-stream-edge-cases-test.js +0 -666
- package/test/imap-stream-test.js +0 -177
- package/test/imapflow-test.js +0 -258
- package/test/integration/README.md +0 -52
- package/test/integration/dovecot-test.conf +0 -27
- package/test/integration/rev2-live-test.js +0 -431
- package/test/integration/run-rev2-tests.sh +0 -75
- package/test/integration-test.js +0 -83
- package/test/jp-decoder-test.js +0 -304
- package/test/limited-passthrough-test.js +0 -299
- package/test/memory-cleanup-test.js +0 -144
- package/test/memory-leak-test.js +0 -667
- package/test/parser-limits-test.js +0 -292
- package/test/proxy-connection-test.js +0 -738
- package/test/reliability-improvements-test.js +0 -548
- package/test/search-compiler-test.js +0 -1300
- package/test/search-test.js +0 -329
- package/test/special-use-test.js +0 -418
- package/test/starttls-injection-test.js +0 -181
- package/test/tag-correlation-test.js +0 -333
- package/test/timer-policy-test.js +0 -227
- package/test/token-parser-test.js +0 -456
- package/test/tools-test.js +0 -2013
- package/test/unhandled-rejection-test.js +0 -661
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ImapFlow } from '../imap-flow.js';
|
|
2
|
+
import type { CopyResponseObject, MessageRangeOptions } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Moves messages from the current mailbox to another mailbox.
|
|
5
|
+
*
|
|
6
|
+
* @param connection - IMAP connection instance
|
|
7
|
+
* @param range - Message sequence number or UID range
|
|
8
|
+
* @param destination - Destination mailbox path
|
|
9
|
+
* @param options - Move options
|
|
10
|
+
* @param options.uid - If true, use UID MOVE instead of MOVE
|
|
11
|
+
* @returns Move result with UID mapping if available, false on failure, or undefined if preconditions not met
|
|
12
|
+
*/
|
|
13
|
+
export default function move(connection: ImapFlow, range: string, destination: string | string[], options?: MessageRangeOptions | undefined): Promise<CopyResponseObject | false | undefined>;
|
|
@@ -1,34 +1,27 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const { normalizePath, encodePath, enhanceCommandError, hasCapability } = require('../tools.js');
|
|
4
|
-
const { parseCopyUid } = require('./copyuid-parser.js');
|
|
5
|
-
|
|
1
|
+
import { normalizePath, encodePath, enhanceCommandError, hasCapability } from '../tools.js';
|
|
2
|
+
import { parseCopyUid } from './copyuid-parser.js';
|
|
6
3
|
/**
|
|
7
4
|
* Moves messages from the current mailbox to another mailbox.
|
|
8
5
|
*
|
|
9
|
-
* @param
|
|
10
|
-
* @param
|
|
11
|
-
* @param
|
|
12
|
-
* @param
|
|
13
|
-
* @param
|
|
14
|
-
* @returns
|
|
6
|
+
* @param connection - IMAP connection instance
|
|
7
|
+
* @param range - Message sequence number or UID range
|
|
8
|
+
* @param destination - Destination mailbox path
|
|
9
|
+
* @param options - Move options
|
|
10
|
+
* @param options.uid - If true, use UID MOVE instead of MOVE
|
|
11
|
+
* @returns Move result with UID mapping if available, false on failure, or undefined if preconditions not met
|
|
15
12
|
*/
|
|
16
|
-
|
|
13
|
+
export default async function move(connection, range, destination, options) {
|
|
17
14
|
if (connection.state !== connection.states.SELECTED || !range || !destination) {
|
|
18
15
|
// nothing to do here
|
|
19
16
|
return;
|
|
20
17
|
}
|
|
21
|
-
|
|
22
18
|
options = options || {};
|
|
23
19
|
destination = normalizePath(connection, destination);
|
|
24
|
-
|
|
25
20
|
let attributes = [
|
|
26
21
|
{ type: 'SEQUENCE', value: range },
|
|
27
22
|
{ type: 'ATOM', value: encodePath(connection, destination) }
|
|
28
23
|
];
|
|
29
|
-
|
|
30
24
|
let map = { path: connection.mailbox.path, destination };
|
|
31
|
-
|
|
32
25
|
// Fallback for servers without the MOVE extension (RFC 6851):
|
|
33
26
|
// emulate MOVE using COPY + flag as \Deleted + EXPUNGE.
|
|
34
27
|
if (!hasCapability(connection, 'MOVE')) {
|
|
@@ -36,25 +29,24 @@ module.exports = async (connection, range, destination, options) => {
|
|
|
36
29
|
await connection.messageDelete(range, Object.assign({ silent: true }, options));
|
|
37
30
|
return result;
|
|
38
31
|
}
|
|
39
|
-
|
|
40
32
|
let response;
|
|
41
33
|
try {
|
|
42
34
|
// Some servers send COPYUID in an untagged OK before the tagged response,
|
|
43
35
|
// others include it in the tagged OK. We check both to be safe.
|
|
44
36
|
response = await connection.exec(options.uid ? 'UID MOVE' : 'MOVE', attributes, {
|
|
45
37
|
untagged: {
|
|
46
|
-
OK: async untagged => {
|
|
38
|
+
OK: async (untagged) => {
|
|
47
39
|
parseCopyUid(untagged, map);
|
|
48
40
|
}
|
|
49
41
|
}
|
|
50
42
|
});
|
|
51
43
|
response.next();
|
|
52
|
-
|
|
53
44
|
parseCopyUid(response.response, map);
|
|
54
45
|
return map;
|
|
55
|
-
}
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
56
48
|
await enhanceCommandError(err);
|
|
57
49
|
connection.log.warn({ err, cid: connection.id });
|
|
58
50
|
return false;
|
|
59
51
|
}
|
|
60
|
-
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ImapFlow } from '../imap-flow.js';
|
|
2
|
+
import type { NamespaceObject } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Returned instead of a namespace when the NAMESPACE command failed
|
|
5
|
+
*/
|
|
6
|
+
export interface NamespaceErrorResult {
|
|
7
|
+
error: true;
|
|
8
|
+
status: string | undefined;
|
|
9
|
+
text: string | undefined;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Prefix and delimiter derived from `LIST "" ""`
|
|
13
|
+
*/
|
|
14
|
+
export interface ListPrefixInfo {
|
|
15
|
+
flags?: Set<string> | undefined;
|
|
16
|
+
delimiter?: string | null | undefined;
|
|
17
|
+
prefix?: string | undefined;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Requests NAMESPACE info from the server.
|
|
21
|
+
*
|
|
22
|
+
* @param connection - IMAP connection instance
|
|
23
|
+
* @returns The primary personal namespace, or an error object on failure
|
|
24
|
+
*/
|
|
25
|
+
export default function namespace(connection: ImapFlow): Promise<NamespaceObject | NamespaceErrorResult | undefined>;
|
|
@@ -1,19 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const { hasCapability, getStringList } = require('../tools.js');
|
|
4
|
-
|
|
1
|
+
import { hasCapability, getStringList } from '../tools.js';
|
|
5
2
|
/**
|
|
6
3
|
* Requests NAMESPACE info from the server.
|
|
7
4
|
*
|
|
8
|
-
* @param
|
|
9
|
-
* @returns
|
|
5
|
+
* @param connection - IMAP connection instance
|
|
6
|
+
* @returns The primary personal namespace, or an error object on failure
|
|
10
7
|
*/
|
|
11
|
-
|
|
8
|
+
export default async function namespace(connection) {
|
|
12
9
|
if (![connection.states.AUTHENTICATED, connection.states.SELECTED].includes(connection.state)) {
|
|
13
10
|
// nothing to do here
|
|
14
11
|
return;
|
|
15
12
|
}
|
|
16
|
-
|
|
17
13
|
if (!hasCapability(connection, 'NAMESPACE')) {
|
|
18
14
|
// Fallback: when the server does not support the NAMESPACE extension (RFC 2342),
|
|
19
15
|
// derive the prefix and delimiter from a LIST "" "" command, which returns
|
|
@@ -33,7 +29,6 @@ module.exports = async connection => {
|
|
|
33
29
|
connection.namespace = connection.namespaces.personal[0];
|
|
34
30
|
return connection.namespace;
|
|
35
31
|
}
|
|
36
|
-
|
|
37
32
|
let response;
|
|
38
33
|
try {
|
|
39
34
|
let map = {};
|
|
@@ -44,7 +39,7 @@ module.exports = async connection => {
|
|
|
44
39
|
// [1] = other users' namespaces (shared by other users)
|
|
45
40
|
// [2] = shared namespaces (public/organizational folders)
|
|
46
41
|
// Each section is either NIL or a list of (prefix, delimiter) pairs.
|
|
47
|
-
NAMESPACE: async untagged => {
|
|
42
|
+
NAMESPACE: async (untagged) => {
|
|
48
43
|
if (!untagged.attributes || !untagged.attributes.length) {
|
|
49
44
|
return;
|
|
50
45
|
}
|
|
@@ -55,18 +50,16 @@ module.exports = async connection => {
|
|
|
55
50
|
}
|
|
56
51
|
});
|
|
57
52
|
connection.namespaces = map;
|
|
58
|
-
|
|
59
53
|
// make sure that we have the first personal namespace always set
|
|
60
54
|
if (!connection.namespaces.personal[0]) {
|
|
61
55
|
connection.namespaces.personal[0] = { prefix: '', delimiter: '.' };
|
|
62
56
|
}
|
|
63
57
|
connection.namespaces.personal[0].prefix = connection.namespaces.personal[0].prefix || '';
|
|
64
58
|
response.next();
|
|
65
|
-
|
|
66
59
|
connection.namespace = connection.namespaces.personal[0];
|
|
67
|
-
|
|
68
60
|
return connection.namespace;
|
|
69
|
-
}
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
70
63
|
connection.log.warn({ err, cid: connection.id });
|
|
71
64
|
return {
|
|
72
65
|
error: true,
|
|
@@ -74,13 +67,12 @@ module.exports = async connection => {
|
|
|
74
67
|
text: err.responseText
|
|
75
68
|
};
|
|
76
69
|
}
|
|
77
|
-
}
|
|
78
|
-
|
|
70
|
+
}
|
|
79
71
|
/**
|
|
80
72
|
* Derives namespace prefix and delimiter from a LIST command when NAMESPACE is not supported.
|
|
81
73
|
*
|
|
82
|
-
* @param
|
|
83
|
-
* @returns
|
|
74
|
+
* @param connection - IMAP connection instance
|
|
75
|
+
* @returns Object with prefix, delimiter, and flags, or empty object on failure
|
|
84
76
|
*/
|
|
85
77
|
async function getListPrefix(connection) {
|
|
86
78
|
let response;
|
|
@@ -90,14 +82,13 @@ async function getListPrefix(connection) {
|
|
|
90
82
|
// and the root name, without listing any actual mailboxes.
|
|
91
83
|
response = await connection.exec('LIST', ['', ''], {
|
|
92
84
|
untagged: {
|
|
93
|
-
LIST: async untagged => {
|
|
85
|
+
LIST: async (untagged) => {
|
|
94
86
|
if (!untagged.attributes || !untagged.attributes.length) {
|
|
95
87
|
return;
|
|
96
88
|
}
|
|
97
|
-
|
|
98
89
|
map.flags = new Set(getStringList(untagged.attributes[0]));
|
|
99
|
-
map.delimiter = untagged.attributes[1] && untagged.attributes[1].value;
|
|
100
|
-
map.prefix = (untagged.attributes[2] && untagged.attributes[2].value) || '';
|
|
90
|
+
map.delimiter = (untagged.attributes[1] && untagged.attributes[1].value);
|
|
91
|
+
map.prefix = ((untagged.attributes[2] && untagged.attributes[2].value) || '');
|
|
101
92
|
if (map.delimiter && map.prefix.charAt(0) === map.delimiter) {
|
|
102
93
|
map.prefix = map.prefix.slice(1);
|
|
103
94
|
}
|
|
@@ -106,39 +97,38 @@ async function getListPrefix(connection) {
|
|
|
106
97
|
});
|
|
107
98
|
response.next();
|
|
108
99
|
return map;
|
|
109
|
-
}
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
110
102
|
connection.log.warn({ err, cid: connection.id });
|
|
111
103
|
return {};
|
|
112
104
|
}
|
|
113
105
|
}
|
|
114
|
-
|
|
115
106
|
/**
|
|
116
107
|
* Parses namespace information from an IMAP NAMESPACE response attribute.
|
|
117
108
|
*
|
|
118
|
-
* @param
|
|
119
|
-
* @returns
|
|
109
|
+
* @param attribute - Namespace attribute array from the server response
|
|
110
|
+
* @returns Array of namespace entries, or false if empty
|
|
120
111
|
*/
|
|
121
112
|
function getNamsepaceInfo(attribute) {
|
|
122
|
-
if (!attribute || !attribute.length) {
|
|
113
|
+
if (!attribute || !Array.isArray(attribute) || !attribute.length) {
|
|
123
114
|
return false;
|
|
124
115
|
}
|
|
125
|
-
|
|
126
116
|
return attribute
|
|
127
|
-
.filter(
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
117
|
+
.filter(entry => {
|
|
118
|
+
let pair = entry;
|
|
119
|
+
// RFC 2342 section 5 allows the delimiter to be NIL when the namespace has
|
|
120
|
+
// no hierarchy. The token parser emits a literal `null` for NIL.
|
|
121
|
+
return pair.length >= 2 && pair[0] && typeof pair[0].value === 'string' && (pair[1] === null || (pair[1] && typeof pair[1].value === 'string'));
|
|
122
|
+
})
|
|
133
123
|
.map(entry => {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
124
|
+
let pair = entry;
|
|
125
|
+
let prefix = pair[0].value;
|
|
126
|
+
let delimiter = pair[1] === null ? null : pair[1].value;
|
|
127
|
+
// Append the delimiter to the prefix if it doesn't already end with one,
|
|
128
|
+
// so callers can construct full paths by simply concatenating prefix + name.
|
|
129
|
+
if (delimiter && prefix && prefix.charAt(prefix.length - 1) !== delimiter) {
|
|
130
|
+
prefix += delimiter;
|
|
131
|
+
}
|
|
132
|
+
return { prefix, delimiter };
|
|
133
|
+
});
|
|
144
134
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ImapFlow } from '../imap-flow.js';
|
|
2
|
+
/**
|
|
3
|
+
* Sends a NOOP command to the server.
|
|
4
|
+
*
|
|
5
|
+
* @param connection - IMAP connection instance
|
|
6
|
+
* @returns True on success, false on failure
|
|
7
|
+
*/
|
|
8
|
+
export default function noop(connection: ImapFlow): Promise<boolean>;
|
|
@@ -1,18 +1,17 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
2
|
* Sends a NOOP command to the server.
|
|
5
3
|
*
|
|
6
|
-
* @param
|
|
7
|
-
* @returns
|
|
4
|
+
* @param connection - IMAP connection instance
|
|
5
|
+
* @returns True on success, false on failure
|
|
8
6
|
*/
|
|
9
|
-
|
|
7
|
+
export default async function noop(connection) {
|
|
10
8
|
try {
|
|
11
9
|
let response = await connection.exec('NOOP', false, { comment: 'Requested by command' });
|
|
12
10
|
response.next();
|
|
13
11
|
return true;
|
|
14
|
-
}
|
|
12
|
+
}
|
|
13
|
+
catch (err) {
|
|
15
14
|
connection.log.warn({ err, cid: connection.id });
|
|
16
15
|
return false;
|
|
17
16
|
}
|
|
18
|
-
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ImapFlow } from '../imap-flow.js';
|
|
2
|
+
import type { QuotaResponse } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Requests quota information for a mailbox.
|
|
5
|
+
*
|
|
6
|
+
* @param connection - IMAP connection instance
|
|
7
|
+
* @param path - Mailbox path to query quota for
|
|
8
|
+
* @returns Quota information object, false if QUOTA not supported or on failure, or undefined if preconditions not met
|
|
9
|
+
*/
|
|
10
|
+
export default function quota(connection: ImapFlow, path: string | string[]): Promise<QuotaResponse | false | undefined>;
|
|
@@ -1,75 +1,61 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const { encodePath, normalizePath, enhanceCommandError, parseUintValue, isUnsafeKey } = require('../tools.js');
|
|
4
|
-
|
|
1
|
+
import { encodePath, normalizePath, enhanceCommandError, parseUintValue, isUnsafeKey } from '../tools.js';
|
|
5
2
|
/**
|
|
6
3
|
* Requests quota information for a mailbox.
|
|
7
4
|
*
|
|
8
|
-
* @param
|
|
9
|
-
* @param
|
|
10
|
-
* @returns
|
|
5
|
+
* @param connection - IMAP connection instance
|
|
6
|
+
* @param path - Mailbox path to query quota for
|
|
7
|
+
* @returns Quota information object, false if QUOTA not supported or on failure, or undefined if preconditions not met
|
|
11
8
|
*/
|
|
12
|
-
|
|
9
|
+
export default async function quota(connection, path) {
|
|
13
10
|
if (![connection.states.AUTHENTICATED, connection.states.SELECTED].includes(connection.state) || !path) {
|
|
14
11
|
// nothing to do here
|
|
15
12
|
return;
|
|
16
13
|
}
|
|
17
|
-
|
|
18
14
|
if (!connection.capabilities.has('QUOTA')) {
|
|
19
15
|
return false;
|
|
20
16
|
}
|
|
21
|
-
|
|
22
17
|
path = normalizePath(connection, path);
|
|
23
|
-
|
|
24
18
|
let map = { path };
|
|
25
|
-
|
|
26
19
|
// Parse a QUOTA response. The resource list uses a repeating triplet pattern (i % 3):
|
|
27
20
|
// position 0: resource name (e.g., "STORAGE", "MESSAGE")
|
|
28
21
|
// position 1: current usage
|
|
29
22
|
// position 2: limit
|
|
30
23
|
// Storage values are in KB on the wire; multiply by 1024 to report bytes.
|
|
31
|
-
let processQuotaResponse = untagged => {
|
|
24
|
+
let processQuotaResponse = (untagged) => {
|
|
32
25
|
let attributes = untagged.attributes && untagged.attributes[1];
|
|
33
|
-
if (!attributes || !attributes.length) {
|
|
26
|
+
if (!attributes || !Array.isArray(attributes) || !attributes.length) {
|
|
34
27
|
return false;
|
|
35
28
|
}
|
|
36
|
-
|
|
37
29
|
let key = false;
|
|
38
30
|
attributes.forEach((attribute, i) => {
|
|
39
31
|
const position = i % 3;
|
|
40
|
-
|
|
41
32
|
if (position === 0) {
|
|
42
33
|
key = attribute && typeof attribute.value === 'string' ? attribute.value.toLowerCase() : false;
|
|
43
34
|
return;
|
|
44
35
|
}
|
|
45
|
-
|
|
46
36
|
if (!key) {
|
|
47
37
|
return;
|
|
48
38
|
}
|
|
49
|
-
|
|
50
39
|
// isNaN() also passes '1e5', ' 12 ' and 'Infinity', none of which is a usable octet count
|
|
51
40
|
let value = parseUintValue(attribute && attribute.value);
|
|
52
41
|
if (value === false) {
|
|
53
42
|
return;
|
|
54
43
|
}
|
|
55
|
-
|
|
56
44
|
// Resource names are server-controlled. This object is returned to the caller, so it
|
|
57
45
|
// keeps a normal prototype and unsafe names are dropped instead; the fixed fields
|
|
58
46
|
// must keep their values too.
|
|
59
47
|
if (isUnsafeKey(key) || key === 'path' || key === 'quotaroot') {
|
|
60
48
|
return;
|
|
61
49
|
}
|
|
62
|
-
|
|
63
50
|
if (!map[key]) {
|
|
64
51
|
map[key] = {};
|
|
65
52
|
}
|
|
66
|
-
|
|
67
53
|
// Storage quota is reported in KB by IMAP; convert to bytes for consistency
|
|
68
54
|
const multiplier = key === 'storage' ? 1024 : 1;
|
|
69
|
-
|
|
70
55
|
if (position === 1) {
|
|
71
56
|
map[key].usage = value * multiplier;
|
|
72
|
-
}
|
|
57
|
+
}
|
|
58
|
+
else if (position === 2) {
|
|
73
59
|
map[key].limit = value * multiplier;
|
|
74
60
|
// Calculate usage percentage for convenient display
|
|
75
61
|
if (map[key].limit) {
|
|
@@ -78,7 +64,6 @@ module.exports = async (connection, path) => {
|
|
|
78
64
|
}
|
|
79
65
|
});
|
|
80
66
|
};
|
|
81
|
-
|
|
82
67
|
let quotaFound = false;
|
|
83
68
|
let response;
|
|
84
69
|
try {
|
|
@@ -89,31 +74,28 @@ module.exports = async (connection, path) => {
|
|
|
89
74
|
untagged: {
|
|
90
75
|
// QUOTAROOT response tells us which quota root applies to this mailbox.
|
|
91
76
|
// A mailbox may have zero or one quota root.
|
|
92
|
-
QUOTAROOT: async untagged => {
|
|
93
|
-
let quotaRoot =
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
: false;
|
|
77
|
+
QUOTAROOT: async (untagged) => {
|
|
78
|
+
let quotaRoot = untagged.attributes && untagged.attributes[1] && typeof untagged.attributes[1].value === 'string'
|
|
79
|
+
? untagged.attributes[1].value
|
|
80
|
+
: false;
|
|
97
81
|
if (quotaRoot) {
|
|
98
82
|
map.quotaRoot = quotaRoot;
|
|
99
83
|
}
|
|
100
84
|
},
|
|
101
85
|
// QUOTA response provides the actual resource usage and limits
|
|
102
|
-
QUOTA: async untagged => {
|
|
86
|
+
QUOTA: async (untagged) => {
|
|
103
87
|
quotaFound = true;
|
|
104
88
|
processQuotaResponse(untagged);
|
|
105
89
|
}
|
|
106
90
|
}
|
|
107
91
|
});
|
|
108
|
-
|
|
109
92
|
response.next();
|
|
110
|
-
|
|
111
93
|
// Fallback: if we got a quota root but no QUOTA response inline,
|
|
112
94
|
// explicitly request quota for that root.
|
|
113
95
|
if (map.quotaRoot && !quotaFound) {
|
|
114
96
|
response = await connection.exec('GETQUOTA', [{ type: 'ATOM', value: map.quotaRoot }], {
|
|
115
97
|
untagged: {
|
|
116
|
-
QUOTA: async untagged => {
|
|
98
|
+
QUOTA: async (untagged) => {
|
|
117
99
|
processQuotaResponse(untagged);
|
|
118
100
|
}
|
|
119
101
|
}
|
|
@@ -122,11 +104,11 @@ module.exports = async (connection, path) => {
|
|
|
122
104
|
// waits for the response to be handed back before parsing any further input.
|
|
123
105
|
response.next();
|
|
124
106
|
}
|
|
125
|
-
|
|
126
107
|
return map;
|
|
127
|
-
}
|
|
108
|
+
}
|
|
109
|
+
catch (err) {
|
|
128
110
|
await enhanceCommandError(err);
|
|
129
111
|
connection.log.warn({ err, cid: connection.id });
|
|
130
112
|
return false;
|
|
131
113
|
}
|
|
132
|
-
}
|
|
114
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ImapFlow } from '../imap-flow.js';
|
|
2
|
+
import type { MailboxRenameResponse } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Renames an existing mailbox.
|
|
5
|
+
*
|
|
6
|
+
* @param connection - IMAP connection instance
|
|
7
|
+
* @param path - Current mailbox path
|
|
8
|
+
* @param newPath - New mailbox path
|
|
9
|
+
* @returns Object with old and new paths, or undefined if preconditions not met
|
|
10
|
+
* @throws If the RENAME command fails
|
|
11
|
+
*/
|
|
12
|
+
export default function rename(connection: ImapFlow, path: string | string[], newPath: string | string[]): Promise<MailboxRenameResponse | undefined>;
|
|
@@ -1,33 +1,27 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const { encodePath, normalizePath, enhanceCommandError } = require('../tools.js');
|
|
4
|
-
|
|
1
|
+
import { encodePath, normalizePath, enhanceCommandError } from '../tools.js';
|
|
5
2
|
/**
|
|
6
3
|
* Renames an existing mailbox.
|
|
7
4
|
*
|
|
8
|
-
* @param
|
|
9
|
-
* @param
|
|
10
|
-
* @param
|
|
11
|
-
* @returns
|
|
12
|
-
* @throws
|
|
5
|
+
* @param connection - IMAP connection instance
|
|
6
|
+
* @param path - Current mailbox path
|
|
7
|
+
* @param newPath - New mailbox path
|
|
8
|
+
* @returns Object with old and new paths, or undefined if preconditions not met
|
|
9
|
+
* @throws If the RENAME command fails
|
|
13
10
|
*/
|
|
14
|
-
|
|
11
|
+
export default async function rename(connection, path, newPath) {
|
|
15
12
|
if (![connection.states.AUTHENTICATED, connection.states.SELECTED].includes(connection.state)) {
|
|
16
13
|
// nothing to do here
|
|
17
14
|
return;
|
|
18
15
|
}
|
|
19
|
-
|
|
20
16
|
// Normalize both paths (resolve special names, apply namespace prefix) and encode
|
|
21
17
|
// them for the IMAP wire format (modified UTF-7 for non-ASCII characters).
|
|
22
18
|
path = normalizePath(connection, path);
|
|
23
19
|
newPath = normalizePath(connection, newPath);
|
|
24
|
-
|
|
25
20
|
// Must close/deselect the mailbox before renaming if it's currently selected,
|
|
26
21
|
// as IMAP servers will not rename an active mailbox.
|
|
27
22
|
if (connection.state === connection.states.SELECTED && connection.mailbox.path === path) {
|
|
28
23
|
await connection.run('CLOSE');
|
|
29
24
|
}
|
|
30
|
-
|
|
31
25
|
let response;
|
|
32
26
|
try {
|
|
33
27
|
let map = {
|
|
@@ -40,9 +34,10 @@ module.exports = async (connection, path, newPath) => {
|
|
|
40
34
|
]);
|
|
41
35
|
response.next();
|
|
42
36
|
return map;
|
|
43
|
-
}
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
44
39
|
await enhanceCommandError(err);
|
|
45
40
|
connection.log.warn({ err, cid: connection.id });
|
|
46
41
|
throw err;
|
|
47
42
|
}
|
|
48
|
-
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ImapFlow } from '../imap-flow.js';
|
|
2
|
+
import type { ESearchResult, SearchObject, SearchOptions } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Searches for messages matching the specified criteria.
|
|
5
|
+
*
|
|
6
|
+
* @param connection - IMAP connection instance
|
|
7
|
+
* @param query - Search query object, or true/empty object to match all messages
|
|
8
|
+
* @param options - Search options
|
|
9
|
+
* @param options.uid - If true, use UID SEARCH instead of SEARCH
|
|
10
|
+
* @param options.returnOptions - ESEARCH RETURN options. When present AND the
|
|
11
|
+
* server advertises ESEARCH capability, triggers ESEARCH and returns an ESearchResult.
|
|
12
|
+
* Items are strings ('MIN','MAX','COUNT','ALL') or objects ({ partial: '1:100' }).
|
|
13
|
+
* When server lacks ESEARCH, falls back to plain SEARCH and returns number[].
|
|
14
|
+
*/
|
|
15
|
+
export default function search(connection: ImapFlow, query: SearchObject | boolean | null | undefined, options?: SearchOptions | undefined): Promise<number[] | ESearchResult | false>;
|