/* 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 "dlist.h" #include "ftpd.h" #include "locstr.h" #include "string.h" #include "html.h" #include "face/lod.h" #include "face/edit.h" #include "var.h" #include "ntlocale.h" #include "main.h" #include "httpd.h" #include "savedvar.h" #include #include #include #include #include #include #include #include "signal.h" #include "ping.h" #include "filter.h" #include "face/themes.h" #include "hproxy.h" using namespace d4x; extern tMain aa; void tTriger::reset() { old=curent; }; void tTriger::clear() { old=-1; curent=0; }; void tTriger::set(fsize_t a ) { curent=a; }; void tTriger::update() { old=curent-1; }; int tTriger::change() { return old==curent?0:1; }; /* file locking functions */ /* return zero id all ok */ int d4x_f_lock(int fd){ struct flock a; a.l_type=F_WRLCK; a.l_whence=SEEK_SET; a.l_start=0; a.l_len=1; if (fcntl(fd,F_SETLK,&a)==-1){ switch(errno){ case EINVAL: //not supported by fs case ENOLCK: //too many locks return(-1); }; return(1); }; return(0); }; void d4x_f_unlock(int fd){ struct flock a; a.l_type=F_UNLCK; a.l_whence=SEEK_SET; a.l_start=0; a.l_len=1; fcntl(fd,F_SETLK,&a); }; /*------------------------------------------------------------- tDefaultWL --------------------------------------------------------------*/ tDefaultWL::tDefaultWL(){ fd=-1; LOG=NULL; segments=NULL; fdlock=0; overlap_flag=0; }; fsize_t tDefaultWL::read(void *dst,fsize_t len){ if (fd>=0){ fsize_t loaded_size=::read(fd,dst,len); return(loaded_size); }; return(0); }; int tDefaultWL::is_overlaped(){ return(overlap_flag); }; fsize_t tDefaultWL::write(const void *buff, fsize_t len){ DBC_RETVAL_IF_FAIL(buff!=NULL,0); if (fd>=0){ fsize_t cur=(fsize_t)(lseek(fd,0,SEEK_CUR)); fsize_t saved_size=::write(fd,buff,len); if (saved_sizeinsert(cur,cur+saved_size); }; return (saved_size); }; return 0; }; void tDefaultWL::set_log(tLog *log){ LOG=log; }; void tDefaultWL::unlock_fd(){ if (fdlock) d4x_f_unlock(fd); fdlock=0; }; int tDefaultWL::lock_fd(){ /*trying to lock*/ switch(d4x_f_lock(fd)){ case 0: fdlock=1; break; case 1: log(LOG_ERROR,_("File is already opened by another download!")); return(-1); case -1: log(LOG_WARNING,_("Filesystem do not support advisory record locking!")); log(LOG_WARNING,_("Will proceed without it but beware that you might have problems.")); }; return(0); /*end of trying */ }; void tDefaultWL::set_segments(tSegmentator *newseg){ segments=newseg; }; void tDefaultWL::fd_close(){ if (fd>=0){ unlock_fd(); close(fd); }; }; void tDefaultWL::set_fd(int newfd,int lockstate){ if (fd>=0) fd_close(); fdlock=lockstate; fd=newfd; }; int tDefaultWL::get_fd(){ return(fd); }; fsize_t tDefaultWL::shift(fsize_t len,int mode){ if (fd>=0){ // printf("Shift to %i\n",shift); return(lseek(fd,len,mode)); }; return 0; }; void tDefaultWL::truncate(){ if (fd>=0){ off_t a=lseek(fd,0,SEEK_CUR); ftruncate(fd,a); if (segments) segments->truncate(a); // log_printf(LOG_WARNING,"truncate file to %i",a); }; }; void tDefaultWL::log(int type,const char *str){ DBC_RETURN_IF_FAIL(str!=NULL); if (LOG){ LOG->add(str,type); }; }; void tDefaultWL::cookie_set(tCookie *cookie){ COOKIES->lock.lock(); tCookie *temp=COOKIES->find_exact(cookie); if (temp){ if (cookie->get_time()del(temp); delete(temp); }else{ temp->value=cookie->value; temp->set_time(cookie->get_time()); temp->myown=1; }; COOKIES->lock.unlock(); delete(cookie); return; }; cookie->myown=1; COOKIES->add(cookie); COOKIES->lock.unlock(); }; std::string tDefaultWL::cookie(const char *host, const char *path){ DBC_RETVAL_IF_FAIL(host!=NULL,NULL); DBC_RETVAL_IF_FAIL(path!=NULL,NULL); COOKIES->lock.lock(); tCookie *temp=COOKIES->find(host); std::string request_string; tDownload **dwn=my_pthread_key_get(); if (dwn && *dwn && (*dwn)->config->cookie.get()){ COOKIES->lock.unlock(); return(copy_string((*dwn)->config->cookie.get())); }; while (temp){ // temp->print(); if (begin_string(path,temp->path.c_str())) request_string+=temp->name+"="+temp->value+";"; if (temp->get_time()del(temp); delete(temp); temp=COOKIES->find(host); }else temp=COOKIES->find(temp,host); }; COOKIES->lock.unlock(); return(request_string); }; tDefaultWL::~tDefaultWL(){ fd_close(); }; /*************Split Information****************/ d4xCondition::d4xCondition(){ pthread_mutex_init(&my_mutex,NULL); }; void d4xCondition::set_value(int val){ pthread_mutex_lock(&my_mutex); value=val; pthread_mutex_unlock(&my_mutex); }; int d4xCondition::get_value(){ pthread_mutex_lock(&my_mutex); int val=value; pthread_mutex_unlock(&my_mutex); return(val); }; int d4xCondition::dec(){ pthread_mutex_lock(&my_mutex); value-=1; int val=value; pthread_mutex_unlock(&my_mutex); return(val); }; int d4xCondition::inc(){ pthread_mutex_lock(&my_mutex); value+=1; int val=value; pthread_mutex_unlock(&my_mutex); return(val); }; d4xCondition::~d4xCondition(){ pthread_mutex_destroy(&my_mutex); }; tSplitInfo::tSplitInfo(){ FirstByte=LastByte=-1; next_part=parent=grandparent=NULL; thread_num=1; cond=NULL; reset(); }; void tSplitInfo::reset(){ failed=prepared=run=0; stopcount=runcount=0; }; tSplitInfo::~tSplitInfo(){ if (next_part) delete(next_part); }; /**********************************************/ tDownload::tDownload() { sizequery=0; list_iter=NULL; fsearch=0; restart_from_begin=0; regex_match=NULL; config=NULL; next2stop=prev2update=next2update=NULL; protect=0; next=prev=NULL; split=NULL; who=NULL; CurrentLog=LOG=NULL; WL=NULL; editor=NULL; // config->ftp_recurse_depth=config->http_recurse_depth=1; SpeedLimit=NULL; finfo.size=-1; finfo.type=T_NONE; DIR=NULL; finfo.perm=S_IWUSR | S_IRUSR; Start=Pause=Difference=HistoryTime=0; Percent=0; myowner=NULL; thread_id=0; DIR=NULL; action=ACTION_NONE; ScheduleTime=0; segments=NULL; ALTS=NULL; }; fsize_t tDownload::filesize(){ if (finfo.size==0 && who) finfo.size=who->another_way_get_size(); return(finfo.size>0?finfo.size:0); }; fsize_t tDownload::get_loaded(){ if (segments){ return(segments->get_total()); }; return(0); }; int tDownload::cmp(tAbstractSortNode *b){ DBC_RETVAL_IF_FAIL(b!=NULL,0); tDownload *bb=(tDownload*)b; int r=strcmp(info.file.c_str(),bb->info.file.c_str()); if (r) return r; r=strcmp(info.path.c_str(),bb->info.path.c_str()); if (r) return r; r=strcmp(info.file.c_str(),bb->info.file.c_str()); if (r) return r; return strcmp(info.params.c_str(),bb->info.params.c_str()); }; void tDownload::delete_editor() { if (editor) delete editor; }; void tDownload::print_error(int err){ switch(err){ case ERROR_ACCESS: WL->log_printf(LOG_ERROR, _("You have no permissions to create file at path %s"), config->save_path.get()); break; case ERROR_NO_SPACE:{ WL->log_printf(LOG_ERROR, _("You have no space at path %s for creating file"), config->save_path.get()); break; }; case ERROR_DIRECTORY:{ WL->log(LOG_ERROR,_("Directory already created!:))")); break; }; }; }; void tDownload::print() { //do nothing }; int tDownload::owner(){ if (myowner) return(myowner->get_key()); return(DL_ALONE); }; void tDownload::remove_tmp_files(){ d4x::Path path=make_path_to_file(); if (!Name2Save.empty()){ path/=Name2Save; }else{ if (info.file.empty()) path/=std::string(".")+CFG.DEFAULT_NAME; else path/=std::string(".")+info.file; }; if (!info.params.empty()){ path+=std::string("?")+info.params; }; remove(path.c_str()); path+=std::string(".segments"); remove(path.c_str()); }; int tDownload::delete_file() { if (who==NULL) return(0); int rvalue=0; tFileInfo *D_FILE=who->get_file_info(); if (D_FILE->type==T_FILE) { char *name,*guess; make_file_names(&name,&guess); if (remove(guess) && remove(name)) rvalue=-1; delete[] name; delete[] guess; }; return rvalue; }; void tDownload::make_file_names(char **name, char **guess){ DBC_RETURN_IF_FAIL(name!=NULL); DBC_RETURN_IF_FAIL(guess!=NULL); char *real_path=parse_save_path(config->save_path.get(),info.file.c_str()); if (!Name2Save.empty()) who->make_full_pathes(real_path, Name2Save.c_str(), name,guess); else who->make_full_pathes(real_path,name,guess); delete[] real_path; }; int tDownload::try_to_lock_fdesc(){ if (im_first) return(((tDefaultWL*)(WL))->lock_fd()); return(0); }; fsize_t tDownload::init_segmentator(int fdesc,fsize_t cursize,char *name){ fsize_t rvalue=cursize; im_first=0; ((tDefaultWL*)(WL))->set_fd(fdesc); if (segments==NULL){ im_first=1; if (try_to_lock_fdesc()) return(-1); segments=new tSegmentator; char *segname=sum_strings(name,".segments",NULL); segments->init(segname); delete[] segname; tSegment *first_seg=segments->get_first(); if (first_seg && first_seg->next!=NULL && (unsigned long int)rvalueend){ WL->log(LOG_WARNING,"Segmentation info is wrong!"); rvalue=0; ftruncate(fdesc,0); segments->truncate(0); }else{ if ((first_seg==NULL || first_seg->next==NULL)){ if (rvalue>0) segments->insert(0,rvalue); segments->truncate(rvalue); }; }; first_seg=segments->get_first(); rvalue=first_seg?first_seg->end:0; }; ((tDefaultWL*)(WL))->set_segments(segments); return rvalue; }; fsize_t tDownload::create_file() { if (!who) return -1; tFileInfo *D_FILE=who->get_file_info(); int fdesc=-1; fsize_t rvalue=0; char *name,*guess; make_file_names(&name,&guess); make_dir_hier_without_last(name); switch (D_FILE->type) { case T_LINK:{ //this is a link WL->log(LOG_WARNING,_("Trying to create a link")); int err=symlink(D_FILE->body.get(),guess); if (err) { switch (errno){ case EEXIST: WL->log(LOG_ERROR,_("Link already created!:))")); break; case EACCES: print_error(ERROR_ACCESS); break; default: WL->log(LOG_ERROR,_("Can't create link")); rvalue=-1; break; }; }; chmod(guess,D_FILE->perm | S_IWUSR); break; }; case T_FILE:{ //this is a file WL->log(LOG_WARNING,_("Trying to create a file")); if (restart_from_begin){ fdesc=open(guess,O_RDWR|O_TRUNC,S_IRUSR | S_IWUSR ); }else fdesc=open(guess,O_RDWR,S_IRUSR | S_IWUSR ); if (fdesc<0) { if (restart_from_begin){ fdesc=open(name,O_RDWR|O_CREAT|O_TRUNC,S_IRUSR | S_IWUSR ); }else fdesc=open(name,O_RDWR|O_CREAT,S_IRUSR | S_IWUSR ); if (fdesc<0) { switch (errno){ case EACCES: print_error(ERROR_ACCESS); rvalue=-1; break; case ENOSPC: print_error(ERROR_NO_SPACE); rvalue=-1; break; default: WL->log(LOG_ERROR,_("Can't create file at the path:")); WL->log(LOG_ERROR,config->save_path.get()); WL->log(LOG_ERROR,_("which has name:")); WL->log(LOG_ERROR,name); rvalue=-1; }; break; }; need_to_rename=1; }else{ need_to_rename=0; }; restart_from_begin=0; WL->log(LOG_OK,_("File was created!")); rvalue=init_segmentator(fdesc,lseek(fdesc,0,SEEK_END),name); break; }; case T_DIR:{ //this is a directory WL->log(LOG_WARNING,_("Trying to create a dir")); if (info.file.empty()){ print_error(ERROR_DIRECTORY); break; }; int temp=0; if (strlen(guess)) temp=mkdir(guess,S_IRWXU); if (temp) { if (errno!=EEXIST) { WL->log(LOG_ERROR,_("Can't create directory!")); rvalue=-1; break; }; print_error(ERROR_DIRECTORY); }; chmod(guess,D_FILE->perm | S_IWUSR |S_IXUSR); break; }; case T_DEVICE:{ //this is device WL->log(LOG_WARNING,_("Downloader can't create devices...")); break; }; default:{ who->print_error(ERROR_UNKNOWN); }; }; delete[] name; delete[] guess; return rvalue; }; int tDownload::file_type() { if (!who) return(T_FILE); tFileInfo *D_FILE=who->get_file_info(); return (D_FILE->type); }; void tDownload::set_date_file() { if (!who) return; tFileInfo *D_FILE=who->get_file_info(); if (config->get_date) { char *name,*guess; make_file_names(&name,&guess); struct utimbuf dates; dates.actime=dates.modtime=D_FILE->date; utime(name,&dates); utime(guess,&dates); delete[] name; delete[] guess; }; if (config->permisions) fchmod(((tDefaultWL *)(WL))->get_fd(),D_FILE->perm); else fchmod(((tDefaultWL *)(WL))->get_fd(),get_permisions_from_int(CFG.DEFAULT_PERMISIONS)); }; void tDownload::update_trigers() { Speed.update(); ActStatus.update(); Size.update(); Attempt.update(); Remain.update(); finfo.oldtype=finfo.type-1; }; void tDownload::make_file_visible(){ if (who && need_to_rename){ tFileInfo *D_FILE=who->get_file_info(); if (D_FILE->type==T_FILE) { char *oldname,*newname; make_file_names(&oldname,&newname); rename(oldname,newname); delete[] oldname; delete[] newname; }; }; }; void tDownload::set_default_cfg(){ config->copy_ints(&(CFG.DEFAULT_CFG)); config->http_recursing=config->http_recurse_depth==1?0:1; config->user_agent.set(CFG.USER_AGENT); config->Filter.set(CFG.DEFAULT_FILTER); if (myowner && myowner->PAPA) config->save_path.set(myowner->PAPA->save_path.get()); else config->save_path.set(CFG.GLOBAL_SAVE_PATH); if (CFG.SOCKS_HOST){ config->socks_host.set(CFG.SOCKS_HOST); config->socks_port=CFG.SOCKS_PORT; if (CFG.SOCKS_USER && CFG.SOCKS_PASS){ config->socks_user.set(CFG.SOCKS_USER); config->socks_pass.set(CFG.SOCKS_PASS); }; }; config->proxy.type=CFG.FTP_PROXY_TYPE; config->proxy.no_cache=CFG.PROXY_NO_CACHE; if (CFG.USE_PROXY_FOR_FTP) { config->proxy.ftp_host.set(CFG.FTP_PROXY_HOST); config->proxy.ftp_port=CFG.FTP_PROXY_PORT; if (CFG.NEED_PASS_FTP_PROXY) { config->proxy.ftp_user.set(CFG.FTP_PROXY_USER); config->proxy.ftp_pass.set(CFG.FTP_PROXY_PASS); }; }; if (CFG.USE_PROXY_FOR_HTTP) { config->proxy.http_host.set(CFG.HTTP_PROXY_HOST); config->proxy.http_port=CFG.HTTP_PROXY_PORT; if (CFG.NEED_PASS_HTTP_PROXY) { config->proxy.http_user.set(CFG.HTTP_PROXY_USER); config->proxy.http_pass.set(CFG.HTTP_PROXY_PASS); }; }; if (CFG.NUMBER_OF_PARTS>1 && split==NULL){ split=new tSplitInfo; split->NumOfParts=CFG.NUMBER_OF_PARTS; }; }; void tDownload::copy(tDownload *dwn){ info=dwn->info; Description.set(dwn->Description.get()); if (dwn->config){ if (config==NULL) config=new tCfg; config->copy(dwn->config); restart_from_begin=dwn->restart_from_begin; config->referer.set(dwn->config->referer.get()); Name2Save=dwn->Name2Save; config->save_path.set(dwn->config->save_path.get()); config->log_save_path.set(dwn->config->log_save_path.get()); }else{ if (config) delete(config); config=NULL; }; if (dwn->split==NULL && split) delete(split); if (dwn->split){ if (split==NULL) split=new tSplitInfo; split->NumOfParts=dwn->split->NumOfParts; }; }; d4x::Path tDownload::make_path_to_file(){ int noconfig=0; if (config==NULL){ noconfig=1; config=new tCfg; set_default_cfg(); }; char *real_path=parse_save_path(config->save_path.get(),info.file.c_str()); d4x::Path rval(real_path); delete [] real_path; if (info.proto==D_PROTO_HTTP && config->http_recursing){ if (config->leave_server) rval/=d4x::Path(info.host)/info.path; else rval/=info.path; }; if (noconfig){ delete(config); config=NULL; }; return(rval); }; d4x::Path tDownload::create_new_file_path(){ if (info.mask) return(info.path); return (info.path/info.file); }; d4x::Path tDownload::create_new_save_path(){ if (info.mask) return d4x::Path(config->save_path.get()); if (config->save_path.get()) { return(d4x::Path(config->save_path.get())/(Name2Save.empty()?info.file:Name2Save)); }; return(d4x::Path(Name2Save.empty()?info.file:Name2Save)); }; void tDownload::convert_list_to_dir() { if (who==NULL) { return; }; tFtpDownload *tmp=(tFtpDownload *)(who); tStringList *dir=tmp->dir(); if (DIR) { DIR->done(); } else { DIR=new tDList(DL_TEMP); DIR->init(0); }; if (dir==NULL || dir->first()==NULL) { return; }; d4x::Path path=create_new_file_path(); d4x::Path savepath=create_new_save_path(); tString *temp=dir->last(); tFileInfo *prom=new tFileInfo; while (temp) { ftp_cut_string_list(temp->body,prom,1); if (prom->name.get() && !equal(prom->name.get(),".") && !equal(prom->name.get(),"..") && (prom->type!=T_DIR || config->ftp_recurse_depth!=2) && (prom->type==T_DIR || !info.mask || check_mask(prom->name.get(),info.file.c_str()))) { tDownload *onenew=new tDownload; d4x::URL *addrnew=&(onenew->info); onenew->config=new tCfg; onenew->config->isdefault=0; addrnew->path=path; if (prom->type==T_DIR){ if (info.mask){ addrnew->path/=std::string(prom->name.get()); addrnew->file=info.file; }else{ addrnew->path/=std::string(prom->name.get()); }; d4x::Path SavePath=savepath/std::string(prom->name.get()); onenew->config->save_path.set(SavePath.c_str()); addrnew->mask=info.mask; } else { addrnew->file=prom->name.get(); onenew->config->save_path.set(savepath.c_str()); }; addrnew->copy_host(info); onenew->config->copy(config); onenew->config->ftp_recurse_depth = config->ftp_recurse_depth ? config->ftp_recurse_depth-1 : 0; onenew->config->http_recurse_depth = config->http_recurse_depth; onenew->set_split_count(split?split->NumOfParts:0); if (CFG.RECURSIVE_OPTIMIZE) { onenew->finfo.type=prom->type; onenew->finfo.size=prom->size; onenew->finfo.date=prom->date; if (config->permisions) onenew->finfo.perm=prom->perm; if (onenew->finfo.type==T_LINK) { if (config->follow_link==1){ onenew->finfo.type=T_NONE; d4x::Path tmppath=onenew->info.path/std::string(prom->body.get()); std::string::size_type a=tmppath.rfind('/'); if (a!=std::string::npos){ onenew->info.file=tmppath.substr(a+1); onenew->info.path=tmppath.substr(0,a); }else{ onenew->info.file=tmppath; onenew->info.path=""; }; onenew->finfo.size=0; //follow symbolik link size is unknown yet onenew->finfo.date=0; //date is unknown too :-( }else{ onenew->finfo.body.set(prom->body.get()); }; }; }; if (addrnew->is_valid()){ DIR->insert(onenew); }else delete(onenew); }; dir->del(temp); delete(temp); temp=dir->last(); prom->name.set(NULL); prom->body.set(NULL); }; delete (prom); }; void make_dir_hier(char *path) { DBC_RETURN_IF_FAIL(path!=NULL); char *temp=path; while (temp) { temp=index(temp+1,'/'); if (temp) *temp=0; mkdir(path,S_IRWXU); if (temp) *temp='/'; }; }; void make_dir_hier_without_last(char *path) { DBC_RETURN_IF_FAIL(path!=NULL); char *temp=rindex(path,'/'); if (temp){ *temp=0; make_dir_hier(path); *temp='/'; }; }; static int is_subdir(const char *path, const char *subdir){ if (begin_string(subdir,path)){ int len=strlen(path); if (subdir[len]=='/' || subdir[len]==0) return(1); }; return(0); }; int tDownload::http_check_settings(const d4x::URL &what){ if (what.host!=info.host){ return (config->leave_server); }; if (config->dont_leave_dir==0 || is_subdir(info.path.c_str(),what.path.c_str())) return 1; return 0; }; void tDownload::convert_list_to_dir2(tQueue *dir) { if (!dir) return; if (DIR) { DIR->done(); DIR->init(0); } else { DIR=new tDList(DL_TEMP); DIR->init(0); }; tHtmlUrl *temp=(tHtmlUrl *)dir->last(); d4x::Filter filter; if (config->Filter.get()) filter=FILTERS_DB.find(config->Filter.get()); while (temp) { tDownload *onenew=new tDownload; onenew->config=new tCfg; onenew->config->isdefault=0; onenew->config->save_path.set(config->save_path.get()); if (onenew->config->save_path.get()) normalize_path(onenew->config->save_path.get()); onenew->config->http_recursing=1; onenew->config->copy(config); onenew->set_split_count(split?split->NumOfParts:0); onenew->config->http_recurse_depth = config->http_recurse_depth ? config->http_recurse_depth-1 : 0; onenew->config->ftp_recurse_depth = config->ftp_recurse_depth; onenew->config->referer.set(std::string(info).c_str()); onenew->Description.set(temp->descr); if (temp->info.is_valid() && http_check_settings(temp->info)){ onenew->info=temp->info; if (!filter.empty()){ if (filter.match(onenew->info)){ onenew->info.tag.clear(); //this info is not needed any more DIR->insert(onenew); }else{ delete(onenew); }; }else{ DIR->insert(onenew); }; }else{ delete(onenew); }; dir->del(temp); delete(temp); temp=(tHtmlUrl *)dir->last(); }; }; void tDownload::save_to_config(int fd){ f_wstr_lf(fd,"Download:"); f_wstr_lf(fd,"URL:"); f_wstr_lf(fd,std::string(info).c_str()); if (split) write_named_integer(fd,"SplitTo:",split->NumOfParts); if (config && config->isdefault==0) config->save_to_config(fd); if (ScheduleTime) write_named_time(fd,"Time:",ScheduleTime); if (HistoryTime) write_named_time(fd,"HTime:",HistoryTime); int tmpid=owner(); if (tmpid==DL_SIZEQUERY) write_named_integer(fd,"State:",action); else write_named_integer(fd,"State:",tmpid); if (finfo.size>0){ write_named_fsize(fd,"size:",finfo.size); if (Size>0) write_named_fsize(fd,"loaded:",Size); }; if (Description.get()) write_named_string(fd,"Description:",Description.get()); if (!Name2Save.empty()) write_named_string(fd,"SaveName:",Name2Save.c_str()); if (protect) write_named_integer(fd,"protect:",protect); if (ALTS) ALTS->save_to_config(fd); if (restart_from_begin) write_named_integer(fd,"restart_from_begin:",restart_from_begin); f_wstr_lf(fd,"EndDownload:"); }; int tDownload::load_from_config(int fd){ tSavedVar table_of_fields[]={ {"Url:", SV_TYPE_URL, &(info)}, {"State:", SV_TYPE_INT, &status}, {"Time:", SV_TYPE_TIME, &ScheduleTime}, {"HTime:", SV_TYPE_TIME, &HistoryTime}, {"Cfg:", SV_TYPE_CFG, &config}, {"SavePath:", SV_TYPE_PSTR, &(config->save_path)}, {"SaveName:", SV_TYPE_STDSTR, &(Name2Save)}, {"SplitTo:", SV_TYPE_SPLIT, &(split)}, {"size:", SV_TYPE_LINT, &(finfo.size)}, {"loaded:", SV_TYPE_FSIZE_TRIGER, &(Size)}, {"protect:", SV_TYPE_INT, &(protect)}, {"Description:",SV_TYPE_PSTR, &(Description)}, {"Alt:", SV_TYPE_ALT, &(ALTS)}, {"restart_from_begin:",SV_TYPE_INT,&restart_from_begin}, {"EndDownload:",SV_TYPE_END, NULL} }; char buf[MAX_LEN]; while(f_rstr(fd,buf,MAX_LEN)>0){ unsigned int i; for (i=0;i0) Percent=(fsize_t(Size)*float(100))/float(finfo.size); return(0); }else{ if (sv_parse_file(fd,&(table_of_fields[i]),buf,MAX_LEN)) return(-1); }; }; }; }; return -1; }; void tDownload::check_local_file_time(){ if (split==NULL){ struct stat tmpstat; fstat(((tDefaultWL *)WL)->get_fd(),&tmpstat); who->set_local_filetime(tmpstat.st_mtime); }; }; void tDownload::http_postload(){ d4xContentDisposition *cd=((tHttpDownload *)who)->get_content_disp(); if (cd){ if (cd->filename.get()){ char *buf=new char[1000]; char *oldname,*newname; make_file_names(&oldname,&newname); char *tmp=rindex(newname,'/'); if (tmp){ *tmp=0; char *a=tmp; tmp=sum_strings(newname,"/",cd->filename.get(),NULL); *a='/'; }else{ tmp=copy_string(cd->filename.get()); }; char *cpfrom; if (need_to_rename){ cpfrom=oldname; }else cpfrom=newname; WL->log_printf(LOG_WARNING,_("Trying to copy %s to %s due 'Content-Disposition'"), cpfrom,tmp); if (file_copy(cpfrom,tmp,buf,1000)) WL->log(LOG_ERROR,_("Error during copying!")); delete[] buf; delete[] tmp; delete[] newname; delete[] oldname; }; }; }; void tDownload::download_completed(int type) { who->done(); im_last=1; if (split && split->cond && split->cond->dec()!=0) im_last=0; if (split==NULL) WL->truncate(); switch (type){ case D_PROTO_HTTP:{ if (im_last){ http_recurse(); http_postload(); if (split && split->grandparent!=this){ if (split->grandparent->DIR) delete(split->grandparent->DIR); split->grandparent->DIR=DIR; DIR=NULL; }; }; break; }; case D_PROTO_FTP:{ if (finfo.type==T_DIR && config->ftp_recurse_depth!=1) convert_list_to_dir(); }; }; WL->log(LOG_OK,_("Downloading was successefully completed!")); if (im_last && CFG.WRITE_DESCRIPTION && info.proto!=D_PROTO_SEARCH){ /* add string into Descript.ion file */ d4x::Path path=make_path_to_file(); path/=std::string("Descript.ion"); int fd=open(path.c_str(),O_WRONLY|O_CREAT,S_IRUSR | S_IWUSR ); lseek(fd,0,SEEK_END); /* locking file exclusively */ struct flock a; a.l_type=F_WRLCK; a.l_whence=SEEK_SET; a.l_start=0; a.l_len=1; fcntl(fd,F_SETLKW,&a); /* writing file */ if (Name2Save.empty()) f_wstr(fd,info.file.c_str()); else f_wstr(fd,Name2Save.c_str()); f_wstr(fd," - "); if (Description.get()) { f_wstr(fd,Description.get()); f_wstr(fd," ["); f_wstr(fd,std::string(info).c_str()); f_wchar(fd,']'); } else { f_wstr(fd,std::string(info).c_str()); }; f_wchar(fd,'\n'); /* unlocking file */ a.l_type=F_UNLCK; fcntl(fd,F_SETLK,&a); close(fd); }; if (im_last){ make_file_visible(); set_date_file(); }; if (config->sleep_before_complete) sleep(config->time_for_sleep); D4X_UPDATE.add(this,DOWNLOAD_COMPLETE); }; void tDownload::download_failed() { if (who) who->done(); if (segments) segments->save(); WL->log(LOG_ERROR,_("Downloading was failed...")); D4X_UPDATE.add(this,DOWNLOAD_FATAL); }; static void _html_parser_destroy_(void *a){ tHtmlParser *b=(tHtmlParser *)a; if (b) delete(b); }; static void _html_parser_dir_destroy_(void *a){ tStringList *b=(tStringList *)a; if (b) delete(b); }; void tDownload::http_recurse() { tHttpDownload *httpd=(tHttpDownload *)(who); char *type=httpd->get_content_type(); if ((config->change_links || config->http_recurse_depth!=1) && type && begin_string_uncase(type,"audio/x-pn-realaudio")){ d4x::Path a(make_path_to_file()); a/=info.file; if (!info.params.empty()) a+=std::string("?")+info.params; int fd=open(a.c_str(),O_RDWR,S_IRUSR | S_IWUSR); if (fd>=0){ char *buf=new char[MAX_LEN]; *buf=0; f_rstr(fd,buf,MAX_LEN); tQueue *dir=new tQueue; pthread_cleanup_push(_html_parser_dir_destroy_,dir); tHtmlUrl *node=new tHtmlUrl; info.tag.clear(); node->info=std::string(buf); delete[] buf; dir->insert(node); if (config->http_recurse_depth!=1) convert_list_to_dir2(dir); /* FIXME: what about changing link? */ pthread_cleanup_pop(1); }; close(fd); }; if ((config->change_links || config->http_recurse_depth!=1) && type && begin_string_uncase(type,"text/html")){ tQueue *dir=new tQueue; tHtmlParser *html=new tHtmlParser; if (who) html->set_content_type(((tHttpDownload*)who)->get_content_type()); pthread_cleanup_push(_html_parser_dir_destroy_,dir); pthread_cleanup_push(_html_parser_destroy_,html); dir->init(0); if (config->change_links){ d4x::Path a(make_path_to_file()); a/=info.file; if (info.params.empty()) a+=std::string(".fl"); else a+=std::string("?")+info.params; html->out_fd=open(a.c_str(),O_RDWR|O_CREAT|O_TRUNC,S_IRUSR | S_IWUSR ); html->leave=config->leave_server; html->parse(WL,dir,info,config->quest_sign_replace); if (html->out_fd){ char *name,*guess; make_file_names(&name,&guess); if (need_to_rename){ delete[] guess; remove(name); rename(a.c_str(),name); delete[] name; }else{ delete[] name; remove(guess); rename(a.c_str(),guess); delete[] guess; }; ((tDefaultWL*)(WL))->set_fd(html->out_fd,0); }; }else{ html->out_fd=-1; html->parse(WL,dir,info,config->quest_sign_replace); }; pthread_cleanup_pop(1); if (config->http_recurse_depth!=1){ convert_list_to_dir2(dir); }; pthread_cleanup_pop(1); }else if(type && begin_string_uncase(type,"text/html")){ tQueue *dir=new tQueue; pthread_cleanup_push(_html_parser_dir_destroy_,dir); tHtmlParser *html=new tHtmlParser; pthread_cleanup_push(_html_parser_destroy_,html); if (who) html->set_content_type(((tHttpDownload*)who)->get_content_type()); dir->init(0); html->out_fd=-1; html->parse(WL,dir,info,0); pthread_cleanup_pop(1); //look for meta tag to redirect tHtmlUrl *temp=(tHtmlUrl *)dir->last(); while(temp){ if (strcasecmp(temp->info.tag.c_str(),"meta")==0){ finfo.type=T_REDIRECT; RedirectURL=temp->info; break; }; temp=(tHtmlUrl *)dir->next(); }; pthread_cleanup_pop(1); }; }; void tDownload::export_socket(tDownloader *what){ if (WL->is_overlaped()) return; SocketPtr sock=what->export_ctrl_socket(); if (sock.get()){ GVARS.SOCKETS->insert(info,sock); }; }; void tDownload::http_check_redirect(bool removefiles){ char *newurl=newurl=who->get_new_url(); if (config->change_links && (config->http_recurse_depth!=1 || config->http_recursing)){ /* wtrite simply HTML file for redirection */ WL->shift(0); static char *redirect_html="" "D4X Redirect page"; WL->write(redirect_html,strlen(redirect_html)); d4x::URL tmpadr=fix_url_global(newurl, info, ((tDefaultWL *)(WL))->get_fd(), config->leave_server); WL->write(redirect_html_end,strlen(redirect_html_end)); who->done(); make_file_visible(); }else{ who->done(); if (removefiles) delete_file(); }; delete[] newurl; d4x::URL addr=redirect_url(); finfo.type=T_REDIRECT; if (addr.is_valid()){ if (config->http_recursing ||config->http_recurse_depth!=1){ if (equal_uncase(addr.host.c_str(),info.host.c_str()) || config->leave_server){ finfo.type=T_REDIRECT; }else{ finfo.type=T_FILE; }; }; d4x::Filter filter; if (config->Filter.get()) filter=FILTERS_DB.find(config->Filter.get()); if (!filter.empty() && finfo.type==T_REDIRECT){ if (filter.match(addr)) finfo.type=T_REDIRECT; else{ finfo.type=T_FILE; WL->log(LOG_WARNING,_("Redirection blocked by filter")); }; }; }; WL->log(LOG_WARNING,_("Redirect detected...")); }; void tDownload::download_http_size(){ WL->log(LOG_WARNING,_("Size detection only!")); SocketPtr s=GVARS.SOCKETS->find_and_remove(info); if (who->init(info,config,s)==0) { who->init_download(info.path,info.file); finfo.size=who->get_size_only(); finfo.type=T_FILE; if (((tHttpDownload*)who)->persistent()) export_socket(who); }; D4X_UPDATE.add(this,DOWNLOAD_COMPLETE); }; void tDownload::download_ftp_size(){ WL->log(LOG_WARNING,_("Size detection only!")); SocketPtr s=GVARS.SOCKETS->find_and_remove(info); if (who->init(info,config,s)==0) { who->init_download(info.path,info.file); status=DOWNLOAD_SIZE_WAIT; fsize_t size=who->get_size(); if (size>=0) { finfo.size=size; finfo.type=file_type(); }; }; export_socket(who); D4X_UPDATE.add(this,DOWNLOAD_COMPLETE); }; void tDownload::download_http() { if (!who) who=new tHttpDownload(WL); if (sizequery){ sizequery=0; download_http_size(); return; }; config->split=split?1:0; SocketPtr s=GVARS.SOCKETS->find_and_remove(info); if (who->init(info,config,s)) { download_failed(); return; }; who->init_download(info.path,info.file); /* We need to know size of already loaded file * but I think if file not found we need to delete it * because in http name of file may be specify * in http answer */ fsize_t CurentSize=create_file(); if (CurentSize<0) { download_failed(); return; }; ((tDefaultWL*)(WL))->unlock_fd(); if (split && !im_first) CurentSize=split->FirstByte; fsize_t SizeDecrement=CurentSize>0 && segments->one_segment()?1:0; if (SizeDecrement) ((tHttpDownload*)who)->pass_first_segment(); who->set_loaded(CurentSize-SizeDecrement); CurentSize=who->rollback(); if (split) split->FirstByte=CurentSize; fsize_t size=who->get_size(); if (!im_first && split && split->FirstByte>0 && who->reget()==0){ WL->log(LOG_WARNING,_("Multithreaded downloading is not possible due to server limitations (resuming not supported)")); download_completed(D_PROTO_HTTP); return; }; /* In the case if file already loaded */ if (size==CurentSize+SizeDecrement && size>0 && config->rollback==0) { check_local_file_time(); if (!who->remote_file_changed()){ finfo.size=size; finfo.type=T_FILE; WL->log(LOG_OK,_("Local file is seems to be equal to remote one")); download_completed(D_PROTO_HTTP); return; }; }; /* There are must be procedure for removing file * wich execute if CurentSize==0 */ if (size==-1) { http_check_redirect(CurentSize<=0); D4X_UPDATE.add(this,DOWNLOAD_COMPLETE); return; }; if (im_first && ((tDefaultWL*)(WL))->lock_fd()){ download_failed(); return; }; if (size<0 && split==NULL && CurentSize==0) { if (CurentSize==0 && segments) segments->complete(); if (delete_file()) WL->log(LOG_WARNING,_("It is strange that we can't delete file which just created...")); }; if (size<-1) { WL->log(LOG_WARNING,_("File not found")); download_failed(); return; }; finfo.size=size; finfo.type=T_FILE; /* there we need to create file again * if CurentSize==0 */ if (split && im_first){ if (who->reget()) prepare_splits(); else split->LastByte=size; }; check_local_file_time(); fsize_t SIZE_FOR_DOWNLOAD=who->reget()?size-CurentSize:size; SIZE_FOR_DOWNLOAD=(split && split->LastByte>0)?split->LastByte-split->FirstByte:SIZE_FOR_DOWNLOAD; Difference=0; status=DOWNLOAD_GO; if (who->download(SIZE_FOR_DOWNLOAD)) { download_failed(); return; }; if (!split && ((tHttpDownload*)who)->persistent()) export_socket(who); download_completed(D_PROTO_HTTP); }; void tDownload::remove_links(d4xSearchEngine *engine){ d4xFtpRegex ftpr; regex_t regs[2]; ftpr.compile(engine->match.get(),info.file.c_str()); ftpr.compile_regexes(regs); tDownload *tmp=DIR->last(); tDList *nDIR=new tDList; while(tmp){ DIR->del(tmp); char *a=ftpr.cut(std::string(tmp->info).c_str(),regs); if (a){ // printf("%s\n",a); tmp->info=std::string(a); delete[] a; if (nDIR->find(tmp->info)) delete(tmp); else{ nDIR->insert(tmp); }; }else{ delete(tmp); }; tmp=DIR->last(); }; delete(DIR); DIR=nDIR; }; static void _tmp_sort_free_(void *buf){ d4xPing *tmp=(d4xPing *)buf; delete(tmp); }; static int _cmp_pinged_hosts_(tNode *a,tNode *b){ tDownload *aa=(tDownload *)a; tDownload *bb=(tDownload *)b; float rval=(aa->Percent/aa->Attempt)-(bb->Percent/bb->Attempt); if (rval==0) return(0); return(rval>0?1:-1); }; void tDownload::sort_links(){ if (DIR==NULL || DIR->count()<=0) return; WL->log(LOG_OK,_("Sorting started")); int i=0; while (ilog_printf(LOG_OK,_("Pinging (atempt %i of %i)"),i+1,CFG.SEARCH_PING_TIMES); if (ActStatus==0){ //clear previous percentage for non comulative ping tDownload *a=DIR->last(); while(a){ a->Percent=0; a->Attempt=0; a=DIR->next(); }; }; d4xPing *tmp=new d4xPing; pthread_cleanup_push(_tmp_sort_free_,tmp); tmp->run(DIR,WL); pthread_cleanup_pop(1); DIR->sort(_cmp_pinged_hosts_); if (!i) ActStatus=1; i+=1; }; }; static void _tmp_info_remove_(void *addr){ d4x::URL *info=(d4x::URL *)addr; delete(info); }; void tDownload::ftp_search_sizes(){ WL->log(LOG_WARNING,_("Trying to determine filesizes")); delete(who); who=NULL; tDownload *tmp=DIR->last(); config->number_of_attempts=5; while(tmp){ tDownload *nexttmp=DIR->next(); if (config->proxy.ftp_host.get() && config->proxy.type) who=new tProxyDownload(WL); else who=new tFtpDownload(WL); if (who->init(tmp->info,config)){ WL->log(LOG_ERROR,"Can't determine filesize"); tmp->finfo.size=-1; }else{ who->init_download(tmp->info.path, tmp->info.file); tmp->finfo.size=who->get_size_only(); }; who->done(); delete(who); who=NULL; tmp=nexttmp; }; }; void tDownload::ftp_search() { /* FIXME: prepare new url for ftp search */ if (action!=ACTION_REPING){ Size=0; d4xSearchEngine *engine=D4X_SEARCH_ENGINES.get_next_used_engine(NULL); tDList *TMP_DIR=NULL; while(engine){ d4x::URL *tmpinfo=new d4x::URL; fsize_t size=0; int who_download_status=0; pthread_cleanup_push(_tmp_info_remove_,tmpinfo); config->change_links=0; engine->prepare_url(*tmpinfo,finfo.size,info.file.c_str(),CFG.SEARCH_PERSERVER); pthread_cleanup_pop(0); if (who->init(*tmpinfo,config)) { delete(tmpinfo); download_failed(); return; }; pthread_cleanup_push(_tmp_info_remove_,tmpinfo); who->init_download(tmpinfo->path,tmpinfo->file); who->set_loaded(0); size=who->get_size(); pthread_cleanup_pop(0); if (size<=-1) { WL->log(LOG_WARNING,_("Searching failed")); delete(tmpinfo); download_failed(); return; }; pthread_cleanup_push(_tmp_info_remove_,tmpinfo); finfo.type=T_FILE; Start=Pause=time(NULL); Difference=0; status=DOWNLOAD_GO; who_download_status=who->download(0); pthread_cleanup_pop(0); if (who_download_status) { delete(tmpinfo); download_failed(); return; }; pthread_cleanup_push(_tmp_info_remove_,tmpinfo); config->http_recurse_depth=2; config->leave_server=1; d4x::URL *a=new d4x::URL(info); info=*tmpinfo; pthread_cleanup_push(_tmp_info_remove_,a); http_recurse(); info=*a; pthread_cleanup_pop(1); who->done(); remove_links(engine); if (TMP_DIR){ if (DIR){ tDownload *dwn=DIR->first(); while(dwn){ DIR->del(dwn); TMP_DIR->insert_if_absent(dwn); dwn=DIR->first(); }; delete(DIR); DIR=NULL; }; }else{ TMP_DIR=DIR; DIR=NULL; }; Size=TMP_DIR->count(); engine=D4X_SEARCH_ENGINES.get_next_used_engine(engine); pthread_cleanup_pop(1); if (Size>=CFG.SEARCH_ENTRIES) break; }; if (TMP_DIR && !DIR) DIR=TMP_DIR; }else{ Size=DIR->count(); }; if (finfo.size<0 && DIR!=NULL && DIR->count()>0) ftp_search_sizes(); sort_links(); WL->log(LOG_OK,_("Search had been completed!")); D4X_UPDATE.add(this,DOWNLOAD_COMPLETE); }; void tDownload::download_ftp(){ WL->log(LOG_WARNING,_("Was Started!")); if (!who) who=new tFtpDownload(WL); if (sizequery){ sizequery=0; download_ftp_size(); return; }; if (finfo.type==T_LINK && config->follow_link!=2) { WL->log(LOG_WARNING,_("It is a link and we already load it")); who->init_download("",info.file); who->set_file_info(&finfo); create_file(); set_date_file(); download_completed(D_PROTO_FTP); return; }; config->split=split?1:0; SocketPtr s=GVARS.SOCKETS->find_and_remove(info); if (who->init(info,config,s)) { download_failed(); return; }; who->init_download(info.path,info.file); if (finfo.size<0 || finfo.type==T_NONE) { status=DOWNLOAD_SIZE_WAIT; fsize_t size=who->get_size(); if (size<0) { WL->log(LOG_ERROR,_("File not found")); if (info.mask){ download_failed(); return; }; WL->log(LOG_ERROR,_("Trying to work without CWD")); ((tFtpDownload *)(who))->dont_cwd(); finfo.type=T_FILE; }else{ finfo.size=size; finfo.type=file_type(); }; } else { who->set_file_info(&(finfo)); }; if (finfo.type==T_LINK){ finfo.size=0; if (config->follow_link==2){ tFileInfo *i=who->get_file_info(); i->type=finfo.type=T_FILE; }; }; fsize_t CurentSize=0; if (info.mask==0){ CurentSize=create_file(); //if it was link finfo.type=file_type(); }; if (finfo.type==T_DEVICE) { download_completed(D_PROTO_FTP); return; }; if (CurentSize<0) { download_failed(); return; }; if (finfo.size && CurentSize>finfo.size) CurentSize=finfo.size; if (split && finfo.type==T_FILE){ if (im_first){ if (who->reget()) prepare_splits(); else split->LastByte=CurentSize; }else{ CurentSize=split->FirstByte; }; }; check_local_file_time(); who->set_loaded(CurentSize); if (split) WL->shift(CurentSize); fsize_t SIZE_FOR_DOWNLOAD=(split && split->LastByte>0)?split->LastByte-split->FirstByte:0; Difference=0; status=DOWNLOAD_GO; if (who->download(SIZE_FOR_DOWNLOAD)) { download_failed(); return; }; if (config->dont_send_quit) export_socket(who); if (config->follow_link==1 && finfo.type==T_LINK) finfo.type=T_REDIRECT; download_completed(D_PROTO_FTP); }; #define SPLIT_MINIMUM_PART 5120 int tDownload::find_best_split(){ tSegment *holes=segments->to_holes(finfo.size); tSegment *tmp=holes->next; tSegment *best=holes; fsize_t maxlen=holes->end-holes->begin; while(tmp){ fsize_t l=tmp->end-tmp->begin; if (l>maxlen){ maxlen=l; best=tmp; }; tmp=tmp->next; }; split->FirstByte=split->LastByte=0; // if this part is already loading by another thread then we // need to load only part of this chunk tDownload *gp=split->grandparent; while (gp){ if (gp!=this && ((gp->split->LastByte>=best->begin && gp->split->LastByte<=best->end) || (gp->split->FirstByte>=best->begin && gp->split->FirstByte<=best->end)|| (gp->split->FirstByte<=best->begin && gp->split->LastByte>=best->end))) break; gp=gp->split->next_part; }; if (gp){ split->FirstByte=best->begin+maxlen/2; }else{ split->FirstByte=best->begin; }; split->LastByte=best->end; int completed=0; if (best->begin==0) completed=1; while(holes){ tmp=holes->next; delete(holes); holes=tmp; }; int k=(info.proto==D_PROTO_FTP && (config==NULL || config->proxy.ftp_host.get()==NULL || config->proxy.type==0))?12:8; if (split->LastByte-split->FirstByte>SPLIT_MINIMUM_PART*k && completed==0){ return 1; }; split->FirstByte=split->LastByte=0; return 0; }; void tDownload::prepare_splits(){ DBC_RETURN_IF_FAIL(split!=NULL); DBC_RETURN_IF_FAIL(segments!=NULL); // printf("__%Li__\n",finfo.size); tSegment *holes=segments->to_holes(finfo.size); tSegment *tmp; /* printf("split to %i parts[holes->offest_in_file=%i]\n",split->NumOfParts,holes->offset_in_file); tmp=holes; while(tmp){ printf("L[%i]:%li %li\n",holes->offset_in_file,holes->begin,holes->end); tmp=tmp->next; }; */ while(split->NumOfParts>holes->offset_in_file){ tSegment *largest=holes; tmp=holes->next; while(tmp){ if ((tmp->end-tmp->begin)>(largest->end-largest->begin)) largest=tmp; tmp=tmp->next; }; if (largest->end-largest->beginlog(LOG_WARNING,_("Can't split file to specified number of parts!")); break; }; tmp=new tSegment; tmp->end=largest->end; tmp->begin=largest->begin+(largest->end-largest->begin)/(split->NumOfParts-holes->offset_in_file+1); largest->end=tmp->begin; tmp->next=largest->next; largest->next=tmp; holes->offset_in_file+=1; }; if (holes->next && holes->end==holes->next->begin){ holes->end+=(holes->end-holes->begin)/10; holes->next->begin=holes->end; }; split->cond=new d4xCondition; // if (split->NumOfPartsoffset_in_file) split->NumOfParts=holes->offset_in_file; split->cond->set_value(split->NumOfParts); split->FirstByte=holes->begin; split->LastByte=holes->end; split->thread_num=1; // printf("%Li %Li\n",split->FirstByte,split->LastByte); tmp=holes->next; delete(holes); holes=tmp; tSplitInfo *newsplit=split; tDownload *parent=this; char i='1'; std::list::iterator alt; if (ALTS){ ALTS->lock_by_download(); alt=ALTS->LST.begin(); }; split->alt=0; int alt_num=1; while(holes){ tmp=holes->next; // printf("H:%Li %Li\n",holes->begin,holes->end); if (parent->split->thread_numNumOfParts){ if (newsplit->next_part==NULL) newsplit->next_part=new tDownload; tDownload *temp=newsplit->next_part; temp->status=DOWNLOAD_REAL_STOP; if (temp->split==NULL) temp->split=new tSplitInfo; else temp->split->reset(); newsplit=temp->split; newsplit->cond=split->cond; newsplit->NumOfParts=split->NumOfParts; temp->split->grandparent=this; temp->split->parent=parent; temp->split->thread_num=parent->split->thread_num+1; parent=temp; temp->split->FirstByte=holes->begin; temp->split->LastByte=holes->end; // printf("%Li %Li\n",newsplit->FirstByte,newsplit->LastByte); temp->segments=segments; if (temp->config==NULL) temp->config=new tCfg; temp->config->copy(config); if (config->log_save_path.get()){ char *tmppath=sum_strings(config->log_save_path.get(),"_ ", NULL); tmppath[strlen(tmppath)-1]=i; temp->config->log_save_path.set(tmppath); }; i+=1; temp->config->speed=(config->speed/split->NumOfParts)*temp->split->NumOfParts; temp->config->user_agent.set(config->user_agent.get()); temp->config->referer.set(config->referer.get()); temp->config->save_path.set(config->save_path.get()); temp->Name2Save=Name2Save; temp->finfo.size=finfo.size; temp->finfo.type=finfo.type; temp->finfo.perm=finfo.perm; temp->finfo.date=finfo.date; if (ALTS && alt!=ALTS->LST.end()){ temp->split->alt=alt_num; temp->info=(*alt)->info; (*alt)->set_proxy_settings(temp); }else{ temp->split->alt=0; temp->info=info; }; if (ALTS){ if (alt!=ALTS->LST.end()){ alt++; alt_num++; }else{ alt=ALTS->LST.begin(); alt_num=1; }; }; }; delete(holes); holes=tmp; }; if (ALTS) ALTS->unlock_by_download(); // to avoid broken downloads when we can't detect resuming support at first request // first thread always load from begining to end if (split->FirstByte==0) split->LastByte=finfo.size; split->prepared=1; }; void tDownload::delete_who(){ if (who){ delete(who); who=NULL; }; }; d4x::URL tDownload::redirect_url(){ if (RedirectURL.is_valid()){ return RedirectURL; }else if (who){ char *newurl=NULL; newurl=who->get_new_url(); if (newurl) { d4x::URL addr=fix_url_global(newurl,info,-1,0); delete[] newurl; return(addr); }; }; return d4x::URL(); }; void tDownload::set_split_count(int num){ if (num>1){ if (num>10) num=10; if (split==NULL) split=new tSplitInfo; split->NumOfParts=num; split->grandparent=this; }else{ if (split) delete(split); split=NULL; }; }; void tDownload::set_initial_speedlimit(){ if (CFG.SPEED_LIMIT<3 && CFG.SPEED_LIMIT>0){ SpeedLimit->set((CFG.SPEED_LIMIT==1 ? CFG.SPEED_LIMIT_1:CFG.SPEED_LIMIT_2)/50+1); }else if (myowner && myowner->PAPA){ SpeedLimit->base2=myowner->PAPA->SpdLmt/myowner->count(); }else if (split && split->grandparent && split->grandparent->myowner){ tDList *o=split->grandparent->myowner; SpeedLimit->base2=o->PAPA->SpdLmt/o->count(); }; }; tDownload::~tDownload() { if (list_iter) gtk_tree_iter_free(list_iter); if (config) delete(config); if (myowner) myowner->del(this); if (who) delete who; if (editor) delete editor; if (LOG) LOG->ref_dec(); if (DIR) delete DIR; if (WL) delete(WL); if (split) delete(split); if (ALTS) delete(ALTS); }; //**********************************************/ tDList::tDList():tQueue(){ Pixmap=LPE_UNKNOWN; empty=non_empty=NULL; }; tDList::tDList(int key):tQueue(){ Pixmap=LPE_UNKNOWN; OwnerKey=key; empty=non_empty=NULL; }; void tDList::set_empty_func(void (*emp)(),void (*nonemp)()){ empty=emp; non_empty=nonemp; if (Num && non_empty) non_empty(); else if (empty) empty(); }; void tDList::init_pixmap(int a){ Pixmap=a; }; int tDList::get_key(){ return(OwnerKey); }; void tDList::insert(tDownload *what) { DBC_RETURN_IF_FAIL(what!=NULL); if (Num==0 && non_empty!=NULL) non_empty(); tQueue::insert(what); what->myowner=this; if (Pixmap!=LPE_UNKNOWN && PAPA) PAPA->qv.set_pixmap(what,Pixmap); }; void tDList::insert_before(tDownload *what,tDownload *where) { DBC_RETURN_IF_FAIL(where!=NULL); DBC_RETURN_IF_FAIL(where->myowner==this); tQueue::insert_before(what,where); what->myowner=this; if (Pixmap!=LPE_UNKNOWN && PAPA) PAPA->qv.set_pixmap(what,Pixmap); }; void tDList::del(tDownload *what) { DBC_RETURN_IF_FAIL(what->myowner==this); if (Num==1 && empty!=NULL) empty(); tQueue::del(what); what->myowner=NULL; }; void tDList::forward(tDownload *what) { DBC_RETURN_IF_FAIL(what!=NULL); if (what->next) { tDownload *temp=(tDownload *)(what->next); if ((temp->prev=what->prev)) what->prev->next=temp; else Last=what->next; what->prev=temp; if ((what->next=temp->next)) temp->next->prev=what; else First=what; what->prev->next=what; }; }; void tDList::backward(tDownload *what) { DBC_RETURN_IF_FAIL(what!=NULL); if (what->prev) { tDownload *temp=(tDownload *)(what->prev); if ((temp->next=what->next)) what->next->prev=temp; else First=what->prev; what->next=temp; if ((what->prev=temp->prev)) temp->prev->next=what; else Last=what; what->next->prev=what; }; }; tDownload *tDList::find(const d4x::URL &addr){ tNode *a=First; while(a){ if (((tDownload*)a)->info==addr) return((tDownload*)a); a=a->prev; }; return(NULL); }; void tDList::insert_if_absent(tDownload *what){ if (find(what->info)) delete(what); else insert(what); }; void tDList::dispose(){ // ALL_DOWNLOADS->del((tDownload *)First); tQueue::dispose(); }; tDownload *tDList::last() { return (tDownload *)(Curent=Last); }; tDownload *tDList::first() { return (tDownload *)(Curent=First); }; tDownload *tDList::next() { return (tDownload *)tQueue::next(); }; tDownload *tDList::prev() { return (tDownload *)tQueue::prev(); }; tDList::~tDList() { done(); };