ref: babf901b4a508c3ec5d1f89655f10377bbdf9637
dir: /appl/cmd/sendmail.b/
implement Sendmail;
include "sys.m";
sys: Sys;
include "draw.m";
include "bufio.m";
include "daytime.m";
include "smtp.m";
include "env.m";
sprint, fprint : import sys;
DEBUG : con 0;
STRMAX : con 512;
Sendmail : module
{
PATH : con "/dis/sendmail.dis";
# argv is list of persons to send mail to (or nil if To: lines present in message)
# mail is read from standard input
# scans mail for headers (From: , To: , Cc: , Subject: , Re: ) where case is not sensitive
init: fn(ctxt : ref Draw->Context, argv : list of string);
};
init(nil : ref Draw->Context, args : list of string) {
from : string;
tos, cc : list of string = nil;
sys = load Sys Sys->PATH;
smtp := load Smtp Smtp->PATH;
if (smtp == nil)
error(sprint("cannot load %s", Smtp->PATH), 1);
daytime := load Daytime Daytime->PATH;
if (daytime == nil)
error(sprint("cannot load %s", Daytime->PATH), 1);
msgl := readin();
for (ml := msgl; ml != nil; ml = tl ml) {
msg := hd ml;
lenm := len msg;
sol := 1;
for (i := 0; i < lenm; i++) {
if (sol) {
for (j := i; j < lenm; j++)
if (msg[j] == '\n')
break;
s := msg[i:j];
if (from == nil) {
from = match(s, "from");
if (from != nil)
from = extract(from);
}
if (tos == nil)
tos = lmatch(s, "to");
if (cc == nil)
cc = lmatch(s, "cc");
sol = 0;
}
if (msg[i] == '\n')
sol = 1;
}
}
if (tos != nil && tl args != nil)
error("recipients specified on To: line and as args - aborted", 1);
if (from == nil)
from = readfile("/dev/user");
from = adddom(from);
if (tos == nil)
tos = tl args;
(ok, err) := smtp->open(nil);
if (ok < 0) {
smtp->close();
error(sprint("smtp open failed: %s", err), 1);
}
dump(from, tos, cc, msgl);
msgl = "From " + from + "\t" + daytime->time() + "\n" :: msgl;
# msgl = "From: " + from + "\n" + "Date: " + daytime->time() + "\n" :: msgl;
(ok, err) = smtp->sendmail(from, tos, cc, msgl);
if (ok < 0) {
smtp->close();
error(sprint("send failed : %s", err), 0);
}
smtp->close();
}
readin() : list of string
{
m : string;
ls : list of string;
nc : int;
bufio := load Bufio Bufio->PATH;
Iobuf : import bufio;
b := bufio->fopen(sys->fildes(0), Bufio->OREAD);
ls = nil;
m = nil;
nc = 0;
while ((s := b.gets('\n')) != nil) {
if (nc > STRMAX) {
ls = m :: ls;
m = nil;
nc = 0;
}
m += s;
nc += len s;
}
b.close();
if (m != nil)
ls = m :: ls;
return rev(ls);
}
match(s: string, pat : string) : string
{
ls := len s;
lp := len pat;
if (ls < lp)
return nil;
for (i := 0; i < lp; i++) {
c := s[i];
if (c >= 'A' && c <= 'Z')
c += 'a'-'A';
if (c != pat[i])
return nil;
}
if (i < len s && s[i] == ':')
i++;
else if (i < len s - 1 && s[i] == ' ' && s[i+1] == ':')
i += 2;
else
return nil;
while (i < len s && (s[i] == ' ' || s[i] == '\t'))
i++;
j := ls-1;
while (j >= 0 && (s[j] == ' ' || s[j] == '\t' || s[j] == '\n'))
j--;
return s[i:j+1];
}
lmatch(s : string, pat : string) : list of string
{
r := match(s, pat);
if (r != nil) {
(ok, lr) := sys->tokenize(r, " ,\t");
return lr;
}
return nil;
}
extract(s : string) : string
{
ls := len s;
for(i := 0; i < ls; i++) {
if(s[i] == '<') {
for(j := i+1; j < ls; j++)
if(s[j] == '>')
break;
return s[i+1:j];
}
}
return s;
}
adddom(s : string) : string
{
if (s == nil)
return nil;
for (i := 0; i < len s; i++)
if (s[i] == '@')
return s;
# better to get it from environment if possible
env := load Env Env->PATH;
if (env != nil && (dom := env->getenv("DOMAIN")) != nil) {
ldom := len dom;
if (dom[ldom - 1] == '\n')
dom = dom[0:ldom - 1];
return s + "@" + dom;
}
d := readfile("/usr/" + s + "/mail/domain");
if (d != nil) {
ld := len d;
if (d[ld - 1] == '\n')
d = d[0:ld - 1];
return s + "@" + d;
}
return s;
}
readfile(f : string) : string
{
fd := sys->open(f, sys->OREAD);
if(fd == nil)
return nil;
buf := array[128] of byte;
n := sys->read(fd, buf, len buf);
if(n < 0)
return nil;
return string buf[0:n];
}
rev(l1 : list of string) : list of string
{
l2 : list of string = nil;
for ( ; l1 != nil; l1 = tl l1)
l2 = hd l1 :: l2;
return l2;
}
lprint(fd : ref Sys->FD, ls : list of string)
{
for ( ; ls != nil; ls = tl ls)
fprint(fd, "%s ", hd ls);
fprint(fd, "\n");
}
cfd : ref Sys->FD;
opencons()
{
if (cfd == nil)
cfd = sys->open("/dev/cons", Sys->OWRITE);
}
dump(from : string, tos : list of string, cc : list of string, msgl : list of string)
{
if (DEBUG) {
opencons();
fprint(cfd, "from\n");
fprint(cfd, "%s\n", from);
fprint(cfd, "to\n");
lprint(cfd, tos);
fprint(cfd, "cc\n");
lprint(cfd, cc);
fprint(cfd, "message\n");
for ( ; msgl != nil; msgl = tl msgl) {
fprint(cfd, "%s", hd msgl);
fprint(cfd, "xxxx\n");
}
}
}
error(s : string, ex : int)
{
if (DEBUG) {
opencons();
fprint(cfd, "sendmail: %s\n", s);
}
fprint(sys->fildes(2), "sendmail: %s\n", s);
if (ex)
exit;
}