|
|
1.1 root 1: /* filelist.c */
2:
3: /* Utility to create list of files from Synchronet file directories */
4: /* Default list format is FILES.BBS, but file size, uploader, upload date */
5: /* and other information can be included. */
6:
1.1.1.2 ! root 7: /* $Id: filelist.c,v 1.16 2011/09/07 22:17:37 rswindell Exp $ */
1.1 root 8:
9: /****************************************************************************
10: * @format.tab-size 4 (Plain Text/Source Code File Header) *
11: * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
12: * *
1.1.1.2 ! root 13: * Copyright 2011 Rob Swindell - http://www.synchro.net/copyright.html *
1.1 root 14: * *
15: * This program is free software; you can redistribute it and/or *
16: * modify it under the terms of the GNU General Public License *
17: * as published by the Free Software Foundation; either version 2 *
18: * of the License, or (at your option) any later version. *
19: * See the GNU General Public License for more details: gpl.txt or *
20: * http://www.fsf.org/copyleft/gpl.html *
21: * *
22: * Anonymous FTP access to the most recent released source is available at *
23: * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
24: * *
25: * Anonymous CVS access to the development source and modification history *
26: * is available at cvs.synchro.net:/cvsroot/sbbs, example: *
27: * cvs -d :pserver:[email protected]:/cvsroot/sbbs login *
28: * (just hit return, no password is necessary) *
29: * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src *
30: * *
31: * For Synchronet coding style and modification guidelines, see *
32: * http://www.synchro.net/source.html *
33: * *
34: * You are encouraged to submit any modifications (preferably in Unix diff *
35: * format) via e-mail to [email protected] *
36: * *
37: * Note: If this box doesn't appear square, then you need to fix your tabs. *
38: ****************************************************************************/
39:
40: #include "sbbs.h"
41:
1.1.1.2 ! root 42: #define FILELIST_VER "3.15"
1.1 root 43:
44: #define MAX_NOTS 25
45:
46: scfg_t scfg;
47:
48: char *crlf="\r\n";
49:
50: /****************************************************************************/
51: /****************************************************************************/
1.1.1.2 ! root 52: int lprintf(int level, const char *fmat, ...)
1.1 root 53: {
54: va_list argptr;
55: char sbuf[256];
56: int chcount;
57:
58: va_start(argptr,fmat);
59: chcount=vsprintf(sbuf,fmat,argptr);
60: va_end(argptr);
61: truncsp(sbuf);
62: printf("%s\n",sbuf);
63: return(chcount);
64: }
65:
66: void stripctrlz(char *str)
67: {
68: char tmp[1024];
69: int i,j,k;
70:
71: k=strlen(str);
72: for(i=j=0;i<k;i++)
73: if(str[i]!=0x1a)
74: tmp[j++]=str[i];
75: tmp[j]=0;
76: strcpy(str,tmp);
77: }
78:
79:
80: #define ALL (1L<<0)
81: #define PAD (1L<<1)
82: #define HDR (1L<<2)
83: #define CDT_ (1L<<3)
84: #define EXT (1L<<4)
85: #define ULN (1L<<5)
86: #define ULD (1L<<6)
87: #define DLS (1L<<7)
88: #define DLD (1L<<8)
89: #define NOD (1L<<9)
90: #define PLUS (1L<<10)
91: #define MINUS (1L<<11)
92: #define JST (1L<<12)
93: #define NOE (1L<<13)
94: #define DFD (1L<<14)
95: #define TOT (1L<<15)
96: #define AUTO (1L<<16)
97:
98: /*********************/
99: /* Entry point (duh) */
100: /*********************/
101: int main(int argc, char **argv)
102: {
103: char revision[16];
104: char error[512];
105: char *p,str[256],fname[256],ext,not[MAX_NOTS][9];
106: uchar *datbuf,*ixbbuf;
107: int i,j,file,dirnum,libnum,desc_off,lines,nots=0
108: ,omode=O_WRONLY|O_CREAT|O_TRUNC;
1.1.1.2 ! root 109: ulong l,m,n,cdt,misc=0,total_cdt=0,total_files=0,dir_files,datbuflen;
! 110: time_t uld,dld,now;
! 111: long max_age=0;
1.1 root 112: FILE *in,*out=NULL;
113:
1.1.1.2 ! root 114: sscanf("$Revision: 1.16 $", "%*s %s", revision);
1.1 root 115:
116: fprintf(stderr,"\nFILELIST v%s-%s (rev %s) - Generate Synchronet File "
117: "Directory Lists\n"
118: ,FILELIST_VER
119: ,PLATFORM_DESC
120: ,revision
121: );
122:
123: if(argc<2
124: || strcmp(argv[1],"-?")==0
125: || strcmp(argv[1],"-help")==0
126: || strcmp(argv[1],"--help")==0
127: || strcmp(argv[1],"/?")==0
128: ) {
1.1.1.2 ! root 129: printf("\n usage: FILELIST <dir_code or - for ALL> [switches] [outfile]\n");
1.1 root 130: printf("\n");
131: printf("switches: -lib name All directories of specified library\n");
132: printf(" -not code Exclude specific directory\n");
1.1.1.2 ! root 133: printf(" -new days Include only new files in listing (days since upload)\n");
1.1 root 134: printf(" -cat Concatenate to existing outfile\n");
135: printf(" -pad Pad filename with spaces\n");
136: printf(" -hdr Include directory headers\n");
137: printf(" -cdt Include credit value\n");
138: printf(" -tot Include credit totals\n");
139: printf(" -uln Include uploader's name\n");
140: printf(" -uld Include upload date\n");
141: printf(" -dfd Include DOS file date\n");
142: printf(" -dld Include download date\n");
143: printf(" -dls Include total downloads\n");
144: printf(" -nod Exclude normal descriptions\n");
145: printf(" -noe Exclude normal descriptions, if extended "
146: "exists\n");
147: printf(" -ext Include extended descriptions\n");
148: printf(" -jst Justify extended descriptions under normal\n");
149: printf(" -+ Include extended description indicator (+)\n");
150: printf(" -- Include offline file indicator (-)\n");
151: printf(" -* Short-hand for -pad -hdr -cdt -+ --\n");
152: exit(0); }
153:
154: p=getenv("SBBSCTRL");
155: if(p==NULL) {
156: printf("\nSBBSCTRL environment variable not set.\n");
157: printf("\nExample: SET SBBSCTRL=/sbbs/ctrl\n");
158: exit(1);
159: }
160:
1.1.1.2 ! root 161: now=time(NULL);
! 162:
1.1 root 163: memset(&scfg,0,sizeof(scfg));
164: scfg.size=sizeof(scfg);
165: SAFECOPY(scfg.ctrl_dir,p);
166:
167: if(chdir(scfg.ctrl_dir)!=0)
168: fprintf(stderr,"!ERROR changing directory to: %s", scfg.ctrl_dir);
169:
170: printf("\nLoading configuration files from %s\n",scfg.ctrl_dir);
171: if(!load_cfg(&scfg,NULL,TRUE,error)) {
172: fprintf(stderr,"!ERROR loading configuration files: %s\n",error);
173: exit(1);
174: }
175: SAFECOPY(scfg.temp_dir,"../temp");
176: prep_dir(scfg.ctrl_dir, scfg.temp_dir, sizeof(scfg.temp_dir));
177:
178: dirnum=libnum=-1;
1.1.1.2 ! root 179: if(argv[1][0]=='*' || strcmp(argv[1],"-")==0)
1.1 root 180: misc|=ALL;
181: else if(argv[1][0]!='-') {
182: strupr(argv[1]);
183: for(i=0;i<scfg.total_dirs;i++)
184: if(!stricmp(argv[1],scfg.dir[i]->code))
185: break;
186: if(i>=scfg.total_dirs) {
187: printf("\nDirectory code '%s' not found.\n",argv[1]);
188: exit(1); }
189: dirnum=i; }
190: for(i=1;i<argc;i++) {
191: if(!stricmp(argv[i],"-lib")) {
192: if(dirnum!=-1) {
193: printf("\nBoth directory code and -lib parameters were used.\n");
194: exit(1); }
195: i++;
196: if(i>=argc) {
197: printf("\nLibrary short name must follow -lib parameter.\n");
198: exit(1); }
199: strupr(argv[i]);
200: for(j=0;j<scfg.total_libs;j++)
201: if(!stricmp(scfg.lib[j]->sname,argv[i]))
202: break;
203: if(j>=scfg.total_libs) {
204: printf("\nLibrary short name '%s' not found.\n",argv[i]);
205: exit(1); }
206: libnum=j; }
207: else if(!stricmp(argv[i],"-not")) {
208: if(nots>=MAX_NOTS) {
209: printf("\nMaximum number of -not options (%u) exceeded.\n"
210: ,MAX_NOTS);
211: exit(1); }
212: i++;
213: if(i>=argc) {
214: printf("\nDirectory internal code must follow -not parameter.\n");
215: exit(1); }
216: sprintf(not[nots++],"%.8s",argv[i]); }
217: else if(!stricmp(argv[i],"-all")) {
218: if(dirnum!=-1) {
219: printf("\nBoth directory code and -all parameters were used.\n");
220: exit(1); }
221: if(libnum!=-1) {
222: printf("\nBoth library name and -all parameters were used.\n");
223: exit(1); }
224: misc|=ALL; }
1.1.1.2 ! root 225: else if(!stricmp(argv[i],"-new")) {
! 226: i++;
! 227: if(i>=argc) {
! 228: printf("\nDays since upload must follow -new parameter.\n");
! 229: exit(1);
! 230: }
! 231: max_age=strtol(argv[i],NULL,0);
! 232: }
1.1 root 233: else if(!stricmp(argv[i],"-pad"))
234: misc|=PAD;
235: else if(!stricmp(argv[i],"-cat"))
236: omode=O_WRONLY|O_CREAT|O_APPEND;
237: else if(!stricmp(argv[i],"-hdr"))
238: misc|=HDR;
239: else if(!stricmp(argv[i],"-cdt"))
240: misc|=CDT_;
241: else if(!stricmp(argv[i],"-tot"))
242: misc|=TOT;
243: else if(!stricmp(argv[i],"-ext"))
244: misc|=EXT;
245: else if(!stricmp(argv[i],"-uln"))
246: misc|=ULN;
247: else if(!stricmp(argv[i],"-uld"))
248: misc|=ULD;
249: else if(!stricmp(argv[i],"-dld"))
250: misc|=DLD;
251: else if(!stricmp(argv[i],"-dfd"))
252: misc|=DFD;
253: else if(!stricmp(argv[i],"-dls"))
254: misc|=DLS;
255: else if(!stricmp(argv[i],"-nod"))
256: misc|=NOD;
257: else if(!stricmp(argv[i],"-jst"))
258: misc|=(EXT|JST);
259: else if(!stricmp(argv[i],"-noe"))
260: misc|=(EXT|NOE);
261: else if(!stricmp(argv[i],"-+"))
262: misc|=PLUS;
263: else if(!stricmp(argv[i],"--"))
264: misc|=MINUS;
265: else if(!stricmp(argv[i],"-*"))
266: misc|=(HDR|PAD|CDT_|PLUS|MINUS);
267:
268: else if(i!=1) {
1.1.1.2 ! root 269: if(argv[i][0]=='*' || strcmp(argv[i],"-")==0) {
1.1 root 270: misc|=AUTO;
271: continue; }
272: if((j=nopen(argv[i],omode))==-1) {
273: printf("\nError opening/creating %s for output.\n",argv[i]);
274: exit(1); }
275: out=fdopen(j,"wb"); } }
276:
277: if(!out && !(misc&AUTO)) {
278: printf("\nOutput file not specified, using FILES.BBS in each "
279: "directory.\n");
280: misc|=AUTO; }
281:
282: for(i=0;i<scfg.total_dirs;i++) {
1.1.1.2 ! root 283: dir_files=0;
1.1 root 284: if(!(misc&ALL) && i!=dirnum && scfg.dir[i]->lib!=libnum)
285: continue;
286: for(j=0;j<nots;j++)
287: if(!stricmp(not[j],scfg.dir[i]->code))
288: break;
289: if(j<nots)
290: continue;
291: if(misc&AUTO && scfg.dir[i]->seqdev) /* CD-ROM */
292: continue;
293: printf("\n%-*s %s",LEN_GSNAME,scfg.lib[scfg.dir[i]->lib]->sname,scfg.dir[i]->lname);
294: sprintf(str,"%s%s.ixb",scfg.dir[i]->data_dir,scfg.dir[i]->code);
295: if((file=nopen(str,O_RDONLY))==-1)
296: continue;
297: l=filelength(file);
298: if(misc&AUTO) {
299: sprintf(str,"%sFILES.BBS",scfg.dir[i]->path);
300: if((j=nopen(str,omode))==-1) {
301: printf("\nError opening/creating %s for output.\n",str);
302: exit(1); }
303: out=fdopen(j,"wb"); }
304: if(misc&HDR) {
305: sprintf(fname,"%-*s %-*s Files: %4lu"
306: ,LEN_GSNAME,scfg.lib[scfg.dir[i]->lib]->sname
307: ,LEN_SLNAME,scfg.dir[i]->lname,l/F_IXBSIZE);
308: fprintf(out,"%s\r\n",fname);
309: memset(fname,'-',strlen(fname));
310: fprintf(out,"%s\r\n",fname); }
311: if(!l) {
312: close(file);
313: if(misc&AUTO) fclose(out);
314: continue; }
315: if((ixbbuf=(char *)malloc(l))==NULL) {
316: close(file);
317: if(misc&AUTO) fclose(out);
318: printf("\7ERR_ALLOC %s %lu\n",str,l);
319: continue; }
320: if(read(file,ixbbuf,l)!=(int)l) {
321: close(file);
322: if(misc&AUTO) fclose(out);
323: printf("\7ERR_READ %s %lu\n",str,l);
324: free((char *)ixbbuf);
325: continue; }
326: close(file);
327: sprintf(str,"%s%s.dat",scfg.dir[i]->data_dir,scfg.dir[i]->code);
328: if((file=nopen(str,O_RDONLY))==-1) {
329: printf("\7ERR_OPEN %s %u\n",str,O_RDONLY);
330: free((char *)ixbbuf);
331: if(misc&AUTO) fclose(out);
332: continue; }
333: datbuflen=filelength(file);
334: if((datbuf=malloc(datbuflen))==NULL) {
335: close(file);
336: printf("\7ERR_ALLOC %s %lu\n",str,datbuflen);
337: free((char *)ixbbuf);
338: if(misc&AUTO) fclose(out);
339: continue; }
340: if(read(file,datbuf,datbuflen)!=(int)datbuflen) {
341: close(file);
342: printf("\7ERR_READ %s %lu\n",str,datbuflen);
343: free((char *)datbuf);
344: free((char *)ixbbuf);
345: if(misc&AUTO) fclose(out);
346: continue; }
347: close(file);
348: m=0L;
349: while(m<l && !ferror(out)) {
350: for(j=0;j<12 && m<l;j++)
351: if(j==8)
352: str[j]=ixbbuf[m]>' ' ? '.' : ' ';
353: else
354: str[j]=ixbbuf[m++]; /* Turns FILENAMEEXT into FILENAME.EXT */
355: str[j]=0;
356: unpadfname(str,fname);
357: n=ixbbuf[m]|((long)ixbbuf[m+1]<<8)|((long)ixbbuf[m+2]<<16);
358: uld=(ixbbuf[m+3]|((long)ixbbuf[m+4]<<8)|((long)ixbbuf[m+5]<<16)
359: |((long)ixbbuf[m+6]<<24));
360: dld=(ixbbuf[m+7]|((long)ixbbuf[m+8]<<8)|((long)ixbbuf[m+9]<<16)
361: |((long)ixbbuf[m+10]<<24));
362: m+=11;
363:
364: if(n>=datbuflen /* index out of bounds */
365: || datbuf[n+F_DESC+LEN_FDESC]!=CR) { /* corrupted data */
366: fprintf(stderr,"\n\7%s%s is corrupted!\n"
367: ,scfg.dir[i]->data_dir,scfg.dir[i]->code);
368: exit(-1); }
1.1.1.2 ! root 369:
! 370: if(max_age && ((now - uld) / (24*60*60) > max_age))
! 371: continue;
! 372:
! 373: fprintf(out,"%-12.12s",misc&PAD ? str : fname);
1.1 root 374:
1.1.1.2 ! root 375: total_files++;
! 376: dir_files++;
1.1 root 377:
378: if(misc&PLUS && datbuf[n+F_MISC]!=ETX
379: && (datbuf[n+F_MISC]-' ')&FM_EXTDESC)
380: fputc('+',out);
381: else
382: fputc(' ',out);
383:
384: desc_off=12;
385: if(misc&(CDT_|TOT)) {
386: getrec((char *)&datbuf[n],F_CDT,LEN_FCDT,str);
387: cdt=atol(str);
388: total_cdt+=cdt;
389: if(misc&CDT_) {
390: fprintf(out,"%7lu",cdt);
391: desc_off+=7; } }
392:
393: if(misc&MINUS) {
394: sprintf(str,"%s%s",scfg.dir[i]->path,fname);
395: if(!fexistcase(str))
396: fputc('-',out);
397: else
398: fputc(' ',out); }
399: else
400: fputc(' ',out);
401: desc_off++;
402:
403: if(misc&DFD) {
404: sprintf(str,"%s%s",scfg.dir[i]->path,fname);
405: fprintf(out,"%s ",unixtodstr(&scfg,fdate(str),str));
406: desc_off+=9; }
407:
408: if(misc&ULD) {
409: fprintf(out,"%s ",unixtodstr(&scfg,uld,str));
410: desc_off+=9; }
411:
412: if(misc&ULN) {
413: getrec((char *)&datbuf[n],F_ULER,25,str);
414: fprintf(out,"%-25s ",str);
415: desc_off+=26; }
416:
417: if(misc&DLD) {
418: fprintf(out,"%s ",unixtodstr(&scfg,dld,str));
419: desc_off+=9; }
420:
421: if(misc&DLS) {
422: getrec((char *)&datbuf[n],F_TIMESDLED,5,str);
423: j=atoi(str);
424: fprintf(out,"%5u ",j);
425: desc_off+=6; }
426:
427: if(datbuf[n+F_MISC]!=ETX && (datbuf[n+F_MISC]-' ')&FM_EXTDESC)
428: ext=1; /* extended description exists */
429: else
430: ext=0; /* it doesn't */
431:
432: if(!(misc&NOD) && !(misc&NOE && ext)) {
433: getrec((char *)&datbuf[n],F_DESC,LEN_FDESC,str);
434: fprintf(out,"%s",str); }
435:
436: if(misc&EXT && ext) { /* Print ext desc */
437:
438: sprintf(str,"%s%s.exb",scfg.dir[i]->data_dir,scfg.dir[i]->code);
439: if(!fexist(str))
440: continue;
441: if((j=nopen(str,O_RDONLY))==-1) {
442: printf("\7ERR_OPEN %s %u\n",str,O_RDONLY);
443: continue; }
444: if((in=fdopen(j,"rb"))==NULL) {
445: close(j);
446: continue; }
447: fseek(in,(n/F_LEN)*512L,SEEK_SET);
448: lines=0;
449: if(!(misc&NOE)) {
450: fprintf(out,"\r\n");
451: lines++; }
452: while(!feof(in) && !ferror(in)
453: && ftell(in)<(long)((n/F_LEN)+1)*512L) {
454: if(!fgets(str,128,in) || !str[0])
455: break;
456: stripctrlz(str);
457: if(lines) {
458: if(misc&JST)
459: fprintf(out,"%*s",desc_off,"");
460: fputc(' ',out); /* indent one character */ }
461: fprintf(out,"%s",str);
462: lines++; }
463: fclose(in); }
464: fprintf(out,"\r\n"); }
465: free((char *)datbuf);
466: free((char *)ixbbuf);
1.1.1.2 ! root 467: if(dir_files)
! 468: fprintf(out,"\r\n"); /* blank line at end of dir */
1.1 root 469: if(misc&AUTO) fclose(out); }
470:
471: if(misc&TOT && !(misc&AUTO))
472: fprintf(out,"TOTALS\n------\n%lu credits/bytes in %lu files.\r\n"
473: ,total_cdt,total_files);
474: printf("\nDone.\n");
475: return(0);
476: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.