1
0
mirror of https://blitiri.com.ar/repos/chasquid synced 2025-12-18 14:47:03 +00:00

Introduce an "envelope" package

This patch introduces an "envelope" package which, for now, provides simple
utilities for getting the user and domain of an address.

It also changes the couriers to use it (but other implementations remain, will
be moved over in subsequent patches).
This commit is contained in:
Alberto Bertogli
2016-07-19 23:18:40 +01:00
parent 831ef13132
commit 362ef6f6d0
6 changed files with 97 additions and 28 deletions

View File

@@ -1,7 +1,7 @@
// Package courier implements various couriers for delivering messages. // Package courier implements various couriers for delivering messages.
package courier package courier
import "strings" import "blitiri.com.ar/go/chasquid/internal/envelope"
// Courier delivers mail to a single recipient. // Courier delivers mail to a single recipient.
// It is implemented by different couriers, for both local and remote // 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 { func (r *Router) Deliver(from string, to string, data []byte) error {
d := domainOf(to) d := envelope.DomainOf(to)
if r.LocalDomains[d] { if r.LocalDomains[d] {
return r.Local.Deliver(from, to, data) return r.Local.Deliver(from, to, data)
} else { } else {
return r.Remote.Deliver(from, to, data) 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
}

View File

@@ -8,6 +8,7 @@ import (
"time" "time"
"unicode" "unicode"
"blitiri.com.ar/go/chasquid/internal/envelope"
"blitiri.com.ar/go/chasquid/internal/trace" "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() defer tr.Finish()
// Get the user, and sanitize to be extra paranoid. // Get the user, and sanitize to be extra paranoid.
user := sanitizeForProcmail(userOf(to)) user := sanitizeForProcmail(envelope.UserOf(to))
tr.LazyPrintf("%s -> %s (%s)", from, user, to) domain := sanitizeForProcmail(envelope.DomainOf(to))
tr.LazyPrintf("%s -> %s (%s @ %s)", from, user, to, domain)
// Prepare the command, replacing the necessary arguments. // Prepare the command, replacing the necessary arguments.
replacer := strings.NewReplacer(
"%user%", user,
"%domain%", domain)
args := []string{} args := []string{}
for _, a := range MailDeliveryAgentArgs { for _, a := range MailDeliveryAgentArgs {
args = append(args, strings.Replace(a, "%user%", user, -1)) args = append(args, replacer.Replace(a))
} }
cmd := exec.Command(MailDeliveryAgentBin, args...) cmd := exec.Command(MailDeliveryAgentBin, args...)

View File

@@ -19,7 +19,8 @@ func TestProcmail(t *testing.T) {
MailDeliveryAgentArgs = []string{dir + "/%user%"} MailDeliveryAgentArgs = []string{dir + "/%user%"}
p := Procmail{} p := Procmail{}
err = p.Deliver("from@x", "to@y", []byte("data"))
err = p.Deliver("from@x", "to@local", []byte("data"))
if err != nil { if err != nil {
t.Fatalf("Deliver: %v", err) t.Fatalf("Deliver: %v", err)
} }
@@ -36,7 +37,8 @@ func TestProcmailTimeout(t *testing.T) {
procmailTimeout = 100 * time.Millisecond procmailTimeout = 100 * time.Millisecond
p := Procmail{} p := Procmail{}
err := p.Deliver("from", "to", []byte("data"))
err := p.Deliver("from", "to@local", []byte("data"))
if err != timeoutError { if err != timeoutError {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }

View File

@@ -8,6 +8,7 @@ import (
"github.com/golang/glog" "github.com/golang/glog"
"blitiri.com.ar/go/chasquid/internal/envelope"
"blitiri.com.ar/go/chasquid/internal/trace" "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() defer tr.Finish()
tr.LazyPrintf("%s -> %s", from, to) tr.LazyPrintf("%s -> %s", from, to)
mx, err := lookupMX(domainOf(to)) mx, err := lookupMX(envelope.DomainOf(to))
if err != nil { if err != nil {
return tr.Errorf("Could not find mail server: %v", err) return tr.Errorf("Could not find mail server: %v", err)
} }

View File

@@ -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)
}

View File

@@ -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)
}
}
}