xref: /plan9/acme/mail/src/reply.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
1*7dd7cddfSDavid du Colombier #include <u.h>
2*7dd7cddfSDavid du Colombier #include <libc.h>
3*7dd7cddfSDavid du Colombier #include <bio.h>
4*7dd7cddfSDavid du Colombier #include <thread.h>
5*7dd7cddfSDavid du Colombier #include <ctype.h>
6*7dd7cddfSDavid du Colombier #include <plumb.h>
7*7dd7cddfSDavid du Colombier #include "dat.h"
8*7dd7cddfSDavid du Colombier 
9*7dd7cddfSDavid du Colombier static int	replyid;
10*7dd7cddfSDavid du Colombier 
11*7dd7cddfSDavid du Colombier int
12*7dd7cddfSDavid du Colombier EQUAL(char *s, char *t)
13*7dd7cddfSDavid du Colombier {
14*7dd7cddfSDavid du Colombier 	while(tolower(*s) == tolower(*t++))
15*7dd7cddfSDavid du Colombier 		if(*s++ == '\0')
16*7dd7cddfSDavid du Colombier 			return 1;
17*7dd7cddfSDavid du Colombier 	return 0;
18*7dd7cddfSDavid du Colombier }
19*7dd7cddfSDavid du Colombier 
20*7dd7cddfSDavid du Colombier void
21*7dd7cddfSDavid du Colombier mkreply(Message *m, char *label, char *to)
22*7dd7cddfSDavid du Colombier {
23*7dd7cddfSDavid du Colombier 	Message *r;
24*7dd7cddfSDavid du Colombier 	char *dir, *t;
25*7dd7cddfSDavid du Colombier 
26*7dd7cddfSDavid du Colombier 	r = emalloc(sizeof(Message));
27*7dd7cddfSDavid du Colombier 	r->isreply = 1;
28*7dd7cddfSDavid du Colombier 	if(m != nil)
29*7dd7cddfSDavid du Colombier 		r->replyname = estrdup(m->name);
30*7dd7cddfSDavid du Colombier 	r->next = replies.head;
31*7dd7cddfSDavid du Colombier 	r->prev = nil;
32*7dd7cddfSDavid du Colombier 	if(replies.head != nil)
33*7dd7cddfSDavid du Colombier 		replies.head->prev = r;
34*7dd7cddfSDavid du Colombier 	replies.head = r;
35*7dd7cddfSDavid du Colombier 	if(replies.tail == nil)
36*7dd7cddfSDavid du Colombier 		replies.tail = r;
37*7dd7cddfSDavid du Colombier 	r->name = emalloc(strlen(mbox.name)+strlen(label)+10);
38*7dd7cddfSDavid du Colombier 	sprint(r->name, "%s%s%d", mbox.name, label, ++replyid);
39*7dd7cddfSDavid du Colombier 	r->w = newwindow();
40*7dd7cddfSDavid du Colombier 	winname(r->w, r->name);
41*7dd7cddfSDavid du Colombier 	wintagwrite(r->w, "|fmt Post", 5+4);
42*7dd7cddfSDavid du Colombier 	r->tagposted = 1;
43*7dd7cddfSDavid du Colombier 	threadcreate(mesgctl, r, STACK);
44*7dd7cddfSDavid du Colombier 	winopenbody(r->w, OWRITE);
45*7dd7cddfSDavid du Colombier 	if(to!=nil && to[0]!='\0')
46*7dd7cddfSDavid du Colombier 		Bprint(r->w->body, "%s\n", to);
47*7dd7cddfSDavid du Colombier 	if(m != nil){
48*7dd7cddfSDavid du Colombier 		dir = estrstrdup(mbox.name, m->name);
49*7dd7cddfSDavid du Colombier 		if(to == nil){
50*7dd7cddfSDavid du Colombier 			/* Reply goes to replyto; Reply all goes to From and To and CC */
51*7dd7cddfSDavid du Colombier 			if(strcmp(label, "Reply") == 0)
52*7dd7cddfSDavid du Colombier 				Bprint(r->w->body, "To: %s\n", m->replyto);
53*7dd7cddfSDavid du Colombier 			else{	/* Replyall */
54*7dd7cddfSDavid du Colombier 				if(strlen(m->from) > 0)
55*7dd7cddfSDavid du Colombier 					Bprint(r->w->body, "To: %s\n", m->from);
56*7dd7cddfSDavid du Colombier 				if(strlen(m->to) > 0)
57*7dd7cddfSDavid du Colombier 					Bprint(r->w->body, "To: %s\n", m->to);
58*7dd7cddfSDavid du Colombier 				if(strlen(m->cc) > 0)
59*7dd7cddfSDavid du Colombier 					Bprint(r->w->body, "CC: %s\n", m->cc);
60*7dd7cddfSDavid du Colombier 			}
61*7dd7cddfSDavid du Colombier 		}
62*7dd7cddfSDavid du Colombier 		if(strlen(m->subject) > 0){
63*7dd7cddfSDavid du Colombier 			t = "Subject: Re: ";
64*7dd7cddfSDavid du Colombier 			if(strlen(m->subject) >= 3)
65*7dd7cddfSDavid du Colombier 				if(tolower(m->subject[0])=='r' && tolower(m->subject[1])=='e' && m->subject[2]==':')
66*7dd7cddfSDavid du Colombier 					t = "Subject: ";
67*7dd7cddfSDavid du Colombier 			Bprint(r->w->body, "%s%s\n", t, m->subject);
68*7dd7cddfSDavid du Colombier 		}
69*7dd7cddfSDavid du Colombier 		Bprint(r->w->body, "Include: %sraw\n", dir);
70*7dd7cddfSDavid du Colombier 		free(dir);
71*7dd7cddfSDavid du Colombier 	}
72*7dd7cddfSDavid du Colombier 	Bprint(r->w->body, "\n");
73*7dd7cddfSDavid du Colombier 	if(m == nil)
74*7dd7cddfSDavid du Colombier 		Bprint(r->w->body, "\n");
75*7dd7cddfSDavid du Colombier 	winclosebody(r->w);
76*7dd7cddfSDavid du Colombier 	if(m == nil)
77*7dd7cddfSDavid du Colombier 		winselect(r->w, "0", 0);
78*7dd7cddfSDavid du Colombier 	else
79*7dd7cddfSDavid du Colombier 		winselect(r->w, "$", 0);
80*7dd7cddfSDavid du Colombier 	winclean(r->w);
81*7dd7cddfSDavid du Colombier 	windormant(r->w);
82*7dd7cddfSDavid du Colombier }
83*7dd7cddfSDavid du Colombier 
84*7dd7cddfSDavid du Colombier void
85*7dd7cddfSDavid du Colombier delreply(Message *m)
86*7dd7cddfSDavid du Colombier {
87*7dd7cddfSDavid du Colombier 	if(m->next == nil)
88*7dd7cddfSDavid du Colombier 		replies.tail = m->prev;
89*7dd7cddfSDavid du Colombier 	else
90*7dd7cddfSDavid du Colombier 		m->next->prev = m->prev;
91*7dd7cddfSDavid du Colombier 	if(m->prev == nil)
92*7dd7cddfSDavid du Colombier 		replies.head = m->next;
93*7dd7cddfSDavid du Colombier 	else
94*7dd7cddfSDavid du Colombier 		m->prev->next = m->next;
95*7dd7cddfSDavid du Colombier 	mesgfreeparts(m);
96*7dd7cddfSDavid du Colombier 	free(m);
97*7dd7cddfSDavid du Colombier }
98*7dd7cddfSDavid du Colombier 
99*7dd7cddfSDavid du Colombier enum
100*7dd7cddfSDavid du Colombier {
101*7dd7cddfSDavid du Colombier 	NARGS		= 100,
102*7dd7cddfSDavid du Colombier 	NARGCHAR	= 8*1024,
103*7dd7cddfSDavid du Colombier 	EXECSTACK 	= STACK+(NARGS+1)*sizeof(char*)+NARGCHAR
104*7dd7cddfSDavid du Colombier };
105*7dd7cddfSDavid du Colombier 
106*7dd7cddfSDavid du Colombier struct Exec
107*7dd7cddfSDavid du Colombier {
108*7dd7cddfSDavid du Colombier 	char		**argv;
109*7dd7cddfSDavid du Colombier 	int		p[2];
110*7dd7cddfSDavid du Colombier 	Channel	*sync;
111*7dd7cddfSDavid du Colombier };
112*7dd7cddfSDavid du Colombier 
113*7dd7cddfSDavid du Colombier /* copy argv to stack and free the incoming strings, so we don't leak argument vectors */
114*7dd7cddfSDavid du Colombier void
115*7dd7cddfSDavid du Colombier buildargv(char **inargv, char *argv[NARGS+1], char args[NARGCHAR])
116*7dd7cddfSDavid du Colombier {
117*7dd7cddfSDavid du Colombier 	int i, n;
118*7dd7cddfSDavid du Colombier 	char *s, *a;
119*7dd7cddfSDavid du Colombier 
120*7dd7cddfSDavid du Colombier 	s = args;
121*7dd7cddfSDavid du Colombier 	for(i=0; i<NARGS; i++){
122*7dd7cddfSDavid du Colombier 		a = inargv[i];
123*7dd7cddfSDavid du Colombier 		if(a == nil)
124*7dd7cddfSDavid du Colombier 			break;
125*7dd7cddfSDavid du Colombier 		n = strlen(a)+1;
126*7dd7cddfSDavid du Colombier 		if((s-args)+n >= NARGCHAR)	/* too many characters */
127*7dd7cddfSDavid du Colombier 			break;
128*7dd7cddfSDavid du Colombier 		argv[i] = s;
129*7dd7cddfSDavid du Colombier 		memmove(s, a, n);
130*7dd7cddfSDavid du Colombier 		s += n;
131*7dd7cddfSDavid du Colombier 		free(a);
132*7dd7cddfSDavid du Colombier 	}
133*7dd7cddfSDavid du Colombier 	argv[i] = nil;
134*7dd7cddfSDavid du Colombier }
135*7dd7cddfSDavid du Colombier 
136*7dd7cddfSDavid du Colombier void
137*7dd7cddfSDavid du Colombier execproc(void *v)
138*7dd7cddfSDavid du Colombier {
139*7dd7cddfSDavid du Colombier 	struct Exec *e;
140*7dd7cddfSDavid du Colombier 	int p[2];
141*7dd7cddfSDavid du Colombier 	char *argv[NARGS+1], args[NARGCHAR];
142*7dd7cddfSDavid du Colombier 
143*7dd7cddfSDavid du Colombier 	e = v;
144*7dd7cddfSDavid du Colombier 	p[0] = e->p[0];
145*7dd7cddfSDavid du Colombier 	p[1] = e->p[1];
146*7dd7cddfSDavid du Colombier 	rfork(RFFDG);
147*7dd7cddfSDavid du Colombier 	sendul(e->sync, 1);
148*7dd7cddfSDavid du Colombier 	buildargv(e->argv, argv, args);
149*7dd7cddfSDavid du Colombier 	free(e->argv);
150*7dd7cddfSDavid du Colombier 	chanfree(e->sync);
151*7dd7cddfSDavid du Colombier 	free(e);
152*7dd7cddfSDavid du Colombier 	dup(p[0], 0);
153*7dd7cddfSDavid du Colombier 	close(p[1]);
154*7dd7cddfSDavid du Colombier 	procexec(nil, "/bin/upas/marshal", argv);
155*7dd7cddfSDavid du Colombier 	threadprint(2, "Mail: can't exec %s: %r\n", argv[0]);
156*7dd7cddfSDavid du Colombier 	threadexits("can't exec");
157*7dd7cddfSDavid du Colombier }
158*7dd7cddfSDavid du Colombier 
159*7dd7cddfSDavid du Colombier enum{
160*7dd7cddfSDavid du Colombier 	ATTACH,
161*7dd7cddfSDavid du Colombier 	BCC,
162*7dd7cddfSDavid du Colombier 	CC,
163*7dd7cddfSDavid du Colombier 	FROM,
164*7dd7cddfSDavid du Colombier 	INCLUDE,
165*7dd7cddfSDavid du Colombier 	TO,
166*7dd7cddfSDavid du Colombier };
167*7dd7cddfSDavid du Colombier 
168*7dd7cddfSDavid du Colombier char *headers[] = {
169*7dd7cddfSDavid du Colombier 	"attach:",
170*7dd7cddfSDavid du Colombier 	"bcc:",
171*7dd7cddfSDavid du Colombier 	"cc:",
172*7dd7cddfSDavid du Colombier 	"from:",
173*7dd7cddfSDavid du Colombier 	"include:",
174*7dd7cddfSDavid du Colombier 	"to:",
175*7dd7cddfSDavid du Colombier 	nil,
176*7dd7cddfSDavid du Colombier };
177*7dd7cddfSDavid du Colombier 
178*7dd7cddfSDavid du Colombier int
179*7dd7cddfSDavid du Colombier whichheader(char *h)
180*7dd7cddfSDavid du Colombier {
181*7dd7cddfSDavid du Colombier 	int i;
182*7dd7cddfSDavid du Colombier 
183*7dd7cddfSDavid du Colombier 	for(i=0; headers[i]!=nil; i++)
184*7dd7cddfSDavid du Colombier 		if(EQUAL(h, headers[i]))
185*7dd7cddfSDavid du Colombier 			return i;
186*7dd7cddfSDavid du Colombier 	return -1;
187*7dd7cddfSDavid du Colombier }
188*7dd7cddfSDavid du Colombier 
189*7dd7cddfSDavid du Colombier char *tolist[200];
190*7dd7cddfSDavid du Colombier char	*cclist[200];
191*7dd7cddfSDavid du Colombier char	*bcclist[200];
192*7dd7cddfSDavid du Colombier int ncc, nbcc, nto;
193*7dd7cddfSDavid du Colombier char	*attlist[200];
194*7dd7cddfSDavid du Colombier int	rfc822[200];
195*7dd7cddfSDavid du Colombier 
196*7dd7cddfSDavid du Colombier int
197*7dd7cddfSDavid du Colombier addressed(char *name)
198*7dd7cddfSDavid du Colombier {
199*7dd7cddfSDavid du Colombier 	int i;
200*7dd7cddfSDavid du Colombier 
201*7dd7cddfSDavid du Colombier 	for(i=0; i<nto; i++)
202*7dd7cddfSDavid du Colombier 		if(strcmp(name, tolist[i]) == 0)
203*7dd7cddfSDavid du Colombier 			return 1;
204*7dd7cddfSDavid du Colombier 	for(i=0; i<ncc; i++)
205*7dd7cddfSDavid du Colombier 		if(strcmp(name, cclist[i]) == 0)
206*7dd7cddfSDavid du Colombier 			return 1;
207*7dd7cddfSDavid du Colombier 	for(i=0; i<nbcc; i++)
208*7dd7cddfSDavid du Colombier 		if(strcmp(name, bcclist[i]) == 0)
209*7dd7cddfSDavid du Colombier 			return 1;
210*7dd7cddfSDavid du Colombier 	return 0;
211*7dd7cddfSDavid du Colombier }
212*7dd7cddfSDavid du Colombier 
213*7dd7cddfSDavid du Colombier char*
214*7dd7cddfSDavid du Colombier skipbl(char *s, char *e)
215*7dd7cddfSDavid du Colombier {
216*7dd7cddfSDavid du Colombier 	while(s < e){
217*7dd7cddfSDavid du Colombier 		if(*s!=' ' && *s!='\t' && *s!=',')
218*7dd7cddfSDavid du Colombier 			break;
219*7dd7cddfSDavid du Colombier 		s++;
220*7dd7cddfSDavid du Colombier 	}
221*7dd7cddfSDavid du Colombier 	return s;
222*7dd7cddfSDavid du Colombier }
223*7dd7cddfSDavid du Colombier 
224*7dd7cddfSDavid du Colombier char*
225*7dd7cddfSDavid du Colombier findbl(char *s, char *e)
226*7dd7cddfSDavid du Colombier {
227*7dd7cddfSDavid du Colombier 	while(s < e){
228*7dd7cddfSDavid du Colombier 		if(*s==' ' || *s=='\t' || *s==',')
229*7dd7cddfSDavid du Colombier 			break;
230*7dd7cddfSDavid du Colombier 		s++;
231*7dd7cddfSDavid du Colombier 	}
232*7dd7cddfSDavid du Colombier 	return s;
233*7dd7cddfSDavid du Colombier }
234*7dd7cddfSDavid du Colombier 
235*7dd7cddfSDavid du Colombier /*
236*7dd7cddfSDavid du Colombier  * comma-separate possibly blank-separated strings in line; e points before newline
237*7dd7cddfSDavid du Colombier  */
238*7dd7cddfSDavid du Colombier void
239*7dd7cddfSDavid du Colombier commas(char *s, char *e)
240*7dd7cddfSDavid du Colombier {
241*7dd7cddfSDavid du Colombier 	char *t;
242*7dd7cddfSDavid du Colombier 
243*7dd7cddfSDavid du Colombier 	/* may have initial blanks */
244*7dd7cddfSDavid du Colombier 	s = skipbl(s, e);
245*7dd7cddfSDavid du Colombier 	while(s < e){
246*7dd7cddfSDavid du Colombier 		s = findbl(s, e);
247*7dd7cddfSDavid du Colombier 		if(s == e)
248*7dd7cddfSDavid du Colombier 			break;
249*7dd7cddfSDavid du Colombier 		t = skipbl(s, e);
250*7dd7cddfSDavid du Colombier 		if(t == e)	/* no more words */
251*7dd7cddfSDavid du Colombier 			break;
252*7dd7cddfSDavid du Colombier 		/* patch comma */
253*7dd7cddfSDavid du Colombier 		*s++ = ',';
254*7dd7cddfSDavid du Colombier 		while(s < t)
255*7dd7cddfSDavid du Colombier 			*s++ = ' ';
256*7dd7cddfSDavid du Colombier 	}
257*7dd7cddfSDavid du Colombier }
258*7dd7cddfSDavid du Colombier 
259*7dd7cddfSDavid du Colombier void
260*7dd7cddfSDavid du Colombier mesgsend(Message *m)
261*7dd7cddfSDavid du Colombier {
262*7dd7cddfSDavid du Colombier 	char *s, *body, *to;
263*7dd7cddfSDavid du Colombier 	int i, j, h, n, natt, p[2];
264*7dd7cddfSDavid du Colombier 	struct Exec *e;
265*7dd7cddfSDavid du Colombier 	Channel *sync;
266*7dd7cddfSDavid du Colombier 	int first, nfld, delit;
267*7dd7cddfSDavid du Colombier 	char *copy, *fld[100];
268*7dd7cddfSDavid du Colombier 
269*7dd7cddfSDavid du Colombier 	body = winreadbody(m->w, &n);
270*7dd7cddfSDavid du Colombier 	/* assemble to: list from first line, to: line, and cc: line */
271*7dd7cddfSDavid du Colombier 	nto = 0;
272*7dd7cddfSDavid du Colombier 	natt = 0;
273*7dd7cddfSDavid du Colombier 	ncc = 0;
274*7dd7cddfSDavid du Colombier 	nbcc = 0;
275*7dd7cddfSDavid du Colombier 	first = 1;
276*7dd7cddfSDavid du Colombier 	to = body;
277*7dd7cddfSDavid du Colombier 	for(;;){
278*7dd7cddfSDavid du Colombier 		for(s=to; *s!='\n'; s++)
279*7dd7cddfSDavid du Colombier 			if(*s == '\0'){
280*7dd7cddfSDavid du Colombier 				free(body);
281*7dd7cddfSDavid du Colombier 				return;
282*7dd7cddfSDavid du Colombier 			}
283*7dd7cddfSDavid du Colombier 		if(s++ == to)	/* blank line */
284*7dd7cddfSDavid du Colombier 			break;
285*7dd7cddfSDavid du Colombier 		/* make copy of line to tokenize */
286*7dd7cddfSDavid du Colombier 		copy = emalloc(s-to);
287*7dd7cddfSDavid du Colombier 		memmove(copy, to, s-to);
288*7dd7cddfSDavid du Colombier 		copy[s-to-1] = '\0';
289*7dd7cddfSDavid du Colombier 		nfld = tokenizec(copy, fld, nelem(fld), ", \t");
290*7dd7cddfSDavid du Colombier 		if(nfld == 0){
291*7dd7cddfSDavid du Colombier 			free(copy);
292*7dd7cddfSDavid du Colombier 			break;
293*7dd7cddfSDavid du Colombier 		}
294*7dd7cddfSDavid du Colombier 		n -= s-to;
295*7dd7cddfSDavid du Colombier 		switch(h = whichheader(fld[0])){
296*7dd7cddfSDavid du Colombier 		case TO:
297*7dd7cddfSDavid du Colombier 		case FROM:
298*7dd7cddfSDavid du Colombier 			delit = (h == FROM);
299*7dd7cddfSDavid du Colombier 			commas(to+strlen(fld[0]), s-1);
300*7dd7cddfSDavid du Colombier 			for(i=1; i<nfld && nto<nelem(tolist); i++)
301*7dd7cddfSDavid du Colombier 				if(!addressed(fld[i]))
302*7dd7cddfSDavid du Colombier 					tolist[nto++] = estrdup(fld[i]);
303*7dd7cddfSDavid du Colombier 			break;
304*7dd7cddfSDavid du Colombier 		case BCC:
305*7dd7cddfSDavid du Colombier 			delit = 1;
306*7dd7cddfSDavid du Colombier 			commas(to+strlen(fld[0]), s-1);
307*7dd7cddfSDavid du Colombier 			for(i=1; i<nfld && nbcc<nelem(bcclist); i++)
308*7dd7cddfSDavid du Colombier 				if(!addressed(fld[i]))
309*7dd7cddfSDavid du Colombier 					bcclist[nbcc++] = estrdup(fld[i]);
310*7dd7cddfSDavid du Colombier 			break;
311*7dd7cddfSDavid du Colombier 		case CC:
312*7dd7cddfSDavid du Colombier 			delit = 0;
313*7dd7cddfSDavid du Colombier 			commas(to+strlen(fld[0]), s-1);
314*7dd7cddfSDavid du Colombier 			for(i=1; i<nfld && ncc<nelem(cclist); i++)
315*7dd7cddfSDavid du Colombier 				if(!addressed(fld[i]))
316*7dd7cddfSDavid du Colombier 					cclist[ncc++] = estrdup(fld[i]);
317*7dd7cddfSDavid du Colombier 			break;
318*7dd7cddfSDavid du Colombier 		case ATTACH:
319*7dd7cddfSDavid du Colombier 		case INCLUDE:
320*7dd7cddfSDavid du Colombier 			delit = 1;
321*7dd7cddfSDavid du Colombier 			for(i=1; i<nfld && natt<nelem(attlist); i++){
322*7dd7cddfSDavid du Colombier 				attlist[natt] = estrdup(fld[i]);
323*7dd7cddfSDavid du Colombier 				rfc822[natt++] = (h == INCLUDE);
324*7dd7cddfSDavid du Colombier 			}
325*7dd7cddfSDavid du Colombier 			break;
326*7dd7cddfSDavid du Colombier 		default:
327*7dd7cddfSDavid du Colombier 			if(first){
328*7dd7cddfSDavid du Colombier 				delit = 1;
329*7dd7cddfSDavid du Colombier 				for(i=0; i<nfld && nto<nelem(tolist); i++)
330*7dd7cddfSDavid du Colombier 					tolist[nto++] = estrdup(fld[i]);
331*7dd7cddfSDavid du Colombier 			}else	/* ignore it */
332*7dd7cddfSDavid du Colombier 				delit = 0;
333*7dd7cddfSDavid du Colombier 			break;
334*7dd7cddfSDavid du Colombier 		}
335*7dd7cddfSDavid du Colombier 		if(delit){
336*7dd7cddfSDavid du Colombier 			/* delete line from body */
337*7dd7cddfSDavid du Colombier 			memmove(to, s, n+1);
338*7dd7cddfSDavid du Colombier 		}else
339*7dd7cddfSDavid du Colombier 			to = s;
340*7dd7cddfSDavid du Colombier 		free(copy);
341*7dd7cddfSDavid du Colombier 		first = 0;
342*7dd7cddfSDavid du Colombier 	}
343*7dd7cddfSDavid du Colombier 
344*7dd7cddfSDavid du Colombier 	e = emalloc(sizeof(struct Exec));
345*7dd7cddfSDavid du Colombier 	if(pipe(p) < 0)
346*7dd7cddfSDavid du Colombier 		error("Mail: can't create pipe\n");
347*7dd7cddfSDavid du Colombier 	e->p[0] = p[0];
348*7dd7cddfSDavid du Colombier 	e->p[1] = p[1];
349*7dd7cddfSDavid du Colombier 	e->argv = emalloc((1+4*natt+nto+ncc+nbcc+1)*sizeof(char*));
350*7dd7cddfSDavid du Colombier 	e->argv[0] = estrdup("marshal");
351*7dd7cddfSDavid du Colombier 	j = 1;
352*7dd7cddfSDavid du Colombier 	for(i=0; i<natt; i++){
353*7dd7cddfSDavid du Colombier 		if(rfc822[i]){
354*7dd7cddfSDavid du Colombier 			e->argv[j++] = estrdup("-t");
355*7dd7cddfSDavid du Colombier 			e->argv[j++] = estrdup("message/rfc822");
356*7dd7cddfSDavid du Colombier 			e->argv[j++] = estrdup("-A");
357*7dd7cddfSDavid du Colombier 		}else
358*7dd7cddfSDavid du Colombier 			e->argv[j++] = estrdup("-a");
359*7dd7cddfSDavid du Colombier 		e->argv[j++] = attlist[i];
360*7dd7cddfSDavid du Colombier 	}
361*7dd7cddfSDavid du Colombier 	for(i=0; i<nto; i++)
362*7dd7cddfSDavid du Colombier 		e->argv[j++] = tolist[i];
363*7dd7cddfSDavid du Colombier 	for(i=0; i<ncc; i++)
364*7dd7cddfSDavid du Colombier 		e->argv[j++] = cclist[i];
365*7dd7cddfSDavid du Colombier 	for(i=0; i<nbcc; i++)
366*7dd7cddfSDavid du Colombier 		e->argv[j++] = bcclist[i];
367*7dd7cddfSDavid du Colombier 	sync = chancreate(sizeof(int), 0);
368*7dd7cddfSDavid du Colombier 	e->sync = sync;
369*7dd7cddfSDavid du Colombier 	proccreate(execproc, e, EXECSTACK);
370*7dd7cddfSDavid du Colombier 	recvul(sync);
371*7dd7cddfSDavid du Colombier 	close(p[0]);
372*7dd7cddfSDavid du Colombier 
373*7dd7cddfSDavid du Colombier 	i = strlen(body);
374*7dd7cddfSDavid du Colombier 	if(i > 0)
375*7dd7cddfSDavid du Colombier 		write(p[1], body, i);
376*7dd7cddfSDavid du Colombier 
377*7dd7cddfSDavid du Colombier 	/* guarantee a blank line, to ensure attachments are separated from body */
378*7dd7cddfSDavid du Colombier 	if(i==0 || body[i-1]!='\n')
379*7dd7cddfSDavid du Colombier 		write(p[1], "\n\n", 2);
380*7dd7cddfSDavid du Colombier 	else if(i>1 && body[i-2]!='\n')
381*7dd7cddfSDavid du Colombier 		write(p[1], "\n", 1);
382*7dd7cddfSDavid du Colombier 	close(p[1]);
383*7dd7cddfSDavid du Colombier 	free(body);
384*7dd7cddfSDavid du Colombier 
385*7dd7cddfSDavid du Colombier 	if(m->replyname != nil)
386*7dd7cddfSDavid du Colombier 		mesgmenumark(mbox.w, m->replyname, "\t[replied]");
387*7dd7cddfSDavid du Colombier 	if(m->name[0] == '/')
388*7dd7cddfSDavid du Colombier 		s = estrdup(m->name);
389*7dd7cddfSDavid du Colombier 	else
390*7dd7cddfSDavid du Colombier 		s = estrstrdup(mbox.name, m->name);
391*7dd7cddfSDavid du Colombier 	s = egrow(s, "-R", nil);
392*7dd7cddfSDavid du Colombier 	winname(m->w, s);
393*7dd7cddfSDavid du Colombier 	free(s);
394*7dd7cddfSDavid du Colombier 	winclean(m->w);
395*7dd7cddfSDavid du Colombier }
396