/* 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 <sys/types.h>
#include <sys/stat.h>
#if (defined(__unix__) || defined(unix)) && !defined(USG)
#include <sys/param.h>
#endif
#include <sys/timeb.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <signal.h>
#include "var.h"
#include "ftpd.h"
#include "httpd.h"
#include "hproxy.h"
#include "locstr.h"
#include "main.h"
#include "dlist.h"
#include "meter.h"
#include "log.h"
#include "mainlog.h"
#include "signal.h"
#include "savelog.h"
#include "face/list.h"
#include "face/buttons.h"
#include "face/log.h"
#include "face/edit.h"
#include "face/addd.h"
#include "face/fsface.h"
#include "config.h"
#include "ntlocale.h"
#include "memwl.h"
#include "schedule.h"
#include "html.h"
#include "filter.h"
#include "sndserv.h"
#include "xml.h"
#include "face/passface.h"
#include "face/saveload.h"
#include <algorithm>
#include <functional>
tMLog *MainLog=NULL;
d4xDownloadQueue *D4X_QUEUE=NULL;
tQueue D4X_QTREE;
tMeter *GlobalMeter=NULL;
tMeter *LocalMeter=NULL;
tMeter *GraphMeter=NULL;
tMeter *GraphLMeter=NULL;
tMsgQueue *LogsMsgQueue;
int calc_curent_run(char *host,int port) {
return (D4X_QUEUE->current_run(host,port));
};
int d4x_only_one_queue(){
if (D4X_QTREE.count()>1 || ((d4xDownloadQueue*)(D4X_QTREE.first()))->child.count()) return(0);
return(1);
};
static void d4x_qtree_for_each_rec(tQueue *q,d4xQTreeFunc dothis,void *a){
d4xDownloadQueue *dq=(d4xDownloadQueue*)(q->first());
while (dq){
d4xDownloadQueue *next=(d4xDownloadQueue *)(dq->prev);
d4x_qtree_for_each_rec(&(dq->child),dothis,a);
dothis(dq,a);
dq=next;
};
};
void d4x_qtree_for_each(d4xQTreeFunc dothis,void *a){
d4x_qtree_for_each_rec(&D4X_QTREE,dothis,a);
};
//**********************************************/
typedef void (*SigactionHandler)(int);
void _sig_pipe_handler_(){
};
int tMain::init() {
TO_WAIT_IF_HERE=DONTRY2RUN=0;
GVARS.SOCKETS=new d4x::SocketsHistory;
ftpsearch=NULL;
prev_speed_limit=0;
list_to_delete=NULL;
GlobalMeter=new tMeter;
GlobalMeter->init(METER_LENGTH);
LocalMeter=new tMeter;
LocalMeter->init(METER_LENGTH);
GraphMeter=new tMeter;
GraphMeter->init(GRAPH_METER_LENGTH);
GraphLMeter=new tMeter;
GraphLMeter->init(GRAPH_METER_LENGTH);
SpeedScheduler=new d4x::SpeedQueue;
MainScheduler=new d4xScheduler;
MainScheduler->load();
ALL_DOWNLOADS=new tDB;
d4x::filters_load_rc();
LastReadedBytes=0;
/* Create msgqueue for logs update */
MsgQueue=new tMsgQueue;
MsgQueue->init(0);
LogsMsgQueue=MsgQueue;
SOUND_SERVER=new d4xSndServer;
SOUND_SERVER->init_sounds();
/* setting up signal handlers */
struct sigaction action,old_action;
action.sa_handler=SigactionHandler(my_main_quit);
action.sa_flags=0;//SA_NOCLDSTOP;
sigaction(SIGINT,&action,&old_action);
sigaction(SIGTERM,&action,&old_action);
action.sa_flags=0;
action.sa_handler=SigactionHandler(_sig_pipe_handler_);
sigaction(SIGPIPE,&action,&old_action);
sigset_t oldmask,newmask;
sigemptyset(&newmask);
sigaddset(&newmask,SIGINT);
sigaddset(&newmask,SIGTERM);
pthread_sigmask(SIG_UNBLOCK,&newmask,&oldmask);
server=new tMsgServer;
if (server->init()){
perror(_("Can't init control socket!\n"));
delete(server);
return(-1);
};
FaceForPasswords=new tFacePass;
FaceForPasswords->load();
return(0);
};
void create_new_queue(char *name,d4xDownloadQueue *papa){
d4xDownloadQueue *q=new d4xDownloadQueue;
q->name.set(name);
if (papa){
q->inherit_settings(papa);
papa->subq_add(q);
}else{
if (D4X_QTREE.last())
q->inherit_settings((d4xDownloadQueue*)D4X_QTREE.last(),CFG.GLOBAL_SAVE_PATH);
D4X_QTREE.insert(q);
};
if (CFG.WITHOUT_FACE==0){
q->qv.init();
q->init_pixmaps();
D4X_QVT->add(q,papa);
if (!D4X_QUEUE) D4X_QVT->switch_remote(q);
}else{
if (!D4X_QUEUE) D4X_QUEUE=q;
};
};
void tMain::init_qtree(tQueue *list,d4xDownloadQueue *papa){
d4xDownloadQueue *q=(d4xDownloadQueue *)(list->first());
while(q){
if (q->SpdLmt)
SpeedScheduler->insert(q);
q->parent=papa;
if (CFG.WITHOUT_FACE==0){
D4X_QVT->add(q,papa);
if (q->IamDefault)
D4X_QVT->switch_remote(q);
}else{
if (q->IamDefault){
D4X_QUEUE=q;
};
};
init_qtree(&(q->child),q);
try_to_run_run(q);
try_to_run_wait(q);
q=(d4xDownloadQueue *)(q->prev);
};
};
void tMain::load_defaults() {
MainLog->add(_("Loading default list of downloads"),LOG_OK|LOG_DETAILED);
read_list();
if (D4X_QTREE.count()){
init_qtree(&D4X_QTREE);
if (!D4X_QUEUE){
d4xDownloadQueue *q=(d4xDownloadQueue *)(D4X_QTREE.first());
if (CFG.WITHOUT_FACE){
D4X_QUEUE=q;
}else{
D4X_QVT->switch_remote(q);
};
};
}else{
create_new_queue("Main");
};
if (!CFG.WITHOUT_FACE)
D4X_QUEUE->qv.set_shift(CFG.CLIST_SHIFT);
};
void tMain::init_main_log() {
MainLog=new tMLog;
MainLog->init(CFG.MAX_MAIN_LOG_LENGTH);
if (CFG.WITHOUT_FACE==0)
MainLog->init_list(GTK_TREE_VIEW(MainLogList));
MainLog->reinit_file();
MainLog->add("----------------------------------------",LOG_FROM_SERVER);
};
void tMain::redraw_logs() {
int limit = 12;
GList *tmplist=NULL;
while (limit>0) {
limit--;
tLogMsg *Msg=(tLogMsg*)MsgQueue->first();
if (Msg) {
if (Msg->type&MQT_MY){
if (Msg->what){
if (Msg->which->freezed_flag==0){
tmplist=log_window_freeze(tmplist,Msg->which);
};
log_window_add_string(Msg->which,Msg->what);
}else{
del_first_from_log(Msg->which);
};
};
if (Msg->type&MQT_COM){
if (Msg->what){
if (Msg->which==D4X_LOG_DISPLAY.log)
d4x_main_log_add_string(Msg->what);
}else{
if (Msg->which==D4X_LOG_DISPLAY.log)
d4x_main_log_del_string();
};
};
Msg->which->unlock();
Msg->which->ref_dec();
MsgQueue->del(Msg);
delete(Msg);
}else
break;
};
while(tmplist){
tmplist=log_window_unfreeze(tmplist);
};
};
void tMain::absolute_delete_download(tDownload *what) {
DBC_RETURN_IF_FAIL(what!=NULL);
if (CFG.WITHOUT_FACE==0 && D4X_LOG_DISPLAY.papa==what)
D4X_LOG_DISPLAY.papa=NULL;
DQV(what).remove(what);
d4xDownloadQueue *q=what->myowner->PAPA;
q->del(what);
ALL_DOWNLOADS->del(what);
FaceForPasswords->stop_matched(what);
delete(what);
};
void tMain::del_completed(d4xDownloadQueue *queue) {
MainLog->add(_("Delete completed downloads"),LOG_OK|LOG_DETAILED);
del_all_from_list(DL_COMPLETE,queue);
};
void tMain::rerun_failed(){
tDownload *temp=D4X_QUEUE->first(DL_STOP);
while (temp) {
continue_download(temp);
temp=D4X_QUEUE->first(DL_STOP);
};
};
void tMain::del_fataled(d4xDownloadQueue *queue){
MainLog->add(_("Delete failed downloads"),LOG_OK|LOG_DETAILED);
del_all_from_list(DL_STOP,queue);
};
void tMain::del_all_from_list(int list,d4xDownloadQueue *queue){
tDownload *temp=queue?queue->first(list):D4X_QUEUE->first(list);
while (temp) {
tDownload *next=(tDownload *)(temp->prev);
if (!temp->protect){
absolute_delete_download(temp);
};
temp=next;
};
};
void tMain::del_all() {
if (D4X_QUEUE->count())
MainLog->add(_("Clear queue of downloads"),LOG_ERROR);
tDownload *temp=D4X_QUEUE->first(DL_RUN);
while (temp) {
stop_download(temp);
temp=D4X_QUEUE->first(DL_RUN);
};
temp=D4X_QUEUE->first(DL_STOPWAIT);
while (temp) {
if (!temp->protect)
temp->action=ACTION_DELETE;
temp=(tDownload *)(temp->prev);
};
del_all_from_list(DL_PAUSE);
del_all_from_list(DL_WAIT);
del_all_from_list(DL_STOP);
del_all_from_list(DL_COMPLETE);
del_all_from_list(DL_LIMIT);
};
int tMain::run_new_thread(tDownload *what) {
DBC_RETVAL_IF_FAIL(what!=NULL,-1);
pthread_attr_t attr_p;
what->status=READY_TO_RUN;
what->STOPPED_BY_USER=false;
if (!what->LOG) {
what->LOG=new tLog;
what->LOG->ref_inc();
if (CFG.WITHOUT_FACE)
what->LOG->init(2); // two strings in log if run without interface
else
what->LOG->init(CFG.MAX_LOG_LENGTH);
};
if (what->info.proto==D_PROTO_SEARCH){
what->WL=new tMemoryWL;
((tMemoryWL *)(what->WL))->set_log(what->LOG);
}else{
what->WL=new tDefaultWL;
((tDefaultWL *)(what->WL))->set_log(what->LOG);
};
what->update_trigers();
what->config->redirect_count=0;
what->Size.reset(); // no need update size
if (what->SpeedLimit==NULL) what->SpeedLimit=new d4x::Speed;
/* set speed limitation */
if (what->split && what->split->NumOfParts){
what->SpeedLimit->base = what->config->speed/what->split->NumOfParts;
}else{
what->SpeedLimit->base = what->config->speed;
};
what->set_initial_speedlimit();
SpeedScheduler->insert(what->SpeedLimit);
if (what->editor) what->editor->disable_ok_button();
MainLog->myprintf(LOG_OK|LOG_DETAILED,_("Run new thread for %z"),what);
pthread_attr_init(&attr_p);
pthread_attr_setdetachstate(&attr_p,PTHREAD_CREATE_JOINABLE);
pthread_attr_setscope(&attr_p,PTHREAD_SCOPE_SYSTEM);
if (pthread_create(&what->thread_id,&attr_p,download_last,(void *)what)){
MainLog->add(_("Can't run new thread for downloading!"),LOG_ERROR);
return(-1);
};
return(0);
};
void tMain::stop_split(tDownload *what){
DBC_RETURN_IF_FAIL(what!=NULL);
tDownload *tmp=what->split->next_part;
int a=1;
while(tmp){
a++;
if (tmp->split->run)
stop_thread(tmp);
else
what->split->stopcount+=1;
tmp=tmp->split?tmp->split->next_part:NULL;
};
what->split->stopcount+=what->split->NumOfParts-a;
};
tDownload *tMain::find_url(const d4x::URL &adr){
tDownload tmp;
tmp.info=adr;
tDownload *a=ALL_DOWNLOADS->find(&tmp);
return(a);
};
void tMain::stop_download_url(const d4x::URL &adr){
tDownload *a=find_url(adr);
if (a) stop_download(a);
};
void tMain::continue_download_url(const d4x::URL &adr){
tDownload *a=find_url(adr);
if (a) continue_download(a);
};
void tMain::delete_download_url(const d4x::URL &adr){
tDownload *a=find_url(adr);
if (a) delete_download(a);
};
void tMain::stop_download(tDownload *what) {
DBC_RETURN_IF_FAIL(what!=NULL);
int owner=what->owner();
if (owner==DL_STOPWAIT && what->action!=ACTION_DELETE) {
what->action=ACTION_STOP;
return;
};
d4xDownloadQueue *papa=what->myowner->PAPA;
if (papa->is_first(DL_SIZEQUERY,what)){
stop_thread(what);
return;
};
if (owner==DL_RUN) {
papa->del(what);
MainLog->myprintf(LOG_WARNING,_("Downloading of file %s from %s was terminated [by user]"),
what->info.file.c_str(),
what->info.host.c_str());
stop_thread(what);
if (what->split)
stop_split(what);
papa->add(what,DL_STOPWAIT);
what->ActStatus.clear();
} else {
if (owner==DL_WAIT || owner==DL_LIMIT || owner==DL_SIZEQUERY) {
what->sizequery=0;
FaceForPasswords->stop_matched(what);
papa->del(what);
papa->add(what,DL_PAUSE);
what->ActStatus.clear();
try_to_run_wait(papa);
};
};
};
int tMain::delete_download(tDownload *what,int flag) {
if (!what) return 0;
if (what->protect) return 0;
if (what->owner()==DL_RUN)
stop_download(what);
d4xDownloadQueue *papa=what->myowner->PAPA;
if (papa->is_first(DL_SIZEQUERY,what)){
papa->del(what);
stop_thread(what);
papa->add(what,DL_STOPWAIT);
what->action=ACTION_DELETE;
sizequery_run_first(papa);
return(0);
};
if (what->owner()==DL_STOPWAIT){
if (flag)
what->action=ACTION_REAL_DELETE;
else
what->action=ACTION_DELETE;
return 0;
};
MainLog->myprintf(LOG_WARNING,_("Delete file %s from queue of downloads"),what->info.file.c_str());
if (flag)
what->remove_tmp_files();
absolute_delete_download(what);
return 1;
};
void tMain::try_to_run_split(tDownload *what){
DBC_RETURN_IF_FAIL(what!=NULL);
if (what->split->runcount>=what->split->NumOfParts) return;
if (what->status==DOWNLOAD_GO || what->status==DOWNLOAD_COMPLETE){
tDownload *dwn=what->split->next_part;
while (dwn && FaceForPasswords->limit_check(what)==0){
if (dwn->split->run==0){
if (run_new_thread(dwn)) return;
dwn->split->run=1;
what->split->runcount+=1;
FaceForPasswords->limit_inc(what);
};
dwn=dwn->split->next_part;
};
};
};
int tMain::try_to_run_download(tDownload *what){
DBC_RETVAL_IF_FAIL(what!=NULL,-1);
time_t NOW;
time(&NOW);
d4xDownloadQueue *papa=what->myowner->PAPA;
if (papa->count(DL_RUN)<50) {
what->SpeedCalc.reset();
what->Start=what->Pause=time(NULL);
if (what->config==NULL){
what->config=new tCfg;
what->set_default_cfg();
};
// to avoid old info in columns
if (CFG.WITHOUT_FACE==0)
DQV(what).change_data(what->list_iter,PAUSE_COL);
if (what->split){
what->finfo.size=-1;
what->split->FirstByte=0;
what->split->LastByte=-1;
what->split->reset();
what->config->rollback=0;
// what->config->ftp_recurse_depth = 1;
what->split->grandparent=what;
// what->config->http_recurse_depth = 1;
};
if (run_new_thread(what)) return -1;
if (what->split){
what->split->runcount=1;
what->split->run=1;
};
return 1;
};
return 0;
};
void tMain::insert_into_wait_list(tDownload *what,
d4xDownloadQueue *dq){
if (CFG.WITHOUT_FACE){
dq->add(what);
}else{
tDownload *temp=dq->last(DL_WAIT);
if (!temp || dq->qv.get_row_num(temp) < dq->qv.get_row_num(what))
dq->add(what);
else {
temp=dq->first(DL_WAIT);
while (temp && dq->qv.get_row_num(temp) < dq->qv.get_row_num(what))
temp=(tDownload*)(temp->prev);
dq->insert_before(what,temp);
};
D4X_QVT->update(dq);
};
};
void tMain::continue_download(tDownload *what) {
if (CFG.OFFLINE_MODE) return;
if (!what) return;
switch (what->owner()) {
case DL_SIZEQUERY:
break;
case DL_STOPWAIT:
if (what->action!=ACTION_DELETE &&
what->action!=ACTION_REAL_DELETE)
what->action=ACTION_CONTINUE;
break;
case DL_RUN:
stop_download(what);
if (what->owner()==DL_STOPWAIT){
what->action=ACTION_CONTINUE;
break;
};
default:
MainLog->myprintf(LOG_OK,_("Continue downloading of file %s from %s..."),
what->info.file.c_str(),
what->info.host.c_str());
d4xDownloadQueue *papa=what->myowner->PAPA;
if (CFG.ALLOW_FORCE_RUN && what->owner()!=DL_PAUSE && try_to_run_download(what)) {
papa->del(what);
papa->add(what,DL_RUN);
} else {
papa->del(what);
insert_into_wait_list(what,papa);
try_to_run_wait(papa);
};
};
what->Attempt.clear();
what->finfo.size=-1;
};
void tMain::add_dir(tDownload *parent,int http) {
if (parent==NULL || parent->DIR==NULL) return;
tDownload *temp=parent->DIR->last();
d4xDownloadQueue *q=D4X_QUEUE;
D4X_QUEUE=parent->myowner->PAPA;
while(temp) {
parent->DIR->del(temp);
int totop=parent->config->ftp_dirontop && temp->finfo.type==T_DIR;
tDownload *ex=add_downloading(temp,totop);
if (ex) {
if (ex->config && ex->config->http_recurse_depth<temp->config->http_recurse_depth &&
ex->myowner==parent->myowner){
ex->config->http_recurse_depth=temp->config->http_recurse_depth;
continue_download(ex);
};
delete temp;
};
temp=parent->DIR->last();
};
D4X_QUEUE=q;
};
void tMain::speed_calculation(tDownload *what){
DBC_RETURN_IF_FAIL(what!=NULL);
time_t NOWTMP;
time(&NOWTMP);
switch(what->finfo.type) {
case T_FILE:{
time_t newdiff=NOWTMP-what->Start;
time_t difdif=what->Difference-newdiff;
/* detecting clock skew */
if (difdif<-1800)
what->Start+=difdif;
else if (difdif>1800)
what->Start-=difdif;
what->Difference=NOWTMP-what->Start;
int REAL_SIZE=what->finfo.size;
if (REAL_SIZE==0 && what->who!=NULL)
what->finfo.size=REAL_SIZE=what->who->another_way_get_size();
if (what->who) what->Size=what->get_loaded();
what->Remain=REAL_SIZE-what->Size;
if (what->Difference!=0 && what->who) {
what->Speed=what->SpeedCalc.speed();
};
};
};
};
void tMain::print_info(tDownload *what) {
DBC_RETURN_IF_FAIL(what!=NULL);
if (CFG.WITHOUT_FACE){
speed_calculation(what);
return;
};
d4xDownloadQueue *PAPA=what->myowner->PAPA;
char data[MAX_LEN];
int downloading_started=0;
if (what->who) {
what->ActStatus=what->who->get_status();
if (what->ActStatus==D_DOWNLOAD ||
what->status==DOWNLOAD_COMPLETE ||
what->status==DOWNLOAD_FATAL){
downloading_started=1;
if (!what->who->reget())
what->ActStatus=D_DOWNLOAD_BAD;
};
if (!what->ActStatus) {
what->ActStatus.reset();
// DQV(what).set_run_icon(what);
};
};
switch(what->finfo.type) {
case T_FILE:{
if (what->finfo.type!=what->finfo.oldtype)
DQV(what).change_data(what->list_iter,FILE_TYPE_COL,_("file"));
fsize_t REAL_SIZE=what->filesize();
DQV(what).change_data(what->list_iter,FULL_SIZE_COL,make_number_nice(REAL_SIZE,PAPA->NICE_DEC_DIGITALS));
what->Size=what->get_loaded();
what->Remain=REAL_SIZE-what->Size;
if (!what->Remain && what->Remain>=0)
DQV(what).change_data(what->list_iter,REMAIN_SIZE_COL,
make_number_nice(fsize_t(what->Remain),PAPA->NICE_DEC_DIGITALS));
time_t NOWTMP;
time(&NOWTMP);
if (what->Start>0) {
time_t newdiff=NOWTMP-what->Start;
time_t difdif=what->Difference-newdiff;
/* detecting clock skew */
if (difdif<-1800)
what->Start+=difdif;
else if (difdif>1800)
what->Start-=difdif;
what->Difference=NOWTMP-what->Start;
DQV(what).change_data(what->list_iter,TIME_COL,convert_time(newdiff,PAPA->TIME_FORMAT));
};
if (!what->Size) {
DQV(what).change_data(what->list_iter,DOWNLOADED_SIZE_COL,
make_number_nice(fsize_t(what->Size),PAPA->NICE_DEC_DIGITALS));
time_t Pause=NOWTMP;
if (Pause - what->Pause > 4)
DQV(what).change_data(what->list_iter,PAUSE_COL);
what->Pause = Pause;
} else {
if (what->status==DOWNLOAD_GO) {
int Pause=NOWTMP-what->Pause;
if (Pause>=30)
DQV(what).change_data(what->list_iter,PAUSE_COL,convert_time(Pause,PAPA->TIME_FORMAT));
};
};
what->Percent=100;
if (REAL_SIZE!=0)
what->Percent=float((fsize_t(what->Size)*double(100))/double(REAL_SIZE));
/* setting new title of log*/
if (CFG.USE_MAINWIN_TITLE){
char title[MAX_LEN];
std::string rfile=hexed_string(what->info.file);
sprintf(title,"%2.0f%% %lli/%lli %s",what->Percent,fsize_t(what->Size),REAL_SIZE,rfile.c_str());
log_window_set_title(what,title);
log_window_set_split_info(what);
};
DQV(what).set_run_icon(what);
if (!what->Size) {
DQV(what).set_percent(what->list_iter,what->Percent);
};
what->Size.reset();
/* Speed calculation
*/
if (what->Difference!=0 && what->who) {
what->Speed=what->SpeedCalc.speed();
if (!what->Speed){
DQV(what).change_data(what->list_iter,SPEED_COL,
make_number_nice(fsize_t(what->Speed),PAPA->SPEED_FORMAT?2:0));
what->Speed.reset();
};
if (what->finfo.size>0 && what->Speed>0){
fsize_t tmp=(REAL_SIZE-what->Size)/what->Speed;
if (tmp>=0 && tmp<24*3660) {
DQV(what).change_data(what->list_iter,ELAPSED_TIME_COL,
convert_time(tmp,PAPA->TIME_FORMAT));
} else
DQV(what).change_data(what->list_iter,ELAPSED_TIME_COL,"...");
} else
DQV(what).change_data(what->list_iter,ELAPSED_TIME_COL,"...");
};
break;
};
case T_DIR:{
if (what->finfo.type!=what->finfo.oldtype)
DQV(what).change_data(what->list_iter,FILE_TYPE_COL,_("dir"));
break;
};
case T_LINK:{
if (what->finfo.type!=what->finfo.oldtype)
DQV(what).change_data(what->list_iter,FILE_TYPE_COL,_("link"));
break;
};
case T_DEVICE:{
if (what->finfo.type!=what->finfo.oldtype)
DQV(what).change_data(what->list_iter,FILE_TYPE_COL,_("device"));
break;
};
default:
if (what->finfo.type!=what->finfo.oldtype)
DQV(what).change_data(what->list_iter,FILE_TYPE_COL,"???");
};
if (what->finfo.type==T_DIR || what->finfo.type==T_NONE){
if (what->who) what->Size=what->who->get_readed();
if (!what->Size) {
DQV(what).change_data(what->list_iter,DOWNLOADED_SIZE_COL,
make_number_nice(fsize_t(what->Size),PAPA->NICE_DEC_DIGITALS));
what->Size.reset();
};
};
if (!what->Attempt) {
what->Attempt.reset();
if (what->config->number_of_attempts > 0)
DQV(what).change_data(what->list_iter,TREAT_COL,
boost::lexical_cast<std::string>(fsize_t(what->Attempt))+"/"+
boost::lexical_cast<std::string>(what->config->number_of_attempts));
else
DQV(what).change_data(what->list_iter,TREAT_COL,boost::lexical_cast<std::string>(fsize_t(what->Attempt)));
};
what->finfo.oldtype=what->finfo.type;
};
void tMain::redirect(tDownload *what,d4xDownloadQueue *dq) {
DBC_RETURN_IF_FAIL(what!=NULL);
what->config->redirect_count+=1;
if (what->config->redirect_count>10){
what->delete_who();
MainLog->myprintf(LOG_ERROR,_("Too many redirections!"),what);
dq->add(what,DL_COMPLETE);
what->finfo.type=T_NONE;
return;
};
d4x::URL addr=what->redirect_url();
if (addr.is_valid()) {
/*
if (what->config->leave_server==0 && equal_uncase(addr->host.get(),what->info->host.get())==0){
MainLog->myprintf(LOG_ERROR,_("Redirection from [%z] to the different host forbidden by download's preferences!"),what);
D4X_QUEUE->add(what,DL_COMPLETE);
delete(addr);
return;
};
*/
if (addr==what->info && equal(what->config->referer.get(),std::string(what->info).c_str())){
MainLog->myprintf(LOG_ERROR,_("Redirection from [%z] to the same location!"),what);
dq->add(what,DL_COMPLETE);
return;
};
if (ALL_DOWNLOADS->find(addr)) {
dq->add(what,DL_COMPLETE);
return;
};
ALL_DOWNLOADS->del(what);
what->config->referer.set(std::string(what->info).c_str());
if (addr.file==what->info.file)
what->restart_from_begin=1;
what->info=addr;
ALL_DOWNLOADS->insert(what);
tDownload *temp=dq->first(DL_WAIT);
if (temp)
dq->insert_before(what,temp);
else
dq->add(what,DL_WAIT);
// normalize_path(what->get_SavePath());
what->finfo.type=what->status=0;
what->finfo.size=-1;
if (CFG.WITHOUT_FACE==0){
dq->qv.change_data(what->list_iter,URL_COL,what->info);
dq->qv.set_filename(what);
for (int i=FILE_TYPE_COL;i<PERCENT_COL;i++)
if (i!=PERCENT_COL)
DQV(what).change_data(what->list_iter,i,"");
};
}else{
MainLog->myprintf(LOG_ERROR,_("Redirection from [%z] to nowhere!"),what);
dq->add(what,DL_COMPLETE);
what->finfo.type=T_NONE;
};
what->delete_who();
};
void tMain::post_stopping(tDownload *what){
/* dispose tSegmentator only for main thread */
if (what->segments){
delete(what->segments);
what->segments=NULL;
};
if (what->split && what->split->cond){
delete(what->split->cond);
what->split->cond=NULL;
};
if (what->config->isdefault && what->editor==NULL){
delete(what->config);
what->config=NULL;
};
if (what->editor) what->editor->enable_ok_button();
FaceForPasswords->stop_matched(what);
};
void tMain::prepare_for_stoping_pre(tDownload *what){
MainLog->myprintf(LOG_OK|LOG_DETAILED,_("Prepare thread %i of [%z] for stoping"),what->split?what->split->thread_num:1,what);
if (what->SpeedLimit) SpeedScheduler->del(what->SpeedLimit);
delete (what->SpeedLimit);
what->SpeedLimit=NULL;
if (what->WL){
delete(what->WL);
what->WL=NULL;
};
};
void tMain::prepare_for_stoping(tDownload *what) {
DBC_RETURN_IF_FAIL(what!=NULL);
prepare_for_stoping_pre(what);
if (what->split){
what->split->grandparent->split->stopcount+=1;
FaceForPasswords->limit_dec(what->split->grandparent);
// what->split->run=0;
}else
FaceForPasswords->limit_dec(what);
};
void tMain::case_download_completed(tDownload *what){
DBC_RETURN_IF_FAIL(what!=NULL);
d4xDownloadQueue *papa=what->myowner->PAPA;
papa->del(what);
if (what->finfo.type==T_REDIRECT) {
MainLog->myprintf(LOG_OK,_("Redirect from %z"),what);
redirect(what,papa);
real_stop_thread(what);
post_stopping(what);
}else{
papa->add(what,DL_COMPLETE);
if (what->file_type()==T_DIR) {
MainLog->myprintf(LOG_OK,_("Downloading of directory %z was completed"),what);
if (what->config->ftp_recurse_depth!=1) add_dir(what);
} else {
fsize_t bytes = what->finfo.size==0 ? what->who->get_readed():what->finfo.size;
MainLog->myprintf(LOG_OK,_("Downloading of file %z (%ll bytes) was completed at speed %ll bytes/sec"),what,bytes,fsize_t(what->Speed));
if (what->config->http_recurse_depth!=1 && what->DIR)
add_dir(what,1);
};
real_stop_thread(what);
post_stopping(what);
if (papa->AUTODEL_COMPLETED && what->protect==0) {
MainLog->myprintf(LOG_WARNING|LOG_DETAILED,_("%z was deleted from queue of downloads as completed download"),what);
absolute_delete_download(what);
};
};
};
void tMain::case_download_failed(tDownload *what){
DBC_RETURN_IF_FAIL(what!=NULL);
d4xDownloadQueue *papa=what->myowner->PAPA;
papa->del(what);
papa->add(what,DL_STOP);
MainLog->myprintf(LOG_ERROR,_("Downloading of file %z was terminated by fatal error"),what);
if (papa->AUTODEL_FAILED && what->protect==0) {
MainLog->myprintf(LOG_WARNING|LOG_DETAILED,_("%z was deleted from queue of downloads as failed download"),what);
absolute_delete_download(what);
};
};
void tMain::main_circle_first(tDownload *dwn){
/* look for stopped threads */
tDownload *grandpapa=dwn;
prepare_for_stoping(dwn);
real_stop_thread(dwn);
if (dwn->split){
grandpapa=dwn->split->grandparent;
if (grandpapa->split->stopcount!=grandpapa->split->NumOfParts &&
grandpapa->split->prepared)
return;
};
int status=grandpapa->status;
post_stopping(grandpapa);
d4xDownloadQueue *papa=grandpapa->myowner->PAPA;
if (status==DOWNLOAD_REAL_STOP ||
status==DOWNLOAD_COMPLETE ||
status==DOWNLOAD_FATAL) {
papa->del(grandpapa);
papa->add(grandpapa,DL_PAUSE);
switch(grandpapa->action){
case ACTION_REAL_DELETE:
delete_download(grandpapa,1);
break;
case ACTION_DELETE:
delete_download(grandpapa,0);
break;
case ACTION_CONTINUE:
continue_download(grandpapa);
grandpapa->action=ACTION_NONE;
break;
case ACTION_STOP:
grandpapa->action=ACTION_NONE;
break;
case ACTION_FAILED:
grandpapa->action=ACTION_NONE;
papa->del(grandpapa);
papa->add(grandpapa,DL_STOP);
break;
case ACTION_SIZEQUERY:
move_to_sizequery(grandpapa);
break;
};
};
};
static bool _alt_equal_host_(tDownload *dwn,d4x::Alt *alt){
return alt->info.host==dwn->info.host;
};
int tMain::try_to_switch(tDownload *dwn){
if (dwn->ALTS==0 || dwn->ALTS->LST.empty()) return(0);
d4xAltList *ALTS=dwn->ALTS;
std::list<d4x::Alt*>::iterator alt=std::find_if(ALTS->LST.begin(),
ALTS->LST.end(),
std::bind1st(std::ptr_fun(_alt_equal_host_),dwn));
if (alt!=ALTS->LST.end()) alt++;
if (alt==ALTS->LST.end()){
// first switching, add this url to its own alternates
d4x::Alt *newalt=new d4x::Alt;
newalt->info=dwn->info;
dwn->ALTS->lock.lock();
dwn->ALTS->add(newalt);
dwn->ALTS->lock.unlock();
alt=ALTS->LST.begin();
};
if (ALL_DOWNLOADS->find((*alt)->info)){
return(0);
};
ALL_DOWNLOADS->del(dwn);
dwn->info=(*alt)->info;
ALL_DOWNLOADS->insert(dwn);
FaceForPasswords->set_do_not_run(1);
prepare_for_stoping(dwn);
real_stop_thread(dwn);
if (run_new_thread(dwn))
return(0);
FaceForPasswords->limit_inc(dwn);
FaceForPasswords->set_do_not_run(0);
if (dwn->split) dwn->split->stopcount-=1;
return(1);
};
int tMain::try_to_switch_split(tDownload *dwn,tDownload *gp){
if (gp==dwn) return(try_to_switch(dwn));
if (gp->ALTS==NULL || gp->ALTS->LST.empty()) return(0);
int n=dwn->split->alt+1;
std::list<d4x::Alt*>::iterator alt=gp->ALTS->LST.begin();
advance(alt,n);
if (alt!=gp->ALTS->LST.end()){
dwn->split->alt+=1;
dwn->info=(*alt)->info;
}else{
dwn->info=gp->info;
};
dwn->split->run=0;
FaceForPasswords->set_do_not_run(1);
prepare_for_stoping(dwn);
gp->split->stopcount-=1; //to avoid wrong stopcount
real_stop_thread(dwn);
try_to_run_split(gp);
FaceForPasswords->set_do_not_run(0);
return(1);
};
void tMain::check_split(tDownload *dwn){
tDownload *grandparent=dwn->split->grandparent;
if (dwn->status==DOWNLOAD_FATAL){
if (try_to_switch_split(dwn,grandparent))
return;
stop_download(grandparent);
grandparent->action=ACTION_FAILED;
main_circle_first(dwn);
try_to_run_wait(grandparent->myowner->PAPA);
return;
};
if (grandparent->split->prepared){
// we need to check overlaping event here for splited downloads
// just find best part to download, and go! :-)
if (dwn->WL->is_overlaped() || dwn->status==DOWNLOAD_COMPLETE){
if (dwn->find_best_split() && dwn && dwn->who->reget()){
real_stop_thread(dwn);
prepare_for_stoping_pre(dwn);
dwn->split->cond->inc();
run_new_thread(dwn);
return;
};
};
prepare_for_stoping(dwn);
try_to_run_split(grandparent);
if (dwn!=grandparent) real_stop_thread(dwn);
if (grandparent->split->NumOfParts==grandparent->split->stopcount)
main_circle_second(grandparent);
}else{
try_to_run_split(grandparent);
if (grandparent->status==DOWNLOAD_COMPLETE ||
grandparent->status==DOWNLOAD_FATAL)
prepare_for_stoping(grandparent);
main_circle_second(grandparent);
};
};
void tMain::main_circle_second(tDownload *dwn){
/* look for completeted or faild threads */
int failed=0,completed=0;
d4xDownloadQueue *papa=dwn->myowner->PAPA;
dwn->status_cp=dwn->status;
switch(dwn->status) {
case DOWNLOAD_COMPLETE:{
if (dwn->segments)
dwn->segments->complete();
print_info(dwn); //to avoid wrong percentage after completing
case_download_completed(dwn);
completed=1;
break;
};
case DOWNLOAD_FATAL:{
if (dwn->split==NULL && try_to_switch(dwn)) return;
case_download_failed(dwn);
real_stop_thread(dwn);
post_stopping(dwn);
failed=1;
break;
};
};
int paparun=papa->count(DL_RUN);
if (paparun==0){
papa->speed.reset();
if (!CFG.WITHOUT_FACE)
D4X_QVT->update_speed(papa);
};
if (completed){
if (paparun==0 &&
papa->count(DL_WAIT)==0)
SOUND_SERVER->add_event(SND_QUEUE_FINISH);
else
SOUND_SERVER->add_event(SND_COMPLETE);
try_to_run_wait(papa);
};
if (failed){
try_to_run_wait(papa);
SOUND_SERVER->add_event(SND_FAIL);
};
};
void tMain::main_circle_nano1(){
int i=10;
D4X_UPDATE.lock();
while(D4X_UPDATE.first && i>0){
tDownload *dwn=D4X_UPDATE.first;
if (dwn->owner()==DL_RUN){
if (dwn->split)
try_to_run_split(dwn);
if (dwn->myowner->PAPA==D4X_QUEUE){
print_info(dwn);
};
if (dwn->myowner && dwn->myowner->PAPA && !CFG.WITHOUT_FACE)
D4X_QVT->update_speed(dwn->myowner->PAPA);
};
D4X_UPDATE.del();
i--;
};
D4X_UPDATE.unlock();
};
void tMain::main_circle_nano2(){
if (CFG.OFFLINE_MODE) return;
D4X_UPDATE.lock_s();
D4X_UPDATE.lock();
int i=0;
while (D4X_UPDATE.first_s){
tDownload *dwn=D4X_UPDATE.first_s;
tDownload *gp=dwn;
D4X_UPDATE.del_s();
D4X_UPDATE.del(dwn);
if (dwn->split)
gp=dwn->split->grandparent;
// printf("%p %p\n",dwn,gp);
switch(gp->owner()){
case DL_RUN:
if (dwn->split){
check_split(dwn);
break;
}else{
if (dwn->WL->is_overlaped() && dwn->status==DOWNLOAD_COMPLETE){
real_stop_thread(dwn);
prepare_for_stoping_pre(dwn);
run_new_thread(dwn);
break;
};
prepare_for_stoping(gp);
};
main_circle_second(gp);
break;
case DL_STOPWAIT:
main_circle_first(dwn);
break;
case DL_SIZEQUERY:{
real_stop_thread(dwn);
prepare_for_stoping(dwn);
d4xDownloadQueue *papa=dwn->myowner->PAPA;
print_info(dwn);
papa->del(dwn);
if (dwn->action==DL_WAIT || dwn->action==DL_SIZEQUERY){
dwn->sizequery=0;
insert_into_wait_list(dwn,papa);
}else{
papa->add(dwn,dwn->action);
};
sizequery_run_first(papa);
if (dwn->editor) dwn->editor->enable_ok_button();
break;
};
default:
break;
};
if (i++>5) break;
};
D4X_UPDATE.unlock();
D4X_UPDATE.unlock_s();
};
int tMain::set_auto_run(int a){
int old=DONTRY2RUN;
DONTRY2RUN=a;
return(old);
};
void tMain::try_to_run_run(d4xDownloadQueue *papa){
tDownload *temp=papa->first(DL_RUN);
while(temp) {
tDownload *temp_next=(tDownload *)(temp->prev);
int rvalue=try_to_run_download(temp);
if (rvalue<0){
papa->del(temp);
papa->add(temp,DL_WAIT);
}else{
FaceForPasswords->match_and_check(temp,1);
FaceForPasswords->limit_to_run(temp);
};
temp=temp_next;
};
};
void tMain::try_to_run_wait(d4xDownloadQueue *papa){
if (DONTRY2RUN) return;
tDownload *temp=papa->first(DL_WAIT);
while(temp && papa->count(DL_RUN)<papa->MAX_ACTIVE) {
tDownload *temp_next=(tDownload *)(temp->prev);
if (FaceForPasswords->match_and_check(temp)==0){
FaceForPasswords->limit_to_run(temp);
int rvalue=try_to_run_download(temp);
if (rvalue<0){
break;
};
if (rvalue) {
papa->del(temp);
papa->add(temp,DL_RUN);
};
};
temp=temp_next;
};
};
void tMain::main_circle() {
if (ftpsearch) ftpsearch->cycle();
speed();
MainScheduler->run(this);
if (CFG.WITHOUT_FACE==0){
prepare_buttons();
D4X_UPDATE.update(D4X_QUEUE->get_queue(DL_RUN));
};
GVARS.SOCKETS->kill_old();
};
void tMain::set_speed(int speed){
CFG.SPEED_LIMIT=speed;
if (CFG.SPEED_LIMIT>3) CFG.SPEED_LIMIT=3;
if (CFG.SPEED_LIMIT<1) CFG.SPEED_LIMIT=1;
if (CFG.WITHOUT_FACE==0) set_speed_buttons();
};
void tMain::check_for_remote_commands(){
int i=0;
while (!server->empty()){
d4x::RemoteCommand addnew=server->get_command();
switch (addnew.type){
case PACKET_RERUN_FAILED:{
MainLog->myprintf(LOG_FROM_SERVER|LOG_DETAILED,"%s %s",_("Restarting failed downloads"),_("[control socket]"));
rerun_failed();
break;
};
case PACKET_OPENLIST:{
create_addlinks_with_referer(addnew.params,CFG.LOCAL_SAVE_PATH);
break;
};
case PACKET_ADD_OPEN:{
if (CFG.WITHOUT_FACE==0){
if (addnew.params.size()>1)
init_add_dnd_window(addnew.params[0].c_str(),NULL,addnew.params[1].c_str());
else
init_add_dnd_window(addnew.params[0].c_str(),NULL);
};
break;
};
case PACKET_STOP:{
// MainLog->myprintf(LOG_FROM_SERVER,_("Stop the download via control socket [%s]"),addnew.params[0].c_str());
stop_download_url(d4x::URL(addnew.params[0]));
break;
};
case PACKET_DEL:{
MainLog->myprintf(LOG_FROM_SERVER,_("Remove the download via control socket [%s]"),addnew.params[0].c_str());
delete_download_url(d4x::URL(addnew.params[0]));
break;
};
case PACKET_ADD:{
TO_WAIT_IF_HERE=1;
MainLog->myprintf(LOG_FROM_SERVER,_("Adding downloading via control socket [%s]"),addnew.params[0].c_str());
if (addnew.params.size()>1)
add_downloading(addnew.params[0].c_str(),CFG.LOCAL_SAVE_PATH,0,0,addnew.params[1].c_str());
else
add_downloading(addnew.params[0].c_str(),CFG.LOCAL_SAVE_PATH);
TO_WAIT_IF_HERE=0;
break;
};
case PACKET_SET_SPEED_LIMIT:{
sscanf(addnew.params[0].c_str(),"%i",&CFG.SPEED_LIMIT);
set_speed(CFG.SPEED_LIMIT);
MainLog->myprintf(LOG_FROM_SERVER|LOG_DETAILED,_("Set speed limitation to %s %s"),
_(SPEED_LIMITATIONS_NAMES[CFG.SPEED_LIMIT]),
_("[control socket]"));
break;
};
case PACKET_SET_SAVE_PATH:{
/* to avoid misunderstandings we allow only absolute
pathes here
*/
if (addnew.params[0].c_str() && addnew.params[0].c_str()[0]=='/'){
delete[] CFG.LOCAL_SAVE_PATH;
CFG.LOCAL_SAVE_PATH=copy_string(addnew.params[0].c_str());
};
break;
};
case PACKET_SET_MAX_THREADS:{
sscanf(addnew.params[0].c_str(),"%i",&(D4X_QUEUE->MAX_ACTIVE));
if (D4X_QUEUE->MAX_ACTIVE>50) D4X_QUEUE->MAX_ACTIVE=50;
if (D4X_QUEUE->MAX_ACTIVE<0) D4X_QUEUE->MAX_ACTIVE=0;
MainLog->myprintf(LOG_FROM_SERVER|LOG_DETAILED,"%s %i %s",_("Setup maximum active downloads to"),D4X_QUEUE->MAX_ACTIVE,_("[control socket]"));
if (CFG.WITHOUT_FACE==0) D4X_QVT->update(D4X_QUEUE);
break;
};
case PACKET_DEL_COMPLETED:{
MainLog->myprintf(LOG_FROM_SERVER|LOG_DETAILED,"%s %s",_("Delete completed downloads"),_("[control socket]"));
del_all_from_list(DL_COMPLETE);
break;
};
case PACKET_MSG:
MainLog->myprintf(LOG_FROM_SERVER,"%s %s",addnew.params[0].c_str(),_("[control socket]"));
break;
case PACKET_ICONIFY:
if (CFG.WITHOUT_FACE==0) main_window_iconify();
break;
case PACKET_POPUP:
if (CFG.WITHOUT_FACE==0) main_window_popup();
break;
case PACKET_EXIT_TIME:{
int tmp;
if (addnew.params[0].c_str() && sscanf(addnew.params[0].c_str(),"%d",&tmp)){
if (tmp==0){
CFG.EXIT_COMPLETE=0;
MainLog->myprintf(LOG_FROM_SERVER,_("Exiting if nothing to do is switched off"),_("[control socket]"));
};
if (tmp>0){
CFG.EXIT_COMPLETE=1;
CFG.EXIT_COMPLETE_TIME=tmp;
MainLog->myprintf(LOG_FROM_SERVER,_("Downloader will exit if nothing to do after %i minutes %s"),tmp,_("[control socket]"));
};
};
break;
};
case PACKET_SWITCH_QUEUE:{
int num=0;
if (addnew.params[0].c_str() && sscanf(addnew.params[0].c_str(),"%d",&num)==1 && num>0){
d4xDownloadQueue *q=d4x_get_queue_num(num);
if (q){
if (CFG.WITHOUT_FACE==0){
D4X_QVT->switch_remote(q);
}else{
MainLog->myprintf(LOG_FROM_SERVER,_("Default queue is '%s' now."),q->name.get());
D4X_QUEUE=q;
};
};
};
break;
};
};
i+=1;
if (i>10) break;
};
};
//**********************************************/
void tMain::ftp_search(tDownload *what,int type){
DBC_RETURN_IF_FAIL(what!=NULL);
if (!what->info.file.empty()){
tDownload *tmp=new tDownload;
tmp->config=new tCfg;
tmp->fsearch=type;
tmp->set_default_cfg();
tmp->info=what->info;
tmp->finfo.size=what->finfo.size;
tmp->info.proto=D_PROTO_SEARCH;
if (tmp->split){
delete(tmp->split);
tmp->split=NULL;
};
ftpsearch->add(tmp);
};
};
void tMain::ftp_search_name(char *name){
if (name){
tDownload *tmp=new tDownload;
tmp->config=new tCfg;
tmp->fsearch=0;
tmp->set_default_cfg();
tmp->info.file=name;
tmp->finfo.size=-1;
tmp->info.proto=D_PROTO_SEARCH;
if (tmp->split){
delete(tmp->split);
tmp->split=NULL;
};
ftpsearch->add(tmp);
};
};
void tMain::ftp_search_reping(tDownload *what){
if (ftpsearch)
ftpsearch->reping(what);
};
void tMain::ftp_search_remove(tDownload *what){
if (ftpsearch)
ftpsearch->remove(what);
};
void tMain::schedule_download(tDownload *what){
if (what->owner()==DL_RUN || what->owner()==DL_STOPWAIT)
return;
DQV(what).remove(what);
ALL_DOWNLOADS->del(what);
what->myowner->PAPA->del(what);
if (what->LOG){
delete(what->LOG);
what->LOG=NULL;
};
if (what->split){
delete(what->split);
what->split=NULL;
};
MainScheduler->add_scheduled(what);
};
void tMain::sizequery_run_first(d4xDownloadQueue *q){
tDownload *torun=q->first(DL_SIZEQUERY);
if (torun){
if (torun->config==NULL){
torun->config=new tCfg;
torun->set_default_cfg();
};
if (torun->split)
torun->split->grandparent=torun;
run_new_thread(torun);
};
};
void tMain::move_to_sizequery(tDownload *what){
if (CFG.OFFLINE_MODE) return;
if (what==NULL) return;
if (what->owner()==DL_STOPWAIT){
what->action=ACTION_SIZEQUERY;
return;
};
int owner=what->owner();
if (owner!=DL_SIZEQUERY && owner!=DL_RUN){
d4xDownloadQueue *papa=what->myowner->PAPA;
what->action=owner;
papa->del(what);
papa->add(what,DL_SIZEQUERY);
what->sizequery=1;
if (papa->count(DL_SIZEQUERY)==1)
sizequery_run_first(papa);
};
};
tDownload *tMain::add_downloading(tDownload *what,int to_top) {
tDownload *tdwn=NULL;
if ((tdwn=ALL_DOWNLOADS->find(what)) || !what->info.is_valid()) {
printf("%s\n",std::string(what->info).c_str());
if (TO_WAIT_IF_HERE && tdwn && tdwn->owner()!=DL_RUN){
continue_download(tdwn);
};
return(tdwn);
};
if (what->ScheduleTime){
MainScheduler->add_scheduled(what);
return(NULL);
};
if (what->config==NULL){
FaceForPasswords->set_cfg(what);
};
ALL_DOWNLOADS->insert(what);
tDownload *f=D4X_QUEUE->first(DL_WAIT);
if (to_top && f)
D4X_QUEUE->insert_before(what,f);
else
D4X_QUEUE->add(what);
if (to_top)
D4X_QUEUE->qv.add_first(what);
else
D4X_QUEUE->qv.add(what);
try_to_run_wait(D4X_QUEUE);
return(NULL);
};
tDownload *tMain::add_downloading_to(tDownload *what,int to_top) {
DBC_RETVAL_IF_FAIL(what!=NULL,NULL);
int owner=what->status;
if (what->ScheduleTime){
MainScheduler->add_scheduled(what);
return NULL;
};
if (owner>DL_ALONE && owner<DL_TEMP){
DONTRY2RUN=1;
if (add_downloading(what,to_top)){
tDownload *dwn=ALL_DOWNLOADS->find(what);
// if (dwn && CFG.WITHOUT_FACE==0 && CFG.NEED_DIALOG_FOR_DND==0){
// D4X_QVT->move_to(dwn);
// };
delete (what);
DONTRY2RUN=0;;
return dwn;
};
switch(owner){
case DL_RUN:{
if (try_to_run_download(what)){
D4X_QUEUE->del(what);
D4X_QUEUE->add(what,DL_RUN);
};
break;
};
case DL_STOPWAIT:
case DL_STOP:{
D4X_QUEUE->del(what);
D4X_QUEUE->add(what,DL_STOP);
break;
};
case DL_COMPLETE:{
D4X_QUEUE->del(what);
D4X_QUEUE->add(what,DL_COMPLETE);
break;
};
case DL_PAUSE:{
D4X_QUEUE->del(what);
D4X_QUEUE->add(what,DL_PAUSE);
break;
};
};
DONTRY2RUN=0;
try_to_run_wait(D4X_QUEUE);
}else{
delete(what);
};
return(NULL);
};
int tMain::add_downloading(const char *adr,char *where,char *name,char *desc,const char *referer) {
if (adr==NULL) return -1;
// if (!addr->is_valid()) return -1;
tDownload *whatadd=new tDownload;
whatadd->info=std::string(adr);
if (where && *where) {
whatadd->config=new tCfg;
whatadd->set_default_cfg();
whatadd->config->save_path.set(where);
whatadd->config->isdefault=0;
};
if (referer && *referer){
if (whatadd->config==0){
whatadd->config=new tCfg;
whatadd->set_default_cfg();
whatadd->config->isdefault=0;
};
whatadd->config->referer.set(referer);
};
if (whatadd->info.file.empty()) {
whatadd->finfo.type=T_DIR;
whatadd->finfo.size=0;
};
// normalize_path(whatadd->get_SavePath());
if (name && strlen(name) && whatadd->config){
whatadd->Name2Save=name;
};
whatadd->Description.set(desc);
if (add_downloading(whatadd)) {
delete(whatadd);
return -1;
};
return 0;
};
unsigned int tMain::get_precise_time(){
#if (defined(BSD) && (BSD >= 199306))
struct timeval tp;
gettimeofday(&tp, NULL);
return(tp.tv_sec*1000+tp.tv_usec/1000);
#else
struct timeb tp;
ftime(&tp);
return(tp.time*1000+tp.millitm);
#endif
};
void tMain::speed() {
unsigned int curent_time=get_precise_time();
unsigned int TimeLeft=curent_time-LastTime;
tMeter::BSize readed_bytes=GVARS.READED_BYTES;
tMeter::BSize bytes=readed_bytes-LastReadedBytes;
if (TimeLeft!=0){
int Speed=((bytes*1000)/TimeLeft);
LastReadedBytes=readed_bytes;
GlobalMeter->add(Speed);
GraphMeter->add(Speed);
LastTime=curent_time;
};
int SPEED_LIMIT=0;
switch (CFG.SPEED_LIMIT) {
case 1: {
SPEED_LIMIT=(TimeLeft*CFG.SPEED_LIMIT_1)/1000;
break;
};
case 2: {
SPEED_LIMIT=(TimeLeft*CFG.SPEED_LIMIT_2)/1000;
break;
};
case 3:
default:{
SPEED_LIMIT=0;
};
};
if (SPEED_LIMIT){
// SPEED_LIMIT+=(prev_speed_limit-bytes)/2;
if (SPEED_LIMIT>0)
SpeedScheduler->schedule(SPEED_LIMIT,1);
}else
SpeedScheduler->schedule(TimeLeft);
prev_speed_limit=SPEED_LIMIT;
};
void tMain::run(int argv,char **argc) {
SOUND_SERVER->run_thread();
if (CFG.WITHOUT_FACE==0){
if (CFG.USE_THEME && CFG.THEME_FILE){
char *tmp=sum_strings(CFG.THEMES_DIR,"/",CFG.THEME_FILE,".xml",NULL);
D4X_THEME_DATA=d4x_xml_parse_file(tmp);
delete[] tmp;
};
ftpsearch=new tFtpSearchCtrl;
init_face(argv,argc);
ftpsearch->init(FSearchView,this,MainLog);
fs_list_set_size();
};
init_main_log();
MainLog->add(VERSION_NAME,LOG_WARNING);
COOKIES=new tCookiesTree;
COOKIES->load_cookies();
load_defaults();
if (CFG.WITHOUT_FACE==0){
prepare_buttons();
init_timeouts();
};
parse_command_line_postload(argv,argc);
server->run_thread();
LastTime=get_precise_time();
var_check_all_limits();
MainLog->add(_("Loading FTP-Search engines"),LOG_WARNING);
D4X_SEARCH_ENGINES.load();
MainLog->add(_("Normally started"),LOG_WARNING);
check_for_remote_commands();
GlobalMeter->set_mode(CFG.GRAPH_MODE);
GraphMeter->set_mode(CFG.GRAPH_MODE);
MainScheduler->clear_old();
if (CFG.WITHOUT_FACE==0){
SOUND_SERVER->add_event(SND_STARTUP);
gtk_main();
}else{
run_without_face();
};
};
void tMain::run_without_face(){
int TIME_FOR_SAVING=CFG.SAVE_LIST_INTERVAL * 60;
int COMPLETE_INTERVAL=CFG.EXIT_COMPLETE_TIME * 60;
struct timespec ival={0,200000000};
int i=0;
while(1){
check_for_remote_commands();
main_circle_nano2();
if (i++>=5){
main_circle();
i=0;
};
nanosleep(&ival,NULL);
// sleep(1);
TIME_FOR_SAVING-=1;
if (!TIME_FOR_SAVING) {
if (CFG.SAVE_LIST) {
save_list();
};
TIME_FOR_SAVING=CFG.SAVE_LIST_INTERVAL * 60;
};
if (CFG.EXIT_COMPLETE && d4x_run_or_wait_downloads()==0){
COMPLETE_INTERVAL-=1;
if (COMPLETE_INTERVAL<0){
break;
};
}else{
COMPLETE_INTERVAL=CFG.EXIT_COMPLETE_TIME * 60;
};
};
save_list();
done();
save_config();
for (int i=0;i<LAST_HISTORY;i++)
delete(ALL_HISTORIES[i]);
};
void tMain::run_after_quit(){
if (CFG.EXEC_WHEN_QUIT && strlen(CFG.EXEC_WHEN_QUIT))
system(CFG.EXEC_WHEN_QUIT);
};
void tMain::add_download_message(tDownload *what) {
if (!what) return;
std::string rfile=hexed_string(what->info.file);
MainLog->myprintf(LOG_OK,_("Added downloading of file %s from %s [by user]"),rfile.c_str(),what->info.host.c_str());
};
static int not_all_stopped(tQueue *q){
d4xDownloadQueue *dq=(d4xDownloadQueue *)q->first();
while(dq){
if (dq->count(DL_STOPWAIT))
return(1);
if (not_all_stopped(&(dq->child)))
return(1);
dq=(d4xDownloadQueue *)(dq->prev);
};
return(0);
};
void tMain::stop_all(tQueue *q){
d4xDownloadQueue *dq=(d4xDownloadQueue *)q->first();
while(dq){
stop_all(&(dq->child));
tDownload *d=dq->first(DL_RUN);
while (d){
stop_download(d);
d=dq->first(DL_RUN);
}
dq=(d4xDownloadQueue *)(dq->prev);
};
};
void tMain::stop_all_offline(tQueue *q){
d4xDownloadQueue *dq=(d4xDownloadQueue *)q->first();
while(dq){
stop_all_offline(&(dq->child));
tDownload *d=dq->first(DL_RUN);
while (d){
stop_download(d);
d->action=ACTION_CONTINUE;
d=dq->first(DL_RUN);
}
d=dq->first(DL_SIZEQUERY);
if (d)
stop_download(d);
dq=(d4xDownloadQueue *)(dq->prev);
};
};
void tMain::switch_offline_mode(){
if (CFG.OFFLINE_MODE==0){
CFG.OFFLINE_MODE=1;
stop_all_offline(&D4X_QTREE);
ftpsearch->stop_all_offline();
MainLog->add(_("Downloader is in offline mode now"),LOG_WARNING|LOG_DETAILED);
}else{
CFG.OFFLINE_MODE=0;
int tmpfr=CFG.ALLOW_FORCE_RUN;
CFG.ALLOW_FORCE_RUN=1;
main_circle_nano2();
CFG.ALLOW_FORCE_RUN=tmpfr;
MainLog->add(_("Offline mode is turned off"),LOG_WARNING|LOG_DETAILED);
};
if (!CFG.WITHOUT_FACE){
d4x_main_offline_mode();
};
};
void tMain::done() {
/* There are we MUST stop all threads!!!
*/
server->stop_thread();
/* removing ftpsearch before removing all queues
to avoid segfault at host-limit checks */
if (ftpsearch) delete(ftpsearch);
FaceForPasswords->save();
if (FaceForPasswords)
delete (FaceForPasswords);
stop_all(&D4X_QTREE);
while(not_all_stopped(&D4X_QTREE)){
main_circle_nano2();
sleep(1);
};
D4X_QUEUE->done();
MainScheduler->save();
delete(MainScheduler);
delete(GlobalMeter);
delete(GraphMeter);
delete(GraphLMeter);
delete(LocalMeter);
delete(ALL_DOWNLOADS); // delete or not delete that is the question :-)
COOKIES->save_cookies();
delete(COOKIES);
MainLog->init_list(NULL);
MainLog->myprintf(LOG_OK,_("%lu bytes loaded during the session"),GVARS.READED_BYTES);
MainLog->add(_("Downloader exited normaly"),LOG_OK);
delete(MainLog);
delete(SpeedScheduler);
close(LOCK_FILE_D);
delete (server);
delete (MsgQueue);
/*
for (int i=URL_HISTORY;i<LAST_HISTORY;i++)
if (ALL_HISTORIES[i]) delete(ALL_HISTORIES[i]);
*/
SOUND_SERVER->stop_thread();
delete(SOUND_SERVER);
delete(GVARS.SOCKETS);
if (D4X_THEME_DATA) delete(D4X_THEME_DATA);
if (LOCK_FILE) remove(LOCK_FILE);
if (D4X_QVT) delete(D4X_QVT);
};
void tMain::reinit_main_log() {
MainLog->reinit(CFG.MAX_MAIN_LOG_LENGTH);
MainLog->reinit_file();
};
//*****************************************************************/
//-----------------------------------------------------------------
void *download_last(void *nothing) {
tDownload *what=(tDownload *)nothing;
my_pthread_key_init();
my_pthread_key_set(what);
init_signal_handler();
if (what) {
d4x::URL *addr=&(what->info);
what->LOG->MsgQueue=LogsMsgQueue;
if (what->config->log_save_path.get()){
char *real_path=parse_save_path(what->config->log_save_path.get(),what->info.file.c_str());
make_dir_hier_without_last(real_path);
if (what->LOG->init_save(real_path)){
what->WL->log_printf(LOG_ERROR,
_("Can't open '%s' to save log"),
real_path);
};
delete[] real_path;
}else{
what->LOG->init_save(NULL);
};
if ((what->config->proxy.http_host.get() && addr->proto==D_PROTO_HTTP) ||
(what->config->proxy.ftp_host.get() && addr->proto==D_PROTO_FTP && what->config->proxy.type)) {
what->who=new tProxyDownload(what->WL);
what->download_http();
pthread_exit(NULL);
return NULL;
};
switch(addr->proto){
case D_PROTO_SEARCH:
if (what->who==NULL){
if (what->config->proxy.http_host.get())
what->who=new tProxyDownload(what->WL);
else
what->who=new tHttpDownload(what->WL);
};
what->ftp_search();
break;
#ifdef HAVE_SSL
case D_PROTO_HTTPS:
#endif //HAVE_SSL
case D_PROTO_HTTP:
what->download_http();
break;
case D_PROTO_FTP:
what->download_ftp();
break;
default:
what->WL->log(LOG_ERROR,_("Such protocol is not supported!"));
what->download_failed();
break;
};
};
pthread_exit(NULL);
return NULL;
};
//------------------------------------------------------------------------
syntax highlighted by Code2HTML, v. 0.9.1