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

📄 fetch.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
字号:
#include <u.h>#include <libc.h>#include <bio.h>#include <auth.h>#include "imap4d.h"char *fetchPartNames[FPMax] ={	"",	"HEADER",	"HEADER.FIELDS",	"HEADER.FIELDS.NOT",	"MIME",	"TEXT",};/* * implicitly set the \seen flag.  done in a separate pass * so the .imp file doesn't need to be open while the * messages are sent to the client. */intfetchSeen(Box *box, Msg *m, int uids, void *vf){	Fetch *f;	USED(uids);	if(m->expunged)		return uids;	for(f = vf; f != nil; f = f->next){		switch(f->op){		case FRfc822:		case FRfc822Text:		case FBodySect:			msgSeen(box, m);			goto breakout;		}	}breakout:	return 1;}/* * fetch messages * * imap4 body[] requestes get translated to upas/fs files as follows *	body[id.header] == id/rawheader file + extra \r\n *	body[id.text] == id/rawbody *	body[id.mime] == id/mimeheader + extra \r\n *	body[id] === body[id.header] + body[id.text]*/intfetchMsg(Box *, Msg *m, int uids, void *vf){	Tm tm;	Fetch *f;	char *sep;	int todo;	if(m->expunged)		return uids;	todo = 0;	for(f = vf; f != nil; f = f->next){		switch(f->op){		case FFlags:			todo = 1;			break;		case FUid:			todo = 1;			break;		case FInternalDate:		case FEnvelope:		case FRfc822:		case FRfc822Head:		case FRfc822Size:		case FRfc822Text:		case FBodySect:		case FBodyPeek:		case FBody:		case FBodyStruct:			todo = 1;			if(!msgStruct(m, 1)){				msgDead(m);				return uids;			}			break;		default:			bye("bad implementation of fetch");			return 0;		}	}	if(m->expunged)		return uids;	if(!todo)		return 1;	/*	 * note: it is allowed to send back the responses one at a time	 * rather than all together.  this is exploited to send flags elsewhere.	 */	Bprint(&bout, "* %lud FETCH (", m->seq);	sep = "";	if(uids){		Bprint(&bout, "UID %lud", m->uid);		sep = " ";	}	for(f = vf; f != nil; f = f->next){		switch(f->op){		default:			bye("bad implementation of fetch");			break;		case FFlags:			Bprint(&bout, "%sFLAGS (", sep);			writeFlags(&bout, m, 1);			Bprint(&bout, ")");			break;		case FUid:			if(uids)				continue;			Bprint(&bout, "%sUID %lud", sep, m->uid);			break;		case FEnvelope:			Bprint(&bout, "%sENVELOPE ", sep);			fetchEnvelope(m);			break;		case FInternalDate:			Bprint(&bout, "%sINTERNALDATE ", sep);			Bimapdate(&bout, date2tm(&tm, m->unixDate));			break;		case FBody:			Bprint(&bout, "%sBODY ", sep);			fetchBodyStruct(m, &m->head, 0);			break;		case FBodyStruct:			Bprint(&bout, "%sBODYSTRUCTURE ", sep);			fetchBodyStruct(m, &m->head, 1);			break;		case FRfc822Size:			Bprint(&bout, "%sRFC822.SIZE %lud", sep, msgSize(m));			break;		case FRfc822:			f->part = FPAll;			Bprint(&bout, "%sRFC822", sep);			fetchBody(m, f);			break;		case FRfc822Head:			f->part = FPHead;			Bprint(&bout, "%sRFC822.HEADER", sep);			fetchBody(m, f);			break;		case FRfc822Text:			f->part = FPText;			Bprint(&bout, "%sRFC822.TEXT", sep);			fetchBody(m, f);			break;		case FBodySect:		case FBodyPeek:			Bprint(&bout, "%sBODY", sep);			fetchBody(fetchSect(m, f), f);			break;		}		sep = " ";	}	Bprint(&bout, ")\r\n");	return 1;}/* * print out section, part, headers; * find and return message section */Msg *fetchSect(Msg *m, Fetch *f){	Bputc(&bout, '[');	BNList(&bout, f->sect, ".");	if(f->part != FPAll){		if(f->sect != nil)			Bputc(&bout, '.');		Bprint(&bout, "%s", fetchPartNames[f->part]);		if(f->hdrs != nil){			Bprint(&bout, " (");			BSList(&bout, f->hdrs, " ");			Bputc(&bout, ')');		}	}	Bprint(&bout, "]");	return findMsgSect(m, f->sect);}/* * actually return the body pieces */voidfetchBody(Msg *m, Fetch *f){	Pair p;	char *s, *t, *e, buf[BufSize + 2];	ulong n, start, stop, pos;	int fd, nn;	if(m == nil){		fetchBodyStr(f, "", 0);		return;	}	switch(f->part){	case FPHeadFields:	case FPHeadFieldsNot:		n = m->head.size + 3;		s = emalloc(n);		n = selectFields(s, n, m->head.buf, f->hdrs, f->part == FPHeadFields);		fetchBodyStr(f, s, n);		free(s);		return;	case FPHead:		fetchBodyStr(f, m->head.buf, m->head.size);		return;	case FPMime:		fetchBodyStr(f, m->mime.buf, m->mime.size);		return;	case FPAll:		fd = msgFile(m, "rawbody");		if(fd < 0){			msgDead(m);			fetchBodyStr(f, "", 0);			return;		}		p = fetchBodyPart(f, msgSize(m));		start = p.start;		if(start < m->head.size){			stop = p.stop;			if(stop > m->head.size)				stop = m->head.size;			Bwrite(&bout, &m->head.buf[start], stop - start);			start = 0;			stop = p.stop;			if(stop <= m->head.size){				close(fd);				return;			}		}else			start -= m->head.size;		stop = p.stop - m->head.size;		break;	case FPText:		fd = msgFile(m, "rawbody");		if(fd < 0){			msgDead(m);			fetchBodyStr(f, "", 0);			return;		}		p = fetchBodyPart(f, m->size);		start = p.start;		stop = p.stop;		break;	default:		fetchBodyStr(f, "", 0);		return;	}	/*	 * read in each block, convert \n without \r to \r\n.	 * this means partial fetch requires fetching everything	 * through stop, since we don't know how many \r's will be added	 */	buf[0] = ' ';	for(pos = 0; pos < stop; ){		n = BufSize;		if(n > stop - pos)			n = stop - pos;		n = read(fd, &buf[1], n);		if(n <= 0){			fetchBodyFill(stop - pos);			break;		}		e = &buf[n + 1];		*e = '\0';		for(s = &buf[1]; s < e && pos < stop; s = t + 1){			t = memchr(s, '\n', e - s);			if(t == nil)				t = e;			n = t - s;			if(pos < start){				if(pos + n <= start){					s = t;					pos += n;				}else{					s += start - pos;					pos = start;				}				n = t - s;			}			nn = n;			if(pos + nn > stop)				nn = stop - pos;			if(Bwrite(&bout, s, nn) != nn)				writeErr();			pos += n;			if(*t == '\n'){				if(t[-1] != '\r'){					if(pos >= start && pos < stop)						Bputc(&bout, '\r');					pos++;				}				if(pos >= start && pos < stop)					Bputc(&bout, '\n');				pos++;			}		}		buf[0] = e[-1];	}	close(fd);}/* * resolve the actual bounds of any partial fetch, * and print out the bounds & size of string returned */PairfetchBodyPart(Fetch *f, ulong size){	Pair p;	ulong start, stop;	start = 0;	stop = size;	if(f->partial){		start = f->start;		if(start > size)			start = size;		stop = start + f->size;		if(stop > size)			stop = size;		Bprint(&bout, "<%lud>", start);	}	Bprint(&bout, " {%lud}\r\n", stop - start);	p.start = start;	p.stop = stop;	return p;}/* * something went wrong fetching data * produce fill bytes for what we've committed to produce */voidfetchBodyFill(ulong n){	while(n-- > 0)		if(Bputc(&bout, ' ') < 0)			writeErr();}/* * return a simple string */voidfetchBodyStr(Fetch *f, char *buf, ulong size){	Pair p;	p = fetchBodyPart(f, size);	Bwrite(&bout, &buf[p.start], p.stop-p.start);}char*printnlist(NList *sect){	static char buf[100];	char *p;	for(p= buf; sect; sect=sect->next){		p += sprint(p, "%ld", sect->n);		if(sect->next)			*p++ = '.';	}	*p = '\0';	return buf;}/* * find the numbered sub-part of the message */Msg*findMsgSect(Msg *m, NList *sect){	ulong id;	for(; sect != nil; sect = sect->next){		id = sect->n;#ifdef HACK		/* HACK to solve extra level of structure not visible from upas/fs  */		if(m->kids == 0 && id == 1 && sect->next == nil){			if(m->mime.type->s && strcmp(m->mime.type->s, "message")==0)			if(m->mime.type->t && strcmp(m->mime.type->t, "rfc822")==0)			if(m->head.type->s && strcmp(m->head.type->s, "text")==0)			if(m->head.type->t && strcmp(m->head.type->t, "plain")==0)				break;		}		/* end of HACK */#endif HACK		for(m = m->kids; m != nil; m = m->next)			if(m->id == id)				break;		if(m == nil)			return nil;	}	return m;}voidfetchEnvelope(Msg *m){	Tm tm;	Bputc(&bout, '(');	Brfc822date(&bout, date2tm(&tm, m->info[IDate]));	Bputc(&bout, ' ');	Bimapstr(&bout, m->info[ISubject]);	Bputc(&bout, ' ');	Bimapaddr(&bout, m->from);	Bputc(&bout, ' ');	Bimapaddr(&bout, m->sender);	Bputc(&bout, ' ');	Bimapaddr(&bout, m->replyTo);	Bputc(&bout, ' ');	Bimapaddr(&bout, m->to);	Bputc(&bout, ' ');	Bimapaddr(&bout, m->cc);	Bputc(&bout, ' ');	Bimapaddr(&bout, m->bcc);	Bputc(&bout, ' ');	Bimapstr(&bout, m->info[IInReplyTo]);	Bputc(&bout, ' ');	Bimapstr(&bout, m->info[IMessageId]);	Bputc(&bout, ')');}voidfetchBodyStruct(Msg *m, Header *h, int extensions){	Msg *k;	ulong len;	if(msgIsMulti(h)){		Bputc(&bout, '(');		for(k = m->kids; k != nil; k = k->next)			fetchBodyStruct(k, &k->mime, extensions);		Bputc(&bout, ' ');		Bimapstr(&bout, h->type->t);		if(extensions){			Bputc(&bout, ' ');			BimapMimeParams(&bout, h->type->next);			fetchStructExt(h);		}		Bputc(&bout, ')');		return;	}	Bputc(&bout, '(');	if(h->type != nil){		Bimapstr(&bout, h->type->s);		Bputc(&bout, ' ');		Bimapstr(&bout, h->type->t);		Bputc(&bout, ' ');		BimapMimeParams(&bout, h->type->next);	}else		Bprint(&bout, "\"text\" \"plain\" NIL");	Bputc(&bout, ' ');	if(h->id != nil)		Bimapstr(&bout, h->id->s);	else		Bprint(&bout, "NIL");	Bputc(&bout, ' ');	if(h->description != nil)		Bimapstr(&bout, h->description->s);	else		Bprint(&bout, "NIL");	Bputc(&bout, ' ');	if(h->encoding != nil)		Bimapstr(&bout, h->encoding->s);	else		Bprint(&bout, "NIL");	/*	 * this is so strange: return lengths for a body[text] response,	 * except in the case of a multipart message, when return lengths for a body[] response	 */	len = m->size;	if(h == &m->mime)		len += m->head.size;	Bprint(&bout, " %lud", len);	len = m->lines;	if(h == &m->mime)		len += m->head.lines;	if(h->type == nil || cistrcmp(h->type->s, "text") == 0){		Bprint(&bout, " %lud", len);	}else if(msgIsRfc822(h)){		Bputc(&bout, ' ');		k = m;		if(h != &m->mime)			k = m->kids;		if(k == nil)			Bprint(&bout, "(NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL) (\"text\" \"plain\" NIL NIL NIL NIL 0 0) 0");		else{			fetchEnvelope(k);			Bputc(&bout, ' ');			fetchBodyStruct(k, &k->head, extensions);			Bprint(&bout, " %lud", len);		}	}	if(extensions){		Bputc(&bout, ' ');		/*		 * don't have the md5 laying around,		 * since the header & body have added newlines.		 */		Bprint(&bout, "NIL");		fetchStructExt(h);	}	Bputc(&bout, ')');}/* * common part of bodystructure extensions */voidfetchStructExt(Header *h){	Bputc(&bout, ' ');	if(h->disposition != nil){		Bputc(&bout, '(');		Bimapstr(&bout, h->disposition->s);		Bputc(&bout, ' ');		BimapMimeParams(&bout, h->disposition->next);		Bputc(&bout, ')');	}else		Bprint(&bout, "NIL");	Bputc(&bout, ' ');	if(h->language != nil){		if(h->language->next != nil)			BimapMimeParams(&bout, h->language->next);		else			Bimapstr(&bout, h->language->s);	}else		Bprint(&bout, "NIL");}intBimapMimeParams(Biobuf *b, MimeHdr *mh){	char *sep;	int n;	if(mh == nil)		return Bprint(b, "NIL");	n = Bputc(b, '(');	sep = "";	for(; mh != nil; mh = mh->next){		n += Bprint(b, sep);		n += Bimapstr(b, mh->s);		n += Bputc(b, ' ');		n += Bimapstr(b, mh->t);		sep = " ";	}	n += Bputc(b, ')');	return n;}/* * print a list of addresses; * each address is printed as '(' personalName AtDomainList mboxName hostName ')' * the AtDomainList is always NIL */intBimapaddr(Biobuf *b, MAddr *a){	char *host, *sep;	int n;	if(a == nil)		return Bprint(b, "NIL");	n = Bputc(b, '(');	sep = "";	for(; a != nil; a = a->next){		n += Bprint(b, "%s(", sep);		n += Bimapstr(b, a->personal);		n += Bprint(b," NIL ");		n += Bimapstr(b, a->box);		n += Bputc(b, ' ');		/*		 * can't send NIL as hostName, since that is code for a group		 */		host = a->host;		if(host == nil)			host = "";		n += Bimapstr(b, host);		n += Bputc(b, ')');		sep = " ";	}	n += Bputc(b, ')');	return n;}

⌨️ 快捷键说明

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