home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1998 September / PCO_0998.ISO / filesbbs / dos / sbbs_src.exe / SBBS / DELFILES / DELFILES.C next >
Encoding:
C/C++ Source or Header  |  1997-05-18  |  22.1 KB  |  764 lines

  1. #line 1 "DELFILES.C"
  2.  
  3. /* Developed 1990-1997 by Rob Swindell; PO Box 501, Yorba Linda, CA 92885 */
  4.  
  5. #include "sbbs.h"
  6.  
  7. #define DELFILES_VER "1.01"
  8.  
  9. char tmp[256];
  10.  
  11. #define MAX_NOTS    25
  12.  
  13. #define ALL     (1L<<0)
  14. #define OFFLINE (1L<<1)
  15. #define NO_LINK (1L<<2)
  16. #define REPORT    (1L<<3)
  17.  
  18. void bail(int code)
  19. {
  20. exit(code);
  21. }
  22.  
  23. long lputs(char FAR16 *str)
  24. {
  25.     char tmp[256];
  26.     int i,j,k;
  27.  
  28. j=strlen(str);
  29. for(i=k=0;i<j;i++)      /* remove CRs */
  30.     if(str[i]==CR && str[i+1]==LF)
  31.         continue;
  32.     else
  33.         tmp[k++]=str[i];
  34. tmp[k]=0;
  35. return(fputs(tmp,stdout));
  36. }
  37.  
  38. /****************************************************************************/
  39. /* Performs printf() through local assembly routines                        */
  40. /* Called from everywhere                                                   */
  41. /****************************************************************************/
  42. int lprintf(char *fmat, ...)
  43. {
  44.     va_list argptr;
  45.     char sbuf[256];
  46.     int chcount;
  47.  
  48. va_start(argptr,fmat);
  49. chcount=vsprintf(sbuf,fmat,argptr);
  50. va_end(argptr);
  51. lputs(sbuf);
  52. return(chcount);
  53. }
  54.  
  55. /****************************************************************************/
  56. /* Truncates white-space chars off end of 'str' and terminates at first tab */
  57. /****************************************************************************/
  58. void truncsp(char *str)
  59. {
  60.     int c;
  61.  
  62. str[strcspn(str,"\t")]=0;
  63. c=strlen(str);
  64. while(c && (uchar)str[c-1]<=SP) c--;
  65. str[c]=0;
  66. }
  67.  
  68. /****************************************************************************/
  69. /* Puts a backslash on path strings                                         */
  70. /****************************************************************************/
  71. void backslash(char *str)
  72. {
  73.     int i;
  74.  
  75. i=strlen(str);
  76. if(i && str[i-1]!='\\') {
  77.     str[i]='\\'; str[i+1]=0; }
  78. }
  79.  
  80. /****************************************************************************/
  81. /* Network open function. Opens all files DENYALL and retries LOOP_NOPEN    */
  82. /* number of times if the attempted file is aREADy open or denying access  */
  83. /* for some other reason.    All files are opened in BINARY mode.            */
  84. /****************************************************************************/
  85. int nopen(char *str, int access)
  86. {
  87.     char logstr[256];
  88.     int file,share,count=0;
  89.  
  90. if(access==O_RDONLY) share=SH_DENYWR;
  91.     else share=SH_DENYRW;
  92. while(((file=sopen(str,O_BINARY|access,share,S_IWRITE))==-1)
  93.     && errno==EACCES && count++<LOOP_NOPEN);
  94. if(file==-1 && errno==EACCES)
  95.     lputs("\7\r\nNOPEN: ACCESS DENIED\r\n\7");
  96. return(file);
  97. }
  98.  
  99. /****************************************************************************/
  100. /* This function performs an nopen, but returns a file stream with a buffer */
  101. /* allocated.                                                                */
  102. /****************************************************************************/
  103. FILE *fnopen(int *file, char *str, int access)
  104. {
  105.     char mode[128];
  106.     FILE *stream;
  107.  
  108. if(((*file)=nopen(str,access))==-1) {
  109.     printf("nopen -1\n");
  110.     return(NULL); }
  111.  
  112. if(access&O_APPEND) {
  113.     if(access&O_RDONLY)
  114.         strcpy(mode,"a+");
  115.     else
  116.         strcpy(mode,"a"); }
  117. else {
  118.     if(access&O_WRONLY)
  119.         strcpy(mode,"r+");
  120.     else
  121.         strcpy(mode,"r"); }
  122. stream=fdopen((*file),mode);
  123. if(stream==NULL) {
  124.     printf("fdopen NULL mode='%s'\n",mode);
  125.     close(*file);
  126.     return(NULL); }
  127. setvbuf(stream,NULL,_IOFBF,16*1024);
  128. return(stream);
  129. }
  130.  
  131. /****************************************************************************/
  132. /* Checks the disk drive for the existence of a file. Returns 1 if it       */
  133. /* exists, 0 if it doesn't.                                                 */
  134. /****************************************************************************/
  135. char fexist(char *filespec)
  136. {
  137.     struct find_t f;
  138.     uint i;
  139.  
  140. i=_dos_findfirst(filespec,_A_NORMAL,&f);
  141. #ifdef __WATCOMC__
  142. _dos_findclose(&f);
  143. #endif
  144. if(!i)
  145.     return(1);
  146. return(0);
  147. }
  148.  
  149. /****************************************************************************/
  150. /* Returns the length of the file in 'filespec'                             */
  151. /****************************************************************************/
  152. long flength(char *filespec)
  153. {
  154.     struct find_t f;
  155.     uint i;
  156.  
  157. i=_dos_findfirst(filespec,_A_NORMAL,&f);
  158. #ifdef __WATCOMC__
  159. _dos_findclose(&f);
  160. #endif
  161. if(!i)
  162.     return(f.size);
  163. return(-1L);
  164. }
  165.  
  166. #ifndef __FLAT__
  167. /****************************************************************************/
  168. /* This function reads files that are potentially larger than 32k.          */
  169. /* Up to one megabyte of data can be read with each call.                   */
  170. /****************************************************************************/
  171. long lread(int file, char HUGE16 *buf,long bytes)
  172. {
  173.     long count;
  174.  
  175. for(count=bytes;count>32767;count-=32767,buf+=32767)
  176.     if(read(file,(char *)buf,32767)!=32767)
  177.         return(-1L);
  178. if(read(file,(char *)buf,(int)count)!=count)
  179.     return(-1L);
  180. return(bytes);
  181. }
  182.  
  183. /****************************************************************************/
  184. /* This function writes files that are potentially larger than 32767 bytes  */
  185. /* Up to one megabytes of data can be written with each call.                */
  186. /****************************************************************************/
  187. long lwrite(int file, char HUGE16 *buf, long bytes)
  188. {
  189.  
  190.     long count;
  191.  
  192. for(count=bytes;count>32767;count-=32767,buf+=32767)
  193.     if(write(file,(char *)buf,32767)!=32767)
  194.         return(-1L);
  195. if(write(file,(char *)buf,(int)count)!=count)
  196.     return(-1L);
  197. return(bytes);
  198. }
  199. #endif
  200.  
  201. /****************************************************************************/
  202. /* Removes any files in the user transfer index (XFER.IXT) that match the   */
  203. /* specifications of dest, or source user, or filename or any combination.  */
  204. /****************************************************************************/
  205. void rmuserxfers(int fromuser, int destuser, char *fname)
  206. {
  207.     char str[256],*ixtbuf;
  208.     int file;
  209.     long l,length;
  210.  
  211. sprintf(str,"%sXFER.IXT",data_dir);
  212. if(!fexist(str))
  213.     return;
  214. if(!flength(str)) {
  215.     remove(str);
  216.     return; }
  217. if((file=nopen(str,O_RDONLY))==-1) {
  218.     printf("ERROR opening %s\r\n",str);
  219.     return; }
  220. length=filelength(file);
  221. if((ixtbuf=(char *)MALLOC(length))==NULL) {
  222.     close(file);
  223.     printf("ERROR allocating %lu bytes for %s\r\n",length,str);
  224.     return; }
  225. if(read(file,ixtbuf,length)!=length) {
  226.     close(file);
  227.     FREE(ixtbuf);
  228.     printf("ERROR reading %lu bytes from %s\r\n",length,str);
  229.     return; }
  230. close(file);
  231. if((file=nopen(str,O_WRONLY|O_TRUNC))==-1) {
  232.     FREE(ixtbuf);
  233.     printf("ERROR opening %s\r\n",str);
  234.     return; }
  235. for(l=0;l<length;l+=24) {
  236.     if(fname!=NULL && fname[0]) {               /* fname specified */
  237.         if(!strncmp(ixtbuf+l+5,fname,12)) {     /* this is the file */
  238.             if(destuser && fromuser) {          /* both dest and from user */
  239.                 if(atoi(ixtbuf+l)==destuser && atoi(ixtbuf+l+18)==fromuser)
  240.                     continue; }                 /* both match */
  241.             else if(fromuser) {                 /* from user */
  242.                 if(atoi(ixtbuf+l+18)==fromuser) /* matches */
  243.                     continue; }
  244.             else if(destuser) {                 /* dest user */
  245.                 if(atoi(ixtbuf+l)==destuser)    /* matches */
  246.                     continue; }
  247.             else continue; } }                  /* no users, so match */
  248.     else if(destuser && fromuser) {
  249.         if(atoi(ixtbuf+l+18)==fromuser && atoi(ixtbuf+l)==destuser)
  250.             continue; }
  251.     else if(destuser && atoi(ixtbuf+l)==destuser)
  252.         continue;
  253.     else if(fromuser && atoi(ixtbuf+l+18)==fromuser)
  254.         continue;
  255.     write(file,ixtbuf+l,24); }
  256. close(file);
  257. FREE(ixtbuf);
  258. }
  259.  
  260. /****************************************************************************/
  261. /* Removes DAT and IXB entries for the file in the struct 'f'               */
  262. /****************************************************************************/
  263. void removefiledat(file_t f)
  264. {
  265.     char c,str[256],ixbname[12],HUGE16 *ixbbuf,fname[13];
  266.     int file;
  267.     ulong l,length;
  268.  
  269. strcpy(fname,f.name);
  270. for(c=8;c<12;c++)   /* Turn FILENAME.EXT into FILENAMEEXT */
  271.     fname[c]=fname[c+1];
  272. sprintf(str,"%s%s.IXB",dir[f.dir]->data_dir,dir[f.dir]->code);
  273. if((file=nopen(str,O_RDONLY))==-1) {
  274.     printf("ERROR opening %s\r\n",str);
  275.     return; }
  276. length=filelength(file);
  277. if(!length) {
  278.     close(file);
  279.     return; }
  280. if((ixbbuf=(char *)MALLOC(length))==0) {
  281.     close(file);
  282.     printf("ERROR allocating %lu bytes for %s\r\n",length,str);
  283.     return; }
  284. if(lread(file,ixbbuf,length)!=length) {
  285.     close(file);
  286.     printf("ERROR reading %lu bytes from %s\r\n",length,str);
  287.     FREE((char *)ixbbuf);
  288.     return; }
  289. close(file);
  290. if((file=nopen(str,O_WRONLY|O_TRUNC))==-1) {
  291.     printf("ERROR opening %s\r\n",str);
  292.     return; }
  293. for(l=0;l<length;l+=F_IXBSIZE) {
  294.     for(c=0;c<11;c++)
  295.         ixbname[c]=ixbbuf[l+c];
  296.     ixbname[c]=0;
  297.     if(strcmp(ixbname,fname))
  298.         if(lwrite(file,&ixbbuf[l],F_IXBSIZE)!=F_IXBSIZE) {
  299.             close(file);
  300.             printf("ERROR writing %lu bytes to %s\r\n",F_IXBSIZE,str);
  301.             FREE((char *)ixbbuf);
  302.             return; } }
  303. FREE((char *)ixbbuf);
  304. close(file);
  305. sprintf(str,"%s%s.DAT",dir[f.dir]->data_dir,dir[f.dir]->code);
  306. if((file=nopen(str,O_WRONLY))==-1) {
  307.     printf("ERROR opening %s\r\n",str);
  308.     return; }
  309. lseek(file,f.datoffset,SEEK_SET);
  310. c=ETX;          /* If first char of record is ETX, record is unused */
  311. if(write(file,&c,1)!=1) { /* So write a D_T on the first byte of the record */
  312.     close(file);
  313.     printf("ERROR writing to %s\r\n",str);
  314.     return; }
  315. close(file);
  316. if(f.dir==user_dir)  /* remove file from index */
  317.     rmuserxfers(0,0,f.name);
  318. }
  319.  
  320. /****************************************************************************/
  321. /* Places into 'strout' CR or ETX terminated string starting at             */
  322. /* 'start' and ending at 'start'+'length' or terminator from 'strin'        */
  323. /****************************************************************************/
  324. void getrec(char *strin,int start,int length,char *strout)
  325. {
  326.     int i=0,stop;
  327.  
  328. stop=start+length;
  329. while(start<stop) {
  330.     if(strin[start]==ETX)
  331.         break;
  332.     strout[i++]=strin[start++]; }
  333. strout[i]=0;
  334. }
  335.  
  336. /****************************************************************************/
  337. /* Turns FILE    .EXT into FILE.EXT                                         */
  338. /****************************************************************************/
  339. char *unpadfname(char *filename, char *str)
  340. {
  341.     char c,d;
  342.  
  343. for(c=0,d=0;c<strlen(filename);c++)
  344.     if(filename[c]!=SP) str[d++]=filename[c];
  345. str[d]=0;
  346. return(str);
  347. }
  348.  
  349. /****************************************************************************/
  350. /* Returns the time/date of the file in 'filespec' in time_t (unix) format  */
  351. /****************************************************************************/
  352. long fdate(char *filespec)
  353. {
  354.     int     file;
  355. #ifdef __WATCOMC__
  356.     unsigned short ft,fd;
  357. #else
  358.     unsigned ft,fd;
  359. #endif
  360.     struct    tm t;
  361.  
  362. if((file=nopen(filespec,O_RDONLY))==-1)
  363.     return(0);
  364. _dos_getftime(file,&fd,&ft);
  365. close(file);
  366. memset(&t,0,sizeof(t));
  367. t.tm_year=((fd&0xfe00)>>9)+80;
  368. t.tm_mon=((fd&0x01e0)>>5)-1;
  369. t.tm_mday=fd&0x1f;
  370. t.tm_hour=(ft&0xf800)>>11;
  371. t.tm_min=(ft&0x07e0)>>5;
  372. t.tm_sec=(ft&0x001f)<<1;
  373. return(mktime(&t));
  374. }
  375.  
  376. /****************************************************************************/
  377. /* Converts an ASCII Hex string into an ulong                               */
  378. /****************************************************************************/
  379. ulong ahtoul(char *str)
  380. {
  381.     ulong l,val=0;
  382.  
  383. while((l=(*str++)|0x20)!=0x20)
  384.     val=(l&0xf)+(l>>6&1)*9+val*16;
  385. return(val);
  386. }
  387.  
  388. uint hptoi(char *str)
  389. {
  390.     char tmp[128];
  391.     uint i;
  392.  
  393. if(!str[1] || toupper(str[0])<='F')
  394.     return(ahtoul(str));
  395. strcpy(tmp,str);
  396. tmp[0]='F';
  397. i=ahtoul(tmp)+((toupper(str[0])-'F')*0x10);
  398. return(i);
  399. }
  400.  
  401. /****************************************************************************/
  402. /* Gets filedata from dircode.DAT file                                        */
  403. /* Need fields .name ,.dir and .offset to get other info                    */
  404. /* Does not fill .dateuled or .datedled fields.                             */
  405. /****************************************************************************/
  406. void getfiledat(file_t *f)
  407. {
  408.     char buf[F_LEN+1],str[256],tmp[256];
  409.     int file;
  410.     long length;
  411.  
  412. sprintf(str,"%s%s.DAT",dir[f->dir]->data_dir,dir[f->dir]->code);
  413. if((file=nopen(str,O_RDONLY))==-1) {
  414.     printf("ERROR opening %s\r\n",str);
  415.     return; }
  416. length=filelength(file);
  417. if(f->datoffset>length) {
  418.     close(file);
  419.     printf("ERROR %s filelength %ld is less than offset\r\n",str,length);
  420.     return; }
  421. if(length%F_LEN) {
  422.     close(file);
  423.     printf("ERROR %s filelength %ld is not evenly divisible\r\n",str,length);
  424.     return; }
  425. lseek(file,f->datoffset,SEEK_SET);
  426. if(read(file,buf,F_LEN)!=F_LEN) {
  427.     close(file);
  428.     printf("ERROR reading %ld bytes from %s\r\n",F_LEN,str);
  429.     return; }
  430. close(file);
  431. getrec(buf,F_ALTPATH,2,str);
  432. f->altpath=hptoi(str);
  433. getrec(buf,F_CDT,7,str);
  434. f->cdt=atol(str);
  435.  
  436. if(!f->size) {                    /* only read disk if this is null */
  437.     if(dir[f->dir]->misc&DIR_FCHK) {
  438.         sprintf(str,"%s%s"
  439.             ,f->altpath>0 && f->altpath<=altpaths ? altpath[f->altpath-1]
  440.             : dir[f->dir]->path,unpadfname(f->name,tmp));
  441.         f->size=flength(str);
  442.         f->date=fdate(str); }
  443.     else {
  444.         f->size=f->cdt;
  445.         f->date=0; } }
  446. //if((f->size>0L) && cur_cps)
  447. //      f->timetodl=(f->size/(ulong)cur_cps);
  448. //else
  449.     f->timetodl=0;
  450.  
  451. getrec(buf,F_DESC,LEN_FDESC,f->desc);
  452. getrec(buf,F_ULER,LEN_ALIAS,f->uler);
  453. getrec(buf,F_TIMESDLED,5,str);
  454. f->timesdled=atoi(str);
  455. getrec(buf,F_OPENCOUNT,3,str);
  456. f->opencount=atoi(str);
  457. if(buf[F_MISC]!=ETX)
  458.     f->misc=buf[F_MISC]-SP;
  459. else
  460.     f->misc=0;
  461. }
  462.  
  463. /****************************************************************************/
  464. /* Checks  directory data file for 'filename' (must be padded). If found,   */
  465. /* it returns the 1, else returns 0.                                        */
  466. /* Called from upload and bulkupload                                        */
  467. /****************************************************************************/
  468. char findfile(uint dirnum, char *filename)
  469. {
  470.     char str[256],c,fname[128],HUGE16 *ixbbuf;
  471.     int file;
  472.     ulong length,l;
  473.  
  474. strcpy(fname,filename);
  475. for(c=8;c<12;c++)   /* Turn FILENAME.EXT into FILENAMEEXT */
  476.     fname[c]=fname[c+1];
  477. sprintf(str,"%s%s.IXB",dir[dirnum]->data_dir,dir[dirnum]->code);
  478. if((file=nopen(str,O_RDONLY))==-1) return(0);
  479. length=filelength(file);
  480. if(!length) {
  481.     close(file);
  482.     return(0); }
  483. if((ixbbuf=(char *)MALLOC(length))==NULL) {
  484.     close(file);
  485.     printf("ERR_ALLOC %s %lu\n",str,length);
  486.     return(0); }
  487. if(lread(file,ixbbuf,length)!=length) {
  488.     close(file);
  489.     FREE((char *)ixbbuf);
  490.     return(0); }
  491. close(file);
  492. for(l=0;l<length;l+=F_IXBSIZE) {
  493.     for(c=0;c<11;c++)
  494.         if(fname[c]!=ixbbuf[l+c]) break;
  495.     if(c==11) break; }
  496. FREE((char *)ixbbuf);
  497. if(l<length)
  498.     return(1);
  499. return(0);
  500. }
  501.  
  502. /****************************************************************************/
  503. /* Turns FILE.EXT into FILE    .EXT                                         */
  504. /* Called from upload                                                       */
  505. /****************************************************************************/
  506. char *padfname(char *filename, char *str)
  507. {
  508.     char c,d;
  509.  
  510. for(c=0;c<8;c++)
  511.     if(filename[c]=='.' || !filename[c]) break;
  512.     else str[c]=filename[c];
  513. d=c;
  514. if(filename[c]=='.') c++;
  515. while(d<8)
  516.     str[d++]=SP;
  517. str[d++]='.';
  518. while(d<12)
  519.     if(!filename[c]) break;
  520.     else str[d++]=filename[c++];
  521. while(d<12)
  522.     str[d++]=SP;
  523. str[d]=0;
  524. return(str);
  525. }
  526.  
  527. void main(int argc, char **argv)
  528. {
  529.     char str[256],fname[256],not[MAX_NOTS][9],nots=0,*p;
  530.     uchar HUGE16 *ixbbuf;
  531.     int i,j,dirnum,libnum,file;
  532.     ulong l,m,n,length;
  533.     long misc=0;
  534.     time_t now;
  535.     read_cfg_text_t txt;
  536.     file_t workfile;
  537.     struct find_t ff;
  538.  
  539. putenv("TZ=UCT0");
  540. _fmode=O_BINARY;
  541. setvbuf(stdout,NULL,_IONBF,0);
  542.  
  543. fprintf(stderr,"\nDELFILES Version %s (%s) - Removes files from Synchronet "
  544.     "Filebase\n"
  545.     ,DELFILES_VER
  546. #if defined(__OS2__)
  547.     ,"OS/2"
  548. #elif defined(__NT__)
  549.     ,"Win32"
  550. #elif defined(__DOS4G__)
  551.     ,"DOS4G"
  552. #elif defined(__FLAT__)
  553.     ,"DOS32"
  554. #else
  555.     ,"DOS16"
  556. #endif
  557.     );
  558.  
  559. if(argc<2) {
  560.     printf("\n   usage: DELFILES <dir_code or * for ALL> [switches]\n");
  561.     printf("\nswitches: /LIB name All directories of specified library\n");
  562.     printf("          /NOT code Exclude specific directory\n");
  563.     printf("          /OFF      Remove files that are offline "
  564.         "(don't exist on disk)\n");
  565.     printf("          /NOL      Remove files with no link "
  566.         "(don't exist in database)\n");
  567.     printf("          /RPT      Report findings only "
  568.         "(don't delete any files)\n");
  569.     exit(0); }
  570.  
  571. p=getenv("SBBSNODE");
  572. if(p==NULL) {
  573.     printf("\nSBBSNODE environment variable not set.\n");
  574.     printf("\nExample: SET SBBSNODE=C:\\SBBS\\NODE1\n");
  575.     exit(1); }
  576.  
  577. putenv("TZ=UCT0");
  578.  
  579. strcpy(node_dir,p);
  580. if(node_dir[strlen(node_dir)-1]!='\\')
  581.     strcat(node_dir,"\\");
  582.  
  583. txt.openerr="\7\nError opening %s for read.\n";
  584. txt.reading="\nReading %s...";
  585. txt.readit="\rRead %s       ";
  586. txt.allocerr="\7\nError allocating %u bytes of memory\n";
  587. txt.error="\7\nERROR: Offset %lu in %s\r\n\n";
  588.  
  589. read_node_cfg(txt);
  590. if(ctrl_dir[0]=='.') {   /* Relative path */
  591.     strcpy(str,ctrl_dir);
  592.     sprintf(ctrl_dir,"%s%s",node_dir,str); }
  593. read_main_cfg(txt);
  594. if(data_dir[0]=='.') {   /* Relative path */
  595.     strcpy(str,data_dir);
  596.     sprintf(data_dir,"%s%s",node_dir,str); }
  597. if(temp_dir[1]!=':' && temp_dir[0]!='\\') {
  598.     strcpy(str,temp_dir);
  599.     sprintf(temp_dir,"%s%s",node_dir,str); }
  600. read_file_cfg(txt);
  601. printf("\n\n");
  602.  
  603. dirnum=libnum=-1;
  604. if(argv[1][0]=='*')
  605.     misc|=ALL;
  606. else if(argv[1][0]!='/') {
  607.     strupr(argv[1]);
  608.     for(i=0;i<total_dirs;i++)
  609.         if(!stricmp(argv[1],dir[i]->code))
  610.             break;
  611.     if(i>=total_dirs) {
  612.         printf("\nDirectory code '%s' not found.\n",argv[1]);
  613.         exit(1); }
  614.     dirnum=i; }
  615. for(i=1;i<argc;i++) {
  616.     if(!stricmp(argv[i],"/LIB")) {
  617.         if(dirnum!=-1) {
  618.             printf("\nBoth directory code and /LIB parameters were used.\n");
  619.             exit(1); }
  620.         i++;
  621.         if(i>=argc) {
  622.             printf("\nLibrary short name must follow /LIB parameter.\n");
  623.             exit(1); }
  624.         strupr(argv[i]);
  625.         for(j=0;j<total_libs;j++)
  626.             if(!stricmp(lib[j]->sname,argv[i]))
  627.                 break;
  628.         if(j>=total_libs) {
  629.             printf("\nLibrary short name '%s' not found.\n",argv[i]);
  630.             exit(1); }
  631.         libnum=j; }
  632.     else if(!stricmp(argv[i],"/NOT")) {
  633.         if(nots>=MAX_NOTS) {
  634.             printf("\nMaximum number of /NOT options (%u) exceeded.\n"
  635.                 ,MAX_NOTS);
  636.             exit(1); }
  637.         i++;
  638.         if(i>=argc) {
  639.             printf("\nDirectory internal code must follow /NOT parameter.\n");
  640.             exit(1); }
  641.         sprintf(not[nots++],"%.8s",argv[i]); }
  642.     else if(!stricmp(argv[i],"/OFF"))
  643.         misc|=OFFLINE;
  644.     else if(!stricmp(argv[i],"/NOL"))
  645.         misc|=NO_LINK;
  646.     else if(!stricmp(argv[i],"/RPT"))
  647.         misc|=REPORT;
  648.     else if(!stricmp(argv[i],"/ALL")) {
  649.         if(dirnum!=-1) {
  650.             printf("\nBoth directory code and /ALL parameters were used.\n");
  651.             exit(1); }
  652.         if(libnum!=-1) {
  653.             printf("\nBoth library name and /ALL parameters were used.\n");
  654.             exit(1); }
  655.         misc|=ALL; } }
  656.  
  657. for(i=0;i<total_dirs;i++) {
  658.     if(!(misc&ALL) && i!=dirnum && dir[i]->lib!=libnum)
  659.         continue;
  660.     for(j=0;j<nots;j++)
  661.         if(!stricmp(not[j],dir[i]->code))
  662.             break;
  663.     if(j<nots)
  664.         continue;
  665.  
  666.     if(misc&NO_LINK && dir[i]->misc&DIR_FCHK) {
  667.         strcpy(tmp,dir[i]->path);
  668.         if(tmp[0]=='.') {
  669.             sprintf(str,"%s%s",node_dir,tmp);
  670.             strcpy(tmp,str); }
  671.         sprintf(str,"%s*.*",tmp);
  672.         printf("\nSearching %s for unlinked files\n",str);
  673.         for(j=_dos_findfirst(str,_A_NORMAL,&ff);!j
  674.             ;j=_dos_findnext(&ff)) {
  675.             strupr(ff.name);
  676.             padfname(ff.name,str);
  677.             if(!findfile(i,str)) {
  678.                 sprintf(str,"%s%s",tmp,ff.name);
  679.                 printf("Removing %s (not in database)\n",ff.name);
  680.                 if(!(misc&REPORT) && remove(str))
  681.                     printf("Error removing %s\n",str); } }
  682. #ifdef __WATCOMC__
  683.         _dos_findclose(&ff);
  684. #endif
  685.     }
  686.  
  687.     if(!dir[i]->maxage && !(misc&OFFLINE))
  688.         continue;
  689.  
  690.     printf("\nScanning %s %s\n",lib[dir[i]->lib]->sname,dir[i]->lname);
  691.  
  692.     sprintf(str,"%s%s.IXB",dir[i]->data_dir,dir[i]->code);
  693.     if((file=nopen(str,O_RDONLY))==-1)
  694.         continue;
  695.     l=filelength(file);
  696.     if(!l) {
  697.         close(file);
  698.         continue; }
  699.     if((ixbbuf=(char *)MALLOC(l))==NULL) {
  700.         close(file);
  701.         printf("\7ERR_ALLOC %s %lu\n",str,l);
  702.         continue; }
  703.     if(read(file,ixbbuf,l)!=l) {
  704.         close(file);
  705.         printf("\7ERR_READ %s %lu\n",str,l);
  706.         FREE((char *)ixbbuf);
  707.         continue; }
  708.     close(file);
  709.  
  710.     m=0L;
  711.     now=time(NULL);
  712.     while(m<l) {
  713.         memset(&workfile,0,sizeof(file_t));
  714.         for(j=0;j<12 && m<l;j++)
  715.             if(j==8)
  716.                 fname[j]='.';
  717.             else
  718.                 fname[j]=ixbbuf[m++];
  719.         fname[j]=0;
  720.         strcpy(workfile.name,fname);
  721.         unpadfname(workfile.name,fname);
  722.         workfile.dir=i;
  723.         sprintf(str,"%s%s"
  724.             ,workfile.altpath>0 && workfile.altpath<=altpaths
  725.                 ? altpath[workfile.altpath-1]
  726.             : dir[workfile.dir]->path,fname);
  727.         if(str[0]=='.') {
  728.             sprintf(tmp,"%s%s",node_dir,str);
  729.             strcpy(str,tmp); }
  730.         workfile.datoffset=ixbbuf[m]|((long)ixbbuf[m+1]<<8)
  731.             |((long)ixbbuf[m+2]<<16);
  732.         workfile.dateuled=(ixbbuf[m+3]|((long)ixbbuf[m+4]<<8)
  733.             |((long)ixbbuf[m+5]<<16)|((long)ixbbuf[m+6]<<24));
  734.         workfile.datedled=(ixbbuf[m+7]|((long)ixbbuf[m+8]<<8)
  735.             |((long)ixbbuf[m+9]<<16)|((long)ixbbuf[m+10]<<24));
  736.         m+=11;
  737.         if(dir[i]->maxage && dir[i]->misc&DIR_SINCEDL && workfile.datedled
  738.             && (now-workfile.datedled)/86400L>dir[i]->maxage) {
  739.                 printf("Deleting %s (%ld days since last download)\n",fname
  740.                     ,(now-workfile.datedled)/86400L);
  741.                 getfiledat(&workfile);
  742.                 if(!(misc&REPORT)) {
  743.                     removefiledat(workfile);
  744.                     if(remove(str))
  745.                         printf("Error removing %s\n",str); } }
  746.         else if(dir[i]->maxage
  747.             && !(workfile.datedled && dir[i]->misc&DIR_SINCEDL)
  748.             && (now-workfile.dateuled)/86400L>dir[i]->maxage) {
  749.                 printf("Deleting %s (uploaded %ld days ago)\n",fname
  750.                     ,(now-workfile.dateuled)/86400L);
  751.                 getfiledat(&workfile);
  752.                 if(!(misc&REPORT)) {
  753.                     removefiledat(workfile);
  754.                     if(remove(str))
  755.                         printf("Error removing %s\n",str); } }
  756.         else if(misc&OFFLINE && dir[i]->misc&DIR_FCHK && !fexist(str)) {
  757.                 printf("Removing %s (doesn't exist)\n",fname);
  758.                 getfiledat(&workfile);
  759.                 if(!(misc&REPORT))
  760.                     removefiledat(workfile); } }
  761.  
  762.     FREE((char *)ixbbuf); }
  763. }
  764.