home *** CD-ROM | disk | FTP | other *** search
- /* ============================================================= */
- /* Rob Hamerling's MAXIMUS download file scan and sort utility. */
- /* -> DOWNCOL.C */
- /* -> Functions to collect download file information. */
- /* ============================================================= */
-
- #define INCL_DOS
- #define INCL_DOSFILEMGR
- #define INCL_DOSERRORS
- #define INCL_NOPMAPI
- #include <os2.h>
-
- #include <conio.h>
- #include <fcntl.h>
- #include <io.h>
- #include <malloc.h>
- #include <share.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys\types.h>
-
- #include "..\max\mstruct.h" // MAXIMUS definitions
- #include "downsort.h" // downsort defines
- #include "downfpro.h" // downsort function prototypes
-
-
- /* prototypes of local function functions */
-
- void add_to_chain(struct _filechain **cp, struct _filechain *tp);
- int area_selection(char *, char [][MAXANAME]);
- struct _filechain *add_comment(char *, struct _downpath huge *,
- char *, short int, unsigned short int);
- struct _filechain *assign_desc(short int, char *, struct _filechain **,
- struct _downpath huge *, char *, short int, unsigned short int);
- char *build_desc(FILE *, char *, char **);
- unsigned short int combine_comments(void);
- struct _filechain *desc_dup(struct _filechain *, char *,
- struct _downpath huge *, short int, unsigned short int,
- unsigned short int, unsigned short int);
- void desc_old(struct _filechain **, char *, struct _downpath huge *,
- short int, short int, unsigned short int,
- unsigned short int, unsigned short int);
- unsigned short int fill_chn(struct _downpath huge *, struct _filechain **);
- struct _filechain *file_element(struct _downpath huge *,
- #ifndef __32BIT__
- struct _FILEFINDBUF *);
- #else
- struct _FILEFINDBUF3 *);
- #endif
- unsigned short int free_orphan(void);
- unsigned short int get_desc(struct _downpath huge *, struct _filechain **);
- char *parse_fname(char *);
- int sort_path(const void *, const void *);
-
-
- /* ---------------------------- */
- /* Collect download file area's */
- /* ---------------------------- */
- unsigned short int collect_area(struct _downpath huge **area)
- {
- #ifndef __32BIT__
- unsigned short int
- #else
- unsigned long int
- #endif
- af, oaction; // file handle, open_action
- /* short in 286, long in 386 mode */
- int rc; // returncode
- short int i,j,k,m; // counters
- struct _area a; // MAXIMUS (minimum) area struct.
- struct _downpath huge *d; // ptr to array with area-info
- struct _FILESTATUS fs; // file status buffer
-
- rc = DosOpen(areadat_path, // open 'carefully'
- &af, // pointer to File Handle
- &oaction, // pointer to action field
- 0L, // new filesize (N/A)
- FILE_NORMAL, // attributes
- FILE_OPEN, // open flags
- OPEN_ACCESS_READONLY | // mode
- OPEN_SHARE_DENYWRITE,
- 0L); // no EA's
- if (rc != NO_ERROR) { // open error
- printf(OPEN_FAIL, areadat_path, rc);
- DosExit(rc,0);
- }
- if (oaction != FILE_EXISTED) { // not found
- printf(OPEN_ACTN, areadat_path, oaction);
- DosExit(5,0);
- }
- else {
- if (oper_mode != QUIET)
- printf("\nCollecting file-area information from %s",
- areadat_path);
- rc = DosQFileInfo(af, 1, &fs, sizeof(fs)); // get info of AREA.DAT
- read(af,(char *)&a,sizeof(struct _area)); // obtain first part
- m = 0; // init participating file count
- if (a.id != AREA_id) { // validate MAXIMUS format
- printf("\nSorry, %s-file has unsupported AREA.DAT format!",
- areadat_path);
- printf("\n%s %c.%c%c works only for %s version 2.00 and up!",
- PROGNAME,VERSION,SUBVERS,SUFFIX,MAX);
- }
- else { // acceptable AREA.DAT
- k = (short int)(fs.cbFile / a.struct_len); // number of area's
- for (i=0; i<k; i++) { // count area's with downloads
- lseek(af, i*(long)a.struct_len, SEEK_SET); // locate to next
- read(af, (char *)&a, sizeof(struct _area));
- if (a.filepath[0] != '\0' &&
- a.filepath[0] != ' ' &&
- a.filepriv <= ABS_MAX_priv && // within report privilege
- area_selection(a.name, selected_area)) // not excluded
- m++; // participating filearea count
- }
- if (m > 0) { /* any area's participating */
- #ifndef __32BIT__
- d = (struct _downpath huge *)halloc(m, sizeof(struct _downpath));
- #else
- d = (struct _downpath *)malloc(m * sizeof(struct _downpath));
- #endif
- if (d == NULL) { // memory not obtained?
- printf(MSG_MEM, PROGNAME);
- DosExit(6,0);
- }
- else { // have memory for area-info
- *area = d; // set return pointer
- for (i=m=0; i<k; i++) { // all area's
- lseek(af, i*(long)a.struct_len, SEEK_SET); // locate to next
- read(af, (char *)&a, sizeof(struct _area));
- if ( a.filepath[0] != '\0' && // filename(?)
- a.filepath[0] != ' ' && // filename(?)
- a.filepriv <= ABS_MAX_priv && // within report privilege
- area_selection(a.name, selected_area)) { // selected
- d[m].priv = a.filepriv; // download privilege
- strcpy(d[m].name, a.name); // area name ... edit!
- d[m].anum = i; // AREA.DAT seq. nbr
- d[m].file_count = 0; // init file count
- d[m].byte_count = 0L; // init byte count
- d[m].newest = NULL; // pointer to newest file
- strcpy(d[m].pname, a.filepath); // download path
- j = strlen(d[m].pname);
- if (j>0 && d[m].pname[j-1] != '\\')
- d[m].pname[j] = '\\'; // add backslash if needed
- strcpy(d[m].filesbbs, a.filesbbs); // files.bbs
- strcpy(d[m].adesc, a.fileinfo); // filearea title
- ++m; // filearea index
- }
- }
- }
- // manipulate here area-names for 'intelligent' sorting
- max_aname = 0; // init max areaname length
- for (i=0; i<m; i++) // all collected area's
- max_aname = max(strlen(d[i].name), max_aname);
- for (i=0; i<m; i++) { // all collected area's
- sprintf(d[i].ename,
- (d[i].name[0]<'0' || d[i].name[0]>'9') // not num
- ? "%-*.*s" : "%*.*s", // left or right aligned
- max_aname, max_aname, d[i].name);
- d[i].ename[max_aname] = '\0'; // end of string
- j = k = max_aname-1; // init offset values
- while (j>=0 && d[i].ename[j] == ' ') // search last char
- j--;
- if (j < k) { // spaces found
- while (j>=0 &&
- d[i].ename[j]>='0' &&
- d[i].ename[j]<='9') {
- d[i].ename[k--] = d[i].ename[j]; // move
- d[i].ename[j--] = ' '; // replace by blank
- }
- }
- }
- #if defined(DEBUG)
- dump_area_array(d,m,"check on ename editing");
- #endif
- }
- }
-
- DosClose(af); // close area.dat-file
- return(m); // report number of downloadarea's
- }
- }
-
- /* ---------------------------- */
- /* Collect all file information */
- /* ---------------------------- */
- unsigned int collect_file(unsigned int a,
- struct _downpath huge *area)
- {
- unsigned short int i,k,l,fc,orphan_count; // counters
- struct _filechain *ca,*ce; // ptrs to file info
-
- fc = orphan_count = 0; // init file and orphan count
- if (oper_mode != QUIET)
- printf("\nCollecting file data");
- qsort(area, a, sizeof(struct _downpath), sort_path);
- // WARNING: do no sort again in this array!
- for (i=0; i<a; i++) { // all download areas
- if (oper_mode == VERBOSE)
- printf("\n files in DL-dir %s (area %s)",
- area[i].pname,
- area[i].name);
- else if (oper_mode != QUIET)
- printf(".");
-
- if (i<1 || stricmp(area[i].pname, area[i-1].pname)) { // pathnames
- if (lp[P_ORP].priv[0] > HIDDEN) // orphan report not req'd
- orphan_count += free_orphan(); // free orphans still in chain
- ca = NULL; // for new directory
- k = fill_chn(&area[i], &ca); // read directory
- // returns #files + ptr to first
- fc += k; // add to total
- if (ca!=NULL) { // any files in group
- if ((ce = first_element) != NULL) { // not empty chain
- while (ce->next_element != NULL) // find last element
- ce = ce->next_element;
- ce->next_element = ca; // couple new group to chain
- }
- if (first_element==NULL) // first non-empty group
- first_element = ca; // set pointer to head of chain
- }
- }
- if (oper_mode == VERBOSE)
- printf("\r %5d",k); // total this download path
- l = get_desc(&area[i], &ca); // obtain descriptions
- fc += l; // add 'offline' filecount
- if (first_element==NULL) // very first
- first_element = ca; // set pointer to head of chain
- if (l>0 && oper_mode==VERBOSE) // any offline files found
- printf("\r %5d", k += l); // value after get_desc
- } // all area's processed
-
- if ((ca = first_element) != NULL) { // any files
- if (lp[P_ORP].priv[0] > HIDDEN) { // orphan report not req'd
- orphan_count += free_orphan(); // free any left orphans
- if (ca->priv >= HIDDEN) { // first is an orphan
- first_element=ca->next_element; // new ptr to first
- free(ca); // free memory block
- ++orphan_count; // one more dropped
- }
- }
- }
- if (orphan_count>0 && oper_mode==VERBOSE)
- printf("\n %5u orphans detected and dropped (in total)",
- orphan_count);
-
- fc -= orphan_count; // less dropped orphans
-
- #if defined(DEBUG)
- dump_file_chain(first_element, " --> after all areas");
- #endif
-
- if (fc) { // file(s) present
- k=0; // init count
- if ((ca = first_element) != NULL) { // pointer to first element
- ++k; // at least 1
- while (ca->next_element != NULL) { // find last
- ++k; // another element
- ca = ca->next_element; // pointer to next
- }
- }
- if (fc != k) { // compare counts
- printf("\nInternal error in data collection phase, "
- "counted: %u entries, chainsize=%u",
- fc, k); // counter values
- DosExit(99,0); // quit on error
- }
- }
- return(fc); // file total count
- }
-
- /* ---------------------------------------- */
- /* Add all subdir-filenames to the chain, */
- /* for further processing by mainline. */
- /* NOTE: - full path name assumed! */
- /* returns number of files in this area */
- /* ---------------------------------------- */
- unsigned short int fill_chn(struct _downpath huge *parea,
- struct _filechain **cp)
- {
- int rc; // returncode of DOS-calls
- unsigned short int fc; // area-file counter
- struct _filechain *ca,*ce,*tp; // new, curr, temp, chain ptrs
- char down_spec[MAXPATH]; // file specification buffer
- HDIR fhandle = HDIR_CREATE; // FindFirst/Last handle
- #ifndef __32BIT__
- unsigned int fentries; // # entries to be retrieved
- struct _FILEFINDBUF cf; // file-info buffer
- #else
- unsigned long int fentries; // # entries to be retrieved
- struct _FILEFINDBUF3 cf; // file-info buffer
- #endif
-
- fc = 0; // init filecount of this area
- fentries = 1; // retreive 1 at a time (DOS!)
- strcpy(down_spec,parea->pname); // path
- strcat(down_spec,"*.*"); // file-spec
- rc = DosFindFirst(down_spec,
- &fhandle,
- FILE_NORMAL,
- &cf,
- #ifndef __32BIT__
- sizeof(struct _FILEFINDBUF),
- &fentries,
- 0L); // unused with OS/2 < 2.0
- #else
- sizeof(struct _FILEFINDBUF3),
- &fentries,
- FIL_STANDARD); // no EA's OS/2 2.0+
- #endif
- ca = NULL; // no first in group yet
- while (rc == 0) {
- if ((wild_comp(cf.achName,"FILES.*") != 0) &&
- (wild_comp(cf.achName,"*.BAK") != 0) &&
- (wild_comp(cf.achName,"SYSTEM*.?BS") != 0) &&
- (wild_comp(cf.achName,"DIR.?BS") != 0)) {
-
- tp = file_element(parea, &cf); // add new element to chain
- // note: exits if no memory
- if (ca == NULL) // it is first element in group
- ca = ce = tp; // first and last in group
- else { // not first
- ce->next_element = tp; // chain-ptr in previous
- ce = tp; // new last in group
- }
- ++fc; // update filecount this area
- byte_count += cf.cbFile; // update file bytecount
-
- if (oper_mode==VERBOSE && (fc%25)==0) // every 25 files
- cprintf("\r %5u",fc);
- }
- fentries = 1; // retreive 1 at a time (DOS!)
- rc = DosFindNext(fhandle,
- &cf,
- #ifndef __32BIT__
- sizeof(struct _FILEFINDBUF),
- &fentries);
- #else
- sizeof(struct _FILEFINDBUF3),
- &fentries);
- #endif
- }
- DosFindClose(fhandle); // close directory association
- *cp = ca; // pointer to first new this area
- return(fc);
- } // return # of allocated elements
-
- /* -------------------------------------- */
- /* Add file description to chian elements */
- /* -------------------------------------- */
- unsigned short int get_desc(struct _downpath huge *parea,
- struct _filechain **cp)
- {
- #ifndef __32BIT__
- unsigned short int
- #else
- unsigned long int
- #endif
- fih, // file handle
- oaction; // open-action flags
- FILE *fi; // file pointer
- unsigned short int y; // number of offline files
- struct _filechain *ce, *tp; // ptrs to file-info
- char buf[MAXRCD]; // read-buffer for FILES.BBS
- char filename[MAXFN]; // filename from FILES.BBS buf
- char *desc, *rp; // ptr to desc / return val gets()
- short int i,k,m,p,x; // counters
- short int fpriv; // file privilege
- int rc; // returncode
- unsigned short int bbsseq; // current line number of FILES.BBS
- char desc_spec[MAXPATH];
- struct _filechain **fa; // pointer to file sort-array
- static char prop[4] = "/|\\-"; // rotating propeller
-
- if (strlen(parea->filesbbs) > 0) // explicit specification?
- strcpy(desc_spec,parea->filesbbs); // explicitly specified FileList
- else { // no
- strcpy(desc_spec,parea->pname); // get path to download directory
- strcat(desc_spec,lp[P_FIL].name); // add filename
- strcat(desc_spec,"."); // add separator
- strcat(desc_spec,lp[P_FIL].ext); // add extension
- }
-
- fpriv = parea->priv; // area-priv is default file priv
- // FILES.BBS may be in use!!!
- rc = DosOpen(desc_spec, // Open 'carefully'
- &fih, // pointer to File Handle
- &oaction, // pointer to action field
- 0L, // new filesize (N/A)
- FILE_NORMAL, // attributes
- FILE_OPEN, // open flags
- OPEN_ACCESS_READONLY | // mode
- OPEN_SHARE_DENYWRITE,
- 0L); // no EA's OS/2 2.0+
- if (rc) { // open error
- printf(OPEN_FAIL, desc_spec, rc);
- return(0); // no: return to caller
- }
- if ( (fi = fdopen(fih, "r")) == NULL) { // open now as stream
- printf(OPEN_FAIL, desc_spec, 0); // dummy rc
- return(0); // no: return to caller
- }
-
- ce = *cp; // ptr to 1st element of group
- for (x=0; ce != NULL; x++) // count collected dir entries
- ce = ce->next_element;
-
- if (x > 0) { // if any files in dir
- fa = (struct _filechain **)malloc(x * sizeof(struct _filechain *));
- if (fa == NULL) { // not enough memory
- printf(MSG_MEM,PROGNAME);
- DosExit(11,0);
- }
- ce = *cp; // ptr to 1st element of group
- for (i=0; ce != NULL; i++) { // init sort array
- fa[i] = ce; // element pointer into array
- ce = ce->next_element;
- }
- qsort(fa, x, sizeof(struct _filechain *), sort_gbl);
- } //
- else // no files in group
- fa=NULL; // no array allocated
-
- y = 0; // init 'offline' counter
- bbsseq = 0; // init counter
- rp = fgets(buf, MAXDESC, fi); // get first FILES.BBS record
- while (rp != NULL) { // until end of FILES.BBS
- bbsseq++; // line counter
- m = strlen(buf); // length of input string
- if (m>1 && buf[0] == '\20') { // privilege change (^P) ?
- for (k=0; k<HIDDEN-TWIT && priv_name[k][0]!=buf[1]; k++);
- if (TWIT + k > parea->priv) // only if higher than area-priv
- fpriv = TWIT + k; // new (higher) prilivege
- rp = fgets(buf, MAXDESC, fi); // continue
- }
- else if (parse_fname(buf) == NULL) { // NOT likely a filename
- if (bbsseq > 8 && // past 'standard' header
- (lp[P_ALL].sortflag == KEEPSEQ || // ALL-list or
- lp[P_IPF].sortflag == KEEPSEQ || // IPF-list or
- lp[P_IP2].sortflag == KEEPSEQ || // IP2-list or
- (lp[P_FIL].sortflag == KEEPSEQ &&
- lp[P_FIL].priv[0] <= HIDDEN))) { // FIL-list req'd with '/K'
- tp = add_comment(EMPTY, parea, // filename = null-string
- buf, fpriv, bbsseq);
- add_to_chain(cp, tp); // add element to end-of-chain
- ++y; // add 1 to 'offline' filecount
- }
- rp = fgets(buf, MAXDESC, fi); // continue
- }
- else { // probably file descr record
- for (i=0; i < MAXFN-1 && // maximum filename length (8.3)
- i < m && // string length
- buf[i] != ' ' && // space character
- buf[i] != '\r' && // CR character
- buf[i] != '\n'; // LF character
- i++); // scan for filespec
- strncpy(filename, buf, i); // save filename
- filename[i] = '\0'; // end of string
- desc = build_desc(fi, buf, &rp); // build description string
- if (desc == NULL) // no description
- rp = fgets(buf, MAXDESC, fi); // next record
- tp = assign_desc(x, filename, // assign desc to file(s)
- fa, parea, desc, fpriv, bbsseq);
- if (tp != NULL) { // new element for group
- add_to_chain(cp, tp); // add element to end-of-chain
- ++y; // add 1 to offline filecount
- }
- }
- if (oper_mode == VERBOSE && (bbsseq%5) == 0)
- cprintf("\r%c",prop[p=(++p)&3]); // propeller
- }
- if (fa != NULL) // memory for array allocated
- free(fa); // free temp sort array
- x = combine_comments(); // drop comment pairs
- if (oper_mode == VERBOSE)
- cprintf("\r "); // clear propeller
- fclose(fi); // finished with this FILES.BBS
- DosClose(fih); // close the handle
- return(y-x); // return 'offline' filecount
- // (includes comment elements)
- }
-
- /* -------------------------------------- */
- /* Add a new file element to end-of-chain */
- /* -------------------------------------- */
- void add_to_chain(struct _filechain **cp,
- struct _filechain *tp)
- {
- struct _filechain *ce; // work pointer
-
- if (*cp == NULL) { // group was empty
- *cp = tp; // return ptr to first in group
- if (first_element == NULL) // whole chain empty
- return; // ===> nothing else to do here!
- else // something in chain
- ce = first_element; // ptr to very 1st element
- }
- else
- ce = *cp; // pointer to 1st in group
-
- while (ce->next_element != NULL) // search last element
- ce = ce->next_element;
- ce->next_element = tp; // add new element to chain
- }
-
- /* ------------------------------------- */
- /* Build file description memory block */
- /* ------------------------------------- */
- char *build_desc(FILE *fi,
- char *ibuf,
- char **rp)
- {
- char *fd; // pointer memory block with desc
- char *desc; // string work pointers
- char buf2[MAXDESC]; // work buffers
- unsigned short int k; // counter
-
- desc = next_word(ibuf); // locate description
- if (desc != NULL) { // start of description found
- for (k=0; desc[k]; ++k) { // search first NL/CR
- if (desc[k]=='\r' || desc[k]=='\n') {
- desc[k] = '\0';
- break;
- }
- }
- strcpy(buf2, desc); // save desc in buf2
- while (((*rp = fgets(ibuf, MAXDESC, fi)) != NULL) && // next rcd
- (ibuf[0] == ' ') && // probably desc continuation
- ((desc = next_word(ibuf)) != NULL)) {
- for (k=0; desc[k]!='\0'; ++k) {
- if (desc[k]=='\r' || desc[k]=='\n') {
- desc[k] = '\0';
- break;
- }
- }
- if ((strlen(buf2) + k + 1) <= sizeof(buf2)) { // not too long
- strcat(buf2," "); // single space
- strcat(buf2, desc); // concat desc to buf2
- }
- }
- fd = malloc(strlen(buf2)+1); // obtain memory
- if (fd == NULL) {
- printf(MSG_MEM,PROGNAME); // not enough memory
- DosExit(12,0);
- }
- else
- strcpy(fd, buf2); // store description
- }
- else // no description
- fd = NULL; // return value
- return(fd); // return with pointer
- }
-
- /* ------------------------------------- */
- /* Assign description to file element(s) */
- /* ------------------------------------- */
- struct _filechain *assign_desc(short int x,
- char *filename,
- struct _filechain **fa,
- struct _downpath huge *parea,
- char *desc,
- short int fpriv,
- unsigned short int bbsseq)
- {
- short int low,high,index; // indexes
- short int b,n; // counters
- unsigned short int dlb,dlt; // download flags in description
- struct _filechain *tp; // ptr to file-info
- char dl_flags[5]; // copy of first part description
-
- dlb = dlt = 0; // flags off
- if (desc != NULL) { // only when real descr. present
- strncpy(dl_flags, desc, 4); // copy part of description
- if (dl_flags[0] == '/') { // could be valid dl_flag
- strupr(dl_flags); // make all uppercase
- if (dl_flags[1] == 'B' || dl_flags[2] == 'B')
- dlb = 1; // unlimited download bytes flag
- if (dl_flags[1] == 'T' || dl_flags[2] == 'T')
- dlt = 1; // unlimited download time flag
- desc = next_word(desc); // shift the description pointer
- }
- }
-
- low = 0; // index of first entry
- high = x-1; // index of last entry
- while (low <= high) { // binary search in array
- index = (high + low) / 2; // middle of interval
- if ((b = wild_comp(fa[index]->fname,filename)) < 0)
- low = index + 1; // new low boundary
- else if (b > 0) // 'b'-value from previous 'if'
- high = index - 1; // new high boundary
- else
- break; // equal: found
- }
-
- tp = NULL; // init to 'not offline'
- if (x < 1 || // no files in directory at all
- wild_comp(fa[index]->fname,filename)) { // this one not in dir
- tp = file_element(parea, NULL); // alloc new element
- strcpy(tp->fname, filename); // copy filename to new element
- tp->fdesc = (desc != NULL) ? desc : NDS; // assign 'some' desc
- tp->priv = fpriv; // copy privilege
- tp->fseq = bbsseq; // copy FILES.BBS line number
- tp->dl_b = dlb; // copy download bytes flag
- tp->dl_t = dlt; // copy download time flag
- if (oper_mode == VERBOSE) {
- cprintf("\r %c", 25); // erase progress counter
- printf("\n %s %s", OFFLINE, filename); // display filename
- }
- }
- else { // file found in directory
- n = index; // 'hit' and lower entries
- while (n>=0 && wild_comp(fa[n]->fname,filename) == 0) {
- if (fa[n]->fdesc == NULL) // no description assigned yet
- desc_old(fa, desc, parea, n, fpriv, bbsseq, dlb, dlt);
- else if (strcmp(fa[n]->parea->name,parea->name)) // diff. dir
- tp = desc_dup(fa[n], desc, parea, fpriv, bbsseq, dlb, dlt); // new
- --n; // next lower
- }
- n = index + 1; // higher entries
- while (n<x && wild_comp(fa[n]->fname,filename) == 0) {
- if (fa[n]->fdesc == NULL) // no description assigned yet
- desc_old(fa, desc, parea, n, fpriv, bbsseq, dlb, dlt);
- else if (strcmp(fa[n]->parea->name,parea->name)) // diff. dir
- tp = desc_dup(fa[n], desc, parea, fpriv, bbsseq, dlb, dlt); // new
- ++n; // next higher
- }
- }
- return(tp); // return pointer to new(?)
- // element or NULL if not new
- }
-
- /* ---------------------------------------------- */
- /* Create duplicate file element with description */
- /* ---------------------------------------------- */
- struct _filechain *desc_dup(struct _filechain *fa,
- char *desc,
- struct _downpath huge *parea,
- short int fpriv,
- unsigned short int bbsseq,
- unsigned short int dlb,
- unsigned short int dlt)
- {
- struct _filechain *tp; // ptr to file-info
-
- tp = file_element(parea, NULL); // alloc new element
- tp->wdate = fa->wdate; // copy file wrtie date
- tp->wtime = fa->wtime; // copy file write time
- tp->cdate = fa->cdate; // copy file create date
- tp->ctime = fa->ctime; // copy file create time
- tp->size = fa->size; // copy file size
- tp->attr = fa->attr; // copy file attr
- tp->fseq = bbsseq; // copy FILES.BBS line number
- tp->priv = fpriv; // copy privilege
- tp->dl_b = dlb; // copy download bytes flag
- tp->dl_t = dlt; // copy download time flag
- strcpy(tp->fname, fa->fname); // copy filename to new element
- tp->fdesc = (desc != NULL) ? desc : NDS; // add pointer to desc.
- return(tp); // return pointer
- }
-
- /* --------------------------------------------- */
- /* Update existing file element with description */
- /* --------------------------------------------- */
- void desc_old(struct _filechain **fa,
- char *desc,
- struct _downpath huge *parea,
- short int n,
- short int fpriv,
- unsigned short int bbsseq,
- unsigned short int dlb,
- unsigned short int dlt)
- {
- fa[n]->fdesc = (desc != NULL) ? desc : NDS; // ptr to descr.
- fa[n]->parea = parea; // copy / overwrite area ptr
- fa[n]->priv = fpriv; // copy privilege
- fa[n]->dl_b = dlb; // copy download bytes flag
- fa[n]->dl_t = dlt; // copy download time flag
- fa[n]->fseq = bbsseq; // copy FILES.BBS line number
- }
-
- /* ---------------------------------------- */
- /* Add single file-entry to file-chain */
- /* returns: pointer to new element */
- /* ---------------------------------------- */
- struct _filechain *file_element(struct _downpath huge *parea,
- #ifndef __32BIT__
- struct _FILEFINDBUF *cf)
- #else
- struct _FILEFINDBUF3 *cf)
- #endif
- {
- struct _filechain *tp; // temporary-pointer
-
- tp = (struct _filechain *)malloc(sizeof(struct _filechain));
- if (tp == NULL) {
- printf(MSG_MEM,PROGNAME); // not enough memory
- DosExit(11,0);
- }
- memset(tp, '\0', sizeof(struct _filechain)); // whole struct zeroes
- tp->next_element = NULL; // ptr to next
- tp->fseq = 65535; // default FILES.BBS line number
- tp->priv = HIDDEN; // unless FILES.BBS proves otherwise
- tp->fdesc = NULL; // unless found in FILES.BBS
- tp->parea = parea; // copy pointer to area info
- if (cf != NULL) { // file-system info available
- tp->wdate = cf->fdateLastWrite;
- tp->wtime = cf->ftimeLastWrite;
- if (file_time(cf->fdateCreation, cf->ftimeCreation) >
- file_time(cf->fdateLastWrite, cf->ftimeLastWrite) ) { /* HPFS */
- tp->cdate = cf->fdateCreation; // creation most recent
- tp->ctime = cf->ftimeCreation;
- }
- else { // otherwise and non-HPFS volumes
- tp->cdate = cf->fdateLastWrite;
- tp->ctime = cf->ftimeLastWrite;
- }
- tp->size = cf->cbFile;
- tp->attr = cf->attrFile;
- strncpy(tp->fname, cf->achName, MAXFN);
- }
- return(tp);
- }
-
- /* --------------------------------- */
- /* Build comment entry in file-chain */
- /* --------------------------------- */
- struct _filechain *add_comment(char *filename,
- struct _downpath huge *parea,
- char *fdesc,
- short int fpriv,
- unsigned short int bbsseq)
- {
- struct _filechain *tp; // ptr to file-info
- char *fd; // ptr to file description
- char buf2[MAXDESC]; // work buffer
- unsigned short int k; // counter
-
- /* strcpy 55h */
- strncpy(buf2, fdesc, MAXDESC); // save desc in buf2
- for (k=0; buf2[k]!='\0'; ++k) // scan work buffer
- if (buf2[k]=='\r' || buf2[k]=='\n') { // for NL/CR
- buf2[k] = '\0'; // replace by end-of-string
- break;
- }
- tp = file_element(parea, NULL); // alloc new element
- /* strcpy 55h */
- strncpy(tp->fname, filename, MAXFN); // EMPTY for comment
- tp->priv = fpriv; // privilege
- tp->fseq = bbsseq; // FILES.BBS line number
- tp->cmt = 1; // indicate as comment element
- fd = malloc(k + 1); // obtain memory for desc
- if (fd == NULL) {
- printf(MSG_MEM,PROGNAME); // not enough memory
- DosExit(12,0);
- }
- else {
- strcpy(fd, buf2); // store description
- tp->fdesc = fd; // pointer to desc
- }
- return(tp); // return pointer
- }
-
- /* ----------------------------------------------------------- */
- /* Release memory occupied by orphan entries. */
- /* If first element contains an orphan it will not be removed! */
- /* ----------------------------------------------------------- */
- unsigned short int free_orphan()
- {
- unsigned short int orp_cnt; // removed orphan counter
- struct _filechain *ca,*cb; // current and next chain pointer
-
- orp_cnt = 0; // initial orphan count
- if ((ca=first_element) != NULL) { // any file elements in chain
- while ((cb=ca->next_element) != NULL) { // all elements (but first)
- if (cb->priv >= HIDDEN) { // probably orphan?
- ca->next_element = cb->next_element; // new ptr in current element
- free(cb); // free memory block
- ++orp_cnt; // one more dropped
- } // note: do not shift current
- else // not an orphan
- ca = cb; // shift +1 current element
- }
- } // only orphans
- return(orp_cnt); // report # of removed orphans
- }
-
- /* ---------------------------------------------------- */
- /* Combine consecutive comment lines to a single string */
- /* return the number of freed chain elements */
- /* ---------------------------------------------------- */
- unsigned short int combine_comments(void)
- {
- unsigned short int cmt_cnt; // freed elements count
- struct _filechain *ca,*cb; // current and next chain pointer
- char *new; // ptr to combined comments
- unsigned int k,l; // string lengths
-
- #if defined(DEBUG)
- dump_file_chain(first_element, "begin combine_comments()");
- #endif
- cmt_cnt = 0; // initial freed elements count
- if ((ca=first_element) != NULL) { // any elements in chain
- while ((cb=ca->next_element) != NULL) { // all elements
- if (ca->fname[0] == '\0' && // comment #1
- cb->fname[0] == '\0' && // comment #2
- cb->fseq == ca->fseq+1) { // consecutive lines in FILES.BBS
- k = strlen(ca->fdesc); // take length of 1st comment
- l = strlen(cb->fdesc); // take length of 2nd comment
- if ((new = (char *)malloc(k+l+2)) != NULL) { // mem obtained
- strcpy(new,ca->fdesc); // copy 1st comment
- strcat(new,"\n"); // insert newline
- strcat(new,cb->fdesc); // copy 2nd comment
- free(ca->fdesc); // release 1st old comment
- free(cb->fdesc); // release 2nd old comment
- ca->fdesc = new; // ptr to combined desc in cur el.
- ca->next_element = cb->next_element; // new ptr in cur el.
- free(cb); // release 2nd chain-element
- ++cmt_cnt; // update counter
- }
- else
- ca = cb; // no memory: proceed
- }
- else // not 2 consecutive comments
- ca = cb; // shift +1 current element
- }
- } // only orphans
- #if defined(DEBUG)
- dump_file_chain(first_element, "end combine_comments()");
- #endif
- return(cmt_cnt); // report # of removed elements
- }
-
- /* ----------------------------------- */
- /* Check if string could be a filename */
- /* ----------------------------------- */
- char *parse_fname(char *buf)
- {
- if ( strlen(buf) < 2 || // empty line
- buf[0] <= ' ' ||
- buf[0] == '\"' ||
- (buf[0] >= '+' && buf[0] <= '/') ||
- (buf[0] >= ':' && buf[0] <= '>') ||
- (buf[0] >= '[' && buf[0] <= ']') ||
- buf[0] == '|' ||
- buf[0] >= 128)
- return(NULL); // probably not a filename
- else
- return(buf); // pointer to filename
- }
-
-
- /* ------------------------------------- */
- /* Determine if area is within selection */
- /* ------------------------------------- */
- int area_selection(char *name,
- char sel_array[][MAXANAME])
- {
- int result;
- short int i;
-
- if (area_IN_EX) { // area selection specified
- result = (area_IN_EX < 0) ? 1 : 0; // default not found: IN=0 EX=1
- for (i=0; strcmp(sel_array[i], EMPTY); i++) {
- if (!strnicmp(sel_array[i], name, strlen(sel_array[i]))) {
- result = (area_IN_EX < 0) ? 0 : 1; // found: IN=1 EX=0
- break; // escape from while-loop
- }
- }
- }
- else
- result = 1; // no selections: all
- return(result); // return selection result
- }
-
- /* =================================================== */
- /* Compare for sort of area-array on download pathname */
- /* =================================================== */
- int sort_path(const void *p,
- const void *q)
- {
- int rc;
- struct _downpath huge *x, *y;
- x = (struct _downpath huge *)p;
- y = (struct _downpath huge *)q;
- if ((rc = stricmp(x->pname, y->pname)) == 0) // download pathname
- rc = stricmp(x->name, y->name); // area name
- return(rc);
- }
-
-
- #if defined(DEBUG)
- /* =============== */
- /* Dump area array */
- /* =============== */
- int dump_area_array(struct _downpath huge *aa, // pointer to array
- short int m, // number of elements
- char *id) // log id
- {
- short int i;
- FILE *log;
-
- log = fopen("downsort.log","a"); // append!
- fprintf(log,"\n"); // newline
- sep_line(log,'═',79); // separate from previous append
- fprintf(log,"(%s) %s\n", today, id); // timestamp + id
- flushall();
- for (i=0; i<m; i++) {
- fprintf(log,"\n%4d. bytecount=%10lu priv=%5d anum=%d filecount=%5u\n",
- i+1,
- aa[i].byte_count,
- aa[i].priv,
- aa[i].anum,
- aa[i].file_count);
- fprintf(log," name %s\nename %s\npname %s\nf_bbs %s\n desc %s\n",
- aa[i].name,
- aa[i].ename,
- aa[i].pname,
- aa[i].filesbbs,
- aa[i].adesc);
- fprintf(log,"newst %s\n",
- (aa[i].newest != NULL) ? aa[i].newest->fname : "-");
- flushall(); // write buffers before continue
- }
- fclose(log);
- return(i);
- }
-
- /* =============== */
- /* Dump file chain */
- /* =============== */
- int dump_file_chain(struct _filechain *f, // pointer to chain
- char *id) // log id
- {
- FILE *log;
- unsigned short int fc; // element count
- struct _filechain *fe; //
-
- log = fopen("downsort.log","a"); // append!
- fprintf(log,"\n"); // newline
- sep_line(log,'═',79,0); // separate from previous append
- fprintf(log,"(%s) %s\n\n", today, id); // timestamp + id
- flushall(); // force physical write(s)
- fe = f; // pointer to first element
- fc = 0; // counter=0
- while(fe != NULL) {
- if (fe->fname[0] != '\0') {
- fprintf(log,"%*.*s", MAXANAME, MAXANAME, fe->parea->name); // area
- fprintf(log," %s ", fe->fname); // filename
- }
- fprintf(log,"%s\n",
- (fe->fdesc != NULL) ? fe->fdesc : EMPTY); // file desc
- fc++;
- fe = fe->next_element;
- }
- fprintf(log,"\nChain_element_count = %u\n\n", fc);
- fclose(log);
- return(fc);
- }
- #endif
-
-