w3m

Unnamed repository; edit this file to name it for gitweb.
git clone https://logand.com/git/w3m.git/
Log | Files | Refs | README

cookie.c (18108B)


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