author | Alberto Bertogli
<albertito@blitiri.com.ar> 2016-07-19 22:18:40 UTC |
committer | Alberto Bertogli
<albertito@blitiri.com.ar> 2016-07-22 00:44:45 UTC |
parent | 831ef131325a6aa3ed9be9f9dec10e02c9bf43c3 |
internal/courier/courier.go | +2 | -22 |
internal/courier/procmail.go | +8 | -3 |
internal/courier/procmail_test.go | +4 | -2 |
internal/courier/smtp.go | +2 | -1 |
internal/envelope/envelope.go | +38 | -0 |
internal/envelope/envelope_test.go | +43 | -0 |
diff --git a/internal/courier/courier.go b/internal/courier/courier.go index 42635f5..a6e2acd 100644 --- a/internal/courier/courier.go +++ b/internal/courier/courier.go @@ -1,7 +1,7 @@ // Package courier implements various couriers for delivering messages. package courier -import "strings" +import "blitiri.com.ar/go/chasquid/internal/envelope" // Courier delivers mail to a single recipient. // It is implemented by different couriers, for both local and remote @@ -19,30 +19,10 @@ type Router struct { } func (r *Router) Deliver(from string, to string, data []byte) error { - d := domainOf(to) + d := envelope.DomainOf(to) if r.LocalDomains[d] { return r.Local.Deliver(from, to, data) } else { return r.Remote.Deliver(from, to, data) } } - -// Split an user@domain address into user and domain. -func split(addr string) (string, string) { - ps := strings.SplitN(addr, "@", 2) - if len(ps) != 2 { - return addr, "" - } - - return ps[0], ps[1] -} - -func userOf(addr string) string { - user, _ := split(addr) - return user -} - -func domainOf(addr string) string { - _, domain := split(addr) - return domain -} diff --git a/internal/courier/procmail.go b/internal/courier/procmail.go index c307500..ceeebcd 100644 --- a/internal/courier/procmail.go +++ b/internal/courier/procmail.go @@ -8,6 +8,7 @@ import ( "time" "unicode" + "blitiri.com.ar/go/chasquid/internal/envelope" "blitiri.com.ar/go/chasquid/internal/trace" ) @@ -36,13 +37,17 @@ func (p *Procmail) Deliver(from string, to string, data []byte) error { defer tr.Finish() // Get the user, and sanitize to be extra paranoid. - user := sanitizeForProcmail(userOf(to)) - tr.LazyPrintf("%s -> %s (%s)", from, user, to) + user := sanitizeForProcmail(envelope.UserOf(to)) + domain := sanitizeForProcmail(envelope.DomainOf(to)) + tr.LazyPrintf("%s -> %s (%s @ %s)", from, user, to, domain) // Prepare the command, replacing the necessary arguments. + replacer := strings.NewReplacer( + "%user%", user, + "%domain%", domain) args := []string{} for _, a := range MailDeliveryAgentArgs { - args = append(args, strings.Replace(a, "%user%", user, -1)) + args = append(args, replacer.Replace(a)) } cmd := exec.Command(MailDeliveryAgentBin, args...) diff --git a/internal/courier/procmail_test.go b/internal/courier/procmail_test.go index c806acc..7e69d33 100644 --- a/internal/courier/procmail_test.go +++ b/internal/courier/procmail_test.go @@ -19,7 +19,8 @@ func TestProcmail(t *testing.T) { MailDeliveryAgentArgs = []string{dir + "/%user%"} p := Procmail{} - err = p.Deliver("from@x", "to@y", []byte("data")) + + err = p.Deliver("from@x", "to@local", []byte("data")) if err != nil { t.Fatalf("Deliver: %v", err) } @@ -36,7 +37,8 @@ func TestProcmailTimeout(t *testing.T) { procmailTimeout = 100 * time.Millisecond p := Procmail{} - err := p.Deliver("from", "to", []byte("data")) + + err := p.Deliver("from", "to@local", []byte("data")) if err != timeoutError { t.Errorf("Unexpected error: %v", err) } diff --git a/internal/courier/smtp.go b/internal/courier/smtp.go index 4750cd1..423cb50 100644 --- a/internal/courier/smtp.go +++ b/internal/courier/smtp.go @@ -8,6 +8,7 @@ import ( "github.com/golang/glog" + "blitiri.com.ar/go/chasquid/internal/envelope" "blitiri.com.ar/go/chasquid/internal/trace" ) @@ -33,7 +34,7 @@ func (s *SMTP) Deliver(from string, to string, data []byte) error { defer tr.Finish() tr.LazyPrintf("%s -> %s", from, to) - mx, err := lookupMX(domainOf(to)) + mx, err := lookupMX(envelope.DomainOf(to)) if err != nil { return tr.Errorf("Could not find mail server: %v", err) } diff --git a/internal/envelope/envelope.go b/internal/envelope/envelope.go new file mode 100644 index 0000000..c1d4233 --- /dev/null +++ b/internal/envelope/envelope.go @@ -0,0 +1,38 @@ +// Package envelope implements functions related to handling email envelopes +// (basically tuples of (from, to, data). +package envelope + +import ( + "strings" + + "blitiri.com.ar/go/chasquid/internal/set" +) + +// Split an user@domain address into user and domain. +func split(addr string) (string, string) { + ps := strings.SplitN(addr, "@", 2) + if len(ps) != 2 { + return addr, "" + } + + return ps[0], ps[1] +} + +func UserOf(addr string) string { + user, _ := split(addr) + return user +} + +func DomainOf(addr string) string { + _, domain := split(addr) + return domain +} + +func DomainIn(addr string, locals *set.String) bool { + domain := DomainOf(addr) + if domain == "" { + return true + } + + return locals.Has(domain) +} diff --git a/internal/envelope/envelope_test.go b/internal/envelope/envelope_test.go new file mode 100644 index 0000000..e8746a7 --- /dev/null +++ b/internal/envelope/envelope_test.go @@ -0,0 +1,43 @@ +package envelope + +import ( + "testing" + + "blitiri.com.ar/go/chasquid/internal/set" +) + +func TestSplit(t *testing.T) { + cases := []struct { + addr, user, domain string + }{ + {"lalala@lelele", "lalala", "lelele"}, + } + + for _, c := range cases { + if user := UserOf(c.addr); user != c.user { + t.Errorf("%q: expected user %q, got %q", c.addr, c.user, user) + } + if domain := DomainOf(c.addr); domain != c.domain { + t.Errorf("%q: expected domain %q, got %q", + c.addr, c.domain, domain) + } + } +} + +func TestDomainIn(t *testing.T) { + ls := set.NewString("domain1", "domain2") + cases := []struct { + addr string + in bool + }{ + {"u@domain1", true}, + {"u@domain2", true}, + {"u@domain3", false}, + {"u", true}, + } + for _, c := range cases { + if in := DomainIn(c.addr, ls); in != c.in { + t.Errorf("%q: expected %v, got %v", c.addr, c.in, in) + } + } +}