-
Rob Swindell authoredRob Swindell authored
listfile.cpp 30.36 KiB
/* Synchronet file database listing functions */
/****************************************************************************
* @format.tab-size 4 (Plain Text/Source Code File Header) *
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
* *
* Copyright Rob Swindell - http://www.synchro.net/copyright.html *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* See the GNU General Public License for more details: gpl.txt or *
* http://www.fsf.org/copyleft/gpl.html *
* *
* For Synchronet coding style and modification guidelines, see *
* http://www.synchro.net/source.html *
* *
* Note: If this box doesn't appear square, then you need to fix your tabs. *
****************************************************************************/
#include "sbbs.h"
#include "filedat.h"
#define BF_MAX 26 /* Batch Flag max: A-Z */
int extdesclines(char *str);
/*****************************************************************************/
/* List files in directory 'dir' that match 'filespec'. */
/* 'mode' determines other criteria */
/* the files must meet before they'll be listed. 'mode' bit FL_NOHDR doesn't */
/* list the directory header. */
/* Returns -1 if the listing was aborted, otherwise total files listed */
/*****************************************************************************/
int sbbs_t::listfiles(uint dirnum, const char *filespec, FILE* tofile, long mode)
{
char hdr[256],letter='A',*p;
uchar flagprompt=0;
int c, d;
uint i,j;
int found=0,lastbat=0,disp;
size_t m=0;
long anchor=0,next;
file_t* bf[BF_MAX]; /* bf is batch flagged files */
smb_t smb;
ulong file_row[26];
if(!smb_init_dir(&cfg, &smb, dirnum))
return 0;
if(mode&FL_ULTIME) {
last_ns_time = now;
if(!newfiles(&smb, ns_time)) // this is fast
return 0;
}
if(smb_open_dir(&cfg, &smb, dirnum) != SMB_SUCCESS)
return 0;
size_t file_count = 0;
file_t* file_list = loadfiles(&smb
, (mode&(FL_FINDDESC|FL_EXFIND)) ? NULL : filespec
, (mode&FL_ULTIME) ? ns_time : 0
, file_detail_extdesc
, (enum file_sort)cfg.dir[dirnum]->sort
, &file_count);
if(file_list == NULL || file_count < 1) {
smb_close(&smb);
free(file_list);
return 0;
}
if(!tofile) {
action=NODE_LFIL;
getnodedat(cfg.node_num,&thisnode,0);
if(thisnode.action!=NODE_LFIL) { /* was a sync */
if(getnodedat(cfg.node_num,&thisnode,true)==0) {
thisnode.action=NODE_LFIL;
putnodedat(cfg.node_num,&thisnode);
}
}
}
m = 0; // current file index
file_t* f;
while(online) {
if(found<0)
found=0;
if(m>=file_count || flagprompt) { /* End of list */
if(useron.misc&BATCHFLAG && !tofile && found && found!=lastbat
&& !(mode&(FL_EXFIND|FL_VIEW))) {
flagprompt=0;
lncntr=0;
if((i=batchflagprompt(&smb, bf, file_row, letter-'A', file_count))==2) {
m=anchor;
found-=letter-'A';
letter='A';
}
else if(i==3) {
if((long)anchor-(letter-'A')<0) {
m=0;
found=0;
}
else {
m=anchor-(letter-'A');
found-=letter-'A';
}
letter='A';
}
else if((int)i==-1) {
found = -1;
break;
}
else
break;
getnodedat(cfg.node_num,&thisnode,0);
nodesync();
}
else
break;
}
if(m < file_count)
f = &file_list[m];
if(letter>'Z')
letter='A';
if(letter=='A')
anchor=m;
if(msgabort()) { /* used to be !tofile && msgabort() */
found = -1;
break;
}
#if 0 /* unnecessary? */
if(!(mode&(FL_FINDDESC|FL_EXFIND)) && filespec[0]
&& !filematch(str,filespec)) {
m+=11;
continue;
}
#endif
if(mode&(FL_FINDDESC|FL_EXFIND)) {
p = (f->desc == NULL) ? NULL : strcasestr(f->desc, filespec);
if(!(mode&FL_EXFIND) && p==NULL) {
m++;
continue;
}
if(mode&FL_EXFIND && f->extdesc != NULL) { /* search extended description */
if(!strcasestr((char*)f->extdesc, filespec) && p == NULL) { /* not in description or */
m++; /* extended description */
continue;
}
}
else if(p == NULL) { /* no extended description and not in desc */
m++;
continue;
}
}
/** necessary?
if(mode&FL_ULTIME) {
if(ns_time>(ixbbuf[m+3]|((long)ixbbuf[m+4]<<8)|((long)ixbbuf[m+5]<<16)
|((long)ixbbuf[m+6]<<24))) {
m+=11;
continue;
}
}
**/
if(useron.misc&BATCHFLAG && letter=='A' && found && !tofile
&& !(mode&(FL_EXFIND|FL_VIEW))
&& (!mode || !(useron.misc&EXPERT)))
bputs(text[FileListBatchCommands]);
m++;
if(!found && !(mode&(FL_EXFIND|FL_VIEW))) {
for(i=0;i<usrlibs;i++)
if(usrlib[i]==cfg.dir[dirnum]->lib)
break;
for(j=0;j<usrdirs[i];j++)
if(usrdir[i][j]==dirnum)
break; /* big header */
if((!mode || !(useron.misc&EXPERT)) && !tofile && (!filespec[0]
|| (strchr(filespec,'*') || strchr(filespec,'?')))) {
sprintf(hdr,"%s%s.hdr",cfg.dir[dirnum]->data_dir,cfg.dir[dirnum]->code);
if(fexistcase(hdr))
printfile(hdr,0); /* Use DATA\DIRS\<CODE>.HDR */
else {
if(useron.misc&BATCHFLAG)
bputs(text[FileListBatchCommands]);
else {
CLS;
d=strlen(cfg.lib[usrlib[i]]->lname)>strlen(cfg.dir[dirnum]->lname) ?
strlen(cfg.lib[usrlib[i]]->lname)+17
: strlen(cfg.dir[dirnum]->lname)+17;
if(i>8 || j>8) d++;
attr(cfg.color[clr_filelsthdrbox]);
bputs("\xc9\xcd"); /* use to start with \r\n */
for(c=0;c<d;c++)
outchar('\xcd');
bputs("\xbb\r\n\xba ");
sprintf(hdr,text[BoxHdrLib],i+1,cfg.lib[usrlib[i]]->lname);
bputs(hdr);
for(c=bstrlen(hdr);c<d;c++)
outchar(' ');
attr(cfg.color[clr_filelsthdrbox]);
bputs("\xba\r\n\xba ");
sprintf(hdr,text[BoxHdrDir],j+1,cfg.dir[dirnum]->lname);
bputs(hdr);
for(c=bstrlen(hdr);c<d;c++)
outchar(' ');
attr(cfg.color[clr_filelsthdrbox]);
bputs("\xba\r\n\xba ");
sprintf(hdr,text[BoxHdrFiles], file_count);
bputs(hdr);
for(c=bstrlen(hdr);c<d;c++)
outchar(' ');
attr(cfg.color[clr_filelsthdrbox]);
bputs("\xba\r\n\xc8\xcd");
for(c=0;c<d;c++)
outchar('\xcd');
bputs("\xbc\r\n");
}
}
}
else { /* short header */
if(tofile) {
c = fprintf(tofile,"\r\n(%u) %s ",i+1,cfg.lib[usrlib[i]]->sname) - 2;
}
else {
sprintf(hdr,text[ShortHdrLib],i+1,cfg.lib[usrlib[i]]->sname);
bputs("\r\1>\r\n");
bputs(hdr);
c=bstrlen(hdr);
}
if(tofile) {
c += fprintf(tofile,"(%u) %s",j+1,cfg.dir[dirnum]->lname);
}
else {
sprintf(hdr,text[ShortHdrDir],j+1,cfg.dir[dirnum]->lname);
bputs(hdr);
c+=bstrlen(hdr);
}
if(tofile) {
fprintf(tofile,"\r\n%.*s\r\n", c, "----------------------------------------------------------------");
}
else {
CRLF;
attr(cfg.color[clr_filelstline]);
while(c--)
outchar('\xC4');
CRLF;
}
}
}
long currow = row;
next=m;
disp=1;
if(mode&(FL_EXFIND|FL_VIEW)) {
if(!found)
bputs("\r\1>");
if(!viewfile(f, INT_TO_BOOL(mode&FL_EXFIND))) {
found = -1;
break;
}
CRLF;
}
else if(tofile)
listfiletofile(f, tofile);
else if(mode&FL_FINDDESC)
disp=listfile(f, dirnum, filespec, letter);
else
disp=listfile(f, dirnum, nulstr, letter);
if(!disp && letter>'A') {
next=m-1;
letter--;
}
else {
disp=1;
found++;
}
if(sys_status&SS_ABORT) {
found = -1;
break;
}
if(mode&(FL_EXFIND|FL_VIEW))
continue;
if(useron.misc&BATCHFLAG && !tofile) {
if(disp) {
bf[letter-'A'] = f;
file_row[letter-'A'] = currow;
}
m++;
if(flagprompt || letter=='Z' || !disp ||
(filespec[0] && !strchr(filespec,'*') && !strchr(filespec,'?')
&& !(mode&FL_FINDDESC))
|| (useron.misc&BATCHFLAG && !tofile && lncntr>=rows-2)
) {
flagprompt=0;
lncntr=0;
lastbat=found;
if((int)(i=batchflagprompt(&smb, bf, file_row, letter-'A'+1, file_count))<1) {
if((int)i==-1)
found = -1;
break;
}
if(i==2) {
next=anchor;
found-=(letter-'A')+1;
}
else if(i==3) {
if((long)anchor-((letter-'A'+1))<0) {
next=0;
found=0;
}
else {
next=anchor-((letter-'A'+1));
found-=letter-'A'+1;
}
}
getnodedat(cfg.node_num,&thisnode,0);
nodesync();
letter='A';
}
else
letter++;
}
if(useron.misc&BATCHFLAG && !tofile
&& lncntr>=rows-2) {
lncntr=0; /* defeat pause() */
flagprompt=1;
}
m=next;
if(mode&FL_FINDDESC) continue;
if(filespec[0] && !strchr(filespec,'*') && !strchr(filespec,'?') && m)
break;
}
freefiles(file_list, file_count);
smb_close(&smb);
return found;
}
/****************************************************************************/
/* Prints one file's information on a single line */
/* Return 1 if displayed, 0 otherwise */
/****************************************************************************/
bool sbbs_t::listfile(file_t* f, uint dirnum, const char *search, const char letter)
{
char *ptr,*cr,*lf;
bool exist = true;
char* ext=NULL;
char path[MAX_PATH+1];
int i,j;
off_t cdt;
int size_attr=clr_filecdt;
if(f->extdesc != NULL && *f->extdesc && (useron.misc&EXTDESC)) {
ext = f->extdesc;
if((useron.misc&BATCHFLAG) && lncntr+extdesclines(ext)>=rows-2 && letter!='A')
return false;
}
attr(cfg.color[clr_filename]);
char fname[13]; /* This is one of the only 8.3 filename formats left! (used for display purposes only) */
bprintf("%-*s", (int)sizeof(fname)-1, format_filename(f->name, fname, sizeof(fname)-1, /* pad: */TRUE));
getfilepath(&cfg, f, path);
if(f->extdesc != NULL && *f->extdesc && !(useron.misc&EXTDESC))
outchar('+');
else
outchar(' ');
if(useron.misc&BATCHFLAG) {
attr(cfg.color[clr_filedesc]);
bprintf("%c",letter);
}
cdt = f->cost;
if(f->size == -1) {
exist = false;
size_attr = clr_err;
}
else if((cfg.dir[dirnum]->misc & (DIR_FREE | DIR_FCHK)) == (DIR_FREE | DIR_FCHK))
cdt = getfilesize(&cfg, f);
char bytes[32];
unsigned units = 1;
do {
byte_estimate_to_str(cdt, bytes, sizeof(bytes), units, /* precision: */1);
units *= 1024;
} while(strlen(bytes) > 6 && units < 1024 * 1024 * 1024);
attr(cfg.color[size_attr]);
if(useron.misc&BATCHFLAG) {
if(!cdt && !(cfg.dir[dirnum]->misc&DIR_FREE)) {
attr(curatr^(HIGH|BLINK));
bputs(" FREE");
}
else
bprintf("%6s", bytes);
}
else {
if(!cdt && !(cfg.dir[dirnum]->misc&DIR_FREE)) { /* FREE file */
attr(curatr^(HIGH|BLINK));
bputs(" FREE");
}
else
bprintf("%7s", bytes);
}
if(exist)
outchar(' ');
else
outchar('-');
attr(cfg.color[clr_filedesc]);
if(ext == NULL) {
char* fdesc = f->desc;
SKIP_WHITESPACE(fdesc);
if(fdesc == NULL || *fdesc == '\0')
bputs(P_TRUNCATE, f->name);
else if(search[0]) { /* high-light string in string */
ptr = strcasestr(fdesc, search);
if(ptr != NULL) {
i=strlen(search);
j=ptr - fdesc;
bprintf("%.*s",j,fdesc);
attr(cfg.color[clr_filedesc]^HIGH);
bprintf("%.*s",i,fdesc+j);
attr(cfg.color[clr_filedesc]);
bprintf("%.*s",(int)strlen(fdesc)-(j+i),fdesc+j+i);
}
}
else {
bputs(P_TRUNCATE, fdesc);
}
CRLF;
} else {
char* ext_desc = strdup((char*)ext);
truncsp(ext_desc);
ptr=(char*)ext_desc;
SKIP_CRLF(ptr);
while(ptr && *ptr && !msgabort()) {
cr=strchr(ptr,CR);
lf=strchr(ptr,LF);
if(lf && (lf<cr || !cr)) cr=lf;
if(cr>ptr+LEN_FDESC)
cr=ptr+LEN_FDESC;
else if(cr)
*cr=0;
char str[256];
sprintf(str,"%.*s\r\n",LEN_FDESC,ptr);
putmsg(str,P_NOATCODES|P_SAVEATR);
if(!cr) {
if(strlen(ptr)>LEN_FDESC)
cr=ptr+LEN_FDESC;
else
break;
}
if(!(*(cr+1)) || !(*(cr+2)))
break;
bprintf("%21s",nulstr);
ptr=cr;
if(!(*ptr)) ptr++;
while(*ptr==LF || *ptr==CR) ptr++;
}
free(ext_desc);
}
return true;
}
/****************************************************************************/
/* Batch flagging prompt for download, extended info, and archive viewing */
/* Returns -1 if 'Q' or Ctrl-C, 0 if skip, 1 if [Enter], 2 otherwise */
/* or 3, backwards. */
/****************************************************************************/
int sbbs_t::batchflagprompt(smb_t* smb, file_t** bf, ulong* row, uint total
,long totalfiles)
{
char ch,str[256],*p,remcdt=0,remfile=0;
int c, d;
char path[MAX_PATH + 1];
uint i,j,ml=0,md=0,udir,ulib;
for(ulib=0;ulib<usrlibs;ulib++)
if(usrlib[ulib]==cfg.dir[smb->dirnum]->lib)
break;
for(udir=0;udir<usrdirs[ulib];udir++)
if(usrdir[ulib][udir]==smb->dirnum)
break;
CRLF;
while(online) {
bprintf(text[BatchFlagPrompt]
,ulib+1
,cfg.lib[cfg.dir[smb->dirnum]->lib]->sname
,udir+1
,cfg.dir[smb->dirnum]->sname
,total, totalfiles);
ch=getkey(K_UPPER);
clearline();
if(ch=='?') {
menu("batflag");
if(lncntr)
pause();
return(2);
}
if(ch==text[YNQP][2] || sys_status&SS_ABORT)
return(-1);
if(ch=='S')
return(0);
if(ch=='P' || ch=='-')
return(3);
if(ch=='B' || ch=='D') { /* Flag for batch download */
if(useron.rest&FLAG('D')) {
bputs(text[R_Download]);
return(2);
}
if(total==1) {
addtobatdl(bf[0]);
if(ch=='D')
start_batch_download();
CRLF;
return(2);
}
link_list_t saved_hotspots = mouse_hotspots;
ZERO_VAR(mouse_hotspots);
for(i=0; i < total; i++)
add_hotspot((char)('A' + i), /* hungry: */true, -1, -1, row[i]);
bputs(text[BatchDlFlags]);
d=getstr(str, BF_MAX, K_NOCRLF);
clear_hotspots();
mouse_hotspots = saved_hotspots;
lncntr=0;
if(sys_status&SS_ABORT)
return(-1);
if(d > 0) { /* d is string length */
strupr(str);
CRLF;
lncntr=0;
for(c=0;c<d;c++) {
if(batdn_total() >= cfg.max_batdn) {
bprintf(text[BatchDlQueueIsFull],str+c);
break;
}
if(str[c]=='*' || strchr(str+c,'.')) { /* filename or spec given */
// f.dir=dirnum;
p=strchr(str+c,' ');
if(!p) p=strchr(str+c,',');
if(p) *p=0;
for(i=0;i<total;i++) {
if(batdn_total() >= cfg.max_batdn) {
bprintf(text[BatchDlQueueIsFull],str+c);
break;
}
if(filematch(bf[i]->name, str+c)) {
addtobatdl(bf[i]);
}
}
}
if(strchr(str+c,'.'))
c+=strlen(str+c);
else if(str[c]<'A'+(char)total && str[c]>='A') {
addtobatdl(bf[str[c]-'A']);
}
}
if(ch=='D')
start_batch_download();
CRLF;
return(2);
}
clearline();
continue;
}
if(ch=='E' || ch=='V') { /* Extended Info */
if(total==1) {
if(!viewfile(bf[0], ch=='E'))
return(-1);
return(2);
}
link_list_t saved_hotspots = mouse_hotspots;
ZERO_VAR(mouse_hotspots);
for(i=0; i < total; i++)
add_hotspot((char)('A' + i), /* hungry: */true, -1, -1, row[i]);
bputs(text[BatchDlFlags]);
d=getstr(str, BF_MAX, K_NOCRLF);
clear_hotspots();
mouse_hotspots = saved_hotspots;
lncntr=0;
if(sys_status&SS_ABORT)
return(-1);
if(d > 0) { /* d is string length */
strupr(str);
CRLF;
lncntr=0;
for(c=0;c<d;c++) {
if(str[c]=='*' || strchr(str+c,'.')) { /* filename or spec given */
// f.dir=dirnum;
p=strchr(str+c,' ');
if(!p) p=strchr(str+c,',');
if(p) *p=0;
for(i=0;i<total;i++) {
if(filematch(bf[i]->name, str+c)) {
if(!viewfile(bf[i], ch=='E'))
return(-1);
}
}
}
if(strchr(str+c,'.'))
c+=strlen(str+c);
else if(str[c]<'A'+(char)total && str[c]>='A') {
if(!viewfile(bf[str[c]-'A'], ch=='E'))
return(-1);
}
}
cond_newline();
return(2);
}
clearline();
continue;
}
if((ch=='R' || ch=='M') /* Delete or Move */
&& !(useron.rest&FLAG('R'))
&& (dir_op(smb->dirnum) || useron.exempt&FLAG('R'))) {
if(total==1) {
strcpy(str,"A");
d=1;
}
else {
link_list_t saved_hotspots = mouse_hotspots;
ZERO_VAR(mouse_hotspots);
for(i=0; i < total; i++)
add_hotspot((char)('A' + i), /* hungry: */true, -1, -1, row[i]);
bputs(text[BatchDlFlags]);
d=getstr(str, BF_MAX, K_NOCRLF);
clear_hotspots();
mouse_hotspots = saved_hotspots;
}
lncntr=0;
if(sys_status&SS_ABORT)
return(-1);
if(d > 0) { /* d is string length */
strupr(str);
if(total > 1)
newline();
if(ch=='R') {
if(noyes(text[RemoveFileQ]))
return(2);
remcdt = TRUE;
remfile = TRUE;
if(dir_op(smb->dirnum)) {
remcdt=!noyes(text[RemoveCreditsQ]);
remfile=!noyes(text[DeleteFileQ]);
}
}
else if(ch=='M') {
CRLF;
for(i=0;i<usrlibs;i++)
bprintf(text[MoveToLibLstFmt],i+1,cfg.lib[usrlib[i]]->lname);
SYNC;
bprintf(text[MoveToLibPrompt],cfg.dir[smb->dirnum]->lib+1);
if((int)(ml=getnum(usrlibs))==-1)
return(2);
if(!ml)
ml=cfg.dir[smb->dirnum]->lib;
else
ml--;
CRLF;
for(j=0;j<usrdirs[ml];j++)
bprintf(text[MoveToDirLstFmt]
,j+1,cfg.dir[usrdir[ml][j]]->lname);
SYNC;
bprintf(text[MoveToDirPrompt],usrdirs[ml]);
if((int)(md=getnum(usrdirs[ml]))==-1)
return(2);
if(!md)
md=usrdirs[ml]-1;
else md--;
CRLF;
}
lncntr=0;
for(c=0;c<d;c++) {
if(str[c]=='*' || strchr(str+c,'.')) { /* filename or spec given */
// f.dir=dirnum;
p=strchr(str+c,' ');
if(!p) p=strchr(str+c,',');
if(p) *p=0;
for(i=0;i<total;i++) {
if(filematch(bf[i]->name, str+c)) {
if(ch=='R') {
if(removefile(smb, bf[i])) {
if(remfile) {
if(remove(getfilepath(&cfg, bf[i], path)) != 0)
errormsg(WHERE, ERR_REMOVE, path);
}
if(remcdt)
removefcdt(bf[i]);
}
}
else if(ch=='M')
movefile(smb, bf[i], usrdir[ml][md]);
}
}
}
if(strchr(str+c,'.'))
c+=strlen(str+c);
else if(str[c]<'A'+(char)total && str[c]>='A') {
file_t* f = bf[str[c]-'A'];
if(ch=='R') {
if(removefile(smb, f)) {
if(remfile) {
if(remove(getfilepath(&cfg, f, path)) != 0 && fexist(path))
errormsg(WHERE, ERR_REMOVE, path);
}
if(remcdt)
removefcdt(f);
}
}
else if(ch=='M')
movefile(smb, f, usrdir[ml][md]);
}
}
return(2);
}
clearline();
continue;
}
return(1);
}
return(-1);
}
/****************************************************************************/
/* List detailed information about the files in 'filespec'. Prompts for */
/* action depending on 'mode.' */
/* Returns number of files matching filespec that were found */
/****************************************************************************/
int sbbs_t::listfileinfo(uint dirnum, const char *filespec, long mode)
{
char str[MAX_PATH + 1],path[MAX_PATH + 1],dirpath[MAX_PATH + 1],done=0,ch;
char tmp[512];
int error;
int found=0;
uint i,j;
size_t m;
time_t start,end,t;
file_t* f;
struct tm tm;
smb_t smb;
if(!smb_init_dir(&cfg, &smb, dirnum))
return 0;
if(smb_open_dir(&cfg, &smb, dirnum) != SMB_SUCCESS)
return 0;
size_t file_count = 0;
file_t* file_list = loadfiles(&smb
, filespec
, /* time_t */0
, file_detail_extdesc
, (enum file_sort)cfg.dir[dirnum]->sort
, &file_count);
if(file_list == NULL || file_count < 1) {
smb_close(&smb);
free(file_list);
return 0;
}
m=0;
while(online && !done && m < file_count) {
f = &file_list[m];
if(mode==FI_REMOVE && dir_op(dirnum))
action=NODE_SYSP;
else action=NODE_LFIL;
if(msgabort()) {
found=-1;
break;
}
m++;
if(mode==FI_OLD && f->hdr.last_downloaded > ns_time)
continue;
if((mode==FI_OLDUL || mode==FI_OLD) && f->hdr.when_written.time > ns_time)
continue;
curdirnum = dirnum;
if(mode==FI_OFFLINE && getfilesize(&cfg, f) >= 0)
continue;
if(mode==FI_USERXFER) {
str_list_t dest_user_list = strListSplitCopy(NULL, f->to_list, ",");
char usernum[16];
SAFEPRINTF(usernum, "%u", useron.number);
int dest_user = strListFind(dest_user_list, usernum, /* case-sensitive: */true);
strListFree(&dest_user_list);
if(dest_user < 0)
continue;
}
SAFECOPY(dirpath, cfg.dir[f->dir]->path);
if((mode==FI_REMOVE) && (!dir_op(dirnum) && stricmp(f->from
,useron.alias) && !(useron.exempt&FLAG('R'))))
continue;
found++;
if(mode==FI_INFO) {
switch(viewfile(f, true)) {
case 0:
done=1;
found=-1;
break;
case -2:
m--;
if(m)
m--;
break;
}
}
else {
showfileinfo(f, /* show_extdesc: */mode != FI_DOWNLOAD);
// newline();
}
if(mode==FI_REMOVE || mode==FI_OLD || mode==FI_OLDUL
|| mode==FI_OFFLINE) {
SYNC;
// CRLF;
SAFECOPY(str, "VEQRNP\b-\r");
if(dir_op(dirnum)) {
mnemonics(text[SysopRemoveFilePrompt]);
SAFECAT(str,"FMC");
}
else if(useron.exempt&FLAG('R')) {
mnemonics(text[RExemptRemoveFilePrompt]);
SAFECAT(str,"M");
}
else
mnemonics(text[UserRemoveFilePrompt]);
switch(getkeys(str,0)) {
case 'V':
viewfilecontents(f);
CRLF;
ASYNC;
pause();
m--;
continue;
case 'E': /* edit file information */
if(dir_op(dirnum)) {
bputs(text[EditFilename]);
SAFECOPY(str, f->name);
if(!getstr(str, MAX_FILENAME_LEN, K_EDIT|K_AUTODEL))
break;
if(strcmp(str,f->name) != 0) { /* rename */
if(stricmp(str,f->name)
&& findfile(&cfg, f->dir, path, NULL))
bprintf(text[FileAlreadyThere],path);
else {
SAFEPRINTF2(path,"%s%s",dirpath,f->name);
SAFEPRINTF2(tmp,"%s%s",dirpath,str);
if(fexistcase(path) && rename(path,tmp))
bprintf(text[CouldntRenameFile],path,tmp);
else {
bprintf(text[FileRenamed],path,tmp);
smb_new_hfield_str(f, SMB_FILENAME, str);
updatefile(&cfg, f);
}
}
}
}
// Description
bputs(text[EditDescription]);
char fdesc[LEN_FDESC + 1];
SAFECOPY(fdesc, f->desc);
getstr(fdesc, sizeof(fdesc)-1, K_LINE|K_EDIT|K_AUTODEL|K_TRIM);
if(sys_status&SS_ABORT)
break;
if(strcmp(fdesc, f->desc))
smb_new_hfield_str(f, SMB_FILEDESC, fdesc);
// Tags
if((cfg.dir[dirnum]->misc & DIR_FILETAGS) || dir_op(dirnum)) {
char tags[64] = "";
bputs(text[TagFilePrompt]);
if(f->tags != NULL)
SAFECOPY(tags, f->tags);
getstr(tags, sizeof(tags)-1, K_LINE|K_EDIT|K_AUTODEL|K_TRIM);
if(sys_status&SS_ABORT)
break;
if((f->tags == NULL && *tags != '\0') || (f->tags != NULL && strcmp(tags, f->tags)))
smb_new_hfield_str(f, SMB_TAGS, tags);
}
// Extended Description
if(f->extdesc != NULL && *f->extdesc) {
if(!noyes(text[DeleteExtDescriptionQ])) {
// TODO
}
}
if(!dir_op(dirnum)) {
updatefile(&cfg, f);
break;
}
char uploader[LEN_ALIAS + 1];
SAFECOPY(uploader, f->from);
bputs(text[EditUploader]);
if(!getstr(uploader, sizeof(uploader), K_EDIT|K_AUTODEL))
break;
smb_new_hfield_str(f, SMB_FILEUPLOADER, uploader);
ultoa(f->cost,str,10);
bputs(text[EditCreditValue]);
getstr(str,10,K_NUMBER|K_EDIT|K_AUTODEL);
if(sys_status&SS_ABORT)
break;
f->cost = atol(str);
smb_new_hfield(f, SMB_COST, sizeof(f->cost), &f->cost);
ultoa(f->hdr.times_downloaded,str,10);
bputs(text[EditTimesDownloaded]);
getstr(str,5,K_NUMBER|K_EDIT|K_AUTODEL);
if(sys_status&SS_ABORT)
break;
f->hdr.times_downloaded=atoi(str);
if(sys_status&SS_ABORT)
break;
inputnstime32((time32_t*)&f->hdr.when_imported.time);
updatefile(&cfg, f);
break;
case 'F': /* delete file only */
SAFEPRINTF2(str,"%s%s",dirpath,f->name);
if(!fexistcase(str))
bprintf(text[FileDoesNotExist],str);
else {
if(!noyes(text[DeleteFileQ])) {
if(remove(str))
bprintf(text[CouldntRemoveFile],str);
else {
SAFEPRINTF(tmp, "deleted %s", str);
logline(nulstr, tmp);
}
}
}
break;
case 'R': /* remove file from database */
if(noyes(text[RemoveFileQ]))
break;
if(removefile(&smb, f)) {
getfilepath(&cfg, f, path);
if(fexistcase(path)) {
if(dir_op(dirnum)) {
if(!noyes(text[DeleteFileQ])) {
if(remove(path) != 0)
errormsg(WHERE, ERR_REMOVE, path);
else {
SAFEPRINTF(tmp, "deleted %s", path);
logline(nulstr,path);
}
}
}
else if(remove(str)) /* always remove if not sysop */
bprintf(text[CouldntRemoveFile],str);
}
}
if(dir_op(dirnum) || useron.exempt&FLAG('R')) {
i=cfg.lib[cfg.dir[f->dir]->lib]->offline_dir;
if(i!=dirnum && i!=INVALID_DIR
&& !findfile(&cfg, i, f->name, NULL)) {
sprintf(str,text[AddToOfflineDirQ]
,f->name,cfg.lib[cfg.dir[i]->lib]->sname,cfg.dir[i]->sname);
if(yesno(str)) {
addfile(&cfg, i, f, f->extdesc, /* client: */NULL);
}
}
}
if(dir_op(dirnum) || stricmp(f->from, useron.alias)) {
if(noyes(text[RemoveCreditsQ]))
/* Fall through */ break;
}
case 'C': /* remove credits only */
removefcdt(f);
break;
case 'M': /* move the file to another dir */
CRLF;
for(i=0;i<usrlibs;i++)
bprintf(text[MoveToLibLstFmt],i+1,cfg.lib[usrlib[i]]->lname);
SYNC;
bprintf(text[MoveToLibPrompt],cfg.dir[dirnum]->lib+1);
if((int)(i=getnum(usrlibs))==-1)
continue;
if(!i)
i=cfg.dir[dirnum]->lib;
else
i--;
CRLF;
for(j=0;j<usrdirs[i];j++)
bprintf(text[MoveToDirLstFmt]
,j+1,cfg.dir[usrdir[i][j]]->lname);
SYNC;
bprintf(text[MoveToDirPrompt],usrdirs[i]);
if((int)(j=getnum(usrdirs[i]))==-1)
continue;
if(!j)
j=usrdirs[i]-1;
else j--;
CRLF;
movefile(&smb, f, usrdir[i][j]);
break;
case 'P': /* previous */
case '-':
case '\b':
m--;
if(m)
m--;
break;
case 'Q': /* quit */
found=-1;
done=1;
break;
}
}
else if(mode==FI_DOWNLOAD || mode==FI_USERXFER) {
getfilepath(&cfg, f, path);
if(getfilesize(&cfg, f) < 1L) { /* getfilesize will set this to -1 if non-existant */
SYNC; /* and 0 byte files shouldn't be d/led */
mnemonics(text[QuitOrNext]);
if(getkeys("\rQ",0)=='Q') {
found=-1;
break;
}
continue;
}
if(!is_download_free(&cfg,f->dir,&useron,&client)
&& f->cost>(useron.cdt+useron.freecdt)) {
SYNC;
bprintf(text[YouOnlyHaveNCredits]
,ultoac(useron.cdt+useron.freecdt,tmp));
mnemonics(text[QuitOrNext]);
if(getkeys("\rQ",0)=='Q') {
found=-1;
break;
}
continue;
}
if(!chk_ar(cfg.dir[f->dir]->dl_ar,&useron,&client)) {
SYNC;
bputs(text[CantDownloadFromDir]);
mnemonics(text[QuitOrNext]);
if(getkeys("\rQ",0)=='Q') {
found=-1;
break;
}
continue;
}
if(!(cfg.dir[f->dir]->misc&DIR_TFREE) && gettimetodl(&cfg, f, cur_cps) > timeleft && !dir_op(dirnum)
&& !(useron.exempt&FLAG('T'))) {
SYNC;
bputs(text[NotEnoughTimeToDl]);
mnemonics(text[QuitOrNext]);
if(getkeys("\rQ",0)=='Q') {
found=-1;
break;
}
continue;
}
xfer_prot_menu(XFER_DOWNLOAD);
SYNC;
mnemonics(text[ProtocolBatchQuitOrNext]);
sprintf(str,"B%cN\r",text[YNQP][2]);
for(i=0;i<cfg.total_prots;i++)
if(cfg.prot[i]->dlcmd[0]
&& chk_ar(cfg.prot[i]->ar,&useron,&client)) {
sprintf(str + strlen(str), "%c", cfg.prot[i]->mnemonic);
}
// ungetkey(useron.prot);
ch=(char)getkeys(str,0);
if(ch==text[YNQP][2]) {
found=-1;
done=1;
}
else if(ch=='B') {
if(!addtobatdl(f)) {
break;
}
}
else if(ch!=CR && ch!='N') {
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) {
delfiles(cfg.temp_dir,ALLFILES);
if(cfg.dir[f->dir]->seqdev) {
lncntr=0;
seqwait(cfg.dir[f->dir]->seqdev);
bprintf(text[RetrievingFile],f->name);
getfilepath(&cfg, f, str);
SAFEPRINTF2(path,"%s%s",cfg.temp_dir,f->name);
mv(str,path,1); /* copy the file to temp dir */
if(getnodedat(cfg.node_num,&thisnode,true)==0) {
thisnode.aux=0xf0;
putnodedat(cfg.node_num,&thisnode);
}
CRLF;
}
const char* file_ext = getfext(f->name);
if(file_ext != NULL) {
for(j=0; j<cfg.total_dlevents; j++) {
if(!stricmp(cfg.dlevent[j]->ext, file_ext + 1)
&& chk_ar(cfg.dlevent[j]->ar,&useron,&client)) {
bputs(cfg.dlevent[j]->workstr);
external(cmdstr(cfg.dlevent[j]->cmd,path,nulstr,NULL)
,EX_OUTL);
CRLF;
}
}
}
getnodedat(cfg.node_num,&thisnode,1);
action=NODE_DLNG;
t=now + gettimetodl(&cfg, f, cur_cps);
localtime_r(&t,&tm);
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,path,nulstr,false);
end=time(NULL);
if(cfg.dir[f->dir]->misc&DIR_TFREE)
starttime+=end-start;
if(checkprotresult(cfg.prot[i],error, f))
downloadedfile(f);
else
notdownloaded(f->size, start, end);
delfiles(cfg.temp_dir,ALLFILES);
autohangup();
}
}
}
if(filespec[0] && !strchr(filespec,'*') && !strchr(filespec,'?'))
break;
}
freefiles(file_list, file_count);
smb_close(&smb);
return(found);
}
/****************************************************************************/
/* Prints one file's information on a single line to a file stream 'fp' */
/****************************************************************************/
void sbbs_t::listfiletofile(file_t* f, FILE* fp)
{
char fname[13]; /* This is one of the only 8.3 filename formats left! (used for display purposes only) */
fprintf(fp, "%-*s %10lu %s\r\n", (int)sizeof(fname)-1, format_filename(f->name, fname, sizeof(fname)-1, /* pad: */TRUE)
,(ulong)getfilesize(&cfg, f), f->desc);
}
int extdesclines(char *str)
{
int i,lc,last;
for(i=lc=last=0;str[i];i++)
if(str[i]==LF || i-last>LEN_FDESC) {
lc++;
last=i;
}
return(lc);
}