mbox.c

来自「这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易」· C语言 代码 · 共 814 行 · 第 1/2 页

C
814
字号
}intemptyImp(char *mbox){	Dir *d;	long mode;	int fd;	fd = cdCreate(mboxDir, impName(mbox), OWRITE, 0664);	if(fd < 0)		return -1;	d = cdDirstat(mboxDir, mbox);	if(d == nil){		close(fd);		return -1;	}	fprint(fd, "%s%.*lud %.*lud\n", IMPMAGIC, NUid, d->mtime, NUid, 1UL);	mode = d->mode & 0777;	nulldir(d);	d->mode = mode;	dirfwstat(fd, d);	free(d);	return fd;}/* * try to match permissions with mbox */static intcreateImp(Box *box, Qid *qid){	Dir *d;	long mode;	int fd;	fd = cdCreate(mboxDir, box->imp, OREAD, 0664);	if(fd < 0)		return -1;	d = cdDirstat(mboxDir, box->name);	if(d != nil){		mode = d->mode & 0777;		nulldir(d);		d->mode = mode;		dirfwstat(fd, d);		free(d);	}	if(fqid(fd, qid) < 0){		close(fd);		return -1;	}	return fd;}/* * read or re-read a .imp file. * this is tricky: *	messages can be deleted by another agent *	we might still have a Msg for an expunged message, *		because we haven't told the client yet. *	we can have a Msg without a .imp entry. *	flag information is added at the end of the .imp by copy & append *	there can be duplicate messages (same digests). * * look up existing messages based on uid. * look up new messages based on in order digest matching. * * note: in the face of duplicate messages, one of which is deleted, * two active servers may decide different ones are valid, and so return * different uids for the messages.  this situation will stablize when the servers exit. */static intparseImp(Biobuf *b, Box *box){	Msg *m, *mm = nil;	char *s, *t, *toks[3];	ulong uid, u;	int match, n;	m = box->msgs;	s = Brdline(b, '\n');	if(s == nil || Blinelen(b) != STRLEN(IMPMAGIC)	|| strncmp(s, IMPMAGIC, STRLEN(IMPMAGIC)) != 0)		return 0;	s = Brdline(b, '\n');	if(s == nil || Blinelen(b) != 2*NUid + 2)		return 0;	s[2*NUid + 1] = '\0';	u = strtoul(s, &t, 10);	if(u != box->uidvalidity && box->uidvalidity != 0)		return 0;	box->uidvalidity = u;	if(*t != ' ' || t != s + NUid)		return 0;	t++;	u = strtoul(t, &t, 10);	if(box->uidnext > u)		return 0;	box->uidnext = u;	if(t != s + 2*NUid+1 || box->uidnext == 0)		return 0;	uid = ~0;	while(m != nil){		s = Brdline(b, '\n');		if(s == nil)			break;		n = Blinelen(b) - 1;		if(n != NDigest + NUid + NFlags + 2		|| s[NDigest] != ' ' || s[NDigest + NUid + 1] != ' ')			return 0;		toks[0] = s;		s[NDigest] = '\0';		toks[1] = s + NDigest + 1;		s[NDigest + NUid + 1] = '\0';		toks[2] = s + NDigest + NUid + 2;		s[n] = '\0';		t = toks[1];		u = strtoul(t, &t, 10);		if(*t != '\0' || uid != ~0 && (uid >= u && u || u && !uid))			return 0;		uid = u;		/*		 * zero uid => added by append or copy, only flags valid		 * can only match messages without uids, but this message		 * may not be the next one, and may have been deleted.		 */		if(!uid){			for(; m != nil && m->uid; m = m->next)				;			for(mm = m; mm != nil; mm = mm->next){				if(mm->info[IDigest] != nil &&				    strcmp(mm->info[IDigest], toks[0]) == 0){					if(!mm->uid)						mm->flags = 0;					if(!impFlags(box, mm, toks[2]))						return 0;					m = mm->next;					break;				}			}			continue;		}		/*		 * ignore expunged messages,		 * and messages already assigned uids which don't match this uid.		 * such messages must have been deleted by another imap server,		 * which updated the mailbox and .imp file since we read the mailbox,		 * or because upas/fs got confused by consecutive duplicate messages,		 * the first of which was deleted by another imap server.		 */		for(; m != nil && (m->expunged || m->uid && m->uid < uid); m = m->next)			;		if(m == nil)			break;		/*		 * only check for digest match on the next message,		 * since it comes before all other messages, and therefore		 * must be in the .imp file if they should be.		 */		match = mm != nil && mm->info[IDigest] != nil &&			strcmp(m->info[IDigest], toks[0]) == 0;		if(uid && (m->uid == uid || !m->uid && match)){			if(!match)				bye("inconsistent uid");			/*			 * wipe out recent flag if some other server saw this new message.			 * it will be read from the .imp file if is really should be set,			 * ie the message was only seen by a status command.			 */			if(!m->uid)				m->flags = 0;			if(!impFlags(box, m, toks[2]))				return 0;			m->uid = uid;			m = m->next;		}	}	return 1;}/* * parse .imp flags */static intimpFlags(Box *box, Msg *m, char *flags){	int i, f;	f = 0;	for(i = 0; i < NFlags; i++){		if(flags[i] == '-')			continue;		if(flags[i] != flagChars[i].name[0])			return 0;		f |= flagChars[i].v;	}	/*	 * recent flags are set until the first time message's box is selected or examined.	 * it may be stored in the file as a side effect of a status or subscribe command;	 * if so, clear it out.	 */	if((f & MRecent) && strcmp(box->fs, "imap") == 0)		box->dirtyImp = 1;	f |= m->flags & MRecent;	/*	 * all old messages with changed flags should be reported to the client	 */	if(m->uid && m->flags != f){		box->sendFlags = 1;		m->sendFlags = 1;	}	m->flags = f;	return 1;}/* * assign uids to any new messages * which aren't already in the .imp file. * sum up totals for flag values. */static voidboxFlags(Box *box){	Msg *m;	box->recent = 0;	for(m = box->msgs; m != nil; m = m->next){		if(m->uid == 0){			box->dirtyImp = 1;			box->uidnext = uidRenumber(m, box->uidnext, 0);		}		if(m->flags & MRecent)			box->recent++;	}}static ulonguidRenumber(Msg *m, ulong uid, int force){	for(; m != nil; m = m->next){		if(!force && m->uid != 0)			bye("uid renumbering with a valid uid");		m->uid = uid++;	}	return uid;}voidcloseBox(Box *box, int opened){	Msg *m, *next;	/*	 * make sure to leave the mailbox directory so upas/fs can close the mailbox	 */	myChdir(mboxDir);	if(box->writable){		deleteMsgs(box);		if(expungeMsgs(box, 0))			closeImp(box, checkBox(box, 1));	}	if(fprint(fsCtl, "close %s", box->fs) < 0 && opened)		bye("can't talk to mail server");	for(m = box->msgs; m != nil; m = next){		next = m->next;		freeMsg(m);	}	free(box->name);	free(box->fs);	free(box->fsDir);	free(box->imp);	free(box);}intdeleteMsgs(Box *box){	Msg *m;	char buf[BufSize], *p, *start;	int ok;	if(!box->writable)		return 0;	/*	 * first pass: delete messages; gang the writes together for speed.	 */	ok = 1;	start = seprint(buf, buf + sizeof(buf), "delete %s", box->fs);	p = start;	for(m = box->msgs; m != nil; m = m->next){		if((m->flags & MDeleted) && !m->expunged){			m->expunged = 1;			p = seprint(p, buf + sizeof(buf), " %lud", m->id);			if(p + 32 >= buf + sizeof(buf)){				if(write(fsCtl, buf, p - buf) < 0)					bye("can't talk to mail server");				p = start;			}		}	}	if(p != start && write(fsCtl, buf, p - buf) < 0)		bye("can't talk to mail server");	return ok;}/* * second pass: remove the message structure, * and renumber message sequence numbers. * update messages counts in mailbox. * returns true if anything changed. */intexpungeMsgs(Box *box, int send){	Msg *m, *next, *last;	ulong n;	n = 0;	last = nil;	for(m = box->msgs; m != nil; m = next){		m->seq -= n;		next = m->next;		if(m->expunged){			if(send)				Bprint(&bout, "* %lud expunge\r\n", m->seq);			if(m->flags & MRecent)				box->recent--;			n++;			if(last == nil)				box->msgs = next;			else				last->next = next;			freeMsg(m);		}else			last = m;	}	if(n){		box->max -= n;		box->dirtyImp = 1;	}	return n;}static voidfsInit(void){	if(fsCtl >= 0)		return;	fsCtl = open("/mail/fs/ctl", ORDWR);	if(fsCtl < 0)		bye("can't open mail file system");	if(fprint(fsCtl, "close mbox") < 0)		bye("can't initialize mail file system");}static char *stoplist[] ={	"mbox",	"pipeto",	"forward",	"names",	0};/* * reject bad mailboxes based on mailbox name */intokMbox(char *path){	char *name;	int i;	name = strrchr(path, '/');	if(name == nil)		name = path;	else		name++;	if(strlen(name) + STRLEN(".imp") >= MboxNameLen)		return 0;	for(i = 0; stoplist[i]; i++)		if(strcmp(name, stoplist[i]) == 0)			return 0;	if(isprefix("L.", name) || isprefix("imap-tmp.", name)	|| issuffix(".imp", name)	|| strcmp("imap.subscribed", name) == 0	|| isdotdot(name) || name[0] == '/')		return 0;	return 1;}

⌨️ 快捷键说明

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