imapflow 1.7.7 → 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 +27 -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 +785 -1802
- 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 -57
- 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 -873
- 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 -593
|
@@ -1,809 +0,0 @@
|
|
|
1
|
-
/*eslint no-unused-expressions: 0, prefer-arrow-callback: 0 */
|
|
2
|
-
|
|
3
|
-
'use strict';
|
|
4
|
-
|
|
5
|
-
const { parser, compiler } = require('../lib/handler/imap-handler');
|
|
6
|
-
|
|
7
|
-
let asyncWrapper = (test, handler) => {
|
|
8
|
-
handler(test)
|
|
9
|
-
.then(() => test.done())
|
|
10
|
-
.catch(err => {
|
|
11
|
-
test.ifError(err);
|
|
12
|
-
test.done();
|
|
13
|
-
});
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
module.exports['IMAP Compiler: mixed'] = test =>
|
|
17
|
-
asyncWrapper(test, async test => {
|
|
18
|
-
const command =
|
|
19
|
-
'* FETCH (ENVELOPE ("Mon, 2 Sep 2013 05:30:13 -0700 (PDT)" NIL ((NIL NIL "andris" "kreata.ee")) ((NIL NIL "andris" "kreata.ee")) ((NIL NIL "andris" "kreata.ee")) ((NIL NIL "andris" "tr.ee")) NIL NIL NIL "<-4730417346358914070@unknownmsgid>") BODYSTRUCTURE (("MESSAGE" "RFC822" NIL NIL NIL "7BIT" 105 (NIL NIL ((NIL NIL "andris" "kreata.ee")) ((NIL NIL "andris" "kreata.ee")) ((NIL NIL "andris" "kreata.ee")) ((NIL NIL "andris" "pangalink.net")) NIL NIL "<test1>" NIL) ("TEXT" "PLAIN" NIL NIL NIL "7BIT" 12 0 NIL NIL NIL) 5 NIL NIL NIL)("MESSAGE" "RFC822" NIL NIL NIL "7BIT" 83 (NIL NIL ((NIL NIL "andris" "kreata.ee")) ((NIL NIL "andris" "kreata.ee")) ((NIL NIL "andris" "kreata.ee")) ((NIL NIL "andris" "pangalink.net")) NIL NIL "NIL" NIL) ("TEXT" "PLAIN" NIL NIL NIL "7BIT" 12 0 NIL NIL NIL) 4 NIL NIL NIL)("TEXT" "HTML" ("CHARSET" "utf-8") NIL NIL "QUOTED-PRINTABLE" 19 0 NIL NIL NIL) "MIXED" ("BOUNDARY" "----mailcomposer-?=_1-1328088797399") NIL NIL))';
|
|
20
|
-
const parsed = await parser(command, {
|
|
21
|
-
allowUntagged: true
|
|
22
|
-
});
|
|
23
|
-
const compiled = (await compiler(parsed)).toString();
|
|
24
|
-
test.equal(compiled, command);
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
module.exports['IMAP Compiler: no attributes'] = test =>
|
|
28
|
-
asyncWrapper(test, async test =>
|
|
29
|
-
test.equal(
|
|
30
|
-
(
|
|
31
|
-
await compiler({
|
|
32
|
-
tag: '*',
|
|
33
|
-
command: 'CMD'
|
|
34
|
-
})
|
|
35
|
-
).toString(),
|
|
36
|
-
'* CMD'
|
|
37
|
-
)
|
|
38
|
-
);
|
|
39
|
-
|
|
40
|
-
module.exports['IMAP Compiler: TEXT'] = test =>
|
|
41
|
-
asyncWrapper(test, async test =>
|
|
42
|
-
test.equal(
|
|
43
|
-
(
|
|
44
|
-
await compiler({
|
|
45
|
-
tag: '*',
|
|
46
|
-
command: 'CMD',
|
|
47
|
-
attributes: [
|
|
48
|
-
{
|
|
49
|
-
type: 'TEXT',
|
|
50
|
-
value: 'Tere tere!'
|
|
51
|
-
}
|
|
52
|
-
]
|
|
53
|
-
})
|
|
54
|
-
).toString(),
|
|
55
|
-
'* CMD Tere tere!'
|
|
56
|
-
)
|
|
57
|
-
);
|
|
58
|
-
|
|
59
|
-
module.exports['IMAP Compiler: NUMBER attribute'] = test =>
|
|
60
|
-
asyncWrapper(test, async test =>
|
|
61
|
-
test.equal(
|
|
62
|
-
(
|
|
63
|
-
await compiler({
|
|
64
|
-
tag: '*',
|
|
65
|
-
command: 'CMD',
|
|
66
|
-
attributes: [
|
|
67
|
-
{
|
|
68
|
-
type: 'NUMBER',
|
|
69
|
-
value: 42
|
|
70
|
-
}
|
|
71
|
-
]
|
|
72
|
-
})
|
|
73
|
-
).toString(),
|
|
74
|
-
'* CMD 42'
|
|
75
|
-
)
|
|
76
|
-
);
|
|
77
|
-
|
|
78
|
-
module.exports['IMAP Compiler: NUMBER attribute defaults missing value to 0'] = test =>
|
|
79
|
-
asyncWrapper(test, async test =>
|
|
80
|
-
test.equal(
|
|
81
|
-
(
|
|
82
|
-
await compiler({
|
|
83
|
-
tag: '*',
|
|
84
|
-
command: 'CMD',
|
|
85
|
-
attributes: [{ type: 'NUMBER' }]
|
|
86
|
-
})
|
|
87
|
-
).toString(),
|
|
88
|
-
'* CMD 0'
|
|
89
|
-
)
|
|
90
|
-
);
|
|
91
|
-
|
|
92
|
-
module.exports['IMAP Compiler: unrecognized value type compiles to empty buffer'] = test =>
|
|
93
|
-
asyncWrapper(test, async test => {
|
|
94
|
-
// A SEQUENCE node whose value is neither string/number/Buffer falls through
|
|
95
|
-
// formatRespEntry to an empty Buffer rather than throwing.
|
|
96
|
-
let out = (
|
|
97
|
-
await compiler({
|
|
98
|
-
tag: '*',
|
|
99
|
-
command: 'CMD',
|
|
100
|
-
attributes: [{ type: 'SEQUENCE', value: { unexpected: true } }]
|
|
101
|
-
})
|
|
102
|
-
).toString();
|
|
103
|
-
test.equal(out, '* CMD ');
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
module.exports['IMAP Compiler: SECTION'] = test =>
|
|
107
|
-
asyncWrapper(test, async test =>
|
|
108
|
-
test.equal(
|
|
109
|
-
(
|
|
110
|
-
await compiler({
|
|
111
|
-
tag: '*',
|
|
112
|
-
command: 'CMD',
|
|
113
|
-
attributes: [
|
|
114
|
-
{
|
|
115
|
-
type: 'SECTION',
|
|
116
|
-
section: [
|
|
117
|
-
{
|
|
118
|
-
type: 'ATOM',
|
|
119
|
-
value: 'ALERT'
|
|
120
|
-
}
|
|
121
|
-
]
|
|
122
|
-
}
|
|
123
|
-
]
|
|
124
|
-
})
|
|
125
|
-
).toString(),
|
|
126
|
-
'* CMD [ALERT]'
|
|
127
|
-
)
|
|
128
|
-
);
|
|
129
|
-
|
|
130
|
-
module.exports['IMAP Compiler: escaped ATOM'] = test =>
|
|
131
|
-
asyncWrapper(test, async test =>
|
|
132
|
-
test.equal(
|
|
133
|
-
(
|
|
134
|
-
await compiler({
|
|
135
|
-
tag: '*',
|
|
136
|
-
command: 'CMD',
|
|
137
|
-
attributes: [
|
|
138
|
-
{
|
|
139
|
-
type: 'ATOM',
|
|
140
|
-
value: 'ALERT'
|
|
141
|
-
},
|
|
142
|
-
{
|
|
143
|
-
type: 'ATOM',
|
|
144
|
-
value: '\\ALERT'
|
|
145
|
-
},
|
|
146
|
-
{
|
|
147
|
-
type: 'ATOM',
|
|
148
|
-
value: 'NO ALERT'
|
|
149
|
-
}
|
|
150
|
-
]
|
|
151
|
-
})
|
|
152
|
-
).toString(),
|
|
153
|
-
'* CMD ALERT \\ALERT "NO ALERT"'
|
|
154
|
-
)
|
|
155
|
-
);
|
|
156
|
-
|
|
157
|
-
module.exports['IMAP Compiler: SEQUENCE'] = test =>
|
|
158
|
-
asyncWrapper(test, async test =>
|
|
159
|
-
test.equal(
|
|
160
|
-
(
|
|
161
|
-
await compiler({
|
|
162
|
-
tag: '*',
|
|
163
|
-
command: 'CMD',
|
|
164
|
-
attributes: [
|
|
165
|
-
{
|
|
166
|
-
type: 'SEQUENCE',
|
|
167
|
-
value: '*:4,5,6'
|
|
168
|
-
}
|
|
169
|
-
]
|
|
170
|
-
})
|
|
171
|
-
).toString(),
|
|
172
|
-
'* CMD *:4,5,6'
|
|
173
|
-
)
|
|
174
|
-
);
|
|
175
|
-
|
|
176
|
-
module.exports['IMAP Compiler: NIL'] = test =>
|
|
177
|
-
asyncWrapper(test, async test =>
|
|
178
|
-
test.equal(
|
|
179
|
-
(
|
|
180
|
-
await compiler({
|
|
181
|
-
tag: '*',
|
|
182
|
-
command: 'CMD',
|
|
183
|
-
attributes: [null, null]
|
|
184
|
-
})
|
|
185
|
-
).toString(),
|
|
186
|
-
'* CMD NIL NIL'
|
|
187
|
-
)
|
|
188
|
-
);
|
|
189
|
-
|
|
190
|
-
module.exports['IMAP Compiler: quoted TEXT'] = test =>
|
|
191
|
-
asyncWrapper(test, async test =>
|
|
192
|
-
test.equal(
|
|
193
|
-
(
|
|
194
|
-
await compiler({
|
|
195
|
-
tag: '*',
|
|
196
|
-
command: 'CMD',
|
|
197
|
-
attributes: [
|
|
198
|
-
{
|
|
199
|
-
type: 'String',
|
|
200
|
-
value: 'Tere tere!',
|
|
201
|
-
sensitive: true
|
|
202
|
-
},
|
|
203
|
-
'Vana kere'
|
|
204
|
-
]
|
|
205
|
-
})
|
|
206
|
-
).toString(),
|
|
207
|
-
'* CMD "Tere tere!" "Vana kere"'
|
|
208
|
-
)
|
|
209
|
-
);
|
|
210
|
-
|
|
211
|
-
module.exports['IMAP Compiler: keep short strings'] = test =>
|
|
212
|
-
asyncWrapper(test, async test =>
|
|
213
|
-
test.equal(
|
|
214
|
-
(
|
|
215
|
-
await compiler(
|
|
216
|
-
{
|
|
217
|
-
tag: '*',
|
|
218
|
-
command: 'CMD',
|
|
219
|
-
attributes: [
|
|
220
|
-
{
|
|
221
|
-
type: 'String',
|
|
222
|
-
value: 'Tere tere!'
|
|
223
|
-
},
|
|
224
|
-
'Vana kere'
|
|
225
|
-
]
|
|
226
|
-
},
|
|
227
|
-
{ asArray: false, isLogging: true }
|
|
228
|
-
)
|
|
229
|
-
).toString(),
|
|
230
|
-
'* CMD "Tere tere!" "Vana kere"'
|
|
231
|
-
)
|
|
232
|
-
);
|
|
233
|
-
|
|
234
|
-
module.exports['IMAP Compiler: hide sensitive strings'] = test =>
|
|
235
|
-
asyncWrapper(test, async test =>
|
|
236
|
-
test.equal(
|
|
237
|
-
(
|
|
238
|
-
await compiler(
|
|
239
|
-
{
|
|
240
|
-
tag: '*',
|
|
241
|
-
command: 'CMD',
|
|
242
|
-
attributes: [
|
|
243
|
-
{
|
|
244
|
-
type: 'String',
|
|
245
|
-
value: 'Tere tere!',
|
|
246
|
-
sensitive: true
|
|
247
|
-
},
|
|
248
|
-
'Vana kere'
|
|
249
|
-
]
|
|
250
|
-
},
|
|
251
|
-
{ asArray: false, isLogging: true }
|
|
252
|
-
)
|
|
253
|
-
).toString(),
|
|
254
|
-
'* CMD "(* value hidden *)" "Vana kere"'
|
|
255
|
-
)
|
|
256
|
-
);
|
|
257
|
-
|
|
258
|
-
module.exports['IMAP Compiler: hide long strings'] = test =>
|
|
259
|
-
asyncWrapper(test, async test =>
|
|
260
|
-
test.equal(
|
|
261
|
-
(
|
|
262
|
-
await compiler(
|
|
263
|
-
{
|
|
264
|
-
tag: '*',
|
|
265
|
-
command: 'CMD',
|
|
266
|
-
attributes: [
|
|
267
|
-
{
|
|
268
|
-
type: 'String',
|
|
269
|
-
value: 'Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere! Tere tere!'
|
|
270
|
-
},
|
|
271
|
-
'Vana kere'
|
|
272
|
-
]
|
|
273
|
-
},
|
|
274
|
-
{ asArray: false, isLogging: true }
|
|
275
|
-
)
|
|
276
|
-
).toString(),
|
|
277
|
-
'* CMD "(* 219B string *)" "Vana kere"'
|
|
278
|
-
)
|
|
279
|
-
);
|
|
280
|
-
|
|
281
|
-
module.exports['IMAP Compiler: no command'] = test =>
|
|
282
|
-
asyncWrapper(test, async test =>
|
|
283
|
-
test.equal(
|
|
284
|
-
(
|
|
285
|
-
await compiler({
|
|
286
|
-
tag: '*',
|
|
287
|
-
attributes: [
|
|
288
|
-
1,
|
|
289
|
-
{
|
|
290
|
-
type: 'ATOM',
|
|
291
|
-
value: 'EXPUNGE'
|
|
292
|
-
}
|
|
293
|
-
]
|
|
294
|
-
})
|
|
295
|
-
).toString(),
|
|
296
|
-
'* 1 EXPUNGE'
|
|
297
|
-
)
|
|
298
|
-
);
|
|
299
|
-
|
|
300
|
-
module.exports['IMAP Compiler: LITERAL text'] = test =>
|
|
301
|
-
asyncWrapper(test, async test =>
|
|
302
|
-
test.equal(
|
|
303
|
-
(
|
|
304
|
-
await compiler({
|
|
305
|
-
tag: '*',
|
|
306
|
-
command: 'CMD',
|
|
307
|
-
attributes: [
|
|
308
|
-
// keep indentation
|
|
309
|
-
{
|
|
310
|
-
type: 'LITERAL',
|
|
311
|
-
value: 'Tere tere!'
|
|
312
|
-
},
|
|
313
|
-
'Vana kere'
|
|
314
|
-
]
|
|
315
|
-
})
|
|
316
|
-
).toString(),
|
|
317
|
-
'* CMD {10}\r\nTere tere! "Vana kere"'
|
|
318
|
-
)
|
|
319
|
-
);
|
|
320
|
-
|
|
321
|
-
module.exports['IMAP Compiler: LITERAL literal'] = test =>
|
|
322
|
-
asyncWrapper(test, async test =>
|
|
323
|
-
test.equal(
|
|
324
|
-
(
|
|
325
|
-
await compiler({
|
|
326
|
-
tag: '*',
|
|
327
|
-
command: 'CMD',
|
|
328
|
-
attributes: [
|
|
329
|
-
// keep indentation
|
|
330
|
-
{
|
|
331
|
-
type: 'LITERAL',
|
|
332
|
-
value: 'Tere\x00 tere!',
|
|
333
|
-
isLiteral8: false
|
|
334
|
-
},
|
|
335
|
-
'Vana kere'
|
|
336
|
-
]
|
|
337
|
-
})
|
|
338
|
-
).toString(),
|
|
339
|
-
'* CMD {11}\r\nTere\x00 tere! "Vana kere"'
|
|
340
|
-
)
|
|
341
|
-
);
|
|
342
|
-
|
|
343
|
-
module.exports['IMAP Compiler: LITERAL literal8'] = test =>
|
|
344
|
-
asyncWrapper(test, async test =>
|
|
345
|
-
test.equal(
|
|
346
|
-
(
|
|
347
|
-
await compiler({
|
|
348
|
-
tag: '*',
|
|
349
|
-
command: 'CMD',
|
|
350
|
-
attributes: [
|
|
351
|
-
// keep indentation
|
|
352
|
-
{
|
|
353
|
-
type: 'LITERAL',
|
|
354
|
-
value: 'Tere\x00 tere!',
|
|
355
|
-
isLiteral8: true
|
|
356
|
-
},
|
|
357
|
-
'Vana kere'
|
|
358
|
-
]
|
|
359
|
-
})
|
|
360
|
-
).toString(),
|
|
361
|
-
'* CMD ~{11}\r\nTere\x00 tere! "Vana kere"'
|
|
362
|
-
)
|
|
363
|
-
);
|
|
364
|
-
|
|
365
|
-
// RFC 7888 (folded into IMAP4rev2): with LITERAL- a non-synchronizing literal
|
|
366
|
-
// marker {n+} is only allowed for literals of up to 4096 bytes - anything larger
|
|
367
|
-
// must use the synchronizing {n} form, in every compilation mode
|
|
368
|
-
module.exports['IMAP Compiler: LITERAL- oversized literal stays synchronizing in single-buffer mode'] = test =>
|
|
369
|
-
asyncWrapper(test, async test => {
|
|
370
|
-
let payload = 'a'.repeat(4097);
|
|
371
|
-
let compiled = (
|
|
372
|
-
await compiler(
|
|
373
|
-
{
|
|
374
|
-
tag: '*',
|
|
375
|
-
command: 'CMD',
|
|
376
|
-
attributes: [
|
|
377
|
-
{
|
|
378
|
-
type: 'LITERAL',
|
|
379
|
-
value: payload
|
|
380
|
-
}
|
|
381
|
-
]
|
|
382
|
-
},
|
|
383
|
-
{ literalMinus: true }
|
|
384
|
-
)
|
|
385
|
-
).toString();
|
|
386
|
-
test.ok(compiled.startsWith('* CMD {4097}\r\n'), `must not use a non-synchronizing marker: ${compiled.slice(0, 20)}`);
|
|
387
|
-
});
|
|
388
|
-
|
|
389
|
-
module.exports['IMAP Compiler: LITERAL- boundary: exactly 4096 bytes is non-synchronizing'] = test =>
|
|
390
|
-
asyncWrapper(test, async test => {
|
|
391
|
-
let payload = 'a'.repeat(4096);
|
|
392
|
-
let parts = (
|
|
393
|
-
await compiler(
|
|
394
|
-
{
|
|
395
|
-
tag: '*',
|
|
396
|
-
command: 'CMD',
|
|
397
|
-
attributes: [
|
|
398
|
-
{
|
|
399
|
-
type: 'LITERAL',
|
|
400
|
-
value: payload
|
|
401
|
-
}
|
|
402
|
-
]
|
|
403
|
-
},
|
|
404
|
-
{ asArray: true, literalMinus: true }
|
|
405
|
-
)
|
|
406
|
-
).map(entry => entry.toString());
|
|
407
|
-
test.equal(parts.length, 1, 'literal must be appended inline without a continuation break');
|
|
408
|
-
test.ok(parts[0].startsWith('* CMD {4096+}\r\n'));
|
|
409
|
-
});
|
|
410
|
-
|
|
411
|
-
module.exports['IMAP Compiler: LITERAL- boundary: 4097 bytes falls back to synchronizing'] = test =>
|
|
412
|
-
asyncWrapper(test, async test => {
|
|
413
|
-
let payload = 'a'.repeat(4097);
|
|
414
|
-
let parts = (
|
|
415
|
-
await compiler(
|
|
416
|
-
{
|
|
417
|
-
tag: '*',
|
|
418
|
-
command: 'CMD',
|
|
419
|
-
attributes: [
|
|
420
|
-
{
|
|
421
|
-
type: 'LITERAL',
|
|
422
|
-
value: payload
|
|
423
|
-
}
|
|
424
|
-
]
|
|
425
|
-
},
|
|
426
|
-
{ asArray: true, literalMinus: true }
|
|
427
|
-
)
|
|
428
|
-
).map(entry => entry.toString());
|
|
429
|
-
test.equal(parts.length, 2, 'literal must wait for a continuation response');
|
|
430
|
-
test.ok(parts[0].endsWith('{4097}\r\n'), `marker must be synchronizing: ${parts[0].slice(-12)}`);
|
|
431
|
-
});
|
|
432
|
-
|
|
433
|
-
// The literal size marker counts octets, not UTF-16 code units - a unicode string
|
|
434
|
-
// value must declare its UTF-8 byte length
|
|
435
|
-
module.exports['IMAP Compiler: LITERAL declares byte length for unicode string values'] = test =>
|
|
436
|
-
asyncWrapper(test, async test => {
|
|
437
|
-
let compiled = await compiler({
|
|
438
|
-
tag: '*',
|
|
439
|
-
command: 'CMD',
|
|
440
|
-
attributes: [
|
|
441
|
-
{
|
|
442
|
-
type: 'LITERAL',
|
|
443
|
-
value: 'Sõnumid'
|
|
444
|
-
}
|
|
445
|
-
]
|
|
446
|
-
});
|
|
447
|
-
test.equal(compiled.toString(), '* CMD {8}\r\nSõnumid');
|
|
448
|
-
});
|
|
449
|
-
|
|
450
|
-
module.exports['IMAP Compiler: LITERAL array 1'] = test =>
|
|
451
|
-
asyncWrapper(test, async test =>
|
|
452
|
-
test.deepEqual(
|
|
453
|
-
(
|
|
454
|
-
await compiler(
|
|
455
|
-
{
|
|
456
|
-
tag: '*',
|
|
457
|
-
command: 'CMD',
|
|
458
|
-
attributes: [
|
|
459
|
-
{
|
|
460
|
-
type: 'LITERAL',
|
|
461
|
-
value: 'Tere tere!'
|
|
462
|
-
},
|
|
463
|
-
{
|
|
464
|
-
type: 'LITERAL',
|
|
465
|
-
value: 'Vana kere'
|
|
466
|
-
}
|
|
467
|
-
]
|
|
468
|
-
},
|
|
469
|
-
{ asArray: true }
|
|
470
|
-
)
|
|
471
|
-
).map(entry => entry.toString()),
|
|
472
|
-
['* CMD {10}\r\n', 'Tere tere! {9}\r\n', 'Vana kere']
|
|
473
|
-
)
|
|
474
|
-
);
|
|
475
|
-
|
|
476
|
-
module.exports['IMAP Compiler: LITERAL array 2'] = test =>
|
|
477
|
-
asyncWrapper(test, async test =>
|
|
478
|
-
test.deepEqual(
|
|
479
|
-
(
|
|
480
|
-
await compiler(
|
|
481
|
-
{
|
|
482
|
-
tag: '*',
|
|
483
|
-
command: 'CMD',
|
|
484
|
-
attributes: [
|
|
485
|
-
{
|
|
486
|
-
type: 'LITERAL',
|
|
487
|
-
value: 'Tere tere!'
|
|
488
|
-
},
|
|
489
|
-
{
|
|
490
|
-
type: 'LITERAL',
|
|
491
|
-
value: 'Vana kere'
|
|
492
|
-
},
|
|
493
|
-
'zzz'
|
|
494
|
-
]
|
|
495
|
-
},
|
|
496
|
-
{ asArray: true }
|
|
497
|
-
)
|
|
498
|
-
).map(entry => entry.toString()),
|
|
499
|
-
['* CMD {10}\r\n', 'Tere tere! {9}\r\n', 'Vana kere "zzz"']
|
|
500
|
-
)
|
|
501
|
-
);
|
|
502
|
-
|
|
503
|
-
module.exports['IMAP Compiler: LITERALPLUS array'] = test =>
|
|
504
|
-
asyncWrapper(test, async test =>
|
|
505
|
-
test.deepEqual(
|
|
506
|
-
(
|
|
507
|
-
await compiler(
|
|
508
|
-
{
|
|
509
|
-
tag: '*',
|
|
510
|
-
command: 'CMD',
|
|
511
|
-
attributes: [
|
|
512
|
-
{
|
|
513
|
-
type: 'LITERAL',
|
|
514
|
-
value: 'Tere tere!'
|
|
515
|
-
},
|
|
516
|
-
{
|
|
517
|
-
type: 'LITERAL',
|
|
518
|
-
value: 'Vana kere'
|
|
519
|
-
},
|
|
520
|
-
'zzz'
|
|
521
|
-
]
|
|
522
|
-
},
|
|
523
|
-
{ asArray: true, literalPlus: true }
|
|
524
|
-
)
|
|
525
|
-
).map(entry => entry.toString()),
|
|
526
|
-
['* CMD {10+}\r\nTere tere! {9+}\r\nVana kere "zzz"']
|
|
527
|
-
)
|
|
528
|
-
);
|
|
529
|
-
|
|
530
|
-
module.exports['IMAP Compiler: LITERAL array without tag/command'] = test =>
|
|
531
|
-
asyncWrapper(test, async test =>
|
|
532
|
-
test.deepEqual(
|
|
533
|
-
(
|
|
534
|
-
await compiler(
|
|
535
|
-
{
|
|
536
|
-
attributes: [
|
|
537
|
-
{
|
|
538
|
-
type: 'LITERAL',
|
|
539
|
-
value: 'Tere tere!'
|
|
540
|
-
},
|
|
541
|
-
{
|
|
542
|
-
type: 'LITERAL',
|
|
543
|
-
value: 'Vana kere'
|
|
544
|
-
}
|
|
545
|
-
]
|
|
546
|
-
},
|
|
547
|
-
{ asArray: true }
|
|
548
|
-
)
|
|
549
|
-
).map(entry => entry.toString()),
|
|
550
|
-
['{10}\r\n', 'Tere tere! {9}\r\n', 'Vana kere']
|
|
551
|
-
)
|
|
552
|
-
);
|
|
553
|
-
|
|
554
|
-
module.exports['IMAP Compiler: LITERAL byte length'] = test =>
|
|
555
|
-
asyncWrapper(test, async test =>
|
|
556
|
-
test.deepEqual(
|
|
557
|
-
(
|
|
558
|
-
await compiler(
|
|
559
|
-
{
|
|
560
|
-
tag: '*',
|
|
561
|
-
command: 'CMD',
|
|
562
|
-
attributes: [
|
|
563
|
-
{
|
|
564
|
-
type: 'LITERAL',
|
|
565
|
-
value: 'Tere tere!'
|
|
566
|
-
},
|
|
567
|
-
'Vana kere'
|
|
568
|
-
]
|
|
569
|
-
},
|
|
570
|
-
{ asArray: false, isLogging: true }
|
|
571
|
-
)
|
|
572
|
-
).toString(),
|
|
573
|
-
'* CMD "(* 10B literal *)" "Vana kere"'
|
|
574
|
-
)
|
|
575
|
-
);
|
|
576
|
-
|
|
577
|
-
module.exports['IMAP Compiler: MongoDB binary object is unwrapped'] = test =>
|
|
578
|
-
asyncWrapper(test, async test => {
|
|
579
|
-
// Create a non-Buffer object with a .buffer property (simulates MongoDB Binary)
|
|
580
|
-
const mongoBinary = { buffer: Buffer.from('test data') };
|
|
581
|
-
const compiled = (
|
|
582
|
-
await compiler({
|
|
583
|
-
tag: '*',
|
|
584
|
-
command: 'CMD',
|
|
585
|
-
attributes: [mongoBinary]
|
|
586
|
-
})
|
|
587
|
-
).toString();
|
|
588
|
-
// The buffer content should appear in the output (unwrapped from the MongoDB binary wrapper)
|
|
589
|
-
test.ok(compiled.includes('test data'), 'should contain the buffer content after unwrapping');
|
|
590
|
-
test.ok(compiled.includes('CMD'), 'should contain command');
|
|
591
|
-
});
|
|
592
|
-
|
|
593
|
-
module.exports['IMAP Compiler: long string truncated in logging mode'] = test =>
|
|
594
|
-
asyncWrapper(test, async test => {
|
|
595
|
-
const longString = 'x'.repeat(150);
|
|
596
|
-
const compiled = (
|
|
597
|
-
await compiler(
|
|
598
|
-
{
|
|
599
|
-
tag: '*',
|
|
600
|
-
command: 'CMD',
|
|
601
|
-
attributes: [longString]
|
|
602
|
-
},
|
|
603
|
-
{ asArray: false, isLogging: true }
|
|
604
|
-
)
|
|
605
|
-
).toString();
|
|
606
|
-
test.ok(compiled.includes('150B string'), 'should show byte count instead of content');
|
|
607
|
-
test.ok(!compiled.includes('x'.repeat(150)), 'should not contain the full string');
|
|
608
|
-
});
|
|
609
|
-
|
|
610
|
-
module.exports['IMAP Compiler: literal truncated in logging mode'] = test =>
|
|
611
|
-
asyncWrapper(test, async test => {
|
|
612
|
-
const compiled = (
|
|
613
|
-
await compiler(
|
|
614
|
-
{
|
|
615
|
-
tag: '*',
|
|
616
|
-
command: 'CMD',
|
|
617
|
-
attributes: [{ type: 'LITERAL', value: Buffer.alloc(200) }]
|
|
618
|
-
},
|
|
619
|
-
{ asArray: false, isLogging: true }
|
|
620
|
-
)
|
|
621
|
-
).toString();
|
|
622
|
-
test.ok(compiled.includes('200B literal'), 'should show byte count for literal');
|
|
623
|
-
});
|
|
624
|
-
|
|
625
|
-
module.exports['IMAP Compiler: partial range in SECTION'] = test =>
|
|
626
|
-
asyncWrapper(test, async test => {
|
|
627
|
-
const compiled = (
|
|
628
|
-
await compiler({
|
|
629
|
-
tag: '*',
|
|
630
|
-
command: 'CMD',
|
|
631
|
-
attributes: [
|
|
632
|
-
{
|
|
633
|
-
type: 'SECTION',
|
|
634
|
-
section: [{ type: 'ATOM', value: 'BODY' }],
|
|
635
|
-
partial: [0, 50]
|
|
636
|
-
}
|
|
637
|
-
]
|
|
638
|
-
})
|
|
639
|
-
).toString();
|
|
640
|
-
test.ok(compiled.includes('<0.50>'), 'should contain partial range <0.50>');
|
|
641
|
-
});
|
|
642
|
-
|
|
643
|
-
// Returns the error a compile attempt raised, or undefined when it succeeded.
|
|
644
|
-
// Several cases below assert that a token can never reach the wire, and the
|
|
645
|
-
// try/catch is the only interesting part of each. Takes either an attributes
|
|
646
|
-
// array (compiled under a default tag/command) or a full response object.
|
|
647
|
-
const compileError = async input => {
|
|
648
|
-
try {
|
|
649
|
-
await compiler(Array.isArray(input) ? { tag: 'A', command: 'CMD', attributes: input } : input);
|
|
650
|
-
} catch (err) {
|
|
651
|
-
return err;
|
|
652
|
-
}
|
|
653
|
-
};
|
|
654
|
-
|
|
655
|
-
module.exports['IMAP Compiler: SEQUENCE rejects values that are not sequence sets'] = test =>
|
|
656
|
-
asyncWrapper(test, async test => {
|
|
657
|
-
// Sequence sets are written verbatim, so a range string that reached the
|
|
658
|
-
// compiler unvalidated would put a second command on the wire
|
|
659
|
-
for (let value of ['1\r\nZZ1 LOGOUT', '1 2', '1;2', 'ALL', '1:2)', '1\t2', Buffer.from('1\r\nZZ NOOP')]) {
|
|
660
|
-
let err = await compileError([{ type: 'SEQUENCE', value }]);
|
|
661
|
-
test.equal(err && err.code, 'InvalidSequenceSet', `${JSON.stringify(value.toString())} must be rejected`);
|
|
662
|
-
}
|
|
663
|
-
});
|
|
664
|
-
|
|
665
|
-
module.exports['IMAP Compiler: SEQUENCE accepts every valid sequence-set form'] = test =>
|
|
666
|
-
asyncWrapper(test, async test => {
|
|
667
|
-
// '$' is the RFC 5182 SEARCHRES saved-result marker, valid as the entire set
|
|
668
|
-
for (let value of ['1', '*', '1:*', '*:1', '1,3,5', '1:3,7,9:*', '4294967295', '$']) {
|
|
669
|
-
const compiled = (await compiler({ tag: 'A', command: 'FETCH', attributes: [{ type: 'SEQUENCE', value }] })).toString();
|
|
670
|
-
test.equal(compiled, `A FETCH ${value}`);
|
|
671
|
-
}
|
|
672
|
-
|
|
673
|
-
// '$' only stands for the whole set, never an element of one
|
|
674
|
-
for (let value of ['$,1', '1,$', '$:2']) {
|
|
675
|
-
let err = await compileError([{ type: 'SEQUENCE', value }]);
|
|
676
|
-
test.equal(err && err.code, 'InvalidSequenceSet', `${JSON.stringify(value)} must be rejected`);
|
|
677
|
-
}
|
|
678
|
-
});
|
|
679
|
-
|
|
680
|
-
module.exports['IMAP Compiler: SEQUENCE validation stays linear on huge valid sets'] = test =>
|
|
681
|
-
asyncWrapper(test, async test => {
|
|
682
|
-
// The regex this replaced overflowed the engine's backtrack stack with an
|
|
683
|
-
// uncoded RangeError at roughly a million comma-separated elements - a set
|
|
684
|
-
// a fetch over a large mailbox can legitimately produce
|
|
685
|
-
const huge = Array.from({ length: 1500000 }, (_, i) => i + 1).join(',');
|
|
686
|
-
const compiled = await compiler({ tag: 'A', command: 'FETCH', attributes: [{ type: 'SEQUENCE', value: huge }] });
|
|
687
|
-
test.ok(compiled.toString().endsWith(huge), 'the huge but valid set must compile');
|
|
688
|
-
});
|
|
689
|
-
|
|
690
|
-
module.exports['IMAP Compiler: SEQUENCE validation is skipped when logging'] = test =>
|
|
691
|
-
asyncWrapper(test, async test => {
|
|
692
|
-
// The incoming token parser accepts sequence-shaped tokens the strict grammar
|
|
693
|
-
// rejects (an ESEARCH set like "1:2:3", a folder name like "12:30:00"). Every
|
|
694
|
-
// parsed server response is re-compiled for the log, so a throw here would let
|
|
695
|
-
// one quirky server line kill the whole connection.
|
|
696
|
-
for (let value of ['1:2:3', '12:30:00', '1,2:3:4']) {
|
|
697
|
-
const compiled = (await compiler({ tag: '*', command: 'OK', attributes: [{ type: 'SEQUENCE', value }] }, { isLogging: true })).toString();
|
|
698
|
-
test.equal(compiled, `* OK ${value}`, 'logging re-compile must pass the token through');
|
|
699
|
-
}
|
|
700
|
-
});
|
|
701
|
-
|
|
702
|
-
module.exports['IMAP Compiler: tag and command cannot carry a line terminator'] = test =>
|
|
703
|
-
asyncWrapper(test, async test => {
|
|
704
|
-
// The tag/command preamble is written verbatim ahead of any token, so it goes
|
|
705
|
-
// through the same choke point as everything else
|
|
706
|
-
let err = await compileError({ tag: 'A\r\nZZ LOGOUT', command: 'NOOP' });
|
|
707
|
-
test.equal(err && err.code, 'InvalidTokenValue', 'CRLF in the tag must be rejected');
|
|
708
|
-
|
|
709
|
-
err = await compileError({ tag: 'A', command: 'NOOP\r\nZZ LOGOUT' });
|
|
710
|
-
test.equal(err && err.code, 'InvalidTokenValue', 'CRLF in the command must be rejected');
|
|
711
|
-
});
|
|
712
|
-
|
|
713
|
-
module.exports['IMAP Compiler: quoted strings use IMAP escaping, not JSON escaping'] = test =>
|
|
714
|
-
asyncWrapper(test, async test => {
|
|
715
|
-
// Only DQUOTE and backslash have escapes in the IMAP grammar - a tab must
|
|
716
|
-
// survive as a raw byte rather than becoming a literal backslash-t
|
|
717
|
-
const compiled = (await compiler({ tag: 'A', command: 'CMD', attributes: [{ type: 'STRING', value: 'a\tb"c\\d' }] })).toString();
|
|
718
|
-
test.equal(compiled, 'A CMD "a\tb\\"c\\\\d"');
|
|
719
|
-
});
|
|
720
|
-
|
|
721
|
-
module.exports['IMAP Compiler: quoted strings reject CR, LF and NUL'] = test =>
|
|
722
|
-
asyncWrapper(test, async test => {
|
|
723
|
-
for (let value of ['a\rb', 'a\nb', 'a\0b']) {
|
|
724
|
-
let err = await compileError([{ type: 'STRING', value }]);
|
|
725
|
-
test.equal(err && err.code, 'InvalidStringValue', `${JSON.stringify(value)} cannot be sent as a quoted string`);
|
|
726
|
-
}
|
|
727
|
-
});
|
|
728
|
-
|
|
729
|
-
module.exports['IMAP Compiler: a mailbox name with CRLF cannot reach the wire'] = test =>
|
|
730
|
-
asyncWrapper(test, async test => {
|
|
731
|
-
// Paths travel as ATOM tokens and get quoted when they fall outside ATOM-CHAR
|
|
732
|
-
let err = await compileError([{ type: 'ATOM', value: 'INBOX\r\nZZ LOGOUT' }]);
|
|
733
|
-
test.equal(err && err.code, 'InvalidStringValue');
|
|
734
|
-
});
|
|
735
|
-
|
|
736
|
-
module.exports['IMAP Compiler: response text cannot carry a line terminator'] = test =>
|
|
737
|
-
asyncWrapper(test, async test => {
|
|
738
|
-
// TEXT is written verbatim as well, so it gets the same guarantee even though
|
|
739
|
-
// only the parser produces it today
|
|
740
|
-
let err = await compileError([{ type: 'TEXT', value: 'oops\r\nZZ NOOP' }]);
|
|
741
|
-
test.equal(err && err.code, 'InvalidTextValue');
|
|
742
|
-
});
|
|
743
|
-
|
|
744
|
-
module.exports['IMAP Compiler: NUMBER coerces its value instead of writing it through'] = test =>
|
|
745
|
-
asyncWrapper(test, async test => {
|
|
746
|
-
const compiled = (await compiler({ tag: 'A', command: 'CMD', attributes: [{ type: 'NUMBER', value: '1\r\nZZ NOOP' }] })).toString();
|
|
747
|
-
test.equal(compiled, 'A CMD 0', 'a non-numeric value must not reach the wire verbatim');
|
|
748
|
-
test.equal((await compiler({ tag: 'A', command: 'CMD', attributes: [{ type: 'NUMBER', value: '42' }] })).toString(), 'A CMD 42');
|
|
749
|
-
});
|
|
750
|
-
|
|
751
|
-
module.exports['IMAP Compiler: numeric tokens clamp to bounded non-negative integers'] = test =>
|
|
752
|
-
asyncWrapper(test, async test => {
|
|
753
|
-
// Infinity, negatives and unsafe magnitudes would otherwise emit bytes outside
|
|
754
|
-
// the number alphabet ("Infinity", "-5", "1e+300") and get a server BAD blamed
|
|
755
|
-
// on the server instead of the caller
|
|
756
|
-
for (let [value, expected] of [
|
|
757
|
-
[Infinity, '0'],
|
|
758
|
-
['Infinity', '0'],
|
|
759
|
-
[-5, '0'],
|
|
760
|
-
['2e21', '0'],
|
|
761
|
-
[4.6, '5']
|
|
762
|
-
]) {
|
|
763
|
-
const compiled = (await compiler({ tag: 'A', command: 'CMD', attributes: [{ type: 'NUMBER', value }] })).toString();
|
|
764
|
-
test.equal(compiled, `A CMD ${expected}`, `${JSON.stringify(value)} must clamp to ${expected}`);
|
|
765
|
-
}
|
|
766
|
-
});
|
|
767
|
-
|
|
768
|
-
module.exports['IMAP Compiler: partial range coerces its elements'] = test =>
|
|
769
|
-
asyncWrapper(test, async test => {
|
|
770
|
-
// The partial range is the last token component written verbatim, so it is
|
|
771
|
-
// coerced rather than joined as-is
|
|
772
|
-
const attributes = [{ type: 'ATOM', value: 'BODY.PEEK', section: [], partial: ['0>\r\nZZ NOOP'] }];
|
|
773
|
-
const compiled = (await compiler({ tag: 'A', command: 'FETCH', attributes })).toString();
|
|
774
|
-
test.equal(compiled, 'A FETCH BODY.PEEK[]<0>');
|
|
775
|
-
|
|
776
|
-
const normal = (
|
|
777
|
-
await compiler({ tag: 'A', command: 'FETCH', attributes: [{ type: 'ATOM', value: 'BODY.PEEK', section: [], partial: [0, 1024] }] })
|
|
778
|
-
).toString();
|
|
779
|
-
test.equal(normal, 'A FETCH BODY.PEEK[]<0.1024>');
|
|
780
|
-
|
|
781
|
-
// Floats and unbounded numerics clamp the same way NUMBER tokens do, so no
|
|
782
|
-
// non-digit byte ("512.5", "Infinity") can appear inside the partial range
|
|
783
|
-
const float = (
|
|
784
|
-
await compiler({ tag: 'A', command: 'FETCH', attributes: [{ type: 'ATOM', value: 'BODY.PEEK', section: [], partial: [0, 512.5] }] })
|
|
785
|
-
).toString();
|
|
786
|
-
test.equal(float, 'A FETCH BODY.PEEK[]<0.513>');
|
|
787
|
-
|
|
788
|
-
const unbounded = (
|
|
789
|
-
await compiler({ tag: 'A', command: 'FETCH', attributes: [{ type: 'ATOM', value: 'BODY.PEEK', section: [], partial: ['Infinity', '2e21'] }] })
|
|
790
|
-
).toString();
|
|
791
|
-
test.equal(unbounded, 'A FETCH BODY.PEEK[]<0.0>');
|
|
792
|
-
});
|
|
793
|
-
|
|
794
|
-
module.exports['IMAP Compiler: logging output never throws on unsendable values'] = test =>
|
|
795
|
-
asyncWrapper(test, async test => {
|
|
796
|
-
// The logging pass must survive whatever the wire pass refuses, so a rejected
|
|
797
|
-
// command can still be logged
|
|
798
|
-
const compiled = (
|
|
799
|
-
await compiler(
|
|
800
|
-
{
|
|
801
|
-
tag: 'A',
|
|
802
|
-
command: 'LOGIN',
|
|
803
|
-
attributes: [{ type: 'STRING', value: 'a\r\nb' }]
|
|
804
|
-
},
|
|
805
|
-
{ isLogging: true }
|
|
806
|
-
)
|
|
807
|
-
).toString();
|
|
808
|
-
test.ok(compiled.includes('\\r\\n'), 'control characters stay escaped for the log');
|
|
809
|
-
});
|