Haraka 3.1.0 → 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 +69 -50
  4. package/Plugins.md +3 -1
  5. package/README.md +1 -1
  6. package/bin/haraka +475 -478
  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 +34 -27
  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 +38 -33
  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/connection.js CHANGED
@@ -1,28 +1,28 @@
1
- 'use strict';
1
+ 'use strict'
2
2
  // a single connection
3
3
 
4
- const dns = require('node:dns');
5
- const net = require('node:net');
6
- const os = require('node:os');
4
+ const dns = require('node:dns')
5
+ const net = require('node:net')
6
+ const os = require('node:os')
7
7
 
8
8
  // npm libs
9
- const ipaddr = require('ipaddr.js');
10
- const config = require('haraka-config');
11
- const constants = require('haraka-constants');
12
- const net_utils = require('haraka-net-utils');
13
- const Notes = require('haraka-notes');
14
- const utils = require('haraka-utils');
15
- const { Address } = require('address-rfc2821');
16
- const ResultStore = require('haraka-results');
9
+ const ipaddr = require('ipaddr.js')
10
+ const config = require('haraka-config')
11
+ const constants = require('haraka-constants')
12
+ const net_utils = require('haraka-net-utils')
13
+ const Notes = require('haraka-notes')
14
+ const utils = require('haraka-utils')
15
+ const { Address } = require('address-rfc2821')
16
+ const ResultStore = require('haraka-results')
17
17
 
18
18
  // Haraka libs
19
- const logger = require('./logger');
20
- const trans = require('./transaction');
21
- const plugins = require('./plugins');
22
- const rfc1869 = require('./rfc1869');
23
- const outbound = require('./outbound');
19
+ const logger = require('./logger')
20
+ const trans = require('./transaction')
21
+ const plugins = require('./plugins')
22
+ const rfc1869 = require('./rfc1869')
23
+ const outbound = require('./outbound')
24
24
 
25
- const states = constants.connection.state;
25
+ const states = constants.connection.state
26
26
 
27
27
  const cfg = config.get('connection.ini', {
28
28
  booleans: [
@@ -31,402 +31,395 @@ const cfg = config.get('connection.ini', {
31
31
  '+headers.add_received',
32
32
  '+headers.show_version',
33
33
  '+headers.clean_auth_results',
34
- ]
35
- });
34
+ ],
35
+ })
36
36
 
37
- const haproxy_hosts_ipv4 = [];
38
- const haproxy_hosts_ipv6 = [];
37
+ const haproxy_hosts_ipv4 = []
38
+ const haproxy_hosts_ipv6 = []
39
39
 
40
40
  for (const ip of cfg.haproxy.hosts) {
41
- if (!ip) continue;
41
+ if (!ip) continue
42
42
  if (net.isIPv6(ip.split('/')[0])) {
43
- haproxy_hosts_ipv6.push([ipaddr.IPv6.parse(ip.split('/')[0]), parseInt(ip.split('/')[1] || 64)]);
44
- }
45
- else {
46
- haproxy_hosts_ipv4.push([ipaddr.IPv4.parse(ip.split('/')[0]), parseInt(ip.split('/')[1] || 32)]);
43
+ haproxy_hosts_ipv6.push([ipaddr.IPv6.parse(ip.split('/')[0]), parseInt(ip.split('/')[1] || 64)])
44
+ } else {
45
+ haproxy_hosts_ipv4.push([ipaddr.IPv4.parse(ip.split('/')[0]), parseInt(ip.split('/')[1] || 32)])
47
46
  }
48
47
  }
49
48
 
50
49
  class Connection {
51
- constructor (client, server, smtp_cfg) {
52
- this.client = client;
53
- this.server = server;
50
+ constructor(client, server, smtp_cfg) {
51
+ this.client = client
52
+ this.server = server
54
53
 
55
54
  this.local = {
56
55
  ip: null,
57
56
  port: null,
58
57
  host: net_utils.get_primary_host_name(),
59
58
  info: 'Haraka',
60
- };
59
+ }
61
60
  this.remote = {
62
- ip: null,
61
+ ip: null,
63
62
  port: null,
64
63
  host: null,
65
64
  info: null,
66
65
  closed: false,
67
66
  is_private: false,
68
67
  is_local: false,
69
- };
68
+ }
70
69
  this.hello = {
71
70
  host: null,
72
71
  verb: null,
73
- };
72
+ }
74
73
  this.tls = {
75
74
  enabled: false,
76
75
  advertised: false,
77
76
  verified: false,
78
77
  cipher: {},
79
- };
78
+ }
80
79
  this.proxy = {
81
80
  allowed: false,
82
81
  ip: null,
83
82
  type: null,
84
83
  timer: null,
85
- };
86
- this.set('tls', 'enabled', (!!server.has_tls));
87
-
88
- this.current_data = null;
89
- this.current_line = null;
90
- this.state = states.PAUSE;
91
- this.encoding = 'utf8';
92
- this.prev_state = null;
93
- this.loop_code = null;
94
- this.loop_msg = null;
95
- this.uuid = utils.uuid();
96
- this.notes = new Notes();
97
- this.transaction = null;
98
- this.tran_count = 0;
99
- this.capabilities = null;
100
- this.early_talker = false;
101
- this.pipelining = false;
102
- this._relaying = false;
103
- this.esmtp = false;
104
- this.last_response = null;
105
- this.hooks_to_run = [];
106
- this.start_time = Date.now();
107
- this.last_reject = '';
108
- this.totalbytes = 0;
84
+ }
85
+ this.set('tls', 'enabled', !!server.has_tls)
86
+
87
+ this.current_data = null
88
+ this.current_line = null
89
+ this.state = states.PAUSE
90
+ this.encoding = 'utf8'
91
+ this.prev_state = null
92
+ this.loop_code = null
93
+ this.loop_msg = null
94
+ this.uuid = utils.uuid()
95
+ this.notes = new Notes()
96
+ this.transaction = null
97
+ this.tran_count = 0
98
+ this.capabilities = null
99
+ this.early_talker = false
100
+ this.pipelining = false
101
+ this._relaying = false
102
+ this.esmtp = false
103
+ this.last_response = null
104
+ this.hooks_to_run = []
105
+ this.start_time = Date.now()
106
+ this.last_reject = ''
107
+ this.totalbytes = 0
109
108
  this.rcpt_count = {
110
- accept: 0,
109
+ accept: 0,
111
110
  tempfail: 0,
112
- reject: 0,
113
- };
111
+ reject: 0,
112
+ }
114
113
  this.msg_count = {
115
- accept: 0,
114
+ accept: 0,
116
115
  tempfail: 0,
117
- reject: 0,
118
- };
119
- this.results = new ResultStore(this);
120
- this.errors = 0;
121
- this.last_rcpt_msg = null;
122
- this.hook = null;
116
+ reject: 0,
117
+ }
118
+ this.results = new ResultStore(this)
119
+ this.errors = 0
120
+ this.last_rcpt_msg = null
121
+ this.hook = null
123
122
  if (cfg.headers.show_version) {
124
- this.local.info += `/${utils.getVersion(__dirname)}`;
123
+ this.local.info += `/${utils.getVersion(__dirname)}`
125
124
  }
126
- Connection.setupClient(this);
125
+ Connection.setupClient(this)
127
126
  }
128
- static setupClient (self) {
129
- const ip = self.client.remoteAddress;
127
+ static setupClient(self) {
128
+ const ip = self.client.remoteAddress
130
129
  if (!ip) {
131
- self.logdebug('setupClient got no IP address for this connection!');
132
- self.client.destroy();
133
- return;
130
+ self.logdebug('setupClient got no IP address for this connection!')
131
+ self.client.destroy()
132
+ return
134
133
  }
135
134
 
136
- const local_addr = self.server.address();
137
- self.set('local', 'ip', ipaddr.process(self.client.localAddress || local_addr.address).toString());
138
- self.set('local', 'port', (self.client.localPort || local_addr.port));
139
- self.results.add({name: 'local'}, self.local);
135
+ const local_addr = self.server.address()
136
+ self.set('local', 'ip', ipaddr.process(self.client.localAddress || local_addr.address).toString())
137
+ self.set('local', 'port', self.client.localPort || local_addr.port)
138
+ self.results.add({ name: 'local' }, self.local)
140
139
 
141
- self.set('remote', 'ip', ipaddr.process(ip).toString());
142
- self.set('remote', 'port', self.client.remotePort);
143
- self.results.add({name: 'remote'}, self.remote);
140
+ self.set('remote', 'ip', ipaddr.process(ip).toString())
141
+ self.set('remote', 'port', self.client.remotePort)
142
+ self.results.add({ name: 'remote' }, self.remote)
144
143
 
145
- self.lognotice( 'connect', {
144
+ self.lognotice('connect', {
146
145
  ip: self.remote.ip,
147
146
  port: self.remote.port,
148
147
  local_ip: self.local.ip,
149
- local_port: self.local.port
150
- });
148
+ local_port: self.local.port,
149
+ })
151
150
 
152
- if (!self.client.on) return;
151
+ if (!self.client.on) return
153
152
 
154
- const log_data = {ip: self.remote.ip}
153
+ const log_data = { ip: self.remote.ip }
155
154
  if (self.remote.host) log_data.host = self.remote.host
156
155
 
157
156
  self.client.on('end', () => {
158
- if (self.state >= states.DISCONNECTING) return;
159
- self.remote.closed = true;
160
- self.loginfo('client half closed connection', log_data);
161
- self.fail();
162
- });
163
-
164
- self.client.on('close', has_error => {
165
- if (self.state >= states.DISCONNECTING) return;
166
- self.remote.closed = true;
167
- self.loginfo('client dropped connection', log_data);
168
- self.fail();
169
- });
170
-
171
- self.client.on('error', err => {
172
- if (self.state >= states.DISCONNECTING) return;
173
- self.loginfo(`client connection error: ${err}`, log_data);
174
- self.fail();
175
- });
157
+ if (self.state >= states.DISCONNECTING) return
158
+ self.remote.closed = true
159
+ self.loginfo('client half closed connection', log_data)
160
+ self.fail()
161
+ })
162
+
163
+ self.client.on('close', (has_error) => {
164
+ if (self.state >= states.DISCONNECTING) return
165
+ self.remote.closed = true
166
+ self.loginfo('client dropped connection', log_data)
167
+ self.fail()
168
+ })
169
+
170
+ self.client.on('error', (err) => {
171
+ if (self.state >= states.DISCONNECTING) return
172
+ self.loginfo(`client connection error: ${err}`, log_data)
173
+ self.fail()
174
+ })
176
175
 
177
176
  self.client.on('timeout', () => {
178
177
  // FIN has sent, when timeout just destroy socket
179
178
  if (self.state >= states.DISCONNECTED) {
180
- self.client.destroy();
179
+ self.client.destroy()
181
180
  self.loginfo(`timeout, destroy socket (state:${self.state})`)
182
- return;
181
+ return
183
182
  }
184
- if (self.state >= states.DISCONNECTING) return;
183
+ if (self.state >= states.DISCONNECTING) return
185
184
  self.respond(421, 'timeout', () => {
186
- self.fail('client connection timed out', log_data);
187
- });
188
- });
189
-
190
- self.client.on('data', data => {
191
- self.process_data(data);
192
- });
193
-
194
- const ha_list = net.isIPv6(self.remote.ip) ? haproxy_hosts_ipv6 : haproxy_hosts_ipv4;
195
- if (ha_list.some((element, index, array) => {
196
- return ipaddr.parse(self.remote.ip).match(element[0], element[1]);
197
- })) {
198
- self.proxy.allowed = true;
185
+ self.fail('client connection timed out', log_data)
186
+ })
187
+ })
188
+
189
+ self.client.on('data', (data) => {
190
+ self.process_data(data)
191
+ })
192
+
193
+ const ha_list = net.isIPv6(self.remote.ip) ? haproxy_hosts_ipv6 : haproxy_hosts_ipv4
194
+ if (
195
+ ha_list.some((element, index, array) => {
196
+ return ipaddr.parse(self.remote.ip).match(element[0], element[1])
197
+ })
198
+ ) {
199
+ self.proxy.allowed = true
199
200
  // Wait for PROXY command
200
201
  self.proxy.timer = setTimeout(() => {
201
- self.respond(421, 'PROXY timeout',() => {
202
- self.disconnect();
203
- });
204
- }, 30 * 1000);
205
- }
206
- else {
207
- plugins.run_hooks('connect_init', self);
202
+ self.respond(421, 'PROXY timeout', () => {
203
+ self.disconnect()
204
+ })
205
+ }, 30 * 1000)
206
+ } else {
207
+ plugins.run_hooks('connect_init', self)
208
208
  }
209
209
  }
210
- setTLS (obj) {
211
- this.set('hello', 'host', undefined);
212
- this.set('tls', 'enabled', true);
213
- for (const t of ['cipher','verified','verifyError','peerCertificate']) {
214
- if (obj[t] === undefined) continue;
215
- this.set('tls', t, obj[t]);
210
+ setTLS(obj) {
211
+ this.set('hello', 'host', undefined)
212
+ this.set('tls', 'enabled', true)
213
+ for (const t of ['cipher', 'verified', 'verifyError', 'peerCertificate']) {
214
+ if (obj[t] === undefined) continue
215
+ this.set('tls', t, obj[t])
216
216
  }
217
217
  // prior to 2017-07, authorized and verified were both used. Verified
218
218
  // seems to be the more common and has the property updated in the
219
219
  // tls object. However, authorized has been up-to-date in the notes. Store
220
220
  // in both, for backwards compatibility.
221
221
  this.notes.tls = {
222
- authorized: obj.verified, // legacy name
222
+ authorized: obj.verified, // legacy name
223
223
  authorizationError: obj.verifyError,
224
224
  cipher: obj.cipher,
225
225
  peerCertificate: obj.peerCertificate,
226
226
  }
227
227
  }
228
- set (prop_str, val) {
228
+ set(prop_str, val) {
229
229
  if (arguments.length === 3) {
230
- prop_str = `${arguments[0]}.${arguments[1]}`;
231
- val = arguments[2];
230
+ prop_str = `${arguments[0]}.${arguments[1]}`
231
+ val = arguments[2]
232
232
  }
233
233
 
234
- const path_parts = prop_str.split('.');
235
- let loc = this;
236
- for (let i=0; i < path_parts.length; i++) {
237
- const part = path_parts[i];
238
- if (part === "__proto__" || part === "constructor") continue;
234
+ const path_parts = prop_str.split('.')
235
+ let loc = this
236
+ for (let i = 0; i < path_parts.length; i++) {
237
+ const part = path_parts[i]
238
+ if (part === '__proto__' || part === 'constructor') continue
239
239
 
240
240
  // while another part remains
241
- if (i < (path_parts.length - 1)) {
242
- if (loc[part] === undefined) loc[part] = {}; // initialize
243
- loc = loc[part]; // descend
244
- continue;
241
+ if (i < path_parts.length - 1) {
242
+ if (loc[part] === undefined) loc[part] = {} // initialize
243
+ loc = loc[part] // descend
244
+ continue
245
245
  }
246
246
 
247
247
  // last part, so assign the value
248
- loc[part] = val;
248
+ loc[part] = val
249
249
  }
250
250
 
251
251
  // Set is_private, is_local automatically when remote.ip is set
252
252
  if (prop_str === 'remote.ip') {
253
- this.set('remote.is_local', net_utils.is_local_ip(this.remote.ip));
253
+ this.set('remote.is_local', net_utils.is_local_ip(this.remote.ip))
254
254
  if (this.remote.is_local) {
255
- this.set('remote.is_private', true);
256
- }
257
- else {
258
- this.set('remote.is_private', net_utils.is_private_ip(this.remote.ip));
255
+ this.set('remote.is_private', true)
256
+ } else {
257
+ this.set('remote.is_private', net_utils.is_private_ip(this.remote.ip))
259
258
  }
260
259
  }
261
260
  }
262
- get (prop_str) {
261
+ get(prop_str) {
263
262
  return prop_str.split('.').reduce((prev, curr) => {
264
263
  return prev ? prev[curr] : undefined
265
264
  }, this)
266
265
  }
267
- set relaying (val) {
266
+ set relaying(val) {
268
267
  if (this.transaction) {
269
- this.transaction._relaying = val;
270
- }
271
- else {
272
- this._relaying = val;
268
+ this.transaction._relaying = val
269
+ } else {
270
+ this._relaying = val
273
271
  }
274
272
  }
275
- get relaying () {
276
- if (this.transaction && '_relaying' in this.transaction) return this.transaction._relaying;
277
- return this._relaying;
273
+ get relaying() {
274
+ if (this.transaction && '_relaying' in this.transaction) return this.transaction._relaying
275
+ return this._relaying
278
276
  }
279
- process_line (line) {
280
-
277
+ process_line(line) {
281
278
  if (this.state >= states.DISCONNECTING) {
282
279
  if (logger.would_log(logger.LOGPROTOCOL)) {
283
- this.logprotocol(`C: (after-disconnect): ${this.current_line}`, {'state': this.state});
280
+ this.logprotocol(`C: (after-disconnect): ${this.current_line}`, {
281
+ state: this.state,
282
+ })
284
283
  }
285
- this.loginfo(`data after disconnect from ${this.remote.ip}`);
286
- return;
284
+ this.loginfo(`data after disconnect from ${this.remote.ip}`)
285
+ return
287
286
  }
288
287
 
289
288
  if (this.state === states.DATA) {
290
289
  if (logger.would_log(logger.LOGDATA)) {
291
- this.logdata(`C: ${line}`);
290
+ this.logdata(`C: ${line}`)
292
291
  }
293
- this.accumulate_data(line);
294
- return;
292
+ this.accumulate_data(line)
293
+ return
295
294
  }
296
295
 
297
- this.current_line = line.toString(this.encoding).replace(/\r?\n/, '');
296
+ this.current_line = line.toString(this.encoding).replace(/\r?\n/, '')
298
297
  if (logger.would_log(logger.LOGPROTOCOL)) {
299
- this.logprotocol(`C: ${this.current_line}`, {'state': this.state});
298
+ this.logprotocol(`C: ${this.current_line}`, { state: this.state })
300
299
  }
301
300
 
302
301
  // Check for non-ASCII characters
303
302
  /* eslint no-control-regex: 0 */
304
303
  if (/[^\x00-\x7F]/.test(this.current_line)) {
305
304
  // See if this is a TLS handshake
306
- const buf = Buffer.from(this.current_line.substr(0,3), 'binary');
307
- if (buf[0] === 0x16 && buf[1] === 0x03 &&
308
- (buf[2] === 0x00 || buf[2] === 0x01) // SSLv3/TLS1.x format
305
+ const buf = Buffer.from(this.current_line.substr(0, 3), 'binary')
306
+ if (
307
+ buf[0] === 0x16 &&
308
+ buf[1] === 0x03 &&
309
+ (buf[2] === 0x00 || buf[2] === 0x01) // SSLv3/TLS1.x format
309
310
  ) {
310
311
  // Nuke the current input buffer to prevent processing further input
311
- this.current_data = null;
312
- this.respond(501, 'SSL attempted over a non-SSL socket');
313
- this.disconnect();
314
- return;
315
- }
316
- else if (this.hello.verb == 'HELO') {
317
- return this.respond(501, 'Syntax error (8-bit characters not allowed)');
312
+ this.current_data = null
313
+ this.respond(501, 'SSL attempted over a non-SSL socket')
314
+ this.disconnect()
315
+ return
316
+ } else if (this.hello.verb == 'HELO') {
317
+ return this.respond(501, 'Syntax error (8-bit characters not allowed)')
318
318
  }
319
319
  }
320
320
 
321
321
  if (this.state === states.CMD) {
322
- this.state = states.PAUSE_SMTP;
323
- const matches = /^([^ ]*)( +(.*))?$/.exec(this.current_line);
322
+ this.state = states.PAUSE_SMTP
323
+ const matches = /^([^ ]*)( +(.*))?$/.exec(this.current_line)
324
324
  if (!matches) {
325
- return plugins.run_hooks('unrecognized_command',
326
- this, [this.current_line]);
325
+ return plugins.run_hooks('unrecognized_command', this, [this.current_line])
327
326
  }
328
- const cmd = matches[1];
329
- const method = `cmd_${cmd.toLowerCase()}`;
330
- const remaining = matches[3] || '';
327
+ const cmd = matches[1]
328
+ const method = `cmd_${cmd.toLowerCase()}`
329
+ const remaining = matches[3] || ''
331
330
  if (this[method]) {
332
331
  try {
333
- this[method](remaining);
334
- }
335
- catch (err) {
332
+ this[method](remaining)
333
+ } catch (err) {
336
334
  if (err.stack) {
337
- this.logerror(`${method} failed: ${err}`);
338
- err.stack.split("\n").forEach(this.logerror);
339
- }
340
- else {
341
- this.logerror(`${method} failed: ${err}`);
335
+ this.logerror(`${method} failed: ${err}`)
336
+ err.stack.split('\n').forEach(this.logerror)
337
+ } else {
338
+ this.logerror(`${method} failed: ${err}`)
342
339
  }
343
- this.respond(421, "Internal Server Error", () => {
344
- this.disconnect();
345
- });
340
+ this.respond(421, 'Internal Server Error', () => {
341
+ this.disconnect()
342
+ })
346
343
  }
347
- }
348
- else {
344
+ } else {
349
345
  // unrecognized command
350
- plugins.run_hooks('unrecognized_command', this, [ cmd, remaining ]);
346
+ plugins.run_hooks('unrecognized_command', this, [cmd, remaining])
351
347
  }
352
- }
353
- else if (this.state === states.LOOP) {
348
+ } else if (this.state === states.LOOP) {
354
349
  // Allow QUIT
355
350
  if (this.current_line.toUpperCase() === 'QUIT') {
356
- this.cmd_quit();
351
+ this.cmd_quit()
352
+ } else {
353
+ this.respond(this.loop_code, this.loop_msg)
357
354
  }
358
- else {
359
- this.respond(this.loop_code, this.loop_msg);
360
- }
361
- }
362
- else {
363
- throw new Error(`unknown state ${this.state}`);
355
+ } else {
356
+ throw new Error(`unknown state ${this.state}`)
364
357
  }
365
358
  }
366
- process_data (data) {
359
+ process_data(data) {
367
360
  if (this.state >= states.DISCONNECTING) {
368
- this.loginfo(`data after disconnect from ${this.remote.ip}`);
369
- return;
361
+ this.loginfo(`data after disconnect from ${this.remote.ip}`)
362
+ return
370
363
  }
371
364
 
372
365
  if (!this.current_data || !this.current_data.length) {
373
- this.current_data = data;
374
- }
375
- else {
366
+ this.current_data = data
367
+ } else {
376
368
  // Data left over in buffer
377
- const buf = Buffer.concat(
378
- [ this.current_data, data ],
379
- (this.current_data.length + data.length)
380
- );
381
- this.current_data = buf;
369
+ const buf = Buffer.concat([this.current_data, data], this.current_data.length + data.length)
370
+ this.current_data = buf
382
371
  }
383
372
 
384
- this._process_data();
373
+ this._process_data()
385
374
  }
386
- _process_data () {
375
+ _process_data() {
387
376
  // We *must* detect disconnected connections here as the state
388
377
  // only transitions to states.CMD in the respond function below.
389
378
  // Otherwise if multiple commands are pipelined and then the
390
379
  // connection is dropped; we'll end up in the function forever.
391
- if (this.state >= states.DISCONNECTING) return;
380
+ if (this.state >= states.DISCONNECTING) return
392
381
 
393
- let maxlength;
382
+ let maxlength
394
383
  if (this.state === states.PAUSE_DATA || this.state === states.DATA) {
395
- maxlength = cfg.max.data_line_length;
396
- }
397
- else {
398
- maxlength = cfg.max.line_length;
384
+ maxlength = cfg.max.data_line_length
385
+ } else {
386
+ maxlength = cfg.max.line_length
399
387
  }
400
388
 
401
- let offset;
402
- while (this.current_data && ((offset = utils.indexOfLF(this.current_data, maxlength)) !== -1)) {
389
+ let offset
390
+ while (this.current_data && (offset = utils.indexOfLF(this.current_data, maxlength)) !== -1) {
403
391
  if (this.state === states.PAUSE_DATA) {
404
- return;
392
+ return
405
393
  }
406
- let this_line = this.current_data.slice(0, offset+1);
394
+ let this_line = this.current_data.slice(0, offset + 1)
407
395
  // Hack: bypass this code to allow HAProxy's PROXY extension
408
- const proxyStart = this.proxy.allowed && /^PROXY /.test(this_line);
396
+ const proxyStart = this.proxy.allowed && /^PROXY /.test(this_line)
409
397
  if (this.state === states.PAUSE && proxyStart) {
410
- if (this.proxy.timer) clearTimeout(this.proxy.timer);
411
- this.state = states.CMD;
412
- this.current_data = this.current_data.slice(this_line.length);
413
- this.process_line(this_line);
398
+ if (this.proxy.timer) clearTimeout(this.proxy.timer)
399
+ this.state = states.CMD
400
+ this.current_data = this.current_data.slice(this_line.length)
401
+ this.process_line(this_line)
414
402
  }
415
403
  // Detect early_talker but allow PIPELINING extension (ESMTP)
416
404
  else if ((this.state === states.PAUSE || this.state === states.PAUSE_SMTP) && !this.esmtp) {
417
405
  // Allow EHLO/HELO to be pipelined with PROXY
418
- if (this.proxy.allowed && /^(?:EH|HE)LO /i.test(this_line)) return;
406
+ if (this.proxy.allowed && /^(?:EH|HE)LO /i.test(this_line)) return
419
407
  if (!this.early_talker) {
420
- this_line = this_line.toString().replace(/\r?\n/,'');
421
- this.logdebug('[early_talker]', { state: this.state, esmtp: this.esmtp, line: this_line });
408
+ this_line = this_line.toString().replace(/\r?\n/, '')
409
+ this.logdebug('[early_talker]', {
410
+ state: this.state,
411
+ esmtp: this.esmtp,
412
+ line: this_line,
413
+ })
422
414
  }
423
- this.early_talker = true;
424
- setImmediate(() => { this._process_data() });
425
- break;
426
- }
427
- else if ((this.state === states.PAUSE || this.state === states.PAUSE_SMTP) && this.esmtp) {
428
- let valid = true;
429
- const cmd = this_line.toString('ascii').slice(0,4).toUpperCase();
415
+ this.early_talker = true
416
+ setImmediate(() => {
417
+ this._process_data()
418
+ })
419
+ break
420
+ } else if ((this.state === states.PAUSE || this.state === states.PAUSE_SMTP) && this.esmtp) {
421
+ let valid = true
422
+ const cmd = this_line.toString('ascii').slice(0, 4).toUpperCase()
430
423
  switch (cmd) {
431
424
  case 'RSET':
432
425
  case 'MAIL':
@@ -435,13 +428,13 @@ class Connection {
435
428
  case 'SAML':
436
429
  case 'RCPT':
437
430
  // These can be anywhere in the group
438
- break;
431
+ break
439
432
  default:
440
433
  // Anything else *MUST* be the last command in the group
441
434
  if (this_line.length !== this.current_data.length) {
442
- valid = false;
435
+ valid = false
443
436
  }
444
- break;
437
+ break
445
438
  }
446
439
  if (valid) {
447
440
  // Valid PIPELINING
@@ -451,740 +444,742 @@ class Connection {
451
444
  // has reset the state back to states.CMD and this
452
445
  // ensures that we only process one command at a
453
446
  // time.
454
- this.pipelining = true;
455
- this.logdebug(`pipeline: ${this_line}`);
456
- }
457
- else {
447
+ this.pipelining = true
448
+ this.logdebug(`pipeline: ${this_line}`)
449
+ } else {
458
450
  // Invalid pipeline sequence
459
451
  // Treat this as early talker
460
452
  if (!this.early_talker) {
461
- this.logdebug('[early_talker]', { state: this.state, esmtp: this.esmtp, line: this_line });
453
+ this.logdebug('[early_talker]', {
454
+ state: this.state,
455
+ esmtp: this.esmtp,
456
+ line: this_line,
457
+ })
462
458
  }
463
- this.early_talker = true;
464
- setImmediate(() => { this._process_data() });
459
+ this.early_talker = true
460
+ setImmediate(() => {
461
+ this._process_data()
462
+ })
465
463
  }
466
- break;
467
- }
468
- else {
469
- this.current_data = this.current_data.slice(this_line.length);
470
- this.process_line(this_line);
464
+ break
465
+ } else {
466
+ this.current_data = this.current_data.slice(this_line.length)
467
+ this.process_line(this_line)
471
468
  }
472
469
  }
473
470
 
474
- if (this.current_data && (this.current_data.length > maxlength) &&
475
- (utils.indexOfLF(this.current_data, maxlength) === -1)) {
471
+ if (
472
+ this.current_data &&
473
+ this.current_data.length > maxlength &&
474
+ utils.indexOfLF(this.current_data, maxlength) === -1
475
+ ) {
476
476
  if (this.state !== states.DATA && this.state !== states.PAUSE_DATA) {
477
477
  // In command mode, reject:
478
- this.client.pause();
479
- this.current_data = null;
480
- return this.respond(521, "Command line too long", () => {
481
- this.disconnect();
482
- });
483
- }
484
- else {
485
- this.loginfo(`DATA line length (${this.current_data.length}) exceeds limit of ${maxlength} bytes`);
486
- this.transaction.notes.data_line_length_exceeded = true;
487
- const b = Buffer.concat([
488
- this.current_data.slice(0, maxlength - 2),
489
- Buffer.from("\r\n ", 'utf8'),
490
- this.current_data.slice(maxlength - 2)
491
- ], this.current_data.length + 3);
492
- this.current_data = b;
493
- return this._process_data();
478
+ this.client.pause()
479
+ this.current_data = null
480
+ return this.respond(521, 'Command line too long', () => {
481
+ this.disconnect()
482
+ })
483
+ } else {
484
+ this.loginfo(`DATA line length (${this.current_data.length}) exceeds limit of ${maxlength} bytes`)
485
+ this.transaction.notes.data_line_length_exceeded = true
486
+ const b = Buffer.concat(
487
+ [
488
+ this.current_data.slice(0, maxlength - 2),
489
+ Buffer.from('\r\n ', 'utf8'),
490
+ this.current_data.slice(maxlength - 2),
491
+ ],
492
+ this.current_data.length + 3,
493
+ )
494
+ this.current_data = b
495
+ return this._process_data()
494
496
  }
495
497
  }
496
498
  }
497
- respond (code, msg, func) {
498
- let uuid = '';
499
- let messages;
499
+ respond(code, msg, func) {
500
+ let uuid = ''
501
+ let messages
500
502
 
501
503
  if (this.state === states.DISCONNECTED) {
502
- if (func) func();
503
- return;
504
+ if (func) func()
505
+ return
504
506
  }
505
507
  // Check to see if DSN object was passed in
506
508
  if (typeof msg === 'object' && msg.constructor.name === 'DSN') {
507
509
  // Override
508
- code = msg.code;
509
- msg = msg.reply;
510
+ code = msg.code
511
+ msg = msg.reply
510
512
  }
511
513
 
512
514
  if (!Array.isArray(msg)) {
513
- messages = msg.toString().split(/\n/);
514
- }
515
- else {
516
- messages = msg.slice();
515
+ messages = msg.toString().split(/\n/)
516
+ } else {
517
+ messages = msg.slice()
517
518
  }
518
519
  messages = messages.filter((msg2) => {
519
- return /\S/.test(msg2);
520
- });
520
+ return /\S/.test(msg2)
521
+ })
521
522
 
522
523
  // Multiline AUTH PLAIN as in RFC-4954 page 8.
523
524
  if (code === 334 && !messages.length) {
524
- messages = [' '];
525
+ messages = [' ']
525
526
  }
526
527
 
527
528
  if (code >= 400) {
528
- this.last_reject = `${code} ${messages.join(' ')}`;
529
+ this.last_reject = `${code} ${messages.join(' ')}`
529
530
  if (cfg.uuid.deny_chars) {
530
- uuid = (this.transaction || this).uuid;
531
+ uuid = (this.transaction || this).uuid
531
532
  if (cfg.uuid.deny_chars > 1) {
532
- uuid = uuid.substr(0, cfg.uuid.deny_chars);
533
+ uuid = uuid.substr(0, cfg.uuid.deny_chars)
533
534
  }
534
535
  }
535
536
  }
536
537
 
537
- let mess;
538
- let buf = '';
539
- const hostname = os.hostname().split('.').shift();
540
- const _uuid = uuid ? `[${uuid}@${hostname}] ` : '';
538
+ let mess
539
+ let buf = ''
540
+ const hostname = os.hostname().split('.').shift()
541
+ const _uuid = uuid ? `[${uuid}@${hostname}] ` : ''
541
542
 
542
543
  while ((mess = messages.shift())) {
543
- const line = `${code}${(messages.length ? "-" : " ")}${_uuid}${mess}`;
544
- this.logprotocol(`S: ${line}`);
545
- buf = `${buf}${line}\r\n`;
544
+ const line = `${code}${messages.length ? '-' : ' '}${_uuid}${mess}`
545
+ this.logprotocol(`S: ${line}`)
546
+ buf = `${buf}${line}\r\n`
546
547
  }
547
548
 
548
- if (this.client.write === undefined) return buf; // testing
549
+ if (this.client.write === undefined) return buf // testing
549
550
 
550
551
  try {
551
- this.client.write(buf);
552
- }
553
- catch (err) {
554
- return this.fail(`Writing response: ${buf} failed: ${err}`);
552
+ this.client.write(buf)
553
+ } catch (err) {
554
+ return this.fail(`Writing response: ${buf} failed: ${err}`)
555
555
  }
556
556
 
557
557
  // Store the last response
558
- this.last_response = buf;
558
+ this.last_response = buf
559
559
 
560
560
  // Don't change loop state
561
561
  if (this.state !== states.LOOP) {
562
- this.state = states.CMD;
562
+ this.state = states.CMD
563
563
  }
564
564
 
565
565
  // Run optional closure before handling and further commands
566
- if (func) func();
566
+ if (func) func()
567
567
 
568
568
  // Process any buffered commands (PIPELINING)
569
- this._process_data();
569
+ this._process_data()
570
570
  }
571
- fail (err, err_data) {
572
- if (err) this.logwarn(err, err_data);
573
- this.hooks_to_run = [];
574
- this.disconnect();
571
+ fail(err, err_data) {
572
+ if (err) this.logwarn(err, err_data)
573
+ this.hooks_to_run = []
574
+ this.disconnect()
575
575
  }
576
- disconnect () {
577
- if (this.state >= states.DISCONNECTING) return;
578
- this.state = states.DISCONNECTING;
579
- this.current_data = null; // don't process any more data we have already received
576
+ disconnect() {
577
+ if (this.state >= states.DISCONNECTING) return
578
+ this.state = states.DISCONNECTING
579
+ this.current_data = null // don't process any more data we have already received
580
580
  this.reset_transaction(() => {
581
- plugins.run_hooks('disconnect', this);
582
- });
581
+ plugins.run_hooks('disconnect', this)
582
+ })
583
583
  }
584
- disconnect_respond () {
584
+ disconnect_respond() {
585
585
  const logdetail = {
586
- 'ip': this.remote.ip,
587
- 'rdns': ((this.remote.host) ? this.remote.host : ''),
588
- 'helo': ((this.hello.host) ? this.hello.host : ''),
589
- 'relay': (this.relaying ? 'Y' : 'N'),
590
- 'early': (this.early_talker ? 'Y' : 'N'),
591
- 'esmtp': (this.esmtp ? 'Y' : 'N'),
592
- 'tls': (this.tls.enabled ? 'Y' : 'N'),
593
- 'pipe': (this.pipelining ? 'Y' : 'N'),
594
- 'errors': this.errors,
595
- 'txns': this.tran_count,
596
- 'rcpts': `${this.rcpt_count.accept}/${this.rcpt_count.tempfail}/${this.rcpt_count.reject}`,
597
- 'msgs': `${this.msg_count.accept}/${this.msg_count.tempfail}/${this.msg_count.reject}`,
598
- 'bytes': this.totalbytes,
599
- 'lr': ((this.last_reject) ? this.last_reject : ''),
600
- 'time': (Date.now() - this.start_time)/1000,
601
- };
602
-
603
- this.results.add({name: 'disconnect'}, {
604
- duration: (Date.now() - this.start_time)/1000,
605
- });
606
- this.lognotice('disconnect', logdetail);
607
- this.state = states.DISCONNECTED;
608
- this.client.end();
609
- }
610
- get_capabilities () {
611
- return [];
612
- }
613
- tran_uuid () {
614
- this.tran_count++;
615
- return `${this.uuid}.${this.tran_count}`;
616
- }
617
- reset_transaction (cb) {
618
- this.results.add({name: 'reset'}, {
619
- duration: (Date.now() - this.start_time)/1000,
620
- });
586
+ ip: this.remote.ip,
587
+ rdns: this.remote.host ? this.remote.host : '',
588
+ helo: this.hello.host ? this.hello.host : '',
589
+ relay: this.relaying ? 'Y' : 'N',
590
+ early: this.early_talker ? 'Y' : 'N',
591
+ esmtp: this.esmtp ? 'Y' : 'N',
592
+ tls: this.tls.enabled ? 'Y' : 'N',
593
+ pipe: this.pipelining ? 'Y' : 'N',
594
+ errors: this.errors,
595
+ txns: this.tran_count,
596
+ rcpts: `${this.rcpt_count.accept}/${this.rcpt_count.tempfail}/${this.rcpt_count.reject}`,
597
+ msgs: `${this.msg_count.accept}/${this.msg_count.tempfail}/${this.msg_count.reject}`,
598
+ bytes: this.totalbytes,
599
+ lr: this.last_reject ? this.last_reject : '',
600
+ time: (Date.now() - this.start_time) / 1000,
601
+ }
602
+
603
+ this.results.add(
604
+ { name: 'disconnect' },
605
+ {
606
+ duration: (Date.now() - this.start_time) / 1000,
607
+ },
608
+ )
609
+ this.lognotice('disconnect', logdetail)
610
+ this.state = states.DISCONNECTED
611
+ this.client.end()
612
+ }
613
+ get_capabilities() {
614
+ return []
615
+ }
616
+ tran_uuid() {
617
+ this.tran_count++
618
+ return `${this.uuid}.${this.tran_count}`
619
+ }
620
+ reset_transaction(cb) {
621
+ this.results.add(
622
+ { name: 'reset' },
623
+ {
624
+ duration: (Date.now() - this.start_time) / 1000,
625
+ },
626
+ )
621
627
  if (this.transaction && this.transaction.resetting === false) {
622
628
  // Pause connection to allow the hook to complete
623
- this.pause();
624
- this.transaction.resetting = true;
625
- plugins.run_hooks('reset_transaction', this, cb);
626
- }
627
- else {
628
- this.transaction = null;
629
- if (cb) cb();
629
+ this.pause()
630
+ this.transaction.resetting = true
631
+ plugins.run_hooks('reset_transaction', this, cb)
632
+ } else {
633
+ this.transaction = null
634
+ if (cb) cb()
630
635
  }
631
636
  }
632
- reset_transaction_respond (retval, msg, cb) {
637
+ reset_transaction_respond(retval, msg, cb) {
633
638
  if (this.transaction) {
634
- this.transaction.message_stream.destroy();
635
- this.transaction = null;
639
+ this.transaction.message_stream.destroy()
640
+ this.transaction = null
636
641
  }
637
- if (cb) cb();
642
+ if (cb) cb()
638
643
  // Allow the connection to continue
639
- this.resume();
644
+ this.resume()
640
645
  }
641
- init_transaction (cb) {
646
+ init_transaction(cb) {
642
647
  this.reset_transaction(() => {
643
- this.transaction = trans.createTransaction(this.tran_uuid(), cfg);
648
+ this.transaction = trans.createTransaction(this.tran_uuid(), cfg)
644
649
  // Catch any errors from the message_stream
645
650
  this.transaction.message_stream.on('error', (err) => {
646
- this.logcrit(`message_stream error: ${err.message}`);
651
+ this.logcrit(`message_stream error: ${err.message}`)
647
652
  this.respond('421', 'Internal Server Error', () => {
648
- this.disconnect();
649
- });
650
- });
651
- this.transaction.results = new ResultStore(this);
652
- if (cb) cb();
653
- });
654
- }
655
- loop_respond (code, msg) {
656
- if (this.state >= states.DISCONNECTING) return;
657
- this.state = states.LOOP;
658
- this.loop_code = code;
659
- this.loop_msg = msg;
660
- this.respond(code, msg);
661
- }
662
- pause () {
663
- if (this.state >= states.DISCONNECTING) return;
664
- this.client.pause();
665
- if (this.state !== states.PAUSE_DATA) this.prev_state = this.state;
666
- this.state = states.PAUSE_DATA;
667
- }
668
- resume () {
669
- if (this.state >= states.DISCONNECTING) return;
670
- this.client.resume();
653
+ this.disconnect()
654
+ })
655
+ })
656
+ this.transaction.results = new ResultStore(this)
657
+ if (cb) cb()
658
+ })
659
+ }
660
+ loop_respond(code, msg) {
661
+ if (this.state >= states.DISCONNECTING) return
662
+ this.state = states.LOOP
663
+ this.loop_code = code
664
+ this.loop_msg = msg
665
+ this.respond(code, msg)
666
+ }
667
+ pause() {
668
+ if (this.state >= states.DISCONNECTING) return
669
+ this.client.pause()
670
+ if (this.state !== states.PAUSE_DATA) this.prev_state = this.state
671
+ this.state = states.PAUSE_DATA
672
+ }
673
+ resume() {
674
+ if (this.state >= states.DISCONNECTING) return
675
+ this.client.resume()
671
676
  if (this.prev_state) {
672
- this.state = this.prev_state;
673
- this.prev_state = null;
677
+ this.state = this.prev_state
678
+ this.prev_state = null
674
679
  }
675
- setImmediate(() => this._process_data());
680
+ setImmediate(() => this._process_data())
676
681
  }
677
682
  /////////////////////////////////////////////////////////////////////////////
678
683
  // SMTP Responses
679
- connect_init_respond (retval, msg) {
684
+ connect_init_respond(retval, msg) {
680
685
  // retval and message are ignored
681
- this.logdebug('running connect_init_respond');
682
- plugins.run_hooks('lookup_rdns', this);
686
+ this.logdebug('running connect_init_respond')
687
+ plugins.run_hooks('lookup_rdns', this)
683
688
  }
684
- lookup_rdns_respond (retval, msg) {
689
+ lookup_rdns_respond(retval, msg) {
685
690
  switch (retval) {
686
691
  case constants.ok:
687
- this.set('remote', 'host', (msg || 'Unknown'));
688
- this.set('remote', 'info', (this.remote.info || this.remote.host));
689
- plugins.run_hooks('connect', this);
690
- break;
692
+ this.set('remote', 'host', msg || 'Unknown')
693
+ this.set('remote', 'info', this.remote.info || this.remote.host)
694
+ plugins.run_hooks('connect', this)
695
+ break
691
696
  case constants.deny:
692
- this.loop_respond(554, msg || "rDNS Lookup Failed");
693
- break;
697
+ this.loop_respond(554, msg || 'rDNS Lookup Failed')
698
+ break
694
699
  case constants.denydisconnect:
695
700
  case constants.disconnect:
696
- this.respond(554, msg || "rDNS Lookup Failed", () => {
697
- this.disconnect();
698
- });
699
- break;
701
+ this.respond(554, msg || 'rDNS Lookup Failed', () => {
702
+ this.disconnect()
703
+ })
704
+ break
700
705
  case constants.denysoft:
701
- this.loop_respond(421, msg || "rDNS Temporary Failure");
702
- break;
706
+ this.loop_respond(421, msg || 'rDNS Temporary Failure')
707
+ break
703
708
  case constants.denysoftdisconnect:
704
- this.respond(421, msg || "rDNS Temporary Failure", () => {
705
- this.disconnect();
706
- });
707
- break;
709
+ this.respond(421, msg || 'rDNS Temporary Failure', () => {
710
+ this.disconnect()
711
+ })
712
+ break
708
713
  default:
709
714
  // BUG: dns.reverse throws on invalid input (and sometimes valid
710
715
  // input nodejs/node#47847). Also throws when empty results
711
716
  try {
712
717
  dns.reverse(this.remote.ip, (err, domains) => {
713
- this.rdns_response(err, domains);
718
+ this.rdns_response(err, domains)
714
719
  })
715
- }
716
- catch (err) {
717
- this.rdns_response(err, []);
720
+ } catch (err) {
721
+ this.rdns_response(err, [])
718
722
  }
719
723
  }
720
724
  }
721
- rdns_response (err, domains) {
725
+ rdns_response(err, domains) {
722
726
  if (err) {
723
727
  switch (err.code) {
724
728
  case dns.NXDOMAIN:
725
729
  case dns.NOTFOUND:
726
- this.set('remote', 'host', 'NXDOMAIN');
727
- break;
730
+ this.set('remote', 'host', 'NXDOMAIN')
731
+ break
728
732
  default:
729
- this.set('remote', 'host', 'DNSERROR');
730
- break;
733
+ this.set('remote', 'host', 'DNSERROR')
734
+ break
731
735
  }
736
+ } else {
737
+ this.set('remote', 'host', domains[0] || 'Unknown')
738
+ this.results.add({ name: 'remote' }, this.remote)
732
739
  }
733
- else {
734
- this.set('remote', 'host', (domains[0] || 'Unknown'));
735
- this.results.add({name: 'remote'}, this.remote);
736
- }
737
- this.set('remote', 'info', this.remote.info || this.remote.host);
738
- plugins.run_hooks('connect', this);
740
+ this.set('remote', 'info', this.remote.info || this.remote.host)
741
+ plugins.run_hooks('connect', this)
739
742
  }
740
- unrecognized_command_respond (retval, msg) {
743
+ unrecognized_command_respond(retval, msg) {
741
744
  switch (retval) {
742
745
  case constants.ok:
743
746
  // response already sent, cool...
744
- break;
747
+ break
745
748
  case constants.next_hook:
746
- plugins.run_hooks(msg, this);
747
- break;
749
+ plugins.run_hooks(msg, this)
750
+ break
748
751
  case constants.deny:
749
- this.respond(500, msg || "Unrecognized command");
750
- break;
752
+ this.respond(500, msg || 'Unrecognized command')
753
+ break
751
754
  case constants.denydisconnect:
752
755
  case constants.denysoftdisconnect:
753
- this.respond(retval === constants.denydisconnect ? 521 : 421, msg || "Unrecognized command", () => {
754
- this.disconnect();
755
- });
756
- break;
756
+ this.respond(retval === constants.denydisconnect ? 521 : 421, msg || 'Unrecognized command', () => {
757
+ this.disconnect()
758
+ })
759
+ break
757
760
  default:
758
- this.errors++;
759
- this.respond(500, msg || "Unrecognized command");
761
+ this.errors++
762
+ this.respond(500, msg || 'Unrecognized command')
760
763
  }
761
764
  }
762
- connect_respond (retval, msg) {
765
+ connect_respond(retval, msg) {
763
766
  // RFC 5321 Section 4.3.2 states that the only valid SMTP codes here are:
764
767
  // 220 = Service ready
765
768
  // 554 = Transaction failed (no SMTP service here)
766
769
  // 421 = Service shutting down and closing transmission channel
767
770
  switch (retval) {
768
771
  case constants.deny:
769
- this.loop_respond(554, msg || "Your mail is not welcome here");
770
- break;
772
+ this.loop_respond(554, msg || 'Your mail is not welcome here')
773
+ break
771
774
  case constants.denydisconnect:
772
775
  case constants.disconnect:
773
- this.respond(554, msg || "Your mail is not welcome here", () => {
774
- this.disconnect();
775
- });
776
- break;
776
+ this.respond(554, msg || 'Your mail is not welcome here', () => {
777
+ this.disconnect()
778
+ })
779
+ break
777
780
  case constants.denysoft:
778
- this.loop_respond(421, msg || "Come back later");
779
- break;
781
+ this.loop_respond(421, msg || 'Come back later')
782
+ break
780
783
  case constants.denysoftdisconnect:
781
- this.respond(421, msg || "Come back later", () => {
782
- this.disconnect();
783
- });
784
- break;
784
+ this.respond(421, msg || 'Come back later', () => {
785
+ this.disconnect()
786
+ })
787
+ break
785
788
  default: {
786
- let greeting;
789
+ let greeting
787
790
  if (cfg.message.greeting?.length) {
788
791
  // RFC5321 section 4.2
789
792
  // Hostname/domain should appear after the 220
790
- greeting = [...cfg.message.greeting];
791
- greeting[0] = `${this.local.host} ESMTP ${greeting[0]}`;
793
+ greeting = [...cfg.message.greeting]
794
+ greeting[0] = `${this.local.host} ESMTP ${greeting[0]}`
792
795
  if (cfg.uuid.banner_chars) {
793
- greeting[0] += ` (${this.uuid.substr(0, cfg.uuid.banner_chars)})`;
796
+ greeting[0] += ` (${this.uuid.substr(0, cfg.uuid.banner_chars)})`
794
797
  }
795
- }
796
- else {
797
- greeting = `${this.local.host} ESMTP ${this.local.info} ready`;
798
+ } else {
799
+ greeting = `${this.local.host} ESMTP ${this.local.info} ready`
798
800
  if (cfg.uuid.banner_chars) {
799
- greeting += ` (${this.uuid.substr(0, cfg.uuid.banner_chars)})`;
801
+ greeting += ` (${this.uuid.substr(0, cfg.uuid.banner_chars)})`
800
802
  }
801
803
  }
802
- this.respond(220, msg || greeting);
804
+ this.respond(220, msg || greeting)
803
805
  }
804
806
  }
805
807
  }
806
- get_remote (prop) {
808
+ get_remote(prop) {
807
809
  switch (this.remote[prop]) {
808
810
  case 'NXDOMAIN':
809
811
  case 'DNSERROR':
810
812
  case '':
811
813
  case undefined:
812
814
  case null:
813
- return `[${this.remote.ip}]`;
815
+ return `[${this.remote.ip}]`
814
816
  default:
815
- return `${this.remote[prop]} [${this.remote.ip}]`;
817
+ return `${this.remote[prop]} [${this.remote.ip}]`
816
818
  }
817
819
  }
818
- helo_respond (retval, msg) {
820
+ helo_respond(retval, msg) {
819
821
  switch (retval) {
820
822
  case constants.deny:
821
- this.respond(550, msg || "HELO denied", () => {
822
- this.set('hello', 'verb', null);
823
- this.set('hello', 'host', null);
824
- });
825
- break;
823
+ this.respond(550, msg || 'HELO denied', () => {
824
+ this.set('hello', 'verb', null)
825
+ this.set('hello', 'host', null)
826
+ })
827
+ break
826
828
  case constants.denydisconnect:
827
- this.respond(550, msg || "HELO denied", () => {
828
- this.disconnect();
829
- });
830
- break;
829
+ this.respond(550, msg || 'HELO denied', () => {
830
+ this.disconnect()
831
+ })
832
+ break
831
833
  case constants.denysoft:
832
- this.respond(450, msg || "HELO denied", () => {
833
- this.set('hello', 'verb', null);
834
- this.set('hello', 'host', null);
835
- });
836
- break;
834
+ this.respond(450, msg || 'HELO denied', () => {
835
+ this.set('hello', 'verb', null)
836
+ this.set('hello', 'host', null)
837
+ })
838
+ break
837
839
  case constants.denysoftdisconnect:
838
- this.respond(450, msg || "HELO denied", () => {
839
- this.disconnect();
840
- });
841
- break;
840
+ this.respond(450, msg || 'HELO denied', () => {
841
+ this.disconnect()
842
+ })
843
+ break
842
844
  default:
843
845
  // RFC5321 section 4.1.1.1
844
846
  // Hostname/domain should appear after 250
845
- this.respond(250, `${this.local.host} Hello ${this.get_remote('host')}, ${cfg.message.helo}`);
847
+ this.respond(250, `${this.local.host} Hello ${this.get_remote('host')}, ${cfg.message.helo}`)
846
848
  }
847
849
  }
848
- ehlo_respond (retval, msg) {
849
-
850
+ ehlo_respond(retval, msg) {
850
851
  switch (retval) {
851
852
  case constants.deny:
852
- this.respond(550, msg || "EHLO denied", () => {
853
- this.set('hello', 'verb', null);
854
- this.set('hello', 'host', null);
855
- });
856
- break;
853
+ this.respond(550, msg || 'EHLO denied', () => {
854
+ this.set('hello', 'verb', null)
855
+ this.set('hello', 'host', null)
856
+ })
857
+ break
857
858
  case constants.denydisconnect:
858
- this.respond(550, msg || "EHLO denied", () => {
859
- this.disconnect();
860
- });
861
- break;
859
+ this.respond(550, msg || 'EHLO denied', () => {
860
+ this.disconnect()
861
+ })
862
+ break
862
863
  case constants.denysoft:
863
- this.respond(450, msg || "EHLO denied", () => {
864
- this.set('hello', 'verb', null);
865
- this.set('hello', 'host', null);
866
- });
867
- break;
864
+ this.respond(450, msg || 'EHLO denied', () => {
865
+ this.set('hello', 'verb', null)
866
+ this.set('hello', 'host', null)
867
+ })
868
+ break
868
869
  case constants.denysoftdisconnect:
869
- this.respond(450, msg || "EHLO denied", () => {
870
- this.disconnect();
871
- });
872
- break;
870
+ this.respond(450, msg || 'EHLO denied', () => {
871
+ this.disconnect()
872
+ })
873
+ break
873
874
  default: {
874
875
  // RFC5321 section 4.1.1.1
875
876
  // Hostname/domain should appear after 250
876
877
 
877
878
  const response = [
878
879
  `${this.local.host} Hello ${this.get_remote('host')}, ${cfg.message.helo}`,
879
- "PIPELINING",
880
- "8BITMIME",
881
- ];
880
+ 'PIPELINING',
881
+ '8BITMIME',
882
+ ]
882
883
 
883
- if (cfg.main.smtputf8) response.push("SMTPUTF8");
884
+ if (cfg.main.smtputf8) response.push('SMTPUTF8')
884
885
 
885
- response.push(`SIZE ${cfg.max.bytes}`);
886
+ response.push(`SIZE ${cfg.max.bytes}`)
886
887
 
887
- this.capabilities = response;
888
+ this.capabilities = response
888
889
 
889
- plugins.run_hooks('capabilities', this);
890
- this.esmtp = true;
890
+ plugins.run_hooks('capabilities', this)
891
+ this.esmtp = true
891
892
  }
892
893
  }
893
894
  }
894
- capabilities_respond (retval, msg) {
895
- this.respond(250, this.capabilities);
895
+ capabilities_respond(retval, msg) {
896
+ this.respond(250, this.capabilities)
896
897
  }
897
- quit_respond (retval, msg) {
898
+ quit_respond(retval, msg) {
898
899
  this.respond(221, msg || `${this.local.host} ${cfg.message.close}`, () => {
899
- this.disconnect();
900
- });
900
+ this.disconnect()
901
+ })
901
902
  }
902
- vrfy_respond (retval, msg) {
903
+ vrfy_respond(retval, msg) {
903
904
  switch (retval) {
904
905
  case constants.deny:
905
- this.respond(550, msg || "Access Denied", () => {
906
- this.reset_transaction();
907
- });
908
- break;
906
+ this.respond(550, msg || 'Access Denied', () => {
907
+ this.reset_transaction()
908
+ })
909
+ break
909
910
  case constants.denydisconnect:
910
- this.respond(550, msg || "Access Denied", () => {
911
- this.disconnect();
912
- });
913
- break;
911
+ this.respond(550, msg || 'Access Denied', () => {
912
+ this.disconnect()
913
+ })
914
+ break
914
915
  case constants.denysoft:
915
- this.respond(450, msg || "Lookup Failed", () => {
916
- this.reset_transaction();
917
- });
918
- break;
916
+ this.respond(450, msg || 'Lookup Failed', () => {
917
+ this.reset_transaction()
918
+ })
919
+ break
919
920
  case constants.denysoftdisconnect:
920
- this.respond(450, msg || "Lookup Failed", () => {
921
- this.disconnect();
922
- });
923
- break;
921
+ this.respond(450, msg || 'Lookup Failed', () => {
922
+ this.disconnect()
923
+ })
924
+ break
924
925
  case constants.ok:
925
- this.respond(250, msg || "User OK");
926
- break;
926
+ this.respond(250, msg || 'User OK')
927
+ break
927
928
  default:
928
- this.respond(252, "Just try sending a mail and we'll see how it turns out...");
929
+ this.respond(252, "Just try sending a mail and we'll see how it turns out...")
929
930
  }
930
931
  }
931
- noop_respond (retval, msg) {
932
+ noop_respond(retval, msg) {
932
933
  switch (retval) {
933
934
  case constants.deny:
934
- this.respond(500, msg || "Stop wasting my time");
935
- break;
935
+ this.respond(500, msg || 'Stop wasting my time')
936
+ break
936
937
  case constants.denydisconnect:
937
- this.respond(500, msg || "Stop wasting my time", () => {
938
- this.disconnect();
939
- });
940
- break;
938
+ this.respond(500, msg || 'Stop wasting my time', () => {
939
+ this.disconnect()
940
+ })
941
+ break
941
942
  default:
942
- this.respond(250, "OK");
943
+ this.respond(250, 'OK')
943
944
  }
944
945
  }
945
- rset_respond (retval, msg) {
946
- this.respond(250, "OK", () => {
947
- this.reset_transaction();
946
+ rset_respond(retval, msg) {
947
+ this.respond(250, 'OK', () => {
948
+ this.reset_transaction()
948
949
  })
949
950
  }
950
- mail_respond (retval, msg) {
951
+ mail_respond(retval, msg) {
951
952
  if (!this.transaction) {
952
- this.logerror("mail_respond found no transaction!");
953
- return;
954
- }
955
- const sender = this.transaction.mail_from;
956
- const dmsg = `sender ${sender.format()}`;
957
- this.lognotice(
958
- dmsg,
959
- {
960
- 'code': constants.translate(retval),
961
- 'msg': (msg || ''),
962
- }
963
- );
953
+ this.logerror('mail_respond found no transaction!')
954
+ return
955
+ }
956
+ const sender = this.transaction.mail_from
957
+ const dmsg = `sender ${sender.format()}`
958
+ this.lognotice(dmsg, {
959
+ code: constants.translate(retval),
960
+ msg: msg || '',
961
+ })
964
962
 
965
963
  const store_results = (action) => {
966
- let addr = sender.format();
967
- if (addr.length > 2) { // all but null sender
968
- addr = addr.substr(1, addr.length -2); // trim off < >
964
+ let addr = sender.format()
965
+ if (addr.length > 2) {
966
+ // all but null sender
967
+ addr = addr.substr(1, addr.length - 2) // trim off < >
969
968
  }
970
- this.transaction.results.add({name: 'mail_from'}, {
971
- action,
972
- code: constants.translate(retval),
973
- address: addr,
974
- });
969
+ this.transaction.results.add(
970
+ { name: 'mail_from' },
971
+ {
972
+ action,
973
+ code: constants.translate(retval),
974
+ address: addr,
975
+ },
976
+ )
975
977
  }
976
978
 
977
979
  switch (retval) {
978
980
  case constants.deny:
979
981
  this.respond(550, msg || `${dmsg} denied`, () => {
980
- store_results('reject');
981
- this.reset_transaction();
982
- });
983
- break;
982
+ store_results('reject')
983
+ this.reset_transaction()
984
+ })
985
+ break
984
986
  case constants.denydisconnect:
985
- this.respond(550, msg || `${dmsg} denied`, () => {
986
- store_results('reject');
987
- this.disconnect();
988
- });
989
- break;
987
+ this.respond(550, msg || `${dmsg} denied`, () => {
988
+ store_results('reject')
989
+ this.disconnect()
990
+ })
991
+ break
990
992
  case constants.denysoft:
991
993
  this.respond(450, msg || `${dmsg} denied`, () => {
992
- store_results('tempfail');
993
- this.reset_transaction();
994
- });
995
- break;
994
+ store_results('tempfail')
995
+ this.reset_transaction()
996
+ })
997
+ break
996
998
  case constants.denysoftdisconnect:
997
999
  this.respond(450, msg || `${dmsg} denied`, () => {
998
- store_results('tempfail');
999
- this.disconnect();
1000
- });
1001
- break;
1000
+ store_results('tempfail')
1001
+ this.disconnect()
1002
+ })
1003
+ break
1002
1004
  default:
1003
- store_results('accept');
1004
- this.respond(250, msg || `${dmsg} OK`);
1005
+ store_results('accept')
1006
+ this.respond(250, msg || `${dmsg} OK`)
1005
1007
  }
1006
1008
  }
1007
- rcpt_incr (rcpt, action, msg, retval) {
1008
- this.transaction.rcpt_count[action]++;
1009
- this.rcpt_count[action]++;
1009
+ rcpt_incr(rcpt, action, msg, retval) {
1010
+ this.transaction.rcpt_count[action]++
1011
+ this.rcpt_count[action]++
1010
1012
 
1011
- const addr = rcpt.format();
1013
+ const addr = rcpt.format()
1012
1014
  const recipient = {
1013
- address: addr.substr(1, addr.length -2),
1014
- action
1015
- };
1015
+ address: addr.substr(1, addr.length - 2),
1016
+ action,
1017
+ }
1016
1018
 
1017
1019
  if (msg && action !== 'accept') {
1018
1020
  if (typeof msg === 'object' && msg.constructor.name === 'DSN') {
1019
- recipient.msg = msg.reply;
1020
- recipient.code = msg.code;
1021
- }
1022
- else {
1023
- recipient.msg = msg;
1024
- recipient.code = constants.translate(retval);
1021
+ recipient.msg = msg.reply
1022
+ recipient.code = msg.code
1023
+ } else {
1024
+ recipient.msg = msg
1025
+ recipient.code = constants.translate(retval)
1025
1026
  }
1026
1027
  }
1027
1028
 
1028
- this.transaction.results.push({name: 'rcpt_to'}, { recipient });
1029
+ this.transaction.results.push({ name: 'rcpt_to' }, { recipient })
1029
1030
  }
1030
- rcpt_ok_respond (retval, msg) {
1031
+ rcpt_ok_respond(retval, msg) {
1031
1032
  if (!this.transaction) {
1032
- this.results.add(this, {err: 'rcpt_ok_respond found no transaction'});
1033
- return;
1034
- }
1035
- if (!msg) msg = this.last_rcpt_msg;
1036
- const rcpt = this.transaction.rcpt_to[this.transaction.rcpt_to.length - 1];
1037
- const dmsg = `recipient ${rcpt.format()}`;
1033
+ this.results.add(this, {
1034
+ err: 'rcpt_ok_respond found no transaction',
1035
+ })
1036
+ return
1037
+ }
1038
+ if (!msg) msg = this.last_rcpt_msg
1039
+ const rcpt = this.transaction.rcpt_to[this.transaction.rcpt_to.length - 1]
1040
+ const dmsg = `recipient ${rcpt.format()}`
1038
1041
  // Log OK instead of CONT as this hook only runs if hook_rcpt returns OK
1039
- this.lognotice(
1040
- dmsg,
1041
- {
1042
- 'code': constants.translate((retval === constants.cont ? constants.ok : retval)),
1043
- 'msg': (msg || ''),
1044
- 'sender': this.transaction.mail_from.address(),
1045
- }
1046
- );
1042
+ this.lognotice(dmsg, {
1043
+ code: constants.translate(retval === constants.cont ? constants.ok : retval),
1044
+ msg: msg || '',
1045
+ sender: this.transaction.mail_from.address(),
1046
+ })
1047
1047
  switch (retval) {
1048
1048
  case constants.deny:
1049
1049
  this.respond(550, msg || `${dmsg} denied`, () => {
1050
- this.rcpt_incr(rcpt, 'reject', msg, retval);
1051
- this.transaction.rcpt_to.pop();
1052
- });
1053
- break;
1050
+ this.rcpt_incr(rcpt, 'reject', msg, retval)
1051
+ this.transaction.rcpt_to.pop()
1052
+ })
1053
+ break
1054
1054
  case constants.denydisconnect:
1055
1055
  this.respond(550, msg || `${dmsg} denied`, () => {
1056
- this.rcpt_incr(rcpt, 'reject', msg, retval);
1057
- this.disconnect();
1058
- });
1059
- break;
1056
+ this.rcpt_incr(rcpt, 'reject', msg, retval)
1057
+ this.disconnect()
1058
+ })
1059
+ break
1060
1060
  case constants.denysoft:
1061
1061
  this.respond(450, msg || `${dmsg} denied`, () => {
1062
- this.rcpt_incr(rcpt, 'tempfail', msg, retval);
1063
- this.transaction.rcpt_to.pop();
1064
- });
1065
- break;
1062
+ this.rcpt_incr(rcpt, 'tempfail', msg, retval)
1063
+ this.transaction.rcpt_to.pop()
1064
+ })
1065
+ break
1066
1066
  case constants.denysoftdisconnect:
1067
1067
  this.respond(450, msg || `${dmsg} denied`, () => {
1068
- this.rcpt_incr(rcpt, 'tempfail', msg, retval);
1069
- this.disconnect();
1070
- });
1071
- break;
1068
+ this.rcpt_incr(rcpt, 'tempfail', msg, retval)
1069
+ this.disconnect()
1070
+ })
1071
+ break
1072
1072
  default:
1073
1073
  this.respond(250, msg || `${dmsg} OK`, () => {
1074
- this.rcpt_incr(rcpt, 'accept', msg, retval);
1075
- });
1074
+ this.rcpt_incr(rcpt, 'accept', msg, retval)
1075
+ })
1076
1076
  }
1077
1077
  }
1078
- rcpt_respond (retval, msg) {
1078
+ rcpt_respond(retval, msg) {
1079
1079
  if (retval === constants.cont && this.relaying) {
1080
- retval = constants.ok;
1080
+ retval = constants.ok
1081
1081
  }
1082
1082
 
1083
1083
  if (!this.transaction) {
1084
- this.results.add(this, {err: 'rcpt_respond found no transaction'});
1085
- return;
1084
+ this.results.add(this, {
1085
+ err: 'rcpt_respond found no transaction',
1086
+ })
1087
+ return
1086
1088
  }
1087
- const rcpt = this.transaction.rcpt_to[this.transaction.rcpt_to.length - 1];
1088
- const dmsg = `recipient ${rcpt.format()}`;
1089
+ const rcpt = this.transaction.rcpt_to[this.transaction.rcpt_to.length - 1]
1090
+ const dmsg = `recipient ${rcpt.format()}`
1089
1091
  if (retval !== constants.ok) {
1090
- this.lognotice(
1091
- dmsg,
1092
- {
1093
- 'code': constants.translate((retval === constants.cont ? constants.ok : retval)),
1094
- 'msg': (msg || ''),
1095
- 'sender': this.transaction.mail_from.address(),
1096
- }
1097
- );
1092
+ this.lognotice(dmsg, {
1093
+ code: constants.translate(retval === constants.cont ? constants.ok : retval),
1094
+ msg: msg || '',
1095
+ sender: this.transaction.mail_from.address(),
1096
+ })
1098
1097
  }
1099
1098
  switch (retval) {
1100
1099
  case constants.deny:
1101
1100
  this.respond(550, msg || `${dmsg} denied`, () => {
1102
- this.rcpt_incr(rcpt, 'reject', msg, retval);
1103
- this.transaction.rcpt_to.pop();
1104
- });
1105
- break;
1101
+ this.rcpt_incr(rcpt, 'reject', msg, retval)
1102
+ this.transaction.rcpt_to.pop()
1103
+ })
1104
+ break
1106
1105
  case constants.denydisconnect:
1107
1106
  this.respond(550, msg || `${dmsg} denied`, () => {
1108
- this.rcpt_incr(rcpt, 'reject', msg, retval);
1109
- this.disconnect();
1110
- });
1111
- break;
1107
+ this.rcpt_incr(rcpt, 'reject', msg, retval)
1108
+ this.disconnect()
1109
+ })
1110
+ break
1112
1111
  case constants.denysoft:
1113
1112
  this.respond(450, msg || `${dmsg} denied`, () => {
1114
- this.rcpt_incr(rcpt, 'tempfail', msg, retval);
1115
- this.transaction.rcpt_to.pop();
1116
- });
1117
- break;
1113
+ this.rcpt_incr(rcpt, 'tempfail', msg, retval)
1114
+ this.transaction.rcpt_to.pop()
1115
+ })
1116
+ break
1118
1117
  case constants.denysoftdisconnect:
1119
1118
  this.respond(450, msg || `${dmsg} denied`, () => {
1120
- this.rcpt_incr(rcpt, 'tempfail', msg, retval);
1121
- this.disconnect();
1122
- });
1123
- break;
1119
+ this.rcpt_incr(rcpt, 'tempfail', msg, retval)
1120
+ this.disconnect()
1121
+ })
1122
+ break
1124
1123
  case constants.ok:
1125
1124
  // Store any msg for rcpt_ok
1126
- this.last_rcpt_msg = msg;
1127
- plugins.run_hooks('rcpt_ok', this, rcpt);
1128
- break;
1125
+ this.last_rcpt_msg = msg
1126
+ plugins.run_hooks('rcpt_ok', this, rcpt)
1127
+ break
1129
1128
  default: {
1130
1129
  if (retval !== constants.cont) {
1131
- this.logalert("No plugin determined if relaying was allowed");
1130
+ this.logalert('No plugin determined if relaying was allowed')
1132
1131
  }
1133
- const rej_msg = `I cannot deliver mail for ${rcpt.format()}`;
1132
+ const rej_msg = `I cannot deliver mail for ${rcpt.format()}`
1134
1133
  this.respond(550, rej_msg, () => {
1135
- this.rcpt_incr(rcpt, 'reject', rej_msg, retval);
1136
- this.transaction.rcpt_to.pop();
1137
- });
1134
+ this.rcpt_incr(rcpt, 'reject', rej_msg, retval)
1135
+ this.transaction.rcpt_to.pop()
1136
+ })
1138
1137
  }
1139
1138
  }
1140
1139
  }
1141
1140
  /////////////////////////////////////////////////////////////////////////////
1142
1141
  // HAProxy support
1143
1142
 
1144
- cmd_proxy (line) {
1145
-
1143
+ cmd_proxy(line) {
1146
1144
  if (!this.proxy.allowed) {
1147
- this.respond(421, `PROXY not allowed from ${this.remote.ip}`);
1148
- return this.disconnect();
1145
+ this.respond(421, `PROXY not allowed from ${this.remote.ip}`)
1146
+ return this.disconnect()
1149
1147
  }
1150
1148
 
1151
- const match = /(TCP4|TCP6|UNKNOWN) (\S+) (\S+) (\d+) (\d+)$/.exec(line);
1149
+ const match = /(TCP4|TCP6|UNKNOWN) (\S+) (\S+) (\d+) (\d+)$/.exec(line)
1152
1150
  if (!match) {
1153
- this.respond(421, 'Invalid PROXY format');
1154
- return this.disconnect();
1151
+ this.respond(421, 'Invalid PROXY format')
1152
+ return this.disconnect()
1155
1153
  }
1156
- const proto = match[1];
1157
- const src_ip = match[2];
1158
- const dst_ip = match[3];
1159
- const src_port = match[4];
1160
- const dst_port = match[5];
1154
+ const proto = match[1]
1155
+ const src_ip = match[2]
1156
+ const dst_ip = match[3]
1157
+ const src_port = match[4]
1158
+ const dst_port = match[5]
1161
1159
 
1162
1160
  // Validate source/destination IP
1163
1161
  /*eslint no-fallthrough: 0 */
1164
1162
  switch (proto) {
1165
1163
  case 'TCP4':
1166
1164
  if (ipaddr.IPv4.isValid(src_ip) && ipaddr.IPv4.isValid(dst_ip)) {
1167
- break;
1165
+ break
1168
1166
  }
1169
1167
  case 'TCP6':
1170
1168
  if (ipaddr.IPv6.isValid(src_ip) && ipaddr.IPv6.isValid(dst_ip)) {
1171
- break;
1169
+ break
1172
1170
  }
1173
1171
  // case 'UNKNOWN':
1174
1172
  default:
1175
- this.respond(421, 'Invalid PROXY format');
1176
- return this.disconnect();
1173
+ this.respond(421, 'Invalid PROXY format')
1174
+ return this.disconnect()
1177
1175
  }
1178
1176
 
1179
1177
  // Apply changes
1180
- this.loginfo(
1181
- 'HAProxy',
1182
- {
1183
- proto,
1184
- src_ip: `${src_ip}:${src_port}`,
1185
- dst_ip: `${dst_ip}:${dst_port}`,
1186
- }
1187
- );
1178
+ this.loginfo('HAProxy', {
1179
+ proto,
1180
+ src_ip: `${src_ip}:${src_port}`,
1181
+ dst_ip: `${dst_ip}:${dst_port}`,
1182
+ })
1188
1183
 
1189
1184
  this.notes.proxy = {
1190
1185
  type: 'haproxy',
@@ -1193,697 +1188,666 @@ class Connection {
1193
1188
  src_port,
1194
1189
  dst_ip,
1195
1190
  dst_port,
1196
- proxy_ip: this.remote.ip
1197
- };
1191
+ proxy_ip: this.remote.ip,
1192
+ }
1198
1193
 
1199
1194
  this.reset_transaction(() => {
1200
- this.set('proxy.ip', this.remote.ip);
1201
- this.set('proxy.type', 'haproxy');
1202
- this.relaying = false;
1203
- this.set('local.ip', dst_ip);
1204
- this.set('local.port', parseInt(dst_port, 10));
1205
- this.set('remote.ip', src_ip);
1206
- this.set('remote.port', parseInt(src_port, 10));
1207
- this.set('remote.host', null);
1208
- this.set('hello.host', null);
1209
- plugins.run_hooks('connect_init', this);
1210
- });
1195
+ this.set('proxy.ip', this.remote.ip)
1196
+ this.set('proxy.type', 'haproxy')
1197
+ this.relaying = false
1198
+ this.set('local.ip', dst_ip)
1199
+ this.set('local.port', parseInt(dst_port, 10))
1200
+ this.set('remote.ip', src_ip)
1201
+ this.set('remote.port', parseInt(src_port, 10))
1202
+ this.set('remote.host', null)
1203
+ this.set('hello.host', null)
1204
+ plugins.run_hooks('connect_init', this)
1205
+ })
1211
1206
  }
1212
1207
  /////////////////////////////////////////////////////////////////////////////
1213
1208
  // SMTP Commands
1214
1209
 
1215
- cmd_internalcmd (line) {
1210
+ cmd_internalcmd(line) {
1216
1211
  if (!this.remote.is_local) {
1217
- return this.respond(501, "INTERNALCMD not allowed remotely");
1212
+ return this.respond(501, 'INTERNALCMD not allowed remotely')
1218
1213
  }
1219
- const results = (String(line)).split(/ +/);
1214
+ const results = String(line).split(/ +/)
1220
1215
  if (/key:/.test(results[0])) {
1221
- const internal_key = config.get('internalcmd_key');
1216
+ const internal_key = config.get('internalcmd_key')
1222
1217
  if (results[0] != `key:${internal_key}`) {
1223
- return this.respond(501, "Invalid internalcmd_key - check config");
1218
+ return this.respond(501, 'Invalid internalcmd_key - check config')
1224
1219
  }
1225
- results.shift();
1226
- }
1227
- else if (config.get('internalcmd_key')) {
1228
- return this.respond(501, "Missing internalcmd_key - check config");
1220
+ results.shift()
1221
+ } else if (config.get('internalcmd_key')) {
1222
+ return this.respond(501, 'Missing internalcmd_key - check config')
1229
1223
  }
1230
1224
 
1231
1225
  // Now send the internal command to the master process
1232
- const command = results.shift();
1226
+ const command = results.shift()
1233
1227
  if (!command) {
1234
- return this.respond(501, "No command given");
1228
+ return this.respond(501, 'No command given')
1235
1229
  }
1236
1230
 
1237
- require('./server').sendToMaster(command, results);
1238
- return this.respond(250, "Command sent for execution. Check Haraka logs for results.");
1231
+ require('./server').sendToMaster(command, results)
1232
+ return this.respond(250, 'Command sent for execution. Check Haraka logs for results.')
1239
1233
  }
1240
- cmd_helo (line) {
1241
- const results = (String(line)).split(/ +/);
1242
- const host = results[0];
1234
+ cmd_helo(line) {
1235
+ const results = String(line).split(/ +/)
1236
+ const host = results[0]
1243
1237
  if (!host) {
1244
- return this.respond(501, "HELO requires domain/address - see RFC-2821 4.1.1.1");
1238
+ return this.respond(501, 'HELO requires domain/address - see RFC-2821 4.1.1.1')
1245
1239
  }
1246
1240
 
1247
1241
  this.reset_transaction(() => {
1248
- this.set('hello', 'verb', 'HELO');
1249
- this.set('hello', 'host', host);
1250
- this.results.add({ name: 'helo' }, this.hello);
1251
- plugins.run_hooks('helo', this, host);
1252
- });
1253
- }
1254
- cmd_ehlo (line) {
1255
- const results = (String(line)).split(/ +/);
1256
- const host = results[0];
1242
+ this.set('hello', 'verb', 'HELO')
1243
+ this.set('hello', 'host', host)
1244
+ this.results.add({ name: 'helo' }, this.hello)
1245
+ plugins.run_hooks('helo', this, host)
1246
+ })
1247
+ }
1248
+ cmd_ehlo(line) {
1249
+ const results = String(line).split(/ +/)
1250
+ const host = results[0]
1257
1251
  if (!host) {
1258
- return this.respond(501, "EHLO requires domain/address - see RFC-2821 4.1.1.1");
1252
+ return this.respond(501, 'EHLO requires domain/address - see RFC-2821 4.1.1.1')
1259
1253
  }
1260
1254
 
1261
1255
  this.reset_transaction(() => {
1262
- this.set('hello', 'verb', 'EHLO');
1263
- this.set('hello', 'host', host);
1264
- this.results.add({ name: 'helo' }, this.hello);
1265
- plugins.run_hooks('ehlo', this, host);
1266
- });
1256
+ this.set('hello', 'verb', 'EHLO')
1257
+ this.set('hello', 'host', host)
1258
+ this.results.add({ name: 'helo' }, this.hello)
1259
+ plugins.run_hooks('ehlo', this, host)
1260
+ })
1267
1261
  }
1268
- cmd_quit (args) {
1262
+ cmd_quit(args) {
1269
1263
  // RFC 5321 Section 4.3.2
1270
1264
  // QUIT does not accept arguments
1271
1265
  if (args) {
1272
- return this.respond(501, "Syntax error");
1266
+ return this.respond(501, 'Syntax error')
1273
1267
  }
1274
- plugins.run_hooks('quit', this);
1268
+ plugins.run_hooks('quit', this)
1275
1269
  }
1276
- cmd_rset (args) {
1270
+ cmd_rset(args) {
1277
1271
  // RFC 5321 Section 4.3.2
1278
1272
  // RSET does not accept arguments
1279
1273
  if (args) {
1280
- return this.respond(501, "Syntax error");
1274
+ return this.respond(501, 'Syntax error')
1281
1275
  }
1282
- plugins.run_hooks('rset', this);
1276
+ plugins.run_hooks('rset', this)
1283
1277
  }
1284
- cmd_vrfy (line) {
1278
+ cmd_vrfy(line) {
1285
1279
  // only supported via plugins
1286
- plugins.run_hooks('vrfy', this);
1280
+ plugins.run_hooks('vrfy', this)
1287
1281
  }
1288
- cmd_noop () {
1289
- plugins.run_hooks('noop', this);
1282
+ cmd_noop() {
1283
+ plugins.run_hooks('noop', this)
1290
1284
  }
1291
- cmd_help () {
1292
- this.respond(250, "Not implemented");
1285
+ cmd_help() {
1286
+ this.respond(250, 'Not implemented')
1293
1287
  }
1294
- cmd_mail (line) {
1288
+ cmd_mail(line) {
1295
1289
  if (!this.hello.host) {
1296
- this.errors++;
1297
- return this.respond(503, 'Use EHLO/HELO before MAIL');
1290
+ this.errors++
1291
+ return this.respond(503, 'Use EHLO/HELO before MAIL')
1298
1292
  }
1299
1293
  // Require authentication on ports 587 & 465
1300
- if (!this.relaying && [587,465].includes(this.local.port)) {
1301
- this.errors++;
1302
- return this.respond(550, 'Authentication required');
1294
+ if (!this.relaying && [587, 465].includes(this.local.port)) {
1295
+ this.errors++
1296
+ return this.respond(550, 'Authentication required')
1303
1297
  }
1304
1298
 
1305
- let results;
1299
+ let results
1306
1300
  try {
1307
- results = rfc1869.parse('mail', line, (!this.relaying && cfg.main.strict_rfc1869));
1308
- }
1309
- catch (err) {
1310
- this.errors++;
1301
+ results = rfc1869.parse('mail', line, !this.relaying && cfg.main.strict_rfc1869)
1302
+ } catch (err) {
1303
+ this.errors++
1311
1304
  if (err.stack) {
1312
- this.lognotice(err.stack.split(/\n/)[0]);
1313
- }
1314
- else {
1315
- this.logerror(err);
1305
+ this.lognotice(err.stack.split(/\n/)[0])
1306
+ } else {
1307
+ this.logerror(err)
1316
1308
  }
1317
1309
  // Explicitly handle out-of-disk space errors
1318
1310
  if (err.code === 'ENOSPC') {
1319
- return this.respond(452, 'Internal Server Error');
1320
- }
1321
- else {
1322
- return this.respond(501, ['Command parsing failed', err]);
1311
+ return this.respond(452, 'Internal Server Error')
1312
+ } else {
1313
+ return this.respond(501, ['Command parsing failed', err])
1323
1314
  }
1324
1315
  }
1325
1316
 
1326
- let from;
1317
+ let from
1327
1318
  try {
1328
- from = new Address(results.shift());
1329
- }
1330
- catch (err) {
1331
- return this.respond(501, `Invalid MAIL FROM address`);
1319
+ from = new Address(results.shift())
1320
+ } catch (err) {
1321
+ return this.respond(501, `Invalid MAIL FROM address`)
1332
1322
  }
1333
1323
 
1334
1324
  // Get rest of key=value pairs
1335
- const params = {};
1336
- results.forEach(param => {
1337
- const kv = param.match(/^([^=]+)(?:=(.+))?$/);
1338
- if (kv)
1339
- params[kv[1].toUpperCase()] = kv[2] || null;
1340
- });
1325
+ const params = {}
1326
+ results.forEach((param) => {
1327
+ const kv = param.match(/^([^=]+)(?:=(.+))?$/)
1328
+ if (kv) params[kv[1].toUpperCase()] = kv[2] || null
1329
+ })
1341
1330
 
1342
1331
  // Parameters are only valid if EHLO was sent
1343
1332
  if (!this.esmtp && Object.keys(params).length > 0) {
1344
- return this.respond(555, 'Invalid command parameters');
1333
+ return this.respond(555, 'Invalid command parameters')
1345
1334
  }
1346
1335
 
1347
1336
  // Handle SIZE extension
1348
1337
  if (params?.SIZE && params.SIZE > 0) {
1349
1338
  if (cfg.max.bytes > 0 && params.SIZE > cfg.max.bytes) {
1350
- return this.respond(550, 'Message too big!');
1339
+ return this.respond(550, 'Message too big!')
1351
1340
  }
1352
1341
  }
1353
1342
 
1354
1343
  this.init_transaction(() => {
1355
- this.transaction.mail_from = from;
1344
+ this.transaction.mail_from = from
1356
1345
  if (this.hello.verb == 'HELO') {
1357
- this.transaction.encoding = 'binary';
1358
- this.encoding = 'binary';
1346
+ this.transaction.encoding = 'binary'
1347
+ this.encoding = 'binary'
1359
1348
  }
1360
- plugins.run_hooks('mail', this, [from, params]);
1361
- });
1349
+ plugins.run_hooks('mail', this, [from, params])
1350
+ })
1362
1351
  }
1363
- cmd_rcpt (line) {
1352
+ cmd_rcpt(line) {
1364
1353
  if (!this.transaction || !this.transaction.mail_from) {
1365
- this.errors++;
1366
- return this.respond(503, "Use MAIL before RCPT");
1354
+ this.errors++
1355
+ return this.respond(503, 'Use MAIL before RCPT')
1367
1356
  }
1368
1357
 
1369
- let results;
1358
+ let results
1370
1359
  try {
1371
- results = rfc1869.parse('rcpt', line, cfg.main.strict_rfc1869 && !this.relaying);
1372
- }
1373
- catch (err) {
1374
- this.errors++;
1360
+ results = rfc1869.parse('rcpt', line, cfg.main.strict_rfc1869 && !this.relaying)
1361
+ } catch (err) {
1362
+ this.errors++
1375
1363
  if (err.stack) {
1376
- this.lognotice(err.stack.split(/\n/)[0]);
1377
- }
1378
- else {
1379
- this.logerror(err);
1364
+ this.lognotice(err.stack.split(/\n/)[0])
1365
+ } else {
1366
+ this.logerror(err)
1380
1367
  }
1381
1368
  // Explicitly handle out-of-disk space errors
1382
1369
  if (err.code === 'ENOSPC') {
1383
- return this.respond(452, 'Internal Server Error');
1384
- }
1385
- else {
1386
- return this.respond(501, ["Command parsing failed", err]);
1370
+ return this.respond(452, 'Internal Server Error')
1371
+ } else {
1372
+ return this.respond(501, ['Command parsing failed', err])
1387
1373
  }
1388
1374
  }
1389
1375
 
1390
- let recip;
1376
+ let recip
1391
1377
  try {
1392
- recip = new Address(results.shift());
1393
- }
1394
- catch (err) {
1395
- return this.respond(501, `Invalid RCPT TO address`);
1378
+ recip = new Address(results.shift())
1379
+ } catch (err) {
1380
+ return this.respond(501, `Invalid RCPT TO address`)
1396
1381
  }
1397
1382
 
1398
1383
  // Get rest of key=value pairs
1399
- const params = {};
1384
+ const params = {}
1400
1385
  results.forEach((param) => {
1401
- const kv = param.match(/^([^=]+)(?:=(.+))?$/);
1402
- if (kv)
1403
- params[kv[1].toUpperCase()] = kv[2] || null;
1404
- });
1386
+ const kv = param.match(/^([^=]+)(?:=(.+))?$/)
1387
+ if (kv) params[kv[1].toUpperCase()] = kv[2] || null
1388
+ })
1405
1389
 
1406
1390
  // Parameters are only valid if EHLO was sent
1407
1391
  if (!this.esmtp && Object.keys(params).length > 0) {
1408
- return this.respond(555, 'Invalid command parameters');
1392
+ return this.respond(555, 'Invalid command parameters')
1409
1393
  }
1410
1394
 
1411
- this.transaction.rcpt_to.push(recip);
1412
- plugins.run_hooks('rcpt', this, [recip, params]);
1395
+ this.transaction.rcpt_to.push(recip)
1396
+ plugins.run_hooks('rcpt', this, [recip, params])
1413
1397
  }
1414
- received_line () {
1415
- let smtp = this.hello.verb === 'EHLO' ? 'ESMTP' : 'SMTP';
1398
+ received_line() {
1399
+ let smtp = this.hello.verb === 'EHLO' ? 'ESMTP' : 'SMTP'
1416
1400
  // Implement RFC3848
1417
- if (this.tls.enabled) smtp += 'S';
1418
- if (this.authheader) smtp += 'A';
1401
+ if (this.tls.enabled) smtp += 'S'
1402
+ if (this.authheader) smtp += 'A'
1419
1403
 
1420
- let sslheader;
1404
+ let sslheader
1421
1405
 
1422
1406
  if (this.get('tls.cipher.version')) {
1423
1407
  // standardName appeared in Node.js v12.16 and v13.4
1424
1408
  // RFC 8314
1425
- sslheader = `tls ${this.tls.cipher.standardName || this.tls.cipher.name}`;
1409
+ sslheader = `tls ${this.tls.cipher.standardName || this.tls.cipher.name}`
1426
1410
  }
1427
1411
 
1428
1412
  let received_header = `from ${this.hello.host} (${this.get_remote('info')})\r
1429
1413
  \tby ${this.local.host} (${this.local.info}) with ${smtp} id ${this.transaction.uuid}\r
1430
- \tenvelope-from ${this.transaction.mail_from.format()}`;
1414
+ \tenvelope-from ${this.transaction.mail_from.format()}`
1431
1415
 
1432
- if (sslheader) received_header += `\r\n\t${sslheader.replace(/\r?\n\t?$/,'')}`
1416
+ if (sslheader) received_header += `\r\n\t${sslheader.replace(/\r?\n\t?$/, '')}`
1433
1417
 
1434
1418
  // Does not follow RFC 5321 section 4.4 grammar
1435
1419
  if (this.authheader) received_header += ` ${this.authheader.replace(/\r?\n\t?$/, '')}`
1436
1420
 
1437
1421
  received_header += `;\r\n\t${utils.date_to_str(new Date())}`
1438
1422
 
1439
- return received_header;
1423
+ return received_header
1440
1424
  }
1441
- auth_results (message) {
1425
+ auth_results(message) {
1442
1426
  // https://datatracker.ietf.org/doc/rfc7001/
1443
- const has_tran = !!((this.transaction?.notes));
1427
+ const has_tran = !!this.transaction?.notes
1444
1428
 
1445
1429
  // initialize connection note
1446
1430
  if (!this.notes.authentication_results) {
1447
- this.notes.authentication_results = [];
1431
+ this.notes.authentication_results = []
1448
1432
  }
1449
1433
 
1450
1434
  // initialize transaction note, if possible
1451
1435
  if (has_tran === true && !this.transaction.notes.authentication_results) {
1452
- this.transaction.notes.authentication_results = [];
1436
+ this.transaction.notes.authentication_results = []
1453
1437
  }
1454
1438
 
1455
1439
  // if message, store it in the appropriate note
1456
1440
  if (message) {
1457
1441
  if (has_tran === true) {
1458
- this.transaction.notes.authentication_results.push(message);
1459
- }
1460
- else {
1461
- this.notes.authentication_results.push(message);
1442
+ this.transaction.notes.authentication_results.push(message)
1443
+ } else {
1444
+ this.notes.authentication_results.push(message)
1462
1445
  }
1463
1446
  }
1464
1447
 
1465
1448
  // assemble the new header
1466
- let header = [ this.local.host ];
1467
- header = header.concat(this.notes.authentication_results);
1449
+ let header = [this.local.host]
1450
+ header = header.concat(this.notes.authentication_results)
1468
1451
  if (has_tran === true) {
1469
- header = header.concat(this.transaction.notes.authentication_results);
1452
+ header = header.concat(this.transaction.notes.authentication_results)
1470
1453
  }
1471
- if (header.length === 1) return ''; // no results
1472
- return header.join(";\r\n\t");
1454
+ if (header.length === 1) return '' // no results
1455
+ return header.join(';\r\n\t')
1473
1456
  }
1474
- auth_results_clean () {
1457
+ auth_results_clean() {
1475
1458
  // move any existing Auth-Res headers to Original-Auth-Res headers
1476
1459
  // http://tools.ietf.org/html/draft-kucherawy-original-authres-00.html
1477
- const ars = this.transaction.header.get_all('Authentication-Results');
1478
- if (ars.length === 0) return;
1460
+ const ars = this.transaction.header.get_all('Authentication-Results')
1461
+ if (ars.length === 0) return
1479
1462
 
1480
1463
  for (const element of ars) {
1481
- this.transaction.add_header('Original-Authentication-Results', element);
1464
+ this.transaction.add_header('Original-Authentication-Results', element)
1482
1465
  }
1483
- this.transaction.remove_header('Authentication-Results');
1484
- this.logdebug("Authentication-Results moved to Original-Authentication-Results");
1466
+ this.transaction.remove_header('Authentication-Results')
1467
+ this.logdebug('Authentication-Results moved to Original-Authentication-Results')
1485
1468
  }
1486
- cmd_data (args) {
1469
+ cmd_data(args) {
1487
1470
  // RFC 5321 Section 4.3.2
1488
1471
  // DATA does not accept arguments
1489
1472
  if (args) {
1490
- this.errors++;
1491
- return this.respond(501, "Syntax error");
1473
+ this.errors++
1474
+ return this.respond(501, 'Syntax error')
1492
1475
  }
1493
1476
  if (!this.transaction) {
1494
- this.errors++;
1495
- return this.respond(503, "MAIL required first");
1477
+ this.errors++
1478
+ return this.respond(503, 'MAIL required first')
1496
1479
  }
1497
1480
  if (!this.transaction.rcpt_to.length) {
1498
1481
  if (this.pipelining) {
1499
- return this.respond(554, "No valid recipients");
1482
+ return this.respond(554, 'No valid recipients')
1500
1483
  }
1501
- this.errors++;
1502
- return this.respond(503, "RCPT required first");
1484
+ this.errors++
1485
+ return this.respond(503, 'RCPT required first')
1503
1486
  }
1504
1487
 
1505
1488
  if (cfg.headers.add_received) {
1506
- this.accumulate_data(`Received: ${this.received_line()}\r\n`);
1489
+ this.accumulate_data(`Received: ${this.received_line()}\r\n`)
1507
1490
  }
1508
- plugins.run_hooks('data', this);
1491
+ plugins.run_hooks('data', this)
1509
1492
  }
1510
- data_respond (retval, msg) {
1511
- let cont = 0;
1493
+ data_respond(retval, msg) {
1494
+ let cont = 0
1512
1495
  switch (retval) {
1513
1496
  case constants.deny:
1514
- this.respond(554, msg || "Message denied", () => {
1515
- this.reset_transaction();
1516
- });
1517
- break;
1497
+ this.respond(554, msg || 'Message denied', () => {
1498
+ this.reset_transaction()
1499
+ })
1500
+ break
1518
1501
  case constants.denydisconnect:
1519
- this.respond(554, msg || "Message denied", () => {
1520
- this.disconnect();
1521
- });
1522
- break;
1502
+ this.respond(554, msg || 'Message denied', () => {
1503
+ this.disconnect()
1504
+ })
1505
+ break
1523
1506
  case constants.denysoft:
1524
- this.respond(451, msg || "Message denied", () => {
1525
- this.reset_transaction();
1526
- });
1527
- break;
1507
+ this.respond(451, msg || 'Message denied', () => {
1508
+ this.reset_transaction()
1509
+ })
1510
+ break
1528
1511
  case constants.denysoftdisconnect:
1529
- this.respond(451, msg || "Message denied", () => {
1530
- this.disconnect();
1531
- });
1532
- break;
1512
+ this.respond(451, msg || 'Message denied', () => {
1513
+ this.disconnect()
1514
+ })
1515
+ break
1533
1516
  default:
1534
- cont = 1;
1517
+ cont = 1
1535
1518
  }
1536
- if (!cont) return;
1519
+ if (!cont) return
1537
1520
 
1538
1521
  // We already checked for MAIL/RCPT in cmd_data
1539
- this.respond(354, "go ahead, make my day", () => {
1522
+ this.respond(354, 'go ahead, make my day', () => {
1540
1523
  // OK... now we get the data
1541
- this.state = states.DATA;
1542
- this.transaction.data_bytes = 0;
1543
- });
1524
+ this.state = states.DATA
1525
+ this.transaction.data_bytes = 0
1526
+ })
1544
1527
  }
1545
- accumulate_data (line) {
1546
-
1547
- this.transaction.data_bytes += line.length;
1528
+ accumulate_data(line) {
1529
+ this.transaction.data_bytes += line.length
1548
1530
 
1549
1531
  // Look for .\r\n
1550
- if (line.length === 3 &&
1551
- line[0] === 0x2e &&
1552
- line[1] === 0x0d &&
1553
- line[2] === 0x0a) {
1554
- this.data_done();
1555
- return;
1532
+ if (line.length === 3 && line[0] === 0x2e && line[1] === 0x0d && line[2] === 0x0a) {
1533
+ this.data_done()
1534
+ return
1556
1535
  }
1557
1536
 
1558
1537
  // Look for .\n
1559
- if (line.length === 2 &&
1560
- line[0] === 0x2e &&
1561
- line[1] === 0x0a) {
1562
- this.lognotice('Client sent bare line-feed - .\\n rather than .\\r\\n');
1563
- this.respond(451, "Bare line-feed; see http://haraka.github.io/barelf/", () => {
1564
- this.reset_transaction();
1565
- });
1566
- return;
1538
+ if (line.length === 2 && line[0] === 0x2e && line[1] === 0x0a) {
1539
+ this.lognotice('Client sent bare line-feed - .\\n rather than .\\r\\n')
1540
+ this.respond(451, 'Bare line-feed; see http://haraka.github.io/barelf/', () => {
1541
+ this.reset_transaction()
1542
+ })
1543
+ return
1567
1544
  }
1568
1545
 
1569
1546
  // Stop accumulating data as we're going to reject at dot.
1570
1547
  if (cfg.max.bytes && this.transaction.data_bytes > cfg.max.bytes) {
1571
- return;
1548
+ return
1572
1549
  }
1573
1550
 
1574
1551
  if (this.transaction.mime_part_count >= cfg.max.mime_parts) {
1575
- this.logcrit("Possible DoS attempt - too many MIME parts");
1576
- this.respond(554, "Transaction failed due to too many MIME parts", () => {
1577
- this.disconnect();
1578
- });
1579
- return;
1552
+ this.logcrit('Possible DoS attempt - too many MIME parts')
1553
+ this.respond(554, 'Transaction failed due to too many MIME parts', () => {
1554
+ this.disconnect()
1555
+ })
1556
+ return
1580
1557
  }
1581
1558
 
1582
- this.transaction.add_data(line);
1559
+ this.transaction.add_data(line)
1583
1560
  }
1584
- data_done () {
1585
- this.pause();
1586
- this.totalbytes += this.transaction.data_bytes;
1561
+ data_done() {
1562
+ this.pause()
1563
+ this.totalbytes += this.transaction.data_bytes
1587
1564
 
1588
1565
  // Check message size limit
1589
1566
  if (cfg.max.bytes && this.transaction.data_bytes > cfg.max.bytes) {
1590
- this.lognotice(`Incoming message exceeded max size of ${cfg.max.bytes}`);
1591
- return plugins.run_hooks('max_data_exceeded', this);
1567
+ this.lognotice(`Incoming message exceeded max size of ${cfg.max.bytes}`)
1568
+ return plugins.run_hooks('max_data_exceeded', this)
1592
1569
  }
1593
1570
 
1594
1571
  // Check max received headers count
1595
1572
  if (this.transaction.header.get_all('received').length > cfg.headers.max_received) {
1596
- this.logerror("Incoming message had too many Received headers");
1597
- this.respond(550, "Too many received headers - possible mail loop", () => {
1598
- this.reset_transaction();
1599
- });
1600
- return;
1573
+ this.logerror('Incoming message had too many Received headers')
1574
+ this.respond(550, 'Too many received headers - possible mail loop', () => {
1575
+ this.reset_transaction()
1576
+ })
1577
+ return
1601
1578
  }
1602
1579
 
1603
1580
  // Warn if we hit the maximum parsed header lines limit
1604
1581
  if (this.transaction.header_lines.length >= cfg.headers.max_lines) {
1605
- this.logwarn(`Incoming message reached maximum parsing limit of ${cfg.headers.max_lines} header lines`);
1582
+ this.logwarn(`Incoming message reached maximum parsing limit of ${cfg.headers.max_lines} header lines`)
1606
1583
  }
1607
1584
 
1608
1585
  if (cfg.headers.clean_auth_results) {
1609
- this.auth_results_clean(); // rename old A-R headers
1586
+ this.auth_results_clean() // rename old A-R headers
1610
1587
  }
1611
- const ar_field = this.auth_results(); // assemble new one
1588
+ const ar_field = this.auth_results() // assemble new one
1612
1589
  if (ar_field) {
1613
- this.transaction.add_header('Authentication-Results', ar_field);
1590
+ this.transaction.add_header('Authentication-Results', ar_field)
1614
1591
  }
1615
1592
 
1616
1593
  this.transaction.end_data(() => {
1617
1594
  // As this will be called asynchronously,
1618
1595
  // make sure we still have a transaction.
1619
- if (!this.transaction) return;
1596
+ if (!this.transaction) return
1620
1597
  // Record the start time of this hook as we can't take too long
1621
1598
  // as the client will typically hang up after 2 to 3 minutes
1622
1599
  // despite the RFC mandating that 10 minutes should be allowed.
1623
- this.transaction.data_post_start = Date.now();
1624
- plugins.run_hooks('data_post', this);
1625
- });
1626
- }
1627
- data_post_respond (retval, msg) {
1628
- if (!this.transaction) return;
1629
- this.transaction.data_post_delay = (Date.now() - this.transaction.data_post_start)/1000;
1630
- const mid = this.transaction.header.get('Message-ID') || '';
1631
- this.lognotice(
1632
- 'message',
1633
- {
1634
- 'mid': mid.replace(/\r?\n/,''),
1635
- 'size': this.transaction.data_bytes,
1636
- 'rcpts': `${this.transaction.rcpt_count.accept}/${this.transaction.rcpt_count.tempfail}/${this.transaction.rcpt_count.reject}`,
1637
- 'delay': this.transaction.data_post_delay,
1638
- 'code': constants.translate(retval),
1639
- 'msg': (msg || ''),
1640
- }
1641
- );
1642
- const ar_field = this.auth_results(); // assemble A-R header
1600
+ this.transaction.data_post_start = Date.now()
1601
+ plugins.run_hooks('data_post', this)
1602
+ })
1603
+ }
1604
+ data_post_respond(retval, msg) {
1605
+ if (!this.transaction) return
1606
+ this.transaction.data_post_delay = (Date.now() - this.transaction.data_post_start) / 1000
1607
+ const mid = this.transaction.header.get('Message-ID') || ''
1608
+ this.lognotice('message', {
1609
+ mid: mid.replace(/\r?\n/, ''),
1610
+ size: this.transaction.data_bytes,
1611
+ rcpts: `${this.transaction.rcpt_count.accept}/${this.transaction.rcpt_count.tempfail}/${this.transaction.rcpt_count.reject}`,
1612
+ delay: this.transaction.data_post_delay,
1613
+ code: constants.translate(retval),
1614
+ msg: msg || '',
1615
+ })
1616
+ const ar_field = this.auth_results() // assemble A-R header
1643
1617
  if (ar_field) {
1644
- this.transaction.remove_header('Authentication-Results');
1645
- this.transaction.add_leading_header('Authentication-Results', ar_field);
1618
+ this.transaction.remove_header('Authentication-Results')
1619
+ this.transaction.add_leading_header('Authentication-Results', ar_field)
1646
1620
  }
1647
1621
  switch (retval) {
1648
1622
  case constants.deny:
1649
- this.respond(550, msg || "Message denied", () => {
1650
- this.msg_count.reject++;
1651
- this.transaction.msg_status = 'rejected';
1652
- this.reset_transaction(() => this.resume());
1653
- });
1654
- break;
1623
+ this.respond(550, msg || 'Message denied', () => {
1624
+ this.msg_count.reject++
1625
+ this.transaction.msg_status = 'rejected'
1626
+ this.reset_transaction(() => this.resume())
1627
+ })
1628
+ break
1655
1629
  case constants.denydisconnect:
1656
- this.respond(550, msg || "Message denied",() => {
1657
- this.msg_count.reject++;
1658
- this.transaction.msg_status = 'rejected';
1659
- this.disconnect();
1660
- });
1661
- break;
1630
+ this.respond(550, msg || 'Message denied', () => {
1631
+ this.msg_count.reject++
1632
+ this.transaction.msg_status = 'rejected'
1633
+ this.disconnect()
1634
+ })
1635
+ break
1662
1636
  case constants.denysoft:
1663
- this.respond(450, msg || "Message denied temporarily", () => {
1664
- this.msg_count.tempfail++;
1665
- this.transaction.msg_status = 'deferred';
1666
- this.reset_transaction(() => this.resume());
1667
- });
1668
- break;
1637
+ this.respond(450, msg || 'Message denied temporarily', () => {
1638
+ this.msg_count.tempfail++
1639
+ this.transaction.msg_status = 'deferred'
1640
+ this.reset_transaction(() => this.resume())
1641
+ })
1642
+ break
1669
1643
  case constants.denysoftdisconnect:
1670
- this.respond(450, msg || "Message denied temporarily",() => {
1671
- this.msg_count.tempfail++;
1672
- this.transaction.msg_status = 'deferred';
1673
- this.disconnect();
1674
- });
1675
- break;
1644
+ this.respond(450, msg || 'Message denied temporarily', () => {
1645
+ this.msg_count.tempfail++
1646
+ this.transaction.msg_status = 'deferred'
1647
+ this.disconnect()
1648
+ })
1649
+ break
1676
1650
  default:
1677
1651
  if (this.relaying) {
1678
- plugins.run_hooks("queue_outbound", this);
1679
- }
1680
- else {
1681
- plugins.run_hooks("queue", this);
1652
+ plugins.run_hooks('queue_outbound', this)
1653
+ } else {
1654
+ plugins.run_hooks('queue', this)
1682
1655
  }
1683
1656
  }
1684
1657
  }
1685
- max_data_exceeded_respond (retval, msg) {
1658
+ max_data_exceeded_respond(retval, msg) {
1686
1659
  // TODO: Maybe figure out what to do with other return codes
1687
- this.respond(retval === constants.denysoft ? 450 : 550, "Message too big!", () => {
1688
- this.reset_transaction();
1689
- });
1660
+ this.respond(retval === constants.denysoft ? 450 : 550, 'Message too big!', () => {
1661
+ this.reset_transaction()
1662
+ })
1690
1663
  }
1691
- queue_msg (retval, msg) {
1664
+ queue_msg(retval, msg) {
1692
1665
  if (msg) {
1693
1666
  if (typeof msg === 'object' && msg.constructor.name === 'DSN') {
1694
1667
  return msg.reply
1695
1668
  }
1696
- return msg;
1669
+ return msg
1697
1670
  }
1698
1671
 
1699
1672
  switch (retval) {
1700
1673
  case constants.ok:
1701
- return 'Message Queued';
1674
+ return 'Message Queued'
1702
1675
  case constants.deny:
1703
1676
  case constants.denydisconnect:
1704
- return 'Message denied';
1677
+ return 'Message denied'
1705
1678
  case constants.denysoft:
1706
1679
  case constants.denysoftdisconnect:
1707
- return 'Message denied temporarily';
1680
+ return 'Message denied temporarily'
1708
1681
  default:
1709
- return '';
1682
+ return ''
1710
1683
  }
1711
1684
  }
1712
- store_queue_result (retval, msg) {
1713
- const res_as = {name: 'queue'};
1685
+ store_queue_result(retval, msg) {
1686
+ const res_as = { name: 'queue' }
1714
1687
  switch (retval) {
1715
1688
  case constants.ok:
1716
- this.transaction.results.add(res_as, { pass: msg });
1717
- break;
1689
+ this.transaction.results.add(res_as, { pass: msg })
1690
+ break
1718
1691
  case constants.deny:
1719
1692
  case constants.denydisconnect:
1720
1693
  case constants.denysoft:
1721
1694
  case constants.denysoftdisconnect:
1722
- this.transaction.results.add(res_as, { fail: msg });
1723
- break;
1695
+ this.transaction.results.add(res_as, { fail: msg })
1696
+ break
1724
1697
  case constants.cont:
1725
- break;
1698
+ break
1726
1699
  default:
1727
- this.transaction.results.add(res_as, { msg });
1728
- break;
1700
+ this.transaction.results.add(res_as, { msg })
1701
+ break
1729
1702
  }
1730
1703
  }
1731
- queue_outbound_respond (retval, msg) {
1732
- if (this.remote.closed) return;
1733
- msg = this.queue_msg(retval, msg) || 'Message Queued';
1734
- this.store_queue_result(retval, msg);
1735
- msg = `${msg} (${this.transaction.uuid})`;
1704
+ queue_outbound_respond(retval, msg) {
1705
+ if (this.remote.closed) return
1706
+ msg = this.queue_msg(retval, msg) || 'Message Queued'
1707
+ this.store_queue_result(retval, msg)
1708
+ msg = `${msg} (${this.transaction.uuid})`
1736
1709
  if (retval !== constants.ok) {
1737
- this.lognotice(
1738
- 'queue',
1739
- {
1740
- code: constants.translate(retval),
1741
- msg
1742
- }
1743
- );
1710
+ this.lognotice('queue', {
1711
+ code: constants.translate(retval),
1712
+ msg,
1713
+ })
1744
1714
  }
1745
1715
  switch (retval) {
1746
1716
  case constants.ok:
1747
- plugins.run_hooks('queue_ok', this, msg);
1748
- break;
1717
+ plugins.run_hooks('queue_ok', this, msg)
1718
+ break
1749
1719
  case constants.deny:
1750
1720
  this.respond(550, msg, () => {
1751
- this.msg_count.reject++;
1752
- this.transaction.msg_status = 'rejected';
1753
- this.reset_transaction(() => this.resume());
1754
- });
1755
- break;
1721
+ this.msg_count.reject++
1722
+ this.transaction.msg_status = 'rejected'
1723
+ this.reset_transaction(() => this.resume())
1724
+ })
1725
+ break
1756
1726
  case constants.denydisconnect:
1757
1727
  this.respond(550, msg, () => {
1758
- this.msg_count.reject++;
1759
- this.transaction.msg_status = 'rejected';
1760
- this.disconnect();
1761
- });
1762
- break;
1728
+ this.msg_count.reject++
1729
+ this.transaction.msg_status = 'rejected'
1730
+ this.disconnect()
1731
+ })
1732
+ break
1763
1733
  case constants.denysoft:
1764
1734
  this.respond(450, msg, () => {
1765
- this.msg_count.tempfail++;
1766
- this.transaction.msg_status = 'deferred';
1767
- this.reset_transaction(() => this.resume());
1768
- });
1769
- break;
1735
+ this.msg_count.tempfail++
1736
+ this.transaction.msg_status = 'deferred'
1737
+ this.reset_transaction(() => this.resume())
1738
+ })
1739
+ break
1770
1740
  case constants.denysoftdisconnect:
1771
1741
  this.respond(450, msg, () => {
1772
- this.msg_count.tempfail++;
1773
- this.transaction.msg_status = 'deferred';
1774
- this.disconnect();
1775
- });
1776
- break;
1742
+ this.msg_count.tempfail++
1743
+ this.transaction.msg_status = 'deferred'
1744
+ this.disconnect()
1745
+ })
1746
+ break
1777
1747
  default:
1778
1748
  outbound.send_trans_email(this.transaction, (retval2, msg2) => {
1779
- if (!msg2) msg2 = this.queue_msg(retval2, msg);
1749
+ if (!msg2) msg2 = this.queue_msg(retval2, msg)
1780
1750
  switch (retval2) {
1781
1751
  case constants.ok:
1782
- if (!msg2) msg2 = this.queue_msg(retval2, msg2);
1783
- plugins.run_hooks('queue_ok', this, msg2);
1784
- break;
1752
+ if (!msg2) msg2 = this.queue_msg(retval2, msg2)
1753
+ plugins.run_hooks('queue_ok', this, msg2)
1754
+ break
1785
1755
  case constants.deny:
1786
- if (!msg2) msg2 = this.queue_msg(retval2, msg2);
1756
+ if (!msg2) msg2 = this.queue_msg(retval2, msg2)
1787
1757
  this.respond(550, msg2, () => {
1788
- this.msg_count.reject++;
1789
- this.transaction.msg_status = 'rejected';
1758
+ this.msg_count.reject++
1759
+ this.transaction.msg_status = 'rejected'
1790
1760
  this.reset_transaction(() => {
1791
- this.resume();
1792
- });
1793
- });
1794
- break;
1761
+ this.resume()
1762
+ })
1763
+ })
1764
+ break
1795
1765
  default:
1796
- this.logerror(`Unrecognized response from outbound layer: ${retval2} : ${msg2}`);
1797
- this.respond(550, msg2 || "Internal Server Error", () => {
1798
- this.msg_count.reject++;
1799
- this.transaction.msg_status = 'rejected';
1766
+ this.logerror(`Unrecognized response from outbound layer: ${retval2} : ${msg2}`)
1767
+ this.respond(550, msg2 || 'Internal Server Error', () => {
1768
+ this.msg_count.reject++
1769
+ this.transaction.msg_status = 'rejected'
1800
1770
  this.reset_transaction(() => {
1801
- this.resume();
1802
- });
1803
- });
1771
+ this.resume()
1772
+ })
1773
+ })
1804
1774
  }
1805
- });
1775
+ })
1806
1776
  }
1807
1777
  }
1808
- queue_respond (retval, msg) {
1809
- msg = this.queue_msg(retval, msg);
1810
- this.store_queue_result(retval, msg);
1811
- msg = `${msg} (${this.transaction.uuid})`;
1778
+ queue_respond(retval, msg) {
1779
+ msg = this.queue_msg(retval, msg)
1780
+ this.store_queue_result(retval, msg)
1781
+ msg = `${msg} (${this.transaction.uuid})`
1812
1782
 
1813
1783
  if (retval !== constants.ok) {
1814
- this.lognotice(
1815
- 'queue',
1816
- {
1817
- code: constants.translate(retval),
1818
- msg
1819
- }
1820
- );
1784
+ this.lognotice('queue', {
1785
+ code: constants.translate(retval),
1786
+ msg,
1787
+ })
1821
1788
  }
1822
1789
  switch (retval) {
1823
1790
  case constants.ok:
1824
- plugins.run_hooks('queue_ok', this, msg);
1825
- break;
1791
+ plugins.run_hooks('queue_ok', this, msg)
1792
+ break
1826
1793
  case constants.deny:
1827
1794
  this.respond(550, msg, () => {
1828
- this.msg_count.reject++;
1829
- this.transaction.msg_status = 'rejected';
1830
- this.reset_transaction(() => this.resume());
1831
- });
1832
- break;
1795
+ this.msg_count.reject++
1796
+ this.transaction.msg_status = 'rejected'
1797
+ this.reset_transaction(() => this.resume())
1798
+ })
1799
+ break
1833
1800
  case constants.denydisconnect:
1834
1801
  this.respond(550, msg, () => {
1835
- this.msg_count.reject++;
1836
- this.transaction.msg_status = 'rejected';
1837
- this.disconnect();
1838
- });
1839
- break;
1802
+ this.msg_count.reject++
1803
+ this.transaction.msg_status = 'rejected'
1804
+ this.disconnect()
1805
+ })
1806
+ break
1840
1807
  case constants.denysoft:
1841
1808
  this.respond(450, msg, () => {
1842
- this.msg_count.tempfail++;
1843
- this.transaction.msg_status = 'deferred';
1844
- this.reset_transaction(() => this.resume());
1845
- });
1846
- break;
1809
+ this.msg_count.tempfail++
1810
+ this.transaction.msg_status = 'deferred'
1811
+ this.reset_transaction(() => this.resume())
1812
+ })
1813
+ break
1847
1814
  case constants.denysoftdisconnect:
1848
1815
  this.respond(450, msg, () => {
1849
- this.msg_count.tempfail++;
1850
- this.transaction.msg_status = 'deferred';
1851
- this.disconnect();
1852
- });
1853
- break;
1816
+ this.msg_count.tempfail++
1817
+ this.transaction.msg_status = 'deferred'
1818
+ this.disconnect()
1819
+ })
1820
+ break
1854
1821
  default:
1855
- if (!msg) msg = 'Queuing declined or disabled, try later';
1822
+ if (!msg) msg = 'Queuing declined or disabled, try later'
1856
1823
  this.respond(451, msg, () => {
1857
- this.msg_count.tempfail++;
1858
- this.transaction.msg_status = 'deferred';
1859
- this.reset_transaction(() => this.resume());
1860
- });
1861
- break;
1824
+ this.msg_count.tempfail++
1825
+ this.transaction.msg_status = 'deferred'
1826
+ this.reset_transaction(() => this.resume())
1827
+ })
1828
+ break
1862
1829
  }
1863
1830
  }
1864
- queue_ok_respond (retval, msg, params) {
1831
+ queue_ok_respond(retval, msg, params) {
1865
1832
  // This hook is common to both hook_queue and hook_queue_outbound
1866
1833
  // retval and msg are ignored in this hook so we always log OK
1867
- this.lognotice(
1868
- 'queue',
1869
- {
1870
- code: 'OK',
1871
- msg: (params || '')
1872
- }
1873
- );
1834
+ this.lognotice('queue', {
1835
+ code: 'OK',
1836
+ msg: params || '',
1837
+ })
1874
1838
 
1875
1839
  this.respond(250, params, () => {
1876
- this.msg_count.accept++;
1877
- if (this.transaction) this.transaction.msg_status = 'accepted';
1878
- this.reset_transaction(() => this.resume());
1879
- });
1840
+ this.msg_count.accept++
1841
+ if (this.transaction) this.transaction.msg_status = 'accepted'
1842
+ this.reset_transaction(() => this.resume())
1843
+ })
1880
1844
  }
1881
1845
  }
1882
1846
 
1883
- exports.Connection = Connection;
1847
+ exports.Connection = Connection
1884
1848
 
1885
1849
  exports.createConnection = (client, server, cfg) => {
1886
- return new Connection(client, server, cfg);
1850
+ return new Connection(client, server, cfg)
1887
1851
  }
1888
1852
 
1889
1853
  logger.add_log_methods(Connection)