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
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const { guardedPromise, hasCapability, logConnectionError, restampConnectionError, unrefTimer } = require('../tools.js');
|
|
4
|
-
|
|
1
|
+
import { guardedPromise, hasCapability, logConnectionError, restampConnectionError, unrefTimer, clearTimer } from '../tools.js';
|
|
5
2
|
const NOOP_INTERVAL = 2 * 60 * 1000;
|
|
6
|
-
|
|
7
3
|
/**
|
|
8
4
|
* Marks the connection as idling on behalf of one session and returns a release function.
|
|
9
5
|
*
|
|
@@ -11,14 +7,13 @@ const NOOP_INTERVAL = 2 * 60 * 1000;
|
|
|
11
7
|
* finishes late (a poll that completes after cancellation, an IDLE that unwinds after a restart)
|
|
12
8
|
* cannot clear the flag of the session that has since taken over.
|
|
13
9
|
*
|
|
14
|
-
* @param
|
|
15
|
-
* @returns
|
|
10
|
+
* @param connection - IMAP connection instance
|
|
11
|
+
* @returns Release function, safe to call more than once
|
|
16
12
|
*/
|
|
17
13
|
function claimIdling(connection) {
|
|
18
14
|
let token = {};
|
|
19
15
|
connection._idleSession = token;
|
|
20
16
|
connection.idling = true;
|
|
21
|
-
|
|
22
17
|
return () => {
|
|
23
18
|
if (connection._idleSession === token) {
|
|
24
19
|
connection._idleSession = null;
|
|
@@ -26,25 +21,21 @@ function claimIdling(connection) {
|
|
|
26
21
|
}
|
|
27
22
|
};
|
|
28
23
|
}
|
|
29
|
-
|
|
30
24
|
/**
|
|
31
25
|
* Runs a single IDLE session on the connection.
|
|
32
26
|
*
|
|
33
|
-
* @param
|
|
34
|
-
* @returns
|
|
27
|
+
* @param connection - IMAP connection instance
|
|
28
|
+
* @returns Void on success, false on failure
|
|
35
29
|
*/
|
|
36
30
|
async function runIdle(connection) {
|
|
37
31
|
let response;
|
|
38
|
-
|
|
39
32
|
// Queue of promises waiting for IDLE to break. When another command needs to run,
|
|
40
33
|
// it calls connection.preCheck() which queues a promise here and sends DONE to break IDLE.
|
|
41
34
|
let preCheckWaitQueue = [];
|
|
42
|
-
|
|
43
35
|
// The preCheck function this session owns. Only this session may clear it from the
|
|
44
36
|
// connection, so a newer IDLE session that already installed its own is left alone.
|
|
45
37
|
let ownPreCheck = null;
|
|
46
38
|
let releaseIdling = claimIdling(connection);
|
|
47
|
-
|
|
48
39
|
try {
|
|
49
40
|
// State flags for the IDLE lifecycle:
|
|
50
41
|
// - doneRequested: someone wants to break IDLE (e.g., to run another command)
|
|
@@ -53,7 +44,6 @@ async function runIdle(connection) {
|
|
|
53
44
|
let doneRequested = false;
|
|
54
45
|
let doneSent = false;
|
|
55
46
|
let canEnd = false;
|
|
56
|
-
|
|
57
47
|
// preCheck sends DONE to break out of IDLE. Called when another command
|
|
58
48
|
// needs to run on this connection (e.g., a FETCH or STORE from user code).
|
|
59
49
|
let preCheck = async () => {
|
|
@@ -63,25 +53,22 @@ async function runIdle(connection) {
|
|
|
63
53
|
src: 'c',
|
|
64
54
|
msg: `DONE`,
|
|
65
55
|
comment: `breaking IDLE`,
|
|
66
|
-
lockId: connection.currentLock
|
|
56
|
+
lockId: connection.currentLock ? connection.currentLock.lockId : undefined,
|
|
67
57
|
path: connection.mailbox && connection.mailbox.path,
|
|
68
58
|
cid: connection.id
|
|
69
59
|
});
|
|
70
60
|
connection.write('DONE');
|
|
71
61
|
doneSent = true;
|
|
72
|
-
|
|
73
62
|
releaseIdling();
|
|
74
63
|
if (connection.preCheck === ownPreCheck) {
|
|
75
64
|
connection.preCheck = false; // unset itself
|
|
76
65
|
}
|
|
77
|
-
|
|
78
66
|
while (preCheckWaitQueue.length) {
|
|
79
67
|
let { resolve } = preCheckWaitQueue.shift();
|
|
80
68
|
resolve();
|
|
81
69
|
}
|
|
82
70
|
}
|
|
83
71
|
};
|
|
84
|
-
|
|
85
72
|
// Public interface for breaking IDLE. Returns a promise that resolves when
|
|
86
73
|
// IDLE is actually broken and the connection is free for other commands.
|
|
87
74
|
let connectionPreCheck = () => {
|
|
@@ -90,10 +77,9 @@ async function runIdle(connection) {
|
|
|
90
77
|
let handler = guardedPromise((resolve, reject) => {
|
|
91
78
|
preCheckWaitQueue.push({ resolve, reject });
|
|
92
79
|
});
|
|
93
|
-
|
|
94
80
|
connection.log.trace({
|
|
95
81
|
msg: 'Requesting IDLE break',
|
|
96
|
-
lockId: connection.currentLock
|
|
82
|
+
lockId: connection.currentLock ? connection.currentLock.lockId : undefined,
|
|
97
83
|
path: connection.mailbox && connection.mailbox.path,
|
|
98
84
|
queued: preCheckWaitQueue.length,
|
|
99
85
|
doneRequested,
|
|
@@ -101,16 +87,12 @@ async function runIdle(connection) {
|
|
|
101
87
|
doneSent,
|
|
102
88
|
cid: connection.id
|
|
103
89
|
});
|
|
104
|
-
|
|
105
|
-
preCheck().catch(err => logConnectionError(connection, 'Failed to break IDLE', err));
|
|
106
|
-
|
|
90
|
+
preCheck().catch((err) => logConnectionError(connection, 'Failed to break IDLE', err));
|
|
107
91
|
return handler;
|
|
108
92
|
};
|
|
109
|
-
|
|
110
93
|
// Register preCheck on the connection so other code (e.g., getMailboxLock) can break IDLE
|
|
111
94
|
ownPreCheck = connectionPreCheck;
|
|
112
95
|
connection.preCheck = connectionPreCheck;
|
|
113
|
-
|
|
114
96
|
response = await connection.exec('IDLE', false, {
|
|
115
97
|
// Server responds with "+" continuation to acknowledge IDLE mode.
|
|
116
98
|
// After this, the server will push untagged responses for mailbox changes.
|
|
@@ -118,7 +100,7 @@ async function runIdle(connection) {
|
|
|
118
100
|
onPlusTag: async () => {
|
|
119
101
|
connection.log.debug({
|
|
120
102
|
msg: `Initiated IDLE, waiting for server input`,
|
|
121
|
-
lockId: connection.currentLock
|
|
103
|
+
lockId: connection.currentLock ? connection.currentLock.lockId : undefined,
|
|
122
104
|
doneRequested,
|
|
123
105
|
cid: connection.id
|
|
124
106
|
});
|
|
@@ -126,17 +108,18 @@ async function runIdle(connection) {
|
|
|
126
108
|
if (doneRequested) {
|
|
127
109
|
try {
|
|
128
110
|
await preCheck();
|
|
129
|
-
}
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
130
113
|
logConnectionError(connection, 'Failed to break IDLE', err);
|
|
131
114
|
}
|
|
132
115
|
}
|
|
133
116
|
},
|
|
134
|
-
onSend: () => {}
|
|
117
|
+
onSend: () => { }
|
|
135
118
|
});
|
|
136
|
-
|
|
137
119
|
response.next();
|
|
138
120
|
return;
|
|
139
|
-
}
|
|
121
|
+
}
|
|
122
|
+
catch (err) {
|
|
140
123
|
logConnectionError(connection, 'IDLE session failed', err);
|
|
141
124
|
if (preCheckWaitQueue.length) {
|
|
142
125
|
// One error for the whole queue: every waiter failed at the same site, for the same
|
|
@@ -149,7 +132,8 @@ async function runIdle(connection) {
|
|
|
149
132
|
}
|
|
150
133
|
}
|
|
151
134
|
return false;
|
|
152
|
-
}
|
|
135
|
+
}
|
|
136
|
+
finally {
|
|
153
137
|
// Single ownership cleanup for every outcome: explicit break, tagged completion
|
|
154
138
|
// (including a server-terminated IDLE, where preCheck never ran), rejected command,
|
|
155
139
|
// parser failure and connection close. `idling` drives socket-timeout handling, so it
|
|
@@ -164,7 +148,6 @@ async function runIdle(connection) {
|
|
|
164
148
|
}
|
|
165
149
|
}
|
|
166
150
|
}
|
|
167
|
-
|
|
168
151
|
/**
|
|
169
152
|
* Runs one fallback poll. The real SELECT and STATUS commands are reused instead of replaying the
|
|
170
153
|
* saved wire arguments, so a poll applies exactly the same mailbox state transitions, events and
|
|
@@ -172,19 +155,16 @@ async function runIdle(connection) {
|
|
|
172
155
|
* than connection.run(), because run() awaits preCheck() - and the preCheck it would await is the
|
|
173
156
|
* one this very polling session installed, so the session would cancel itself.
|
|
174
157
|
*
|
|
175
|
-
* @param
|
|
176
|
-
* @param
|
|
177
|
-
* @returns {Promise<void>}
|
|
158
|
+
* @param connection - IMAP connection instance
|
|
159
|
+
* @param session - Polling session state
|
|
178
160
|
*/
|
|
179
161
|
async function pollOnce(connection, session) {
|
|
180
162
|
let path = connection.mailbox && connection.mailbox.path;
|
|
181
|
-
|
|
182
163
|
switch (connection.missingIdleCommand) {
|
|
183
164
|
case 'SELECT':
|
|
184
165
|
connection.log.debug({ msg: `Running SELECT to detect changes in folder`, cid: connection.id });
|
|
185
166
|
await connection.runInternal('SELECT', path, { readOnly: session.selectCommand.command === 'EXAMINE' });
|
|
186
167
|
break;
|
|
187
|
-
|
|
188
168
|
case 'STATUS': {
|
|
189
169
|
connection.log.debug({ msg: `Running STATUS to detect changes in folder`, cid: connection.id });
|
|
190
170
|
// HIGHESTMODSEQ is filtered out again unless the server advertises CONDSTORE, so a
|
|
@@ -204,7 +184,6 @@ async function pollOnce(connection, session) {
|
|
|
204
184
|
}
|
|
205
185
|
break;
|
|
206
186
|
}
|
|
207
|
-
|
|
208
187
|
case 'NOOP':
|
|
209
188
|
default: {
|
|
210
189
|
let response = await connection.exec('NOOP', false, { comment: 'IDLE not supported' });
|
|
@@ -213,7 +192,6 @@ async function pollOnce(connection, session) {
|
|
|
213
192
|
}
|
|
214
193
|
}
|
|
215
194
|
}
|
|
216
|
-
|
|
217
195
|
/**
|
|
218
196
|
* Polls the selected mailbox at a fixed interval, for servers without IDLE support.
|
|
219
197
|
*
|
|
@@ -221,25 +199,21 @@ async function pollOnce(connection, session) {
|
|
|
221
199
|
* a poll starts and again before the next timer is scheduled, and a poll that completes after
|
|
222
200
|
* cancellation can neither run again nor take ownership away from a newer IDLE session.
|
|
223
201
|
*
|
|
224
|
-
* @param
|
|
225
|
-
* @param
|
|
226
|
-
* @returns {Promise<void>}
|
|
202
|
+
* @param connection - IMAP connection instance
|
|
203
|
+
* @param maxIdleTime - Upper bound for the polling interval
|
|
227
204
|
*/
|
|
228
205
|
async function runPollingFallback(connection, maxIdleTime) {
|
|
229
206
|
if (!connection.currentSelectCommand) {
|
|
230
207
|
return;
|
|
231
208
|
}
|
|
232
|
-
|
|
233
209
|
let session = {
|
|
234
210
|
cancelled: false,
|
|
235
211
|
timer: null,
|
|
236
212
|
preCheck: null,
|
|
237
213
|
selectCommand: connection.currentSelectCommand
|
|
238
214
|
};
|
|
239
|
-
|
|
240
215
|
let interval = maxIdleTime ? Math.min(NOOP_INTERVAL, maxIdleTime) : NOOP_INTERVAL;
|
|
241
216
|
let releaseIdling = claimIdling(connection);
|
|
242
|
-
|
|
243
217
|
try {
|
|
244
218
|
await new Promise(resolve => {
|
|
245
219
|
// Idempotent cancellation. Never keyed off connection.preCheck, because a newer IDLE
|
|
@@ -249,54 +223,47 @@ async function runPollingFallback(connection, maxIdleTime) {
|
|
|
249
223
|
return;
|
|
250
224
|
}
|
|
251
225
|
session.cancelled = true;
|
|
252
|
-
|
|
226
|
+
clearTimer(session.timer);
|
|
253
227
|
session.timer = null;
|
|
254
228
|
resolve();
|
|
255
229
|
};
|
|
256
|
-
|
|
257
230
|
session.preCheck = async () => {
|
|
258
231
|
connection.log.debug({ msg: `Breaking NOOP loop`, cid: connection.id });
|
|
259
232
|
cancel();
|
|
260
233
|
};
|
|
261
234
|
connection.preCheck = session.preCheck;
|
|
262
|
-
|
|
263
235
|
const runPoll = () => {
|
|
264
236
|
if (session.cancelled) {
|
|
265
237
|
return;
|
|
266
238
|
}
|
|
267
|
-
|
|
268
239
|
// The transport or the mailbox may be gone by the time the timer fires
|
|
269
240
|
if (!connection.socket || connection.socket.destroyed || connection.state !== connection.states.SELECTED || !connection.mailbox) {
|
|
270
241
|
return cancel();
|
|
271
242
|
}
|
|
272
|
-
|
|
273
243
|
pollOnce(connection, session)
|
|
274
244
|
.then(() => {
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
.catch(err => {
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
245
|
+
// Stamped only after a poll actually completed: a failed poll must not
|
|
246
|
+
// satisfy the resumed schedule below, or the next session would defer
|
|
247
|
+
// its first poll a full interval past an attempt that checked nothing.
|
|
248
|
+
connection._lastPollAt = Date.now();
|
|
249
|
+
// Cancellation is re-checked here: the session may have been broken while
|
|
250
|
+
// this poll was in flight, and an orphaned poller must not schedule again.
|
|
251
|
+
if (session.cancelled) {
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
scheduleNextPoll(interval);
|
|
255
|
+
})
|
|
256
|
+
.catch((err) => {
|
|
257
|
+
logConnectionError(connection, 'Failed to poll for mailbox changes', err);
|
|
258
|
+
cancel();
|
|
259
|
+
});
|
|
290
260
|
};
|
|
291
|
-
|
|
292
261
|
function scheduleNextPoll(delay) {
|
|
293
262
|
session.timer = setTimeout(runPoll, delay);
|
|
294
263
|
// Background polling must not keep the process alive
|
|
295
264
|
unrefTimer(session.timer);
|
|
296
265
|
}
|
|
297
|
-
|
|
298
266
|
connection.log.debug({ msg: `Initiated NOOP loop`, cid: connection.id });
|
|
299
|
-
|
|
300
267
|
// Every auto-IDLE restart begins a fresh polling session, so an unconditional first
|
|
301
268
|
// poll would tie the poll rate to how often the caller runs commands rather than to
|
|
302
269
|
// `interval`: with a short autoIdleDelay, a command every few seconds turns into a
|
|
@@ -308,13 +275,15 @@ async function runPollingFallback(connection, maxIdleTime) {
|
|
|
308
275
|
let sinceLastPoll = Math.max(0, Date.now() - (connection._lastPollAt || 0));
|
|
309
276
|
if (sinceLastPoll >= interval) {
|
|
310
277
|
runPoll();
|
|
311
|
-
}
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
312
280
|
scheduleNextPoll(interval - sinceLastPoll);
|
|
313
281
|
}
|
|
314
282
|
});
|
|
315
|
-
}
|
|
283
|
+
}
|
|
284
|
+
finally {
|
|
316
285
|
session.cancelled = true;
|
|
317
|
-
|
|
286
|
+
clearTimer(session.timer);
|
|
318
287
|
session.timer = null;
|
|
319
288
|
releaseIdling();
|
|
320
289
|
if (connection.preCheck === session.preCheck) {
|
|
@@ -322,20 +291,18 @@ async function runPollingFallback(connection, maxIdleTime) {
|
|
|
322
291
|
}
|
|
323
292
|
}
|
|
324
293
|
}
|
|
325
|
-
|
|
326
294
|
/**
|
|
327
295
|
* Listens for changes in the selected mailbox using IDLE or NOOP polling fallback.
|
|
328
296
|
*
|
|
329
|
-
* @param
|
|
330
|
-
* @param
|
|
331
|
-
* @returns
|
|
297
|
+
* @param connection - IMAP connection instance
|
|
298
|
+
* @param maxIdleTime - Maximum time in milliseconds to stay in IDLE before restarting
|
|
299
|
+
* @returns Void on success, false on failure, or undefined if not in SELECTED state
|
|
332
300
|
*/
|
|
333
|
-
|
|
301
|
+
export default async function idle(connection, maxIdleTime) {
|
|
334
302
|
if (connection.state !== connection.states.SELECTED) {
|
|
335
303
|
// nothing to do here
|
|
336
304
|
return;
|
|
337
305
|
}
|
|
338
|
-
|
|
339
306
|
// If server supports IDLE (RFC 2177, folded into base IMAP4rev2), use it for
|
|
340
307
|
// real-time push notifications. Otherwise, fall back to periodic polling with
|
|
341
308
|
// NOOP/STATUS/SELECT.
|
|
@@ -354,7 +321,7 @@ module.exports = async (connection, maxIdleTime) => {
|
|
|
354
321
|
stillIdling = true;
|
|
355
322
|
// request IDLE break if IDLE has been running for allowed time
|
|
356
323
|
connection.log.trace({ msg: 'Max allowed IDLE time reached', cid: connection.id });
|
|
357
|
-
connection.preCheck().catch(err => logConnectionError(connection, 'Failed to break IDLE for restart', err));
|
|
324
|
+
connection.preCheck().catch((err) => logConnectionError(connection, 'Failed to break IDLE for restart', err));
|
|
358
325
|
}
|
|
359
326
|
}
|
|
360
327
|
}, maxIdleTime);
|
|
@@ -369,8 +336,7 @@ module.exports = async (connection, maxIdleTime) => {
|
|
|
369
336
|
stillIdling = false;
|
|
370
337
|
}
|
|
371
338
|
}
|
|
372
|
-
|
|
373
339
|
// Fallback for servers without IDLE support: poll at regular intervals using
|
|
374
340
|
// NOOP (default), STATUS, or SELECT depending on missingIdleCommand config.
|
|
375
341
|
return runPollingFallback(connection, maxIdleTime);
|
|
376
|
-
}
|
|
342
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ImapFlow } from '../imap-flow.js';
|
|
2
|
+
import type { ListOptions, ListResponse } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Lists mailboxes from the server, including subscription status and special-use flags.
|
|
5
|
+
*
|
|
6
|
+
* @param connection - IMAP connection instance
|
|
7
|
+
* @param reference - Reference name (namespace prefix)
|
|
8
|
+
* @param mailbox - Mailbox name pattern with possible wildcards
|
|
9
|
+
* @param options - List options
|
|
10
|
+
* @param options.listOnly - If true, return entries after LIST without LSUB or status queries
|
|
11
|
+
* @param options.statusQuery - Status data items to query for each listed mailbox
|
|
12
|
+
* @param options.specialUseHints - Hints mapping mailbox paths to special-use types (sent, junk, trash, drafts, archive)
|
|
13
|
+
* @returns Array of mailbox entries sorted by special-use flags and name
|
|
14
|
+
* @throws If the LIST command fails
|
|
15
|
+
*/
|
|
16
|
+
export default function list(connection: ImapFlow, reference: string | undefined, mailbox: string | undefined, options?: ListOptions | undefined): Promise<ListResponse[]>;
|