shithub: Nail

ref: 5d357160775432816ceb80bfabc98375f7db73a5
dir: /comp.c/

View raw version
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <thread.h>
#include <regexp.h>

#include "mail.h"

typedef struct Fn	Fn;

struct Fn {
	char *name;
	void (*fn)(Comp *, char **, int);
};

void
execmarshal(void *p)
{
	Comp *c;
	char *dashr;

	c = p;
	rfork(RFFDG);
	dup(c->fd[0], 0);
	close(c->fd[0]);
	close(c->fd[1]);
	dashr = (c->rpath != nil) ? "-R" : nil;
	procexecl(c->sync, "/bin/upas/marshal", "marshal", "-8", dashr, c->rpath, nil);
}

static void
postmesg(Comp *c, char **, int nf)
{
	char *buf, wpath[64], *path;
	int n, fd;
	Mesg *m;

	snprint(wpath, sizeof(wpath), "/mnt/acme/%d/body", c->id);
	if(nf != 0){
		fprint(2, "Post: too many args\n");
		return;
	}
	if((fd = open(wpath, OREAD)) == -1){
		fprint(2, "open body: %r\n");
		return;
	}
	if(pipe(c->fd) == -1)
		sysfatal("pipe: %r\n");

	c->sync = chancreate(sizeof(ulong), 0);
	procrfork(execmarshal, c, Stack, RFNOTEG);
	recvul(c->sync);
	chanfree(c->sync);
	close(c->fd[0]);

	buf = emalloc(Bufsz);
	while((n = read(fd, buf, Bufsz)) > 0)
		if(write(c->fd[1], buf, n) != n)
			break;
	close(c->fd[1]);
	close(fd);
	if(n == -1)
		return;

	if(fprint(c->ctl, "name %s:Sent\n", c->path) == -1)
		sysfatal("write ctl: %r");
	if(c->replyto != nil){
		if((m = mesglookup(c->rname, c->rdigest)) == nil)
			return;
		m->flags |= Fresp;
		path = estrjoin(mbox.path, "/", m->name, "/flags", nil);
		if((fd = open(path, OWRITE)) != -1){
			fprint(fd, "+a");
			close(fd);
		}
		mbredraw(m, 0, 0);
		free(path);
	}
	fprint(c->ctl, "clean\n");
}

static void
compquit(Comp *c, char **, int)
{
	c->quitting = 1;
}

static Fn compfn[] = {
	{"Post", postmesg},
	{"Del", compquit},
	{nil},
};

static void
compmain(void *cp)
{
	char *f[32];
	int nf;
	Event ev;
	Comp *c, **pc;
	Fn *p;

	c = cp;
	c->quitting = 0;
	c->qnext = mbox.opencomp;
	mbox.opencomp = c;
	fprint(c->ctl, "clean\n");
	mbox.nopen++;
	while(!c->quitting){
		if(winevent(c, &ev) != 'M')
			continue;
		if(strcmp(ev.text, "Del") == 0)
			break;
		switch(ev.type){
		case 'l':
		case 'L':
			if(matchmesg(&mbox, ev.text))
				mesgopen(ev.text, nil);
			else
				winreturn(c, &ev);
			break;
		case 'x':
		case 'X':
			if((nf = tokenize(ev.text, f, nelem(f))) == 0)
				continue;
			for(p = compfn; p->fn != nil; p++)
				if(strcmp(p->name, f[0]) == 0){
					p->fn(c, &f[1], nf - 1);
					break;
				}
			if(p->name == nil && !(ev.flags & 0x2))
				winreturn(c, &ev);
			break;
		break;
		}
	}
	for(pc = &mbox.opencomp; *pc != nil; pc = &(*pc)->qnext)
		if(*pc == c){
			*pc = c->qnext;
			break;
		}
	mbox.nopen--;
	c->qnext = nil;
	winclose(c);
	free(c->replyto);
	free(c->rname);
	free(c->rdigest);
	free(c->rpath);
	threadexits(nil);
}

static Biobuf*
openbody(Mesg *r)
{
	Biobuf *f;
	int q0, q1;
	char *s;

	assert(r->state & Sopen);

	wingetsel(r, &q0, &q1);
	if(q1 - q0 != 0){
		s = smprint("/mnt/acme/%d/xdata", r->id);
		f = Bopen(s, OREAD);
		free(s);
	}else
		f = mesgopenbody(r);
	return f;
}

void
compose(char *to, Mesg *r, int quote, int all)
{
	static int ncompose;
	Biobuf *rfd, *wfd;
	Comp *c;
	char *ln;

	c = emalloc(sizeof(Comp));
	if(r != nil)
		c->path = esmprint("%s%s%s.%d", mbox.path, r->name, "Reply", ncompose++);
	else
		c->path = esmprint("%sCompose.%d", mbox.path, ncompose++);
	wininit(c, c->path);

	wintagwrite(c, "Post ");
	wfd = bwinopen(c, "body", OWRITE);
	if(r == nil || !all)
		Bprint(wfd, "To: %s\n", to);
	else{
		if(strlen(r->from) > 0)
			Bprint(wfd, "To: %s\n", r->from);
		if(strlen(r->to) > 0)
			Bprint(wfd, "To: %s\n", r->to);
		if(strlen(r->cc) > 0)
			Bprint(wfd, "CC: %s\n", r->cc);
	}
	if(r == nil)
		Bprint(wfd, "Subject: ");
	else{
		if(r->messageid != nil)
			c->replyto = estrdup(r->messageid);
		c->rpath = estrjoin(mbox.path, r->name, nil);
		c->rname = estrdup(r->name);
		c->rdigest = estrdup(r->digest);
		Bprint(wfd, "Subject: ");
		if(r->subject != nil && cistrncmp(r->subject, "Re", 2) != 0)
			Bprint(wfd, "Re: ");
		Bprint(wfd, "%s\n\n", r->subject);
		if(quote){
			Bprint(wfd, "Quoth %s:\n", r->fromcolon);
			rfd = openbody(r);
			if(rfd != nil)
				while((ln = Brdstr(rfd, '\n', 0)) != nil)
					if(Bprint(wfd, "> %s", ln) == -1)
						break;
			Bterm(rfd);
		}
		Bterm(wfd);
	}
	Bterm(wfd);
	fprint(c->addr, "$");
	fprint(c->ctl, "dot=addr");
	threadcreate(compmain, c, Stack);
}