vartflagbool// If set, we need to take the recipient(s) from the message headers. We only do one recipient, in To.
o:=0
fori,s:=rangeargs{
ifs=="--"{
o=i+1
break
}
if!strings.HasPrefix(s,"-"){
o=i
break
}
s=s[1:]
ifstrings.HasPrefix(s,"F"){
from=s[1:]
log.Printf("ignoring -F %q",from)// todo
}elseifs=="t"{
tflag=true
}
o=i+1
// Ignore options otherwise.
// todo: we may want to parse more flags. some invocations may not be about sending a message. for now, we'll assume sendmail is only invoked to send a message.
}
args=args[o:]
// todo: perhaps allow configuration of config file through environment variable? have to keep in mind that mox with setgid moxsubmit would be reading the file.
constconfPath="/etc/moxsubmit.conf"
err:=sconf.ParseFile(confPath,&submitconf)
xcheckf(err,"parsing config")
varrecipientstring
iflen(args)==1&&!tflag{
recipient=args[0]
if!strings.Contains(recipient,"@"){
ifsubmitconf.DefaultDestination==""{
log.Fatalf("recipient %q has no @ and no default destination configured",recipient)
}
recipient=submitconf.DefaultDestination
}else{
_,err:=smtp.ParseAddress(args[0])
xcheckf(err,"parsing recipient address")
}
}elseif!tflag||len(args)!=0{
log.Fatalln("need either exactly 1 recipient, or -t")
}
// Read message and build message we are going to send. We replace \n
// with \r\n, and we replace the From header.
// todo: should we also wrap lines that are too long? perhaps only if this is just text, no multipart?
varsbstrings.Builder
r:=bufio.NewReader(os.Stdin)
header:=true// Whether we are in the header.
fmt.Fprintf(&sb,"From: <%s>\r\n",submitconf.From)
varhaveTobool
for{
line,err:=r.ReadString('\n')
iferr!=nil&&err!=io.EOF{
xcheckf(err,"reading message")
}
ifline!=""{
if!strings.HasSuffix(line,"\n"){
line+="\n"
}
if!strings.HasSuffix(line,"\r\n"){
line=line[:len(line)-1]+"\r\n"
}
ifheader&&line=="\r\n"{
// Bare \r\n marks end of header.
if!haveTo{
line=fmt.Sprintf("To: <%s>\r\n",recipient)+line
}
header=false
}elseifheader{
t:=strings.SplitN(line,":",2)
iflen(t)!=2{
log.Fatalf("invalid message, missing colon in header")
}
k:=strings.ToLower(t[0])
ifk=="from"{
// We already added a From header.
iferr==io.EOF{
break
}
continue
}elseiftflag&&k=="to"{
ifrecipient!=""{
log.Fatalf("only single To header allowed")
}
s:=strings.TrimSpace(t[1])
if!strings.Contains(s,"@"){
ifsubmitconf.DefaultDestination==""{
log.Fatalf("recipient %q has no @ and no default destination is configured",s)
}
recipient=submitconf.DefaultDestination
}else{
addrs,err:=mail.ParseAddressList(s)
xcheckf(err,"parsing To address list")
iflen(addrs)!=1{
log.Fatalf("only single address allowed in To header")
}
recipient=addrs[0].Address
}
}
ifk=="to"{
haveTo=true
}
}
sb.WriteString(line)
}
iferr==io.EOF{
break
}
}
msg:=sb.String()
ifrecipient==""{
log.Fatalf("no recipient")
}
// Message seems acceptable. We'll try to deliver it from here. If that fails, we