361 lines · 5.4 KB · C
RawDownload
#include "common.h" enum{	Mbox	= 1,	Mdir,}; typedef struct Folder Folder;struct Folder{	int	open;	int	ofd;	int	type;	Biobuf	*out;	Mlock	*l;};static Folder ftab[5]; static Folder*getfolder(Biobuf *out){	int i;	Folder *f; 	for(i = 0; i < nelem(ftab); i++){		f = ftab+i;		if(f->open == 0){			f->open = 1;			f->ofd = -1;			f->type = 0;			return f;		}		if(f->out == out)			return f;	}	sysfatal("folder.c:ftab too small");	return 0;} static intputfolder(Folder *f){	int r; 	r = 0;	if(f->l)		sysunlock(f->l);	if(f->out)		r |= Bterm(f->out);	if(f->ofd > 0){		close(f->ofd);		free(f->out);	}	memset(f, 0, sizeof *f);	return r;} static Biobuf*mboxopen(char *s){	Folder *f; 	f = getfolder(0);	f->l = syslock(s);		/* traditional botch: ignore failure */	if((f->ofd = open(s, OWRITE)) == -1)	if((f->ofd = create(s, OWRITE|OEXCL, DMAPPEND|0600)) == -1){		putfolder(f);		return nil;	}	seek(f->ofd, 0, 2);	f->out = malloc(sizeof *f->out);	Binit(f->out, f->ofd, OWRITE);	f->type = Mbox;	return f->out;} /* * sync with send/cat_mail.c:/^mdir */static Biobuf*mdiropen(char *s, long t){	char buf[64];	long i;	Folder *f; 	f = getfolder(0);	for(i = 0; i < 100; i++){		snprint(buf, sizeof buf, "%s/%lud.%.2ld", s, t, i);		if((f->ofd = create(buf, OWRITE|OEXCL, DMAPPEND|0660)) != -1)			goto found;	}	putfolder(f);	return nil;found:	werrstr("");	f->out = malloc(sizeof *f->out);	Binit(f->out, f->ofd, OWRITE);	f->type = Mdir;	return f->out;} Biobuf*openfolder(char *s, long t){	int isdir;	Dir *d; 	if(d = dirstat(s)){		isdir = d->mode&DMDIR;		free(d);	}else{		isdir = create(s, OREAD, DMDIR|0777);		if(isdir == -1)			return nil;		close(isdir);		isdir = 1;	}	if(isdir)		return mdiropen(s, t);	else		return mboxopen(s);} intrenamefolder(Biobuf *b, long t){	char buf[32];	int i;	Dir d;	Folder *f; 	f = getfolder(b);	if(f->type != Mdir)		return 0;	for(i = 0; i < 100; i++){		nulldir(&d);		snprint(buf, sizeof buf, "%lud.%.2d", t, i);		d.name = buf;		if(dirfwstat(Bfildes(b), &d) > 0)			return 0;	}	return -1;} intclosefolder(Biobuf *b){	return putfolder(getfolder(b));} /* * escape "From " at the beginning of a line; * translate \r\n to \n for imap */static intmboxesc(Biobuf *in, Biobuf *out, int type){	char *s;	int n; 	for(; s = Brdstr(in, '\n', 0); free(s)){		if(!strncmp(s, "From ", 5))			Bputc(out, ' ');		n = strlen(s);		if(n > 1 && s[n-2] == '\r'){			s[n-2] = '\n';			n--;		}		if(Bwrite(out, s, n) == Beof){			free(s);			return -1;		}		if(s[n-1] != '\n')			Bputc(out, '\n');	}	if(type == Mbox)		Bputc(out, '\n');	if(Bflush(out) == Beof)		return -1;	return 0;} intappendfolder(Biobuf *b, char *addr, long *t, int fd){	char *s;	int r;	Biobuf bin;	Folder *f;	Tm tm; 	f = getfolder(b);	Bseek(f->out, 0, 2);	Binit(&bin, fd, OREAD);	s = Brdstr(&bin, '\n', 0);	if(!s || strncmp(s, "From ", 5))		Bprint(f->out, "From %s %.28s\n", addr, ctime(*t));	else if(fromtotm(s, &tm) >= 0)		*t = tm2sec(&tm);	if(s)		Bwrite(f->out, s, strlen(s));	free(s);	r = mboxesc(&bin, f->out, f->type);	return r | Bterm(&bin);} intfappendfolder(char *addr, long t, char *s, int fd){	long t0, r;	Biobuf *b; 	b = openfolder(s, t);	if(b == nil)		return -1;	t0 = t;	r = appendfolder(b, addr, &t, fd);	if(t != t0)		renamefolder(b, t);	r |= closefolder(b);	return r;} /* * BOTCH sync with ../imap4d/mbox.c:/^okmbox */ static char *specialfile[] ={	"L.mbox",	"forward",	"headers",	"imap.subscribed",	"names",	"pipefrom",	"pipeto",}; static intspecial(char *s){	char *p;	int i; 	p = strrchr(s, '/');	if(p == nil)		p = s;	else		p++;	for(i = 0; i < nelem(specialfile); i++)		if(strcmp(p, specialfile[i]) == 0)			return 1;	return 0;} static char*mkmbpath(char *s, int n, char *user, char *mb, char *path){	char *p, *e, *r, buf[Pathlen]; 	if(!mb)		return mboxpathbuf(s, n, user, path);	e = buf+sizeof buf;	p = seprint(buf, e, "%s", mb);	if(r = strrchr(buf, '/'))		p = r;	seprint(p, e, "/%s", path);	return mboxpathbuf(s, n, user, buf);}  /* * fancy processing for ned: * we default to storing in $mail/f then just in $mail. */char*ffoldername(char *mb, char *user, char *rcvr){	char *p;	int c, n;	Dir *d;	static char buf[Pathlen]; 	d = dirstat(mkmbpath(buf, sizeof buf, user, mb, "f/"));	n = strlen(buf);	if(!d ||  d->qid.type != QTDIR)		buf[n -= 2] = 0;	free(d); 	if(p = strrchr(rcvr, '!'))		rcvr = p+1;	while(n < sizeof buf-1 && (c = *rcvr++)){		if(c== '@')			break;		if(c == '/')			c = '_';		buf[n++] = c;	}	buf[n] = 0; 	if(special(buf)){		fprint(2, "!won't overwrite %s\n", buf);		return nil;	}	return buf;} char*foldername(char *mb, char *user, char *path){	static char buf[Pathlen]; 	mkmbpath(buf, sizeof buf, user, mb, path);	if(special(buf)){		fprint(2, "!won't overwrite %s\n", buf);		return nil;	}	return buf;} static intappend(Biobuf *in, Biobuf *out){	char *buf;	int n, m; 	buf = malloc(8192);	for(;;){		m = 0;		n = Bread(in, buf, 8192);		if(n <= 0)			break;		m = Bwrite(out, buf, n);		if(m != n)			break;	}	if(m != n)		n = -1;	else		n = 1;	free(buf);	return n;} /* symmetry for nedmail; misnamed */intfappendfile(char*, char *target, int in){	int fd, r;	Biobuf bin, out; 	if((fd = create(target, ORDWR|OEXCL, 0666)) == -1)		return -1;	Binit(&out, fd, OWRITE);	Binit(&bin, in, OREAD);	r = append(&bin, &out);	Bterm(&bin);	Bterm(&out);	close(fd);	return r;}