filelist.c 13.3 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
31
#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"
#include <stdarg.h>
32

33
#define FILELIST_VER "3.15"
34
35
36
37
38
39
40
41
42

#define MAX_NOTS 25

scfg_t scfg;

char *crlf="\r\n";

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

	va_start(argptr,fmat);
	chcount=vsprintf(sbuf,fmat,argptr);
	va_end(argptr);
52
53
	truncsp(sbuf);
	printf("%s\n",sbuf);
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
	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);
}


#define ALL 	(1L<<0)
#define PAD 	(1L<<1)
#define HDR 	(1L<<2)
#define CDT_	(1L<<3)
#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];
96
	char	str[256],fname[256],ext,not[MAX_NOTS][9];
97
	uchar	*datbuf,*ixbbuf;
rswindell's avatar
rswindell committed
98
	int 	i,j,file,dirnum,libnum,desc_off,lines,nots=0
99
			,omode=O_WRONLY|O_CREAT|O_TRUNC;
100
	ulong	l,m,n,cdt,misc=0,total_cdt=0,total_files=0,dir_files,datbuflen;
101
	time32_t uld,dld,now;
102
	long	max_age=0;
103
104
	FILE	*in,*out=NULL;

Rob Swindell's avatar
Rob Swindell committed
105
	sscanf("$Revision: 1.22 $", "%*s %s", revision);
106
107
108
109
110
111
112
113
114
115
116
117
118
119

	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
		) {
120
		printf("\n   usage: FILELIST <dir_code or - for ALL> [switches] [outfile]\n");
121
122
123
		printf("\n");
		printf("switches: -lib name All directories of specified library\n");
		printf("          -not code Exclude specific directory\n");
124
		printf("          -new days Include only new files in listing (days since upload)\n");
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
		printf("          -cat      Concatenate to existing outfile\n");
		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");
		printf("          -dfd      Include DOS file date\n");
		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");
143
144
		exit(0); 
	}
145

146
	now=time32(NULL);
147

148
149
	memset(&scfg,0,sizeof(scfg));
	scfg.size=sizeof(scfg);
150
	SAFECOPY(scfg.ctrl_dir, get_ctrl_dir(/* warn: */TRUE));
151
152
153
154
155

	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);
156
	if(!load_cfg(&scfg, /* text: */NULL, /* prep: */TRUE, /* node: */FALSE, error, sizeof(error))) {
157
158
159
		fprintf(stderr,"!ERROR loading configuration files: %s\n",error);
		exit(1);
	}
rswindell's avatar
rswindell committed
160
161
	SAFECOPY(scfg.temp_dir,"../temp");
	prep_dir(scfg.ctrl_dir, scfg.temp_dir, sizeof(scfg.temp_dir));
162
163

	dirnum=libnum=-1;
164
	if(argv[1][0]=='*' || strcmp(argv[1],"-")==0)
165
166
167
168
169
170
171
172
		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]);
173
174
175
176
			exit(1); 
		}
		dirnum=i; 
	}
177
178
179
180
	for(i=1;i<argc;i++) {
		if(!stricmp(argv[i],"-lib")) {
			if(dirnum!=-1) {
				printf("\nBoth directory code and -lib parameters were used.\n");
181
182
				exit(1); 
			}
183
184
185
			i++;
			if(i>=argc) {
				printf("\nLibrary short name must follow -lib parameter.\n");
186
187
				exit(1); 
			}
188
189
190
191
192
193
			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]);
194
195
196
197
				exit(1); 
			}
			libnum=j; 
		}
198
199
200
201
		else if(!stricmp(argv[i],"-not")) {
			if(nots>=MAX_NOTS) {
				printf("\nMaximum number of -not options (%u) exceeded.\n"
					,MAX_NOTS);
202
203
				exit(1); 
			}
204
205
206
			i++;
			if(i>=argc) {
				printf("\nDirectory internal code must follow -not parameter.\n");
207
208
209
210
				exit(1); 
			}
			sprintf(not[nots++],"%.8s",argv[i]); 
		}
211
212
213
		else if(!stricmp(argv[i],"-all")) {
			if(dirnum!=-1) {
				printf("\nBoth directory code and -all parameters were used.\n");
214
215
				exit(1); 
			}
216
217
			if(libnum!=-1) {
				printf("\nBoth library name and -all parameters were used.\n");
218
219
220
221
				exit(1); 
			}
			misc|=ALL; 
		}
222
223
224
225
226
227
228
229
		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);
		}
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
		else if(!stricmp(argv[i],"-pad"))
			misc|=PAD;
		else if(!stricmp(argv[i],"-cat"))
			omode=O_WRONLY|O_CREAT|O_APPEND;
		else if(!stricmp(argv[i],"-hdr"))
			misc|=HDR;
		else if(!stricmp(argv[i],"-cdt"))
			misc|=CDT_;
		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],"-*"))
			misc|=(HDR|PAD|CDT_|PLUS|MINUS);

		else if(i!=1) {
266
			if(argv[i][0]=='*' || strcmp(argv[i],"-")==0) {
267
				misc|=AUTO;
268
269
				continue; 
			}
270
271
			if((j=nopen(argv[i],omode))==-1) {
				printf("\nError opening/creating %s for output.\n",argv[i]);
272
273
274
275
276
				exit(1); 
			}
			out=fdopen(j,"wb"); 
		} 
	}
277
278
279
280

	if(!out && !(misc&AUTO)) {
		printf("\nOutput file not specified, using FILES.BBS in each "
			"directory.\n");
281
282
		misc|=AUTO; 
	}
283
284

	for(i=0;i<scfg.total_dirs;i++) {
285
		dir_files=0;
286
287
288
289
290
291
292
293
294
295
		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);
296
		sprintf(str,"%s%s.ixb",scfg.dir[i]->data_dir,scfg.dir[i]->code);
297
298
299
300
301
302
303
		if((file=nopen(str,O_RDONLY))==-1)
			continue;
		l=filelength(file);
		if(misc&AUTO) {
			sprintf(str,"%sFILES.BBS",scfg.dir[i]->path);
			if((j=nopen(str,omode))==-1) {
				printf("\nError opening/creating %s for output.\n",str);
304
305
306
307
				exit(1); 
			}
			out=fdopen(j,"wb"); 
		}
308
		if(misc&HDR) {
rswindell's avatar
rswindell committed
309
			sprintf(fname,"%-*s      %-*s       Files: %4lu"
310
311
312
				,LEN_GSNAME,scfg.lib[scfg.dir[i]->lib]->sname
				,LEN_SLNAME,scfg.dir[i]->lname,l/F_IXBSIZE);
			fprintf(out,"%s\r\n",fname);
rswindell's avatar
rswindell committed
313
			memset(fname,'-',strlen(fname));
314
315
			fprintf(out,"%s\r\n",fname); 
		}
316
317
318
		if(!l) {
			close(file);
			if(misc&AUTO) fclose(out);
319
320
			continue; 
		}
321
		if((ixbbuf=(uchar *)malloc(l))==NULL) {
322
323
324
			close(file);
			if(misc&AUTO) fclose(out);
			printf("\7ERR_ALLOC %s %lu\n",str,l);
325
326
			continue; 
		}
327
328
329
330
		if(read(file,ixbbuf,l)!=(int)l) {
			close(file);
			if(misc&AUTO) fclose(out);
			printf("\7ERR_READ %s %lu\n",str,l);
deuce's avatar
deuce committed
331
			free((char *)ixbbuf);
332
333
			continue; 
		}
334
		close(file);
335
		sprintf(str,"%s%s.dat",scfg.dir[i]->data_dir,scfg.dir[i]->code);
336
		if((file=nopen(str,O_RDONLY))==-1) {
rswindell's avatar
rswindell committed
337
			printf("\7ERR_OPEN %s %u\n",str,O_RDONLY);
deuce's avatar
deuce committed
338
			free((char *)ixbbuf);
339
			if(misc&AUTO) fclose(out);
340
341
			continue; 
		}
342
		datbuflen=filelength(file);
deuce's avatar
deuce committed
343
		if((datbuf=malloc(datbuflen))==NULL) {
344
345
			close(file);
			printf("\7ERR_ALLOC %s %lu\n",str,datbuflen);
deuce's avatar
deuce committed
346
			free((char *)ixbbuf);
347
			if(misc&AUTO) fclose(out);
348
349
			continue; 
		}
350
351
352
		if(read(file,datbuf,datbuflen)!=(int)datbuflen) {
			close(file);
			printf("\7ERR_READ %s %lu\n",str,datbuflen);
deuce's avatar
deuce committed
353
354
			free((char *)datbuf);
			free((char *)ixbbuf);
355
			if(misc&AUTO) fclose(out);
356
357
			continue; 
		}
358
359
360
361
362
		close(file);
		m=0L;
		while(m<l && !ferror(out)) {
			for(j=0;j<12 && m<l;j++)
				if(j==8)
363
					str[j]=ixbbuf[m]>' ' ? '.' : ' ';
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
				else
					str[j]=ixbbuf[m++]; /* Turns FILENAMEEXT into FILENAME.EXT */
			str[j]=0;
			unpadfname(str,fname);
			n=ixbbuf[m]|((long)ixbbuf[m+1]<<8)|((long)ixbbuf[m+2]<<16);
			uld=(ixbbuf[m+3]|((long)ixbbuf[m+4]<<8)|((long)ixbbuf[m+5]<<16)
				|((long)ixbbuf[m+6]<<24));
			dld=(ixbbuf[m+7]|((long)ixbbuf[m+8]<<8)|((long)ixbbuf[m+9]<<16)
				|((long)ixbbuf[m+10]<<24));
			m+=11;

			if(n>=datbuflen 							/* index out of bounds */
				|| datbuf[n+F_DESC+LEN_FDESC]!=CR) {	/* corrupted data */
				fprintf(stderr,"\n\7%s%s is corrupted!\n"
					,scfg.dir[i]->data_dir,scfg.dir[i]->code);
379
380
				exit(-1); 
			}
381
382
383
384
385
			
			if(max_age && ((now - uld) / (24*60*60) > max_age))
				continue;

			fprintf(out,"%-12.12s",misc&PAD ? str : fname);
386

387
388
			total_files++;
			dir_files++;
389
390

			if(misc&PLUS && datbuf[n+F_MISC]!=ETX
391
				&& (datbuf[n+F_MISC]-' ')&FM_EXTDESC)
392
393
				fputc('+',out);
			else
394
				fputc(' ',out);
395
396
397
398
399
400
401
402

			desc_off=12;
			if(misc&(CDT_|TOT)) {
				getrec((char *)&datbuf[n],F_CDT,LEN_FCDT,str);
				cdt=atol(str);
				total_cdt+=cdt;
				if(misc&CDT_) {
					fprintf(out,"%7lu",cdt);
403
404
405
					desc_off+=7; 
				} 
			}
406
407

			if(misc&MINUS) {
408
				SAFEPRINTF2(str,"%s%s",scfg.dir[i]->path,fname);
409
				if(!fexistcase(str))
410
411
					fputc('-',out);
				else
412
413
					fputc(' ',out); 
			}
414
			else
415
				fputc(' ',out);
416
417
418
			desc_off++;

			if(misc&DFD) {
419
				SAFEPRINTF2(str,"%s%s",scfg.dir[i]->path,fname);
420
				fprintf(out,"%s ",unixtodstr(&scfg,(time32_t)fdate(str),str));
421
422
				desc_off+=9; 
			}
423
424
425

			if(misc&ULD) {
				fprintf(out,"%s ",unixtodstr(&scfg,uld,str));
426
427
				desc_off+=9; 
			}
428
429
430
431

			if(misc&ULN) {
				getrec((char *)&datbuf[n],F_ULER,25,str);
				fprintf(out,"%-25s ",str);
432
433
				desc_off+=26; 
			}
434
435
436

			if(misc&DLD) {
				fprintf(out,"%s ",unixtodstr(&scfg,dld,str));
437
438
				desc_off+=9; 
			}
439
440
441
442
443

			if(misc&DLS) {
				getrec((char *)&datbuf[n],F_TIMESDLED,5,str);
				j=atoi(str);
				fprintf(out,"%5u ",j);
444
445
				desc_off+=6; 
			}
446

447
			if(datbuf[n+F_MISC]!=ETX && (datbuf[n+F_MISC]-' ')&FM_EXTDESC)
448
449
450
451
452
453
				ext=1;	/* extended description exists */
			else
				ext=0;	/* it doesn't */

			if(!(misc&NOD) && !(misc&NOE && ext)) {
				getrec((char *)&datbuf[n],F_DESC,LEN_FDESC,str);
454
455
				fprintf(out,"%s",str); 
			}
456
457
458

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

459
				sprintf(str,"%s%s.exb",scfg.dir[i]->data_dir,scfg.dir[i]->code);
460
461
462
				if(!fexist(str))
					continue;
				if((j=nopen(str,O_RDONLY))==-1) {
rswindell's avatar
rswindell committed
463
					printf("\7ERR_OPEN %s %u\n",str,O_RDONLY);
464
465
					continue; 
				}
466
467
				if((in=fdopen(j,"rb"))==NULL) {
					close(j);
468
469
					continue; 
				}
470
471
472
473
				fseek(in,(n/F_LEN)*512L,SEEK_SET);
				lines=0;
				if(!(misc&NOE)) {
					fprintf(out,"\r\n");
474
475
					lines++; 
				}
476
477
478
479
480
481
482
483
				while(!feof(in) && !ferror(in)
					&& ftell(in)<(long)((n/F_LEN)+1)*512L) {
					if(!fgets(str,128,in) || !str[0])
						break;
					stripctrlz(str);
					if(lines) {
						if(misc&JST)
							fprintf(out,"%*s",desc_off,"");
484
						fputc(' ',out);				/* indent one character */ }
485
					fprintf(out,"%s",str);
486
487
488
489
490
491
					lines++; 
				}
				fclose(in); 
			}
			fprintf(out,"\r\n"); 
		}
deuce's avatar
deuce committed
492
493
		free((char *)datbuf);
		free((char *)ixbbuf);
494
495
		if(dir_files)
			fprintf(out,"\r\n"); /* blank line at end of dir */
496
497
		if(misc&AUTO) fclose(out); 
	}
498
499
500
501
502
503
504

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