Synchronet now requires the libarchive development package (e.g. libarchive-dev on Debian-based Linux distros, libarchive.org for more info) to build successfully.

Commit 18aaca6b authored by Rob Swindell's avatar Rob Swindell 💬

Add optional "temp file transfer" module (defaults to "tempxfer"[.js])

This module (name configurable in SCFG->System->Loadable Modules) replaces the old hard-coded temp/archive file menu in v3.18 and earlier, going all the way back to v1a. Good-bye to yet more old and crufty Synchronet C source code. :-/

Change the "Pre Xtrn Prog" and "Post Xtrn Prop" menu option in SCFG->System->Loadable Modules to just "Pre Xtrn" and "Post Xtrn". The help text had the wrong names anyway (now fixed).
Save the menu lightbar position in the "Loadable Modules" SCFG menu.
parent 23f611f0
Pipeline #2323 passed with stage
in 7 minutes and 45 seconds
......@@ -3464,7 +3464,6 @@ sbbs_t::sbbs_t(ushort node_num, union xp_sockaddr *addr, size_t addr_len, const
main_cmds = 0;
xfer_cmds = 0;
posts_read = 0;
temp_cdt = 0;
autohang = 0;
curgrp = 0;
curlib = 0;
......
......@@ -581,9 +581,6 @@ public:
uint main_cmds; /* Number of Main Commands this call */
uint xfer_cmds; /* Number of Xfer Commands this call */
ulong posts_read; /* Number of Posts read this call */
char temp_uler[31]; /* User who uploaded the files to temp dir */
char temp_file[41]; /* Origin of extracted temp files */
long temp_cdt; /* Credit value of file that was extracted */
bool autohang; /* Used for auto-hangup after transfer */
size_t logcol; /* Current column of log file */
uint criterrs; /* Critical error counter */
......@@ -1070,7 +1067,6 @@ public:
/* tmp_xfer.cpp */
void temp_xfer(void);
void extract(uint dirnum);
const char* temp_cmd(void); /* Returns temp file command line */
ulong create_filelist(const char *name, long mode);
......
......@@ -1656,6 +1656,7 @@ void sys_cfg(void)
break;
case 12: /* Loadable Modules */
done=0;
bar=0;
k=0;
while(!done) {
i=0;
......@@ -1669,8 +1670,8 @@ void sys_cfg(void)
sprintf(opt[i++],"%-16.16s%s","Auto Message",cfg.automsg_mod);
sprintf(opt[i++],"%-16.16s%s","Text Section",cfg.textsec_mod);
sprintf(opt[i++],"%-16.16s%s","Xtrn Section",cfg.xtrnsec_mod);
sprintf(opt[i++],"%-16.16s%s","Pre Xtrn Prog",cfg.prextrn_mod);
sprintf(opt[i++],"%-16.16s%s","Post Xtrn Prog",cfg.postxtrn_mod);
sprintf(opt[i++],"%-16.16s%s","Pre Xtrn",cfg.prextrn_mod);
sprintf(opt[i++],"%-16.16s%s","Post Xtrn",cfg.postxtrn_mod);
sprintf(opt[i++],"%-16.16s%s","Read Mail",cfg.readmail_mod);
sprintf(opt[i++],"%-16.16s%s","Scan Msgs",cfg.scanposts_mod);
sprintf(opt[i++],"%-16.16s%s","Scan Subs",cfg.scansubs_mod);
......@@ -1679,6 +1680,7 @@ void sys_cfg(void)
sprintf(opt[i++],"%-16.16s%s","List Nodes",cfg.nodelist_mod);
sprintf(opt[i++],"%-16.16s%s","Who's Online",cfg.whosonline_mod);
sprintf(opt[i++],"%-16.16s%s","Private Msg",cfg.privatemsg_mod);
sprintf(opt[i++],"%-16.16s%s","Temp Transfer",cfg.tempxfer_mod);
opt[i][0]=0;
uifc.helpbuf=
"`Loadable Modules:`\n"
......@@ -1688,34 +1690,35 @@ void sys_cfg(void)
"operations. The name (root filename) of the module can be specified for\n"
"each of the available operations listed below:\n"
"\n"
"`Login` Required module for interactive terminal logins (answer)\n"
"`Logon` Executed during terminal logon procedure\n"
"`Sync` Executed when terminal nodes are periodically synchronized\n"
"`Logoff` Executed during terminal logoff procedure (interactive)\n"
"`Logout` Executed during terminal logout procedure (offline)\n"
"`New User` Executed at end of new terminal user creation process\n"
"`Expired User` Executed during daily event when user expires (offline)\n"
"`Auto Message` Executed when a user chooses to edit the auto-message\n"
"`Text Section` Executed to handle general text file (viewing) section\n"
"`Xtrn Section` Executed to handle external programs (doors) section\n"
"`Xtrn Prog Pre` Executed before external programs (doors) run\n"
"`Xtrn Prog Post` Executed after external programs (doors) run\n"
"`Login` Required module for interactive terminal logins (answer)\n"
"`Logon` Executed during terminal logon procedure\n"
"`Sync` Executed when terminal nodes are periodically synchronized\n"
"`Logoff` Executed during terminal logoff procedure (interactive)\n"
"`Logout` Executed during terminal logout procedure (offline)\n"
"`New User` Executed at end of new terminal user creation process\n"
"`Expired User` Executed during daily event when user expires (offline)\n"
"`Auto Message` Executed when a user chooses to edit the auto-message\n"
"`Text Section` Executed to handle general text file (viewing) section\n"
"`Xtrn Section` Executed to handle external programs (doors) section\n"
"`Pre Xtrn` Executed before external programs (doors) run\n"
"`Post Xtrn` Executed after external programs (doors) run\n"
"`Temp Transfer` Temporary/archive file transfer menu\n"
"\n"
"Full module command-lines may be used for the operations listed below:\n"
"\n"
"`Read Mail` Executed when a user reads email/netmail\n"
"`Scan Msgs` Executed when a user reads or scans a message sub-board\n"
"`Scan Subs` Executed when a user scans one or more sub-boards for msgs\n"
"`List Msgs` Executed when a user lists msgs from the msg read prompt\n"
"`List Logons` Executed when a user lists logons ('-y' for yesterday)\n"
"`List Nodes` Executed when a user lists all nodes\n"
"`Who's Online` Executed when a user lists the nodes in-use (e.g. `^U`)\n"
"`Private Msg` Executed when a user sends a private node msg (e.g. `^P`)\n"
"`Read Mail` Executed when a user reads email/netmail\n"
"`Scan Msgs` Executed when a user reads or scans a message sub-board\n"
"`Scan Subs` Executed when a user scans one or more sub-boards for msgs\n"
"`List Msgs` Executed when a user lists msgs from the msg read prompt\n"
"`List Logons` Executed when a user lists logons ('-y' for yesterday)\n"
"`List Nodes` Executed when a user lists all nodes\n"
"`Who's Online` Executed when a user lists the nodes in-use (e.g. `^U`)\n"
"`Private Msg` Executed when a user sends a private node msg (e.g. `^P`)\n"
"\n"
"`Note:` JavaScript modules take precedence over Baja modules if both exist\n"
" in your `exec` or `mods` directories.\n"
;
switch(uifc.list(WIN_ACT|WIN_T2B|WIN_RHT,0,0,40,&k,0
switch(uifc.list(WIN_ACT|WIN_T2B|WIN_RHT,0,0,40,&k,&bar
,"Loadable Modules",opt)) {
case -1:
......@@ -1802,6 +1805,10 @@ void sys_cfg(void)
uifc.input(WIN_MID|WIN_SAV,0,0,"Private Message Command"
,cfg.privatemsg_mod,sizeof(cfg.privatemsg_mod)-1,K_EDIT);
break;
case 20:
uifc.input(WIN_MID|WIN_SAV,0,0,"Temporary File Transfer Module"
,cfg.tempxfer_mod, sizeof(cfg.tempxfer_mod)-1, K_EDIT);
break;
}
}
break;
......
......@@ -600,6 +600,7 @@ typedef struct
char logonlist_mod[LEN_CMD+1];
char prextrn_mod[LEN_MODNAME+1]; /* External Program pre-execution module */
char postxtrn_mod[LEN_MODNAME+1]; /* External Program post-execution module */
char tempxfer_mod[LEN_MODNAME+1];
char scfg_cmd[LEN_CMD+1]; /* SCFG command line - unused! */
uchar smb_retry_time; /* Seconds to retry on SMBs */
uint16_t sec_warn; /* Seconds before inactivity warning */
......
......@@ -252,13 +252,18 @@ BOOL read_main_cfg(scfg_t* cfg, char* error, size_t maxerrlen)
SAFECOPY(cfg->logonlist_mod, "logonlist");
get_str(cfg->prextrn_mod,instream);
if(cfg->prextrn_mod[0] == '\xff')
if(cfg->prextrn_mod[0] == '\xff')
SAFECOPY(cfg->prextrn_mod, "prextrn");
get_str(cfg->postxtrn_mod,instream);
if(cfg->postxtrn_mod[0] == '\xff')
SAFECOPY(cfg->postxtrn_mod, "postxtrn");
for(i=0;i<117;i++) /* unused - initialized to 0xff */
if(cfg->postxtrn_mod[0] == '\xff')
SAFECOPY(cfg->postxtrn_mod, "postxtrn");
get_str(cfg->tempxfer_mod, instream);
if(cfg->tempxfer_mod[0] == '\xff')
SAFECOPY(cfg->tempxfer_mod, "tempxfer");
get_int(c, instream);
for(i=0;i<112;i++) /* unused - initialized to 0xff */
get_int(n,instream);
get_int(cfg->user_backup_level,instream);
......
......@@ -254,9 +254,12 @@ BOOL write_main_cfg(scfg_t* cfg, int backup_level)
put_str(cfg->prextrn_mod,stream);
put_str(cfg->postxtrn_mod,stream);
put_str(cfg->tempxfer_mod, stream);
c=0xff;
put_int(c, stream);
n=0xffff;
for(i=0;i<117;i++)
for(i=0;i<112;i++)
put_int(n,stream);
put_int(cfg->user_backup_level,stream);
......
......@@ -27,391 +27,11 @@
/*****************************************************************************/
void sbbs_t::temp_xfer()
{
#if 0 // TODO
char str[256],tmp2[256],done=0,ch;
char tmp[512];
int error;
uint i,dirnum=cfg.total_dirs,files;
ulong bytes;
ulong space;
time_t start,end,t;
file_t f;
glob_t g;
struct tm tm;
if(!usrlibs)
return;
if(useron.rest&FLAG('D')) {
bputs(text[R_Download]);
return;
}
/*************************************/
/* Create TEMP directory information */
/*************************************/
if((cfg.dir[dirnum]=(dir_t *)malloc(sizeof(dir_t)))==0) {
errormsg(WHERE,ERR_ALLOC,"temp_dir",sizeof(dir_t));
if(!cfg.tempxfer_mod[0]) {
bprintf(text[DirectoryDoesNotExist], "temp (module)");
return;
}
memset(cfg.dir[dirnum],0,sizeof(dir_t));
SAFECOPY(cfg.dir[dirnum]->lname,"Temporary");
SAFECOPY(cfg.dir[dirnum]->sname,"Temp");
SAFECOPY(cfg.dir[dirnum]->code,"TEMP");
SAFECOPY(cfg.dir[dirnum]->path,cfg.temp_dir);
SAFECOPY(cfg.dir[dirnum]->data_dir,cfg.dir[0]->data_dir);
cfg.dir[dirnum]->maxfiles=MAX_FILES;
temp_dirnum=curdirnum=usrdir[curlib][curdir[curlib]];
cfg.total_dirs++;
/****************************/
/* Fill filedat information */
/****************************/
memset(&f,0,sizeof(f));
SAFEPRINTF2(f.name,"temp_%3.3d.%s",cfg.node_num,useron.tmpext);
SAFECOPY(f.desc,"Temp File");
f.dir=dirnum;
if(useron.misc&(RIP|WIP|HTML) && !(useron.misc&EXPERT))
menu("tempxfer");
lncntr=0;
while(online && !done) {
if(!(useron.misc&(EXPERT|RIP|WIP|HTML))) {
sys_status&=~SS_ABORT;
if(lncntr) {
SYNC;
CRLF;
if(lncntr) /* CRLF or SYNC can cause pause */
pause();
}
menu("tempxfer");
}
ASYNC;
bputs(text[TempDirPrompt]);
SAFECOPY(f.uler,temp_uler);
ch=(char)getkeys("ADEFNILQRVX?\r",0);
if(ch>' ')
logch(ch,0);
switch(ch) {
case 'A': /* add to temp file */
if(!isdir(cfg.temp_dir)) {
bprintf(text[DirectoryDoesNotExist], cfg.temp_dir);
lprintf(LOG_ERR,"Temp directory does not exist: %s", cfg.temp_dir);
break;
}
/* free disk space */
space=getfreediskspace(cfg.temp_dir,1024);
if(space<(ulong)cfg.min_dspace) {
bputs(text[LowDiskSpace]);
lprintf(LOG_ERR,"Diskspace is low: %s (%lu kilobytes)"
,cfg.temp_dir,space);
if(!dir_op(dirnum))
break;
}
bprintf(text[DiskNBytesFree],ultoac(space,tmp));
if(!getfilespec(str))
break;
if(!checkfname(str))
break;
SAFEPRINTF2(tmp2,"added %s to %s"
,str,f.name);
logline(nulstr,tmp2);
SAFEPRINTF2(tmp2,"%s%s",cfg.temp_dir,str);
SAFEPRINTF2(str,"%s%s",cfg.temp_dir,f.name);
external(cmdstr(temp_cmd(),str,tmp2,NULL),EX_WILDCARD|EX_STDOUT);
break;
case 'D': /* download from temp dir */
SAFEPRINTF2(str,"%s%s",cfg.temp_dir,f.name);
if(!fexist(str)) {
bprintf(text[TempFileNotCreatedYet],f.name);
break;
}
f.size=f.cdt=(long)flength(str);
f.opencount=0;
if(temp_cdt) /* if file was not free */
f.cdt=f.size;
else
f.cdt=0;
if(!(useron.exempt&FLAG('D'))
&& f.cdt>useron.cdt+useron.freecdt) {
bprintf(text[YouOnlyHaveNCredits]
,ultoac(useron.cdt+useron.freecdt,tmp));
break; /* f.cdt must equal size here */
}
if(!(useron.exempt&FLAG('T')) && !dir_op(dirnum)
&& !(cfg.dir[temp_dirnum]->misc&DIR_TFREE) && cur_cps
&& f.size/(ulong)cur_cps>timeleft) {
bputs(text[NotEnoughTimeToDl]);
break;
}
if(!chk_ar(cfg.dir[temp_dirnum]->dl_ar,&useron,&client)) {
bputs(text[CantDownloadFromDir]);
break;
}
addfiledat(&cfg,&f);
xfer_prot_menu(XFER_DOWNLOAD);
SYNC;
mnemonics(text[ProtocolOrQuit]);
SAFECOPY(tmp2,"Q");
for(i=0;i<cfg.total_prots;i++)
if(cfg.prot[i]->dlcmd[0] && chk_ar(cfg.prot[i]->ar,&useron,&client)) {
sprintf(tmp,"%c",cfg.prot[i]->mnemonic);
SAFECAT(tmp2,tmp);
}
ungetkey(useron.prot);
ch=(char)getkeys(tmp2,0);
for(i=0;i<cfg.total_prots;i++)
if(cfg.prot[i]->dlcmd[0] && cfg.prot[i]->mnemonic==ch
&& chk_ar(cfg.prot[i]->ar,&useron,&client))
break;
if(i<cfg.total_prots) {
getnodedat(cfg.node_num,&thisnode,1);
action=NODE_DLNG;
t=now;
if(cur_cps)
t+=(f.size/(ulong)cur_cps);
if(localtime_r(&t,&tm)==NULL)
break;
thisnode.aux=(tm.tm_hour*60)+tm.tm_min;
putnodedat(cfg.node_num,&thisnode); /* calculate ETA */
start=time(NULL);
error=protocol(cfg.prot[i],XFER_DOWNLOAD,str,nulstr,false);
end=time(NULL);
if(cfg.dir[temp_dirnum]->misc&DIR_TFREE)
starttime+=end-start;
if(checkprotresult(cfg.prot[i],error,&f))
downloadedfile(&f);
else
notdownloaded(f.size,start,end);
autohangup();
}
removefiledat(&cfg,&f);
break;
case 'E':
extract(usrdir[curlib][curdir[curlib]]);
sys_status&=~SS_ABORT;
break;
case 'F': /* Create a file list */
delfiles(cfg.temp_dir,ALLFILES);
create_filelist("FILELIST.TXT",0);
if(!(sys_status&SS_ABORT))
logline(nulstr,"Created list of all files");
CRLF;
sys_status&=~SS_ABORT;
break;
case 'I': /* information on what's here */
bprintf(text[TempFileInfo],f.uler,temp_file);
break;
case 'L': /* list files in dir */
if(!getfilespec(str))
break;
if(!checkfname(str))
break;
bytes=files=0L;
CRLF;
SAFEPRINTF2(tmp2,"%s%s",cfg.temp_dir,str);
glob(tmp2,0,NULL,&g);
for(i=0;i<(uint)g.gl_pathc && !msgabort();i++) {
if(isdir(g.gl_pathv[i]))
continue;
t=fdate(g.gl_pathv[i]);
bprintf("%-25s %15s %s\r\n",getfname(g.gl_pathv[i])
,ultoac((long)flength(g.gl_pathv[i]),tmp)
,timestr(t));
files++;
bytes+=(long)flength(g.gl_pathv[i]);
}
globfree(&g);
if(!files)
bputs(text[EmptyDir]);
else if(files>1)
bprintf(text[TempDirTotal],ultoac(bytes,tmp),files);
break;
case 'N': /* Create a list of new files */
delfiles(cfg.temp_dir,ALLFILES);
create_filelist("NEWFILES.TXT",FL_ULTIME);
if(!(sys_status&SS_ABORT))
logline(nulstr,"Created list of new files");
CRLF;
sys_status&=~SS_ABORT;
break;
case 'R': /* Remove files from dir */
if(!getfilespec(str) || !checkfname(str))
break;
bprintf(text[NFilesRemoved],delfiles(cfg.temp_dir,str));
break;
case 'V': /* view files in dir */
bputs(text[FileSpec]);
if(!getstr(str,64,K_NONE) || !checkfname(str))
break;
viewfiles(dirnum,str);
break;
case CR:
case 'Q': /* quit */
done=1;
break;
case 'X': /* extract from archive in temp dir */
extract(dirnum);
sys_status&=~SS_ABORT;
break;
case '?': /* menu */
if(useron.misc&(EXPERT|RIP|WIP|HTML))
menu("tempxfer");
break;
}
if(sys_status&SS_ABORT)
break;
}
free(cfg.dir[dirnum]);
cfg.total_dirs--;
#endif
}
/*****************************************************************************/
/* Handles extraction from a normal transfer file to the temp directory */
/*****************************************************************************/
void sbbs_t::extract(uint dirnum)
{
#if 0 // NFB-TODO
char fname[13],str[256],excmd[256],path[256],done
,tmp[256],intmp=0;
uint i,j;
ulong space;
file_t f;
DIR* dir;
DIRENT* dirent;
temp_dirnum=curdirnum=dirnum;
if(!strcmp(cfg.dir[dirnum]->code,"TEMP"))
intmp=1;
if(!isdir(cfg.temp_dir)) {
bprintf(text[DirectoryDoesNotExist], cfg.temp_dir);
lprintf(LOG_ERR,"Temp directory does not exist: %s", cfg.temp_dir);
return;
}
/* get free disk space */
space=getfreediskspace(cfg.temp_dir,1024);
if(space<(ulong)cfg.min_dspace) {
bputs(text[LowDiskSpace]);
lprintf(LOG_ERR,"Diskspace is low: %s (%lu kilobytes)",cfg.temp_dir,space);
if(!dir_op(dirnum))
return;
}
else if(!intmp) { /* not in temp dir */
CRLF;
}
bprintf(text[DiskNBytesFree],ultoac(space,tmp));
if(!intmp) { /* not extracting FROM temp directory */
SAFEPRINTF2(str,"%s%s",cfg.temp_dir,ALLFILES);
if(fexist(str)) {
bputs(text[RemovingTempFiles]);
dir=opendir(cfg.temp_dir);
while(dir!=NULL && (dirent=readdir(dir))!=NULL) {
SAFEPRINTF2(str,"%s%s",cfg.temp_dir,dirent->d_name);
if(!isdir(str))
remove(str);
}
if(dir!=NULL)
closedir(dir);
CRLF;
}
}
bputs(text[ExtractFrom]);
if(!getstr(fname,sizeof(fname)-1,K_NONE) || !checkfname(fname) || strchr(fname,'*')
|| strchr(fname,'?'))
return;
padfname(fname,f.name);
SAFECOPY(str,f.name);
truncsp(str);
for(i=0;i<cfg.total_fextrs;i++)
if(!stricmp(str+9,cfg.fextr[i]->ext) && chk_ar(cfg.fextr[i]->ar,&useron,&client)) {
SAFECOPY(excmd,cfg.fextr[i]->cmd);
break;
}
if(i==cfg.total_fextrs) {
bputs(text[UnextractableFile]);
return;
}
if(!intmp && !findfile(&cfg, dirnum, f.name, NULL)) { /* not temp dir */
bputs(text[SearchingAllDirs]);
for(i=0;i<usrdirs[curlib] && !msgabort();i++) {
if(i==dirnum) continue;
if(findfile(&cfg, usrdir[curlib][i], f.name, NULL))
break;
}
if(i==usrdirs[curlib]) { /* not found in cur lib */
bputs(text[SearchingAllLibs]);
for(i=j=0;i<usrlibs;i++) {
if(i==curlib) continue;
for(j=0;j<usrdirs[i] && !msgabort();j++)
if(findfile(&cfg, usrdir[i][j], f.name, NULL))
break;
if(j<usrdirs[i])
break;
}
if(i==usrlibs) {
bputs(text[FileNotFound]); /* not in database */
return;
}
dirnum=usrdir[i][j];
}
else
dirnum=usrdir[curlib][i];
}
if(sys_status&SS_ABORT)
return;
SAFEPRINTF2(path,"%s%s",cfg.dir[dirnum]->path,fname);
if(!intmp) { /* not temp dir, so get temp_file info */
f.datoffset=f.dateuled=f.datedled=0L;
f.dir=dirnum;
getfileixb(&cfg,&f);
if(!f.datoffset && !f.dateuled && !f.datedled) /* error reading ixb */
return;
f.size=0;
getfiledat(&cfg,&f);
fileinfo(&f);
if(f.altpath>0 && f.altpath<=cfg.altpaths)
SAFEPRINTF2(path,"%s%s",cfg.altpath[f.altpath-1],fname);
temp_dirnum=dirnum;
if(cfg.dir[f.dir]->misc&DIR_FREE)
temp_cdt=0L;
else
temp_cdt=f.cdt;
SAFECOPY(temp_uler,f.uler);
SAFECOPY(temp_file,f.name); /* padded filename */
}
if(!fexistcase(path)) {
bprintf(text[FileDoesNotExist],path); /* not on disk */
return;
}
done=0;
while(online && !done) {
mnemonics(text[ExtractFilesPrompt]);
switch(getkeys("EVQ",0)) {
case 'E':
if(!getfilespec(str))
break;
if(!checkfname(str))
break;
if((i=external(cmdstr(excmd,path,str,NULL),EX_STDIO))!=0) {
errormsg(WHERE,ERR_EXEC,cmdstr(excmd,path,str,NULL),i);
return;
}
SAFEPRINTF2(tmp,"extracted %s from %s", str,path);
logline(nulstr,tmp);
CRLF;
break;
case 'V':
viewfiles(dirnum,fname);
break;
default:
done=1;
break;
}
}
#endif
exec_bin(cfg.tempxfer_mod, &main_csi);
}
/****************************************************************************/
......@@ -465,8 +85,6 @@ ulong sbbs_t::create_filelist(const char *name, long mode)
SAFEPRINTF2(str,"%s%s",cfg.temp_dir,name);
remove(str);
}
SAFECOPY(temp_file,name);
SAFECOPY(temp_uler,"File List");
return(k);
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment