imapkit 4.3.0 → 5.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/README.md +167 -51
- package/bin/help.txt +17 -3
- package/bin/imapkit.js +53 -23
- package/dist/cjs/commands/append.js +1 -1
- package/dist/cjs/commands/create.js +2 -2
- package/dist/cjs/commands/delete.js +2 -14
- package/dist/cjs/commands/handlers/flags.d.ts +3 -3
- package/dist/cjs/commands/handlers/flags.js +3 -3
- package/dist/cjs/commands/handlers/store.js +3 -3
- package/dist/cjs/commands/rename.js +6 -46
- package/dist/cjs/commands/select.js +1 -0
- package/dist/cjs/commands/subscribe.js +7 -8
- package/dist/cjs/commands/unsubscribe.js +3 -9
- package/dist/cjs/control.d.ts +430 -0
- package/dist/cjs/control.js +637 -0
- package/dist/cjs/index.d.ts +8 -1
- package/dist/cjs/index.js +9 -2
- package/dist/cjs/load-plugins.d.ts +1 -1
- package/dist/cjs/load-plugins.js +7 -2
- package/dist/cjs/plugins/acl.js +109 -42
- package/dist/cjs/plugins/condstore.js +7 -0
- package/dist/cjs/plugins/index.js +1 -3
- package/dist/cjs/plugins/metadata.js +140 -57
- package/dist/cjs/plugins/objectid.js +10 -0
- package/dist/cjs/plugins/quota.js +50 -2
- package/dist/cjs/plugins/savedate.js +1 -1
- package/dist/cjs/plugins/special-use.d.ts +0 -8
- package/dist/cjs/plugins/special-use.js +23 -0
- package/dist/cjs/quirks.d.ts +28 -0
- package/dist/cjs/quirks.js +124 -0
- package/dist/cjs/random.d.ts +10 -0
- package/dist/cjs/random.js +22 -0
- package/dist/cjs/rest.d.ts +50 -0
- package/dist/cjs/rest.js +561 -0
- package/dist/cjs/script.d.ts +33 -4
- package/dist/cjs/script.js +64 -4
- package/dist/cjs/server.d.ts +149 -8
- package/dist/cjs/server.js +429 -152
- package/dist/cjs/smtp-listener.d.ts +3 -2
- package/dist/cjs/smtp-listener.js +10 -6
- package/dist/cjs/storage-schema.d.ts +139 -0
- package/dist/cjs/storage-schema.js +215 -0
- package/dist/cjs/store-operations.d.ts +168 -0
- package/dist/cjs/store-operations.js +422 -0
- package/dist/cjs/types.d.ts +22 -1
- package/dist/esm/commands/append.js +1 -1
- package/dist/esm/commands/create.js +2 -2
- package/dist/esm/commands/delete.js +2 -14
- package/dist/esm/commands/handlers/flags.d.ts +3 -3
- package/dist/esm/commands/handlers/flags.js +3 -3
- package/dist/esm/commands/handlers/store.js +3 -3
- package/dist/esm/commands/rename.js +6 -46
- package/dist/esm/commands/select.js +1 -0
- package/dist/esm/commands/subscribe.js +7 -8
- package/dist/esm/commands/unsubscribe.js +3 -9
- package/dist/esm/control.d.ts +430 -0
- package/dist/esm/control.js +630 -0
- package/dist/esm/index.d.ts +8 -1
- package/dist/esm/index.js +5 -2
- package/dist/esm/load-plugins.d.ts +1 -1
- package/dist/esm/load-plugins.js +7 -2
- package/dist/esm/plugins/acl.js +109 -42
- package/dist/esm/plugins/condstore.js +7 -0
- package/dist/esm/plugins/index.js +1 -3
- package/dist/esm/plugins/metadata.js +140 -57
- package/dist/esm/plugins/objectid.js +10 -0
- package/dist/esm/plugins/quota.js +50 -2
- package/dist/esm/plugins/savedate.js +1 -1
- package/dist/esm/plugins/special-use.d.ts +0 -8
- package/dist/esm/plugins/special-use.js +23 -0
- package/dist/esm/quirks.d.ts +28 -0
- package/dist/esm/quirks.js +120 -0
- package/dist/esm/random.d.ts +10 -0
- package/dist/esm/random.js +19 -0
- package/dist/esm/rest.d.ts +50 -0
- package/dist/esm/rest.js +553 -0
- package/dist/esm/script.d.ts +33 -4
- package/dist/esm/script.js +63 -4
- package/dist/esm/server.d.ts +149 -8
- package/dist/esm/server.js +429 -152
- package/dist/esm/smtp-listener.d.ts +3 -2
- package/dist/esm/smtp-listener.js +10 -6
- package/dist/esm/storage-schema.d.ts +139 -0
- package/dist/esm/storage-schema.js +211 -0
- package/dist/esm/store-operations.d.ts +168 -0
- package/dist/esm/store-operations.js +407 -0
- package/dist/esm/types.d.ts +22 -1
- package/dist/plugin-help.json +0 -14
- package/package.json +11 -3
- package/dist/cjs/plugins/xtoybird.d.ts +0 -2
- package/dist/cjs/plugins/xtoybird.js +0 -236
- package/dist/esm/plugins/xtoybird.d.ts +0 -2
- package/dist/esm/plugins/xtoybird.js +0 -218
package/dist/esm/script.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
import { seededRandom } from './random.js';
|
|
2
|
+
import { MAX_NUMBER } from './numbers.js';
|
|
3
|
+
const EVENTS = ['greeting', 'command', 'input', 'response', 'continuation', 'quiet'];
|
|
2
4
|
const OUTPUT_EVENTS = ['greeting', 'response', 'continuation'];
|
|
3
5
|
// the events where a key is valid, every other key is a typo and refused
|
|
4
6
|
const KEYS = {
|
|
5
7
|
on: EVENTS,
|
|
6
|
-
|
|
7
|
-
|
|
8
|
+
// a quiet event belongs to the command that waits for input (IDLE), if there is one
|
|
9
|
+
command: ['command', 'input', 'response', 'continuation', 'quiet'],
|
|
10
|
+
tag: ['command', 'input', 'response', 'continuation', 'quiet'],
|
|
8
11
|
description: ['response', 'continuation'],
|
|
9
12
|
session: EVENTS,
|
|
10
13
|
user: EVENTS,
|
|
@@ -15,6 +18,8 @@ const KEYS = {
|
|
|
15
18
|
when: EVENTS,
|
|
16
19
|
nth: EVENTS,
|
|
17
20
|
times: EVENTS,
|
|
21
|
+
chance: EVENTS,
|
|
22
|
+
quietFor: ['quiet'],
|
|
18
23
|
mutate: ['response', 'continuation'],
|
|
19
24
|
literals: ['response'],
|
|
20
25
|
defer: ['response'],
|
|
@@ -22,7 +27,7 @@ const KEYS = {
|
|
|
22
27
|
before: OUTPUT_EVENTS,
|
|
23
28
|
after: OUTPUT_EVENTS,
|
|
24
29
|
run: ['command', 'input'],
|
|
25
|
-
drop:
|
|
30
|
+
drop: ['greeting', 'command', 'input', 'response', 'continuation'],
|
|
26
31
|
delay: ['greeting', 'command', 'response', 'continuation'],
|
|
27
32
|
chunk: EVENTS,
|
|
28
33
|
chunkDelay: EVENTS,
|
|
@@ -70,6 +75,12 @@ function validateRule(rule) {
|
|
|
70
75
|
throw new TypeError('Script rule option "' + key + '" can not be used with "on": "' + rule.on + '"');
|
|
71
76
|
}
|
|
72
77
|
}
|
|
78
|
+
if (rule.on === 'quiet' && !(Number.isInteger(rule.quietFor) && rule.quietFor > 0)) {
|
|
79
|
+
throw new TypeError('A quiet rule needs "quietFor", a positive number of milliseconds');
|
|
80
|
+
}
|
|
81
|
+
if (rule.chance !== undefined && !(typeof rule.chance === 'number' && rule.chance >= 0 && rule.chance <= 1)) {
|
|
82
|
+
throw new TypeError('Script rule option "chance" must be a number from 0 to 1');
|
|
83
|
+
}
|
|
73
84
|
if (!ACTIONS.some(key => rule[key] !== undefined && rule[key] !== false)) {
|
|
74
85
|
throw new TypeError('A script rule needs an action (' + ACTIONS.join(', ') + ')');
|
|
75
86
|
}
|
|
@@ -92,6 +103,9 @@ function validateRule(rule) {
|
|
|
92
103
|
}
|
|
93
104
|
}
|
|
94
105
|
for (const key of ['delay', 'chunkDelay', 'truncate']) {
|
|
106
|
+
if (key === 'chunkDelay' && rule[key] === 'tick') {
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
95
109
|
if (rule[key] !== undefined && !(Number.isInteger(rule[key]) && rule[key] >= 0)) {
|
|
96
110
|
throw new TypeError('Script rule option "' + key + '" must be a non-negative integer');
|
|
97
111
|
}
|
|
@@ -150,6 +164,14 @@ export class ServerScript {
|
|
|
150
164
|
constructor(server, rules) {
|
|
151
165
|
this.server = server;
|
|
152
166
|
this.entries = [];
|
|
167
|
+
this.ruleCounter = 0;
|
|
168
|
+
const seed = server.options.scriptSeed;
|
|
169
|
+
const seedRandom = () => {
|
|
170
|
+
this.random = seededRandom(typeof seed === 'number' ? seed : Math.floor(Math.random() * MAX_NUMBER));
|
|
171
|
+
};
|
|
172
|
+
seedRandom();
|
|
173
|
+
// control.reset() starts the same random sequence again
|
|
174
|
+
server.on('reset', seedRandom);
|
|
153
175
|
this.watched = new Set();
|
|
154
176
|
if (rules) {
|
|
155
177
|
this.add(rules);
|
|
@@ -199,6 +221,26 @@ export class ServerScript {
|
|
|
199
221
|
setEntries(entries) {
|
|
200
222
|
this.entries = entries;
|
|
201
223
|
this.watched = new Set(entries.map(entry => entry.rule.on));
|
|
224
|
+
if (this.watched.has('quiet')) {
|
|
225
|
+
// sessions that are quiet already start counting now
|
|
226
|
+
this.server.connections?.forEach(connection => connection.watchQuiet());
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* The next quiet time a rule waits for, after the quiet time the rules were checked for already
|
|
231
|
+
*
|
|
232
|
+
* @param {Number} checked Milliseconds of quiet the rules were checked for
|
|
233
|
+
* @return {Number|null} the smallest `quietFor` above it, null if there is none
|
|
234
|
+
*/
|
|
235
|
+
nextQuiet(checked) {
|
|
236
|
+
let next = null;
|
|
237
|
+
for (const entry of this.entries) {
|
|
238
|
+
const quietFor = entry.rule.quietFor;
|
|
239
|
+
if (entry.rule.on === 'quiet' && quietFor !== undefined && quietFor > checked && (next === null || quietFor < next)) {
|
|
240
|
+
next = quietFor;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
return next;
|
|
202
244
|
}
|
|
203
245
|
addEntry(rule, match) {
|
|
204
246
|
// a copy, so that changing the caller's object later does not change the rule
|
|
@@ -212,6 +254,7 @@ export class ServerScript {
|
|
|
212
254
|
}
|
|
213
255
|
}
|
|
214
256
|
const entry = {
|
|
257
|
+
id: ++this.ruleCounter,
|
|
215
258
|
rule: copy,
|
|
216
259
|
match,
|
|
217
260
|
sets,
|
|
@@ -238,6 +281,9 @@ export class ServerScript {
|
|
|
238
281
|
if (entry.matched < (rule.nth || 1) || (rule.times !== undefined && entry.hits >= rule.times)) {
|
|
239
282
|
continue;
|
|
240
283
|
}
|
|
284
|
+
if (rule.chance !== undefined && this.random() >= rule.chance) {
|
|
285
|
+
continue;
|
|
286
|
+
}
|
|
241
287
|
entry.hits++;
|
|
242
288
|
this.server.emit('script', { rule, event: context.event, session: context.session, tag: context.tag, command: context.command });
|
|
243
289
|
return rule;
|
|
@@ -259,6 +305,9 @@ export class ServerScript {
|
|
|
259
305
|
if (rule.untagged !== undefined && rule.untagged !== (!context.response || context.response.tag === '*')) {
|
|
260
306
|
return false;
|
|
261
307
|
}
|
|
308
|
+
if (rule.quietFor !== undefined && (context.quiet || 0) < rule.quietFor) {
|
|
309
|
+
return false;
|
|
310
|
+
}
|
|
262
311
|
if (entry.match && !entry.match.test(context.data)) {
|
|
263
312
|
return false;
|
|
264
313
|
}
|
|
@@ -452,6 +501,16 @@ function sendBytes(connection, rule, data, delay) {
|
|
|
452
501
|
close: rule.close || (rule.truncate === undefined ? undefined : true)
|
|
453
502
|
});
|
|
454
503
|
}
|
|
504
|
+
/**
|
|
505
|
+
* Handles a quiet event with the rule that matched it: sends the bytes of `send` and closes the connection with `close`
|
|
506
|
+
*
|
|
507
|
+
* @param {Object} connection IMAP connection
|
|
508
|
+
* @param {Object} rule Rule that matched
|
|
509
|
+
* @param {Object} context Event context
|
|
510
|
+
*/
|
|
511
|
+
export function handleQuiet(connection, rule, context) {
|
|
512
|
+
sendBytes(connection, rule, resolveBytes(rule.send, context) || Buffer.alloc(0));
|
|
513
|
+
}
|
|
455
514
|
/**
|
|
456
515
|
* Handles a command or input line with the rule that matched it: sends the bytes of `send`, closes the connection,
|
|
457
516
|
* and processes the line as usual with `run` (or when the rule only delays it)
|
package/dist/esm/server.d.ts
CHANGED
|
@@ -1,12 +1,28 @@
|
|
|
1
1
|
import { Stream } from 'node:stream';
|
|
2
2
|
import net from 'node:net';
|
|
3
|
+
import http from 'node:http';
|
|
3
4
|
import tls from 'node:tls';
|
|
4
5
|
import type { CompilerOptions, ParserOptions } from 'imap-handler';
|
|
5
6
|
import type { ResolvedCommandOptions } from './command-states.js';
|
|
7
|
+
import { Control } from './control.js';
|
|
8
|
+
import type { SessionInfo } from './control.js';
|
|
6
9
|
import { ServerScript } from './script.js';
|
|
7
10
|
import type { DeferredOutput, OutputOperation, ScriptContext, ScriptEvent, ScriptRule } from './script.js';
|
|
8
11
|
import type { AppendCheck, AppendCheckOptions, AppendDataHandler, AppendMessage, CapabilityCheck, CheckResult, ClosedCheck, CommandCheck, CommandContext, CommandOptions, CommandHandler, ConnectionHandler, ConnectionState, CopyHandler, FetchHandler, IMAPResponse, IMAPServerOptions, ListedMailbox, LiteralFilter, Mailbox, MailboxHandler, MailboxStatus, Message, MessageFilter, MessageHandler, MessageRange, Namespace, Notification, NotifyEvent, NotifyFilter, OutputHandler, ParsedCommand, RangeLimit, Refusal, SearchAccessCheck, SearchHandler, SearchLimit, ServerStorage, StatusHandler, StorageMailbox, StorageMessage, StoreHandler, SubscriptionStandIn, Transport, UrlAccessCheck, UserData } from './types.js';
|
|
9
12
|
declare const TAG_REGEX: RegExp;
|
|
13
|
+
/** The parts of a smtp-server SMTPServer that the server uses, smtp-server is an optional dependency */
|
|
14
|
+
interface SMTPListener {
|
|
15
|
+
close(callback: () => void): void;
|
|
16
|
+
once(event: 'error', listener: (err: Error) => void): unknown;
|
|
17
|
+
removeListener(event: 'error', listener: (err: Error) => void): unknown;
|
|
18
|
+
server: net.Server;
|
|
19
|
+
}
|
|
20
|
+
/** The command whose tagged response is pending, and the session state before it ran */
|
|
21
|
+
interface CommandStart {
|
|
22
|
+
tag: string;
|
|
23
|
+
command: string;
|
|
24
|
+
state: ConnectionState;
|
|
25
|
+
}
|
|
10
26
|
/**
|
|
11
27
|
* Creates a new IMAP server, call `listen()` on it to start accepting connections
|
|
12
28
|
*
|
|
@@ -64,7 +80,58 @@ declare class IMAPServer extends Stream {
|
|
|
64
80
|
script: ServerScript;
|
|
65
81
|
/** connections accepted so far, the number of a connection is `connection.sessionNumber` */
|
|
66
82
|
sessionCounter: number;
|
|
83
|
+
/** the control API, see src/control.ts */
|
|
84
|
+
control: Control;
|
|
85
|
+
/** the SMTP server that `start()` runs for the `smtp` option */
|
|
86
|
+
smtpServer: SMTPListener | null;
|
|
87
|
+
/** the HTTP server of the REST API that `start()` runs for the `rest` option */
|
|
88
|
+
restServer: http.Server | null;
|
|
67
89
|
constructor(options?: IMAPServerOptions);
|
|
90
|
+
/**
|
|
91
|
+
* Sets the users from the `users` option, or the default user. The users are deep copied, so that runtime changes
|
|
92
|
+
* never leak into the caller's objects or into other servers built from the same fixture. Without a prototype,
|
|
93
|
+
* user names like "__proto__" or "toString" are plain keys
|
|
94
|
+
*/
|
|
95
|
+
loadUsers(): void;
|
|
96
|
+
/**
|
|
97
|
+
* Builds the mailboxes from the `storage` option, a deep copy of it. Message and mailbox handlers of plugins run
|
|
98
|
+
* on every message and mailbox
|
|
99
|
+
*/
|
|
100
|
+
loadStorage(): void;
|
|
101
|
+
/**
|
|
102
|
+
* Starts accepting connections
|
|
103
|
+
*
|
|
104
|
+
* @param {Number} [port] Port to listen on, a free port if not set
|
|
105
|
+
* @param {String} [host] Address to listen on, all addresses if not set
|
|
106
|
+
* @return {Promise<Number>} resolves with the port the server listens on
|
|
107
|
+
*/
|
|
108
|
+
start(port?: number, host?: string): Promise<number>;
|
|
109
|
+
/**
|
|
110
|
+
* Starts the REST API of the `rest` option, see src/rest.ts
|
|
111
|
+
*
|
|
112
|
+
* @return {Promise<Number>} resolves with the HTTP port
|
|
113
|
+
*/
|
|
114
|
+
startRest(): Promise<number>;
|
|
115
|
+
/**
|
|
116
|
+
* Starts the SMTP server of the `smtp` option. smtp-server is an optional dependency, loaded only here
|
|
117
|
+
*
|
|
118
|
+
* @return {Promise<Number>} resolves with the SMTP port
|
|
119
|
+
*/
|
|
120
|
+
startSmtp(): Promise<number>;
|
|
121
|
+
/**
|
|
122
|
+
* Loads the SMTP listener, which needs the smtp-server package
|
|
123
|
+
*
|
|
124
|
+
* @return {Promise<Object>} the smtp-listener module
|
|
125
|
+
*/
|
|
126
|
+
loadSmtpListener(): Promise<{
|
|
127
|
+
startSMTPServer(port: number, server: IMAPServer, callback: (port: number) => void, host?: string): SMTPListener;
|
|
128
|
+
}>;
|
|
129
|
+
/**
|
|
130
|
+
* Stops the server and closes every connection
|
|
131
|
+
*
|
|
132
|
+
* @return {Promise} resolves when the server is closed
|
|
133
|
+
*/
|
|
134
|
+
stop(): Promise<void>;
|
|
68
135
|
/**
|
|
69
136
|
* Starts accepting connections, takes the arguments of `net.Server#listen()`
|
|
70
137
|
*/
|
|
@@ -72,6 +139,13 @@ declare class IMAPServer extends Stream {
|
|
|
72
139
|
listen(port: number, hostname: string, listeningListener?: () => void): void;
|
|
73
140
|
listen(options: net.ListenOptions, listeningListener?: () => void): void;
|
|
74
141
|
close(callback?: (err?: Error) => void): void;
|
|
142
|
+
/**
|
|
143
|
+
* Stops the SMTP and REST listeners of `start()`
|
|
144
|
+
*
|
|
145
|
+
* @param {Boolean} force true closes the open REST connections too, otherwise only the idle ones (a request that
|
|
146
|
+
* is answered, like POST /v1/shutdown, finishes first)
|
|
147
|
+
*/
|
|
148
|
+
closeListeners(force: boolean): void;
|
|
75
149
|
/**
|
|
76
150
|
* Returns TLS key and certificate. Without credentials in the options the
|
|
77
151
|
* bundled self-signed certificate for localhost is used.
|
|
@@ -144,13 +218,23 @@ declare class IMAPServer extends Stream {
|
|
|
144
218
|
*
|
|
145
219
|
* @param {String} type Kind of change
|
|
146
220
|
* @param {String} path Storage name of the mailbox
|
|
147
|
-
* @param {Object} [details] `{ oldPath, mailbox }`: the earlier name of a renamed mailbox, the mailbox
|
|
148
|
-
* object that a DELETE removed
|
|
221
|
+
* @param {Object} [details] `{ oldPath, mailbox, created }`: the earlier name of a renamed mailbox, the mailbox
|
|
222
|
+
* object that a DELETE removed, the mailboxes a CREATE made (superior levels first)
|
|
149
223
|
*/
|
|
150
224
|
mailboxChanged(type: string, path: string, details?: {
|
|
151
225
|
oldPath?: string | undefined;
|
|
152
226
|
mailbox?: Mailbox | undefined;
|
|
227
|
+
created?: string[] | undefined;
|
|
153
228
|
}): void;
|
|
229
|
+
/**
|
|
230
|
+
* Runs a change with `origin` as the session that caused it, the `origin` of the notifications and events it
|
|
231
|
+
* makes. Commands run with their session, the control API with null
|
|
232
|
+
*
|
|
233
|
+
* @param {Object|null} origin Session, or null for a change from outside
|
|
234
|
+
* @param {Function} fn Change
|
|
235
|
+
* @return {*} the result of fn
|
|
236
|
+
*/
|
|
237
|
+
withOrigin<T>(origin: IMAPConnection | null, fn: () => T): T;
|
|
154
238
|
/**
|
|
155
239
|
* Retrieves the handler of an IMAP command
|
|
156
240
|
*
|
|
@@ -286,6 +370,13 @@ declare class IMAPServer extends Stream {
|
|
|
286
370
|
* @param {Array} flags Flags of a message
|
|
287
371
|
*/
|
|
288
372
|
rememberFlags(mailbox: Mailbox, flags: string[]): void;
|
|
373
|
+
/**
|
|
374
|
+
* The current time for dates the server sets itself (INTERNALDATE of a message without one, SAVEDATE). The `now`
|
|
375
|
+
* option fixes it for repeatable tests: a Date, a timestamp, or a function that returns one
|
|
376
|
+
*
|
|
377
|
+
* @return {Date} current time
|
|
378
|
+
*/
|
|
379
|
+
now(): Date;
|
|
289
380
|
/**
|
|
290
381
|
* Converts a date-time value from storage or a client to the form it is sent in
|
|
291
382
|
*
|
|
@@ -482,6 +573,8 @@ declare class IMAPConnection {
|
|
|
482
573
|
/** notifications are sent right away instead of before the next tagged response (IDLE) */
|
|
483
574
|
directNotifications: boolean;
|
|
484
575
|
notificationQueue: Notification[];
|
|
576
|
+
/** the plain socket that STARTTLS wrapped in TLS */
|
|
577
|
+
tcpSocket: net.Socket | null | undefined;
|
|
485
578
|
/** the number of the connection, 1 for the first one the server accepted (script rules match it) */
|
|
486
579
|
sessionNumber: number;
|
|
487
580
|
/** the tag and name of the command whose input handler reads the lines that follow (IDLE, AUTHENTICATE) */
|
|
@@ -508,11 +601,18 @@ declare class IMAPConnection {
|
|
|
508
601
|
} | undefined;
|
|
509
602
|
/** output that waits behind a delay of a script rule, null when output is written right away */
|
|
510
603
|
_outputQueue: OutputOperation[] | null;
|
|
511
|
-
_outputTimer: ReturnType<typeof setTimeout> | null;
|
|
604
|
+
_outputTimer: ReturnType<typeof setTimeout> | ReturnType<typeof setImmediate> | null;
|
|
605
|
+
/** a piece of a chunked write with chunkDelay 0 or "tick" waits until it was handed to the system */
|
|
606
|
+
_outputWaiting: boolean | undefined;
|
|
512
607
|
/** untagged responses that `defer` rules hold back, see releaseDeferred in src/script.ts */
|
|
513
608
|
_deferredOutput: DeferredOutput[] | null;
|
|
514
609
|
/** a script rule closes the connection with a RST, see closeNow */
|
|
515
610
|
_resetting: boolean | undefined;
|
|
611
|
+
/** time of the last input or output, and the timer of the quiet events of script rules, see watchQuiet */
|
|
612
|
+
_lastActivity: number | undefined;
|
|
613
|
+
_quietTimer: ReturnType<typeof setTimeout> | null | undefined;
|
|
614
|
+
/** the command whose tagged response is pending and the session before it ran, see commandCompleted */
|
|
615
|
+
_commandStart: CommandStart | null | undefined;
|
|
516
616
|
constructor(server: IMAPServer, socket: net.Socket);
|
|
517
617
|
/**
|
|
518
618
|
* Writes protocol output to the client, through the transport layer if there is one
|
|
@@ -540,8 +640,9 @@ declare class IMAPConnection {
|
|
|
540
640
|
*
|
|
541
641
|
* @param {Buffer} data Output
|
|
542
642
|
* @param {Object|null} transport Transport layer
|
|
643
|
+
* @param {Function} [callback] Called once the data was handed to the system (a transport: on the next turn)
|
|
543
644
|
*/
|
|
544
|
-
writeLayer(data: Buffer, transport: Transport | null): void;
|
|
645
|
+
writeLayer(data: Buffer, transport: Transport | null, callback?: () => void): void;
|
|
545
646
|
/**
|
|
546
647
|
* Sends output through the script rule that handles its event, if there is one
|
|
547
648
|
*
|
|
@@ -564,7 +665,19 @@ declare class IMAPConnection {
|
|
|
564
665
|
*
|
|
565
666
|
* @param {Buffer} data Data to send
|
|
566
667
|
*/
|
|
567
|
-
writeRaw(data: Buffer | string): void;
|
|
668
|
+
writeRaw(data: Buffer | string, callback?: () => void): void;
|
|
669
|
+
/**
|
|
670
|
+
* Notes input or output for the quiet events of script rules (#88)
|
|
671
|
+
*/
|
|
672
|
+
touch(): void;
|
|
673
|
+
/**
|
|
674
|
+
* Starts waiting for the next quiet event, if a rule waits for one and the session is not waiting already. When
|
|
675
|
+
* the time is up, the first rule that matches handles the event (`send`, `close`), the output it sends starts
|
|
676
|
+
* the next quiet time
|
|
677
|
+
*
|
|
678
|
+
* @param {Number} [checked] Quiet time the rules were checked for already, only longer ones are waited for
|
|
679
|
+
*/
|
|
680
|
+
watchQuiet(checked?: number): void;
|
|
568
681
|
/**
|
|
569
682
|
* Handles data from the socket, through the transport layer if there is one
|
|
570
683
|
*
|
|
@@ -947,6 +1060,34 @@ declare class IMAPConnection {
|
|
|
947
1060
|
* @param {Boolean} [scripted] The line comes from a script rule with `run`, it is next in the queue
|
|
948
1061
|
*/
|
|
949
1062
|
scheduleCommand(data: string, scripted?: boolean): void;
|
|
1063
|
+
/**
|
|
1064
|
+
* Emits the `command` event when the tagged response of a command goes out, and the `session` events "login"
|
|
1065
|
+
* (the command authenticated the session) and "logout" (back to Not Authenticated, UNAUTHENTICATE). Every command
|
|
1066
|
+
* that changes these does so before its tagged response. "select" and "unselect" come from SELECT and
|
|
1067
|
+
* closeMailbox(). Tests wait for these instead of polling
|
|
1068
|
+
*
|
|
1069
|
+
* @param {String} status OK, NO or BAD
|
|
1070
|
+
*/
|
|
1071
|
+
commandCompleted(status: string): void;
|
|
1072
|
+
/**
|
|
1073
|
+
* Emits a `session` event, `{ type, session, ...fields }`
|
|
1074
|
+
*
|
|
1075
|
+
* @param {String} type Event type
|
|
1076
|
+
* @param {Object} [fields] More fields of the event
|
|
1077
|
+
*/
|
|
1078
|
+
emitSession(type: string, fields?: Record<string, unknown>): void;
|
|
1079
|
+
/**
|
|
1080
|
+
* Describes the session without credentials or sockets, for the control API and the `session` events
|
|
1081
|
+
*
|
|
1082
|
+
* @return {Object} `{ session, user, state, mailbox, readOnly, enabled, secure, compressed, remoteAddress }`
|
|
1083
|
+
*/
|
|
1084
|
+
describe(): SessionInfo;
|
|
1085
|
+
/**
|
|
1086
|
+
* Checks if output can still be sent: the socket is open and the connection is not closing (BYE, LOGOUT)
|
|
1087
|
+
*
|
|
1088
|
+
* @return {Boolean} true for a live session
|
|
1089
|
+
*/
|
|
1090
|
+
isOpen(): boolean;
|
|
950
1091
|
/**
|
|
951
1092
|
* Handles a command line with the script rule that matched it, after the rule's delay. With `run` the line
|
|
952
1093
|
* goes through the parser and the command handler as usual afterwards
|
|
@@ -961,19 +1102,19 @@ declare class IMAPConnection {
|
|
|
961
1102
|
*
|
|
962
1103
|
* @param {Object} mailbox Mailbox to check for
|
|
963
1104
|
* @param {Boolean} [ignoreSelf] If set to true, does not send any notices to itself
|
|
964
|
-
* @param {Boolean} [
|
|
1105
|
+
* @param {Boolean} [ignoreExists] If set to true, does not send EXISTS notice to itself
|
|
965
1106
|
*/
|
|
966
1107
|
expungeDeleted(mailbox: Mailbox, ignoreSelf?: boolean, ignoreExists?: boolean): void;
|
|
967
1108
|
/**
|
|
968
1109
|
* Given a set of messages in a mailbox (possibly via getMessageRange), remove
|
|
969
|
-
* them from the mailbox and generate EXPUNGE notifications.
|
|
1110
|
+
* them from the mailbox and generate EXPUNGE notifications, see expungeMessages() in store-operations.ts
|
|
970
1111
|
*
|
|
971
1112
|
* @param {Object} mailbox Mailbox to check for
|
|
972
1113
|
* @param {Function|Array} messagesOrFilterFunc An Array of messages in the
|
|
973
1114
|
* folder that should be removed or a filtering function that indicates
|
|
974
1115
|
* messages to be removed by returning true.
|
|
975
1116
|
* @param {Boolean} [ignoreSelf] If set to true, does not send any notices to itself
|
|
976
|
-
* @param {Boolean} [
|
|
1117
|
+
* @param {Boolean} [ignoreExists] If set to true, does not send EXISTS notice to itself
|
|
977
1118
|
* @param {Boolean} [highestFirst] If set to true, the EXPUNGE responses go from the highest UID to the lowest
|
|
978
1119
|
* (MESSAGELIMIT, RFC 9738 section 3.1), otherwise from the lowest
|
|
979
1120
|
*/
|