diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2017-07-05 19:45:56 +0200 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2017-07-05 19:45:56 +0200 |
| commit | 6fe1bcf384a34fdfc1704ff98ee5151a75d031a2 (patch) | |
| tree | ec0fc9cc5a17cdafacd6a04bb599865a2d959dbe /pkg/email | |
| parent | 6231964849eb9362c20b82279d92da96fb556209 (diff) | |
pkg/email: add AddAddrContext/RemoveAddrContext
Replace extractBugID function with more general AddAddrContext/RemoveAddrContext.
Diffstat (limited to 'pkg/email')
| -rw-r--r-- | pkg/email/parser.go | 69 | ||||
| -rw-r--r-- | pkg/email/parser_test.go | 81 |
2 files changed, 88 insertions, 62 deletions
diff --git a/pkg/email/parser.go b/pkg/email/parser.go index 5d8c54d2c..f0297a588 100644 --- a/pkg/email/parser.go +++ b/pkg/email/parser.go @@ -50,11 +50,12 @@ func Parse(r io.Reader, ownEmail string) (*Email, error) { bugID := "" var ccList []string for _, addr := range append(cc, to...) { - bugID1, own := extractBugID(addr.Address, ownEmail) - if bugID == "" { - bugID = bugID1 - } - if !own { + cleaned, context, _ := RemoveAddrContext(addr.Address) + if cleaned == ownEmail { + if bugID == "" { + bugID = context + } + } else { ccList = append(ccList, addr.String()) } } @@ -87,31 +88,39 @@ func Parse(r io.Reader, ownEmail string) (*Email, error) { return email, nil } -// extractBugID extracts bug ID encoded in receiver email. -// We send emails from <something+BUG_ID_HASH@something.com>. -// from is potentially such email address, canonical is <something@something.com>. -// This function returns BUG_ID_HASH, or an empty string if from does not contain -// the hash or is different from canonical. -func extractBugID(from, canonical string) (string, bool) { - if email, err := mail.ParseAddress(canonical); err == nil { - canonical = email.Address - } - canonical = strings.ToLower(canonical) - plusPos := strings.IndexByte(from, '+') - if plusPos == -1 { - return "", strings.ToLower(from) == canonical - } - atPos := strings.IndexByte(from[plusPos:], '@') - if atPos == -1 { - return "", false - } - user := from[:plusPos] - domain := from[plusPos+atPos:] - hash := from[plusPos+1 : plusPos+atPos] - if strings.ToLower(user+domain) != canonical { - return "", false - } - return hash, true +// AddAddrContext embeds context into local part of the provided email address using '+'. +// Returns the resulting email address. +func AddAddrContext(email, context string) (string, error) { + addr, err := mail.ParseAddress(email) + if err != nil { + return "", fmt.Errorf("failed to parse %q as email: %v", email, err) + } + at := strings.IndexByte(addr.Address, '@') + if at == -1 { + return "", fmt.Errorf("failed to parse %q as email: no @", email) + } + addr.Address = addr.Address[:at] + "+" + context + addr.Address[at:] + return addr.String(), nil +} + +// RemoveAddrContext extracts context after '+' from the local part of the provided email address. +// Returns address without the context and the context. +func RemoveAddrContext(email string) (string, string, error) { + addr, err := mail.ParseAddress(email) + if err != nil { + return "", "", fmt.Errorf("failed to parse %q as email: %v", email, err) + } + at := strings.IndexByte(addr.Address, '@') + if at == -1 { + return "", "", fmt.Errorf("failed to parse %q as email: no @", email) + } + plus := strings.LastIndexByte(addr.Address[:at], '+') + if plus == -1 { + return email, "", nil + } + context := addr.Address[plus+1 : at] + addr.Address = addr.Address[:plus] + addr.Address[at:] + return addr.String(), context, nil } // extractCommand extracts command to syzbot from email body. diff --git a/pkg/email/parser_test.go b/pkg/email/parser_test.go index 7b2aa9a0f..d05a597be 100644 --- a/pkg/email/parser_test.go +++ b/pkg/email/parser_test.go @@ -23,16 +23,55 @@ func TestExtractCommand(t *testing.T) { } } -func TestExtractBugID(t *testing.T) { - for i, test := range extractBugIDTests { - t.Run(fmt.Sprint(i), func(t *testing.T) { - bugID, own := extractBugID(test.email, `"Foo Bar" <foo@bar.com>`) - if bugID != test.bugID || own != test.own { - t.Logf("expect: own=%v %q", test.own, test.bugID) - t.Logf("got : own=%v %q", test.own, bugID) - t.Fail() - } - }) +func TestAddRemoveAddrContext(t *testing.T) { + email := `"Foo Bar" <foo@bar.com>` + email00, context00, err := RemoveAddrContext(email) + if err != nil { + t.Fatal(err) + } + if email != email00 { + t.Fatalf("want: %q, got %q", email, email00) + } + if context00 != "" { + t.Fatalf("want context: %q, got %q", "", context00) + } + context1 := "context1" + email1, err := AddAddrContext(email, context1) + if err != nil { + t.Fatal(err) + } + want1 := `"Foo Bar" <foo+context1@bar.com>` + if want1 != email1 { + t.Fatalf("want: %q, got %q", want1, email1) + } + context2 := "context2" + email2, err := AddAddrContext(email1, context2) + if err != nil { + t.Fatal(err) + } + want2 := `"Foo Bar" <foo+context1+context2@bar.com>` + if want2 != email2 { + t.Fatalf("want: %q, got %q", want2, email2) + } + email1, context20, err := RemoveAddrContext(email2) + if err != nil { + t.Fatal(err) + } + if want1 != email1 { + t.Fatalf("want: %q, got %q", want1, email1) + } + if context2 != context20 { + t.Fatalf("want context: %q, got %q", context2, context20) + } + email0, context10, err := RemoveAddrContext(email1) + if err != nil { + t.Fatal(err) + } + if email != email0 { + t.Fatalf("want: %q, got %q", email, email0) + } + if context1 != context10 { + t.Fatalf("want context: %q, got %q", context1, context10) } } @@ -86,28 +125,6 @@ line 2 }, } -var extractBugIDTests = []struct { - email string - bugID string - own bool -}{ - { - `foo@bar.com`, - ``, - true, - }, - { - `foo+123@baz.com`, - ``, - false, - }, - { - `foo+123@bar.com`, - `123`, - true, - }, -} - var parseTests = []struct { email string res *Email |
