Haraka 3.1.1 → 3.1.2

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 (160) hide show
  1. package/.prettierignore +4 -0
  2. package/CONTRIBUTORS.md +5 -5
  3. package/Changes.md +62 -50
  4. package/Plugins.md +3 -1
  5. package/README.md +1 -1
  6. package/bin/haraka +475 -479
  7. package/config/outbound.ini +3 -0
  8. package/connection.js +1072 -1108
  9. package/docs/Connection.md +29 -30
  10. package/docs/CoreConfig.md +38 -39
  11. package/docs/CustomReturnCodes.md +0 -1
  12. package/docs/HAProxy.md +2 -2
  13. package/docs/Header.md +1 -1
  14. package/docs/Logging.md +29 -5
  15. package/docs/Outbound.md +93 -78
  16. package/docs/Plugins.md +103 -108
  17. package/docs/Transaction.md +49 -51
  18. package/docs/Tutorial.md +127 -143
  19. package/docs/deprecated/access.md +0 -1
  20. package/docs/deprecated/backscatterer.md +2 -3
  21. package/docs/deprecated/connect.rdns_access.md +18 -27
  22. package/docs/deprecated/data.headers.md +0 -1
  23. package/docs/deprecated/data.nomsgid.md +1 -2
  24. package/docs/deprecated/data.noreceived.md +1 -2
  25. package/docs/deprecated/data.rfc5322_header_checks.md +1 -2
  26. package/docs/deprecated/dkim_sign.md +13 -17
  27. package/docs/deprecated/dkim_verify.md +9 -17
  28. package/docs/deprecated/dnsbl.md +36 -38
  29. package/docs/deprecated/dnswl.md +41 -43
  30. package/docs/deprecated/lookup_rdns.strict.md +21 -34
  31. package/docs/deprecated/mail_from.access.md +17 -25
  32. package/docs/deprecated/mail_from.blocklist.md +9 -12
  33. package/docs/deprecated/mail_from.nobounces.md +1 -2
  34. package/docs/deprecated/rcpt_to.access.md +20 -27
  35. package/docs/deprecated/rcpt_to.blocklist.md +10 -13
  36. package/docs/deprecated/rcpt_to.routes.md +0 -1
  37. package/docs/deprecated/rdns.regexp.md +13 -15
  38. package/docs/plugins/aliases.md +89 -89
  39. package/docs/plugins/auth/auth_bridge.md +5 -7
  40. package/docs/plugins/auth/auth_ldap.md +11 -14
  41. package/docs/plugins/auth/auth_proxy.md +10 -12
  42. package/docs/plugins/auth/auth_vpopmaild.md +5 -6
  43. package/docs/plugins/auth/flat_file.md +4 -4
  44. package/docs/plugins/block_me.md +3 -3
  45. package/docs/plugins/data.signatures.md +1 -2
  46. package/docs/plugins/delay_deny.md +3 -4
  47. package/docs/plugins/max_unrecognized_commands.md +4 -4
  48. package/docs/plugins/prevent_credential_leaks.md +6 -6
  49. package/docs/plugins/process_title.md +18 -18
  50. package/docs/plugins/queue/deliver.md +2 -3
  51. package/docs/plugins/queue/discard.md +4 -4
  52. package/docs/plugins/queue/lmtp.md +1 -3
  53. package/docs/plugins/queue/qmail-queue.md +7 -9
  54. package/docs/plugins/queue/quarantine.md +16 -21
  55. package/docs/plugins/queue/rabbitmq.md +8 -11
  56. package/docs/plugins/queue/rabbitmq_amqplib.md +43 -39
  57. package/docs/plugins/queue/smtp_bridge.md +7 -10
  58. package/docs/plugins/queue/smtp_forward.md +42 -34
  59. package/docs/plugins/queue/smtp_proxy.md +30 -29
  60. package/docs/plugins/queue/test.md +1 -3
  61. package/docs/plugins/rcpt_to.in_host_list.md +6 -6
  62. package/docs/plugins/rcpt_to.max_count.md +1 -1
  63. package/docs/plugins/record_envelope_addresses.md +3 -3
  64. package/docs/plugins/reseed_rng.md +6 -6
  65. package/docs/plugins/status.md +9 -8
  66. package/docs/plugins/tarpit.md +7 -11
  67. package/docs/plugins/tls.md +12 -17
  68. package/docs/plugins/toobusy.md +4 -4
  69. package/docs/plugins/xclient.md +3 -3
  70. package/docs/tutorials/Migrating_from_v1_to_v2.md +19 -41
  71. package/docs/tutorials/SettingUpOutbound.md +6 -9
  72. package/endpoint.js +35 -38
  73. package/eslint.config.mjs +22 -19
  74. package/haraka.js +42 -47
  75. package/host_pool.js +75 -79
  76. package/http/html/404.html +45 -49
  77. package/http/html/index.html +39 -28
  78. package/http/package.json +2 -4
  79. package/line_socket.js +27 -28
  80. package/logger.js +182 -201
  81. package/outbound/client_pool.js +33 -33
  82. package/outbound/config.js +64 -59
  83. package/outbound/fsync_writestream.js +24 -25
  84. package/outbound/hmail.js +888 -835
  85. package/outbound/index.js +194 -187
  86. package/outbound/qfile.js +49 -52
  87. package/outbound/queue.js +197 -190
  88. package/outbound/timer_queue.js +41 -43
  89. package/outbound/tls.js +68 -61
  90. package/outbound/todo.js +11 -11
  91. package/package.json +32 -32
  92. package/plugins/.eslintrc.yaml +0 -1
  93. package/plugins/auth/auth_base.js +123 -127
  94. package/plugins/auth/auth_bridge.js +7 -7
  95. package/plugins/auth/auth_proxy.js +121 -126
  96. package/plugins/auth/auth_vpopmaild.js +84 -85
  97. package/plugins/auth/flat_file.js +18 -17
  98. package/plugins/block_me.js +31 -31
  99. package/plugins/data.signatures.js +13 -13
  100. package/plugins/delay_deny.js +65 -61
  101. package/plugins/prevent_credential_leaks.js +23 -23
  102. package/plugins/process_title.js +125 -128
  103. package/plugins/profile.js +5 -5
  104. package/plugins/queue/deliver.js +3 -3
  105. package/plugins/queue/discard.js +13 -14
  106. package/plugins/queue/lmtp.js +16 -17
  107. package/plugins/queue/qmail-queue.js +54 -55
  108. package/plugins/queue/quarantine.js +68 -70
  109. package/plugins/queue/rabbitmq.js +80 -87
  110. package/plugins/queue/rabbitmq_amqplib.js +75 -54
  111. package/plugins/queue/smtp_bridge.js +16 -16
  112. package/plugins/queue/smtp_forward.js +175 -179
  113. package/plugins/queue/smtp_proxy.js +69 -71
  114. package/plugins/queue/test.js +9 -9
  115. package/plugins/rcpt_to.host_list_base.js +30 -34
  116. package/plugins/rcpt_to.in_host_list.js +19 -19
  117. package/plugins/record_envelope_addresses.js +4 -4
  118. package/plugins/reseed_rng.js +4 -4
  119. package/plugins/status.js +90 -97
  120. package/plugins/tarpit.js +25 -14
  121. package/plugins/tls.js +68 -68
  122. package/plugins/toobusy.js +21 -23
  123. package/plugins/xclient.js +51 -53
  124. package/plugins.js +276 -293
  125. package/rfc1869.js +30 -35
  126. package/server.js +308 -299
  127. package/smtp_client.js +244 -228
  128. package/test/.eslintrc.yaml +0 -1
  129. package/test/connection.js +127 -134
  130. package/test/endpoint.js +53 -47
  131. package/test/fixtures/line_socket.js +12 -12
  132. package/test/fixtures/util_hmailitem.js +89 -85
  133. package/test/host_pool.js +90 -92
  134. package/test/installation/plugins/base_plugin.js +2 -2
  135. package/test/installation/plugins/folder_plugin/index.js +2 -3
  136. package/test/installation/plugins/inherits.js +3 -3
  137. package/test/installation/plugins/load_first.js +2 -3
  138. package/test/installation/plugins/plugin.js +1 -3
  139. package/test/installation/plugins/tls.js +2 -4
  140. package/test/logger.js +135 -116
  141. package/test/outbound/hmail.js +49 -35
  142. package/test/outbound/index.js +118 -101
  143. package/test/outbound/qfile.js +51 -53
  144. package/test/outbound_bounce_net_errors.js +84 -69
  145. package/test/outbound_bounce_rfc3464.js +235 -165
  146. package/test/plugins/auth/auth_base.js +420 -279
  147. package/test/plugins/auth/auth_vpopmaild.js +38 -39
  148. package/test/plugins/queue/smtp_forward.js +126 -104
  149. package/test/plugins/rcpt_to.host_list_base.js +85 -67
  150. package/test/plugins/rcpt_to.in_host_list.js +159 -112
  151. package/test/plugins/status.js +71 -64
  152. package/test/plugins/tls.js +37 -34
  153. package/test/plugins.js +97 -92
  154. package/test/rfc1869.js +19 -26
  155. package/test/server.js +293 -272
  156. package/test/smtp_client.js +180 -176
  157. package/test/tls_socket.js +62 -66
  158. package/test/transaction.js +159 -160
  159. package/tls_socket.js +331 -333
  160. package/transaction.js +129 -137
package/outbound/queue.js CHANGED
@@ -1,121 +1,119 @@
1
- 'use strict';
1
+ 'use strict'
2
2
 
3
- const child_process = require('node:child_process');
4
- const fs = require('node:fs');
5
- const path = require('node:path');
3
+ const child_process = require('node:child_process')
4
+ const fs = require('node:fs')
5
+ const path = require('node:path')
6
6
 
7
- const async = require('async');
8
- const { Address } = require('address-rfc2821');
9
- const config = require('haraka-config');
7
+ const async = require('async')
8
+ const { Address } = require('address-rfc2821')
9
+ const config = require('haraka-config')
10
10
 
11
- const logger = require('../logger');
12
- const TimerQueue = require('./timer_queue');
13
- const HMailItem = require('./hmail');
14
- const obc = require('./config');
15
- const _qfile = require('./qfile');
16
- const obtls = require('./tls');
11
+ const logger = require('../logger')
12
+ const TimerQueue = require('./timer_queue')
13
+ const HMailItem = require('./hmail')
14
+ const obc = require('./config')
15
+ const _qfile = require('./qfile')
16
+ const obtls = require('./tls')
17
17
 
18
- exports.name = 'outbound/queue';
18
+ exports.name = 'outbound/queue'
19
19
 
20
- let queue_dir;
20
+ let queue_dir
21
21
  if (config.get('queue_dir')) {
22
- queue_dir = path.resolve(config.get('queue_dir'));
23
- }
24
- else if (process.env.HARAKA) {
25
- queue_dir = path.resolve(process.env.HARAKA, 'queue');
26
- }
27
- else {
28
- queue_dir = path.resolve('test', 'test-queue');
22
+ queue_dir = path.resolve(config.get('queue_dir'))
23
+ } else if (process.env.HARAKA) {
24
+ queue_dir = path.resolve(process.env.HARAKA, 'queue')
25
+ } else {
26
+ queue_dir = path.resolve('test', 'test-queue')
29
27
  }
30
28
 
31
- exports.queue_dir = queue_dir;
29
+ exports.queue_dir = queue_dir
32
30
 
33
31
  const load_queue = async.queue((file, cb) => {
34
- const hmail = new HMailItem(file, path.join(queue_dir, file));
35
- exports._add_hmail(hmail);
36
- hmail.once('ready', cb);
37
- }, obc.cfg.concurrency_max);
38
-
39
- let in_progress = 0;
40
- const delivery_queue = exports.delivery_queue = async.queue((hmail, cb) => {
41
- in_progress++;
32
+ const hmail = new HMailItem(file, path.join(queue_dir, file))
33
+ exports._add_hmail(hmail)
34
+ hmail.once('ready', cb)
35
+ }, obc.cfg.concurrency_max)
36
+
37
+ let in_progress = 0
38
+ const delivery_queue = (exports.delivery_queue = async.queue((hmail, cb) => {
39
+ in_progress++
42
40
  hmail.next_cb = () => {
43
- in_progress--;
44
- cb();
45
- };
46
- if (obtls.cfg) return hmail.send();
41
+ in_progress--
42
+ cb()
43
+ }
44
+ if (obtls.cfg) return hmail.send()
47
45
  obtls.init(() => {
48
- hmail.send();
49
- });
50
- }, obc.cfg.concurrency_max);
46
+ hmail.send()
47
+ })
48
+ }, obc.cfg.concurrency_max))
51
49
 
52
- const temp_fail_queue = exports.temp_fail_queue = new TimerQueue();
50
+ const temp_fail_queue = (exports.temp_fail_queue = new TimerQueue())
53
51
 
54
- let queue_count = 0;
52
+ let queue_count = 0
55
53
 
56
- exports.get_stats = () => `${in_progress}/${exports.delivery_queue.length()}/${exports.temp_fail_queue.length()}`;
54
+ exports.get_stats = () => `${in_progress}/${exports.delivery_queue.length()}/${exports.temp_fail_queue.length()}`
57
55
 
58
- exports.list_queue = cb => {
59
- exports._load_cur_queue(null, exports._list_file, cb);
56
+ exports.list_queue = (cb) => {
57
+ exports._load_cur_queue(null, exports._list_file, cb)
60
58
  }
61
59
 
62
60
  exports._stat_file = (file, cb) => {
63
- queue_count++;
64
- setImmediate(cb);
61
+ queue_count++
62
+ setImmediate(cb)
65
63
  }
66
64
 
67
- exports.stat_queue = cb => {
68
- const self = exports;
69
- exports._load_cur_queue(null, exports._stat_file, err => {
70
- if (err) return cb(err);
71
- return cb(null, self.stats());
72
- });
65
+ exports.stat_queue = (cb) => {
66
+ const self = exports
67
+ exports._load_cur_queue(null, exports._stat_file, (err) => {
68
+ if (err) return cb(err)
69
+ return cb(null, self.stats())
70
+ })
73
71
  }
74
72
 
75
- exports.load_queue = pid => {
73
+ exports.load_queue = (pid) => {
76
74
  // Initialise and load queue
77
75
  // This function is called first when not running under cluster,
78
- exports.ensure_queue_dir();
79
- exports.delete_dot_files();
76
+ exports.ensure_queue_dir()
77
+ exports.delete_dot_files()
80
78
 
81
79
  exports._load_cur_queue(pid, exports._add_file, () => {
82
- logger.info(exports, `[pid: ${pid}] ${delivery_queue.length()} files in my delivery queue`);
83
- logger.info(exports, `[pid: ${pid}] ${load_queue.length()} files in my load queue`);
84
- logger.info(exports, `[pid: ${pid}] ${temp_fail_queue.length()} files in my temp fail queue`);
85
- });
80
+ logger.info(exports, `[pid: ${pid}] ${delivery_queue.length()} files in my delivery queue`)
81
+ logger.info(exports, `[pid: ${pid}] ${load_queue.length()} files in my load queue`)
82
+ logger.info(exports, `[pid: ${pid}] ${temp_fail_queue.length()} files in my temp fail queue`)
83
+ })
86
84
  }
87
85
 
88
86
  exports._load_cur_queue = (pid, iteratee, cb) => {
89
- logger.info(exports, "Loading outbound queue from ", queue_dir);
87
+ logger.info(exports, 'Loading outbound queue from ', queue_dir)
90
88
  fs.readdir(queue_dir, (err, files) => {
91
89
  if (err) {
92
- return logger.error(exports, `Failed to load queue directory (${queue_dir}): ${err}`);
90
+ return logger.error(exports, `Failed to load queue directory (${queue_dir}): ${err}`)
93
91
  }
94
92
 
95
- this.cur_time = new Date(); // set once so we're not calling it a lot
93
+ this.cur_time = new Date() // set once so we're not calling it a lot
96
94
 
97
- this.load_queue_files(pid, files, iteratee, cb);
98
- });
95
+ this.load_queue_files(pid, files, iteratee, cb)
96
+ })
99
97
  }
100
98
 
101
- exports.read_parts = file => {
99
+ exports.read_parts = (file) => {
102
100
  if (file.indexOf(_qfile.platformDOT) === 0) {
103
- logger.warn(exports, `'Skipping' dot-file in queue folder: ${file}`);
104
- return false;
101
+ logger.warn(exports, `'Skipping' dot-file in queue folder: ${file}`)
102
+ return false
105
103
  }
106
104
 
107
105
  if (file.startsWith('error.')) {
108
- logger.warn(exports, `'Skipping' error file in queue folder: ${file}`);
109
- return false;
106
+ logger.warn(exports, `'Skipping' error file in queue folder: ${file}`)
107
+ return false
110
108
  }
111
109
 
112
- const parts = _qfile.parts(file);
110
+ const parts = _qfile.parts(file)
113
111
  if (!parts) {
114
- logger.error(exports, `Unrecognized file in queue folder: ${file}`);
115
- return false;
112
+ logger.error(exports, `Unrecognized file in queue folder: ${file}`)
113
+ return false
116
114
  }
117
115
 
118
- return parts;
116
+ return parts
119
117
  }
120
118
 
121
119
  exports.rename_to_actual_pid = (file, parts, cb) => {
@@ -125,166 +123,176 @@ exports.rename_to_actual_pid = (file, parts, cb) => {
125
123
  uid: parts.uid,
126
124
  next_attempt: parts.next_attempt,
127
125
  attempts: parts.attempts,
128
- });
126
+ })
129
127
 
130
- fs.rename(path.join(queue_dir, file), path.join(queue_dir, new_filename), err => {
128
+ fs.rename(path.join(queue_dir, file), path.join(queue_dir, new_filename), (err) => {
131
129
  if (err) {
132
- return cb(`Unable to rename queue file: ${file} to ${new_filename} : ${err}`);
130
+ return cb(`Unable to rename queue file: ${file} to ${new_filename} : ${err}`)
133
131
  }
134
132
 
135
- cb(null, new_filename);
136
- });
133
+ cb(null, new_filename)
134
+ })
137
135
  }
138
136
 
139
137
  exports._add_file = (file, cb) => {
140
- const self = exports;
141
- const parts = _qfile.parts(file);
138
+ const self = exports
139
+ const parts = _qfile.parts(file)
142
140
 
143
141
  if (parts.next_attempt <= self.cur_time) {
144
- logger.debug(exports, `File ${file} needs processing now`);
145
- load_queue.push(file);
146
- }
147
- else {
148
- logger.debug(exports, `File ${file} needs processing later: ${parts.next_attempt - self.cur_time}ms`);
149
- temp_fail_queue.add(file, parts.next_attempt - self.cur_time, () => { load_queue.push(file);});
142
+ logger.debug(exports, `File ${file} needs processing now`)
143
+ load_queue.push(file)
144
+ } else {
145
+ logger.debug(exports, `File ${file} needs processing later: ${parts.next_attempt - self.cur_time}ms`)
146
+ temp_fail_queue.add(file, parts.next_attempt - self.cur_time, () => {
147
+ load_queue.push(file)
148
+ })
150
149
  }
151
150
 
152
- cb();
151
+ cb()
153
152
  }
154
153
 
155
154
  exports.load_queue_files = (pid, input_files, iteratee, callback = function () {}) => {
156
- const self = exports;
157
- const searchPid = parseInt(pid);
155
+ const self = exports
156
+ const searchPid = parseInt(pid)
158
157
 
159
- let stat_renamed = 0;
160
- let stat_loaded = 0;
158
+ let stat_renamed = 0
159
+ let stat_loaded = 0
161
160
 
162
161
  if (searchPid) {
163
- logger.info(exports, `Grabbing queue files for pid: ${pid}`);
164
- }
165
- else {
166
- logger.info(exports, "Loading the queue...");
162
+ logger.info(exports, `Grabbing queue files for pid: ${pid}`)
163
+ } else {
164
+ logger.info(exports, 'Loading the queue...')
167
165
  }
168
166
 
169
- async.map(input_files, (file, cb) => {
170
- const parts = self.read_parts(file);
171
- if (!parts) return cb();
172
-
173
- if (searchPid) {
174
- if (parts.pid !== searchPid) return cb();
175
-
176
- self.rename_to_actual_pid(file, parts, (error, renamed_file) => {
177
- if (error) {
178
- logger.error(exports, `${error}`);
179
- return cb();
180
- }
181
-
182
- stat_renamed++;
183
- stat_loaded++;
184
- cb(null, renamed_file);
185
- });
186
- }
187
- else {
188
- stat_loaded++;
189
- cb(null, file);
190
- }
191
-
192
- }, (err, results) => {
193
- if (err) logger.err(exports, `[pid: ${pid}] ${err}`);
194
- if (searchPid) logger.info(exports, `[pid: ${pid}] ${stat_renamed} files old PID queue fixed up`);
195
- logger.debug(exports, `[pid: ${pid}] ${stat_loaded} files loaded`);
196
-
197
- async.map(results.filter((i) => i), iteratee, callback);
198
- });
167
+ async.map(
168
+ input_files,
169
+ (file, cb) => {
170
+ const parts = self.read_parts(file)
171
+ if (!parts) return cb()
172
+
173
+ if (searchPid) {
174
+ if (parts.pid !== searchPid) return cb()
175
+
176
+ self.rename_to_actual_pid(file, parts, (error, renamed_file) => {
177
+ if (error) {
178
+ logger.error(exports, `${error}`)
179
+ return cb()
180
+ }
181
+
182
+ stat_renamed++
183
+ stat_loaded++
184
+ cb(null, renamed_file)
185
+ })
186
+ } else {
187
+ stat_loaded++
188
+ cb(null, file)
189
+ }
190
+ },
191
+ (err, results) => {
192
+ if (err) logger.err(exports, `[pid: ${pid}] ${err}`)
193
+ if (searchPid) logger.info(exports, `[pid: ${pid}] ${stat_renamed} files old PID queue fixed up`)
194
+ logger.debug(exports, `[pid: ${pid}] ${stat_loaded} files loaded`)
195
+
196
+ async.map(
197
+ results.filter((i) => i),
198
+ iteratee,
199
+ callback,
200
+ )
201
+ },
202
+ )
199
203
  }
200
204
 
201
205
  exports.stats = () => {
202
206
  return {
203
207
  queue_dir,
204
208
  queue_count,
205
- };
209
+ }
206
210
  }
207
211
 
208
212
  exports._list_file = (file, cb) => {
209
- const tl_reader = fs.createReadStream(path.join(queue_dir, file), {start: 0, end: 3});
210
- tl_reader.on('error', err => {
211
- console.error(`Error reading queue file: ${file}:`, err);
212
- });
213
- tl_reader.once('data', buf => {
213
+ const tl_reader = fs.createReadStream(path.join(queue_dir, file), {
214
+ start: 0,
215
+ end: 3,
216
+ })
217
+ tl_reader.on('error', (err) => {
218
+ console.error(`Error reading queue file: ${file}:`, err)
219
+ })
220
+ tl_reader.once('data', (buf) => {
214
221
  // I'm making the assumption here we won't ever read less than 4 bytes
215
222
  // as no filesystem on the planet should be that dumb...
216
- tl_reader.destroy();
217
- const todo_len = (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3];
218
- const td_reader = fs.createReadStream(path.join(queue_dir, file), {encoding: 'utf8', start: 4, end: todo_len + 3});
219
- let todo = '';
220
- td_reader.on('data', str => {
221
- todo += str;
223
+ tl_reader.destroy()
224
+ const todo_len = (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3]
225
+ const td_reader = fs.createReadStream(path.join(queue_dir, file), {
226
+ encoding: 'utf8',
227
+ start: 4,
228
+ end: todo_len + 3,
229
+ })
230
+ let todo = ''
231
+ td_reader.on('data', (str) => {
232
+ todo += str
222
233
  if (Buffer.byteLength(todo) === todo_len) {
223
234
  // we read everything
224
- const todo_struct = JSON.parse(todo);
225
- todo_struct.rcpt_to = todo_struct.rcpt_to.map(a => new Address (a));
226
- todo_struct.mail_from = new Address(todo_struct.mail_from);
227
- todo_struct.file = file;
228
- todo_struct.full_path = path.join(queue_dir, file);
229
- const parts = _qfile.parts(file);
230
- todo_struct.pid = (parts?.pid) || null;
231
- cb(null, todo_struct);
235
+ const todo_struct = JSON.parse(todo)
236
+ todo_struct.rcpt_to = todo_struct.rcpt_to.map((a) => new Address(a))
237
+ todo_struct.mail_from = new Address(todo_struct.mail_from)
238
+ todo_struct.file = file
239
+ todo_struct.full_path = path.join(queue_dir, file)
240
+ const parts = _qfile.parts(file)
241
+ todo_struct.pid = parts?.pid || null
242
+ cb(null, todo_struct)
232
243
  }
233
- });
244
+ })
234
245
  td_reader.on('end', () => {
235
246
  if (Buffer.byteLength(todo) !== todo_len) {
236
- console.error("Didn't find right amount of data in todo for file:", file);
237
- return cb();
247
+ console.error("Didn't find right amount of data in todo for file:", file)
248
+ return cb()
238
249
  }
239
- });
240
- });
250
+ })
251
+ })
241
252
  }
242
253
 
243
254
  exports.flush_queue = (domain, pid) => {
244
255
  if (domain) {
245
256
  exports.list_queue((err, qlist) => {
246
- if (err) return logger.error(exports, `Failed to load queue: ${err}`);
257
+ if (err) return logger.error(exports, `Failed to load queue: ${err}`)
247
258
  for (const todo of qlist) {
248
- if (todo.domain.toLowerCase() != domain.toLowerCase()) return;
249
- if (pid && todo.pid != pid) return;
259
+ if (todo.domain.toLowerCase() != domain.toLowerCase()) return
260
+ if (pid && todo.pid != pid) return
250
261
  // console.log("requeue: ", todo);
251
- delivery_queue.push(new HMailItem(todo.file, todo.full_path));
262
+ delivery_queue.push(new HMailItem(todo.file, todo.full_path))
252
263
  }
253
264
  })
254
- }
255
- else {
256
- temp_fail_queue.drain();
265
+ } else {
266
+ temp_fail_queue.drain()
257
267
  }
258
268
  }
259
269
 
260
- exports.load_pid_queue = pid => {
261
- logger.info(exports, `Loading queue for pid: ${pid}`);
262
- exports.load_queue(pid);
270
+ exports.load_pid_queue = (pid) => {
271
+ logger.info(exports, `Loading queue for pid: ${pid}`)
272
+ exports.load_queue(pid)
263
273
  }
264
274
 
265
275
  exports.ensure_queue_dir = () => {
266
276
  // this code is only run at start-up.
267
- if (fs.existsSync(queue_dir)) return;
277
+ if (fs.existsSync(queue_dir)) return
268
278
 
269
- logger.debug(exports, `Creating queue directory ${queue_dir}`);
279
+ logger.debug(exports, `Creating queue directory ${queue_dir}`)
270
280
  try {
271
- fs.mkdirSync(queue_dir, 493); // 493 == 0755
272
- const cfg = config.get('smtp.ini');
281
+ fs.mkdirSync(queue_dir, 493) // 493 == 0755
282
+ const cfg = config.get('smtp.ini')
273
283
  let uid
274
284
  let gid
275
- if (cfg.user) uid = child_process.execSync(`id -u ${cfg.user}`).toString().trim();
276
- if (cfg.group) gid = child_process.execSync(`id -g ${cfg.group}`).toString().trim();
285
+ if (cfg.user) uid = child_process.execSync(`id -u ${cfg.user}`).toString().trim()
286
+ if (cfg.group) gid = child_process.execSync(`id -g ${cfg.group}`).toString().trim()
277
287
  if (uid && gid) {
278
288
  fs.chown(queue_dir, uid, gid)
279
- }
280
- else if (uid) {
289
+ } else if (uid) {
281
290
  fs.chown(queue_dir, uid)
282
291
  }
283
- }
284
- catch (err) {
292
+ } catch (err) {
285
293
  if (err.code !== 'EEXIST') {
286
- logger.error(exports, `Error creating queue directory: ${err}`);
287
- throw err;
294
+ logger.error(exports, `Error creating queue directory: ${err}`)
295
+ throw err
288
296
  }
289
297
  }
290
298
  }
@@ -292,43 +300,42 @@ exports.ensure_queue_dir = () => {
292
300
  exports.delete_dot_files = () => {
293
301
  for (const file of fs.readdirSync(queue_dir)) {
294
302
  if (file.indexOf(_qfile.platformDOT) === 0) {
295
- logger.warn(exports, `Removing left over dot-file: ${file}`);
296
- return fs.unlinkSync(path.join(queue_dir, file));
303
+ logger.warn(exports, `Removing left over dot-file: ${file}`)
304
+ return fs.unlinkSync(path.join(queue_dir, file))
297
305
  }
298
306
  }
299
307
  }
300
308
 
301
- exports._add_hmail = hmail => {
309
+ exports._add_hmail = (hmail) => {
302
310
  if (hmail.next_process < exports.cur_time) {
303
- delivery_queue.push(hmail);
304
- }
305
- else {
311
+ delivery_queue.push(hmail)
312
+ } else {
306
313
  temp_fail_queue.add(hmail.filename, hmail.next_process - exports.cur_time, () => {
307
- delivery_queue.push(hmail);
308
- });
314
+ delivery_queue.push(hmail)
315
+ })
309
316
  }
310
317
  }
311
318
 
312
- exports.scan_queue_pids = cb => {
313
- const self = exports;
319
+ exports.scan_queue_pids = (cb) => {
320
+ const self = exports
314
321
 
315
322
  // Under cluster, this is called first by the master
316
- self.ensure_queue_dir();
317
- self.delete_dot_files();
323
+ self.ensure_queue_dir()
324
+ self.delete_dot_files()
318
325
 
319
326
  fs.readdir(queue_dir, (err, files) => {
320
327
  if (err) {
321
- logger.error(exports, `Failed to load queue directory (${queue_dir}): ${err}`);
322
- return cb(err);
328
+ logger.error(exports, `Failed to load queue directory (${queue_dir}): ${err}`)
329
+ return cb(err)
323
330
  }
324
331
 
325
- const pids = {};
332
+ const pids = {}
326
333
 
327
334
  for (const file of files) {
328
- const parts = self.read_parts(file);
329
- if (parts) pids[parts.pid] = true;
335
+ const parts = self.read_parts(file)
336
+ if (parts) pids[parts.pid] = true
330
337
  }
331
338
 
332
- return cb(null, Object.keys(pids));
333
- });
339
+ return cb(null, Object.keys(pids))
340
+ })
334
341
  }
@@ -1,88 +1,86 @@
1
- 'use strict';
1
+ 'use strict'
2
2
 
3
- const logger = require('../logger');
3
+ const logger = require('../logger')
4
4
 
5
5
  class TQTimer {
6
-
7
- constructor (id, fire_time, cb) {
8
- this.id = id;
9
- this.fire_time = fire_time;
10
- this.cb = cb;
6
+ constructor(id, fire_time, cb) {
7
+ this.id = id
8
+ this.fire_time = fire_time
9
+ this.cb = cb
11
10
  }
12
11
 
13
- cancel () {
14
- this.cb = null;
12
+ cancel() {
13
+ this.cb = null
15
14
  }
16
-
17
15
  }
18
16
 
19
17
  class TimerQueue {
20
-
21
- constructor (interval = 1000) {
18
+ constructor(interval = 1000) {
22
19
  this.name = 'outbound/timer_queue'
23
- this.queue = [];
24
- this.interval_timer = setInterval(() => { this.fire(); }, interval);
20
+ this.queue = []
21
+ this.interval_timer = setInterval(() => {
22
+ this.fire()
23
+ }, interval)
25
24
  this.interval_timer.unref() // allow server to exit
26
25
  }
27
26
 
28
- add (id, ms, cb) {
29
- const fire_time = Date.now() + ms;
27
+ add(id, ms, cb) {
28
+ const fire_time = Date.now() + ms
30
29
 
31
- const timer = new TQTimer(id, fire_time, cb);
30
+ const timer = new TQTimer(id, fire_time, cb)
32
31
 
33
- if ((this.queue.length === 0) ||
34
- fire_time >= this.queue[this.queue.length - 1].fire_time) {
35
- this.queue.push(timer);
36
- return timer;
32
+ if (this.queue.length === 0 || fire_time >= this.queue[this.queue.length - 1].fire_time) {
33
+ this.queue.push(timer)
34
+ return timer
37
35
  }
38
36
 
39
- for (let i=0; i < this.queue.length; i++) {
37
+ for (let i = 0; i < this.queue.length; i++) {
40
38
  if (this.queue[i].fire_time > fire_time) {
41
- this.queue.splice(i, 0, timer);
42
- return timer;
39
+ this.queue.splice(i, 0, timer)
40
+ return timer
43
41
  }
44
42
  }
45
43
 
46
- throw "Should never get here";
44
+ throw 'Should never get here'
47
45
  }
48
46
 
49
- discard (id) {
47
+ discard(id) {
50
48
  for (let i = 0; i < this.queue.length; i++) {
51
49
  if (this.queue[i].id === id) {
52
- this.queue[i].cancel();
53
- return this.queue.splice(i, 1);
50
+ this.queue[i].cancel()
51
+ return this.queue.splice(i, 1)
54
52
  }
55
53
  }
56
54
 
57
- throw `${id} not found`;
55
+ throw `${id} not found`
58
56
  }
59
57
 
60
- fire () {
61
- if (this.queue.length === 0) return;
58
+ fire() {
59
+ if (this.queue.length === 0) return
62
60
 
63
- const now = Date.now();
61
+ const now = Date.now()
64
62
 
65
63
  while (this.queue.length && this.queue[0].fire_time <= now) {
66
- const to_run = this.queue.shift();
67
- if (to_run.cb) to_run.cb();
64
+ const to_run = this.queue.shift()
65
+ if (to_run.cb) to_run.cb()
68
66
  }
69
67
  }
70
68
 
71
- length () {
72
- return this.queue.length;
69
+ length() {
70
+ return this.queue.length
73
71
  }
74
72
 
75
- drain () {
76
- logger.debug(this, `Draining ${this.queue.length} items from the queue`);
73
+ drain() {
74
+ logger.debug(this, `Draining ${this.queue.length} items from the queue`)
77
75
  while (this.queue.length) {
78
- const to_run = this.queue.shift();
79
- if (to_run.cb) to_run.cb();
76
+ const to_run = this.queue.shift()
77
+ if (to_run.cb) to_run.cb()
80
78
  }
81
79
  }
82
80
 
83
- shutdown () {
84
- clearInterval(this.interval_timer);
81
+ shutdown() {
82
+ clearInterval(this.interval_timer)
85
83
  }
86
84
  }
87
85
 
88
- module.exports = TimerQueue;
86
+ module.exports = TimerQueue