638 lines · 11.7 KB · C
RawDownload
#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);} /* overly conservative; we should move everything up rather than use space */intkillnulls(char *s, char *e){	char *p; 	for(p = s; p < e; p++)		if(*p == 0)			*p = ' ';	return e-s;} /* * 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;			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; 			nn = killnulls(s, s+nn);			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

Lines 1–500 of 638.