models.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. package guerrilla
  2. import (
  3. "bufio"
  4. "errors"
  5. "fmt"
  6. "io"
  7. "strconv"
  8. "strings"
  9. )
  10. var (
  11. LineLimitExceeded = errors.New("Maximum line length exceeded")
  12. MessageSizeExceeded = errors.New("Maximum message size exceeded")
  13. )
  14. // Backends process received mail. Depending on the implementation, that can
  15. // be storing in a database, retransmitting to another server, etc.
  16. // Must return an SMTP message (i.e. "250 OK") and a boolean indicating
  17. // whether the message was processed successfully.
  18. type Backend interface {
  19. Process(*Envelope) BackendResult
  20. Shutdown() error
  21. }
  22. // BackendResult represents a response to an SMTP client after receiving DATA.
  23. // The String method should return an SMTP message ready to send back to the
  24. // client, for example `250 OK: Message received`.
  25. type BackendResult interface {
  26. fmt.Stringer
  27. // Code should return the SMTP code associated with this response, ie. `250`
  28. Code() int
  29. }
  30. // Internal implementation of BackendResult for use by backend implementations.
  31. type backendResult string
  32. func (br backendResult) String() string {
  33. return string(br)
  34. }
  35. // Parses the SMTP code from the first 3 characters of the SMTP message.
  36. // Returns 554 if code cannot be parsed.
  37. func (br backendResult) Code() int {
  38. trimmed := strings.TrimSpace(string(br))
  39. if len(trimmed) < 3 {
  40. return 554
  41. }
  42. code, err := strconv.Atoi(trimmed[:3])
  43. if err != nil {
  44. return 554
  45. }
  46. return code
  47. }
  48. func NewBackendResult(message string) BackendResult {
  49. return backendResult(message)
  50. }
  51. // EmailAddress encodes an email address of the form `<user@host>`
  52. type EmailAddress struct {
  53. User string
  54. Host string
  55. }
  56. func (ep *EmailAddress) String() string {
  57. return fmt.Sprintf("%s@%s", ep.User, ep.Host)
  58. }
  59. func (ep *EmailAddress) isEmpty() bool {
  60. return ep.User == "" && ep.Host == ""
  61. }
  62. // we need to adjust the limit, so we embed io.LimitedReader
  63. type adjustableLimitedReader struct {
  64. R *io.LimitedReader
  65. }
  66. // bolt this on so we can adjust the limit
  67. func (alr *adjustableLimitedReader) setLimit(n int64) {
  68. alr.R.N = n
  69. }
  70. // Returns a specific error when a limit is reached, that can be differentiated
  71. // from an EOF error from the standard io.Reader.
  72. func (alr *adjustableLimitedReader) Read(p []byte) (n int, err error) {
  73. n, err = alr.R.Read(p)
  74. if err == io.EOF && alr.R.N <= 0 {
  75. // return our custom error since io.Reader returns EOF
  76. err = LineLimitExceeded
  77. }
  78. return
  79. }
  80. // allocate a new adjustableLimitedReader
  81. func newAdjustableLimitedReader(r io.Reader, n int64) *adjustableLimitedReader {
  82. lr := &io.LimitedReader{R: r, N: n}
  83. return &adjustableLimitedReader{lr}
  84. }
  85. // This is a bufio.Reader what will use our adjustable limit reader
  86. // We 'extend' buffio to have the limited reader feature
  87. type smtpBufferedReader struct {
  88. *bufio.Reader
  89. alr *adjustableLimitedReader
  90. }
  91. // Delegate to the adjustable limited reader
  92. func (sbr *smtpBufferedReader) setLimit(n int64) {
  93. sbr.alr.setLimit(n)
  94. }
  95. // Set a new reader & use it to reset the underlying reader
  96. func (sbr *smtpBufferedReader) Reset(r io.Reader) {
  97. sbr.alr = newAdjustableLimitedReader(r, CommandLineMaxLength)
  98. sbr.Reader.Reset(sbr.alr)
  99. }
  100. // Allocate a new SMTPBufferedReader
  101. func newSMTPBufferedReader(rd io.Reader) *smtpBufferedReader {
  102. alr := newAdjustableLimitedReader(rd, CommandLineMaxLength)
  103. s := &smtpBufferedReader{bufio.NewReader(alr), alr}
  104. return s
  105. }