ZhiQiang_Yang98 79f5c035ab Revert "syn"
This reverts commit 34a3ce7899a56f426ddb1f91073dfcd1cd373b5b.
2022-11-28 10:49:41 +08:00

904 lines
30 KiB
C

/*------------------------------------------------------------------------------
* download.c : gnss data downloader
*
* Copyright (C) 2012-2020 by T.TAKASU, All rights reserved.
*
* version : $Revision:$ $Date:$
* history : 2012/12/28 1.0 new
* 2013/06/02 1.1 replace S_IREAD by S_IRUSR
* 2020/11/30 1.2 support protocol https:// and ftps://
* support compressed RINEX (CRX) files
* support wild-card (*) in URL for FTP and FTPS
* use "=" to separate file name from URL
* fix bug on double-free of download paths
* limit max number of download paths
* use integer types in stdint.h
*-----------------------------------------------------------------------------*/
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "rtklib.h"
#define FTP_CMD "wget" /* FTP/HTTP command */
#define FTP_TIMEOUT 60 /* FTP/HTTP timeout (s) */
#define FTP_LISTING ".listing" /* FTP listing file */
#define FTP_NOFILE 2048 /* FTP error no file */
#define HTTP_NOFILE 1 /* HTTP error no file */
#define FTP_RETRY 3 /* FTP number of retry */
#define MAX_PATHS 131072 /* max number of download paths */
/* type definitions ----------------------------------------------------------*/
typedef struct { /* download path type */
char *remot; /* remote path */
char *local; /* local path */
} path_t;
typedef struct { /* download paths type */
path_t *path; /* download paths */
int n,nmax; /* number and max number of paths */
} paths_t;
/* execute command with test timeout -----------------------------------------*/
extern int execcmd_to(const char *cmd)
{
#ifdef WIN32
PROCESS_INFORMATION info;
STARTUPINFO si={0};
DWORD stat;
char cmds[4096];
si.cb=sizeof(si);
sprintf(cmds,"cmd /c %s",cmd);
if (!CreateProcess(NULL,(LPTSTR)cmds,NULL,NULL,FALSE,CREATE_NO_WINDOW,NULL,
NULL,&si,&info)) return -1;
while (WaitForSingleObject(info.hProcess,10)==WAIT_TIMEOUT) {
showmsg("");
}
if (!GetExitCodeProcess(info.hProcess,&stat)) stat=-1;
CloseHandle(info.hProcess);
CloseHandle(info.hThread);
return (int)stat;
#else
return system(cmd);
#endif
}
/* generate path by replacing keywords ---------------------------------------*/
static void genpath(const char *file, const char *name, gtime_t time, int seqno,
char *path)
{
char buff[1024],*p,*q,*r,*env,var[1024]="";
char l_name[1024]="",u_name[1024]="";
for (p=l_name,q=(char *)name;(*p=(char)tolower(*q));p++,q++) ;
for (p=u_name,q=(char *)name;(*p=(char)toupper(*q));p++,q++) ;
for (p=buff,q=(char *)file;(*p=*q);p++,q++) {
if (*q=='%') q++; else continue;
if (*q=='s'||*q=='r') p+=sprintf(p,"%s",l_name)-1;
else if (*q=='S'||*q=='R') p+=sprintf(p,"%s",u_name)-1;
else if (*q=='N') p+=sprintf(p,"%d",seqno)-1;
else if (*q=='{'&&(r=strchr(q+1,'}'))) {
strncpy(var,q+1,r-q-1);
var[r-q-1]='\0';
if ((env=getenv(var))) p+=sprintf(p,"%s",env)-1;
q=r;
}
else q--;
}
reppath(buff,path,time,"","");
}
/* parse field strings separated by spaces -----------------------------------*/
static char *parse_str(char *buff, char *str, int nmax)
{
char *p,*q,sep[]=" \r\n";
for (p=buff;*p&&*p==' ';p++) ;
if (*p=='"') sep[0]=*p++; /* enclosed within quotation marks */
for (q=str;*p&&!strchr(sep,*p);p++) {
if (q<str+nmax-1) *q++=*p;
}
*q='\0';
return *p?p+1:p;
}
/* compare str1 and str2 with wildcards (*) ----------------------------------*/
static int cmp_str(const char *str1, const char *str2)
{
char s1[1026],s2[1026],*p,*q;
sprintf(s1,"^%s$",str1);
sprintf(s2,"^%s$",str2);
for (p=s1,q=strtok(s2,"*");q;q=strtok(NULL,"*")) {
if ((p=strstr(p,q))) p+=strlen(q); else break;
}
return p!=NULL;
}
/* remote to local file path -------------------------------------------------*/
static void remot2local(const char *remot, const char *dir, char *local)
{
char *p;
if ((p=strrchr(remot,'='))) p++;
else if ((p=strrchr(remot,'/'))) p++;
else p=(char *)remot;
sprintf(local,"%s%c%s",dir,FILEPATHSEP,p);
}
/* test file existence -------------------------------------------------------*/
static int exist_file(const char *local)
{
#ifdef WIN32
DWORD stat=GetFileAttributes(local);
return stat!=0xFFFFFFFF;
#else
struct stat buff;
if (stat(local,&buff)) return 0;
return buff.st_mode&S_IRUSR;
#endif
}
/* test local file existence -------------------------------------------------*/
static int test_file(const char *local)
{
char buff[1024],*p;
int comp=0;
if (strchr(local,'*')) { /* test wild-card (*) in path */
return 0;
}
strcpy(buff,local);
if ((p=strrchr(buff,'.'))&&
(!strcmp(p,".z")||!strcmp(p,".gz")||!strcmp(p,".zip")||
!strcmp(p,".Z")||!strcmp(p,".GZ")||!strcmp(p,".ZIP"))) {
*p='\0';
if (exist_file(buff)) return 1;
comp=1;
}
if ((p=strrchr(buff,'.'))&&strlen(p)==4&&(*(p+3)=='d'||*(p+3)=='D')) {
*(p+3)=*(p+3)=='d'?'o':'O';
if (exist_file(buff)) return 1;
comp=1;
}
if ((p=strrchr(buff,'.'))&&(!strcmp(p,".crx")||!strcmp(p,".CRX"))) {
if (!strcmp(p,".crx")) strcpy(p,".cro"); else strcpy(p,".CRO");
if (exist_file(buff)) return 1;
comp=1;
}
if (!exist_file(buff)) return 0;
return comp?2:1;
}
/* free download paths -------------------------------------------------------*/
static void free_path(paths_t *paths)
{
int i;
if (!paths) return;
for (i=0;i<paths->n;i++) {
free(paths->path[i].remot);
free(paths->path[i].local);
}
free(paths->path);
}
/* add download paths --------------------------------------------------------*/
static int add_path(paths_t *paths, const char *remot, const char *dir)
{
path_t *paths_path;
char local[1024];
if (paths->n>=paths->nmax) {
if ((paths->nmax=paths->nmax<=0?1024:paths->nmax*2)>MAX_PATHS) {
return 0;
}
paths_path=(path_t *)realloc(paths->path,sizeof(path_t)*paths->nmax);
if (!paths_path) {
return 0;
}
paths->path=paths_path;
}
remot2local(remot,dir,local);
paths->path[paths->n].remot=paths->path[paths->n].local=NULL;
if (!(paths->path[paths->n].remot=(char *)malloc(strlen(remot)+1))||
!(paths->path[paths->n].local=(char *)malloc(strlen(local)+1))) {
return 0;
}
strcpy(paths->path[paths->n].remot,remot);
strcpy(paths->path[paths->n].local,local);
paths->n++;
return 1;
}
/* generate download path ----------------------------------------------------*/
static int gen_path(gtime_t time, gtime_t time_p, int seqnos, int seqnoe,
const url_t *url, const char *sta, const char *dir,
paths_t *paths)
{
char remot[1024],remot_p[1024],dir_t[1024];
int i;
if (!*dir) dir=url->dir;
if (!*dir) dir=".";
if (strstr(url->path,"%N")) {
for (i=seqnos;i<=seqnoe;i++) {
genpath(url->path,sta,time,i,remot);
genpath(dir ,sta,time,i,dir_t);
if (time_p.time) {
genpath(url->path,sta,time_p,i,remot_p);
if (!strcmp(remot_p,remot)) continue;
}
if (!add_path(paths,remot,dir_t)) return 0;
}
}
else {
genpath(url->path,sta,time,0,remot);
genpath(dir ,sta,time,0,dir_t);
if (time_p.time) {
genpath(url->path,sta,time_p,0,remot_p);
if (!strcmp(remot_p,remot)) return 1;
}
if (!add_path(paths,remot,dir_t)) return 0;
}
return 1;
}
/* generate download paths ---------------------------------------------------*/
static int gen_paths(gtime_t time, gtime_t time_p, int seqnos, int seqnoe,
const url_t *url, char **stas, int nsta, const char *dir,
paths_t *paths)
{
int i;
if (strstr(url->path,"%s")||strstr(url->path,"%S")) {
for (i=0;i<nsta;i++) {
if (!gen_path(time,time_p,seqnos,seqnoe,url,stas[i],dir,paths)) {
return 0;
}
}
}
else {
if (!gen_path(time,time_p,seqnos,seqnoe,url,"",dir,paths)) {
return 0;
}
}
return 1;
}
/* compact download paths ----------------------------------------------------*/
static void compact_paths(paths_t *paths)
{
int i,j,k;
for (i=0;i<paths->n;i++) {
for (j=i+1;j<paths->n;j++) {
if (strcmp(paths->path[i].remot,paths->path[j].remot)) continue;
free(paths->path[j].remot);
free(paths->path[j].local);
for (k=j;k<paths->n-1;k++) paths->path[k]=paths->path[k+1];
paths->n--; j--;
}
}
}
/* generate local directory recursively --------------------------------------*/
static int mkdir_r(const char *dir)
{
char pdir[1024],*p;
#ifdef WIN32
HANDLE h;
WIN32_FIND_DATA data;
if (!*dir||!strcmp(dir+1,":\\")) return 1;
strcpy(pdir,dir);
if ((p=strrchr(pdir,FILEPATHSEP))) {
*p='\0';
h=FindFirstFile(pdir,&data);
if (h==INVALID_HANDLE_VALUE) {
if (!mkdir_r(pdir)) return 0;
}
else FindClose(h);
}
if (CreateDirectory(dir,NULL)||
GetLastError()==ERROR_ALREADY_EXISTS) return 1;
trace(2,"directory generation error: dir=%s\n",dir);
return 0;
#else
FILE *fp;
if (!*dir) return 1;
strcpy(pdir,dir);
if ((p=strrchr(pdir,FILEPATHSEP))) {
*p='\0';
if (!(fp=fopen(pdir,"r"))) {
if (!mkdir_r(pdir)) return 0;
}
else fclose(fp);
}
if (!mkdir(dir,0777)||errno==EEXIST) return 1;
trace(2,"directory generation error: dir=%s\n",dir);
return 0;
#endif
}
/* get remote file list for FTP or FTPS --------------------------------------*/
static int get_list(const path_t *path, const char *usr, const char *pwd,
const char *proxy)
{
FILE *fp;
char cmd[4096],env[1024]="",remot[1024],*opt="",*opt2="",*p;
int stat;
#ifndef WIN32
opt2=" -o /dev/null";
#endif
remove(FTP_LISTING);
strcpy(remot,path->remot);
if ((p=strrchr(remot,'/'))) strcpy(p+1,"__REQUEST_LIST__"); else return 0;
if (*proxy) {
sprintf(env,"set ftp_proxy=http://%s & ",proxy);
opt="--proxy=on ";
}
sprintf(cmd,"%s%s %s --ftp-user=%s --ftp-password=%s --glob=off "
"--passive-ftp --no-remove-listing -N %s-t 1 -T %d%s\n",
env,FTP_CMD,remot,usr,pwd,opt,FTP_TIMEOUT,opt2);
execcmd_to(cmd);
if (!(fp=fopen(FTP_LISTING,"r"))) return 0;
fclose(fp);
return 1;
}
/* replace wild-card (*) in the paths ----------------------------------------*/
static int rep_paths(path_t *path, const char *file)
{
char buff1[1024],buff2[1024],*p,*q,*remot,*local;
strcpy(buff1,path->remot);
strcpy(buff2,path->local);
if ((p=strrchr(buff1,'/'))) p++; else p=buff1;
if ((q=strrchr(buff2,FILEPATHSEP))) q++; else q=buff2;
strcpy(p,file);
strcpy(q,file);
if (!(remot=(char *)malloc(strlen(buff1)+1)) ||
!(local=(char *)malloc(strlen(buff2)+1))) {
free(remot);
return 0;
}
strcpy(remot,buff1);
strcpy(local,buff2);
free(path->remot);
free(path->local);
path->remot=remot;
path->local=local;
return 1;
}
/* test file in remote file list ---------------------------------------------*/
static int test_list(path_t *path)
{
FILE *fp;
char buff[1024],*file,*list,*p;
int i;
if (!(fp=fopen(FTP_LISTING,"r"))) return 1;
if ((p=strrchr(path->remot,'/'))) file=p+1; else return 1;
/* search file in remote file list */
while (fgets(buff,sizeof(buff),fp)) {
/* remove symbolic link */
if ((p=strstr(buff,"->"))) *p='\0';
for (i=strlen(buff)-1;i>=0;i--) {
if (strchr(" \r\n",buff[i])) buff[i]='\0'; else break;
}
/* file as last field */
if ((p=strrchr(buff,' '))) list=p+1; else list=buff;
if (!strcmp(file,list)) {
fclose(fp);
return 1;
}
/* compare with wild-card (*) */
if (cmp_str(list,file)) {
/* replace wild-card (*) in the paths */
if (!rep_paths(path,list)) {
fclose(fp);
return 0;
}
fclose(fp);
return 1;
}
}
fclose(fp);
return 0;
}
/* execute download ----------------------------------------------------------*/
static int exec_down(path_t *path, char *remot_p, const char *usr,
const char *pwd, const char *proxy, int opts, int *n,
FILE *fp)
{
char dir[1024],errfile[1024],tmpfile[1024],cmd[4096],env[1024]="";
char opt[1024]="",*opt2="",*p;
int ret,proto;
#ifndef WIN32
opt2=" 2> /dev/null";
#endif
strcpy(dir,path->local);
if ((p=strrchr(dir,FILEPATHSEP))) *p='\0';
if (!strncmp(path->remot,"ftp://" ,6)) proto=0;
else if (!strncmp(path->remot,"ftps://" ,7)) proto=2;
else if (!strncmp(path->remot,"http://" ,7)) proto=1;
else if (!strncmp(path->remot,"https://",8)) proto=1;
else {
trace(2,"exec_down: invalid path %s\n",path->remot);
showmsg("STAT=X");
if (fp) fprintf(fp,"%s ERROR (INVALID PATH)\n",path->remot);
n[1]++;
return 0;
}
/* test local file existence */
if (!(opts&DLOPT_FORCE)&&test_file(path->local)) {
showmsg("STAT=.");
if (fp) fprintf(fp,"%s in %s\n",path->remot,dir);
n[2]++;
return 0;
}
showmsg("STAT=_");
/* get remote file list for FTP or FTPS */
if ((proto==0||proto==2)&&(p=strrchr(path->remot,'/'))&&
strncmp(path->remot,remot_p,p-path->remot)) {
if (get_list(path,usr,pwd,proxy)) {
strcpy(remot_p,path->remot);
}
}
/* test file in listing for FTP or FTPS or extend wild-card in file path */
if ((proto==0||proto==2)&&!test_list(path)) {
showmsg("STAT=x");
if (fp) fprintf(fp,"%s NO_FILE\n",path->remot);
n[1]++;
return 0;
}
/* generate local directory recursively */
if (!mkdir_r(dir)) {
showmsg("STAT=X");
if (fp) fprintf(fp,"%s -> %s ERROR (LOCAL DIR)\n",path->remot,dir);
n[3]++;
return 0;
}
/* re-test local file existence for file with wild-card */
if (!(opts&DLOPT_FORCE)&&test_file(path->local)) {
showmsg("STAT=.");
if (fp) fprintf(fp,"%s in %s\n",path->remot,dir);
n[2]++;
return 0;
}
/* proxy option */
if (*proxy) {
sprintf(env,"set %s_proxy=http://%s & ",proto==0||proto==2?"ftp":"http",
proxy);
sprintf(opt," --proxy=on ");
}
/* download command */
sprintf(errfile,"%s.err",path->local);
if (proto==0||proto==2) {
sprintf(cmd,"%s%s %s --ftp-user=%s --ftp-password=%s --glob=off "
"--passive-ftp %s-t %d -T %d -O \"%s\" -o \"%s\"%s\n",
env,FTP_CMD,path->remot,usr,pwd,opt,FTP_RETRY,FTP_TIMEOUT,
path->local,errfile,opt2);
}
else {
if (*pwd) {
sprintf(opt+strlen(opt)," --http-user=%s --http-password=%s ",usr,
pwd);
}
sprintf(cmd,"%s%s %s %s-t %d -T %d -O \"%s\" -o \"%s\"%s\n",env,FTP_CMD,
path->remot,opt,FTP_RETRY,FTP_TIMEOUT,path->local,errfile,opt2);
}
if (fp) fprintf(fp,"%s -> %s",path->remot,dir);
/* execute download command */
if ((ret=execcmd_to(cmd))) {
if ((proto==0&&ret==FTP_NOFILE)||
(proto==1&&ret==HTTP_NOFILE)) {
showmsg("STAT=x");
if (fp) fprintf(fp," NO_FILE\n");
n[1]++;
}
else {
trace(2,"exec_down: error proto=%d %d\n",proto,ret);
showmsg("STAT=X");
if (fp) fprintf(fp," ERROR (%d)\n",ret);
n[3]++;
}
remove(path->local);
if (!(opts&DLOPT_HOLDERR)) {
remove(errfile);
}
return ret==2;
}
remove(errfile);
/* uncompress download file */
if (!(opts&DLOPT_KEEPCMP)&&(p=strrchr(path->local,'.'))&&
(!strcmp(p,".z")||!strcmp(p,".gz")||!strcmp(p,".zip")||
!strcmp(p,".Z")||!strcmp(p,".GZ")||!strcmp(p,".ZIP"))) {
if (rtk_uncompress(path->local,tmpfile)) {
remove(path->local);
}
else {
trace(2,"exec_down: uncompress error\n");
showmsg("STAT=C");
if (fp) fprintf(fp," ERROR (UNCOMP)\n");
n[3]++;
return 0;
}
}
showmsg("STAT=o");
if (fp) fprintf(fp," OK\n");
n[0]++;
return 0;
}
/* test local file -----------------------------------------------------------*/
static int test_local(gtime_t ts, gtime_t te, double ti, const char *path,
const char *sta, const char *dir, int *nc, int *nt,
FILE *fp)
{
gtime_t time;
char remot[1024],remot_p[1024],dir_t[1024],local[1024],str[1024];
int stat,abort=0;
for (time=ts;timediff(time,te)<=1E-3;time=timeadd(time,ti)) {
sprintf(str,"%s->%s",path,local);
if (showmsg(str)) {
abort=1;
break;
}
genpath(path,sta,time,0,remot);
genpath(dir ,sta,time,0,dir_t);
remot2local(remot,dir_t,local);
stat=test_file(local);
fprintf(fp," %s",stat==0?"-":(stat==1?"o":"z"));
showmsg("STAT=%s",stat==0?"x":(stat==1?"o":"z"));
(*nt)++; if (stat) (*nc)++;
}
fprintf(fp,"\n");
return abort;
}
/* test local files ----------------------------------------------------------*/
static int test_locals(gtime_t ts, gtime_t te, double ti, const url_t *url,
char **stas, int nsta, const char *dir, int *nc, int *nt,
FILE *fp)
{
int i;
if (strstr(url->path,"%s")||strstr(url->path,"%S")) {
fprintf(fp,"%s\n",url->type);
for (i=0;i<nsta;i++) {
fprintf(fp,"%-12s:",stas[i]);
if (test_local(ts,te,ti,url->path,stas[i],*dir?dir:url->dir,nc+i,
nt+i,fp)) {
return 1;
}
}
}
else {
fprintf(fp,"%-12s:",url->type);
if (test_local(ts,te,ti,url->path,"",*dir?dir:url->dir,nc,nt,fp)) {
return 1;
}
}
return 0;
}
/* print total count of local files ------------------------------------------*/
static int print_total(const url_t *url, char **stas, int nsta, int *nc,
int *nt, FILE *fp)
{
int i;
if (strstr(url->path,"%s")||strstr(url->path,"%S")) {
fprintf(fp,"%s\n",url->type);
for (i=0;i<nsta;i++) {
fprintf(fp,"%-12s: %5d/%5d\n",stas[i],nc[i],nt[i]);
}
return nsta;
}
fprintf(fp,"%-12s: %5d/%5d\n",url->type,nc[0],nt[0]);
return 1;
}
/* read URL list file ----------------------------------------------------------
* read URL list file for GNSS data
* args : char *file I URL list file
* char **types I selected types ("*":wildcard)
* int ntype I number of selected types
* urls_t *urls O URL list
* int nmax I max number of URL list
* return : number of URL addresses (0:error)
* notes :
* (1) URL list file contains records containing the following fields
* separated by spaces. if a field contains spaces, enclose it within "".
*
* data_type url_address default_local_directory
*
* (2) strings after # in a line are treated as comments
* (3) url_address should be:
*
* ftp://host_address/file_path or
* ftps://host_address/file_path or
* http://host_address/file_path or
* https://host_address/file_path
*
* (4) the field url_address or default_local_directory can include the
* follwing keywords replaced by date, time, station names and environment
* variables.
*
* %Y -> yyyy : year (4 digits) (2000-2099)
* %y -> yy : year (2 digits) (00-99)
* %m -> mm : month (01-12)
* %d -> dd : day of month (01-31)
* %h -> hh : hours (00-23)
* %H -> a : hour code (a-x)
* %M -> mm : minutes (00-59)
* %n -> ddd : day of year (001-366)
* %W -> wwww : gps week (0001-9999)
* %D -> d : day of gps week (0-6)
* %N -> nnn : general number
* %s -> ssss : station name (lower-case)
* %S -> SSSS : station name (upper-case)
* %r -> rrrr : station name
* %{env} -> env : environment variable
*-----------------------------------------------------------------------------*/
extern int dl_readurls(const char *file, char **types, int ntype, url_t *urls,
int nmax)
{
FILE *fp;
char buff[2048],type[32],path[1024],dir[1024],*p;
int i,n=0;
if (!(fp=fopen(file,"r"))) {
fprintf(stderr,"options file read error %s\n",file);
return 0;
}
for (i=0;i<ntype;i++) {
rewind(fp);
while (fgets(buff,sizeof(buff),fp)&&n<nmax) {
if ((p=strchr(buff,'#'))) *p='\0';
p=buff;
p=parse_str(p,type,sizeof(type));
p=parse_str(p,path,sizeof(path));
p=parse_str(p,dir ,sizeof(dir ));
if (!*type||!*path) continue;
if (!cmp_str(type,types[i])) continue;
strcpy(urls[n ].type,type);
strcpy(urls[n ].path,path);
strcpy(urls[n++].dir ,dir );
}
}
fclose(fp);
if (n<=0) {
fprintf(stderr,"no url in options file %s\n",file);
return 0;
}
return n;
}
/* read station list file ------------------------------------------------------
* read station list file
* args : char *file I station list file
* char **stas O stations
* int nmax I max number of stations
* return : number of stations (0:error)
* notes :
* (1) station list file contains station names separated by spaces.
* (2) strings after # in a line are treated as comments
*-----------------------------------------------------------------------------*/
extern int dl_readstas(const char *file, char **stas, int nmax)
{
FILE *fp;
char buff[4096],*p;
int n=0;
if (!(fp=fopen(file,"r"))) {
fprintf(stderr,"station list file read error %s\n",file);
return 0;
}
while (fgets(buff,sizeof(buff),fp)&&n<nmax) {
if ((p=strchr(buff,'#'))) *p='\0';
for (p=strtok(buff," \r\n");p&&n<nmax;p=strtok(NULL," \r\n")) {
strcpy(stas[n++],p);
}
}
fclose(fp);
if (n<=0) {
fprintf(stderr,"no station in station file %s\n",file);
return 0;
}
return n;
}
/* execute download ------------------------------------------------------------
* execute download
* args : gtime_t ts,te I time start and end
* double tint I time interval (s)
* int seqnos I sequence number start
* int seqnoe I sequence number end
* url_t *urls I URL list
* int nurl I number of URL list
* char **stas I station list
* int nsta I number of station list
* char *dir I local directory
* char *remote_p I previous remote file path
* char *usr I login user for FTP or FTPS
* char *pwd I login password for FTP or FTPS
* char *proxy I proxy server address
* int opts I download options (or of the followings)
* DLOPT_FORCE = force download existing file
* DLOPT_KEEPCMP=keep compressed file
* DLOPT_HOLDERR=hold on error file
* DLOPT_HOLDLST=hold on listing file
* char *msg O output messages
* FILE *fp IO log file pointer (NULL: no output log)
* return : status (1:ok,0:error,-1:aborted)
* notes : The URL list should be read by using dl_readurl()
* In the FTP or FTPS cases, the file name in a URL can contain wild-
* cards (*). The directory in a URL can not contain any wild-cards.
* If the file name contains wild-cards, dl_exec() gets a file-list in
* the remote directory and downloads the firstly matched file in the
* remote file-list. The secondary matched or the following files are
* not downloaded.
*-----------------------------------------------------------------------------*/
extern int dl_exec(gtime_t ts, gtime_t te, double ti, int seqnos, int seqnoe,
const url_t *urls, int nurl, char **stas, int nsta,
const char *dir, const char *usr, const char *pwd,
const char *proxy, int opts, char *msg, FILE *fp)
{
paths_t paths={0};
gtime_t ts_p={0};
char str[2048],remot_p[1024]="";
int i,n[4]={0};
uint32_t tick=tickget();
showmsg("STAT=_");
/* generate download paths */
while (timediff(ts,te)<1E-3) {
for (i=0;i<nurl;i++) {
if (!gen_paths(ts,ts_p,seqnos,seqnoe,urls+i,stas,nsta,dir,&paths)) {
free_path(&paths);
sprintf(msg,"too many download files");
return 0;
}
}
ts_p=ts; ts=timeadd(ts,ti);
}
/* compact download paths */
compact_paths(&paths);
if (paths.n<=0) {
sprintf(msg,"no download data");
return 0;
}
for (i=0;i<paths.n;i++) {
sprintf(str,"%s->%s (%d/%d)",paths.path[i].remot,paths.path[i].local,i+1,
paths.n);
if (showmsg(str)) break;
/* execute download */
if (exec_down(paths.path+i,remot_p,usr,pwd,proxy,opts,n,fp)) {
break;
}
}
if (!(opts&DLOPT_HOLDLST)) {
remove(FTP_LISTING);
}
sprintf(msg,"OK=%d No_File=%d Skip=%d Error=%d (Time=%.1f s)",n[0],n[1],n[2],
n[3],(tickget()-tick)*0.001);
free_path(&paths);
return 1;
}
/* execute local file test -----------------------------------------------------
* execute local file test
* args : gtime_t ts,te I time start and end
* double tint I time interval (s)
* url_t *urls I remote URL addresses
* int nurl I number of remote URL addresses
* char **stas I stations
* int nsta I number of stations
* char *dir I local directory
* int ncol I number of column
* int datefmt I date format (0:year-dow,1:year-dd/mm,2:week)
* FILE *fp IO log test result file pointer
* return : status (1:ok,0:error,-1:aborted)
*-----------------------------------------------------------------------------*/
extern void dl_test(gtime_t ts, gtime_t te, double ti, const url_t *urls,
int nurl, char **stas, int nsta, const char *dir,
int ncol, int datefmt, FILE *fp)
{
gtime_t time;
double tow;
char year[32],date[32],date_p[32];
int i,j,n,m,*nc,*nt,week,flag,abort=0;
if (ncol<1) ncol=1; else if (ncol>200) ncol=200;
fprintf(fp,"** LOCAL DATA AVAILABILITY (%s, %s) **\n\n",
time_str(timeget(),0),*dir?dir:"*");
for (i=n=0;i<nurl;i++) {
n+=strstr(urls[i].path,"%s")||strstr(urls[i].path,"%S")?nsta:1;
}
nc=imat(n,1);
nt=imat(n,1);
for (i=0;i<n;i++) nc[i]=nt[i]=0;
for (;timediff(ts,te)<1E-3&&!abort;ts=timeadd(ts,ti*ncol)) {
genpath(datefmt==0?" %Y-":"%Y/%m/","",ts,0,year);
if (datefmt<=1) fprintf(fp,"%s %s",datefmt==0?"DOY ":"DATE",year);
else fprintf(fp,"WEEK ");
*date_p='\0'; flag=0;
m=datefmt==2?1:2;
for (i=0;i<(ncol+m-1)/m;i++) {
time=timeadd(ts,ti*i*m);
if (timediff(time,te)>=1E-3) break;
if (datefmt<=1) {
genpath(datefmt==0?"%n":"%d","",time,0,date);
fprintf(fp,"%-4s",strcmp(date,date_p)?date:"");
}
else {
if (fabs(time2gpst(time,&week))<1.0) {
fprintf(fp,"%04d",week); flag=1;
}
else {
fprintf(fp,"%s",flag?"":" "); flag=0;
}
}
strcpy(date_p,date);
}
fprintf(fp,"\n");
for (i=j=0;i<nurl&&!abort;i++) {
time=timeadd(ts,ti*ncol-1.0);
if (timediff(time,te)>=0.0) time=te;
/* test local files */
abort=test_locals(ts,time,ti,urls+i,stas,nsta,dir,nc+j,nt+j,fp);
j+=strstr(urls[i].path,"%s")||strstr(urls[i].path,"%S")?nsta:1;
}
fprintf(fp,"\n");
}
fprintf(fp,"# COUNT : FILES/TOTAL\n");
for (i=j=0;i<nurl;i++) {
j+=print_total(urls+i,stas,nsta,nc+j,nt+j,fp);
}
free(nc); free(nt);
}