aboutsummaryrefslogblamecommitdiffstats
path: root/frame.c
blob: 5850f7fc90af7715abeb9a18924960ea559f8a3b (plain) (tree)
1
                                                       






































                                                       
                              
                                

                                                                       

































                                                     
                              
                                

                                                                       




























                                                  
                                             







                                        
                                 
              

                                                              
                                                                 
                                                               



















































































































































                                                                      
                         






                                             




                                                                                   















                                  
                                          






                                                    



























                                                                    
                                                    


                                      
                                     












                                                           
                                






















                                                                   


                                  


                            
                              




                                                             
                               









                                                         

                                












                                                                  
                                                    








                                                                                             
               































                                                                   
                                                 



























                                                                      
                                                                            












                                                                          
                                                    




                                                                         
                           










                                                                    





                                                         


                                                                                  
                                             
                                                                      


                                                                                










                                                              



                                                              
                                                      








                                                            
                         

                  



                                         
                                                       





































                                                                            

                                                                          
                                                         
                             





                                                                            
                                                                       


























































                                                                                
                                                                                    






























































                                                                               
                                                          

                                            
                             












































































                                                                                 
/* $Id: frame.c,v 1.5 2001/11/20 13:17:13 ukai Exp $ */
#include "fm.h"
#include "parsetagx.h"
#include "myctype.h"
#include <signal.h>
#include <setjmp.h>

#ifdef KANJI_SYMBOLS
#define RULE_WIDTH 2
#else				/* not KANJI_SYMBOLS */
#define RULE_WIDTH 1
#endif				/* not KANJI_SYMBOLS */

static JMP_BUF AbortLoading;
struct frameset *renderFrameSet = NULL;

static MySignalHandler
KeyAbort(SIGNAL_ARG)
{
    LONGJMP(AbortLoading, 1);
}

struct frameset *
newFrameSet(struct parsed_tag *tag)
{
    struct frameset *f;
    int i;
    char *cols = NULL, *rows = NULL, *p, *q;
    char *length[100];

    f = New(struct frameset);
    f->attr = F_FRAMESET;
    f->name = NULL;
    f->currentURL = NULL;
    parsedtag_get_value(tag, ATTR_COLS, &cols);
    parsedtag_get_value(tag, ATTR_ROWS, &rows);
    i = 0;
    if (cols) {
	length[i] = p = cols;
	while (*p != '\0')
	    if (*p++ == ',') {
		length[++i] = p;
		if (i >= sizeof(length) / sizeof(length[0]) - 2) break;
	    }
	length[++i] = p + 1;
    }
    if (i > 1) {
	f->col = i;
	f->width = New_N(char *, i);
	p = length[i];
	do {
	    i--;
	    q = p - 2;
	    p = length[i];
	    switch (*q) {
		Str tmp;
	    case '%':
		f->width[i] = allocStr(p, q - p + 1);
		break;
	    case '*':
		f->width[i] = "*";
		break;
	    default:
		tmp = Sprintf("%d", atoi(p));
		f->width[i] = tmp->ptr;
		break;
	    }
	} while (i);
    }
    else {
	f->col = 1;
	f->width = New_N(char *, 1);
	f->width[0] = "*";
    }
    i = 0;
    if (rows) {
	length[i] = p = rows;
	while (*p != '\0')
	    if (*p++ == ',') {
		length[++i] = p;
		if (i >= sizeof(length) / sizeof(length[0]) - 2) break;
	    }
	length[++i] = p + 1;
    }
    if (i > 1) {
	f->row = i;
	f->height = New_N(char *, i);
	p = length[i];
	do {
	    i--;
	    q = p - 2;
	    p = length[i];
	    f->height[i] = allocStr(p, q - p + 1);
	} while (i);
    }
    else {
	f->row = 1;
	f->height = New_N(char *, 1);
	f->height[0] = "*";
    }
    i = f->row * f->col;
    f->i = 0;
    f->frame = New_N(union frameset_element, i);
    do {
	i--;
	f->frame[i].element = NULL;
    } while (i);
    return f;
}

struct frame_body *
newFrame(struct parsed_tag *tag, Buffer *buf)
{
    struct frame_body *body;
    char *p;

    body = New(struct frame_body);
    bzero((void *) body, sizeof(*body));
    body->attr = F_UNLOADED;
    body->flags = 0;
    body->baseURL = baseURL(buf);
    if (tag) {
	if (parsedtag_get_value(tag, ATTR_SRC, &p))
	    body->url = url_quote_conv(p, buf->document_code);
	if (parsedtag_get_value(tag, ATTR_NAME, &p) && *p != '_')
	    body->name = url_quote_conv(p, buf->document_code);
    }
    return body;
}

static void
unloadFrame(struct frame_body *b)
{
    if (b->source && b->flags & FB_TODELETE)
	pushText(fileToDelete, b->source);
    b->attr = F_UNLOADED;
}

void
deleteFrame(struct frame_body *b)
{
    if (b == NULL)
	return;
    unloadFrame(b);
    bzero((void *) b, sizeof(*b));
}

void
addFrameSetElement(struct frameset *f, union frameset_element element)
{
    int i;

    if (f == NULL)
	return;
    i = f->i;
    if (i >= f->col * f->row)
	return;
    f->frame[i] = element;
    f->i++;
}

void
deleteFrameSet(struct frameset *f)
{
    int i;

    if (f == NULL)
	return;
    for (i = 0; i < f->col * f->row; i++) {
	deleteFrameSetElement(f->frame[i]);
    }
    f->name = NULL;
    f->currentURL = NULL;
    return;
}

void
deleteFrameSetElement(union frameset_element e)
{
    if (e.element == NULL)
	return;
    switch (e.element->attr) {
    case F_UNLOADED:
	break;
    case F_BODY:
	deleteFrame(e.body);
	break;
    case F_FRAMESET:
	deleteFrameSet(e.set);
	break;
    default:
	break;
    }
    return;
}

static struct frame_body *
copyFrame(struct frame_body *ob)
{
    struct frame_body *rb;

    rb = New(struct frame_body);
    bcopy((const void *) ob, (void *) rb, sizeof(struct frame_body));
    rb->flags &= ~FB_TODELETE;
    return rb;
}

struct frameset *
copyFrameSet(struct frameset *of)
{
    struct frameset *rf;
    int n;

    rf = New(struct frameset);
    n = of->col * of->row;
    bcopy((const void *) of, (void *) rf, sizeof(struct frameset));
    rf->width = New_N(char *, rf->col);
    bcopy((const void *) of->width,
	  (void *) rf->width,
	  sizeof(char *) * rf->col);
    rf->height = New_N(char *, rf->row);
    bcopy((const void *) of->height,
	  (void *) rf->height,
	  sizeof(char *) * rf->row);
    rf->frame = New_N(union frameset_element, n);
    while (n) {
	n--;
	if (!of->frame[n].element)
	    goto attr_default;
	switch (of->frame[n].element->attr) {
	case F_UNLOADED:
	case F_BODY:
	    rf->frame[n].body = copyFrame(of->frame[n].body);
	    break;
	case F_FRAMESET:
	    rf->frame[n].set = copyFrameSet(of->frame[n].set);
	    break;
	default:
	  attr_default:
	    rf->frame[n].element = NULL;
	    break;
	}
    }
    return rf;
}

void
flushFrameSet(struct frameset *fs)
{
    int             n = fs->i;

    while (n) {
	n--;
	if (!fs->frame[n].element)
	    goto attr_default;
	switch (fs->frame[n].element->attr) {
	case F_UNLOADED:
	case F_BODY:
	    fs->frame[n].body->nameList = NULL;
	    break;
	case F_FRAMESET:
	    flushFrameSet(fs->frame[n].set);
	    break;
	default:
	  attr_default:
	    /* nothing to do */
	    break;
	}
    }
}

void
pushFrameTree(struct frameset_queue **fqpp,
	      struct frameset *fs,
             Buffer *buf)
{
    struct frameset_queue *rfq, *cfq = *fqpp;

    if (!fs)
	return;

    rfq = New(struct frameset_queue);
    rfq->linenumber = (buf && buf->currentLine) ? buf->currentLine->linenumber : 1;
    rfq->top_linenumber = (buf && buf->topLine) ? buf->topLine->linenumber : 1;
    rfq->pos = buf ? buf->pos : 0;
    rfq->currentColumn = buf ? buf->currentColumn : 0;
    rfq->formitem = buf ? buf->formitem : NULL;

    rfq->back = cfq;
    if (cfq) {
	rfq->next = cfq->next;
	if (cfq->next)
	    cfq->next->back = rfq;
	cfq->next = rfq;
    }
    else
	rfq->next = cfq;
    rfq->frameset = fs;
    *fqpp = rfq;
    return;
}

struct frameset *
popFrameTree(struct frameset_queue **fqpp)
{
    struct frameset_queue *rfq = NULL, *cfq = *fqpp;
    struct frameset *rfs = NULL;

    if (!cfq)
	return rfs;

    rfs = cfq->frameset;
    if (cfq->next) {
	(rfq = cfq->next)->back = cfq->back;
    }
    if (cfq->back) {
	(rfq = cfq->back)->next = cfq->next;
    }
    *fqpp = rfq;
    bzero((void *) cfq, sizeof(struct frameset_queue));
    return rfs;
}

void
resetFrameElement(union frameset_element *f_element,
		  Buffer * buf,
		  char *referer,
		  FormList * request)
{
    char *f_name;
    struct frame_body *f_body;

    f_name = f_element->element->name;
    if (buf->frameset) {
	/* frame cascade */
	deleteFrameSetElement(*f_element);
	f_element->set = buf->frameset;
	f_element->set->currentURL = New(ParsedURL);
	copyParsedURL(f_element->set->currentURL, &buf->currentURL);
       buf->frameset = popFrameTree(&(buf->frameQ));
	f_element->set->name = f_name;
    }
    else {
	f_body = newFrame(NULL, buf);
	f_body->attr = F_BODY;
	f_body->name = f_name;
	f_body->url = parsedURL2Str(&buf->currentURL)->ptr;
	if (buf->real_scheme == SCM_LOCAL) {
	    f_body->source = buf->sourcefile;
	}
	else {
	    Str tmp = tmpfname(TMPF_FRAME, NULL);
	    rename(buf->sourcefile, tmp->ptr);
	    f_body->source = tmp->ptr;
	    f_body->flags |= FB_TODELETE;
	    buf->sourcefile = NULL;
	}
       f_body->type = buf->type;
	f_body->referer = referer;
	f_body->request = request;
	deleteFrameSetElement(*f_element);
	f_element->body = f_body;
    }
}

static struct frameset *
frame_download_source(struct frame_body *b, ParsedURL * currentURL,
		      ParsedURL * baseURL, int flag)
{
    Buffer *buf;
    struct frameset *ret_frameset = NULL;
    Str tmp;
    ParsedURL url;

    if (b == NULL || b->url == NULL || b->url[0] == '\0')
	return NULL;
    if (b->baseURL)
	baseURL = b->baseURL;
    parseURL2(b->url, &url, currentURL);
    switch (url.scheme) {
    case SCM_LOCAL:
/*
	b->source = url.real_file;
*/
	b->flags = 0;
    default:
	is_redisplay = TRUE;
       w3m_dump |= DUMP_FRAME;
	buf = loadGeneralFile(b->url,
			      baseURL ? baseURL : currentURL,
			      b->referer,
			      flag,
			      b->request);
       w3m_dump &= ~DUMP_FRAME;
	is_redisplay = FALSE;
	break;
    }

    if (buf == NULL || buf == NO_BUFFER) {
	b->source = NULL;
	b->flags = (buf == NO_BUFFER) ? FB_NO_BUFFER : 0;
	return NULL;
    }
    b->url = parsedURL2Str(&buf->currentURL)->ptr;
    b->source = buf->sourcefile;
    b->type = buf->type;
    if (buf->real_scheme != SCM_LOCAL) {
	tmp = tmpfname(TMPF_FRAME, NULL);
	rename(buf->sourcefile, tmp->ptr);
	b->source = tmp->ptr;
	b->flags |= FB_TODELETE;
	buf->sourcefile = NULL;
    }
    b->attr = F_BODY;
    if (buf->frameset) {
	ret_frameset = buf->frameset;
	ret_frameset->name = b->name;
	ret_frameset->currentURL = New(ParsedURL);
	copyParsedURL(ret_frameset->currentURL, &buf->currentURL);
       buf->frameset = popFrameTree(&(buf->frameQ));
    }
    discardBuffer(buf);
    return ret_frameset;
}

static int
createFrameFile(struct frameset *f, FILE * f1, Buffer * current, int level, int force_reload)
{
    int r, c, t_stack;
    URLFile f2;
#ifdef JP_CHARSET
    char code, ic, charset[2];
#endif				/* JP_CHARSET */
    char *d_target, *p_target, *s_target, *t_target;
    ParsedURL *currentURL, base;
    MySignalHandler(*prevtrap) (SIGNAL_ARG) = NULL;
    int flag;

    if (f == NULL)
	return -1;

    if (level == 0) {
	if (SETJMP(AbortLoading) != 0) {
	    if (fmInitialized)
		term_raw();
	    signal(SIGINT, prevtrap);
	    return -1;
	}
	prevtrap = signal(SIGINT, KeyAbort);
	if (fmInitialized)
	    term_cbreak();

	f->name = "_top";
    }

    if (level > 7) {
	fputs("Too many frameset tasked.\n", f1);
	return -1;
    }

    if (level == 0) {
	fprintf(f1, "<html><head><title>%s</title></head><body>\n",
		html_quote(current->buffername));
	fputs("<table hborder width=\"100%\">\n", f1);
    }
    else
	fputs("<table hborder>\n", f1);

    currentURL = f->currentURL ? f->currentURL : &current->currentURL;
#ifdef JP_CHARSET
    charset[1] = '\0';
#endif
    for (r = 0; r < f->row; r++) {
	fputs("<tr valign=top>\n", f1);
	for (c = 0; c < f->col; c++) {
	    union frameset_element frame;
	    struct frameset *f_frameset;
	    int i = c + r * f->col;
	    char *p = "";
	    Str tok = Strnew();
	    int status;

	    frame = f->frame[i];

	    if (frame.element == NULL) {
		fputs("<td>\n</td>\n", f1);
		continue;
	    }

	    fputs("<td", f1);
	    if (frame.element->name)
		fprintf(f1, " id=\"_%s\"", html_quote(frame.element->name));
	    if (!r)
		fprintf(f1, " width=\"%s\"", f->width[c]);
	    fputs(">\n", f1);

	    flag = 0;
	    if (force_reload) {
		flag |= RG_NOCACHE;
		if (frame.element->attr == F_BODY)
		    unloadFrame(frame.body);
	    }
	    switch (frame.element->attr) {
	    default:
		fprintf(f1, "Frameset \"%s\" frame %d: type unrecognized",
			html_quote(f->name), i + 1);
		break;
	    case F_UNLOADED:
		if (!frame.body->name && f->name) {
		    frame.body->name = Sprintf("%s_%d", f->name, i)->ptr;
		}
		fflush(f1);
		f_frameset = frame_download_source(frame.body,
						   currentURL,
						   current->baseURL,
						   flag);
		if (f_frameset) {
		    deleteFrame(frame.body);
		    f->frame[i].set = frame.set = f_frameset;
		    goto render_frameset;
		}
		/* fall through */
	    case F_BODY:
		init_stream(&f2, SCM_LOCAL, NULL);
		if (frame.body->source) {
		    fflush(f1);
		    examineFile(frame.body->source, &f2);
		}
		if (f2.stream == NULL) {
		    frame.body->attr = F_UNLOADED;
		    if (frame.body->flags & FB_NO_BUFFER)
			fprintf(f1, "Open %s with other method", frame.body->url);
		    else if (frame.body->url)
			fprintf(f1, "Can't open %s", frame.body->url);
		    else
			fprintf(f1, "This frame (%s) contains no src attribute",
			    frame.body->name ? frame.body->name : "(no name)");
		    break;
		}
		parseURL2(frame.body->url, &base, currentURL);
		p_target = f->name;
		s_target = frame.body->name;
		t_target = "_blank";
		d_target = TargetSelf ? s_target : t_target;
#ifdef JP_CHARSET
		code = '\0';
#endif				/* JP_CHARSET */
		t_stack = 0;
        if (frame.body->type &&
               ! strcasecmp(frame.body->type, "text/plain")) {
            Str tmp;
            fprintf(f1, "<pre>\n");
            while ((tmp = StrmyUFgets(&f2))->length) {
#ifdef JP_CHARSET
               if ((ic = checkShiftCode(tmp, code)) != '\0')
                tmp = conv_str(tmp, (code = ic), InnerCode);

#endif                /* JP_CHARSET */
               cleanup_line(tmp, HTML_MODE);
               fprintf(f1, "%s", html_quote(tmp->ptr));
            }
            fprintf(f1, "</pre>\n");
            UFclose(&f2);
            break;
        }
		do {
		    status = R_ST_NORMAL;
		    do {
			if (*p == '\0') {
 			    Str tmp = StrmyUFgets(&f2);
			    if (tmp->length == 0 && status != R_ST_NORMAL)
				tmp = correct_irrtag(status);
			    if (tmp->length == 0)
				break;
#ifdef JP_CHARSET
			    if ((ic = checkShiftCode(tmp, code)) != '\0')
				tmp = conv_str(tmp, (code = ic), InnerCode);

#endif				/* JP_CHARSET */
			    cleanup_line(tmp, HTML_MODE);
			    p = tmp->ptr;
			}
			if (status == R_ST_NORMAL || ST_IS_COMMENT(status))
			    read_token(tok, &p, &status, 1, 0);
			else
			    read_token(tok, &p, &status, 1, 1);
		    } while (status != R_ST_NORMAL);

		    if (tok->length == 0)
			continue;

		    if (tok->ptr[0] == '<') {
			char *q = tok->ptr;
			int j, a_target = 0;
			struct parsed_tag *tag;
			ParsedURL url;

			if (!(tag = parse_tag(&q, FALSE)))
			    goto token_end;

			switch (tag->tagid) {
			case HTML_TITLE:
			    fputs("<!-- title:", f1);
			    goto token_end;
			case HTML_N_TITLE:
			    fputs("-->", f1);
			    goto token_end;
			case HTML_BASE:
			    if (parsedtag_get_value(tag, ATTR_HREF, &q)) {
				q = url_quote_conv(q, code);
				parseURL(q, &base, NULL);
			    }
			    if (parsedtag_get_value(tag, ATTR_TARGET, &q)) {
				if (!strcasecmp(q, "_self"))
				    d_target = s_target;
				else if (!strcasecmp(q, "_parent"))
				    d_target = p_target;
				else
				    d_target = url_quote_conv(q, code);
			    }
			    /* fall thru, "BASE" is prohibit tag */
			case HTML_HEAD:
			case HTML_N_HEAD:
			case HTML_BODY:
			case HTML_N_BODY:
			case HTML_META:
			case HTML_DOCTYPE:
			    /* prohibit_tags */
			    Strshrinkfirst(tok, 1);
			    Strshrink(tok, 1);
			    fprintf(f1, "<!-- %s -->", tok->ptr);
			    goto token_end;
			case HTML_TABLE:
			    t_stack++;
			    break;
			case HTML_N_TABLE:
			    t_stack--;
			    if (t_stack < 0) {
				t_stack = 0;
				Strshrinkfirst(tok, 1);
				Strshrink(tok, 1);
				fprintf(f1,
				    "<!-- table stack underflow: %s -->",
					tok->ptr);
				goto token_end;
			    }
			    break;
			case HTML_THEAD:
			case HTML_N_THEAD:
			case HTML_TBODY:
			case HTML_N_TBODY:
			case HTML_TFOOT:
			case HTML_N_TFOOT:
			case HTML_TD:
			case HTML_N_TD:
			case HTML_TR:
			case HTML_N_TR:
			case HTML_TH:
			case HTML_N_TH:
			    /* table_tags MUST be in table stack */
			    if (!t_stack) {
				Strshrinkfirst(tok, 1);
				Strshrink(tok, 1);
				fprintf(f1, "<!-- %s -->", tok->ptr);
				goto token_end;

			    }
			    break;
			default:
			    break;
			}
			for (j = 0; j < TagMAP[tag->tagid].max_attribute; j++) {
			    switch (tag->attrid[j]) {
			    case ATTR_SRC:
			    case ATTR_HREF:
			    case ATTR_ACTION:
				if (!tag->value[j])
				    break;
				tag->value[j] = url_quote_conv(tag->value[j], code);
				parseURL2(tag->value[j], &url, &base);
				if (url.scheme == SCM_MAILTO ||
				    url.scheme == SCM_UNKNOWN ||
				    url.scheme == SCM_MISSING)
				    break;
				a_target |= 1;
				tag->value[j] = parsedURL2Str(&url)->ptr;
				tag->need_reconstruct = TRUE;
				parsedtag_set_value(tag,
						    ATTR_REFERER,
						    parsedURL2Str(&base)->ptr);
#ifdef JP_CHARSET
				if (code != '\0') {
				    charset[0] = code;
				    parsedtag_set_value(tag,
							ATTR_CHARSET,
							charset);
				}
#endif
				break;
			    case ATTR_TARGET:
				if (!tag->value[j])
				    break;
				a_target |= 2;
				if (!strcasecmp(tag->value[j], "_self")) {
				    parsedtag_set_value(tag,
							ATTR_TARGET,
							s_target);
				}
				else if (!strcasecmp(tag->value[j],
						     "_parent")) {
				    parsedtag_set_value(tag,
							ATTR_TARGET,
							p_target);
				}
				break;
			    case ATTR_NAME:
			    case ATTR_ID:
				if (!tag->value[j])
				    break;
				parsedtag_set_value(tag,
						    ATTR_FRAMENAME,
						    s_target);
				break;
			    }
			}
			if (a_target == 1) {
			    /* there is HREF attribute and no TARGET
			     * attribute */
			    parsedtag_set_value(tag,
						ATTR_TARGET,
						d_target);
			}
			if (parsedtag_need_reconstruct(tag))
			    Strfputs(parsedtag2str(tag), f1);
			else
			    Strfputs(tok, f1);
		    }
		    else {
			Strfputs(tok, f1);
		    }
		  token_end:
		    Strclear(tok);
		} while (*p != '\0' || !iseos(f2.stream));
		while (t_stack--)
		    fputs("</TABLE>\n", f1);
		UFclose(&f2);
		break;
	    case F_FRAMESET:
	      render_frameset:
		if (!frame.set->name && f->name) {
		    frame.set->name = Sprintf("%s_%d", f->name, i)->ptr;
		}
		createFrameFile(frame.set, f1, current, level + 1, force_reload);
		break;
	    }
	    fputs("</td>\n", f1);
	}
	fputs("</tr>\n", f1);
    }

    fputs("</table>\n", f1);
    if (level == 0) {
	fputs("</body></html>\n", f1);
	signal(SIGINT, prevtrap);
	if (fmInitialized)
	    term_raw();
    }
    return 0;
}

Buffer *
renderFrame(Buffer * Cbuf, int force_reload)
{
    Str tmp;
    FILE *f;
    Buffer *buf;
    int flag;
    struct frameset *fset;

    tmp = tmpfname(TMPF_FRAME, ".html");
    f = fopen(tmp->ptr, "w");
    if (f == NULL)
	return NULL;
    /* 
     * if (Cbuf->frameQ != NULL) fset = Cbuf->frameQ->frameset; else */
    fset = Cbuf->frameset;
    if (fset == NULL || createFrameFile(fset, f, Cbuf, 0, force_reload) < 0)
	return NULL;
    fclose(f);
    flag = RG_FRAME;
    if ((Cbuf->currentURL).is_nocache)
	flag |= RG_NOCACHE;
    renderFrameSet = Cbuf->frameset;
    flushFrameSet(renderFrameSet);
    buf = loadGeneralFile(tmp->ptr, NULL, NULL, flag, NULL);
    renderFrameSet = NULL;
    if (buf == NULL || buf == NO_BUFFER)
	return NULL;
    buf->sourcefile = tmp->ptr;
    copyParsedURL(&buf->currentURL, &Cbuf->currentURL);
    return buf;
}

union frameset_element *
search_frame(struct frameset *fset, char *name)
{
    int i;
    union frameset_element *e = NULL;

    for (i = 0; i < fset->col * fset->row; i++) {
	e = &(fset->frame[i]);
	if (e->element != NULL) {
	    if (e->element->name && !strcmp(e->element->name, name)) {
		return e;
	    }
	    else if (e->element->attr == F_FRAMESET &&
		     (e = search_frame(e->set, name))) {
		return e;
	    }
	}
    }
    return NULL;
}