imapkit 4.3.1 → 5.0.1
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 +187 -67
- package/bin/help.txt +20 -5
- package/bin/imapkit.js +64 -24
- 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/fetch.js +2 -1
- 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 +7 -7
- package/dist/cjs/commands/list.js +17 -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 +425 -0
- package/dist/cjs/control.js +637 -0
- package/dist/cjs/dates.d.ts +9 -1
- package/dist/cjs/dates.js +20 -0
- package/dist/cjs/envelope.d.ts +1 -1
- package/dist/cjs/envelope.js +26 -1
- package/dist/cjs/index.d.ts +9 -1
- package/dist/cjs/index.js +9 -2
- package/dist/cjs/load-plugins.d.ts +3 -1
- package/dist/cjs/load-plugins.js +28 -4
- package/dist/cjs/plugins/acl.js +109 -42
- package/dist/cjs/plugins/binary.js +2 -1
- package/dist/cjs/plugins/condstore.js +7 -0
- package/dist/cjs/plugins/context-search.js +2 -2
- package/dist/cjs/plugins/create-special-use.d.ts +0 -5
- package/dist/cjs/plugins/create-special-use.js +11 -1
- package/dist/cjs/plugins/imap4rev2.js +5 -0
- package/dist/cjs/plugins/index.js +1 -3
- package/dist/cjs/plugins/metadata-server.d.ts +6 -2
- package/dist/cjs/plugins/metadata-server.js +3 -1
- package/dist/cjs/plugins/metadata.d.ts +5 -1
- package/dist/cjs/plugins/metadata.js +143 -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 +125 -0
- package/dist/cjs/random.d.ts +10 -0
- package/dist/cjs/random.js +22 -0
- package/dist/cjs/rest.d.ts +54 -0
- package/dist/cjs/rest.js +567 -0
- package/dist/cjs/script.d.ts +33 -4
- package/dist/cjs/script.js +64 -4
- package/dist/cjs/server.d.ts +199 -9
- package/dist/cjs/server.js +603 -227
- 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 +222 -0
- package/dist/cjs/store-operations.d.ts +171 -0
- package/dist/cjs/store-operations.js +425 -0
- package/dist/cjs/types.d.ts +26 -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/fetch.js +2 -1
- 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 +7 -7
- package/dist/esm/commands/list.js +17 -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 +425 -0
- package/dist/esm/control.js +630 -0
- package/dist/esm/dates.d.ts +9 -1
- package/dist/esm/dates.js +20 -1
- package/dist/esm/envelope.d.ts +1 -1
- package/dist/esm/envelope.js +26 -1
- package/dist/esm/index.d.ts +9 -1
- package/dist/esm/index.js +5 -2
- package/dist/esm/load-plugins.d.ts +3 -1
- package/dist/esm/load-plugins.js +28 -4
- package/dist/esm/plugins/acl.js +109 -42
- package/dist/esm/plugins/binary.js +2 -1
- package/dist/esm/plugins/condstore.js +7 -0
- package/dist/esm/plugins/context-search.js +2 -2
- package/dist/esm/plugins/create-special-use.d.ts +0 -5
- package/dist/esm/plugins/create-special-use.js +8 -1
- package/dist/esm/plugins/imap4rev2.js +5 -0
- package/dist/esm/plugins/index.js +1 -3
- package/dist/esm/plugins/metadata-server.d.ts +6 -2
- package/dist/esm/plugins/metadata-server.js +3 -1
- package/dist/esm/plugins/metadata.d.ts +5 -1
- package/dist/esm/plugins/metadata.js +143 -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 +121 -0
- package/dist/esm/random.d.ts +10 -0
- package/dist/esm/random.js +19 -0
- package/dist/esm/rest.d.ts +54 -0
- package/dist/esm/rest.js +559 -0
- package/dist/esm/script.d.ts +33 -4
- package/dist/esm/script.js +63 -4
- package/dist/esm/server.d.ts +199 -9
- package/dist/esm/server.js +606 -230
- 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 +218 -0
- package/dist/esm/store-operations.d.ts +171 -0
- package/dist/esm/store-operations.js +410 -0
- package/dist/esm/types.d.ts +26 -1
- package/dist/plugin-help.json +3 -16
- 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/bin/imapkit.js
CHANGED
|
@@ -21,25 +21,39 @@ const { values: argv } = parseArgs({
|
|
|
21
21
|
storage: { type: 'string' },
|
|
22
22
|
script: { type: 'string' },
|
|
23
23
|
plugin: { type: 'string', multiple: true },
|
|
24
|
-
smtpPort: { type: 'string' }
|
|
24
|
+
smtpPort: { type: 'string' },
|
|
25
|
+
'smtp-port': { type: 'string' },
|
|
26
|
+
'rest-port': { type: 'string' },
|
|
27
|
+
'rest-host': { type: 'string' },
|
|
28
|
+
'rest-token': { type: 'string' },
|
|
29
|
+
quirk: { type: 'string', multiple: true },
|
|
30
|
+
'script-seed': { type: 'string' }
|
|
25
31
|
}
|
|
26
32
|
});
|
|
27
33
|
|
|
28
34
|
const isTrue = value => (value || '').toString().trim().toLowerCase() === 'true';
|
|
29
35
|
|
|
36
|
+
// a repeated option or a comma separated list, e.g. --plugin=IDLE,MOVE --plugin=ID
|
|
37
|
+
const listOption = value =>
|
|
38
|
+
[]
|
|
39
|
+
.concat(value || [])
|
|
40
|
+
.flatMap(item =>
|
|
41
|
+
String(item)
|
|
42
|
+
.trim()
|
|
43
|
+
.split(/\s*,\s*/)
|
|
44
|
+
)
|
|
45
|
+
.filter(Boolean);
|
|
46
|
+
|
|
30
47
|
const configLocation = argv.config || process.env.IMAPKIT_CONFIG;
|
|
31
48
|
const storageLocation = argv.storage || process.env.IMAPKIT_STORAGE;
|
|
32
49
|
const scriptLocation = argv.script || process.env.IMAPKIT_SCRIPT;
|
|
33
|
-
const smtpPort = argv.smtpPort || process.env.IMAPKIT_SMTPPORT;
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
.split(/\s*,\s*/)
|
|
41
|
-
)
|
|
42
|
-
.filter(Boolean);
|
|
50
|
+
const smtpPort = argv.smtpPort || argv['smtp-port'] || process.env.IMAPKIT_SMTPPORT;
|
|
51
|
+
const restPort = argv['rest-port'] || process.env.IMAPKIT_REST_PORT;
|
|
52
|
+
const restHost = argv['rest-host'] || process.env.IMAPKIT_REST_HOST;
|
|
53
|
+
const restToken = argv['rest-token'] || process.env.IMAPKIT_REST_TOKEN;
|
|
54
|
+
const quirksList = listOption(argv.quirk || process.env.IMAPKIT_QUIRKS);
|
|
55
|
+
const scriptSeed = argv['script-seed'] || process.env.IMAPKIT_SCRIPT_SEED;
|
|
56
|
+
const pluginsList = listOption(argv.plugin || process.env.IMAPKIT_PLUGINS).map(plugin => plugin.toUpperCase());
|
|
43
57
|
const secure = isTrue(argv.secure || process.env.IMAPKIT_SECURE);
|
|
44
58
|
const debug = isTrue(argv.debug || process.env.IMAPKIT_DEBUG);
|
|
45
59
|
|
|
@@ -69,7 +83,9 @@ if (debug) {
|
|
|
69
83
|
config.debug = true;
|
|
70
84
|
}
|
|
71
85
|
|
|
72
|
-
|
|
86
|
+
// secureConnection can also come from the --config file
|
|
87
|
+
const isSecure = secure || config.secureConnection === true;
|
|
88
|
+
const port = argv.port || process.env.IMAPKIT_PORT || config.port || (isSecure ? 993 : 143);
|
|
73
89
|
|
|
74
90
|
if (argv.help) {
|
|
75
91
|
const help = fs.readFileSync(path.join(__dirname, 'help.txt'), 'utf-8');
|
|
@@ -93,18 +109,42 @@ if (argv.help) {
|
|
|
93
109
|
.trim()
|
|
94
110
|
);
|
|
95
111
|
} else {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
|
|
112
|
+
if (quirksList.length) {
|
|
113
|
+
config.quirks = quirksList;
|
|
114
|
+
}
|
|
115
|
+
if (scriptSeed !== undefined) {
|
|
116
|
+
config.scriptSeed = Number(scriptSeed);
|
|
117
|
+
}
|
|
118
|
+
if (restPort) {
|
|
119
|
+
config.rest = { port: Number(restPort), host: restHost, token: restToken };
|
|
120
|
+
}
|
|
106
121
|
if (smtpPort) {
|
|
107
|
-
//
|
|
108
|
-
|
|
122
|
+
// smtp-server is an optional dependency, start() loads it only when SMTP is enabled
|
|
123
|
+
config.smtp = { port: Number(smtpPort) };
|
|
124
|
+
}
|
|
125
|
+
let server;
|
|
126
|
+
try {
|
|
127
|
+
server = imapkit(config);
|
|
128
|
+
} catch (err) {
|
|
129
|
+
// an unknown plugin or quirk name, invalid storage ...
|
|
130
|
+
console.error('Failed to start ImapKit: %s', err.message);
|
|
131
|
+
process.exit(1);
|
|
109
132
|
}
|
|
133
|
+
console.log('Starting ImapKit ...');
|
|
134
|
+
server.start(Number(port)).then(
|
|
135
|
+
listening => {
|
|
136
|
+
// the actual port, also for -p 0
|
|
137
|
+
console.log('ImapKit successfully%s listening on port %s', isSecure ? ' and securely' : '', listening);
|
|
138
|
+
if (server.restServer) {
|
|
139
|
+
console.log('REST API listening on %s:%s', (config.rest && config.rest.host) || '127.0.0.1', server.restServer.address().port);
|
|
140
|
+
}
|
|
141
|
+
if (server.smtpServer) {
|
|
142
|
+
console.log('Incoming SMTP server up and running on port %s', server.smtpServer.server.address().port);
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
err => {
|
|
146
|
+
console.error('Failed to start ImapKit: %s', err.message);
|
|
147
|
+
process.exit(1);
|
|
148
|
+
}
|
|
149
|
+
);
|
|
110
150
|
}
|
|
@@ -45,7 +45,7 @@ function parseFlags(connection, list) {
|
|
|
45
45
|
throw new Error('Invalid flags argument');
|
|
46
46
|
}
|
|
47
47
|
const value = (0, flags_js_1.normalizeSystemFlag)(flag.value);
|
|
48
|
-
(0, flags_js_1.checkSystemFlags)(connection, value);
|
|
48
|
+
(0, flags_js_1.checkSystemFlags)(connection.server, value);
|
|
49
49
|
return value;
|
|
50
50
|
});
|
|
51
51
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.default = createCommand;
|
|
4
|
+
const store_operations_js_1 = require("../store-operations.js");
|
|
4
5
|
function createCommand(connection, parsed, data, callback) {
|
|
5
6
|
if (!parsed.attributes || parsed.attributes.length !== 1 || !parsed.attributes[0] || ['STRING', 'LITERAL', 'ATOM'].indexOf(parsed.attributes[0].type) < 0) {
|
|
6
7
|
connection.send({
|
|
@@ -18,7 +19,7 @@ function createCommand(connection, parsed, data, callback) {
|
|
|
18
19
|
const path = parsed.attributes[0].value;
|
|
19
20
|
let mailbox;
|
|
20
21
|
try {
|
|
21
|
-
mailbox = connection.server
|
|
22
|
+
mailbox = (0, store_operations_js_1.createMailbox)(connection.server, path);
|
|
22
23
|
}
|
|
23
24
|
catch (err) {
|
|
24
25
|
const E = err;
|
|
@@ -26,7 +27,6 @@ function createCommand(connection, parsed, data, callback) {
|
|
|
26
27
|
connection.sendStatus(parsed, data, 'NO', E.message, E.code, 'CREATE FAILED');
|
|
27
28
|
return callback();
|
|
28
29
|
}
|
|
29
|
-
connection.server.mailboxChanged('create', mailbox.path);
|
|
30
30
|
connection.send({
|
|
31
31
|
tag: parsed.tag,
|
|
32
32
|
command: 'OK',
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.default = deleteCommand;
|
|
4
|
+
const store_operations_js_1 = require("../store-operations.js");
|
|
4
5
|
function deleteCommand(connection, parsed, data, callback) {
|
|
5
6
|
if (!parsed.attributes || parsed.attributes.length !== 1 || !parsed.attributes[0] || ['STRING', 'LITERAL', 'ATOM'].indexOf(parsed.attributes[0].type) < 0) {
|
|
6
7
|
connection.send({
|
|
@@ -16,27 +17,14 @@ function deleteCommand(connection, parsed, data, callback) {
|
|
|
16
17
|
return callback();
|
|
17
18
|
}
|
|
18
19
|
const path = parsed.attributes[0].value;
|
|
19
|
-
const mailbox = connection.server.getMailbox(path);
|
|
20
|
-
if (!mailbox) {
|
|
21
|
-
connection.sendStatus(parsed, data, 'NO', 'Mailbox does not exist', 'NONEXISTENT', 'DELETE FAILED');
|
|
22
|
-
return callback();
|
|
23
|
-
}
|
|
24
20
|
try {
|
|
25
|
-
connection.server
|
|
21
|
+
(0, store_operations_js_1.deleteMailbox)(connection.server, path);
|
|
26
22
|
}
|
|
27
23
|
catch (err) {
|
|
28
24
|
const E = err;
|
|
29
25
|
connection.sendStatus(parsed, data, 'NO', E.message, E.code, 'DELETE FAILED');
|
|
30
26
|
return callback();
|
|
31
27
|
}
|
|
32
|
-
connection.server.mailboxChanged('delete', mailbox.path, { mailbox });
|
|
33
|
-
// RFC 2180 section 3.3: the other sessions that have the mailbox selected are disconnected with an untagged
|
|
34
|
-
// BYE (RFC 2683 section 3.1.2), as they can not be told about the deletion in any other way
|
|
35
|
-
connection.server.connections.forEach(other => {
|
|
36
|
-
if (other !== connection && other.selectedMailbox === mailbox) {
|
|
37
|
-
other.bye('Selected mailbox was deleted', 'MAILBOX DELETED');
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
28
|
connection.send({
|
|
41
29
|
tag: parsed.tag,
|
|
42
30
|
command: 'OK',
|
|
@@ -85,7 +85,8 @@ function getSection(data, query, global) {
|
|
|
85
85
|
else if (query.section.length > 1) {
|
|
86
86
|
throw new Error((key || 'Part number') + ' does not take any arguments');
|
|
87
87
|
}
|
|
88
|
-
//
|
|
88
|
+
// a part that does not exist is returned as an empty string, like Dovecot does: RFC 3501 and RFC 9051 section
|
|
89
|
+
// 6.4.5 define no error for it, only an empty string for a partial range that starts beyond the end of the text
|
|
89
90
|
const node = path ? (0, mimeparser_js_1.resolveNode)(data.tree, path, global) : data.tree;
|
|
90
91
|
if (!node) {
|
|
91
92
|
return '';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { IMAPServer } from '../../types.js';
|
|
2
2
|
declare const INVALID_KEYWORD_CHAR: RegExp;
|
|
3
3
|
/**
|
|
4
4
|
* System flags are case-insensitive, so "\seen" becomes "\Seen"
|
|
@@ -10,8 +10,8 @@ declare function normalizeSystemFlag(flag: string): string;
|
|
|
10
10
|
/**
|
|
11
11
|
* Throws if a flag can not be stored: an unknown system flag (including \Recent) or an invalid keyword
|
|
12
12
|
*
|
|
13
|
-
* @param {Object}
|
|
13
|
+
* @param {Object} server IMAP server, its systemFlags are the system flags that can be stored
|
|
14
14
|
* @param {String} flag Normalized flag value
|
|
15
15
|
*/
|
|
16
|
-
declare function checkSystemFlags(
|
|
16
|
+
declare function checkSystemFlags(server: IMAPServer, flag: string): void;
|
|
17
17
|
export { INVALID_KEYWORD_CHAR, normalizeSystemFlag, checkSystemFlags };
|
|
@@ -24,12 +24,12 @@ function normalizeSystemFlag(flag) {
|
|
|
24
24
|
/**
|
|
25
25
|
* Throws if a flag can not be stored: an unknown system flag (including \Recent) or an invalid keyword
|
|
26
26
|
*
|
|
27
|
-
* @param {Object}
|
|
27
|
+
* @param {Object} server IMAP server, its systemFlags are the system flags that can be stored
|
|
28
28
|
* @param {String} flag Normalized flag value
|
|
29
29
|
*/
|
|
30
|
-
function checkSystemFlags(
|
|
30
|
+
function checkSystemFlags(server, flag) {
|
|
31
31
|
if (flag.charAt(0) === '\\') {
|
|
32
|
-
if (
|
|
32
|
+
if (server.systemFlags.indexOf(flag) < 0) {
|
|
33
33
|
throw new Error('Invalid system flag ' + flag);
|
|
34
34
|
}
|
|
35
35
|
}
|
|
@@ -9,9 +9,9 @@ function setFlags(connection, message, flags) {
|
|
|
9
9
|
const messageFlags = [];
|
|
10
10
|
[].concat(flags).forEach(flag => {
|
|
11
11
|
flag = (0, flags_js_1.normalizeSystemFlag)(typeof flag === 'string' ? flag : String(flag.value || ''));
|
|
12
|
-
(0, flags_js_1.checkSystemFlags)(connection, flag);
|
|
13
|
-
//
|
|
14
|
-
if (
|
|
12
|
+
(0, flags_js_1.checkSystemFlags)(connection.server, flag);
|
|
13
|
+
// a flag that is not in PERMANENTFLAGS is ignored (RFC 3501 section 7.1, RFC 9051 section 7.1)
|
|
14
|
+
if (!connection.server.isPermanentFlag(mailbox, flag)) {
|
|
15
15
|
return;
|
|
16
16
|
}
|
|
17
17
|
if (messageFlags.indexOf(flag) < 0) {
|
|
@@ -25,9 +25,9 @@ function addFlags(connection, message, flags) {
|
|
|
25
25
|
const mailbox = connection.selectedMailbox;
|
|
26
26
|
[].concat(flags).forEach(flag => {
|
|
27
27
|
flag = (0, flags_js_1.normalizeSystemFlag)(typeof flag === 'string' ? flag : String(flag.value || ''));
|
|
28
|
-
(0, flags_js_1.checkSystemFlags)(connection, flag);
|
|
29
|
-
//
|
|
30
|
-
if (
|
|
28
|
+
(0, flags_js_1.checkSystemFlags)(connection.server, flag);
|
|
29
|
+
// a flag that is not in PERMANENTFLAGS is ignored (RFC 3501 section 7.1, RFC 9051 section 7.1)
|
|
30
|
+
if (!connection.server.isPermanentFlag(mailbox, flag)) {
|
|
31
31
|
return;
|
|
32
32
|
}
|
|
33
33
|
if (message.flags.indexOf(flag) < 0) {
|
|
@@ -39,7 +39,7 @@ function addFlags(connection, message, flags) {
|
|
|
39
39
|
function removeFlags(connection, message, flags) {
|
|
40
40
|
[].concat(flags).forEach(flag => {
|
|
41
41
|
flag = (0, flags_js_1.normalizeSystemFlag)(typeof flag === 'string' ? flag : String(flag.value || ''));
|
|
42
|
-
(0, flags_js_1.checkSystemFlags)(connection, flag);
|
|
42
|
+
(0, flags_js_1.checkSystemFlags)(connection.server, flag);
|
|
43
43
|
if (message.flags.indexOf(flag) >= 0) {
|
|
44
44
|
for (let i = 0; i < message.flags.length; i++) {
|
|
45
45
|
if (message.flags[i] === flag) {
|
|
@@ -22,8 +22,22 @@ function listCommand(connection, parsed, data, callback) {
|
|
|
22
22
|
return callback();
|
|
23
23
|
}
|
|
24
24
|
if (!parsed.attributes[1].value) {
|
|
25
|
-
// empty
|
|
26
|
-
|
|
25
|
+
// RFC 3501 section 6.3.8: "An empty ("" string) mailbox name argument is a special request to return the
|
|
26
|
+
// hierarchy delimiter and the root name of the name given in the reference. The value returned as the root
|
|
27
|
+
// MAY be the empty string if the reference is non-rooted or is an empty string."
|
|
28
|
+
const server = connection.server;
|
|
29
|
+
const reference = parsed.attributes[0].value || '';
|
|
30
|
+
// the namespace of the reference, the personal one for a reference that is not a valid name
|
|
31
|
+
let key = server.referenceNamespace;
|
|
32
|
+
try {
|
|
33
|
+
key = server.getNamespace(connection.importMailboxName(reference)) || key;
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
// not a mailbox name, so not in another namespace
|
|
37
|
+
}
|
|
38
|
+
const namespace = key !== false ? server.storage[key] : undefined;
|
|
39
|
+
// the root of a name in another namespace is the prefix of that namespace, like "#news." in the RFC example
|
|
40
|
+
const root = key !== false && key !== server.referenceNamespace ? connection.exportMailboxName(key) : '';
|
|
27
41
|
if (namespace) {
|
|
28
42
|
connection.send({
|
|
29
43
|
tag: '*',
|
|
@@ -36,7 +50,7 @@ function listCommand(connection, parsed, data, callback) {
|
|
|
36
50
|
}
|
|
37
51
|
],
|
|
38
52
|
namespace.separator,
|
|
39
|
-
|
|
53
|
+
root
|
|
40
54
|
]
|
|
41
55
|
}, 'LIST ITEM', parsed, data);
|
|
42
56
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.default = renameCommand;
|
|
4
|
+
const store_operations_js_1 = require("../store-operations.js");
|
|
4
5
|
function renameCommand(connection, parsed, data, callback) {
|
|
5
6
|
if (!parsed.attributes ||
|
|
6
7
|
parsed.attributes.length !== 2 ||
|
|
@@ -22,56 +23,15 @@ function renameCommand(connection, parsed, data, callback) {
|
|
|
22
23
|
}
|
|
23
24
|
const source = parsed.attributes[0].value;
|
|
24
25
|
const destination = parsed.attributes[1].value;
|
|
25
|
-
|
|
26
|
-
const mailbox = server.getMailbox(source);
|
|
27
|
-
const target = server.getMailbox(destination);
|
|
28
|
-
const sendError = (code, message) => {
|
|
29
|
-
connection.sendStatus(parsed, data, 'NO', message, code, 'RENAME FAILED');
|
|
30
|
-
return callback();
|
|
31
|
-
};
|
|
32
|
-
// check everything that can be checked up front, so that a failed RENAME never loses the source
|
|
33
|
-
if (!mailbox || mailbox.flags.indexOf('\\Noselect') >= 0) {
|
|
34
|
-
return sendError('NONEXISTENT', 'Mailbox does not exist');
|
|
35
|
-
}
|
|
36
|
-
if (target && target.flags.indexOf('\\Noselect') < 0) {
|
|
37
|
-
return sendError('ALREADYEXISTS', 'Mailbox already exists');
|
|
38
|
-
}
|
|
39
|
-
const separator = server.getSeparator(mailbox);
|
|
40
|
-
if (destination.substr(0, mailbox.path.length + separator.length) === mailbox.path + separator) {
|
|
41
|
-
return sendError('CANNOT', 'Can not move a mailbox into itself');
|
|
42
|
-
}
|
|
43
|
-
const oldPath = mailbox.path;
|
|
44
|
-
let newPath;
|
|
26
|
+
let renamed;
|
|
45
27
|
try {
|
|
46
|
-
|
|
47
|
-
// Renaming INBOX moves its messages to the new mailbox and leaves INBOX empty (RFC 3501 section 6.3.5)
|
|
48
|
-
const newMailbox = server.createMailbox(destination);
|
|
49
|
-
newPath = newMailbox.path;
|
|
50
|
-
mailbox.messages.forEach((message) => {
|
|
51
|
-
server.copyMessage(newMailbox, message);
|
|
52
|
-
});
|
|
53
|
-
connection.expungeSpecificMessages(mailbox, () => true);
|
|
54
|
-
}
|
|
55
|
-
else {
|
|
56
|
-
server.deleteMailbox(source, true);
|
|
57
|
-
try {
|
|
58
|
-
server.createMailbox(destination, mailbox);
|
|
59
|
-
}
|
|
60
|
-
catch (E) {
|
|
61
|
-
// put the source mailbox back where it was
|
|
62
|
-
server.createMailbox(source, mailbox);
|
|
63
|
-
server.indexFolders();
|
|
64
|
-
throw E;
|
|
65
|
-
}
|
|
66
|
-
server.indexFolders();
|
|
67
|
-
newPath = mailbox.path;
|
|
68
|
-
}
|
|
28
|
+
renamed = (0, store_operations_js_1.renameMailbox)(connection.server, source, destination);
|
|
69
29
|
}
|
|
70
30
|
catch (err) {
|
|
71
31
|
const E = err;
|
|
72
|
-
|
|
32
|
+
connection.sendStatus(parsed, data, 'NO', E.message, E.code, 'RENAME FAILED');
|
|
33
|
+
return callback();
|
|
73
34
|
}
|
|
74
|
-
server.mailboxChanged('rename', newPath, { oldPath });
|
|
75
35
|
connection.send({
|
|
76
36
|
tag: parsed.tag,
|
|
77
37
|
command: 'OK',
|
|
@@ -81,7 +41,7 @@ function renameCommand(connection, parsed, data, callback) {
|
|
|
81
41
|
value: 'RENAME completed'
|
|
82
42
|
}
|
|
83
43
|
]
|
|
84
|
-
}, 'RENAME', parsed, data, mailbox);
|
|
44
|
+
}, 'RENAME', parsed, data, renamed.mailbox);
|
|
85
45
|
return callback();
|
|
86
46
|
}
|
|
87
47
|
{
|
|
@@ -60,6 +60,7 @@ function selectMailbox(connection, parsed, data, callback, readOnly) {
|
|
|
60
60
|
connection.state = 'Selected';
|
|
61
61
|
connection.selectedMailbox = mailbox;
|
|
62
62
|
connection.readOnly = readOnly;
|
|
63
|
+
connection.emitSession('select');
|
|
63
64
|
connection.notificationQueue = [];
|
|
64
65
|
// \Recent is a session flag: a read-write session takes over the messages
|
|
65
66
|
// that no other session has seen yet (RFC 3501 section 2.3.2)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.default = subscribeCommand;
|
|
4
|
+
const store_operations_js_1 = require("../store-operations.js");
|
|
4
5
|
function subscribeCommand(connection, parsed, data, callback) {
|
|
5
6
|
if (!parsed.attributes || parsed.attributes.length !== 1 || !parsed.attributes[0] || ['STRING', 'LITERAL', 'ATOM'].indexOf(parsed.attributes[0].type) < 0) {
|
|
6
7
|
connection.send({
|
|
@@ -15,15 +16,13 @@ function subscribeCommand(connection, parsed, data, callback) {
|
|
|
15
16
|
}, 'INVALID COMMAND', parsed, data);
|
|
16
17
|
return callback();
|
|
17
18
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
if (!mailbox || mailbox.flags.indexOf('\\Noselect') >= 0) {
|
|
21
|
-
connection.sendStatus(parsed, data, 'NO', 'Mailbox does not exist', 'NONEXISTENT', 'SUBSCRIBE FAILED');
|
|
22
|
-
return callback();
|
|
19
|
+
try {
|
|
20
|
+
(0, store_operations_js_1.subscribeMailbox)(connection.server, parsed.attributes[0].value);
|
|
23
21
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
connection.
|
|
22
|
+
catch (err) {
|
|
23
|
+
const E = err;
|
|
24
|
+
connection.sendStatus(parsed, data, 'NO', E.message, E.code, 'SUBSCRIBE FAILED');
|
|
25
|
+
return callback();
|
|
27
26
|
}
|
|
28
27
|
connection.send({
|
|
29
28
|
tag: parsed.tag,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.default = unsubscribeCommand;
|
|
4
|
+
const store_operations_js_1 = require("../store-operations.js");
|
|
4
5
|
function unsubscribeCommand(connection, parsed, data, callback) {
|
|
5
6
|
if (!parsed.attributes || parsed.attributes.length !== 1 || !parsed.attributes[0] || ['STRING', 'LITERAL', 'ATOM'].indexOf(parsed.attributes[0].type) < 0) {
|
|
6
7
|
connection.send({
|
|
@@ -15,15 +16,8 @@ function unsubscribeCommand(connection, parsed, data, callback) {
|
|
|
15
16
|
}, 'INVALID COMMAND', parsed, data);
|
|
16
17
|
return callback();
|
|
17
18
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
path = 'INBOX';
|
|
21
|
-
}
|
|
22
|
-
// The subscription list holds names, so a name stays removable after its mailbox is deleted
|
|
23
|
-
// (RFC 3501 section 6.3.6). Removing a name that is not subscribed is not an error (RFC 9051 section 6.3.8)
|
|
24
|
-
if (connection.server.subscriptions.delete(path)) {
|
|
25
|
-
connection.server.mailboxChanged('unsubscribe', path);
|
|
26
|
-
}
|
|
19
|
+
// removing a name that is not subscribed is not an error (RFC 9051 section 6.3.8)
|
|
20
|
+
(0, store_operations_js_1.unsubscribeMailbox)(connection.server, parsed.attributes[0].value);
|
|
27
21
|
connection.send({
|
|
28
22
|
tag: parsed.tag,
|
|
29
23
|
command: 'OK',
|