/*	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 "cookie.h"
#include "locstr.h"
#include "var.h"
#include "ntlocale.h"
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <dirent.h>
#include <time.h>
#include <ctype.h>
#include <sstream>

/* determine which cookies file is newer Netscape or Mozilla's one
   It's allowed to use non reentrant variance of readdir() cos here's first
   place where readdir() is used
 */

char *d4x_get_best_in_subdir(const char *path,time_t *a){
	DIR *d=opendir(path);
	char *best=NULL;
	time_t besttime=0;
	if (d){
		struct dirent *de=NULL;
		while((de=readdir(d))){
			if (de->d_name && !equal(de->d_name,"..") &&
			    !equal(de->d_name,".")){
				char *tmppath=sum_strings(path,"/",de->d_name,NULL);
				struct stat s;
				stat(tmppath,&s);
				if (S_ISDIR(s.st_mode)){
					char *p=sum_strings(tmppath,"/","cookies.txt",NULL);
					if (stat(p,&s)==0 && S_ISREG(s.st_mode) &&
					    (best==NULL ||  besttime<s.st_mtime)){
						if (best) delete[] best;
						best=p;
						besttime=s.st_mtime;
					}else
						delete[] p;
				};
				delete[] tmppath;
			};
		};
		closedir(d);
	};
	*a=besttime;
	return(best);
};

char *d4x_get_best_cookies(){
	char *tmppath=sum_strings(HOME_VARIABLE,"/.mozilla",NULL);
	DIR *d=opendir(tmppath);
	delete[] tmppath;
	char *best=NULL;
	time_t besttime=0;
	if (d){
		struct dirent *de=NULL;
		while((de=readdir(d))){
			if (de->d_name && !equal(de->d_name,"..") &&
			    !equal(de->d_name,".")){
				tmppath=sum_strings(HOME_VARIABLE,"/.mozilla/",de->d_name,NULL);
				struct stat s;
				stat(tmppath,&s);
				if (S_ISDIR(s.st_mode)){
					time_t a;
					char *p1=d4x_get_best_in_subdir(tmppath,&a);
					if (p1 && a>besttime){
						if (best) delete[] best;
						best=p1;
						besttime=a;
					};
				};
				delete[] tmppath;
			};
		};
		closedir(d);
	};
	tmppath=sum_strings(HOME_VARIABLE,"/.netscape/cookies",NULL);
	struct stat s;
	if (stat(tmppath,&s)==0 && S_ISREG(s.st_mode) &&
	    (s.st_mtime>besttime || best==NULL)){
		if (best) delete[] best;
		best=tmppath;
	}else
		delete[] tmppath;
	return(best);
};
/*******************************************************/

tCookie::tCookie(){
	time_of_life=time_t(0);
	myown=0;
};

void tCookie::set_time(time_t t){
	time_of_life=t;
};

void tCookie::set_time(const std::string &what){
	time_of_life=strtoll(what.c_str(), (char **)NULL, 10);
};

void tCookie::init(char *a,char *b,char *c,char *d){
	host=a;
	path=b;
	name=c;
	value=d;
};

time_t tCookie::get_time(){ return time_of_life;};

void tCookie::print(){
};

int tCookie::parse(char *str,const char *srchost,const char *srcpath){
	char *cur=str;
	while(cur && *cur){
		cur=skip_spaces(cur);
		char *n=index(cur,';');
		if (n) *n=0;
		char *eq=index(cur,'=');
		if (eq){
			*eq=0;
			char *a=copy_string(cur);
			char *b=a+strlen(a)-1;
			while (isspace(*b) && b>a){
				*b=0;
				b--;
			};
			b=skip_spaces(eq+1);
			char *c=copy_string(b);
			b=c+strlen(c)-1;
			while (isspace(*b) && b>c){
				*b=0;
				b--;
			};
			if (name.empty()){
				name=a;
				value=c;
			};
			if (equal_uncase(a,"expires")){
				time_of_life=ctime_to_time(c);
			};
			if (equal_uncase(a,"path")){
				path=c;
			};
			if (equal_uncase(a,"domain")){
				host=c;
			};
			delete[] a;
			delete[] c;
			*eq='=';
		};
		if (n){
			*n=';';
			n+=1;
		};
		cur=n;
	};
	if (time_of_life==0) time_of_life=time(NULL)+30*3600;
	if (srchost && host.empty()) host=srchost;
	if (srcpath && path.empty()){
		path=std::string("/")+srcpath;
	};
	if (name.empty() || value.empty() || path.empty() || host.empty())
		return(1);
	return(0);
};

int cmp_back(const char *a,const char *b){
	const char *bb=b+strlen(b)-1;
	const char *aa=a+strlen(a)-1;
	while(bb>b && aa>a){
		if (*bb!=*aa) return(*bb-*aa);
		bb--;aa--;
	};
	if (bb>b) return(-1);
	if (aa>a) return(1);
	return(0);
};

int tCookie::cmp(tAbstractSortNode *b){
	DBC_RETVAL_IF_FAIL(b!=NULL,0);
//	printf("%s %s %i\n",((tCookie *)b)->host.get(),host.get(),cmp_back(((tCookie *)b)->host.get(),host.get()));
	return(cmp_back(((tCookie *)b)->host.c_str(),host.c_str()));
};

tCookie::~tCookie(){
};

/*
 */

tCookie *tCookiesTree::find_exact(tCookie *cookie){
	tCookie *temp=find(cookie->host.c_str());
	while (temp){
		if (cookie->path==temp->path &&
		    cookie->name==temp->name){
			return temp;
		};
		temp=find(temp,cookie->host.c_str());
	};
	return(NULL);
};

tCookie *tCookiesTree::find(const char *what) {
	DBC_RETVAL_IF_FAIL(what!=NULL,NULL);
	if (Top && string_ended(((tCookie*)Top)->host.c_str(),what)==0)
		return((tCookie*)Top);
//	if (Top) printf("--- find from %s ---\n",((tCookie *)Top)->host.get());
	return find((tCookie *)Top,what);
};

tCookie *tCookiesTree::find(tCookie *begin,const char *what) {
	tCookie *temp=begin;
	while (temp) {
//		printf("%s %s ",temp->host.get(),what);
		int a=cmp_back(what,temp->host.c_str());
		if (a<0){
			temp=(tCookie *)(temp->more);
		}else {
			temp=(tCookie *)(temp->less);
		};
		if (temp && string_ended(temp->host.c_str(),what)==0){
			return temp;
		};
	};
	return NULL;
};

char *D4X_COOKIES_FILE="cookies.txt";

void tCookiesTree::load_from_file(int fd,int myown){
	char temp[MAX_LEN];
	while (f_rstr(fd,temp,MAX_LEN)){
		if (*temp!='#'){
			tCookie *cookie=new tCookie;
			std::istringstream ist(temp);
			std::string s,t;
			ist>>cookie->host>>s>>cookie->path>>s>>t>>cookie->name>>cookie->value;
			cookie->set_time(t);
			cookie->myown=myown;
			if (cookie->path.empty() ||  find_exact(cookie))
				delete(cookie);
			else
				add(cookie);
		};
	};
};


void tCookiesTree::save_cookie(int fd,tCookie *what){
	if (what->myown){
		f_wstr(fd,what->host.c_str());
		f_wstr(fd,"\tFALSE\t");
		f_wstr(fd,hexed_string(what->path).c_str());
		f_wstr(fd,"\tFALSE\t");
		static char str[MAX_LEN];
		sprintf(str,"%ld",(long int)(what->get_time()));
		f_wstr(fd,str);
		f_wchar(fd,'\t');
		f_wstr(fd,hexed_string(what->name).c_str());
		f_wchar(fd,'\t');
		f_wstr(fd,hexed_string(what->value).c_str());
		f_wchar(fd,'\n');
	};
	if (what->less) save_cookie(fd,(tCookie *)(what->less));
	if (what->more) save_cookie(fd,(tCookie *)(what->more));
};

void tCookiesTree::save_cookies(){
	char *path=sum_strings(HOME_VARIABLE,"/",CFG_DIR,"/",D4X_COOKIES_FILE,NULL);
	int fd=open(path,O_TRUNC | O_CREAT |O_RDWR,S_IRUSR | S_IWUSR);
	delete[] path;
	if (fd>=0){
		if (Top) save_cookie(fd,(tCookie*)Top);
		close(fd);
	};
};


void tCookiesTree::load_cookies(){
	char *path=d4x_get_best_cookies();
	MainLog->add(_("Loading cookies"),LOG_WARNING | LOG_DETAILED);
	if (path!=NULL){
		int fd=open(path,O_RDONLY);
		if (fd>=0){
			load_from_file(fd);
			close(fd);
			MainLog->myprintf(LOG_OK|LOG_DETAILED,_("%i cookies loaded from browsers' files"),NUM);
		}else{
			MainLog->myprintf(LOG_ERROR|LOG_DETAILED,_("Can't open cookies file %s!"),path);
		};
		delete[] path;
	};
	path=sum_strings(HOME_VARIABLE,"/",CFG_DIR,"/",D4X_COOKIES_FILE,NULL);
	int fd=open(path,O_RDONLY);
	delete[] path;
	if (fd>=0){
		load_from_file(fd,1);
		close(fd);
		MainLog->myprintf(LOG_OK|LOG_DETAILED,_("%i cookies loaded"),NUM);
	};
};

tCookiesTree::~tCookiesTree(){
	while (Top){
		tCookie *temp=(tCookie *)Top;
		del((tCookie*)Top);
		delete(temp);
	};
};


syntax highlighted by Code2HTML, v. 0.9.1