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.
- package/.prettierignore +4 -0
- package/CONTRIBUTORS.md +5 -5
- package/Changes.md +69 -50
- package/Plugins.md +3 -1
- package/README.md +1 -1
- package/bin/haraka +475 -478
- package/config/outbound.ini +3 -0
- package/connection.js +1072 -1108
- package/docs/Connection.md +29 -30
- package/docs/CoreConfig.md +38 -39
- package/docs/CustomReturnCodes.md +0 -1
- package/docs/HAProxy.md +2 -2
- package/docs/Header.md +1 -1
- package/docs/Logging.md +29 -5
- package/docs/Outbound.md +93 -78
- package/docs/Plugins.md +103 -108
- package/docs/Transaction.md +49 -51
- package/docs/Tutorial.md +127 -143
- package/docs/deprecated/access.md +0 -1
- package/docs/deprecated/backscatterer.md +2 -3
- package/docs/deprecated/connect.rdns_access.md +18 -27
- package/docs/deprecated/data.headers.md +0 -1
- package/docs/deprecated/data.nomsgid.md +1 -2
- package/docs/deprecated/data.noreceived.md +1 -2
- package/docs/deprecated/data.rfc5322_header_checks.md +1 -2
- package/docs/deprecated/dkim_sign.md +13 -17
- package/docs/deprecated/dkim_verify.md +9 -17
- package/docs/deprecated/dnsbl.md +36 -38
- package/docs/deprecated/dnswl.md +41 -43
- package/docs/deprecated/lookup_rdns.strict.md +21 -34
- package/docs/deprecated/mail_from.access.md +17 -25
- package/docs/deprecated/mail_from.blocklist.md +9 -12
- package/docs/deprecated/mail_from.nobounces.md +1 -2
- package/docs/deprecated/rcpt_to.access.md +20 -27
- package/docs/deprecated/rcpt_to.blocklist.md +10 -13
- package/docs/deprecated/rcpt_to.routes.md +0 -1
- package/docs/deprecated/rdns.regexp.md +13 -15
- package/docs/plugins/aliases.md +89 -89
- package/docs/plugins/auth/auth_bridge.md +5 -7
- package/docs/plugins/auth/auth_ldap.md +11 -14
- package/docs/plugins/auth/auth_proxy.md +10 -12
- package/docs/plugins/auth/auth_vpopmaild.md +5 -6
- package/docs/plugins/auth/flat_file.md +4 -4
- package/docs/plugins/block_me.md +3 -3
- package/docs/plugins/data.signatures.md +1 -2
- package/docs/plugins/delay_deny.md +3 -4
- package/docs/plugins/max_unrecognized_commands.md +4 -4
- package/docs/plugins/prevent_credential_leaks.md +6 -6
- package/docs/plugins/process_title.md +18 -18
- package/docs/plugins/queue/deliver.md +2 -3
- package/docs/plugins/queue/discard.md +4 -4
- package/docs/plugins/queue/lmtp.md +1 -3
- package/docs/plugins/queue/qmail-queue.md +7 -9
- package/docs/plugins/queue/quarantine.md +16 -21
- package/docs/plugins/queue/rabbitmq.md +8 -11
- package/docs/plugins/queue/rabbitmq_amqplib.md +43 -39
- package/docs/plugins/queue/smtp_bridge.md +7 -10
- package/docs/plugins/queue/smtp_forward.md +42 -34
- package/docs/plugins/queue/smtp_proxy.md +30 -29
- package/docs/plugins/queue/test.md +1 -3
- package/docs/plugins/rcpt_to.in_host_list.md +6 -6
- package/docs/plugins/rcpt_to.max_count.md +1 -1
- package/docs/plugins/record_envelope_addresses.md +3 -3
- package/docs/plugins/reseed_rng.md +6 -6
- package/docs/plugins/status.md +9 -8
- package/docs/plugins/tarpit.md +7 -11
- package/docs/plugins/tls.md +12 -17
- package/docs/plugins/toobusy.md +4 -4
- package/docs/plugins/xclient.md +3 -3
- package/docs/tutorials/Migrating_from_v1_to_v2.md +19 -41
- package/docs/tutorials/SettingUpOutbound.md +6 -9
- package/endpoint.js +35 -38
- package/eslint.config.mjs +22 -19
- package/haraka.js +42 -47
- package/host_pool.js +75 -79
- package/http/html/404.html +45 -49
- package/http/html/index.html +39 -28
- package/http/package.json +2 -4
- package/line_socket.js +27 -28
- package/logger.js +182 -201
- package/outbound/client_pool.js +34 -27
- package/outbound/config.js +64 -59
- package/outbound/fsync_writestream.js +24 -25
- package/outbound/hmail.js +888 -835
- package/outbound/index.js +194 -187
- package/outbound/qfile.js +49 -52
- package/outbound/queue.js +197 -190
- package/outbound/timer_queue.js +41 -43
- package/outbound/tls.js +68 -61
- package/outbound/todo.js +11 -11
- package/package.json +38 -33
- package/plugins/.eslintrc.yaml +0 -1
- package/plugins/auth/auth_base.js +123 -127
- package/plugins/auth/auth_bridge.js +7 -7
- package/plugins/auth/auth_proxy.js +121 -126
- package/plugins/auth/auth_vpopmaild.js +84 -85
- package/plugins/auth/flat_file.js +18 -17
- package/plugins/block_me.js +31 -31
- package/plugins/data.signatures.js +13 -13
- package/plugins/delay_deny.js +65 -61
- package/plugins/prevent_credential_leaks.js +23 -23
- package/plugins/process_title.js +125 -128
- package/plugins/profile.js +5 -5
- package/plugins/queue/deliver.js +3 -3
- package/plugins/queue/discard.js +13 -14
- package/plugins/queue/lmtp.js +16 -17
- package/plugins/queue/qmail-queue.js +54 -55
- package/plugins/queue/quarantine.js +68 -70
- package/plugins/queue/rabbitmq.js +80 -87
- package/plugins/queue/rabbitmq_amqplib.js +75 -54
- package/plugins/queue/smtp_bridge.js +16 -16
- package/plugins/queue/smtp_forward.js +175 -179
- package/plugins/queue/smtp_proxy.js +69 -71
- package/plugins/queue/test.js +9 -9
- package/plugins/rcpt_to.host_list_base.js +30 -34
- package/plugins/rcpt_to.in_host_list.js +19 -19
- package/plugins/record_envelope_addresses.js +4 -4
- package/plugins/reseed_rng.js +4 -4
- package/plugins/status.js +90 -97
- package/plugins/tarpit.js +25 -14
- package/plugins/tls.js +68 -68
- package/plugins/toobusy.js +21 -23
- package/plugins/xclient.js +51 -53
- package/plugins.js +276 -293
- package/rfc1869.js +30 -35
- package/server.js +308 -299
- package/smtp_client.js +244 -228
- package/test/.eslintrc.yaml +0 -1
- package/test/connection.js +127 -134
- package/test/endpoint.js +53 -47
- package/test/fixtures/line_socket.js +12 -12
- package/test/fixtures/util_hmailitem.js +89 -85
- package/test/host_pool.js +90 -92
- package/test/installation/plugins/base_plugin.js +2 -2
- package/test/installation/plugins/folder_plugin/index.js +2 -3
- package/test/installation/plugins/inherits.js +3 -3
- package/test/installation/plugins/load_first.js +2 -3
- package/test/installation/plugins/plugin.js +1 -3
- package/test/installation/plugins/tls.js +2 -4
- package/test/logger.js +135 -116
- package/test/outbound/hmail.js +49 -35
- package/test/outbound/index.js +118 -101
- package/test/outbound/qfile.js +51 -53
- package/test/outbound_bounce_net_errors.js +84 -69
- package/test/outbound_bounce_rfc3464.js +235 -165
- package/test/plugins/auth/auth_base.js +420 -279
- package/test/plugins/auth/auth_vpopmaild.js +38 -39
- package/test/plugins/queue/smtp_forward.js +126 -104
- package/test/plugins/rcpt_to.host_list_base.js +85 -67
- package/test/plugins/rcpt_to.in_host_list.js +159 -112
- package/test/plugins/status.js +71 -64
- package/test/plugins/tls.js +37 -34
- package/test/plugins.js +97 -92
- package/test/rfc1869.js +19 -26
- package/test/server.js +293 -272
- package/test/smtp_client.js +180 -176
- package/test/tls_socket.js +62 -66
- package/test/transaction.js +159 -160
- package/tls_socket.js +331 -333
- package/transaction.js +129 -137
package/transaction.js
CHANGED
|
@@ -1,252 +1,244 @@
|
|
|
1
|
-
'use strict'
|
|
1
|
+
'use strict'
|
|
2
2
|
// An SMTP Transaction
|
|
3
3
|
|
|
4
|
-
const util
|
|
4
|
+
const util = require('node:util')
|
|
5
5
|
|
|
6
|
-
const Notes
|
|
7
|
-
const utils
|
|
6
|
+
const Notes = require('haraka-notes')
|
|
7
|
+
const utils = require('haraka-utils')
|
|
8
8
|
const message = require('haraka-email-message')
|
|
9
9
|
|
|
10
10
|
class Transaction {
|
|
11
|
-
constructor
|
|
12
|
-
this.uuid = uuid || utils.uuid()
|
|
13
|
-
this.cfg = cfg
|
|
14
|
-
this.mail_from = null
|
|
15
|
-
this.rcpt_to = []
|
|
16
|
-
this.header_lines = []
|
|
17
|
-
this.data_lines = []
|
|
18
|
-
this.attachment_start_hooks = []
|
|
19
|
-
this.banner = null
|
|
20
|
-
this.body_filters = []
|
|
21
|
-
this.data_bytes = 0
|
|
22
|
-
this.header_pos = 0
|
|
23
|
-
this.found_hb_sep = false
|
|
24
|
-
this.body = null
|
|
25
|
-
this.parse_body = false
|
|
26
|
-
this.notes = new Notes()
|
|
27
|
-
this.notes.skip_plugins = []
|
|
28
|
-
this.header = new message.Header()
|
|
29
|
-
this.message_stream = new message.stream(this.cfg, this.uuid, this.header.header_list)
|
|
30
|
-
this.discard_data = false
|
|
31
|
-
this.resetting = false
|
|
11
|
+
constructor(uuid, cfg = {}) {
|
|
12
|
+
this.uuid = uuid || utils.uuid()
|
|
13
|
+
this.cfg = cfg
|
|
14
|
+
this.mail_from = null
|
|
15
|
+
this.rcpt_to = []
|
|
16
|
+
this.header_lines = []
|
|
17
|
+
this.data_lines = []
|
|
18
|
+
this.attachment_start_hooks = []
|
|
19
|
+
this.banner = null
|
|
20
|
+
this.body_filters = []
|
|
21
|
+
this.data_bytes = 0
|
|
22
|
+
this.header_pos = 0
|
|
23
|
+
this.found_hb_sep = false
|
|
24
|
+
this.body = null
|
|
25
|
+
this.parse_body = false
|
|
26
|
+
this.notes = new Notes()
|
|
27
|
+
this.notes.skip_plugins = []
|
|
28
|
+
this.header = new message.Header()
|
|
29
|
+
this.message_stream = new message.stream(this.cfg, this.uuid, this.header.header_list)
|
|
30
|
+
this.discard_data = false
|
|
31
|
+
this.resetting = false
|
|
32
32
|
this.rcpt_count = {
|
|
33
33
|
accept: 0,
|
|
34
34
|
tempfail: 0,
|
|
35
35
|
reject: 0,
|
|
36
36
|
}
|
|
37
|
-
this.msg_status = undefined
|
|
38
|
-
this.data_post_start = null
|
|
39
|
-
this.data_post_delay = 0
|
|
40
|
-
this.encoding = 'utf8'
|
|
41
|
-
this.mime_part_count = 0
|
|
37
|
+
this.msg_status = undefined
|
|
38
|
+
this.data_post_start = null
|
|
39
|
+
this.data_post_delay = 0
|
|
40
|
+
this.encoding = 'utf8'
|
|
41
|
+
this.mime_part_count = 0
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
ensure_body
|
|
45
|
-
if (this.body) return
|
|
44
|
+
ensure_body() {
|
|
45
|
+
if (this.body) return
|
|
46
46
|
|
|
47
|
-
this.body = new message.Body(this.header)
|
|
48
|
-
this.body.on('mime_boundary', m => this.incr_mime_count())
|
|
47
|
+
this.body = new message.Body(this.header)
|
|
48
|
+
this.body.on('mime_boundary', (m) => this.incr_mime_count())
|
|
49
49
|
|
|
50
50
|
for (const hook of this.attachment_start_hooks) {
|
|
51
|
-
this.body.on('attachment_start', hook)
|
|
51
|
+
this.body.on('attachment_start', hook)
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
if (this.banner) this.body.set_banner(this.banner)
|
|
54
|
+
if (this.banner) this.body.set_banner(this.banner)
|
|
55
55
|
|
|
56
56
|
for (const o of this.body_filters) {
|
|
57
57
|
this.body.add_filter((ct, enc, buf) => {
|
|
58
|
-
const re_match =
|
|
59
|
-
const ct_begins = ct.toLowerCase().indexOf(String(o.ct_match).toLowerCase()) === 0
|
|
60
|
-
if (re_match || ct_begins) return o.filter(ct, enc, buf)
|
|
58
|
+
const re_match = util.types.isRegExp(o.ct_match) && o.ct_match.test(ct.toLowerCase())
|
|
59
|
+
const ct_begins = ct.toLowerCase().indexOf(String(o.ct_match).toLowerCase()) === 0
|
|
60
|
+
if (re_match || ct_begins) return o.filter(ct, enc, buf)
|
|
61
61
|
})
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
// Removes the CR of a CRLF newline at the end of the buffer.
|
|
66
|
-
remove_final_cr
|
|
67
|
-
if (data.length < 2) return data
|
|
68
|
-
if (!Buffer.isBuffer(data)) data = Buffer.from(data)
|
|
66
|
+
remove_final_cr(data) {
|
|
67
|
+
if (data.length < 2) return data
|
|
68
|
+
if (!Buffer.isBuffer(data)) data = Buffer.from(data)
|
|
69
69
|
|
|
70
|
-
if (data[data.length - 2] ===
|
|
71
|
-
data[data.length - 2] =
|
|
72
|
-
return data.slice(0, data.length - 1)
|
|
70
|
+
if (data[data.length - 2] === 0x0d && data[data.length - 1] === 0x0a) {
|
|
71
|
+
data[data.length - 2] = 0x0a
|
|
72
|
+
return data.slice(0, data.length - 1)
|
|
73
73
|
}
|
|
74
|
-
return data
|
|
74
|
+
return data
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
// Duplicates any '.' chars at the beginning of a line (dot-stuffing) and
|
|
78
78
|
// ensures all newlines are CRLF.
|
|
79
|
-
add_dot_stuffing_and_ensure_crlf_newlines
|
|
80
|
-
if (!data.length) return data
|
|
81
|
-
if (!Buffer.isBuffer(data)) data = Buffer.from(data)
|
|
79
|
+
add_dot_stuffing_and_ensure_crlf_newlines(data) {
|
|
80
|
+
if (!data.length) return data
|
|
81
|
+
if (!Buffer.isBuffer(data)) data = Buffer.from(data)
|
|
82
82
|
|
|
83
83
|
// Make a new buffer big enough to hold two bytes for every one input
|
|
84
84
|
// byte. At most, we add one extra character per input byte, so this
|
|
85
85
|
// is always big enough. We allocate it "unsafe" (i.e. no memset) for
|
|
86
86
|
// speed because we're about to fill it with data, and the remainder of
|
|
87
87
|
// the space we don't fill will be sliced away before we return this.
|
|
88
|
-
const output = Buffer.allocUnsafe(data.length * 2)
|
|
89
|
-
let output_pos = 0
|
|
88
|
+
const output = Buffer.allocUnsafe(data.length * 2)
|
|
89
|
+
let output_pos = 0
|
|
90
90
|
|
|
91
|
-
let input_pos = 0
|
|
92
|
-
let next_dot = data.indexOf(
|
|
93
|
-
let next_lf = data.indexOf(
|
|
91
|
+
let input_pos = 0
|
|
92
|
+
let next_dot = data.indexOf(0x2e)
|
|
93
|
+
let next_lf = data.indexOf(0x0a)
|
|
94
94
|
while (next_dot !== -1 || next_lf !== -1) {
|
|
95
|
-
const run_end =
|
|
96
|
-
? next_dot : next_lf;
|
|
95
|
+
const run_end = next_dot !== -1 && (next_lf === -1 || next_dot < next_lf) ? next_dot : next_lf
|
|
97
96
|
|
|
98
|
-
// Copy up
|
|
97
|
+
// Copy up to whichever comes first, '.' or '\n' (but don't
|
|
99
98
|
// copy the '.' or '\n' itself).
|
|
100
|
-
data.copy(output, output_pos, input_pos, run_end)
|
|
101
|
-
output_pos += run_end - input_pos
|
|
99
|
+
data.copy(output, output_pos, input_pos, run_end)
|
|
100
|
+
output_pos += run_end - input_pos
|
|
102
101
|
|
|
103
|
-
if (data[run_end] ===
|
|
102
|
+
if (data[run_end] === 0x2e && (run_end === 0 || data[run_end - 1] === 0x0a)) {
|
|
104
103
|
// Replace /^\./ with '..'
|
|
105
|
-
output[output_pos++] =
|
|
106
|
-
}
|
|
107
|
-
else if (data[run_end] === 0x0A && (run_end === 0 || data[run_end - 1] !== 0x0D)) {
|
|
104
|
+
output[output_pos++] = 0x2e
|
|
105
|
+
} else if (data[run_end] === 0x0a && (run_end === 0 || data[run_end - 1] !== 0x0d)) {
|
|
108
106
|
// Replace /\r?\n/ with '\r\n'
|
|
109
|
-
output[output_pos++] =
|
|
107
|
+
output[output_pos++] = 0x0d
|
|
110
108
|
}
|
|
111
|
-
output[output_pos++] = data[run_end]
|
|
109
|
+
output[output_pos++] = data[run_end]
|
|
112
110
|
|
|
113
|
-
input_pos = run_end + 1
|
|
111
|
+
input_pos = run_end + 1
|
|
114
112
|
|
|
115
113
|
if (run_end === next_dot) {
|
|
116
|
-
next_dot = data.indexOf(
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
next_lf = data.indexOf(0x0A, input_pos);
|
|
114
|
+
next_dot = data.indexOf(0x2e, input_pos)
|
|
115
|
+
} else {
|
|
116
|
+
next_lf = data.indexOf(0x0a, input_pos)
|
|
120
117
|
}
|
|
121
118
|
}
|
|
122
119
|
|
|
123
120
|
if (input_pos < data.length) {
|
|
124
|
-
data.copy(output, output_pos, input_pos)
|
|
125
|
-
output_pos += data.length - input_pos
|
|
121
|
+
data.copy(output, output_pos, input_pos)
|
|
122
|
+
output_pos += data.length - input_pos
|
|
126
123
|
}
|
|
127
124
|
|
|
128
|
-
return output.slice(0, output_pos)
|
|
125
|
+
return output.slice(0, output_pos)
|
|
129
126
|
}
|
|
130
127
|
|
|
131
|
-
add_data
|
|
132
|
-
if (typeof line === 'string') {
|
|
133
|
-
|
|
128
|
+
add_data(line) {
|
|
129
|
+
if (typeof line === 'string') {
|
|
130
|
+
// This shouldn't ever happen.
|
|
131
|
+
line = Buffer.from(line, this.encoding)
|
|
134
132
|
}
|
|
135
133
|
// is this the end of headers line?
|
|
136
|
-
if (this.header_pos === 0 &&
|
|
137
|
-
(
|
|
138
|
-
this.
|
|
139
|
-
this.
|
|
140
|
-
this.
|
|
141
|
-
|
|
142
|
-
}
|
|
143
|
-
else if (this.header_pos === 0) {
|
|
134
|
+
if (this.header_pos === 0 && (line[0] === 0x0a || (line[0] === 0x0d && line[1] === 0x0a))) {
|
|
135
|
+
this.header.parse(this.header_lines)
|
|
136
|
+
this.header_pos = this.header_lines.length
|
|
137
|
+
this.found_hb_sep = true
|
|
138
|
+
if (this.parse_body) this.ensure_body()
|
|
139
|
+
} else if (this.header_pos === 0) {
|
|
144
140
|
// Build up headers
|
|
145
141
|
if (this.header_lines.length < (this.cfg?.headers?.max_lines || 1000)) {
|
|
146
|
-
if (line[0] ===
|
|
147
|
-
this.header_lines.push(line.toString(this.encoding).replace(/\r\n$/, '\n'))
|
|
142
|
+
if (line[0] === 0x2e) line = line.slice(1) // Strip leading '.'
|
|
143
|
+
this.header_lines.push(line.toString(this.encoding).replace(/\r\n$/, '\n'))
|
|
148
144
|
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
if (new_line[0] === 0x2E) new_line = new_line.slice(1); // Strip leading "."
|
|
145
|
+
} else if (this.parse_body) {
|
|
146
|
+
let new_line = line
|
|
147
|
+
if (new_line[0] === 0x2e) new_line = new_line.slice(1) // Strip leading "."
|
|
153
148
|
|
|
154
|
-
line = this.add_dot_stuffing_and_ensure_crlf_newlines(
|
|
155
|
-
this.body.parse_more(this.remove_final_cr(new_line))
|
|
156
|
-
);
|
|
149
|
+
line = this.add_dot_stuffing_and_ensure_crlf_newlines(this.body.parse_more(this.remove_final_cr(new_line)))
|
|
157
150
|
|
|
158
|
-
if (!line.length) return
|
|
151
|
+
if (!line.length) return // buffering for banners
|
|
159
152
|
}
|
|
160
153
|
|
|
161
|
-
if (!this.discard_data) this.message_stream.add_line(line)
|
|
154
|
+
if (!this.discard_data) this.message_stream.add_line(line)
|
|
162
155
|
}
|
|
163
156
|
|
|
164
|
-
end_data
|
|
157
|
+
end_data(cb) {
|
|
165
158
|
if (!this.found_hb_sep && this.header_lines.length) {
|
|
166
159
|
// Headers not parsed yet - must be a busted email
|
|
167
160
|
// Strategy: Find the first line that doesn't look like a header.
|
|
168
161
|
// Treat anything before that as headers, anything after as body.
|
|
169
|
-
let header_pos = 0
|
|
162
|
+
let header_pos = 0
|
|
170
163
|
for (let i = 0; i < this.header_lines.length; i++) {
|
|
171
164
|
// Anything that doesn't match a header or continuation
|
|
172
165
|
if (!/^(?:([^\s:]*):\s*([\s\S]*)$|[ \t])/.test(this.header_lines[i])) {
|
|
173
|
-
break
|
|
166
|
+
break
|
|
174
167
|
}
|
|
175
|
-
header_pos = i
|
|
168
|
+
header_pos = i
|
|
176
169
|
}
|
|
177
|
-
const body_lines = this.header_lines.splice(header_pos + 1)
|
|
178
|
-
this.header.parse(this.header_lines)
|
|
179
|
-
this.header_pos = header_pos
|
|
170
|
+
const body_lines = this.header_lines.splice(header_pos + 1)
|
|
171
|
+
this.header.parse(this.header_lines)
|
|
172
|
+
this.header_pos = header_pos
|
|
180
173
|
if (this.parse_body) {
|
|
181
|
-
this.ensure_body()
|
|
174
|
+
this.ensure_body()
|
|
182
175
|
for (const bodyLine of body_lines) {
|
|
183
|
-
this.body.parse_more(bodyLine)
|
|
176
|
+
this.body.parse_more(bodyLine)
|
|
184
177
|
}
|
|
185
178
|
}
|
|
186
179
|
}
|
|
187
180
|
if (this.header_pos && this.parse_body) {
|
|
188
|
-
const line = this.add_dot_stuffing_and_ensure_crlf_newlines(this.body.parse_end())
|
|
181
|
+
const line = this.add_dot_stuffing_and_ensure_crlf_newlines(this.body.parse_end())
|
|
189
182
|
if (line.length) {
|
|
190
|
-
this.body.force_end()
|
|
183
|
+
this.body.force_end()
|
|
191
184
|
|
|
192
|
-
if (!this.discard_data) this.message_stream.add_line(line)
|
|
185
|
+
if (!this.discard_data) this.message_stream.add_line(line)
|
|
193
186
|
}
|
|
194
187
|
}
|
|
195
188
|
|
|
196
189
|
if (this.discard_data) {
|
|
197
|
-
cb()
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
this.message_stream.add_line_end(cb);
|
|
190
|
+
cb()
|
|
191
|
+
} else {
|
|
192
|
+
this.message_stream.add_line_end(cb)
|
|
201
193
|
}
|
|
202
194
|
}
|
|
203
195
|
|
|
204
|
-
add_header
|
|
205
|
-
this.header.add_end(key, value)
|
|
206
|
-
if (this.header_pos > 0) this.reset_headers()
|
|
196
|
+
add_header(key, value) {
|
|
197
|
+
this.header.add_end(key, value)
|
|
198
|
+
if (this.header_pos > 0) this.reset_headers()
|
|
207
199
|
}
|
|
208
200
|
|
|
209
|
-
add_leading_header
|
|
210
|
-
this.header.add(key, value)
|
|
211
|
-
if (this.header_pos > 0) this.reset_headers()
|
|
201
|
+
add_leading_header(key, value) {
|
|
202
|
+
this.header.add(key, value)
|
|
203
|
+
if (this.header_pos > 0) this.reset_headers()
|
|
212
204
|
}
|
|
213
205
|
|
|
214
|
-
reset_headers
|
|
215
|
-
const header_lines = this.header.lines()
|
|
216
|
-
this.header_pos = header_lines.length
|
|
206
|
+
reset_headers() {
|
|
207
|
+
const header_lines = this.header.lines()
|
|
208
|
+
this.header_pos = header_lines.length
|
|
217
209
|
}
|
|
218
210
|
|
|
219
|
-
remove_header
|
|
220
|
-
this.header.remove(key)
|
|
221
|
-
if (this.header_pos > 0) this.reset_headers()
|
|
211
|
+
remove_header(key) {
|
|
212
|
+
this.header.remove(key)
|
|
213
|
+
if (this.header_pos > 0) this.reset_headers()
|
|
222
214
|
}
|
|
223
215
|
|
|
224
|
-
attachment_hooks
|
|
225
|
-
this.parse_body = true
|
|
226
|
-
this.attachment_start_hooks.push(start)
|
|
216
|
+
attachment_hooks(start, data, end) {
|
|
217
|
+
this.parse_body = true
|
|
218
|
+
this.attachment_start_hooks.push(start)
|
|
227
219
|
}
|
|
228
220
|
|
|
229
|
-
set_banner
|
|
221
|
+
set_banner(text, html) {
|
|
230
222
|
// throw "transaction.set_banner is currently non-functional";
|
|
231
|
-
this.parse_body = true
|
|
223
|
+
this.parse_body = true
|
|
232
224
|
if (!html) {
|
|
233
|
-
html = text.replace(/\n/g, '<br/>\n')
|
|
225
|
+
html = text.replace(/\n/g, '<br/>\n')
|
|
234
226
|
}
|
|
235
|
-
this.banner = [text, html]
|
|
227
|
+
this.banner = [text, html]
|
|
236
228
|
}
|
|
237
229
|
|
|
238
|
-
add_body_filter
|
|
239
|
-
this.parse_body = true
|
|
240
|
-
this.body_filters.push({ ct_match, filter })
|
|
230
|
+
add_body_filter(ct_match, filter) {
|
|
231
|
+
this.parse_body = true
|
|
232
|
+
this.body_filters.push({ ct_match, filter })
|
|
241
233
|
}
|
|
242
234
|
|
|
243
|
-
incr_mime_count
|
|
244
|
-
this.mime_part_count
|
|
235
|
+
incr_mime_count(line) {
|
|
236
|
+
this.mime_part_count++
|
|
245
237
|
}
|
|
246
238
|
}
|
|
247
239
|
|
|
248
|
-
exports.Transaction = Transaction
|
|
240
|
+
exports.Transaction = Transaction
|
|
249
241
|
|
|
250
242
|
exports.createTransaction = (uuid, cfg) => {
|
|
251
|
-
return new Transaction(uuid, cfg)
|
|
243
|
+
return new Transaction(uuid, cfg)
|
|
252
244
|
}
|