1 /* $Id: frame.c,v 1.34 2003/09/26 17:59:51 ukai Exp $ */
2 #include "fm.h"
3 #include "parsetagx.h"
4 #include "myctype.h"
5 #include <signal.h>
6 #include <setjmp.h>
7 
8 static JMP_BUF AbortLoading;
9 struct frameset *renderFrameSet = NULL;
10 
11 static MySignalHandler
KeyAbort(SIGNAL_ARG)12 KeyAbort(SIGNAL_ARG)
13 {
14     LONGJMP(AbortLoading, 1);
15 }
16 
17 static int
parseFrameSetLength(char * s,char *** ret)18 parseFrameSetLength(char *s, char ***ret)
19 {
20     int i, len;
21     char *p, *q, **lv;
22 
23     i = 1;
24 
25     if (s)
26 	for (p = s; (p = strchr(p, ',')); ++p)
27 	    ++i;
28     else
29 	s = "*";
30 
31     lv = New_N(char *, i);
32 
33     for (i = 0, p = s;; ++p) {
34 	SKIP_BLANKS(p);
35 	len = strtol(p, &q, 10);
36 
37 	switch (*q) {
38 	case '%':
39 	    lv[i++] = Sprintf("%d%%", len)->ptr;
40 	    break;
41 	case '*':
42 	    lv[i++] = "*";
43 	    break;
44 	default:
45 	    lv[i++] = Sprintf("%d", len)->ptr;
46 	    break;
47 	}
48 
49 	if (!(p = strchr(q, ',')))
50 	    break;
51     }
52 
53     *ret = lv;
54     return i;
55 }
56 
57 struct frameset *
newFrameSet(struct parsed_tag * tag)58 newFrameSet(struct parsed_tag *tag)
59 {
60     struct frameset *f;
61     int i;
62     char *cols = NULL, *rows = NULL;
63 
64     f = New(struct frameset);
65     f->attr = F_FRAMESET;
66     f->name = NULL;
67     f->currentURL = NULL;
68     parsedtag_get_value(tag, ATTR_COLS, &cols);
69     parsedtag_get_value(tag, ATTR_ROWS, &rows);
70     f->col = parseFrameSetLength(cols, &f->width);
71     f->row = parseFrameSetLength(rows, &f->height);
72     f->i = 0;
73     i = f->row * f->col;
74     f->frame = New_N(union frameset_element, i);
75     do {
76 	f->frame[--i].element = NULL;
77     } while (i);
78     return f;
79 }
80 
81 struct frame_body *
newFrame(struct parsed_tag * tag,Buffer * buf)82 newFrame(struct parsed_tag *tag, Buffer *buf)
83 {
84     struct frame_body *body;
85     char *p;
86 
87     body = New(struct frame_body);
88     bzero((void *)body, sizeof(*body));
89     body->attr = F_UNLOADED;
90     body->flags = 0;
91     body->baseURL = baseURL(buf);
92     if (tag) {
93 	if (parsedtag_get_value(tag, ATTR_SRC, &p))
94 	    body->url = url_encode(remove_space(p), body->baseURL,
95 				   buf->document_charset);
96 	if (parsedtag_get_value(tag, ATTR_NAME, &p) && *p != '_')
97 	    body->name = url_quote_conv(p, buf->document_charset);
98     }
99     return body;
100 }
101 
102 static void
unloadFrame(struct frame_body * b)103 unloadFrame(struct frame_body *b)
104 {
105     b->attr = F_UNLOADED;
106 }
107 
108 void
deleteFrame(struct frame_body * b)109 deleteFrame(struct frame_body *b)
110 {
111     if (b == NULL)
112 	return;
113     unloadFrame(b);
114     bzero((void *)b, sizeof(*b));
115 }
116 
117 void
addFrameSetElement(struct frameset * f,union frameset_element element)118 addFrameSetElement(struct frameset *f, union frameset_element element)
119 {
120     int i;
121 
122     if (f == NULL)
123 	return;
124     i = f->i;
125     if (i >= f->col * f->row)
126 	return;
127     f->frame[i] = element;
128     f->i++;
129 }
130 
131 void
deleteFrameSet(struct frameset * f)132 deleteFrameSet(struct frameset *f)
133 {
134     int i;
135 
136     if (f == NULL)
137 	return;
138     for (i = 0; i < f->col * f->row; i++) {
139 	deleteFrameSetElement(f->frame[i]);
140     }
141     f->name = NULL;
142     f->currentURL = NULL;
143     return;
144 }
145 
146 void
deleteFrameSetElement(union frameset_element e)147 deleteFrameSetElement(union frameset_element e)
148 {
149     if (e.element == NULL)
150 	return;
151     switch (e.element->attr) {
152     case F_UNLOADED:
153 	break;
154     case F_BODY:
155 	deleteFrame(e.body);
156 	break;
157     case F_FRAMESET:
158 	deleteFrameSet(e.set);
159 	break;
160     default:
161 	break;
162     }
163     return;
164 }
165 
166 static struct frame_body *
copyFrame(struct frame_body * ob)167 copyFrame(struct frame_body *ob)
168 {
169     struct frame_body *rb;
170 
171     rb = New(struct frame_body);
172     bcopy((const void *)ob, (void *)rb, sizeof(struct frame_body));
173     return rb;
174 }
175 
176 struct frameset *
copyFrameSet(struct frameset * of)177 copyFrameSet(struct frameset *of)
178 {
179     struct frameset *rf;
180     int n;
181 
182     rf = New(struct frameset);
183     n = of->col * of->row;
184     bcopy((const void *)of, (void *)rf, sizeof(struct frameset));
185     rf->width = New_N(char *, rf->col);
186     bcopy((const void *)of->width,
187 	  (void *)rf->width, sizeof(char *) * rf->col);
188     rf->height = New_N(char *, rf->row);
189     bcopy((const void *)of->height,
190 	  (void *)rf->height, sizeof(char *) * rf->row);
191     rf->frame = New_N(union frameset_element, n);
192     while (n) {
193 	n--;
194 	if (!of->frame[n].element)
195 	    goto attr_default;
196 	switch (of->frame[n].element->attr) {
197 	case F_UNLOADED:
198 	case F_BODY:
199 	    rf->frame[n].body = copyFrame(of->frame[n].body);
200 	    break;
201 	case F_FRAMESET:
202 	    rf->frame[n].set = copyFrameSet(of->frame[n].set);
203 	    break;
204 	default:
205 	  attr_default:
206 	    rf->frame[n].element = NULL;
207 	    break;
208 	}
209     }
210     return rf;
211 }
212 
213 void
flushFrameSet(struct frameset * fs)214 flushFrameSet(struct frameset *fs)
215 {
216     int n = fs->i;
217 
218     while (n) {
219 	n--;
220 	if (!fs->frame[n].element)
221 	    goto attr_default;
222 	switch (fs->frame[n].element->attr) {
223 	case F_UNLOADED:
224 	case F_BODY:
225 	    fs->frame[n].body->nameList = NULL;
226 	    break;
227 	case F_FRAMESET:
228 	    flushFrameSet(fs->frame[n].set);
229 	    break;
230 	default:
231 	  attr_default:
232 	    /* nothing to do */
233 	    break;
234 	}
235     }
236 }
237 
238 void
pushFrameTree(struct frameset_queue ** fqpp,struct frameset * fs,Buffer * buf)239 pushFrameTree(struct frameset_queue **fqpp, struct frameset *fs, Buffer *buf)
240 {
241     struct frameset_queue *rfq, *cfq = *fqpp;
242 
243     if (!fs)
244 	return;
245 
246     rfq = New(struct frameset_queue);
247     rfq->linenumber = (buf
248 		       && buf->currentLine) ? buf->currentLine->linenumber : 1;
249     rfq->top_linenumber = (buf && buf->topLine) ? buf->topLine->linenumber : 1;
250     rfq->pos = buf ? buf->pos : 0;
251     rfq->currentColumn = buf ? buf->currentColumn : 0;
252     rfq->formitem = buf ? buf->formitem : NULL;
253 
254     rfq->back = cfq;
255     if (cfq) {
256 	rfq->next = cfq->next;
257 	if (cfq->next)
258 	    cfq->next->back = rfq;
259 	cfq->next = rfq;
260     }
261     else
262 	rfq->next = cfq;
263     rfq->frameset = fs;
264     *fqpp = rfq;
265     return;
266 }
267 
268 struct frameset *
popFrameTree(struct frameset_queue ** fqpp)269 popFrameTree(struct frameset_queue **fqpp)
270 {
271     struct frameset_queue *rfq = NULL, *cfq = *fqpp;
272     struct frameset *rfs = NULL;
273 
274     if (!cfq)
275 	return rfs;
276 
277     rfs = cfq->frameset;
278     if (cfq->next) {
279 	(rfq = cfq->next)->back = cfq->back;
280     }
281     if (cfq->back) {
282 	(rfq = cfq->back)->next = cfq->next;
283     }
284     *fqpp = rfq;
285     bzero((void *)cfq, sizeof(struct frameset_queue));
286     return rfs;
287 }
288 
289 void
resetFrameElement(union frameset_element * f_element,Buffer * buf,char * referer,FormList * request)290 resetFrameElement(union frameset_element *f_element,
291 		  Buffer *buf, char *referer, FormList *request)
292 {
293     char *f_name;
294     struct frame_body *f_body;
295 
296     f_name = f_element->element->name;
297     if (buf->frameset) {
298 	/* frame cascade */
299 	deleteFrameSetElement(*f_element);
300 	f_element->set = buf->frameset;
301 	f_element->set->currentURL = New(ParsedURL);
302 	copyParsedURL(f_element->set->currentURL, &buf->currentURL);
303 	buf->frameset = popFrameTree(&(buf->frameQ));
304 	f_element->set->name = f_name;
305     }
306     else {
307 	f_body = newFrame(NULL, buf);
308 	f_body->attr = F_BODY;
309 	f_body->name = f_name;
310 	f_body->url = parsedURL2Str(&buf->currentURL)->ptr;
311 	f_body->source = buf->sourcefile;
312 	buf->sourcefile = NULL;
313 	if (buf->mailcap_source) {
314 	    f_body->source = buf->mailcap_source;
315 	    buf->mailcap_source = NULL;
316 	}
317 	f_body->type = buf->type;
318 	f_body->referer = referer;
319 	f_body->request = request;
320 	deleteFrameSetElement(*f_element);
321 	f_element->body = f_body;
322     }
323 }
324 
325 static struct frameset *
frame_download_source(struct frame_body * b,ParsedURL * currentURL,ParsedURL * baseURL,int flag)326 frame_download_source(struct frame_body *b, ParsedURL *currentURL,
327 		      ParsedURL *baseURL, int flag)
328 {
329     Buffer *buf;
330     struct frameset *ret_frameset = NULL;
331     ParsedURL url;
332 
333     if (b == NULL || b->url == NULL || b->url[0] == '\0')
334 	return NULL;
335     if (b->baseURL)
336 	baseURL = b->baseURL;
337     parseURL2(b->url, &url, currentURL);
338     switch (url.scheme) {
339     case SCM_LOCAL:
340 #if 0
341 	b->source = url.real_file;
342 #endif
343 	b->flags = 0;
344     default:
345 	is_redisplay = TRUE;
346 	w3m_dump |= DUMP_FRAME;
347 	buf = loadGeneralFile(b->url,
348 			      baseURL ? baseURL : currentURL,
349 			      b->referer, flag | RG_FRAME_SRC, b->request);
350 #ifdef USE_SSL
351 	/* XXX certificate? */
352 	if (buf && buf != NO_BUFFER)
353 	    b->ssl_certificate = buf->ssl_certificate;
354 #endif
355 	w3m_dump &= ~DUMP_FRAME;
356 	is_redisplay = FALSE;
357 	break;
358     }
359 
360     if (buf == NULL || buf == NO_BUFFER) {
361 	b->source = NULL;
362 	b->flags = (buf == NO_BUFFER) ? FB_NO_BUFFER : 0;
363 	return NULL;
364     }
365     b->url = parsedURL2Str(&buf->currentURL)->ptr;
366     b->type = buf->type;
367     b->source = buf->sourcefile;
368     buf->sourcefile = NULL;
369     if (buf->mailcap_source) {
370 	b->source = buf->mailcap_source;
371 	buf->mailcap_source = NULL;
372     }
373     b->attr = F_BODY;
374     if (buf->frameset) {
375 	ret_frameset = buf->frameset;
376 	ret_frameset->name = b->name;
377 	ret_frameset->currentURL = New(ParsedURL);
378 	copyParsedURL(ret_frameset->currentURL, &buf->currentURL);
379 	buf->frameset = popFrameTree(&(buf->frameQ));
380     }
381     discardBuffer(buf);
382     return ret_frameset;
383 }
384 
385 #define CASE_TABLE_TAG \
386 	case HTML_TR:\
387 	case HTML_N_TR:\
388 	case HTML_TD:\
389 	case HTML_N_TD:\
390 	case HTML_TH:\
391 	case HTML_N_TH:\
392 	case HTML_THEAD:\
393 	case HTML_N_THEAD:\
394 	case HTML_TBODY:\
395 	case HTML_N_TBODY:\
396 	case HTML_TFOOT:\
397 	case HTML_N_TFOOT:\
398 	case HTML_COLGROUP:\
399 	case HTML_N_COLGROUP:\
400 	case HTML_COL
401 
402 static int
createFrameFile(struct frameset * f,FILE * f1,Buffer * current,int level,int force_reload)403 createFrameFile(struct frameset *f, FILE * f1, Buffer *current, int level,
404 		int force_reload)
405 {
406     int r, c, t_stack;
407     URLFile f2;
408 #ifdef USE_M17N
409     wc_ces charset, doc_charset;
410 #endif
411     char *d_target, *p_target, *s_target, *t_target;
412     ParsedURL *currentURL, base;
413     MySignalHandler(*volatile prevtrap) (SIGNAL_ARG) = NULL;
414     int flag;
415 
416     if (f == NULL)
417 	return -1;
418 
419     if (level == 0) {
420 	if (SETJMP(AbortLoading) != 0) {
421 	    TRAP_OFF;
422 	    return -1;
423 	}
424 	TRAP_ON;
425 	f->name = "_top";
426     }
427 
428     if (level > 7) {
429 	fputs("Too many frameset tasked.\n", f1);
430 	return -1;
431     }
432 
433     if (level == 0) {
434 	fprintf(f1, "<html><head><title>%s</title></head><body>\n",
435 		html_quote(current->buffername));
436 	fputs("<table hborder width=\"100%\">\n", f1);
437     }
438     else
439 	fputs("<table hborder>\n", f1);
440 
441     currentURL = f->currentURL ? f->currentURL : &current->currentURL;
442     for (r = 0; r < f->row; r++) {
443 	fputs("<tr valign=top>\n", f1);
444 	for (c = 0; c < f->col; c++) {
445 	    union frameset_element frame;
446 	    struct frameset *f_frameset;
447 	    int i = c + r * f->col;
448 	    char *p = "";
449 	    int status = R_ST_NORMAL;
450 	    Str tok = Strnew();
451 	    int pre_mode = 0;
452 	    int end_tag = 0;
453 
454 	    frame = f->frame[i];
455 
456 	    if (frame.element == NULL) {
457 		fputs("<td>\n</td>\n", f1);
458 		continue;
459 	    }
460 
461 	    fputs("<td", f1);
462 	    if (frame.element->name)
463 		fprintf(f1, " id=\"_%s\"", html_quote(frame.element->name));
464 	    if (!r)
465 		fprintf(f1, " width=\"%s\"", f->width[c]);
466 	    fputs(">\n", f1);
467 
468 	    flag = 0;
469 	    if (force_reload) {
470 		flag |= RG_NOCACHE;
471 		if (frame.element->attr == F_BODY)
472 		    unloadFrame(frame.body);
473 	    }
474 	    switch (frame.element->attr) {
475 	    default:
476 		/* FIXME: gettextize? */
477 		fprintf(f1, "Frameset \"%s\" frame %d: type unrecognized",
478 			html_quote(f->name), i + 1);
479 		break;
480 	    case F_UNLOADED:
481 		if (!frame.body->name && f->name) {
482 		    frame.body->name = Sprintf("%s_%d", f->name, i)->ptr;
483 		}
484 		fflush(f1);
485 		f_frameset = frame_download_source(frame.body,
486 						   currentURL,
487 						   current->baseURL, flag);
488 		if (f_frameset) {
489 		    deleteFrame(frame.body);
490 		    f->frame[i].set = frame.set = f_frameset;
491 		    goto render_frameset;
492 		}
493 		/* fall through */
494 	    case F_BODY:
495 		init_stream(&f2, SCM_LOCAL, NULL);
496 		if (frame.body->source) {
497 		    fflush(f1);
498 		    examineFile(frame.body->source, &f2);
499 		}
500 		if (f2.stream == NULL) {
501 		    frame.body->attr = F_UNLOADED;
502 		    if (frame.body->flags & FB_NO_BUFFER)
503 			/* FIXME: gettextize? */
504 			fprintf(f1, "Open %s with other method",
505 				html_quote(frame.body->url));
506 		    else if (frame.body->url)
507 			/* FIXME: gettextize? */
508 			fprintf(f1, "Can't open %s",
509 				html_quote(frame.body->url));
510 		    else
511 			/* FIXME: gettextize? */
512 			fprintf(f1,
513 				"This frame (%s) contains no src attribute",
514 				frame.body->name ? html_quote(frame.body->name)
515 				: "(no name)");
516 		    break;
517 		}
518 		parseURL2(frame.body->url, &base, currentURL);
519 		p_target = f->name;
520 		s_target = frame.body->name;
521 		t_target = "_blank";
522 		d_target = TargetSelf ? s_target : t_target;
523 #ifdef USE_M17N
524 		charset = WC_CES_US_ASCII;
525 		if (current->document_charset != WC_CES_US_ASCII)
526 		    doc_charset = current->document_charset;
527 		else
528 		    doc_charset = DocumentCharset;
529 #endif
530 		t_stack = 0;
531 		if (frame.body->type &&
532 		    !strcasecmp(frame.body->type, "text/plain")) {
533 		    Str tmp;
534 		    fprintf(f1, "<pre>\n");
535 		    while ((tmp = StrmyUFgets(&f2))->length) {
536 			tmp = convertLine(NULL, tmp, HTML_MODE, &charset,
537 					  doc_charset);
538 			fprintf(f1, "%s", html_quote(tmp->ptr));
539 		    }
540 		    fprintf(f1, "</pre>\n");
541 		    UFclose(&f2);
542 		    break;
543 		}
544 		do {
545 		    int is_tag = FALSE;
546 		    char *q;
547 		    struct parsed_tag *tag;
548 
549 		    do {
550 			if (*p == '\0') {
551 			    Str tmp = StrmyUFgets(&f2);
552 			    if (tmp->length == 0)
553 				break;
554 			    tmp = convertLine(NULL, tmp, HTML_MODE, &charset,
555 					      doc_charset);
556 			    p = tmp->ptr;
557 			}
558 			read_token(tok, &p, &status, 1, status != R_ST_NORMAL);
559 		    } while (status != R_ST_NORMAL);
560 
561 		    if (tok->length == 0)
562 			continue;
563 
564 		    if (tok->ptr[0] == '<') {
565 			if (tok->ptr[1] &&
566 			    REALLY_THE_BEGINNING_OF_A_TAG(tok->ptr))
567 			    is_tag = TRUE;
568 			else if (!(pre_mode & (RB_PLAIN | RB_INTXTA |
569 					       RB_SCRIPT | RB_STYLE))) {
570 			    p = Strnew_m_charp(tok->ptr + 1, p, NULL)->ptr;
571 			    tok = Strnew_charp("&lt;");
572 			}
573 		    }
574 		    if (is_tag) {
575 			if (pre_mode & (RB_PLAIN | RB_INTXTA | RB_SCRIPT |
576 					RB_STYLE)) {
577 			    q = tok->ptr;
578 			    if ((tag = parse_tag(&q, FALSE)) &&
579 				tag->tagid == end_tag) {
580 				if (pre_mode & RB_PLAIN) {
581 				    fputs("</PRE_PLAIN>", f1);
582 				    pre_mode = 0;
583 				    end_tag = 0;
584 				    goto token_end;
585 				}
586 				pre_mode = 0;
587 				end_tag = 0;
588 				goto proc_normal;
589 			    }
590 			    if (strncmp(tok->ptr, "<!--", 4) &&
591 				(q = strchr(tok->ptr + 1, '<'))) {
592 				tok = Strnew_charp_n(tok->ptr, q - tok->ptr);
593 				p = Strnew_m_charp(q, p, NULL)->ptr;
594 				status = R_ST_NORMAL;
595 			    }
596 			    is_tag = FALSE;
597 			}
598 			else if (pre_mode & RB_INSELECT) {
599 			    q = tok->ptr;
600 			    if ((tag = parse_tag(&q, FALSE))) {
601 				if ((tag->tagid == end_tag) ||
602 				    (tag->tagid == HTML_N_FORM)) {
603 				    if (tag->tagid == HTML_N_FORM)
604 					fputs("</SELECT>", f1);
605 				    pre_mode = 0;
606 				    end_tag = 0;
607 				    goto proc_normal;
608 				}
609 				if (t_stack) {
610 				    switch (tag->tagid) {
611 				    case HTML_TABLE:
612 				    case HTML_N_TABLE:
613 				      CASE_TABLE_TAG:
614 					fputs("</SELECT>", f1);
615 					pre_mode = 0;
616 					end_tag = 0;
617 					goto proc_normal;
618 				    }
619 				}
620 			    }
621 			}
622 		    }
623 
624 		  proc_normal:
625 		    if (is_tag) {
626 			char *q = tok->ptr;
627 			int j, a_target = 0;
628 			ParsedURL url;
629 
630 			if (!(tag = parse_tag(&q, FALSE)))
631 			    goto token_end;
632 
633 			switch (tag->tagid) {
634 			case HTML_TITLE:
635 			    fputs("<!-- title:", f1);
636 			    goto token_end;
637 			case HTML_N_TITLE:
638 			    fputs("-->", f1);
639 			    goto token_end;
640 			case HTML_BASE:
641 			    /* "BASE" is prohibit tag */
642 			    if (parsedtag_get_value(tag, ATTR_HREF, &q)) {
643 				q = url_encode(remove_space(q), NULL, charset);
644 				parseURL(q, &base, NULL);
645 			    }
646 			    if (parsedtag_get_value(tag, ATTR_TARGET, &q)) {
647 				if (!strcasecmp(q, "_self"))
648 				    d_target = s_target;
649 				else if (!strcasecmp(q, "_parent"))
650 				    d_target = p_target;
651 				else
652 				    d_target = url_quote_conv(q, charset);
653 			    }
654 			    Strshrinkfirst(tok, 1);
655 			    Strshrink(tok, 1);
656 			    fprintf(f1, "<!-- %s -->", html_quote(tok->ptr));
657 			    goto token_end;
658 			case HTML_META:
659 			    if (parsedtag_get_value(tag, ATTR_HTTP_EQUIV, &q)
660 				&& !strcasecmp(q, "refresh")) {
661 				if (parsedtag_get_value(tag, ATTR_CONTENT, &q)
662 				    ) {
663 				    Str s_tmp = NULL;
664 				    int refresh_interval =
665 					getMetaRefreshParam(q, &s_tmp);
666 				    if (s_tmp) {
667 					q = html_quote(s_tmp->ptr);
668 					fprintf(f1,
669 						"Refresh (%d sec) <a href=\"%s\">%s</a>\n",
670 						refresh_interval, q, q);
671 				    }
672 				}
673 			    }
674 #ifdef USE_M17N
675 			    if (UseContentCharset &&
676 				parsedtag_get_value(tag, ATTR_HTTP_EQUIV, &q)
677 				&& !strcasecmp(q, "Content-Type")
678 				&& parsedtag_get_value(tag, ATTR_CONTENT, &q)
679 				&& (q = strcasestr(q, "charset")) != NULL) {
680 				q += 7;
681 				SKIP_BLANKS(q);
682 				if (*q == '=') {
683 				    wc_ces c;
684 				    q++;
685 				    SKIP_BLANKS(q);
686 				    if ((c = wc_guess_charset(q, 0)) != 0) {
687 					doc_charset = c;
688 					charset = WC_CES_US_ASCII;
689 				    }
690 				}
691 			    }
692 #endif
693 			    /* fall thru, "META" is prohibit tag */
694 			case HTML_HEAD:
695 			case HTML_N_HEAD:
696 			case HTML_BODY:
697 			case HTML_N_BODY:
698 			case HTML_DOCTYPE:
699 			    /* prohibit_tags */
700 			    Strshrinkfirst(tok, 1);
701 			    Strshrink(tok, 1);
702 			    fprintf(f1, "<!-- %s -->", html_quote(tok->ptr));
703 			    goto token_end;
704 			case HTML_TABLE:
705 			    t_stack++;
706 			    break;
707 			case HTML_N_TABLE:
708 			    t_stack--;
709 			    if (t_stack < 0) {
710 				t_stack = 0;
711 				Strshrinkfirst(tok, 1);
712 				Strshrink(tok, 1);
713 				fprintf(f1,
714 					"<!-- table stack underflow: %s -->",
715 					html_quote(tok->ptr));
716 				goto token_end;
717 			    }
718 			    break;
719 			  CASE_TABLE_TAG:
720 			    /* table_tags MUST be in table stack */
721 			    if (!t_stack) {
722 				Strshrinkfirst(tok, 1);
723 				Strshrink(tok, 1);
724 				fprintf(f1, "<!-- %s -->",
725 					html_quote(tok->ptr));
726 				goto token_end;
727 
728 			    }
729 			    break;
730 			case HTML_SELECT:
731 			    pre_mode = RB_INSELECT;
732 			    end_tag = HTML_N_SELECT;
733 			    break;
734 			case HTML_TEXTAREA:
735 			    pre_mode = RB_INTXTA;
736 			    end_tag = HTML_N_TEXTAREA;
737 			    break;
738 			case HTML_SCRIPT:
739 			    pre_mode = RB_SCRIPT;
740 			    end_tag = HTML_N_SCRIPT;
741 			    break;
742 			case HTML_STYLE:
743 			    pre_mode = RB_STYLE;
744 			    end_tag = HTML_N_STYLE;
745 			    break;
746 			case HTML_LISTING:
747 			    pre_mode = RB_PLAIN;
748 			    end_tag = HTML_N_LISTING;
749 			    fputs("<PRE_PLAIN>", f1);
750 			    goto token_end;
751 			case HTML_XMP:
752 			    pre_mode = RB_PLAIN;
753 			    end_tag = HTML_N_XMP;
754 			    fputs("<PRE_PLAIN>", f1);
755 			    goto token_end;
756 			case HTML_PLAINTEXT:
757 			    pre_mode = RB_PLAIN;
758 			    end_tag = MAX_HTMLTAG;
759 			    fputs("<PRE_PLAIN>", f1);
760 			    goto token_end;
761 			default:
762 			    break;
763 			}
764 			for (j = 0; j < TagMAP[tag->tagid].max_attribute; j++) {
765 			    switch (tag->attrid[j]) {
766 			    case ATTR_SRC:
767 			    case ATTR_HREF:
768 			    case ATTR_ACTION:
769 				if (!tag->value[j])
770 				    break;
771 				tag->value[j] =
772 				    url_encode(remove_space(tag->value[j]),
773 					       &base, charset);
774 				tag->need_reconstruct = TRUE;
775 				parseURL2(tag->value[j], &url, &base);
776 				if (url.scheme == SCM_UNKNOWN ||
777 #ifndef USE_W3MMAILER
778 				    url.scheme == SCM_MAILTO ||
779 #endif
780 				    url.scheme == SCM_MISSING)
781 				    break;
782 				a_target |= 1;
783 				tag->value[j] = parsedURL2Str(&url)->ptr;
784 				parsedtag_set_value(tag,
785 						    ATTR_REFERER,
786 						    parsedURL2Str(&base)->ptr);
787 #ifdef USE_M17N
788 				if (tag->attrid[j] == ATTR_ACTION &&
789 				    charset != WC_CES_US_ASCII)
790 				    parsedtag_set_value(tag,
791 							ATTR_CHARSET,
792 							wc_ces_to_charset
793 							(charset));
794 #endif
795 				break;
796 			    case ATTR_TARGET:
797 				if (!tag->value[j])
798 				    break;
799 				a_target |= 2;
800 				if (!strcasecmp(tag->value[j], "_self")) {
801 				    parsedtag_set_value(tag,
802 							ATTR_TARGET, s_target);
803 				}
804 				else if (!strcasecmp(tag->value[j], "_parent")) {
805 				    parsedtag_set_value(tag,
806 							ATTR_TARGET, p_target);
807 				}
808 				break;
809 			    case ATTR_NAME:
810 			    case ATTR_ID:
811 				if (!tag->value[j])
812 				    break;
813 				parsedtag_set_value(tag,
814 						    ATTR_FRAMENAME, s_target);
815 				break;
816 			    }
817 			}
818 			if (a_target == 1) {
819 			    /* there is HREF attribute and no TARGET
820 			     * attribute */
821 			    parsedtag_set_value(tag, ATTR_TARGET, d_target);
822 			}
823 			if (parsedtag_need_reconstruct(tag))
824 			    tok = parsedtag2str(tag);
825 			Strfputs(tok, f1);
826 		    }
827 		    else {
828 			if (pre_mode & RB_PLAIN)
829 			    fprintf(f1, "%s", html_quote(tok->ptr));
830 			else if (pre_mode & RB_INTXTA)
831 			    fprintf(f1, "%s",
832 				    html_quote(html_unquote(tok->ptr)));
833 			else
834 			    Strfputs(tok, f1);
835 		    }
836 		  token_end:
837 		    Strclear(tok);
838 		} while (*p != '\0' || !iseos(f2.stream));
839 		if (pre_mode & RB_PLAIN)
840 		    fputs("</PRE_PLAIN>\n", f1);
841 		else if (pre_mode & RB_INTXTA)
842 		    fputs("</TEXTAREA></FORM>\n", f1);
843 		else if (pre_mode & RB_INSELECT)
844 		    fputs("</SELECT></FORM>\n", f1);
845 		else if (pre_mode & (RB_SCRIPT | RB_STYLE)) {
846 		    if (status != R_ST_NORMAL)
847 			fputs(correct_irrtag(status)->ptr, f1);
848 		    if (pre_mode & RB_SCRIPT)
849 			fputs("</SCRIPT>\n", f1);
850 		    else if (pre_mode & RB_STYLE)
851 			fputs("</STYLE>\n", f1);
852 		}
853 		while (t_stack--)
854 		    fputs("</TABLE>\n", f1);
855 		UFclose(&f2);
856 		break;
857 	    case F_FRAMESET:
858 	      render_frameset:
859 		if (!frame.set->name && f->name) {
860 		    frame.set->name = Sprintf("%s_%d", f->name, i)->ptr;
861 		}
862 		createFrameFile(frame.set, f1, current, level + 1,
863 				force_reload);
864 		break;
865 	    }
866 	    fputs("</td>\n", f1);
867 	}
868 	fputs("</tr>\n", f1);
869     }
870 
871     fputs("</table>\n", f1);
872     if (level == 0) {
873 	fputs("</body></html>\n", f1);
874 	TRAP_OFF;
875     }
876     return 0;
877 }
878 
879 Buffer *
renderFrame(Buffer * Cbuf,int force_reload)880 renderFrame(Buffer *Cbuf, int force_reload)
881 {
882     Str tmp;
883     FILE *f;
884     Buffer *buf;
885     int flag;
886     struct frameset *fset;
887 #ifdef USE_M17N
888     wc_ces doc_charset = DocumentCharset;
889 #endif
890 
891     tmp = tmpfname(TMPF_FRAME, ".html");
892     f = fopen(tmp->ptr, "w");
893     if (f == NULL)
894 	return NULL;
895     /*
896      * if (Cbuf->frameQ != NULL) fset = Cbuf->frameQ->frameset; else */
897     fset = Cbuf->frameset;
898     if (fset == NULL || createFrameFile(fset, f, Cbuf, 0, force_reload) < 0) {
899 	fclose(f);
900 	return NULL;
901     }
902     fclose(f);
903     flag = RG_FRAME;
904     if ((Cbuf->currentURL).is_nocache)
905 	flag |= RG_NOCACHE;
906     renderFrameSet = Cbuf->frameset;
907     flushFrameSet(renderFrameSet);
908 #ifdef USE_M17N
909     DocumentCharset = InnerCharset;
910 #endif
911     buf = loadGeneralFile(tmp->ptr, NULL, NULL, flag, NULL);
912 #ifdef USE_M17N
913     DocumentCharset = doc_charset;
914 #endif
915     renderFrameSet = NULL;
916     if (buf == NULL || buf == NO_BUFFER)
917 	return NULL;
918     buf->sourcefile = tmp->ptr;
919 #ifdef USE_M17N
920     buf->document_charset = Cbuf->document_charset;
921 #endif
922     copyParsedURL(&buf->currentURL, &Cbuf->currentURL);
923     preFormUpdateBuffer(buf);
924     return buf;
925 }
926 
927 union frameset_element *
search_frame(struct frameset * fset,char * name)928 search_frame(struct frameset *fset, char *name)
929 {
930     int i;
931     union frameset_element *e = NULL;
932 
933     for (i = 0; i < fset->col * fset->row; i++) {
934 	e = &(fset->frame[i]);
935 	if (e->element != NULL) {
936 	    if (e->element->name && !strcmp(e->element->name, name)) {
937 		return e;
938 	    }
939 	    else if (e->element->attr == F_FRAMESET &&
940 		     (e = search_frame(e->set, name))) {
941 		return e;
942 	    }
943 	}
944     }
945     return NULL;
946 }
947