xref: /plan9/acme/mail/src/reply.c (revision 80ee5cbfe36716af62da8896207e9763b8e3d760)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <bio.h>
47dd7cddfSDavid du Colombier #include <thread.h>
57dd7cddfSDavid du Colombier #include <ctype.h>
67dd7cddfSDavid du Colombier #include <plumb.h>
77dd7cddfSDavid du Colombier #include "dat.h"
87dd7cddfSDavid du Colombier 
97dd7cddfSDavid du Colombier static int	replyid;
107dd7cddfSDavid du Colombier 
117dd7cddfSDavid du Colombier int
127dd7cddfSDavid du Colombier EQUAL(char *s, char *t)
137dd7cddfSDavid du Colombier {
147dd7cddfSDavid du Colombier 	while(tolower(*s) == tolower(*t++))
157dd7cddfSDavid du Colombier 		if(*s++ == '\0')
167dd7cddfSDavid du Colombier 			return 1;
177dd7cddfSDavid du Colombier 	return 0;
187dd7cddfSDavid du Colombier }
197dd7cddfSDavid du Colombier 
207dd7cddfSDavid du Colombier void
217dd7cddfSDavid du Colombier mkreply(Message *m, char *label, char *to)
227dd7cddfSDavid du Colombier {
237dd7cddfSDavid du Colombier 	Message *r;
247dd7cddfSDavid du Colombier 	char *dir, *t;
257dd7cddfSDavid du Colombier 
267dd7cddfSDavid du Colombier 	r = emalloc(sizeof(Message));
277dd7cddfSDavid du Colombier 	r->isreply = 1;
287dd7cddfSDavid du Colombier 	if(m != nil)
297dd7cddfSDavid du Colombier 		r->replyname = estrdup(m->name);
307dd7cddfSDavid du Colombier 	r->next = replies.head;
317dd7cddfSDavid du Colombier 	r->prev = nil;
327dd7cddfSDavid du Colombier 	if(replies.head != nil)
337dd7cddfSDavid du Colombier 		replies.head->prev = r;
347dd7cddfSDavid du Colombier 	replies.head = r;
357dd7cddfSDavid du Colombier 	if(replies.tail == nil)
367dd7cddfSDavid du Colombier 		replies.tail = r;
377dd7cddfSDavid du Colombier 	r->name = emalloc(strlen(mbox.name)+strlen(label)+10);
387dd7cddfSDavid du Colombier 	sprint(r->name, "%s%s%d", mbox.name, label, ++replyid);
397dd7cddfSDavid du Colombier 	r->w = newwindow();
407dd7cddfSDavid du Colombier 	winname(r->w, r->name);
417dd7cddfSDavid du Colombier 	wintagwrite(r->w, "|fmt Post", 5+4);
427dd7cddfSDavid du Colombier 	r->tagposted = 1;
437dd7cddfSDavid du Colombier 	threadcreate(mesgctl, r, STACK);
447dd7cddfSDavid du Colombier 	winopenbody(r->w, OWRITE);
457dd7cddfSDavid du Colombier 	if(to!=nil && to[0]!='\0')
467dd7cddfSDavid du Colombier 		Bprint(r->w->body, "%s\n", to);
477dd7cddfSDavid du Colombier 	if(m != nil){
487dd7cddfSDavid du Colombier 		dir = estrstrdup(mbox.name, m->name);
497dd7cddfSDavid du Colombier 		if(to == nil){
507dd7cddfSDavid du Colombier 			/* Reply goes to replyto; Reply all goes to From and To and CC */
517dd7cddfSDavid du Colombier 			if(strcmp(label, "Reply") == 0)
527dd7cddfSDavid du Colombier 				Bprint(r->w->body, "To: %s\n", m->replyto);
537dd7cddfSDavid du Colombier 			else{	/* Replyall */
547dd7cddfSDavid du Colombier 				if(strlen(m->from) > 0)
557dd7cddfSDavid du Colombier 					Bprint(r->w->body, "To: %s\n", m->from);
567dd7cddfSDavid du Colombier 				if(strlen(m->to) > 0)
577dd7cddfSDavid du Colombier 					Bprint(r->w->body, "To: %s\n", m->to);
587dd7cddfSDavid du Colombier 				if(strlen(m->cc) > 0)
597dd7cddfSDavid du Colombier 					Bprint(r->w->body, "CC: %s\n", m->cc);
607dd7cddfSDavid du Colombier 			}
617dd7cddfSDavid du Colombier 		}
627dd7cddfSDavid du Colombier 		if(strlen(m->subject) > 0){
637dd7cddfSDavid du Colombier 			t = "Subject: Re: ";
647dd7cddfSDavid du Colombier 			if(strlen(m->subject) >= 3)
657dd7cddfSDavid du Colombier 				if(tolower(m->subject[0])=='r' && tolower(m->subject[1])=='e' && m->subject[2]==':')
667dd7cddfSDavid du Colombier 					t = "Subject: ";
677dd7cddfSDavid du Colombier 			Bprint(r->w->body, "%s%s\n", t, m->subject);
687dd7cddfSDavid du Colombier 		}
697dd7cddfSDavid du Colombier 		Bprint(r->w->body, "Include: %sraw\n", dir);
707dd7cddfSDavid du Colombier 		free(dir);
717dd7cddfSDavid du Colombier 	}
727dd7cddfSDavid du Colombier 	Bprint(r->w->body, "\n");
737dd7cddfSDavid du Colombier 	if(m == nil)
747dd7cddfSDavid du Colombier 		Bprint(r->w->body, "\n");
757dd7cddfSDavid du Colombier 	winclosebody(r->w);
767dd7cddfSDavid du Colombier 	if(m == nil)
777dd7cddfSDavid du Colombier 		winselect(r->w, "0", 0);
787dd7cddfSDavid du Colombier 	else
797dd7cddfSDavid du Colombier 		winselect(r->w, "$", 0);
807dd7cddfSDavid du Colombier 	winclean(r->w);
817dd7cddfSDavid du Colombier 	windormant(r->w);
827dd7cddfSDavid du Colombier }
837dd7cddfSDavid du Colombier 
847dd7cddfSDavid du Colombier void
857dd7cddfSDavid du Colombier delreply(Message *m)
867dd7cddfSDavid du Colombier {
877dd7cddfSDavid du Colombier 	if(m->next == nil)
887dd7cddfSDavid du Colombier 		replies.tail = m->prev;
897dd7cddfSDavid du Colombier 	else
907dd7cddfSDavid du Colombier 		m->next->prev = m->prev;
917dd7cddfSDavid du Colombier 	if(m->prev == nil)
927dd7cddfSDavid du Colombier 		replies.head = m->next;
937dd7cddfSDavid du Colombier 	else
947dd7cddfSDavid du Colombier 		m->prev->next = m->next;
957dd7cddfSDavid du Colombier 	mesgfreeparts(m);
967dd7cddfSDavid du Colombier 	free(m);
977dd7cddfSDavid du Colombier }
987dd7cddfSDavid du Colombier 
997dd7cddfSDavid du Colombier enum
1007dd7cddfSDavid du Colombier {
1017dd7cddfSDavid du Colombier 	NARGS		= 100,
1027dd7cddfSDavid du Colombier 	NARGCHAR	= 8*1024,
1037dd7cddfSDavid du Colombier 	EXECSTACK 	= STACK+(NARGS+1)*sizeof(char*)+NARGCHAR
1047dd7cddfSDavid du Colombier };
1057dd7cddfSDavid du Colombier 
1067dd7cddfSDavid du Colombier struct Exec
1077dd7cddfSDavid du Colombier {
1087dd7cddfSDavid du Colombier 	char		**argv;
1097dd7cddfSDavid du Colombier 	int		p[2];
1107dd7cddfSDavid du Colombier 	Channel	*sync;
1117dd7cddfSDavid du Colombier };
1127dd7cddfSDavid du Colombier 
1137dd7cddfSDavid du Colombier /* copy argv to stack and free the incoming strings, so we don't leak argument vectors */
1147dd7cddfSDavid du Colombier void
1157dd7cddfSDavid du Colombier buildargv(char **inargv, char *argv[NARGS+1], char args[NARGCHAR])
1167dd7cddfSDavid du Colombier {
1177dd7cddfSDavid du Colombier 	int i, n;
1187dd7cddfSDavid du Colombier 	char *s, *a;
1197dd7cddfSDavid du Colombier 
1207dd7cddfSDavid du Colombier 	s = args;
1217dd7cddfSDavid du Colombier 	for(i=0; i<NARGS; i++){
1227dd7cddfSDavid du Colombier 		a = inargv[i];
1237dd7cddfSDavid du Colombier 		if(a == nil)
1247dd7cddfSDavid du Colombier 			break;
1257dd7cddfSDavid du Colombier 		n = strlen(a)+1;
1267dd7cddfSDavid du Colombier 		if((s-args)+n >= NARGCHAR)	/* too many characters */
1277dd7cddfSDavid du Colombier 			break;
1287dd7cddfSDavid du Colombier 		argv[i] = s;
1297dd7cddfSDavid du Colombier 		memmove(s, a, n);
1307dd7cddfSDavid du Colombier 		s += n;
1317dd7cddfSDavid du Colombier 		free(a);
1327dd7cddfSDavid du Colombier 	}
1337dd7cddfSDavid du Colombier 	argv[i] = nil;
1347dd7cddfSDavid du Colombier }
1357dd7cddfSDavid du Colombier 
1367dd7cddfSDavid du Colombier void
1377dd7cddfSDavid du Colombier execproc(void *v)
1387dd7cddfSDavid du Colombier {
1397dd7cddfSDavid du Colombier 	struct Exec *e;
1407dd7cddfSDavid du Colombier 	int p[2];
1417dd7cddfSDavid du Colombier 	char *argv[NARGS+1], args[NARGCHAR];
1427dd7cddfSDavid du Colombier 
1437dd7cddfSDavid du Colombier 	e = v;
1447dd7cddfSDavid du Colombier 	p[0] = e->p[0];
1457dd7cddfSDavid du Colombier 	p[1] = e->p[1];
1467dd7cddfSDavid du Colombier 	rfork(RFFDG);
1477dd7cddfSDavid du Colombier 	sendul(e->sync, 1);
1487dd7cddfSDavid du Colombier 	buildargv(e->argv, argv, args);
1497dd7cddfSDavid du Colombier 	free(e->argv);
1507dd7cddfSDavid du Colombier 	chanfree(e->sync);
1517dd7cddfSDavid du Colombier 	free(e);
1527dd7cddfSDavid du Colombier 	dup(p[0], 0);
1537dd7cddfSDavid du Colombier 	close(p[1]);
1547dd7cddfSDavid du Colombier 	procexec(nil, "/bin/upas/marshal", argv);
155*80ee5cbfSDavid du Colombier //threadprint(2, "exec: /bin/upas/marshal");
156*80ee5cbfSDavid du Colombier //{int i;
157*80ee5cbfSDavid du Colombier //for(i=0; argv[i]; i++) print(" '%s'", argv[i]);
158*80ee5cbfSDavid du Colombier //print("\n");
159*80ee5cbfSDavid du Colombier //}
160*80ee5cbfSDavid du Colombier //argv[0] = "cat";
161*80ee5cbfSDavid du Colombier //argv[1] = nil;
162*80ee5cbfSDavid du Colombier //procexec(nil, "/bin/cat", argv);
1637dd7cddfSDavid du Colombier 	threadprint(2, "Mail: can't exec %s: %r\n", argv[0]);
1647dd7cddfSDavid du Colombier 	threadexits("can't exec");
1657dd7cddfSDavid du Colombier }
1667dd7cddfSDavid du Colombier 
1677dd7cddfSDavid du Colombier enum{
1687dd7cddfSDavid du Colombier 	ATTACH,
1697dd7cddfSDavid du Colombier 	BCC,
1707dd7cddfSDavid du Colombier 	CC,
1717dd7cddfSDavid du Colombier 	FROM,
1727dd7cddfSDavid du Colombier 	INCLUDE,
1737dd7cddfSDavid du Colombier 	TO,
1747dd7cddfSDavid du Colombier };
1757dd7cddfSDavid du Colombier 
1767dd7cddfSDavid du Colombier char *headers[] = {
1777dd7cddfSDavid du Colombier 	"attach:",
1787dd7cddfSDavid du Colombier 	"bcc:",
1797dd7cddfSDavid du Colombier 	"cc:",
1807dd7cddfSDavid du Colombier 	"from:",
1817dd7cddfSDavid du Colombier 	"include:",
1827dd7cddfSDavid du Colombier 	"to:",
1837dd7cddfSDavid du Colombier 	nil,
1847dd7cddfSDavid du Colombier };
1857dd7cddfSDavid du Colombier 
1867dd7cddfSDavid du Colombier int
1877dd7cddfSDavid du Colombier whichheader(char *h)
1887dd7cddfSDavid du Colombier {
1897dd7cddfSDavid du Colombier 	int i;
1907dd7cddfSDavid du Colombier 
1917dd7cddfSDavid du Colombier 	for(i=0; headers[i]!=nil; i++)
1927dd7cddfSDavid du Colombier 		if(EQUAL(h, headers[i]))
1937dd7cddfSDavid du Colombier 			return i;
1947dd7cddfSDavid du Colombier 	return -1;
1957dd7cddfSDavid du Colombier }
1967dd7cddfSDavid du Colombier 
1977dd7cddfSDavid du Colombier char *tolist[200];
1987dd7cddfSDavid du Colombier char	*cclist[200];
1997dd7cddfSDavid du Colombier char	*bcclist[200];
2007dd7cddfSDavid du Colombier int ncc, nbcc, nto;
2017dd7cddfSDavid du Colombier char	*attlist[200];
2027dd7cddfSDavid du Colombier int	rfc822[200];
2037dd7cddfSDavid du Colombier 
2047dd7cddfSDavid du Colombier int
2057dd7cddfSDavid du Colombier addressed(char *name)
2067dd7cddfSDavid du Colombier {
2077dd7cddfSDavid du Colombier 	int i;
2087dd7cddfSDavid du Colombier 
2097dd7cddfSDavid du Colombier 	for(i=0; i<nto; i++)
2107dd7cddfSDavid du Colombier 		if(strcmp(name, tolist[i]) == 0)
2117dd7cddfSDavid du Colombier 			return 1;
2127dd7cddfSDavid du Colombier 	for(i=0; i<ncc; i++)
2137dd7cddfSDavid du Colombier 		if(strcmp(name, cclist[i]) == 0)
2147dd7cddfSDavid du Colombier 			return 1;
2157dd7cddfSDavid du Colombier 	for(i=0; i<nbcc; i++)
2167dd7cddfSDavid du Colombier 		if(strcmp(name, bcclist[i]) == 0)
2177dd7cddfSDavid du Colombier 			return 1;
2187dd7cddfSDavid du Colombier 	return 0;
2197dd7cddfSDavid du Colombier }
2207dd7cddfSDavid du Colombier 
2217dd7cddfSDavid du Colombier char*
2227dd7cddfSDavid du Colombier skipbl(char *s, char *e)
2237dd7cddfSDavid du Colombier {
2247dd7cddfSDavid du Colombier 	while(s < e){
2257dd7cddfSDavid du Colombier 		if(*s!=' ' && *s!='\t' && *s!=',')
2267dd7cddfSDavid du Colombier 			break;
2277dd7cddfSDavid du Colombier 		s++;
2287dd7cddfSDavid du Colombier 	}
2297dd7cddfSDavid du Colombier 	return s;
2307dd7cddfSDavid du Colombier }
2317dd7cddfSDavid du Colombier 
2327dd7cddfSDavid du Colombier char*
2337dd7cddfSDavid du Colombier findbl(char *s, char *e)
2347dd7cddfSDavid du Colombier {
2357dd7cddfSDavid du Colombier 	while(s < e){
2367dd7cddfSDavid du Colombier 		if(*s==' ' || *s=='\t' || *s==',')
2377dd7cddfSDavid du Colombier 			break;
2387dd7cddfSDavid du Colombier 		s++;
2397dd7cddfSDavid du Colombier 	}
2407dd7cddfSDavid du Colombier 	return s;
2417dd7cddfSDavid du Colombier }
2427dd7cddfSDavid du Colombier 
2437dd7cddfSDavid du Colombier /*
2447dd7cddfSDavid du Colombier  * comma-separate possibly blank-separated strings in line; e points before newline
2457dd7cddfSDavid du Colombier  */
2467dd7cddfSDavid du Colombier void
2477dd7cddfSDavid du Colombier commas(char *s, char *e)
2487dd7cddfSDavid du Colombier {
2497dd7cddfSDavid du Colombier 	char *t;
2507dd7cddfSDavid du Colombier 
2517dd7cddfSDavid du Colombier 	/* may have initial blanks */
2527dd7cddfSDavid du Colombier 	s = skipbl(s, e);
2537dd7cddfSDavid du Colombier 	while(s < e){
2547dd7cddfSDavid du Colombier 		s = findbl(s, e);
2557dd7cddfSDavid du Colombier 		if(s == e)
2567dd7cddfSDavid du Colombier 			break;
2577dd7cddfSDavid du Colombier 		t = skipbl(s, e);
2587dd7cddfSDavid du Colombier 		if(t == e)	/* no more words */
2597dd7cddfSDavid du Colombier 			break;
2607dd7cddfSDavid du Colombier 		/* patch comma */
2617dd7cddfSDavid du Colombier 		*s++ = ',';
2627dd7cddfSDavid du Colombier 		while(s < t)
2637dd7cddfSDavid du Colombier 			*s++ = ' ';
2647dd7cddfSDavid du Colombier 	}
2657dd7cddfSDavid du Colombier }
2667dd7cddfSDavid du Colombier 
2677dd7cddfSDavid du Colombier void
2687dd7cddfSDavid du Colombier mesgsend(Message *m)
2697dd7cddfSDavid du Colombier {
2707dd7cddfSDavid du Colombier 	char *s, *body, *to;
2717dd7cddfSDavid du Colombier 	int i, j, h, n, natt, p[2];
2727dd7cddfSDavid du Colombier 	struct Exec *e;
2737dd7cddfSDavid du Colombier 	Channel *sync;
2747dd7cddfSDavid du Colombier 	int first, nfld, delit;
2757dd7cddfSDavid du Colombier 	char *copy, *fld[100];
2767dd7cddfSDavid du Colombier 
2777dd7cddfSDavid du Colombier 	body = winreadbody(m->w, &n);
2787dd7cddfSDavid du Colombier 	/* assemble to: list from first line, to: line, and cc: line */
2797dd7cddfSDavid du Colombier 	nto = 0;
2807dd7cddfSDavid du Colombier 	natt = 0;
2817dd7cddfSDavid du Colombier 	ncc = 0;
2827dd7cddfSDavid du Colombier 	nbcc = 0;
2837dd7cddfSDavid du Colombier 	first = 1;
2847dd7cddfSDavid du Colombier 	to = body;
2857dd7cddfSDavid du Colombier 	for(;;){
2867dd7cddfSDavid du Colombier 		for(s=to; *s!='\n'; s++)
2877dd7cddfSDavid du Colombier 			if(*s == '\0'){
2887dd7cddfSDavid du Colombier 				free(body);
2897dd7cddfSDavid du Colombier 				return;
2907dd7cddfSDavid du Colombier 			}
2917dd7cddfSDavid du Colombier 		if(s++ == to)	/* blank line */
2927dd7cddfSDavid du Colombier 			break;
2937dd7cddfSDavid du Colombier 		/* make copy of line to tokenize */
2947dd7cddfSDavid du Colombier 		copy = emalloc(s-to);
2957dd7cddfSDavid du Colombier 		memmove(copy, to, s-to);
2967dd7cddfSDavid du Colombier 		copy[s-to-1] = '\0';
2977dd7cddfSDavid du Colombier 		nfld = tokenizec(copy, fld, nelem(fld), ", \t");
2987dd7cddfSDavid du Colombier 		if(nfld == 0){
2997dd7cddfSDavid du Colombier 			free(copy);
3007dd7cddfSDavid du Colombier 			break;
3017dd7cddfSDavid du Colombier 		}
3027dd7cddfSDavid du Colombier 		n -= s-to;
3037dd7cddfSDavid du Colombier 		switch(h = whichheader(fld[0])){
3047dd7cddfSDavid du Colombier 		case TO:
3057dd7cddfSDavid du Colombier 		case FROM:
306*80ee5cbfSDavid du Colombier 			delit = 1;
3077dd7cddfSDavid du Colombier 			commas(to+strlen(fld[0]), s-1);
3087dd7cddfSDavid du Colombier 			for(i=1; i<nfld && nto<nelem(tolist); i++)
3097dd7cddfSDavid du Colombier 				if(!addressed(fld[i]))
3107dd7cddfSDavid du Colombier 					tolist[nto++] = estrdup(fld[i]);
3117dd7cddfSDavid du Colombier 			break;
3127dd7cddfSDavid du Colombier 		case BCC:
3137dd7cddfSDavid du Colombier 			delit = 1;
3147dd7cddfSDavid du Colombier 			commas(to+strlen(fld[0]), s-1);
3157dd7cddfSDavid du Colombier 			for(i=1; i<nfld && nbcc<nelem(bcclist); i++)
3167dd7cddfSDavid du Colombier 				if(!addressed(fld[i]))
3177dd7cddfSDavid du Colombier 					bcclist[nbcc++] = estrdup(fld[i]);
3187dd7cddfSDavid du Colombier 			break;
3197dd7cddfSDavid du Colombier 		case CC:
320*80ee5cbfSDavid du Colombier 			delit = 1;
3217dd7cddfSDavid du Colombier 			commas(to+strlen(fld[0]), s-1);
3227dd7cddfSDavid du Colombier 			for(i=1; i<nfld && ncc<nelem(cclist); i++)
3237dd7cddfSDavid du Colombier 				if(!addressed(fld[i]))
3247dd7cddfSDavid du Colombier 					cclist[ncc++] = estrdup(fld[i]);
3257dd7cddfSDavid du Colombier 			break;
3267dd7cddfSDavid du Colombier 		case ATTACH:
3277dd7cddfSDavid du Colombier 		case INCLUDE:
3287dd7cddfSDavid du Colombier 			delit = 1;
3297dd7cddfSDavid du Colombier 			for(i=1; i<nfld && natt<nelem(attlist); i++){
3307dd7cddfSDavid du Colombier 				attlist[natt] = estrdup(fld[i]);
3317dd7cddfSDavid du Colombier 				rfc822[natt++] = (h == INCLUDE);
3327dd7cddfSDavid du Colombier 			}
3337dd7cddfSDavid du Colombier 			break;
3347dd7cddfSDavid du Colombier 		default:
3357dd7cddfSDavid du Colombier 			if(first){
3367dd7cddfSDavid du Colombier 				delit = 1;
3377dd7cddfSDavid du Colombier 				for(i=0; i<nfld && nto<nelem(tolist); i++)
3387dd7cddfSDavid du Colombier 					tolist[nto++] = estrdup(fld[i]);
3397dd7cddfSDavid du Colombier 			}else	/* ignore it */
3407dd7cddfSDavid du Colombier 				delit = 0;
3417dd7cddfSDavid du Colombier 			break;
3427dd7cddfSDavid du Colombier 		}
3437dd7cddfSDavid du Colombier 		if(delit){
3447dd7cddfSDavid du Colombier 			/* delete line from body */
3457dd7cddfSDavid du Colombier 			memmove(to, s, n+1);
3467dd7cddfSDavid du Colombier 		}else
3477dd7cddfSDavid du Colombier 			to = s;
3487dd7cddfSDavid du Colombier 		free(copy);
3497dd7cddfSDavid du Colombier 		first = 0;
3507dd7cddfSDavid du Colombier 	}
3517dd7cddfSDavid du Colombier 
3527dd7cddfSDavid du Colombier 	e = emalloc(sizeof(struct Exec));
3537dd7cddfSDavid du Colombier 	if(pipe(p) < 0)
3547dd7cddfSDavid du Colombier 		error("Mail: can't create pipe\n");
3557dd7cddfSDavid du Colombier 	e->p[0] = p[0];
3567dd7cddfSDavid du Colombier 	e->p[1] = p[1];
357*80ee5cbfSDavid du Colombier 	e->argv = emalloc((1+1+4*natt+1)*sizeof(char*));
3587dd7cddfSDavid du Colombier 	e->argv[0] = estrdup("marshal");
359*80ee5cbfSDavid du Colombier 	e->argv[1] = estrdup("-8");
360*80ee5cbfSDavid du Colombier 	j = 2;
3617dd7cddfSDavid du Colombier 	for(i=0; i<natt; i++){
3627dd7cddfSDavid du Colombier 		if(rfc822[i]){
3637dd7cddfSDavid du Colombier 			e->argv[j++] = estrdup("-t");
3647dd7cddfSDavid du Colombier 			e->argv[j++] = estrdup("message/rfc822");
3657dd7cddfSDavid du Colombier 			e->argv[j++] = estrdup("-A");
3667dd7cddfSDavid du Colombier 		}else
3677dd7cddfSDavid du Colombier 			e->argv[j++] = estrdup("-a");
3687dd7cddfSDavid du Colombier 		e->argv[j++] = attlist[i];
3697dd7cddfSDavid du Colombier 	}
3707dd7cddfSDavid du Colombier 	sync = chancreate(sizeof(int), 0);
3717dd7cddfSDavid du Colombier 	e->sync = sync;
3727dd7cddfSDavid du Colombier 	proccreate(execproc, e, EXECSTACK);
3737dd7cddfSDavid du Colombier 	recvul(sync);
3747dd7cddfSDavid du Colombier 	close(p[0]);
3757dd7cddfSDavid du Colombier 
376*80ee5cbfSDavid du Colombier 	/* using marshal -8, so generate rfc822 headers */
377*80ee5cbfSDavid du Colombier 	if(nto > 0){
378*80ee5cbfSDavid du Colombier 		threadprint(p[1], "To: ");
379*80ee5cbfSDavid du Colombier 		for(i=0; i<nto-1; i++)
380*80ee5cbfSDavid du Colombier 			threadprint(p[1], "%s, ", tolist[i]);
381*80ee5cbfSDavid du Colombier 		threadprint(p[1], "%s\n", tolist[i]);
382*80ee5cbfSDavid du Colombier 	}
383*80ee5cbfSDavid du Colombier 	if(ncc > 0){
384*80ee5cbfSDavid du Colombier 		threadprint(p[1], "CC: ");
385*80ee5cbfSDavid du Colombier 		for(i=0; i<ncc-1; i++)
386*80ee5cbfSDavid du Colombier 			threadprint(p[1], "%s, ", cclist[i]);
387*80ee5cbfSDavid du Colombier 		threadprint(p[1], "%s\n", cclist[i]);
388*80ee5cbfSDavid du Colombier 	}
389*80ee5cbfSDavid du Colombier 	if(nbcc > 0){
390*80ee5cbfSDavid du Colombier 		threadprint(p[1], "BCC: ");
391*80ee5cbfSDavid du Colombier 		for(i=0; i<nbcc-1; i++)
392*80ee5cbfSDavid du Colombier 			threadprint(p[1], "%s, ", bcclist[i]);
393*80ee5cbfSDavid du Colombier 		threadprint(p[1], "%s\n", bcclist[i]);
394*80ee5cbfSDavid du Colombier 	}
395*80ee5cbfSDavid du Colombier 
3967dd7cddfSDavid du Colombier 	i = strlen(body);
3977dd7cddfSDavid du Colombier 	if(i > 0)
3987dd7cddfSDavid du Colombier 		write(p[1], body, i);
3997dd7cddfSDavid du Colombier 
4007dd7cddfSDavid du Colombier 	/* guarantee a blank line, to ensure attachments are separated from body */
4017dd7cddfSDavid du Colombier 	if(i==0 || body[i-1]!='\n')
4027dd7cddfSDavid du Colombier 		write(p[1], "\n\n", 2);
4037dd7cddfSDavid du Colombier 	else if(i>1 && body[i-2]!='\n')
4047dd7cddfSDavid du Colombier 		write(p[1], "\n", 1);
4057dd7cddfSDavid du Colombier 	close(p[1]);
4067dd7cddfSDavid du Colombier 	free(body);
4077dd7cddfSDavid du Colombier 
4087dd7cddfSDavid du Colombier 	if(m->replyname != nil)
4097dd7cddfSDavid du Colombier 		mesgmenumark(mbox.w, m->replyname, "\t[replied]");
4107dd7cddfSDavid du Colombier 	if(m->name[0] == '/')
4117dd7cddfSDavid du Colombier 		s = estrdup(m->name);
4127dd7cddfSDavid du Colombier 	else
4137dd7cddfSDavid du Colombier 		s = estrstrdup(mbox.name, m->name);
4147dd7cddfSDavid du Colombier 	s = egrow(s, "-R", nil);
4157dd7cddfSDavid du Colombier 	winname(m->w, s);
4167dd7cddfSDavid du Colombier 	free(s);
4177dd7cddfSDavid du Colombier 	winclean(m->w);
4187dd7cddfSDavid du Colombier }
419