listfile.cpp 28.5 KB
Newer Older
1 2 3 4 5 6
/* 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)		*
 *																			*
7
 * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
 *																			*
 * 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"
23
#include "filedat.h"
24 25 26 27 28 29

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

int extdesclines(char *str);

/*****************************************************************************/
30 31
/* List files in directory 'dir' that match 'filespec'.						 */
/* 'mode' determines other criteria											 */
32 33 34 35
/* 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		 */
/*****************************************************************************/
36
int sbbs_t::listfiles(uint dirnum, const char *filespec, FILE* tofile, long mode)
37
{
38
	char	hdr[256],letter='A';
39
	uchar	flagprompt=0;
40
	int		c, d;
41
	uint	i,j;
42 43 44 45
	int		found=0,lastbat=0,disp;
	size_t	m=0;
	long	anchor=0,next;
	file_t* bf[BF_MAX];	/* bf is batch flagged files */
46
	ulong	file_row[BF_MAX];
47
	size_t	longest = 0;
48

49 50
	if(!smb_init_dir(&cfg, &smb, dirnum))
		return 0;
51
	if(mode&FL_ULTIME) {
52 53 54
		last_ns_time = now;
		if(!newfiles(&smb, ns_time))	// this is fast
			return 0;
55
	}
56 57 58 59 60
	if(smb_open_dir(&cfg, &smb, dirnum) != SMB_SUCCESS)
		return 0;

	size_t file_count = 0;
	file_t* file_list = loadfiles(&smb
61 62
		, (mode & FL_FIND) ? NULL : filespec
		, (mode & FL_ULTIME) ? ns_time : 0
63
		, tofile == NULL ? file_detail_extdesc : file_detail_normal
64 65 66 67 68 69
		, (enum file_sort)cfg.dir[dirnum]->sort
		, &file_count);
	if(file_list == NULL || file_count < 1) {
		smb_close(&smb);
		free(file_list);
		return 0;
70
	}
71

72 73 74 75 76 77
	for(i = 0; i < file_count; i++) {
		size_t len = strlen(file_list[i].name);
		if(len > longest)
			longest = len;
	}

78 79 80 81
	if(!tofile) {
		action=NODE_LFIL;
		getnodedat(cfg.node_num,&thisnode,0);
		if(thisnode.action!=NODE_LFIL) {	/* was a sync */
82 83 84 85 86 87
			if(getnodedat(cfg.node_num,&thisnode,true)==0) {
				thisnode.action=NODE_LFIL;
				putnodedat(cfg.node_num,&thisnode); 
			} 
		} 
	}
88

89 90 91
	m = 0; // current file index
	file_t* f;
	while(online) {
92 93
		if(found<0)
			found=0;
94
		if(m>=file_count || flagprompt) {		  /* End of list */
95
			if(useron.misc&BATCHFLAG && !tofile && found && found!=lastbat
96
				&& !(mode&(FL_EXT|FL_VIEW))) {
97 98
				flagprompt=0;
				lncntr=0;
99
				if((i=batchflagprompt(&smb, bf, file_row, letter-'A', file_count))==2) {
100 101
					m=anchor;
					found-=letter-'A';
102 103
					letter='A'; 
				}
104
				else if(i==3) {
105
					if((long)anchor-(letter-'A')<0) {
106
						m=0;
107 108
						found=0; 
					}
109
					else {
110
						m=anchor-(letter-'A');
111 112 113 114
						found-=letter-'A'; 
					}
					letter='A'; 
				}
115
				else if((int)i==-1) {
116 117
					found = -1;
					break;
118
				}
119 120 121
				else
					break;
				getnodedat(cfg.node_num,&thisnode,0);
122 123
				nodesync(); 
			}
124
			else
125 126
				break; 
		}
127 128
		if(m < file_count)
			f = &file_list[m];
129 130 131 132 133 134 135

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

		if(msgabort()) {		 /* used to be !tofile && msgabort() */
136 137
			found = -1;
			break;
138
		}
139 140
		if(mode & FL_FIND) {
			char* p = (f->desc == NULL) ? NULL : strcasestr(f->desc, filespec);
141 142
			if(p == NULL)
				p = strcasestr(f->name, filespec);
143 144 145 146 147 148 149 150
			if(p == NULL && f->extdesc != NULL)
				p = strcasestr((char*)f->extdesc, filespec);
			if(p == NULL && f->tags != NULL)
				p = strcasestr(f->tags, filespec);
			if(p == NULL && f->author != NULL)
				p = strcasestr(f->author, filespec);
			if(p == NULL && f->author_org != NULL)
				p = strcasestr(f->author_org, filespec);
151
			if(p == NULL) {
152 153
				m++;
				continue; 
154 155
			}
		}
156
		if(useron.misc&BATCHFLAG && letter=='A' && found && !tofile
157
			&& !(mode&(FL_EXT | FL_VIEW))
158 159
			&& (!mode || !(useron.misc&EXPERT)))
			bputs(text[FileListBatchCommands]);
160
		m++;
161
		if(!found && !(mode&(FL_EXT | FL_VIEW))) {
162 163 164 165 166 167 168 169
			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,'?')))) {
170
				sprintf(hdr,"%s%s.hdr",cfg.dir[dirnum]->data_dir,cfg.dir[dirnum]->code);
171
				if(fexistcase(hdr))
172 173 174 175 176 177 178 179 180 181 182
					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]);
183
						bputs("\xc9\xcd");            /* use to start with \r\n */
184
						for(c=0;c<d;c++)
185 186
							outchar('\xcd');
						bputs("\xbb\r\n\xba ");
187 188 189
						sprintf(hdr,text[BoxHdrLib],i+1,cfg.lib[usrlib[i]]->lname);
						bputs(hdr);
						for(c=bstrlen(hdr);c<d;c++)
190
							outchar(' ');
191
						attr(cfg.color[clr_filelsthdrbox]);
192
						bputs("\xba\r\n\xba ");
193 194 195
						sprintf(hdr,text[BoxHdrDir],j+1,cfg.dir[dirnum]->lname);
						bputs(hdr);
						for(c=bstrlen(hdr);c<d;c++)
196
							outchar(' ');
197
						attr(cfg.color[clr_filelsthdrbox]);
198 199
						bputs("\xba\r\n\xba ");
						sprintf(hdr,text[BoxHdrFiles], file_count);
200 201
						bputs(hdr);
						for(c=bstrlen(hdr);c<d;c++)
202
							outchar(' ');
203
						attr(cfg.color[clr_filelsthdrbox]);
204
						bputs("\xba\r\n\xc8\xcd");
205
						for(c=0;c<d;c++)
206 207
							outchar('\xcd');
						bputs("\xbc\r\n"); 
208 209
					}
				}
210
			}
211 212
			else {					/* short header */
				if(tofile) {
213
					c = fprintf(tofile,"\r\n(%u) %s ",i+1,cfg.lib[usrlib[i]]->sname) - 2;
214
				}
215 216 217
				else {
					sprintf(hdr,text[ShortHdrLib],i+1,cfg.lib[usrlib[i]]->sname);
					bputs("\r\1>\r\n");
218
					bputs(hdr); 
219
					c=bstrlen(hdr);
220
				}
221
				if(tofile) {
222
					c += fprintf(tofile,"(%u) %s",j+1,cfg.dir[dirnum]->lname);
223
				}
224 225
				else {
					sprintf(hdr,text[ShortHdrDir],j+1,cfg.dir[dirnum]->lname);
226
					bputs(hdr); 
227
					c+=bstrlen(hdr);
228
				}
229
				if(tofile) {
230
					fprintf(tofile,"\r\n%.*s\r\n", c, "----------------------------------------------------------------");
231
				}
232 233 234 235
				else {
					CRLF;
					attr(cfg.color[clr_filelstline]);
					while(c--)
rswindell's avatar
rswindell committed
236
						outchar('\xC4');
237 238 239 240
					CRLF; 
				} 
			} 
		}
241
		long currow = row;
242 243
		next=m;
		disp=1;
244
		if(mode&(FL_EXT | FL_VIEW)) {
245 246
			if(!found)
				bputs("\r\1>");
247
			if(!viewfile(f, INT_TO_BOOL(mode & FL_EXT))) {
248 249
				found = -1;
				break;
250
			}
251
			CRLF;
252
		}
253
		else if(tofile)
254
			listfiletofile(f, tofile);
255
		else if(mode & FL_FIND)
256
			disp=listfile(f, dirnum, filespec, letter, longest);
257
		else
258
			disp=listfile(f, dirnum, nulstr, letter, longest);
259
		if(!disp && letter>'A') {
260
			next=m-1;
261 262
			letter--; 
		}
263 264
		else {
			disp=1;
265 266
			found++; 
		}
267
		if(sys_status&SS_ABORT) {
268 269
			found = -1;
			break;
270
		}
271
		if(mode&(FL_EXT | FL_VIEW))
272 273 274
			continue;
		if(useron.misc&BATCHFLAG && !tofile) {
			if(disp) {
275
				bf[letter-'A'] = f;
276
				file_row[letter-'A'] = currow;
277
			}
278
			m++;
279 280
			if(flagprompt || letter=='Z' || !disp ||
				(filespec[0] && !strchr(filespec,'*') && !strchr(filespec,'?')
281
				&& !(mode & FL_FIND))
282 283 284 285 286
				|| (useron.misc&BATCHFLAG && !tofile && lncntr>=rows-2)
				) {
				flagprompt=0;
				lncntr=0;
				lastbat=found;
287
				if((int)(i=batchflagprompt(&smb, bf, file_row, letter-'A'+1, file_count))<1) {
288
					if((int)i==-1)
289 290
						found = -1;
					break;
291
				}
292 293
				if(i==2) {
					next=anchor;
294 295
					found-=(letter-'A')+1; 
				}
296
				else if(i==3) {
297
					if((long)anchor-((letter-'A'+1))<0) {
298
						next=0;
299 300
						found=0; 
					}
301
					else {
302 303 304
						next=anchor-((letter-'A'+1));
						found-=letter-'A'+1; 
					} 
305
				}
306 307
				getnodedat(cfg.node_num,&thisnode,0);
				nodesync();
308 309 310 311
				letter='A';	
			}
			else
				letter++; 
312
		}
313 314 315
		if(useron.misc&BATCHFLAG && !tofile
			&& lncntr>=rows-2) {
			lncntr=0;		/* defeat pause() */
316 317
			flagprompt=1; 
		}
318
		m=next;
319
		if(mode & FL_FIND) continue;
320
		if(filespec[0] && !strchr(filespec,'*') && !strchr(filespec,'?') && m)
321 322
			break; 
	}
323

324 325 326
	freefiles(file_list, file_count);
	smb_close(&smb);
	return found;
327 328 329 330 331 332
}

/****************************************************************************/
/* Prints one file's information on a single line                           */
/* Return 1 if displayed, 0 otherwise										*/
/****************************************************************************/
333
bool sbbs_t::listfile(file_t* f, uint dirnum, const char *search, const char letter, size_t namelen)
334
{
335
	char	*ptr;
336 337
	bool	exist = true;
	char*	ext=NULL;
338
	char	path[MAX_PATH+1];
339
    int		i,j;
340
    off_t	cdt;
341
	int		size_attr=clr_filecdt;
342

343 344 345 346 347 348 349 350 351 352 353 354
	if(useron.misc & EXTDESC) {
		if(f->extdesc != NULL && (ext = strdup(f->extdesc)) != NULL) {
			strip_ctrl(ext, ext);
			truncsp(ext);
			char ch = *ext;
			FREE_AND_NULL(ext);
			if(ch != '\0') {
				ext = f->extdesc;
				if((useron.misc&BATCHFLAG) && lncntr+extdesclines(ext)>=rows-2 && letter!='A')
					return false;
			}
		}
355
	}
356

357
	cond_newline();
358
	attr(cfg.color[(f->hdr.attr & MSG_DELETE) ? clr_err : clr_filename]);
359 360 361 362 363
	char fname[SMB_FILEIDX_NAMELEN + 1];
	if(namelen < 12 || cols < 132)
		namelen = 12;
	else if(namelen > sizeof(fname) - 1)
		namelen = sizeof(fname) - 1;
Rob Swindell's avatar
Rob Swindell committed
364
	bprintf("%-*s", (int)namelen, format_filename(f->name, fname, namelen, /* pad: */TRUE));
365
	getfilepath(&cfg, f, path);
366

367 368
	if(f->extdesc != NULL && *f->extdesc && !(useron.misc&EXTDESC))
		outchar('+');
369
	else
370
		outchar(' '); 
371
	if(useron.misc&BATCHFLAG) {
372
		attr(curatr ^ HIGH);
373 374
		bprintf("%c",letter); 
	}
375 376 377 378
	cdt = f->cost;
	if(f->size == -1) {
		exist = false;
		size_attr = clr_err; 
379
	}
380 381 382 383 384 385 386 387
	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);
388
	attr(cfg.color[size_attr]);
389
	if(useron.misc&BATCHFLAG) {
390
		if(!cdt && !(cfg.dir[dirnum]->misc&DIR_FREE)) {
391
			attr(curatr^(HIGH|BLINK));
392 393
			bputs("  FREE"); 
		}
394 395
		else 
			bprintf("%6s", bytes);
396
	}
397
	else {
398
		if(!cdt && !(cfg.dir[dirnum]->misc&DIR_FREE)) {  /* FREE file */
399
			attr(curatr^(HIGH|BLINK));
400 401
			bputs("   FREE"); 
		}
402 403
		else 
			bprintf("%7s", bytes);
404
	}
405
	if(exist)
406
		outchar(' ');
407 408 409
	else
		outchar('-');
	attr(cfg.color[clr_filedesc]);
410

411 412 413 414 415 416 417 418 419 420 421 422 423 424 425
	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);
426 427
			} else
				bputs(P_TRUNCATE, fdesc);
428 429 430
		}
		else {
			bputs(P_TRUNCATE, fdesc);
431 432
		}
		CRLF; 
433
	} else {
434 435 436 437 438 439
		truncsp(ext);
		while(strncmp(ext, "\r\n", 2) == 0
			|| strnicmp(ext, "\001N", 2) == 0
			|| strnicmp(ext, "\0010", 2) == 0
			|| strnicmp(ext, "\001W", 2) == 0)
			ext += 2;
440
		putmsg(ext, P_INDENT | P_NOATCODES | P_CPM_EOF | P_TRUNCATE | P_AUTO_UTF8);
441
	}
442
	return true;
443 444 445 446 447 448 449
}

/****************************************************************************/
/* 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. 														*/
/****************************************************************************/
450
int sbbs_t::batchflagprompt(smb_t* smb, file_t** bf, ulong* row, uint total
451 452
							,long totalfiles)
{
453
	char	ch,str[256],*p,remcdt=0,remfile=0;
454
	int		c, d;
455
	char 	path[MAX_PATH + 1];
456
	uint	i,j,ml=0,md=0,udir,ulib;
457 458

	for(ulib=0;ulib<usrlibs;ulib++)
459
		if(usrlib[ulib]==cfg.dir[smb->dirnum]->lib)
460 461
			break;
	for(udir=0;udir<usrdirs[ulib];udir++)
462
		if(usrdir[ulib][udir]==smb->dirnum)
463 464
			break;

465
	cond_blankline();
466 467 468
	while(online) {
		bprintf(text[BatchFlagPrompt]
			,ulib+1
469
			,cfg.lib[cfg.dir[smb->dirnum]->lib]->sname
470
			,udir+1
471
			,cfg.dir[smb->dirnum]->sname
472
			,total, totalfiles);
473 474 475
		ch=getkey(K_UPPER);
		clearline();
		if(ch=='?') {
476
			menu("batflag");
477 478
			if(lncntr)
				pause();
479 480
			return(2); 
		}
481
		if(ch==quit_key() || sys_status&SS_ABORT)
482 483 484 485 486
			return(-1);
		if(ch=='S')
			return(0);
		if(ch=='P' || ch=='-')
			return(3);
487 488
		if(ch=='T') {
			useron.misc ^= EXTDESC;
489
			putuserrec(&cfg, useron.number, U_MISC, 0, ultoa(useron.misc,str,16));
490 491
			return 2;
		}
492
		if(ch=='B' || ch=='D') {    /* Flag for batch download */
493 494
			if(useron.rest&FLAG('D')) {
				bputs(text[R_Download]);
495 496
				return(2); 
			}
497
			if(total==1) {
498
				addtobatdl(bf[0]);
499
				if(ch=='D')
500
					start_batch_download();
501
				CRLF;
502 503
				return(2); 
			}
504 505 506 507
			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]);
508
			bputs(text[BatchDlFlags]);
509
			d=getstr(str, BF_MAX, K_NOCRLF);
510 511
			clear_hotspots();
			mouse_hotspots = saved_hotspots;
512 513 514
			lncntr=0;
			if(sys_status&SS_ABORT)
				return(-1);
515 516
			if(d > 0) { 	/* d is string length */
				strupr(str);
517 518 519
				CRLF;
				lncntr=0;
				for(c=0;c<d;c++) {
520
					if(batdn_total() >= cfg.max_batdn) {
521
						bprintf(text[BatchDlQueueIsFull],str+c);
522 523
						break; 
					}
524
					if(str[c]=='*' || strchr(str+c,'.')) {     /* filename or spec given */
525
//						f.dir=dirnum;
526
						p=strchr(str+c,' ');
527 528 529
						if(!p) p=strchr(str+c,',');
						if(p) *p=0;
						for(i=0;i<total;i++) {
530
							if(batdn_total() >= cfg.max_batdn) {
531
								bprintf(text[BatchDlQueueIsFull],str+c);
532 533
								break; 
							}
534 535
							if(filematch(bf[i]->name, str+c)) {
								addtobatdl(bf[i]); 
536 537 538
							} 
						} 
					}
539 540 541
					if(strchr(str+c,'.'))
						c+=strlen(str+c);
					else if(str[c]<'A'+(char)total && str[c]>='A') {
542
						addtobatdl(bf[str[c]-'A']);
543
					} 
544
				}
545 546
				if(ch=='D')
					start_batch_download();
547
				CRLF;
548 549
				return(2); 
			}
550
			clearline();
551 552
			continue; 
		}
553 554 555

		if(ch=='E' || ch=='V') {    /* Extended Info */
			if(total==1) {
556
				if(!viewfile(bf[0], ch=='E'))
557
					return(-1);
558 559
				return(2); 
			}
560 561 562 563
			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]);
564
			bputs(text[BatchDlFlags]);
565
			d=getstr(str, BF_MAX, K_NOCRLF);
566 567
			clear_hotspots();
			mouse_hotspots = saved_hotspots;
568 569 570
			lncntr=0;
			if(sys_status&SS_ABORT)
				return(-1);
571 572
			if(d > 0) { 	/* d is string length */
				strupr(str);
573 574 575
				CRLF;
				lncntr=0;
				for(c=0;c<d;c++) {
576
					if(str[c]=='*' || strchr(str+c,'.')) {     /* filename or spec given */
577
//						f.dir=dirnum;
578
						p=strchr(str+c,' ');
579 580 581
						if(!p) p=strchr(str+c,',');
						if(p) *p=0;
						for(i=0;i<total;i++) {
582 583
							if(filematch(bf[i]->name, str+c)) {
								if(!viewfile(bf[i], ch=='E'))
584 585 586 587
									return(-1); 
							} 
						} 
					}
588 589 590
					if(strchr(str+c,'.'))
						c+=strlen(str+c);
					else if(str[c]<'A'+(char)total && str[c]>='A') {
591 592 593
						if(!viewfile(bf[str[c]-'A'], ch=='E'))
							return(-1); 
					} 
594
				}
595
				cond_newline();
596 597
				return(2); 
			}
598
			clearline();
599 600
			continue; 
		}
601

602
		if((ch=='R' || ch=='M')     /* Delete or Move */
603
			&& !(useron.rest&FLAG('R'))
604
			&& (dir_op(smb->dirnum) || useron.exempt&FLAG('R'))) {
605 606
			if(total==1) {
				strcpy(str,"A");
607 608
				d=1; 
			}
609
			else {
610 611 612 613
				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]);
614
				bputs(text[BatchDlFlags]);
615
				d=getstr(str, BF_MAX, K_NOCRLF);
616 617
				clear_hotspots();
				mouse_hotspots = saved_hotspots;
618
			}
619 620 621
			lncntr=0;
			if(sys_status&SS_ABORT)
				return(-1);
622 623 624 625
			if(d > 0) { 	/* d is string length */
				strupr(str);
				if(total > 1)
					newline();
626 627
				if(ch=='R') {
					if(noyes(text[RemoveFileQ]))
628
						return(2);
629 630 631 632
					remcdt = TRUE;
					remfile = TRUE;
					if(dir_op(smb->dirnum)) {
						remfile=!noyes(text[DeleteFileQ]);
633
						remcdt=!noyes(text[RemoveCreditsQ]);
634
					}
635
				}
636 637 638 639 640
				else if(ch=='M') {
					CRLF;
					for(i=0;i<usrlibs;i++)
						bprintf(text[MoveToLibLstFmt],i+1,cfg.lib[usrlib[i]]->lname);
					SYNC;
641
					bprintf(text[MoveToLibPrompt],cfg.dir[smb->dirnum]->lib+1);
642
					if((int)(ml=getnum(usrlibs))==-1)
643 644
						return(2);
					if(!ml)
645
						ml=cfg.dir[smb->dirnum]->lib;
646 647 648 649 650 651 652 653
					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]);
654
					if((int)(md=getnum(usrdirs[ml]))==-1)
655 656 657 658
						return(2);
					if(!md)
						md=usrdirs[ml]-1;
					else md--;
659 660
					CRLF; 
				}
661 662
				lncntr=0;
				for(c=0;c<d;c++) {
663
					if(str[c]=='*' || strchr(str+c,'.')) {     /* filename or spec given */
664
//						f.dir=dirnum;
665
						p=strchr(str+c,' ');
666 667 668
						if(!p) p=strchr(str+c,',');
						if(p) *p=0;
						for(i=0;i<total;i++) {
669
							if(!(bf[i]->hdr.attr & MSG_DELETE) && filematch(bf[i]->name, str+c)) {
670
								if(ch=='R') {
671 672 673 674 675 676 677
									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]);
678 679
									}
								}
680
								else if(ch=='M')
681
									movefile(smb, bf[i], usrdir[ml][md]); 
682 683 684
							} 
						} 
					}
685 686 687
					if(strchr(str+c,'.'))
						c+=strlen(str+c);
					else if(str[c]<'A'+(char)total && str[c]>='A') {
688
						file_t* f = bf[str[c]-'A'];
689 690 691 692 693 694 695 696 697
						if(!(f->hdr.attr & MSG_DELETE)) {
							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);
698
								}
699
							}
700 701
							else if(ch=='M')
								movefile(smb, f, usrdir[ml][md]);
702
						}
703
					} 
704 705 706
				}
				return(2); 
			}
707
			clearline();
708 709
			continue; 
		}
710

711 712
		return(1); 
	}
713 714 715 716 717 718 719 720 721

	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                */
/****************************************************************************/
722
int sbbs_t::listfileinfo(uint dirnum, const char *filespec, long mode)
723
{
724
	char	str[MAX_PATH + 1],path[MAX_PATH + 1],dirpath[MAX_PATH + 1],done=0,ch;
725
	char 	tmp[512];
rswindell's avatar
rswindell committed
726
	int		error;
727 728
	int		found=0;
    uint	i,j;
729
    size_t	m;
730
    time_t	start,end,t;
731
    file_t*	f;
732
	struct	tm tm;
733

734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749
	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;
750
	}
751

752
	m=0;
753 754
	while(online && !done && m < file_count) {
		f = &file_list[m];
755 756 757 758 759
		if(mode==FI_REMOVE && dir_op(dirnum))
			action=NODE_SYSP;
		else action=NODE_LFIL;
		if(msgabort()) {
			found=-1;
760 761
			break; 
		}
762
		m++;
763 764
		if(f->hdr.attr & MSG_DELETE)
			continue;
765
		if(mode==FI_OLD && f->hdr.last_downloaded > ns_time)
766
			continue;
767
		if((mode==FI_OLDUL || mode==FI_OLD) && f->hdr.when_written.time > ns_time)
768
			continue;
769 770
		curdirnum = dirnum;
		if(mode==FI_OFFLINE && getfilesize(&cfg, f) >= 0)
771
			continue;
772 773 774 775 776 777 778 779 780
		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;
		}
781 782
		SAFECOPY(dirpath, cfg.dir[f->dir]->path);
		if((mode==FI_REMOVE) && (!dir_op(dirnum) && stricmp(f->from
783 784 785 786
			,useron.alias) && !(useron.exempt&FLAG('R'))))
			continue;
		found++;
		if(mode==FI_INFO) {
787 788 789 790 791 792 793 794 795 796 797
			switch(viewfile(f, true)) {
				case 0:
					done=1;
					found=-1;
					break;
				case -2:
					m