1
0
mirror of https://blitiri.com.ar/repos/chasquid synced 2026-01-08 17:51:57 +00:00

courier: Tidy up the Procmail courier

This patch tidies up the Procmail courier:
 - Move the configuration options to the courier instance, instead of using
   global variables.
 - Implement more useful string replacement options.
 - Use exec.CommandContext for running the command with a timeout.

As a consequence of the first item, the queue now takes the couriers via its
constructor.
This commit is contained in:
Alberto Bertogli
2016-09-23 00:45:21 +01:00
parent d05b8ef189
commit 667358d72e
11 changed files with 69 additions and 69 deletions

View File

@@ -2,6 +2,7 @@ package courier
import (
"bytes"
"context"
"fmt"
"os/exec"
"strings"
@@ -12,44 +13,46 @@ import (
"blitiri.com.ar/go/chasquid/internal/trace"
)
var (
// Location of the procmail binary, and arguments to use.
// The string "%user%" will be replaced with the local user.
// TODO: Make these a part of the courier instance itself? Why do they
// have to be global?
MailDeliveryAgentBin = "procmail"
MailDeliveryAgentArgs = []string{"-d", "%user%"}
// Give procmail 1m to deliver mail.
procmailTimeout = 1 * time.Minute
)
var (
errTimeout = fmt.Errorf("Operation timed out")
)
// Procmail delivers local mail via procmail.
type Procmail struct {
Binary string // Path to the binary.
Args []string // Arguments to pass.
Timeout time.Duration // Timeout for each invocation.
}
func (p *Procmail) Deliver(from string, to string, data []byte) error {
tr := trace.New("Procmail", "Deliver")
defer tr.Finish()
// Get the user, and sanitize to be extra paranoid.
user := sanitizeForProcmail(envelope.UserOf(to))
domain := sanitizeForProcmail(envelope.DomainOf(to))
tr.LazyPrintf("%s -> %s (%s @ %s)", from, user, to, domain)
// Sanitize, just in case.
from = sanitizeForProcmail(from)
to = sanitizeForProcmail(to)
tr.LazyPrintf("%s -> %s", from, to)
// Prepare the command, replacing the necessary arguments.
replacer := strings.NewReplacer(
"%user%", user,
"%domain%", domain)
"%from%", from,
"%from_user%", envelope.UserOf(from),
"%from_domain%", envelope.DomainOf(from),
"%to%", to,
"%to_user%", envelope.UserOf(to),
"%to_domain%", envelope.DomainOf(to),
)
args := []string{}
for _, a := range MailDeliveryAgentArgs {
for _, a := range p.Args {
args = append(args, replacer.Replace(a))
}
cmd := exec.Command(MailDeliveryAgentBin, args...)
ctx, _ := context.WithDeadline(context.Background(),
time.Now().Add(p.Timeout))
cmd := exec.CommandContext(ctx, p.Binary, args...)
cmdStdin, err := cmd.StdinPipe()
if err != nil {
@@ -72,13 +75,9 @@ func (p *Procmail) Deliver(from string, to string, data []byte) error {
cmdStdin.Close()
timer := time.AfterFunc(procmailTimeout, func() {
cmd.Process.Kill()
})
err = cmd.Wait()
timedOut := !timer.Stop()
if timedOut {
if ctx.Err() == context.DeadlineExceeded {
return tr.Error(errTimeout)
}
if err != nil {