xref: /plan9/acme/mail/src/mail.c (revision 92fd5f07b1a087b08202ebf1f2c7a9d735cb6b8f)
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 <plumb.h>
69a747e4fSDavid du Colombier #include <ctype.h>
77dd7cddfSDavid du Colombier #include "dat.h"
87dd7cddfSDavid du Colombier 
959cc4ca5SDavid du Colombier char	*maildir = "/mail/fs/";			/* mountpoint of mail file system */
1059cc4ca5SDavid du Colombier char	*mailtermdir = "/mnt/term/mail/fs/";	/* alternate mountpoint */
1159cc4ca5SDavid du Colombier char *mboxname = "mbox";			/* mailboxdir/mboxname is mail spool file */
1259cc4ca5SDavid du Colombier char	*mailboxdir = nil;				/* nil == /mail/box/$user */
1359cc4ca5SDavid du Colombier char *fsname;						/* filesystem for mailboxdir/mboxname is at maildir/fsname */
149a747e4fSDavid du Colombier char	*user;
159a747e4fSDavid du Colombier char	*outgoing;
167dd7cddfSDavid du Colombier 
177dd7cddfSDavid du Colombier Window	*wbox;
187dd7cddfSDavid du Colombier Message	mbox;
197dd7cddfSDavid du Colombier Message	replies;
207dd7cddfSDavid du Colombier char		*home;
217dd7cddfSDavid du Colombier int		plumbsendfd;
227dd7cddfSDavid du Colombier int		plumbseemailfd;
237dd7cddfSDavid du Colombier int		plumbshowmailfd;
249a747e4fSDavid du Colombier int		plumbsendmailfd;
257dd7cddfSDavid du Colombier Channel	*cplumb;
267dd7cddfSDavid du Colombier Channel	*cplumbshow;
279a747e4fSDavid du Colombier Channel	*cplumbsend;
287dd7cddfSDavid du Colombier int		wctlfd;
297dd7cddfSDavid du Colombier void		mainctl(void*);
307dd7cddfSDavid du Colombier void		plumbproc(void*);
317dd7cddfSDavid du Colombier void		plumbshowproc(void*);
329a747e4fSDavid du Colombier void		plumbsendproc(void*);
337dd7cddfSDavid du Colombier void		plumbthread(void);
347dd7cddfSDavid du Colombier void		plumbshowthread(void*);
359a747e4fSDavid du Colombier void		plumbsendthread(void*);
369a747e4fSDavid du Colombier 
379a747e4fSDavid du Colombier int			shortmenu;
387dd7cddfSDavid du Colombier 
397dd7cddfSDavid du Colombier void
usage(void)407dd7cddfSDavid du Colombier usage(void)
417dd7cddfSDavid du Colombier {
42c27b0bc9SDavid du Colombier 	fprint(2, "usage: Mail [-sS] [-o outgoing] [mailboxname [directoryname]]\n");
437dd7cddfSDavid du Colombier 	threadexitsall("usage");
447dd7cddfSDavid du Colombier }
457dd7cddfSDavid du Colombier 
467dd7cddfSDavid du Colombier void
removeupasfs(void)477dd7cddfSDavid du Colombier removeupasfs(void)
487dd7cddfSDavid du Colombier {
497dd7cddfSDavid du Colombier 	char buf[256];
507dd7cddfSDavid du Colombier 
517dd7cddfSDavid du Colombier 	if(strcmp(mboxname, "mbox") == 0)
527dd7cddfSDavid du Colombier 		return;
537dd7cddfSDavid du Colombier 	snprint(buf, sizeof buf, "close %s", mboxname);
547dd7cddfSDavid du Colombier 	write(mbox.ctlfd, buf, strlen(buf));
557dd7cddfSDavid du Colombier }
567dd7cddfSDavid du Colombier 
579a747e4fSDavid du Colombier int
ismaildir(char * s)589a747e4fSDavid du Colombier ismaildir(char *s)
599a747e4fSDavid du Colombier {
609a747e4fSDavid du Colombier 	char buf[256];
619a747e4fSDavid du Colombier 	Dir *d;
629a747e4fSDavid du Colombier 	int ret;
639a747e4fSDavid du Colombier 
649a747e4fSDavid du Colombier 	snprint(buf, sizeof buf, "%s%s", maildir, s);
659a747e4fSDavid du Colombier 	d = dirstat(buf);
669a747e4fSDavid du Colombier 	if(d == nil)
679a747e4fSDavid du Colombier 		return 0;
689a747e4fSDavid du Colombier 	ret = d->qid.type & QTDIR;
699a747e4fSDavid du Colombier 	free(d);
709a747e4fSDavid du Colombier 	return ret;
719a747e4fSDavid du Colombier }
729a747e4fSDavid du Colombier 
737dd7cddfSDavid du Colombier void
threadmain(int argc,char * argv[])747dd7cddfSDavid du Colombier threadmain(int argc, char *argv[])
757dd7cddfSDavid du Colombier {
769a747e4fSDavid du Colombier 	char *s, *name;
770fb3f58eSDavid du Colombier 	char err[ERRMAX], *cmd;
789a747e4fSDavid du Colombier 	int i, newdir;
790fb3f58eSDavid du Colombier 	Fmt fmt;
807dd7cddfSDavid du Colombier 
81d9306527SDavid du Colombier 	doquote = needsrcquote;
82d9306527SDavid du Colombier 	quotefmtinstall();
83d9306527SDavid du Colombier 
847dd7cddfSDavid du Colombier 	/* open these early so we won't miss notification of new mail messages while we read mbox */
857dd7cddfSDavid du Colombier 	plumbsendfd = plumbopen("send", OWRITE|OCEXEC);
867dd7cddfSDavid du Colombier 	plumbseemailfd = plumbopen("seemail", OREAD|OCEXEC);
877dd7cddfSDavid du Colombier 	plumbshowmailfd = plumbopen("showmail", OREAD|OCEXEC);
887dd7cddfSDavid du Colombier 
899a747e4fSDavid du Colombier 	shortmenu = 0;
907dd7cddfSDavid du Colombier 	ARGBEGIN{
919a747e4fSDavid du Colombier 	case 's':
929a747e4fSDavid du Colombier 		shortmenu = 1;
939a747e4fSDavid du Colombier 		break;
949a747e4fSDavid du Colombier 	case 'S':
959a747e4fSDavid du Colombier 		shortmenu = 2;
969a747e4fSDavid du Colombier 		break;
97c27b0bc9SDavid du Colombier 	case 'o':
98c27b0bc9SDavid du Colombier 		outgoing = EARGF(usage());
99c27b0bc9SDavid du Colombier 		break;
100786b84f9SDavid du Colombier 	case 'm':
101786b84f9SDavid du Colombier 		smprint(maildir, "%s/", EARGF(usage()));
102786b84f9SDavid du Colombier 		break;
1039a747e4fSDavid du Colombier 	default:
1049a747e4fSDavid du Colombier 		usage();
1057dd7cddfSDavid du Colombier 	}ARGEND
1069a747e4fSDavid du Colombier 
10759cc4ca5SDavid du Colombier 	name = "mbox";
1089a747e4fSDavid du Colombier 
1099a747e4fSDavid du Colombier 	/* bind the terminal /mail/fs directory over the local one */
1109a747e4fSDavid du Colombier 	if(access(maildir, 0)<0 && access(mailtermdir, 0)==0)
1119a747e4fSDavid du Colombier 		bind(mailtermdir, maildir, MAFTER);
1129a747e4fSDavid du Colombier 
1139a747e4fSDavid du Colombier 	newdir = 1;
1147dd7cddfSDavid du Colombier 	if(argc > 0){
1157dd7cddfSDavid du Colombier 		i = strlen(argv[0]);
11659cc4ca5SDavid du Colombier 		if(argc>2 || i==0)
1177dd7cddfSDavid du Colombier 			usage();
1189a747e4fSDavid du Colombier 		/* see if the name is that of an existing /mail/fs directory */
1199a747e4fSDavid du Colombier 		if(argc==1 && strchr(argv[0], '/')==0 && ismaildir(argv[0])){
1209a747e4fSDavid du Colombier 			name = argv[0];
1219a747e4fSDavid du Colombier 			mboxname = eappend(estrdup(maildir), "", name);
1229a747e4fSDavid du Colombier 			newdir = 0;
1239a747e4fSDavid du Colombier 		}else{
1247dd7cddfSDavid du Colombier 			if(argv[0][i-1] == '/')
1257dd7cddfSDavid du Colombier 				argv[0][i-1] = '\0';
1267dd7cddfSDavid du Colombier 			s = strrchr(argv[0], '/');
1277dd7cddfSDavid du Colombier 			if(s == nil)
1287dd7cddfSDavid du Colombier 				mboxname = estrdup(argv[0]);
1297dd7cddfSDavid du Colombier 			else{
1307dd7cddfSDavid du Colombier 				*s++ = '\0';
1317dd7cddfSDavid du Colombier 				if(*s == '\0')
1327dd7cddfSDavid du Colombier 					usage();
1337dd7cddfSDavid du Colombier 				mailboxdir = argv[0];
1347dd7cddfSDavid du Colombier 				mboxname = estrdup(s);
1357dd7cddfSDavid du Colombier 			}
1367dd7cddfSDavid du Colombier 			if(argc > 1)
1377dd7cddfSDavid du Colombier 				name = argv[1];
1387dd7cddfSDavid du Colombier 			else
1397dd7cddfSDavid du Colombier 				name = mboxname;
1407dd7cddfSDavid du Colombier 		}
1419a747e4fSDavid du Colombier 	}
1429a747e4fSDavid du Colombier 
1437dd7cddfSDavid du Colombier 	user = getenv("user");
1447dd7cddfSDavid du Colombier 	if(user == nil)
1457dd7cddfSDavid du Colombier 		user = "none";
1467dd7cddfSDavid du Colombier 	if(mailboxdir == nil)
1477dd7cddfSDavid du Colombier 		mailboxdir = estrstrdup("/mail/box/", user);
148c27b0bc9SDavid du Colombier 	if(outgoing == nil)
1499a747e4fSDavid du Colombier 		outgoing = estrstrdup(mailboxdir, "/outgoing");
1507dd7cddfSDavid du Colombier 
1517dd7cddfSDavid du Colombier 	s = estrstrdup(maildir, "ctl");
1527dd7cddfSDavid du Colombier 	mbox.ctlfd = open(s, ORDWR|OCEXEC);
1537dd7cddfSDavid du Colombier 	if(mbox.ctlfd < 0)
154*92fd5f07SDavid du Colombier 		error("can't open %s: %r", s);
1557dd7cddfSDavid du Colombier 
15659cc4ca5SDavid du Colombier 	fsname = estrdup(name);
1579a747e4fSDavid du Colombier 	if(newdir && argc > 0){
15859cc4ca5SDavid du Colombier 		s = emalloc(5+strlen(mailboxdir)+strlen(mboxname)+strlen(name)+10+1);
1597dd7cddfSDavid du Colombier 		for(i=0; i<10; i++){
16059cc4ca5SDavid du Colombier 			sprint(s, "open %s/%s %s", mailboxdir, mboxname, fsname);
1617dd7cddfSDavid du Colombier 			if(write(mbox.ctlfd, s, strlen(s)) >= 0)
1627dd7cddfSDavid du Colombier 				break;
1637dd7cddfSDavid du Colombier 			err[0] = '\0';
1649a747e4fSDavid du Colombier 			errstr(err, sizeof err);
165b7b24591SDavid du Colombier 			if(strstr(err, "mbox name in use") == nil)
166*92fd5f07SDavid du Colombier 				error("can't create directory %s for mail: %s", name, err);
16759cc4ca5SDavid du Colombier 			free(fsname);
16859cc4ca5SDavid du Colombier 			fsname = emalloc(strlen(name)+10);
16959cc4ca5SDavid du Colombier 			sprint(fsname, "%s-%d", name, i);
1707dd7cddfSDavid du Colombier 		}
1719a747e4fSDavid du Colombier 		if(i == 10)
172ee55fa65SDavid du Colombier 			error("can't open %s/%s: %r", mailboxdir, mboxname);
17359cc4ca5SDavid du Colombier 		free(s);
1747dd7cddfSDavid du Colombier 	}
1757dd7cddfSDavid du Colombier 
17659cc4ca5SDavid du Colombier 	s = estrstrdup(fsname, "/");
17759cc4ca5SDavid du Colombier 	mbox.name = estrstrdup(maildir, s);
1789a747e4fSDavid du Colombier 	mbox.level= 0;
17959cc4ca5SDavid du Colombier 	readmbox(&mbox, maildir, s);
1807dd7cddfSDavid du Colombier 	home = getenv("home");
1817dd7cddfSDavid du Colombier 	if(home == nil)
1827dd7cddfSDavid du Colombier 		home = "/";
1837dd7cddfSDavid du Colombier 
1847dd7cddfSDavid du Colombier 	wbox = newwindow();
1857dd7cddfSDavid du Colombier 	winname(wbox, mbox.name);
1869a747e4fSDavid du Colombier 	wintagwrite(wbox, "Put Mail Delmesg ", 3+1+4+1+7+1);
1877dd7cddfSDavid du Colombier 	threadcreate(mainctl, wbox, STACK);
1880fb3f58eSDavid du Colombier 
1890fb3f58eSDavid du Colombier 	fmtstrinit(&fmt);
1900fb3f58eSDavid du Colombier 	fmtprint(&fmt, "Mail");
1910fb3f58eSDavid du Colombier 	if(shortmenu)
1920fb3f58eSDavid du Colombier 		fmtprint(&fmt, " -%c", "sS"[shortmenu-1]);
1930fb3f58eSDavid du Colombier 	if(outgoing)
1940fb3f58eSDavid du Colombier 		fmtprint(&fmt, " -o %s", outgoing);
1950fb3f58eSDavid du Colombier 	fmtprint(&fmt, " %s", name);
1960fb3f58eSDavid du Colombier 	cmd = fmtstrflush(&fmt);
1970fb3f58eSDavid du Colombier 	if(cmd == nil)
1980fb3f58eSDavid du Colombier 		sysfatal("out of memory");
1997dd7cddfSDavid du Colombier 	winsetdump(wbox, "/acme/mail", cmd);
2007dd7cddfSDavid du Colombier 	mbox.w = wbox;
2017dd7cddfSDavid du Colombier 
2027dd7cddfSDavid du Colombier 	mesgmenu(wbox, &mbox);
2037dd7cddfSDavid du Colombier 	winclean(wbox);
2047dd7cddfSDavid du Colombier 
2057dd7cddfSDavid du Colombier 	wctlfd = open("/dev/wctl", OWRITE|OCEXEC);	/* for acme window */
2067dd7cddfSDavid du Colombier 	cplumb = chancreate(sizeof(Plumbmsg*), 0);
2077dd7cddfSDavid du Colombier 	cplumbshow = chancreate(sizeof(Plumbmsg*), 0);
2083ff48bf5SDavid du Colombier 	if(strcmp(name, "mbox") == 0){
2093ff48bf5SDavid du Colombier 		/*
2103ff48bf5SDavid du Colombier 		 * Avoid creating multiple windows to send mail by only accepting
2113ff48bf5SDavid du Colombier 		 * sendmail plumb messages if we're reading the main mailbox.
2123ff48bf5SDavid du Colombier 		 */
2133ff48bf5SDavid du Colombier 		plumbsendmailfd = plumbopen("sendmail", OREAD|OCEXEC);
2149a747e4fSDavid du Colombier 		cplumbsend = chancreate(sizeof(Plumbmsg*), 0);
2153ff48bf5SDavid du Colombier 		proccreate(plumbsendproc, nil, STACK);
2163ff48bf5SDavid du Colombier 		threadcreate(plumbsendthread, nil, STACK);
2173ff48bf5SDavid du Colombier 	}
2187dd7cddfSDavid du Colombier 	/* start plumb reader as separate proc ... */
2197dd7cddfSDavid du Colombier 	proccreate(plumbproc, nil, STACK);
2207dd7cddfSDavid du Colombier 	proccreate(plumbshowproc, nil, STACK);
2217dd7cddfSDavid du Colombier 	threadcreate(plumbshowthread, nil, STACK);
2227dd7cddfSDavid du Colombier 	/* ... and use this thread to read the messages */
2237dd7cddfSDavid du Colombier 	plumbthread();
2247dd7cddfSDavid du Colombier }
2257dd7cddfSDavid du Colombier 
2267dd7cddfSDavid du Colombier void
plumbproc(void *)2277dd7cddfSDavid du Colombier plumbproc(void*)
2287dd7cddfSDavid du Colombier {
2297dd7cddfSDavid du Colombier 	Plumbmsg *m;
2307dd7cddfSDavid du Colombier 
2317dd7cddfSDavid du Colombier 	threadsetname("plumbproc");
2327dd7cddfSDavid du Colombier 	for(;;){
2337dd7cddfSDavid du Colombier 		m = plumbrecv(plumbseemailfd);
2347dd7cddfSDavid du Colombier 		sendp(cplumb, m);
2357dd7cddfSDavid du Colombier 		if(m == nil)
2367dd7cddfSDavid du Colombier 			threadexits(nil);
2377dd7cddfSDavid du Colombier 	}
2387dd7cddfSDavid du Colombier }
2397dd7cddfSDavid du Colombier 
2407dd7cddfSDavid du Colombier void
plumbshowproc(void *)2417dd7cddfSDavid du Colombier plumbshowproc(void*)
2427dd7cddfSDavid du Colombier {
2437dd7cddfSDavid du Colombier 	Plumbmsg *m;
2447dd7cddfSDavid du Colombier 
2457dd7cddfSDavid du Colombier 	threadsetname("plumbshowproc");
2467dd7cddfSDavid du Colombier 	for(;;){
2477dd7cddfSDavid du Colombier 		m = plumbrecv(plumbshowmailfd);
2487dd7cddfSDavid du Colombier 		sendp(cplumbshow, m);
2497dd7cddfSDavid du Colombier 		if(m == nil)
2507dd7cddfSDavid du Colombier 			threadexits(nil);
2517dd7cddfSDavid du Colombier 	}
2527dd7cddfSDavid du Colombier }
2537dd7cddfSDavid du Colombier 
2547dd7cddfSDavid du Colombier void
plumbsendproc(void *)2559a747e4fSDavid du Colombier plumbsendproc(void*)
2569a747e4fSDavid du Colombier {
2579a747e4fSDavid du Colombier 	Plumbmsg *m;
2589a747e4fSDavid du Colombier 
2599a747e4fSDavid du Colombier 	threadsetname("plumbsendproc");
2609a747e4fSDavid du Colombier 	for(;;){
2619a747e4fSDavid du Colombier 		m = plumbrecv(plumbsendmailfd);
2629a747e4fSDavid du Colombier 		sendp(cplumbsend, m);
2639a747e4fSDavid du Colombier 		if(m == nil)
2649a747e4fSDavid du Colombier 			threadexits(nil);
2659a747e4fSDavid du Colombier 	}
2669a747e4fSDavid du Colombier }
2679a747e4fSDavid du Colombier 
2689a747e4fSDavid du Colombier void
newmesg(char * name,char * digest)2697dd7cddfSDavid du Colombier newmesg(char *name, char *digest)
2707dd7cddfSDavid du Colombier {
2719a747e4fSDavid du Colombier 	Dir *d;
2727dd7cddfSDavid du Colombier 
2737dd7cddfSDavid du Colombier 	if(strncmp(name, mbox.name, strlen(mbox.name)) != 0)
2747dd7cddfSDavid du Colombier 		return;	/* message is about another mailbox */
2757dd7cddfSDavid du Colombier 	if(mesglookupfile(&mbox, name, digest) != nil)
2767dd7cddfSDavid du Colombier 		return;
2779a747e4fSDavid du Colombier 	d = dirstat(name);
2789a747e4fSDavid du Colombier 	if(d == nil)
2797dd7cddfSDavid du Colombier 		return;
2809a747e4fSDavid du Colombier 	if(mesgadd(&mbox, mbox.name, d, digest))
2817dd7cddfSDavid du Colombier 		mesgmenunew(wbox, &mbox);
2829a747e4fSDavid du Colombier 	free(d);
2837dd7cddfSDavid du Colombier }
2847dd7cddfSDavid du Colombier 
2857dd7cddfSDavid du Colombier void
showmesg(char * name,char * digest)2867dd7cddfSDavid du Colombier showmesg(char *name, char *digest)
2877dd7cddfSDavid du Colombier {
2887dd7cddfSDavid du Colombier 	char *n;
2897dd7cddfSDavid du Colombier 
2907dd7cddfSDavid du Colombier 	if(strncmp(name, mbox.name, strlen(mbox.name)) != 0)
2917dd7cddfSDavid du Colombier 		return;	/* message is about another mailbox */
2927dd7cddfSDavid du Colombier 	n = estrdup(name+strlen(mbox.name));
2937dd7cddfSDavid du Colombier 	if(n[strlen(n)-1] != '/')
2947dd7cddfSDavid du Colombier 		n = egrow(n, "/", nil);
2957dd7cddfSDavid du Colombier 	mesgopen(&mbox, mbox.name, name+strlen(mbox.name), nil, 1, digest);
2967dd7cddfSDavid du Colombier 	free(n);
2977dd7cddfSDavid du Colombier }
2987dd7cddfSDavid du Colombier 
2997dd7cddfSDavid du Colombier void
delmesg(char * name,char * digest,int dodel)3009a747e4fSDavid du Colombier delmesg(char *name, char *digest, int dodel)
3017dd7cddfSDavid du Colombier {
3027dd7cddfSDavid du Colombier 	Message *m;
3037dd7cddfSDavid du Colombier 
3047dd7cddfSDavid du Colombier 	m = mesglookupfile(&mbox, name, digest);
3059a747e4fSDavid du Colombier 	if(m != nil){
3067dd7cddfSDavid du Colombier 		mesgmenumarkdel(wbox, &mbox, m, 0);
3079a747e4fSDavid du Colombier 		if(dodel)
3089a747e4fSDavid du Colombier 			m->writebackdel = 1;
3099a747e4fSDavid du Colombier 	}
3107dd7cddfSDavid du Colombier }
3117dd7cddfSDavid du Colombier 
3127dd7cddfSDavid du Colombier void
plumbthread(void)3137dd7cddfSDavid du Colombier plumbthread(void)
3147dd7cddfSDavid du Colombier {
3157dd7cddfSDavid du Colombier 	Plumbmsg *m;
3167dd7cddfSDavid du Colombier 	Plumbattr *a;
3177dd7cddfSDavid du Colombier 	char *type, *digest;
3187dd7cddfSDavid du Colombier 
3197dd7cddfSDavid du Colombier 	threadsetname("plumbthread");
3207dd7cddfSDavid du Colombier 	while((m = recvp(cplumb)) != nil){
3217dd7cddfSDavid du Colombier 		a = m->attr;
3227dd7cddfSDavid du Colombier 		digest = plumblookup(a, "digest");
3237dd7cddfSDavid du Colombier 		type = plumblookup(a, "mailtype");
3247dd7cddfSDavid du Colombier 		if(type == nil)
3259a747e4fSDavid du Colombier 			fprint(2, "Mail: plumb message with no mailtype attribute\n");
3267dd7cddfSDavid du Colombier 		else if(strcmp(type, "new") == 0)
3277dd7cddfSDavid du Colombier 			newmesg(m->data, digest);
3287dd7cddfSDavid du Colombier 		else if(strcmp(type, "delete") == 0)
3299a747e4fSDavid du Colombier 			delmesg(m->data, digest, 0);
3307dd7cddfSDavid du Colombier 		else
3319a747e4fSDavid du Colombier 			fprint(2, "Mail: unknown plumb attribute %s\n", type);
3327dd7cddfSDavid du Colombier 		plumbfree(m);
3337dd7cddfSDavid du Colombier 	}
3347dd7cddfSDavid du Colombier 	threadexits(nil);
3357dd7cddfSDavid du Colombier }
3367dd7cddfSDavid du Colombier 
3377dd7cddfSDavid du Colombier void
plumbshowthread(void *)3387dd7cddfSDavid du Colombier plumbshowthread(void*)
3397dd7cddfSDavid du Colombier {
3407dd7cddfSDavid du Colombier 	Plumbmsg *m;
3417dd7cddfSDavid du Colombier 
3427dd7cddfSDavid du Colombier 	threadsetname("plumbshowthread");
3437dd7cddfSDavid du Colombier 	while((m = recvp(cplumbshow)) != nil){
3447dd7cddfSDavid du Colombier 		showmesg(m->data, plumblookup(m->attr, "digest"));
3457dd7cddfSDavid du Colombier 		plumbfree(m);
3467dd7cddfSDavid du Colombier 	}
3477dd7cddfSDavid du Colombier 	threadexits(nil);
3487dd7cddfSDavid du Colombier }
3497dd7cddfSDavid du Colombier 
3509a747e4fSDavid du Colombier void
plumbsendthread(void *)3519a747e4fSDavid du Colombier plumbsendthread(void*)
3529a747e4fSDavid du Colombier {
3539a747e4fSDavid du Colombier 	Plumbmsg *m;
3549a747e4fSDavid du Colombier 
3559a747e4fSDavid du Colombier 	threadsetname("plumbsendthread");
3569a747e4fSDavid du Colombier 	while((m = recvp(cplumbsend)) != nil){
357d9306527SDavid du Colombier 		mkreply(nil, "Mail", m->data, m->attr, nil);
3589a747e4fSDavid du Colombier 		plumbfree(m);
3599a747e4fSDavid du Colombier 	}
3609a747e4fSDavid du Colombier 	threadexits(nil);
3619a747e4fSDavid du Colombier }
3629a747e4fSDavid du Colombier 
3637dd7cddfSDavid du Colombier int
mboxcommand(Window * w,char * s)3647dd7cddfSDavid du Colombier mboxcommand(Window *w, char *s)
3657dd7cddfSDavid du Colombier {
3669a747e4fSDavid du Colombier 	char *args[10], **targs;
3677dd7cddfSDavid du Colombier 	Message *m, *next;
3689a747e4fSDavid du Colombier 	int ok, nargs, i, j;
3699a747e4fSDavid du Colombier 	char buf[128];
3707dd7cddfSDavid du Colombier 
3719a747e4fSDavid du Colombier 	nargs = tokenize(s, args, nelem(args));
3729a747e4fSDavid du Colombier 	if(nargs == 0)
3739a747e4fSDavid du Colombier 		return 0;
3749a747e4fSDavid du Colombier 	if(strcmp(args[0], "Mail") == 0){
3759a747e4fSDavid du Colombier 		if(nargs == 1)
376d9306527SDavid du Colombier 			mkreply(nil, "Mail", "", nil, nil);
3779a747e4fSDavid du Colombier 		else
378d9306527SDavid du Colombier 			mkreply(nil, "Mail", args[1], nil, nil);
3797dd7cddfSDavid du Colombier 		return 1;
3807dd7cddfSDavid du Colombier 	}
3817dd7cddfSDavid du Colombier 	if(strcmp(s, "Del") == 0){
3827dd7cddfSDavid du Colombier 		if(mbox.dirty){
3837dd7cddfSDavid du Colombier 			mbox.dirty = 0;
3849a747e4fSDavid du Colombier 			fprint(2, "mail: mailbox not written\n");
3857dd7cddfSDavid du Colombier 			return 1;
3867dd7cddfSDavid du Colombier 		}
3877dd7cddfSDavid du Colombier 		ok = 1;
3887dd7cddfSDavid du Colombier 		for(m=mbox.head; m!=nil; m=next){
3897dd7cddfSDavid du Colombier 			next = m->next;
3907dd7cddfSDavid du Colombier 			if(m->w){
3917dd7cddfSDavid du Colombier 				if(windel(m->w, 0))
3927dd7cddfSDavid du Colombier 					m->w = nil;
3937dd7cddfSDavid du Colombier 				else
3947dd7cddfSDavid du Colombier 					ok = 0;
3957dd7cddfSDavid du Colombier 			}
3967dd7cddfSDavid du Colombier 		}
3977dd7cddfSDavid du Colombier 		for(m=replies.head; m!=nil; m=next){
3987dd7cddfSDavid du Colombier 			next = m->next;
3997dd7cddfSDavid du Colombier 			if(m->w){
4007dd7cddfSDavid du Colombier 				if(windel(m->w, 0))
4017dd7cddfSDavid du Colombier 					m->w = nil;
4027dd7cddfSDavid du Colombier 				else
4037dd7cddfSDavid du Colombier 					ok = 0;
4047dd7cddfSDavid du Colombier 			}
4057dd7cddfSDavid du Colombier 		}
4067dd7cddfSDavid du Colombier 		if(ok){
4077dd7cddfSDavid du Colombier 			windel(w, 1);
4087dd7cddfSDavid du Colombier 			removeupasfs();
4097dd7cddfSDavid du Colombier 			threadexitsall(nil);
4107dd7cddfSDavid du Colombier 		}
4117dd7cddfSDavid du Colombier 		return 1;
4127dd7cddfSDavid du Colombier 	}
4137dd7cddfSDavid du Colombier 	if(strcmp(s, "Put") == 0){
4147dd7cddfSDavid du Colombier 		rewritembox(wbox, &mbox);
4157dd7cddfSDavid du Colombier 		return 1;
4167dd7cddfSDavid du Colombier 	}
4179a747e4fSDavid du Colombier 	if(strcmp(s, "Delmesg") == 0){
4189a747e4fSDavid du Colombier 		if(nargs > 1){
4199a747e4fSDavid du Colombier 			for(i=1; i<nargs; i++){
4209a747e4fSDavid du Colombier 				snprint(buf, sizeof buf, "%s%s", mbox.name, args[i]);
4219a747e4fSDavid du Colombier 				delmesg(buf, nil, 1);
4229a747e4fSDavid du Colombier 			}
4239a747e4fSDavid du Colombier 		}
4249a747e4fSDavid du Colombier 		s = winselection(w);
425d9306527SDavid du Colombier 		if(s == nil)
426d9306527SDavid du Colombier 			return 1;
4279a747e4fSDavid du Colombier 		nargs = 1;
4289a747e4fSDavid du Colombier 		for(i=0; s[i]; i++)
4299a747e4fSDavid du Colombier 			if(s[i] == '\n')
4309a747e4fSDavid du Colombier 				nargs++;
4319a747e4fSDavid du Colombier 		targs = emalloc(nargs*sizeof(char*));	/* could be too many for a local array */
4329a747e4fSDavid du Colombier 		nargs = getfields(s, targs, nargs, 1, "\n");
4339a747e4fSDavid du Colombier 		for(i=0; i<nargs; i++){
4349a747e4fSDavid du Colombier 			if(!isdigit(targs[i][0]))
4359a747e4fSDavid du Colombier 				continue;
4369a747e4fSDavid du Colombier 			j = atoi(targs[i]);	/* easy way to parse the number! */
4379a747e4fSDavid du Colombier 			if(j == 0)
4389a747e4fSDavid du Colombier 				continue;
4399a747e4fSDavid du Colombier 			snprint(buf, sizeof buf, "%s%d", mbox.name, j);
4409a747e4fSDavid du Colombier 			delmesg(buf, nil, 1);
4419a747e4fSDavid du Colombier 		}
4429a747e4fSDavid du Colombier 		free(s);
4439a747e4fSDavid du Colombier 		free(targs);
4449a747e4fSDavid du Colombier 		return 1;
4459a747e4fSDavid du Colombier 	}
4467dd7cddfSDavid du Colombier 	return 0;
4477dd7cddfSDavid du Colombier }
4487dd7cddfSDavid du Colombier 
4497dd7cddfSDavid du Colombier void
mainctl(void * v)4507dd7cddfSDavid du Colombier mainctl(void *v)
4517dd7cddfSDavid du Colombier {
4527dd7cddfSDavid du Colombier 	Window *w;
4537dd7cddfSDavid du Colombier 	Event *e, *e2, *eq, *ea;
4547dd7cddfSDavid du Colombier 	int na, nopen;
4557dd7cddfSDavid du Colombier 	char *s, *t, *buf;
4567dd7cddfSDavid du Colombier 
4577dd7cddfSDavid du Colombier 	w = v;
4587dd7cddfSDavid du Colombier 	proccreate(wineventproc, w, STACK);
4597dd7cddfSDavid du Colombier 
4607dd7cddfSDavid du Colombier 	for(;;){
4617dd7cddfSDavid du Colombier 		e = recvp(w->cevent);
4627dd7cddfSDavid du Colombier 		switch(e->c1){
4637dd7cddfSDavid du Colombier 		default:
4647dd7cddfSDavid du Colombier 		Unknown:
4657dd7cddfSDavid du Colombier 			print("unknown message %c%c\n", e->c1, e->c2);
4667dd7cddfSDavid du Colombier 			break;
4677dd7cddfSDavid du Colombier 
4687dd7cddfSDavid du Colombier 		case 'E':	/* write to body; can't affect us */
4697dd7cddfSDavid du Colombier 			break;
4707dd7cddfSDavid du Colombier 
4717dd7cddfSDavid du Colombier 		case 'F':	/* generated by our actions; ignore */
4727dd7cddfSDavid du Colombier 			break;
4737dd7cddfSDavid du Colombier 
4747dd7cddfSDavid du Colombier 		case 'K':	/* type away; we don't care */
4757dd7cddfSDavid du Colombier 			break;
4767dd7cddfSDavid du Colombier 
4777dd7cddfSDavid du Colombier 		case 'M':
4787dd7cddfSDavid du Colombier 			switch(e->c2){
4797dd7cddfSDavid du Colombier 			case 'x':
4807dd7cddfSDavid du Colombier 			case 'X':
4817dd7cddfSDavid du Colombier 				ea = nil;
4827dd7cddfSDavid du Colombier 				e2 = nil;
4837dd7cddfSDavid du Colombier 				if(e->flag & 2)
4847dd7cddfSDavid du Colombier 					e2 = recvp(w->cevent);
4857dd7cddfSDavid du Colombier 				if(e->flag & 8){
4867dd7cddfSDavid du Colombier 					ea = recvp(w->cevent);
4877dd7cddfSDavid du Colombier 					na = ea->nb;
4887dd7cddfSDavid du Colombier 					recvp(w->cevent);
4897dd7cddfSDavid du Colombier 				}else
4907dd7cddfSDavid du Colombier 					na = 0;
4917dd7cddfSDavid du Colombier 				s = e->b;
4927dd7cddfSDavid du Colombier 				/* if it's a known command, do it */
4937dd7cddfSDavid du Colombier 				if((e->flag&2) && e->nb==0)
4947dd7cddfSDavid du Colombier 					s = e2->b;
4957dd7cddfSDavid du Colombier 				if(na){
4967dd7cddfSDavid du Colombier 					t = emalloc(strlen(s)+1+na+1);
4977dd7cddfSDavid du Colombier 					sprint(t, "%s %s", s, ea->b);
4987dd7cddfSDavid du Colombier 					s = t;
4997dd7cddfSDavid du Colombier 				}
5007dd7cddfSDavid du Colombier 				/* if it's a long message, it can't be for us anyway */
5017dd7cddfSDavid du Colombier 				if(!mboxcommand(w, s))	/* send it back */
5027dd7cddfSDavid du Colombier 					winwriteevent(w, e);
5037dd7cddfSDavid du Colombier 				if(na)
5047dd7cddfSDavid du Colombier 					free(s);
5057dd7cddfSDavid du Colombier 				break;
5067dd7cddfSDavid du Colombier 
5077dd7cddfSDavid du Colombier 			case 'l':
5087dd7cddfSDavid du Colombier 			case 'L':
5097dd7cddfSDavid du Colombier 				buf = nil;
5107dd7cddfSDavid du Colombier 				eq = e;
5117dd7cddfSDavid du Colombier 				if(e->flag & 2){
5127dd7cddfSDavid du Colombier 					e2 = recvp(w->cevent);
5137dd7cddfSDavid du Colombier 					eq = e2;
5147dd7cddfSDavid du Colombier 				}
5157dd7cddfSDavid du Colombier 				s = eq->b;
5167dd7cddfSDavid du Colombier 				if(eq->q1>eq->q0 && eq->nb==0){
5177dd7cddfSDavid du Colombier 					buf = emalloc((eq->q1-eq->q0)*UTFmax+1);
5187dd7cddfSDavid du Colombier 					winread(w, eq->q0, eq->q1, buf);
5197dd7cddfSDavid du Colombier 					s = buf;
5207dd7cddfSDavid du Colombier 				}
5217dd7cddfSDavid du Colombier 				nopen = 0;
5227dd7cddfSDavid du Colombier 				do{
5237dd7cddfSDavid du Colombier 					/* skip 'deleted' string if present' */
5247dd7cddfSDavid du Colombier 					if(strncmp(s, deleted, strlen(deleted)) == 0)
5257dd7cddfSDavid du Colombier 						s += strlen(deleted);
5267dd7cddfSDavid du Colombier 					/* skip mail box name if present */
5277dd7cddfSDavid du Colombier 					if(strncmp(s, mbox.name, strlen(mbox.name)) == 0)
5287dd7cddfSDavid du Colombier 						s += strlen(mbox.name);
5297dd7cddfSDavid du Colombier 					nopen += mesgopen(&mbox, mbox.name, s, nil, 0, nil);
5307dd7cddfSDavid du Colombier 					while(*s!='\0' && *s++!='\n')
5317dd7cddfSDavid du Colombier 						;
5327dd7cddfSDavid du Colombier 				}while(*s);
5337dd7cddfSDavid du Colombier 				if(nopen == 0)	/* send it back */
5347dd7cddfSDavid du Colombier 					winwriteevent(w, e);
5357dd7cddfSDavid du Colombier 				free(buf);
5367dd7cddfSDavid du Colombier 				break;
5377dd7cddfSDavid du Colombier 
5387dd7cddfSDavid du Colombier 			case 'I':	/* modify away; we don't care */
5397dd7cddfSDavid du Colombier 			case 'D':
5407dd7cddfSDavid du Colombier 			case 'd':
5417dd7cddfSDavid du Colombier 			case 'i':
5427dd7cddfSDavid du Colombier 				break;
5437dd7cddfSDavid du Colombier 
5447dd7cddfSDavid du Colombier 			default:
5457dd7cddfSDavid du Colombier 				goto Unknown;
5467dd7cddfSDavid du Colombier 			}
5477dd7cddfSDavid du Colombier 		}
5487dd7cddfSDavid du Colombier 	}
5497dd7cddfSDavid du Colombier }
5509a747e4fSDavid du Colombier 
551