xref: /plan9/sys/src/cmd/upas/fs/mbox.c (revision 43aadf5e5598b9159a98f64e309c3ae860328a56)
17dd7cddfSDavid du Colombier #include "common.h"
27dd7cddfSDavid du Colombier #include <ctype.h>
37dd7cddfSDavid du Colombier #include <plumb.h>
47dd7cddfSDavid du Colombier #include <libsec.h>
57dd7cddfSDavid du Colombier #include "dat.h"
67dd7cddfSDavid du Colombier 
77dd7cddfSDavid du Colombier typedef struct Header Header;
87dd7cddfSDavid du Colombier 
97dd7cddfSDavid du Colombier struct Header {
107dd7cddfSDavid du Colombier 	char *type;
117dd7cddfSDavid du Colombier 	void (*f)(Message*, Header*, char*);
127dd7cddfSDavid du Colombier 	int len;
137dd7cddfSDavid du Colombier };
147dd7cddfSDavid du Colombier 
157dd7cddfSDavid du Colombier /* headers */
167dd7cddfSDavid du Colombier static	void	ctype(Message*, Header*, char*);
177dd7cddfSDavid du Colombier static	void	cencoding(Message*, Header*, char*);
187dd7cddfSDavid du Colombier static	void	cdisposition(Message*, Header*, char*);
197dd7cddfSDavid du Colombier static	void	date822(Message*, Header*, char*);
207dd7cddfSDavid du Colombier static	void	from822(Message*, Header*, char*);
217dd7cddfSDavid du Colombier static	void	to822(Message*, Header*, char*);
227dd7cddfSDavid du Colombier static	void	sender822(Message*, Header*, char*);
237dd7cddfSDavid du Colombier static	void	replyto822(Message*, Header*, char*);
247dd7cddfSDavid du Colombier static	void	subject822(Message*, Header*, char*);
257dd7cddfSDavid du Colombier static	void	inreplyto822(Message*, Header*, char*);
267dd7cddfSDavid du Colombier static	void	cc822(Message*, Header*, char*);
277dd7cddfSDavid du Colombier static	void	bcc822(Message*, Header*, char*);
287dd7cddfSDavid du Colombier static	void	messageid822(Message*, Header*, char*);
297dd7cddfSDavid du Colombier static	void	mimeversion(Message*, Header*, char*);
303ff48bf5SDavid du Colombier static	void	nullsqueeze(Message*);
317dd7cddfSDavid du Colombier enum
327dd7cddfSDavid du Colombier {
337dd7cddfSDavid du Colombier 	Mhead=	11,	/* offset of first mime header */
347dd7cddfSDavid du Colombier };
357dd7cddfSDavid du Colombier 
367dd7cddfSDavid du Colombier Header head[] =
377dd7cddfSDavid du Colombier {
387dd7cddfSDavid du Colombier 	{ "date:", date822, },
397dd7cddfSDavid du Colombier 	{ "from:", from822, },
407dd7cddfSDavid du Colombier 	{ "to:", to822, },
417dd7cddfSDavid du Colombier 	{ "sender:", sender822, },
427dd7cddfSDavid du Colombier 	{ "reply-to:", replyto822, },
437dd7cddfSDavid du Colombier 	{ "subject:", subject822, },
447dd7cddfSDavid du Colombier 	{ "cc:", cc822, },
457dd7cddfSDavid du Colombier 	{ "bcc:", bcc822, },
467dd7cddfSDavid du Colombier 	{ "in-reply-to:", inreplyto822, },
477dd7cddfSDavid du Colombier 	{ "mime-version:", mimeversion, },
487dd7cddfSDavid du Colombier 	{ "message-id:", messageid822, },
497dd7cddfSDavid du Colombier 
507dd7cddfSDavid du Colombier [Mhead]	{ "content-type:", ctype, },
517dd7cddfSDavid du Colombier 	{ "content-transfer-encoding:", cencoding, },
527dd7cddfSDavid du Colombier 	{ "content-disposition:", cdisposition, },
537dd7cddfSDavid du Colombier 	{ 0, },
547dd7cddfSDavid du Colombier };
557dd7cddfSDavid du Colombier 
567dd7cddfSDavid du Colombier static	void	fatal(char *fmt, ...);
577dd7cddfSDavid du Colombier static	void	initquoted(void);
587dd7cddfSDavid du Colombier static	void	startheader(Message*);
597dd7cddfSDavid du Colombier static	void	startbody(Message*);
607dd7cddfSDavid du Colombier static	char*	skipwhite(char*);
617dd7cddfSDavid du Colombier static	char*	skiptosemi(char*);
627dd7cddfSDavid du Colombier static	char*	getstring(char*, String*, int);
637dd7cddfSDavid du Colombier static	void	setfilename(Message*, char*);
647dd7cddfSDavid du Colombier static	char*	lowercase(char*);
657dd7cddfSDavid du Colombier static	int	is8bit(Message*);
667dd7cddfSDavid du Colombier static	int	headerline(char**, String*);
677dd7cddfSDavid du Colombier static	void	initheaders(void);
687dd7cddfSDavid du Colombier static void	parseattachments(Message*, Mailbox*);
697dd7cddfSDavid du Colombier 
707dd7cddfSDavid du Colombier int		debug;
7180ee5cbfSDavid du Colombier 
7280ee5cbfSDavid du Colombier char *Enotme = "path not served by this file server";
737dd7cddfSDavid du Colombier 
747dd7cddfSDavid du Colombier enum
757dd7cddfSDavid du Colombier {
767dd7cddfSDavid du Colombier 	Chunksize = 1024,
777dd7cddfSDavid du Colombier };
787dd7cddfSDavid du Colombier 
7980ee5cbfSDavid du Colombier Mailboxinit *boxinit[] = {
8080ee5cbfSDavid du Colombier 	imap4mbox,
8180ee5cbfSDavid du Colombier 	pop3mbox,
82*43aadf5eSDavid du Colombier 	planbmbox,
83*43aadf5eSDavid du Colombier 	planbvmbox,
8480ee5cbfSDavid du Colombier 	plan9mbox,
8580ee5cbfSDavid du Colombier };
8680ee5cbfSDavid du Colombier 
8780ee5cbfSDavid du Colombier char*
syncmbox(Mailbox * mb,int doplumb)8880ee5cbfSDavid du Colombier syncmbox(Mailbox *mb, int doplumb)
8980ee5cbfSDavid du Colombier {
9080ee5cbfSDavid du Colombier 	return (*mb->sync)(mb, doplumb);
9180ee5cbfSDavid du Colombier }
9280ee5cbfSDavid du Colombier 
937dd7cddfSDavid du Colombier /* create a new mailbox */
947dd7cddfSDavid du Colombier char*
newmbox(char * path,char * name,int std)957dd7cddfSDavid du Colombier newmbox(char *path, char *name, int std)
967dd7cddfSDavid du Colombier {
977dd7cddfSDavid du Colombier 	Mailbox *mb, **l;
987dd7cddfSDavid du Colombier 	char *p, *rv;
9980ee5cbfSDavid du Colombier 	int i;
10080ee5cbfSDavid du Colombier 
10180ee5cbfSDavid du Colombier 	initheaders();
10280ee5cbfSDavid du Colombier 
1037dd7cddfSDavid du Colombier 	mb = emalloc(sizeof(*mb));
1047dd7cddfSDavid du Colombier 	strncpy(mb->path, path, sizeof(mb->path)-1);
1057dd7cddfSDavid du Colombier 	if(name == nil){
1067dd7cddfSDavid du Colombier 		p = strrchr(path, '/');
1077dd7cddfSDavid du Colombier 		if(p == nil)
1087dd7cddfSDavid du Colombier 			p = path;
1097dd7cddfSDavid du Colombier 		else
1107dd7cddfSDavid du Colombier 			p++;
1117dd7cddfSDavid du Colombier 		if(*p == 0){
1127dd7cddfSDavid du Colombier 			free(mb);
1137dd7cddfSDavid du Colombier 			return "bad mbox name";
1147dd7cddfSDavid du Colombier 		}
1157dd7cddfSDavid du Colombier 		strncpy(mb->name, p, sizeof(mb->name)-1);
1167dd7cddfSDavid du Colombier 	} else {
1177dd7cddfSDavid du Colombier 		strncpy(mb->name, name, sizeof(mb->name)-1);
1187dd7cddfSDavid du Colombier 	}
1197dd7cddfSDavid du Colombier 
12080ee5cbfSDavid du Colombier 	rv = nil;
12180ee5cbfSDavid du Colombier 	// check for a mailbox type
12280ee5cbfSDavid du Colombier 	for(i=0; i<nelem(boxinit); i++)
12380ee5cbfSDavid du Colombier 		if((rv = (*boxinit[i])(mb, path)) != Enotme)
12480ee5cbfSDavid du Colombier 			break;
12580ee5cbfSDavid du Colombier 	if(i == nelem(boxinit)){
12680ee5cbfSDavid du Colombier 		free(mb);
12780ee5cbfSDavid du Colombier 		return "bad path";
12880ee5cbfSDavid du Colombier 	}
12980ee5cbfSDavid du Colombier 
13080ee5cbfSDavid du Colombier 	// on error, give up
1315d459b5aSDavid du Colombier 	if(rv){
1325d459b5aSDavid du Colombier 		free(mb);
13380ee5cbfSDavid du Colombier 		return rv;
1345d459b5aSDavid du Colombier 	}
13580ee5cbfSDavid du Colombier 
1367dd7cddfSDavid du Colombier 	// make sure name isn't taken
1377dd7cddfSDavid du Colombier 	qlock(&mbllock);
13859cc4ca5SDavid du Colombier 	for(l = &mbl; *l != nil; l = &(*l)->next){
1397dd7cddfSDavid du Colombier 		if(strcmp((*l)->name, mb->name) == 0){
14059cc4ca5SDavid du Colombier 			if(strcmp(path, (*l)->path) == 0)
1417dd7cddfSDavid du Colombier 				rv = nil;
1427dd7cddfSDavid du Colombier 			else
1437dd7cddfSDavid du Colombier 				rv = "mbox name in use";
14480ee5cbfSDavid du Colombier 			if(mb->close)
14580ee5cbfSDavid du Colombier 				(*mb->close)(mb);
1467dd7cddfSDavid du Colombier 			free(mb);
1477dd7cddfSDavid du Colombier 			qunlock(&mbllock);
1487dd7cddfSDavid du Colombier 			return rv;
1497dd7cddfSDavid du Colombier 		}
15059cc4ca5SDavid du Colombier 	}
15159cc4ca5SDavid du Colombier 
152ed250ae1SDavid du Colombier 	// always try locking
153ed250ae1SDavid du Colombier 	mb->dolock = 1;
15459cc4ca5SDavid du Colombier 
1557dd7cddfSDavid du Colombier 	mb->refs = 1;
1567dd7cddfSDavid du Colombier 	mb->next = nil;
1577dd7cddfSDavid du Colombier 	mb->id = newid();
1587dd7cddfSDavid du Colombier 	mb->root = newmessage(nil);
1597dd7cddfSDavid du Colombier 	mb->std = std;
1607dd7cddfSDavid du Colombier 	*l = mb;
1617dd7cddfSDavid du Colombier 	qunlock(&mbllock);
1627dd7cddfSDavid du Colombier 
1637dd7cddfSDavid du Colombier 	qlock(mb);
16480ee5cbfSDavid du Colombier 	if(mb->ctl){
1659a747e4fSDavid du Colombier 		henter(PATH(mb->id, Qmbox), "ctl",
1669a747e4fSDavid du Colombier 			(Qid){PATH(mb->id, Qmboxctl), 0, QTFILE}, nil, mb);
16780ee5cbfSDavid du Colombier 	}
1687dd7cddfSDavid du Colombier 	rv = syncmbox(mb, 0);
1697dd7cddfSDavid du Colombier 	qunlock(mb);
1707dd7cddfSDavid du Colombier 
1717dd7cddfSDavid du Colombier 	return rv;
1727dd7cddfSDavid du Colombier }
1737dd7cddfSDavid du Colombier 
1747dd7cddfSDavid du Colombier // close the named mailbox
1757dd7cddfSDavid du Colombier void
freembox(char * name)1767dd7cddfSDavid du Colombier freembox(char *name)
1777dd7cddfSDavid du Colombier {
1785d459b5aSDavid du Colombier 	Mailbox **l, *mb;
1797dd7cddfSDavid du Colombier 
1807dd7cddfSDavid du Colombier 	qlock(&mbllock);
1815d459b5aSDavid du Colombier 	for(l=&mbl; *l != nil; l=&(*l)->next){
1825d459b5aSDavid du Colombier 		if(strcmp(name, (*l)->name) == 0){
1835d459b5aSDavid du Colombier 			mb = *l;
1845d459b5aSDavid du Colombier 			*l = mb->next;
1857dd7cddfSDavid du Colombier 			mboxdecref(mb);
1867dd7cddfSDavid du Colombier 			break;
1877dd7cddfSDavid du Colombier 		}
1885d459b5aSDavid du Colombier 	}
1899a747e4fSDavid du Colombier 	hfree(PATH(0, Qtop), name);
1907dd7cddfSDavid du Colombier 	qunlock(&mbllock);
1917dd7cddfSDavid du Colombier }
1927dd7cddfSDavid du Colombier 
1937dd7cddfSDavid du Colombier static void
initheaders(void)1947dd7cddfSDavid du Colombier initheaders(void)
1957dd7cddfSDavid du Colombier {
1967dd7cddfSDavid du Colombier 	Header *h;
1977dd7cddfSDavid du Colombier 	static int already;
1987dd7cddfSDavid du Colombier 
1997dd7cddfSDavid du Colombier 	if(already)
2007dd7cddfSDavid du Colombier 		return;
2017dd7cddfSDavid du Colombier 	already = 1;
2027dd7cddfSDavid du Colombier 
2037dd7cddfSDavid du Colombier 	for(h = head; h->type != nil; h++)
2047dd7cddfSDavid du Colombier 		h->len = strlen(h->type);
2057dd7cddfSDavid du Colombier }
2067dd7cddfSDavid du Colombier 
2077dd7cddfSDavid du Colombier /*
2087dd7cddfSDavid du Colombier  *  parse a Unix style header
2097dd7cddfSDavid du Colombier  */
21080ee5cbfSDavid du Colombier void
parseunix(Message * m)2117dd7cddfSDavid du Colombier parseunix(Message *m)
2127dd7cddfSDavid du Colombier {
2137dd7cddfSDavid du Colombier 	char *p;
2147dd7cddfSDavid du Colombier 	String *h;
2157dd7cddfSDavid du Colombier 
2167dd7cddfSDavid du Colombier 	h = s_new();
2177dd7cddfSDavid du Colombier 	for(p = m->start + 5; *p && *p != '\r' && *p != '\n'; p++)
2187dd7cddfSDavid du Colombier 		s_putc(h, *p);
2197dd7cddfSDavid du Colombier 	s_terminate(h);
2207dd7cddfSDavid du Colombier 	s_restart(h);
2217dd7cddfSDavid du Colombier 
2227dd7cddfSDavid du Colombier 	m->unixfrom = s_parse(h, s_reset(m->unixfrom));
2237dd7cddfSDavid du Colombier 	m->unixdate = s_append(s_reset(m->unixdate), h->ptr);
2247dd7cddfSDavid du Colombier 
2257dd7cddfSDavid du Colombier 	s_free(h);
2267dd7cddfSDavid du Colombier }
2277dd7cddfSDavid du Colombier 
2287dd7cddfSDavid du Colombier /*
2297dd7cddfSDavid du Colombier  *  parse a message
2307dd7cddfSDavid du Colombier  */
23180ee5cbfSDavid du Colombier void
parseheaders(Message * m,int justmime,Mailbox * mb,int addfrom)2327a02f3c0SDavid du Colombier parseheaders(Message *m, int justmime, Mailbox *mb, int addfrom)
2337dd7cddfSDavid du Colombier {
2347dd7cddfSDavid du Colombier 	String *hl;
2357dd7cddfSDavid du Colombier 	Header *h;
23680ee5cbfSDavid du Colombier 	char *p, *q;
2377dd7cddfSDavid du Colombier 	int i;
2387dd7cddfSDavid du Colombier 
2397dd7cddfSDavid du Colombier 	if(m->whole == m->whole->whole){
2409a747e4fSDavid du Colombier 		henter(PATH(mb->id, Qmbox), m->name,
2419a747e4fSDavid du Colombier 			(Qid){PATH(m->id, Qdir), 0, QTDIR}, m, mb);
2427dd7cddfSDavid du Colombier 	} else {
2439a747e4fSDavid du Colombier 		henter(PATH(m->whole->id, Qdir), m->name,
2449a747e4fSDavid du Colombier 			(Qid){PATH(m->id, Qdir), 0, QTDIR}, m, mb);
2457dd7cddfSDavid du Colombier 	}
2467dd7cddfSDavid du Colombier 	for(i = 0; i < Qmax; i++)
2479a747e4fSDavid du Colombier 		henter(PATH(m->id, Qdir), dirtab[i],
2489a747e4fSDavid du Colombier 			(Qid){PATH(m->id, i), 0, QTFILE}, m, mb);
2497dd7cddfSDavid du Colombier 
2507dd7cddfSDavid du Colombier 	// parse mime headers
2517dd7cddfSDavid du Colombier 	p = m->header;
2527dd7cddfSDavid du Colombier 	hl = s_new();
2537dd7cddfSDavid du Colombier 	while(headerline(&p, hl)){
2547dd7cddfSDavid du Colombier 		if(justmime)
2557dd7cddfSDavid du Colombier 			h = &head[Mhead];
2567dd7cddfSDavid du Colombier 		else
2577dd7cddfSDavid du Colombier 			h = head;
2587dd7cddfSDavid du Colombier 		for(; h->type; h++){
2597dd7cddfSDavid du Colombier 			if(cistrncmp(s_to_c(hl), h->type, h->len) == 0){
2607dd7cddfSDavid du Colombier 				(*h->f)(m, h, s_to_c(hl));
2617dd7cddfSDavid du Colombier 				break;
2627dd7cddfSDavid du Colombier 			}
2637dd7cddfSDavid du Colombier 		}
2647dd7cddfSDavid du Colombier 		s_reset(hl);
2657dd7cddfSDavid du Colombier 	}
2667dd7cddfSDavid du Colombier 	s_free(hl);
2677dd7cddfSDavid du Colombier 
2687dd7cddfSDavid du Colombier 	// the blank line isn't really part of the body or header
2697dd7cddfSDavid du Colombier 	if(justmime){
2707dd7cddfSDavid du Colombier 		m->mhend = p;
2717dd7cddfSDavid du Colombier 		m->hend = m->header;
2727dd7cddfSDavid du Colombier 	} else {
2737dd7cddfSDavid du Colombier 		m->hend = p;
2747dd7cddfSDavid du Colombier 	}
2757dd7cddfSDavid du Colombier 	if(*p == '\n')
2767dd7cddfSDavid du Colombier 		p++;
2777dd7cddfSDavid du Colombier 	m->rbody = m->body = p;
2787dd7cddfSDavid du Colombier 
2793ff48bf5SDavid du Colombier 	// if type is text, get any nulls out of the body.  This is
2803ff48bf5SDavid du Colombier 	// for the two seans and imap clients that get confused.
2813ff48bf5SDavid du Colombier 	if(strncmp(s_to_c(m->type), "text/", 5) == 0)
2823ff48bf5SDavid du Colombier 		nullsqueeze(m);
2833ff48bf5SDavid du Colombier 
28480ee5cbfSDavid du Colombier 	//
28580ee5cbfSDavid du Colombier 	// cobble together Unix-style from line
28680ee5cbfSDavid du Colombier 	// for local mailbox messages, we end up recreating the
28780ee5cbfSDavid du Colombier 	// original header.
28880ee5cbfSDavid du Colombier 	// for pop3 messages, the best we can do is
28980ee5cbfSDavid du Colombier 	// use the From: information and the RFC822 date.
29080ee5cbfSDavid du Colombier 	//
29167031067SDavid du Colombier 	if(m->unixdate == nil || strcmp(s_to_c(m->unixdate), "???") == 0
29267031067SDavid du Colombier 	|| strcmp(s_to_c(m->unixdate), "Thu Jan 1 00:00:00 GMT 1970") == 0){
29367031067SDavid du Colombier 		if(m->unixdate){
29467031067SDavid du Colombier 			s_free(m->unixdate);
29567031067SDavid du Colombier 			m->unixdate = nil;
29667031067SDavid du Colombier 		}
29780ee5cbfSDavid du Colombier 		// look for the date in the first Received: line.
29880ee5cbfSDavid du Colombier 		// it's likely to be the right time zone (it's
29980ee5cbfSDavid du Colombier 	 	// the local system) and in a convenient format.
30080ee5cbfSDavid du Colombier 		if(cistrncmp(m->header, "received:", 9)==0){
301d9306527SDavid du Colombier 			if((q = strchr(m->header, ';')) != nil){
302d9306527SDavid du Colombier 				p = q;
303d9306527SDavid du Colombier 				while((p = strchr(p, '\n')) != nil){
304d9306527SDavid du Colombier 					if(p[1] != ' ' && p[1] != '\t' && p[1] != '\n')
305d9306527SDavid du Colombier 						break;
306d9306527SDavid du Colombier 					p++;
307d9306527SDavid du Colombier 				}
308d9306527SDavid du Colombier 				if(p){
30980ee5cbfSDavid du Colombier 					*p = '\0';
31080ee5cbfSDavid du Colombier 					m->unixdate = date822tounix(q+1);
31180ee5cbfSDavid du Colombier 					*p = '\n';
31280ee5cbfSDavid du Colombier 				}
31380ee5cbfSDavid du Colombier 			}
314d9306527SDavid du Colombier 		}
31580ee5cbfSDavid du Colombier 
31680ee5cbfSDavid du Colombier 		// fall back on the rfc822 date
31780ee5cbfSDavid du Colombier 		if(m->unixdate==nil && m->date822)
31880ee5cbfSDavid du Colombier 			m->unixdate = date822tounix(s_to_c(m->date822));
31980ee5cbfSDavid du Colombier 	}
32080ee5cbfSDavid du Colombier 
3219a747e4fSDavid du Colombier 	if(m->unixheader != nil)
3229a747e4fSDavid du Colombier 		s_free(m->unixheader);
3237a02f3c0SDavid du Colombier 
3247a02f3c0SDavid du Colombier 	// only fake header for top-level messages for pop3 and imap4
3257a02f3c0SDavid du Colombier 	// clients (those protocols don't include the unix header).
3267a02f3c0SDavid du Colombier 	// adding the unix header all the time screws up mime-attached
3277a02f3c0SDavid du Colombier 	// rfc822 messages.
3287a02f3c0SDavid du Colombier 	if(!addfrom && !m->unixfrom){
3297a02f3c0SDavid du Colombier 		m->unixheader = nil;
3307a02f3c0SDavid du Colombier 		return;
3317a02f3c0SDavid du Colombier 	}
3327a02f3c0SDavid du Colombier 
33380ee5cbfSDavid du Colombier 	m->unixheader = s_copy("From ");
33467031067SDavid du Colombier 	if(m->unixfrom && strcmp(s_to_c(m->unixfrom), "???") != 0)
33580ee5cbfSDavid du Colombier 		s_append(m->unixheader, s_to_c(m->unixfrom));
33680ee5cbfSDavid du Colombier 	else if(m->from822)
33780ee5cbfSDavid du Colombier 		s_append(m->unixheader, s_to_c(m->from822));
33880ee5cbfSDavid du Colombier 	else
33980ee5cbfSDavid du Colombier 		s_append(m->unixheader, "???");
34080ee5cbfSDavid du Colombier 
34180ee5cbfSDavid du Colombier 	s_append(m->unixheader, " ");
34280ee5cbfSDavid du Colombier 	if(m->unixdate)
34380ee5cbfSDavid du Colombier 		s_append(m->unixheader, s_to_c(m->unixdate));
34480ee5cbfSDavid du Colombier 	else
34567031067SDavid du Colombier 		s_append(m->unixheader, "Thu Jan  1 00:00:00 GMT 1970");
34680ee5cbfSDavid du Colombier 
34780ee5cbfSDavid du Colombier 	s_append(m->unixheader, "\n");
34880ee5cbfSDavid du Colombier }
34980ee5cbfSDavid du Colombier 
3509a747e4fSDavid du Colombier String*
promote(String ** sp)3519a747e4fSDavid du Colombier promote(String **sp)
3529a747e4fSDavid du Colombier {
3539a747e4fSDavid du Colombier 	String *s;
3549a747e4fSDavid du Colombier 
3559a747e4fSDavid du Colombier 	if(*sp != nil)
3569a747e4fSDavid du Colombier 		s = s_clone(*sp);
3579a747e4fSDavid du Colombier 	else
3589a747e4fSDavid du Colombier 		s = nil;
3599a747e4fSDavid du Colombier 	return s;
3609a747e4fSDavid du Colombier }
3619a747e4fSDavid du Colombier 
36280ee5cbfSDavid du Colombier void
parsebody(Message * m,Mailbox * mb)36380ee5cbfSDavid du Colombier parsebody(Message *m, Mailbox *mb)
36480ee5cbfSDavid du Colombier {
3659a747e4fSDavid du Colombier 	Message *nm;
3669a747e4fSDavid du Colombier 
3677dd7cddfSDavid du Colombier 	// recurse
3687dd7cddfSDavid du Colombier 	if(strncmp(s_to_c(m->type), "multipart/", 10) == 0){
3697dd7cddfSDavid du Colombier 		parseattachments(m, mb);
3707dd7cddfSDavid du Colombier 	} else if(strcmp(s_to_c(m->type), "message/rfc822") == 0){
3717dd7cddfSDavid du Colombier 		decode(m);
3727dd7cddfSDavid du Colombier 		parseattachments(m, mb);
3739a747e4fSDavid du Colombier 		nm = m->part;
3749a747e4fSDavid du Colombier 
3759a747e4fSDavid du Colombier 		// promote headers
3765d459b5aSDavid du Colombier 		if(m->replyto822 == nil && m->from822 == nil && m->sender822 == nil){
3779a747e4fSDavid du Colombier 			m->from822 = promote(&nm->from822);
3789a747e4fSDavid du Colombier 			m->to822 = promote(&nm->to822);
3799a747e4fSDavid du Colombier 			m->date822 = promote(&nm->date822);
3809a747e4fSDavid du Colombier 			m->sender822 = promote(&nm->sender822);
3819a747e4fSDavid du Colombier 			m->replyto822 = promote(&nm->replyto822);
3829a747e4fSDavid du Colombier 			m->subject822 = promote(&nm->subject822);
3839a747e4fSDavid du Colombier 			m->unixdate = promote(&nm->unixdate);
3847dd7cddfSDavid du Colombier 		}
3857dd7cddfSDavid du Colombier 	}
3865d459b5aSDavid du Colombier }
3877dd7cddfSDavid du Colombier 
38880ee5cbfSDavid du Colombier void
parse(Message * m,int justmime,Mailbox * mb,int addfrom)3897a02f3c0SDavid du Colombier parse(Message *m, int justmime, Mailbox *mb, int addfrom)
39080ee5cbfSDavid du Colombier {
3917a02f3c0SDavid du Colombier 	parseheaders(m, justmime, mb, addfrom);
39280ee5cbfSDavid du Colombier 	parsebody(m, mb);
39380ee5cbfSDavid du Colombier }
39480ee5cbfSDavid du Colombier 
3957dd7cddfSDavid du Colombier static void
parseattachments(Message * m,Mailbox * mb)3967dd7cddfSDavid du Colombier parseattachments(Message *m, Mailbox *mb)
3977dd7cddfSDavid du Colombier {
3987dd7cddfSDavid du Colombier 	Message *nm, **l;
3997dd7cddfSDavid du Colombier 	char *p, *x;
4007dd7cddfSDavid du Colombier 
4017dd7cddfSDavid du Colombier 	// if there's a boundary, recurse...
4027dd7cddfSDavid du Colombier 	if(m->boundary != nil){
4037dd7cddfSDavid du Colombier 		p = m->body;
4047dd7cddfSDavid du Colombier 		nm = nil;
4057dd7cddfSDavid du Colombier 		l = &m->part;
4067dd7cddfSDavid du Colombier 		for(;;){
4077dd7cddfSDavid du Colombier 			x = strstr(p, s_to_c(m->boundary));
4083ff48bf5SDavid du Colombier 
4093ff48bf5SDavid du Colombier 			/* no boundary, we're done */
4103ff48bf5SDavid du Colombier 			if(x == nil){
4117dd7cddfSDavid du Colombier 				if(nm != nil)
4127dd7cddfSDavid du Colombier 					nm->rbend = nm->bend = nm->end = m->bend;
4137dd7cddfSDavid du Colombier 				break;
4147dd7cddfSDavid du Colombier 			}
4153ff48bf5SDavid du Colombier 
4163ff48bf5SDavid du Colombier 			/* boundary must be at the start of a line */
4173ff48bf5SDavid du Colombier 			if(x != m->body && *(x-1) != '\n'){
4183ff48bf5SDavid du Colombier 				p = x+1;
4193ff48bf5SDavid du Colombier 				continue;
4203ff48bf5SDavid du Colombier 			}
4213ff48bf5SDavid du Colombier 
4227dd7cddfSDavid du Colombier 			if(nm != nil)
4237dd7cddfSDavid du Colombier 				nm->rbend = nm->bend = nm->end = x;
4247dd7cddfSDavid du Colombier 			x += strlen(s_to_c(m->boundary));
4257dd7cddfSDavid du Colombier 
4267dd7cddfSDavid du Colombier 			/* is this the last part? ignore anything after it */
4277dd7cddfSDavid du Colombier 			if(strncmp(x, "--", 2) == 0)
4287dd7cddfSDavid du Colombier 				break;
4297dd7cddfSDavid du Colombier 
4307dd7cddfSDavid du Colombier 			p = strchr(x, '\n');
4317dd7cddfSDavid du Colombier 			if(p == nil)
4327dd7cddfSDavid du Colombier 				break;
4337dd7cddfSDavid du Colombier 			nm = newmessage(m);
4347dd7cddfSDavid du Colombier 			nm->start = nm->header = nm->body = nm->rbody = ++p;
4357dd7cddfSDavid du Colombier 			nm->mheader = nm->header;
4367dd7cddfSDavid du Colombier 			*l = nm;
4377dd7cddfSDavid du Colombier 			l = &nm->next;
4387dd7cddfSDavid du Colombier 		}
4397dd7cddfSDavid du Colombier 		for(nm = m->part; nm != nil; nm = nm->next)
4407a02f3c0SDavid du Colombier 			parse(nm, 1, mb, 0);
4419a747e4fSDavid du Colombier 		return;
4427dd7cddfSDavid du Colombier 	}
4439a747e4fSDavid du Colombier 
4449a747e4fSDavid du Colombier 	// if we've got an rfc822 message, recurse...
4459a747e4fSDavid du Colombier 	if(strcmp(s_to_c(m->type), "message/rfc822") == 0){
4467dd7cddfSDavid du Colombier 		nm = newmessage(m);
4477dd7cddfSDavid du Colombier 		m->part = nm;
4487dd7cddfSDavid du Colombier 		nm->start = nm->header = nm->body = nm->rbody = m->body;
4497dd7cddfSDavid du Colombier 		nm->end = nm->bend = nm->rbend = m->bend;
4507a02f3c0SDavid du Colombier 		parse(nm, 0, mb, 0);
4517dd7cddfSDavid du Colombier 	}
4527dd7cddfSDavid du Colombier }
4537dd7cddfSDavid du Colombier 
4547dd7cddfSDavid du Colombier /*
4557dd7cddfSDavid du Colombier  *  pick up a header line
4567dd7cddfSDavid du Colombier  */
4577dd7cddfSDavid du Colombier static int
headerline(char ** pp,String * hl)4587dd7cddfSDavid du Colombier headerline(char **pp, String *hl)
4597dd7cddfSDavid du Colombier {
4607dd7cddfSDavid du Colombier 	char *p, *x;
4617dd7cddfSDavid du Colombier 
4627dd7cddfSDavid du Colombier 	s_reset(hl);
4637dd7cddfSDavid du Colombier 	p = *pp;
4647dd7cddfSDavid du Colombier 	x = strpbrk(p, ":\n");
4657dd7cddfSDavid du Colombier 	if(x == nil || *x == '\n')
4667dd7cddfSDavid du Colombier 		return 0;
4677dd7cddfSDavid du Colombier 	for(;;){
4687dd7cddfSDavid du Colombier 		x = strchr(p, '\n');
4697dd7cddfSDavid du Colombier 		if(x == nil)
4707dd7cddfSDavid du Colombier 			x = p + strlen(p);
4717dd7cddfSDavid du Colombier 		s_nappend(hl, p, x-p);
4727dd7cddfSDavid du Colombier 		p = x;
473223a736eSDavid du Colombier 		if(*p != '\n' || *++p != ' ' && *p != '\t')
4747dd7cddfSDavid du Colombier 			break;
475223a736eSDavid du Colombier 		while(*p == ' ' || *p == '\t')
476223a736eSDavid du Colombier 			p++;
477223a736eSDavid du Colombier 		s_putc(hl, ' ');
4787dd7cddfSDavid du Colombier 	}
4797dd7cddfSDavid du Colombier 	*pp = p;
4807dd7cddfSDavid du Colombier 	return 1;
4817dd7cddfSDavid du Colombier }
4827dd7cddfSDavid du Colombier 
48334e11723SDavid du Colombier /* returns nil iff there are no addressees */
4847dd7cddfSDavid du Colombier static String*
addr822(char * p)4857dd7cddfSDavid du Colombier addr822(char *p)
4867dd7cddfSDavid du Colombier {
4877dd7cddfSDavid du Colombier 	String *s, *list;
4887dd7cddfSDavid du Colombier 	int incomment, addrdone, inanticomment, quoted;
4897dd7cddfSDavid du Colombier 	int n;
4907dd7cddfSDavid du Colombier 	int c;
4917dd7cddfSDavid du Colombier 
4927dd7cddfSDavid du Colombier 	list = s_new();
4937dd7cddfSDavid du Colombier 	s = s_new();
4947dd7cddfSDavid du Colombier 	quoted = incomment = addrdone = inanticomment = 0;
4957dd7cddfSDavid du Colombier 	n = 0;
4967dd7cddfSDavid du Colombier 	for(; *p; p++){
4977dd7cddfSDavid du Colombier 		c = *p;
4987dd7cddfSDavid du Colombier 
4997dd7cddfSDavid du Colombier 		// whitespace is ignored
5007dd7cddfSDavid du Colombier 		if(!quoted && isspace(c) || c == '\r')
5017dd7cddfSDavid du Colombier 			continue;
5027dd7cddfSDavid du Colombier 
5037dd7cddfSDavid du Colombier 		// strings are always treated as atoms
5047dd7cddfSDavid du Colombier 		if(!quoted && c == '"'){
5057dd7cddfSDavid du Colombier 			if(!addrdone && !incomment)
5067dd7cddfSDavid du Colombier 				s_putc(s, c);
5077dd7cddfSDavid du Colombier 			for(p++; *p; p++){
5087dd7cddfSDavid du Colombier 				if(!addrdone && !incomment)
5097dd7cddfSDavid du Colombier 					s_putc(s, *p);
5107dd7cddfSDavid du Colombier 				if(!quoted && *p == '"')
5117dd7cddfSDavid du Colombier 					break;
5127dd7cddfSDavid du Colombier 				if(*p == '\\')
5137dd7cddfSDavid du Colombier 					quoted = 1;
5147dd7cddfSDavid du Colombier 				else
5157dd7cddfSDavid du Colombier 					quoted = 0;
5167dd7cddfSDavid du Colombier 			}
5177dd7cddfSDavid du Colombier 			if(*p == 0)
5187dd7cddfSDavid du Colombier 				break;
5197dd7cddfSDavid du Colombier 			quoted = 0;
5207dd7cddfSDavid du Colombier 			continue;
5217dd7cddfSDavid du Colombier 		}
5227dd7cddfSDavid du Colombier 
5237dd7cddfSDavid du Colombier 		// ignore everything in an expicit comment
5247dd7cddfSDavid du Colombier 		if(!quoted && c == '('){
5257dd7cddfSDavid du Colombier 			incomment = 1;
5267dd7cddfSDavid du Colombier 			continue;
5277dd7cddfSDavid du Colombier 		}
5287dd7cddfSDavid du Colombier 		if(incomment){
5297dd7cddfSDavid du Colombier 			if(!quoted && c == ')')
5307dd7cddfSDavid du Colombier 				incomment = 0;
5317dd7cddfSDavid du Colombier 			quoted = 0;
5327dd7cddfSDavid du Colombier 			continue;
5337dd7cddfSDavid du Colombier 		}
5347dd7cddfSDavid du Colombier 
5357dd7cddfSDavid du Colombier 		// anticomments makes everything outside of them comments
5367dd7cddfSDavid du Colombier 		if(!quoted && c == '<' && !inanticomment){
5377dd7cddfSDavid du Colombier 			inanticomment = 1;
5387dd7cddfSDavid du Colombier 			s = s_reset(s);
5397dd7cddfSDavid du Colombier 			continue;
5407dd7cddfSDavid du Colombier 		}
5417dd7cddfSDavid du Colombier 		if(!quoted && c == '>' && inanticomment){
5427dd7cddfSDavid du Colombier 			addrdone = 1;
5437dd7cddfSDavid du Colombier 			inanticomment = 0;
5447dd7cddfSDavid du Colombier 			continue;
5457dd7cddfSDavid du Colombier 		}
5467dd7cddfSDavid du Colombier 
5477dd7cddfSDavid du Colombier 		// commas separate addresses
5487dd7cddfSDavid du Colombier 		if(!quoted && c == ',' && !inanticomment){
5497dd7cddfSDavid du Colombier 			s_terminate(s);
5507dd7cddfSDavid du Colombier 			addrdone = 0;
5517dd7cddfSDavid du Colombier 			if(n++ != 0)
5527dd7cddfSDavid du Colombier 				s_append(list, " ");
5537dd7cddfSDavid du Colombier 			s_append(list, s_to_c(s));
5547dd7cddfSDavid du Colombier 			s = s_reset(s);
5557dd7cddfSDavid du Colombier 			continue;
5567dd7cddfSDavid du Colombier 		}
5577dd7cddfSDavid du Colombier 
5587dd7cddfSDavid du Colombier 		// what's left is part of the address
5597dd7cddfSDavid du Colombier 		s_putc(s, c);
5607dd7cddfSDavid du Colombier 
5617dd7cddfSDavid du Colombier 		// quoted characters are recognized only as characters
5627dd7cddfSDavid du Colombier 		if(c == '\\')
5637dd7cddfSDavid du Colombier 			quoted = 1;
5647dd7cddfSDavid du Colombier 		else
5657dd7cddfSDavid du Colombier 			quoted = 0;
5667dd7cddfSDavid du Colombier 
5677dd7cddfSDavid du Colombier 	}
5687dd7cddfSDavid du Colombier 
5697dd7cddfSDavid du Colombier 	if(*s_to_c(s) != 0){
5707dd7cddfSDavid du Colombier 		s_terminate(s);
5717dd7cddfSDavid du Colombier 		if(n++ != 0)
5727dd7cddfSDavid du Colombier 			s_append(list, " ");
5737dd7cddfSDavid du Colombier 		s_append(list, s_to_c(s));
5747dd7cddfSDavid du Colombier 	}
5757dd7cddfSDavid du Colombier 	s_free(s);
5767dd7cddfSDavid du Colombier 
57734e11723SDavid du Colombier 	if(n == 0){		/* no addressees given, just the keyword */
5787dd7cddfSDavid du Colombier 		s_free(list);
5797dd7cddfSDavid du Colombier 		return nil;
5807dd7cddfSDavid du Colombier 	}
5817dd7cddfSDavid du Colombier 	return list;
5827dd7cddfSDavid du Colombier }
5837dd7cddfSDavid du Colombier 
5843e748dfcSDavid du Colombier /*
5853e748dfcSDavid du Colombier  * per rfc2822 §4.5.3, permit multiple to, cc and bcc headers by
5863e748dfcSDavid du Colombier  * concatenating their values.
5873e748dfcSDavid du Colombier  */
5883e748dfcSDavid du Colombier 
5897dd7cddfSDavid du Colombier static void
to822(Message * m,Header * h,char * p)5907dd7cddfSDavid du Colombier to822(Message *m, Header *h, char *p)
5917dd7cddfSDavid du Colombier {
5923e748dfcSDavid du Colombier 	String *s;
5933e748dfcSDavid du Colombier 
5947dd7cddfSDavid du Colombier 	p += strlen(h->type);
5953e748dfcSDavid du Colombier 	s = addr822(p);
5963e748dfcSDavid du Colombier 	if (m->to822 == nil)
5973e748dfcSDavid du Colombier 		m->to822 = s;
59834e11723SDavid du Colombier 	else if (s != nil) {
5993e748dfcSDavid du Colombier 		s_append(m->to822, " ");
6003e748dfcSDavid du Colombier 		s_append(m->to822, s_to_c(s));
6013e748dfcSDavid du Colombier 		s_free(s);
6023e748dfcSDavid du Colombier 	}
6037dd7cddfSDavid du Colombier }
6047dd7cddfSDavid du Colombier 
6057dd7cddfSDavid du Colombier static void
cc822(Message * m,Header * h,char * p)6067dd7cddfSDavid du Colombier cc822(Message *m, Header *h, char *p)
6077dd7cddfSDavid du Colombier {
6083e748dfcSDavid du Colombier 	String *s;
6093e748dfcSDavid du Colombier 
6107dd7cddfSDavid du Colombier 	p += strlen(h->type);
6113e748dfcSDavid du Colombier 	s = addr822(p);
6123e748dfcSDavid du Colombier 	if (m->cc822 == nil)
6133e748dfcSDavid du Colombier 		m->cc822 = s;
61434e11723SDavid du Colombier 	else if (s != nil) {
6153e748dfcSDavid du Colombier 		s_append(m->cc822, " ");
6163e748dfcSDavid du Colombier 		s_append(m->cc822, s_to_c(s));
6173e748dfcSDavid du Colombier 		s_free(s);
6183e748dfcSDavid du Colombier 	}
6197dd7cddfSDavid du Colombier }
6207dd7cddfSDavid du Colombier 
6217dd7cddfSDavid du Colombier static void
bcc822(Message * m,Header * h,char * p)6227dd7cddfSDavid du Colombier bcc822(Message *m, Header *h, char *p)
6237dd7cddfSDavid du Colombier {
6243e748dfcSDavid du Colombier 	String *s;
6253e748dfcSDavid du Colombier 
6267dd7cddfSDavid du Colombier 	p += strlen(h->type);
6273e748dfcSDavid du Colombier 	s = addr822(p);
6283e748dfcSDavid du Colombier 	if (m->bcc822 == nil)
6293e748dfcSDavid du Colombier 		m->bcc822 = s;
63034e11723SDavid du Colombier 	else if (s != nil) {
6313e748dfcSDavid du Colombier 		s_append(m->bcc822, " ");
6323e748dfcSDavid du Colombier 		s_append(m->bcc822, s_to_c(s));
6333e748dfcSDavid du Colombier 		s_free(s);
6343e748dfcSDavid du Colombier 	}
6357dd7cddfSDavid du Colombier }
6367dd7cddfSDavid du Colombier 
6377dd7cddfSDavid du Colombier static void
from822(Message * m,Header * h,char * p)6387dd7cddfSDavid du Colombier from822(Message *m, Header *h, char *p)
6397dd7cddfSDavid du Colombier {
6407dd7cddfSDavid du Colombier 	p += strlen(h->type);
6417dd7cddfSDavid du Colombier 	s_free(m->from822);
6427dd7cddfSDavid du Colombier 	m->from822 = addr822(p);
6437dd7cddfSDavid du Colombier }
6447dd7cddfSDavid du Colombier 
6457dd7cddfSDavid du Colombier static void
sender822(Message * m,Header * h,char * p)6467dd7cddfSDavid du Colombier sender822(Message *m, Header *h, char *p)
6477dd7cddfSDavid du Colombier {
6487dd7cddfSDavid du Colombier 	p += strlen(h->type);
6497dd7cddfSDavid du Colombier 	s_free(m->sender822);
6507dd7cddfSDavid du Colombier 	m->sender822 = addr822(p);
6517dd7cddfSDavid du Colombier }
6527dd7cddfSDavid du Colombier 
6537dd7cddfSDavid du Colombier static void
replyto822(Message * m,Header * h,char * p)6547dd7cddfSDavid du Colombier replyto822(Message *m, Header *h, char *p)
6557dd7cddfSDavid du Colombier {
6567dd7cddfSDavid du Colombier 	p += strlen(h->type);
6577dd7cddfSDavid du Colombier 	s_free(m->replyto822);
6587dd7cddfSDavid du Colombier 	m->replyto822 = addr822(p);
6597dd7cddfSDavid du Colombier }
6607dd7cddfSDavid du Colombier 
6617dd7cddfSDavid du Colombier static void
mimeversion(Message * m,Header * h,char * p)6627dd7cddfSDavid du Colombier mimeversion(Message *m, Header *h, char *p)
6637dd7cddfSDavid du Colombier {
6647dd7cddfSDavid du Colombier 	p += strlen(h->type);
6657dd7cddfSDavid du Colombier 	s_free(m->mimeversion);
6667dd7cddfSDavid du Colombier 	m->mimeversion = addr822(p);
6677dd7cddfSDavid du Colombier }
6687dd7cddfSDavid du Colombier 
6697dd7cddfSDavid du Colombier static void
killtrailingwhite(char * p)6707dd7cddfSDavid du Colombier killtrailingwhite(char *p)
6717dd7cddfSDavid du Colombier {
6727dd7cddfSDavid du Colombier 	char *e;
6737dd7cddfSDavid du Colombier 
6747dd7cddfSDavid du Colombier 	e = p + strlen(p) - 1;
6757dd7cddfSDavid du Colombier 	while(e > p && isspace(*e))
6767dd7cddfSDavid du Colombier 		*e-- = 0;
6777dd7cddfSDavid du Colombier }
6787dd7cddfSDavid du Colombier 
6797dd7cddfSDavid du Colombier static void
date822(Message * m,Header * h,char * p)6807dd7cddfSDavid du Colombier date822(Message *m, Header *h, char *p)
6817dd7cddfSDavid du Colombier {
6827dd7cddfSDavid du Colombier 	p += strlen(h->type);
6837dd7cddfSDavid du Colombier 	p = skipwhite(p);
6847dd7cddfSDavid du Colombier 	s_free(m->date822);
6857dd7cddfSDavid du Colombier 	m->date822 = s_copy(p);
6867dd7cddfSDavid du Colombier 	p = s_to_c(m->date822);
6877dd7cddfSDavid du Colombier 	killtrailingwhite(p);
6887dd7cddfSDavid du Colombier }
6897dd7cddfSDavid du Colombier 
6907dd7cddfSDavid du Colombier static void
subject822(Message * m,Header * h,char * p)6917dd7cddfSDavid du Colombier subject822(Message *m, Header *h, char *p)
6927dd7cddfSDavid du Colombier {
6937dd7cddfSDavid du Colombier 	p += strlen(h->type);
6947dd7cddfSDavid du Colombier 	p = skipwhite(p);
6957dd7cddfSDavid du Colombier 	s_free(m->subject822);
6967dd7cddfSDavid du Colombier 	m->subject822 = s_copy(p);
6977dd7cddfSDavid du Colombier 	p = s_to_c(m->subject822);
6987dd7cddfSDavid du Colombier 	killtrailingwhite(p);
6997dd7cddfSDavid du Colombier }
7007dd7cddfSDavid du Colombier 
7017dd7cddfSDavid du Colombier static void
inreplyto822(Message * m,Header * h,char * p)7027dd7cddfSDavid du Colombier inreplyto822(Message *m, Header *h, char *p)
7037dd7cddfSDavid du Colombier {
7047dd7cddfSDavid du Colombier 	p += strlen(h->type);
7057dd7cddfSDavid du Colombier 	p = skipwhite(p);
7067dd7cddfSDavid du Colombier 	s_free(m->inreplyto822);
7077dd7cddfSDavid du Colombier 	m->inreplyto822 = s_copy(p);
7087dd7cddfSDavid du Colombier 	p = s_to_c(m->inreplyto822);
7097dd7cddfSDavid du Colombier 	killtrailingwhite(p);
7107dd7cddfSDavid du Colombier }
7117dd7cddfSDavid du Colombier 
7127dd7cddfSDavid du Colombier static void
messageid822(Message * m,Header * h,char * p)7137dd7cddfSDavid du Colombier messageid822(Message *m, Header *h, char *p)
7147dd7cddfSDavid du Colombier {
7157dd7cddfSDavid du Colombier 	p += strlen(h->type);
7167dd7cddfSDavid du Colombier 	p = skipwhite(p);
7177dd7cddfSDavid du Colombier 	s_free(m->messageid822);
7187dd7cddfSDavid du Colombier 	m->messageid822 = s_copy(p);
7197dd7cddfSDavid du Colombier 	p = s_to_c(m->messageid822);
7207dd7cddfSDavid du Colombier 	killtrailingwhite(p);
7217dd7cddfSDavid du Colombier }
7227dd7cddfSDavid du Colombier 
7237dd7cddfSDavid du Colombier static int
isattribute(char ** pp,char * attr)7247dd7cddfSDavid du Colombier isattribute(char **pp, char *attr)
7257dd7cddfSDavid du Colombier {
7267dd7cddfSDavid du Colombier 	char *p;
7277dd7cddfSDavid du Colombier 	int n;
7287dd7cddfSDavid du Colombier 
7297dd7cddfSDavid du Colombier 	n = strlen(attr);
7307dd7cddfSDavid du Colombier 	p = *pp;
7317dd7cddfSDavid du Colombier 	if(cistrncmp(p, attr, n) != 0)
7327dd7cddfSDavid du Colombier 		return 0;
7337dd7cddfSDavid du Colombier 	p += n;
7347dd7cddfSDavid du Colombier 	while(*p == ' ')
7357dd7cddfSDavid du Colombier 		p++;
7367dd7cddfSDavid du Colombier 	if(*p++ != '=')
7377dd7cddfSDavid du Colombier 		return 0;
7387dd7cddfSDavid du Colombier 	while(*p == ' ')
7397dd7cddfSDavid du Colombier 		p++;
7407dd7cddfSDavid du Colombier 	*pp = p;
7417dd7cddfSDavid du Colombier 	return 1;
7427dd7cddfSDavid du Colombier }
7437dd7cddfSDavid du Colombier 
7447dd7cddfSDavid du Colombier static void
ctype(Message * m,Header * h,char * p)7457dd7cddfSDavid du Colombier ctype(Message *m, Header *h, char *p)
7467dd7cddfSDavid du Colombier {
7477dd7cddfSDavid du Colombier 	String *s;
7487dd7cddfSDavid du Colombier 
7497dd7cddfSDavid du Colombier 	p += h->len;
7507dd7cddfSDavid du Colombier 	p = skipwhite(p);
7517dd7cddfSDavid du Colombier 
7527dd7cddfSDavid du Colombier 	p = getstring(p, m->type, 1);
7537dd7cddfSDavid du Colombier 
7547dd7cddfSDavid du Colombier 	while(*p){
7557dd7cddfSDavid du Colombier 		if(isattribute(&p, "boundary")){
7567dd7cddfSDavid du Colombier 			s = s_new();
7577dd7cddfSDavid du Colombier 			p = getstring(p, s, 0);
7587dd7cddfSDavid du Colombier 			m->boundary = s_reset(m->boundary);
7597dd7cddfSDavid du Colombier 			s_append(m->boundary, "--");
7607dd7cddfSDavid du Colombier 			s_append(m->boundary, s_to_c(s));
7617dd7cddfSDavid du Colombier 			s_free(s);
7627dd7cddfSDavid du Colombier 		} else if(cistrncmp(p, "multipart", 9) == 0){
7637dd7cddfSDavid du Colombier 			/*
7647dd7cddfSDavid du Colombier 			 *  the first unbounded part of a multipart message,
7657dd7cddfSDavid du Colombier 			 *  the preamble, is not displayed or saved
7667dd7cddfSDavid du Colombier 			 */
7677dd7cddfSDavid du Colombier 		} else if(isattribute(&p, "name")){
7687dd7cddfSDavid du Colombier 			if(m->filename == nil)
7697dd7cddfSDavid du Colombier 				setfilename(m, p);
7707dd7cddfSDavid du Colombier 		} else if(isattribute(&p, "charset")){
7717dd7cddfSDavid du Colombier 			p = getstring(p, s_reset(m->charset), 0);
7727dd7cddfSDavid du Colombier 		}
7737dd7cddfSDavid du Colombier 
7747dd7cddfSDavid du Colombier 		p = skiptosemi(p);
7757dd7cddfSDavid du Colombier 	}
7767dd7cddfSDavid du Colombier }
7777dd7cddfSDavid du Colombier 
7787dd7cddfSDavid du Colombier static void
cencoding(Message * m,Header * h,char * p)7797dd7cddfSDavid du Colombier cencoding(Message *m, Header *h, char *p)
7807dd7cddfSDavid du Colombier {
7817dd7cddfSDavid du Colombier 	p += h->len;
7827dd7cddfSDavid du Colombier 	p = skipwhite(p);
7837dd7cddfSDavid du Colombier 	if(cistrncmp(p, "base64", 6) == 0)
7847dd7cddfSDavid du Colombier 		m->encoding = Ebase64;
7857dd7cddfSDavid du Colombier 	else if(cistrncmp(p, "quoted-printable", 16) == 0)
7867dd7cddfSDavid du Colombier 		m->encoding = Equoted;
7877dd7cddfSDavid du Colombier }
7887dd7cddfSDavid du Colombier 
7897dd7cddfSDavid du Colombier static void
cdisposition(Message * m,Header * h,char * p)7907dd7cddfSDavid du Colombier cdisposition(Message *m, Header *h, char *p)
7917dd7cddfSDavid du Colombier {
7927dd7cddfSDavid du Colombier 	p += h->len;
7937dd7cddfSDavid du Colombier 	p = skipwhite(p);
7947dd7cddfSDavid du Colombier 	while(*p){
7957dd7cddfSDavid du Colombier 		if(cistrncmp(p, "inline", 6) == 0){
7967dd7cddfSDavid du Colombier 			m->disposition = Dinline;
7977dd7cddfSDavid du Colombier 		} else if(cistrncmp(p, "attachment", 10) == 0){
7987dd7cddfSDavid du Colombier 			m->disposition = Dfile;
7997dd7cddfSDavid du Colombier 		} else if(cistrncmp(p, "filename=", 9) == 0){
8007dd7cddfSDavid du Colombier 			p += 9;
8017dd7cddfSDavid du Colombier 			setfilename(m, p);
8027dd7cddfSDavid du Colombier 		}
8037dd7cddfSDavid du Colombier 		p = skiptosemi(p);
8047dd7cddfSDavid du Colombier 	}
8057dd7cddfSDavid du Colombier 
8067dd7cddfSDavid du Colombier }
8077dd7cddfSDavid du Colombier 
8087dd7cddfSDavid du Colombier ulong msgallocd, msgfreed;
8097dd7cddfSDavid du Colombier 
8107dd7cddfSDavid du Colombier Message*
newmessage(Message * parent)8117dd7cddfSDavid du Colombier newmessage(Message *parent)
8127dd7cddfSDavid du Colombier {
8137dd7cddfSDavid du Colombier 	static int id;
8147dd7cddfSDavid du Colombier 	Message *m;
8157dd7cddfSDavid du Colombier 
8167dd7cddfSDavid du Colombier 	msgallocd++;
8177dd7cddfSDavid du Colombier 
8187dd7cddfSDavid du Colombier 	m = emalloc(sizeof(*m));
8197dd7cddfSDavid du Colombier 	memset(m, 0, sizeof(*m));
8207dd7cddfSDavid du Colombier 	m->disposition = Dnone;
8217dd7cddfSDavid du Colombier 	m->type = s_copy("text/plain");
8227dd7cddfSDavid du Colombier 	m->charset = s_copy("iso-8859-1");
8237dd7cddfSDavid du Colombier 	m->id = newid();
8247dd7cddfSDavid du Colombier 	if(parent)
8257dd7cddfSDavid du Colombier 		sprint(m->name, "%d", ++(parent->subname));
8267dd7cddfSDavid du Colombier 	if(parent == nil)
8277dd7cddfSDavid du Colombier 		parent = m;
8287dd7cddfSDavid du Colombier 	m->whole = parent;
8297dd7cddfSDavid du Colombier 	m->hlen = -1;
8307dd7cddfSDavid du Colombier 	return m;
8317dd7cddfSDavid du Colombier }
8327dd7cddfSDavid du Colombier 
8337dd7cddfSDavid du Colombier // delete a message from a mailbox
8347dd7cddfSDavid du Colombier void
delmessage(Mailbox * mb,Message * m)8357dd7cddfSDavid du Colombier delmessage(Mailbox *mb, Message *m)
8367dd7cddfSDavid du Colombier {
8377dd7cddfSDavid du Colombier 	Message **l;
8387dd7cddfSDavid du Colombier 	int i;
8397dd7cddfSDavid du Colombier 
8407dd7cddfSDavid du Colombier 	mb->vers++;
8417dd7cddfSDavid du Colombier 	msgfreed++;
8427dd7cddfSDavid du Colombier 
8437dd7cddfSDavid du Colombier 	if(m->whole != m){
8447dd7cddfSDavid du Colombier 		// unchain from parent
8457dd7cddfSDavid du Colombier 		for(l = &m->whole->part; *l && *l != m; l = &(*l)->next)
8467dd7cddfSDavid du Colombier 			;
8477dd7cddfSDavid du Colombier 		if(*l != nil)
8487dd7cddfSDavid du Colombier 			*l = m->next;
8497dd7cddfSDavid du Colombier 
8507dd7cddfSDavid du Colombier 		// clear out of name lookup hash table
8517dd7cddfSDavid du Colombier 		if(m->whole->whole == m->whole)
8529a747e4fSDavid du Colombier 			hfree(PATH(mb->id, Qmbox), m->name);
8537dd7cddfSDavid du Colombier 		else
8549a747e4fSDavid du Colombier 			hfree(PATH(m->whole->id, Qdir), m->name);
8557dd7cddfSDavid du Colombier 		for(i = 0; i < Qmax; i++)
8569a747e4fSDavid du Colombier 			hfree(PATH(m->id, Qdir), dirtab[i]);
8577dd7cddfSDavid du Colombier 	}
8587dd7cddfSDavid du Colombier 
8597dd7cddfSDavid du Colombier 	/* recurse through sub-parts */
8607dd7cddfSDavid du Colombier 	while(m->part)
8617dd7cddfSDavid du Colombier 		delmessage(mb, m->part);
8627dd7cddfSDavid du Colombier 
8637dd7cddfSDavid du Colombier 	/* free memory */
8647dd7cddfSDavid du Colombier 	if(m->mallocd)
8657dd7cddfSDavid du Colombier 		free(m->start);
8667dd7cddfSDavid du Colombier 	if(m->hallocd)
8677dd7cddfSDavid du Colombier 		free(m->header);
8687dd7cddfSDavid du Colombier 	if(m->ballocd)
8697dd7cddfSDavid du Colombier 		free(m->body);
8707dd7cddfSDavid du Colombier 	s_free(m->unixfrom);
8717dd7cddfSDavid du Colombier 	s_free(m->unixdate);
8729a747e4fSDavid du Colombier 	s_free(m->unixheader);
8737dd7cddfSDavid du Colombier 	s_free(m->from822);
8747dd7cddfSDavid du Colombier 	s_free(m->sender822);
8757dd7cddfSDavid du Colombier 	s_free(m->to822);
8767dd7cddfSDavid du Colombier 	s_free(m->bcc822);
87759cc4ca5SDavid du Colombier 	s_free(m->cc822);
8787dd7cddfSDavid du Colombier 	s_free(m->replyto822);
8797dd7cddfSDavid du Colombier 	s_free(m->date822);
8807dd7cddfSDavid du Colombier 	s_free(m->inreplyto822);
88159cc4ca5SDavid du Colombier 	s_free(m->subject822);
8827dd7cddfSDavid du Colombier 	s_free(m->messageid822);
8837dd7cddfSDavid du Colombier 	s_free(m->addrs);
8847dd7cddfSDavid du Colombier 	s_free(m->mimeversion);
88559cc4ca5SDavid du Colombier 	s_free(m->sdigest);
8867dd7cddfSDavid du Colombier 	s_free(m->boundary);
8877dd7cddfSDavid du Colombier 	s_free(m->type);
8887dd7cddfSDavid du Colombier 	s_free(m->charset);
8897dd7cddfSDavid du Colombier 	s_free(m->filename);
8907dd7cddfSDavid du Colombier 
8917dd7cddfSDavid du Colombier 	free(m);
8927dd7cddfSDavid du Colombier }
8937dd7cddfSDavid du Colombier 
8947dd7cddfSDavid du Colombier // mark messages (identified by path) for deletion
8957dd7cddfSDavid du Colombier void
delmessages(int ac,char ** av)8967dd7cddfSDavid du Colombier delmessages(int ac, char **av)
8977dd7cddfSDavid du Colombier {
8987dd7cddfSDavid du Colombier 	Mailbox *mb;
8997dd7cddfSDavid du Colombier 	Message *m;
9007dd7cddfSDavid du Colombier 	int i, needwrite;
9017dd7cddfSDavid du Colombier 
9027dd7cddfSDavid du Colombier 	qlock(&mbllock);
9037dd7cddfSDavid du Colombier 	for(mb = mbl; mb != nil; mb = mb->next)
9047dd7cddfSDavid du Colombier 		if(strcmp(av[0], mb->name) == 0){
9057dd7cddfSDavid du Colombier 			qlock(mb);
9067dd7cddfSDavid du Colombier 			break;
9077dd7cddfSDavid du Colombier 		}
9087dd7cddfSDavid du Colombier 	qunlock(&mbllock);
9097dd7cddfSDavid du Colombier 	if(mb == nil)
9107dd7cddfSDavid du Colombier 		return;
9117dd7cddfSDavid du Colombier 
9127dd7cddfSDavid du Colombier 	needwrite = 0;
9137dd7cddfSDavid du Colombier 	for(i = 1; i < ac; i++){
9147dd7cddfSDavid du Colombier 		for(m = mb->root->part; m != nil; m = m->next)
9157dd7cddfSDavid du Colombier 			if(strcmp(m->name, av[i]) == 0){
9167dd7cddfSDavid du Colombier 				if(!m->deleted){
9177dd7cddfSDavid du Colombier 					mailplumb(mb, m, 1);
9187dd7cddfSDavid du Colombier 					needwrite = 1;
9197dd7cddfSDavid du Colombier 					m->deleted = 1;
92059cc4ca5SDavid du Colombier 					logmsg("deleting", m);
9217dd7cddfSDavid du Colombier 				}
9227dd7cddfSDavid du Colombier 				break;
9237dd7cddfSDavid du Colombier 			}
9247dd7cddfSDavid du Colombier 	}
9257dd7cddfSDavid du Colombier 	if(needwrite)
9267dd7cddfSDavid du Colombier 		syncmbox(mb, 1);
9277dd7cddfSDavid du Colombier 	qunlock(mb);
9287dd7cddfSDavid du Colombier }
9297dd7cddfSDavid du Colombier 
9307dd7cddfSDavid du Colombier /*
9317dd7cddfSDavid du Colombier  *  the following are called with the mailbox qlocked
9327dd7cddfSDavid du Colombier  */
9337dd7cddfSDavid du Colombier void
msgincref(Message * m)9347dd7cddfSDavid du Colombier msgincref(Message *m)
9357dd7cddfSDavid du Colombier {
9367dd7cddfSDavid du Colombier 	m->refs++;
9377dd7cddfSDavid du Colombier }
9387dd7cddfSDavid du Colombier void
msgdecref(Mailbox * mb,Message * m)9397dd7cddfSDavid du Colombier msgdecref(Mailbox *mb, Message *m)
9407dd7cddfSDavid du Colombier {
9417dd7cddfSDavid du Colombier 	m->refs--;
9427dd7cddfSDavid du Colombier 	if(m->refs == 0 && m->deleted)
9437dd7cddfSDavid du Colombier 		syncmbox(mb, 1);
9447dd7cddfSDavid du Colombier }
9457dd7cddfSDavid du Colombier 
9467dd7cddfSDavid du Colombier /*
9477dd7cddfSDavid du Colombier  *  the following are called with mbllock'd
9487dd7cddfSDavid du Colombier  */
9497dd7cddfSDavid du Colombier void
mboxincref(Mailbox * mb)9507dd7cddfSDavid du Colombier mboxincref(Mailbox *mb)
9517dd7cddfSDavid du Colombier {
9529a747e4fSDavid du Colombier 	assert(mb->refs > 0);
9537dd7cddfSDavid du Colombier 	mb->refs++;
9547dd7cddfSDavid du Colombier }
9557dd7cddfSDavid du Colombier void
mboxdecref(Mailbox * mb)9567dd7cddfSDavid du Colombier mboxdecref(Mailbox *mb)
9577dd7cddfSDavid du Colombier {
9589a747e4fSDavid du Colombier 	assert(mb->refs > 0);
9597dd7cddfSDavid du Colombier 	qlock(mb);
9607dd7cddfSDavid du Colombier 	mb->refs--;
9617dd7cddfSDavid du Colombier 	if(mb->refs == 0){
9627dd7cddfSDavid du Colombier 		delmessage(mb, mb->root);
96380ee5cbfSDavid du Colombier 		if(mb->ctl)
9649a747e4fSDavid du Colombier 			hfree(PATH(mb->id, Qmbox), "ctl");
96580ee5cbfSDavid du Colombier 		if(mb->close)
96680ee5cbfSDavid du Colombier 			(*mb->close)(mb);
9677dd7cddfSDavid du Colombier 		free(mb);
9687dd7cddfSDavid du Colombier 	} else
9697dd7cddfSDavid du Colombier 		qunlock(mb);
9707dd7cddfSDavid du Colombier }
9717dd7cddfSDavid du Colombier 
9727dd7cddfSDavid du Colombier int
cistrncmp(char * a,char * b,int n)9737dd7cddfSDavid du Colombier cistrncmp(char *a, char *b, int n)
9747dd7cddfSDavid du Colombier {
9757dd7cddfSDavid du Colombier 	while(n-- > 0){
9767dd7cddfSDavid du Colombier 		if(tolower(*a++) != tolower(*b++))
9777dd7cddfSDavid du Colombier 			return -1;
9787dd7cddfSDavid du Colombier 	}
9797dd7cddfSDavid du Colombier 	return 0;
9807dd7cddfSDavid du Colombier }
9817dd7cddfSDavid du Colombier 
9827dd7cddfSDavid du Colombier int
cistrcmp(char * a,char * b)9837dd7cddfSDavid du Colombier cistrcmp(char *a, char *b)
9847dd7cddfSDavid du Colombier {
9857dd7cddfSDavid du Colombier 	for(;;){
9867dd7cddfSDavid du Colombier 		if(tolower(*a) != tolower(*b++))
9877dd7cddfSDavid du Colombier 			return -1;
9887dd7cddfSDavid du Colombier 		if(*a++ == 0)
9897dd7cddfSDavid du Colombier 			break;
9907dd7cddfSDavid du Colombier 	}
9917dd7cddfSDavid du Colombier 	return 0;
9927dd7cddfSDavid du Colombier }
9937dd7cddfSDavid du Colombier 
9947dd7cddfSDavid du Colombier static char*
skipwhite(char * p)9957dd7cddfSDavid du Colombier skipwhite(char *p)
9967dd7cddfSDavid du Colombier {
9977dd7cddfSDavid du Colombier 	while(isspace(*p))
9987dd7cddfSDavid du Colombier 		p++;
9997dd7cddfSDavid du Colombier 	return p;
10007dd7cddfSDavid du Colombier }
10017dd7cddfSDavid du Colombier 
10027dd7cddfSDavid du Colombier static char*
skiptosemi(char * p)10037dd7cddfSDavid du Colombier skiptosemi(char *p)
10047dd7cddfSDavid du Colombier {
10057dd7cddfSDavid du Colombier 	while(*p && *p != ';')
10067dd7cddfSDavid du Colombier 		p++;
10077dd7cddfSDavid du Colombier 	while(*p == ';' || isspace(*p))
10087dd7cddfSDavid du Colombier 		p++;
10097dd7cddfSDavid du Colombier 	return p;
10107dd7cddfSDavid du Colombier }
10117dd7cddfSDavid du Colombier 
10127dd7cddfSDavid du Colombier static char*
getstring(char * p,String * s,int dolower)10137dd7cddfSDavid du Colombier getstring(char *p, String *s, int dolower)
10147dd7cddfSDavid du Colombier {
10157dd7cddfSDavid du Colombier 	s = s_reset(s);
10167dd7cddfSDavid du Colombier 	p = skipwhite(p);
10177dd7cddfSDavid du Colombier 	if(*p == '"'){
10187dd7cddfSDavid du Colombier 		p++;
10197dd7cddfSDavid du Colombier 		for(;*p && *p != '"'; p++)
10207dd7cddfSDavid du Colombier 			if(dolower)
10217dd7cddfSDavid du Colombier 				s_putc(s, tolower(*p));
10227dd7cddfSDavid du Colombier 			else
10237dd7cddfSDavid du Colombier 				s_putc(s, *p);
10247dd7cddfSDavid du Colombier 		if(*p == '"')
10257dd7cddfSDavid du Colombier 			p++;
10267dd7cddfSDavid du Colombier 		s_terminate(s);
10277dd7cddfSDavid du Colombier 
10287dd7cddfSDavid du Colombier 		return p;
10297dd7cddfSDavid du Colombier 	}
10307dd7cddfSDavid du Colombier 
10319a747e4fSDavid du Colombier 	for(; *p && !isspace(*p) && *p != ';'; p++)
10327dd7cddfSDavid du Colombier 		if(dolower)
10337dd7cddfSDavid du Colombier 			s_putc(s, tolower(*p));
10347dd7cddfSDavid du Colombier 		else
10357dd7cddfSDavid du Colombier 			s_putc(s, *p);
10367dd7cddfSDavid du Colombier 	s_terminate(s);
10377dd7cddfSDavid du Colombier 
10387dd7cddfSDavid du Colombier 	return p;
10397dd7cddfSDavid du Colombier }
10407dd7cddfSDavid du Colombier 
10417dd7cddfSDavid du Colombier static void
setfilename(Message * m,char * p)10427dd7cddfSDavid du Colombier setfilename(Message *m, char *p)
10437dd7cddfSDavid du Colombier {
10447dd7cddfSDavid du Colombier 	m->filename = s_reset(m->filename);
10457dd7cddfSDavid du Colombier 	getstring(p, m->filename, 0);
10467dd7cddfSDavid du Colombier 	for(p = s_to_c(m->filename); *p; p++)
10477dd7cddfSDavid du Colombier 		if(*p == ' ' || *p == '\t' || *p == ';')
10487dd7cddfSDavid du Colombier 			*p = '_';
10497dd7cddfSDavid du Colombier }
10507dd7cddfSDavid du Colombier 
10517dd7cddfSDavid du Colombier //
10527dd7cddfSDavid du Colombier // undecode message body
10537dd7cddfSDavid du Colombier //
10547dd7cddfSDavid du Colombier void
decode(Message * m)10557dd7cddfSDavid du Colombier decode(Message *m)
10567dd7cddfSDavid du Colombier {
10577dd7cddfSDavid du Colombier 	int i, len;
10587dd7cddfSDavid du Colombier 	char *x;
10597dd7cddfSDavid du Colombier 
10607dd7cddfSDavid du Colombier 	if(m->decoded)
10617dd7cddfSDavid du Colombier 		return;
10627dd7cddfSDavid du Colombier 	switch(m->encoding){
10637dd7cddfSDavid du Colombier 	case Ebase64:
10647dd7cddfSDavid du Colombier 		len = m->bend - m->body;
10657dd7cddfSDavid du Colombier 		i = (len*3)/4+1;	// room for max chars + null
10667dd7cddfSDavid du Colombier 		x = emalloc(i);
10677dd7cddfSDavid du Colombier 		len = dec64((uchar*)x, i, m->body, len);
10687dd7cddfSDavid du Colombier 		if(m->ballocd)
10697dd7cddfSDavid du Colombier 			free(m->body);
10707dd7cddfSDavid du Colombier 		m->body = x;
10717dd7cddfSDavid du Colombier 		m->bend = x + len;
10727dd7cddfSDavid du Colombier 		m->ballocd = 1;
10737dd7cddfSDavid du Colombier 		break;
10747dd7cddfSDavid du Colombier 	case Equoted:
10757dd7cddfSDavid du Colombier 		len = m->bend - m->body;
10767dd7cddfSDavid du Colombier 		x = emalloc(len+2);	// room for null and possible extra nl
107717dd33a2SDavid du Colombier 		len = decquoted(x, m->body, m->bend, 0);
10787dd7cddfSDavid du Colombier 		if(m->ballocd)
10797dd7cddfSDavid du Colombier 			free(m->body);
10807dd7cddfSDavid du Colombier 		m->body = x;
10817dd7cddfSDavid du Colombier 		m->bend = x + len;
10827dd7cddfSDavid du Colombier 		m->ballocd = 1;
10837dd7cddfSDavid du Colombier 		break;
10847dd7cddfSDavid du Colombier 	default:
10857dd7cddfSDavid du Colombier 		break;
10867dd7cddfSDavid du Colombier 	}
10877dd7cddfSDavid du Colombier 	m->decoded = 1;
10887dd7cddfSDavid du Colombier }
10897dd7cddfSDavid du Colombier 
10907dd7cddfSDavid du Colombier // convert latin1 to utf
10917dd7cddfSDavid du Colombier void
convert(Message * m)10927dd7cddfSDavid du Colombier convert(Message *m)
10937dd7cddfSDavid du Colombier {
10947dd7cddfSDavid du Colombier 	int len;
10957dd7cddfSDavid du Colombier 	char *x;
10967dd7cddfSDavid du Colombier 
10977dd7cddfSDavid du Colombier 	// don't convert if we're not a leaf, not text, or already converted
10987dd7cddfSDavid du Colombier 	if(m->converted)
10997dd7cddfSDavid du Colombier 		return;
11007dd7cddfSDavid du Colombier 	if(m->part != nil)
11017dd7cddfSDavid du Colombier 		return;
11027dd7cddfSDavid du Colombier 	if(cistrncmp(s_to_c(m->type), "text", 4) != 0)
11037dd7cddfSDavid du Colombier 		return;
11047dd7cddfSDavid du Colombier 
1105816336a7SDavid du Colombier 	len = xtoutf(s_to_c(m->charset), &x, m->body, m->bend);
11067dd7cddfSDavid du Colombier 	if(len > 0){
11077dd7cddfSDavid du Colombier 		if(m->ballocd)
11087dd7cddfSDavid du Colombier 			free(m->body);
11097dd7cddfSDavid du Colombier 		m->body = x;
11107dd7cddfSDavid du Colombier 		m->bend = x + len;
11117dd7cddfSDavid du Colombier 		m->ballocd = 1;
11127dd7cddfSDavid du Colombier 	}
11137dd7cddfSDavid du Colombier 	m->converted = 1;
11147dd7cddfSDavid du Colombier }
11157dd7cddfSDavid du Colombier 
11167dd7cddfSDavid du Colombier static int
hex2int(int x)11177dd7cddfSDavid du Colombier hex2int(int x)
11187dd7cddfSDavid du Colombier {
11197dd7cddfSDavid du Colombier 	if(x >= '0' && x <= '9')
11207dd7cddfSDavid du Colombier 		return x - '0';
11217dd7cddfSDavid du Colombier 	if(x >= 'A' && x <= 'F')
11227dd7cddfSDavid du Colombier 		return (x - 'A') + 10;
11237dd7cddfSDavid du Colombier 	if(x >= 'a' && x <= 'f')
11247dd7cddfSDavid du Colombier 		return (x - 'a') + 10;
11256aadf539SDavid du Colombier 	return -1;
11267dd7cddfSDavid du Colombier }
11277dd7cddfSDavid du Colombier 
1128816336a7SDavid du Colombier // underscores are translated in 2047 headers (uscores=1)
1129816336a7SDavid du Colombier // but not in the body (uscores=0)
11307dd7cddfSDavid du Colombier static char*
decquotedline(char * out,char * in,char * e,int uscores)113117dd33a2SDavid du Colombier decquotedline(char *out, char *in, char *e, int uscores)
11327dd7cddfSDavid du Colombier {
11336aadf539SDavid du Colombier 	int c, c2, soft;
11347dd7cddfSDavid du Colombier 
11357dd7cddfSDavid du Colombier 	/* dump trailing white space */
11367dd7cddfSDavid du Colombier 	while(e >= in && (*e == ' ' || *e == '\t' || *e == '\r' || *e == '\n'))
11377dd7cddfSDavid du Colombier 		e--;
11387dd7cddfSDavid du Colombier 
11397dd7cddfSDavid du Colombier 	/* trailing '=' means no newline */
11407dd7cddfSDavid du Colombier 	if(*e == '='){
11417dd7cddfSDavid du Colombier 		soft = 1;
11427dd7cddfSDavid du Colombier 		e--;
11437dd7cddfSDavid du Colombier 	} else
11447dd7cddfSDavid du Colombier 		soft = 0;
11457dd7cddfSDavid du Colombier 
11467dd7cddfSDavid du Colombier 	while(in <= e){
11477dd7cddfSDavid du Colombier 		c = (*in++) & 0xff;
1148816336a7SDavid du Colombier 		switch(c){
1149816336a7SDavid du Colombier 		case '_':
1150816336a7SDavid du Colombier 			if(uscores){
1151816336a7SDavid du Colombier 				*out++ = ' ';
1152816336a7SDavid du Colombier 				break;
1153816336a7SDavid du Colombier 			}
1154816336a7SDavid du Colombier 		default:
11557dd7cddfSDavid du Colombier 			*out++ = c;
11567dd7cddfSDavid du Colombier 			break;
1157816336a7SDavid du Colombier 		case '=':
11586aadf539SDavid du Colombier 			c  = hex2int(*in++);
11596aadf539SDavid du Colombier 			c2 = hex2int(*in++);
11606aadf539SDavid du Colombier 			if (c != -1 && c2 != -1)
11616aadf539SDavid du Colombier 				*out++ = c<<4 | c2;
11626aadf539SDavid du Colombier 			else {
11636aadf539SDavid du Colombier 				*out++ = '=';
11646aadf539SDavid du Colombier 				in -= 2;
11656aadf539SDavid du Colombier 			}
11667dd7cddfSDavid du Colombier 			break;
11677dd7cddfSDavid du Colombier 		}
11687dd7cddfSDavid du Colombier 	}
11697dd7cddfSDavid du Colombier 	if(!soft)
11707dd7cddfSDavid du Colombier 		*out++ = '\n';
11717dd7cddfSDavid du Colombier 	*out = 0;
11727dd7cddfSDavid du Colombier 
11737dd7cddfSDavid du Colombier 	return out;
11747dd7cddfSDavid du Colombier }
11757dd7cddfSDavid du Colombier 
11767dd7cddfSDavid du Colombier int
decquoted(char * out,char * in,char * e,int uscores)117717dd33a2SDavid du Colombier decquoted(char *out, char *in, char *e, int uscores)
11787dd7cddfSDavid du Colombier {
11797dd7cddfSDavid du Colombier 	char *p, *nl;
11807dd7cddfSDavid du Colombier 
11817dd7cddfSDavid du Colombier 	p = out;
11827dd7cddfSDavid du Colombier 	while((nl = strchr(in, '\n')) != nil && nl < e){
118317dd33a2SDavid du Colombier 		p = decquotedline(p, in, nl, uscores);
11847dd7cddfSDavid du Colombier 		in = nl + 1;
11857dd7cddfSDavid du Colombier 	}
11867dd7cddfSDavid du Colombier 	if(in < e)
118717dd33a2SDavid du Colombier 		p = decquotedline(p, in, e-1, uscores);
11887dd7cddfSDavid du Colombier 
11897dd7cddfSDavid du Colombier 	// make sure we end with a new line
11907dd7cddfSDavid du Colombier 	if(*(p-1) != '\n'){
11917dd7cddfSDavid du Colombier 		*p++ = '\n';
11927dd7cddfSDavid du Colombier 		*p = 0;
11937dd7cddfSDavid du Colombier 	}
11947dd7cddfSDavid du Colombier 
11957dd7cddfSDavid du Colombier 	return p - out;
11967dd7cddfSDavid du Colombier }
11977dd7cddfSDavid du Colombier 
11987dd7cddfSDavid du Colombier static char*
lowercase(char * p)11997dd7cddfSDavid du Colombier lowercase(char *p)
12007dd7cddfSDavid du Colombier {
12017dd7cddfSDavid du Colombier 	char *op;
12027dd7cddfSDavid du Colombier 	int c;
12037dd7cddfSDavid du Colombier 
12047dd7cddfSDavid du Colombier 	for(op = p; c = *p; p++)
12057dd7cddfSDavid du Colombier 		if(isupper(c))
12067dd7cddfSDavid du Colombier 			*p = tolower(c);
12077dd7cddfSDavid du Colombier 	return op;
12087dd7cddfSDavid du Colombier }
12097dd7cddfSDavid du Colombier 
12107dd7cddfSDavid du Colombier // translate latin1 directly since it fits neatly in utf
1211816336a7SDavid du Colombier static int
latin1toutf(char ** out,char * in,char * e)1212816336a7SDavid du Colombier latin1toutf(char **out, char *in, char *e)
12137dd7cddfSDavid du Colombier {
1214816336a7SDavid du Colombier 	int n;
12157dd7cddfSDavid du Colombier 	char *p;
1216816336a7SDavid du Colombier 	Rune r;
12177dd7cddfSDavid du Colombier 
1218816336a7SDavid du Colombier 	n = 0;
1219816336a7SDavid du Colombier 	for(p = in; p < e; p++)
1220816336a7SDavid du Colombier 		if(*p & 0x80)
1221816336a7SDavid du Colombier 			n++;
1222816336a7SDavid du Colombier 	if(n == 0)
1223816336a7SDavid du Colombier 		return 0;
1224816336a7SDavid du Colombier 
1225816336a7SDavid du Colombier 	n += e-in;
1226816336a7SDavid du Colombier 	*out = p = malloc(n+1);
1227816336a7SDavid du Colombier 	if(p == nil)
1228816336a7SDavid du Colombier 		return 0;
1229816336a7SDavid du Colombier 
12307dd7cddfSDavid du Colombier 	for(; in < e; in++){
1231816336a7SDavid du Colombier 		r = (uchar)*in;
12327dd7cddfSDavid du Colombier 		p += runetochar(p, &r);
12337dd7cddfSDavid du Colombier 	}
12347dd7cddfSDavid du Colombier 	*p = 0;
1235816336a7SDavid du Colombier 	return p - *out;
12367dd7cddfSDavid du Colombier }
12377dd7cddfSDavid du Colombier 
1238816336a7SDavid du Colombier // translate any thing using the tcs program
12397dd7cddfSDavid du Colombier int
xtoutf(char * charset,char ** out,char * in,char * e)12407dd7cddfSDavid du Colombier xtoutf(char *charset, char **out, char *in, char *e)
12417dd7cddfSDavid du Colombier {
12427dd7cddfSDavid du Colombier 	char *av[4];
12437dd7cddfSDavid du Colombier 	int totcs[2];
12447dd7cddfSDavid du Colombier 	int fromtcs[2];
12457dd7cddfSDavid du Colombier 	int n, len, sofar;
12467dd7cddfSDavid du Colombier 	char *p;
12477dd7cddfSDavid du Colombier 
1248816336a7SDavid du Colombier 	// might not need to convert
1249816336a7SDavid du Colombier 	if(cistrcmp(charset, "us-ascii") == 0 || cistrcmp(charset, "utf-8") == 0)
1250816336a7SDavid du Colombier 		return 0;
1251816336a7SDavid du Colombier 	if(cistrcmp(charset, "iso-8859-1") == 0)
1252816336a7SDavid du Colombier 		return latin1toutf(out, in, e);
1253816336a7SDavid du Colombier 
12547dd7cddfSDavid du Colombier 	len = e-in+1;
12557dd7cddfSDavid du Colombier 	sofar = 0;
12567dd7cddfSDavid du Colombier 	*out = p = malloc(len+1);
12577dd7cddfSDavid du Colombier 	if(p == nil)
12587dd7cddfSDavid du Colombier 		return 0;
12597dd7cddfSDavid du Colombier 
12607dd7cddfSDavid du Colombier 	av[0] = charset;
12617dd7cddfSDavid du Colombier 	av[1] = "-f";
12627dd7cddfSDavid du Colombier 	av[2] = charset;
12637dd7cddfSDavid du Colombier 	av[3] = 0;
12647dd7cddfSDavid du Colombier 	if(pipe(totcs) < 0)
1265816336a7SDavid du Colombier 		goto error;
12667dd7cddfSDavid du Colombier 	if(pipe(fromtcs) < 0){
12677dd7cddfSDavid du Colombier 		close(totcs[0]); close(totcs[1]);
1268816336a7SDavid du Colombier 		goto error;
12697dd7cddfSDavid du Colombier 	}
12707dd7cddfSDavid du Colombier 	switch(rfork(RFPROC|RFFDG|RFNOWAIT)){
12717dd7cddfSDavid du Colombier 	case -1:
12727dd7cddfSDavid du Colombier 		close(fromtcs[0]); close(fromtcs[1]);
12737dd7cddfSDavid du Colombier 		close(totcs[0]); close(totcs[1]);
1274816336a7SDavid du Colombier 		goto error;
12757dd7cddfSDavid du Colombier 	case 0:
12767dd7cddfSDavid du Colombier 		close(fromtcs[0]); close(totcs[1]);
12777dd7cddfSDavid du Colombier 		dup(fromtcs[1], 1);
12787dd7cddfSDavid du Colombier 		dup(totcs[0], 0);
12797dd7cddfSDavid du Colombier 		close(fromtcs[1]); close(totcs[0]);
12809a747e4fSDavid du Colombier 		dup(open("/dev/null", OWRITE), 2);
12817dd7cddfSDavid du Colombier 		exec("/bin/tcs", av);
12827dd7cddfSDavid du Colombier 		_exits(0);
12837dd7cddfSDavid du Colombier 	default:
12847dd7cddfSDavid du Colombier 		close(fromtcs[1]); close(totcs[0]);
12857dd7cddfSDavid du Colombier 		switch(rfork(RFPROC|RFFDG|RFNOWAIT)){
12867dd7cddfSDavid du Colombier 		case -1:
12877dd7cddfSDavid du Colombier 			close(fromtcs[0]); close(totcs[1]);
1288816336a7SDavid du Colombier 			goto error;
12897dd7cddfSDavid du Colombier 		case 0:
12907dd7cddfSDavid du Colombier 			close(fromtcs[0]);
12917dd7cddfSDavid du Colombier 			while(in < e){
12927dd7cddfSDavid du Colombier 				n = write(totcs[1], in, e-in);
12937dd7cddfSDavid du Colombier 				if(n <= 0)
12947dd7cddfSDavid du Colombier 					break;
12957dd7cddfSDavid du Colombier 				in += n;
12967dd7cddfSDavid du Colombier 			}
12977dd7cddfSDavid du Colombier 			close(totcs[1]);
12987dd7cddfSDavid du Colombier 			_exits(0);
12997dd7cddfSDavid du Colombier 		default:
13007dd7cddfSDavid du Colombier 			close(totcs[1]);
13017dd7cddfSDavid du Colombier 			for(;;){
13027dd7cddfSDavid du Colombier 				n = read(fromtcs[0], &p[sofar], len-sofar);
13037dd7cddfSDavid du Colombier 				if(n <= 0)
13047dd7cddfSDavid du Colombier 					break;
13057dd7cddfSDavid du Colombier 				sofar += n;
13067dd7cddfSDavid du Colombier 				p[sofar] = 0;
13077dd7cddfSDavid du Colombier 				if(sofar == len){
13087dd7cddfSDavid du Colombier 					len += 1024;
1309816336a7SDavid du Colombier 					p = realloc(p, len+1);
13107dd7cddfSDavid du Colombier 					if(p == nil)
1311816336a7SDavid du Colombier 						goto error;
1312816336a7SDavid du Colombier 					*out = p;
13137dd7cddfSDavid du Colombier 				}
13147dd7cddfSDavid du Colombier 			}
13157dd7cddfSDavid du Colombier 			close(fromtcs[0]);
13167dd7cddfSDavid du Colombier 			break;
13177dd7cddfSDavid du Colombier 		}
13187dd7cddfSDavid du Colombier 		break;
13197dd7cddfSDavid du Colombier 	}
1320816336a7SDavid du Colombier 	if(sofar == 0)
1321816336a7SDavid du Colombier 		goto error;
13227dd7cddfSDavid du Colombier 	return sofar;
13237dd7cddfSDavid du Colombier 
1324816336a7SDavid du Colombier error:
1325816336a7SDavid du Colombier 	free(*out);
1326816336a7SDavid du Colombier 	*out = nil;
1327816336a7SDavid du Colombier 	return 0;
13287dd7cddfSDavid du Colombier }
13297dd7cddfSDavid du Colombier 
13307dd7cddfSDavid du Colombier void *
emalloc(ulong n)13317dd7cddfSDavid du Colombier emalloc(ulong n)
13327dd7cddfSDavid du Colombier {
13337dd7cddfSDavid du Colombier 	void *p;
13347dd7cddfSDavid du Colombier 
13357dd7cddfSDavid du Colombier 	p = mallocz(n, 1);
13367dd7cddfSDavid du Colombier 	if(!p){
133780ee5cbfSDavid du Colombier 		fprint(2, "%s: out of memory alloc %lud\n", argv0, n);
13387dd7cddfSDavid du Colombier 		exits("out of memory");
13397dd7cddfSDavid du Colombier 	}
134080ee5cbfSDavid du Colombier 	setmalloctag(p, getcallerpc(&n));
13417dd7cddfSDavid du Colombier 	return p;
13427dd7cddfSDavid du Colombier }
13437dd7cddfSDavid du Colombier 
13447dd7cddfSDavid du Colombier void *
erealloc(void * p,ulong n)13457dd7cddfSDavid du Colombier erealloc(void *p, ulong n)
13467dd7cddfSDavid du Colombier {
13473ff48bf5SDavid du Colombier 	if(n == 0)
13483ff48bf5SDavid du Colombier 		n = 1;
13497dd7cddfSDavid du Colombier 	p = realloc(p, n);
13507dd7cddfSDavid du Colombier 	if(!p){
135180ee5cbfSDavid du Colombier 		fprint(2, "%s: out of memory realloc %lud\n", argv0, n);
13527dd7cddfSDavid du Colombier 		exits("out of memory");
13537dd7cddfSDavid du Colombier 	}
135480ee5cbfSDavid du Colombier 	setrealloctag(p, getcallerpc(&p));
13557dd7cddfSDavid du Colombier 	return p;
13567dd7cddfSDavid du Colombier }
13577dd7cddfSDavid du Colombier 
13587dd7cddfSDavid du Colombier void
mailplumb(Mailbox * mb,Message * m,int delete)13597dd7cddfSDavid du Colombier mailplumb(Mailbox *mb, Message *m, int delete)
13607dd7cddfSDavid du Colombier {
13617dd7cddfSDavid du Colombier 	Plumbmsg p;
13627dd7cddfSDavid du Colombier 	Plumbattr a[7];
13637dd7cddfSDavid du Colombier 	char buf[256];
13647dd7cddfSDavid du Colombier 	int ai;
13657dd7cddfSDavid du Colombier 	char lenstr[10], *from, *subject, *date;
13667dd7cddfSDavid du Colombier 	static int fd = -1;
13677dd7cddfSDavid du Colombier 
13687dd7cddfSDavid du Colombier 	if(m->subject822 == nil)
13697dd7cddfSDavid du Colombier 		subject = "";
13707dd7cddfSDavid du Colombier 	else
13717dd7cddfSDavid du Colombier 		subject = s_to_c(m->subject822);
13727dd7cddfSDavid du Colombier 
13737dd7cddfSDavid du Colombier 	if(m->from822 != nil)
13747dd7cddfSDavid du Colombier 		from = s_to_c(m->from822);
13757dd7cddfSDavid du Colombier 	else if(m->unixfrom != nil)
13767dd7cddfSDavid du Colombier 		from = s_to_c(m->unixfrom);
13777dd7cddfSDavid du Colombier 	else
13787dd7cddfSDavid du Colombier 		from = "";
13797dd7cddfSDavid du Colombier 
13807dd7cddfSDavid du Colombier 	if(m->unixdate != nil)
13817dd7cddfSDavid du Colombier 		date = s_to_c(m->unixdate);
13827dd7cddfSDavid du Colombier 	else
13837dd7cddfSDavid du Colombier 		date = "";
13847dd7cddfSDavid du Colombier 
13857dd7cddfSDavid du Colombier 	sprint(lenstr, "%ld", m->end-m->start);
13867dd7cddfSDavid du Colombier 
13877dd7cddfSDavid du Colombier 	if(biffing && !delete)
13887dd7cddfSDavid du Colombier 		print("[ %s / %s / %s ]\n", from, subject, lenstr);
13897dd7cddfSDavid du Colombier 
13907dd7cddfSDavid du Colombier 	if(!plumbing)
13917dd7cddfSDavid du Colombier 		return;
13927dd7cddfSDavid du Colombier 
13937dd7cddfSDavid du Colombier 	if(fd < 0)
13947dd7cddfSDavid du Colombier 		fd = plumbopen("send", OWRITE);
13957dd7cddfSDavid du Colombier 	if(fd < 0)
13967dd7cddfSDavid du Colombier 		return;
13977dd7cddfSDavid du Colombier 
13987dd7cddfSDavid du Colombier 	p.src = "mailfs";
13997dd7cddfSDavid du Colombier 	p.dst = "seemail";
14007dd7cddfSDavid du Colombier 	p.wdir = "/mail/fs";
14017dd7cddfSDavid du Colombier 	p.type = "text";
14027dd7cddfSDavid du Colombier 
14037dd7cddfSDavid du Colombier 	ai = 0;
14047dd7cddfSDavid du Colombier 	a[ai].name = "filetype";
14057dd7cddfSDavid du Colombier 	a[ai].value = "mail";
14067dd7cddfSDavid du Colombier 
14077dd7cddfSDavid du Colombier 	a[++ai].name = "sender";
14087dd7cddfSDavid du Colombier 	a[ai].value = from;
14097dd7cddfSDavid du Colombier 	a[ai-1].next = &a[ai];
14107dd7cddfSDavid du Colombier 
14117dd7cddfSDavid du Colombier 	a[++ai].name = "length";
14127dd7cddfSDavid du Colombier 	a[ai].value = lenstr;
14137dd7cddfSDavid du Colombier 	a[ai-1].next = &a[ai];
14147dd7cddfSDavid du Colombier 
14157dd7cddfSDavid du Colombier 	a[++ai].name = "mailtype";
14167dd7cddfSDavid du Colombier 	a[ai].value = delete?"delete":"new";
14177dd7cddfSDavid du Colombier 	a[ai-1].next = &a[ai];
14187dd7cddfSDavid du Colombier 
14197dd7cddfSDavid du Colombier 	a[++ai].name = "date";
14207dd7cddfSDavid du Colombier 	a[ai].value = date;
14217dd7cddfSDavid du Colombier 	a[ai-1].next = &a[ai];
14227dd7cddfSDavid du Colombier 
14239a747e4fSDavid du Colombier 	if(m->sdigest){
14247dd7cddfSDavid du Colombier 		a[++ai].name = "digest";
14257dd7cddfSDavid du Colombier 		a[ai].value = s_to_c(m->sdigest);
14267dd7cddfSDavid du Colombier 		a[ai-1].next = &a[ai];
14279a747e4fSDavid du Colombier 	}
14287dd7cddfSDavid du Colombier 
14297dd7cddfSDavid du Colombier 	a[ai].next = nil;
14307dd7cddfSDavid du Colombier 
14317dd7cddfSDavid du Colombier 	p.attr = a;
14327dd7cddfSDavid du Colombier 	snprint(buf, sizeof(buf), "%s/%s/%s",
14337dd7cddfSDavid du Colombier 		mntpt, mb->name, m->name);
14347dd7cddfSDavid du Colombier 	p.ndata = strlen(buf);
14357dd7cddfSDavid du Colombier 	p.data = buf;
14367dd7cddfSDavid du Colombier 
14377dd7cddfSDavid du Colombier 	plumbsend(fd, &p);
14387dd7cddfSDavid du Colombier }
14397dd7cddfSDavid du Colombier 
14407dd7cddfSDavid du Colombier //
14417dd7cddfSDavid du Colombier // count the number of lines in the body (for imap4)
14427dd7cddfSDavid du Colombier //
14437dd7cddfSDavid du Colombier void
countlines(Message * m)14447dd7cddfSDavid du Colombier countlines(Message *m)
14457dd7cddfSDavid du Colombier {
14467dd7cddfSDavid du Colombier 	int i;
14477dd7cddfSDavid du Colombier 	char *p;
14487dd7cddfSDavid du Colombier 
14497dd7cddfSDavid du Colombier 	i = 0;
14507dd7cddfSDavid du Colombier 	for(p = strchr(m->rbody, '\n'); p != nil && p < m->rbend; p = strchr(p+1, '\n'))
14517dd7cddfSDavid du Colombier 		i++;
14527dd7cddfSDavid du Colombier 	sprint(m->lines, "%d", i);
14537dd7cddfSDavid du Colombier }
145459cc4ca5SDavid du Colombier 
145559cc4ca5SDavid du Colombier char *LOG = "fs";
145659cc4ca5SDavid du Colombier 
145759cc4ca5SDavid du Colombier void
logmsg(char * s,Message * m)145859cc4ca5SDavid du Colombier logmsg(char *s, Message *m)
145959cc4ca5SDavid du Colombier {
146059cc4ca5SDavid du Colombier 	int pid;
146159cc4ca5SDavid du Colombier 
146259cc4ca5SDavid du Colombier 	if(!logging)
146359cc4ca5SDavid du Colombier 		return;
146459cc4ca5SDavid du Colombier 	pid = getpid();
146559cc4ca5SDavid du Colombier 	if(m == nil)
146659cc4ca5SDavid du Colombier 		syslog(0, LOG, "%s.%d: %s", user, pid, s);
146759cc4ca5SDavid du Colombier 	else
146859cc4ca5SDavid du Colombier 		syslog(0, LOG, "%s.%d: %s msg from %s digest %s",
146959cc4ca5SDavid du Colombier 			user, pid, s,
147059cc4ca5SDavid du Colombier 			m->from822 ? s_to_c(m->from822) : "?",
147159cc4ca5SDavid du Colombier 			s_to_c(m->sdigest));
147259cc4ca5SDavid du Colombier }
147380ee5cbfSDavid du Colombier 
14743ff48bf5SDavid du Colombier /*
14753ff48bf5SDavid du Colombier  *  squeeze nulls out of the body
14763ff48bf5SDavid du Colombier  */
14773ff48bf5SDavid du Colombier static void
nullsqueeze(Message * m)14783ff48bf5SDavid du Colombier nullsqueeze(Message *m)
14793ff48bf5SDavid du Colombier {
14803ff48bf5SDavid du Colombier 	char *p, *q;
14813ff48bf5SDavid du Colombier 
14827a02f3c0SDavid du Colombier 	q = memchr(m->body, 0, m->end-m->body);
14833ff48bf5SDavid du Colombier 	if(q == nil)
14847a02f3c0SDavid du Colombier 		return;
14857a02f3c0SDavid du Colombier 
14867a02f3c0SDavid du Colombier 	for(p = m->body; q < m->end; q++){
14877a02f3c0SDavid du Colombier 		if(*q == 0)
14887a02f3c0SDavid du Colombier 			continue;
14897a02f3c0SDavid du Colombier 		*p++ = *q;
14903ff48bf5SDavid du Colombier 	}
14917a02f3c0SDavid du Colombier 	m->bend = m->rbend = m->end = p;
14923ff48bf5SDavid du Colombier }
14933ff48bf5SDavid du Colombier 
14943ff48bf5SDavid du Colombier 
149580ee5cbfSDavid du Colombier //
149680ee5cbfSDavid du Colombier // convert an RFC822 date into a Unix style date
149780ee5cbfSDavid du Colombier // for when the Unix From line isn't there (e.g. POP3).
149880ee5cbfSDavid du Colombier // enough client programs depend on having a Unix date
149980ee5cbfSDavid du Colombier // that it's easiest to write this conversion code once, right here.
150080ee5cbfSDavid du Colombier //
150180ee5cbfSDavid du Colombier // people don't follow RFC822 particularly closely,
150280ee5cbfSDavid du Colombier // so we use strtotm, which is a bunch of heuristics.
150380ee5cbfSDavid du Colombier //
150480ee5cbfSDavid du Colombier 
150580ee5cbfSDavid du Colombier extern int strtotm(char*, Tm*);
150680ee5cbfSDavid du Colombier String*
date822tounix(char * s)150780ee5cbfSDavid du Colombier date822tounix(char *s)
150880ee5cbfSDavid du Colombier {
150980ee5cbfSDavid du Colombier 	char *p, *q;
151080ee5cbfSDavid du Colombier 	Tm tm;
151180ee5cbfSDavid du Colombier 
151280ee5cbfSDavid du Colombier 	if(strtotm(s, &tm) < 0)
151380ee5cbfSDavid du Colombier 		return nil;
151480ee5cbfSDavid du Colombier 
151580ee5cbfSDavid du Colombier 	p = asctime(&tm);
151680ee5cbfSDavid du Colombier 	if(q = strchr(p, '\n'))
151780ee5cbfSDavid du Colombier 		*q = '\0';
151880ee5cbfSDavid du Colombier 	return s_copy(p);
151980ee5cbfSDavid du Colombier }
152080ee5cbfSDavid du Colombier 
1521