1*37da2899SCharles.Forsythimplement Sendmail; 2*37da2899SCharles.Forsyth 3*37da2899SCharles.Forsythinclude "sys.m"; 4*37da2899SCharles.Forsyth sys: Sys; 5*37da2899SCharles.Forsythinclude "draw.m"; 6*37da2899SCharles.Forsythinclude "bufio.m"; 7*37da2899SCharles.Forsythinclude "daytime.m"; 8*37da2899SCharles.Forsythinclude "smtp.m"; 9*37da2899SCharles.Forsythinclude "env.m"; 10*37da2899SCharles.Forsyth 11*37da2899SCharles.Forsythsprint, fprint : import sys; 12*37da2899SCharles.Forsyth 13*37da2899SCharles.ForsythDEBUG : con 0; 14*37da2899SCharles.ForsythSTRMAX : con 512; 15*37da2899SCharles.Forsyth 16*37da2899SCharles.ForsythSendmail : module 17*37da2899SCharles.Forsyth{ 18*37da2899SCharles.Forsyth PATH : con "/dis/sendmail.dis"; 19*37da2899SCharles.Forsyth 20*37da2899SCharles.Forsyth # argv is list of persons to send mail to (or nil if To: lines present in message) 21*37da2899SCharles.Forsyth # mail is read from standard input 22*37da2899SCharles.Forsyth # scans mail for headers (From: , To: , Cc: , Subject: , Re: ) where case is not sensitive 23*37da2899SCharles.Forsyth init: fn(ctxt : ref Draw->Context, argv : list of string); 24*37da2899SCharles.Forsyth}; 25*37da2899SCharles.Forsyth 26*37da2899SCharles.Forsythinit(nil : ref Draw->Context, args : list of string) { 27*37da2899SCharles.Forsyth from : string; 28*37da2899SCharles.Forsyth tos, cc : list of string = nil; 29*37da2899SCharles.Forsyth 30*37da2899SCharles.Forsyth sys = load Sys Sys->PATH; 31*37da2899SCharles.Forsyth smtp := load Smtp Smtp->PATH; 32*37da2899SCharles.Forsyth if (smtp == nil) 33*37da2899SCharles.Forsyth error(sprint("cannot load %s", Smtp->PATH), 1); 34*37da2899SCharles.Forsyth daytime := load Daytime Daytime->PATH; 35*37da2899SCharles.Forsyth if (daytime == nil) 36*37da2899SCharles.Forsyth error(sprint("cannot load %s", Daytime->PATH), 1); 37*37da2899SCharles.Forsyth msgl := readin(); 38*37da2899SCharles.Forsyth for (ml := msgl; ml != nil; ml = tl ml) { 39*37da2899SCharles.Forsyth msg := hd ml; 40*37da2899SCharles.Forsyth lenm := len msg; 41*37da2899SCharles.Forsyth sol := 1; 42*37da2899SCharles.Forsyth for (i := 0; i < lenm; i++) { 43*37da2899SCharles.Forsyth if (sol) { 44*37da2899SCharles.Forsyth for (j := i; j < lenm; j++) 45*37da2899SCharles.Forsyth if (msg[j] == '\n') 46*37da2899SCharles.Forsyth break; 47*37da2899SCharles.Forsyth s := msg[i:j]; 48*37da2899SCharles.Forsyth if (from == nil) { 49*37da2899SCharles.Forsyth from = match(s, "from"); 50*37da2899SCharles.Forsyth if (from != nil) 51*37da2899SCharles.Forsyth from = extract(from); 52*37da2899SCharles.Forsyth } 53*37da2899SCharles.Forsyth if (tos == nil) 54*37da2899SCharles.Forsyth tos = lmatch(s, "to"); 55*37da2899SCharles.Forsyth if (cc == nil) 56*37da2899SCharles.Forsyth cc = lmatch(s, "cc"); 57*37da2899SCharles.Forsyth sol = 0; 58*37da2899SCharles.Forsyth } 59*37da2899SCharles.Forsyth if (msg[i] == '\n') 60*37da2899SCharles.Forsyth sol = 1; 61*37da2899SCharles.Forsyth } 62*37da2899SCharles.Forsyth } 63*37da2899SCharles.Forsyth if (tos != nil && tl args != nil) 64*37da2899SCharles.Forsyth error("recipients specified on To: line and as args - aborted", 1); 65*37da2899SCharles.Forsyth if (from == nil) 66*37da2899SCharles.Forsyth from = readfile("/dev/user"); 67*37da2899SCharles.Forsyth from = adddom(from); 68*37da2899SCharles.Forsyth if (tos == nil) 69*37da2899SCharles.Forsyth tos = tl args; 70*37da2899SCharles.Forsyth (ok, err) := smtp->open(nil); 71*37da2899SCharles.Forsyth if (ok < 0) { 72*37da2899SCharles.Forsyth smtp->close(); 73*37da2899SCharles.Forsyth error(sprint("smtp open failed: %s", err), 1); 74*37da2899SCharles.Forsyth } 75*37da2899SCharles.Forsyth dump(from, tos, cc, msgl); 76*37da2899SCharles.Forsyth msgl = "From " + from + "\t" + daytime->time() + "\n" :: msgl; 77*37da2899SCharles.Forsyth # msgl = "From: " + from + "\n" + "Date: " + daytime->time() + "\n" :: msgl; 78*37da2899SCharles.Forsyth (ok, err) = smtp->sendmail(from, tos, cc, msgl); 79*37da2899SCharles.Forsyth if (ok < 0) { 80*37da2899SCharles.Forsyth smtp->close(); 81*37da2899SCharles.Forsyth error(sprint("send failed : %s", err), 0); 82*37da2899SCharles.Forsyth } 83*37da2899SCharles.Forsyth smtp->close(); 84*37da2899SCharles.Forsyth} 85*37da2899SCharles.Forsyth 86*37da2899SCharles.Forsythreadin() : list of string 87*37da2899SCharles.Forsyth{ 88*37da2899SCharles.Forsyth m : string; 89*37da2899SCharles.Forsyth ls : list of string; 90*37da2899SCharles.Forsyth nc : int; 91*37da2899SCharles.Forsyth 92*37da2899SCharles.Forsyth bufio := load Bufio Bufio->PATH; 93*37da2899SCharles.Forsyth Iobuf : import bufio; 94*37da2899SCharles.Forsyth b := bufio->fopen(sys->fildes(0), Bufio->OREAD); 95*37da2899SCharles.Forsyth ls = nil; 96*37da2899SCharles.Forsyth m = nil; 97*37da2899SCharles.Forsyth nc = 0; 98*37da2899SCharles.Forsyth while ((s := b.gets('\n')) != nil) { 99*37da2899SCharles.Forsyth if (nc > STRMAX) { 100*37da2899SCharles.Forsyth ls = m :: ls; 101*37da2899SCharles.Forsyth m = nil; 102*37da2899SCharles.Forsyth nc = 0; 103*37da2899SCharles.Forsyth } 104*37da2899SCharles.Forsyth m += s; 105*37da2899SCharles.Forsyth nc += len s; 106*37da2899SCharles.Forsyth } 107*37da2899SCharles.Forsyth b.close(); 108*37da2899SCharles.Forsyth if (m != nil) 109*37da2899SCharles.Forsyth ls = m :: ls; 110*37da2899SCharles.Forsyth return rev(ls); 111*37da2899SCharles.Forsyth} 112*37da2899SCharles.Forsyth 113*37da2899SCharles.Forsythmatch(s: string, pat : string) : string 114*37da2899SCharles.Forsyth{ 115*37da2899SCharles.Forsyth ls := len s; 116*37da2899SCharles.Forsyth lp := len pat; 117*37da2899SCharles.Forsyth if (ls < lp) 118*37da2899SCharles.Forsyth return nil; 119*37da2899SCharles.Forsyth for (i := 0; i < lp; i++) { 120*37da2899SCharles.Forsyth c := s[i]; 121*37da2899SCharles.Forsyth if (c >= 'A' && c <= 'Z') 122*37da2899SCharles.Forsyth c += 'a'-'A'; 123*37da2899SCharles.Forsyth if (c != pat[i]) 124*37da2899SCharles.Forsyth return nil; 125*37da2899SCharles.Forsyth } 126*37da2899SCharles.Forsyth if (i < len s && s[i] == ':') 127*37da2899SCharles.Forsyth i++; 128*37da2899SCharles.Forsyth else if (i < len s - 1 && s[i] == ' ' && s[i+1] == ':') 129*37da2899SCharles.Forsyth i += 2; 130*37da2899SCharles.Forsyth else 131*37da2899SCharles.Forsyth return nil; 132*37da2899SCharles.Forsyth while (i < len s && (s[i] == ' ' || s[i] == '\t')) 133*37da2899SCharles.Forsyth i++; 134*37da2899SCharles.Forsyth j := ls-1; 135*37da2899SCharles.Forsyth while (j >= 0 && (s[j] == ' ' || s[j] == '\t' || s[j] == '\n')) 136*37da2899SCharles.Forsyth j--; 137*37da2899SCharles.Forsyth return s[i:j+1]; 138*37da2899SCharles.Forsyth} 139*37da2899SCharles.Forsyth 140*37da2899SCharles.Forsythlmatch(s : string, pat : string) : list of string 141*37da2899SCharles.Forsyth{ 142*37da2899SCharles.Forsyth r := match(s, pat); 143*37da2899SCharles.Forsyth if (r != nil) { 144*37da2899SCharles.Forsyth (ok, lr) := sys->tokenize(r, " ,\t"); 145*37da2899SCharles.Forsyth return lr; 146*37da2899SCharles.Forsyth } 147*37da2899SCharles.Forsyth return nil; 148*37da2899SCharles.Forsyth} 149*37da2899SCharles.Forsyth 150*37da2899SCharles.Forsythextract(s : string) : string 151*37da2899SCharles.Forsyth{ 152*37da2899SCharles.Forsyth ls := len s; 153*37da2899SCharles.Forsyth for(i := 0; i < ls; i++) { 154*37da2899SCharles.Forsyth if(s[i] == '<') { 155*37da2899SCharles.Forsyth for(j := i+1; j < ls; j++) 156*37da2899SCharles.Forsyth if(s[j] == '>') 157*37da2899SCharles.Forsyth break; 158*37da2899SCharles.Forsyth return s[i+1:j]; 159*37da2899SCharles.Forsyth } 160*37da2899SCharles.Forsyth } 161*37da2899SCharles.Forsyth return s; 162*37da2899SCharles.Forsyth} 163*37da2899SCharles.Forsyth 164*37da2899SCharles.Forsythadddom(s : string) : string 165*37da2899SCharles.Forsyth{ 166*37da2899SCharles.Forsyth if (s == nil) 167*37da2899SCharles.Forsyth return nil; 168*37da2899SCharles.Forsyth for (i := 0; i < len s; i++) 169*37da2899SCharles.Forsyth if (s[i] == '@') 170*37da2899SCharles.Forsyth return s; 171*37da2899SCharles.Forsyth # better to get it from environment if possible 172*37da2899SCharles.Forsyth env := load Env Env->PATH; 173*37da2899SCharles.Forsyth if (env != nil && (dom := env->getenv("DOMAIN")) != nil) { 174*37da2899SCharles.Forsyth ldom := len dom; 175*37da2899SCharles.Forsyth if (dom[ldom - 1] == '\n') 176*37da2899SCharles.Forsyth dom = dom[0:ldom - 1]; 177*37da2899SCharles.Forsyth return s + "@" + dom; 178*37da2899SCharles.Forsyth } 179*37da2899SCharles.Forsyth d := readfile("/usr/" + s + "/mail/domain"); 180*37da2899SCharles.Forsyth if (d != nil) { 181*37da2899SCharles.Forsyth ld := len d; 182*37da2899SCharles.Forsyth if (d[ld - 1] == '\n') 183*37da2899SCharles.Forsyth d = d[0:ld - 1]; 184*37da2899SCharles.Forsyth return s + "@" + d; 185*37da2899SCharles.Forsyth } 186*37da2899SCharles.Forsyth return s; 187*37da2899SCharles.Forsyth} 188*37da2899SCharles.Forsyth 189*37da2899SCharles.Forsythreadfile(f : string) : string 190*37da2899SCharles.Forsyth{ 191*37da2899SCharles.Forsyth fd := sys->open(f, sys->OREAD); 192*37da2899SCharles.Forsyth if(fd == nil) 193*37da2899SCharles.Forsyth return nil; 194*37da2899SCharles.Forsyth buf := array[128] of byte; 195*37da2899SCharles.Forsyth n := sys->read(fd, buf, len buf); 196*37da2899SCharles.Forsyth if(n < 0) 197*37da2899SCharles.Forsyth return nil; 198*37da2899SCharles.Forsyth return string buf[0:n]; 199*37da2899SCharles.Forsyth} 200*37da2899SCharles.Forsyth 201*37da2899SCharles.Forsythrev(l1 : list of string) : list of string 202*37da2899SCharles.Forsyth{ 203*37da2899SCharles.Forsyth l2 : list of string = nil; 204*37da2899SCharles.Forsyth 205*37da2899SCharles.Forsyth for ( ; l1 != nil; l1 = tl l1) 206*37da2899SCharles.Forsyth l2 = hd l1 :: l2; 207*37da2899SCharles.Forsyth return l2; 208*37da2899SCharles.Forsyth} 209*37da2899SCharles.Forsyth 210*37da2899SCharles.Forsythlprint(fd : ref Sys->FD, ls : list of string) 211*37da2899SCharles.Forsyth{ 212*37da2899SCharles.Forsyth for ( ; ls != nil; ls = tl ls) 213*37da2899SCharles.Forsyth fprint(fd, "%s ", hd ls); 214*37da2899SCharles.Forsyth fprint(fd, "\n"); 215*37da2899SCharles.Forsyth} 216*37da2899SCharles.Forsyth 217*37da2899SCharles.Forsythcfd : ref Sys->FD; 218*37da2899SCharles.Forsyth 219*37da2899SCharles.Forsythopencons() 220*37da2899SCharles.Forsyth{ 221*37da2899SCharles.Forsyth if (cfd == nil) 222*37da2899SCharles.Forsyth cfd = sys->open("/dev/cons", Sys->OWRITE); 223*37da2899SCharles.Forsyth} 224*37da2899SCharles.Forsyth 225*37da2899SCharles.Forsythdump(from : string, tos : list of string, cc : list of string, msgl : list of string) 226*37da2899SCharles.Forsyth{ 227*37da2899SCharles.Forsyth if (DEBUG) { 228*37da2899SCharles.Forsyth opencons(); 229*37da2899SCharles.Forsyth fprint(cfd, "from\n"); 230*37da2899SCharles.Forsyth fprint(cfd, "%s\n", from); 231*37da2899SCharles.Forsyth fprint(cfd, "to\n"); 232*37da2899SCharles.Forsyth lprint(cfd, tos); 233*37da2899SCharles.Forsyth fprint(cfd, "cc\n"); 234*37da2899SCharles.Forsyth lprint(cfd, cc); 235*37da2899SCharles.Forsyth fprint(cfd, "message\n"); 236*37da2899SCharles.Forsyth for ( ; msgl != nil; msgl = tl msgl) { 237*37da2899SCharles.Forsyth fprint(cfd, "%s", hd msgl); 238*37da2899SCharles.Forsyth fprint(cfd, "xxxx\n"); 239*37da2899SCharles.Forsyth } 240*37da2899SCharles.Forsyth } 241*37da2899SCharles.Forsyth} 242*37da2899SCharles.Forsyth 243*37da2899SCharles.Forsytherror(s : string, ex : int) 244*37da2899SCharles.Forsyth{ 245*37da2899SCharles.Forsyth if (DEBUG) { 246*37da2899SCharles.Forsyth opencons(); 247*37da2899SCharles.Forsyth fprint(cfd, "sendmail: %s\n", s); 248*37da2899SCharles.Forsyth } 249*37da2899SCharles.Forsyth fprint(sys->fildes(2), "sendmail: %s\n", s); 250*37da2899SCharles.Forsyth if (ex) 251*37da2899SCharles.Forsyth exit; 252*37da2899SCharles.Forsyth} 253