xref: /plan9/sys/src/cmd/faces/plumb.c (revision b85a83648eec38fe82b6f00adfd7828ceec5ee8d)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <draw.h>
47dd7cddfSDavid du Colombier #include <plumb.h>
57dd7cddfSDavid du Colombier #include <regexp.h>
67dd7cddfSDavid du Colombier #include <bio.h>
77dd7cddfSDavid du Colombier #include "faces.h"
87dd7cddfSDavid du Colombier 
97dd7cddfSDavid du Colombier static int		showfd = -1;
107dd7cddfSDavid du Colombier static int		seefd = -1;
117dd7cddfSDavid du Colombier static int		logfd = -1;
127dd7cddfSDavid du Colombier static char	*user;
137dd7cddfSDavid du Colombier static char	*logtag;
14*a3b78ba5SDavid du Colombier 
15*a3b78ba5SDavid du Colombier char		**maildirs;
16*a3b78ba5SDavid du Colombier int		nmaildirs;
177dd7cddfSDavid du Colombier 
187dd7cddfSDavid du Colombier void
initplumb(void)197dd7cddfSDavid du Colombier initplumb(void)
207dd7cddfSDavid du Colombier {
217dd7cddfSDavid du Colombier 	showfd = plumbopen("send", OWRITE);
227dd7cddfSDavid du Colombier 	seefd = plumbopen("seemail", OREAD);
237dd7cddfSDavid du Colombier 
247dd7cddfSDavid du Colombier 	if(seefd < 0){
257dd7cddfSDavid du Colombier 		logfd = open("/sys/log/mail", OREAD);
267dd7cddfSDavid du Colombier 		seek(logfd, 0LL, 2);
277dd7cddfSDavid du Colombier 		user = getenv("user");
287dd7cddfSDavid du Colombier 		if(user == nil){
297dd7cddfSDavid du Colombier 			fprint(2, "faces: can't find user name: %r\n");
307dd7cddfSDavid du Colombier 			exits("$user");
317dd7cddfSDavid du Colombier 		}
327dd7cddfSDavid du Colombier 		logtag = emalloc(32+strlen(user)+1);
337dd7cddfSDavid du Colombier 		sprint(logtag, " delivered %s From ", user);
347dd7cddfSDavid du Colombier 	}
357dd7cddfSDavid du Colombier }
367dd7cddfSDavid du Colombier 
375fab9909SDavid du Colombier void
addmaildir(char * dir)385fab9909SDavid du Colombier addmaildir(char *dir)
395fab9909SDavid du Colombier {
405fab9909SDavid du Colombier 	maildirs = erealloc(maildirs, (nmaildirs+1)*sizeof(char*));
415fab9909SDavid du Colombier 	maildirs[nmaildirs++] = dir;
425fab9909SDavid du Colombier }
435fab9909SDavid du Colombier 
447dd7cddfSDavid du Colombier char*
attr(Face * f)457dd7cddfSDavid du Colombier attr(Face *f)
467dd7cddfSDavid du Colombier {
477dd7cddfSDavid du Colombier 	static char buf[128];
487dd7cddfSDavid du Colombier 
497dd7cddfSDavid du Colombier 	if(f->str[Sdigest]){
507dd7cddfSDavid du Colombier 		snprint(buf, sizeof buf, "digest=%s", f->str[Sdigest]);
517dd7cddfSDavid du Colombier 		return buf;
527dd7cddfSDavid du Colombier 	}
537dd7cddfSDavid du Colombier 	return nil;
547dd7cddfSDavid du Colombier }
557dd7cddfSDavid du Colombier 
567dd7cddfSDavid du Colombier void
showmail(Face * f)577dd7cddfSDavid du Colombier showmail(Face *f)
587dd7cddfSDavid du Colombier {
597dd7cddfSDavid du Colombier 	char *s;
607dd7cddfSDavid du Colombier 	int n;
617dd7cddfSDavid du Colombier 
627dd7cddfSDavid du Colombier 	if(showfd<0 || f->str[Sshow]==nil || f->str[Sshow][0]=='\0')
637dd7cddfSDavid du Colombier 		return;
647dd7cddfSDavid du Colombier 	s = emalloc(128+strlen(f->str[Sshow])+1);
657dd7cddfSDavid du Colombier 	n = sprint(s, "faces\nshowmail\n/mail/fs/\ntext\n%s\n%ld\n%s", attr(f), strlen(f->str[Sshow]), f->str[Sshow]);
667dd7cddfSDavid du Colombier 	write(showfd, s, n);
677dd7cddfSDavid du Colombier 	free(s);
687dd7cddfSDavid du Colombier }
697dd7cddfSDavid du Colombier 
707dd7cddfSDavid du Colombier char*
value(Plumbattr * attr,char * key,char * def)717dd7cddfSDavid du Colombier value(Plumbattr *attr, char *key, char *def)
727dd7cddfSDavid du Colombier {
737dd7cddfSDavid du Colombier 	char *v;
747dd7cddfSDavid du Colombier 
757dd7cddfSDavid du Colombier 	v = plumblookup(attr, key);
767dd7cddfSDavid du Colombier 	if(v)
777dd7cddfSDavid du Colombier 		return v;
787dd7cddfSDavid du Colombier 	return def;
797dd7cddfSDavid du Colombier }
807dd7cddfSDavid du Colombier 
817dd7cddfSDavid du Colombier void
setname(Face * f,char * sender)827dd7cddfSDavid du Colombier setname(Face *f, char *sender)
837dd7cddfSDavid du Colombier {
847dd7cddfSDavid du Colombier 	char *at, *bang;
857dd7cddfSDavid du Colombier 	char *p;
867dd7cddfSDavid du Colombier 
877dd7cddfSDavid du Colombier 	/* works with UTF-8, although it's written as ASCII */
887dd7cddfSDavid du Colombier 	for(p=sender; *p!='\0'; p++)
897dd7cddfSDavid du Colombier 		*p = tolower(*p);
907dd7cddfSDavid du Colombier 	f->str[Suser] = sender;
917dd7cddfSDavid du Colombier 	at = strchr(sender, '@');
927dd7cddfSDavid du Colombier 	if(at){
937dd7cddfSDavid du Colombier 		*at++ = '\0';
947dd7cddfSDavid du Colombier 		f->str[Sdomain] = estrdup(at);
957dd7cddfSDavid du Colombier 		return;
967dd7cddfSDavid du Colombier 	}
977dd7cddfSDavid du Colombier 	bang = strchr(sender, '!');
987dd7cddfSDavid du Colombier 	if(bang){
997dd7cddfSDavid du Colombier 		*bang++ = '\0';
1007dd7cddfSDavid du Colombier 		f->str[Suser] = estrdup(bang);
1017dd7cddfSDavid du Colombier 		f->str[Sdomain] = sender;
1027dd7cddfSDavid du Colombier 		return;
1037dd7cddfSDavid du Colombier 	}
1047dd7cddfSDavid du Colombier }
1057dd7cddfSDavid du Colombier 
1067dd7cddfSDavid du Colombier int
getc(void)1077dd7cddfSDavid du Colombier getc(void)
1087dd7cddfSDavid du Colombier {
1097dd7cddfSDavid du Colombier 	static uchar buf[512];
1107dd7cddfSDavid du Colombier 	static int nbuf = 0;
1117dd7cddfSDavid du Colombier 	static int i = 0;
1127dd7cddfSDavid du Colombier 
1137dd7cddfSDavid du Colombier 	while(i == nbuf){
1147dd7cddfSDavid du Colombier 		i = 0;
1157dd7cddfSDavid du Colombier 		nbuf = read(logfd, buf, sizeof buf);
1167dd7cddfSDavid du Colombier 		if(nbuf == 0){
1177dd7cddfSDavid du Colombier 			sleep(15000);
1187dd7cddfSDavid du Colombier 			continue;
1197dd7cddfSDavid du Colombier 		}
1207dd7cddfSDavid du Colombier 		if(nbuf < 0)
1217dd7cddfSDavid du Colombier 			return -1;
1227dd7cddfSDavid du Colombier 	}
1237dd7cddfSDavid du Colombier 	return buf[i++];
1247dd7cddfSDavid du Colombier }
1257dd7cddfSDavid du Colombier 
1267dd7cddfSDavid du Colombier char*
getline(char * buf,int n)1277dd7cddfSDavid du Colombier getline(char *buf, int n)
1287dd7cddfSDavid du Colombier {
1297dd7cddfSDavid du Colombier 	int i, c;
1307dd7cddfSDavid du Colombier 
1317dd7cddfSDavid du Colombier 	for(i=0; i<n-1; i++){
1327dd7cddfSDavid du Colombier 		c = getc();
1337dd7cddfSDavid du Colombier 		if(c <= 0)
1347dd7cddfSDavid du Colombier 			return nil;
1357dd7cddfSDavid du Colombier 		if(c == '\n')
1367dd7cddfSDavid du Colombier 			break;
1377dd7cddfSDavid du Colombier 		buf[i] = c;
1387dd7cddfSDavid du Colombier 	}
1397dd7cddfSDavid du Colombier 	buf[i] = '\0';
1407dd7cddfSDavid du Colombier 	return buf;
1417dd7cddfSDavid du Colombier }
1427dd7cddfSDavid du Colombier 
143d9306527SDavid du Colombier static char* months[] = {
144d9306527SDavid du Colombier 	"jan", "feb", "mar", "apr",
145d9306527SDavid du Colombier 	"may", "jun", "jul", "aug",
146d9306527SDavid du Colombier 	"sep", "oct", "nov", "dec"
147d9306527SDavid du Colombier };
1487dd7cddfSDavid du Colombier 
149d9306527SDavid du Colombier static int
getmon(char * s)150d9306527SDavid du Colombier getmon(char *s)
151d9306527SDavid du Colombier {
152d9306527SDavid du Colombier 	int i;
153d9306527SDavid du Colombier 
154d9306527SDavid du Colombier 	for(i=0; i<nelem(months); i++)
155d9306527SDavid du Colombier 		if(cistrcmp(months[i], s) == 0)
156d9306527SDavid du Colombier 			return i;
157d9306527SDavid du Colombier 	return -1;
158d9306527SDavid du Colombier }
159d9306527SDavid du Colombier 
160d9306527SDavid du Colombier /* Fri Jul 23 14:05:14 EDT 1999 */
161d9306527SDavid du Colombier ulong
parsedatev(char ** a)162d9306527SDavid du Colombier parsedatev(char **a)
163d9306527SDavid du Colombier {
164d9306527SDavid du Colombier 	char *p;
165d9306527SDavid du Colombier 	Tm tm;
166d9306527SDavid du Colombier 
167d9306527SDavid du Colombier 	memset(&tm, 0, sizeof tm);
168d9306527SDavid du Colombier 	if((tm.mon=getmon(a[1])) == -1)
169d9306527SDavid du Colombier 		goto Err;
170d9306527SDavid du Colombier 	tm.mday = strtol(a[2], &p, 10);
171d9306527SDavid du Colombier 	if(*p != '\0')
172d9306527SDavid du Colombier 		goto Err;
173d9306527SDavid du Colombier 	tm.hour = strtol(a[3], &p, 10);
174d9306527SDavid du Colombier 	if(*p != ':')
175d9306527SDavid du Colombier 		goto Err;
176d9306527SDavid du Colombier 	tm.min = strtol(p+1, &p, 10);
177d9306527SDavid du Colombier 	if(*p != ':')
178d9306527SDavid du Colombier 		goto Err;
179d9306527SDavid du Colombier 	tm.sec = strtol(p+1, &p, 10);
180d9306527SDavid du Colombier 	if(*p != '\0')
181d9306527SDavid du Colombier 		goto Err;
182d9306527SDavid du Colombier 	if(strlen(a[4]) != 3)
183d9306527SDavid du Colombier 		goto Err;
184d9306527SDavid du Colombier 	strcpy(tm.zone, a[4]);
185d9306527SDavid du Colombier 	if(strlen(a[5]) != 4)
186d9306527SDavid du Colombier 		goto Err;
187d9306527SDavid du Colombier 	tm.year = strtol(a[5], &p, 10);
188d9306527SDavid du Colombier 	if(*p != '\0')
189d9306527SDavid du Colombier 		goto Err;
190d9306527SDavid du Colombier 	tm.year -= 1900;
191d9306527SDavid du Colombier 	return tm2sec(&tm);
192d9306527SDavid du Colombier Err:
193d9306527SDavid du Colombier 	return time(0);
194d9306527SDavid du Colombier }
195d9306527SDavid du Colombier 
196d9306527SDavid du Colombier ulong
parsedate(char * s)197d9306527SDavid du Colombier parsedate(char *s)
198d9306527SDavid du Colombier {
199d9306527SDavid du Colombier 	char *f[10];
200d9306527SDavid du Colombier 	int nf;
201d9306527SDavid du Colombier 
202d9306527SDavid du Colombier 	nf = getfields(s, f, nelem(f), 1, " ");
203d9306527SDavid du Colombier 	if(nf < 6)
204d9306527SDavid du Colombier 		return time(0);
205d9306527SDavid du Colombier 	return parsedatev(f);
206d9306527SDavid du Colombier }
207d9306527SDavid du Colombier 
208d9306527SDavid du Colombier /* achille Jul 23 14:05:15 delivered jmk From ms.com!bub Fri Jul 23 14:05:14 EDT 1999 (plan9.bell-labs.com!jmk) 1352 */
209d9306527SDavid du Colombier /* achille Oct 26 13:45:42 remote local!rsc From rsc Sat Oct 26 13:45:41 EDT 2002 (rsc) 170 */
210d9306527SDavid du Colombier int
parselog(char * s,char ** sender,ulong * xtime)211d9306527SDavid du Colombier parselog(char *s, char **sender, ulong *xtime)
212d9306527SDavid du Colombier {
213d9306527SDavid du Colombier 	char *f[20];
214d9306527SDavid du Colombier 	int nf;
215d9306527SDavid du Colombier 
216d9306527SDavid du Colombier 	nf = getfields(s, f, nelem(f), 1, " ");
217d9306527SDavid du Colombier 	if(nf < 14)
2187dd7cddfSDavid du Colombier 		return 0;
219d9306527SDavid du Colombier 	if(strcmp(f[4], "delivered") == 0 && strcmp(f[5], user) == 0)
220d9306527SDavid du Colombier 		goto Found;
221d9306527SDavid du Colombier 	if(strcmp(f[4], "remote") == 0 && strncmp(f[5], "local!", 6) == 0 && strcmp(f[5]+6, user) == 0)
222d9306527SDavid du Colombier 		goto Found;
223d9306527SDavid du Colombier 	return 0;
224d9306527SDavid du Colombier 
225d9306527SDavid du Colombier Found:
226d9306527SDavid du Colombier 	*sender = estrdup(f[7]);
227d9306527SDavid du Colombier 	*xtime = parsedatev(&f[8]);
2287dd7cddfSDavid du Colombier 	return 1;
2297dd7cddfSDavid du Colombier }
2307dd7cddfSDavid du Colombier 
2317dd7cddfSDavid du Colombier int
logrecv(char ** sender,ulong * xtime)232d9306527SDavid du Colombier logrecv(char **sender, ulong *xtime)
2337dd7cddfSDavid du Colombier {
2347dd7cddfSDavid du Colombier 	char buf[4096];
2357dd7cddfSDavid du Colombier 
2367dd7cddfSDavid du Colombier 	for(;;){
2377dd7cddfSDavid du Colombier 		if(getline(buf, sizeof buf) == nil)
2387dd7cddfSDavid du Colombier 			return 0;
239d9306527SDavid du Colombier 		if(parselog(buf, sender, xtime))
2407dd7cddfSDavid du Colombier 			return 1;
2417dd7cddfSDavid du Colombier 	}
2427dd7cddfSDavid du Colombier }
2437dd7cddfSDavid du Colombier 
2447dd7cddfSDavid du Colombier char*
tweakdate(char * d)2457dd7cddfSDavid du Colombier tweakdate(char *d)
2467dd7cddfSDavid du Colombier {
2477dd7cddfSDavid du Colombier 	char e[8];
2487dd7cddfSDavid du Colombier 
2497dd7cddfSDavid du Colombier 	/* d, date = "Mon Aug  2 23:46:55 EDT 1999" */
2509a747e4fSDavid du Colombier 
2519a747e4fSDavid du Colombier 	if(strlen(d) < strlen("Mon Aug  2 23:46:55 EDT 1999"))
2529a747e4fSDavid du Colombier 		return estrdup("");
2537dd7cddfSDavid du Colombier 	if(strncmp(date, d, 4+4+3) == 0)
25459cc4ca5SDavid du Colombier 		snprint(e, sizeof e, "%.5s", d+4+4+3);	/* 23:46 */
2557dd7cddfSDavid du Colombier 	else
25659cc4ca5SDavid du Colombier 		snprint(e, sizeof e, "%.6s", d+4);	/* Aug  2 */
2577dd7cddfSDavid du Colombier 	return estrdup(e);
2587dd7cddfSDavid du Colombier }
2597dd7cddfSDavid du Colombier 
2607dd7cddfSDavid du Colombier Face*
nextface(void)2617dd7cddfSDavid du Colombier nextface(void)
2627dd7cddfSDavid du Colombier {
2635fab9909SDavid du Colombier 	int i;
2647dd7cddfSDavid du Colombier 	Face *f;
2657dd7cddfSDavid du Colombier 	Plumbmsg *m;
266d9306527SDavid du Colombier 	char *t, *senderp, *showmailp, *digestp;
267d9306527SDavid du Colombier 	ulong xtime;
2687dd7cddfSDavid du Colombier 
2697dd7cddfSDavid du Colombier 	f = emalloc(sizeof(Face));
2707dd7cddfSDavid du Colombier 	for(;;){
2717dd7cddfSDavid du Colombier 		if(seefd >= 0){
2727dd7cddfSDavid du Colombier 			m = plumbrecv(seefd);
2737dd7cddfSDavid du Colombier 			if(m == nil)
2747dd7cddfSDavid du Colombier 				killall("error on seemail plumb port");
2757dd7cddfSDavid du Colombier 			t = value(m->attr, "mailtype", "");
276*a3b78ba5SDavid du Colombier 			if(strcmp(t, "delete") == 0)
2777dd7cddfSDavid du Colombier 				delete(m->data, value(m->attr, "digest", nil));
278*a3b78ba5SDavid du Colombier 			else if(strcmp(t, "new") != 0)
2797dd7cddfSDavid du Colombier 				fprint(2, "faces: unknown plumb message type %s\n", t);
280*a3b78ba5SDavid du Colombier 			else for(i=0; i<nmaildirs; i++)
2816b6b9ac8SDavid du Colombier 				if(strncmp(m->data, maildirs[i], strlen(maildirs[i])) == 0)
2825fab9909SDavid du Colombier 					goto Found;
2837dd7cddfSDavid du Colombier 			plumbfree(m);
2847dd7cddfSDavid du Colombier 			continue;
2855fab9909SDavid du Colombier 
2865fab9909SDavid du Colombier 		Found:
287d9306527SDavid du Colombier 			xtime = parsedate(value(m->attr, "date", date));
2887dd7cddfSDavid du Colombier 			digestp = value(m->attr, "digest", nil);
289d9306527SDavid du Colombier 			if(alreadyseen(digestp)){
2907dd7cddfSDavid du Colombier 				/* duplicate upas/fs can send duplicate messages */
2917dd7cddfSDavid du Colombier 				plumbfree(m);
2927dd7cddfSDavid du Colombier 				continue;
2937dd7cddfSDavid du Colombier 			}
2947dd7cddfSDavid du Colombier 			senderp = estrdup(value(m->attr, "sender", "???"));
2957dd7cddfSDavid du Colombier 			showmailp = estrdup(m->data);
2967dd7cddfSDavid du Colombier 			if(digestp)
2977dd7cddfSDavid du Colombier 				digestp = estrdup(digestp);
2987dd7cddfSDavid du Colombier 			plumbfree(m);
2997dd7cddfSDavid du Colombier 		}else{
300d9306527SDavid du Colombier 			if(logrecv(&senderp, &xtime) <= 0)
3017dd7cddfSDavid du Colombier 				killall("error reading log file");
3027dd7cddfSDavid du Colombier 			showmailp = estrdup("");
3037dd7cddfSDavid du Colombier 			digestp = nil;
3047dd7cddfSDavid du Colombier 		}
3057dd7cddfSDavid du Colombier 		setname(f, senderp);
306d9306527SDavid du Colombier 		f->time = xtime;
307d9306527SDavid du Colombier 		f->tm = *localtime(xtime);
3087dd7cddfSDavid du Colombier 		f->str[Sshow] = showmailp;
3097dd7cddfSDavid du Colombier 		f->str[Sdigest] = digestp;
3107dd7cddfSDavid du Colombier 		return f;
3117dd7cddfSDavid du Colombier 	}
3127dd7cddfSDavid du Colombier }
3137dd7cddfSDavid du Colombier 
3147dd7cddfSDavid du Colombier char*
iline(char * data,char ** pp)3157dd7cddfSDavid du Colombier iline(char *data, char **pp)
3167dd7cddfSDavid du Colombier {
3177dd7cddfSDavid du Colombier 	char *p;
3187dd7cddfSDavid du Colombier 
3197dd7cddfSDavid du Colombier 	for(p=data; *p!='\0' && *p!='\n'; p++)
3207dd7cddfSDavid du Colombier 		;
3217dd7cddfSDavid du Colombier 	if(*p == '\n')
3227dd7cddfSDavid du Colombier 		*p++ = '\0';
3237dd7cddfSDavid du Colombier 	*pp = p;
3247dd7cddfSDavid du Colombier 	return data;
3257dd7cddfSDavid du Colombier }
3267dd7cddfSDavid du Colombier 
3277dd7cddfSDavid du Colombier Face*
dirface(char * dir,char * num)3287dd7cddfSDavid du Colombier dirface(char *dir, char *num)
3297dd7cddfSDavid du Colombier {
3307dd7cddfSDavid du Colombier 	Face *f;
3317dd7cddfSDavid du Colombier 	char *from, *date;
3329a747e4fSDavid du Colombier 	char buf[1024], pwd[1024], *info, *p, *digest;
3337dd7cddfSDavid du Colombier 	int n, fd;
3349a747e4fSDavid du Colombier 	ulong len;
3357dd7cddfSDavid du Colombier 
3367dd7cddfSDavid du Colombier 	/*
3377dd7cddfSDavid du Colombier 	 * loadmbox leaves us in maildir, so we needn't
3387dd7cddfSDavid du Colombier 	 * walk /mail/fs/mbox for each face; this makes startup
3397dd7cddfSDavid du Colombier 	 * a fair bit quicker.
3407dd7cddfSDavid du Colombier 	 */
3417dd7cddfSDavid du Colombier 	if(getwd(pwd, sizeof pwd) != nil && strcmp(pwd, dir) == 0)
3427dd7cddfSDavid du Colombier 		sprint(buf, "%s/info", num);
3437dd7cddfSDavid du Colombier 	else
3447dd7cddfSDavid du Colombier 		sprint(buf, "%s/%s/info", dir, num);
3459a747e4fSDavid du Colombier 	len = dirlen(buf);
3469a747e4fSDavid du Colombier 	if(len <= 0)
3479a747e4fSDavid du Colombier 		return nil;
3487dd7cddfSDavid du Colombier 	fd = open(buf, OREAD);
3497dd7cddfSDavid du Colombier 	if(fd < 0)
3507dd7cddfSDavid du Colombier 		return nil;
3519a747e4fSDavid du Colombier 	info = emalloc(len+1);
3529a747e4fSDavid du Colombier 	n = readn(fd, info, len);
3537dd7cddfSDavid du Colombier 	close(fd);
3549a747e4fSDavid du Colombier 	if(n < 0){
3559a747e4fSDavid du Colombier 		free(info);
3567dd7cddfSDavid du Colombier 		return nil;
3579a747e4fSDavid du Colombier 	}
3587dd7cddfSDavid du Colombier 	info[n] = '\0';
3597dd7cddfSDavid du Colombier 	f = emalloc(sizeof(Face));
3607dd7cddfSDavid du Colombier 	from = iline(info, &p);	/* from */
3617dd7cddfSDavid du Colombier 	iline(p, &p);	/* to */
3627dd7cddfSDavid du Colombier 	iline(p, &p);	/* cc */
3637dd7cddfSDavid du Colombier 	iline(p, &p);	/* replyto */
3647dd7cddfSDavid du Colombier 	date = iline(p, &p);	/* date */
3657dd7cddfSDavid du Colombier 	setname(f, estrdup(from));
366d9306527SDavid du Colombier 	f->time = parsedate(date);
367d9306527SDavid du Colombier 	f->tm = *localtime(f->time);
3687dd7cddfSDavid du Colombier 	sprint(buf, "%s/%s", dir, num);
3697dd7cddfSDavid du Colombier 	f->str[Sshow] = estrdup(buf);
3707dd7cddfSDavid du Colombier 	iline(p, &p);	/* subject */
3717dd7cddfSDavid du Colombier 	iline(p, &p);	/* mime content type */
3727dd7cddfSDavid du Colombier 	iline(p, &p);	/* mime disposition */
3737dd7cddfSDavid du Colombier 	iline(p, &p);	/* filename */
3747dd7cddfSDavid du Colombier 	digest = iline(p, &p);	/* digest */
3757dd7cddfSDavid du Colombier 	f->str[Sdigest] = estrdup(digest);
3769a747e4fSDavid du Colombier 	free(info);
3777dd7cddfSDavid du Colombier 	return f;
3787dd7cddfSDavid du Colombier }
379