Skip to content

Commit

Permalink
SMTP: Adding index field, addressing search FIXMEs
Browse files Browse the repository at this point in the history
  • Loading branch information
Lucas Hinderberger committed Jun 25, 2024
1 parent 9b1f5b2 commit b3cf8cb
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 16 deletions.
22 changes: 10 additions & 12 deletions internal/smtp/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,14 +101,13 @@ func (h *smtpHTTPHandler) handleMessageIndex(w http.ResponseWriter, r *http.Requ
if headerSearchRgx == nil {
receivedMessages = h.server.ReceivedMessages()
} else {
// FIXME: This does not preserve the correct indexes!
receivedMessages = h.server.SearchByHeader(headerSearchRgx)
}

messagesOut := make([]any, 0)

for i, msg := range receivedMessages {
messagesOut = append(messagesOut, buildMessageBasicMeta(msg, i))
for _, msg := range receivedMessages {
messagesOut = append(messagesOut, buildMessageBasicMeta(msg))
}

out := make(map[string]any)
Expand All @@ -124,7 +123,7 @@ func (h *smtpHTTPHandler) handleMessageMeta(w http.ResponseWriter, r *http.Reque
return
}

out := buildMessageBasicMeta(msg, idx)
out := buildMessageBasicMeta(msg)

out["body_size"] = len(msg.Body())

Expand Down Expand Up @@ -169,14 +168,13 @@ func (h *smtpHTTPHandler) handleMultipartIndex(w http.ResponseWriter, r *http.Re
if headerSearchRgx == nil {
multiparts = msg.Multiparts()
} else {
// FIXME: This does not preserve the correct indexes!
multiparts = msg.SearchPartsByHeader(headerSearchRgx)
}

multipartsOut := make([]any, 0)

for i, part := range multiparts {
multipartsOut = append(multipartsOut, buildMultipartMeta(part, i))
for _, part := range multiparts {
multipartsOut = append(multipartsOut, buildMultipartMeta(part))
}

out := make(map[string]any)
Expand All @@ -201,7 +199,7 @@ func (h *smtpHTTPHandler) handleMultipartMeta(
return
}

handlerutil.RespondWithJSON(w, http.StatusOK, buildMultipartMeta(part, partIdx))
handlerutil.RespondWithJSON(w, http.StatusOK, buildMultipartMeta(part))
}

func (h *smtpHTTPHandler) handleMultipartBody(
Expand Down Expand Up @@ -256,16 +254,16 @@ func retrievePart(w http.ResponseWriter, msg *ReceivedMessage, partIdx int) *Rec
return msg.Multiparts()[partIdx]
}

func buildMessageBasicMeta(msg *ReceivedMessage, idx int) map[string]any {
func buildMessageBasicMeta(msg *ReceivedMessage) map[string]any {
return map[string]any{
"idx": idx,
"idx": msg.Index(),
"receivedAt": msg.ReceivedAt(),
}
}

func buildMultipartMeta(part *ReceivedPart, partIdx int) map[string]any {
func buildMultipartMeta(part *ReceivedPart) map[string]any {
out := map[string]any{
"idx": partIdx,
"idx": part.Index(),
"body_size": len(part.Body()),
}

Expand Down
21 changes: 18 additions & 3 deletions internal/smtp/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import (

// ReceivedMessage contains a single email message as received via SMTP.
type ReceivedMessage struct {
index int

smtpFrom string
smtpRcptTo []string
rawMessageData []byte
Expand All @@ -34,6 +36,8 @@ type ReceivedMessage struct {
// ReceivedPart contains a single part of a multipart message as received
// via SMTP.
type ReceivedPart struct {
index int

headers textproto.MIMEHeader
body []byte
}
Expand All @@ -45,6 +49,7 @@ type ReceivedPart struct {
// If a maxMessageSize of 0 is given, this function will default to using
// DefaultMaxMessageSize.
func NewReceivedMessage(
index int,
from string, rcptTo []string, rawMessageData []byte, receivedAt time.Time,
maxMessageSize int64,
) (*ReceivedMessage, error) {
Expand All @@ -63,6 +68,7 @@ func NewReceivedMessage(
}

msg := &ReceivedMessage{
index: index,
smtpFrom: from,
smtpRcptTo: rcptTo,
rawMessageData: rawMessageData,
Expand Down Expand Up @@ -92,7 +98,7 @@ func NewReceivedMessage(

r := multipart.NewReader(bytes.NewReader(msg.body), boundary)

for {
for i := 0; ; i++ {
rawPart, err := r.NextPart()
if err != nil {
if errors.Is(err, io.EOF) {
Expand All @@ -102,7 +108,7 @@ func NewReceivedMessage(
}
}

part, err := NewReceivedPart(rawPart, maxMessageSize)
part, err := NewReceivedPart(i, rawPart, maxMessageSize)
if err != nil {
return nil, fmt.Errorf("could not parse message part: %w", err)
}
Expand Down Expand Up @@ -150,7 +156,7 @@ func (m *ReceivedMessage) SearchPartsByHeader(re *regexp.Regexp) []*ReceivedPart
// Incoming data is truncated after the given maximum message size.
// If a maxMessageSize of 0 is given, this function will default to using
// DefaultMaxMessageSize.
func NewReceivedPart(p *multipart.Part, maxMessageSize int64) (*ReceivedPart, error) {
func NewReceivedPart(index int, p *multipart.Part, maxMessageSize int64) (*ReceivedPart, error) {
if maxMessageSize == 0 {
maxMessageSize = DefaultMaxMessageSize
}
Expand All @@ -161,6 +167,7 @@ func NewReceivedPart(p *multipart.Part, maxMessageSize int64) (*ReceivedPart, er
}

part := &ReceivedPart{
index: index,
headers: p.Header,
body: body,
}
Expand All @@ -184,6 +191,10 @@ func (m *ReceivedMessage) Headers() mail.Header {
return m.headers
}

func (m *ReceivedMessage) Index() int {
return m.index
}

func (m *ReceivedMessage) IsMultipart() bool {
return m.isMultipart
}
Expand Down Expand Up @@ -215,3 +226,7 @@ func (p *ReceivedPart) Body() []byte {
func (p *ReceivedPart) Headers() textproto.MIMEHeader {
return p.headers
}

func (p *ReceivedPart) Index() int {
return p.index
}
5 changes: 4 additions & 1 deletion internal/smtp/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,13 @@ func (s *session) Data(r io.Reader) error {
s.server.mutex.Lock()
defer s.server.mutex.Unlock()

idx := len(s.server.receivedMessages)
now := time.Now()

logrus.Infof("SMTP: Receiving message from %s to %v at %v", s.from, s.rcptTo, now)
msg, err := NewReceivedMessage(s.from, s.rcptTo, rawData, now, s.server.maxMessageSize)
msg, err := NewReceivedMessage(
idx, s.from, s.rcptTo, rawData, now, s.server.maxMessageSize,
)
if err != nil {
errWrapped := fmt.Errorf("error constructing ReceivedMessage in SMTP server: %w", err)
logrus.Error("SMTP:", errWrapped) // this is logged in our server
Expand Down

0 comments on commit b3cf8cb

Please sign in to comment.