xref: /inferno-os/appl/cmd/sendmail.b (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
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