reader.go 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. package mail
  2. import (
  3. "bufio"
  4. "io"
  5. "net/textproto"
  6. "github.com/flashmob/go-guerrilla/mail/mimeparse"
  7. )
  8. // MimeDotReader parses the mime structure while reading using the underlying reader
  9. type MimeDotReader struct {
  10. R io.Reader
  11. p *mimeparse.Parser
  12. mimeErr error
  13. }
  14. // Read parses the mime structure wile reading. Results are immediately available in
  15. // the data-structure returned from Parts() after each read.
  16. func (r *MimeDotReader) Read(p []byte) (n int, err error) {
  17. n, err = r.R.Read(p)
  18. if n > 0 {
  19. if r.mimeErr == nil {
  20. r.mimeErr = r.p.Parse(p)
  21. }
  22. }
  23. return
  24. }
  25. // Close closes the underlying reader if it's a ReadCloser and closes the mime parser
  26. func (r MimeDotReader) Close() (err error) {
  27. defer func() {
  28. if err == nil && r.mimeErr != nil {
  29. err = r.mimeErr
  30. }
  31. }()
  32. if rc, t := r.R.(io.ReadCloser); t {
  33. err = rc.Close()
  34. }
  35. // parser already closed?
  36. if r.mimeErr != nil {
  37. return
  38. }
  39. // close the parser
  40. r.mimeErr = r.p.Close()
  41. return
  42. }
  43. // Parts returns the mime-header parts built by the parser
  44. func (r *MimeDotReader) Parts() mimeparse.Parts {
  45. return r.p.Parts
  46. }
  47. // Returns the underlying io.Reader (which is a dotReader from textproto)
  48. // useful for reading from directly if mime parsing is not desirable.
  49. func (r *MimeDotReader) DotReader() io.Reader {
  50. return r.R
  51. }
  52. // NewMimeDotReader returns a pointer to a new MimeDotReader
  53. // br is the underlying reader it will read from
  54. // maxNodes limits the number of nodes can be added to the mime tree before the mime-parser aborts
  55. func NewMimeDotReader(br *bufio.Reader, maxNodes int) *MimeDotReader {
  56. r := new(MimeDotReader)
  57. r.R = textproto.NewReader(br).DotReader()
  58. if maxNodes > 0 {
  59. r.p = mimeparse.NewMimeParserLimited(maxNodes)
  60. } else {
  61. r.p = mimeparse.NewMimeParser()
  62. }
  63. r.p.Open()
  64. return r
  65. }