listfile.cpp 38.9 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
/* listfile.cpp */

/* Synchronet file database listing functions */

/* $Id$ */

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
rswindell's avatar
rswindell committed
11
 * Copyright 2009 Rob Swindell - http://www.synchro.net/copyright.html		*
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
 *																			*
 * 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										*
 *																			*
 * Anonymous FTP access to the most recent released source is available at	*
 * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
 *																			*
 * Anonymous CVS access to the development source and modification history	*
 * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
 *     (just hit return, no password is necessary)							*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
 *																			*
 * For Synchronet coding style and modification guidelines, see				*
 * http://www.synchro.net/source.html										*
 *																			*
 * You are encouraged to submit any modifications (preferably in Unix diff	*
 * format) via e-mail to mods@synchro.net									*
 *																			*
 * Note: If this box doesn't appear square, then you need to fix your tabs.	*
 ****************************************************************************/

#include "sbbs.h"

#define BF_MAX	26	/* Batch Flag max: A-Z */	

int extdesclines(char *str);

/*****************************************************************************/
/* List files in directory 'dir' that match 'filespec'. Filespec must be 	 */
/* padded. ex: FILE*   .EXT, not FILE*.EXT. 'mode' determines other critiria */
/* 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		 */
/*****************************************************************************/
51
int sbbs_t::listfiles(uint dirnum, const char *filespec, int tofile, long mode)
52
53
{
	char	str[256],hdr[256],c,d,letter='A',*p,*datbuf,ext[513];
54
	char 	tmp[512];
55
56
57
58
	uchar*	ixbbuf;
	uchar	flagprompt=0;
	uint	i,j;
	int		file,found=0,lastbat=0,disp;
deuce's avatar
64-bit    
deuce committed
59
60
	long	m=0,n,anchor=0,next,datbuflen;
	int32_t	l;
61
62
63
64
	file_t	f,bf[26];	/* bf is batch flagged files */

	if(mode&FL_ULTIME) {
		last_ns_time=now;
65
		sprintf(str,"%s%s.dab",cfg.dir[dirnum]->data_dir,cfg.dir[dirnum]->code);
66
67
68
69
		if((file=nopen(str,O_RDONLY))!=-1) {
			read(file,&l,4);
			close(file);
			if(ns_time>(time_t)l)
70
71
72
				return(0); 
		}
	}
73
	sprintf(str,"%s%s.ixb",cfg.dir[dirnum]->data_dir,cfg.dir[dirnum]->code);
74
75
76
77
78
	if((file=nopen(str,O_RDONLY))==-1)
		return(0);
	l=filelength(file);
	if(!l) {
		close(file);
79
80
		return(0); 
	}
deuce's avatar
deuce committed
81
	if((ixbbuf=(uchar *)malloc(l))==NULL) {
82
83
		close(file);
		errormsg(WHERE,ERR_ALLOC,str,l);
84
85
		return(0); 
	}
86
87
88
	if(lread(file,ixbbuf,l)!=l) {
		close(file);
		errormsg(WHERE,ERR_READ,str,l);
deuce's avatar
deuce committed
89
		free((char *)ixbbuf);
90
91
		return(0); 
	}
92
	close(file);
93
	sprintf(str,"%s%s.dat",cfg.dir[dirnum]->data_dir,cfg.dir[dirnum]->code);
94
95
	if((file=nopen(str,O_RDONLY))==-1) {
		errormsg(WHERE,ERR_OPEN,str,O_RDONLY);
deuce's avatar
deuce committed
96
		free((char *)ixbbuf);
97
98
		return(0); 
	}
99
	datbuflen=filelength(file);
deuce's avatar
deuce committed
100
	if((datbuf=(char *)malloc(datbuflen))==NULL) {
101
102
		close(file);
		errormsg(WHERE,ERR_ALLOC,str,datbuflen);
deuce's avatar
deuce committed
103
		free((char *)ixbbuf);
104
105
		return(0); 
	}
106
107
108
	if(lread(file,datbuf,datbuflen)!=datbuflen) {
		close(file);
		errormsg(WHERE,ERR_READ,str,datbuflen);
deuce's avatar
deuce committed
109
110
		free((char *)datbuf);
		free((char *)ixbbuf);
111
112
		return(0); 
	}
113
114
115
116
117
	close(file);
	if(!tofile) {
		action=NODE_LFIL;
		getnodedat(cfg.node_num,&thisnode,0);
		if(thisnode.action!=NODE_LFIL) {	/* was a sync */
118
119
120
121
122
123
			if(getnodedat(cfg.node_num,&thisnode,true)==0) {
				thisnode.action=NODE_LFIL;
				putnodedat(cfg.node_num,&thisnode); 
			} 
		} 
	}
124
125
126
127
128
129
130
131
132
133
134
135

	while(online && found<MAX_FILES) {
		if(found<0)
			found=0;
		if(m>=l || flagprompt) {		  /* End of list */
			if(useron.misc&BATCHFLAG && !tofile && found && found!=lastbat
				&& !(mode&(FL_EXFIND|FL_VIEW))) {
				flagprompt=0;
				lncntr=0;
				if((i=batchflagprompt(dirnum,bf,letter-'A',l/F_IXBSIZE))==2) {
					m=anchor;
					found-=letter-'A';
136
137
					letter='A'; 
				}
138
139
140
				else if(i==3) {
					if((long)anchor-((letter-'A')*F_IXBSIZE)<0) {
						m=0;
141
142
						found=0; 
					}
143
144
					else {
						m=anchor-((letter-'A')*F_IXBSIZE);
145
146
147
148
						found-=letter-'A'; 
					}
					letter='A'; 
				}
149
				else if((int)i==-1) {
deuce's avatar
deuce committed
150
151
					free((char *)ixbbuf);
					free((char *)datbuf);
152
153
					return(-1); 
				}
154
155
156
				else
					break;
				getnodedat(cfg.node_num,&thisnode,0);
157
158
				nodesync(); 
			}
159
			else
160
161
				break; 
		}
162
163
164
165
166
167
168

		if(letter>'Z')
			letter='A';
		if(letter=='A')
			anchor=m;

		if(msgabort()) {		 /* used to be !tofile && msgabort() */
deuce's avatar
deuce committed
169
170
			free((char *)ixbbuf);
			free((char *)datbuf);
171
172
			return(-1); 
		}
173
		for(j=0;j<12 && m<l;j++)
174
175
			if(j==8)
				str[j]=ixbbuf[m]>' ' ? '.' : ' ';
176
177
178
179
180
181
			else
				str[j]=ixbbuf[m++];		/* Turns FILENAMEEXT into FILENAME.EXT */
		str[j]=0;
		if(!(mode&(FL_FINDDESC|FL_EXFIND)) && filespec[0]
			&& !filematch(str,filespec)) {
			m+=11;
182
183
			continue; 
		}
184
185
186
		n=ixbbuf[m]|((long)ixbbuf[m+1]<<8)|((long)ixbbuf[m+2]<<16);
		if(n>=datbuflen) {	/* out of bounds */
			m+=11;
187
188
			continue; 
		}
189
190
191
192
193
194
		if(mode&(FL_FINDDESC|FL_EXFIND)) {
			getrec((char *)&datbuf[n],F_DESC,LEN_FDESC,tmp);
			strupr(tmp);
			p=strstr(tmp,filespec);
			if(!(mode&FL_EXFIND) && p==NULL) {
				m+=11;
195
196
				continue; 
			}
197
198
			getrec((char *)&datbuf[n],F_MISC,1,tmp);
			j=tmp[0];  /* misc bits */
199
			if(j) j-=' ';
200
			if(mode&FL_EXFIND && j&FM_EXTDESC) { /* search extended description */
201
				getextdesc(&cfg,dirnum,n,ext);
202
203
204
				strupr(ext);
				if(!strstr(ext,filespec) && !p) {	/* not in description or */
					m+=11;						 /* extended description */
205
206
207
					continue; 
				}
			}
208
209
			else if(!p) {			 /* no extended description and not in desc */
				m+=11;
210
211
				continue; } 
		}
212
213
214
215
		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;
216
217
				continue; } 
		}
218
219
220
221
222
223
224
225
226
227
228
229
230
231
		if(useron.misc&BATCHFLAG && letter=='A' && found && !tofile
			&& !(mode&(FL_EXFIND|FL_VIEW))
			&& (!mode || !(useron.misc&EXPERT)))
			bputs(text[FileListBatchCommands]);
		m+=11;
		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,'?')))) {
232
				sprintf(hdr,"%s%s.hdr",cfg.dir[dirnum]->data_dir,cfg.dir[dirnum]->code);
233
				if(fexistcase(hdr))
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
					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("");            /* use to start with \r\n */
						for(c=0;c<d;c++)
							outchar('');
						bputs("\r\n ");
						sprintf(hdr,text[BoxHdrLib],i+1,cfg.lib[usrlib[i]]->lname);
						bputs(hdr);
						for(c=bstrlen(hdr);c<d;c++)
252
							outchar(' ');
253
254
255
256
						bputs("\r\n ");
						sprintf(hdr,text[BoxHdrDir],j+1,cfg.dir[dirnum]->lname);
						bputs(hdr);
						for(c=bstrlen(hdr);c<d;c++)
257
							outchar(' ');
258
259
260
261
						bputs("\r\n ");
						sprintf(hdr,text[BoxHdrFiles],l/F_IXBSIZE);
						bputs(hdr);
						for(c=bstrlen(hdr);c<d;c++)
262
							outchar(' ');
263
264
265
						bputs("\r\n");
						for(c=0;c<d;c++)
							outchar('');
266
267
268
269
						bputs("\r\n"); 
					} 
				} 
			}
270
271
272
273
			else {					/* short header */
				if(tofile) {
					sprintf(hdr,"(%u) %s ",i+1,cfg.lib[usrlib[i]]->sname);
					write(tofile,crlf,2);
274
275
					write(tofile,hdr,strlen(hdr)); 
				}
276
277
278
				else {
					sprintf(hdr,text[ShortHdrLib],i+1,cfg.lib[usrlib[i]]->sname);
					bputs("\r\1>\r\n");
279
280
					bputs(hdr); 
				}
281
282
283
				c=bstrlen(hdr);
				if(tofile) {
					sprintf(hdr,"(%u) %s",j+1,cfg.dir[dirnum]->lname);
284
285
					write(tofile,hdr,strlen(hdr)); 
				}
286
287
				else {
					sprintf(hdr,text[ShortHdrDir],j+1,cfg.dir[dirnum]->lname);
288
289
					bputs(hdr); 
				}
290
291
292
293
				c+=bstrlen(hdr);
				if(tofile) {
					write(tofile,crlf,2);
					sprintf(hdr,"%*s",c,nulstr);
294
					memset(hdr,'',c);
295
					strcat(hdr,crlf);
296
297
					write(tofile,hdr,strlen(hdr)); 
				}
298
299
300
301
302
				else {
					CRLF;
					attr(cfg.color[clr_filelstline]);
					while(c--)
						outchar('');
303
304
305
306
					CRLF; 
				} 
			} 
		}
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
		next=m;
		disp=1;
		if(mode&(FL_EXFIND|FL_VIEW)) {
			f.dir=dirnum;
			strcpy(f.name,str);
			m-=11;
			f.datoffset=n;
			f.dateuled=ixbbuf[m+3]|((long)ixbbuf[m+4]<<8)
				|((long)ixbbuf[m+5]<<16)|((long)ixbbuf[m+6]<<24);
			f.datedled=ixbbuf[m+7]|((long)ixbbuf[m+8]<<8)
				|((long)ixbbuf[m+9]<<16)|((long)ixbbuf[m+10]<<24);
			m+=11;
			f.size=0;
			getfiledat(&cfg,&f);
			if(!found)
				bputs("\r\1>");
			if(mode&FL_EXFIND) {
				if(!viewfile(&f,1)) {
deuce's avatar
deuce committed
325
326
					free((char *)ixbbuf);
					free((char *)datbuf);
327
328
					return(-1); } 
			}
329
330
			else {
				if(!viewfile(&f,0)) {
deuce's avatar
deuce committed
331
332
					free((char *)ixbbuf);
					free((char *)datbuf);
333
334
335
336
					return(-1); 
				} 
			} 
		}
337
338
339
340
341
342
343
344
345

		else if(tofile)
			listfiletofile(str,&datbuf[n],dirnum,tofile);
		else if(mode&FL_FINDDESC)
			disp=listfile(str,&datbuf[n],dirnum,filespec,letter,n);
		else
			disp=listfile(str,&datbuf[n],dirnum,nulstr,letter,n);
		if(!disp && letter>'A') {
			next=m-F_IXBSIZE;
346
347
			letter--; 
		}
348
349
		else {
			disp=1;
350
351
			found++; 
		}
352
		if(sys_status&SS_ABORT) {
deuce's avatar
deuce committed
353
354
			free((char *)ixbbuf);
			free((char *)datbuf);
355
356
			return(-1); 
		}
357
358
359
360
361
362
363
364
365
366
		if(mode&(FL_EXFIND|FL_VIEW))
			continue;
		if(useron.misc&BATCHFLAG && !tofile) {
			if(disp) {
				strcpy(bf[letter-'A'].name,str);
				m-=11;
				bf[letter-'A'].datoffset=n;
				bf[letter-'A'].dateuled=ixbbuf[m+3]|((long)ixbbuf[m+4]<<8)
					|((long)ixbbuf[m+5]<<16)|((long)ixbbuf[m+6]<<24);
				bf[letter-'A'].datedled=ixbbuf[m+7]|((long)ixbbuf[m+8]<<8)
367
368
					|((long)ixbbuf[m+9]<<16)|((long)ixbbuf[m+10]<<24); 
			}
369
370
371
372
373
374
375
376
377
378
			m+=11;
			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(dirnum,bf,letter-'A'+1,l/F_IXBSIZE))<1) {
deuce's avatar
deuce committed
379
380
					free((char *)ixbbuf);
					free((char *)datbuf);
381
					if((int)i==-1)
382
383
						return(-1);
					else
384
385
						return(found); 
				}
386
387
				if(i==2) {
					next=anchor;
388
389
					found-=(letter-'A')+1; 
				}
390
391
392
				else if(i==3) {
					if((long)anchor-((letter-'A'+1)*F_IXBSIZE)<0) {
						next=0;
393
394
						found=0; 
					}
395
396
					else {
						next=anchor-((letter-'A'+1)*F_IXBSIZE);
397
398
						found-=letter-'A'+1; } 
				}
399
400
401
				getnodedat(cfg.node_num,&thisnode,0);
				nodesync();
				letter='A';	}
402
403
			else letter++; 
		}
404
405
406
		if(useron.misc&BATCHFLAG && !tofile
			&& lncntr>=rows-2) {
			lncntr=0;		/* defeat pause() */
407
408
			flagprompt=1; 
		}
409
410
411
		m=next;
		if(mode&FL_FINDDESC) continue;
		if(filespec[0] && !strchr(filespec,'*') && !strchr(filespec,'?') && m)
412
413
			break; 
	}
414

deuce's avatar
deuce committed
415
416
	free((char *)ixbbuf);
	free((char *)datbuf);
417
418
419
420
421
422
423
	return(found);
}

/****************************************************************************/
/* Prints one file's information on a single line                           */
/* Return 1 if displayed, 0 otherwise										*/
/****************************************************************************/
424
425
bool sbbs_t::listfile(const char *fname, const char *buf, uint dirnum
	, const char *search, const char letter, ulong datoffset)
426
{
427
	char	str[256],ext[513]="",*ptr,*cr,*lf,exist=1;
428
	char	path[MAX_PATH+1];
429
430
431
432
	char 	tmp[512];
    uchar	alt;
    int		i,j;
    ulong	cdt;
433

434
	if(buf[F_MISC]!=ETX && (buf[F_MISC]-' ')&FM_EXTDESC && useron.misc&EXTDESC) {
435
		getextdesc(&cfg,dirnum,datoffset,ext);
436
		if(useron.misc&BATCHFLAG && lncntr+extdesclines(ext)>=rows-2 && letter!='A')
437
438
			return(false); 
	}
439

440
441
	attr(cfg.color[clr_filename]);
	bputs(fname);
442

443
	getrec(buf,F_ALTPATH,2,str);
444
445
446
447
	alt=(uchar)ahtoul(str);
	sprintf(path,"%s%s",alt>0 && alt<=cfg.altpaths ? cfg.altpath[alt-1]:cfg.dir[dirnum]->path
		,unpadfname(fname,tmp));

448
	if(buf[F_MISC]!=ETX && (buf[F_MISC]-' ')&FM_EXTDESC) {
449
450
451
		if(!(useron.misc&EXTDESC))
			outchar('+');
		else
452
453
			outchar(' '); 
	}
454
	else
455
		outchar(' ');
456
457
	if(useron.misc&BATCHFLAG) {
		attr(cfg.color[clr_filedesc]);
458
459
		bprintf("%c",letter); 
	}
460
	if(cfg.dir[dirnum]->misc&DIR_FCHK && !fexistcase(path)) {
461
		exist=0;
462
463
		attr(cfg.color[clr_err]); 
	}
464
465
	else
		attr(cfg.color[clr_filecdt]);
466
	getrec(buf,F_CDT,LEN_FCDT,str);
467
468
469
470
	cdt=atol(str);
	if(useron.misc&BATCHFLAG) {
		if(!cdt) {
			attr(curatr^(HIGH|BLINK));
471
472
			bputs("  FREE"); 
		}
473
474
475
		else {
			if(cdt<1024)    /* 1k is smallest size */
				cdt=1024;
476
477
478
			if(cdt>(99999*1024))
				bprintf("%5luM",cdt/(1024*1024));
			else
479
480
				bprintf("%5luk",cdt/1024L); } 
	}
481
482
483
	else {
		if(!cdt) {  /* FREE file */
			attr(curatr^(HIGH|BLINK));
484
485
			bputs("   FREE"); 
		}
486
487
488
		else if(cdt>9999999L)
			bprintf("%6luk",cdt/1024L);
		else
489
490
			bprintf("%7lu",cdt); 
	}
491
	if(exist)
492
		outchar(' ');
493
494
	else
		outchar('-');
495
	getrec(buf,F_DESC,LEN_FDESC,str);
496
	attr(cfg.color[clr_filedesc]);
497
498
499

#ifdef _WIN32
 
500
	if(exist && !(cfg.file_misc&FM_NO_LFN)) {
501
502
		fexistcase(path);	/* Get real (long?) filename */
		ptr=getfname(path);
503
		if(stricmp(ptr,tmp) && stricmp(ptr,str))
504
			bprintf("%.*s\r\n%21s",LEN_FDESC,ptr,"");
505
	}
506

507
#endif
508

509
510
511
512
513
514
515
516
517
518
519
	if(!ext[0]) {
		if(search[0]) { /* high-light string in string */
			strcpy(tmp,str);
			strupr(tmp);
			ptr=strstr(tmp,search);
			i=strlen(search);
			j=ptr-tmp;
			bprintf("%.*s",j,str);
			attr(cfg.color[clr_filedesc]^HIGH);
			bprintf("%.*s",i,str+j);
			attr(cfg.color[clr_filedesc]);
520
521
			bprintf("%.*s",strlen(str)-(j+i),str+j+i); 
		}
522
523
		else
			bputs(str);
524
525
		CRLF; 
	}
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
	ptr=ext;
	while(*ptr && ptr<ext+512 && !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;
		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
541
542
				break; 
		}
543
544
545
546
547
		if(!(*(cr+1)) || !(*(cr+2)))
			break;
		bprintf("%21s",nulstr);
		ptr=cr;
		if(!(*ptr)) ptr++;
548
549
		while(*ptr==LF || *ptr==CR) ptr++; 
	}
550
551
552
553
554
555
556
557
	return(true);
}

/****************************************************************************/
/* Remove credits from uploader of file 'f'                                 */
/****************************************************************************/
bool sbbs_t::removefcdt(file_t* f)
{
558
559
560
561
	char	str[128];
	char 	tmp[512];
	int		u;
	long	cdt;
562

563
	if((u=matchuser(&cfg,f->uler,TRUE /*sysop_alias*/))==0) {
564
	   bputs(text[UnknownUser]);
565
566
	   return(false); 
	}
567
568
569
570
571
572
573
574
575
576
577
578
	cdt=0L;
	if(cfg.dir[f->dir]->misc&DIR_CDTMIN && cur_cps) {
		if(cfg.dir[f->dir]->misc&DIR_CDTUL)
			cdt=((ulong)(f->cdt*(cfg.dir[f->dir]->up_pct/100.0))/cur_cps)/60;
		if(cfg.dir[f->dir]->misc&DIR_CDTDL
			&& f->timesdled)  /* all downloads */
			cdt+=((ulong)((long)f->timesdled
				*f->cdt*(cfg.dir[f->dir]->dn_pct/100.0))/cur_cps)/60;
		adjustuserrec(&cfg,u,U_MIN,10,-cdt);
		sprintf(str,"%lu minute",cdt);
		sprintf(tmp,text[FileRemovedUserMsg]
			,f->name,cdt ? str : text[No]);
579
580
		putsmsg(&cfg,u,tmp); 
	}
581
582
583
584
585
586
587
588
589
590
	else {
		if(cfg.dir[f->dir]->misc&DIR_CDTUL)
			cdt=(ulong)(f->cdt*(cfg.dir[f->dir]->up_pct/100.0));
		if(cfg.dir[f->dir]->misc&DIR_CDTDL
			&& f->timesdled)  /* all downloads */
			cdt+=(ulong)((long)f->timesdled
				*f->cdt*(cfg.dir[f->dir]->dn_pct/100.0));
		adjustuserrec(&cfg,u,U_CDT,10,-cdt);
		sprintf(tmp,text[FileRemovedUserMsg]
			,f->name,cdt ? ultoac(cdt,str) : text[No]);
591
592
		putsmsg(&cfg,u,tmp); 
	}
593
594
595
596
597
598

	adjustuserrec(&cfg,u,U_ULB,10,-f->size);
	adjustuserrec(&cfg,u,U_ULS,5,-1);
	return(true);
}

599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
bool sbbs_t::removefile(file_t* f)
{
	char str[256];

	if(removefiledat(&cfg,f)) {
		SAFEPRINTF4(str,"%s removed %s from %s %s"
			,useron.alias
			,f->name
			,cfg.lib[cfg.dir[f->dir]->lib]->sname,cfg.dir[f->dir]->sname);
		logline("U-",str);
		return(true);
	}
	SAFEPRINTF2(str,"%s %s",cfg.lib[cfg.dir[f->dir]->lib]->sname,cfg.dir[f->dir]->sname);
	errormsg(WHERE, ERR_REMOVE, f->name, 0, str);
	return(false);
}

616
617
618
619
620
/****************************************************************************/
/* Move file 'f' from f.dir to newdir                                       */
/****************************************************************************/
bool sbbs_t::movefile(file_t* f, int newdir)
{
621
	char str[MAX_PATH+1],path[MAX_PATH+1],fname[128],ext[1024];
622
623
624
625
	int olddir=f->dir;

	if(findfile(&cfg,newdir,f->name)) {
		bprintf(text[FileAlreadyThere],f->name);
626
627
		return(false); 
	}
628
	getextdesc(&cfg,olddir,f->datoffset,ext);
629
630
631
632
633
634
635
636
	if(cfg.dir[olddir]->misc&DIR_MOVENEW)
		f->dateuled=time(NULL);
	unpadfname(f->name,fname);
	removefiledat(&cfg,f);
	f->dir=newdir;
	addfiledat(&cfg,f);
	bprintf(text[MovedFile],f->name
		,cfg.lib[cfg.dir[f->dir]->lib]->sname,cfg.dir[f->dir]->sname);
637
638
	sprintf(str,"%s moved %s to %s %s",f->name
		,useron.alias
639
640
641
642
		,cfg.lib[cfg.dir[f->dir]->lib]->sname,cfg.dir[f->dir]->sname);
	logline(nulstr,str);
	if(!f->altpath) {	/* move actual file */
		sprintf(str,"%s%s",cfg.dir[olddir]->path,fname);
643
		if(fexistcase(str)) {
644
645
646
647
			sprintf(path,"%s%s",cfg.dir[f->dir]->path,getfname(str));
			mv(str,path,0); 
		} 
	}
648
	if(f->misc&FM_EXTDESC)
649
		putextdesc(&cfg,f->dir,f->datoffset,ext);
650
651
652
653
654
655
656
657
658
659
660
	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(uint dirnum, file_t* bf, uint total
							,long totalfiles)
{
661
	char	ch,c,d,str[256],fname[128],*p,remcdt=0,remfile=0;
662
	char 	tmp[512];
663
	uint	i,j,ml=0,md=0,udir,ulib;
664
	file_t	f;
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683

	for(ulib=0;ulib<usrlibs;ulib++)
		if(usrlib[ulib]==cfg.dir[dirnum]->lib)
			break;
	for(udir=0;udir<usrdirs[ulib];udir++)
		if(usrdir[ulib][udir]==dirnum)
			break;

	CRLF;
	while(online) {
		bprintf(text[BatchFlagPrompt]
			,ulib+1
			,cfg.lib[cfg.dir[dirnum]->lib]->sname
			,udir+1
			,cfg.dir[dirnum]->sname
			,totalfiles);
		ch=getkey(K_UPPER);
		clearline();
		if(ch=='?') {
684
			menu("batflag");
685
686
			if(lncntr)
				pause();
687
688
			return(2); 
		}
689
690
691
692
693
694
695
696
697
		if(ch=='Q' || sys_status&SS_ABORT)
			return(-1);
		if(ch=='S')
			return(0);
		if(ch=='P' || ch=='-')
			return(3);
		if(ch=='B') {    /* Flag for batch download */
			if(useron.rest&FLAG('D')) {
				bputs(text[R_Download]);
698
699
				return(2); 
			}
700
701
702
703
704
705
706
707
			if(total==1) {
				f.dir=dirnum;
				strcpy(f.name,bf[0].name);
				f.datoffset=bf[0].datoffset;
				f.size=0;
				getfiledat(&cfg,&f);
				addtobatdl(&f);
				CRLF;
708
709
				return(2); 
			}
710
711
712
713
714
715
716
717
718
719
720
			bputs(text[BatchDlFlags]);
			d=getstr(str,BF_MAX,K_UPPER|K_LOWPRIO|K_NOCRLF);
			lncntr=0;
			if(sys_status&SS_ABORT)
				return(-1);
			if(d) { 	/* d is string length */
				CRLF;
				lncntr=0;
				for(c=0;c<d;c++) {
					if(batdn_total>=cfg.max_batdn) {
						bprintf(text[BatchDlQueueIsFull],str+c);
721
722
						break; 
					}
723
724
					if(strchr(str+c,'.')) {     /* filename or spec given */
						f.dir=dirnum;
725
						p=strchr(str+c,' ');
726
727
728
729
730
						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);
731
732
								break; 
							}
733
734
735
736
737
738
							padfname(str+c,tmp);
							if(filematch(bf[i].name,tmp)) {
								strcpy(f.name,bf[i].name);
								f.datoffset=bf[i].datoffset;
								f.size=0;
								getfiledat(&cfg,&f);
739
740
741
742
								addtobatdl(&f); 
							} 
						} 
					}
743
744
745
746
747
748
749
750
					if(strchr(str+c,'.'))
						c+=strlen(str+c);
					else if(str[c]<'A'+(char)total && str[c]>='A') {
						f.dir=dirnum;
						strcpy(f.name,bf[str[c]-'A'].name);
						f.datoffset=bf[str[c]-'A'].datoffset;
						f.size=0;
						getfiledat(&cfg,&f);
751
752
						addtobatdl(&f); } 
				}
753
				CRLF;
754
755
				return(2); 
			}
756
			clearline();
757
758
			continue; 
		}
759
760
761
762
763
764
765
766
767
768
769
770

		if(ch=='E' || ch=='V') {    /* Extended Info */
			if(total==1) {
				f.dir=dirnum;
				strcpy(f.name,bf[0].name);
				f.datoffset=bf[0].datoffset;
				f.dateuled=bf[0].dateuled;
				f.datedled=bf[0].datedled;
				f.size=0;
				getfiledat(&cfg,&f);
				if(!viewfile(&f,ch=='E'))
					return(-1);
771
772
				return(2); 
			}
773
774
775
776
777
778
779
780
781
782
783
			bputs(text[BatchDlFlags]);
			d=getstr(str,BF_MAX,K_UPPER|K_LOWPRIO|K_NOCRLF);
			lncntr=0;
			if(sys_status&SS_ABORT)
				return(-1);
			if(d) { 	/* d is string length */
				CRLF;
				lncntr=0;
				for(c=0;c<d;c++) {
					if(strchr(str+c,'.')) {     /* filename or spec given */
						f.dir=dirnum;
784
						p=strchr(str+c,' ');
785
786
787
788
789
790
791
792
793
794
795
796
						if(!p) p=strchr(str+c,',');
						if(p) *p=0;
						for(i=0;i<total;i++) {
							padfname(str+c,tmp);
							if(filematch(bf[i].name,tmp)) {
								strcpy(f.name,bf[i].name);
								f.datoffset=bf[i].datoffset;
								f.dateuled=bf[i].dateuled;
								f.datedled=bf[i].datedled;
								f.size=0;
								getfiledat(&cfg,&f);
								if(!viewfile(&f,ch=='E'))
797
798
799
800
									return(-1); 
							} 
						} 
					}
801
802
803
804
805
806
807
808
809
810
811
					if(strchr(str+c,'.'))
						c+=strlen(str+c);
					else if(str[c]<'A'+(char)total && str[c]>='A') {
						f.dir=dirnum;
						strcpy(f.name,bf[str[c]-'A'].name);
						f.datoffset=bf[str[c]-'A'].datoffset;
						f.dateuled=bf[str[c]-'A'].dateuled;
						f.datedled=bf[str[c]-'A'].datedled;
						f.size=0;
						getfiledat(&cfg,&f);
						if(!viewfile(&f,ch=='E'))
812
813
814
815
							return(-1); } 
				}
				return(2); 
			}
816
			clearline();
817
818
			continue; 
		}
819
820
821
822
823
824

		if((ch=='D' || ch=='M')     /* Delete or Move */
			&& !(useron.rest&FLAG('R'))
			&& (dir_op(dirnum) || useron.exempt&FLAG('R'))) {
			if(total==1) {
				strcpy(str,"A");
825
826
				d=1; 
			}
827
828
			else {
				bputs(text[BatchDlFlags]);
829
830
				d=getstr(str,BF_MAX,K_UPPER|K_LOWPRIO|K_NOCRLF); 
			}
831
832
833
834
835
836
837
838
839
840
841
			lncntr=0;
			if(sys_status&SS_ABORT)
				return(-1);
			if(d) { 	/* d is string length */
				CRLF;
				if(ch=='D') {
					if(noyes(text[AreYouSureQ]))
						return(2);
					remcdt=remfile=1;
					if(dir_op(dirnum)) {
						remcdt=!noyes(text[RemoveCreditsQ]);
842
843
						remfile=!noyes(text[DeleteFileQ]); } 
				}
844
845
846
847
848
849
				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[dirnum]->lib+1);
850
					if((int)(ml=getnum(usrlibs))==-1)
851
852
853
854
855
856
857
858
859
860
861
						return(2);
					if(!ml)
						ml=cfg.dir[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]);
862
					if((int)(md=getnum(usrdirs[ml]))==-1)
863
864
865
866
						return(2);
					if(!md)
						md=usrdirs[ml]-1;
					else md--;
867
868
					CRLF; 
				}
869
870
871
872
				lncntr=0;
				for(c=0;c<d;c++) {
					if(strchr(str+c,'.')) {     /* filename or spec given */
						f.dir=dirnum;
873
						p=strchr(str+c,' ');
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
						if(!p) p=strchr(str+c,',');
						if(p) *p=0;
						for(i=0;i<total;i++) {
							padfname(str+c,tmp);
							if(filematch(bf[i].name,tmp)) {
								strcpy(f.name,bf[i].name);
								unpadfname(f.name,fname);
								f.datoffset=bf[i].datoffset;
								f.dateuled=bf[i].dateuled;
								f.datedled=bf[i].datedled;
								f.size=0;
								getfiledat(&cfg,&f);
								if(f.opencount) {
									bprintf(text[FileIsOpen]
										,f.opencount,f.opencount>1 ? "s":nulstr);
889
890
									continue; 
								}
891
								if(ch=='D') {
892
									removefile(&f);
893
894
									if(remfile) {
										sprintf(tmp,"%s%s",cfg.dir[f.dir]->path,fname);
895
896
										remove(tmp); 
									}
897
									if(remcdt)
898
899
										removefcdt(&f); 
								}
900
								else if(ch=='M')
901
902
903
904
									movefile(&f,usrdir[ml][md]); 
							} 
						} 
					}
905
906
907
908
909
910
911
912
913
914
915
916
917
918
					if(strchr(str+c,'.'))
						c+=strlen(str+c);
					else if(str[c]<'A'+(char)total && str[c]>='A') {
						f.dir=dirnum;
						strcpy(f.name,bf[str[c]-'A'].name);
						unpadfname(f.name,fname);
						f.datoffset=bf[str[c]-'A'].datoffset;
						f.dateuled=bf[str[c]-'A'].dateuled;
						f.datedled=bf[str[c]-'A'].datedled;
						f.size=0;
						getfiledat(&cfg,&f);
						if(f.opencount) {
							bprintf(text[FileIsOpen]
								,f.opencount,f.opencount>1 ? "s":nulstr);
919
920
							continue; 
						}
921
						if(ch=='D') {
922
							removefile(&f);
923
924
							if(remfile) {
								sprintf(tmp,"%s%s",cfg.dir[f.dir]->path,fname);
925
926
								remove(tmp); 
							}
927
							if(remcdt)
928
929
								removefcdt(&f); 
						}
930
						else if(ch=='M')
931
932
933
934
							movefile(&f,usrdir[ml][md]); } 
				}
				return(2); 
			}
935
			clearline();
936
937
			continue; 
		}
938

939
940
		return(1); 
	}
941
942
943
944
945
946
947
948
949
950
951
952

	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, char *filespec, long mode)
{
	char	str[258],path[258],dirpath[256],done=0,ch,fname[13],ext[513];
953
954
	char 	tmp[512];
	uchar	*ixbbuf,*usrxfrbuf=NULL,*p;
955
	int		file;
rswindell's avatar
rswindell committed
956
	int		error;
957
958
	int		found=0;
    uint	i,j;
959
	long	usrxfrlen=0;
960
961
962
963
    long	m,l;
	long	usrcdt;
    time_t	start,end,t;
    file_t	f;
964
	struct	tm tm;
965

966
	sprintf(str,"%sxfer.ixt",cfg.data_dir);
967
968
969
	if(mode==FI_USERXFER) {
		if(flength(str)<1L)
			return(0);
970
971
		if((file=nopen(str,O_RDONLY))==-1) {
			errormsg(WHERE,ERR_OPEN,str,O_RDONLY);
972
973
			return(0); 
		}
974
		usrxfrlen=filelength(file);
deuce's avatar
deuce committed
975
		if((usrxfrbuf=(uchar *)malloc(usrxfrlen))==NULL) {
976
977
			close(file);
			errormsg(WHERE,ERR_ALLOC,str,usrxfrlen);
978
979
			return(0); 
		}
980
981
		if(read(file,usrxfrbuf,usrxfrlen)!=usrxfrlen) {
			close(file);
deuce's avatar
deuce committed
982
			free(usrxfrbuf);
983
			errormsg(WHERE,ERR_READ,str,usrxfrlen);
984
985
986
987
			return(0); 
		}
		close(file); 
	}
988
	sprintf(str,"%s%s.ixb",cfg.dir[dirnum]->data_dir,cfg.dir[dirnum]->code);
989
990
991
992
993
	if((file=nopen(str,O_RDONLY))==-1)
		return(0);
	l=filelength(file);
	if(!l) {
		close(file);
994
995
		return(0); 
	}
deuce's avatar
deuce committed
996
	if((ixbbuf=(uchar *)malloc(l))==NULL) {
997
998
		close(file);
		errormsg(WHERE,ERR_ALLOC,str,l);
999
1000
		return(0); 
	}
1001
1002
1003
	if(lread(file,ixbbuf,l)!=l) {
		close(file);
		errormsg(WHERE,ERR_READ,str,l);
deuce's avatar
deuce committed
1004
		free((char *)ixbbuf);
1005
		if(usrxfrbuf)
deuce's avatar
deuce committed
1006
			free(usrxfrbuf);
1007
1008
		return(0); 
	}
1009
	close(file);
1010
	sprintf(str,"%s%s.dat",cfg.dir[dirnum]->data_dir,cfg.dir[dirnum]->code);
1011
1012
	if((file=nopen(str,O_RDONLY))==-1) {
		errormsg(WHERE,ERR_READ,str,O_RDONLY);
deuce's avatar
deuce committed
1013
		free((char *)ixbbuf);
1014
		if(usrxfrbuf)
deuce's avatar
deuce committed
1015
			free(usrxfrbuf);
1016
1017
		return(0); 
	}
1018
1019
1020
1021
1022
1023
1024
1025
	close(file);
	m=0;
	while(online && !done && m<l) {
		if(mode==FI_REMOVE && dir_op(dirnum))
			action=NODE_SYSP;
		else action=NODE_LFIL;
		if(msgabort()) {
			found=-1;
1026
1027
			break; 
		}
1028
		for(i=0;i<12 && m<l;i++)
1029
1030
			if(i==8)
				str[i]=ixbbuf[m]>' ' ? '.' : ' ';
1031
1032
1033
1034
1035
1036
			else
				str[i]=ixbbuf[m++];     /* Turns FILENAMEEXT into FILENAME.EXT */
		str[i]=0;
		unpadfname(str,fname);
		if(filespec[0] && !filematch(str,filespec)) {
			m+=11;
1037
1038
			continue; 
		}
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
		f.datoffset=ixbbuf[m]|((long)ixbbuf[m+1]<<8)|((long)ixbbuf[m+2]<<16);
		f.dateuled=ixbbuf[m+3]|((long)ixbbuf[m+4]<<8)
			|((long)ixbbuf[m+5]<<16)|((long)ixbbuf[m+6]<<24);
		f.datedled=ixbbuf[m+7]|((long)ixbbuf[m+8]<<8)
			|((long)ixbbuf[m+9]<<16)|((long)ixbbuf[m+10]<<24);
		m+=11;
		if(mode==FI_OLD && f.datedled>ns_time)
			continue;
		if((mode==FI_OLDUL || mode==FI_OLD) && f.dateuled>ns_time)
			continue;
		f.dir=curdirnum=dirnum;
		strcpy(f.name,str);
		f.size=0;
		getfiledat(&cfg,&f);
		if(mode==FI_OFFLINE && f.size>=0)
			continue;
		if(f.altpath>0 && f.altpath<=cfg.altpaths)
			strcpy(dirpath,cfg.altpath[f.altpath-1]);
		else
			strcpy(dirpath,cfg.dir[f.dir]->path);
		if(mode==FI_CLOSE && !f.opencount)
			continue;
		if(mode==FI_USERXFER) {
			for(p=usrxfrbuf;p<usrxfrbuf+usrxfrlen;p+=24) {
				sprintf(str,"%17.17s",p);   /* %4.4u %12.12s */
				if(!strcmp(str+5,f.name) && useron.number==atoi(str))
1065
1066
					break; 
			}
1067
			if(p>=usrxfrbuf+usrxfrlen) /* file wasn't found */
1068
1069
				continue; 
		}
1070
		if((mode==FI_REMOVE) && (!dir_op(dirnum) && stricmp(f.uler
1071
1072
1073
1074
1075
1076
			,useron.alias) && !(useron.exempt&FLAG('R'))))
			continue;
		found++;
		if(mode==FI_INFO) {
			if(!viewfile(&f,1)) {
				done=1;
1077
1078
				found=-1; } 
		}
1079
1080
1081
1082
1083
		else
			fileinfo(&f);
		if(mode==FI_CLOSE) {
			if(!noyes(text[CloseFileRecordQ])) {
				f.opencount=0;
1084
1085
				putfiledat(&cfg,&f); } 
		}
1086
1087
1088
1089
1090
1091
		else if(mode==FI_REMOVE || mode==FI_OLD || mode==FI_OLDUL
			|| mode==FI_OFFLINE) {
			SYNC;
			CRLF;
			if(f.opencount) {
				mnemonics(text[QuitOrNext]);
1092
1093
				strcpy(str,"Q\r"); 
			}
1094
1095
			else if(dir_op(dirnum)) {
				mnemonics(text[SysopRemoveFilePrompt]);
1096
1097
				strcpy(str,"VEFMCQR\r"); 
			}
1098
1099
			else if(useron.exempt&FLAG('R')) {
				mnemonics(text[RExemptRemoveFilePrompt]);
1100
1101
				strcpy(str,"VEMQR\r"); 
			}
1102
1103
			else {
				mnemonics(text[UserRemoveFilePrompt]);
1104
1105
				strcpy(str,"VEQR\r"); 
			}
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
			switch(getkeys(str,0)) {
				case 'V':
					viewfilecontents(&f);
					CRLF;
					ASYNC;
					pause();
					m-=F_IXBSIZE;
					continue;
				case 'E':   /* edit file information */
					if(dir_op(dirnum)) {
						bputs(text[EditFilename]);
						strcpy(str,fname);
1118
1119
						if(!getstr(str,12,K_EDIT|K_AUTODEL))
							break;
1120
1121
						if(strcmp(str,fname)) { /* rename */
							padfname(str,path);
1122
1123
							if(stricmp(str,fname)
								&& findfile(&cfg,f.dir,path))
1124
1125
1126
1127
								bprintf(text[FileAlreadyThere],path);
							else {
								sprintf(path,"%s%s",dirpath,fname);
								sprintf(tmp,"%s%s",dirpath,str);
1128
								if(fexistcase(path) && rename(path,tmp))
1129
1130
1131
1132
1133
1134
									bprintf(text[CouldntRenameFile],path,tmp);
								else {
									bprintf(text[FileRenamed],path,tmp);
									strcpy(fname,str);
									removefiledat(&cfg,&f);
									strcpy(f.name,padfname(str,tmp));
1135
1136
1137
1138
1139
									addfiledat(&cfg,&f); 
								} 
							} 
						} 
					}
1140
1141
					bputs(text[EditDescription]);
					getstr(f.desc,LEN_FDESC,K_LINE|K_EDIT|K_AUTODEL);
1142
1143
					if(sys_status&SS_ABORT)
						break;
1144
1145
1146
					if(f.misc&FM_EXTDESC) {
						if(!noyes(text[DeleteExtDescriptionQ])) {
							remove(str);
1147
1148
							f.misc&=~FM_EXTDESC; } 
					}
1149
1150