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

filelist.c 12.5 KB
Newer Older
1 2 3 4 5 6 7 8
/* Utility to create list of files from Synchronet file directories */
/* Default list format is FILES.BBS, but file size, uploader, upload date */
/* and other information can be included. */

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
9
 * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
10 11 12 13 14 15 16 17 18 19 20 21 22 23
 *																			*
 * 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.	*
 ****************************************************************************/

24 25 26 27 28 29 30
#include "datewrap.h"
#include "load_cfg.h"
#include "str_util.h"
#include "date_str.h"
#include "nopen.h"
#include "filedat.h"
#include "dat_rec.h"
31
#include "smblib.h"
32
#include <stdarg.h>
33

34
#define FILELIST_VER "3.19"
35 36 37 38 39 40 41 42 43

#define MAX_NOTS 25

scfg_t scfg;

char *crlf="\r\n";

/****************************************************************************/
/****************************************************************************/
44
int lprintf(int level, const char *fmat, ...)
45 46 47 48 49 50 51 52
{
	va_list argptr;
	char sbuf[256];
	int chcount;

	va_start(argptr,fmat);
	chcount=vsprintf(sbuf,fmat,argptr);
	va_end(argptr);
53 54
	truncsp(sbuf);
	printf("%s\n",sbuf);
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
	return(chcount);
}

void stripctrlz(char *str)
{
	char tmp[1024];
	int i,j,k;

	k=strlen(str);
	for(i=j=0;i<k;i++)
		if(str[i]!=0x1a)
			tmp[j++]=str[i];
	tmp[j]=0;
	strcpy(str,tmp);
}

71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
char* byteStr(unsigned long value)
{
	static char tmp[128];

	if(value>=(1024*1024*1024))
		sprintf(tmp, "%5.1fG", value/(1024.0*1024.0*1024.0));
	else if(value>=(1024*1024))
		sprintf(tmp, "%5.1fM", value/(1024.0*1024.0));
	else if(value>=1024)
		sprintf(tmp, "%5.1fK", value/1024.0); 
	else
		sprintf(tmp, "%5luB", value);
	return tmp;
}

void fprint_extdesc(FILE* fp, char* ext_desc, int desc_off)
{
	for(char* line = strtok(ext_desc, "\n"); line != NULL; line = strtok(NULL, "\n")) {
		truncsp(line);
		fprintf(fp, "\n%*s %s", desc_off, "", line);
	}
}
93 94 95 96

#define ALL 	(1L<<0)
#define PAD 	(1L<<1)
#define HDR 	(1L<<2)
97
#define CREDITS	(1L<<3)
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
#define EXT 	(1L<<4)
#define ULN 	(1L<<5)
#define ULD 	(1L<<6)
#define DLS 	(1L<<7)
#define DLD 	(1L<<8)
#define NOD 	(1L<<9)
#define PLUS	(1L<<10)
#define MINUS	(1L<<11)
#define JST 	(1L<<12)
#define NOE 	(1L<<13)
#define DFD 	(1L<<14)
#define TOT 	(1L<<15)
#define AUTO	(1L<<16)

/*********************/
/* Entry point (duh) */
/*********************/
int main(int argc, char **argv)
{
	char	revision[16];
	char	error[512];
119 120 121 122 123
	char	*p,str[256],fname[256],ext,not[MAX_NOTS][9];
	int 	i,j,dirnum,libnum,desc_off,lines,nots=0;
	char*	omode="w";
	char*	pattern=NULL;
	ulong	m,cdt,misc=0,total_cdt=0,total_files=0,dir_files;
124
	long	max_age=0;
125
	FILE*	out=NULL;
126

Rob Swindell's avatar
Rob Swindell committed
127
	sscanf("$Revision: 1.22 $", "%*s %s", revision);
128 129 130 131 132 133 134 135 136 137 138 139 140 141

	fprintf(stderr,"\nFILELIST v%s-%s (rev %s) - Generate Synchronet File "
		"Directory Lists\n"
		,FILELIST_VER
		,PLATFORM_DESC
		,revision
		);

	if(argc<2 
		|| strcmp(argv[1],"-?")==0 
		|| strcmp(argv[1],"-help")==0 
		|| strcmp(argv[1],"--help")==0 
		|| strcmp(argv[1],"/?")==0
		) {
142
		printf("\n   usage: FILELIST <dir_code or - for ALL> [switches] [outfile]\n");
143 144 145
		printf("\n");
		printf("switches: -lib name All directories of specified library\n");
		printf("          -not code Exclude specific directory\n");
146
		printf("          -new days Include only new files in listing (days since upload)\n");
147 148
		printf("          -inc pattern Only list files matching 'pattern'\n");
		printf("          -cat      Concatenate to existing 'outfile'\n");
149 150 151 152 153 154
		printf("          -pad      Pad filename with spaces\n");
		printf("          -hdr      Include directory headers\n");
		printf("          -cdt      Include credit value\n");
		printf("          -tot      Include credit totals\n");
		printf("          -uln      Include uploader's name\n");
		printf("          -uld      Include upload date\n");
155
		printf("          -dfd      Include current file date\n");
156 157 158 159 160 161 162 163 164 165
		printf("          -dld      Include download date\n");
		printf("          -dls      Include total downloads\n");
		printf("          -nod      Exclude normal descriptions\n");
		printf("          -noe      Exclude normal descriptions, if extended "
			"exists\n");
		printf("          -ext      Include extended descriptions\n");
		printf("          -jst      Justify extended descriptions under normal\n");
		printf("          -+        Include extended description indicator (+)\n");
		printf("          --        Include offline file indicator (-)\n");
		printf("          -*        Short-hand for -pad -hdr -cdt -+ --\n");
166 167
		exit(0); 
	}
168

169 170 171 172 173 174
	p=getenv("SBBSCTRL");
	if(p==NULL) {
		printf("\nSBBSCTRL environment variable not set.\n");
		printf("\nExample: SET SBBSCTRL=/sbbs/ctrl\n");
		exit(1);
	}
175

176 177
	memset(&scfg,0,sizeof(scfg));
	scfg.size=sizeof(scfg);
178
	SAFECOPY(scfg.ctrl_dir, get_ctrl_dir(/* warn: */TRUE));
179 180 181 182 183

	if(chdir(scfg.ctrl_dir)!=0)
		fprintf(stderr,"!ERROR changing directory to: %s", scfg.ctrl_dir);

	printf("\nLoading configuration files from %s\n",scfg.ctrl_dir);
184
	if(!load_cfg(&scfg, /* text: */NULL, /* prep: */TRUE, /* node: */FALSE, error, sizeof(error))) {
185 186 187
		fprintf(stderr,"!ERROR loading configuration files: %s\n",error);
		exit(1);
	}
rswindell's avatar
rswindell committed
188 189
	SAFECOPY(scfg.temp_dir,"../temp");
	prep_dir(scfg.ctrl_dir, scfg.temp_dir, sizeof(scfg.temp_dir));
190 191

	dirnum=libnum=-1;
192
	if(argv[1][0]=='*' || strcmp(argv[1],"-")==0)
193 194 195 196 197 198 199 200
		misc|=ALL;
	else if(argv[1][0]!='-') {
		strupr(argv[1]);
		for(i=0;i<scfg.total_dirs;i++)
			if(!stricmp(argv[1],scfg.dir[i]->code))
				break;
		if(i>=scfg.total_dirs) {
			printf("\nDirectory code '%s' not found.\n",argv[1]);
201 202 203 204
			exit(1); 
		}
		dirnum=i; 
	}
205 206 207 208
	for(i=1;i<argc;i++) {
		if(!stricmp(argv[i],"-lib")) {
			if(dirnum!=-1) {
				printf("\nBoth directory code and -lib parameters were used.\n");
209 210
				exit(1); 
			}
211 212 213
			i++;
			if(i>=argc) {
				printf("\nLibrary short name must follow -lib parameter.\n");
214 215
				exit(1); 
			}
216 217 218 219 220 221
			strupr(argv[i]);
			for(j=0;j<scfg.total_libs;j++)
				if(!stricmp(scfg.lib[j]->sname,argv[i]))
					break;
			if(j>=scfg.total_libs) {
				printf("\nLibrary short name '%s' not found.\n",argv[i]);
222 223 224 225
				exit(1); 
			}
			libnum=j; 
		}
226 227 228 229
		else if(!stricmp(argv[i],"-not")) {
			if(nots>=MAX_NOTS) {
				printf("\nMaximum number of -not options (%u) exceeded.\n"
					,MAX_NOTS);
230 231
				exit(1); 
			}
232 233 234
			i++;
			if(i>=argc) {
				printf("\nDirectory internal code must follow -not parameter.\n");
235 236 237 238
				exit(1); 
			}
			sprintf(not[nots++],"%.8s",argv[i]); 
		}
239 240 241
		else if(!stricmp(argv[i],"-all")) {
			if(dirnum!=-1) {
				printf("\nBoth directory code and -all parameters were used.\n");
242 243
				exit(1); 
			}
244 245
			if(libnum!=-1) {
				printf("\nBoth library name and -all parameters were used.\n");
246 247 248 249
				exit(1); 
			}
			misc|=ALL; 
		}
250 251 252 253 254 255 256 257
		else if(!stricmp(argv[i],"-new")) {
			i++;
			if(i>=argc) {
				printf("\nDays since upload must follow -new parameter.\n");
				exit(1); 
			}
			max_age=strtol(argv[i],NULL,0);
		}
258 259 260 261 262 263 264 265
		else if(!stricmp(argv[i],"-inc")) {
			i++;
			if(i>=argc) {
				printf("\nFilename pattern must follow -inc parameter.\n");
				exit(1); 
			}
			pattern = argv[i];
		}
266 267 268
		else if(!stricmp(argv[i],"-pad"))
			misc|=PAD;
		else if(!stricmp(argv[i],"-cat"))
269
			omode="a";
270 271 272
		else if(!stricmp(argv[i],"-hdr"))
			misc|=HDR;
		else if(!stricmp(argv[i],"-cdt"))
273
			misc|=CREDITS;
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298
		else if(!stricmp(argv[i],"-tot"))
			misc|=TOT;
		else if(!stricmp(argv[i],"-ext"))
			misc|=EXT;
		else if(!stricmp(argv[i],"-uln"))
			misc|=ULN;
		else if(!stricmp(argv[i],"-uld"))
			misc|=ULD;
		else if(!stricmp(argv[i],"-dld"))
			misc|=DLD;
		else if(!stricmp(argv[i],"-dfd"))
			misc|=DFD;
		else if(!stricmp(argv[i],"-dls"))
			misc|=DLS;
		else if(!stricmp(argv[i],"-nod"))
			misc|=NOD;
		else if(!stricmp(argv[i],"-jst"))
			misc|=(EXT|JST);
		else if(!stricmp(argv[i],"-noe"))
			misc|=(EXT|NOE);
		else if(!stricmp(argv[i],"-+"))
			misc|=PLUS;
		else if(!stricmp(argv[i],"--"))
			misc|=MINUS;
		else if(!stricmp(argv[i],"-*"))
299
			misc|=(HDR|PAD|CREDITS|PLUS|MINUS);
300 301

		else if(i!=1) {
302
			if(argv[i][0]=='*' || strcmp(argv[i],"-")==0) {
303
				misc|=AUTO;
304 305
				continue; 
			}
306 307
			if((out=fopen(argv[i], omode)) == NULL) {
				perror(argv[i]);
308 309 310 311
				exit(1); 
			}
		} 
	}
312 313 314 315

	if(!out && !(misc&AUTO)) {
		printf("\nOutput file not specified, using FILES.BBS in each "
			"directory.\n");
316 317
		misc|=AUTO; 
	}
318 319

	for(i=0;i<scfg.total_dirs;i++) {
320
		dir_files=0;
321 322 323 324 325 326 327 328 329 330
		if(!(misc&ALL) && i!=dirnum && scfg.dir[i]->lib!=libnum)
			continue;
		for(j=0;j<nots;j++)
			if(!stricmp(not[j],scfg.dir[i]->code))
				break;
		if(j<nots)
			continue;
		if(misc&AUTO && scfg.dir[i]->seqdev) 	/* CD-ROM */
			continue;
		printf("\n%-*s %s",LEN_GSNAME,scfg.lib[scfg.dir[i]->lib]->sname,scfg.dir[i]->lname);
331 332 333 334 335

		smb_t smb;
		int result = smb_open_dir(&scfg, &smb, i);
		if(result != SMB_SUCCESS) {
			fprintf(stderr, "!ERROR %d (%s) opening file base: %s\n", result, smb.last_error, scfg.dir[i]->code);
336
			continue;
337 338 339 340 341 342
		}
		time_t t = 0;
		if(max_age)
			t = time(NULL) - (max_age * 24 * 60 * 60);
		ulong file_count;
		file_t* file_list = loadfiles(&smb
Rob Swindell's avatar
Rob Swindell committed
343
			,/* filespec: */pattern, /* time: */t, file_detail_extdesc, scfg.dir[i]->sort, &file_count);
344

345 346
		if(misc&AUTO) {
			sprintf(str,"%sFILES.BBS",scfg.dir[i]->path);
347 348
			if((out=fopen(str, omode)) == NULL) {
				perror(str);
349 350 351
				exit(1); 
			}
		}
352
		if(misc&HDR) {
rswindell's avatar
rswindell committed
353
			sprintf(fname,"%-*s      %-*s       Files: %4lu"
354
				,LEN_GSNAME,scfg.lib[scfg.dir[i]->lib]->sname
355 356
				,LEN_SLNAME,scfg.dir[i]->lname, (ulong)smb.status.total_files);
			fprintf(out,"%s\n",fname);
rswindell's avatar
rswindell committed
357
			memset(fname,'-',strlen(fname));
358
			fprintf(out,"%s\n",fname); 
359
		}
360
		if(!smb.status.total_files) {
361
			if(misc&AUTO) fclose(out);
362 363
			continue; 
		}
364 365 366 367 368
		int longest_filename = 12;
		for(m = 0; m < file_count; m++) {
			int fnamelen = strlen(file_list[m].name);
			if(fnamelen > longest_filename)
				longest_filename = fnamelen;
369
		}
370 371 372 373 374 375 376 377 378 379 380 381 382
		for(m = 0; m < file_count && !ferror(out); m++) {
			file_t file = file_list[m];

			if(misc&PAD) {
				char* ext = getfext(file.name);
				if(ext == NULL)
					ext="";
				fprintf(out,"%-*.*s%s"
					, (int)(longest_filename - strlen(ext))
					, (int)(strlen(file.name) - strlen(ext))
					, file.name, ext);
			} else
				fprintf(out,"%-*s", longest_filename, file.name);
383

384 385
			total_files++;
			dir_files++;
386

387
			if(misc&PLUS && file.extdesc != NULL && file.extdesc[0])
388 389
				fputc('+',out);
			else
390
				fputc(' ',out);
391

392 393 394
			desc_off = longest_filename;
			if(misc&(CREDITS|TOT)) {
				cdt=file.cost;
395
				total_cdt+=cdt;
396 397 398
				if(misc&CREDITS) {
//					fprintf(out,"%7lu",cdt);
					desc_off += fprintf(out, "%7s", byteStr(cdt));
399 400
				} 
			}
401 402

			if(misc&MINUS) {
403
				sprintf(str,"%s%s",scfg.dir[i]->path,file.name);
404
				if(!fexistcase(str))
405 406
					fputc('-',out);
				else
407 408
					fputc(' ',out); 
			}
409
			else
410
				fputc(' ',out);
411 412 413
			desc_off++;

			if(misc&DFD) {
414 415 416
				// TODO: Fix to support alt-file-paths:
				sprintf(str,"%s%s",scfg.dir[i]->path,file.name);
				desc_off += fprintf(out,"%s ",unixtodstr(&scfg,(time32_t)fdate(str),str));
417
			}
418 419

			if(misc&ULD) {
420
				desc_off += fprintf(out,"%s ",unixtodstr(&scfg,file.hdr.when_imported.time,str));
421
			}
422 423

			if(misc&ULN) {
424
				desc_off += fprintf(out,"%-25s ",file.from);
425
			}
426 427

			if(misc&DLD) {
428
				desc_off += fprintf(out,"%s ",unixtodstr(&scfg,file.hdr.last_downloaded,str));
429
			}
430 431

			if(misc&DLS) {
432
				desc_off += fprintf(out,"%5u ",file.hdr.times_downloaded);
433
			}
434

435
			if(file.extdesc != NULL && file.extdesc[0])
436 437 438 439 440
				ext=1;	/* extended description exists */
			else
				ext=0;	/* it doesn't */

			if(!(misc&NOD) && !(misc&NOE && ext)) {
441
				fprintf(out,"%s",file.desc); 
442
			}
443 444 445 446 447

			if(misc&EXT && ext) {							/* Print ext desc */

				lines=0;
				if(!(misc&NOE)) {
448 449
					truncsp((char*)file.extdesc);
					fprint_extdesc(out, file.extdesc, (misc&JST) ? desc_off : 0);
450 451 452
					lines++; 
				}
			}
453
			fprintf(out,"\n"); 
454
		}
455
		smb_close(&smb);
456
		if(dir_files)
457
			fprintf(out,"\n"); /* blank line at end of dir */
458
		if(misc&AUTO) fclose(out); 
459
		freefiles(file_list, file_count);
460
	}
461 462

	if(misc&TOT && !(misc&AUTO))
463
		fprintf(out,"TOTALS\n------\n%lu credits/bytes in %lu files.\n"
464 465 466 467
			,total_cdt,total_files);
	printf("\nDone.\n");
	return(0);
}