diff options
Diffstat (limited to 'appl/cmd/sendmail.b')
| -rw-r--r-- | appl/cmd/sendmail.b | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/appl/cmd/sendmail.b b/appl/cmd/sendmail.b new file mode 100644 index 00000000..9b6d0c17 --- /dev/null +++ b/appl/cmd/sendmail.b @@ -0,0 +1,252 @@ +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; +} |
