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:
@@ -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
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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...)
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
38
internal/envelope/envelope.go
Normal file
38
internal/envelope/envelope.go
Normal 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)
|
||||||
|
}
|
||||||
43
internal/envelope/envelope_test.go
Normal file
43
internal/envelope/envelope_test.go
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user