1 /* $Id: cookie.c,v 1.11 2010/07/26 11:38:53 htrb Exp $ */
2 
3 /*
4  * References for version 0 cookie:
5  *   [NETACAPE] http://www.netscape.com/newsref/std/cookie_spec.html
6  *
7  * References for version 1 cookie:
8  *   [RFC 2109] http://www.ics.uci.edu/pub/ietf/http/rfc2109.txt
9  *   [DRAFT 12] http://www.ics.uci.edu/pub/ietf/http/draft-ietf-http-state-man-mec-12.txt
10  */
11 
12 #include "fm.h"
13 #include "html.h"
14 
15 #ifdef USE_COOKIE
16 #include <time.h>
17 #include "local.h"
18 #include "regex.h"
19 #include "myctype.h"
20 
21 static int is_saved = 1;
22 
23 #define contain_no_dots(p, ep) (total_dot_number((p),(ep),1)==0)
24 
25 static unsigned int
total_dot_number(char * p,char * ep,unsigned int max_count)26 total_dot_number(char *p, char *ep, unsigned int max_count)
27 {
28     unsigned int count = 0;
29     if (!ep)
30 	ep = p + strlen(p);
31 
32     for (; p < ep && count < max_count; p++) {
33 	if (*p == '.')
34 	    count++;
35     }
36     return count;
37 }
38 
39 
40 static char *
domain_match(char * host,char * domain)41 domain_match(char *host, char *domain)
42 {
43     int m0, m1;
44 
45     /* [RFC 2109] s. 2, "domain-match", case 1
46      * (both are IP and identical)
47      */
48     regexCompile("[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+", 0);
49     m0 = regexMatch(host, -1, 1);
50     m1 = regexMatch(domain, -1, 1);
51     if (m0 && m1) {
52 	if (strcasecmp(host, domain) == 0)
53 	    return host;
54     }
55     else if (!m0 && !m1) {
56 	int offset;
57 	char *domain_p;
58 	/*
59 	 * "." match all domains (w3m only),
60 	 * and ".local" match local domains ([DRAFT 12] s. 2)
61 	 */
62 	if (strcasecmp(domain, ".") == 0 || strcasecmp(domain, ".local") == 0) {
63 	    offset = strlen(host);
64 	    domain_p = &host[offset];
65 	    if (domain[1] == '\0' || contain_no_dots(host, domain_p))
66 		return domain_p;
67 	}
68 	/*
69 	 * special case for domainName = .hostName
70 	 * see nsCookieService.cpp in Firefox.
71 	 */
72 	else if (domain[0] == '.' && strcasecmp(host, &domain[1]) == 0) {
73 	    return host;
74 	}
75 	/* [RFC 2109] s. 2, cases 2, 3 */
76 	else {
77 	    offset = (domain[0] != '.') ? 0 : strlen(host) - strlen(domain);
78 	    domain_p = &host[offset];
79 	    if (offset >= 0 && strcasecmp(domain_p, domain) == 0)
80 		return domain_p;
81 	}
82     }
83     return NULL;
84 }
85 
86 
87 static struct portlist *
make_portlist(Str port)88 make_portlist(Str port)
89 {
90     struct portlist *first = NULL, *pl;
91     char *p;
92     Str tmp = Strnew();
93 
94     p = port->ptr;
95     while (*p) {
96 	while (*p && !IS_DIGIT(*p))
97 	    p++;
98 	Strclear(tmp);
99 	while (*p && IS_DIGIT(*p))
100 	    Strcat_char(tmp, *(p++));
101 	if (tmp->length == 0)
102 	    break;
103 	pl = New(struct portlist);
104 	pl->port = atoi(tmp->ptr);
105 	pl->next = first;
106 	first = pl;
107     }
108     Strfree(tmp);
109     return first;
110 }
111 
112 static Str
portlist2str(struct portlist * first)113 portlist2str(struct portlist *first)
114 {
115     struct portlist *pl;
116     Str tmp;
117 
118     tmp = Sprintf("%d", first->port);
119     for (pl = first->next; pl; pl = pl->next)
120 	Strcat(tmp, Sprintf(", %d", pl->port));
121     return tmp;
122 }
123 
124 static int
port_match(struct portlist * first,int port)125 port_match(struct portlist *first, int port)
126 {
127     struct portlist *pl;
128 
129     for (pl = first; pl; pl = pl->next) {
130 	if (pl->port == port)
131 	    return 1;
132     }
133     return 0;
134 }
135 
136 static void
check_expired_cookies(void)137 check_expired_cookies(void)
138 {
139     struct cookie *p, *p1;
140     time_t now = time(NULL);
141 
142     if (!First_cookie)
143 	return;
144 
145     if (First_cookie->expires != (time_t) - 1 && First_cookie->expires < now) {
146 	if (!(First_cookie->flag & COO_DISCARD))
147 	    is_saved = 0;
148 	First_cookie = First_cookie->next;
149     }
150 
151     for (p = First_cookie; p && p->next; p = p1) {
152 	p1 = p->next;
153 	if (p1->expires != (time_t) - 1 && p1->expires < now) {
154 	    if (!(p1->flag & COO_DISCARD))
155 		is_saved = 0;
156 	    p->next = p1->next;
157 	    p1 = p;
158 	}
159     }
160 }
161 
162 static Str
make_cookie(struct cookie * cookie)163 make_cookie(struct cookie *cookie)
164 {
165     Str tmp = Strdup(cookie->name);
166     Strcat_char(tmp, '=');
167     Strcat(tmp, cookie->value);
168     return tmp;
169 }
170 
171 static int
match_cookie(ParsedURL * pu,struct cookie * cookie,char * domainname)172 match_cookie(ParsedURL *pu, struct cookie *cookie, char *domainname)
173 {
174     if (!domainname)
175 	return 0;
176 
177     if (!domain_match(domainname, cookie->domain->ptr))
178 	return 0;
179     if (strncmp(cookie->path->ptr, pu->file, cookie->path->length) != 0)
180 	return 0;
181 #ifdef USE_SSL
182     if (cookie->flag & COO_SECURE && pu->scheme != SCM_HTTPS)
183 	return 0;
184 #else				/* not USE_SSL */
185     if (cookie->flag & COO_SECURE)
186 	return 0;
187 #endif				/* not USE_SSL */
188     if (cookie->portl && !port_match(cookie->portl, pu->port))
189 	return 0;
190 
191     return 1;
192 }
193 
194 struct cookie *
get_cookie_info(Str domain,Str path,Str name)195 get_cookie_info(Str domain, Str path, Str name)
196 {
197     struct cookie *p;
198 
199     for (p = First_cookie; p; p = p->next) {
200 	if (Strcasecmp(p->domain, domain) == 0 &&
201 	    Strcmp(p->path, path) == 0 && Strcasecmp(p->name, name) == 0)
202 	    return p;
203     }
204     return NULL;
205 }
206 
207 Str
find_cookie(ParsedURL * pu)208 find_cookie(ParsedURL *pu)
209 {
210     Str tmp;
211     struct cookie *p, *p1, *fco = NULL;
212     int version = 0;
213     char *fq_domainname, *domainname;
214 
215     fq_domainname = FQDN(pu->host);
216     check_expired_cookies();
217     for (p = First_cookie; p; p = p->next) {
218 	domainname = (p->version == 0) ? fq_domainname : pu->host;
219 	if (p->flag & COO_USE && match_cookie(pu, p, domainname)) {
220 	    for (p1 = fco; p1 && Strcasecmp(p1->name, p->name);
221 		 p1 = p1->next) ;
222 	    if (p1)
223 		continue;
224 	    p1 = New(struct cookie);
225 	    bcopy(p, p1, sizeof(struct cookie));
226 	    p1->next = fco;
227 	    fco = p1;
228 	    if (p1->version > version)
229 		version = p1->version;
230 	}
231     }
232 
233     if (!fco)
234 	return NULL;
235 
236     tmp = Strnew();
237     if (version > 0)
238 	Strcat(tmp, Sprintf("$Version=\"%d\"; ", version));
239 
240     Strcat(tmp, make_cookie(fco));
241     for (p1 = fco->next; p1; p1 = p1->next) {
242 	Strcat_charp(tmp, "; ");
243 	Strcat(tmp, make_cookie(p1));
244 	if (version > 0) {
245 	    if (p1->flag & COO_PATH)
246 		Strcat(tmp, Sprintf("; $Path=\"%s\"", p1->path->ptr));
247 	    if (p1->flag & COO_DOMAIN)
248 		Strcat(tmp, Sprintf("; $Domain=\"%s\"", p1->domain->ptr));
249 	    if (p1->portl)
250 		Strcat(tmp,
251 		       Sprintf("; $Port=\"%s\"", portlist2str(p1->portl)->ptr));
252 	}
253     }
254     return tmp;
255 }
256 
257 int
check_avoid_wrong_number_of_dots_domain(Str domain)258 check_avoid_wrong_number_of_dots_domain( Str domain )
259 {
260    TextListItem *tl;
261     int avoid_wrong_number_of_dots_domain = FALSE;
262 
263     if (Cookie_avoid_wrong_number_of_dots_domains &&
264             Cookie_avoid_wrong_number_of_dots_domains->nitem > 0) {
265         for (tl = Cookie_avoid_wrong_number_of_dots_domains->first;
266                 tl != NULL; tl = tl->next) {
267             if (domain_match(domain->ptr, tl->ptr)) {
268                 avoid_wrong_number_of_dots_domain = TRUE;
269                 break;
270             }
271         }
272     }
273 
274     if (avoid_wrong_number_of_dots_domain == TRUE) {
275         return TRUE;
276     } else {
277         return FALSE;
278     }
279 }
280 
281 int
add_cookie(ParsedURL * pu,Str name,Str value,time_t expires,Str domain,Str path,int flag,Str comment,int version,Str port,Str commentURL)282 add_cookie(ParsedURL *pu, Str name, Str value,
283 	   time_t expires, Str domain, Str path,
284 	   int flag, Str comment, int version, Str port, Str commentURL)
285 {
286     struct cookie *p;
287     char *domainname = (version == 0) ? FQDN(pu->host) : pu->host;
288     Str odomain = domain, opath = path;
289     struct portlist *portlist = NULL;
290     int use_security = !(flag & COO_OVERRIDE);
291 
292 #define COOKIE_ERROR(err) if(!((err) & COO_OVERRIDE_OK) || use_security) return (err)
293 
294 #ifdef DEBUG
295     fprintf(stderr, "host: [%s, %s] %d\n", pu->host, pu->file, flag);
296     fprintf(stderr, "cookie: [%s=%s]\n", name->ptr, value->ptr);
297     fprintf(stderr, "expires: [%s]\n", asctime(gmtime(&expires)));
298     if (domain)
299 	fprintf(stderr, "domain: [%s]\n", domain->ptr);
300     if (path)
301 	fprintf(stderr, "path: [%s]\n", path->ptr);
302     fprintf(stderr, "version: [%d]\n", version);
303     if (port)
304 	fprintf(stderr, "port: [%s]\n", port->ptr);
305 #endif				/* DEBUG */
306     /* [RFC 2109] s. 4.3.2 case 2; but this (no request-host) shouldn't happen */
307     if (!domainname)
308 	return COO_ENODOT;
309 
310     if (domain) {
311 	char *dp;
312 	/* [DRAFT 12] s. 4.2.2 (does not apply in the case that
313 	 * host name is the same as domain attribute for version 0
314 	 * cookie)
315 	 * I think that this rule has almost the same effect as the
316 	 * tail match of [NETSCAPE].
317 	 */
318 	if (domain->ptr[0] != '.' &&
319 	    (version > 0 || strcasecmp(domainname, domain->ptr) != 0))
320 	    domain = Sprintf(".%s", domain->ptr);
321 
322 	if (version == 0) {
323 	    /* [NETSCAPE] rule */
324 	    unsigned int n = total_dot_number(domain->ptr,
325 				     domain->ptr + domain->length,
326 				     3);
327 	    if (n < 2) {
328 		if (! check_avoid_wrong_number_of_dots_domain(domain)) {
329 		    COOKIE_ERROR(COO_ESPECIAL);
330 		}
331 	    }
332 	}
333 	else {
334 	    /* [DRAFT 12] s. 4.3.2 case 2 */
335 	    if (strcasecmp(domain->ptr, ".local") != 0 &&
336 		contain_no_dots(&domain->ptr[1], &domain->ptr[domain->length]))
337 		COOKIE_ERROR(COO_ENODOT);
338 	}
339 
340 	/* [RFC 2109] s. 4.3.2 case 3 */
341 	if (!(dp = domain_match(domainname, domain->ptr)))
342 	    COOKIE_ERROR(COO_EDOM);
343 	/* [RFC 2409] s. 4.3.2 case 4 */
344 	/* Invariant: dp contains matched domain */
345 	if (version > 0 && !contain_no_dots(domainname, dp))
346 	    COOKIE_ERROR(COO_EBADHOST);
347     }
348     if (path) {
349 	/* [RFC 2109] s. 4.3.2 case 1 */
350 	if (version > 0 && strncmp(path->ptr, pu->file, path->length) != 0)
351 	    COOKIE_ERROR(COO_EPATH);
352     }
353     if (port) {
354 	/* [DRAFT 12] s. 4.3.2 case 5 */
355 	portlist = make_portlist(port);
356 	if (portlist && !port_match(portlist, pu->port))
357 	    COOKIE_ERROR(COO_EPORT);
358     }
359 
360     if (!domain)
361 	domain = Strnew_charp(domainname);
362     if (!path) {
363 	path = Strnew_charp(pu->file);
364 	while (path->length > 0 && Strlastchar(path) != '/')
365 	    Strshrink(path, 1);
366 	if (Strlastchar(path) == '/')
367 	    Strshrink(path, 1);
368     }
369 
370     p = get_cookie_info(domain, path, name);
371     if (!p) {
372 	p = New(struct cookie);
373 	p->flag = 0;
374 	if (default_use_cookie)
375 	    p->flag |= COO_USE;
376 	p->next = First_cookie;
377 	First_cookie = p;
378     }
379 
380     copyParsedURL(&p->url, pu);
381     p->name = name;
382     p->value = value;
383     p->expires = expires;
384     p->domain = domain;
385     p->path = path;
386     p->comment = comment;
387     p->version = version;
388     p->portl = portlist;
389     p->commentURL = commentURL;
390 
391     if (flag & COO_SECURE)
392 	p->flag |= COO_SECURE;
393     else
394 	p->flag &= ~COO_SECURE;
395     if (odomain)
396 	p->flag |= COO_DOMAIN;
397     else
398 	p->flag &= ~COO_DOMAIN;
399     if (opath)
400 	p->flag |= COO_PATH;
401     else
402 	p->flag &= ~COO_PATH;
403     if (flag & COO_DISCARD || p->expires == (time_t) - 1) {
404 	p->flag |= COO_DISCARD;
405     }
406     else {
407 	p->flag &= ~COO_DISCARD;
408 	is_saved = 0;
409     }
410 
411     check_expired_cookies();
412     return 0;
413 }
414 
415 struct cookie *
nth_cookie(int n)416 nth_cookie(int n)
417 {
418     struct cookie *p;
419     int i;
420     for (p = First_cookie, i = 0; p; p = p->next, i++) {
421 	if (i == n)
422 	    return p;
423     }
424     return NULL;
425 }
426 
427 #define str2charp(str) ((str)? (str)->ptr : "")
428 
429 void
save_cookies(void)430 save_cookies(void)
431 {
432     struct cookie *p;
433     char *cookie_file;
434     FILE *fp;
435 
436     check_expired_cookies();
437 
438     if (!First_cookie || is_saved || no_rc_dir)
439 	return;
440 
441     cookie_file = rcFile(COOKIE_FILE);
442     if (!(fp = fopen(cookie_file, "w")))
443 	return;
444 
445     for (p = First_cookie; p; p = p->next) {
446 	if (!(p->flag & COO_USE) || p->flag & COO_DISCARD)
447 	    continue;
448 	fprintf(fp, "%s\t%s\t%s\t%ld\t%s\t%s\t%d\t%d\t%s\t%s\t%s\n",
449 		parsedURL2Str(&p->url)->ptr,
450 		p->name->ptr, p->value->ptr, (long)p->expires,
451 		p->domain->ptr, p->path->ptr, p->flag,
452 		p->version, str2charp(p->comment),
453 		(p->portl) ? portlist2str(p->portl)->ptr : "",
454 		str2charp(p->commentURL));
455     }
456     fclose(fp);
457     chmod(cookie_file, S_IRUSR | S_IWUSR);
458 }
459 
460 static Str
readcol(char ** p)461 readcol(char **p)
462 {
463     Str tmp = Strnew();
464     while (**p && **p != '\n' && **p != '\r' && **p != '\t')
465 	Strcat_char(tmp, *((*p)++));
466     if (**p == '\t')
467 	(*p)++;
468     return tmp;
469 }
470 
471 void
load_cookies(void)472 load_cookies(void)
473 {
474     struct cookie *cookie, *p;
475     FILE *fp;
476     Str line;
477     char *str;
478 
479     if (!(fp = fopen(rcFile(COOKIE_FILE), "r")))
480 	return;
481 
482     if (First_cookie) {
483 	for (p = First_cookie; p->next; p = p->next) ;
484     }
485     else {
486 	p = NULL;
487     }
488     for (;;) {
489 	line = Strfgets(fp);
490 
491 	if (line->length == 0)
492 	    break;
493 	str = line->ptr;
494 	cookie = New(struct cookie);
495 	cookie->next = NULL;
496 	cookie->flag = 0;
497 	cookie->version = 0;
498 	cookie->expires = (time_t) - 1;
499 	cookie->comment = NULL;
500 	cookie->portl = NULL;
501 	cookie->commentURL = NULL;
502 	parseURL(readcol(&str)->ptr, &cookie->url, NULL);
503 	if (!*str)
504 	    break;
505 	cookie->name = readcol(&str);
506 	if (!*str)
507 	    break;
508 	cookie->value = readcol(&str);
509 	if (!*str)
510 	    break;
511 	cookie->expires = (time_t) atol(readcol(&str)->ptr);
512 	if (!*str)
513 	    break;
514 	cookie->domain = readcol(&str);
515 	if (!*str)
516 	    break;
517 	cookie->path = readcol(&str);
518 	if (!*str)
519 	    break;
520 	cookie->flag = atoi(readcol(&str)->ptr);
521 	if (!*str)
522 	    break;
523 	cookie->version = atoi(readcol(&str)->ptr);
524 	if (!*str)
525 	    break;
526 	cookie->comment = readcol(&str);
527 	if (cookie->comment->length == 0)
528 	    cookie->comment = NULL;
529 	if (!*str)
530 	    break;
531 	cookie->portl = make_portlist(readcol(&str));
532 	if (!*str)
533 	    break;
534 	cookie->commentURL = readcol(&str);
535 	if (cookie->commentURL->length == 0)
536 	    cookie->commentURL = NULL;
537 
538 	if (p)
539 	    p->next = cookie;
540 	else
541 	    First_cookie = cookie;
542 	p = cookie;
543     }
544 
545     fclose(fp);
546 }
547 
548 void
initCookie(void)549 initCookie(void)
550 {
551     load_cookies();
552     check_expired_cookies();
553 }
554 
555 Buffer *
cookie_list_panel(void)556 cookie_list_panel(void)
557 {
558     /* FIXME: gettextize? */
559     Str src = Strnew_charp("<html><head><title>Cookies</title></head>"
560 			   "<body><center><b>Cookies</b></center>"
561 			   "<p><form method=internal action=cookie>");
562     struct cookie *p;
563     int i;
564     char *tmp, tmp2[80];
565 
566     if (!use_cookie || !First_cookie)
567 	return NULL;
568 
569     Strcat_charp(src, "<ol>");
570     for (p = First_cookie, i = 0; p; p = p->next, i++) {
571 	tmp = html_quote(parsedURL2Str(&p->url)->ptr);
572 	if (p->expires != (time_t) - 1) {
573 #ifdef HAVE_STRFTIME
574 	    strftime(tmp2, 80, "%a, %d %b %Y %H:%M:%S GMT",
575 		     gmtime(&p->expires));
576 #else				/* not HAVE_STRFTIME */
577 	    struct tm *gmt;
578 	    static char *dow[] = {
579 		"Sun ", "Mon ", "Tue ", "Wed ", "Thu ", "Fri ", "Sat "
580 	    };
581 	    static char *month[] = {
582 		"Jan ", "Feb ", "Mar ", "Apr ", "May ", "Jun ",
583 		"Jul ", "Aug ", "Sep ", "Oct ", "Nov ", "Dec "
584 	    };
585 	    gmt = gmtime(&p->expires);
586 	    strcpy(tmp2, dow[gmt->tm_wday]);
587 	    sprintf(&tmp2[4], "%02d ", gmt->tm_mday);
588 	    strcpy(&tmp2[7], month[gmt->tm_mon]);
589 	    if (gmt->tm_year < 1900)
590 		sprintf(&tmp2[11], "%04d %02d:%02d:%02d GMT",
591 			(gmt->tm_year) + 1900, gmt->tm_hour, gmt->tm_min,
592 			gmt->tm_sec);
593 	    else
594 		sprintf(&tmp2[11], "%04d %02d:%02d:%02d GMT",
595 			gmt->tm_year, gmt->tm_hour, gmt->tm_min, gmt->tm_sec);
596 #endif				/* not HAVE_STRFTIME */
597 	}
598 	else
599 	    tmp2[0] = '\0';
600 	Strcat_charp(src, "<li>");
601 	Strcat_charp(src, "<h1><a href=\"");
602 	Strcat_charp(src, tmp);
603 	Strcat_charp(src, "\">");
604 	Strcat_charp(src, tmp);
605 	Strcat_charp(src, "</a></h1>");
606 
607 	Strcat_charp(src, "<table cellpadding=0>");
608 	if (!(p->flag & COO_SECURE)) {
609 	    Strcat_charp(src, "<tr><td width=\"80\"><b>Cookie:</b></td><td>");
610 	    Strcat_charp(src, html_quote(make_cookie(p)->ptr));
611 	    Strcat_charp(src, "</td></tr>");
612 	}
613 	if (p->comment) {
614 	    Strcat_charp(src, "<tr><td width=\"80\"><b>Comment:</b></td><td>");
615 	    Strcat_charp(src, html_quote(p->comment->ptr));
616 	    Strcat_charp(src, "</td></tr>");
617 	}
618 	if (p->commentURL) {
619 	    Strcat_charp(src,
620 			 "<tr><td width=\"80\"><b>CommentURL:</b></td><td>");
621 	    Strcat_charp(src, "<a href=\"");
622 	    Strcat_charp(src, html_quote(p->commentURL->ptr));
623 	    Strcat_charp(src, "\">");
624 	    Strcat_charp(src, html_quote(p->commentURL->ptr));
625 	    Strcat_charp(src, "</a>");
626 	    Strcat_charp(src, "</td></tr>");
627 	}
628 	if (tmp2[0]) {
629 	    Strcat_charp(src, "<tr><td width=\"80\"><b>Expires:</b></td><td>");
630 	    Strcat_charp(src, tmp2);
631 	    if (p->flag & COO_DISCARD)
632 		Strcat_charp(src, " (Discard)");
633 	    Strcat_charp(src, "</td></tr>");
634 	}
635 	Strcat_charp(src, "<tr><td width=\"80\"><b>Version:</b></td><td>");
636 	Strcat_charp(src, Sprintf("%d", p->version)->ptr);
637 	Strcat_charp(src, "</td></tr><tr><td>");
638 	if (p->domain) {
639 	    Strcat_charp(src, "<tr><td width=\"80\"><b>Domain:</b></td><td>");
640 	    Strcat_charp(src, html_quote(p->domain->ptr));
641 	    Strcat_charp(src, "</td></tr>");
642 	}
643 	if (p->path) {
644 	    Strcat_charp(src, "<tr><td width=\"80\"><b>Path:</b></td><td>");
645 	    Strcat_charp(src, html_quote(p->path->ptr));
646 	    Strcat_charp(src, "</td></tr>");
647 	}
648 	if (p->portl) {
649 	    Strcat_charp(src, "<tr><td width=\"80\"><b>Port:</b></td><td>");
650 	    Strcat_charp(src, html_quote(portlist2str(p->portl)->ptr));
651 	    Strcat_charp(src, "</td></tr>");
652 	}
653 	Strcat_charp(src, "<tr><td width=\"80\"><b>Secure:</b></td><td>");
654 	Strcat_charp(src, (p->flag & COO_SECURE) ? "Yes" : "No");
655 	Strcat_charp(src, "</td></tr><tr><td>");
656 
657 	Strcat(src, Sprintf("<tr><td width=\"80\"><b>Use:</b></td><td>"
658 			    "<input type=radio name=\"%d\" value=1%s>Yes"
659 			    "&nbsp;&nbsp;"
660 			    "<input type=radio name=\"%d\" value=0%s>No",
661 			    i, (p->flag & COO_USE) ? " checked" : "",
662 			    i, (!(p->flag & COO_USE)) ? " checked" : ""));
663 	Strcat_charp(src,
664 		     "</td></tr><tr><td><input type=submit value=\"OK\"></table><p>");
665     }
666     Strcat_charp(src, "</ol></form></body></html>");
667     return loadHTMLString(src);
668 }
669 
670 void
set_cookie_flag(struct parsed_tagarg * arg)671 set_cookie_flag(struct parsed_tagarg *arg)
672 {
673     int n, v;
674     struct cookie *p;
675 
676     while (arg) {
677 	if (arg->arg && *arg->arg && arg->value && *arg->value) {
678 	    n = atoi(arg->arg);
679 	    v = atoi(arg->value);
680 	    if ((p = nth_cookie(n)) != NULL) {
681 		if (v && !(p->flag & COO_USE))
682 		    p->flag |= COO_USE;
683 		else if (!v && p->flag & COO_USE)
684 		    p->flag &= ~COO_USE;
685 		if (!(p->flag & COO_DISCARD))
686 		    is_saved = 0;
687 	    }
688 	}
689 	arg = arg->next;
690     }
691     backBf();
692 }
693 
694 int
check_cookie_accept_domain(char * domain)695 check_cookie_accept_domain(char *domain)
696 {
697     TextListItem *tl;
698 
699     if (domain == NULL)
700 	return 0;
701 
702     if (Cookie_accept_domains && Cookie_accept_domains->nitem > 0) {
703 	for (tl = Cookie_accept_domains->first; tl != NULL; tl = tl->next) {
704 	    if (domain_match(domain, tl->ptr))
705 		return 1;
706 	}
707     }
708     if (Cookie_reject_domains && Cookie_reject_domains->nitem > 0) {
709 	for (tl = Cookie_reject_domains->first; tl != NULL; tl = tl->next) {
710 	    if (domain_match(domain, tl->ptr))
711 		return 0;
712 	}
713     }
714     return 1;
715 }
716 #endif				/* USE_COOKIE */
717