From 69f8bbaed6334c2d42180bf86ee43c9182bcb847 Mon Sep 17 00:00:00 2001 From: Robert Worgul Date: Wed, 18 Aug 2021 21:50:47 +0200 Subject: [PATCH] add computed bcc to Message --- message.go | 71 ++++++++++++++++++++++++++++++++++++++++++++++- message_test.go | 73 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 143 insertions(+), 1 deletion(-) diff --git a/message.go b/message.go index 58e464b..015a716 100644 --- a/message.go +++ b/message.go @@ -7,6 +7,7 @@ import ( "io" "log" "mime" + "net/mail" "strings" "time" ) @@ -51,6 +52,7 @@ type Message struct { ID MessageID From *Path To []*Path + Bcc []*Path Content *Content Created time.Time MIME *MIMEBody // FIXME refactor to use Content.MIME @@ -94,11 +96,13 @@ func (m *SMTPMessage) Parse(hostname string) *Message { } id, _ := NewMessageID(hostname) + content := ContentFromString(m.Data) msg := &Message{ ID: id, From: PathFromString(m.From), To: arr, - Content: ContentFromString(m.Data), + Bcc: extractBcc(arr, content), + Content: content, Created: time.Now(), Raw: m, } @@ -328,3 +332,68 @@ func extractBoundary(contentType string) string { } return "" } + +func (self *Path) equals(other *Path) bool { + if self == other { + return true + } + if other == nil { + return false + } + if self.Domain != other.Domain || self.Mailbox != other.Mailbox || self.Params != other.Params || len(self.Relays) != len(other.Relays) { + return false + } + for i := range self.Relays { + if self.Relays[i] != other.Relays[i] { + return false + } + } + return true +} + +func toPathes(xs []string) []*Path { + var arr []*Path + for _, x := range xs { + as, err := mail.ParseAddressList(x) + if err != nil { + continue + } + for _, a := range as { + arr = append(arr, PathFromString(a.Address)) + } + } + return arr +} + +func remove(s []*Path, i int) []*Path { + s[i] = s[len(s)-1] + return s[:len(s)-1] +} + +func indexOf(xs []*Path, y *Path) int { + for i, x := range xs { + if x.equals(y) { + return i + } + } + return -1 +} + +func extractBcc(allTos []*Path, content *Content) []*Path { + var tos = toPathes(content.Headers["To"]) + var ccs = toPathes(content.Headers["Cc"]) + var arr []*Path + for _, path := range allTos { + if i := indexOf(tos, path); i != -1 { + tos = remove(tos, i) + continue + } + if i := indexOf(ccs, path); i != -1 { + tos = remove(ccs, i) + continue + } + + arr = append(arr, path) + } + return arr +} diff --git a/message_test.go b/message_test.go index 32794a7..ba26954 100644 --- a/message_test.go +++ b/message_test.go @@ -25,3 +25,76 @@ func TestExtractBoundary(t *testing.T) { } } } + +func TestPathEquals(t *testing.T) { + a := Path{ + Relays: []string{"rel"}, + Mailbox: "foo", + Domain: "bar", + Params: "", + } + + if a.equals(nil) { + t.Errorf("Path should never be equal to nil") + } + + if !a.equals(&a) { + t.Errorf("references should be equal") + } + b := a + if !a.equals(&b) { + t.Errorf("%s should be equal to %s.", a, b) + } + mailboxChanged := a + mailboxChanged.Mailbox = "!" + if a.equals(&mailboxChanged) { + t.Errorf("%s should NOT be equal to %s.", a, mailboxChanged) + } + domainChanged := a + domainChanged.Domain = "!" + if a.equals(&domainChanged) { + t.Errorf("%s should NOT be equal to %s.", a, domainChanged) + } + paramsChanged := a + paramsChanged.Params = "!" + if a.equals(¶msChanged) { + t.Errorf("%s should NOT be equal to %s.", a, paramsChanged) + } + relaysChanged := a + relaysChanged.Relays = []string{"baz"} + if a.equals(&relaysChanged) { + t.Errorf("%s should NOT be equal to %s.", a, relaysChanged) + } + relaysChanged.Relays = []string{"baz", "rel"} + if a.equals(&relaysChanged) { + t.Errorf("%s should NOT be equal to %s.", a, relaysChanged) + } +} + +func TestExtractBcc(t *testing.T) { + content := Content{ + Size: 42, + Headers: map[string][]string{}, + Body: "body", + } + emptyTo := extractBcc(toPathes([]string{}), &content) + if l := len(emptyTo); l != 0 { + t.Errorf("result should be empty but had %d entries.", l) + } + + content.Headers["Cc"] = []string{"admin@localhost, Alice , aalesipo@example.com"} + content.Headers["To"] = []string{"circulars@localhost, Bob "} + allTos := []string{ + "circulars@localhost", "admin@localhost", "cjoao0@tinyurl.com", + "aalesipo@example.com", "admin@localhost", "mdenslow2@taobao.com"} + bcc := extractBcc(toPathes(allTos), &content) + if l := len(bcc); l != 2 { + t.Errorf("%v should have 2 entries but had %d entries.", bcc, l) + } + for _, x := range []string{"admin@localhost", "mdenslow2@taobao.com"} { + if indexOf(bcc, PathFromString(x)) == -1 { + t.Errorf("%v should contain %s.", bcc, x) + } + } + +}