⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mbox.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
#include <u.h>#include <libc.h>#include <bio.h>#include <auth.h>#include "imap4d.h"static NamedInt	flagChars[NFlags] ={	{"s",	MSeen},	{"a",	MAnswered},	{"f",	MFlagged},	{"D",	MDeleted},	{"d",	MDraft},	{"r",	MRecent},};static	int	fsCtl = -1;static	void	boxFlags(Box *box);static	int	createImp(Box *box, Qid *qid);static	void	fsInit(void);static	void	mboxGone(Box *box);static	MbLock	*openImp(Box *box, int new);static	int	parseImp(Biobuf *b, Box *box);static	int	readBox(Box *box);static	ulong	uidRenumber(Msg *m, ulong uid, int force);static	int	impFlags(Box *box, Msg *m, char *flags);/* * strategy: * every mailbox file has an associated .imp file * which maps upas/fs message digests to uids & message flags. * * the .imp files are locked by /mail/fs/usename/L.mbox. * whenever the flags can be modified, the lock file * should be opened, thereby locking the uid & flag state. * for example, whenever new uids are assigned to messages, * and whenever flags are changed internally, the lock file * should be open and locked.  this means the file must be * opened during store command, and when changing the \seen * flag for the fetch command. * * if no .imp file exists, a null one must be created before * assigning uids. * * the .imp file has the following format * imp		: "imap internal mailbox description\n" * 			uidvalidity " " uidnext "\n" *			messageLines * * messageLines	: *		| messageLines digest " " uid " " flags "\n" * * uid, uidnext, and uidvalidity are 32 bit decimal numbers * printed right justified in a field NUid characters long. * the 0 uid implies that no uid has been assigned to the message, * but the flags are valid. note that message lines are in mailbox * order, except possibly for 0 uid messages. * * digest is an ascii hex string NDigest characters long. * * flags has a character for each of NFlag flag fields. * if the flag is clear, it is represented by a "-". * set flags are represented as a unique single ascii character. * the currently assigned flags are, in order: *	MSeen		s *	MAnswered	a *	MFlagged	f *	MDeleted	D *	MDraft		d */Box*openBox(char *name, char *fsname, int writable){	Box *box;	MbLock *ml;	int n, new;	if(cistrcmp(name, "inbox") == 0)		name = "mbox";	fsInit();	if(fprint(fsCtl, "open /mail/box/%s/%s %s", username, name, fsname) < 0){//ZZZchar err[ERRMAX];errstr(err, sizeof err);if(strstr(err, "file does not exist") == nil)	fprint(2, "imap4d at %lud: upas/fs open %s/%s as %s failed: '%s' %s\n", time(nil), username, name, fsname, err, ctime(time(nil)));		fprint(fsCtl, "close %s", fsname);		return nil;	}	/*	 * read box to find all messages	 * each one has a directory, and is in numerical order	 */	box = MKZ(Box);	box->writable = writable;	n = strlen(name) + 1;	box->name = emalloc(n);	strcpy(box->name, name);	n += STRLEN(".imp");	box->imp = emalloc(n);	snprint(box->imp, n, "%s.imp", name);	n = strlen(fsname) + 1;	box->fs = emalloc(n);	strcpy(box->fs, fsname);	n = STRLEN("/mail/fs/") + strlen(fsname) + 1;	box->fsDir = emalloc(n);	snprint(box->fsDir, n, "/mail/fs/%s", fsname);	box->uidnext = 1;	new = readBox(box);	if(new >= 0){		ml = openImp(box, new);		if(ml != nil){			closeImp(box, ml);			return box;		}	}	closeBox(box, 0);	return nil;}/* * check mailbox * returns fd of open .imp file if imped. * otherwise, return value is insignificant * * careful: called by idle polling proc */MbLock*checkBox(Box *box, int imped){	MbLock *ml;	Dir *d;	int new;	if(box == nil)		return nil;	/*	 * if stat fails, mailbox must be gone	 */	d = cdDirstat(box->fsDir, ".");	if(d == nil){		mboxGone(box);		return nil;	}	new = 0;	if(box->qid.path != d->qid.path || box->qid.vers != d->qid.vers	|| box->mtime != d->mtime){		new = readBox(box);		if(new < 0){			free(d);			return nil;		}	}	free(d);	ml = openImp(box, new);	if(ml == nil)		box->writable = 0;	else if(!imped){		closeImp(box, ml);		ml = nil;	}	return ml;}/* * mailbox is unreachable, so mark all messages expunged * clean up .imp files as well. */static voidmboxGone(Box *box){	Msg *m;	if(cdExists(mboxDir, box->name) < 0)		cdRemove(mboxDir, box->imp);	for(m = box->msgs; m != nil; m = m->next)		m->expunged = 1;	box->writable = 0;}/* * read messages in the mailbox * mark message that no longer exist as expunged * returns -1 for failure, 0 if no new messages, 1 if new messages. */static intreadBox(Box *box){	Msg *msgs, *m, *last;	Dir *d;	char *s;	long max, id;	int i, nd, fd, new;	fd = cdOpen(box->fsDir, ".", OREAD);	if(fd < 0){		syslog(0, "mail", "imap4d at %lud: upas/fs stat of %s/%s aka %s failed: %r\n", time(nil),			username, box->name, box->fsDir);		mboxGone(box);		return -1;	}	/*	 * read box to find all messages	 * each one has a directory, and is in numerical order	 */	d = dirfstat(fd);	if(d == nil){		close(fd);		return -1;	}	box->mtime = d->mtime;	box->qid = d->qid;	last = nil;	msgs = box->msgs;	max = 0;	new = 0;	free(d);	while((nd = dirread(fd, &d)) > 0){		for(i = 0; i < nd; i++){			s = d[i].name;			id = strtol(s, &s, 10);			if(id <= max || *s != '\0'			|| (d[i].mode & DMDIR) != DMDIR)				continue;			max = id;			while(msgs != nil){				last = msgs;				msgs = msgs->next;				if(last->id == id)					goto continueDir;				last->expunged = 1;			}			new = 1;			m = MKZ(Msg);			m->id = id;			m->fsDir = box->fsDir;			m->fs = emalloc(2 * (MsgNameLen + 1));			m->efs = seprint(m->fs, m->fs + (MsgNameLen + 1), "%lud/", id);			m->size = ~0UL;			m->lines = ~0UL;			m->prev = last;			m->flags = MRecent;			if(!msgInfo(m))				freeMsg(m);			else{				if(last == nil)					box->msgs = m;				else					last->next = m;				last = m;			}	continueDir:;		}		free(d);	}	close(fd);	for(; msgs != nil; msgs = msgs->next)		msgs->expunged = 1;	/*	 * make up the imap message sequence numbers	 */	id = 1;	for(m = box->msgs; m != nil; m = m->next){		if(m->seq && m->seq != id)			bye("internal error assigning message numbers");		m->seq = id++;	}	box->max = id - 1;	return new;}/* * read in the .imp file, or make one if it doesn't exist. * make sure all flags and uids are consistent. * return the mailbox lock. */#define IMPMAGIC	"imap internal mailbox description\n"static MbLock*openImp(Box *box, int new){	Qid qid;	Biobuf b;	MbLock *ml;	int fd;//ZZZZ	int once;	ml = mbLock();	if(ml == nil)		return nil;	fd = cdOpen(mboxDir, box->imp, OREAD);	once = 0;ZZZhack:	if(fd < 0 || fqid(fd, &qid) < 0){		if(fd < 0){			char buf[ERRMAX];			errstr(buf, sizeof buf);			if(cistrstr(buf, "does not exist") == nil)				fprint(2, "imap4d at %lud: imp open failed: %s\n", time(nil), buf);			if(!once && cistrstr(buf, "locked") != nil){				once = 1;				fprint(2, "imap4d at %lud: imp %s/%s %s locked when it shouldn't be; spinning\n", time(nil), username, box->name, box->imp);				fd = openLocked(mboxDir, box->imp, OREAD);				goto ZZZhack;			}		}		if(fd >= 0)			close(fd);		fd = createImp(box, &qid);		if(fd < 0){			mbUnlock(ml);			return nil;		}		box->dirtyImp = 1;		if(box->uidvalidity == 0)			box->uidvalidity = box->mtime;		box->impQid = qid;		new = 1;	}else if(qid.path != box->impQid.path || qid.vers != box->impQid.vers){		Binit(&b, fd, OREAD);		if(!parseImp(&b, box)){			box->dirtyImp = 1;			if(box->uidvalidity == 0)				box->uidvalidity = box->mtime;		}		Bterm(&b);		box->impQid = qid;		new = 1;	}	if(new)		boxFlags(box);	close(fd);	return ml;}/* * close the .imp file, after writing out any changes */voidcloseImp(Box *box, MbLock *ml){	Msg *m;	Qid qid;	Biobuf b;	char buf[NFlags+1];	int fd;	if(ml == nil)		return;	if(!box->dirtyImp){		mbUnlock(ml);		return;	}	fd = cdCreate(mboxDir, box->imp, OWRITE, 0664);	if(fd < 0){		mbUnlock(ml);		return;	}	Binit(&b, fd, OWRITE);	box->dirtyImp = 0;	Bprint(&b, "%s", IMPMAGIC);	Bprint(&b, "%.*lud %.*lud\n", NUid, box->uidvalidity, NUid, box->uidnext);	for(m = box->msgs; m != nil; m = m->next){		if(m->expunged)			continue;		wrImpFlags(buf, m->flags, strcmp(box->fs, "imap") == 0);		Bprint(&b, "%.*s %.*lud %s\n", NDigest, m->info[IDigest], NUid, m->uid, buf);	}	Bterm(&b);	if(fqid(fd, &qid) >= 0)		box->impQid = qid;	close(fd);	mbUnlock(ml);}voidwrImpFlags(char *buf, int flags, int killRecent){	int i;	for(i = 0; i < NFlags; i++){		if((flags & flagChars[i].v)		&& (flagChars[i].v != MRecent || !killRecent))			buf[i] = flagChars[i].name[0];		else			buf[i] = '-';	}	buf[i] = '\0';

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -