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
package/test/imap-parser-test.js
DELETED
|
@@ -1,1474 +0,0 @@
|
|
|
1
|
-
/*eslint no-unused-expressions: 0, prefer-arrow-callback: 0 */
|
|
2
|
-
|
|
3
|
-
'use strict';
|
|
4
|
-
|
|
5
|
-
const { parser } = require('../lib/handler/imap-handler');
|
|
6
|
-
const { ParserInstance } = require('../lib/handler/parser-instance');
|
|
7
|
-
const mimetorture = require('./fixtures/serialized-mimetorture');
|
|
8
|
-
|
|
9
|
-
let asyncWrapper = (test, handler) => {
|
|
10
|
-
handler(test)
|
|
11
|
-
.then(() => test.done())
|
|
12
|
-
.catch(err => {
|
|
13
|
-
test.ifError(err);
|
|
14
|
-
test.done();
|
|
15
|
-
});
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
let asyncWrapperFail = (test, handler) => {
|
|
19
|
-
handler(test)
|
|
20
|
-
.then(() => {
|
|
21
|
-
test.ok(false);
|
|
22
|
-
test.done();
|
|
23
|
-
})
|
|
24
|
-
.catch(err => {
|
|
25
|
-
test.ok(err);
|
|
26
|
-
test.done();
|
|
27
|
-
});
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
// Asserts that `fn` throws (or rejects with) an error carrying the expected `code`,
|
|
31
|
-
// not merely that *some* error was thrown.
|
|
32
|
-
let expectErrorCode = (test, code, fn) =>
|
|
33
|
-
asyncWrapper(test, async test => {
|
|
34
|
-
let err;
|
|
35
|
-
try {
|
|
36
|
-
await fn();
|
|
37
|
-
} catch (e) {
|
|
38
|
-
err = e;
|
|
39
|
-
}
|
|
40
|
-
test.ok(err, 'expected an error to be thrown');
|
|
41
|
-
test.equal(err && err.code, code);
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
module.exports['IMAP Parser: Tags: get TAG'] = test => asyncWrapper(test, async test => test.equal((await parser('TAG1 CMD')).tag, 'TAG1'));
|
|
45
|
-
module.exports['IMAP Parser: Tags: space before TAG'] = test => asyncWrapperFail(test, async test => test.ok(await parser(' TAG CMD')));
|
|
46
|
-
module.exports['IMAP Parser: Tags: fail empty TAG'] = test => asyncWrapperFail(test, async test => test.ok(await parser('')));
|
|
47
|
-
module.exports['IMAP Parser: Tags: * TAG'] = test => asyncWrapper(test, async test => test.equal((await parser('* CMD')).tag, '*'));
|
|
48
|
-
module.exports['IMAP Parser: Tags: + TAG'] = test => asyncWrapper(test, async test => test.equal((await parser('+ CMD')).tag, '+'));
|
|
49
|
-
module.exports['IMAP Parser: Tags: fail TAG only'] = test => asyncWrapperFail(test, async test => test.ok(await parser('TAG1')));
|
|
50
|
-
module.exports['IMAP Parser: Tags: fail invalid char in TAG'] = test => asyncWrapperFail(test, async test => test.ok(await parser('TAG"1 CMD')));
|
|
51
|
-
|
|
52
|
-
module.exports['IMAP Parser: Command: single'] = test => asyncWrapper(test, async test => test.equal((await parser('TAG1 CMD')).command, 'CMD'));
|
|
53
|
-
module.exports['IMAP Parser: Command: multi word'] = test =>
|
|
54
|
-
asyncWrapper(test, async test => test.equal((await parser('TAG1 UID FETCH')).command, 'UID FETCH'));
|
|
55
|
-
module.exports['IMAP Parser: Command: fail extra ws'] = test => asyncWrapperFail(test, async test => test.ok(await parser('TAG1 CMD')));
|
|
56
|
-
module.exports['IMAP Parser: Command: fail empty command'] = test => asyncWrapperFail(test, async test => test.ok(await parser('TAG1 ')));
|
|
57
|
-
module.exports['IMAP Parser: Command: fail invalid char in command'] = test => asyncWrapperFail(test, async test => test.ok(await parser('TAG1 CM=D')));
|
|
58
|
-
|
|
59
|
-
module.exports['IMAP Parser: Args: allow trailing whitespace and empty arguments'] = test =>
|
|
60
|
-
asyncWrapper(test, async test => test.deepEqual(await parser('* SEARCH '), { tag: '*', command: 'SEARCH' }));
|
|
61
|
-
|
|
62
|
-
module.exports['IMAP Parser: Attributes: single atom'] = test =>
|
|
63
|
-
asyncWrapper(test, async test =>
|
|
64
|
-
test.deepEqual((await parser('TAG1 CMD FED')).attributes, [
|
|
65
|
-
{
|
|
66
|
-
type: 'ATOM',
|
|
67
|
-
value: 'FED'
|
|
68
|
-
}
|
|
69
|
-
])
|
|
70
|
-
);
|
|
71
|
-
|
|
72
|
-
module.exports['IMAP Parser: Attributes: multiple atoms'] = test =>
|
|
73
|
-
asyncWrapper(test, async test =>
|
|
74
|
-
test.deepEqual((await parser('TAG1 CMD FED TED')).attributes, [
|
|
75
|
-
{
|
|
76
|
-
type: 'ATOM',
|
|
77
|
-
value: 'FED'
|
|
78
|
-
},
|
|
79
|
-
{
|
|
80
|
-
type: 'ATOM',
|
|
81
|
-
value: 'TED'
|
|
82
|
-
}
|
|
83
|
-
])
|
|
84
|
-
);
|
|
85
|
-
|
|
86
|
-
module.exports['IMAP Parser: Attributes: special char in atom'] = test =>
|
|
87
|
-
asyncWrapper(test, async test =>
|
|
88
|
-
test.deepEqual((await parser('TAG1 CMD %')).attributes, [
|
|
89
|
-
{
|
|
90
|
-
type: 'ATOM',
|
|
91
|
-
value: '%'
|
|
92
|
-
}
|
|
93
|
-
])
|
|
94
|
-
);
|
|
95
|
-
|
|
96
|
-
module.exports['IMAP Parser: Attributes: escaped char in atom'] = test =>
|
|
97
|
-
asyncWrapper(test, async test =>
|
|
98
|
-
test.deepEqual((await parser('TAG1 CMD \\*')).attributes, [
|
|
99
|
-
{
|
|
100
|
-
type: 'ATOM',
|
|
101
|
-
value: '\\*'
|
|
102
|
-
}
|
|
103
|
-
])
|
|
104
|
-
);
|
|
105
|
-
|
|
106
|
-
module.exports['IMAP Parser: Attributes: sub list'] = test =>
|
|
107
|
-
asyncWrapper(test, async test =>
|
|
108
|
-
test.deepEqual((await parser('12.82 STATUS [Gmail].Trash (UIDNEXT UNSEEN HIGHESTMODSEQ)')).attributes, [
|
|
109
|
-
{
|
|
110
|
-
type: 'ATOM',
|
|
111
|
-
value: '[Gmail].Trash'
|
|
112
|
-
},
|
|
113
|
-
[
|
|
114
|
-
{
|
|
115
|
-
type: 'ATOM',
|
|
116
|
-
value: 'UIDNEXT'
|
|
117
|
-
},
|
|
118
|
-
{
|
|
119
|
-
type: 'ATOM',
|
|
120
|
-
value: 'UNSEEN'
|
|
121
|
-
},
|
|
122
|
-
{
|
|
123
|
-
type: 'ATOM',
|
|
124
|
-
value: 'HIGHESTMODSEQ'
|
|
125
|
-
}
|
|
126
|
-
]
|
|
127
|
-
])
|
|
128
|
-
);
|
|
129
|
-
|
|
130
|
-
module.exports['IMAP Parser: Attributes: single string'] = test =>
|
|
131
|
-
asyncWrapper(test, async test =>
|
|
132
|
-
test.deepEqual((await parser('TAG1 CMD "ABCDE"')).attributes, [
|
|
133
|
-
{
|
|
134
|
-
type: 'STRING',
|
|
135
|
-
value: 'ABCDE'
|
|
136
|
-
}
|
|
137
|
-
])
|
|
138
|
-
);
|
|
139
|
-
|
|
140
|
-
module.exports['IMAP Parser: Attributes: multiple strings'] = test =>
|
|
141
|
-
asyncWrapper(test, async test =>
|
|
142
|
-
test.deepEqual((await parser('TAG1 CMD "ABCDE" "DEFGH"')).attributes, [
|
|
143
|
-
{
|
|
144
|
-
type: 'STRING',
|
|
145
|
-
value: 'ABCDE'
|
|
146
|
-
},
|
|
147
|
-
{
|
|
148
|
-
type: 'STRING',
|
|
149
|
-
value: 'DEFGH'
|
|
150
|
-
}
|
|
151
|
-
])
|
|
152
|
-
);
|
|
153
|
-
|
|
154
|
-
module.exports['IMAP Parser: Attributes: invalid char in string'] = test =>
|
|
155
|
-
asyncWrapper(test, async test =>
|
|
156
|
-
test.deepEqual((await parser('* 1 FETCH (BODY[] "\xc2")')).attributes, [
|
|
157
|
-
{
|
|
158
|
-
type: 'ATOM',
|
|
159
|
-
value: 'FETCH'
|
|
160
|
-
},
|
|
161
|
-
[
|
|
162
|
-
{
|
|
163
|
-
type: 'ATOM',
|
|
164
|
-
value: 'BODY',
|
|
165
|
-
section: []
|
|
166
|
-
},
|
|
167
|
-
{
|
|
168
|
-
type: 'STRING',
|
|
169
|
-
value: '\xc2'
|
|
170
|
-
}
|
|
171
|
-
]
|
|
172
|
-
])
|
|
173
|
-
);
|
|
174
|
-
|
|
175
|
-
module.exports['IMAP Parser: Lists: single atom'] = test =>
|
|
176
|
-
asyncWrapper(test, async test =>
|
|
177
|
-
test.deepEqual((await parser('TAG1 CMD (1234)')).attributes, [
|
|
178
|
-
[
|
|
179
|
-
{
|
|
180
|
-
type: 'ATOM',
|
|
181
|
-
value: '1234'
|
|
182
|
-
}
|
|
183
|
-
]
|
|
184
|
-
])
|
|
185
|
-
);
|
|
186
|
-
|
|
187
|
-
module.exports['IMAP Parser: Lists: multiple atoms'] = test =>
|
|
188
|
-
asyncWrapper(test, async test =>
|
|
189
|
-
test.deepEqual((await parser('TAG1 CMD (1234 TERE)')).attributes, [
|
|
190
|
-
[
|
|
191
|
-
{
|
|
192
|
-
type: 'ATOM',
|
|
193
|
-
value: '1234'
|
|
194
|
-
},
|
|
195
|
-
{
|
|
196
|
-
type: 'ATOM',
|
|
197
|
-
value: 'TERE'
|
|
198
|
-
}
|
|
199
|
-
]
|
|
200
|
-
])
|
|
201
|
-
);
|
|
202
|
-
|
|
203
|
-
module.exports['IMAP Parser: Lists: multiple lists'] = test =>
|
|
204
|
-
asyncWrapper(test, async test =>
|
|
205
|
-
test.deepEqual((await parser('TAG1 CMD (1234)(TERE)')).attributes, [
|
|
206
|
-
[
|
|
207
|
-
{
|
|
208
|
-
type: 'ATOM',
|
|
209
|
-
value: '1234'
|
|
210
|
-
}
|
|
211
|
-
],
|
|
212
|
-
[
|
|
213
|
-
{
|
|
214
|
-
type: 'ATOM',
|
|
215
|
-
value: 'TERE'
|
|
216
|
-
}
|
|
217
|
-
]
|
|
218
|
-
])
|
|
219
|
-
);
|
|
220
|
-
|
|
221
|
-
module.exports['IMAP Parser: Lists: extra whitespace in start of list'] = test =>
|
|
222
|
-
asyncWrapper(test, async test =>
|
|
223
|
-
test.deepEqual((await parser('TAG1 CMD ( 1234)')).attributes, [
|
|
224
|
-
[
|
|
225
|
-
{
|
|
226
|
-
type: 'ATOM',
|
|
227
|
-
value: '1234'
|
|
228
|
-
}
|
|
229
|
-
]
|
|
230
|
-
])
|
|
231
|
-
);
|
|
232
|
-
|
|
233
|
-
module.exports['IMAP Parser: Lists: extra whitespace in end of list'] = test =>
|
|
234
|
-
asyncWrapper(test, async test =>
|
|
235
|
-
test.deepEqual((await parser('TAG1 CMD (1234 )')).attributes, [
|
|
236
|
-
[
|
|
237
|
-
{
|
|
238
|
-
type: 'ATOM',
|
|
239
|
-
value: '1234'
|
|
240
|
-
}
|
|
241
|
-
]
|
|
242
|
-
])
|
|
243
|
-
);
|
|
244
|
-
|
|
245
|
-
module.exports['IMAP Parser: Lists: extra whitespace after list'] = test =>
|
|
246
|
-
asyncWrapper(test, async test =>
|
|
247
|
-
test.deepEqual((await parser('TAG1 CMD (1234) ')).attributes, [
|
|
248
|
-
[
|
|
249
|
-
{
|
|
250
|
-
type: 'ATOM',
|
|
251
|
-
value: '1234'
|
|
252
|
-
}
|
|
253
|
-
]
|
|
254
|
-
])
|
|
255
|
-
);
|
|
256
|
-
|
|
257
|
-
module.exports['IMAP Parser: Lists: nested list 1'] = test =>
|
|
258
|
-
asyncWrapper(test, async test =>
|
|
259
|
-
test.deepEqual((await parser('TAG1 CMD (((TERE)) VANA)')).attributes, [
|
|
260
|
-
[
|
|
261
|
-
[
|
|
262
|
-
[
|
|
263
|
-
{
|
|
264
|
-
type: 'ATOM',
|
|
265
|
-
value: 'TERE'
|
|
266
|
-
}
|
|
267
|
-
]
|
|
268
|
-
],
|
|
269
|
-
{
|
|
270
|
-
type: 'ATOM',
|
|
271
|
-
value: 'VANA'
|
|
272
|
-
}
|
|
273
|
-
]
|
|
274
|
-
])
|
|
275
|
-
);
|
|
276
|
-
|
|
277
|
-
module.exports['IMAP Parser: Lists: nested list 2'] = test =>
|
|
278
|
-
asyncWrapper(test, async test =>
|
|
279
|
-
test.deepEqual((await parser('TAG1 CMD (( (TERE)) VANA)')).attributes, [
|
|
280
|
-
[
|
|
281
|
-
[
|
|
282
|
-
[
|
|
283
|
-
{
|
|
284
|
-
type: 'ATOM',
|
|
285
|
-
value: 'TERE'
|
|
286
|
-
}
|
|
287
|
-
]
|
|
288
|
-
],
|
|
289
|
-
{
|
|
290
|
-
type: 'ATOM',
|
|
291
|
-
value: 'VANA'
|
|
292
|
-
}
|
|
293
|
-
]
|
|
294
|
-
])
|
|
295
|
-
);
|
|
296
|
-
|
|
297
|
-
module.exports['IMAP Parser: Lists: nested list 3'] = test =>
|
|
298
|
-
asyncWrapper(test, async test =>
|
|
299
|
-
test.deepEqual((await parser('TAG1 CMD (((TERE) ) VANA)')).attributes, [
|
|
300
|
-
[
|
|
301
|
-
[
|
|
302
|
-
[
|
|
303
|
-
{
|
|
304
|
-
type: 'ATOM',
|
|
305
|
-
value: 'TERE'
|
|
306
|
-
}
|
|
307
|
-
]
|
|
308
|
-
],
|
|
309
|
-
{
|
|
310
|
-
type: 'ATOM',
|
|
311
|
-
value: 'VANA'
|
|
312
|
-
}
|
|
313
|
-
]
|
|
314
|
-
])
|
|
315
|
-
);
|
|
316
|
-
|
|
317
|
-
module.exports['IMAP Parser: Literals: single literal'] = test =>
|
|
318
|
-
asyncWrapper(test, async test =>
|
|
319
|
-
test.deepEqual((await parser('TAG1 CMD {4}\r\n', { literals: [Buffer.from('abcd')] })).attributes, [
|
|
320
|
-
{
|
|
321
|
-
type: 'LITERAL',
|
|
322
|
-
value: Buffer.from('abcd')
|
|
323
|
-
}
|
|
324
|
-
])
|
|
325
|
-
);
|
|
326
|
-
|
|
327
|
-
module.exports['IMAP Parser: Literals: literal with NULL'] = test =>
|
|
328
|
-
asyncWrapper(test, async test =>
|
|
329
|
-
test.deepEqual((await parser('TAG1 CMD {4}\r\n', { literals: [Buffer.from('ab\x00d')] })).attributes, [
|
|
330
|
-
{
|
|
331
|
-
type: 'LITERAL',
|
|
332
|
-
value: Buffer.from('ab\x00d')
|
|
333
|
-
}
|
|
334
|
-
])
|
|
335
|
-
);
|
|
336
|
-
|
|
337
|
-
module.exports['IMAP Parser: empty continuation (+) response'] = test =>
|
|
338
|
-
asyncWrapper(test, async test => {
|
|
339
|
-
let parsed = await parser('+');
|
|
340
|
-
test.equal(parsed.tag, '+');
|
|
341
|
-
test.equal(parsed.command, '');
|
|
342
|
-
});
|
|
343
|
-
|
|
344
|
-
module.exports['IMAP Parser: non-space after command throws ParserError5'] = test => expectErrorCode(test, 'ParserError5', () => parser('TAG1 CMD\tx'));
|
|
345
|
-
|
|
346
|
-
module.exports['IMAP Parser: leading whitespace in attributes throws ParserError7'] = test =>
|
|
347
|
-
expectErrorCode(test, 'ParserError7', () => parser('TAG1 CMD \tx'));
|
|
348
|
-
|
|
349
|
-
module.exports['IMAP Parser: getAttributes on empty input throws ParserError6'] = test =>
|
|
350
|
-
expectErrorCode(test, 'ParserError6', () => {
|
|
351
|
-
// constructed without options to also exercise the options default branch
|
|
352
|
-
let pi = new ParserInstance('');
|
|
353
|
-
return pi.getAttributes();
|
|
354
|
-
});
|
|
355
|
-
|
|
356
|
-
module.exports['IMAP Parser: strips leading NUL padding and records count'] = test =>
|
|
357
|
-
asyncWrapper(test, async test => {
|
|
358
|
-
let buf = Buffer.concat([Buffer.from([0, 0, 0]), Buffer.from('* OK ready')]);
|
|
359
|
-
let parsed = await parser(buf);
|
|
360
|
-
test.equal(parsed.tag, '*');
|
|
361
|
-
test.equal(parsed.command, 'OK');
|
|
362
|
-
test.equal(parsed.nullBytesRemoved, 3);
|
|
363
|
-
});
|
|
364
|
-
|
|
365
|
-
module.exports['IMAP Parser: all-NUL input becomes BAD response'] = test =>
|
|
366
|
-
asyncWrapper(test, async test => {
|
|
367
|
-
let parsed = await parser(Buffer.from([0, 0, 0, 0]));
|
|
368
|
-
test.equal(parsed.tag, '*');
|
|
369
|
-
test.equal(parsed.command, 'BAD');
|
|
370
|
-
test.deepEqual(parsed.attributes, []);
|
|
371
|
-
});
|
|
372
|
-
|
|
373
|
-
module.exports['IMAP Parser: Literals: literal8'] = test =>
|
|
374
|
-
asyncWrapper(test, async test =>
|
|
375
|
-
test.deepEqual((await parser('TAG1 CMD ~{4}\r\n', { literals: [Buffer.from('ab\x00d')] })).attributes, [
|
|
376
|
-
{
|
|
377
|
-
type: 'LITERAL',
|
|
378
|
-
value: Buffer.from('ab\x00d')
|
|
379
|
-
}
|
|
380
|
-
])
|
|
381
|
-
);
|
|
382
|
-
|
|
383
|
-
module.exports['IMAP Parser: Literals: unexpected literal8 prefix'] = test =>
|
|
384
|
-
asyncWrapper(test, async test => {
|
|
385
|
-
try {
|
|
386
|
-
await parser('TAG1 CMD ~\r\n');
|
|
387
|
-
test.ok(false, 'Must throw');
|
|
388
|
-
} catch (err) {
|
|
389
|
-
test.ok(err, 'Error must exist');
|
|
390
|
-
}
|
|
391
|
-
});
|
|
392
|
-
|
|
393
|
-
module.exports['IMAP Parser: Literals: multiple literals'] = test =>
|
|
394
|
-
asyncWrapper(test, async test =>
|
|
395
|
-
test.deepEqual((await parser('TAG1 CMD {4}\r\n {4}\r\n', { literals: [Buffer.from('abcd'), Buffer.from('kere')] })).attributes, [
|
|
396
|
-
{
|
|
397
|
-
type: 'LITERAL',
|
|
398
|
-
value: Buffer.from('abcd')
|
|
399
|
-
},
|
|
400
|
-
{
|
|
401
|
-
type: 'LITERAL',
|
|
402
|
-
value: Buffer.from('kere')
|
|
403
|
-
}
|
|
404
|
-
])
|
|
405
|
-
);
|
|
406
|
-
|
|
407
|
-
module.exports['IMAP Parser: Literals: list'] = test =>
|
|
408
|
-
asyncWrapper(test, async test =>
|
|
409
|
-
test.deepEqual((await parser('TAG1 CMD ({4}\r\n {4}\r\n)', { literals: [Buffer.from('abcd'), Buffer.from('kere')] })).attributes, [
|
|
410
|
-
[
|
|
411
|
-
{
|
|
412
|
-
type: 'LITERAL',
|
|
413
|
-
value: Buffer.from('abcd')
|
|
414
|
-
},
|
|
415
|
-
{
|
|
416
|
-
type: 'LITERAL',
|
|
417
|
-
value: Buffer.from('kere')
|
|
418
|
-
}
|
|
419
|
-
]
|
|
420
|
-
])
|
|
421
|
-
);
|
|
422
|
-
|
|
423
|
-
module.exports['IMAP Parser: Tags: fail extra ws after literal'] = test =>
|
|
424
|
-
asyncWrapperFail(test, async test => test.ok(await parser('TAG1 CMD {4}\r\n{4} \r\n', { literals: [Buffer.from('abcd'), Buffer.from('kere')] })));
|
|
425
|
-
|
|
426
|
-
module.exports['IMAP Parser: Literals: allow zero length literal in the end of a list'] = test =>
|
|
427
|
-
asyncWrapper(test, async test =>
|
|
428
|
-
test.deepEqual((await parser('TAG1 CMD ({0}\r\n)')).attributes, [
|
|
429
|
-
[
|
|
430
|
-
{
|
|
431
|
-
type: 'LITERAL',
|
|
432
|
-
value: Buffer.from('')
|
|
433
|
-
}
|
|
434
|
-
]
|
|
435
|
-
])
|
|
436
|
-
);
|
|
437
|
-
|
|
438
|
-
module.exports['IMAP Parser: Literals: zero length literal keeps the literal queue aligned'] = test =>
|
|
439
|
-
asyncWrapper(test, async test =>
|
|
440
|
-
// ImapStream queues a Buffer for every literal marker it extracts, including
|
|
441
|
-
// {0}, so the parser must consume exactly one queue entry per marker.
|
|
442
|
-
// Otherwise every literal after a {0} in the same response is silently
|
|
443
|
-
// shifted to the wrong value (RFC 9051 4.3 allows {0} as an empty string).
|
|
444
|
-
test.deepEqual((await parser('TAG1 CMD ({0}\r\n {5}\r\n)', { literals: [Buffer.from(''), Buffer.from('hello')] })).attributes, [
|
|
445
|
-
[
|
|
446
|
-
{
|
|
447
|
-
type: 'LITERAL',
|
|
448
|
-
value: Buffer.from('')
|
|
449
|
-
},
|
|
450
|
-
{
|
|
451
|
-
type: 'LITERAL',
|
|
452
|
-
value: Buffer.from('hello')
|
|
453
|
-
}
|
|
454
|
-
]
|
|
455
|
-
])
|
|
456
|
-
);
|
|
457
|
-
|
|
458
|
-
module.exports['IMAP Parser: Literals: zero length literal between literals keeps values aligned'] = test =>
|
|
459
|
-
asyncWrapper(test, async test =>
|
|
460
|
-
test.deepEqual(
|
|
461
|
-
(await parser('TAG1 CMD ({3}\r\n {0}\r\n {5}\r\n)', { literals: [Buffer.from('abc'), Buffer.from(''), Buffer.from('world')] })).attributes,
|
|
462
|
-
[
|
|
463
|
-
[
|
|
464
|
-
{
|
|
465
|
-
type: 'LITERAL',
|
|
466
|
-
value: Buffer.from('abc')
|
|
467
|
-
},
|
|
468
|
-
{
|
|
469
|
-
type: 'LITERAL',
|
|
470
|
-
value: Buffer.from('')
|
|
471
|
-
},
|
|
472
|
-
{
|
|
473
|
-
type: 'LITERAL',
|
|
474
|
-
value: Buffer.from('world')
|
|
475
|
-
}
|
|
476
|
-
]
|
|
477
|
-
]
|
|
478
|
-
)
|
|
479
|
-
);
|
|
480
|
-
|
|
481
|
-
// RFC 9051 updated resp-text to allow empty text: resp-text = ["[" resp-text-code "]" SP] [text]
|
|
482
|
-
module.exports['IMAP Parser: resp-text: bare OK with no text'] = test =>
|
|
483
|
-
asyncWrapper(test, async test => test.deepEqual(await parser('* OK'), { tag: '*', command: 'OK' }));
|
|
484
|
-
|
|
485
|
-
module.exports['IMAP Parser: resp-text: tagged OK with no text'] = test =>
|
|
486
|
-
asyncWrapper(test, async test => test.deepEqual(await parser('TAG1 OK'), { tag: 'TAG1', command: 'OK' }));
|
|
487
|
-
|
|
488
|
-
module.exports['IMAP Parser: resp-text: response code with no trailing text'] = test =>
|
|
489
|
-
asyncWrapper(test, async test => {
|
|
490
|
-
let parsed = await parser('* OK [UIDNEXT 5]');
|
|
491
|
-
test.equal(parsed.command, 'OK');
|
|
492
|
-
test.deepEqual(parsed.attributes, [
|
|
493
|
-
{
|
|
494
|
-
type: 'ATOM',
|
|
495
|
-
value: '',
|
|
496
|
-
section: [
|
|
497
|
-
{ type: 'ATOM', value: 'UIDNEXT' },
|
|
498
|
-
{ type: 'ATOM', value: '5' }
|
|
499
|
-
]
|
|
500
|
-
}
|
|
501
|
-
]);
|
|
502
|
-
});
|
|
503
|
-
|
|
504
|
-
module.exports['IMAP Parser: resp-text: response code with trailing space and no text'] = test =>
|
|
505
|
-
asyncWrapper(test, async test => {
|
|
506
|
-
let parsed = await parser('* OK [READ-WRITE] ');
|
|
507
|
-
test.equal(parsed.command, 'OK');
|
|
508
|
-
test.deepEqual(parsed.attributes, [
|
|
509
|
-
{
|
|
510
|
-
type: 'ATOM',
|
|
511
|
-
value: '',
|
|
512
|
-
section: [{ type: 'ATOM', value: 'READ-WRITE' }]
|
|
513
|
-
}
|
|
514
|
-
]);
|
|
515
|
-
});
|
|
516
|
-
|
|
517
|
-
// RFC 9051 uses number64 (up to 2^63-1) for message and body sizes - values beyond
|
|
518
|
-
// 2^32 must survive the tokenizer without truncation
|
|
519
|
-
module.exports['IMAP Parser: number64: RFC822.SIZE beyond 32 bits'] = test =>
|
|
520
|
-
asyncWrapper(test, async test => {
|
|
521
|
-
let parsed = await parser('* 1 FETCH (RFC822.SIZE 12345678901234)');
|
|
522
|
-
test.deepEqual(parsed.attributes, [
|
|
523
|
-
{ type: 'ATOM', value: 'FETCH' },
|
|
524
|
-
[
|
|
525
|
-
{ type: 'ATOM', value: 'RFC822.SIZE' },
|
|
526
|
-
{ type: 'ATOM', value: '12345678901234' }
|
|
527
|
-
]
|
|
528
|
-
]);
|
|
529
|
-
});
|
|
530
|
-
|
|
531
|
-
module.exports['IMAP Parser: number64: response code argument beyond 32 bits'] = test =>
|
|
532
|
-
asyncWrapper(test, async test => {
|
|
533
|
-
let parsed = await parser('* OK [HIGHESTMODSEQ 90060115194045007] Ok');
|
|
534
|
-
test.deepEqual(parsed.attributes, [
|
|
535
|
-
{
|
|
536
|
-
type: 'ATOM',
|
|
537
|
-
value: '',
|
|
538
|
-
section: [
|
|
539
|
-
{ type: 'ATOM', value: 'HIGHESTMODSEQ' },
|
|
540
|
-
{ type: 'ATOM', value: '90060115194045007' }
|
|
541
|
-
]
|
|
542
|
-
},
|
|
543
|
-
{ type: 'TEXT', value: 'Ok' }
|
|
544
|
-
]);
|
|
545
|
-
});
|
|
546
|
-
|
|
547
|
-
module.exports['IMAP Parser: Section: empty'] = test =>
|
|
548
|
-
asyncWrapper(test, async test =>
|
|
549
|
-
test.deepEqual((await parser('TAG1 CMD BODY[]')).attributes, [
|
|
550
|
-
{
|
|
551
|
-
type: 'ATOM',
|
|
552
|
-
value: 'BODY',
|
|
553
|
-
section: []
|
|
554
|
-
}
|
|
555
|
-
])
|
|
556
|
-
);
|
|
557
|
-
|
|
558
|
-
module.exports['IMAP Parser: Section: list'] = test =>
|
|
559
|
-
asyncWrapper(test, async test =>
|
|
560
|
-
test.deepEqual((await parser('TAG1 CMD BODY[(KERE)]')).attributes, [
|
|
561
|
-
{
|
|
562
|
-
type: 'ATOM',
|
|
563
|
-
value: 'BODY',
|
|
564
|
-
section: [
|
|
565
|
-
[
|
|
566
|
-
{
|
|
567
|
-
type: 'ATOM',
|
|
568
|
-
value: 'KERE'
|
|
569
|
-
}
|
|
570
|
-
]
|
|
571
|
-
]
|
|
572
|
-
}
|
|
573
|
-
])
|
|
574
|
-
);
|
|
575
|
-
|
|
576
|
-
module.exports['IMAP Parser: Section: allow trailing ws'] = test =>
|
|
577
|
-
asyncWrapper(test, async test =>
|
|
578
|
-
test.deepEqual((await parser('TAG1 CMD BODY[HEADER.FIELDS (Subject From) ]')).attributes, [
|
|
579
|
-
{
|
|
580
|
-
type: 'ATOM',
|
|
581
|
-
value: 'BODY',
|
|
582
|
-
section: [
|
|
583
|
-
{
|
|
584
|
-
type: 'ATOM',
|
|
585
|
-
value: 'HEADER.FIELDS'
|
|
586
|
-
},
|
|
587
|
-
[
|
|
588
|
-
{
|
|
589
|
-
type: 'ATOM',
|
|
590
|
-
value: 'Subject'
|
|
591
|
-
},
|
|
592
|
-
{
|
|
593
|
-
type: 'ATOM',
|
|
594
|
-
value: 'From'
|
|
595
|
-
}
|
|
596
|
-
]
|
|
597
|
-
]
|
|
598
|
-
}
|
|
599
|
-
])
|
|
600
|
-
);
|
|
601
|
-
|
|
602
|
-
module.exports['IMAP Parser: Readable: simple'] = test =>
|
|
603
|
-
asyncWrapper(test, async test =>
|
|
604
|
-
test.deepEqual(await parser('* OK Hello world!'), {
|
|
605
|
-
command: 'OK',
|
|
606
|
-
tag: '*',
|
|
607
|
-
attributes: [
|
|
608
|
-
{
|
|
609
|
-
type: 'TEXT',
|
|
610
|
-
value: 'Hello world!'
|
|
611
|
-
}
|
|
612
|
-
]
|
|
613
|
-
})
|
|
614
|
-
);
|
|
615
|
-
|
|
616
|
-
module.exports['IMAP Parser: Readable: section'] = test =>
|
|
617
|
-
asyncWrapper(test, async test =>
|
|
618
|
-
test.deepEqual(await parser('* OK [CAPABILITY IDLE] Hello world!'), {
|
|
619
|
-
command: 'OK',
|
|
620
|
-
tag: '*',
|
|
621
|
-
attributes: [
|
|
622
|
-
{
|
|
623
|
-
section: [
|
|
624
|
-
{
|
|
625
|
-
type: 'ATOM',
|
|
626
|
-
value: 'CAPABILITY'
|
|
627
|
-
},
|
|
628
|
-
{
|
|
629
|
-
type: 'ATOM',
|
|
630
|
-
value: 'IDLE'
|
|
631
|
-
}
|
|
632
|
-
],
|
|
633
|
-
type: 'ATOM',
|
|
634
|
-
value: ''
|
|
635
|
-
},
|
|
636
|
-
{
|
|
637
|
-
type: 'TEXT',
|
|
638
|
-
value: 'Hello world!'
|
|
639
|
-
}
|
|
640
|
-
]
|
|
641
|
-
})
|
|
642
|
-
);
|
|
643
|
-
|
|
644
|
-
// USEATTR is from RFC6154; we are testing that just an ATOM
|
|
645
|
-
// on its own will parse successfully here. (All of the
|
|
646
|
-
// RFC5530 codes are also single atoms.)
|
|
647
|
-
module.exports['IMAP Parser: Section: USEATTR'] = test =>
|
|
648
|
-
asyncWrapper(test, async test =>
|
|
649
|
-
test.deepEqual(await parser('TAG1 OK [USEATTR] \\All not supported'), {
|
|
650
|
-
tag: 'TAG1',
|
|
651
|
-
command: 'OK',
|
|
652
|
-
attributes: [
|
|
653
|
-
{
|
|
654
|
-
type: 'ATOM',
|
|
655
|
-
value: '',
|
|
656
|
-
section: [
|
|
657
|
-
{
|
|
658
|
-
type: 'ATOM',
|
|
659
|
-
value: 'USEATTR'
|
|
660
|
-
}
|
|
661
|
-
]
|
|
662
|
-
},
|
|
663
|
-
{
|
|
664
|
-
type: 'TEXT',
|
|
665
|
-
value: '\\All not supported'
|
|
666
|
-
}
|
|
667
|
-
]
|
|
668
|
-
})
|
|
669
|
-
);
|
|
670
|
-
|
|
671
|
-
// RFC5267 defines the NOUPDATE error. Including for quote /
|
|
672
|
-
// string coverage.
|
|
673
|
-
module.exports['IMAP Parser: Section: NOUPDATE'] = test =>
|
|
674
|
-
asyncWrapper(test, async test =>
|
|
675
|
-
test.deepEqual(await parser('* NO [NOUPDATE "B02"] Too many contexts'), {
|
|
676
|
-
tag: '*',
|
|
677
|
-
command: 'NO',
|
|
678
|
-
attributes: [
|
|
679
|
-
{
|
|
680
|
-
type: 'ATOM',
|
|
681
|
-
value: '',
|
|
682
|
-
section: [
|
|
683
|
-
{
|
|
684
|
-
type: 'ATOM',
|
|
685
|
-
value: 'NOUPDATE'
|
|
686
|
-
},
|
|
687
|
-
{
|
|
688
|
-
type: 'STRING',
|
|
689
|
-
value: 'B02'
|
|
690
|
-
}
|
|
691
|
-
]
|
|
692
|
-
},
|
|
693
|
-
{
|
|
694
|
-
type: 'TEXT',
|
|
695
|
-
value: 'Too many contexts'
|
|
696
|
-
}
|
|
697
|
-
]
|
|
698
|
-
})
|
|
699
|
-
);
|
|
700
|
-
|
|
701
|
-
// RFC5464 defines the METADATA response code; adding this to
|
|
702
|
-
// ensure the transition for when '2199' hits ']' is handled
|
|
703
|
-
// safely.
|
|
704
|
-
module.exports['IMAP Parser: Section: METADATA'] = test =>
|
|
705
|
-
asyncWrapper(test, async test =>
|
|
706
|
-
test.deepEqual(await parser('TAG1 OK [METADATA LONGENTRIES 2199] GETMETADATA complete'), {
|
|
707
|
-
tag: 'TAG1',
|
|
708
|
-
command: 'OK',
|
|
709
|
-
attributes: [
|
|
710
|
-
{
|
|
711
|
-
type: 'ATOM',
|
|
712
|
-
value: '',
|
|
713
|
-
section: [
|
|
714
|
-
{
|
|
715
|
-
type: 'ATOM',
|
|
716
|
-
value: 'METADATA'
|
|
717
|
-
},
|
|
718
|
-
{
|
|
719
|
-
type: 'ATOM',
|
|
720
|
-
value: 'LONGENTRIES'
|
|
721
|
-
},
|
|
722
|
-
{
|
|
723
|
-
type: 'ATOM',
|
|
724
|
-
value: '2199'
|
|
725
|
-
}
|
|
726
|
-
]
|
|
727
|
-
},
|
|
728
|
-
{
|
|
729
|
-
type: 'TEXT',
|
|
730
|
-
value: 'GETMETADATA complete'
|
|
731
|
-
}
|
|
732
|
-
]
|
|
733
|
-
})
|
|
734
|
-
);
|
|
735
|
-
|
|
736
|
-
// RFC4467 defines URLMECH. Included because of the example
|
|
737
|
-
// third atom involves base64-encoding which is somewhat unusual
|
|
738
|
-
module.exports['IMAP Parser: Section: URLMECH'] = test =>
|
|
739
|
-
asyncWrapper(test, async test =>
|
|
740
|
-
test.deepEqual(await parser('TAG1 OK [URLMECH INTERNAL XSAMPLE=P34OKhO7VEkCbsiYY8rGEg==] done'), {
|
|
741
|
-
tag: 'TAG1',
|
|
742
|
-
command: 'OK',
|
|
743
|
-
attributes: [
|
|
744
|
-
{
|
|
745
|
-
type: 'ATOM',
|
|
746
|
-
value: '',
|
|
747
|
-
section: [
|
|
748
|
-
{
|
|
749
|
-
type: 'ATOM',
|
|
750
|
-
value: 'URLMECH'
|
|
751
|
-
},
|
|
752
|
-
{
|
|
753
|
-
type: 'ATOM',
|
|
754
|
-
value: 'INTERNAL'
|
|
755
|
-
},
|
|
756
|
-
{
|
|
757
|
-
type: 'ATOM',
|
|
758
|
-
value: 'XSAMPLE=P34OKhO7VEkCbsiYY8rGEg=='
|
|
759
|
-
}
|
|
760
|
-
]
|
|
761
|
-
},
|
|
762
|
-
{
|
|
763
|
-
type: 'TEXT',
|
|
764
|
-
value: 'done'
|
|
765
|
-
}
|
|
766
|
-
]
|
|
767
|
-
})
|
|
768
|
-
);
|
|
769
|
-
|
|
770
|
-
// RFC2221 defines REFERRAL where the argument is an imapurl
|
|
771
|
-
// (defined by RFC2192 which is obsoleted by RFC5092) which
|
|
772
|
-
// is significantly more complicated than the rest of the IMAP
|
|
773
|
-
// grammar and which was based on the RFC2060 grammar where
|
|
774
|
-
// resp_text_code included:
|
|
775
|
-
// atom [SPACE 1*<any TEXT_CHAR except ']'>]
|
|
776
|
-
// So this is just a test case of our explicit special-casing
|
|
777
|
-
// of REFERRAL.
|
|
778
|
-
module.exports['IMAP Parser: Section: REFERRAL'] = test =>
|
|
779
|
-
asyncWrapper(test, async test =>
|
|
780
|
-
test.deepEqual(await parser('TAG1 NO [REFERRAL IMAP://user;AUTH=*@SERVER2/] Remote Server'), {
|
|
781
|
-
tag: 'TAG1',
|
|
782
|
-
command: 'NO',
|
|
783
|
-
attributes: [
|
|
784
|
-
{
|
|
785
|
-
type: 'ATOM',
|
|
786
|
-
value: '',
|
|
787
|
-
section: [
|
|
788
|
-
{
|
|
789
|
-
type: 'ATOM',
|
|
790
|
-
value: 'REFERRAL'
|
|
791
|
-
},
|
|
792
|
-
{
|
|
793
|
-
type: 'ATOM',
|
|
794
|
-
value: 'IMAP://user;AUTH=*@SERVER2/'
|
|
795
|
-
}
|
|
796
|
-
]
|
|
797
|
-
},
|
|
798
|
-
{
|
|
799
|
-
type: 'TEXT',
|
|
800
|
-
value: 'Remote Server'
|
|
801
|
-
}
|
|
802
|
-
]
|
|
803
|
-
})
|
|
804
|
-
);
|
|
805
|
-
|
|
806
|
-
// PERMANENTFLAGS is from RFC3501. Its syntax is also very
|
|
807
|
-
// similar to BADCHARSET, except BADCHARSET has astrings
|
|
808
|
-
// inside the list.
|
|
809
|
-
module.exports['IMAP Parser: Section: PERMANENTFLAGS'] = test =>
|
|
810
|
-
asyncWrapper(test, async test =>
|
|
811
|
-
test.deepEqual(await parser('* OK [PERMANENTFLAGS (de:hacking $label kt-evalution [css3-page] \\*)] Flags permitted.'), {
|
|
812
|
-
tag: '*',
|
|
813
|
-
command: 'OK',
|
|
814
|
-
attributes: [
|
|
815
|
-
{
|
|
816
|
-
type: 'ATOM',
|
|
817
|
-
value: '',
|
|
818
|
-
section: [
|
|
819
|
-
{
|
|
820
|
-
type: 'ATOM',
|
|
821
|
-
value: 'PERMANENTFLAGS'
|
|
822
|
-
},
|
|
823
|
-
[
|
|
824
|
-
{
|
|
825
|
-
type: 'ATOM',
|
|
826
|
-
value: 'de:hacking'
|
|
827
|
-
},
|
|
828
|
-
{
|
|
829
|
-
type: 'ATOM',
|
|
830
|
-
value: '$label'
|
|
831
|
-
},
|
|
832
|
-
{
|
|
833
|
-
type: 'ATOM',
|
|
834
|
-
value: 'kt-evalution'
|
|
835
|
-
},
|
|
836
|
-
{
|
|
837
|
-
type: 'ATOM',
|
|
838
|
-
value: '[css3-page]'
|
|
839
|
-
},
|
|
840
|
-
{
|
|
841
|
-
type: 'ATOM',
|
|
842
|
-
value: '\\*'
|
|
843
|
-
}
|
|
844
|
-
]
|
|
845
|
-
]
|
|
846
|
-
},
|
|
847
|
-
{
|
|
848
|
-
type: 'TEXT',
|
|
849
|
-
value: 'Flags permitted.'
|
|
850
|
-
}
|
|
851
|
-
]
|
|
852
|
-
})
|
|
853
|
-
);
|
|
854
|
-
|
|
855
|
-
// COPYUID is from RFC4315 and included the previously failing
|
|
856
|
-
// parsing situation of a sequence terminated by ']' rather than
|
|
857
|
-
// whitespace.
|
|
858
|
-
module.exports['IMAP Parser: Section: COPYUID'] = test =>
|
|
859
|
-
asyncWrapper(test, async test =>
|
|
860
|
-
test.deepEqual(await parser('TAG1 OK [COPYUID 4 1417051618:1417051620 1421730687:1421730689] COPY completed'), {
|
|
861
|
-
tag: 'TAG1',
|
|
862
|
-
command: 'OK',
|
|
863
|
-
attributes: [
|
|
864
|
-
{
|
|
865
|
-
type: 'ATOM',
|
|
866
|
-
value: '',
|
|
867
|
-
section: [
|
|
868
|
-
{
|
|
869
|
-
type: 'ATOM',
|
|
870
|
-
value: 'COPYUID'
|
|
871
|
-
},
|
|
872
|
-
{
|
|
873
|
-
type: 'ATOM',
|
|
874
|
-
value: '4'
|
|
875
|
-
},
|
|
876
|
-
{
|
|
877
|
-
type: 'SEQUENCE',
|
|
878
|
-
value: '1417051618:1417051620'
|
|
879
|
-
},
|
|
880
|
-
{
|
|
881
|
-
type: 'SEQUENCE',
|
|
882
|
-
value: '1421730687:1421730689'
|
|
883
|
-
}
|
|
884
|
-
]
|
|
885
|
-
},
|
|
886
|
-
{
|
|
887
|
-
type: 'TEXT',
|
|
888
|
-
value: 'COPY completed'
|
|
889
|
-
}
|
|
890
|
-
]
|
|
891
|
-
})
|
|
892
|
-
);
|
|
893
|
-
|
|
894
|
-
// MODIFIED is from RFC4551 and is basically the same situation
|
|
895
|
-
// as the COPYUID case, but in this case our example sequences
|
|
896
|
-
// have commas in them. (Note that if there was no comma, the
|
|
897
|
-
// '7,9' payload would end up an ATOM.)
|
|
898
|
-
module.exports['IMAP Parser: Section: MODIFIED'] = test =>
|
|
899
|
-
asyncWrapper(test, async test =>
|
|
900
|
-
test.deepEqual(await parser('TAG1 OK [MODIFIED 7,9] Conditional STORE failed'), {
|
|
901
|
-
tag: 'TAG1',
|
|
902
|
-
command: 'OK',
|
|
903
|
-
attributes: [
|
|
904
|
-
{
|
|
905
|
-
type: 'ATOM',
|
|
906
|
-
value: '',
|
|
907
|
-
section: [
|
|
908
|
-
{
|
|
909
|
-
type: 'ATOM',
|
|
910
|
-
value: 'MODIFIED'
|
|
911
|
-
},
|
|
912
|
-
{
|
|
913
|
-
type: 'SEQUENCE',
|
|
914
|
-
value: '7,9'
|
|
915
|
-
}
|
|
916
|
-
]
|
|
917
|
-
},
|
|
918
|
-
{
|
|
919
|
-
type: 'TEXT',
|
|
920
|
-
value: 'Conditional STORE failed'
|
|
921
|
-
}
|
|
922
|
-
]
|
|
923
|
-
})
|
|
924
|
-
);
|
|
925
|
-
|
|
926
|
-
module.exports['IMAP Parser: Partial: Start'] = test =>
|
|
927
|
-
asyncWrapper(test, async test =>
|
|
928
|
-
test.deepEqual((await parser('TAG1 CMD BODY[]<0>')).attributes, [
|
|
929
|
-
{
|
|
930
|
-
type: 'ATOM',
|
|
931
|
-
value: 'BODY',
|
|
932
|
-
section: [],
|
|
933
|
-
partial: [0]
|
|
934
|
-
}
|
|
935
|
-
])
|
|
936
|
-
);
|
|
937
|
-
|
|
938
|
-
module.exports['IMAP Parser: Partial: Start.End'] = test =>
|
|
939
|
-
asyncWrapper(test, async test =>
|
|
940
|
-
test.deepEqual((await parser('TAG1 CMD BODY[]<12.45>')).attributes, [
|
|
941
|
-
{
|
|
942
|
-
type: 'ATOM',
|
|
943
|
-
value: 'BODY',
|
|
944
|
-
section: [],
|
|
945
|
-
partial: [12, 45]
|
|
946
|
-
}
|
|
947
|
-
])
|
|
948
|
-
);
|
|
949
|
-
|
|
950
|
-
module.exports['IMAP Parser: Partial: Section'] = test =>
|
|
951
|
-
asyncWrapper(test, async test =>
|
|
952
|
-
test.deepEqual((await parser('TAG1 CMD BODY[HEADER.FIELDS (Subject From)]<12.45>')).attributes, [
|
|
953
|
-
{
|
|
954
|
-
type: 'ATOM',
|
|
955
|
-
value: 'BODY',
|
|
956
|
-
section: [
|
|
957
|
-
// keep indentation
|
|
958
|
-
{
|
|
959
|
-
type: 'ATOM',
|
|
960
|
-
value: 'HEADER.FIELDS'
|
|
961
|
-
},
|
|
962
|
-
[
|
|
963
|
-
{
|
|
964
|
-
type: 'ATOM',
|
|
965
|
-
value: 'Subject'
|
|
966
|
-
},
|
|
967
|
-
{
|
|
968
|
-
type: 'ATOM',
|
|
969
|
-
value: 'From'
|
|
970
|
-
}
|
|
971
|
-
]
|
|
972
|
-
],
|
|
973
|
-
partial: [12, 45]
|
|
974
|
-
}
|
|
975
|
-
])
|
|
976
|
-
);
|
|
977
|
-
|
|
978
|
-
module.exports['IMAP Parser: Partial: fail zero prefix for start'] = test => asyncWrapperFail(test, async test => test.ok(await parser('TAG1 CMD BODY[]<01>')));
|
|
979
|
-
|
|
980
|
-
module.exports['IMAP Parser: Partial: fail zero prefix for end'] = test => asyncWrapperFail(test, async test => test.ok(await parser('TAG1 CMD BODY[]<0.01>')));
|
|
981
|
-
|
|
982
|
-
module.exports['IMAP Parser: Partial: fail extra separator'] = test => asyncWrapperFail(test, async test => test.ok(await parser('TAG1 CMD BODY[]<0.1.>')));
|
|
983
|
-
|
|
984
|
-
module.exports['IMAP Parser: Sequence: mixed'] = test =>
|
|
985
|
-
asyncWrapper(test, async test =>
|
|
986
|
-
test.deepEqual((await parser('TAG1 CMD *:4,5:7 TEST')).attributes, [
|
|
987
|
-
{
|
|
988
|
-
type: 'SEQUENCE',
|
|
989
|
-
value: '*:4,5:7'
|
|
990
|
-
},
|
|
991
|
-
{
|
|
992
|
-
type: 'ATOM',
|
|
993
|
-
value: 'TEST'
|
|
994
|
-
}
|
|
995
|
-
])
|
|
996
|
-
);
|
|
997
|
-
|
|
998
|
-
module.exports['IMAP Parser: Sequence: range'] = test =>
|
|
999
|
-
asyncWrapper(test, async test =>
|
|
1000
|
-
test.deepEqual((await parser('TAG1 CMD 1:* TEST')).attributes, [
|
|
1001
|
-
{
|
|
1002
|
-
type: 'SEQUENCE',
|
|
1003
|
-
value: '1:*'
|
|
1004
|
-
},
|
|
1005
|
-
{
|
|
1006
|
-
type: 'ATOM',
|
|
1007
|
-
value: 'TEST'
|
|
1008
|
-
}
|
|
1009
|
-
])
|
|
1010
|
-
);
|
|
1011
|
-
|
|
1012
|
-
module.exports['IMAP Parser: Sequence: limited range'] = test =>
|
|
1013
|
-
asyncWrapper(test, async test =>
|
|
1014
|
-
test.deepEqual((await parser('TAG1 CMD *:4 TEST')).attributes, [
|
|
1015
|
-
{
|
|
1016
|
-
type: 'SEQUENCE',
|
|
1017
|
-
value: '*:4'
|
|
1018
|
-
},
|
|
1019
|
-
{
|
|
1020
|
-
type: 'ATOM',
|
|
1021
|
-
value: 'TEST'
|
|
1022
|
-
}
|
|
1023
|
-
])
|
|
1024
|
-
);
|
|
1025
|
-
|
|
1026
|
-
module.exports['IMAP Parser: Sequence: fail partial range'] = test => asyncWrapperFail(test, async test => test.ok(await parser('TAG1 CMD *:4,5:')));
|
|
1027
|
-
|
|
1028
|
-
module.exports['IMAP Parser: Sequence: fail invalid chars'] = test => asyncWrapperFail(test, async test => test.ok(await parser('TAG1 CMD *:4,5:TEST TEST')));
|
|
1029
|
-
|
|
1030
|
-
module.exports['IMAP Parser: Sequence: fail partial range w/ args'] = test =>
|
|
1031
|
-
asyncWrapperFail(test, async test => test.ok(await parser('TAG1 CMD *:4,5: TEST')));
|
|
1032
|
-
|
|
1033
|
-
module.exports['IMAP Parser: Sequence: fail missing colon'] = test => asyncWrapperFail(test, async test => test.ok(await parser('TAG1 CMD *4,5 TEST')));
|
|
1034
|
-
|
|
1035
|
-
module.exports['IMAP Parser: Sequence: fail non-range wildchar 1'] = test => asyncWrapperFail(test, async test => test.ok(await parser('TAG1 CMD *,5 TEST')));
|
|
1036
|
-
|
|
1037
|
-
module.exports['IMAP Parser: Sequence: fail non-range wildchar 2'] = test => asyncWrapperFail(test, async test => test.ok(await parser('TAG1 CMD 5,* TEST')));
|
|
1038
|
-
|
|
1039
|
-
module.exports['IMAP Parser: Sequence: failextra comma'] = test => asyncWrapperFail(test, async test => test.ok(await parser('TAG1 CMD 5, TEST')));
|
|
1040
|
-
|
|
1041
|
-
module.exports['IMAP Parser: escaped quotes'] = test =>
|
|
1042
|
-
asyncWrapper(test, async test =>
|
|
1043
|
-
test.deepEqual((await parser('* 331 FETCH (ENVELOPE ("=?ISO-8859-1?Q?\\"G=FCnter__Hammerl\\"?="))')).attributes, [
|
|
1044
|
-
{
|
|
1045
|
-
type: 'ATOM',
|
|
1046
|
-
value: 'FETCH'
|
|
1047
|
-
},
|
|
1048
|
-
[
|
|
1049
|
-
{
|
|
1050
|
-
type: 'ATOM',
|
|
1051
|
-
value: 'ENVELOPE'
|
|
1052
|
-
},
|
|
1053
|
-
[
|
|
1054
|
-
{
|
|
1055
|
-
type: 'STRING',
|
|
1056
|
-
value: '=?ISO-8859-1?Q?"G=FCnter__Hammerl"?='
|
|
1057
|
-
}
|
|
1058
|
-
]
|
|
1059
|
-
]
|
|
1060
|
-
])
|
|
1061
|
-
);
|
|
1062
|
-
|
|
1063
|
-
module.exports['IMAP Parser: mimetorture'] = test => asyncWrapper(test, async test => test.deepEqual(await parser(mimetorture.input), mimetorture.output));
|
|
1064
|
-
|
|
1065
|
-
module.exports['IMAP Parser, unicode select'] = test =>
|
|
1066
|
-
asyncWrapper(test, async test =>
|
|
1067
|
-
test.deepEqual((await parser('F OK [READ-WRITE] [Gmail]/Visi laiškai selected. (Success) [THROTTLED]')).attributes, [
|
|
1068
|
-
{
|
|
1069
|
-
type: 'ATOM',
|
|
1070
|
-
value: '',
|
|
1071
|
-
section: [{ type: 'ATOM', value: 'READ-WRITE' }]
|
|
1072
|
-
},
|
|
1073
|
-
{ type: 'TEXT', value: '[Gmail]/Visi laiškai selected. (Success) [THROTTLED]' }
|
|
1074
|
-
])
|
|
1075
|
-
);
|
|
1076
|
-
|
|
1077
|
-
module.exports['IMAP Parser, unicode select 2'] = test =>
|
|
1078
|
-
asyncWrapper(test, async test =>
|
|
1079
|
-
test.deepEqual((await parser('E OK [READ-WRITE] [Gmail]/Вся почта selected. (Success) [THROTTLED]')).attributes, [
|
|
1080
|
-
{
|
|
1081
|
-
type: 'ATOM',
|
|
1082
|
-
value: '',
|
|
1083
|
-
section: [{ type: 'ATOM', value: 'READ-WRITE' }]
|
|
1084
|
-
},
|
|
1085
|
-
{ type: 'TEXT', value: '[Gmail]/Вся почта selected. (Success) [THROTTLED]' }
|
|
1086
|
-
])
|
|
1087
|
-
);
|
|
1088
|
-
|
|
1089
|
-
module.exports['IMAP Parser, single quote in atom'] = test =>
|
|
1090
|
-
asyncWrapper(test, async test =>
|
|
1091
|
-
test.deepEqual((await parser('* LIST (HasNoChildren UnMarked) "/" \'a')).attributes, [
|
|
1092
|
-
[
|
|
1093
|
-
{ type: 'ATOM', value: 'HasNoChildren' },
|
|
1094
|
-
{ type: 'ATOM', value: 'UnMarked' }
|
|
1095
|
-
],
|
|
1096
|
-
{ type: 'STRING', value: '/' },
|
|
1097
|
-
{ type: 'ATOM', value: "'a" }
|
|
1098
|
-
])
|
|
1099
|
-
);
|
|
1100
|
-
|
|
1101
|
-
module.exports['IMAP Parser, unicode status 1'] = test =>
|
|
1102
|
-
asyncWrapper(test, async test =>
|
|
1103
|
-
test.deepEqual((await parser('* STATUS Segregator/Społeczności (MESSAGES 0 UIDNEXT 1 UIDVALIDITY 1)')).attributes, [
|
|
1104
|
-
{ type: 'ATOM', value: 'Segregator/Społeczności' },
|
|
1105
|
-
[
|
|
1106
|
-
{ type: 'ATOM', value: 'MESSAGES' },
|
|
1107
|
-
{ type: 'ATOM', value: '0' },
|
|
1108
|
-
{ type: 'ATOM', value: 'UIDNEXT' },
|
|
1109
|
-
{ type: 'ATOM', value: '1' },
|
|
1110
|
-
{ type: 'ATOM', value: 'UIDVALIDITY' },
|
|
1111
|
-
{ type: 'ATOM', value: '1' }
|
|
1112
|
-
]
|
|
1113
|
-
])
|
|
1114
|
-
);
|
|
1115
|
-
module.exports['IMAP Parser, unicode status 12'] = test =>
|
|
1116
|
-
asyncWrapper(test, async test =>
|
|
1117
|
-
test.deepEqual((await parser('* STATUS Šegregator/Społeczności (MESSAGES 0 UIDNEXT 1 UIDVALIDITY 1)')).attributes, [
|
|
1118
|
-
{ type: 'ATOM', value: 'Šegregator/Społeczności' },
|
|
1119
|
-
[
|
|
1120
|
-
{ type: 'ATOM', value: 'MESSAGES' },
|
|
1121
|
-
{ type: 'ATOM', value: '0' },
|
|
1122
|
-
{ type: 'ATOM', value: 'UIDNEXT' },
|
|
1123
|
-
{ type: 'ATOM', value: '1' },
|
|
1124
|
-
{ type: 'ATOM', value: 'UIDVALIDITY' },
|
|
1125
|
-
{ type: 'ATOM', value: '1' }
|
|
1126
|
-
]
|
|
1127
|
-
])
|
|
1128
|
-
);
|
|
1129
|
-
|
|
1130
|
-
module.exports['IMAP Parser, NO with a dot'] = test =>
|
|
1131
|
-
asyncWrapper(test, async test => {
|
|
1132
|
-
let parsed = await parser('X NO Server Unavailable. 15');
|
|
1133
|
-
test.equal(parsed.command, 'NO');
|
|
1134
|
-
test.deepEqual(parsed.attributes, [{ type: 'TEXT', value: 'Server Unavailable. 15' }]);
|
|
1135
|
-
});
|
|
1136
|
-
|
|
1137
|
-
module.exports['IMAP Parser, no tag or response (Exchange)'] = test =>
|
|
1138
|
-
asyncWrapper(test, async test => {
|
|
1139
|
-
let parsed = await parser('Server Unavailable. 15');
|
|
1140
|
-
test.equal(parsed.command, 'BAD');
|
|
1141
|
-
test.deepEqual(parsed.attributes, [{ type: 'TEXT', value: 'Server Unavailable. 15' }]);
|
|
1142
|
-
});
|
|
1143
|
-
|
|
1144
|
-
module.exports['IMAP Parser, BAD with throttling'] = test =>
|
|
1145
|
-
asyncWrapper(test, async test => {
|
|
1146
|
-
let parsed = await parser('X BAD Request is throttled. Suggested Backoff Time: 92415 milliseconds');
|
|
1147
|
-
test.equal(parsed.command, 'BAD');
|
|
1148
|
-
test.deepEqual(parsed.attributes, [{ type: 'TEXT', value: 'Request is throttled. Suggested Backoff Time: 92415 milliseconds' }]);
|
|
1149
|
-
});
|
|
1150
|
-
|
|
1151
|
-
module.exports['IMAP Parser, subfolder square bracket'] = test =>
|
|
1152
|
-
asyncWrapper(test, async test => {
|
|
1153
|
-
let parsed = await parser('* LIST (\\UnMarked) "." INBOX.[Airmail].Snooze');
|
|
1154
|
-
test.deepEqual(parsed.attributes, [
|
|
1155
|
-
[{ type: 'ATOM', value: '\\UnMarked' }],
|
|
1156
|
-
{ type: 'STRING', value: '.' },
|
|
1157
|
-
{ type: 'ATOM', value: 'INBOX.[Airmail].Snooze' }
|
|
1158
|
-
]);
|
|
1159
|
-
});
|
|
1160
|
-
|
|
1161
|
-
module.exports['IMAP Parser, FETCH with full range'] = test =>
|
|
1162
|
-
asyncWrapper(test, async test => {
|
|
1163
|
-
let parsed = await parser('* 32 FETCH (UID 32 RFC822.SIZE 3991 BODY[2.MIME] "(* 61B literal *)" BODY[2]<0.65536> "(* 6B literal *)")');
|
|
1164
|
-
test.deepEqual(parsed.attributes, [
|
|
1165
|
-
{
|
|
1166
|
-
type: 'ATOM',
|
|
1167
|
-
value: 'FETCH'
|
|
1168
|
-
},
|
|
1169
|
-
[
|
|
1170
|
-
{
|
|
1171
|
-
type: 'ATOM',
|
|
1172
|
-
value: 'UID'
|
|
1173
|
-
},
|
|
1174
|
-
{
|
|
1175
|
-
type: 'ATOM',
|
|
1176
|
-
value: '32'
|
|
1177
|
-
},
|
|
1178
|
-
{
|
|
1179
|
-
type: 'ATOM',
|
|
1180
|
-
value: 'RFC822.SIZE'
|
|
1181
|
-
},
|
|
1182
|
-
{
|
|
1183
|
-
type: 'ATOM',
|
|
1184
|
-
value: '3991'
|
|
1185
|
-
},
|
|
1186
|
-
{
|
|
1187
|
-
type: 'ATOM',
|
|
1188
|
-
value: 'BODY',
|
|
1189
|
-
section: [
|
|
1190
|
-
{
|
|
1191
|
-
type: 'ATOM',
|
|
1192
|
-
value: '2.MIME'
|
|
1193
|
-
}
|
|
1194
|
-
]
|
|
1195
|
-
},
|
|
1196
|
-
{
|
|
1197
|
-
type: 'STRING',
|
|
1198
|
-
value: '(* 61B literal *)'
|
|
1199
|
-
},
|
|
1200
|
-
{
|
|
1201
|
-
type: 'ATOM',
|
|
1202
|
-
value: 'BODY',
|
|
1203
|
-
section: [
|
|
1204
|
-
{
|
|
1205
|
-
type: 'ATOM',
|
|
1206
|
-
value: '2'
|
|
1207
|
-
}
|
|
1208
|
-
],
|
|
1209
|
-
partial: [0, 65536]
|
|
1210
|
-
},
|
|
1211
|
-
{
|
|
1212
|
-
type: 'STRING',
|
|
1213
|
-
value: '(* 6B literal *)'
|
|
1214
|
-
}
|
|
1215
|
-
]
|
|
1216
|
-
]);
|
|
1217
|
-
});
|
|
1218
|
-
|
|
1219
|
-
module.exports['IMAP Parser, FETCH with BODYSTRUCTURE'] = test =>
|
|
1220
|
-
asyncWrapper(test, async test => {
|
|
1221
|
-
let parsed = await parser(
|
|
1222
|
-
'* 1013 FETCH (UID 2986 MODSEQ (4960) BODYSTRUCTURE (("text" "plain" ("charset" "us-ascii") NIL NIL "7bit" 16 1 NIL NIL NIL NIL)("message" "rfc822" ("name" "Tellimuse Microsoft 365 Business Standard arve vaatamine.eml") NIL NIL "7bit" 370684 ("Mon, 16 Dec 2024 03:28:28 +0000" "Tellimuse Microsoft 365 Business Standard arve vaatamine" (("Microsoft" NIL "microsoft-noreply" "microsoft.com")) (("Microsoft" NIL "microsoft-noreply" "microsoft.com")) (("Microsoft" NIL "microsoft-noreply" "microsoft.com")) ((NIL NIL "andris.reinman" "gmail.com")) NIL NIL NIL "<58710631-775f-4c07-96ff-28a776f44d90@az.eastus2.microsoft.com>") ((("text" "plain" ("charset" "utf-8") NIL NIL "quoted-printable" 2866 80 NIL NIL NIL NIL)("text" "html" ("charset" "utf-8") NIL NIL "quoted-printable" 78392 1770 NIL NIL NIL NIL) "alternative" ("boundary" "=-EcWGOW6mwE+0T4lm385OWw==") NIL NIL NIL)("application" "octet-stream" ("name" "52482541500.pdf") NIL NIL "base64" 279430 NIL ("attachment" ("filename" "52482541500.pdf")) NIL NIL) "mixed" ("boundary" "=-1wJq2CLBJ6H+Zk2GPX9FKw==") NIL NIL NIL) 5580 NIL ("attachment" ("filename" "Tellimuse Microsoft 365 Business Standard arve vaatamine.eml")) NIL NIL) "mixed" ("boundary" "Apple-Mail=_F700EE9B-43B1-4EF1-95EE-CAA13391B333") NIL NIL NIL))'
|
|
1223
|
-
);
|
|
1224
|
-
|
|
1225
|
-
test.deepEqual(parsed.attributes, [
|
|
1226
|
-
{ type: 'ATOM', value: 'FETCH' },
|
|
1227
|
-
[
|
|
1228
|
-
{ type: 'ATOM', value: 'UID' },
|
|
1229
|
-
{ type: 'ATOM', value: '2986' },
|
|
1230
|
-
{ type: 'ATOM', value: 'MODSEQ' },
|
|
1231
|
-
[{ type: 'ATOM', value: '4960' }],
|
|
1232
|
-
{ type: 'ATOM', value: 'BODYSTRUCTURE' },
|
|
1233
|
-
[
|
|
1234
|
-
[
|
|
1235
|
-
{ type: 'STRING', value: 'text' },
|
|
1236
|
-
{ type: 'STRING', value: 'plain' },
|
|
1237
|
-
[
|
|
1238
|
-
{ type: 'STRING', value: 'charset' },
|
|
1239
|
-
{ type: 'STRING', value: 'us-ascii' }
|
|
1240
|
-
],
|
|
1241
|
-
null,
|
|
1242
|
-
null,
|
|
1243
|
-
{ type: 'STRING', value: '7bit' },
|
|
1244
|
-
{ type: 'ATOM', value: '16' },
|
|
1245
|
-
{ type: 'ATOM', value: '1' },
|
|
1246
|
-
null,
|
|
1247
|
-
null,
|
|
1248
|
-
null,
|
|
1249
|
-
null
|
|
1250
|
-
],
|
|
1251
|
-
[
|
|
1252
|
-
{ type: 'STRING', value: 'message' },
|
|
1253
|
-
{ type: 'STRING', value: 'rfc822' },
|
|
1254
|
-
[
|
|
1255
|
-
{ type: 'STRING', value: 'name' },
|
|
1256
|
-
{ type: 'STRING', value: 'Tellimuse Microsoft 365 Business Standard arve vaatamine.eml' }
|
|
1257
|
-
],
|
|
1258
|
-
null,
|
|
1259
|
-
null,
|
|
1260
|
-
{ type: 'STRING', value: '7bit' },
|
|
1261
|
-
{ type: 'ATOM', value: '370684' },
|
|
1262
|
-
[
|
|
1263
|
-
{ type: 'STRING', value: 'Mon, 16 Dec 2024 03:28:28 +0000' },
|
|
1264
|
-
{ type: 'STRING', value: 'Tellimuse Microsoft 365 Business Standard arve vaatamine' },
|
|
1265
|
-
[
|
|
1266
|
-
[
|
|
1267
|
-
{ type: 'STRING', value: 'Microsoft' },
|
|
1268
|
-
null,
|
|
1269
|
-
{ type: 'STRING', value: 'microsoft-noreply' },
|
|
1270
|
-
{ type: 'STRING', value: 'microsoft.com' }
|
|
1271
|
-
]
|
|
1272
|
-
],
|
|
1273
|
-
[
|
|
1274
|
-
[
|
|
1275
|
-
{ type: 'STRING', value: 'Microsoft' },
|
|
1276
|
-
null,
|
|
1277
|
-
{ type: 'STRING', value: 'microsoft-noreply' },
|
|
1278
|
-
{ type: 'STRING', value: 'microsoft.com' }
|
|
1279
|
-
]
|
|
1280
|
-
],
|
|
1281
|
-
[
|
|
1282
|
-
[
|
|
1283
|
-
{ type: 'STRING', value: 'Microsoft' },
|
|
1284
|
-
null,
|
|
1285
|
-
{ type: 'STRING', value: 'microsoft-noreply' },
|
|
1286
|
-
{ type: 'STRING', value: 'microsoft.com' }
|
|
1287
|
-
]
|
|
1288
|
-
],
|
|
1289
|
-
[[null, null, { type: 'STRING', value: 'andris.reinman' }, { type: 'STRING', value: 'gmail.com' }]],
|
|
1290
|
-
null,
|
|
1291
|
-
null,
|
|
1292
|
-
null,
|
|
1293
|
-
{ type: 'STRING', value: '<58710631-775f-4c07-96ff-28a776f44d90@az.eastus2.microsoft.com>' }
|
|
1294
|
-
],
|
|
1295
|
-
[
|
|
1296
|
-
[
|
|
1297
|
-
[
|
|
1298
|
-
{ type: 'STRING', value: 'text' },
|
|
1299
|
-
{ type: 'STRING', value: 'plain' },
|
|
1300
|
-
[
|
|
1301
|
-
{ type: 'STRING', value: 'charset' },
|
|
1302
|
-
{ type: 'STRING', value: 'utf-8' }
|
|
1303
|
-
],
|
|
1304
|
-
null,
|
|
1305
|
-
null,
|
|
1306
|
-
{ type: 'STRING', value: 'quoted-printable' },
|
|
1307
|
-
{ type: 'ATOM', value: '2866' },
|
|
1308
|
-
{ type: 'ATOM', value: '80' },
|
|
1309
|
-
null,
|
|
1310
|
-
null,
|
|
1311
|
-
null,
|
|
1312
|
-
null
|
|
1313
|
-
],
|
|
1314
|
-
[
|
|
1315
|
-
{ type: 'STRING', value: 'text' },
|
|
1316
|
-
{ type: 'STRING', value: 'html' },
|
|
1317
|
-
[
|
|
1318
|
-
{ type: 'STRING', value: 'charset' },
|
|
1319
|
-
{ type: 'STRING', value: 'utf-8' }
|
|
1320
|
-
],
|
|
1321
|
-
null,
|
|
1322
|
-
null,
|
|
1323
|
-
{ type: 'STRING', value: 'quoted-printable' },
|
|
1324
|
-
{ type: 'ATOM', value: '78392' },
|
|
1325
|
-
{ type: 'ATOM', value: '1770' },
|
|
1326
|
-
null,
|
|
1327
|
-
null,
|
|
1328
|
-
null,
|
|
1329
|
-
null
|
|
1330
|
-
],
|
|
1331
|
-
{ type: 'STRING', value: 'alternative' },
|
|
1332
|
-
[
|
|
1333
|
-
{ type: 'STRING', value: 'boundary' },
|
|
1334
|
-
{ type: 'STRING', value: '=-EcWGOW6mwE+0T4lm385OWw==' }
|
|
1335
|
-
],
|
|
1336
|
-
null,
|
|
1337
|
-
null,
|
|
1338
|
-
null
|
|
1339
|
-
],
|
|
1340
|
-
[
|
|
1341
|
-
{ type: 'STRING', value: 'application' },
|
|
1342
|
-
{ type: 'STRING', value: 'octet-stream' },
|
|
1343
|
-
[
|
|
1344
|
-
{ type: 'STRING', value: 'name' },
|
|
1345
|
-
{ type: 'STRING', value: '52482541500.pdf' }
|
|
1346
|
-
],
|
|
1347
|
-
null,
|
|
1348
|
-
null,
|
|
1349
|
-
{ type: 'STRING', value: 'base64' },
|
|
1350
|
-
{ type: 'ATOM', value: '279430' },
|
|
1351
|
-
null,
|
|
1352
|
-
[
|
|
1353
|
-
{ type: 'STRING', value: 'attachment' },
|
|
1354
|
-
[
|
|
1355
|
-
{ type: 'STRING', value: 'filename' },
|
|
1356
|
-
{ type: 'STRING', value: '52482541500.pdf' }
|
|
1357
|
-
]
|
|
1358
|
-
],
|
|
1359
|
-
null,
|
|
1360
|
-
null
|
|
1361
|
-
],
|
|
1362
|
-
{ type: 'STRING', value: 'mixed' },
|
|
1363
|
-
[
|
|
1364
|
-
{ type: 'STRING', value: 'boundary' },
|
|
1365
|
-
{ type: 'STRING', value: '=-1wJq2CLBJ6H+Zk2GPX9FKw==' }
|
|
1366
|
-
],
|
|
1367
|
-
null,
|
|
1368
|
-
null,
|
|
1369
|
-
null
|
|
1370
|
-
],
|
|
1371
|
-
{ type: 'ATOM', value: '5580' },
|
|
1372
|
-
null,
|
|
1373
|
-
[
|
|
1374
|
-
{ type: 'STRING', value: 'attachment' },
|
|
1375
|
-
[
|
|
1376
|
-
{ type: 'STRING', value: 'filename' },
|
|
1377
|
-
{ type: 'STRING', value: 'Tellimuse Microsoft 365 Business Standard arve vaatamine.eml' }
|
|
1378
|
-
]
|
|
1379
|
-
],
|
|
1380
|
-
null,
|
|
1381
|
-
null
|
|
1382
|
-
],
|
|
1383
|
-
{ type: 'STRING', value: 'mixed' },
|
|
1384
|
-
[
|
|
1385
|
-
{ type: 'STRING', value: 'boundary' },
|
|
1386
|
-
{ type: 'STRING', value: 'Apple-Mail=_F700EE9B-43B1-4EF1-95EE-CAA13391B333' }
|
|
1387
|
-
],
|
|
1388
|
-
null,
|
|
1389
|
-
null,
|
|
1390
|
-
null
|
|
1391
|
-
]
|
|
1392
|
-
]
|
|
1393
|
-
]);
|
|
1394
|
-
});
|
|
1395
|
-
|
|
1396
|
-
// NB! must not share a name with the deep-BODYSTRUCTURE test above - a duplicate
|
|
1397
|
-
// module.exports key silently overwrites the earlier test and it never runs
|
|
1398
|
-
module.exports['IMAP Parser, FETCH exceeding max nesting depth'] = test =>
|
|
1399
|
-
asyncWrapper(test, async test => {
|
|
1400
|
-
try {
|
|
1401
|
-
let parsed = await parser('* 1 FETCH (UID 1 (((((((((((((((((((((((((');
|
|
1402
|
-
test.ok(!parsed);
|
|
1403
|
-
} catch (err) {
|
|
1404
|
-
test.ok(err);
|
|
1405
|
-
if (err.code !== 'MAX_IMAP_NESTING_REACHED') {
|
|
1406
|
-
throw err;
|
|
1407
|
-
}
|
|
1408
|
-
}
|
|
1409
|
-
});
|
|
1410
|
-
|
|
1411
|
-
module.exports['IMAP Parser, ATOM with <, [, ]'] = test =>
|
|
1412
|
-
asyncWrapper(test, async test => {
|
|
1413
|
-
let password = `<[+=</$]`;
|
|
1414
|
-
let parsed = await parser(`3 LOGIN user@domain ${password}`);
|
|
1415
|
-
test.deepEqual(parsed, {
|
|
1416
|
-
tag: '3',
|
|
1417
|
-
command: 'LOGIN',
|
|
1418
|
-
attributes: [
|
|
1419
|
-
{ type: 'ATOM', value: 'user@domain' },
|
|
1420
|
-
{ type: 'ATOM', value: password }
|
|
1421
|
-
]
|
|
1422
|
-
});
|
|
1423
|
-
});
|
|
1424
|
-
|
|
1425
|
-
module.exports['IMAP Parser: unbalanced bracket in a response code keeps the human-readable text'] = test =>
|
|
1426
|
-
asyncWrapper(test, async test => {
|
|
1427
|
-
// RFC 9051 lets a response code carry free text containing '[' but not ']'.
|
|
1428
|
-
// Counting that '[' as a nested bracket loses the whole human-readable text,
|
|
1429
|
-
// which is what NO/BAD error messages are built from.
|
|
1430
|
-
const parsed = await parser('A1 NO [XFOO see bar[baz] mailbox is busy');
|
|
1431
|
-
const text = (parsed.attributes || [])
|
|
1432
|
-
.filter(entry => entry && entry.type === 'TEXT')
|
|
1433
|
-
.map(entry => entry.value)
|
|
1434
|
-
.join('');
|
|
1435
|
-
test.equal(text, 'mailbox is busy');
|
|
1436
|
-
});
|
|
1437
|
-
|
|
1438
|
-
module.exports['IMAP Parser: balanced brackets inside a response code are still tolerated'] = test =>
|
|
1439
|
-
asyncWrapper(test, async test => {
|
|
1440
|
-
// Servers do put bracketed values inside a code, so a plain first-']' scan
|
|
1441
|
-
// would cut the code in half
|
|
1442
|
-
const parsed = await parser('* OK [PERMANENTFLAGS ([css3-page] \\*)] Flags permitted.');
|
|
1443
|
-
const text = (parsed.attributes || [])
|
|
1444
|
-
.filter(entry => entry && entry.type === 'TEXT')
|
|
1445
|
-
.map(entry => entry.value)
|
|
1446
|
-
.join('');
|
|
1447
|
-
test.equal(text, 'Flags permitted.');
|
|
1448
|
-
test.equal(parsed.attributes[0].section[0].value, 'PERMANENTFLAGS');
|
|
1449
|
-
});
|
|
1450
|
-
|
|
1451
|
-
module.exports['IMAP Parser: a parse failure after the tag exposes the parsed tag'] = test =>
|
|
1452
|
-
asyncWrapper(test, async test => {
|
|
1453
|
-
// The connection settles the in-flight command from an unparseable tagged
|
|
1454
|
-
// completion using this tag - re-deriving it from the raw bytes instead would
|
|
1455
|
-
// bypass the leading-NUL workaround and strand the command
|
|
1456
|
-
let err = null;
|
|
1457
|
-
try {
|
|
1458
|
-
await parser(Buffer.from('A5 OK [\x01BAD-CODE] done', 'binary'));
|
|
1459
|
-
} catch (e) {
|
|
1460
|
-
err = e;
|
|
1461
|
-
}
|
|
1462
|
-
test.ok(err, 'the line must fail to parse');
|
|
1463
|
-
test.equal(err && err.parsedTag, 'A5');
|
|
1464
|
-
|
|
1465
|
-
// The NUL-padding workaround is inherited: the exposed tag is the stripped one
|
|
1466
|
-
err = null;
|
|
1467
|
-
try {
|
|
1468
|
-
await parser(Buffer.from('\x00\x00A6 OK [\x01BAD-CODE] done', 'binary'));
|
|
1469
|
-
} catch (e) {
|
|
1470
|
-
err = e;
|
|
1471
|
-
}
|
|
1472
|
-
test.ok(err, 'the padded line must fail to parse');
|
|
1473
|
-
test.equal(err && err.parsedTag, 'A6');
|
|
1474
|
-
});
|