home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Professional / OS2PRO194.ISO / os2 / com / bbs / downsrt / source / downcol.c < prev    next >
C/C++ Source or Header  |  1991-06-06  |  21KB  |  463 lines

  1. /* ============================================================= */
  2. /*  Rob Hamerling's MAXIMUS download file scan and sort utility. */
  3. /*  -> Functions to collect download file information.           */
  4. /* ============================================================= */
  5.  
  6. #define INCL_BASE
  7. #include <os2.h>
  8.  
  9. #include <conio.h>
  10. #include <fcntl.h>
  11. #include <io.h>
  12. #include <share.h>
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <sys\types.h>
  17. #include <sys\stat.h>
  18.  
  19. #include "downsort.h"
  20.  
  21. /* ---------------------------- */
  22. /* Collect download file area's */
  23. /* ---------------------------- */
  24. USHORT collect_down(area)
  25. struct _downpath **area;                // pointer to area-info pointer array
  26. {
  27.   USHORT af,oaction;                    // file handle, open_action
  28.   int    i,j,m,rc;                      // counters, returncode
  29.   unsigned int k;                       // #area's
  30.   union  _areamax u;                    // MAXIMUS area-file record
  31.   struct _downpath *d;                  // ptrs to array of area-info
  32.   struct stat fs;                       // file status buffer
  33.  
  34.   rc = DosOpen(areadat_path,            // Open 'carefully'
  35.           &af,                          // pointer to File Handle
  36.           &oaction,                     // pointer to action field
  37.           0L,                           // new filesize (N/A)
  38.           FILE_NORMAL,                  // attributes
  39.           FILE_OPEN,                    // open flags
  40.           OPEN_ACCESS_READONLY   |      // access flags
  41.             OPEN_SHARE_DENYWRITE |
  42.             OPEN_FLAGS_RANDOMSEQUENTIAL |
  43.             OPEN_FLAGS_NOINHERIT,
  44.           0L);                          // reserved
  45.   if (rc != NO_ERROR) {                 // open error
  46.     printf(OPEN_FAIL,areadat_path);
  47.     exit(rc);
  48.     }
  49.   if (oaction != FILE_EXISTED) {        // not found
  50.     printf(OPEN_FAIL,areadat_path);
  51.     exit(5);
  52.     }
  53.   else {
  54.     if (oper_mode == VERBOSE)
  55.       printf(" from %s",areadat_path);
  56.     stat(areadat_path,&fs);             // get status of AREA.DAT
  57.     read(af,(char *)&u,sizeof(struct _area)); // obtain first record
  58.     if (u.a.id == AREA_id) {
  59.       MAX_level = 102;                  // looks like version 1.02
  60.       k = (int)(fs.st_size / u.a.struct_len);
  61.       }
  62.     else if (u.a1.struct_len == sizeof(struct _area100)) {
  63.       MAX_level = 100;                  // looks like version 1.00
  64.       k = (int)(fs.st_size / u.a1.struct_len);
  65.       }
  66.     else {
  67.       printf("\nSorry, unsupported format of %s-file!",areadat_path);
  68.       printf("\n%s %d.%d%c works for %s version 1.00 and 1.02!",
  69.                  PROGNAME,VERSION,SUBVERS,SUFFIX,MAX);
  70.       exit(8);                          // wrong version of AREA.DATA
  71.       }
  72.  
  73.     d = (struct _downpath *)calloc(k,sizeof(struct _downpath));
  74.     if (d == NULL) {                    // memory not obtained?
  75.       printf(MSG_MEM,PROGNAME);
  76.       exit(6);
  77.       }
  78.     else {
  79.       *area = d;                        // return pointer to caller
  80.       for (i=m=0; i<k; i++) {           // all area records
  81.         if (MAX_level == 102) {         // use version 1.02 layout
  82.           lseek(af,i*(long)u.a.struct_len,SEEK_SET);  // locate to next
  83.           read(af,(char *)&u,sizeof(struct _area));
  84.           if (u.a.filepath[0] != '\0' && u.a.filepath[0] != ' ') {
  85.             d[m].priv      = u.a.filepriv;       // download privilege
  86.             strcpy(d[m].name,u.a.name);          // area name
  87.             strcpy(d[m].pname,u.a.filepath);     // download path
  88.             strcpy(d[m].filesbbs,u.a.filesbbs);  // files.bbs
  89.             strcpy(d[m].adesc,u.a.fileinfo);     // filearea title
  90.             ++m;                        // active filearea count
  91.             }
  92.           }
  93.         else {                          // use version 1.00 layout
  94.           lseek(af,i*(long)u.a1.struct_len,SEEK_SET);  // locate to next
  95.           read(af,(char *)&u,sizeof(struct _area100));
  96.           if (u.a1.filepath[0] != '\0' && u.a1.filepath[0] != ' ') {
  97.             d[m].priv      = u.a1.filepriv;      // download privilege
  98.             strcpy(d[m].name,u.a1.name);         // area name
  99.             strcpy(d[m].pname,u.a1.filepath);    //download path
  100.             strcpy(d[m].filesbbs,u.a1.filesbbs); // files.bbs
  101.             strcpy(d[m].adesc,u.a1.fileinfo);    // filearea title
  102.             ++m;                        // active filearea count
  103.             }
  104.           }
  105.         if (d[m-1].name[0] != '\0' && d[m-1].name[1] == '\0') { // single char?
  106.           d[m-1].name[1] = d[m-1].name[0];  // shift right 1
  107.           d[m-1].name[0] = ' ';         // leading blank
  108.           }
  109.         j = strlen(d[m-1].pname);
  110.         if (j>0 && d[m-1].pname[j-1] != '\\')
  111.           d[m-1].pname[j] = '\\';       // add backslash if needed
  112.         }
  113.       }
  114.     DosClose(af);                       // close area.dat-file
  115.     return(m);                          // report number of downloadarea's
  116.     }
  117.   }
  118.  
  119. /* ---------------------------- */
  120. /* Collect all file information */
  121. /* ---------------------------- */
  122. USHORT collect_file(m,area)
  123. USHORT m;                               // number of download area's
  124. struct _downpath *area;                 // pointer to download path array
  125. {
  126.   USHORT  i,k,n,fc;                     // counters
  127.   struct _filechain *ca;                // ptr to file info
  128.  
  129.   ca = NULL;                            // empty chain!
  130.   fc = 0;                               // total file-counter
  131.   for (i=0; i<m; i++) {                 // all download paths
  132.     if (area[i].priv <= ABS_MAX_priv) { // within report privilege
  133.                                         // returns ptrs first/last active
  134.       if (oper_mode == VERBOSE)
  135.         printf("\n       files in area %-.2s (Priv=%c) DL-dir=%s",
  136.              area[i].name,
  137.              priv_name[area[i].priv-TWIT][0],
  138.              area[i].pname);
  139.       k = fill_chn(&area[i],&ca);       // files in area
  140.       if (oper_mode == VERBOSE)
  141.         printf("\r %5d",k);
  142.       if (k > 0) {                      // any files in this area?
  143.         if (first_element == NULL)
  144.           first_element = ca;           // ptr to very first element
  145.         get_desc(k,ca,&area[i]);        // obtain descriptions
  146.         n = 0;                          // suppose no orphans
  147.         if (lp[P_ORP].priv[0] > HIDDEN) { // orphan report not req'd
  148.           n = free_orphan(ca);          // get rid of orphan-entries
  149.           if (n > 0 && oper_mode==VERBOSE)
  150.             printf("\n %5u orphans dropped",n);
  151.           }
  152.         fc += k - n;                    // total counter
  153.         }
  154.       if (ca != NULL) {
  155.         while (ca->next_element != NULL)  // find last
  156.           ca = ca->next_element;
  157.         }
  158.       }
  159.     }
  160.   return(fc);
  161.   }
  162.  
  163. /* ---------------------------------------- */
  164. /* Add all subdir-filenames to the chain,   */
  165. /* for further processing by mainline.      */
  166. /* NOTE: full path name assumed!            */
  167. /* ---------------------------------------- */
  168. USHORT fill_chn(parea,cp)
  169. struct _downpath *parea;                // pointer to download-info
  170. struct _filechain **cp;                 // ptrs to ptr first/last element
  171. {
  172.   int    rc;                            // returncode of DOS-calls
  173.   USHORT fc;                            // area-file counter
  174.   struct _filechain *ca,*ce,*tp;        // new curr temp chain pointers
  175.   struct _FILEFINDBUF cf;               // OS file-info buffer
  176.   char   down_spec[MAXPATH];            // file specification buffer
  177.   HDIR   fhandle;                       // FindFirst/Last handle
  178.   USHORT fentries;                      // # entries to be retrieved
  179.  
  180.   fc = 0;                               // init filecount of this area
  181.   ce = ca = *cp;                        // ptr to last active element
  182.   strcpy(down_spec,parea->pname);       // path
  183.   strcat(down_spec,"*.*");              // file-spec
  184.   fentries = 1;                         // one at a time!
  185.   fhandle  = HDIR_CREATE;               // new file handle
  186.   rc = DosFindFirst(down_spec,&fhandle,FILE_NORMAL,&cf,
  187.               sizeof(struct _FILEFINDBUF),&fentries,0L);
  188.   while (rc == 0) {
  189.     if ((wild_comp(0,cf.achName,"FILES.?BS")   != 0) &&
  190.         (wild_comp(0,cf.achName,"*.BAK")       != 0) &&
  191.         (wild_comp(0,cf.achName,"SYSTEM*.?BS") != 0) &&
  192.         (wild_comp(0,cf.achName,"DIR.?BS")     != 0)) {
  193.       tp = (struct _filechain *)malloc(sizeof(struct _filechain));
  194.       if (tp == NULL) {
  195.         printf(MSG_MEM,PROGNAME);       // not enough memory
  196.         exit(11);
  197.         }
  198.       if (ca == NULL)                   // very first element
  199.         ca = ce = tp;                   // ptr to first and last active!
  200.       else {                            // not very first
  201.         if (fc == 0)                    // first in this area
  202.           ca = tp;                      // ptr to first active this area
  203.         ce->next_element = tp;          // chain-ptr in current element
  204.         ce = tp;                        // ptr to last active
  205.         }
  206.       ++fc;                             // update filecount this area
  207.       if (oper_mode==VERBOSE && (fc%25)==0)  // every 25 files
  208.         cprintf("\r %5u",fc);
  209.       ce->next_element = NULL;          // copy/init fields
  210.       ce->parea = parea;
  211.       ce->wdate = cf.fdateLastWrite;
  212.       ce->wtime = cf.ftimeLastWrite;
  213.       if (file_time(cf.fdateCreation,cf.ftimeCreation) >
  214.           file_time(cf.fdateLastWrite,cf.ftimeLastWrite) ) {
  215.         ce->cdate = cf.fdateCreation;   // creation most recent
  216.         ce->ctime = cf.ftimeCreation;
  217.         }
  218.       else {                            // otherwise and non-HPFS volumes
  219.         ce->cdate = cf.fdateLastWrite;
  220.         ce->ctime = cf.ftimeLastWrite;
  221.         }
  222.       ce->size  = cf.cbFile;
  223.       byte_count += cf.cbFile;
  224.       ce->attr  = cf.attrFile;
  225.       ce->fseq  = 65535;                // max FILES.BBS line number
  226.       ce->priv  = HIDDEN;               // unless FILES.BBS proves otherwise
  227.       strncpy(ce->fname,cf.achName,MAXFN);
  228.       ce->fdesc = NULL;                 // unless later found in FILES.BBS
  229.       }
  230.     rc = DosFindNext(fhandle,&cf,sizeof(struct _FILEFINDBUF),&fentries);
  231.     }
  232.   DosFindClose(fhandle);                // close directory association
  233.   *cp = ca;                             // pointer to first new this area
  234.   return(fc);
  235.   }
  236.  
  237. /* ---------------------------------------- */
  238. /* Free memory occupied by orphan entries.  */
  239. /* ---------------------------------------- */
  240. USHORT free_orphan(cp)
  241. struct _filechain *cp;                  // ptr to first of chain-element
  242. {
  243.   USHORT  orp_cnt;                      // removed orphan counter
  244.   struct _filechain *ca,*cb;            // current and next chain pointer
  245.  
  246.   orp_cnt = 0;                          // orphan counter
  247.   ca = cp;                              // ptr to current element
  248.   while ((cb = ca->next_element) != NULL) {   // all (but first)
  249.     if (cb->priv >= HIDDEN) {           // probably orphan?
  250.       ca->next_element = cb->next_element; // new ptr in current element
  251.       free(cb);                         // free memory block
  252.       ++orp_cnt;                        // one more dropped
  253.       }                                 // note: do not shift current
  254.     else
  255.       ca = cb;                          // shift +1 current element
  256.     }
  257.   return(orp_cnt);                      // report # of removed orphans
  258.   }
  259.  
  260. /* ------------------------------ */
  261. /* Add file description to chain  */
  262. /* ------------------------------ */
  263. void get_desc(x,cp,parea)
  264. USHORT x;                               // number of file-entries
  265. struct _filechain *cp;                  // ptr to ptr to first of group
  266. struct _downpath *parea;                // pointer to area-info
  267. {
  268.   FILE   *fi;                           // file pointer
  269.   USHORT fih,oaction;                   // file handle, open-action
  270.   struct _filechain *ce;                // ptrs to file-info
  271.   char   buf[MAXRCD];                   // read-buffer for FILES.BBS
  272.   char   filename[MAXFN];               // filename from FILES.BBS buf
  273.   char   *desc,*rp;                     // ptr to desc / return val gets()
  274.   char   buf2[MAXDESC];                 // cumulated (multiline) desc.
  275.   int    b,i,j,k,m,n,p;                 // counters
  276.   int    low,high,index;                // indexes
  277.   int    fpriv, rc;                     // file privilege, returncode
  278.   USHORT bbsseq;                        // record number of FILES.BBS
  279.   char   desc_spec[MAXPATH];
  280.   char   *fd;                           // pointer to file description
  281.   struct _filechain **fa;               // pointer to file sort-array
  282.   static char prop[4]    = "/─\\|";     // rotating propeller
  283.  
  284.   if (strlen(parea->filesbbs) > 0)      // explicit specification?
  285.     strcpy(desc_spec,parea->filesbbs);  // explicitly specified FileList
  286.   else {                                // no
  287.     strcpy(desc_spec,parea->pname);     // get path to download directory
  288.     strcat(desc_spec,lp[P_FIL].name);   // add filename
  289.     strcat(desc_spec,".");              // add separator
  290.     strcat(desc_spec,lp[P_FIL].ext);    // add extension
  291.     }
  292.  
  293.   fpriv = parea->priv;                  // area-priv is default file priv
  294.  
  295.                                         // FILES.BBS may be in use!!!
  296.   rc = DosOpen(desc_spec,               // Open 'carefully'
  297.           &fih,                         // pointer to File Handle
  298.           &oaction,                     // pointer to action field
  299.           0L,                           // new filesize (N/A)
  300.           FILE_NORMAL,                  // attributes
  301.           FILE_OPEN,                    // open flags
  302.           OPEN_ACCESS_READONLY  |       // access flags
  303.             OPEN_SHARE_DENYNONE |
  304.             OPEN_FLAGS_SEQUENTIAL |
  305.             OPEN_FLAGS_NOINHERIT,
  306.           0L);                          // reserved
  307.   if (rc != NO_ERROR || oaction != FILE_EXISTED) {  // not found
  308.     printf(DESC_MISS,desc_spec);
  309.     return;                             // no: return to caller
  310.     }
  311.   if ((fi = fdopen(fih,"r")) == NULL) { // open stream with file handle
  312.     printf(DESC_MISS,desc_spec);
  313.     return;                             // no: return to caller
  314.     }
  315.  
  316.   fa = (struct _filechain **)malloc(x*sizeof(struct _filechain *));
  317.   if (fa == NULL) {                     // not enough memory
  318.     printf(MSG_MEM,PROGNAME);
  319.     exit(11);
  320.     }
  321.   ce = cp;                              // ptr to first file-info
  322.   for (i=0; i<x; i++) {                 // init sort array
  323.     fa[i] = ce;
  324.     ce = ce->next_element;
  325.     }
  326.   qsort(fa,x,sizeof(struct _filechain *),sort_gbl); // sort file pointers
  327.  
  328.   rp = fgets(buf,sizeof buf,fi);        // get first record
  329.   bbsseq = 1;                           // init counter
  330.   while (rp != NULL) {                  // until end of file reached
  331.     m = strlen(buf);                    // length of input string
  332.     if (m <= 2) {                       // empty line
  333.       rp = fgets(buf,sizeof buf,fi);    // get next record
  334.       bbsseq++;                         // next line number
  335.       }
  336.     else if (buf[0] == '\20') {         // privilege change (^P) ?
  337.       for (k=0; k<HIDDEN-TWIT && priv_name[k][0]!=buf[1]; k++);
  338.       if (TWIT + k > parea->priv)       // only if higher than area-priv
  339.         fpriv = TWIT + k;               // new (higher) prilivege
  340.       rp = fgets(buf,sizeof buf,fi);    // continue
  341.       bbsseq++;                         // next line number
  342.       }
  343.     else if ( buf[0] <= ' '  ||
  344.               buf[0] == '\"' ||
  345.              (buf[0] >= '+'  && buf[0] <= '/')  ||
  346.              (buf[0] >= ':'  && buf[0] <= '>')  ||
  347.              (buf[0] >= '['  && buf[0] <= ']')  ||
  348.               buf[0] == '|'  ||
  349.               buf[0] >= 128) {          // non-filename: ignore line
  350.       rp = fgets(buf,sizeof buf,fi);    // continue
  351.       bbsseq++;                         // next line number
  352.       }
  353.     else {                              // probably file descr record
  354.       for (i=0; i < MAXFN-1     &&      // maximum filename length (8.3)
  355.                 i < m           &&      // input string length
  356.                 buf[i] != ' '   &&
  357.                 buf[i] != '\n'; i++);   // scan for filespec
  358.       strncpy(filename,buf,i);          // save filename
  359.       filename[i] = '\0';               // end of string
  360.  
  361.       desc = next_word(buf);            // locate description
  362.       if (desc != NULL) {               // start of description found
  363.         for (k=0; desc[k]; ++k)
  364.           if (desc[k]=='\r' || desc[k]=='\n') {
  365.             desc[k] = '\0';
  366.             break;
  367.             }
  368.         strcpy(buf2,desc);              // save desc in buf2
  369.         while (((rp = fgets(buf,sizeof buf,fi)) != NULL) &&  // next rcd
  370.                (buf[0] == ' ') &&       // probably desc continuation
  371.                ((desc = next_word(buf)) != NULL)) {  // locate desc
  372.           for (k=0; desc[k]!='\0'; ++k)
  373.             if (desc[k]=='\r' || desc[k]=='\n') {
  374.               desc[k] = '\0';
  375.               break;
  376.               }
  377.           if ((strlen(buf2) + k + 1) <= sizeof(buf2)) {  // not too long
  378.             strcat(buf2," ");           // single space
  379.             strcat(buf2,desc);          // concat desc to buf2
  380.             }
  381.           }
  382.         bbsseq++;                       // next line number
  383.         fd = malloc(strlen(buf2)+1);    // obtain memory
  384.         if (fd == NULL) {
  385.           printf(MSG_MEM,PROGNAME);     // not enough memory
  386.           exit(12);
  387.           }
  388.         else
  389.           strcpy(fd,buf2);              // store description
  390.         }
  391.       else {
  392.         rp = fgets(buf,sizeof buf,fi);  // no desc: continue
  393.         bbsseq++;
  394.         }
  395.  
  396.       j = 0;                            // first wild-compare
  397.       low  = 0;                         // index of first entry
  398.       high = x-1;                       // index of last entry
  399.       while (low <= high) {             // binary search in array
  400.         index = (high + low) / 2;       // middle of interval
  401.         if ((b = wild_comp(j,fa[index]->fname,filename)) < 0)
  402.           low = index + 1;              // new low boundary
  403.         else if (b > 0)
  404.           high = index - 1;             // new high boundary
  405.         else
  406.           break;                        // equal: found
  407.         j = 1;                          // subsequent wild-compares
  408.         }
  409.  
  410.       n = index;
  411.       while (n>=0 && wild_comp(0,fa[n]->fname,filename) == 0) {
  412.         if (fa[n]->fdesc == NULL)       // no description assigned yet
  413.           fa[n]->fdesc = (desc != NULL) ? fd : NDS;  // ptr to description
  414.         fa[n]->priv = fpriv;            // copy privilege
  415.         fa[n]->fseq = bbsseq;           // copy FILES.BBS line number
  416.         --n;                            // next lower
  417.         }
  418.  
  419.       n = index + 1;
  420.       while (n<x && wild_comp(0,fa[n]->fname,filename) == 0) {
  421.         if (fa[n]->fdesc == NULL)       // no description assigned yet
  422.           fa[n]->fdesc = (desc != NULL) ? fd : NDS;    // ptr to description
  423.         fa[n]->priv = fpriv;            // copy privilege
  424.         fa[n]->fseq = bbsseq;           // copy FILES.BBS line number
  425.         ++n;                            // next higher
  426.         }
  427.       }
  428.  
  429.     if (oper_mode == VERBOSE)
  430.       cprintf("\r%c",prop[p=(++p)&3]);  // propeller
  431.     }
  432.   if (oper_mode == VERBOSE)
  433.     cprintf("\r ");                     // clear propeller
  434.   free(fa);                             // free temp sort array
  435.   fclose(fi);                           // finished with this FILES.BBS
  436.   DosClose(fih);                        // close the handle
  437.   }
  438.  
  439. /* ------------------------------ */
  440. /* Build pointer-array for sorts  */
  441. /* ------------------------------ */
  442. struct _filechain **prep_sort(cnt,chn)
  443. USHORT  cnt;                            // file count
  444. struct  _filechain *chn;                // pointer to fileinfo struct
  445. {
  446.   USHORT  i;                            // counter
  447.   struct  _filechain **dm;              // pointer to file-sort array
  448.   struct  _filechain *ca;               // pointer to fileinfo (chain)
  449.  
  450.   dm = (struct _filechain **)malloc(cnt*sizeof(struct _filechain *));
  451.   if (dm == NULL) {                     // not enough memory
  452.     printf(MSG_MEM,PROGNAME);
  453.     exit(11);
  454.     }
  455.   ca = chn;                             // ptr to first file-info
  456.   for (i=0; ca != NULL; i++) {          // init sort array
  457.     dm[i] = ca;
  458.     ca = ca->next_element;
  459.     }
  460.   return(dm);
  461.   }
  462.  
  463.