xref: /plan9/sys/src/cmd/ip/imap4d/fetch.c (revision 40fe8d0d2a3c60abd3653acf0a5621d0e6f845e5)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <bio.h>
49a747e4fSDavid du Colombier #include <auth.h>
57dd7cddfSDavid du Colombier #include "imap4d.h"
67dd7cddfSDavid du Colombier 
77dd7cddfSDavid du Colombier char *fetchPartNames[FPMax] =
87dd7cddfSDavid du Colombier {
97dd7cddfSDavid du Colombier 	"",
107dd7cddfSDavid du Colombier 	"HEADER",
117dd7cddfSDavid du Colombier 	"HEADER.FIELDS",
127dd7cddfSDavid du Colombier 	"HEADER.FIELDS.NOT",
137dd7cddfSDavid du Colombier 	"MIME",
147dd7cddfSDavid du Colombier 	"TEXT",
157dd7cddfSDavid du Colombier };
167dd7cddfSDavid du Colombier 
177dd7cddfSDavid du Colombier /*
187dd7cddfSDavid du Colombier  * implicitly set the \seen flag.  done in a separate pass
197dd7cddfSDavid du Colombier  * so the .imp file doesn't need to be open while the
207dd7cddfSDavid du Colombier  * messages are sent to the client.
217dd7cddfSDavid du Colombier  */
227dd7cddfSDavid du Colombier int
fetchSeen(Box * box,Msg * m,int uids,void * vf)237dd7cddfSDavid du Colombier fetchSeen(Box *box, Msg *m, int uids, void *vf)
247dd7cddfSDavid du Colombier {
257dd7cddfSDavid du Colombier 	Fetch *f;
267dd7cddfSDavid du Colombier 
277dd7cddfSDavid du Colombier 	USED(uids);
287dd7cddfSDavid du Colombier 
297dd7cddfSDavid du Colombier 	if(m->expunged)
307dd7cddfSDavid du Colombier 		return uids;
317dd7cddfSDavid du Colombier 	for(f = vf; f != nil; f = f->next){
327dd7cddfSDavid du Colombier 		switch(f->op){
337dd7cddfSDavid du Colombier 		case FRfc822:
347dd7cddfSDavid du Colombier 		case FRfc822Text:
357dd7cddfSDavid du Colombier 		case FBodySect:
367dd7cddfSDavid du Colombier 			msgSeen(box, m);
377dd7cddfSDavid du Colombier 			goto breakout;
387dd7cddfSDavid du Colombier 		}
397dd7cddfSDavid du Colombier 	}
407dd7cddfSDavid du Colombier breakout:
417dd7cddfSDavid du Colombier 
427dd7cddfSDavid du Colombier 	return 1;
437dd7cddfSDavid du Colombier }
447dd7cddfSDavid du Colombier 
457dd7cddfSDavid du Colombier /*
467dd7cddfSDavid du Colombier  * fetch messages
477dd7cddfSDavid du Colombier  *
487dd7cddfSDavid du Colombier  * imap4 body[] requestes get translated to upas/fs files as follows
497dd7cddfSDavid du Colombier  *	body[id.header] == id/rawheader file + extra \r\n
507dd7cddfSDavid du Colombier  *	body[id.text] == id/rawbody
517dd7cddfSDavid du Colombier  *	body[id.mime] == id/mimeheader + extra \r\n
527dd7cddfSDavid du Colombier  *	body[id] === body[id.header] + body[id.text]
537dd7cddfSDavid du Colombier */
547dd7cddfSDavid du Colombier int
fetchMsg(Box *,Msg * m,int uids,void * vf)55becaf2abSDavid du Colombier fetchMsg(Box *, Msg *m, int uids, void *vf)
567dd7cddfSDavid du Colombier {
577dd7cddfSDavid du Colombier 	Tm tm;
587dd7cddfSDavid du Colombier 	Fetch *f;
597dd7cddfSDavid du Colombier 	char *sep;
607dd7cddfSDavid du Colombier 	int todo;
617dd7cddfSDavid du Colombier 
627dd7cddfSDavid du Colombier 	if(m->expunged)
637dd7cddfSDavid du Colombier 		return uids;
647dd7cddfSDavid du Colombier 
657dd7cddfSDavid du Colombier 	todo = 0;
667dd7cddfSDavid du Colombier 	for(f = vf; f != nil; f = f->next){
677dd7cddfSDavid du Colombier 		switch(f->op){
687dd7cddfSDavid du Colombier 		case FFlags:
69229d2d34SDavid du Colombier 			todo = 1;
707dd7cddfSDavid du Colombier 			break;
717dd7cddfSDavid du Colombier 		case FUid:
727dd7cddfSDavid du Colombier 			todo = 1;
737dd7cddfSDavid du Colombier 			break;
747dd7cddfSDavid du Colombier 		case FInternalDate:
757dd7cddfSDavid du Colombier 		case FEnvelope:
767dd7cddfSDavid du Colombier 		case FRfc822:
777dd7cddfSDavid du Colombier 		case FRfc822Head:
787dd7cddfSDavid du Colombier 		case FRfc822Size:
797dd7cddfSDavid du Colombier 		case FRfc822Text:
807dd7cddfSDavid du Colombier 		case FBodySect:
817dd7cddfSDavid du Colombier 		case FBodyPeek:
827dd7cddfSDavid du Colombier 		case FBody:
837dd7cddfSDavid du Colombier 		case FBodyStruct:
847dd7cddfSDavid du Colombier 			todo = 1;
857dd7cddfSDavid du Colombier 			if(!msgStruct(m, 1)){
867dd7cddfSDavid du Colombier 				msgDead(m);
877dd7cddfSDavid du Colombier 				return uids;
887dd7cddfSDavid du Colombier 			}
897dd7cddfSDavid du Colombier 			break;
907dd7cddfSDavid du Colombier 		default:
917dd7cddfSDavid du Colombier 			bye("bad implementation of fetch");
927dd7cddfSDavid du Colombier 			return 0;
937dd7cddfSDavid du Colombier 		}
947dd7cddfSDavid du Colombier 	}
957dd7cddfSDavid du Colombier 
967dd7cddfSDavid du Colombier 	if(m->expunged)
977dd7cddfSDavid du Colombier 		return uids;
987dd7cddfSDavid du Colombier 	if(!todo)
997dd7cddfSDavid du Colombier 		return 1;
1007dd7cddfSDavid du Colombier 
1017dd7cddfSDavid du Colombier 	/*
1027dd7cddfSDavid du Colombier 	 * note: it is allowed to send back the responses one at a time
1037dd7cddfSDavid du Colombier 	 * rather than all together.  this is exploited to send flags elsewhere.
1047dd7cddfSDavid du Colombier 	 */
105f121929fSDavid du Colombier 	Bprint(&bout, "* %lud FETCH (", m->seq);
1067dd7cddfSDavid du Colombier 	sep = "";
1077dd7cddfSDavid du Colombier 	if(uids){
108*40fe8d0dSDavid du Colombier 		Bprint(&bout, "UID %lud", m->uid);
1097dd7cddfSDavid du Colombier 		sep = " ";
1107dd7cddfSDavid du Colombier 	}
1117dd7cddfSDavid du Colombier 	for(f = vf; f != nil; f = f->next){
1127dd7cddfSDavid du Colombier 		switch(f->op){
1137dd7cddfSDavid du Colombier 		default:
1147dd7cddfSDavid du Colombier 			bye("bad implementation of fetch");
1157dd7cddfSDavid du Colombier 			break;
1167dd7cddfSDavid du Colombier 		case FFlags:
117*40fe8d0dSDavid du Colombier 			Bprint(&bout, "%sFLAGS (", sep);
118becaf2abSDavid du Colombier 			writeFlags(&bout, m, 1);
119becaf2abSDavid du Colombier 			Bprint(&bout, ")");
120becaf2abSDavid du Colombier 			break;
1217dd7cddfSDavid du Colombier 		case FUid:
1227dd7cddfSDavid du Colombier 			if(uids)
1237dd7cddfSDavid du Colombier 				continue;
124*40fe8d0dSDavid du Colombier 			Bprint(&bout, "%sUID %lud", sep, m->uid);
1257dd7cddfSDavid du Colombier 			break;
1267dd7cddfSDavid du Colombier 		case FEnvelope:
127*40fe8d0dSDavid du Colombier 			Bprint(&bout, "%sENVELOPE ", sep);
1287dd7cddfSDavid du Colombier 			fetchEnvelope(m);
1297dd7cddfSDavid du Colombier 			break;
1307dd7cddfSDavid du Colombier 		case FInternalDate:
131*40fe8d0dSDavid du Colombier 			Bprint(&bout, "%sINTERNALDATE ", sep);
1327dd7cddfSDavid du Colombier 			Bimapdate(&bout, date2tm(&tm, m->unixDate));
1337dd7cddfSDavid du Colombier 			break;
1347dd7cddfSDavid du Colombier 		case FBody:
135*40fe8d0dSDavid du Colombier 			Bprint(&bout, "%sBODY ", sep);
1367dd7cddfSDavid du Colombier 			fetchBodyStruct(m, &m->head, 0);
1377dd7cddfSDavid du Colombier 			break;
1387dd7cddfSDavid du Colombier 		case FBodyStruct:
139*40fe8d0dSDavid du Colombier 			Bprint(&bout, "%sBODYSTRUCTURE ", sep);
1407dd7cddfSDavid du Colombier 			fetchBodyStruct(m, &m->head, 1);
1417dd7cddfSDavid du Colombier 			break;
1427dd7cddfSDavid du Colombier 		case FRfc822Size:
143f121929fSDavid du Colombier 			Bprint(&bout, "%sRFC822.SIZE %lud", sep, msgSize(m));
1447dd7cddfSDavid du Colombier 			break;
1457dd7cddfSDavid du Colombier 		case FRfc822:
1467dd7cddfSDavid du Colombier 			f->part = FPAll;
147f121929fSDavid du Colombier 			Bprint(&bout, "%sRFC822", sep);
1487dd7cddfSDavid du Colombier 			fetchBody(m, f);
1497dd7cddfSDavid du Colombier 			break;
1507dd7cddfSDavid du Colombier 		case FRfc822Head:
1517dd7cddfSDavid du Colombier 			f->part = FPHead;
152*40fe8d0dSDavid du Colombier 			Bprint(&bout, "%sRFC822.HEADER", sep);
1537dd7cddfSDavid du Colombier 			fetchBody(m, f);
1547dd7cddfSDavid du Colombier 			break;
1557dd7cddfSDavid du Colombier 		case FRfc822Text:
1567dd7cddfSDavid du Colombier 			f->part = FPText;
157*40fe8d0dSDavid du Colombier 			Bprint(&bout, "%sRFC822.TEXT", sep);
1587dd7cddfSDavid du Colombier 			fetchBody(m, f);
1597dd7cddfSDavid du Colombier 			break;
1607dd7cddfSDavid du Colombier 		case FBodySect:
1617dd7cddfSDavid du Colombier 		case FBodyPeek:
162*40fe8d0dSDavid du Colombier 			Bprint(&bout, "%sBODY", sep);
1637dd7cddfSDavid du Colombier 			fetchBody(fetchSect(m, f), f);
1647dd7cddfSDavid du Colombier 			break;
1657dd7cddfSDavid du Colombier 		}
1667dd7cddfSDavid du Colombier 		sep = " ";
1677dd7cddfSDavid du Colombier 	}
1687dd7cddfSDavid du Colombier 	Bprint(&bout, ")\r\n");
1697dd7cddfSDavid du Colombier 
1707dd7cddfSDavid du Colombier 	return 1;
1717dd7cddfSDavid du Colombier }
1727dd7cddfSDavid du Colombier 
1737dd7cddfSDavid du Colombier /*
1747dd7cddfSDavid du Colombier  * print out section, part, headers;
1757dd7cddfSDavid du Colombier  * find and return message section
1767dd7cddfSDavid du Colombier  */
1777dd7cddfSDavid du Colombier Msg *
fetchSect(Msg * m,Fetch * f)1787dd7cddfSDavid du Colombier fetchSect(Msg *m, Fetch *f)
1797dd7cddfSDavid du Colombier {
1807dd7cddfSDavid du Colombier 	Bputc(&bout, '[');
1817dd7cddfSDavid du Colombier 	BNList(&bout, f->sect, ".");
1827dd7cddfSDavid du Colombier 	if(f->part != FPAll){
1837dd7cddfSDavid du Colombier 		if(f->sect != nil)
1847dd7cddfSDavid du Colombier 			Bputc(&bout, '.');
1857dd7cddfSDavid du Colombier 		Bprint(&bout, "%s", fetchPartNames[f->part]);
1867dd7cddfSDavid du Colombier 		if(f->hdrs != nil){
1877dd7cddfSDavid du Colombier 			Bprint(&bout, " (");
1887dd7cddfSDavid du Colombier 			BSList(&bout, f->hdrs, " ");
1897dd7cddfSDavid du Colombier 			Bputc(&bout, ')');
1907dd7cddfSDavid du Colombier 		}
1917dd7cddfSDavid du Colombier 	}
1927dd7cddfSDavid du Colombier 	Bprint(&bout, "]");
1937dd7cddfSDavid du Colombier 	return findMsgSect(m, f->sect);
1947dd7cddfSDavid du Colombier }
1957dd7cddfSDavid du Colombier 
1967dd7cddfSDavid du Colombier /*
1977dd7cddfSDavid du Colombier  * actually return the body pieces
1987dd7cddfSDavid du Colombier  */
1997dd7cddfSDavid du Colombier void
fetchBody(Msg * m,Fetch * f)2007dd7cddfSDavid du Colombier fetchBody(Msg *m, Fetch *f)
2017dd7cddfSDavid du Colombier {
2027dd7cddfSDavid du Colombier 	Pair p;
2037dd7cddfSDavid du Colombier 	char *s, *t, *e, buf[BufSize + 2];
2047dd7cddfSDavid du Colombier 	ulong n, start, stop, pos;
2057dd7cddfSDavid du Colombier 	int fd, nn;
2067dd7cddfSDavid du Colombier 
2077dd7cddfSDavid du Colombier 	if(m == nil){
2087dd7cddfSDavid du Colombier 		fetchBodyStr(f, "", 0);
2097dd7cddfSDavid du Colombier 		return;
2107dd7cddfSDavid du Colombier 	}
2117dd7cddfSDavid du Colombier 	switch(f->part){
2127dd7cddfSDavid du Colombier 	case FPHeadFields:
2137dd7cddfSDavid du Colombier 	case FPHeadFieldsNot:
2147dd7cddfSDavid du Colombier 		n = m->head.size + 3;
2157dd7cddfSDavid du Colombier 		s = emalloc(n);
2167dd7cddfSDavid du Colombier 		n = selectFields(s, n, m->head.buf, f->hdrs, f->part == FPHeadFields);
2177dd7cddfSDavid du Colombier 		fetchBodyStr(f, s, n);
2187dd7cddfSDavid du Colombier 		free(s);
2197dd7cddfSDavid du Colombier 		return;
2207dd7cddfSDavid du Colombier 	case FPHead:
2217dd7cddfSDavid du Colombier 		fetchBodyStr(f, m->head.buf, m->head.size);
2227dd7cddfSDavid du Colombier 		return;
2237dd7cddfSDavid du Colombier 	case FPMime:
2247dd7cddfSDavid du Colombier 		fetchBodyStr(f, m->mime.buf, m->mime.size);
2257dd7cddfSDavid du Colombier 		return;
2267dd7cddfSDavid du Colombier 	case FPAll:
2277dd7cddfSDavid du Colombier 		fd = msgFile(m, "rawbody");
2287dd7cddfSDavid du Colombier 		if(fd < 0){
2297dd7cddfSDavid du Colombier 			msgDead(m);
2307dd7cddfSDavid du Colombier 			fetchBodyStr(f, "", 0);
2317dd7cddfSDavid du Colombier 			return;
2327dd7cddfSDavid du Colombier 		}
2337dd7cddfSDavid du Colombier 		p = fetchBodyPart(f, msgSize(m));
2347dd7cddfSDavid du Colombier 		start = p.start;
2357dd7cddfSDavid du Colombier 		if(start < m->head.size){
2367dd7cddfSDavid du Colombier 			stop = p.stop;
2377dd7cddfSDavid du Colombier 			if(stop > m->head.size)
2387dd7cddfSDavid du Colombier 				stop = m->head.size;
2397dd7cddfSDavid du Colombier 			Bwrite(&bout, &m->head.buf[start], stop - start);
2407dd7cddfSDavid du Colombier 			start = 0;
2417dd7cddfSDavid du Colombier 			stop = p.stop;
2427dd7cddfSDavid du Colombier 			if(stop <= m->head.size){
2437dd7cddfSDavid du Colombier 				close(fd);
2447dd7cddfSDavid du Colombier 				return;
2457dd7cddfSDavid du Colombier 			}
2467dd7cddfSDavid du Colombier 		}else
2477dd7cddfSDavid du Colombier 			start -= m->head.size;
2487dd7cddfSDavid du Colombier 		stop = p.stop - m->head.size;
2497dd7cddfSDavid du Colombier 		break;
2507dd7cddfSDavid du Colombier 	case FPText:
2517dd7cddfSDavid du Colombier 		fd = msgFile(m, "rawbody");
2527dd7cddfSDavid du Colombier 		if(fd < 0){
2537dd7cddfSDavid du Colombier 			msgDead(m);
2547dd7cddfSDavid du Colombier 			fetchBodyStr(f, "", 0);
2557dd7cddfSDavid du Colombier 			return;
2567dd7cddfSDavid du Colombier 		}
2577dd7cddfSDavid du Colombier 		p = fetchBodyPart(f, m->size);
2587dd7cddfSDavid du Colombier 		start = p.start;
2597dd7cddfSDavid du Colombier 		stop = p.stop;
2607dd7cddfSDavid du Colombier 		break;
2617dd7cddfSDavid du Colombier 	default:
2627dd7cddfSDavid du Colombier 		fetchBodyStr(f, "", 0);
2637dd7cddfSDavid du Colombier 		return;
2647dd7cddfSDavid du Colombier 	}
2657dd7cddfSDavid du Colombier 
2667dd7cddfSDavid du Colombier 	/*
2677dd7cddfSDavid du Colombier 	 * read in each block, convert \n without \r to \r\n.
2687dd7cddfSDavid du Colombier 	 * this means partial fetch requires fetching everything
2697dd7cddfSDavid du Colombier 	 * through stop, since we don't know how many \r's will be added
2707dd7cddfSDavid du Colombier 	 */
2717dd7cddfSDavid du Colombier 	buf[0] = ' ';
2727dd7cddfSDavid du Colombier 	for(pos = 0; pos < stop; ){
2737dd7cddfSDavid du Colombier 		n = BufSize;
2747dd7cddfSDavid du Colombier 		if(n > stop - pos)
2757dd7cddfSDavid du Colombier 			n = stop - pos;
2767dd7cddfSDavid du Colombier 		n = read(fd, &buf[1], n);
2777dd7cddfSDavid du Colombier 		if(n <= 0){
2787dd7cddfSDavid du Colombier 			fetchBodyFill(stop - pos);
2797dd7cddfSDavid du Colombier 			break;
2807dd7cddfSDavid du Colombier 		}
2817dd7cddfSDavid du Colombier 		e = &buf[n + 1];
2827dd7cddfSDavid du Colombier 		*e = '\0';
2837dd7cddfSDavid du Colombier 		for(s = &buf[1]; s < e && pos < stop; s = t + 1){
2847dd7cddfSDavid du Colombier 			t = memchr(s, '\n', e - s);
2857dd7cddfSDavid du Colombier 			if(t == nil)
2867dd7cddfSDavid du Colombier 				t = e;
2877dd7cddfSDavid du Colombier 			n = t - s;
2887dd7cddfSDavid du Colombier 			if(pos < start){
2897dd7cddfSDavid du Colombier 				if(pos + n <= start){
2907dd7cddfSDavid du Colombier 					s = t;
2917dd7cddfSDavid du Colombier 					pos += n;
2927dd7cddfSDavid du Colombier 				}else{
2937dd7cddfSDavid du Colombier 					s += start - pos;
2947dd7cddfSDavid du Colombier 					pos = start;
2957dd7cddfSDavid du Colombier 				}
2967dd7cddfSDavid du Colombier 				n = t - s;
2977dd7cddfSDavid du Colombier 			}
2987dd7cddfSDavid du Colombier 			nn = n;
2997dd7cddfSDavid du Colombier 			if(pos + nn > stop)
3007dd7cddfSDavid du Colombier 				nn = stop - pos;
3017dd7cddfSDavid du Colombier 			if(Bwrite(&bout, s, nn) != nn)
3027dd7cddfSDavid du Colombier 				writeErr();
3037dd7cddfSDavid du Colombier 			pos += n;
3047dd7cddfSDavid du Colombier 			if(*t == '\n'){
3057dd7cddfSDavid du Colombier 				if(t[-1] != '\r'){
3067dd7cddfSDavid du Colombier 					if(pos >= start && pos < stop)
3077dd7cddfSDavid du Colombier 						Bputc(&bout, '\r');
3087dd7cddfSDavid du Colombier 					pos++;
3097dd7cddfSDavid du Colombier 				}
3107dd7cddfSDavid du Colombier 				if(pos >= start && pos < stop)
3117dd7cddfSDavid du Colombier 					Bputc(&bout, '\n');
3127dd7cddfSDavid du Colombier 				pos++;
3137dd7cddfSDavid du Colombier 			}
3147dd7cddfSDavid du Colombier 		}
3157dd7cddfSDavid du Colombier 		buf[0] = e[-1];
3167dd7cddfSDavid du Colombier 	}
3177dd7cddfSDavid du Colombier 	close(fd);
3187dd7cddfSDavid du Colombier }
3197dd7cddfSDavid du Colombier 
3207dd7cddfSDavid du Colombier /*
3217dd7cddfSDavid du Colombier  * resolve the actual bounds of any partial fetch,
3227dd7cddfSDavid du Colombier  * and print out the bounds & size of string returned
3237dd7cddfSDavid du Colombier  */
3247dd7cddfSDavid du Colombier Pair
fetchBodyPart(Fetch * f,ulong size)3257dd7cddfSDavid du Colombier fetchBodyPart(Fetch *f, ulong size)
3267dd7cddfSDavid du Colombier {
3277dd7cddfSDavid du Colombier 	Pair p;
3287dd7cddfSDavid du Colombier 	ulong start, stop;
3297dd7cddfSDavid du Colombier 
3307dd7cddfSDavid du Colombier 	start = 0;
3317dd7cddfSDavid du Colombier 	stop = size;
3327dd7cddfSDavid du Colombier 	if(f->partial){
3337dd7cddfSDavid du Colombier 		start = f->start;
3347dd7cddfSDavid du Colombier 		if(start > size)
3357dd7cddfSDavid du Colombier 			start = size;
3367dd7cddfSDavid du Colombier 		stop = start + f->size;
3377dd7cddfSDavid du Colombier 		if(stop > size)
3387dd7cddfSDavid du Colombier 			stop = size;
3397dd7cddfSDavid du Colombier 		Bprint(&bout, "<%lud>", start);
3407dd7cddfSDavid du Colombier 	}
3417dd7cddfSDavid du Colombier 	Bprint(&bout, " {%lud}\r\n", stop - start);
3427dd7cddfSDavid du Colombier 	p.start = start;
3437dd7cddfSDavid du Colombier 	p.stop = stop;
3447dd7cddfSDavid du Colombier 	return p;
3457dd7cddfSDavid du Colombier }
3467dd7cddfSDavid du Colombier 
3477dd7cddfSDavid du Colombier /*
3487dd7cddfSDavid du Colombier  * something went wrong fetching data
3497dd7cddfSDavid du Colombier  * produce fill bytes for what we've committed to produce
3507dd7cddfSDavid du Colombier  */
3517dd7cddfSDavid du Colombier void
fetchBodyFill(ulong n)3527dd7cddfSDavid du Colombier fetchBodyFill(ulong n)
3537dd7cddfSDavid du Colombier {
3547dd7cddfSDavid du Colombier 	while(n-- > 0)
3557dd7cddfSDavid du Colombier 		if(Bputc(&bout, ' ') < 0)
3567dd7cddfSDavid du Colombier 			writeErr();
3577dd7cddfSDavid du Colombier }
3587dd7cddfSDavid du Colombier 
3597dd7cddfSDavid du Colombier /*
3607dd7cddfSDavid du Colombier  * return a simple string
3617dd7cddfSDavid du Colombier  */
3627dd7cddfSDavid du Colombier void
fetchBodyStr(Fetch * f,char * buf,ulong size)3637dd7cddfSDavid du Colombier fetchBodyStr(Fetch *f, char *buf, ulong size)
3647dd7cddfSDavid du Colombier {
3657dd7cddfSDavid du Colombier 	Pair p;
3667dd7cddfSDavid du Colombier 
3677dd7cddfSDavid du Colombier 	p = fetchBodyPart(f, size);
3687dd7cddfSDavid du Colombier 	Bwrite(&bout, &buf[p.start], p.stop-p.start);
3697dd7cddfSDavid du Colombier }
3707dd7cddfSDavid du Colombier 
3719a747e4fSDavid du Colombier char*
printnlist(NList * sect)3729a747e4fSDavid du Colombier printnlist(NList *sect)
3739a747e4fSDavid du Colombier {
3749a747e4fSDavid du Colombier 	static char buf[100];
3759a747e4fSDavid du Colombier 	char *p;
3769a747e4fSDavid du Colombier 
3779a747e4fSDavid du Colombier 	for(p= buf; sect; sect=sect->next){
3789a747e4fSDavid du Colombier 		p += sprint(p, "%ld", sect->n);
3799a747e4fSDavid du Colombier 		if(sect->next)
3809a747e4fSDavid du Colombier 			*p++ = '.';
3819a747e4fSDavid du Colombier 	}
3829a747e4fSDavid du Colombier 	*p = '\0';
3839a747e4fSDavid du Colombier 	return buf;
3849a747e4fSDavid du Colombier }
3859a747e4fSDavid du Colombier 
3867dd7cddfSDavid du Colombier /*
3877dd7cddfSDavid du Colombier  * find the numbered sub-part of the message
3887dd7cddfSDavid du Colombier  */
3897dd7cddfSDavid du Colombier Msg*
findMsgSect(Msg * m,NList * sect)3907dd7cddfSDavid du Colombier findMsgSect(Msg *m, NList *sect)
3917dd7cddfSDavid du Colombier {
3927dd7cddfSDavid du Colombier 	ulong id;
3937dd7cddfSDavid du Colombier 
3947dd7cddfSDavid du Colombier 	for(; sect != nil; sect = sect->next){
3957dd7cddfSDavid du Colombier 		id = sect->n;
3969a747e4fSDavid du Colombier #ifdef HACK
3979a747e4fSDavid du Colombier 		/* HACK to solve extra level of structure not visible from upas/fs  */
3989a747e4fSDavid du Colombier 		if(m->kids == 0 && id == 1 && sect->next == nil){
3999a747e4fSDavid du Colombier 			if(m->mime.type->s && strcmp(m->mime.type->s, "message")==0)
4009a747e4fSDavid du Colombier 			if(m->mime.type->t && strcmp(m->mime.type->t, "rfc822")==0)
4019a747e4fSDavid du Colombier 			if(m->head.type->s && strcmp(m->head.type->s, "text")==0)
4029a747e4fSDavid du Colombier 			if(m->head.type->t && strcmp(m->head.type->t, "plain")==0)
4039a747e4fSDavid du Colombier 				break;
4049a747e4fSDavid du Colombier 		}
4059a747e4fSDavid du Colombier 		/* end of HACK */
4069a747e4fSDavid du Colombier #endif HACK
4077dd7cddfSDavid du Colombier 		for(m = m->kids; m != nil; m = m->next)
4087dd7cddfSDavid du Colombier 			if(m->id == id)
4097dd7cddfSDavid du Colombier 				break;
4107dd7cddfSDavid du Colombier 		if(m == nil)
4117dd7cddfSDavid du Colombier 			return nil;
4127dd7cddfSDavid du Colombier 	}
4137dd7cddfSDavid du Colombier 	return m;
4147dd7cddfSDavid du Colombier }
4157dd7cddfSDavid du Colombier 
4167dd7cddfSDavid du Colombier void
fetchEnvelope(Msg * m)4177dd7cddfSDavid du Colombier fetchEnvelope(Msg *m)
4187dd7cddfSDavid du Colombier {
4197dd7cddfSDavid du Colombier 	Tm tm;
4207dd7cddfSDavid du Colombier 
4217dd7cddfSDavid du Colombier 	Bputc(&bout, '(');
4227dd7cddfSDavid du Colombier 	Brfc822date(&bout, date2tm(&tm, m->info[IDate]));
4237dd7cddfSDavid du Colombier 	Bputc(&bout, ' ');
4247dd7cddfSDavid du Colombier 	Bimapstr(&bout, m->info[ISubject]);
4257dd7cddfSDavid du Colombier 	Bputc(&bout, ' ');
4267dd7cddfSDavid du Colombier 	Bimapaddr(&bout, m->from);
4277dd7cddfSDavid du Colombier 	Bputc(&bout, ' ');
4287dd7cddfSDavid du Colombier 	Bimapaddr(&bout, m->sender);
4297dd7cddfSDavid du Colombier 	Bputc(&bout, ' ');
4307dd7cddfSDavid du Colombier 	Bimapaddr(&bout, m->replyTo);
4317dd7cddfSDavid du Colombier 	Bputc(&bout, ' ');
4327dd7cddfSDavid du Colombier 	Bimapaddr(&bout, m->to);
4337dd7cddfSDavid du Colombier 	Bputc(&bout, ' ');
4347dd7cddfSDavid du Colombier 	Bimapaddr(&bout, m->cc);
4357dd7cddfSDavid du Colombier 	Bputc(&bout, ' ');
4367dd7cddfSDavid du Colombier 	Bimapaddr(&bout, m->bcc);
4377dd7cddfSDavid du Colombier 	Bputc(&bout, ' ');
4387dd7cddfSDavid du Colombier 	Bimapstr(&bout, m->info[IInReplyTo]);
4397dd7cddfSDavid du Colombier 	Bputc(&bout, ' ');
4407dd7cddfSDavid du Colombier 	Bimapstr(&bout, m->info[IMessageId]);
4417dd7cddfSDavid du Colombier 	Bputc(&bout, ')');
4427dd7cddfSDavid du Colombier }
4437dd7cddfSDavid du Colombier 
4447dd7cddfSDavid du Colombier void
fetchBodyStruct(Msg * m,Header * h,int extensions)4457dd7cddfSDavid du Colombier fetchBodyStruct(Msg *m, Header *h, int extensions)
4467dd7cddfSDavid du Colombier {
4477dd7cddfSDavid du Colombier 	Msg *k;
4487dd7cddfSDavid du Colombier 	ulong len;
4497dd7cddfSDavid du Colombier 
4507dd7cddfSDavid du Colombier 	if(msgIsMulti(h)){
4517dd7cddfSDavid du Colombier 		Bputc(&bout, '(');
4527dd7cddfSDavid du Colombier 		for(k = m->kids; k != nil; k = k->next)
4537dd7cddfSDavid du Colombier 			fetchBodyStruct(k, &k->mime, extensions);
4547dd7cddfSDavid du Colombier 
4557dd7cddfSDavid du Colombier 		Bputc(&bout, ' ');
4567dd7cddfSDavid du Colombier 		Bimapstr(&bout, h->type->t);
4577dd7cddfSDavid du Colombier 
4587dd7cddfSDavid du Colombier 		if(extensions){
4597dd7cddfSDavid du Colombier 			Bputc(&bout, ' ');
4607dd7cddfSDavid du Colombier 			BimapMimeParams(&bout, h->type->next);
4617dd7cddfSDavid du Colombier 			fetchStructExt(h);
4627dd7cddfSDavid du Colombier 		}
4637dd7cddfSDavid du Colombier 
4647dd7cddfSDavid du Colombier 		Bputc(&bout, ')');
4657dd7cddfSDavid du Colombier 		return;
4667dd7cddfSDavid du Colombier 	}
4677dd7cddfSDavid du Colombier 
4687dd7cddfSDavid du Colombier 	Bputc(&bout, '(');
4697dd7cddfSDavid du Colombier 	if(h->type != nil){
4707dd7cddfSDavid du Colombier 		Bimapstr(&bout, h->type->s);
4717dd7cddfSDavid du Colombier 		Bputc(&bout, ' ');
4727dd7cddfSDavid du Colombier 		Bimapstr(&bout, h->type->t);
4737dd7cddfSDavid du Colombier 		Bputc(&bout, ' ');
4747dd7cddfSDavid du Colombier 		BimapMimeParams(&bout, h->type->next);
4757dd7cddfSDavid du Colombier 	}else
4767dd7cddfSDavid du Colombier 		Bprint(&bout, "\"text\" \"plain\" NIL");
4777dd7cddfSDavid du Colombier 
4787dd7cddfSDavid du Colombier 	Bputc(&bout, ' ');
4797dd7cddfSDavid du Colombier 	if(h->id != nil)
4807dd7cddfSDavid du Colombier 		Bimapstr(&bout, h->id->s);
4817dd7cddfSDavid du Colombier 	else
4827dd7cddfSDavid du Colombier 		Bprint(&bout, "NIL");
4837dd7cddfSDavid du Colombier 
4847dd7cddfSDavid du Colombier 	Bputc(&bout, ' ');
4857dd7cddfSDavid du Colombier 	if(h->description != nil)
4867dd7cddfSDavid du Colombier 		Bimapstr(&bout, h->description->s);
4877dd7cddfSDavid du Colombier 	else
4887dd7cddfSDavid du Colombier 		Bprint(&bout, "NIL");
4897dd7cddfSDavid du Colombier 
4907dd7cddfSDavid du Colombier 	Bputc(&bout, ' ');
4917dd7cddfSDavid du Colombier 	if(h->encoding != nil)
4927dd7cddfSDavid du Colombier 		Bimapstr(&bout, h->encoding->s);
4937dd7cddfSDavid du Colombier 	else
4947dd7cddfSDavid du Colombier 		Bprint(&bout, "NIL");
4957dd7cddfSDavid du Colombier 
4967dd7cddfSDavid du Colombier 	/*
4977dd7cddfSDavid du Colombier 	 * this is so strange: return lengths for a body[text] response,
4989a747e4fSDavid du Colombier 	 * except in the case of a multipart message, when return lengths for a body[] response
4997dd7cddfSDavid du Colombier 	 */
5007dd7cddfSDavid du Colombier 	len = m->size;
5017dd7cddfSDavid du Colombier 	if(h == &m->mime)
5027dd7cddfSDavid du Colombier 		len += m->head.size;
5037dd7cddfSDavid du Colombier 	Bprint(&bout, " %lud", len);
5047dd7cddfSDavid du Colombier 
5057dd7cddfSDavid du Colombier 	len = m->lines;
5067dd7cddfSDavid du Colombier 	if(h == &m->mime)
5077dd7cddfSDavid du Colombier 		len += m->head.lines;
5087dd7cddfSDavid du Colombier 
5097dd7cddfSDavid du Colombier 	if(h->type == nil || cistrcmp(h->type->s, "text") == 0){
5107dd7cddfSDavid du Colombier 		Bprint(&bout, " %lud", len);
5117dd7cddfSDavid du Colombier 	}else if(msgIsRfc822(h)){
5127dd7cddfSDavid du Colombier 		Bputc(&bout, ' ');
5137dd7cddfSDavid du Colombier 		k = m;
5147dd7cddfSDavid du Colombier 		if(h != &m->mime)
5157dd7cddfSDavid du Colombier 			k = m->kids;
5167dd7cddfSDavid du Colombier 		if(k == nil)
5177dd7cddfSDavid du Colombier 			Bprint(&bout, "(NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL) (\"text\" \"plain\" NIL NIL NIL NIL 0 0) 0");
5187dd7cddfSDavid du Colombier 		else{
5197dd7cddfSDavid du Colombier 			fetchEnvelope(k);
5207dd7cddfSDavid du Colombier 			Bputc(&bout, ' ');
5217dd7cddfSDavid du Colombier 			fetchBodyStruct(k, &k->head, extensions);
5227dd7cddfSDavid du Colombier 			Bprint(&bout, " %lud", len);
5237dd7cddfSDavid du Colombier 		}
5247dd7cddfSDavid du Colombier 	}
5257dd7cddfSDavid du Colombier 
5267dd7cddfSDavid du Colombier 	if(extensions){
5277dd7cddfSDavid du Colombier 		Bputc(&bout, ' ');
5287dd7cddfSDavid du Colombier 
5297dd7cddfSDavid du Colombier 		/*
5307dd7cddfSDavid du Colombier 		 * don't have the md5 laying around,
5317dd7cddfSDavid du Colombier 		 * since the header & body have added newlines.
5327dd7cddfSDavid du Colombier 		 */
5337dd7cddfSDavid du Colombier 		Bprint(&bout, "NIL");
5347dd7cddfSDavid du Colombier 
5357dd7cddfSDavid du Colombier 		fetchStructExt(h);
5367dd7cddfSDavid du Colombier 	}
5377dd7cddfSDavid du Colombier 	Bputc(&bout, ')');
5387dd7cddfSDavid du Colombier }
5397dd7cddfSDavid du Colombier 
5407dd7cddfSDavid du Colombier /*
5417dd7cddfSDavid du Colombier  * common part of bodystructure extensions
5427dd7cddfSDavid du Colombier  */
5437dd7cddfSDavid du Colombier void
fetchStructExt(Header * h)5447dd7cddfSDavid du Colombier fetchStructExt(Header *h)
5457dd7cddfSDavid du Colombier {
5467dd7cddfSDavid du Colombier 	Bputc(&bout, ' ');
5477dd7cddfSDavid du Colombier 	if(h->disposition != nil){
5487dd7cddfSDavid du Colombier 		Bputc(&bout, '(');
5497dd7cddfSDavid du Colombier 		Bimapstr(&bout, h->disposition->s);
5507dd7cddfSDavid du Colombier 		Bputc(&bout, ' ');
5517dd7cddfSDavid du Colombier 		BimapMimeParams(&bout, h->disposition->next);
5527dd7cddfSDavid du Colombier 		Bputc(&bout, ')');
5537dd7cddfSDavid du Colombier 	}else
5547dd7cddfSDavid du Colombier 		Bprint(&bout, "NIL");
5557dd7cddfSDavid du Colombier 	Bputc(&bout, ' ');
5567dd7cddfSDavid du Colombier 	if(h->language != nil){
5577dd7cddfSDavid du Colombier 		if(h->language->next != nil)
5587dd7cddfSDavid du Colombier 			BimapMimeParams(&bout, h->language->next);
5597dd7cddfSDavid du Colombier 		else
5607dd7cddfSDavid du Colombier 			Bimapstr(&bout, h->language->s);
5617dd7cddfSDavid du Colombier 	}else
5627dd7cddfSDavid du Colombier 		Bprint(&bout, "NIL");
5637dd7cddfSDavid du Colombier }
5647dd7cddfSDavid du Colombier 
5657dd7cddfSDavid du Colombier int
BimapMimeParams(Biobuf * b,MimeHdr * mh)5667dd7cddfSDavid du Colombier BimapMimeParams(Biobuf *b, MimeHdr *mh)
5677dd7cddfSDavid du Colombier {
5687dd7cddfSDavid du Colombier 	char *sep;
5697dd7cddfSDavid du Colombier 	int n;
5707dd7cddfSDavid du Colombier 
5717dd7cddfSDavid du Colombier 	if(mh == nil)
5727dd7cddfSDavid du Colombier 		return Bprint(b, "NIL");
5737dd7cddfSDavid du Colombier 
5747dd7cddfSDavid du Colombier 	n = Bputc(b, '(');
5757dd7cddfSDavid du Colombier 
5767dd7cddfSDavid du Colombier 	sep = "";
5777dd7cddfSDavid du Colombier 	for(; mh != nil; mh = mh->next){
5787dd7cddfSDavid du Colombier 		n += Bprint(b, sep);
5797dd7cddfSDavid du Colombier 		n += Bimapstr(b, mh->s);
5807dd7cddfSDavid du Colombier 		n += Bputc(b, ' ');
5817dd7cddfSDavid du Colombier 		n += Bimapstr(b, mh->t);
5827dd7cddfSDavid du Colombier 		sep = " ";
5837dd7cddfSDavid du Colombier 	}
5847dd7cddfSDavid du Colombier 
5857dd7cddfSDavid du Colombier 	n += Bputc(b, ')');
5867dd7cddfSDavid du Colombier 	return n;
5877dd7cddfSDavid du Colombier }
5887dd7cddfSDavid du Colombier 
5897dd7cddfSDavid du Colombier /*
5907dd7cddfSDavid du Colombier  * print a list of addresses;
5917dd7cddfSDavid du Colombier  * each address is printed as '(' personalName AtDomainList mboxName hostName ')'
5927dd7cddfSDavid du Colombier  * the AtDomainList is always NIL
5937dd7cddfSDavid du Colombier  */
5947dd7cddfSDavid du Colombier int
Bimapaddr(Biobuf * b,MAddr * a)5957dd7cddfSDavid du Colombier Bimapaddr(Biobuf *b, MAddr *a)
5967dd7cddfSDavid du Colombier {
5977dd7cddfSDavid du Colombier 	char *host, *sep;
5987dd7cddfSDavid du Colombier 	int n;
5997dd7cddfSDavid du Colombier 
6007dd7cddfSDavid du Colombier 	if(a == nil)
6017dd7cddfSDavid du Colombier 		return Bprint(b, "NIL");
6027dd7cddfSDavid du Colombier 
6037dd7cddfSDavid du Colombier 	n = Bputc(b, '(');
6047dd7cddfSDavid du Colombier 	sep = "";
6057dd7cddfSDavid du Colombier 	for(; a != nil; a = a->next){
6067dd7cddfSDavid du Colombier 		n += Bprint(b, "%s(", sep);
6077dd7cddfSDavid du Colombier 		n += Bimapstr(b, a->personal);
6087dd7cddfSDavid du Colombier 		n += Bprint(b," NIL ");
6097dd7cddfSDavid du Colombier 		n += Bimapstr(b, a->box);
6107dd7cddfSDavid du Colombier 		n += Bputc(b, ' ');
6117dd7cddfSDavid du Colombier 
6127dd7cddfSDavid du Colombier 		/*
6137dd7cddfSDavid du Colombier 		 * can't send NIL as hostName, since that is code for a group
6147dd7cddfSDavid du Colombier 		 */
6157dd7cddfSDavid du Colombier 		host = a->host;
6167dd7cddfSDavid du Colombier 		if(host == nil)
6177dd7cddfSDavid du Colombier 			host = "";
6187dd7cddfSDavid du Colombier 		n += Bimapstr(b, host);
6197dd7cddfSDavid du Colombier 
6207dd7cddfSDavid du Colombier 		n += Bputc(b, ')');
6217dd7cddfSDavid du Colombier 		sep = " ";
6227dd7cddfSDavid du Colombier 	}
6237dd7cddfSDavid du Colombier 	n += Bputc(b, ')');
6247dd7cddfSDavid du Colombier 	return n;
6257dd7cddfSDavid du Colombier }
626