mime_test.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744
  1. package mimeparse
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "io"
  7. "strconv"
  8. "strings"
  9. "testing"
  10. "time"
  11. )
  12. var p *Parser
  13. func init() {
  14. }
  15. func TestInject(t *testing.T) {
  16. p = NewMimeParser()
  17. var b bytes.Buffer
  18. // it should read from both slices
  19. // as if it's a continuous stream
  20. p.inject([]byte("abcd"), []byte("efgh"), []byte("ijkl"))
  21. for i := 0; i < 12; i++ {
  22. b.WriteByte(p.ch)
  23. if p.pos == 3 && p.msgPos < 4 {
  24. if c := p.peek(); c != 101 {
  25. t.Error("next() expecting e, got:", string(c))
  26. }
  27. }
  28. p.next()
  29. if p.ch == 0 {
  30. break
  31. }
  32. }
  33. if b.String() != "abcdefghijkl" {
  34. t.Error("expecting abcdefghijkl, got:", b.String())
  35. }
  36. }
  37. func TestMimeType(t *testing.T) {
  38. p = NewMimeParser()
  39. if isTokenSpecial['-'] {
  40. t.Error("- should not be in the set")
  41. }
  42. p.inject([]byte("text/plain; charset=us-ascii"))
  43. str, err := p.mimeType()
  44. if err != nil {
  45. t.Error(err)
  46. }
  47. if str != "text" {
  48. t.Error("mime type should be: text")
  49. }
  50. }
  51. func TestMimeContentType(t *testing.T) {
  52. p = NewMimeParser()
  53. go func() {
  54. <-p.consumed
  55. p.gotNewSlice <- false
  56. }()
  57. // what happens if we call Charset with empty content type?
  58. empty := contentType{}
  59. blank := empty.Charset()
  60. if blank != "" {
  61. t.Error("expecting charset to be blank")
  62. }
  63. subject := "text/plain; charset=\"us-aScii\"; moo; boundary=\"foo\""
  64. p.inject([]byte(subject))
  65. contentType, err := p.contentType()
  66. if err != nil {
  67. t.Error(err)
  68. }
  69. if charset := contentType.Charset(); charset != "US-ASCII" {
  70. t.Error("charset is not US-ASCII")
  71. }
  72. // test the stringer (note it will canonicalize us-aScii to US-ASCII
  73. subject = strings.Replace(subject, "us-aScii", "US-ASCII", 1)
  74. if ct := contentType.String(); contentType.String() != subject {
  75. t.Error("\n[" + ct + "]\ndoes not equal\n[" + subject + "]")
  76. }
  77. // what happens if we don't use quotes for the param?
  78. subject = "text/plain; charset=us-aScii; moo; boundary=\"foo\""
  79. p.inject([]byte(subject))
  80. contentType, err = p.contentType()
  81. if err != nil {
  82. t.Error(err)
  83. }
  84. if contentType.subType != "plain" {
  85. t.Error("contentType.subType expecting 'plain', got:", contentType.subType)
  86. }
  87. if contentType.superType != "text" {
  88. t.Error("contentType.subType expecting 'text', got:", contentType.superType)
  89. }
  90. }
  91. func TestEmailHeader(t *testing.T) {
  92. p = NewMimeParser()
  93. in := `Wong ignore me
  94. From: Al Gore <[email protected]>
  95. To: White House Transportation Coordinator <[email protected]>
  96. Subject: [Fwd: Map of Argentina with Description]
  97. MIME-Version: 1.0
  98. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed; s=ncr424; d=reliancegeneral.co.in;
  99. h=List-Unsubscribe:MIME-Version:From:To:Reply-To:Date:Subject:Content-Type:Content-Transfer-Encoding:Message-ID; [email protected];
  100. bh=F4UQPGEkpmh54C7v3DL8mm2db1QhZU4gRHR1jDqffG8=;
  101. b=MVltcq6/I9b218a370fuNFLNinR9zQcdBSmzttFkZ7TvV2mOsGrzrwORT8PKYq4KNJNOLBahswXf
  102. GwaMjDKT/5TXzegdX/L3f/X4bMAEO1einn+nUkVGLK4zVQus+KGqm4oP7uVXjqp70PWXScyWWkbT
  103. 1PGUwRfPd/HTJG5IUqs=
  104. Content-Type: multipart/mixed;
  105. boundary="D7F------------D7FD5A0B8AB9C65CCDBFA872"
  106. This is a multi-part message in MIME format.
  107. --D7F------------D7FD5A0B8AB9C65CCDBFA872
  108. Content-Type: text/plain; charset=us-ascii
  109. Content-Transfer-Encoding: 7bit
  110. Fred,
  111. Fire up Air Force One! We\'re going South!
  112. Thanks,
  113. Al
  114. --D7F------------D7FD5A0B8AB9C65CCDBFA872
  115. This
  116. `
  117. p.inject([]byte(in))
  118. h := newPart()
  119. err := p.header(h)
  120. if err != nil {
  121. t.Error(err)
  122. }
  123. if _, err := p.boundary(h.ContentBoundary); err != nil {
  124. t.Error(err)
  125. }
  126. }
  127. func TestBoundary(t *testing.T) {
  128. p = NewMimeParser()
  129. var err error
  130. part := newPart()
  131. part.ContentBoundary = "-wololo-"
  132. // in the middle of the string
  133. test := "The quick brown fo---wololo-\nx jumped over the lazy dog"
  134. p.inject([]byte(test))
  135. _, err = p.boundary(part.ContentBoundary)
  136. if err != nil && err != io.EOF {
  137. t.Error(err)
  138. }
  139. body := string(test[:p.lastBoundaryPos])
  140. if body != "The quick brown fo" {
  141. t.Error("p.lastBoundaryPos seems incorrect")
  142. }
  143. // at the end (with the -- postfix)
  144. p.inject([]byte("The quick brown fox jumped over the lazy dog---wololo---\n"))
  145. _, err = p.boundary(part.ContentBoundary)
  146. if err != nil && err != io.EOF {
  147. t.Error(err)
  148. }
  149. // the boundary with an additional buffer in between
  150. p.inject([]byte("The quick brown fox jumped over the lazy dog"),
  151. []byte("this is the middle"),
  152. []byte("and thats the end---wololo---\n"))
  153. _, err = p.boundary(part.ContentBoundary)
  154. if err != nil && err != io.EOF {
  155. t.Error(err)
  156. }
  157. }
  158. func TestBoundarySplit(t *testing.T) {
  159. p = NewMimeParser()
  160. var err error
  161. part := newPart()
  162. part.ContentBoundary = "-wololo-"
  163. // boundary is split over multiple slices
  164. p.inject(
  165. []byte("The quick brown fox jumped ov---wolo"),
  166. []byte("lo---\ner the lazy dog"))
  167. _, err = p.boundary(part.ContentBoundary)
  168. if err != nil && err != io.EOF {
  169. t.Error(err)
  170. }
  171. body := string([]byte("The quick brown fox jumped ov---wolo")[:p.lastBoundaryPos])
  172. if body != "The quick brown fox jumped ov" {
  173. t.Error("p.lastBoundaryPos value seems incorrect")
  174. }
  175. // boundary has a space, pointer advanced before, and is split over multiple slices
  176. part.ContentBoundary = "XXXXboundary text" // 17 chars
  177. p.inject(
  178. []byte("The quick brown fox jumped ov--X"),
  179. []byte("XXXboundary text\ner the lazy dog"))
  180. p.next() // here the pointer is advanced before the boundary is searched
  181. _, err = p.boundary(part.ContentBoundary)
  182. if err != nil && err != io.EOF {
  183. t.Error(err)
  184. return
  185. }
  186. }
  187. func TestSkip(t *testing.T) {
  188. p = NewMimeParser()
  189. p.inject(
  190. []byte("you cant touch this"),
  191. []byte("stop, hammer time"))
  192. p.skip(3)
  193. if p.pos != 3 {
  194. t.Error("position should be 3 after skipping 3 bytes, it is:", p.pos)
  195. }
  196. p.pos = 0
  197. // after we used next() to advance
  198. p.next()
  199. p.skip(3)
  200. if p.pos != 4 {
  201. t.Error("position should be 4 after skipping 3 bytes, it is:", p.pos)
  202. }
  203. // advance to the 2nd buffer
  204. p.pos = 0
  205. p.msgPos = 0
  206. p.skip(19)
  207. if p.pos != 0 && p.buf[0] != 's' {
  208. t.Error("position should be 0 and p.buf[0] should be 's'")
  209. }
  210. }
  211. func TestHeaderNormalization(t *testing.T) {
  212. p = NewMimeParser()
  213. p.inject([]byte("ConTent-type"))
  214. p.accept.upper = true
  215. for {
  216. p.acceptHeaderName()
  217. p.next()
  218. if p.ch == 0 {
  219. break
  220. }
  221. }
  222. if p.accept.String() != "Content-Type" {
  223. t.Error("header name not normalized, expecting Content-Type")
  224. }
  225. }
  226. func TestMimeContentQuotedParams(t *testing.T) {
  227. p = NewMimeParser()
  228. // quoted
  229. p.inject([]byte("text/plain; charset=\"us-ascii\""))
  230. contentType, err := p.contentType()
  231. if err != nil {
  232. t.Error(err)
  233. }
  234. // with whitespace & tab
  235. p.inject([]byte("text/plain; charset=\"us-ascii\" \tboundary=\"D7F------------D7FD5A0B8AB9C65CCDBFA872\""))
  236. contentType, err = p.contentType()
  237. if err != nil {
  238. t.Error(err)
  239. }
  240. // with comment (ignored)
  241. p.inject([]byte("text/plain; charset=\"us-ascii\" (a comment) \tboundary=\"D7F------------D7FD5A0B8AB9C65CCDBFA872\""))
  242. contentType, err = p.contentType()
  243. if contentType.subType != "plain" {
  244. t.Error("contentType.subType expecting 'plain', got:", contentType.subType)
  245. }
  246. if contentType.superType != "text" {
  247. t.Error("contentType.subType expecting 'text', got:", contentType.superType)
  248. }
  249. if len(contentType.parameters) != 2 {
  250. t.Error("expecting 2 elements in parameters")
  251. } else {
  252. m := make(map[string]string)
  253. for _, e := range contentType.parameters {
  254. m[e.name] = e.value
  255. }
  256. if _, ok := m["charset"]; !ok {
  257. t.Error("charset parameter not present")
  258. }
  259. if b, ok := m["boundary"]; !ok {
  260. t.Error("charset parameter not present")
  261. } else {
  262. if b != "D7F------------D7FD5A0B8AB9C65CCDBFA872" {
  263. t.Error("boundary should be: D7F------------D7FD5A0B8AB9C65CCDBFA872")
  264. }
  265. }
  266. }
  267. }
  268. var email = `From: Al Gore <[email protected]>
  269. To: White House Transportation Coordinator <[email protected]>
  270. Subject: [Fwd: Map of Argentina with Description]
  271. MIME-Version: 1.0
  272. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed; s=ncr424; d=reliancegeneral.co.in;
  273. h=List-Unsubscribe:MIME-Version:From:To:Reply-To:Date:Subject:Content-Type:Content-Transfer-Encoding:Message-ID; [email protected];
  274. bh=F4UQPGEkpmh54C7v3DL8mm2db1QhZU4gRHR1jDqffG8=;
  275. b=MVltcq6/I9b218a370fuNFLNinR9zQcdBSmzttFkZ7TvV2mOsGrzrwORT8PKYq4KNJNOLBahswXf
  276. GwaMjDKT/5TXzegdX/L3f/X4bMAEO1einn+nUkVGLK4zVQus+KGqm4oP7uVXjqp70PWXScyWWkbT
  277. 1PGUwRfPd/HTJG5IUqs=
  278. Content-Type: multipart/mixed;
  279. boundary="D7F------------D7FD5A0B8AB9C65CCDBFA872"
  280. This is a multi-part message in MIME format.
  281. --D7F------------D7FD5A0B8AB9C65CCDBFA872
  282. Content-Type: text/plain; charset=us-ascii
  283. Content-Transfer-Encoding: 7bit
  284. Fred,
  285. Fire up Air Force One! We're going South!
  286. Thanks,
  287. Al
  288. --D7F------------D7FD5A0B8AB9C65CCDBFA872
  289. Content-Type: message/rfc822
  290. Content-Transfer-Encoding: 7bit
  291. Content-Disposition: inline
  292. Return-Path: <[email protected]>
  293. Received: from mailhost.whitehouse.gov ([192.168.51.200])
  294. by heartbeat.whitehouse.gov (8.8.8/8.8.8) with ESMTP id SAA22453
  295. for <[email protected]>;
  296. Mon, 13 Aug 1998 l8:14:23 +1000
  297. Received: from the_big_box.whitehouse.gov ([192.168.51.50])
  298. by mailhost.whitehouse.gov (8.8.8/8.8.7) with ESMTP id RAA20366
  299. for [email protected]; Mon, 13 Aug 1998 17:42:41 +1000
  300. Date: Mon, 13 Aug 1998 17:42:41 +1000
  301. Message-Id: <[email protected]>
  302. From: Bill Clinton <[email protected]>
  303. To: A1 (The Enforcer) Gore <[email protected]>
  304. Subject: Map of Argentina with Description
  305. MIME-Version: 1.0
  306. Content-Type: multipart/mixed;
  307. boundary="DC8------------DC8638F443D87A7F0726DEF7"
  308. This is a multi-part message in MIME format.
  309. --DC8------------DC8638F443D87A7F0726DEF7
  310. Content-Type: text/plain; charset=us-ascii
  311. Content-Transfer-Encoding: 7bit
  312. Hi A1,
  313. I finally figured out this MIME thing. Pretty cool. I'll send you
  314. some sax music in .au files next week!
  315. Anyway, the attached image is really too small to get a good look at
  316. Argentina. Try this for a much better map:
  317. http://www.1one1yp1anet.com/dest/sam/graphics/map-arg.htm
  318. Then again, shouldn't the CIA have something like that?
  319. Bill
  320. --DC8------------DC8638F443D87A7F0726DEF7
  321. Content-Type: image/gif; name="map_of_Argentina.gif"
  322. Content-Transfer-Encoding: base64
  323. Content-Disposition: inline; filename="map_of_Argentina.gif"
  324. R01GOD1hJQA1AKIAAP/////78P/omn19fQAAAAAAAAAAAAAAACwAAAAAJQA1AAAD7Qi63P5w
  325. wEmjBCLrnQnhYCgM1wh+pkgqqeC9XrutmBm7hAK3tP31gFcAiFKVQrGFR6kscnonTe7FAAad
  326. GugmRu3CmiBt57fsVq3Y0VFKnpYdxPC6M7Ze4crnnHum4oN6LFJ1bn5NXTN7OF5fQkN5WYow
  327. BEN2dkGQGWJtSzqGTICJgnQuTJN/WJsojad9qXMuhIWdjXKjY4tenjo6tjVssk2gaWq3uGNX
  328. U6ZGxseyk8SasGw3J9GRzdTQky1iHNvcPNNI4TLeKdfMvy0vMqLrItvuxfDW8ubjueDtJufz
  329. 7itICBxISKDBgwgTKjyYAAA7
  330. --DC8------------DC8638F443D87A7F0726DEF7--
  331. --D7F------------D7FD5A0B8AB9C65CCDBFA872--
  332. `
  333. var email2 = `From: [email protected]
  334. Content-Type: multipart/mixed;
  335. boundary="----_=_NextPart_001_01CBE273.65A0E7AA"
  336. To: [email protected]
  337. This is a multi-part message in MIME format.
  338. ------_=_NextPart_001_01CBE273.65A0E7AA
  339. Content-Type: multipart/alternative;
  340. boundary="----_=_NextPart_002_01CBE273.65A0E7AA"
  341. ------_=_NextPart_002_01CBE273.65A0E7AA
  342. Content-Type: text/plain;
  343. charset="UTF-8"
  344. Content-Transfer-Encoding: base64
  345. [base64-content]
  346. ------_=_NextPart_002_01CBE273.65A0E7AA
  347. Content-Type: text/html;
  348. charset="UTF-8"
  349. Content-Transfer-Encoding: base64
  350. [base64-content]
  351. ------_=_NextPart_002_01CBE273.65A0E7AA--
  352. ------_=_NextPart_001_01CBE273.65A0E7AA
  353. Content-Type: message/rfc822
  354. Content-Transfer-Encoding: 7bit
  355. X-MimeOLE: Produced By Microsoft Exchange V6.5
  356. Content-class: urn:content-classes:message
  357. MIME-Version: 1.0
  358. Content-Type: multipart/mixed;
  359. boundary="----_=_NextPart_003_01CBE272.13692C80"
  360. From: [email protected]
  361. To: [email protected]
  362. This is a multi-part message in MIME format.
  363. ------_=_NextPart_003_01CBE272.13692C80
  364. Content-Type: multipart/alternative;
  365. boundary="----_=_NextPart_004_01CBE272.13692C80"
  366. ------_=_NextPart_004_01CBE272.13692C80
  367. Content-Type: text/plain;
  368. charset="iso-8859-1"
  369. Content-Transfer-Encoding: quoted-printable
  370. =20
  371. Viele Gr=FC=DFe
  372. ------_=_NextPart_004_01CBE272.13692C80
  373. Content-Type: text/html;
  374. charset="iso-8859-1"
  375. Content-Transfer-Encoding: quoted-printable
  376. <html>...</html>
  377. ------_=_NextPart_004_01CBE272.13692C80--
  378. ------_=_NextPart_003_01CBE272.13692C80
  379. Content-Type: application/x-zip-compressed;
  380. name="abc.zip"
  381. Content-Transfer-Encoding: base64
  382. Content-Disposition: attachment;
  383. filename="abc.zip"
  384. [base64-content]
  385. ------_=_NextPart_003_01CBE272.13692C80--
  386. ------_=_NextPart_001_01CBE273.65A0E7AA--`
  387. // note: this mime has an error: the boundary for multipart/alternative is re-used.
  388. // it should use a new unique boundary marker, which then needs to be terminated after
  389. // the text/html part.
  390. var email3 = `MIME-Version: 1.0
  391. X-Mailer: MailBee.NET 8.0.4.428
  392. Subject: test subject
  393. To: [email protected]
  394. Content-Type: multipart/mixed;
  395. boundary="XXXXboundary text"
  396. --XXXXboundary text
  397. Content-Type: multipart/alternative;
  398. boundary="XXXXboundary text"
  399. --XXXXboundary text
  400. Content-Type: text/plain;
  401. charset="utf-8"
  402. Content-Transfer-Encoding: quoted-printable
  403. This is the body text of a sample message.
  404. --XXXXboundary text
  405. Content-Type: text/html;
  406. charset="utf-8"
  407. Content-Transfer-Encoding: quoted-printable
  408. <pre>This is the body text of a sample message.</pre>
  409. --XXXXboundary text
  410. Content-Type: text/plain;
  411. name="log_attachment.txt"
  412. Content-Disposition: attachment;
  413. filename="log_attachment.txt"
  414. Content-Transfer-Encoding: base64
  415. TUlNRS1WZXJzaW9uOiAxLjANClgtTWFpbGVyOiBNYWlsQmVlLk5FVCA4LjAuNC40MjgNClN1Ympl
  416. Y3Q6IHRlc3Qgc3ViamVjdA0KVG86IGtldmlubUBkYXRhbW90aW9uLmNvbQ0KQ29udGVudC1UeXBl
  417. OiBtdWx0aXBhcnQvYWx0ZXJuYXRpdmU7DQoJYm91bmRhcnk9Ii0tLS09X05leHRQYXJ0XzAwMF9B
  418. RTZCXzcyNUUwOUFGLjg4QjdGOTM0Ig0KDQoNCi0tLS0tLT1fTmV4dFBhcnRfMDAwX0FFNkJfNzI1
  419. RTA5QUYuODhCN0Y5MzQNCkNvbnRlbnQtVHlwZTogdGV4dC9wbGFpbjsNCgljaGFyc2V0PSJ1dGYt
  420. OCINCkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6IHF1b3RlZC1wcmludGFibGUNCg0KdGVzdCBi
  421. b2R5DQotLS0tLS09X05leHRQYXJ0XzAwMF9BRTZCXzcyNUUwOUFGLjg4QjdGOTM0DQpDb250ZW50
  422. LVR5cGU6IHRleHQvaHRtbDsNCgljaGFyc2V0PSJ1dGYtOCINCkNvbnRlbnQtVHJhbnNmZXItRW5j
  423. b2Rpbmc6IHF1b3RlZC1wcmludGFibGUNCg0KPHByZT50ZXN0IGJvZHk8L3ByZT4NCi0tLS0tLT1f
  424. TmV4dFBhcnRfMDAwX0FFNkJfNzI1RTA5QUYuODhCN0Y5MzQtLQ0K
  425. --XXXXboundary text--
  426. `
  427. /*
  428. email 1
  429. Array
  430. (
  431. [0] => 1
  432. [1] => 1.1
  433. [2] => 1.2
  434. [3] => 1.2.1
  435. [4] => 1.2.1.1
  436. [5] => 1.2.1.2
  437. )
  438. 0 =>744 to 3029
  439. 1 =>907 to 968
  440. 2 =>1101 to 3029
  441. 3 =>1889 to 3029
  442. 4 =>2052 to 2402
  443. 5 =>2594 to 2983
  444. email 2
  445. 1 0 121 1763 1803
  446. 1.1 207 302 628 668
  447. 1.1.1 343 428 445 485
  448. 1.1.2 485 569 586 628
  449. 1.2 668 730 1763 1803
  450. 1.2.1 730 959 1721 1763
  451. 1.2.1.1 1045 1140 1501 1541
  452. 1.2.1.1.1 1181 1281 1303 1343
  453. 1.2.1.1.2 1343 1442 1459 1501
  454. 1.2.1.2 1541 1703 1721 1763
  455. */
  456. func TestNestedEmail(t *testing.T) {
  457. p = NewMimeParser()
  458. email = email3
  459. //email = strings.Replace(string(email), "\n", "\r\n", -1)
  460. p.inject([]byte(email))
  461. go func() {
  462. time.Sleep(time.Second * 15)
  463. // for debugging deadlocks
  464. //pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)
  465. //os.Exit(1)
  466. }()
  467. if err := p.mime(nil, ""); err != nil {
  468. t.Error(err)
  469. }
  470. //output := email
  471. for part := range p.Parts {
  472. //output = replaceAtIndex(output, '#', p.Parts[part].StartingPos)
  473. //output = replaceAtIndex(output, '&', p.Parts[part].StartingPosBody)
  474. //output = replaceAtIndex(output, '*', p.Parts[part].EndingPosBody)
  475. fmt.Println(p.Parts[part].Node +
  476. " " + strconv.Itoa(int(p.Parts[part].StartingPos)) +
  477. " " + strconv.Itoa(int(p.Parts[part].StartingPosBody)) +
  478. " " + strconv.Itoa(int(p.Parts[part].EndingPosBody)) +
  479. " " + strconv.Itoa(int(p.Parts[part].EndingPos)))
  480. }
  481. //fmt.Print(output)
  482. //fmt.Println(strings.Index(output, "--D7F------------D7FD5A0B8AB9C65CCDBFA872--"))
  483. i := 1
  484. _ = i
  485. //fmt.Println("[" + output[p.Parts[i].StartingPosBody:p.Parts[i].EndingPosBody] + "]")
  486. //i := 2
  487. //fmt.Println("**********{" + output[p.parts[i].startingPosBody:p.parts[i].endingPosBody] + "}**********")
  488. //p.Close()
  489. //p.inject([]byte(email))
  490. //if err := p.mime("", 1, ""); err != nil && err != io.EOF {
  491. // t.Error(err)
  492. //}
  493. //p.Close()
  494. }
  495. func replaceAtIndex(str string, replacement rune, index uint) string {
  496. return str[:index] + string(replacement) + str[index+1:]
  497. }
  498. var email4 = `Subject: test subject
  499. To: [email protected]
  500. This is not a an MIME email
  501. `
  502. func TestNonMineEmail(t *testing.T) {
  503. p = NewMimeParser()
  504. p.inject([]byte(email4))
  505. if err := p.mime(nil, ""); err != nil && err != NotMineErr {
  506. t.Error(err)
  507. } else {
  508. // err should be NotMime
  509. for part := range p.Parts {
  510. fmt.Println(p.Parts[part].Node + " " + strconv.Itoa(int(p.Parts[part].StartingPos)) + " " + strconv.Itoa(int(p.Parts[part].StartingPosBody)) + " " + strconv.Itoa(int(p.Parts[part].EndingPosBody)))
  511. }
  512. }
  513. err := p.Close()
  514. if err != nil {
  515. t.Error(err)
  516. }
  517. // what if we pass an empty string?
  518. p.inject([]byte{' '})
  519. if err := p.mime(nil, ""); err == nil || err == NotMineErr {
  520. t.Error("unexpected error", err)
  521. }
  522. }
  523. var email6 = `Delivered-To: [email protected]
  524. Received: from bb_dyn_pb-146-88-38-36.violin.co.th (bb_dyn_pb-146-88-38-36.violin.co.th [146.88.38.36])
  525. by sharklasers.com with SMTP id [email protected];
  526. Tue, 17 Sep 2019 01:13:00 +0000
  527. Received: from mx03.listsystemsf.net [100.20.38.85] by mxs.perenter.com with SMTP; Tue, 17 Sep 2019 04:57:59 +0500
  528. Received: from mts.locks.grgtween.net ([Tue, 17 Sep 2019 04:52:27 +0500])
  529. by webmail.halftomorrow.com with LOCAL; Tue, 17 Sep 2019 04:52:27 +0500
  530. Received: from mail.naihautsui.co.kr ([61.220.30.1]) by mtu67.syds.piswix.net with ASMTP; Tue, 17 Sep 2019 04:47:25 +0500
  531. Received: from unknown (HELO mx03.listsystemsf.net) (Tue, 17 Sep 2019 04:41:45 +0500)
  532. by smtp-server1.cfdenselr.com with LOCAL; Tue, 17 Sep 2019 04:41:45 +0500
  533. Message-ID: <[email protected]>
  534. Date: Tue, 17 Sep 2019 04:14:56 +0500
  535. Reply-To: "Richard" <[email protected]>
  536. From: "Rick" <[email protected]>
  537. User-Agent: Mozilla 4.73 [de]C-CCK-MCD DT (Win98; U)
  538. X-Accept-Language: en-us
  539. MIME-Version: 1.0
  540. To: "Nevaeh" <[email protected]>
  541. Subject: Cesść tereska
  542. Content-Type: text/html;
  543. charset="iso-8859-1"
  544. Content-Transfer-Encoding: base64
  545. iVBORw0KGgoAAAANSUhEUgAAAG4AAAAyCAIAAAAydXkgAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAA
  546. B3RJTUUH1gYEExgGfYkXIAAAAAd0RVh0QXV0aG9yAKmuzEgAAAAMdEVYdERlc2NyaXB0aW9uABMJ
  547. ISMAAAAKdEVYdENvcHlyaWdodACsD8w6AAAADnRFWHRDcmVhdGlvbiB0aW1lADX3DwkAAAAJdEVY
  548. dFNvZnR3YXJlAF1w/zoAAAALdEVYdERpc2NsYWltZXIAt8C0jwAAAAh0RVh0V2FybmluZwDAG+aH
  549. AAAAB3RFWHRTb3VyY2UA9f+D6wAAAAh0RVh0Q29tbWVudAD2zJa/AAAABnRFWHRUaXRsZQCo7tIn
  550. AAABAElEQVR4nO2ZUY6DIBCG66YH88FGvQLHEI+hHsMriPFw7AMJIYAwoO269v+eSDPDmKn5HOXx
  551. AAAAAAAAAPxblmWRZJZlSU3RCCE451Z1IUQ00c1ScM7p15zHT1J0URSpwUkpmrquh2HY60uA1+vl
  552. /b2qKkp63tUCcA8otrK8k+dKr7+I1V0tEEUppRRCZDcnzZUZHLdP6g6uFomiBACYeHUTTnF9ZwV4
  553. 3dp1HaW0V5dRUR6ZJU3e7kqLaK+9ZpymKamKOV3uTZrhigCAU1wZhV7aRE2IlKn2tq60WNeVHtz3
  554. vV7Xdc05b5pmL0ADVwLg5QOu3BNZhhxVwH1cmYoluwDqX2zbj2bPFgAAAMdJREFUNnUruBIALxmu
  555. dF1mBXhlSimtPzW6O5hfIQOJB7mcK72NSzrk2bYt+ku0IvhL8PCKwxhTi3meT9s06aBGOSjjpduF
  556. Ut1UnlnUUmG4kDtj6j5aa5c3noOfhX4ND1eXhvJMOYZFGYYxNs8zY6wsS73O3u2rUY1jjOkOBlp5
  557. uSf4NTn/fsw4Bz/oSnMMCm9laU4FuzMj5ZpN6K58JrVSfnAEW9d127ZxHInVLZM2TSOlpL/C72He
  558. j2c+wQEAAAAAAAAAfB2/3ihTGANzPd8AAAAASUVORK5CYII=
  559. `
  560. func TestNonMineEmailBigBody(t *testing.T) {
  561. p = NewMimeParser()
  562. b := []byte(email6)
  563. to := 74
  564. var in [][]byte
  565. for i := 0; ; i += to {
  566. if to+i > len(b) {
  567. in = append(in, b[i:])
  568. break
  569. }
  570. in = append(in, b[i:to+i])
  571. }
  572. p.inject(in...)
  573. if err := p.mime(nil, ""); err != nil && err != NotMineErr {
  574. t.Error(err)
  575. } else {
  576. for part := range p.Parts {
  577. fmt.Println(p.Parts[part].Node + " " + strconv.Itoa(int(p.Parts[part].StartingPos)) + " " + strconv.Itoa(int(p.Parts[part].StartingPosBody)) + " " + strconv.Itoa(int(p.Parts[part].EndingPosBody)))
  578. }
  579. }
  580. err := p.Close()
  581. if err != nil {
  582. t.Error(err)
  583. }
  584. // what if we pass an empty string?
  585. p.inject([]byte{' '})
  586. if err := p.mime(nil, ""); err == nil || err == NotMineErr {
  587. t.Error("unexpected error", err)
  588. }
  589. }
  590. func TestMimeErr(t *testing.T) {
  591. p := NewMimeParser()
  592. p.Open()
  593. // the error is missing subtype
  594. data :=
  595. `To "moo": j m
  596. Subject: and a predicate
  597. MIME-Version: 1.0
  598. Content-Type: text;
  599. Content-Transfer-Encoding: 1
  600. Rock the microphone and then I’m gone
  601. `
  602. i, err := p.Write([]byte(data))
  603. if err != nil {
  604. if mimeErr, ok := err.(*Error); !ok {
  605. t.Error("not a *MimeError type")
  606. return
  607. } else {
  608. b, err := json.Marshal(mimeErr.Unwrap())
  609. if err != nil {
  610. t.Error(err)
  611. return
  612. }
  613. if string(b) != "8" {
  614. t.Error("expecting error be 8")
  615. return
  616. }
  617. var parsedErr MimeError
  618. json.Unmarshal(b, &parsedErr)
  619. if parsedErr != ErrorMissingSubtype {
  620. t.Error("expecting error to be ErrorMissingSubtype, got:", parsedErr)
  621. return
  622. }
  623. }
  624. }
  625. if i != 148 {
  626. t.Error("test was expecting to read 148 bytes, got", i)
  627. }
  628. err = p.Close()
  629. }