xref: /plan9/sys/src/libhttpd/parse.c (revision b39189fd423aed869c5cf5189bc504918cff969b)
180ee5cbfSDavid du Colombier #include <u.h>
280ee5cbfSDavid du Colombier #include <libc.h>
32bef681aSDavid du Colombier #include <ctype.h>
480ee5cbfSDavid du Colombier #include <libsec.h>
580ee5cbfSDavid du Colombier #include <bin.h>
680ee5cbfSDavid du Colombier #include <httpd.h>
780ee5cbfSDavid du Colombier #include "escape.h"
880ee5cbfSDavid du Colombier 
980ee5cbfSDavid du Colombier typedef struct Hlex	Hlex;
1080ee5cbfSDavid du Colombier typedef struct MimeHead	MimeHead;
1180ee5cbfSDavid du Colombier 
1280ee5cbfSDavid du Colombier enum
1380ee5cbfSDavid du Colombier {
1480ee5cbfSDavid du Colombier 	/*
1580ee5cbfSDavid du Colombier 	 * tokens
1680ee5cbfSDavid du Colombier 	 */
1780ee5cbfSDavid du Colombier 	Word	= 1,
1880ee5cbfSDavid du Colombier 	QString,
1980ee5cbfSDavid du Colombier };
2080ee5cbfSDavid du Colombier 
2180ee5cbfSDavid du Colombier #define UlongMax	4294967295UL
2280ee5cbfSDavid du Colombier 
2380ee5cbfSDavid du Colombier struct Hlex
2480ee5cbfSDavid du Colombier {
2580ee5cbfSDavid du Colombier 	int	tok;
2680ee5cbfSDavid du Colombier 	int	eoh;
2780ee5cbfSDavid du Colombier 	int	eol;			/* end of header line encountered? */
2880ee5cbfSDavid du Colombier 	uchar	*hstart;		/* start of header */
2980ee5cbfSDavid du Colombier 	jmp_buf	jmp;			/* jmp here to parse header */
3080ee5cbfSDavid du Colombier 	char	wordval[HMaxWord];
3180ee5cbfSDavid du Colombier 	HConnect *c;
3280ee5cbfSDavid du Colombier };
3380ee5cbfSDavid du Colombier 
3480ee5cbfSDavid du Colombier struct MimeHead
3580ee5cbfSDavid du Colombier {
3680ee5cbfSDavid du Colombier 	char	*name;
3780ee5cbfSDavid du Colombier 	void	(*parse)(Hlex*, char*);
3880ee5cbfSDavid du Colombier 	uchar	seen;
3980ee5cbfSDavid du Colombier 	uchar	ignore;
4080ee5cbfSDavid du Colombier };
4180ee5cbfSDavid du Colombier 
4280ee5cbfSDavid du Colombier static void	mimeaccept(Hlex*, char*);
4380ee5cbfSDavid du Colombier static void	mimeacceptchar(Hlex*, char*);
4480ee5cbfSDavid du Colombier static void	mimeacceptenc(Hlex*, char*);
4580ee5cbfSDavid du Colombier static void	mimeacceptlang(Hlex*, char*);
4680ee5cbfSDavid du Colombier static void	mimeagent(Hlex*, char*);
4780ee5cbfSDavid du Colombier static void	mimeauthorization(Hlex*, char*);
4880ee5cbfSDavid du Colombier static void	mimeconnection(Hlex*, char*);
4980ee5cbfSDavid du Colombier static void	mimecontlen(Hlex*, char*);
502bef681aSDavid du Colombier static void	mimecookie(Hlex*, char*);
5180ee5cbfSDavid du Colombier static void	mimeexpect(Hlex*, char*);
5280ee5cbfSDavid du Colombier static void	mimefresh(Hlex*, char*);
5380ee5cbfSDavid du Colombier static void	mimefrom(Hlex*, char*);
5480ee5cbfSDavid du Colombier static void	mimehost(Hlex*, char*);
5580ee5cbfSDavid du Colombier static void	mimeifrange(Hlex*, char*);
5680ee5cbfSDavid du Colombier static void	mimeignore(Hlex*, char*);
5780ee5cbfSDavid du Colombier static void	mimematch(Hlex*, char*);
5880ee5cbfSDavid du Colombier static void	mimemodified(Hlex*, char*);
5980ee5cbfSDavid du Colombier static void	mimenomatch(Hlex*, char*);
6080ee5cbfSDavid du Colombier static void	mimerange(Hlex*, char*);
6180ee5cbfSDavid du Colombier static void	mimetransenc(Hlex*, char*);
6280ee5cbfSDavid du Colombier static void	mimeunmodified(Hlex*, char*);
6380ee5cbfSDavid du Colombier 
6480ee5cbfSDavid du Colombier /*
6580ee5cbfSDavid du Colombier  * headers seen also include
6680ee5cbfSDavid du Colombier  * allow  cache-control chargeto
6780ee5cbfSDavid du Colombier  * content-encoding content-language content-location content-md5 content-range content-type
6880ee5cbfSDavid du Colombier  * date etag expires forwarded last-modified max-forwards pragma
6980ee5cbfSDavid du Colombier  * proxy-agent proxy-authorization proxy-connection
7080ee5cbfSDavid du Colombier  * ua-color ua-cpu ua-os ua-pixels
7180ee5cbfSDavid du Colombier  * upgrade via x-afs-tokens x-serial-number
7280ee5cbfSDavid du Colombier  */
7380ee5cbfSDavid du Colombier static MimeHead	mimehead[] =
7480ee5cbfSDavid du Colombier {
7580ee5cbfSDavid du Colombier 	{"accept",		mimeaccept},
7680ee5cbfSDavid du Colombier 	{"accept-charset",	mimeacceptchar},
7780ee5cbfSDavid du Colombier 	{"accept-encoding",	mimeacceptenc},
7880ee5cbfSDavid du Colombier 	{"accept-language",	mimeacceptlang},
7980ee5cbfSDavid du Colombier 	{"authorization",	mimeauthorization},
8080ee5cbfSDavid du Colombier 	{"connection",		mimeconnection},
8180ee5cbfSDavid du Colombier 	{"content-length",	mimecontlen},
822bef681aSDavid du Colombier 	{"cookie",		mimecookie},
8380ee5cbfSDavid du Colombier 	{"expect",		mimeexpect},
8480ee5cbfSDavid du Colombier 	{"fresh",		mimefresh},
8580ee5cbfSDavid du Colombier 	{"from",		mimefrom},
8680ee5cbfSDavid du Colombier 	{"host",		mimehost},
8780ee5cbfSDavid du Colombier 	{"if-match",		mimematch},
8880ee5cbfSDavid du Colombier 	{"if-modified-since",	mimemodified},
8980ee5cbfSDavid du Colombier 	{"if-none-match",	mimenomatch},
9080ee5cbfSDavid du Colombier 	{"if-range",		mimeifrange},
9180ee5cbfSDavid du Colombier 	{"if-unmodified-since",	mimeunmodified},
9280ee5cbfSDavid du Colombier 	{"range",		mimerange},
9380ee5cbfSDavid du Colombier 	{"transfer-encoding",	mimetransenc},
9480ee5cbfSDavid du Colombier 	{"user-agent",		mimeagent},
9580ee5cbfSDavid du Colombier };
9680ee5cbfSDavid du Colombier 
9780ee5cbfSDavid du Colombier char*		hmydomain;
9880ee5cbfSDavid du Colombier char*		hversion = "HTTP/1.1";
9980ee5cbfSDavid du Colombier 
10080ee5cbfSDavid du Colombier static	void	lexhead(Hlex*);
10180ee5cbfSDavid du Colombier static	void	parsejump(Hlex*, char*);
10280ee5cbfSDavid du Colombier static	int	getc(Hlex*);
10380ee5cbfSDavid du Colombier static	void	ungetc(Hlex*);
10480ee5cbfSDavid du Colombier static	int	wordcr(Hlex*);
10580ee5cbfSDavid du Colombier static	int	wordnl(Hlex*);
10680ee5cbfSDavid du Colombier static	void	word(Hlex*, char*);
10780ee5cbfSDavid du Colombier static	int	lex1(Hlex*, int);
10880ee5cbfSDavid du Colombier static	int	lex(Hlex*);
10980ee5cbfSDavid du Colombier static	int	lexbase64(Hlex*);
11080ee5cbfSDavid du Colombier static	ulong	digtoul(char *s, char **e);
11180ee5cbfSDavid du Colombier 
11280ee5cbfSDavid du Colombier /*
113f9e1cf08SDavid du Colombier  * flush and clean up junk from a request
11480ee5cbfSDavid du Colombier  */
11580ee5cbfSDavid du Colombier void
hreqcleanup(HConnect * c)11680ee5cbfSDavid du Colombier hreqcleanup(HConnect *c)
11780ee5cbfSDavid du Colombier {
11880ee5cbfSDavid du Colombier 	int i;
11980ee5cbfSDavid du Colombier 
12080ee5cbfSDavid du Colombier 	hxferenc(&c->hout, 0);
12180ee5cbfSDavid du Colombier 	memset(&c->req, 0, sizeof(c->req));
12280ee5cbfSDavid du Colombier 	memset(&c->head, 0, sizeof(c->head));
12380ee5cbfSDavid du Colombier 	c->hpos = c->header;
12480ee5cbfSDavid du Colombier 	c->hstop = c->header;
12580ee5cbfSDavid du Colombier 	binfree(&c->bin);
12680ee5cbfSDavid du Colombier 	for(i = 0; i < nelem(mimehead); i++){
12780ee5cbfSDavid du Colombier 		mimehead[i].seen = 0;
12880ee5cbfSDavid du Colombier 		mimehead[i].ignore = 0;
12980ee5cbfSDavid du Colombier 	}
13080ee5cbfSDavid du Colombier }
13180ee5cbfSDavid du Colombier 
13280ee5cbfSDavid du Colombier /*
13380ee5cbfSDavid du Colombier  * list of tokens
13480ee5cbfSDavid du Colombier  * if the client is HTTP/1.0,
13580ee5cbfSDavid du Colombier  * ignore headers which match one of the tokens.
13680ee5cbfSDavid du Colombier  * restarts parsing if necessary.
13780ee5cbfSDavid du Colombier  */
13880ee5cbfSDavid du Colombier static void
mimeconnection(Hlex * h,char *)13980ee5cbfSDavid du Colombier mimeconnection(Hlex *h, char *)
14080ee5cbfSDavid du Colombier {
14180ee5cbfSDavid du Colombier 	char *u, *p;
14280ee5cbfSDavid du Colombier 	int reparse, i;
14380ee5cbfSDavid du Colombier 
14480ee5cbfSDavid du Colombier 	reparse = 0;
14580ee5cbfSDavid du Colombier 	for(;;){
14680ee5cbfSDavid du Colombier 		while(lex(h) != Word)
14780ee5cbfSDavid du Colombier 			if(h->tok != ',')
14880ee5cbfSDavid du Colombier 				goto breakout;
14980ee5cbfSDavid du Colombier 
15080ee5cbfSDavid du Colombier 		if(cistrcmp(h->wordval, "keep-alive") == 0)
15180ee5cbfSDavid du Colombier 			h->c->head.persist = 1;
15280ee5cbfSDavid du Colombier 		else if(cistrcmp(h->wordval, "close") == 0)
15380ee5cbfSDavid du Colombier 			h->c->head.closeit = 1;
15480ee5cbfSDavid du Colombier 		else if(!http11(h->c)){
15580ee5cbfSDavid du Colombier 			for(i = 0; i < nelem(mimehead); i++){
15680ee5cbfSDavid du Colombier 				if(cistrcmp(mimehead[i].name, h->wordval) == 0){
15780ee5cbfSDavid du Colombier 					reparse = mimehead[i].seen && !mimehead[i].ignore;
15880ee5cbfSDavid du Colombier 					mimehead[i].ignore = 1;
15980ee5cbfSDavid du Colombier 					if(cistrcmp(mimehead[i].name, "authorization") == 0){
16080ee5cbfSDavid du Colombier 						h->c->head.authuser = nil;
16180ee5cbfSDavid du Colombier 						h->c->head.authpass = nil;
16280ee5cbfSDavid du Colombier 					}
16380ee5cbfSDavid du Colombier 				}
16480ee5cbfSDavid du Colombier 			}
16580ee5cbfSDavid du Colombier 		}
16680ee5cbfSDavid du Colombier 
16780ee5cbfSDavid du Colombier 		if(lex(h) != ',')
16880ee5cbfSDavid du Colombier 			break;
16980ee5cbfSDavid du Colombier 	}
17080ee5cbfSDavid du Colombier 
17180ee5cbfSDavid du Colombier breakout:;
17280ee5cbfSDavid du Colombier 	/*
17380ee5cbfSDavid du Colombier 	 * if need to ignore headers we've already parsed,
17480ee5cbfSDavid du Colombier 	 * reset & start over.  need to save authorization
17580ee5cbfSDavid du Colombier 	 * info because it's written over when parsed.
17680ee5cbfSDavid du Colombier 	 */
17780ee5cbfSDavid du Colombier 	if(reparse){
17880ee5cbfSDavid du Colombier 		u = h->c->head.authuser;
17980ee5cbfSDavid du Colombier 		p = h->c->head.authpass;
18080ee5cbfSDavid du Colombier 		memset(&h->c->head, 0, sizeof(h->c->head));
18180ee5cbfSDavid du Colombier 		h->c->head.authuser = u;
18280ee5cbfSDavid du Colombier 		h->c->head.authpass = p;
18380ee5cbfSDavid du Colombier 
18480ee5cbfSDavid du Colombier 		h->c->hpos = h->hstart;
18580ee5cbfSDavid du Colombier 		longjmp(h->jmp, 1);
18680ee5cbfSDavid du Colombier 	}
18780ee5cbfSDavid du Colombier }
18880ee5cbfSDavid du Colombier 
18980ee5cbfSDavid du Colombier int
hparseheaders(HConnect * c,int timeout)19080ee5cbfSDavid du Colombier hparseheaders(HConnect *c, int timeout)
19180ee5cbfSDavid du Colombier {
19280ee5cbfSDavid du Colombier 	Hlex h;
19380ee5cbfSDavid du Colombier 
19480ee5cbfSDavid du Colombier 	c->head.fresh_thresh = 0;
19580ee5cbfSDavid du Colombier 	c->head.fresh_have = 0;
19680ee5cbfSDavid du Colombier 	c->head.persist = 0;
19780ee5cbfSDavid du Colombier 	if(c->req.vermaj == 0){
19880ee5cbfSDavid du Colombier 		c->head.host = hmydomain;
19980ee5cbfSDavid du Colombier 		return 1;
20080ee5cbfSDavid du Colombier 	}
20180ee5cbfSDavid du Colombier 
20280ee5cbfSDavid du Colombier 	memset(&h, 0, sizeof(h));
20380ee5cbfSDavid du Colombier 	h.c = c;
204e059317eSDavid du Colombier 	if(timeout)
20580ee5cbfSDavid du Colombier 		alarm(timeout);
206e059317eSDavid du Colombier 	if(hgethead(c, 1) < 0)
2079a747e4fSDavid du Colombier 		return -1;
208e059317eSDavid du Colombier 	if(timeout)
20980ee5cbfSDavid du Colombier 		alarm(0);
21080ee5cbfSDavid du Colombier 	h.hstart = c->hpos;
21180ee5cbfSDavid du Colombier 
21280ee5cbfSDavid du Colombier 	if(setjmp(h.jmp) == -1)
21380ee5cbfSDavid du Colombier 		return -1;
21480ee5cbfSDavid du Colombier 
21580ee5cbfSDavid du Colombier 	h.eol = 0;
21680ee5cbfSDavid du Colombier 	h.eoh = 0;
21780ee5cbfSDavid du Colombier 	h.tok = '\n';
21880ee5cbfSDavid du Colombier 	while(lex(&h) != '\n'){
21980ee5cbfSDavid du Colombier 		if(h.tok == Word && lex(&h) == ':')
22080ee5cbfSDavid du Colombier 			parsejump(&h, hstrdup(c, h.wordval));
22180ee5cbfSDavid du Colombier 		while(h.tok != '\n')
22280ee5cbfSDavid du Colombier 			lex(&h);
22380ee5cbfSDavid du Colombier 		h.eol = h.eoh;
22480ee5cbfSDavid du Colombier 	}
22580ee5cbfSDavid du Colombier 
22680ee5cbfSDavid du Colombier 	if(http11(c)){
22780ee5cbfSDavid du Colombier 		/*
22880ee5cbfSDavid du Colombier 		 * according to the http/1.1 spec,
22980ee5cbfSDavid du Colombier 		 * these rules must be followed
23080ee5cbfSDavid du Colombier 		 */
23180ee5cbfSDavid du Colombier 		if(c->head.host == nil){
23280ee5cbfSDavid du Colombier 			hfail(c, HBadReq, nil);
23380ee5cbfSDavid du Colombier 			return -1;
23480ee5cbfSDavid du Colombier 		}
23580ee5cbfSDavid du Colombier 		if(c->req.urihost != nil)
23680ee5cbfSDavid du Colombier 			c->head.host = c->req.urihost;
23780ee5cbfSDavid du Colombier 		/*
23880ee5cbfSDavid du Colombier 		 * also need to check host is actually this one
23980ee5cbfSDavid du Colombier 		 */
24080ee5cbfSDavid du Colombier 	}else if(c->head.host == nil)
24180ee5cbfSDavid du Colombier 		c->head.host = hmydomain;
24280ee5cbfSDavid du Colombier 	return 1;
24380ee5cbfSDavid du Colombier }
24480ee5cbfSDavid du Colombier 
24580ee5cbfSDavid du Colombier /*
24680ee5cbfSDavid du Colombier  * mimeparams	: | mimeparams ";" mimepara
24780ee5cbfSDavid du Colombier  * mimeparam	: token "=" token | token "=" qstring
24880ee5cbfSDavid du Colombier  */
24980ee5cbfSDavid du Colombier static HSPairs*
mimeparams(Hlex * h)25080ee5cbfSDavid du Colombier mimeparams(Hlex *h)
25180ee5cbfSDavid du Colombier {
25280ee5cbfSDavid du Colombier 	HSPairs *p;
25380ee5cbfSDavid du Colombier 	char *s;
25480ee5cbfSDavid du Colombier 
25580ee5cbfSDavid du Colombier 	p = nil;
25680ee5cbfSDavid du Colombier 	for(;;){
25780ee5cbfSDavid du Colombier 		if(lex(h) != Word)
25880ee5cbfSDavid du Colombier 			break;
25980ee5cbfSDavid du Colombier 		s = hstrdup(h->c, h->wordval);
26080ee5cbfSDavid du Colombier 		if(lex(h) != Word && h->tok != QString)
26180ee5cbfSDavid du Colombier 			break;
26280ee5cbfSDavid du Colombier 		p = hmkspairs(h->c, s, hstrdup(h->c, h->wordval), p);
26380ee5cbfSDavid du Colombier 	}
26480ee5cbfSDavid du Colombier 	return hrevspairs(p);
26580ee5cbfSDavid du Colombier }
26680ee5cbfSDavid du Colombier 
26780ee5cbfSDavid du Colombier /*
26880ee5cbfSDavid du Colombier  * mimehfields	: mimehfield | mimehfields commas mimehfield
26980ee5cbfSDavid du Colombier  * mimehfield	: token mimeparams
27080ee5cbfSDavid du Colombier  * commas	: "," | commas ","
27180ee5cbfSDavid du Colombier  */
27280ee5cbfSDavid du Colombier static HFields*
mimehfields(Hlex * h)27380ee5cbfSDavid du Colombier mimehfields(Hlex *h)
27480ee5cbfSDavid du Colombier {
27580ee5cbfSDavid du Colombier 	HFields *f;
27680ee5cbfSDavid du Colombier 
27780ee5cbfSDavid du Colombier 	f = nil;
27880ee5cbfSDavid du Colombier 	for(;;){
27980ee5cbfSDavid du Colombier 		while(lex(h) != Word)
28080ee5cbfSDavid du Colombier 			if(h->tok != ',')
28180ee5cbfSDavid du Colombier 				goto breakout;
28280ee5cbfSDavid du Colombier 
28380ee5cbfSDavid du Colombier 		f = hmkhfields(h->c, hstrdup(h->c, h->wordval), nil, f);
28480ee5cbfSDavid du Colombier 
28580ee5cbfSDavid du Colombier 		if(lex(h) == ';')
28680ee5cbfSDavid du Colombier 			f->params = mimeparams(h);
28780ee5cbfSDavid du Colombier 		if(h->tok != ',')
28880ee5cbfSDavid du Colombier 			break;
28980ee5cbfSDavid du Colombier 	}
29080ee5cbfSDavid du Colombier breakout:;
29180ee5cbfSDavid du Colombier 	return hrevhfields(f);
29280ee5cbfSDavid du Colombier }
29380ee5cbfSDavid du Colombier 
29480ee5cbfSDavid du Colombier /*
29580ee5cbfSDavid du Colombier  * parse a list of acceptable types, encodings, languages, etc.
29680ee5cbfSDavid du Colombier  */
29780ee5cbfSDavid du Colombier static HContent*
mimeok(Hlex * h,char * name,int multipart,HContent * head)29880ee5cbfSDavid du Colombier mimeok(Hlex *h, char *name, int multipart, HContent *head)
29980ee5cbfSDavid du Colombier {
30080ee5cbfSDavid du Colombier 	char *generic, *specific, *s;
30180ee5cbfSDavid du Colombier 	float v;
30280ee5cbfSDavid du Colombier 
30380ee5cbfSDavid du Colombier 	/*
30480ee5cbfSDavid du Colombier 	 * each type is separated by one or more commas
30580ee5cbfSDavid du Colombier 	 */
30680ee5cbfSDavid du Colombier 	while(lex(h) != Word)
30780ee5cbfSDavid du Colombier 		if(h->tok != ',')
30880ee5cbfSDavid du Colombier 			return head;
30980ee5cbfSDavid du Colombier 
31080ee5cbfSDavid du Colombier 	generic = hstrdup(h->c, h->wordval);
31180ee5cbfSDavid du Colombier 	lex(h);
31280ee5cbfSDavid du Colombier 	if(h->tok == '/' || multipart){
31380ee5cbfSDavid du Colombier 		/*
31480ee5cbfSDavid du Colombier 		 * at one time, IE5 improperly said '*' for single types
31580ee5cbfSDavid du Colombier 		 */
31680ee5cbfSDavid du Colombier 		if(h->tok != '/')
31780ee5cbfSDavid du Colombier 			return nil;
31880ee5cbfSDavid du Colombier 		if(lex(h) != Word)
31980ee5cbfSDavid du Colombier 			return head;
32080ee5cbfSDavid du Colombier 		specific = hstrdup(h->c, h->wordval);
32180ee5cbfSDavid du Colombier 		if(!multipart && strcmp(specific, "*") != 0)
32280ee5cbfSDavid du Colombier 			return head;
32380ee5cbfSDavid du Colombier 		lex(h);
32480ee5cbfSDavid du Colombier 	}else
32580ee5cbfSDavid du Colombier 		specific = nil;
32680ee5cbfSDavid du Colombier 	head = hmkcontent(h->c, generic, specific, head);
32780ee5cbfSDavid du Colombier 
32880ee5cbfSDavid du Colombier 	for(;;){
32980ee5cbfSDavid du Colombier 		switch(h->tok){
33080ee5cbfSDavid du Colombier 		case ';':
33180ee5cbfSDavid du Colombier 			/*
33280ee5cbfSDavid du Colombier 			 * should make a list of these params
33380ee5cbfSDavid du Colombier 			 * for accept, they fall into two classes:
33480ee5cbfSDavid du Colombier 			 *	up to a q=..., they modify the media type.
33580ee5cbfSDavid du Colombier 			 *	afterwards, they acceptance criteria
33680ee5cbfSDavid du Colombier 			 */
33780ee5cbfSDavid du Colombier 			if(lex(h) == Word){
33880ee5cbfSDavid du Colombier 				s = hstrdup(h->c, h->wordval);
33980ee5cbfSDavid du Colombier 				if(lex(h) != '=' || lex(h) != Word && h->tok != QString)
34080ee5cbfSDavid du Colombier 					return head;
34180ee5cbfSDavid du Colombier 				v = strtod(h->wordval, nil);
34280ee5cbfSDavid du Colombier 				if(strcmp(s, "q") == 0)
34380ee5cbfSDavid du Colombier 					head->q = v;
34480ee5cbfSDavid du Colombier 				else if(strcmp(s, "mxb") == 0)
34580ee5cbfSDavid du Colombier 					head->mxb = v;
34651711cb6SDavid du Colombier 				else{
34751711cb6SDavid du Colombier 					/* cope with accept: application/xhtml+xml; profile=http://www.wapforum.org/xhtml, */
34851711cb6SDavid du Colombier 					while(lex(h) == Word || (h->tok != ',' && h->eol == 0) )
34951711cb6SDavid du Colombier 						;
35051711cb6SDavid du Colombier 					return mimeok(h, name, multipart, head);
35151711cb6SDavid du Colombier 				}
35280ee5cbfSDavid du Colombier 			}
35380ee5cbfSDavid du Colombier 			break;
35480ee5cbfSDavid du Colombier 		case ',':
35580ee5cbfSDavid du Colombier 			return  mimeok(h, name, multipart, head);
35680ee5cbfSDavid du Colombier 		default:
35780ee5cbfSDavid du Colombier 			return head;
35880ee5cbfSDavid du Colombier 		}
35980ee5cbfSDavid du Colombier 		lex(h);
36080ee5cbfSDavid du Colombier 	}
36180ee5cbfSDavid du Colombier }
36280ee5cbfSDavid du Colombier 
36380ee5cbfSDavid du Colombier /*
36480ee5cbfSDavid du Colombier  * parse a list of entity tags
36580ee5cbfSDavid du Colombier  * 1#entity-tag
36680ee5cbfSDavid du Colombier  * entity-tag = [weak] opaque-tag
36780ee5cbfSDavid du Colombier  * weak = "W/"
36880ee5cbfSDavid du Colombier  * opaque-tag = quoted-string
36980ee5cbfSDavid du Colombier  */
37080ee5cbfSDavid du Colombier static HETag*
mimeetag(Hlex * h,HETag * head)37180ee5cbfSDavid du Colombier mimeetag(Hlex *h, HETag *head)
37280ee5cbfSDavid du Colombier {
37380ee5cbfSDavid du Colombier 	HETag *e;
37480ee5cbfSDavid du Colombier 	int weak;
37580ee5cbfSDavid du Colombier 
37680ee5cbfSDavid du Colombier 	for(;;){
37780ee5cbfSDavid du Colombier 		while(lex(h) != Word && h->tok != QString)
37880ee5cbfSDavid du Colombier 			if(h->tok != ',')
37980ee5cbfSDavid du Colombier 				return head;
38080ee5cbfSDavid du Colombier 
38180ee5cbfSDavid du Colombier 		weak = 0;
38280ee5cbfSDavid du Colombier 		if(h->tok == Word && strcmp(h->wordval, "*") != 0){
38380ee5cbfSDavid du Colombier 			if(strcmp(h->wordval, "W") != 0)
38480ee5cbfSDavid du Colombier 				return head;
38580ee5cbfSDavid du Colombier 			if(lex(h) != '/' || lex(h) != QString)
38680ee5cbfSDavid du Colombier 				return head;
38780ee5cbfSDavid du Colombier 			weak = 1;
38880ee5cbfSDavid du Colombier 		}
38980ee5cbfSDavid du Colombier 
39080ee5cbfSDavid du Colombier 		e = halloc(h->c, sizeof(HETag));
39180ee5cbfSDavid du Colombier 		e->etag = hstrdup(h->c, h->wordval);
39280ee5cbfSDavid du Colombier 		e->weak = weak;
39380ee5cbfSDavid du Colombier 		e->next = head;
39480ee5cbfSDavid du Colombier 		head = e;
39580ee5cbfSDavid du Colombier 
39680ee5cbfSDavid du Colombier 		if(lex(h) != ',')
39780ee5cbfSDavid du Colombier 			return head;
39880ee5cbfSDavid du Colombier 	}
39980ee5cbfSDavid du Colombier }
40080ee5cbfSDavid du Colombier 
40180ee5cbfSDavid du Colombier /*
40280ee5cbfSDavid du Colombier  * ranges-specifier = byte-ranges-specifier
40380ee5cbfSDavid du Colombier  * byte-ranges-specifier = "bytes" "=" byte-range-set
40480ee5cbfSDavid du Colombier  * byte-range-set = 1#(byte-range-spec|suffix-byte-range-spec)
40580ee5cbfSDavid du Colombier  * byte-range-spec = byte-pos "-" [byte-pos]
40680ee5cbfSDavid du Colombier  * byte-pos = 1*DIGIT
40780ee5cbfSDavid du Colombier  * suffix-byte-range-spec = "-" suffix-length
40880ee5cbfSDavid du Colombier  * suffix-length = 1*DIGIT
40980ee5cbfSDavid du Colombier  *
41080ee5cbfSDavid du Colombier  * syntactically invalid range specifiers cause the
41180ee5cbfSDavid du Colombier  * entire header field to be ignored.
41280ee5cbfSDavid du Colombier  * it is syntactically incorrect for the second byte pos
41380ee5cbfSDavid du Colombier  * to be smaller than the first byte pos
41480ee5cbfSDavid du Colombier  */
41580ee5cbfSDavid du Colombier static HRange*
mimeranges(Hlex * h,HRange * head)41680ee5cbfSDavid du Colombier mimeranges(Hlex *h, HRange *head)
41780ee5cbfSDavid du Colombier {
41880ee5cbfSDavid du Colombier 	HRange *r, *rh, *tail;
41980ee5cbfSDavid du Colombier 	char *w;
42080ee5cbfSDavid du Colombier 	ulong start, stop;
42180ee5cbfSDavid du Colombier 	int suf;
42280ee5cbfSDavid du Colombier 
42380ee5cbfSDavid du Colombier 	if(lex(h) != Word || strcmp(h->wordval, "bytes") != 0 || lex(h) != '=')
42480ee5cbfSDavid du Colombier 		return head;
42580ee5cbfSDavid du Colombier 
42680ee5cbfSDavid du Colombier 	rh = nil;
42780ee5cbfSDavid du Colombier 	tail = nil;
42880ee5cbfSDavid du Colombier 	for(;;){
42980ee5cbfSDavid du Colombier 		while(lex(h) != Word){
43080ee5cbfSDavid du Colombier 			if(h->tok != ','){
43180ee5cbfSDavid du Colombier 				if(h->tok == '\n')
43280ee5cbfSDavid du Colombier 					goto breakout;
43380ee5cbfSDavid du Colombier 				return head;
43480ee5cbfSDavid du Colombier 			}
43580ee5cbfSDavid du Colombier 		}
43680ee5cbfSDavid du Colombier 
43780ee5cbfSDavid du Colombier 		w = h->wordval;
43880ee5cbfSDavid du Colombier 		start = 0;
43980ee5cbfSDavid du Colombier 		suf = 1;
44080ee5cbfSDavid du Colombier 		if(w[0] != '-'){
44180ee5cbfSDavid du Colombier 			suf = 0;
44280ee5cbfSDavid du Colombier 			start = digtoul(w, &w);
44380ee5cbfSDavid du Colombier 			if(w[0] != '-')
44480ee5cbfSDavid du Colombier 				return head;
44580ee5cbfSDavid du Colombier 		}
44680ee5cbfSDavid du Colombier 		w++;
44780ee5cbfSDavid du Colombier 		stop = ~0UL;
44880ee5cbfSDavid du Colombier 		if(w[0] != '\0'){
44980ee5cbfSDavid du Colombier 			stop = digtoul(w, &w);
45080ee5cbfSDavid du Colombier 			if(w[0] != '\0')
45180ee5cbfSDavid du Colombier 				return head;
45280ee5cbfSDavid du Colombier 			if(!suf && stop < start)
45380ee5cbfSDavid du Colombier 				return head;
45480ee5cbfSDavid du Colombier 		}
45580ee5cbfSDavid du Colombier 
45680ee5cbfSDavid du Colombier 		r = halloc(h->c, sizeof(HRange));
45780ee5cbfSDavid du Colombier 		r->suffix = suf;
45880ee5cbfSDavid du Colombier 		r->start = start;
45980ee5cbfSDavid du Colombier 		r->stop = stop;
46080ee5cbfSDavid du Colombier 		r->next = nil;
46180ee5cbfSDavid du Colombier 		if(rh == nil)
46280ee5cbfSDavid du Colombier 			rh = r;
46380ee5cbfSDavid du Colombier 		else
46480ee5cbfSDavid du Colombier 			tail->next = r;
46580ee5cbfSDavid du Colombier 		tail = r;
46680ee5cbfSDavid du Colombier 
46780ee5cbfSDavid du Colombier 		if(lex(h) != ','){
46880ee5cbfSDavid du Colombier 			if(h->tok == '\n')
46980ee5cbfSDavid du Colombier 				break;
47080ee5cbfSDavid du Colombier 			return head;
47180ee5cbfSDavid du Colombier 		}
47280ee5cbfSDavid du Colombier 	}
47380ee5cbfSDavid du Colombier breakout:;
47480ee5cbfSDavid du Colombier 
47580ee5cbfSDavid du Colombier 	if(head == nil)
47680ee5cbfSDavid du Colombier 		return rh;
47780ee5cbfSDavid du Colombier 
47880ee5cbfSDavid du Colombier 	for(tail = head; tail->next != nil; tail = tail->next)
47980ee5cbfSDavid du Colombier 		;
48080ee5cbfSDavid du Colombier 	tail->next = rh;
48180ee5cbfSDavid du Colombier 	return head;
48280ee5cbfSDavid du Colombier }
48380ee5cbfSDavid du Colombier 
48480ee5cbfSDavid du Colombier static void
mimeaccept(Hlex * h,char * name)48580ee5cbfSDavid du Colombier mimeaccept(Hlex *h, char *name)
48680ee5cbfSDavid du Colombier {
48780ee5cbfSDavid du Colombier 	h->c->head.oktype = mimeok(h, name, 1, h->c->head.oktype);
48880ee5cbfSDavid du Colombier }
48980ee5cbfSDavid du Colombier 
49080ee5cbfSDavid du Colombier static void
mimeacceptchar(Hlex * h,char * name)49180ee5cbfSDavid du Colombier mimeacceptchar(Hlex *h, char *name)
49280ee5cbfSDavid du Colombier {
49380ee5cbfSDavid du Colombier 	h->c->head.okchar = mimeok(h, name, 0, h->c->head.okchar);
49480ee5cbfSDavid du Colombier }
49580ee5cbfSDavid du Colombier 
49680ee5cbfSDavid du Colombier static void
mimeacceptenc(Hlex * h,char * name)49780ee5cbfSDavid du Colombier mimeacceptenc(Hlex *h, char *name)
49880ee5cbfSDavid du Colombier {
49980ee5cbfSDavid du Colombier 	h->c->head.okencode = mimeok(h, name, 0, h->c->head.okencode);
50080ee5cbfSDavid du Colombier }
50180ee5cbfSDavid du Colombier 
50280ee5cbfSDavid du Colombier static void
mimeacceptlang(Hlex * h,char * name)50380ee5cbfSDavid du Colombier mimeacceptlang(Hlex *h, char *name)
50480ee5cbfSDavid du Colombier {
50580ee5cbfSDavid du Colombier 	h->c->head.oklang = mimeok(h, name, 0, h->c->head.oklang);
50680ee5cbfSDavid du Colombier }
50780ee5cbfSDavid du Colombier 
50880ee5cbfSDavid du Colombier static void
mimemodified(Hlex * h,char *)50980ee5cbfSDavid du Colombier mimemodified(Hlex *h, char *)
51080ee5cbfSDavid du Colombier {
51180ee5cbfSDavid du Colombier 	lexhead(h);
51280ee5cbfSDavid du Colombier 	h->c->head.ifmodsince = hdate2sec(h->wordval);
51380ee5cbfSDavid du Colombier }
51480ee5cbfSDavid du Colombier 
51580ee5cbfSDavid du Colombier static void
mimeunmodified(Hlex * h,char *)51680ee5cbfSDavid du Colombier mimeunmodified(Hlex *h, char *)
51780ee5cbfSDavid du Colombier {
51880ee5cbfSDavid du Colombier 	lexhead(h);
51980ee5cbfSDavid du Colombier 	h->c->head.ifunmodsince = hdate2sec(h->wordval);
52080ee5cbfSDavid du Colombier }
52180ee5cbfSDavid du Colombier 
52280ee5cbfSDavid du Colombier static void
mimematch(Hlex * h,char *)52380ee5cbfSDavid du Colombier mimematch(Hlex *h, char *)
52480ee5cbfSDavid du Colombier {
52580ee5cbfSDavid du Colombier 	h->c->head.ifmatch = mimeetag(h, h->c->head.ifmatch);
52680ee5cbfSDavid du Colombier }
52780ee5cbfSDavid du Colombier 
52880ee5cbfSDavid du Colombier static void
mimenomatch(Hlex * h,char *)52980ee5cbfSDavid du Colombier mimenomatch(Hlex *h, char *)
53080ee5cbfSDavid du Colombier {
53180ee5cbfSDavid du Colombier 	h->c->head.ifnomatch = mimeetag(h, h->c->head.ifnomatch);
53280ee5cbfSDavid du Colombier }
53380ee5cbfSDavid du Colombier 
53480ee5cbfSDavid du Colombier /*
53580ee5cbfSDavid du Colombier  * argument is either etag or date
53680ee5cbfSDavid du Colombier  */
53780ee5cbfSDavid du Colombier static void
mimeifrange(Hlex * h,char *)53880ee5cbfSDavid du Colombier mimeifrange(Hlex *h, char *)
53980ee5cbfSDavid du Colombier {
54080ee5cbfSDavid du Colombier 	int c, d, et;
54180ee5cbfSDavid du Colombier 
54280ee5cbfSDavid du Colombier 	et = 0;
54380ee5cbfSDavid du Colombier 	c = getc(h);
54480ee5cbfSDavid du Colombier 	while(c == ' ' || c == '\t')
54580ee5cbfSDavid du Colombier 		c = getc(h);
54680ee5cbfSDavid du Colombier 	if(c == '"')
54780ee5cbfSDavid du Colombier 		et = 1;
54880ee5cbfSDavid du Colombier 	else if(c == 'W'){
54980ee5cbfSDavid du Colombier 		d = getc(h);
55080ee5cbfSDavid du Colombier 		if(d == '/')
55180ee5cbfSDavid du Colombier 			et = 1;
55280ee5cbfSDavid du Colombier 		ungetc(h);
55380ee5cbfSDavid du Colombier 	}
55480ee5cbfSDavid du Colombier 	ungetc(h);
55580ee5cbfSDavid du Colombier 	if(et){
55680ee5cbfSDavid du Colombier 		h->c->head.ifrangeetag = mimeetag(h, h->c->head.ifrangeetag);
55780ee5cbfSDavid du Colombier 	}else{
55880ee5cbfSDavid du Colombier 		lexhead(h);
55980ee5cbfSDavid du Colombier 		h->c->head.ifrangedate = hdate2sec(h->wordval);
56080ee5cbfSDavid du Colombier 	}
56180ee5cbfSDavid du Colombier }
56280ee5cbfSDavid du Colombier 
56380ee5cbfSDavid du Colombier static void
mimerange(Hlex * h,char *)56480ee5cbfSDavid du Colombier mimerange(Hlex *h, char *)
56580ee5cbfSDavid du Colombier {
56680ee5cbfSDavid du Colombier 	h->c->head.range = mimeranges(h, h->c->head.range);
56780ee5cbfSDavid du Colombier }
56880ee5cbfSDavid du Colombier 
56980ee5cbfSDavid du Colombier /*
570*b39189fdSDavid du Colombier  * parse it like cookies
571*b39189fdSDavid du Colombier  */
572*b39189fdSDavid du Colombier static void
authdigest(Hlex * h,char *)573*b39189fdSDavid du Colombier authdigest(Hlex *h, char *)
574*b39189fdSDavid du Colombier {
575*b39189fdSDavid du Colombier 	char *s;
576*b39189fdSDavid du Colombier 	HSPairs *p;
577*b39189fdSDavid du Colombier 
578*b39189fdSDavid du Colombier 	p = nil;
579*b39189fdSDavid du Colombier 	for(;;){
580*b39189fdSDavid du Colombier 		while(lex(h) != Word)
581*b39189fdSDavid du Colombier 			if(h->tok != ';' && h->tok != ',')
582*b39189fdSDavid du Colombier 				goto breakout;
583*b39189fdSDavid du Colombier 		s = hstrdup(h->c, h->wordval);
584*b39189fdSDavid du Colombier 		while (lex(h) != Word && h->tok != QString)
585*b39189fdSDavid du Colombier 			if (h->tok != '=')
586*b39189fdSDavid du Colombier 				goto breakout;
587*b39189fdSDavid du Colombier 		p = hmkspairs(h->c, s, hstrdup(h->c, h->wordval), p);
588*b39189fdSDavid du Colombier 	}
589*b39189fdSDavid du Colombier breakout:
590*b39189fdSDavid du Colombier 	h->c->head.authinfo = hrevspairs(p);
591*b39189fdSDavid du Colombier }
592*b39189fdSDavid du Colombier 
593*b39189fdSDavid du Colombier /*
59480ee5cbfSDavid du Colombier  * note: netscape and ie through versions 4.7 and 4
59580ee5cbfSDavid du Colombier  * support only basic authorization, so that is all that is supported here
59680ee5cbfSDavid du Colombier  *
59780ee5cbfSDavid du Colombier  * "Authorization" ":" "Basic" base64-user-pass
59880ee5cbfSDavid du Colombier  * where base64-user-pass is the base64 encoding of
59980ee5cbfSDavid du Colombier  * username ":" password
60080ee5cbfSDavid du Colombier  */
60180ee5cbfSDavid du Colombier static void
authbasic(Hlex * h,char *)602*b39189fdSDavid du Colombier authbasic(Hlex *h, char *)
60380ee5cbfSDavid du Colombier {
60480ee5cbfSDavid du Colombier 	char *up, *p;
60580ee5cbfSDavid du Colombier 	int n;
60680ee5cbfSDavid du Colombier 
60780ee5cbfSDavid du Colombier 	n = lexbase64(h);
60880ee5cbfSDavid du Colombier 	if(!n)
60980ee5cbfSDavid du Colombier 		return;
61080ee5cbfSDavid du Colombier 
61180ee5cbfSDavid du Colombier 	/*
61280ee5cbfSDavid du Colombier 	 * wipe out source for password, so it won't be logged.
61380ee5cbfSDavid du Colombier 	 * it is replaced by a single =,
61480ee5cbfSDavid du Colombier 	 * which is valid base64, but not ok for an auth reponse.
61580ee5cbfSDavid du Colombier 	 * therefore future parses of the header field will not overwrite
61680ee5cbfSDavid du Colombier 	 * authuser and authpass.
61780ee5cbfSDavid du Colombier 	 */
61880ee5cbfSDavid du Colombier 	memmove(h->c->hpos - (n - 1), h->c->hpos, h->c->hstop - h->c->hpos);
61980ee5cbfSDavid du Colombier 	h->c->hstop -= n - 1;
62080ee5cbfSDavid du Colombier 	*h->c->hstop = '\0';
62180ee5cbfSDavid du Colombier 	h->c->hpos -= n - 1;
62280ee5cbfSDavid du Colombier 	h->c->hpos[-1] = '=';
62380ee5cbfSDavid du Colombier 
62480ee5cbfSDavid du Colombier 	up = halloc(h->c, n + 1);
62580ee5cbfSDavid du Colombier 	n = dec64((uchar*)up, n, h->wordval, n);
62680ee5cbfSDavid du Colombier 	up[n] = '\0';
62780ee5cbfSDavid du Colombier 	p = strchr(up, ':');
62880ee5cbfSDavid du Colombier 	if(p != nil){
62980ee5cbfSDavid du Colombier 		*p++ = '\0';
63080ee5cbfSDavid du Colombier 		h->c->head.authuser = hstrdup(h->c, up);
63180ee5cbfSDavid du Colombier 		h->c->head.authpass = hstrdup(h->c, p);
63280ee5cbfSDavid du Colombier 	}
63380ee5cbfSDavid du Colombier }
63480ee5cbfSDavid du Colombier 
635*b39189fdSDavid du Colombier /*
636*b39189fdSDavid du Colombier  * "Authorization" ":" "Basic" | "Digest" ...
637*b39189fdSDavid du Colombier  */
638*b39189fdSDavid du Colombier static void
mimeauthorization(Hlex * h,char *)639*b39189fdSDavid du Colombier mimeauthorization(Hlex *h, char *)
640*b39189fdSDavid du Colombier {
641*b39189fdSDavid du Colombier 	int i;
642*b39189fdSDavid du Colombier 	static MimeHead authparser[] = {
643*b39189fdSDavid du Colombier 		{ "basic", authbasic },
644*b39189fdSDavid du Colombier 		{ "digest", authdigest },
645*b39189fdSDavid du Colombier 	};
646*b39189fdSDavid du Colombier 
647*b39189fdSDavid du Colombier 	if(lex(h) != Word)
648*b39189fdSDavid du Colombier 		return;
649*b39189fdSDavid du Colombier 
650*b39189fdSDavid du Colombier 	for (i = 0; i < nelem(authparser); i++)
651*b39189fdSDavid du Colombier 		if (cistrcmp(h->wordval, authparser[i].name) == 0) {
652*b39189fdSDavid du Colombier 			(*authparser[i].parse)(h, nil);
653*b39189fdSDavid du Colombier 			break;
654*b39189fdSDavid du Colombier 		}
655*b39189fdSDavid du Colombier }
656*b39189fdSDavid du Colombier 
65780ee5cbfSDavid du Colombier static void
mimeagent(Hlex * h,char *)65880ee5cbfSDavid du Colombier mimeagent(Hlex *h, char *)
65980ee5cbfSDavid du Colombier {
66080ee5cbfSDavid du Colombier 	lexhead(h);
66180ee5cbfSDavid du Colombier 	h->c->head.client = hstrdup(h->c, h->wordval);
66280ee5cbfSDavid du Colombier }
66380ee5cbfSDavid du Colombier 
66480ee5cbfSDavid du Colombier static void
mimefrom(Hlex * h,char *)66580ee5cbfSDavid du Colombier mimefrom(Hlex *h, char *)
66680ee5cbfSDavid du Colombier {
66780ee5cbfSDavid du Colombier 	lexhead(h);
66880ee5cbfSDavid du Colombier }
66980ee5cbfSDavid du Colombier 
67080ee5cbfSDavid du Colombier static void
mimehost(Hlex * h,char *)67180ee5cbfSDavid du Colombier mimehost(Hlex *h, char *)
67280ee5cbfSDavid du Colombier {
67380ee5cbfSDavid du Colombier 	char *hd;
67480ee5cbfSDavid du Colombier 
67580ee5cbfSDavid du Colombier 	lexhead(h);
67680ee5cbfSDavid du Colombier 	for(hd = h->wordval; *hd == ' ' || *hd == '\t'; hd++)
67780ee5cbfSDavid du Colombier 		;
67880ee5cbfSDavid du Colombier 	h->c->head.host = hlower(hstrdup(h->c, hd));
67980ee5cbfSDavid du Colombier }
68080ee5cbfSDavid du Colombier 
68180ee5cbfSDavid du Colombier /*
68280ee5cbfSDavid du Colombier  * if present, implies that a message body follows the headers
68380ee5cbfSDavid du Colombier  * "content-length" ":" digits
68480ee5cbfSDavid du Colombier  */
68580ee5cbfSDavid du Colombier static void
mimecontlen(Hlex * h,char *)68680ee5cbfSDavid du Colombier mimecontlen(Hlex *h, char *)
68780ee5cbfSDavid du Colombier {
68880ee5cbfSDavid du Colombier 	char *e;
68980ee5cbfSDavid du Colombier 	ulong v;
69080ee5cbfSDavid du Colombier 
69180ee5cbfSDavid du Colombier 	if(lex(h) != Word)
69280ee5cbfSDavid du Colombier 		return;
69380ee5cbfSDavid du Colombier 	e = h->wordval;
69480ee5cbfSDavid du Colombier 	v = digtoul(e, &e);
69580ee5cbfSDavid du Colombier 	if(v == ~0UL || *e != '\0')
69680ee5cbfSDavid du Colombier 		return;
69780ee5cbfSDavid du Colombier 	h->c->head.contlen = v;
69880ee5cbfSDavid du Colombier }
69980ee5cbfSDavid du Colombier 
70080ee5cbfSDavid du Colombier /*
70180ee5cbfSDavid du Colombier  * mimexpect	: "expect" ":" expects
70280ee5cbfSDavid du Colombier  * expects	: | expects "," expect
70380ee5cbfSDavid du Colombier  * expect	: "100-continue" | token | token "=" token expectparams | token "=" qstring expectparams
70480ee5cbfSDavid du Colombier  * expectparams	: ";" token | ";" token "=" token | token "=" qstring
70580ee5cbfSDavid du Colombier  * for now, we merely parse "100-continue" or anything else.
70680ee5cbfSDavid du Colombier  */
70780ee5cbfSDavid du Colombier static void
mimeexpect(Hlex * h,char *)70880ee5cbfSDavid du Colombier mimeexpect(Hlex *h, char *)
70980ee5cbfSDavid du Colombier {
71080ee5cbfSDavid du Colombier 	if(lex(h) != Word || cistrcmp(h->wordval, "100-continue") != 0 || lex(h) != '\n')
71180ee5cbfSDavid du Colombier 		h->c->head.expectother = 1;
71280ee5cbfSDavid du Colombier 	h->c->head.expectcont = 1;
71380ee5cbfSDavid du Colombier }
71480ee5cbfSDavid du Colombier 
71580ee5cbfSDavid du Colombier static void
mimetransenc(Hlex * h,char *)71680ee5cbfSDavid du Colombier mimetransenc(Hlex *h, char *)
71780ee5cbfSDavid du Colombier {
71880ee5cbfSDavid du Colombier 	h->c->head.transenc = mimehfields(h);
71980ee5cbfSDavid du Colombier }
72080ee5cbfSDavid du Colombier 
72180ee5cbfSDavid du Colombier static void
mimecookie(Hlex * h,char *)7222bef681aSDavid du Colombier mimecookie(Hlex *h, char *)
7232bef681aSDavid du Colombier {
7242bef681aSDavid du Colombier 	char *s;
7252bef681aSDavid du Colombier 	HSPairs *p;
7262bef681aSDavid du Colombier 
7272bef681aSDavid du Colombier 	p = nil;
7282bef681aSDavid du Colombier 	for(;;){
7292bef681aSDavid du Colombier 		while(lex(h) != Word)
7302bef681aSDavid du Colombier 			if(h->tok != ';' && h->tok != ',')
7312bef681aSDavid du Colombier 				goto breakout;
7322bef681aSDavid du Colombier 		s = hstrdup(h->c, h->wordval);
7332bef681aSDavid du Colombier 		while (lex(h) != Word && h->tok != QString)
7342bef681aSDavid du Colombier 			if (h->tok != '=')
7352bef681aSDavid du Colombier 				goto breakout;
7362bef681aSDavid du Colombier 		p = hmkspairs(h->c, s, hstrdup(h->c, h->wordval), p);
7372bef681aSDavid du Colombier 	}
7382bef681aSDavid du Colombier breakout:
7392bef681aSDavid du Colombier 	h->c->head.cookie = hrevspairs(p);
7402bef681aSDavid du Colombier }
7412bef681aSDavid du Colombier 
7422bef681aSDavid du Colombier static void
mimefresh(Hlex * h,char *)74380ee5cbfSDavid du Colombier mimefresh(Hlex *h, char *)
74480ee5cbfSDavid du Colombier {
74580ee5cbfSDavid du Colombier 	char *s;
74680ee5cbfSDavid du Colombier 
74780ee5cbfSDavid du Colombier 	lexhead(h);
74880ee5cbfSDavid du Colombier 	for(s = h->wordval; *s && (*s==' ' || *s=='\t'); s++)
74980ee5cbfSDavid du Colombier 		;
75080ee5cbfSDavid du Colombier 	if(strncmp(s, "pathstat/", 9) == 0)
75180ee5cbfSDavid du Colombier 		h->c->head.fresh_thresh = atoi(s+9);
75280ee5cbfSDavid du Colombier 	else if(strncmp(s, "have/", 5) == 0)
75380ee5cbfSDavid du Colombier 		h->c->head.fresh_have = atoi(s+5);
75480ee5cbfSDavid du Colombier }
75580ee5cbfSDavid du Colombier 
75680ee5cbfSDavid du Colombier static void
mimeignore(Hlex * h,char *)75780ee5cbfSDavid du Colombier mimeignore(Hlex *h, char *)
75880ee5cbfSDavid du Colombier {
75980ee5cbfSDavid du Colombier 	lexhead(h);
76080ee5cbfSDavid du Colombier }
76180ee5cbfSDavid du Colombier 
76280ee5cbfSDavid du Colombier static void
parsejump(Hlex * h,char * k)76380ee5cbfSDavid du Colombier parsejump(Hlex *h, char *k)
76480ee5cbfSDavid du Colombier {
76580ee5cbfSDavid du Colombier 	int l, r, m;
76680ee5cbfSDavid du Colombier 
76780ee5cbfSDavid du Colombier 	l = 1;
76880ee5cbfSDavid du Colombier 	r = nelem(mimehead) - 1;
76980ee5cbfSDavid du Colombier 	while(l <= r){
77080ee5cbfSDavid du Colombier 		m = (r + l) >> 1;
77180ee5cbfSDavid du Colombier 		if(cistrcmp(mimehead[m].name, k) <= 0)
77280ee5cbfSDavid du Colombier 			l = m + 1;
77380ee5cbfSDavid du Colombier 		else
77480ee5cbfSDavid du Colombier 			r = m - 1;
77580ee5cbfSDavid du Colombier 	}
77680ee5cbfSDavid du Colombier 	m = l - 1;
77780ee5cbfSDavid du Colombier 	if(cistrcmp(mimehead[m].name, k) == 0 && !mimehead[m].ignore){
77880ee5cbfSDavid du Colombier 		mimehead[m].seen = 1;
77980ee5cbfSDavid du Colombier 		(*mimehead[m].parse)(h, k);
78080ee5cbfSDavid du Colombier 	}else
78180ee5cbfSDavid du Colombier 		mimeignore(h, k);
78280ee5cbfSDavid du Colombier }
78380ee5cbfSDavid du Colombier 
78480ee5cbfSDavid du Colombier static int
lex(Hlex * h)78580ee5cbfSDavid du Colombier lex(Hlex *h)
78680ee5cbfSDavid du Colombier {
78780ee5cbfSDavid du Colombier 	return h->tok = lex1(h, 0);
78880ee5cbfSDavid du Colombier }
78980ee5cbfSDavid du Colombier 
79080ee5cbfSDavid du Colombier static int
lexbase64(Hlex * h)79180ee5cbfSDavid du Colombier lexbase64(Hlex *h)
79280ee5cbfSDavid du Colombier {
79380ee5cbfSDavid du Colombier 	int c, n;
79480ee5cbfSDavid du Colombier 
79580ee5cbfSDavid du Colombier 	n = 0;
79680ee5cbfSDavid du Colombier 	lex1(h, 1);
79780ee5cbfSDavid du Colombier 
79880ee5cbfSDavid du Colombier 	while((c = getc(h)) >= 0){
799f9e1cf08SDavid du Colombier 		if(!isalnum(c) && c != '+' && c != '/'){
80080ee5cbfSDavid du Colombier 			ungetc(h);
80180ee5cbfSDavid du Colombier 			break;
80280ee5cbfSDavid du Colombier 		}
80380ee5cbfSDavid du Colombier 		if(n < HMaxWord-1)
80480ee5cbfSDavid du Colombier 			h->wordval[n++] = c;
80580ee5cbfSDavid du Colombier 	}
80680ee5cbfSDavid du Colombier 	h->wordval[n] = '\0';
80780ee5cbfSDavid du Colombier 	return n;
80880ee5cbfSDavid du Colombier }
80980ee5cbfSDavid du Colombier 
81080ee5cbfSDavid du Colombier /*
81180ee5cbfSDavid du Colombier  * rfc 822/rfc 1521 lexical analyzer
81280ee5cbfSDavid du Colombier  */
81380ee5cbfSDavid du Colombier static int
lex1(Hlex * h,int skipwhite)81480ee5cbfSDavid du Colombier lex1(Hlex *h, int skipwhite)
81580ee5cbfSDavid du Colombier {
81680ee5cbfSDavid du Colombier 	int level, c;
81780ee5cbfSDavid du Colombier 
81880ee5cbfSDavid du Colombier 	if(h->eol)
81980ee5cbfSDavid du Colombier 		return '\n';
82080ee5cbfSDavid du Colombier 
82180ee5cbfSDavid du Colombier top:
82280ee5cbfSDavid du Colombier 	c = getc(h);
82380ee5cbfSDavid du Colombier 	switch(c){
82480ee5cbfSDavid du Colombier 	case '(':
82580ee5cbfSDavid du Colombier 		level = 1;
82680ee5cbfSDavid du Colombier 		while((c = getc(h)) >= 0){
82780ee5cbfSDavid du Colombier 			if(c == '\\'){
82880ee5cbfSDavid du Colombier 				c = getc(h);
82980ee5cbfSDavid du Colombier 				if(c < 0)
83080ee5cbfSDavid du Colombier 					return '\n';
83180ee5cbfSDavid du Colombier 				continue;
83280ee5cbfSDavid du Colombier 			}
83380ee5cbfSDavid du Colombier 			if(c == '(')
83480ee5cbfSDavid du Colombier 				level++;
83580ee5cbfSDavid du Colombier 			else if(c == ')' && --level == 0)
83680ee5cbfSDavid du Colombier 				break;
83780ee5cbfSDavid du Colombier 			else if(c == '\n'){
83880ee5cbfSDavid du Colombier 				c = getc(h);
83980ee5cbfSDavid du Colombier 				if(c < 0)
84080ee5cbfSDavid du Colombier 					return '\n';
84180ee5cbfSDavid du Colombier 				if(c == ')' && --level == 0)
84280ee5cbfSDavid du Colombier 					break;
84380ee5cbfSDavid du Colombier 				if(c != ' ' && c != '\t'){
84480ee5cbfSDavid du Colombier 					ungetc(h);
84580ee5cbfSDavid du Colombier 					return '\n';
84680ee5cbfSDavid du Colombier 				}
84780ee5cbfSDavid du Colombier 			}
84880ee5cbfSDavid du Colombier 		}
84980ee5cbfSDavid du Colombier 		goto top;
85080ee5cbfSDavid du Colombier 
85180ee5cbfSDavid du Colombier 	case ' ': case '\t':
85280ee5cbfSDavid du Colombier 		goto top;
85380ee5cbfSDavid du Colombier 
85480ee5cbfSDavid du Colombier 	case '\r':
85580ee5cbfSDavid du Colombier 		c = getc(h);
85680ee5cbfSDavid du Colombier 		if(c != '\n'){
85780ee5cbfSDavid du Colombier 			ungetc(h);
85880ee5cbfSDavid du Colombier 			goto top;
85980ee5cbfSDavid du Colombier 		}
86080ee5cbfSDavid du Colombier 
86180ee5cbfSDavid du Colombier 	case '\n':
86280ee5cbfSDavid du Colombier 		if(h->tok == '\n'){
86380ee5cbfSDavid du Colombier 			h->eol = 1;
86480ee5cbfSDavid du Colombier 			h->eoh = 1;
86580ee5cbfSDavid du Colombier 			return '\n';
86680ee5cbfSDavid du Colombier 		}
86780ee5cbfSDavid du Colombier 		c = getc(h);
86880ee5cbfSDavid du Colombier 		if(c < 0){
86980ee5cbfSDavid du Colombier 			h->eol = 1;
87080ee5cbfSDavid du Colombier 			return '\n';
87180ee5cbfSDavid du Colombier 		}
87280ee5cbfSDavid du Colombier 		if(c != ' ' && c != '\t'){
87380ee5cbfSDavid du Colombier 			ungetc(h);
87480ee5cbfSDavid du Colombier 			h->eol = 1;
87580ee5cbfSDavid du Colombier 			return '\n';
87680ee5cbfSDavid du Colombier 		}
87780ee5cbfSDavid du Colombier 		goto top;
87880ee5cbfSDavid du Colombier 
87980ee5cbfSDavid du Colombier 	case ')':
88080ee5cbfSDavid du Colombier 	case '<': case '>':
88180ee5cbfSDavid du Colombier 	case '[': case ']':
88280ee5cbfSDavid du Colombier 	case '@': case '/':
88380ee5cbfSDavid du Colombier 	case ',': case ';': case ':': case '?': case '=':
88480ee5cbfSDavid du Colombier 		if(skipwhite){
88580ee5cbfSDavid du Colombier 			ungetc(h);
88680ee5cbfSDavid du Colombier 			return c;
88780ee5cbfSDavid du Colombier 		}
88880ee5cbfSDavid du Colombier 		return c;
88980ee5cbfSDavid du Colombier 
89080ee5cbfSDavid du Colombier 	case '"':
89180ee5cbfSDavid du Colombier 		if(skipwhite){
89280ee5cbfSDavid du Colombier 			ungetc(h);
89380ee5cbfSDavid du Colombier 			return c;
89480ee5cbfSDavid du Colombier 		}
89580ee5cbfSDavid du Colombier 		word(h, "\"");
89680ee5cbfSDavid du Colombier 		getc(h);		/* skip the closing quote */
89780ee5cbfSDavid du Colombier 		return QString;
89880ee5cbfSDavid du Colombier 
89980ee5cbfSDavid du Colombier 	default:
90080ee5cbfSDavid du Colombier 		ungetc(h);
90180ee5cbfSDavid du Colombier 		if(skipwhite)
90280ee5cbfSDavid du Colombier 			return c;
90380ee5cbfSDavid du Colombier 		word(h, "\"(){}<>@,;:/[]?=\r\n \t");
90480ee5cbfSDavid du Colombier 		if(h->wordval[0] == '\0'){
90580ee5cbfSDavid du Colombier 			h->c->head.closeit = 1;
90680ee5cbfSDavid du Colombier 			hfail(h->c, HSyntax);
90780ee5cbfSDavid du Colombier 			longjmp(h->jmp, -1);
90880ee5cbfSDavid du Colombier 		}
90980ee5cbfSDavid du Colombier 		return Word;
91080ee5cbfSDavid du Colombier 	}
911b85a8364SDavid du Colombier 	/* not reached */
91280ee5cbfSDavid du Colombier }
91380ee5cbfSDavid du Colombier 
91480ee5cbfSDavid du Colombier /*
91580ee5cbfSDavid du Colombier  * return the rest of an rfc 822, including \n
91680ee5cbfSDavid du Colombier  * do not map to lower case
91780ee5cbfSDavid du Colombier  */
91880ee5cbfSDavid du Colombier static void
lexhead(Hlex * h)91980ee5cbfSDavid du Colombier lexhead(Hlex *h)
92080ee5cbfSDavid du Colombier {
92180ee5cbfSDavid du Colombier 	int c, n;
92280ee5cbfSDavid du Colombier 
92380ee5cbfSDavid du Colombier 	n = 0;
92480ee5cbfSDavid du Colombier 	while((c = getc(h)) >= 0){
92580ee5cbfSDavid du Colombier 		if(c == '\r')
92680ee5cbfSDavid du Colombier 			c = wordcr(h);
92780ee5cbfSDavid du Colombier 		else if(c == '\n')
92880ee5cbfSDavid du Colombier 			c = wordnl(h);
92980ee5cbfSDavid du Colombier 		if(c == '\n')
93080ee5cbfSDavid du Colombier 			break;
93180ee5cbfSDavid du Colombier 		if(c == '\\'){
93280ee5cbfSDavid du Colombier 			c = getc(h);
93380ee5cbfSDavid du Colombier 			if(c < 0)
93480ee5cbfSDavid du Colombier 				break;
93580ee5cbfSDavid du Colombier 		}
93680ee5cbfSDavid du Colombier 
93780ee5cbfSDavid du Colombier 		if(n < HMaxWord-1)
93880ee5cbfSDavid du Colombier 			h->wordval[n++] = c;
93980ee5cbfSDavid du Colombier 	}
94080ee5cbfSDavid du Colombier 	h->tok = '\n';
94180ee5cbfSDavid du Colombier 	h->eol = 1;
94280ee5cbfSDavid du Colombier 	h->wordval[n] = '\0';
94380ee5cbfSDavid du Colombier }
94480ee5cbfSDavid du Colombier 
94580ee5cbfSDavid du Colombier static void
word(Hlex * h,char * stop)94680ee5cbfSDavid du Colombier word(Hlex *h, char *stop)
94780ee5cbfSDavid du Colombier {
94880ee5cbfSDavid du Colombier 	int c, n;
94980ee5cbfSDavid du Colombier 
95080ee5cbfSDavid du Colombier 	n = 0;
95180ee5cbfSDavid du Colombier 	while((c = getc(h)) >= 0){
95280ee5cbfSDavid du Colombier 		if(c == '\r')
95380ee5cbfSDavid du Colombier 			c = wordcr(h);
95480ee5cbfSDavid du Colombier 		else if(c == '\n')
95580ee5cbfSDavid du Colombier 			c = wordnl(h);
95680ee5cbfSDavid du Colombier 		if(c == '\\'){
95780ee5cbfSDavid du Colombier 			c = getc(h);
95880ee5cbfSDavid du Colombier 			if(c < 0)
95980ee5cbfSDavid du Colombier 				break;
96080ee5cbfSDavid du Colombier 		}else if(c < 32 || strchr(stop, c) != nil){
96180ee5cbfSDavid du Colombier 			ungetc(h);
96280ee5cbfSDavid du Colombier 			break;
96380ee5cbfSDavid du Colombier 		}
96480ee5cbfSDavid du Colombier 
96580ee5cbfSDavid du Colombier 		if(n < HMaxWord-1)
96680ee5cbfSDavid du Colombier 			h->wordval[n++] = c;
96780ee5cbfSDavid du Colombier 	}
96880ee5cbfSDavid du Colombier 	h->wordval[n] = '\0';
96980ee5cbfSDavid du Colombier }
97080ee5cbfSDavid du Colombier 
97180ee5cbfSDavid du Colombier static int
wordcr(Hlex * h)97280ee5cbfSDavid du Colombier wordcr(Hlex *h)
97380ee5cbfSDavid du Colombier {
97480ee5cbfSDavid du Colombier 	int c;
97580ee5cbfSDavid du Colombier 
97680ee5cbfSDavid du Colombier 	c = getc(h);
97780ee5cbfSDavid du Colombier 	if(c == '\n')
97880ee5cbfSDavid du Colombier 		return wordnl(h);
97980ee5cbfSDavid du Colombier 	ungetc(h);
98080ee5cbfSDavid du Colombier 	return ' ';
98180ee5cbfSDavid du Colombier }
98280ee5cbfSDavid du Colombier 
98380ee5cbfSDavid du Colombier static int
wordnl(Hlex * h)98480ee5cbfSDavid du Colombier wordnl(Hlex *h)
98580ee5cbfSDavid du Colombier {
98680ee5cbfSDavid du Colombier 	int c;
98780ee5cbfSDavid du Colombier 
98880ee5cbfSDavid du Colombier 	c = getc(h);
98980ee5cbfSDavid du Colombier 	if(c == ' ' || c == '\t')
99080ee5cbfSDavid du Colombier 		return c;
99180ee5cbfSDavid du Colombier 	ungetc(h);
99280ee5cbfSDavid du Colombier 
99380ee5cbfSDavid du Colombier 	return '\n';
99480ee5cbfSDavid du Colombier }
99580ee5cbfSDavid du Colombier 
99680ee5cbfSDavid du Colombier static int
getc(Hlex * h)99780ee5cbfSDavid du Colombier getc(Hlex *h)
99880ee5cbfSDavid du Colombier {
99980ee5cbfSDavid du Colombier 	if(h->eoh)
100080ee5cbfSDavid du Colombier 		return -1;
100180ee5cbfSDavid du Colombier 	if(h->c->hpos < h->c->hstop)
100280ee5cbfSDavid du Colombier 		return *h->c->hpos++;
100380ee5cbfSDavid du Colombier 	h->eoh = 1;
100480ee5cbfSDavid du Colombier 	h->eol = 1;
100580ee5cbfSDavid du Colombier 	return -1;
100680ee5cbfSDavid du Colombier }
100780ee5cbfSDavid du Colombier 
100880ee5cbfSDavid du Colombier static void
ungetc(Hlex * h)100980ee5cbfSDavid du Colombier ungetc(Hlex *h)
101080ee5cbfSDavid du Colombier {
101180ee5cbfSDavid du Colombier 	if(h->eoh)
101280ee5cbfSDavid du Colombier 		return;
101380ee5cbfSDavid du Colombier 	h->c->hpos--;
101480ee5cbfSDavid du Colombier }
101580ee5cbfSDavid du Colombier 
101680ee5cbfSDavid du Colombier static ulong
digtoul(char * s,char ** e)101780ee5cbfSDavid du Colombier digtoul(char *s, char **e)
101880ee5cbfSDavid du Colombier {
101980ee5cbfSDavid du Colombier 	ulong v;
102080ee5cbfSDavid du Colombier 	int c, ovfl;
102180ee5cbfSDavid du Colombier 
102280ee5cbfSDavid du Colombier 	v = 0;
102380ee5cbfSDavid du Colombier 	ovfl = 0;
102480ee5cbfSDavid du Colombier 	for(;;){
102580ee5cbfSDavid du Colombier 		c = *s;
102680ee5cbfSDavid du Colombier 		if(c < '0' || c > '9')
102780ee5cbfSDavid du Colombier 			break;
102880ee5cbfSDavid du Colombier 		s++;
102980ee5cbfSDavid du Colombier 		c -= '0';
103080ee5cbfSDavid du Colombier 		if(v > UlongMax/10 || v == UlongMax/10 && c >= UlongMax%10)
103180ee5cbfSDavid du Colombier 			ovfl = 1;
103280ee5cbfSDavid du Colombier 		v = v * 10 + c;
103380ee5cbfSDavid du Colombier 	}
103480ee5cbfSDavid du Colombier 
103580ee5cbfSDavid du Colombier 	if(e)
103680ee5cbfSDavid du Colombier 		*e = s;
103780ee5cbfSDavid du Colombier 	if(ovfl)
103880ee5cbfSDavid du Colombier 		return UlongMax;
103980ee5cbfSDavid du Colombier 	return v;
104080ee5cbfSDavid du Colombier }
104180ee5cbfSDavid du Colombier 
104280ee5cbfSDavid du Colombier int
http11(HConnect * c)104380ee5cbfSDavid du Colombier http11(HConnect *c)
104480ee5cbfSDavid du Colombier {
104580ee5cbfSDavid du Colombier 	return c->req.vermaj > 1 || c->req.vermaj == 1 && c->req.vermin > 0;
104680ee5cbfSDavid du Colombier }
104780ee5cbfSDavid du Colombier 
104880ee5cbfSDavid du Colombier char*
hmkmimeboundary(HConnect * c)104980ee5cbfSDavid du Colombier hmkmimeboundary(HConnect *c)
105080ee5cbfSDavid du Colombier {
105180ee5cbfSDavid du Colombier 	char buf[32];
105280ee5cbfSDavid du Colombier 	int i;
105380ee5cbfSDavid du Colombier 
105480ee5cbfSDavid du Colombier 	srand((time(0)<<16)|getpid());
105580ee5cbfSDavid du Colombier 	strcpy(buf, "upas-");
105680ee5cbfSDavid du Colombier 	for(i = 5; i < sizeof(buf)-1; i++)
105780ee5cbfSDavid du Colombier 		buf[i] = 'a' + nrand(26);
105880ee5cbfSDavid du Colombier 	buf[i] = 0;
105980ee5cbfSDavid du Colombier 	return hstrdup(c, buf);
106080ee5cbfSDavid du Colombier }
106180ee5cbfSDavid du Colombier 
106280ee5cbfSDavid du Colombier HSPairs*
hmkspairs(HConnect * c,char * s,char * t,HSPairs * next)106380ee5cbfSDavid du Colombier hmkspairs(HConnect *c, char *s, char *t, HSPairs *next)
106480ee5cbfSDavid du Colombier {
106580ee5cbfSDavid du Colombier 	HSPairs *sp;
106680ee5cbfSDavid du Colombier 
106780ee5cbfSDavid du Colombier 	sp = halloc(c, sizeof *sp);
106880ee5cbfSDavid du Colombier 	sp->s = s;
106980ee5cbfSDavid du Colombier 	sp->t = t;
107080ee5cbfSDavid du Colombier 	sp->next = next;
107180ee5cbfSDavid du Colombier 	return sp;
107280ee5cbfSDavid du Colombier }
107380ee5cbfSDavid du Colombier 
107480ee5cbfSDavid du Colombier HSPairs*
hrevspairs(HSPairs * sp)107580ee5cbfSDavid du Colombier hrevspairs(HSPairs *sp)
107680ee5cbfSDavid du Colombier {
107780ee5cbfSDavid du Colombier 	HSPairs *last, *next;
107880ee5cbfSDavid du Colombier 
107980ee5cbfSDavid du Colombier 	last = nil;
108080ee5cbfSDavid du Colombier 	for(; sp != nil; sp = next){
108180ee5cbfSDavid du Colombier 		next = sp->next;
108280ee5cbfSDavid du Colombier 		sp->next = last;
108380ee5cbfSDavid du Colombier 		last = sp;
108480ee5cbfSDavid du Colombier 	}
108580ee5cbfSDavid du Colombier 	return last;
108680ee5cbfSDavid du Colombier }
108780ee5cbfSDavid du Colombier 
108880ee5cbfSDavid du Colombier HFields*
hmkhfields(HConnect * c,char * s,HSPairs * p,HFields * next)108980ee5cbfSDavid du Colombier hmkhfields(HConnect *c, char *s, HSPairs *p, HFields *next)
109080ee5cbfSDavid du Colombier {
109180ee5cbfSDavid du Colombier 	HFields *hf;
109280ee5cbfSDavid du Colombier 
109380ee5cbfSDavid du Colombier 	hf = halloc(c, sizeof *hf);
109480ee5cbfSDavid du Colombier 	hf->s = s;
109580ee5cbfSDavid du Colombier 	hf->params = p;
109680ee5cbfSDavid du Colombier 	hf->next = next;
109780ee5cbfSDavid du Colombier 	return hf;
109880ee5cbfSDavid du Colombier }
109980ee5cbfSDavid du Colombier 
110080ee5cbfSDavid du Colombier HFields*
hrevhfields(HFields * hf)110180ee5cbfSDavid du Colombier hrevhfields(HFields *hf)
110280ee5cbfSDavid du Colombier {
110380ee5cbfSDavid du Colombier 	HFields *last, *next;
110480ee5cbfSDavid du Colombier 
110580ee5cbfSDavid du Colombier 	last = nil;
110680ee5cbfSDavid du Colombier 	for(; hf != nil; hf = next){
110780ee5cbfSDavid du Colombier 		next = hf->next;
110880ee5cbfSDavid du Colombier 		hf->next = last;
110980ee5cbfSDavid du Colombier 		last = hf;
111080ee5cbfSDavid du Colombier 	}
111180ee5cbfSDavid du Colombier 	return last;
111280ee5cbfSDavid du Colombier }
111380ee5cbfSDavid du Colombier 
111480ee5cbfSDavid du Colombier HContent*
hmkcontent(HConnect * c,char * generic,char * specific,HContent * next)111580ee5cbfSDavid du Colombier hmkcontent(HConnect *c, char *generic, char *specific, HContent *next)
111680ee5cbfSDavid du Colombier {
111780ee5cbfSDavid du Colombier 	HContent *ct;
111880ee5cbfSDavid du Colombier 
111980ee5cbfSDavid du Colombier 	ct = halloc(c, sizeof(HContent));
112080ee5cbfSDavid du Colombier 	ct->generic = generic;
112180ee5cbfSDavid du Colombier 	ct->specific = specific;
112280ee5cbfSDavid du Colombier 	ct->next = next;
112380ee5cbfSDavid du Colombier 	ct->q = 1;
112480ee5cbfSDavid du Colombier 	ct->mxb = 0;
112580ee5cbfSDavid du Colombier 	return ct;
112680ee5cbfSDavid du Colombier }
1127