xref: /plan9/sys/src/cmd/ip/imap4d/fetch.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <bio.h>
4*9a747e4fSDavid 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
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
557dd7cddfSDavid du Colombier fetchMsg(Box *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:
697dd7cddfSDavid du Colombier 			/*
707dd7cddfSDavid du Colombier 			 * flags get sent with status update
717dd7cddfSDavid du Colombier 			 */
727dd7cddfSDavid du Colombier 			box->sendFlags = 1;
737dd7cddfSDavid du Colombier 			m->sendFlags = 1;
747dd7cddfSDavid du Colombier 			break;
757dd7cddfSDavid du Colombier 		case FUid:
767dd7cddfSDavid du Colombier 			todo = 1;
777dd7cddfSDavid du Colombier 			break;
787dd7cddfSDavid du Colombier 		case FInternalDate:
797dd7cddfSDavid du Colombier 		case FEnvelope:
807dd7cddfSDavid du Colombier 		case FRfc822:
817dd7cddfSDavid du Colombier 		case FRfc822Head:
827dd7cddfSDavid du Colombier 		case FRfc822Size:
837dd7cddfSDavid du Colombier 		case FRfc822Text:
847dd7cddfSDavid du Colombier 		case FBodySect:
857dd7cddfSDavid du Colombier 		case FBodyPeek:
867dd7cddfSDavid du Colombier 		case FBody:
877dd7cddfSDavid du Colombier 		case FBodyStruct:
887dd7cddfSDavid du Colombier 			todo = 1;
897dd7cddfSDavid du Colombier 			if(!msgStruct(m, 1)){
907dd7cddfSDavid du Colombier 				msgDead(m);
917dd7cddfSDavid du Colombier 				return uids;
927dd7cddfSDavid du Colombier 			}
937dd7cddfSDavid du Colombier 			break;
947dd7cddfSDavid du Colombier 		default:
957dd7cddfSDavid du Colombier 			bye("bad implementation of fetch");
967dd7cddfSDavid du Colombier 			return 0;
977dd7cddfSDavid du Colombier 		}
987dd7cddfSDavid du Colombier 	}
997dd7cddfSDavid du Colombier 
1007dd7cddfSDavid du Colombier 	if(m->expunged)
1017dd7cddfSDavid du Colombier 		return uids;
1027dd7cddfSDavid du Colombier 	if(!todo)
1037dd7cddfSDavid du Colombier 		return 1;
1047dd7cddfSDavid du Colombier 
1057dd7cddfSDavid du Colombier 	/*
1067dd7cddfSDavid du Colombier 	 * note: it is allowed to send back the responses one at a time
1077dd7cddfSDavid du Colombier 	 * rather than all together.  this is exploited to send flags elsewhere.
1087dd7cddfSDavid du Colombier 	 */
1097dd7cddfSDavid du Colombier 	Bprint(&bout, "* %lud fetch (", m->seq);
1107dd7cddfSDavid du Colombier 	sep = "";
1117dd7cddfSDavid du Colombier 	if(uids){
1127dd7cddfSDavid du Colombier 		Bprint(&bout, "uid %lud", m->uid);
1137dd7cddfSDavid du Colombier 		sep = " ";
1147dd7cddfSDavid du Colombier 	}
1157dd7cddfSDavid du Colombier 	for(f = vf; f != nil; f = f->next){
1167dd7cddfSDavid du Colombier 		switch(f->op){
1177dd7cddfSDavid du Colombier 		default:
1187dd7cddfSDavid du Colombier 			bye("bad implementation of fetch");
1197dd7cddfSDavid du Colombier 			break;
1207dd7cddfSDavid du Colombier 		case FFlags:
1217dd7cddfSDavid du Colombier 			continue;
1227dd7cddfSDavid du Colombier 		case FUid:
1237dd7cddfSDavid du Colombier 			if(uids)
1247dd7cddfSDavid du Colombier 				continue;
1257dd7cddfSDavid du Colombier 			Bprint(&bout, "%suid %lud", sep, m->uid);
1267dd7cddfSDavid du Colombier 			break;
1277dd7cddfSDavid du Colombier 		case FEnvelope:
1287dd7cddfSDavid du Colombier 			Bprint(&bout, "%senvelope ", sep);
1297dd7cddfSDavid du Colombier 			fetchEnvelope(m);
1307dd7cddfSDavid du Colombier 			break;
1317dd7cddfSDavid du Colombier 		case FInternalDate:
1327dd7cddfSDavid du Colombier 			Bprint(&bout, "%sinternaldate ", sep);
1337dd7cddfSDavid du Colombier 			Bimapdate(&bout, date2tm(&tm, m->unixDate));
1347dd7cddfSDavid du Colombier 			break;
1357dd7cddfSDavid du Colombier 		case FBody:
1367dd7cddfSDavid du Colombier 			Bprint(&bout, "%sbody ", sep);
1377dd7cddfSDavid du Colombier 			fetchBodyStruct(m, &m->head, 0);
1387dd7cddfSDavid du Colombier 			break;
1397dd7cddfSDavid du Colombier 		case FBodyStruct:
1407dd7cddfSDavid du Colombier 			Bprint(&bout, "%sbodystructure ", sep);
1417dd7cddfSDavid du Colombier 			fetchBodyStruct(m, &m->head, 1);
1427dd7cddfSDavid du Colombier 			break;
1437dd7cddfSDavid du Colombier 		case FRfc822Size:
1447dd7cddfSDavid du Colombier 			Bprint(&bout, "%srfc822.size %lud", sep, msgSize(m));
1457dd7cddfSDavid du Colombier 			break;
1467dd7cddfSDavid du Colombier 		case FRfc822:
1477dd7cddfSDavid du Colombier 			f->part = FPAll;
1487dd7cddfSDavid du Colombier 			Bprint(&bout, "%srfc822", sep);
1497dd7cddfSDavid du Colombier 			fetchBody(m, f);
1507dd7cddfSDavid du Colombier 			break;
1517dd7cddfSDavid du Colombier 		case FRfc822Head:
1527dd7cddfSDavid du Colombier 			f->part = FPHead;
1537dd7cddfSDavid du Colombier 			Bprint(&bout, "%srfc822.header", sep);
1547dd7cddfSDavid du Colombier 			fetchBody(m, f);
1557dd7cddfSDavid du Colombier 			break;
1567dd7cddfSDavid du Colombier 		case FRfc822Text:
1577dd7cddfSDavid du Colombier 			f->part = FPText;
1587dd7cddfSDavid du Colombier 			Bprint(&bout, "%srfc822.text", sep);
1597dd7cddfSDavid du Colombier 			fetchBody(m, f);
1607dd7cddfSDavid du Colombier 			break;
1617dd7cddfSDavid du Colombier 		case FBodySect:
1627dd7cddfSDavid du Colombier 		case FBodyPeek:
1637dd7cddfSDavid du Colombier 			Bprint(&bout, "%sbody", sep);
1647dd7cddfSDavid du Colombier 			fetchBody(fetchSect(m, f), f);
1657dd7cddfSDavid du Colombier 			break;
1667dd7cddfSDavid du Colombier 		}
1677dd7cddfSDavid du Colombier 		sep = " ";
1687dd7cddfSDavid du Colombier 	}
1697dd7cddfSDavid du Colombier 	Bprint(&bout, ")\r\n");
1707dd7cddfSDavid du Colombier 
1717dd7cddfSDavid du Colombier 	return 1;
1727dd7cddfSDavid du Colombier }
1737dd7cddfSDavid du Colombier 
1747dd7cddfSDavid du Colombier /*
1757dd7cddfSDavid du Colombier  * print out section, part, headers;
1767dd7cddfSDavid du Colombier  * find and return message section
1777dd7cddfSDavid du Colombier  */
1787dd7cddfSDavid du Colombier Msg *
1797dd7cddfSDavid du Colombier fetchSect(Msg *m, Fetch *f)
1807dd7cddfSDavid du Colombier {
1817dd7cddfSDavid du Colombier 	Bputc(&bout, '[');
1827dd7cddfSDavid du Colombier 	BNList(&bout, f->sect, ".");
1837dd7cddfSDavid du Colombier 	if(f->part != FPAll){
1847dd7cddfSDavid du Colombier 		if(f->sect != nil)
1857dd7cddfSDavid du Colombier 			Bputc(&bout, '.');
1867dd7cddfSDavid du Colombier 		Bprint(&bout, "%s", fetchPartNames[f->part]);
1877dd7cddfSDavid du Colombier 		if(f->hdrs != nil){
1887dd7cddfSDavid du Colombier 			Bprint(&bout, " (");
1897dd7cddfSDavid du Colombier 			BSList(&bout, f->hdrs, " ");
1907dd7cddfSDavid du Colombier 			Bputc(&bout, ')');
1917dd7cddfSDavid du Colombier 		}
1927dd7cddfSDavid du Colombier 	}
1937dd7cddfSDavid du Colombier 	Bprint(&bout, "]");
1947dd7cddfSDavid du Colombier 	return findMsgSect(m, f->sect);
1957dd7cddfSDavid du Colombier }
1967dd7cddfSDavid du Colombier 
1977dd7cddfSDavid du Colombier /*
1987dd7cddfSDavid du Colombier  * actually return the body pieces
1997dd7cddfSDavid du Colombier  */
2007dd7cddfSDavid du Colombier void
2017dd7cddfSDavid du Colombier fetchBody(Msg *m, Fetch *f)
2027dd7cddfSDavid du Colombier {
2037dd7cddfSDavid du Colombier 	Pair p;
2047dd7cddfSDavid du Colombier 	char *s, *t, *e, buf[BufSize + 2];
2057dd7cddfSDavid du Colombier 	ulong n, start, stop, pos;
2067dd7cddfSDavid du Colombier 	int fd, nn;
2077dd7cddfSDavid du Colombier 
2087dd7cddfSDavid du Colombier 	if(m == nil){
2097dd7cddfSDavid du Colombier 		fetchBodyStr(f, "", 0);
2107dd7cddfSDavid du Colombier 		return;
2117dd7cddfSDavid du Colombier 	}
2127dd7cddfSDavid du Colombier 	switch(f->part){
2137dd7cddfSDavid du Colombier 	case FPHeadFields:
2147dd7cddfSDavid du Colombier 	case FPHeadFieldsNot:
2157dd7cddfSDavid du Colombier 		n = m->head.size + 3;
2167dd7cddfSDavid du Colombier 		s = emalloc(n);
2177dd7cddfSDavid du Colombier 		n = selectFields(s, n, m->head.buf, f->hdrs, f->part == FPHeadFields);
2187dd7cddfSDavid du Colombier 		fetchBodyStr(f, s, n);
2197dd7cddfSDavid du Colombier 		free(s);
2207dd7cddfSDavid du Colombier 		return;
2217dd7cddfSDavid du Colombier 	case FPHead:
2227dd7cddfSDavid du Colombier 		fetchBodyStr(f, m->head.buf, m->head.size);
2237dd7cddfSDavid du Colombier 		return;
2247dd7cddfSDavid du Colombier 	case FPMime:
2257dd7cddfSDavid du Colombier 		fetchBodyStr(f, m->mime.buf, m->mime.size);
2267dd7cddfSDavid du Colombier 		return;
2277dd7cddfSDavid du Colombier 	case FPAll:
2287dd7cddfSDavid du Colombier 		fd = msgFile(m, "rawbody");
2297dd7cddfSDavid du Colombier 		if(fd < 0){
2307dd7cddfSDavid du Colombier 			msgDead(m);
2317dd7cddfSDavid du Colombier 			fetchBodyStr(f, "", 0);
2327dd7cddfSDavid du Colombier 			return;
2337dd7cddfSDavid du Colombier 		}
2347dd7cddfSDavid du Colombier 		p = fetchBodyPart(f, msgSize(m));
2357dd7cddfSDavid du Colombier 		start = p.start;
2367dd7cddfSDavid du Colombier 		if(start < m->head.size){
2377dd7cddfSDavid du Colombier 			stop = p.stop;
2387dd7cddfSDavid du Colombier 			if(stop > m->head.size)
2397dd7cddfSDavid du Colombier 				stop = m->head.size;
2407dd7cddfSDavid du Colombier 			Bwrite(&bout, &m->head.buf[start], stop - start);
2417dd7cddfSDavid du Colombier 			start = 0;
2427dd7cddfSDavid du Colombier 			stop = p.stop;
2437dd7cddfSDavid du Colombier 			if(stop <= m->head.size){
2447dd7cddfSDavid du Colombier 				close(fd);
2457dd7cddfSDavid du Colombier 				return;
2467dd7cddfSDavid du Colombier 			}
2477dd7cddfSDavid du Colombier 		}else
2487dd7cddfSDavid du Colombier 			start -= m->head.size;
2497dd7cddfSDavid du Colombier 		stop = p.stop - m->head.size;
2507dd7cddfSDavid du Colombier 		break;
2517dd7cddfSDavid du Colombier 	case FPText:
2527dd7cddfSDavid du Colombier 		fd = msgFile(m, "rawbody");
2537dd7cddfSDavid du Colombier 		if(fd < 0){
2547dd7cddfSDavid du Colombier 			msgDead(m);
2557dd7cddfSDavid du Colombier 			fetchBodyStr(f, "", 0);
2567dd7cddfSDavid du Colombier 			return;
2577dd7cddfSDavid du Colombier 		}
2587dd7cddfSDavid du Colombier 		p = fetchBodyPart(f, m->size);
2597dd7cddfSDavid du Colombier 		start = p.start;
2607dd7cddfSDavid du Colombier 		stop = p.stop;
2617dd7cddfSDavid du Colombier 		break;
2627dd7cddfSDavid du Colombier 	default:
2637dd7cddfSDavid du Colombier 		fetchBodyStr(f, "", 0);
2647dd7cddfSDavid du Colombier 		return;
2657dd7cddfSDavid du Colombier 	}
2667dd7cddfSDavid du Colombier 
2677dd7cddfSDavid du Colombier 	/*
2687dd7cddfSDavid du Colombier 	 * read in each block, convert \n without \r to \r\n.
2697dd7cddfSDavid du Colombier 	 * this means partial fetch requires fetching everything
2707dd7cddfSDavid du Colombier 	 * through stop, since we don't know how many \r's will be added
2717dd7cddfSDavid du Colombier 	 */
2727dd7cddfSDavid du Colombier 	buf[0] = ' ';
2737dd7cddfSDavid du Colombier 	for(pos = 0; pos < stop; ){
2747dd7cddfSDavid du Colombier 		n = BufSize;
2757dd7cddfSDavid du Colombier 		if(n > stop - pos)
2767dd7cddfSDavid du Colombier 			n = stop - pos;
2777dd7cddfSDavid du Colombier 		n = read(fd, &buf[1], n);
2787dd7cddfSDavid du Colombier 		if(n <= 0){
2797dd7cddfSDavid du Colombier 			fetchBodyFill(stop - pos);
2807dd7cddfSDavid du Colombier 			break;
2817dd7cddfSDavid du Colombier 		}
2827dd7cddfSDavid du Colombier 		e = &buf[n + 1];
2837dd7cddfSDavid du Colombier 		*e = '\0';
2847dd7cddfSDavid du Colombier 		for(s = &buf[1]; s < e && pos < stop; s = t + 1){
2857dd7cddfSDavid du Colombier 			t = memchr(s, '\n', e - s);
2867dd7cddfSDavid du Colombier 			if(t == nil)
2877dd7cddfSDavid du Colombier 				t = e;
2887dd7cddfSDavid du Colombier 			n = t - s;
2897dd7cddfSDavid du Colombier 			if(pos < start){
2907dd7cddfSDavid du Colombier 				if(pos + n <= start){
2917dd7cddfSDavid du Colombier 					s = t;
2927dd7cddfSDavid du Colombier 					pos += n;
2937dd7cddfSDavid du Colombier 				}else{
2947dd7cddfSDavid du Colombier 					s += start - pos;
2957dd7cddfSDavid du Colombier 					pos = start;
2967dd7cddfSDavid du Colombier 				}
2977dd7cddfSDavid du Colombier 				n = t - s;
2987dd7cddfSDavid du Colombier 			}
2997dd7cddfSDavid du Colombier 			nn = n;
3007dd7cddfSDavid du Colombier 			if(pos + nn > stop)
3017dd7cddfSDavid du Colombier 				nn = stop - pos;
3027dd7cddfSDavid du Colombier 			if(Bwrite(&bout, s, nn) != nn)
3037dd7cddfSDavid du Colombier 				writeErr();
3047dd7cddfSDavid du Colombier 			pos += n;
3057dd7cddfSDavid du Colombier 			if(*t == '\n'){
3067dd7cddfSDavid du Colombier 				if(t[-1] != '\r'){
3077dd7cddfSDavid du Colombier 					if(pos >= start && pos < stop)
3087dd7cddfSDavid du Colombier 						Bputc(&bout, '\r');
3097dd7cddfSDavid du Colombier 					pos++;
3107dd7cddfSDavid du Colombier 				}
3117dd7cddfSDavid du Colombier 				if(pos >= start && pos < stop)
3127dd7cddfSDavid du Colombier 					Bputc(&bout, '\n');
3137dd7cddfSDavid du Colombier 				pos++;
3147dd7cddfSDavid du Colombier 			}
3157dd7cddfSDavid du Colombier 		}
3167dd7cddfSDavid du Colombier 		buf[0] = e[-1];
3177dd7cddfSDavid du Colombier 	}
3187dd7cddfSDavid du Colombier 	close(fd);
3197dd7cddfSDavid du Colombier }
3207dd7cddfSDavid du Colombier 
3217dd7cddfSDavid du Colombier /*
3227dd7cddfSDavid du Colombier  * resolve the actual bounds of any partial fetch,
3237dd7cddfSDavid du Colombier  * and print out the bounds & size of string returned
3247dd7cddfSDavid du Colombier  */
3257dd7cddfSDavid du Colombier Pair
3267dd7cddfSDavid du Colombier fetchBodyPart(Fetch *f, ulong size)
3277dd7cddfSDavid du Colombier {
3287dd7cddfSDavid du Colombier 	Pair p;
3297dd7cddfSDavid du Colombier 	ulong start, stop;
3307dd7cddfSDavid du Colombier 
3317dd7cddfSDavid du Colombier 	start = 0;
3327dd7cddfSDavid du Colombier 	stop = size;
3337dd7cddfSDavid du Colombier 	if(f->partial){
3347dd7cddfSDavid du Colombier 		start = f->start;
3357dd7cddfSDavid du Colombier 		if(start > size)
3367dd7cddfSDavid du Colombier 			start = size;
3377dd7cddfSDavid du Colombier 		stop = start + f->size;
3387dd7cddfSDavid du Colombier 		if(stop > size)
3397dd7cddfSDavid du Colombier 			stop = size;
3407dd7cddfSDavid du Colombier 		Bprint(&bout, "<%lud>", start);
3417dd7cddfSDavid du Colombier 	}
3427dd7cddfSDavid du Colombier 	Bprint(&bout, " {%lud}\r\n", stop - start);
3437dd7cddfSDavid du Colombier 	p.start = start;
3447dd7cddfSDavid du Colombier 	p.stop = stop;
3457dd7cddfSDavid du Colombier 	return p;
3467dd7cddfSDavid du Colombier }
3477dd7cddfSDavid du Colombier 
3487dd7cddfSDavid du Colombier /*
3497dd7cddfSDavid du Colombier  * something went wrong fetching data
3507dd7cddfSDavid du Colombier  * produce fill bytes for what we've committed to produce
3517dd7cddfSDavid du Colombier  */
3527dd7cddfSDavid du Colombier void
3537dd7cddfSDavid du Colombier fetchBodyFill(ulong n)
3547dd7cddfSDavid du Colombier {
3557dd7cddfSDavid du Colombier 	while(n-- > 0)
3567dd7cddfSDavid du Colombier 		if(Bputc(&bout, ' ') < 0)
3577dd7cddfSDavid du Colombier 			writeErr();
3587dd7cddfSDavid du Colombier }
3597dd7cddfSDavid du Colombier 
3607dd7cddfSDavid du Colombier /*
3617dd7cddfSDavid du Colombier  * return a simple string
3627dd7cddfSDavid du Colombier  */
3637dd7cddfSDavid du Colombier void
3647dd7cddfSDavid du Colombier fetchBodyStr(Fetch *f, char *buf, ulong size)
3657dd7cddfSDavid du Colombier {
3667dd7cddfSDavid du Colombier 	Pair p;
3677dd7cddfSDavid du Colombier 
3687dd7cddfSDavid du Colombier 	p = fetchBodyPart(f, size);
3697dd7cddfSDavid du Colombier 	Bwrite(&bout, &buf[p.start], p.stop-p.start);
3707dd7cddfSDavid du Colombier }
3717dd7cddfSDavid du Colombier 
372*9a747e4fSDavid du Colombier char*
373*9a747e4fSDavid du Colombier printnlist(NList *sect)
374*9a747e4fSDavid du Colombier {
375*9a747e4fSDavid du Colombier 	static char buf[100];
376*9a747e4fSDavid du Colombier 	char *p;
377*9a747e4fSDavid du Colombier 
378*9a747e4fSDavid du Colombier 	for(p= buf; sect; sect=sect->next){
379*9a747e4fSDavid du Colombier 		p += sprint(p, "%ld", sect->n);
380*9a747e4fSDavid du Colombier 		if(sect->next)
381*9a747e4fSDavid du Colombier 			*p++ = '.';
382*9a747e4fSDavid du Colombier 	}
383*9a747e4fSDavid du Colombier 	*p = '\0';
384*9a747e4fSDavid du Colombier 	return buf;
385*9a747e4fSDavid du Colombier }
386*9a747e4fSDavid du Colombier 
3877dd7cddfSDavid du Colombier /*
3887dd7cddfSDavid du Colombier  * find the numbered sub-part of the message
3897dd7cddfSDavid du Colombier  */
3907dd7cddfSDavid du Colombier Msg*
3917dd7cddfSDavid du Colombier findMsgSect(Msg *m, NList *sect)
3927dd7cddfSDavid du Colombier {
3937dd7cddfSDavid du Colombier 	ulong id;
3947dd7cddfSDavid du Colombier 
3957dd7cddfSDavid du Colombier 	for(; sect != nil; sect = sect->next){
3967dd7cddfSDavid du Colombier 		id = sect->n;
397*9a747e4fSDavid du Colombier #ifdef HACK
398*9a747e4fSDavid du Colombier 		/* HACK to solve extra level of structure not visible from upas/fs  */
399*9a747e4fSDavid du Colombier 		if(m->kids == 0 && id == 1 && sect->next == nil){
400*9a747e4fSDavid du Colombier 			if(m->mime.type->s && strcmp(m->mime.type->s, "message")==0)
401*9a747e4fSDavid du Colombier 			if(m->mime.type->t && strcmp(m->mime.type->t, "rfc822")==0)
402*9a747e4fSDavid du Colombier 			if(m->head.type->s && strcmp(m->head.type->s, "text")==0)
403*9a747e4fSDavid du Colombier 			if(m->head.type->t && strcmp(m->head.type->t, "plain")==0)
404*9a747e4fSDavid du Colombier 				break;
405*9a747e4fSDavid du Colombier 		}
406*9a747e4fSDavid du Colombier 		/* end of HACK */
407*9a747e4fSDavid du Colombier #endif HACK
4087dd7cddfSDavid du Colombier 		for(m = m->kids; m != nil; m = m->next)
4097dd7cddfSDavid du Colombier 			if(m->id == id)
4107dd7cddfSDavid du Colombier 				break;
4117dd7cddfSDavid du Colombier 		if(m == nil)
4127dd7cddfSDavid du Colombier 			return nil;
4137dd7cddfSDavid du Colombier 	}
4147dd7cddfSDavid du Colombier 	return m;
4157dd7cddfSDavid du Colombier }
4167dd7cddfSDavid du Colombier 
4177dd7cddfSDavid du Colombier void
4187dd7cddfSDavid du Colombier fetchEnvelope(Msg *m)
4197dd7cddfSDavid du Colombier {
4207dd7cddfSDavid du Colombier 	Tm tm;
4217dd7cddfSDavid du Colombier 
4227dd7cddfSDavid du Colombier 	Bputc(&bout, '(');
4237dd7cddfSDavid du Colombier 	Brfc822date(&bout, date2tm(&tm, m->info[IDate]));
4247dd7cddfSDavid du Colombier 	Bputc(&bout, ' ');
4257dd7cddfSDavid du Colombier 	Bimapstr(&bout, m->info[ISubject]);
4267dd7cddfSDavid du Colombier 	Bputc(&bout, ' ');
4277dd7cddfSDavid du Colombier 	Bimapaddr(&bout, m->from);
4287dd7cddfSDavid du Colombier 	Bputc(&bout, ' ');
4297dd7cddfSDavid du Colombier 	Bimapaddr(&bout, m->sender);
4307dd7cddfSDavid du Colombier 	Bputc(&bout, ' ');
4317dd7cddfSDavid du Colombier 	Bimapaddr(&bout, m->replyTo);
4327dd7cddfSDavid du Colombier 	Bputc(&bout, ' ');
4337dd7cddfSDavid du Colombier 	Bimapaddr(&bout, m->to);
4347dd7cddfSDavid du Colombier 	Bputc(&bout, ' ');
4357dd7cddfSDavid du Colombier 	Bimapaddr(&bout, m->cc);
4367dd7cddfSDavid du Colombier 	Bputc(&bout, ' ');
4377dd7cddfSDavid du Colombier 	Bimapaddr(&bout, m->bcc);
4387dd7cddfSDavid du Colombier 	Bputc(&bout, ' ');
4397dd7cddfSDavid du Colombier 	Bimapstr(&bout, m->info[IInReplyTo]);
4407dd7cddfSDavid du Colombier 	Bputc(&bout, ' ');
4417dd7cddfSDavid du Colombier 	Bimapstr(&bout, m->info[IMessageId]);
4427dd7cddfSDavid du Colombier 	Bputc(&bout, ')');
4437dd7cddfSDavid du Colombier }
4447dd7cddfSDavid du Colombier 
4457dd7cddfSDavid du Colombier void
4467dd7cddfSDavid du Colombier fetchBodyStruct(Msg *m, Header *h, int extensions)
4477dd7cddfSDavid du Colombier {
4487dd7cddfSDavid du Colombier 	Msg *k;
4497dd7cddfSDavid du Colombier 	ulong len;
4507dd7cddfSDavid du Colombier 
4517dd7cddfSDavid du Colombier 	if(msgIsMulti(h)){
4527dd7cddfSDavid du Colombier 		Bputc(&bout, '(');
4537dd7cddfSDavid du Colombier 		for(k = m->kids; k != nil; k = k->next)
4547dd7cddfSDavid du Colombier 			fetchBodyStruct(k, &k->mime, extensions);
4557dd7cddfSDavid du Colombier 
4567dd7cddfSDavid du Colombier 		Bputc(&bout, ' ');
4577dd7cddfSDavid du Colombier 		Bimapstr(&bout, h->type->t);
4587dd7cddfSDavid du Colombier 
4597dd7cddfSDavid du Colombier 		if(extensions){
4607dd7cddfSDavid du Colombier 			Bputc(&bout, ' ');
4617dd7cddfSDavid du Colombier 			BimapMimeParams(&bout, h->type->next);
4627dd7cddfSDavid du Colombier 			fetchStructExt(h);
4637dd7cddfSDavid du Colombier 		}
4647dd7cddfSDavid du Colombier 
4657dd7cddfSDavid du Colombier 		Bputc(&bout, ')');
4667dd7cddfSDavid du Colombier 		return;
4677dd7cddfSDavid du Colombier 	}
4687dd7cddfSDavid du Colombier 
4697dd7cddfSDavid du Colombier 	Bputc(&bout, '(');
4707dd7cddfSDavid du Colombier 	if(h->type != nil){
4717dd7cddfSDavid du Colombier 		Bimapstr(&bout, h->type->s);
4727dd7cddfSDavid du Colombier 		Bputc(&bout, ' ');
4737dd7cddfSDavid du Colombier 		Bimapstr(&bout, h->type->t);
4747dd7cddfSDavid du Colombier 		Bputc(&bout, ' ');
4757dd7cddfSDavid du Colombier 		BimapMimeParams(&bout, h->type->next);
4767dd7cddfSDavid du Colombier 	}else
4777dd7cddfSDavid du Colombier 		Bprint(&bout, "\"text\" \"plain\" NIL");
4787dd7cddfSDavid du Colombier 
4797dd7cddfSDavid du Colombier 	Bputc(&bout, ' ');
4807dd7cddfSDavid du Colombier 	if(h->id != nil)
4817dd7cddfSDavid du Colombier 		Bimapstr(&bout, h->id->s);
4827dd7cddfSDavid du Colombier 	else
4837dd7cddfSDavid du Colombier 		Bprint(&bout, "NIL");
4847dd7cddfSDavid du Colombier 
4857dd7cddfSDavid du Colombier 	Bputc(&bout, ' ');
4867dd7cddfSDavid du Colombier 	if(h->description != nil)
4877dd7cddfSDavid du Colombier 		Bimapstr(&bout, h->description->s);
4887dd7cddfSDavid du Colombier 	else
4897dd7cddfSDavid du Colombier 		Bprint(&bout, "NIL");
4907dd7cddfSDavid du Colombier 
4917dd7cddfSDavid du Colombier 	Bputc(&bout, ' ');
4927dd7cddfSDavid du Colombier 	if(h->encoding != nil)
4937dd7cddfSDavid du Colombier 		Bimapstr(&bout, h->encoding->s);
4947dd7cddfSDavid du Colombier 	else
4957dd7cddfSDavid du Colombier 		Bprint(&bout, "NIL");
4967dd7cddfSDavid du Colombier 
4977dd7cddfSDavid du Colombier 	/*
4987dd7cddfSDavid du Colombier 	 * this is so strange: return lengths for a body[text] response,
499*9a747e4fSDavid du Colombier 	 * except in the case of a multipart message, when return lengths for a body[] response
5007dd7cddfSDavid du Colombier 	 */
5017dd7cddfSDavid du Colombier 	len = m->size;
5027dd7cddfSDavid du Colombier 	if(h == &m->mime)
5037dd7cddfSDavid du Colombier 		len += m->head.size;
5047dd7cddfSDavid du Colombier 	Bprint(&bout, " %lud", len);
5057dd7cddfSDavid du Colombier 
5067dd7cddfSDavid du Colombier 	len = m->lines;
5077dd7cddfSDavid du Colombier 	if(h == &m->mime)
5087dd7cddfSDavid du Colombier 		len += m->head.lines;
5097dd7cddfSDavid du Colombier 
5107dd7cddfSDavid du Colombier 	if(h->type == nil || cistrcmp(h->type->s, "text") == 0){
5117dd7cddfSDavid du Colombier 		Bprint(&bout, " %lud", len);
5127dd7cddfSDavid du Colombier 	}else if(msgIsRfc822(h)){
5137dd7cddfSDavid du Colombier 		Bputc(&bout, ' ');
5147dd7cddfSDavid du Colombier 		k = m;
5157dd7cddfSDavid du Colombier 		if(h != &m->mime)
5167dd7cddfSDavid du Colombier 			k = m->kids;
5177dd7cddfSDavid du Colombier 		if(k == nil)
5187dd7cddfSDavid du Colombier 			Bprint(&bout, "(NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL) (\"text\" \"plain\" NIL NIL NIL NIL 0 0) 0");
5197dd7cddfSDavid du Colombier 		else{
5207dd7cddfSDavid du Colombier 			fetchEnvelope(k);
5217dd7cddfSDavid du Colombier 			Bputc(&bout, ' ');
5227dd7cddfSDavid du Colombier 			fetchBodyStruct(k, &k->head, extensions);
5237dd7cddfSDavid du Colombier 			Bprint(&bout, " %lud", len);
5247dd7cddfSDavid du Colombier 		}
5257dd7cddfSDavid du Colombier 	}
5267dd7cddfSDavid du Colombier 
5277dd7cddfSDavid du Colombier 	if(extensions){
5287dd7cddfSDavid du Colombier 		Bputc(&bout, ' ');
5297dd7cddfSDavid du Colombier 
5307dd7cddfSDavid du Colombier 		/*
5317dd7cddfSDavid du Colombier 		 * don't have the md5 laying around,
5327dd7cddfSDavid du Colombier 		 * since the header & body have added newlines.
5337dd7cddfSDavid du Colombier 		 */
5347dd7cddfSDavid du Colombier 		Bprint(&bout, "NIL");
5357dd7cddfSDavid du Colombier 
5367dd7cddfSDavid du Colombier 		fetchStructExt(h);
5377dd7cddfSDavid du Colombier 	}
5387dd7cddfSDavid du Colombier 	Bputc(&bout, ')');
5397dd7cddfSDavid du Colombier }
5407dd7cddfSDavid du Colombier 
5417dd7cddfSDavid du Colombier /*
5427dd7cddfSDavid du Colombier  * common part of bodystructure extensions
5437dd7cddfSDavid du Colombier  */
5447dd7cddfSDavid du Colombier void
5457dd7cddfSDavid du Colombier fetchStructExt(Header *h)
5467dd7cddfSDavid du Colombier {
5477dd7cddfSDavid du Colombier 	Bputc(&bout, ' ');
5487dd7cddfSDavid du Colombier 	if(h->disposition != nil){
5497dd7cddfSDavid du Colombier 		Bputc(&bout, '(');
5507dd7cddfSDavid du Colombier 		Bimapstr(&bout, h->disposition->s);
5517dd7cddfSDavid du Colombier 		Bputc(&bout, ' ');
5527dd7cddfSDavid du Colombier 		BimapMimeParams(&bout, h->disposition->next);
5537dd7cddfSDavid du Colombier 		Bputc(&bout, ')');
5547dd7cddfSDavid du Colombier 	}else
5557dd7cddfSDavid du Colombier 		Bprint(&bout, "NIL");
5567dd7cddfSDavid du Colombier 	Bputc(&bout, ' ');
5577dd7cddfSDavid du Colombier 	if(h->language != nil){
5587dd7cddfSDavid du Colombier 		if(h->language->next != nil)
5597dd7cddfSDavid du Colombier 			BimapMimeParams(&bout, h->language->next);
5607dd7cddfSDavid du Colombier 		else
5617dd7cddfSDavid du Colombier 			Bimapstr(&bout, h->language->s);
5627dd7cddfSDavid du Colombier 	}else
5637dd7cddfSDavid du Colombier 		Bprint(&bout, "NIL");
5647dd7cddfSDavid du Colombier }
5657dd7cddfSDavid du Colombier 
5667dd7cddfSDavid du Colombier int
5677dd7cddfSDavid du Colombier BimapMimeParams(Biobuf *b, MimeHdr *mh)
5687dd7cddfSDavid du Colombier {
5697dd7cddfSDavid du Colombier 	char *sep;
5707dd7cddfSDavid du Colombier 	int n;
5717dd7cddfSDavid du Colombier 
5727dd7cddfSDavid du Colombier 	if(mh == nil)
5737dd7cddfSDavid du Colombier 		return Bprint(b, "NIL");
5747dd7cddfSDavid du Colombier 
5757dd7cddfSDavid du Colombier 	n = Bputc(b, '(');
5767dd7cddfSDavid du Colombier 
5777dd7cddfSDavid du Colombier 	sep = "";
5787dd7cddfSDavid du Colombier 	for(; mh != nil; mh = mh->next){
5797dd7cddfSDavid du Colombier 		n += Bprint(b, sep);
5807dd7cddfSDavid du Colombier 		n += Bimapstr(b, mh->s);
5817dd7cddfSDavid du Colombier 		n += Bputc(b, ' ');
5827dd7cddfSDavid du Colombier 		n += Bimapstr(b, mh->t);
5837dd7cddfSDavid du Colombier 		sep = " ";
5847dd7cddfSDavid du Colombier 	}
5857dd7cddfSDavid du Colombier 
5867dd7cddfSDavid du Colombier 	n += Bputc(b, ')');
5877dd7cddfSDavid du Colombier 	return n;
5887dd7cddfSDavid du Colombier }
5897dd7cddfSDavid du Colombier 
5907dd7cddfSDavid du Colombier /*
5917dd7cddfSDavid du Colombier  * print a list of addresses;
5927dd7cddfSDavid du Colombier  * each address is printed as '(' personalName AtDomainList mboxName hostName ')'
5937dd7cddfSDavid du Colombier  * the AtDomainList is always NIL
5947dd7cddfSDavid du Colombier  */
5957dd7cddfSDavid du Colombier int
5967dd7cddfSDavid du Colombier Bimapaddr(Biobuf *b, MAddr *a)
5977dd7cddfSDavid du Colombier {
5987dd7cddfSDavid du Colombier 	char *host, *sep;
5997dd7cddfSDavid du Colombier 	int n;
6007dd7cddfSDavid du Colombier 
6017dd7cddfSDavid du Colombier 	if(a == nil)
6027dd7cddfSDavid du Colombier 		return Bprint(b, "NIL");
6037dd7cddfSDavid du Colombier 
6047dd7cddfSDavid du Colombier 	n = Bputc(b, '(');
6057dd7cddfSDavid du Colombier 	sep = "";
6067dd7cddfSDavid du Colombier 	for(; a != nil; a = a->next){
6077dd7cddfSDavid du Colombier 		n += Bprint(b, "%s(", sep);
6087dd7cddfSDavid du Colombier 		n += Bimapstr(b, a->personal);
6097dd7cddfSDavid du Colombier 		n += Bprint(b," NIL ");
6107dd7cddfSDavid du Colombier 		n += Bimapstr(b, a->box);
6117dd7cddfSDavid du Colombier 		n += Bputc(b, ' ');
6127dd7cddfSDavid du Colombier 
6137dd7cddfSDavid du Colombier 		/*
6147dd7cddfSDavid du Colombier 		 * can't send NIL as hostName, since that is code for a group
6157dd7cddfSDavid du Colombier 		 */
6167dd7cddfSDavid du Colombier 		host = a->host;
6177dd7cddfSDavid du Colombier 		if(host == nil)
6187dd7cddfSDavid du Colombier 			host = "";
6197dd7cddfSDavid du Colombier 		n += Bimapstr(b, host);
6207dd7cddfSDavid du Colombier 
6217dd7cddfSDavid du Colombier 		n += Bputc(b, ')');
6227dd7cddfSDavid du Colombier 		sep = " ";
6237dd7cddfSDavid du Colombier 	}
6247dd7cddfSDavid du Colombier 	n += Bputc(b, ')');
6257dd7cddfSDavid du Colombier 	return n;
6267dd7cddfSDavid du Colombier }
627