imapkit 4.3.1 → 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.
Files changed (93) hide show
  1. package/README.md +167 -51
  2. package/bin/help.txt +17 -3
  3. package/bin/imapkit.js +53 -23
  4. package/dist/cjs/commands/append.js +1 -1
  5. package/dist/cjs/commands/create.js +2 -2
  6. package/dist/cjs/commands/delete.js +2 -14
  7. package/dist/cjs/commands/handlers/flags.d.ts +3 -3
  8. package/dist/cjs/commands/handlers/flags.js +3 -3
  9. package/dist/cjs/commands/handlers/store.js +3 -3
  10. package/dist/cjs/commands/rename.js +6 -46
  11. package/dist/cjs/commands/select.js +1 -0
  12. package/dist/cjs/commands/subscribe.js +7 -8
  13. package/dist/cjs/commands/unsubscribe.js +3 -9
  14. package/dist/cjs/control.d.ts +430 -0
  15. package/dist/cjs/control.js +637 -0
  16. package/dist/cjs/index.d.ts +8 -1
  17. package/dist/cjs/index.js +9 -2
  18. package/dist/cjs/load-plugins.d.ts +1 -1
  19. package/dist/cjs/load-plugins.js +7 -2
  20. package/dist/cjs/plugins/acl.js +109 -42
  21. package/dist/cjs/plugins/condstore.js +7 -0
  22. package/dist/cjs/plugins/index.js +1 -3
  23. package/dist/cjs/plugins/metadata.js +140 -57
  24. package/dist/cjs/plugins/objectid.js +10 -0
  25. package/dist/cjs/plugins/quota.js +50 -2
  26. package/dist/cjs/plugins/savedate.js +1 -1
  27. package/dist/cjs/plugins/special-use.d.ts +0 -8
  28. package/dist/cjs/plugins/special-use.js +23 -0
  29. package/dist/cjs/quirks.d.ts +28 -0
  30. package/dist/cjs/quirks.js +124 -0
  31. package/dist/cjs/random.d.ts +10 -0
  32. package/dist/cjs/random.js +22 -0
  33. package/dist/cjs/rest.d.ts +50 -0
  34. package/dist/cjs/rest.js +561 -0
  35. package/dist/cjs/script.d.ts +33 -4
  36. package/dist/cjs/script.js +64 -4
  37. package/dist/cjs/server.d.ts +147 -8
  38. package/dist/cjs/server.js +398 -144
  39. package/dist/cjs/smtp-listener.d.ts +3 -2
  40. package/dist/cjs/smtp-listener.js +10 -6
  41. package/dist/cjs/storage-schema.d.ts +139 -0
  42. package/dist/cjs/storage-schema.js +215 -0
  43. package/dist/cjs/store-operations.d.ts +168 -0
  44. package/dist/cjs/store-operations.js +422 -0
  45. package/dist/cjs/types.d.ts +22 -1
  46. package/dist/esm/commands/append.js +1 -1
  47. package/dist/esm/commands/create.js +2 -2
  48. package/dist/esm/commands/delete.js +2 -14
  49. package/dist/esm/commands/handlers/flags.d.ts +3 -3
  50. package/dist/esm/commands/handlers/flags.js +3 -3
  51. package/dist/esm/commands/handlers/store.js +3 -3
  52. package/dist/esm/commands/rename.js +6 -46
  53. package/dist/esm/commands/select.js +1 -0
  54. package/dist/esm/commands/subscribe.js +7 -8
  55. package/dist/esm/commands/unsubscribe.js +3 -9
  56. package/dist/esm/control.d.ts +430 -0
  57. package/dist/esm/control.js +630 -0
  58. package/dist/esm/index.d.ts +8 -1
  59. package/dist/esm/index.js +5 -2
  60. package/dist/esm/load-plugins.d.ts +1 -1
  61. package/dist/esm/load-plugins.js +7 -2
  62. package/dist/esm/plugins/acl.js +109 -42
  63. package/dist/esm/plugins/condstore.js +7 -0
  64. package/dist/esm/plugins/index.js +1 -3
  65. package/dist/esm/plugins/metadata.js +140 -57
  66. package/dist/esm/plugins/objectid.js +10 -0
  67. package/dist/esm/plugins/quota.js +50 -2
  68. package/dist/esm/plugins/savedate.js +1 -1
  69. package/dist/esm/plugins/special-use.d.ts +0 -8
  70. package/dist/esm/plugins/special-use.js +23 -0
  71. package/dist/esm/quirks.d.ts +28 -0
  72. package/dist/esm/quirks.js +120 -0
  73. package/dist/esm/random.d.ts +10 -0
  74. package/dist/esm/random.js +19 -0
  75. package/dist/esm/rest.d.ts +50 -0
  76. package/dist/esm/rest.js +553 -0
  77. package/dist/esm/script.d.ts +33 -4
  78. package/dist/esm/script.js +63 -4
  79. package/dist/esm/server.d.ts +147 -8
  80. package/dist/esm/server.js +399 -145
  81. package/dist/esm/smtp-listener.d.ts +3 -2
  82. package/dist/esm/smtp-listener.js +10 -6
  83. package/dist/esm/storage-schema.d.ts +139 -0
  84. package/dist/esm/storage-schema.js +211 -0
  85. package/dist/esm/store-operations.d.ts +168 -0
  86. package/dist/esm/store-operations.js +407 -0
  87. package/dist/esm/types.d.ts +22 -1
  88. package/dist/plugin-help.json +0 -14
  89. package/package.json +11 -3
  90. package/dist/cjs/plugins/xtoybird.d.ts +0 -2
  91. package/dist/cjs/plugins/xtoybird.js +0 -236
  92. package/dist/esm/plugins/xtoybird.d.ts +0 -2
  93. package/dist/esm/plugins/xtoybird.js +0 -218
@@ -1,236 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.default = xtoybirdPlugin;
7
- const command_states_js_1 = require("../command-states.js");
8
- /**
9
- * @help Custom plugin to allow programmatic control of the server
10
- * @help Available commands:
11
- * @help XTOYBIRD SERVER dumps server internals
12
- * @help XTOYBIRD CONNECTION dumps connection internals
13
- * @help XTOYBIRD STORAGE dumps storage as JSON
14
- * @help XTOYBIRD USERADD "username" "password" adds or updates user
15
- * @help XTOYBIRD USERDEL "username" removes a user
16
- * @help XTOYBIRD SHUTDOWN Closes the server after the last client
17
- * @help disconnects. New connections are rejected.
18
- * @help Commands are only allowed after login, and only for the owner
19
- * @help (aclOwner option) when ACL is loaded. A test control plugin,
20
- * @help any user it allows can read and change everything
21
- */
22
- const node_util_1 = __importDefault(require("node:util"));
23
- const arguments_js_1 = require("../arguments.js");
24
- function xtoybirdPlugin(server) {
25
- let username;
26
- let password;
27
- let message;
28
- const sendError = (connection, parsed, data, callback, command, message) => {
29
- connection.sendStatus(parsed, data, command, message, false, 'INVALID COMMAND');
30
- return callback();
31
- };
32
- server.setCommandHandler('XTOYBIRD', (connection, parsed, data, callback) => {
33
- // XTOYBIRD bypasses every access check (STORAGE dumps all mailboxes), so with ACL only the owner may use it
34
- if (server.acl && !server.acl.isOwner(connection)) {
35
- connection.sendStatus(parsed, data, 'NO', 'XTOYBIRD is only allowed for the owner', 'NOPERM', 'INVALID COMMAND');
36
- return callback();
37
- }
38
- if (parsed.attributes) {
39
- const subcommand = ((parsed.attributes[0] && parsed.attributes[0].value) || '').toString().toUpperCase();
40
- if (subcommand === 'USERADD' && (parsed.attributes.length !== 3 || !(0, arguments_js_1.isAstring)(parsed.attributes[1]) || !(0, arguments_js_1.isAstring)(parsed.attributes[2]))) {
41
- return sendError(connection, parsed, data, callback, 'BAD', 'USERADD expects username and password');
42
- }
43
- if (subcommand === 'USERDEL' && (parsed.attributes.length !== 2 || !(0, arguments_js_1.isAstring)(parsed.attributes[1]))) {
44
- return sendError(connection, parsed, data, callback, 'BAD', 'USERDEL expects username');
45
- }
46
- switch (subcommand) {
47
- case 'SERVER':
48
- connection.send({
49
- tag: '*',
50
- command: 'XTOYBIRD',
51
- attributes: [
52
- {
53
- type: 'SECTION',
54
- section: [
55
- {
56
- type: 'ATOM',
57
- value: 'XDUMPVAL'
58
- }
59
- ]
60
- },
61
- {
62
- type: 'LITERAL',
63
- value: node_util_1.default.inspect(server, false, 22)
64
- }
65
- ]
66
- }, 'CONNECTION STATUS', parsed, data);
67
- break;
68
- case 'CONNECTION':
69
- connection.send({
70
- tag: '*',
71
- command: 'XTOYBIRD',
72
- attributes: [
73
- {
74
- type: 'SECTION',
75
- section: [
76
- {
77
- type: 'ATOM',
78
- value: 'XDUMPVAL'
79
- }
80
- ]
81
- },
82
- {
83
- type: 'LITERAL',
84
- value: node_util_1.default.inspect(connection, false, 22)
85
- }
86
- ]
87
- }, 'CONNECTION STATUS', parsed, data);
88
- break;
89
- case 'STORAGE':
90
- connection.send({
91
- tag: '*',
92
- command: 'XTOYBIRD',
93
- attributes: [
94
- {
95
- type: 'SECTION',
96
- section: [
97
- {
98
- type: 'ATOM',
99
- value: 'XJSONDUMP'
100
- }
101
- ]
102
- },
103
- {
104
- type: 'LITERAL',
105
- value: JSON.stringify(connection.server.storage, null, 4)
106
- }
107
- ]
108
- }, 'CONNECTION STATUS', parsed, data);
109
- break;
110
- case 'USERADD':
111
- username = parsed.attributes[1].value || '';
112
- password = parsed.attributes[2].value || '';
113
- if (connection.server.getUser(username)) {
114
- connection.server.users[username].password = password;
115
- message = 'updated';
116
- }
117
- else {
118
- connection.server.users[username] = {
119
- password: password
120
- };
121
- message = 'added';
122
- }
123
- connection.send({
124
- tag: '*',
125
- command: 'XTOYBIRD',
126
- attributes: [
127
- {
128
- type: 'SECTION',
129
- section: [
130
- {
131
- type: 'ATOM',
132
- value: 'XUSER'
133
- }
134
- ]
135
- },
136
- {
137
- type: 'TEXT',
138
- value: 'User ' + displayName(username) + message + ' successfully'
139
- }
140
- ]
141
- }, 'CONNECTION USERADD', parsed, data);
142
- break;
143
- case 'USERDEL':
144
- username = parsed.attributes[1].value || '';
145
- if (username in connection.server.users) {
146
- delete connection.server.users[username];
147
- message = 'succeeded';
148
- }
149
- else {
150
- message = 'failed (no such user)';
151
- }
152
- connection.send({
153
- tag: '*',
154
- command: 'XTOYBIRD',
155
- attributes: [
156
- {
157
- type: 'SECTION',
158
- section: [
159
- {
160
- type: 'ATOM',
161
- value: 'XUSER'
162
- }
163
- ]
164
- },
165
- {
166
- type: 'TEXT',
167
- value: 'Removing user ' + displayName(username) + message
168
- }
169
- ]
170
- }, 'CONNECTION USERDEL', parsed, data);
171
- break;
172
- case 'SHUTDOWN':
173
- connection.send({
174
- tag: '*',
175
- command: 'OK',
176
- attributes: [
177
- {
178
- type: 'SECTION',
179
- section: [
180
- {
181
- type: 'ATOM',
182
- value: 'ALERT'
183
- }
184
- ]
185
- },
186
- {
187
- type: 'TEXT',
188
- value: 'System scheduled for shutdown'
189
- }
190
- ]
191
- }, 'CONNECTION SHUTDOWN', parsed, data);
192
- connection.server.close();
193
- break;
194
- default:
195
- connection.send({
196
- tag: parsed.tag,
197
- command: 'BAD',
198
- attributes: [
199
- {
200
- type: 'TEXT',
201
- value: 'Unknown command'
202
- }
203
- ]
204
- }, 'INVALID COMMAND', parsed, data);
205
- return callback();
206
- }
207
- }
208
- connection.send({
209
- tag: parsed.tag,
210
- command: 'OK',
211
- attributes: [
212
- {
213
- type: 'TEXT',
214
- value: 'XTOYBIRD Completed'
215
- }
216
- ]
217
- }, 'XTOYBIRD', parsed, data);
218
- return callback();
219
- }, { states: command_states_js_1.states.AUTHENTICATED });
220
- }
221
- // Response text is free text that some clients still tokenize, so only plain user names are echoed
222
- function displayName(username) {
223
- return /^[\w.@+-]+$/.test(username) ? "'" + username + "' " : '';
224
- }
225
- {
226
- const defaultExport = exports.default;
227
- if (defaultExport && (typeof defaultExport === 'function' || typeof defaultExport === 'object')) {
228
- for (const key of Object.keys(exports)) {
229
- if (key !== 'default' && !(key in defaultExport)) {
230
- defaultExport[key] = exports[key];
231
- }
232
- }
233
- Object.defineProperty(defaultExport, 'default', { value: defaultExport, enumerable: false, writable: true, configurable: true });
234
- module.exports = defaultExport;
235
- }
236
- }
@@ -1,2 +0,0 @@
1
- import type { IMAPServer } from '../types.js';
2
- export default function xtoybirdPlugin(server: IMAPServer): void;
@@ -1,218 +0,0 @@
1
- import { states } from '../command-states.js';
2
- /**
3
- * @help Custom plugin to allow programmatic control of the server
4
- * @help Available commands:
5
- * @help XTOYBIRD SERVER dumps server internals
6
- * @help XTOYBIRD CONNECTION dumps connection internals
7
- * @help XTOYBIRD STORAGE dumps storage as JSON
8
- * @help XTOYBIRD USERADD "username" "password" adds or updates user
9
- * @help XTOYBIRD USERDEL "username" removes a user
10
- * @help XTOYBIRD SHUTDOWN Closes the server after the last client
11
- * @help disconnects. New connections are rejected.
12
- * @help Commands are only allowed after login, and only for the owner
13
- * @help (aclOwner option) when ACL is loaded. A test control plugin,
14
- * @help any user it allows can read and change everything
15
- */
16
- import util from 'node:util';
17
- import { isAstring } from '../arguments.js';
18
- export default function xtoybirdPlugin(server) {
19
- let username;
20
- let password;
21
- let message;
22
- const sendError = (connection, parsed, data, callback, command, message) => {
23
- connection.sendStatus(parsed, data, command, message, false, 'INVALID COMMAND');
24
- return callback();
25
- };
26
- server.setCommandHandler('XTOYBIRD', (connection, parsed, data, callback) => {
27
- // XTOYBIRD bypasses every access check (STORAGE dumps all mailboxes), so with ACL only the owner may use it
28
- if (server.acl && !server.acl.isOwner(connection)) {
29
- connection.sendStatus(parsed, data, 'NO', 'XTOYBIRD is only allowed for the owner', 'NOPERM', 'INVALID COMMAND');
30
- return callback();
31
- }
32
- if (parsed.attributes) {
33
- const subcommand = ((parsed.attributes[0] && parsed.attributes[0].value) || '').toString().toUpperCase();
34
- if (subcommand === 'USERADD' && (parsed.attributes.length !== 3 || !isAstring(parsed.attributes[1]) || !isAstring(parsed.attributes[2]))) {
35
- return sendError(connection, parsed, data, callback, 'BAD', 'USERADD expects username and password');
36
- }
37
- if (subcommand === 'USERDEL' && (parsed.attributes.length !== 2 || !isAstring(parsed.attributes[1]))) {
38
- return sendError(connection, parsed, data, callback, 'BAD', 'USERDEL expects username');
39
- }
40
- switch (subcommand) {
41
- case 'SERVER':
42
- connection.send({
43
- tag: '*',
44
- command: 'XTOYBIRD',
45
- attributes: [
46
- {
47
- type: 'SECTION',
48
- section: [
49
- {
50
- type: 'ATOM',
51
- value: 'XDUMPVAL'
52
- }
53
- ]
54
- },
55
- {
56
- type: 'LITERAL',
57
- value: util.inspect(server, false, 22)
58
- }
59
- ]
60
- }, 'CONNECTION STATUS', parsed, data);
61
- break;
62
- case 'CONNECTION':
63
- connection.send({
64
- tag: '*',
65
- command: 'XTOYBIRD',
66
- attributes: [
67
- {
68
- type: 'SECTION',
69
- section: [
70
- {
71
- type: 'ATOM',
72
- value: 'XDUMPVAL'
73
- }
74
- ]
75
- },
76
- {
77
- type: 'LITERAL',
78
- value: util.inspect(connection, false, 22)
79
- }
80
- ]
81
- }, 'CONNECTION STATUS', parsed, data);
82
- break;
83
- case 'STORAGE':
84
- connection.send({
85
- tag: '*',
86
- command: 'XTOYBIRD',
87
- attributes: [
88
- {
89
- type: 'SECTION',
90
- section: [
91
- {
92
- type: 'ATOM',
93
- value: 'XJSONDUMP'
94
- }
95
- ]
96
- },
97
- {
98
- type: 'LITERAL',
99
- value: JSON.stringify(connection.server.storage, null, 4)
100
- }
101
- ]
102
- }, 'CONNECTION STATUS', parsed, data);
103
- break;
104
- case 'USERADD':
105
- username = parsed.attributes[1].value || '';
106
- password = parsed.attributes[2].value || '';
107
- if (connection.server.getUser(username)) {
108
- connection.server.users[username].password = password;
109
- message = 'updated';
110
- }
111
- else {
112
- connection.server.users[username] = {
113
- password: password
114
- };
115
- message = 'added';
116
- }
117
- connection.send({
118
- tag: '*',
119
- command: 'XTOYBIRD',
120
- attributes: [
121
- {
122
- type: 'SECTION',
123
- section: [
124
- {
125
- type: 'ATOM',
126
- value: 'XUSER'
127
- }
128
- ]
129
- },
130
- {
131
- type: 'TEXT',
132
- value: 'User ' + displayName(username) + message + ' successfully'
133
- }
134
- ]
135
- }, 'CONNECTION USERADD', parsed, data);
136
- break;
137
- case 'USERDEL':
138
- username = parsed.attributes[1].value || '';
139
- if (username in connection.server.users) {
140
- delete connection.server.users[username];
141
- message = 'succeeded';
142
- }
143
- else {
144
- message = 'failed (no such user)';
145
- }
146
- connection.send({
147
- tag: '*',
148
- command: 'XTOYBIRD',
149
- attributes: [
150
- {
151
- type: 'SECTION',
152
- section: [
153
- {
154
- type: 'ATOM',
155
- value: 'XUSER'
156
- }
157
- ]
158
- },
159
- {
160
- type: 'TEXT',
161
- value: 'Removing user ' + displayName(username) + message
162
- }
163
- ]
164
- }, 'CONNECTION USERDEL', parsed, data);
165
- break;
166
- case 'SHUTDOWN':
167
- connection.send({
168
- tag: '*',
169
- command: 'OK',
170
- attributes: [
171
- {
172
- type: 'SECTION',
173
- section: [
174
- {
175
- type: 'ATOM',
176
- value: 'ALERT'
177
- }
178
- ]
179
- },
180
- {
181
- type: 'TEXT',
182
- value: 'System scheduled for shutdown'
183
- }
184
- ]
185
- }, 'CONNECTION SHUTDOWN', parsed, data);
186
- connection.server.close();
187
- break;
188
- default:
189
- connection.send({
190
- tag: parsed.tag,
191
- command: 'BAD',
192
- attributes: [
193
- {
194
- type: 'TEXT',
195
- value: 'Unknown command'
196
- }
197
- ]
198
- }, 'INVALID COMMAND', parsed, data);
199
- return callback();
200
- }
201
- }
202
- connection.send({
203
- tag: parsed.tag,
204
- command: 'OK',
205
- attributes: [
206
- {
207
- type: 'TEXT',
208
- value: 'XTOYBIRD Completed'
209
- }
210
- ]
211
- }, 'XTOYBIRD', parsed, data);
212
- return callback();
213
- }, { states: states.AUTHENTICATED });
214
- }
215
- // Response text is free text that some clients still tokenize, so only plain user names are echoed
216
- function displayName(username) {
217
- return /^[\w.@+-]+$/.test(username) ? "'" + username + "' " : '';
218
- }