w3m

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

map.c (16502B)


      1 /* $Id$ */
      2 /*
      3  * client-side image maps
      4  */
      5 #include "fm.h"
      6 #include <math.h>
      7 
      8 MapList *
      9 searchMapList(Buffer *buf, char *name)
     10 {
     11     MapList *ml;
     12 
     13     if (name == NULL)
     14 	return NULL;
     15     for (ml = buf->maplist; ml != NULL; ml = ml->next) {
     16 	if (!Strcmp_charp(ml->name, name))
     17 	    break;
     18     }
     19     return ml;
     20 }
     21 
     22 #ifdef USE_IMAGE
     23 static int
     24 inMapArea(MapArea * a, int x, int y)
     25 {
     26     int i;
     27     double r1, r2, s, c, t;
     28 
     29     if (!a)
     30 	return FALSE;
     31     switch (a->shape) {
     32     case SHAPE_RECT:
     33 	if (x >= a->coords[0] && y >= a->coords[1] &&
     34 	    x <= a->coords[2] && y <= a->coords[3])
     35 	    return TRUE;
     36 	break;
     37     case SHAPE_CIRCLE:
     38 	if ((x - a->coords[0]) * (x - a->coords[0])
     39 	    + (y - a->coords[1]) * (y - a->coords[1])
     40 	    <= a->coords[2] * a->coords[2])
     41 	    return TRUE;
     42 	break;
     43     case SHAPE_POLY:
     44 	for (t = 0, i = 0; i < a->ncoords; i += 2) {
     45 	    r1 = sqrt((double)(x - a->coords[i]) * (x - a->coords[i])
     46 		      + (double)(y - a->coords[i + 1]) * (y -
     47 							  a->coords[i + 1]));
     48 	    r2 = sqrt((double)(x - a->coords[i + 2]) * (x - a->coords[i + 2])
     49 		      + (double)(y - a->coords[i + 3]) * (y -
     50 							  a->coords[i + 3]));
     51 	    if (r1 == 0 || r2 == 0)
     52 		return TRUE;
     53 	    s = ((double)(x - a->coords[i]) * (y - a->coords[i + 3])
     54 		 - (double)(x - a->coords[i + 2]) * (y -
     55 						     a->coords[i +
     56 							       1])) / r1 / r2;
     57 	    c = ((double)(x - a->coords[i]) * (x - a->coords[i + 2])
     58 		 + (double)(y - a->coords[i + 1]) * (y -
     59 						     a->coords[i +
     60 							       3])) / r1 / r2;
     61 	    t += atan2(s, c);
     62 	}
     63 	if (fabs(t) > 2 * 3.14)
     64 	    return TRUE;
     65 	break;
     66     case SHAPE_DEFAULT:
     67 	return TRUE;
     68     default:
     69 	break;
     70     }
     71     return FALSE;
     72 }
     73 
     74 static int
     75 nearestMapArea(MapList *ml, int x, int y)
     76 {
     77     ListItem *al;
     78     MapArea *a;
     79     int i, l, n = -1, min = -1, limit = pixel_per_char * pixel_per_char
     80 	+ pixel_per_line * pixel_per_line;
     81 
     82     if (!ml || !ml->area)
     83 	return n;
     84     for (i = 0, al = ml->area->first; al != NULL; i++, al = al->next) {
     85 	a = (MapArea *) al->ptr;
     86 	if (a) {
     87 	    l = (a->center_x - x) * (a->center_x - x)
     88 		+ (a->center_y - y) * (a->center_y - y);
     89 	    if ((min < 0 || l < min) && l < limit) {
     90 		n = i;
     91 		min = l;
     92 	    }
     93 	}
     94     }
     95     return n;
     96 }
     97 
     98 static int
     99 searchMapArea(Buffer *buf, MapList *ml, Anchor *a_img)
    100 {
    101     ListItem *al;
    102     MapArea *a;
    103     int i, n;
    104     int px, py;
    105 
    106     if (!(ml && ml->area && ml->area->nitem))
    107 	return -1;
    108     if (!getMapXY(buf, a_img, &px, &py))
    109 	return -1;
    110     n = -ml->area->nitem;
    111     for (i = 0, al = ml->area->first; al != NULL; i++, al = al->next) {
    112 	a = (MapArea *) al->ptr;
    113 	if (!a)
    114 	    continue;
    115 	if (n < 0 && inMapArea(a, px, py)) {
    116 	    if (a->shape == SHAPE_DEFAULT) {
    117 		if (n == -ml->area->nitem)
    118 		    n = -i;
    119 	    }
    120 	    else
    121 		n = i;
    122 	}
    123     }
    124     if (n == -ml->area->nitem)
    125 	return nearestMapArea(ml, px, py);
    126     else if (n < 0)
    127 	return -n;
    128     return n;
    129 }
    130 
    131 MapArea *
    132 retrieveCurrentMapArea(Buffer *buf)
    133 {
    134     Anchor *a_img, *a_form;
    135     FormItemList *fi;
    136     MapList *ml;
    137     ListItem *al;
    138     MapArea *a;
    139     int i, n;
    140 
    141     a_img = retrieveCurrentImg(buf);
    142     if (!(a_img && a_img->image && a_img->image->map))
    143 	return NULL;
    144     a_form = retrieveCurrentForm(buf);
    145     if (!(a_form && a_form->url))
    146 	return NULL;
    147     fi = (FormItemList *)a_form->url;
    148     if (!(fi && fi->parent && fi->parent->item))
    149 	return NULL;
    150     fi = fi->parent->item;
    151     ml = searchMapList(buf, fi->value ? fi->value->ptr : NULL);
    152     if (!ml)
    153 	return NULL;
    154     n = searchMapArea(buf, ml, a_img);
    155     if (n < 0)
    156 	return NULL;
    157     for (i = 0, al = ml->area->first; al != NULL; i++, al = al->next) {
    158 	a = (MapArea *) al->ptr;
    159 	if (a && i == n)
    160 	    return a;
    161     }
    162     return NULL;
    163 }
    164 
    165 int
    166 getMapXY(Buffer *buf, Anchor *a, int *x, int *y)
    167 {
    168     if (!buf || !a || !a->image || !x || !y)
    169 	return 0;
    170     *x = (int)((buf->currentColumn + buf->cursorX
    171 		- COLPOS(buf->currentLine, a->start.pos) + 0.5)
    172 	       * pixel_per_char) - a->image->xoffset;
    173     *y = (int)((buf->currentLine->linenumber - a->image->y + 0.5)
    174 	       * pixel_per_line) - a->image->yoffset;
    175     if (*x <= 0)
    176 	*x = 1;
    177     if (*y <= 0)
    178 	*y = 1;
    179     return 1;
    180 }
    181 #endif
    182 
    183 Anchor *
    184 retrieveCurrentMap(Buffer *buf)
    185 {
    186     Anchor *a;
    187     FormItemList *fi;
    188 
    189     a = retrieveCurrentForm(buf);
    190     if (!a || !a->url)
    191 	return NULL;
    192     fi = (FormItemList *)a->url;
    193     if (fi->parent->method == FORM_METHOD_INTERNAL &&
    194 	!Strcmp_charp(fi->parent->action, "map"))
    195 	return a;
    196     return NULL;
    197 }
    198 
    199 #if defined(USE_IMAGE) || defined(MENU_MAP)
    200 MapArea *
    201 follow_map_menu(Buffer *buf, char *name, Anchor *a_img, int x, int y)
    202 {
    203     MapList *ml;
    204     ListItem *al;
    205     int i, selected = -1;
    206     int initial = 0;
    207 #ifdef MENU_MAP
    208     MapArea *a;
    209     char **label;
    210 #endif
    211 
    212     ml = searchMapList(buf, name);
    213     if (ml == NULL || ml->area == NULL || ml->area->nitem == 0)
    214 	return NULL;
    215 
    216 #ifdef USE_IMAGE
    217     initial = searchMapArea(buf, ml, a_img);
    218     if (initial < 0)
    219 	initial = 0;
    220     else if (!image_map_list) {
    221 	selected = initial;
    222 	goto map_end;
    223     }
    224 #endif
    225 
    226 #ifdef MENU_MAP
    227     label = New_N(char *, ml->area->nitem + 1);
    228     for (i = 0, al = ml->area->first; al != NULL; i++, al = al->next) {
    229 	a = (MapArea *) al->ptr;
    230 	if (a)
    231 	    label[i] = *a->alt ? a->alt : a->url;
    232 	else
    233 	    label[i] = "";
    234     }
    235     label[ml->area->nitem] = NULL;
    236 
    237     optionMenu(x, y, label, &selected, initial, NULL);
    238 #endif
    239 
    240 #ifdef USE_IMAGE
    241   map_end:
    242 #endif
    243     if (selected >= 0) {
    244 	for (i = 0, al = ml->area->first; al != NULL; i++, al = al->next) {
    245 	    if (al->ptr && i == selected)
    246 		return (MapArea *) al->ptr;
    247 	}
    248     }
    249     return NULL;
    250 }
    251 #endif
    252 
    253 #ifndef MENU_MAP
    254 char *map1 = "<HTML><HEAD><TITLE>Image map links</TITLE></HEAD>\
    255 <BODY><H1>Image map links</H1>\
    256 <table>";
    257 
    258 Buffer *
    259 follow_map_panel(Buffer *buf, char *name)
    260 {
    261     Str mappage;
    262     MapList *ml;
    263     ListItem *al;
    264     MapArea *a;
    265     ParsedURL pu;
    266     char *p, *q;
    267     Buffer *newbuf;
    268 
    269     ml = searchMapList(buf, name);
    270     if (ml == NULL)
    271 	return NULL;
    272 
    273     mappage = Strnew_charp(map1);
    274     for (al = ml->area->first; al != NULL; al = al->next) {
    275 	a = (MapArea *) al->ptr;
    276 	if (!a)
    277 	    continue;
    278 	parseURL2(a->url, &pu, baseURL(buf));
    279 	p = parsedURL2Str(&pu)->ptr;
    280 	q = html_quote(p);
    281 	if (DecodeURL)
    282 	    p = html_quote(url_unquote_conv(p, buf->document_charset));
    283 	else
    284 	    p = q;
    285 	Strcat_m_charp(mappage, "<tr valign=top><td><a href=\"", q, "\">",
    286 		       html_quote(*a->alt ? a->alt : mybasename(a->url)),
    287 		       "</a><td>", p, NULL);
    288     }
    289     Strcat_charp(mappage, "</table></body></html>");
    290 
    291     newbuf = loadHTMLString(mappage);
    292 #ifdef USE_M17N
    293     if (newbuf)
    294 	newbuf->document_charset = buf->document_charset;
    295 #endif
    296     return newbuf;
    297 }
    298 #endif
    299 
    300 MapArea *
    301 newMapArea(char *url, char *target, char *alt, char *shape, char *coords)
    302 {
    303     MapArea *a = New(MapArea);
    304 #ifdef USE_IMAGE
    305     char *p;
    306     int i, max;
    307 #endif
    308 
    309     a->url = url;
    310     a->target = target;
    311     a->alt = alt ? alt : "";
    312 #ifdef USE_IMAGE
    313     a->shape = SHAPE_RECT;
    314     if (shape) {
    315 	if (!strcasecmp(shape, "default"))
    316 	    a->shape = SHAPE_DEFAULT;
    317 	else if (!strncasecmp(shape, "rect", 4))
    318 	    a->shape = SHAPE_RECT;
    319 	else if (!strncasecmp(shape, "circ", 4))
    320 	    a->shape = SHAPE_CIRCLE;
    321 	else if (!strncasecmp(shape, "poly", 4))
    322 	    a->shape = SHAPE_POLY;
    323 	else
    324 	    a->shape = SHAPE_UNKNOWN;
    325     }
    326     a->coords = NULL;
    327     a->ncoords = 0;
    328     a->center_x = 0;
    329     a->center_y = 0;
    330     if (a->shape == SHAPE_UNKNOWN || a->shape == SHAPE_DEFAULT)
    331 	return a;
    332     if (!coords) {
    333 	a->shape = SHAPE_UNKNOWN;
    334 	return a;
    335     }
    336     if (a->shape == SHAPE_RECT) {
    337 	a->coords = New_N(short, 4);
    338 	a->ncoords = 4;
    339     }
    340     else if (a->shape == SHAPE_CIRCLE) {
    341 	a->coords = New_N(short, 3);
    342 	a->ncoords = 3;
    343     }
    344     max = a->ncoords;
    345     for (i = 0, p = coords; (a->shape == SHAPE_POLY || i < a->ncoords) && *p;) {
    346 	while (IS_SPACE(*p))
    347 	    p++;
    348 	if (!IS_DIGIT(*p) && *p != '-' && *p != '+')
    349 	    break;
    350 	if (a->shape == SHAPE_POLY) {
    351 	    if (max <= i) {
    352 		max = i ? i * 2 : 6;
    353 		a->coords = New_Reuse(short, a->coords, max + 2);
    354 	    }
    355 	    a->ncoords++;
    356 	}
    357 	a->coords[i] = (short)atoi(p);
    358 	i++;
    359 	if (*p == '-' || *p == '+')
    360 	    p++;
    361 	while (IS_DIGIT(*p))
    362 	    p++;
    363 	if (*p != ',' && !IS_SPACE(*p))
    364 	    break;
    365 	while (IS_SPACE(*p))
    366 	    p++;
    367 	if (*p == ',')
    368 	    p++;
    369     }
    370     if (i != a->ncoords || (a->shape == SHAPE_POLY && a->ncoords < 6)) {
    371 	a->shape = SHAPE_UNKNOWN;
    372 	a->coords = NULL;
    373 	a->ncoords = 0;
    374 	return a;
    375     }
    376     if (a->shape == SHAPE_POLY) {
    377 	a->ncoords = a->ncoords / 2 * 2;
    378 	a->coords[a->ncoords] = a->coords[0];
    379 	a->coords[a->ncoords + 1] = a->coords[1];
    380     }
    381     if (a->shape == SHAPE_CIRCLE) {
    382 	a->center_x = a->coords[0];
    383 	a->center_y = a->coords[1];
    384     }
    385     else {
    386 	for (i = 0; i < a->ncoords / 2; i++) {
    387 	    a->center_x += a->coords[2 * i];
    388 	    a->center_y += a->coords[2 * i + 1];
    389 	}
    390 	a->center_x /= a->ncoords / 2;
    391 	a->center_y /= a->ncoords / 2;
    392     }
    393 #endif
    394     return a;
    395 }
    396 
    397 /* append image map links */
    398 static void
    399 append_map_info(Buffer *buf, Str tmp, FormItemList *fi)
    400 {
    401     MapList *ml;
    402     ListItem *al;
    403     MapArea *a;
    404     ParsedURL pu;
    405     char *p, *q;
    406 
    407     ml = searchMapList(buf, fi->value ? fi->value->ptr : NULL);
    408     if (ml == NULL)
    409 	return;
    410 
    411     Strcat_m_charp(tmp,
    412 		   "<tr valign=top><td colspan=2>Links of current image map",
    413 		   "<tr valign=top><td colspan=2><table>", NULL);
    414     for (al = ml->area->first; al != NULL; al = al->next) {
    415 	a = (MapArea *) al->ptr;
    416 	if (!a)
    417 	    continue;
    418 	parseURL2(a->url, &pu, baseURL(buf));
    419 	q = html_quote(parsedURL2Str(&pu)->ptr);
    420 	if (DecodeURL)
    421 	    p = html_quote(url_unquote_conv(a->url, buf->document_charset));
    422 	else
    423 	    p = html_quote(a->url);
    424 	Strcat_m_charp(tmp, "<tr valign=top><td>&nbsp;&nbsp;<td><a href=\"",
    425 		       q, "\">",
    426 		       html_quote(*a->alt ? a->alt : mybasename(a->url)),
    427 		       "</a><td>", p, "\n", NULL);
    428     }
    429     Strcat_charp(tmp, "</table>");
    430 }
    431 
    432 /* append links */
    433 static void
    434 append_link_info(Buffer *buf, Str html, LinkList * link)
    435 {
    436     LinkList *l;
    437     ParsedURL pu;
    438     char *url;
    439 
    440     if (!link)
    441 	return;
    442 
    443     Strcat_charp(html, "<hr width=50%><h1>Link information</h1><table>\n");
    444     for (l = link; l; l = l->next) {
    445 	if (l->url) {
    446 	    parseURL2(l->url, &pu, baseURL(buf));
    447 	    url = html_quote(parsedURL2Str(&pu)->ptr);
    448 	}
    449 	else
    450 	    url = "(empty)";
    451 	Strcat_m_charp(html, "<tr valign=top><td><a href=\"", url, "\">",
    452 		       l->title ? html_quote(l->title) : "(empty)", "</a><td>",
    453 		       NULL);
    454 	if (l->type == LINK_TYPE_REL)
    455 	    Strcat_charp(html, "[Rel]");
    456 	else if (l->type == LINK_TYPE_REV)
    457 	    Strcat_charp(html, "[Rev]");
    458 	if (!l->url)
    459 	    url = "(empty)";
    460 	else if (DecodeURL)
    461 	    url = html_quote(url_unquote_conv(l->url, buf->document_charset));
    462 	else
    463 	    url = html_quote(l->url);
    464 	Strcat_m_charp(html, "<td>", url, NULL);
    465 	if (l->ctype)
    466 	    Strcat_m_charp(html, " (", html_quote(l->ctype), ")", NULL);
    467 	Strcat_charp(html, "\n");
    468     }
    469     Strcat_charp(html, "</table>\n");
    470 }
    471 
    472 /* append frame URL */
    473 static void
    474 append_frame_info(Buffer *buf, Str html, struct frameset *set, int level)
    475 {
    476     char *p, *q;
    477     int i, j;
    478 
    479     if (!set)
    480 	return;
    481 
    482     for (i = 0; i < set->col * set->row; i++) {
    483 	union frameset_element frame = set->frame[i];
    484 	if (frame.element != NULL) {
    485 	    switch (frame.element->attr) {
    486 	    case F_UNLOADED:
    487 	    case F_BODY:
    488 		if (frame.body->url == NULL)
    489 		    break;
    490 		Strcat_charp(html, "<pre_int>");
    491 		for (j = 0; j < level; j++)
    492 		    Strcat_charp(html, "   ");
    493 		q = html_quote(frame.body->url);
    494 		Strcat_m_charp(html, "<a href=\"", q, "\">", NULL);
    495 		if (frame.body->name) {
    496 		    p = html_quote(url_unquote_conv(frame.body->name,
    497 						    buf->document_charset));
    498 		    Strcat_charp(html, p);
    499 		}
    500 		if (DecodeURL)
    501 		    p = html_quote(url_unquote_conv(frame.body->url,
    502 						    buf->document_charset));
    503 		else
    504 		    p = q;
    505 		Strcat_m_charp(html, " ", p, "</a></pre_int><br>\n", NULL);
    506 #ifdef USE_SSL
    507 		if (frame.body->ssl_certificate)
    508 		    Strcat_m_charp(html,
    509 				   "<blockquote><h2>SSL certificate</h2><pre>\n",
    510 				   html_quote(frame.body->ssl_certificate),
    511 				   "</pre></blockquote>\n", NULL);
    512 #endif
    513 		break;
    514 	    case F_FRAMESET:
    515 		append_frame_info(buf, html, frame.set, level + 1);
    516 		break;
    517 	    }
    518 	}
    519     }
    520 }
    521 
    522 /* 
    523  * information of current page and link 
    524  */
    525 Buffer *
    526 page_info_panel(Buffer *buf)
    527 {
    528     Str tmp = Strnew_size(1024);
    529     Anchor *a;
    530     ParsedURL pu;
    531     TextListItem *ti;
    532     struct frameset *f_set = NULL;
    533     int all;
    534     char *p, *q;
    535 #ifdef USE_M17N
    536     wc_ces_list *list;
    537     char charset[16];
    538 #endif
    539     Buffer *newbuf;
    540 
    541     Strcat_charp(tmp, "<html><head>\
    542 <title>Information about current page</title>\
    543 </head><body>\
    544 <h1>Information about current page</h1>\n");
    545     if (buf == NULL)
    546 	goto end;
    547     all = buf->allLine;
    548     if (all == 0 && buf->lastLine)
    549 	all = buf->lastLine->linenumber;
    550 #ifdef USE_M17N
    551     Strcat_charp(tmp, "<form method=internal action=charset>");
    552 #endif
    553     p = parsedURL2Str(&buf->currentURL)->ptr;
    554     if (DecodeURL)
    555 	p = url_unquote_conv(p, 0);
    556     Strcat_m_charp(tmp, "<table cellpadding=0>",
    557 		   "<tr valign=top><td nowrap>Title<td>",
    558 		   html_quote(buf->buffername),
    559 		   "<tr valign=top><td nowrap>Current URL<td>",
    560 		   html_quote(p),
    561 		   "<tr valign=top><td nowrap>Document Type<td>",
    562 		   buf->real_type ? html_quote(buf->real_type) : "unknown",
    563 		   "<tr valign=top><td nowrap>Last Modified<td>",
    564 		   html_quote(last_modified(buf)), NULL);
    565 #ifdef USE_M17N
    566     if (buf->document_charset != InnerCharset) {
    567 	list = wc_get_ces_list();
    568 	Strcat_charp(tmp,
    569 		     "<tr><td nowrap>Document Charset<td><select name=charset>");
    570 	for (; list->name != NULL; list++) {
    571 	    sprintf(charset, "%d", (unsigned int)list->id);
    572 	    Strcat_m_charp(tmp, "<option value=", charset,
    573 			   (buf->document_charset == list->id) ? " selected>"
    574 			   : ">", list->desc, NULL);
    575 	}
    576 	Strcat_charp(tmp, "</select>");
    577 	Strcat_charp(tmp, "<tr><td><td><input type=submit value=Change>");
    578     }
    579 #endif
    580     Strcat_m_charp(tmp,
    581 		   "<tr valign=top><td nowrap>Number of lines<td>",
    582 		   Sprintf("%d", all)->ptr,
    583 		   "<tr valign=top><td nowrap>Transferred bytes<td>",
    584 		   Sprintf("%d", buf->trbyte)->ptr, NULL);
    585 
    586     a = retrieveCurrentAnchor(buf);
    587     if (a != NULL) {
    588 	parseURL2(a->url, &pu, baseURL(buf));
    589 	p = parsedURL2Str(&pu)->ptr;
    590 	q = html_quote(p);
    591 	if (DecodeURL)
    592 	    p = html_quote(url_unquote_conv(p, buf->document_charset));
    593 	else
    594 	    p = q;
    595 	Strcat_m_charp(tmp,
    596 		       "<tr valign=top><td nowrap>URL of current anchor<td><a href=\"",
    597 		       q, "\">", p, "</a>", NULL);
    598     }
    599     a = retrieveCurrentImg(buf);
    600     if (a != NULL) {
    601 	parseURL2(a->url, &pu, baseURL(buf));
    602 	p = parsedURL2Str(&pu)->ptr;
    603 	q = html_quote(p);
    604 	if (DecodeURL)
    605 	    p = html_quote(url_unquote_conv(p, buf->document_charset));
    606 	else
    607 	    p = q;
    608 	Strcat_m_charp(tmp,
    609 		       "<tr valign=top><td nowrap>URL of current image<td><a href=\"",
    610 		       q, "\">", p, "</a>", NULL);
    611     }
    612     a = retrieveCurrentForm(buf);
    613     if (a != NULL) {
    614 	FormItemList *fi = (FormItemList *)a->url;
    615 	p = form2str(fi);
    616 	if (DecodeURL)
    617 	    p = html_quote(url_unquote_conv(p, buf->document_charset));
    618 	else
    619 	    p = html_quote(p);
    620 	Strcat_m_charp(tmp,
    621 		       "<tr valign=top><td nowrap>Method/type of current form&nbsp;<td>",
    622 		       p, NULL);
    623 	if (fi->parent->method == FORM_METHOD_INTERNAL
    624 	    && !Strcmp_charp(fi->parent->action, "map"))
    625 	    append_map_info(buf, tmp, fi->parent->item);
    626     }
    627     Strcat_charp(tmp, "</table>\n");
    628 #ifdef USE_M17N
    629     Strcat_charp(tmp, "</form>");
    630 #endif
    631 
    632     append_link_info(buf, tmp, buf->linklist);
    633 
    634     if (buf->document_header != NULL) {
    635 	Strcat_charp(tmp, "<hr width=50%><h1>Header information</h1><pre>\n");
    636 	for (ti = buf->document_header->first; ti != NULL; ti = ti->next)
    637 	    Strcat_m_charp(tmp, "<pre_int>", html_quote(ti->ptr),
    638 			   "</pre_int>\n", NULL);
    639 	Strcat_charp(tmp, "</pre>\n");
    640     }
    641 
    642     if (buf->frameset != NULL)
    643 	f_set = buf->frameset;
    644     else if (buf->bufferprop & BP_FRAME &&
    645 	     buf->nextBuffer != NULL && buf->nextBuffer->frameset != NULL)
    646 	f_set = buf->nextBuffer->frameset;
    647 
    648     if (f_set) {
    649 	Strcat_charp(tmp, "<hr width=50%><h1>Frame information</h1>\n");
    650 	append_frame_info(buf, tmp, f_set, 0);
    651     }
    652 #ifdef USE_SSL
    653     if (buf->ssl_certificate)
    654 	Strcat_m_charp(tmp, "<h1>SSL certificate</h1><pre>\n",
    655 		       html_quote(buf->ssl_certificate), "</pre>\n", NULL);
    656 #endif
    657   end:
    658     Strcat_charp(tmp, "</body></html>");
    659     newbuf = loadHTMLString(tmp);
    660 #ifdef USE_M17N
    661     if (newbuf)
    662 	newbuf->document_charset = buf->document_charset;
    663 #endif
    664     return newbuf;
    665 }