/*	WebDownloader for X-Window
 *	Copyright (C) 1999-2002 Koshelev Maxim
 *	This Program is free but not GPL!!! You can't modify it
 *	without agreement with author. You can't distribute modified
 *	program but you can distribute unmodified program.
 *
 *	This program is distributed in the hope that it will be useful,
 *	but WITHOUT ANY WARRANTY; without even the implied warranty of
 *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 */

#include "html.h"
#include "locstr.h"
#include "var.h"
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <ctype.h>
#include <sys/types.h>
#include <stdio.h>

struct tHtmlTegTable{
	char *tag,*field;
	int mod;
};
enum HTML_FIELDS_TYPES{
	HF_TYPE_LINK,
	HF_TYPE_BASE,
	HF_TYPE_BASE_CLOSE,
	HF_TYPE_META
};
	
enum HTML_FIELDS{
	HF_PROFILE,
	HF_STYLE,
	HF_BACKGROUND,
	HF_HREF,
	HF_SRC,
	HF_USEMAP,
	HF_LONGDESC,
	HF_LOWSRC,
	HF_CONTENT,
	HF_CITE,
	HF_DATA,
	HF_HT,
	HF_CODEBASE,
	HF_ACTION,
	HF_HTTP_EQUIV
};

char *HTML_FIELDS_NAMES[]={
	"profile",
	"style",
	"background",
	"href",
	"src",
	"usemap",
	"longdesc",
	"lowsrc",
	"content",
	"cite",
	"data",
	"ht",
	"codebase",
	"action",
	"http-equiv"
};

tHtmlTegTable HTML_TEGS[]={
	{"head",	HTML_FIELDS_NAMES[HF_PROFILE],		0},

	{"body",	HTML_FIELDS_NAMES[HF_BACKGROUND],	0},
//	{"body",	HTML_FIELDS_NAMES[HF_STYLE],		0},

	{"table",	HTML_FIELDS_NAMES[HF_BACKGROUND],	0},
//	{"table",      	HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"th",		HTML_FIELDS_NAMES[HF_BACKGROUND],	0},
//	{"th",		HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"td",		HTML_FIELDS_NAMES[HF_BACKGROUND],	0},
//	{"td",		HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"col",		HTML_FIELDS_NAMES[HF_BACKGROUND],	0},
//	{"col",		HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"thead",	HTML_FIELDS_NAMES[HF_BACKGROUND],	0},
//	{"thead",	HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"tfoot",	HTML_FIELDS_NAMES[HF_BACKGROUND],	0},
//	{"tfoot",	HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"tbody",	HTML_FIELDS_NAMES[HF_BACKGROUND],	0},
//	{"tbody",	HTML_FIELDS_NAMES[HF_STYLE],		0},

	{"a",		HTML_FIELDS_NAMES[HF_HREF],		0},
//	{"a",		HTML_FIELDS_NAMES[HF_STYLE],		0},
//	{"address",	HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"area",	HTML_FIELDS_NAMES[HF_HREF],		0},
//	{"area",	HTML_FIELDS_NAMES[HF_STYLE],		0},

	{"img",		HTML_FIELDS_NAMES[HF_SRC],		0},
	{"img",		HTML_FIELDS_NAMES[HF_LOWSRC],		0},
	{"img",		HTML_FIELDS_NAMES[HF_LONGDESC],		0},
//	{"img",		HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"img",		HTML_FIELDS_NAMES[HF_USEMAP],		0},

	{"link",	HTML_FIELDS_NAMES[HF_HREF],		0},
//	{"link",	HTML_FIELDS_NAMES[HF_STYLE],		0},

//	{"input",	HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"input",	HTML_FIELDS_NAMES[HF_SRC],		0},
	{"input",	HTML_FIELDS_NAMES[HF_USEMAP],		0},

	{"applet",	HTML_FIELDS_NAMES[HF_CODEBASE],		0},
//	{"applet",	HTML_FIELDS_NAMES[HF_STYLE],		0},

	{"iframe",	HTML_FIELDS_NAMES[HF_LONGDESC],		0},
//	{"iframe",	HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"iframe",	HTML_FIELDS_NAMES[HF_SRC],		0},
	{"frame",	HTML_FIELDS_NAMES[HF_LONGDESC],		0},
//	{"frame",	HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"frame",	HTML_FIELDS_NAMES[HF_SRC],		0},

	{"sound",	HTML_FIELDS_NAMES[HF_SRC],		0},
//	{"sound",	HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"bgsound",	HTML_FIELDS_NAMES[HF_SRC],		0},
//	{"bgsound",	HTML_FIELDS_NAMES[HF_STYLE],		0},

	{"script",	HTML_FIELDS_NAMES[HF_SRC],		0},

	{"embed",	HTML_FIELDS_NAMES[HF_SRC],		0},
//	{"embed",	HTML_FIELDS_NAMES[HF_STYLE],		0},

	{"fig",		HTML_FIELDS_NAMES[HF_SRC],		0},
//	{"fig",		HTML_FIELDS_NAMES[HF_STYLE],		0},

	{"overlay",	HTML_FIELDS_NAMES[HF_SRC],		0},
//	{"overlay",	HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"layer",	HTML_FIELDS_NAMES[HF_SRC],		0},
//	{"layer",	HTML_FIELDS_NAMES[HF_STYLE],		0},

	{"ins",		HTML_FIELDS_NAMES[HF_CITE],		0},
//	{"ins",		HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"del",		HTML_FIELDS_NAMES[HF_CITE],		0},
//	{"del",		HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"q",		HTML_FIELDS_NAMES[HF_CITE],		0},
//	{"q",		HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"blockqute",	HTML_FIELDS_NAMES[HF_CITE],		0},
//	{"blockqute",	HTML_FIELDS_NAMES[HF_STYLE],		0},

	{"span",	HTML_FIELDS_NAMES[HF_HREF],		0},
//	{"span",	HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"div",		HTML_FIELDS_NAMES[HF_HREF],		0},
//	{"div",		HTML_FIELDS_NAMES[HF_STYLE],		0},

//	{"object",	HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"object",	HTML_FIELDS_NAMES[HF_USEMAP],		0},
	{"object",	HTML_FIELDS_NAMES[HF_DATA],		0},
/*
	{"center",	HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"h1",		HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"h2",		HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"h3",		HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"h4",		HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"h5",		HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"h6",		HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"hr",		HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"isindex",	HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"p",		HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"pre",		HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"noscript",	HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"dir",		HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"dl",		HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"dt",		HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"dd",		HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"li",		HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"menu",	HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"ol",		HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"ul",		HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"caption",	HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"colgroup",	HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"optgroup",	HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"form",	HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"fieldset",	HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"button",	HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"legend",	HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"label",	HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"select",	HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"option",	HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"textarea",	HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"bdo",		HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"br",		HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"font",	HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"map",		HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"sub",		HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"sup",		HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"abbr",	HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"acronym",	HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"cite",	HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"code",	HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"dfn",		HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"em",		HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"samp",	HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"strong",	HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"var",		HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"b",		HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"big",		HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"i",		HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"s",		HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"small",	HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"strike",	HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"tt",		HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"u",		HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"csobj",	HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"noframes",	HTML_FIELDS_NAMES[HF_STYLE],		0},
	{"frameset",	HTML_FIELDS_NAMES[HF_STYLE],		0},
*/
	{"base",	HTML_FIELDS_NAMES[HF_HREF],		HF_TYPE_BASE},
	{"/base",	NULL,					HF_TYPE_BASE_CLOSE},
	{"meta",	HTML_FIELDS_NAMES[HF_HTTP_EQUIV],	HF_TYPE_META}
};
const int HTML_TEGS_NUM=sizeof(HTML_TEGS)/sizeof(tHtmlTegTable);

tHtmlTagField::tHtmlTagField(){
	name=value=NULL;
	saved=0;
};
void tHtmlTagField::print(){
	printf("Name:\t%s\n",name==NULL?"*NULL*":name);
	printf("Value:\t%s\n",value==NULL?"*NULL*":value);
};

tHtmlTagField::~tHtmlTagField(){
	if (name) delete[] name;
	if (value) delete[] value;
};

tHtmlTag::tHtmlTag(){
	descr=name=NULL;
	fields=NULL;
};

void tHtmlTag::print(){
	printf("Name:\t%s\n",name==NULL?"*NULL*":name);
};

tHtmlTagField *tHtmlTag::find_field(const char *n){
	tHtmlTagField *fld=(tHtmlTagField *)(fields->first());
	while(fld){
		if (strcasecmp(fld->name,n)==0)
			return fld;
		fld=(tHtmlTagField *)(fields->prev());
	};
	return 0;
};

tHtmlTag::~tHtmlTag(){
	if (name) delete[] name;
	if (descr) delete[] descr;
	if (fields) delete(fields);
};
/********************************************************/
tHtmlUrl::tHtmlUrl(){
	descr=NULL;
};

void tHtmlUrl::print(){
};

tHtmlUrl::~tHtmlUrl(){
	if (descr) delete[] descr;
};


/* Will be parse htmls in next assumption:
   <TAG[spaces]FIELD[spaces][=[spaces]VALUE]spacesFIELD[spaces][=[spaces]VALUE]...[spaces]>
 */

char *tHtmlParser::get_string_back(int len,int shift){
	WL->shift(-(len+shift),SEEK_CUR);
	char *temp=new char[len+1];
	WL->read(temp,len);
	temp[len]=0;
	return temp;
};

char *tHtmlParser::get_word(){
	int i=0;
	char p;
	while(WL->read(&p,sizeof(p))>0){
		if (isspace(p) || p=='>'){
			return(get_string_back(i,1));
		};
		i++;
	};
	return NULL;
};

char *tHtmlParser::get_word_o(int shift){
	int i=shift;
	char p;
	while(WL->read(&p,sizeof(p))>0){
		if (isspace(p) ||  p=='>'){
			return(get_string_back(i,1));
		};
		i++;
	};
	return NULL;
};

char *tHtmlParser::get_word(int shift){
	int i=shift;
	char p;
	while(WL->read(&p,sizeof(p))>0){
		if (isspace(p) || p=='=' ||  p=='>'){
			return(get_string_back(i,1));
		};
		i++;
	};
	return NULL;
};

/* compact_string(char *str)
    before exec:    str="\naa\nbb\ncc"
    after execution:    str="aabbcc"
 */
void tHtmlParser::compact_string(char *str){
	char *a=str,*b;
	while (*a){
		if (*a=='\n' || *a=='\r')
			break;
		a+=1;
	};
	b=a;
	while (*a){
		*a=*b;
		if (*a!='\n' && *a!='\r')
			b+=1;
		a+=1;
	};
	*b=0;
};

char *tHtmlParser::get_word_icommas(){
	int i=1;
	char p;
	while(WL->read(&p,sizeof(p))>0){
		if (p=='>'){
			return(get_string_back(i,1));
		};
		i++;
		if (p=='\"'){
			return(get_string_back(i,0));
		};
	};
	return NULL;
};

char *tHtmlParser::get_word_icommas2(){
	int i=1;
	char p;
	while(WL->read(&p,sizeof(p))>0){
		if (p=='>'){
			return(get_string_back(i,1));
		};
		i++;
		if (p=='\''){
			return(get_string_back(i,0));
		};
	};
	return NULL;
};

void tHtmlParser::get_fields(tHtmlTag *tag){
	char p;
	tag->fields=new tQueue;
	tag->fields->init(0);
	while(WL->read(&p,sizeof(p)>0)){
		if (p=='>') return;
		if (!isspace(p)){
			tHtmlTagField *field=new tHtmlTagField;
			field->name=get_word(1);
			tag->fields->insert(field);
			int eqsign=0;
			while(WL->read(&p,sizeof(p)>0)){
				if (p=='>') return;
				if (p=='=') eqsign=1;
				if (!isspace(p) && p!='='){
					if (!eqsign){
						WL->shift(-1,SEEK_CUR);
						break;
					};
					switch(p){
					case '\"':{
						field->value=get_word_icommas();
						break;
					};
					case '\'':{
						field->value=get_word_icommas2();
						break;
					};
					default:
						field->value=get_word_o(1);
					};
					if (field->value)
						compact_string(field->value);
					break;
				};
			};
		};
	};
};

char *tHtmlParser::extract_from_icommas(char *str){
	if (str==NULL) return NULL;
	char *temp=str;
	char *end=NULL;
	switch (*temp){
	case '\'':{
		temp+=1;
		end=index(temp,'\'');
		break;
	};
	case '\"':{
		temp+=1;
		end=index(temp,'\"');
		break;
	};
	};
	if (end)
		return(copy_string2(temp,end-temp));
	return(copy_string(temp));
};

void tHtmlParser::get_tag_descr(tHtmlTag *tag){
	if (strcasecmp(tag->name,"img")==0){
		//get descr from ALT or TITLE field
		tHtmlTagField *fld=tag->find_field("alt");
		if (!fld)
			fld=tag->find_field("title");
		if (fld) tag->descr=copy_string(fld->value);
	}else if (strcasecmp(tag->name,"a")==0){
		//get descr from content of tag
		char *str=new char[51];
		char *p=str;
		while(p-str<50 && WL->read(p,sizeof(char))>0){
			if (*p=='<'){
				WL->shift(-1,SEEK_CUR);
				break;
			};
			p++;
		};
		*p=0;
		WL->shift(str-p,SEEK_CUR);
		tag->descr=str;
	};
};

tHtmlTag *tHtmlParser::get_tag(){
	char p;
	tHtmlTag *rvalue=NULL;
	while(WL->read(&p,sizeof(p))>0){
		if (p=='<'){
			char *name=NULL;
			if ((name=get_word())){
				if (name && equal(name,"!--")){
					if (out_fd>=0){
						f_wstr(out_fd,"<!--");
					};
					while(WL->read(&p,sizeof(p))>0){
						if (out_fd>=0)
							write(out_fd,&p,sizeof(p));
						if (p=='>') break;
					};
					rvalue=get_tag();
					delete[] name;
				}else{
					rvalue=new tHtmlTag;
					rvalue->name=name;
					get_fields(rvalue);
					get_tag_descr(rvalue);
				};
			};
			break;
		}else{
			if (out_fd>=0) write(out_fd,&p,sizeof(p));
		};
	};
	return rvalue;
};

static void write_up_dirs(int out_fd,const char *a){
	int depth=0;
	while(*a){
		depth=1;
		if(*a=='/'){
			f_wstr(out_fd,"../");
		};
		a++;
	};
	if (depth){
		f_wstr(out_fd,"../");
	};
};

d4x::URL fix_url_global(char *url,const d4x::URL &papa,int out_fd,int leave,int quest_sign_replace){
	if (url==NULL || *url==0) return d4x::URL();
	d4x::URL info;
	char *html_shift=NULL;
	if (!global_url(url)) {
		html_shift=rindex(url,'#');
		if (html_shift){
			*html_shift=0;
			html_shift+=1;
		};
		char *quest=index(url,'?');
		if (quest){
			info.params=(quest+1);
			*quest=0;
		};
		if (papa.proto==D_PROTO_FTP){
			quest=index(url,';');
			if (quest)
				*quest=0;
		};
		/* %xx -> CHAR */
		char *tmp=parse_percents(url);
		quest=rindex(tmp,'/');
		if (quest) {
			info.file=(quest+1);
			*quest=0;
			if (*tmp=='/')
				info.path=(tmp+1);
			else{
				if (tmp==quest)
					info.path=("");
				else
					info.path=papa.path/std::string(tmp);
			};
			*quest='/';
		} else {
			info.path=papa.path;
			info.file=tmp;
		};
		delete[] tmp;
		info.file=info.file.substr(0,info.file.find('#'));
		info.copy_host(papa);
	}else{
		if (begin_string_uncase(url,"http:") ||
		    begin_string_uncase(url,"ftp:") ||
		    begin_string_uncase(url,"https:")){
			html_shift=rindex(url,'#');
			if (html_shift)	html_shift+=1;
			info=std::string(url);
			if (papa.proto==D_PROTO_FTP && info.proto==D_PROTO_FTP){
				info.file=info.file.substr(0,info.file.find(';'));
			};
		}else{
			if (out_fd>=0){
				f_wstr(out_fd,url);
			};
			return d4x::URL();
		};
	};
	if (out_fd>=0){
		if (info.host!=papa.host){
			if (leave){
				f_wstr(out_fd,"../");
				write_up_dirs(out_fd,papa.path.c_str());
				f_wstr(out_fd,info.host.c_str());
				f_wchar(out_fd,'/');
				f_wstr(out_fd,info.path.c_str());
				f_wchar(out_fd,'/');
				if (quest_sign_replace && info.file.c_str()[0]==0)
					f_wstr(out_fd,"index_html");
				else
					f_wstr(out_fd,info.file.c_str());
				if (!info.params.empty()){
					f_wstr(out_fd,quest_sign_replace?"%5f":"%3f");
					f_wstr(out_fd,info.params.c_str());
				};
			}else{
				f_wstr(out_fd,std::string(info).c_str());
			};
		}else{
			//FIXME: next code is too ugly :-)
			
			const char *a=papa.path.c_str(); 
			const char *b=info.path.c_str();
			if (*a=='/') a+=1;
			if (*b=='/') b+=1;
			const char *l=b;
			while(*a){
				if (*a==*b){
					if (*b=='/')
						l=b+1;
					a++;
					b++;
				}else
					break;
			};
			if (*a==*b)
				l=b;
			else
				if (*a==0 && *b=='/')
					l=b+1;
			write_up_dirs(out_fd,a);
			if (*l){
				f_wstr(out_fd,l);
				f_wchar(out_fd,'/');
			};
			if (quest_sign_replace && info.file.empty())
				f_wstr(out_fd,"index.html");
			else
				f_wstr(out_fd,info.file.c_str());
			if (!info.params.empty()){
				f_wstr(out_fd,quest_sign_replace?"%5f":"%3f");
				f_wstr(out_fd,info.params.c_str());
			};
		};
		if (html_shift){
			f_wchar(out_fd,'#');
			f_wstr(out_fd,html_shift);
		};
	};
	return(info);
};

char *tHtmlParser::convert_to_utf8(const char *src){
	if (!src) return 0;
	if((g_utf8_validate(src, -1, NULL)) == TRUE)
		return copy_string(src);
	//to avoid different memory freing schemes
	char *tmp=g_convert(src,-1,"UTF-8",codepage.c_str(),NULL,NULL,NULL);
	char *rval=copy_string(tmp);
	g_free(tmp);
	return rval;
};

void tHtmlParser::fix_url(char *url,tQueue *list,const d4x::URL &papa,const char *tag,const char *descr){
	if (out_fd>=0) f_wstr(out_fd,"=\"");
	d4x::URL info=fix_url_global(url,papa,out_fd,leave,quest_sign_replace);
	if (out_fd>=0) f_wchar(out_fd,'\"');
	if (info.is_valid()){
		tHtmlUrl *node=new tHtmlUrl;
		info.tag=tag;
		node->info=info;
		node->descr=convert_to_utf8(descr);
		list->insert(node);
	};
};

void tHtmlParser::write_left_fields(tHtmlTag *tag){
	if (out_fd<0) return;
	if (tag->fields){
		tHtmlTagField *field=(tHtmlTagField *)(tag->fields->first());
		while(field){
			if (field->saved==0 && field->name){
				f_wchar(out_fd,' ');
				f_wstr(out_fd,field->name);
				if (field->value){
					f_wchar(out_fd,'=');
					f_wstr(out_fd,field->value);
				};
			};
			field=(tHtmlTagField *)(tag->fields->prev());
		};
	};
	f_wchar(out_fd,'>');
};

void tHtmlParser::look_for_meta_content(tHtmlTagField *where,
					tQueue *list,
					const d4x::URL &papa,
					const char *tag){
	tHtmlTagField *field=(tHtmlTagField *)(where->prev);
	while (field){
		char *tmp=NULL;
		if (field->name && field->value &&
		    equal_uncase(field->name,HTML_FIELDS_NAMES[HF_CONTENT]))
			tmp=extract_from_icommas(field->value);
		if (tmp){
			/* parsing Refresh in form:
			   "  <int> <;> <url=> URL"
			 */
			char *url=skip_spaces(tmp);
			if (isdigit(*url)) url=index(url,';');
			if (url){
				if (*url==';') url+=1;
				url=skip_spaces(url);
				if (begin_string_uncase(url,"url")){
					url=index(url,'=');
					if (url) url+=1;
				};
				if (url){
					url=skip_spaces(url);
					fix_url(url,list,papa,tag);
				};
			};
			delete[] tmp;
		};
		field=(tHtmlTagField *)(field->prev);
	};
};

void tHtmlParser::set_content_type(const char *ct){
	//Example: text/html; charset=koi8-r
	char *a=index(ct,'=');
	if (a) codepage=a+1;
};


void tHtmlParser::get_charset_from_meta(tHtmlTagField *fld){
	if (fld && fld->value){
		char *val=extract_from_icommas(fld->value);
		set_content_type(val);
		delete [] val;
	};
};

void tHtmlParser::parse(tWriterLoger *wl,tQueue *list,const d4x::URL &papa,int qsignreplace){
	quest_sign_replace=qsignreplace;
	list->done();
	list->init(0);
	base=NULL;
	WL=wl;
	WL->shift(0);
	while(1){
		tHtmlTag *temp=get_tag();
		if (temp==NULL) return;
/*
		printf("Tag:\n");
		temp->print();
		if (temp->fields){
			printf("Fields:\n");
			tHtmlTagField *field=(tHtmlTagField *)(temp->fields->first());
			while(field){
				field->print();
				field=(tHtmlTagField *)(temp->fields->prev());
			};
			printf("EndFields:\n");
		};
		printf("EndTag:\n");
*/
		if (out_fd>=0){
			f_wchar(out_fd,'<');
			f_wstr(out_fd,temp->name);
		};
//		f_wchar(out_fd,' ');
		for (int i=0;i<HTML_TEGS_NUM;i++)
			if(equal_uncase(HTML_TEGS[i].tag,temp->name) &&
			   temp->fields){
				tHtmlTagField *field=(tHtmlTagField *)(temp->fields->first());
				while(field){
					if (field->value && equal_uncase(field->name,HTML_TEGS[i].field)){
						field->saved=1;
						char *tmp=extract_from_icommas(field->value);
						switch(HTML_TEGS[i].mod){
						case HF_TYPE_META:
							if (tmp && equal_uncase(tmp,"refresh"))
								look_for_meta_content(field,list,papa,temp->name);
							if (tmp && equal_uncase(tmp,"Content-Type"))
								get_charset_from_meta(temp->find_field("content"));
							break;
						case HF_TYPE_BASE:
							if (base) delete[] base;
							base=copy_string(tmp);
							if (base){
								char *slash=rindex(base,'/');
								if (slash) *slash=0;
							};
							break;
						default:
							if (base!=NULL && !global_url(tmp)){
								char *tmp1=tmp;
								tmp=compose_path(base,tmp1);
								delete[] tmp1;
							};
							if (strlen(tmp)<MAX_LEN){
								if (out_fd>=0){
									f_wchar(out_fd,' ');
									f_wstr(out_fd,field->name);
								};
								fix_url(tmp,list,papa,temp->name,temp->descr);
							};
						};
						delete[] tmp;
					}else{
						if (HTML_TEGS[i].mod==HF_TYPE_BASE_CLOSE){
							field->saved=1;
							if (base) delete[] base;
							base=NULL;
						};
					};
					field=(tHtmlTagField *)(temp->fields->prev());
				};
			};
		write_left_fields(temp);
		delete(temp);
	};
	if (base) delete[] base;
};


syntax highlighted by Code2HTML, v. 0.9.1