haraka 0.0.32 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (310) hide show
  1. package/.claude/settings.local.json +28 -0
  2. package/.githooks/pre-commit +41 -0
  3. package/.prettierignore +6 -0
  4. package/.qlty/.gitignore +7 -0
  5. package/.qlty/configs/.shellcheckrc +1 -0
  6. package/.qlty/qlty.toml +15 -0
  7. package/CHANGELOG.md +1872 -62
  8. package/CLAUDE.md +40 -0
  9. package/CONTRIBUTORS.md +34 -0
  10. package/Dockerfile +50 -0
  11. package/GEMINI.md +38 -0
  12. package/LICENSE +2 -1
  13. package/Plugins.md +227 -0
  14. package/README.md +100 -115
  15. package/SECURITY.md +178 -0
  16. package/TODO +22 -0
  17. package/address.js +53 -0
  18. package/bin/haraka +593 -0
  19. package/bin/haraka_grep +32 -0
  20. package/config/aliases +2 -0
  21. package/config/auth_flat_file.ini +7 -0
  22. package/config/auth_vpopmaild.ini +9 -0
  23. package/config/connection.ini +79 -0
  24. package/config/delay_deny.ini +7 -0
  25. package/config/dhparams.pem +8 -0
  26. package/config/host_list +3 -0
  27. package/config/host_list_regex +6 -0
  28. package/config/http.ini +11 -0
  29. package/config/lmtp.ini +7 -0
  30. package/config/log.ini +11 -0
  31. package/config/me +1 -0
  32. package/config/outbound.bounce_message +18 -0
  33. package/config/outbound.bounce_message_html +36 -0
  34. package/config/outbound.bounce_message_image +106 -0
  35. package/config/outbound.ini +24 -0
  36. package/config/plugins +67 -0
  37. package/config/smtp.ini +37 -0
  38. package/config/smtp_bridge.ini +4 -0
  39. package/config/smtp_forward.ini +31 -0
  40. package/config/smtp_proxy.ini +27 -0
  41. package/config/tarpit.timeout +1 -0
  42. package/config/tls.ini +83 -0
  43. package/config/tls_cert.pem +23 -0
  44. package/config/tls_key.pem +28 -0
  45. package/config/watch.ini +12 -0
  46. package/config/xclient.hosts +2 -0
  47. package/connection.js +1863 -0
  48. package/contrib/Haraka.cf +6 -0
  49. package/contrib/Haraka.pm +35 -0
  50. package/contrib/bad_smtp_server.pl +25 -0
  51. package/contrib/bsd-rc.d/haraka +61 -0
  52. package/contrib/debian-init.d/haraka +87 -0
  53. package/contrib/haraka.init +96 -0
  54. package/contrib/haraka.service +23 -0
  55. package/contrib/plugin2npm.sh +81 -0
  56. package/contrib/ubuntu-upstart/haraka.conf +27 -0
  57. package/coverage/coverage-final.json +2 -0
  58. package/coverage/coverage-summary.json +33 -0
  59. package/coverage/tmp/coverage-79131-1779241025146-0.json +1 -0
  60. package/coverage/tmp/coverage-79132-1779240999690-0.json +1 -0
  61. package/coverage/tmp/coverage-79172-1779241000095-0.json +1 -0
  62. package/coverage/tmp/coverage-79210-1779241000156-0.json +1 -0
  63. package/coverage/tmp/coverage-79211-1779241000209-0.json +1 -0
  64. package/coverage/tmp/coverage-79212-1779241000266-0.json +1 -0
  65. package/coverage/tmp/coverage-79213-1779241000441-0.json +1 -0
  66. package/coverage/tmp/coverage-79214-1779241000626-0.json +1 -0
  67. package/coverage/tmp/coverage-79215-1779241000795-0.json +1 -0
  68. package/coverage/tmp/coverage-79216-1779241000965-0.json +1 -0
  69. package/coverage/tmp/coverage-79218-1779241001013-0.json +1 -0
  70. package/coverage/tmp/coverage-79219-1779241001179-0.json +1 -0
  71. package/coverage/tmp/coverage-79220-1779241006249-0.json +1 -0
  72. package/coverage/tmp/coverage-79227-1779241011453-0.json +1 -0
  73. package/coverage/tmp/coverage-79229-1779241011537-0.json +1 -0
  74. package/coverage/tmp/coverage-79230-1779241011647-0.json +1 -0
  75. package/coverage/tmp/coverage-79231-1779241011765-0.json +1 -0
  76. package/coverage/tmp/coverage-79232-1779241011841-0.json +1 -0
  77. package/coverage/tmp/coverage-79233-1779241011909-0.json +1 -0
  78. package/coverage/tmp/coverage-79234-1779241011984-0.json +1 -0
  79. package/coverage/tmp/coverage-79235-1779241012055-0.json +1 -0
  80. package/coverage/tmp/coverage-79236-1779241012230-0.json +1 -0
  81. package/coverage/tmp/coverage-79237-1779241012300-0.json +1 -0
  82. package/coverage/tmp/coverage-79238-1779241012368-0.json +1 -0
  83. package/coverage/tmp/coverage-79239-1779241012438-0.json +1 -0
  84. package/coverage/tmp/coverage-79240-1779241012511-0.json +1 -0
  85. package/coverage/tmp/coverage-79241-1779241012582-0.json +1 -0
  86. package/coverage/tmp/coverage-79242-1779241012652-0.json +1 -0
  87. package/coverage/tmp/coverage-79243-1779241012814-0.json +1 -0
  88. package/coverage/tmp/coverage-79244-1779241012931-0.json +1 -0
  89. package/coverage/tmp/coverage-79245-1779241013007-0.json +1 -0
  90. package/coverage/tmp/coverage-79246-1779241013106-0.json +1 -0
  91. package/coverage/tmp/coverage-79247-1779241013178-0.json +1 -0
  92. package/coverage/tmp/coverage-79248-1779241013244-0.json +1 -0
  93. package/coverage/tmp/coverage-79249-1779241013409-0.json +1 -0
  94. package/coverage/tmp/coverage-79250-1779241013697-0.json +1 -0
  95. package/coverage/tmp/coverage-79251-1779241013847-0.json +1 -0
  96. package/coverage/tmp/coverage-79252-1779241014288-0.json +1 -0
  97. package/coverage/tmp/coverage-79253-1779241014378-0.json +1 -0
  98. package/coverage/tmp/coverage-79254-1779241014428-0.json +1 -0
  99. package/coverage/tmp/coverage-79255-1779241021774-0.json +1 -0
  100. package/coverage/tmp/coverage-80382-1779241021949-0.json +1 -0
  101. package/coverage/tmp/coverage-80383-1779241025019-0.json +1 -0
  102. package/coverage/tmp/coverage-80384-1779241025133-0.json +1 -0
  103. package/docs/Body.md +1 -0
  104. package/docs/Config.md +1 -0
  105. package/docs/Connection.md +153 -0
  106. package/docs/CoreConfig.md +96 -0
  107. package/docs/CustomReturnCodes.md +3 -0
  108. package/docs/HAProxy.md +62 -0
  109. package/docs/Header.md +1 -0
  110. package/docs/Logging.md +129 -0
  111. package/docs/Outbound.md +210 -0
  112. package/docs/Plugins.md +372 -0
  113. package/docs/Results.md +7 -0
  114. package/docs/Transaction.md +135 -0
  115. package/docs/Tutorial.md +183 -0
  116. package/docs/deprecated/access.md +3 -0
  117. package/docs/deprecated/backscatterer.md +9 -0
  118. package/docs/deprecated/connect.rdns_access.md +53 -0
  119. package/docs/deprecated/data.headers.md +3 -0
  120. package/docs/deprecated/data.nomsgid.md +7 -0
  121. package/docs/deprecated/data.noreceived.md +11 -0
  122. package/docs/deprecated/data.rfc5322_header_checks.md +11 -0
  123. package/docs/deprecated/dkim_sign.md +97 -0
  124. package/docs/deprecated/dkim_verify.md +28 -0
  125. package/docs/deprecated/dnsbl.md +80 -0
  126. package/docs/deprecated/dnswl.md +73 -0
  127. package/docs/deprecated/lookup_rdns.strict.md +67 -0
  128. package/docs/deprecated/mail_from.access.md +52 -0
  129. package/docs/deprecated/mail_from.blocklist.md +18 -0
  130. package/docs/deprecated/mail_from.nobounces.md +8 -0
  131. package/docs/deprecated/rcpt_to.access.md +53 -0
  132. package/docs/deprecated/rcpt_to.blocklist.md +18 -0
  133. package/docs/deprecated/rcpt_to.routes.md +3 -0
  134. package/docs/deprecated/rdns.regexp.md +30 -0
  135. package/docs/plugins/aliases.md +3 -0
  136. package/docs/plugins/auth/auth_bridge.md +34 -0
  137. package/docs/plugins/auth/auth_ldap.md +4 -0
  138. package/docs/plugins/auth/auth_proxy.md +36 -0
  139. package/docs/plugins/auth/auth_vpopmaild.md +33 -0
  140. package/docs/plugins/auth/flat_file.md +40 -0
  141. package/docs/plugins/block_me.md +18 -0
  142. package/docs/plugins/data.signatures.md +11 -0
  143. package/docs/plugins/delay_deny.md +23 -0
  144. package/docs/plugins/max_unrecognized_commands.md +6 -0
  145. package/docs/plugins/prevent_credential_leaks.md +22 -0
  146. package/docs/plugins/process_title.md +42 -0
  147. package/docs/plugins/queue/deliver.md +3 -0
  148. package/docs/plugins/queue/discard.md +32 -0
  149. package/docs/plugins/queue/lmtp.md +24 -0
  150. package/docs/plugins/queue/qmail-queue.md +16 -0
  151. package/docs/plugins/queue/quarantine.md +87 -0
  152. package/docs/plugins/queue/smtp_bridge.md +32 -0
  153. package/docs/plugins/queue/smtp_forward.md +127 -0
  154. package/docs/plugins/queue/smtp_proxy.md +68 -0
  155. package/docs/plugins/queue/test.md +7 -0
  156. package/docs/plugins/rcpt_to.in_host_list.md +34 -0
  157. package/docs/plugins/rcpt_to.max_count.md +3 -0
  158. package/docs/plugins/record_envelope_addresses.md +20 -0
  159. package/docs/plugins/relay.md +3 -0
  160. package/docs/plugins/reseed_rng.md +16 -0
  161. package/docs/plugins/status.md +41 -0
  162. package/docs/plugins/tarpit.md +50 -0
  163. package/docs/plugins/tls.md +235 -0
  164. package/docs/plugins/toobusy.md +27 -0
  165. package/docs/plugins/xclient.md +10 -0
  166. package/docs/tutorials/Migrating_from_v1_to_v2.md +96 -0
  167. package/docs/tutorials/SettingUpOutbound.md +62 -0
  168. package/eslint.config.mjs +2 -0
  169. package/haraka.js +74 -0
  170. package/haraka.sh +2 -0
  171. package/http/html/404.html +58 -0
  172. package/http/html/index.html +47 -0
  173. package/http/package.json +21 -0
  174. package/line_socket.js +24 -0
  175. package/logger.js +322 -0
  176. package/outbound/client_pool.js +59 -0
  177. package/outbound/config.js +134 -0
  178. package/outbound/hmail.js +1504 -0
  179. package/outbound/index.js +349 -0
  180. package/outbound/qfile.js +93 -0
  181. package/outbound/queue.js +399 -0
  182. package/outbound/tls.js +85 -0
  183. package/outbound/todo.js +17 -0
  184. package/package.json +91 -29
  185. package/plugins/.eslintrc.yaml +3 -0
  186. package/plugins/auth/auth_base.js +261 -0
  187. package/plugins/auth/auth_bridge.js +20 -0
  188. package/plugins/auth/auth_proxy.js +227 -0
  189. package/plugins/auth/auth_vpopmaild.js +162 -0
  190. package/plugins/auth/flat_file.js +44 -0
  191. package/plugins/block_me.js +88 -0
  192. package/plugins/data.signatures.js +30 -0
  193. package/plugins/delay_deny.js +153 -0
  194. package/plugins/prevent_credential_leaks.js +61 -0
  195. package/plugins/process_title.js +197 -0
  196. package/plugins/profile.js +11 -0
  197. package/plugins/queue/deliver.js +12 -0
  198. package/plugins/queue/discard.js +27 -0
  199. package/plugins/queue/lmtp.js +45 -0
  200. package/plugins/queue/qmail-queue.js +93 -0
  201. package/plugins/queue/quarantine.js +133 -0
  202. package/plugins/queue/smtp_bridge.js +45 -0
  203. package/plugins/queue/smtp_forward.js +371 -0
  204. package/plugins/queue/smtp_proxy.js +142 -0
  205. package/plugins/queue/test.js +15 -0
  206. package/plugins/rcpt_to.host_list_base.js +65 -0
  207. package/plugins/rcpt_to.in_host_list.js +56 -0
  208. package/plugins/record_envelope_addresses.js +17 -0
  209. package/plugins/reseed_rng.js +7 -0
  210. package/plugins/status.js +274 -0
  211. package/plugins/tarpit.js +45 -0
  212. package/plugins/tls.js +164 -0
  213. package/plugins/toobusy.js +47 -0
  214. package/plugins/xclient.js +124 -0
  215. package/plugins.js +604 -0
  216. package/queue/1772642154987_1775581346001_4_82235_TGwgfd_2_mattbook-m3.home.simerson.net +0 -0
  217. package/run_tests +11 -0
  218. package/server.js +827 -0
  219. package/smtp_client.js +504 -0
  220. package/test/.eslintrc.yaml +11 -0
  221. package/test/config/auth_flat_file.ini +5 -0
  222. package/test/config/block_me.recipient +1 -0
  223. package/test/config/block_me.senders +1 -0
  224. package/test/config/dhparams.pem +8 -0
  225. package/test/config/host_list +2 -0
  226. package/test/config/outbound_tls_cert.pem +1 -0
  227. package/test/config/outbound_tls_key.pem +1 -0
  228. package/test/config/plugins +7 -0
  229. package/test/config/smtp.ini +11 -0
  230. package/test/config/smtp_forward.ini +30 -0
  231. package/test/config/tls/example.com/_.example.com.key +28 -0
  232. package/test/config/tls/example.com/example.com.crt +25 -0
  233. package/test/config/tls/haraka.local.pem +51 -0
  234. package/test/config/tls.ini +45 -0
  235. package/test/config/tls_cert.pem +21 -0
  236. package/test/config/tls_key.pem +28 -0
  237. package/test/connection.js +817 -0
  238. package/test/fixtures/haproxy_allowed/config/connection.ini +3 -0
  239. package/test/fixtures/haproxy_disabled/config/connection.ini +3 -0
  240. package/test/fixtures/haproxy_untrusted/config/connection.ini +3 -0
  241. package/test/fixtures/line_socket.js +21 -0
  242. package/test/fixtures/todo_qfile.txt +0 -0
  243. package/test/fixtures/util_hmailitem.js +156 -0
  244. package/test/installation/config/test-plugin-flat +1 -0
  245. package/test/installation/config/test-plugin.ini +10 -0
  246. package/test/installation/config/tls.ini +1 -0
  247. package/test/installation/node_modules/load_first/index.js +5 -0
  248. package/test/installation/node_modules/load_first/package.json +11 -0
  249. package/test/installation/node_modules/test-plugin/config/test-plugin-flat +1 -0
  250. package/test/installation/node_modules/test-plugin/config/test-plugin.ini +9 -0
  251. package/test/installation/node_modules/test-plugin/package.json +5 -0
  252. package/test/installation/node_modules/test-plugin/test-plugin.js +5 -0
  253. package/test/installation/plugins/base_plugin.js +3 -0
  254. package/test/installation/plugins/folder_plugin/index.js +3 -0
  255. package/test/installation/plugins/folder_plugin/package.json +11 -0
  256. package/test/installation/plugins/inherits.js +7 -0
  257. package/test/installation/plugins/load_first.js +3 -0
  258. package/test/installation/plugins/plugin.js +1 -0
  259. package/test/installation/plugins/tls.js +3 -0
  260. package/test/logger.js +217 -0
  261. package/test/loud/config/dhparams.pem +0 -0
  262. package/test/loud/config/tls/goobered.pem +45 -0
  263. package/test/loud/config/tls.ini +43 -0
  264. package/test/mail_specimen/base64-root-part.txt +23 -0
  265. package/test/mail_specimen/varied-fold-lengths-preserve-data.txt +283 -0
  266. package/test/outbound/bounce_net_errors.js +133 -0
  267. package/test/outbound/bounce_rfc3464.js +226 -0
  268. package/test/outbound/hmail.js +210 -0
  269. package/test/outbound/index.js +385 -0
  270. package/test/outbound/qfile.js +124 -0
  271. package/test/outbound/queue.js +325 -0
  272. package/test/plugins/auth/auth_base.js +620 -0
  273. package/test/plugins/auth/auth_bridge.js +80 -0
  274. package/test/plugins/auth/auth_vpopmaild.js +81 -0
  275. package/test/plugins/auth/flat_file.js +123 -0
  276. package/test/plugins/block_me.js +141 -0
  277. package/test/plugins/data.signatures.js +111 -0
  278. package/test/plugins/delay_deny.js +262 -0
  279. package/test/plugins/prevent_credential_leaks.js +174 -0
  280. package/test/plugins/process_title.js +141 -0
  281. package/test/plugins/queue/deliver.js +98 -0
  282. package/test/plugins/queue/discard.js +78 -0
  283. package/test/plugins/queue/lmtp.js +137 -0
  284. package/test/plugins/queue/qmail-queue.js +98 -0
  285. package/test/plugins/queue/quarantine.js +80 -0
  286. package/test/plugins/queue/smtp_bridge.js +152 -0
  287. package/test/plugins/queue/smtp_forward.js +1023 -0
  288. package/test/plugins/queue/smtp_proxy.js +138 -0
  289. package/test/plugins/rcpt_to.host_list_base.js +102 -0
  290. package/test/plugins/rcpt_to.in_host_list.js +186 -0
  291. package/test/plugins/record_envelope_addresses.js +66 -0
  292. package/test/plugins/reseed_rng.js +34 -0
  293. package/test/plugins/status.js +207 -0
  294. package/test/plugins/tarpit.js +90 -0
  295. package/test/plugins/tls.js +86 -0
  296. package/test/plugins/toobusy.js +21 -0
  297. package/test/plugins/xclient.js +119 -0
  298. package/test/plugins.js +230 -0
  299. package/test/queue/1507509981169_1507509981169_0_61403_e0Y0Ym_1_fixed +0 -0
  300. package/test/queue/1507509981169_1507509981169_0_61403_e0Y0Ym_1_haraka +0 -0
  301. package/test/queue/1508269674999_1508269674999_0_34002_socVUF_1_haraka +0 -0
  302. package/test/queue/1508455115683_1508455115683_0_90253_9Q4o4V_1_haraka +0 -0
  303. package/test/queue/zero-length +0 -0
  304. package/test/server.js +1012 -0
  305. package/test/smtp_client.js +1303 -0
  306. package/test/tls_socket.js +321 -0
  307. package/test/transaction.js +554 -0
  308. package/tls_socket.js +771 -0
  309. package/transaction.js +267 -0
  310. package/lib/index.js +0 -371
package/transaction.js ADDED
@@ -0,0 +1,267 @@
1
+ 'use strict'
2
+ // An SMTP Transaction
3
+
4
+ const util = require('node:util')
5
+
6
+ const Notes = require('haraka-notes')
7
+ const utils = require('haraka-utils')
8
+ const message = require('haraka-email-message')
9
+
10
+ class Transaction {
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
+ this.rcpt_count = {
33
+ accept: 0,
34
+ tempfail: 0,
35
+ reject: 0,
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
42
+ }
43
+
44
+ ensure_body() {
45
+ if (this.body) return
46
+
47
+ this.body = new message.Body(this.header)
48
+ this.body.on('mime_boundary', () => this.incr_mime_count())
49
+
50
+ for (const hook of this.attachment_start_hooks) {
51
+ this.body.on('attachment_start', hook)
52
+ }
53
+
54
+ if (this.banner) this.body.set_banner(this.banner)
55
+
56
+ for (const o of this.body_filters) {
57
+ this.body.add_filter((ct, enc, buf) => {
58
+ if (!ct) return buf
59
+ const ct_lc = String(ct).toLowerCase().trim()
60
+ const re_match = util.types.isRegExp(o.ct_match) && o.ct_match.test(ct_lc)
61
+ const ct_begins = ct_lc.indexOf(String(o.ct_match).toLowerCase()) === 0
62
+ if (re_match || ct_begins) return o.filter(ct, enc, buf) || buf
63
+ return buf
64
+ })
65
+ }
66
+ }
67
+
68
+ // Removes the CR of a CRLF newline at the end of the buffer.
69
+ remove_final_cr(data) {
70
+ if (data.length < 2) return data
71
+ if (!Buffer.isBuffer(data)) data = Buffer.from(data)
72
+
73
+ if (data[data.length - 2] === 0x0d && data[data.length - 1] === 0x0a) {
74
+ data[data.length - 2] = 0x0a
75
+ return data.slice(0, data.length - 1)
76
+ }
77
+ return data
78
+ }
79
+
80
+ // Duplicates any '.' chars at the beginning of a line (dot-stuffing) and
81
+ // ensures all newlines are CRLF.
82
+ add_dot_stuffing_and_ensure_crlf_newlines(data) {
83
+ if (!data.length) return data
84
+ if (!Buffer.isBuffer(data)) data = Buffer.from(data)
85
+
86
+ // Make a new buffer big enough to hold two bytes for every one input
87
+ // byte. At most, we add one extra character per input byte, so this
88
+ // is always big enough. We allocate it "unsafe" (i.e. no memset) for
89
+ // speed because we're about to fill it with data, and the remainder of
90
+ // the space we don't fill will be sliced away before we return this.
91
+ const output = Buffer.allocUnsafe(data.length * 2)
92
+ let output_pos = 0
93
+
94
+ let input_pos = 0
95
+ let next_dot = data.indexOf(0x2e)
96
+ let next_lf = data.indexOf(0x0a)
97
+ while (next_dot !== -1 || next_lf !== -1) {
98
+ const run_end = next_dot !== -1 && (next_lf === -1 || next_dot < next_lf) ? next_dot : next_lf
99
+
100
+ // Copy up to whichever comes first, '.' or '\n' (but don't
101
+ // copy the '.' or '\n' itself).
102
+ data.copy(output, output_pos, input_pos, run_end)
103
+ output_pos += run_end - input_pos
104
+
105
+ if (data[run_end] === 0x2e && (run_end === 0 || data[run_end - 1] === 0x0a)) {
106
+ // Replace /^\./ with '..'
107
+ output[output_pos++] = 0x2e
108
+ } else if (data[run_end] === 0x0a && (run_end === 0 || data[run_end - 1] !== 0x0d)) {
109
+ // Replace /\r?\n/ with '\r\n'
110
+ output[output_pos++] = 0x0d
111
+ }
112
+ output[output_pos++] = data[run_end]
113
+
114
+ input_pos = run_end + 1
115
+
116
+ if (run_end === next_dot) {
117
+ next_dot = data.indexOf(0x2e, input_pos)
118
+ } else {
119
+ next_lf = data.indexOf(0x0a, input_pos)
120
+ }
121
+ }
122
+
123
+ if (input_pos < data.length) {
124
+ data.copy(output, output_pos, input_pos)
125
+ output_pos += data.length - input_pos
126
+ }
127
+
128
+ return output.slice(0, output_pos)
129
+ }
130
+
131
+ add_data(line) {
132
+ if (typeof line === 'string') {
133
+ // This shouldn't ever happen.
134
+ line = Buffer.from(line, this.encoding)
135
+ }
136
+ // is this the end of headers line?
137
+ if (this.header_pos === 0 && (line[0] === 0x0a || (line[0] === 0x0d && line[1] === 0x0a))) {
138
+ this.header.parse(this.header_lines)
139
+ this.header_pos = this.header.header_list ? this.header.header_list.length : -1
140
+ this.found_hb_sep = true
141
+ if (this.parse_body) this.ensure_body()
142
+ } else if (this.header_pos === 0) {
143
+ // Build up headers
144
+ if (this.header_lines.length < (this.cfg?.headers?.max_lines || 1000)) {
145
+ if (line[0] === 0x2e) line = line.slice(1) // Strip leading '.'
146
+ this.header_lines.push(line.toString(this.encoding).replace(/\r\n$/, '\n'))
147
+ }
148
+ } else if (this.parse_body) {
149
+ this.ensure_body()
150
+ let new_line = line
151
+ if (new_line[0] === 0x2e) new_line = new_line.slice(1) // Strip leading "."
152
+
153
+ line = this.add_dot_stuffing_and_ensure_crlf_newlines(this.body.parse_more(this.remove_final_cr(new_line)))
154
+
155
+ if (!line.length) return // buffering for banners
156
+ }
157
+
158
+ if (!this.discard_data) this.message_stream.add_line(line)
159
+ }
160
+
161
+ end_data(cb) {
162
+ if (!this.found_hb_sep && this.header_lines.length) {
163
+ // Headers not parsed yet - must be a busted email
164
+ // Strategy: Find the first line that doesn't look like a header.
165
+ // Treat anything before that as headers, anything after as body.
166
+ let header_pos = 0
167
+ for (let i = 0; i < this.header_lines.length; i++) {
168
+ // Anything that doesn't match a header or continuation
169
+ if (!/^(?:([^\s:]*):\s*([\s\S]*)$|[ \t])/.test(this.header_lines[i])) {
170
+ break
171
+ }
172
+ header_pos = i
173
+ }
174
+ const body_lines = this.header_lines.splice(header_pos + 1)
175
+ this.header.parse(this.header_lines)
176
+ this.header_pos = this.header.header_list ? this.header.header_list.length : -1
177
+ this.found_hb_sep = true
178
+
179
+ // We MUST add an empty line to the message_stream so that it knows
180
+ // where the headers end. Otherwise it skips everything.
181
+ if (!this.discard_data) this.message_stream.add_line(Buffer.from('\r\n'))
182
+
183
+ if (this.parse_body) {
184
+ this.ensure_body()
185
+ for (const bodyLine of body_lines) {
186
+ this.body.parse_more(bodyLine)
187
+ }
188
+ }
189
+
190
+ for (const bodyLine of body_lines) {
191
+ if (!this.discard_data) this.message_stream.add_line(Buffer.from(`${bodyLine}\n`))
192
+ }
193
+ }
194
+ if (this.header_pos && this.parse_body) {
195
+ const line = this.add_dot_stuffing_and_ensure_crlf_newlines(this.body.parse_end())
196
+ if (line.length) {
197
+ this.body.force_end()
198
+
199
+ if (!this.discard_data) this.message_stream.add_line(line)
200
+ }
201
+ }
202
+
203
+ if (this.discard_data) {
204
+ cb()
205
+ } else {
206
+ this.message_stream.add_line_end(cb)
207
+ }
208
+ }
209
+
210
+ add_header(key, value) {
211
+ this.header.add_end(key, value)
212
+ if (this.found_hb_sep) this.reset_headers()
213
+ }
214
+
215
+ add_leading_header(key, value) {
216
+ this.header.add(key, value)
217
+ if (this.found_hb_sep) this.reset_headers()
218
+ }
219
+
220
+ reset_headers() {
221
+ this.header_pos = this.header.header_list ? this.header.header_list.length : -1
222
+ }
223
+
224
+ remove_header(key) {
225
+ this.header.remove(key)
226
+ if (this.found_hb_sep) this.reset_headers()
227
+ }
228
+
229
+ attachment_hooks(start) {
230
+ this.parse_body = true
231
+ this.attachment_start_hooks.push(start)
232
+ }
233
+
234
+ set_banner(text, html) {
235
+ // throw "transaction.set_banner is currently non-functional";
236
+ this.parse_body = true
237
+ if (!html) {
238
+ html = text.replace(/\n/g, '<br/>\n')
239
+ }
240
+ this.banner = [text, html]
241
+ }
242
+
243
+ add_body_filter(ct_match, filter) {
244
+ this.parse_body = true
245
+ this.body_filters.push({ ct_match, filter })
246
+ if (this.body) {
247
+ this.body.add_filter((ct, enc, buf) => {
248
+ if (!ct) return buf
249
+ const ct_lc = String(ct).toLowerCase().trim()
250
+ const re_match = util.types.isRegExp(ct_match) && ct_match.test(ct_lc)
251
+ const ct_begins = ct_lc.indexOf(String(ct_match).toLowerCase()) === 0
252
+ if (re_match || ct_begins) return filter(ct, enc, buf) || buf
253
+ return buf
254
+ })
255
+ }
256
+ }
257
+
258
+ incr_mime_count() {
259
+ this.mime_part_count++
260
+ }
261
+ }
262
+
263
+ exports.Transaction = Transaction
264
+
265
+ exports.createTransaction = (uuid, cfg) => {
266
+ return new Transaction(uuid, cfg)
267
+ }
package/lib/index.js DELETED
@@ -1,371 +0,0 @@
1
- 'use strict';
2
-
3
- function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
4
-
5
- var React = _interopDefault(require('react'));
6
- var reactNative = require('react-native');
7
-
8
- var classCallCheck = function (instance, Constructor) {
9
- if (!(instance instanceof Constructor)) {
10
- throw new TypeError("Cannot call a class as a function");
11
- }
12
- };
13
-
14
- var createClass = function () {
15
- function defineProperties(target, props) {
16
- for (var i = 0; i < props.length; i++) {
17
- var descriptor = props[i];
18
- descriptor.enumerable = descriptor.enumerable || false;
19
- descriptor.configurable = true;
20
- if ("value" in descriptor) descriptor.writable = true;
21
- Object.defineProperty(target, descriptor.key, descriptor);
22
- }
23
- }
24
-
25
- return function (Constructor, protoProps, staticProps) {
26
- if (protoProps) defineProperties(Constructor.prototype, protoProps);
27
- if (staticProps) defineProperties(Constructor, staticProps);
28
- return Constructor;
29
- };
30
- }();
31
-
32
- var defineProperty = function (obj, key, value) {
33
- if (key in obj) {
34
- Object.defineProperty(obj, key, {
35
- value: value,
36
- enumerable: true,
37
- configurable: true,
38
- writable: true
39
- });
40
- } else {
41
- obj[key] = value;
42
- }
43
-
44
- return obj;
45
- };
46
-
47
- var _extends = Object.assign || function (target) {
48
- for (var i = 1; i < arguments.length; i++) {
49
- var source = arguments[i];
50
-
51
- for (var key in source) {
52
- if (Object.prototype.hasOwnProperty.call(source, key)) {
53
- target[key] = source[key];
54
- }
55
- }
56
- }
57
-
58
- return target;
59
- };
60
-
61
- var inherits = function (subClass, superClass) {
62
- if (typeof superClass !== "function" && superClass !== null) {
63
- throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
64
- }
65
-
66
- subClass.prototype = Object.create(superClass && superClass.prototype, {
67
- constructor: {
68
- value: subClass,
69
- enumerable: false,
70
- writable: true,
71
- configurable: true
72
- }
73
- });
74
- if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
75
- };
76
-
77
- var objectWithoutProperties = function (obj, keys) {
78
- var target = {};
79
-
80
- for (var i in obj) {
81
- if (keys.indexOf(i) >= 0) continue;
82
- if (!Object.prototype.hasOwnProperty.call(obj, i)) continue;
83
- target[i] = obj[i];
84
- }
85
-
86
- return target;
87
- };
88
-
89
- var possibleConstructorReturn = function (self, call) {
90
- if (!self) {
91
- throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
92
- }
93
-
94
- return call && (typeof call === "object" || typeof call === "function") ? call : self;
95
- };
96
-
97
- var toConsumableArray = function (arr) {
98
- if (Array.isArray(arr)) {
99
- for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
100
-
101
- return arr2;
102
- } else {
103
- return Array.from(arr);
104
- }
105
- };
106
-
107
- var Behavior = function (_React$PureComponent) {
108
- inherits(Behavior, _React$PureComponent);
109
-
110
- function Behavior(props) {
111
- classCallCheck(this, Behavior);
112
-
113
- var _this = possibleConstructorReturn(this, (Behavior.__proto__ || Object.getPrototypeOf(Behavior)).call(this, props));
114
-
115
- _initialiseProps.call(_this);
116
-
117
- var _this$props = _this.props,
118
- initialState = _this$props.initialState,
119
- nativeDriver = _this$props.nativeDriver,
120
- driver = _this$props.driver,
121
- unmounted = _this$props.unmounted;
122
-
123
-
124
- _this.nativeDriver = nativeDriver || new reactNative.Animated.Value(initialState);
125
- _this.driver = driver || new reactNative.Animated.Value(initialState);
126
-
127
- _this.key = initialState;
128
-
129
- _this.state = { mounted: !unmounted };
130
- return _this;
131
- }
132
-
133
- createClass(Behavior, [{
134
- key: 'componentWillReceiveProps',
135
- value: function componentWillReceiveProps(nextProps) {
136
- var currentState = this.props.currentState;
137
- var nextCurrentState = nextProps.currentState;
138
-
139
-
140
- if (currentState !== nextCurrentState) {
141
- this.goTo(nextCurrentState);
142
- }
143
- }
144
- }, {
145
- key: 'render',
146
- value: function render() {
147
- var _this2 = this;
148
-
149
- var mounted = this.state.mounted;
150
-
151
-
152
- if (!mounted) return null;
153
-
154
- var _props = this.props,
155
- absolute = _props.absolute,
156
- centered = _props.centered,
157
- children = _props.children,
158
- clamp = _props.clamp,
159
- clearStyleProps = _props.clearStyleProps,
160
- config = _props.config,
161
- driver = _props.driver,
162
- faded = _props.faded,
163
- fixed = _props.fixed,
164
- full = _props.full,
165
- initialState = _props.initialState,
166
- keys = _props.keys,
167
- landing = _props.landing,
168
- nativeDriver = _props.nativeDriver,
169
- pointerEvents = _props.pointerEvents,
170
- skipProps = _props.skipProps,
171
- skipStyleProps = _props.skipStyleProps,
172
- _state = _props.state,
173
- style = _props.style,
174
- styleProps = _props.styleProps,
175
- unmounted = _props.unmounted,
176
- rest = objectWithoutProperties(_props, ['absolute', 'centered', 'children', 'clamp', 'clearStyleProps', 'config', 'driver', 'faded', 'fixed', 'full', 'initialState', 'keys', 'landing', 'nativeDriver', 'pointerEvents', 'skipProps', 'skipStyleProps', 'state', 'style', 'styleProps', 'unmounted']);
177
- var state = this.props.state;
178
-
179
-
180
- var presets = {
181
- faded: [{ opacity: 0 }, { opacity: 1 }]
182
- };
183
-
184
- if (faded) state = presets.faded;
185
-
186
- var layoutPresets = {
187
- absolute: { bottom: 0, left: 0, position: 'absolute', right: 0, top: 0 },
188
- centered: { alignSelf: 'center' },
189
- fixed: { position: 'absolute' },
190
- full: { flex: 1 },
191
- landing: { alignItems: 'center', flex: 1, justifyContent: 'center' }
192
- };
193
-
194
- var viewStyles = _extends({}, layoutPresets[absolute && 'absolute'], layoutPresets[centered && 'centered'], layoutPresets[fixed && 'fixed'], layoutPresets[full && 'full'], layoutPresets[landing && 'landing']);
195
-
196
- var propStyles = Object.keys(rest).reduce(function (obj, key) {
197
- if (skipProps.includes(key)) return obj;
198
-
199
- return _extends({}, obj, defineProperty({}, key, rest[key]));
200
- }, {});
201
-
202
- var inputRange = keys || Array(state.length).fill().map(function (_, index) {
203
- return index;
204
- });
205
-
206
- if (inputRange.length === 1) {
207
- inputRange.push(1);
208
- state.push({});
209
- }
210
-
211
- var getRange = function getRange(prop, defaultValue) {
212
- return state.reduce(function (range, currentState, index) {
213
- var prevState = range[index - 1];
214
-
215
- range.push(currentState[prop] || currentState[prop] === 0 ? currentState[prop] : prevState || prevState === 0 ? prevState : style[prop] || style[prop] === 0 ? style[prop] : defaultValue);
216
-
217
- return range;
218
- }, []);
219
- };
220
-
221
- var addProp = function addProp(prop, defaultValue, native) {
222
- var propDriver = native ? _this2.nativeDriver : _this2.driver;
223
-
224
- return propDriver.interpolate({
225
- inputRange: inputRange,
226
- outputRange: getRange(prop, defaultValue),
227
- extrapolate: clamp ? 'clamp' : undefined
228
- });
229
- };
230
-
231
- var defaultStyleProps = !clearStyleProps ? [{ prop: 'opacity', default: 1, native: true }, { prop: 'rotate', default: '0deg', native: true, transform: true }, { prop: 'scale', default: 1, native: true, transform: true }, { prop: 'translateX', default: 0, native: true, transform: true }, { prop: 'translateY', default: 0, native: true, transform: true }, { prop: 'backgroundColor', default: 'transparent' }, { prop: 'height', default: null }, { prop: 'width', default: null }] : [];
232
-
233
- var nativeStyles = {};
234
- var styles = {};
235
-
236
- var allStyleProps = [].concat(defaultStyleProps, toConsumableArray(styleProps));
237
-
238
- allStyleProps.forEach(function (_ref) {
239
- var prop = _ref.prop,
240
- defaultValue = _ref.default,
241
- native = _ref.native,
242
- transform = _ref.transform;
243
-
244
- if (!skipStyleProps.includes(prop)) {
245
- var stylesRef = native ? nativeStyles : styles;
246
-
247
- if (transform) {
248
- stylesRef.transform = [].concat(toConsumableArray(stylesRef.transform || []), [defineProperty({}, prop, addProp(prop, defaultValue, native))]);
249
- } else {
250
- stylesRef[prop] = addProp(prop, defaultValue, native);
251
- }
252
- }
253
- });
254
-
255
- return React.createElement(
256
- reactNative.Animated.View,
257
- _extends({
258
- ref: this.handleRef,
259
- style: [style, viewStyles, propStyles, nativeStyles]
260
- }, { pointerEvents: pointerEvents }),
261
- React.createElement(
262
- reactNative.Animated.View,
263
- { style: styles },
264
- children
265
- )
266
- );
267
- }
268
- }]);
269
- return Behavior;
270
- }(React.PureComponent);
271
-
272
- Behavior.defaultProps = {
273
- clamp: false,
274
- clearStyleProps: false,
275
- config: { type: 'spring' },
276
- currentState: 0,
277
- initialState: 0,
278
- skipProps: [],
279
- skipStyleProps: [],
280
- state: [{}, {}],
281
- style: {},
282
- styleProps: [],
283
- unmounted: false
284
- };
285
-
286
- var _initialiseProps = function _initialiseProps() {
287
- var _this3 = this;
288
-
289
- this.unmount = function () {
290
- return _this3.setState({ mounted: false });
291
- };
292
-
293
- this.mount = function (state) {
294
- var initialState = _this3.props.initialState;
295
-
296
-
297
- _this3.nativeDriver.setValue(state || initialState);
298
- _this3.driver.setValue(state || initialState);
299
-
300
- _this3.setState({ mounted: true });
301
- };
302
-
303
- this.goTo = function (state) {
304
- var config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
305
- var defaultConfig = _this3.props.config;
306
-
307
- var _defaultConfig$config = _extends({}, defaultConfig, config),
308
- type = _defaultConfig$config.type,
309
- onStart = _defaultConfig$config.onStart,
310
- onComplete = _defaultConfig$config.onComplete,
311
- ref = _defaultConfig$config.ref,
312
- delay = _defaultConfig$config.delay,
313
- opts = objectWithoutProperties(_defaultConfig$config, ['type', 'onStart', 'onComplete', 'ref', 'delay']);
314
-
315
- var engine = type === 'timing' ? reactNative.Animated.timing : reactNative.Animated.spring;
316
-
317
- var animate = function animate(toValue) {
318
- return reactNative.Animated.parallel([engine(_this3.nativeDriver, _extends({}, opts, {
319
- toValue: toValue,
320
- useNativeDriver: true
321
- })), engine(_this3.driver, _extends({}, opts, { useNativeDriver: undefined, toValue: toValue }))]);
322
- };
323
-
324
- if (Array.isArray(state)) {
325
- var sequence = [];
326
-
327
- state.forEach(function (toValue) {
328
- return sequence.push(animate(toValue));
329
- });
330
-
331
- _this3.key = sequence[sequence.length - 1];
332
-
333
- var _animationRef = reactNative.Animated.sequence(sequence);
334
-
335
- if (delay) {
336
- _animationRef = reactNative.Animated.sequence([reactNative.Animated.delay(delay), _animationRef]);
337
- }
338
-
339
- if (ref) return _animationRef;
340
-
341
- return _animationRef.start(function (animation) {
342
- if (onStart) onStart();
343
- if (animation.finished && onComplete) onComplete();
344
- });
345
- }
346
-
347
- _this3.key = state;
348
-
349
- var animationRef = animate(state);
350
-
351
- if (delay) {
352
- animationRef = reactNative.Animated.sequence([reactNative.Animated.delay(delay), animationRef]);
353
- }
354
-
355
- if (ref) return animationRef;
356
-
357
- return animationRef.start(function (animation) {
358
- if (animation.finished && onComplete) onComplete();
359
- });
360
- };
361
-
362
- this.handleRef = function (ref) {
363
- _this3.ref = ref;
364
- };
365
-
366
- this.setNativeProps = function (props) {
367
- _this3.ref.setNativeProps(props);
368
- };
369
- };
370
-
371
- module.exports = Behavior;