/**************************************************************************/
/*                                                                        */
/*                             DWDecode v1.0                              */
/*                                                                        */
/*                                                                        */
/*                    Copyright 1996 by Dick Whiting                     */
/*                                                                        */
/*========================================================================*/
/*                                                                        */
/*                                                                        */
/* Report bugs, comments, etc. to:                                        */
/*                                                                        */
/*                   Dick Whiting <dwhiting@europa.com>                   */
/*                                                                        */
/*                           01 December 1996                             */
/*                                                                        */
/**************************************************************************/

Parse arg commandline                    /* get command line options      */

options failat 21                        /* block rc<21 from sending msgs */
options results                          /* enable return codes           */

SIGNAL ON IOERR
SIGNAL ON SYNTAX

Call Init                                /* initialize tables, vars, etc. */

Do dirptr=1 to dirlist.0                 /* loop thru all directories     */
   Call BldFileNote                      /* Create filenotes for this dir */
   Call ScanFiles                        /* Scan for key strings          */
   Call ReadUnknowns                     /* Check files w/o encode set    */
   Call Phase2                           /* complete info in Files array  */
   Call ReportFiles                      /* generate file by file report  */
   Call IssueWarnings                    /* issue warnings - none so far  */
   Call FileNoteInFiles                  /* filenote inputs-encode & subj */
   Call BuildLists                       /* build array for decoding use  */   
   Call DecodeFiles                      /* do the actual decoding        */ 
   Call DoOldFiles                       /* handle Delete/Mark old files  */
   Call ListStats                        /* report time & cnts for dir    */
   Call DumpArrays                       /* dump arrays for this dir      */   
   if verbose then do
      say time() 'Done processing 'dirlist.dirptr
      say ' '
   end
end 

Cleanup:

if exists(DWtemp'DWdecode.scan') then do /* delete the scan file          */
   Address Command 'Delete 'DWtemp'DWdecode.scan QUIET'
end

if exists(DWtemp'DWdecode.temp') then do /* delete the join temporary file*/
   Address Command 'Delete 'DWtemp'DWdecode.temp QUIET'
end

Address Command 'Assign ' DWassignIN     /* remove the DW assign          */

pragma('D',origdir)                      /* reset to original directory   */

exit

/**************************************************************************/
/*                                                                        */
/*          Build the filenote string as requested in FILENOTE=var        */
/*                                                                        */
/*      Variable fnote may contain variables for later interpretation.    */
/*                                                                        */
/**************************************************************************/
BldFileNote:

   if Filenote~='' then do 
      fnote=filenote
      do j=words(filenote) to 1 by -1
         select
            when upper(word(filenote,j))='%SOURCE' then do
               wptr=wordindex(filenote,j)-1
               fnote=delword(fnote,j,1)
               sdir="'"||'dirlist.dirptr'||"'"
               fnote=insert(sdir,fnote,wptr,length(sdir)+1,' ')
            end
            when upper(substr(word(filenote,j),1,4))='%LLQ' then do
               llqnum=substr(word(filenote,j),5)
               if llqnum='' then llqnum=1
               if ~datatype(llqnum,'N') then llqnum=99
               if llqnum<1 then llqnum=99
               llq=translate(dirlist.dirptr,'  ',':/')
               if llqnum>words(llq) then llqnum=words(llq)
               llq=subword(llq,words(llq)-llqnum+1) 
               wptr=wordindex(filenote,j)-1
               fnote=delword(fnote,j,1)
               fnote=insert(llq,fnote,wptr,length(llq)+1,' ')
            end
            when upper(substr(word(filenote,j),1,4))='%HLQ' then do
               hlqnum=substr(word(filenote,j),5)
               if hlqnum='' then hlqnum=1
               if ~datatype(hlqnum,'N') then hlqnum=1 
               if hlqnum<1 then hlqnum=1 
               hlq=translate(dirlist.dirptr,'  ',':/')
               if hlqnum>words(hlq) then hlqnum=words(hlq)
               hlq=subword(hlq,1,hlqnum)             
               wptr=wordindex(filenote,j)-1
               fnote=delword(fnote,j,1)
               fnote=insert(hlq,fnote,wptr,length(hlq)+1,' ')
            end
            when upper(substr(word(filenote,j),1,5))='%QUAL' then do
               qnum1=substr(word(filenote,j),6,1)
               if qnum1='' then qnum1=1
               if ~datatype(qnum1,'N') then qnum1=1
               if qnum1<1 then qnum=1
               qual=translate(dirlist.dirptr,'  ',':/')
               if qnum1>words(qual) then qnum1=words(qual)
               qnum2=substr(word(filenote,j),7,1)
               if qnum2='' then qnum2=words(qual)
               if ~datatype(qnum2,'N') then qnum2=words(qual)
               if qnum2<1 then qnum=words(qual)
               if qnum2>words(qual) then qnum2=words(qual)
               qual=subword(qual,qnum1,qnum2) 
               wptr=wordindex(filenote,j)-1
               fnote=delword(fnote,j,1)
               fnote=insert(qual,fnote,wptr,length(qual)+1,' ')
            end
            when upper(word(filenote,j))='%SUBJECT' then do
               wptr=wordindex(filenote,j)-1
               fnote=delword(fnote,j,1)
               subj="'"||'Subjinfo.Filesptr.1.1'||"'"
               fnote=insert(subj,fnote,wptr,length(subj)+1,' ')
            end
            when upper(word(filenote,j))='%DATE' then do
               wptr=wordindex(filenote,j)-1
               fnote=delword(fnote,j,1)
               date="'"||'Dateinfo.Filesptr.1.1'||"'"
               fnote=insert(date,fnote,wptr,length(date)+1,' ')
            end
            when upper(word(filenote,j))='%FROM' then do
               wptr=wordindex(filenote,j)-1
               fnote=delword(fnote,j,1)
               from="'"||'Frominfo.Filesptr.1.1'||"'"
               fnote=insert(from,fnote,wptr,length(from)+1,' ')
            end
            otherwise nop
         end
      end   
      fnote=strip(fnote)                    /* remove extra blanks        */
      fnote="'"||fnote||"'"                 /* enclose string in quotes   */
   end   /* matches with filenote~='' */

Return

/**************************************************************************/
/*                                                                        */
/* Scan directory for key strings used for identifying encode type, part  */
/* information and header information.                                    */
/*                                                                        */
/* !! Should allow for multiple search programs, but not sure of output   */
/*    parsing handling. The command could be specified as a template.     */
/*                                                                        */
/**************************************************************************/
/*                                                                        */
/* Read the lines from the sorted scan array. Determine what kind of      */
/* line it is and store appropriately for Date:, From:, and Subject:      */
/*                                                                        */
/* Look for valid Section and begin lines. Get whatever info possible.    */
/* Look for valid Base64 indicators and store info as available.          */
/*                                                                        */
/* The next routine will try to handle completing any parts using the     */
/* information in the subject lines.                                      */
/*                                                                        */
/* ASSUMPTIONS:                                                           */
/*  1) If file has a valid Section or begin line then it is UUencoded.    */
/*  2) If an 'end' line occurs after a begin, it is a 1/1 part.           */
/*  3) If file has a valid Base64 line then the file is Base64 encoded.   */
/*  4) If a nth Base64 marker occurs, assume previous one is complete.    */
/*  5) Files with multiple encoded parts are 1/1 files                    */
/*                                                                        */
/*========================================================================*/
/*                          ARRAY FORMATS                                 */
/*========================================================================*/
/*               (0)=cnt             (0)=cnt                              */
/* Files. format: filename.encodetype.partname.partnum.parttot.startline  */
/*                        .encodetype.partname.partnum.parttot.startline  */
/*                                                                        */
/*                                     (Y/N/.)  (Y/.)     (Y/.)  (Y/.)    */
/* Miscinfo. format: filename.mimetype.decoded.filenoted.chopped.dupfile  */
/*                                                                        */
/*                    (0)=cnt                                             */
/* Subjinfo. format: skipflag.deleteflag.textline                         */
/* Frominfo. format: skipflag.deleteflag.textline                         */
/* Dateinfo. format: skipflag.deleteflag.textline                         */
/*                                                                        */
/*                                   (0)#partname matches in subject line */
/*                                         (0)#partnums in subject line   */
/*                                                    (0)#totals in sub   */
/*                   Files                  spart      spart              */
/* Partone.  format: Pointer.partname.sword.number.loc.total.loc.subjline */
/*                                                                        */
/* Partxxx.=same format as Partone.                                       */
/*                                                                        */
/**************************************************************************/
ScanFiles:

   starttm=time('S')          /* start time for processing this directory */

   Address Command 'Assign ' DWassignIN dirlist.dirptr /*for shorter lines*/ 

   ScanArray.=missing          /* stores parsed information from scan prg */
   ScanArray.0=0                                 /* no scan lines yet     */

   Files.=missing              /* stores information for each news file   */
   Files.0=0                                     /* no File info yet      */

   Miscinfo. =missing          /* stores additional info for file/parts   */
   Miscinfo.0=0                                  /* no Misc info yet      */

   Subjinfo. =missing                            /* init to missing       */
   Subjinfo.0=0                                  /* no Subject lines yet  */

   Frominfo. =missing                            /* init to missing       */
   Frominfo.0=0                                  /* no From    lines yet  */

   Dateinfo. =missing                            /* init to missing       */
   Dateinfo.0=0                                  /* no Date    lines yet  */

   Partone. =missing                             /* init to missing       */
   Partone.0=0                                   /* no partone  lines yet */
   part1cnt=0                                    /* no partone  lines yet */

   Partxxx. =missing                             /* init to missing       */
   Partxxx.0=0                                   /* no partxxx  lines yet */
   partXcnt=0                                    /* no partxxx  lines yet */

   Parts.0=0                                     /* init to zero - report */
   Temppart.0=0                                  /* init to zero - report */ 

   AllBegins.0=0                                 /* lines with begin      */
   AllEncodes.0=0                                /* MIME encoding info    */
   AllSections.0=0                               /* lines with section    */

   warnings.0=0                                  /* used for warning msgs */

if verbose then say time() 'Scanning ' dirlist.dirptr '...' 

   Address Command scanprog dirlist.dirptr 'From:    cs nh num  > ' DWtemp'DWdecode.scan'
   Address Command scanprog dirlist.dirptr 'Subject: cs nh num >> ' DWtemp'DWdecode.scan'
   Address Command scanprog dirlist.dirptr 'Date:    cs nh num >> ' DWtemp'DWdecode.scan'
   Address Command scanprog dirlist.dirptr 'section     nh num >> ' DWtemp'DWdecode.scan'
   Address Command scanprog dirlist.dirptr 'begin    cs nh num >> ' DWtemp'DWdecode.scan'
   Address Command scanprog dirlist.dirptr 'end      cs nh num >> ' DWtemp'DWdecode.scan'
   Address Command scanprog dirlist.dirptr 'Content- cs nh num >> ' DWtemp'DWdecode.scan'
   Address Command scanprog dirlist.dirptr 'number=  cs nh num >> ' DWtemp'DWdecode.scan'
   do i=1 to Base64Types.0
      Address Command scanprog dirlist.dirptr Base64Types.i ' cs nh num >> ' DWtemp'DWdecode.scan'
   end

if verbose then say time() 'Reading the scan file ...'

   goodopen=open('IN',DWtemp'DWdecode.scan','R')
   if ~goodopen then do
      msg='(E) Error in opening ' DWtemp'DWdecode.scan'
      interpret Saycmd
      msg='    No further processing for this directory possible'
      interpret Saycmd
      exit
   end
   dirname=dirlist.dirptr                        /* name of directory     */
   device=substr(dirname,1,pos(':',dirname))     /* get device portion    */
   directs=substr(dirname,pos(':',dirname)+1)    /* remaining portion     */
   if upper(device)='RAM:' then dirname='Ram Disk:'||directs  /* fix Ram: */
   dirlen=length(dirname)                        /* length of dir name    */
   filename=missing                              /* init to missing       */
   sptr=0                                        /* scanarray pointer     */

   do until eof('IN')
      linein=readln('IN')
      select
         when pos(dirname,linein)=1 & word(linein,words(linein))='...' then do
            fullname=subword(linein,1,words(linein)-1) /* name with path  */
            filename=substr(fullname,dirlen+1)   /* just the filename part*/
            if pos('/',filename)>0 then do 
               filename=substr(filename,lastpos('/',filename)+1)
            end
         end
         when words(linein)=2 & word(linein,2)='...' then do
            fullname=word(linein,1)              /* filename with path    */
            filename=substr(fullname,dirlen+1)   /* just the filename part*/
            if pos('/',filename)>0 then do 
               filename=substr(filename,lastpos('/',filename)+1)
            end
         end
         when words(linein) > 0 then do
            linenum=strip(word(linein,1))        /* line number found     */
            linenum=right(linenum,6,'0')         /* put in leading zeros  */
            text=subword(linein,2)               /* remaining string      */
            select 
               when word(text,1)='Newsgroups:' then nop
               when word(text,1)='Xref:' then nop
               when substr(word(text,1),1,2)='X-' then nop
               when word(text,1)='Content-Description:' then nop
               otherwise do
                  sptr=sptr+1                          /* increment cnter */
                  scanarray.0=sptr                     /* store it        */    
                  scanarray.sptr=filename linenum text /* put it in array */   
               end
            end
         end
         otherwise nop /* should be end of file */
      end
   end

   result=close('IN')                            /* close the scan file   */

if verbose then say time() 'Sorting the scan array ...'


   call QSORT(1, scanarray.0, scanarray)     /* sort by name, line number */

   if DEBUG=YES then do 
      msg=' '
      interpret Saycmd
      msg='Dumping ScanArray ...'
      interpret Saycmd
      msg=left(dashes,length(msg))
      interpret Saycmd
      do i=1 to scanarray.0                          /* for debugging     */ 
         msg=scanarray.i
         interpret Saycmd
      end
      msg=' '
      interpret Saycmd
   end

   SkipSubjCnt=0                                 /* used for reporting    */
   SkipFromCnt=0                                 /* used for reporting    */ 
   B64OutCnt=0                                   /* used for reporting    */
   UUOutCnt=0                                    /* used for reporting    */

   oldfile=missing                               /* break control on file */
   oldsection=missing                            /* used to trap end sect.*/
   fptr=0                                        /* files array pointer   */

   partname=missing                              /* no partname yet       */
   partnum=missing                               /* no partnum yet        */
   parttot=missing                               /* no part total yet     */ 
   partlin=missing                               /* decode start line num */
   pptr=0                                        /* zero to start with    */
   encode=missing                                /* init to missing       */ 
   beginfound=NO                                 /* no begins found yet   */
   CCdata=NO                                     /* NO Content data yet   */

if verbose then say time() 'Processing the scan array ...'

   do i=1 to scanarray.0
      filename=word(scanarray.i,1)               /* filename in array     */
      linenum=word(scanarray.i,2)                /* line number in array  */       
      text=subword(scanarray.i,3)                /* remainder of line     */
      if filename~=oldfile then do               /* got a level break     */
         if encode~=missing then Call StorePartVars /* do previous part   */
         if oldfile~=missing then do 
            skipflag=NO                          /* didn't do any skips   */
            Call CheckSkips                      /* handle Skip/Deletes   */
            if skipflag=YES then do              /* clear array entries   */
               Files.fptr.1=missing              /* clear encode value    */
               Frominfo.fptr.1.1=missing
               Subjinfo.fptr.1.1=missing
               Dateinfo.fptr.1.1=missing
               encode=missing                    /* clear control vars    */
               fptr=fptr-1                       /* reuse current slot    */ 
               pptr=0                            /* clear control vars    */
            end 
         end
         oldfile=filename                        /* copy for next break   */
         fptr=fptr+1                             /* next files. pointer   */
         Files.0=fptr                            /* count the file        */
         Files.fptr=filename                     /* store filename        */
         Files.fptr.1.0=0                        /* no parts yet          */
         Dateinfo.fptr=0                         /* don't skip            */
         Dateinfo.fptr.1=0                       /* don't delete          */
         Frominfo.fptr=0                         /* don't skip            */
         Frominfo.fptr.1=0                       /* don't delete          */
         Subjinfo.fptr=0                         /* don't skip            */
         Subjinfo.fptr.1=0                       /* don't delete          */
         pptr=0                                  /* partname slot pointer */
         Call ResetPartVars                      /* reset partname vars   */
         oldsection=missing                      /* used to trap end sect.*/
      end

      select
         when word(text,1)='From:' & Frominfo.fptr.1.1=missing then do
            text=translate(text,'  ','"`')       /* blank all type quotes */
            text=translate(text,' ',"'")         /* blank all type quotes */
            Frominfo.fptr.1.1=substr(text,7)     /* store From info       */
         end
         when word(text,1)='Subject:' & Subjinfo.fptr.1.1=missing then do
            text=translate(text,'  ','"`')       /* blank all type quotes */
            text=translate(text,' ',"'")         /* blank all type quotes */
            Subjinfo.fptr.1.1=substr(text,10)    /* store Subject info    */
         end
         when word(text,1)='Date:' & Dateinfo.fptr.1.1=missing then do
              Dateinfo.fptr.1.1=substr(text,7)
         end
         when pos('SECTION',upper(word(text,1)))>0 then do
            Call CheckSections
            Call StorePartVars                /* complete set - store  */
         end
         when substr(text,1,6)='begin ' & datatype(word(text,2),'N') then do 
            partnum=1                            /* begins are part ones  */
            if partname~=subword(text,3) then do /* didn't have a section */
               partname=subword(text,3)          /* begin line partname   */ 
               encode='UU'                       /* encode type           */
               partlin=linenum            /* good starting point in file  */
               Call StorePartVars                /* complete set - store  */
            end
            beginfound=YES                       /* indicator for 'end '  */ 
         end
         when word(text,1)='end' & encode='UU' & beginfound=YES then do
            parttot=1                            /* !! total - unused ?   */
            Call StorePartVars                   /* store what we've got  */
            Call ResetPartVars                   /* reset partname vars   */
         end
         when pos('Content-',word(text,1))=1 then do
            Call CheckContent
            if CCdata=YES & Ctype>1 & encode ~=missing then do
               Call StorePartVars                /* store what we've got  */
               Call ResetPartVars                /* reset partname vars   */
            end
         end
         otherwise do
            if encode=missing then do            /* not from a Content-   */
               Call CheckBase64                  /* non-MIME B64 encoding */ 
               if encode='64' then do            /* found a B64 start str */
                  partnum=1                      /* begins are part ones  */
                  encode='64'                    /* encode type           */
                  Call StorePartVars             /* store what we've got  */
                  Call ResetPartVars             /* reset partname vars   */
               end
            end
         end
      end
   end                                  /* matches do i=1 to scanarray.0  */

   skipflag=NO                                   /* NO skips yet          */
   Call CheckSkips                               /* check LAST file       */
   if skipflag=YES then fptr=fptr-1              /* don't count last one  */
   if encode~=missing & skipflag=NO then Call StorePartVars /*last part   */
   
   Files.0=fptr                                  /* count of files found  */
   Frominfo.0=fptr                               /* count of files found  */
   Subjinfo.0=fptr                               /* count of files found  */
   Dateinfo.0=fptr                               /* count of files found  */
   Miscinfo.0=fptr                               /* count of files found  */

ScanFilesEnd:

Return

/**************************************************************************/
/*  Check for Skip/Delete based on Subject: or From: lines. If SKIP then  */
/*  filenote the file and reuse Files. slot. If DELETE then delete the    */
/*  file and reuse the slot. Skipped/Deleted will not appear on any rpts  */
/*  or be included in the match logic phases.                             */
/*                                                                        */
/*  Date deletes will be flagged for handling after the Decoding.         */
/**************************************************************************/
DoOldFiles:

   If MarkOld | DeleteOld then do
      do fptr=1 to Files.0
         if ~exists(DWassignIN||Files.fptr) then iterate fptr /* gone     */
         if DeleteOld & ~ScanOnly then do
            if Dateinfo.fptr.1=YES then do
               Address Command 'Delete' DWassignIN||Files.fptr 'QUIET'
            end
         end
         else do
            if Dateinfo.fptr.1=YES then do
               fnsubj=Subjinfo.fptr.1.1          /* subject for filenote  */
               fnsubj=substr(fnsubj,1,75)        /* shorten to max length */ 
               if Files.fptr.1=missing then fnsubj='O   '||fnsubj
                                       else fnsubj='O'||Files.fptr.1||' '||fnsubj
               filein=DWassignIN||Files.fptr
               Address Command 'Filenote 'filein '"'fnsubj'" ' 
            end
         end
      end
   end

Return

/**************************************************************************/
/*                                                                        */
/*           Report counts and time information for this directory        */
/*                                                                        */
/**************************************************************************/
ListStats:

   if ShowStats then do 
      totfiles=SkipSubjCnt+SkipFromCnt+Files.0
      if totfiles=0 then signal ListStatsEnd
      maxval=max(Files.0,Parts.0,Temppart.0,totfiles)
      rlen=length(maxval)
      msg=' ' 
      interpret saycmd
      msg=right(totfiles,rlen) 'File(s) in 'dirlist.dirptr
      interpret saycmd
      msg=right(SkipSubjCnt,rlen) 'File(s) skipped/deleted due to Subject: matches'
      interpret saycmd
      msg=right(SkipFromCnt,rlen) 'File(s) skipped/deleted due to From: matches'
      interpret saycmd
      msg=right(Temppart.0,rlen) 'Encoded pieces completely identified'
      interpret saycmd
      complete=0
      do j=1 to parts.0
         if parts.j.1=parts.j.1.0 then complete=complete+1
      end
      msg=right(complete,rlen) 'Complete encoded files (excludes duplicates)'
      interpret saycmd
      msg=right(UUOutCnt,rlen) 'UU Encoded output files written'
      interpret saycmd
      msg=right(B64OutCnt,rlen) 'Base64 Encoded output files written'
      interpret saycmd

      endtm=time('S')   
      elapstm=endtm-starttm
      hh=elapstm%3600
      hh=right(hh,2,'0')
      elapstm=elapstm-(3600*hh)
      mm=elapstm%60
      mm=right(mm,2,'0')
      ss=elapstm-(60*mm)
      ss=right(ss,2,'0')
      msg=copies(' ',rlen) 'Processing time for this directory:' hh':'mm':'ss 
      interpret Saycmd
   end

ListStatsEnd:

Return

/**************************************************************************/
/*  Check for Skip/Delete based on Subject: or From: lines. If SKIP then  */
/*  filenote the file and reuse Files. slot. If DELETE then delete the    */
/*  file and reuse the slot. Skipped/Deleted will not appear on any rpts  */
/*  or be included in the match logic phases.                             */
/*                                                                        */
/*  Date deletes will be flagged for handling after the Decoding.         */
/**************************************************************************/
CheckSkips:

   If SkipFrom | DeleteFrom then do
      do skipcnt=1 to SkipFroms.0
         if pos(upper(SkipFroms.skipcnt),upper(Frominfo.fptr.1.1))>0 then do
            if DeleteFrom & ~ScanOnly then do 
               Address Command 'Delete' DWassignIN||Files.fptr 'QUIET'
            end
            else do
               fnsubj=Subjinfo.fptr.1.1                   /* subject for filenote  */
               fnsubj=substr(fnsubj,1,75)                 /* shorten to max length */ 
               if Files.fptr.1=missing then fnsubj='F   '||fnsubj
                                       else fnsubj='F'||Files.fptr.1||' '||fnsubj
               filein=DWassignIN||Files.fptr
               Address Command 'Filenote 'filein '"'fnsubj'" ' 
            end
            skipflag=YES
            SkipFromCnt=SkipFromCnt+1
            leave skipcnt         
         end
      end 
   end
   
   If SkipSubject | DeleteSubject then do
      do skipcnt=1 to SkipSubjects.0
         if pos(upper(SkipSubjects.skipcnt),upper(Subjinfo.fptr.1.1))>0 then do
            if DeleteSubject & ~ScanOnly then do
               if exists(DWassignIN||Files.fptr) then do
                  Address Command 'Delete' DWassignIN||Files.fptr 'QUIET'
               end
            end 
            else do
               fnsubj=Subjinfo.fptr.1.1                   /* subject for filenote  */
               fnsubj=substr(fnsubj,1,75)                 /* shorten to max length */ 
               if Files.fptr.1=missing then fnsubj='S   '||fnsubj
                                       else fnsubj='S'||Files.fptr.1||' '||fnsubj
               filein=DWassignIN||Files.fptr
               if ~skipflag then Address Command 'Filenote 'filein '"'fnsubj'" ' 
            end
            if ~skipflag then do
               skipflag=YES
               SkipSubjCnt=SkipSubjCnt+1
            end 
            leave skipcnt         
         end
      end 
   end
   
   If (MarkOld | DeleteOld) & Dateinfo.fptr.1.1~=missing  then do
      datemsg=Dateinfo.fptr.1.1
      Call TimeStamp
      if (today-days)>KeepDays then do
         Dateinfo.fptr.1=YES
      end 
   end

Return

/**************************************************************************/
/*  Attach a filenote to each of the input files with encode & subject    */
/*  This is the time to DELETE non-binaries if requested to.              */
/**************************************************************************/
FileNoteInFiles:

msg='Filenoting input files '
if DeleteText then msg=msg||'and Deleting Text files '
msg=msg||'...'
if verbose then say time() msg

do i=1 to Files.0
   filein=DWassignIN||Files.i                    /* name of file w/path   */
   if DeleteText & Files.i.1=missing then do  /* a 'text' file         */
      Address Command 'Delete ' filein ' QUIET'
      iterate i                                  /* go onto next file     */
   end
   fnsubj=Subjinfo.i.1.1                         /* subject for filenote  */
   fnsubj=substr(fnsubj,1,75)                    /* shorten to max length */ 
   select
      when Files.i.1=missing then do
         encoding='Not an encoded file'
         Address Command 'Filenote 'filein '"    '||fnsubj||'" '
         fnrc=rc
      end
      when Files.i.1='UU' then do
         encoding='UUencode'
         Address Command 'Filenote 'filein '" UU '||fnsubj||'" ' 
         fnrc=rc
      end
      when Files.i.1='64' then do
         encoding='Base64'
         Address Command 'Filenote  'filein '" 64 '||fnsubj||'" ' 
         fnrc=rc
      end
      otherwise nop
   end
   if fnrc>0 then do
      say 'Filenote returned RC='fnrc 'for 'filein
      say 'Subject: 'fnsubj
   end
end

Return

/**************************************************************************/
/*                                                                        */
/*      Reset variables used to identify partnames, number, etc.          */
/*                                                                        */
/**************************************************************************/
ResetPartVars:

   if pptr>1 then do                             /* an nth encode in file */
      prev=pptr-1                                /* point to prev part    */
      Files.fptr.1.prev.1.1=1                    /* must be a part 1/1    */
   end
   
   if encode~=missing then Files.fptr.1.0=pptr   /* store partname cnt    */ 
   partname=missing                              /* no partname yet       */
   partnum=missing                               /* no partnum yet        */
   parttot=missing                               /* no part total yet     */ 
   partlin=missing                               /* decode start line num */
   encode=missing                                /* null for encoding     */
   pptr=pptr+1                                   /* NEXT part for filename*/
   beginfound=NO                                 /* no begins found yet   */
   CCdata=NO                                     /* NO Content data yet   */
   Ctype=0                                       /* no Content-type yet   */

Return

/**************************************************************************/
/*                                                                        */
/*      Store variables used to identify partnames, number, etc.          */
/*                                                                        */
/**************************************************************************/
StorePartVars:

   if encode~=missing   then do
      Files.fptr.1.0=pptr
      Files.fptr.pptr=encode 
   end
   if partname~=missing then do
      Files.fptr.1.pptr=partname 
   end
   if partnum~=missing  then do
      Files.fptr.1.pptr.1=partnum 
   end
   if parttot~=missing  then do
      Files.fptr.1.pptr.1.1=parttot 
   end
   if partlin~=missing  then do
      Files.fptr.1.pptr.1.1.1=partlin 
   end

Return

/**************************************************************************/
/*                                                                        */
/*      See if this one has Section information (we hope so)              */
/*                                                                        */
/**************************************************************************/
CheckSections:

   if text=oldsection then signal CheckSectionsEnd  /* a closing section  */

   if pos('SECTION',upper(text))>0 & TrapAllSecs then do
      AllSections.0=1+AllSections.0
      secptr=AllSections.0
      AllSections.secptr=filename':'text
   end

   do k=1 to sectiontypes.0               /* loop thru various forms      */
      matchctr=0                          /* zero matches at start        */
      do l=1 to sectiontypes.k            /* number of keys to test       */
         key1=sectiontypes.k.l            /* primary search key           */
         key1loc=sectiontypes.k.l.l       /* location of primary key      */
         if word(text,key1loc)=key1 then matchctr=matchctr+1
         else iterate k                   /* on any mismatch quit loop    */
      end
      if matchctr =sectiontypes.k then do        /* found a KNOWN section */
         wpartnum =sectiontypes.k.1.1.1          /* word holding partnum  */
         wparttot =sectiontypes.k.1.1.1.1        /* word holding total    */
         wpartname=sectiontypes.k.1.1.1.1.1      /* name of file          */
         partsep  =sectiontypes.k.1.1.1.1.1.1    /* delimiter char        */
         if wpartnum=wparttot & wpartnum~=missing then do
            partword=word(text,wpartnum)         /* get the word          */
            partnum=substr(partword,1,pos(partsep,partword)-1)
            parttot=substr(partword,pos(partsep,partword)+1)
         end
         else do
            if wpartnum~=missing then partnum=word(text,wpartnum)
            if wparttot~=missing then parttot=word(text,wparttot)
         end
         if wpartname~=missing then partname=word(text,wpartname)
         if ~datatype(partnum,'N') then partnum=missing
         if ~datatype(parttot,'N') then parttot=missing
         encode='UU'                      /* Sections mean UU encoding    */ 
         partlin=linenum                  /* good starting point in file  */
         oldsection=text                  /* use to trap ending section   */
         leave k              /* got everything we could from the SECTION */       
      end  /* if matchctr=sectiontypes.k */
      else do 
         /* !!! should not get here !!! */
         say 'Should not be here--- Check Sections'
      end
   end  /* do k=1 to sectiontypes.0 */

   if pos('SECTION',upper(text))>0 then do    /* unknown section found    */
      if TrapNewSecs=YES & k>sectiontypes.0 then do
         if exists(TrapNewSecsFile) then mode='A'
                                    else mode='W'
         goodopen=open('TRAPSECS',TrapNewSecsFile,mode)
         if ~goodopen then do
            msg='(E) Unable to open TrapSecFile:'TrapNewSecsFile
            interpret Saycmd
            msg='    Setting TrapNewSecs=NO'
            interpret Saycmd
         end
         result=writeln('TRAPSECS',text)
         result=close('TRAPSECS')
      end  /* matches if TrapNewSecs=YES */
   end  /* matches unknown section */

CheckSectionsEnd:

Return

/**************************************************************************/
/*                                                                        */
/*                     Handle the Content- type lines                     */
/*                                                                        */
/**************************************************************************/
CheckContent:

   Select
      When word(text,1)='Content-Type:' & ,
           CCdata=YES & Ctype>0 & encode~=missing then do
         Ctype=Ctype+1
         i=i-1                         /* redo this line next iteration*/
      end
      When word(text,1)='Content-Type:' then do 
         Ctype=0                       /* any previous wasn't encoded  */
         Call CheckCType
      end
      When word(text,1)='Content-Transfer-Encoding:' then do
         Call CheckCEncoding
      end
           
      When word(text,1)='Content-Disposition:' then do 
         Call CheckCDisp
      end
      Otherwise nop
   end
   
CheckContentEnd:

Return

/**************************************************************************/
/*                                                                        */
/*                     Handle Content-Type lines                          */
/*                                                                        */
/**************************************************************************/
CheckCType:

   Select
      when upper(word(text,2))='MULTIPART/MIXED;' then nop 
      when upper(word(text,2))='MESSAGE/PARTIAL;' then do
         Call NextCline
         if substr(CCword1,1,7)='number=' & substr(CCword2,1,6)='total=' then do
            Call CheckCNumber
         end          
         else do
            if substr(CCword1,1,3)='id=' then do    /* a scan word in id  */ 
               i=i+1                                /* skip over id line  */
               Call NextCline
               if substr(CCword1,1,7)='number=' & substr(CCword2,1,6)='total=' then do
                  Call CheckCNumber
               end          
            end  
         end
      end   /* matches MESSAGE/PARTIAL */
      otherwise do  /* all other content-types for now */
         Ctype=Ctype+1                              /* count Content-type */
         if pos('name=',word(text,3))=1 then do
            partname=subword(text,3)
            squote=pos('"',partname)
            equote=lastpos('"',partname)-(squote+1)
            partname=substr(partname,squote+1,equote)
            CCdata=YES
         end
      end   /* matches otherwise other Content-Types */
   end   /* matches Content-Type Select */

CheckCTypeEnd:

Return

/**************************************************************************/
/*                                                                        */
/*                     Point to next line in scanarray                    */
/*                                                                        */
/**************************************************************************/
NextCline:    

   CCi=i+1                               /* temp pointer for next line   */
   CCfile=word(scanarray.CCi,1)
   CCtext=subword(scanarray.CCi,3)
   CCtext=translate(CCtext,'  ',tab)
   CCword1=strip(word(CCtext,1))
   CCword2=strip(word(CCtext,2))

Return

/**************************************************************************/
/*                                                                        */
/*                     Handle number= for Partials                        */
/*                                                                        */
/**************************************************************************/
CheckCNumber:

   partnum=substr(CCword1,8)
   partnum=strip(translate(partnum,' ',';'))
   parttot=substr(CCword2,7)
   parttot=strip(translate(parttot,' ',';'))
   i=CCi
   CCdata=YES

Return

/**************************************************************************/
/*                                                                        */
/*                     Handle Content-Encoding lines                      */
/*                                                                        */
/**************************************************************************/
CheckCEncoding:

   if TrapAllEncs then do
      AllEncodes.0=1+AllEncodes.0
      encptr=AllEncodes.0
      AllEncodes.encptr=filename':'text
   end

   do k=1 to EncTypes.0                   /* loop thru various forms      */
      matchctr=0                          /* zero matches at start        */
      if upper(word(text,2))=upper(EncTypes.k) then do
         matchctr=1                       /* found a match                */ 
         if EncTypes.k.1~=missing then do
            encode=upper(EncTypes.k.1)    /* store encode type            */
            partlin=linenum               /* good starting point in file  */
            if partnum=missing & encode='64' then partnum=1
            CCdata=YES
         end
         leave k
      end
   end  /* do k=1 to EncTypes.0 */

   if TrapNewEncs=YES & matchctr=0 then do   /* must be a new encode type */ 
      if exists(TrapNewEncsFile) then mode='A'
                                 else mode='W'
      goodopen=open('TRAPENCS',TrapNewEncsFile,mode)
      if ~goodopen then do
         msg='(E) Unable to open TrapEncFile:'TrapNewEncsFile
         interpret Saycmd
         msg='    Setting TrapNewEncs=NO'
         interpret Saycmd
      end
      result=writeln('TRAPENCS',text)
      result=close('TRAPENCS')
   end  /* matches if TrapNewEncs=YES */

Return

/**************************************************************************/
/*                                                                        */
/*                     Handle Content-Disposition lines                   */
/*                                                                        */
/**************************************************************************/
CheckCDisp:

   if pos('filename',word(text,3))=1 then do
      partname=subword(text,3)
      squote=pos('"',partname)
      if squote>0 then do 
         equote=lastpos('"',partname)-(squote+1)
         partname=substr(partname,squote+1,equote)
      end
      else do
         partname=strip(substr(partname,10)) 
      end
      CCdata=YES
   end

CheckCDispEnd:

Return

/**************************************************************************/
/*                                                                        */
/*                     Handle the Base64 - type lines                     */
/*                                                                        */
/**************************************************************************/
CheckBase64:

   do k=1 to Base64Types.0                /* loop thru various forms      */
      key1=Base64Types.k                  /* primary search key           */
      key1loc=1                           /* location of primary key      */
      if pos(key1,text)=key1loc then do   /* found a match for Base64     */
         partlin=linenum
         encode='64'                      /* Base64 encoding              */
         leave k                          /* stop looking                 */
      end
   end  /* do k=1 to Base64Types.0 */

Return

/**************************************************************************/
/*                                                                        */
/*  Read all unidentified files looking for UU encoded lines. Only files  */
/*  with encode=missing are read. Should be part x/y and should only have */
/*  a few lines of header info. Not like part 1/y where leading text may  */
/*  be hundreds of lines. Use MaxHeader=25 or less and should be quick.   */
/*                                                                        */
/**************************************************************************/
ReadUnknowns:

if verbose then say time() 'Reading unidentified files for encoded lines ...'

   do i=1 to Files.0
      if Files.i.1=missing then do        /* check file for UU lines      */
         filein=DWassignIN||Files.i

         goodopen=open('IN',filein,'R')
         if ~goodopen then do
            msg='(E) Error in processing input file' filein
            interpret Saycmd
            msg='    Attempting to continuing with next file'
            interpret Saycmd
            iterate
         end

         j=1                                     /* loop control variable */
         mcount=0                                /* reset UU line counter */
         bcount=0                                /* reset 64 line counter */

         do until j>MaxHeader | mcount=MinEncoded | eof('IN')
            linein=readln('IN')
            linein=strip(linein,'T')             /* strip trailing blanks */
            if substr(linein,1,1)='M' & pos(' ',linein)=0 then do
               mcount=mcount+1
               bcount=0                          /* if an 'M' then not 64 */
            end 
            else do 
               if length(linein)>40 & pos(' ',linein)=0 then do
                  bcount=bcount+1 
                  mcount=0
               end 
            end 
            j=j+1                                /* NEXT line number      */
         end

         if mcount>=MinEncoded then do
            Files.i.1='UU'                       /* a UU encoded file     */
            Files.i.1.0=1                        /* 1 entry in array      */
         end 
         else do
            if bcount>=MinEncoded then do
               Files.i.1='64'                    /* Base 64 file?)        */
               Files.i.1.0=1        
            end 
         end 

         result=close('IN')                      /* close the input file  */
      end
   end

Return

/**************************************************************************/
/* First loop thru files and any that have multiples within a single file */
/* are marked as part 1/1. This assumes we don't have multiple PARTS for  */
/* files that have multiple encodes within them.                          */
/*                                                                        */
/*  Next:                                                                 */
/*  locate all encoded files with a missing value for name, num, or total */
/*  To complete this information we need to trust the information in the  */
/*  subject line and make some 'reasonalbe' assumptions. We will also     */
/*  use comparing of subject lines to connect part x/y with the part 1/y  */
/**************************************************************************/
Phase2:         

if verbose then say time() 'Starting Phase2 part identification ...'

   part1cnt=0                               /* count of part 1/. pieces   */
   partXcnt=0                               /* count of part x/y pieces   */

   do i=1 to Files.0        
      Select
         when Files.i.1=missing then nop    /* not an encoded file - skip */
         when Files.i.1.0=1 then do
            partname=Files.i.1.1
            partnum=Files.i.1.1.1
            parttot=Files.i.1.1.1.1
            if partname=missing | partnum=missing | parttot=missing then do
               Call CheckSubject
            end
            else do
               if parttot > 1 then do
                  Call CheckSubject
               end
            end
         end
         when Files.i.1.0>1 then do j=1 to Files.i.1.0
            if Files.i.1.j.1=1 & Files.i.1.j.1.1=missing then do
               Files.i.1.j.1.1=1
            end 
            else do
               if Files.i.1.j.1~=1 & Files.i.1.j.1.1=missing then do
                  Say 'Found multi parts with first not = 1'
                  Say Files.i Files.i.1 Files.i.1.j Files.i.1.j.1 Files.i.1.j.1.1
               end
            end
         end
         otherwise do
            Say 'Found otherwise condition in Phase2'
            Say Files.i Files.i.1 Files.i.1.0 Files.i.1.1 Files.i.1.1.1 Files.i.1.1.1.1
         end
      end
   end

   Call Phase2Files

Return

/**************************************************************************/
/* Scan subject line looking for the partname previously identified. If   */
/* found mark where it/they occur.                                        */
/*                                                                        */
/* If we don't have a partname, then use the bintypes array to locate all */
/* potential filenames and mark where they occur.                         */
/*                                                                        */
/**************************************************************************/
CheckSubject:

   subjline=Subjinfo.i.1.1                     /* current subject line    */
   testword=missing                            /* init to missing         */
   spctr=0                                     /* counter for spartnames  */
   spartname.=missing                          /* init to missing         */
   spartname.0=0                               /* no partnames in subject */
   subjpn=missing                              /* init to missing         */
   subjpt=missing                              /* init to missing         */
   pncnt=0                                     /* counter for subject pns */
   ptcnt=0                                     /* counter for subject pts */

          /*****************************************************/
          /*  Get rid of all the braces, brackets, & parens.   */
          /*  This should take care of problems where user     */
          /*  didn't leave a blank between filename and part   */
          /*  information.                                     */
          /*                                                   */
          /*  Locate all possible binary file names in the     */
          /*  subject line. May be different ones or multiple  */
          /*  ones of the same name.                           */
          /*                                                   */
          /*  If a part 1/x (known from "begin" line) locate   */
          /*  if and where the partname is in the subject.     */
          /*  This will be used as a match locator in phase2.  */
          /*  If we can't locate it we will try to use the     */
          /*  partname we do find in the subject. (Probably a  */
          /*  typo by the user). If there isn't any name in    */
          /*  the subject we will use the entire subject line  */
          /*  for matches.                                     */
          /*                                                   */
          /*  For non 1/x parts, we try to get a subject name  */
          /*  and part information. This will be for reporting */
          /*  purposes only if we don't have the part 1 for it.*/
          /*                                                   */
          /*****************************************************/

   subjline=translate(subjline,'      ','()[]{}') 

          /*****************************************************/
          /*  Count possible file names in the subject line    */
          /*****************************************************/

   do k=1 to words(subjline)                    /* loop thru subject line */
      sword=word(subjline,k)                    /* copy for ease          */
      if partname~=missing then do              /* already have a name    */
         if upper(partname)=upper(sword) then do /* handle as found       */
            spctr=spctr+1                       /* count another          */
            spartname.0=spctr                   /* increment .0 ctr       */
            spartname.spctr=word(subjline,k)    /* store it               */
            spartname.spctr.1=k                 /* which word it is       */  
            iterate k                           /* skip bin type search   */
         end
      end
      do l=1 to Bintypes.0                      /* loop thru binary types */
         if upper(substr(sword,1,7))='HTTP://' then iterate
         if upper(substr(sword,1,4))='WWW.' & upper(right(sword,4))='.COM' then iterate
         if upper(right(sword,length(bintypes.l)))=upper(bintypes.l) then do
            spctr=spctr+1                       /* count another          */
            spartname.0=spctr                   /* increment .0 ctr       */
            spartname.spctr=word(subjline,k)    /* store it               */
            spartname.spctr.1=k                 /* which word it is       */  
            leave l                             /* only count first match */
         end
      end 
   end


          /*****************************************************/
          /*  if a part 1 - see how many subject part names    */
          /*  match actual begin name and where in subject.    */
          /*****************************************************/
   spctr=0                                      /* reset to zero b4 using */
   if partnum=1 then do                /* found via SECTION or begin line */
      part1cnt=part1cnt+1                       /* another part one piece */
      Partone.0=part1cnt                        /* store it               */
      Partone.part1cnt=i                        /* pointer to file array  */     
      Partone.part1cnt.1=partname               /* name of binary file    */
      Partone.part1cnt.1.0=0                    /* no matches yet         */
      Partone.part1cnt.1.1.1.1.1.1.1=subjline   /* store a copy           */
      if partname~=missing then do k=1 to spartname.0
         if upper(partname)=upper(spartname.k) then do
            spctr=spctr+1                       /* increment match ctr    */
            Partone.part1cnt.1.0=spctr          /* count it               */
            Partone.part1cnt.1.spctr=spartname.k.1 /* where in subject    */
         end
      end
      else do /* a part one without a part name */
         Partone.part1cnt.1.0=spartname.0     /* how many in subject line */
         do k=1 to spartname.0
            Partone.part1cnt.1.k=spartname.k.1  /* where in subject line  */
         end
      end
   end
   else do               /* NOT a part 1 piece -- store info for matching */
      partXcnt=partXcnt+1                       /* another part xxx piece */
      Partxxx.0=partXcnt                        /* store it               */
      Partxxx.partXcnt=i                        /* pointer to file array  */     
      Partxxx.partXcnt.1.1.1.1.1.1.1=subjline   /* store a copy           */
      if partname~=missing then Partxxx.partXcnt.1=partname /* know name  */
      Partxxx.partXcnt.1.0=spartname.0        /* how many in subject line */
      do k=1 to spartname.0
         Partxxx.partXcnt.1.k=spartname.k.1     /* where in subject line  */
      end
   end    /* matches else do - NOT a part 1 piece */


          /*****************************************************/
          /*    Look for x/y, (x/y), [x/y], {x/y} formats      */
          /*    and count how many occurrences                 */
          /*****************************************************/
          /*    IF MORE THAN 1 '/' in word skip that word.     */
          /*   (it is probably a date in the mm/dd/yy form)    */
          /*****************************************************/

   if partnum=missing | parttot=missing | parttot>1 then do 
      do j=1 to words(subjline)
         testword=word(subjline,j)
         if pos('/',testword)>0 then do
            if pos('/',testword)~=lastpos('/',testword) then iterate j
            testword=translate(testword,' ','/') /* strip "/" character   */
            pn=strip(word(testword,1))       
            pt=strip(word(testword,2))
            if datatype(pn,'N') & datatype(pt,'N') then do
               subjpn=strip(pn,'L','0')
               subjpt=strip(pt,'L','0')
               pncnt=pncnt+1                     /* found a subj part num */
               ptcnt=ptcnt+1                     /* found a subj total    */
               if partnum=1 then do              /* from section or begin */
                  Partone.part1cnt.1.1.0=pncnt   /* store subj part numcnt*/
                  Partone.part1cnt.1.1.pncnt=subjpn  /* store  part num   */
                  Partone.part1cnt.1.1.pncnt.1=j     /* which word in sub */
                  Partone.part1cnt.1.1.1.1.0=ptcnt /* store subj total cnt*/
                  Partone.part1cnt.1.1.1.1.ptcnt=subjpt /* store part tot */
                  Partone.part1cnt.1.1.1.1.ptcnt.1=j      /* word in subj */
               end
               else do
                  Partxxx.partXcnt.1.1.0=pncnt   /* store subj part numcnt*/
                  Partxxx.partXcnt.1.1.pncnt=subjpn  /* store  part num   */
                  Partxxx.partXcnt.1.1.pncnt.1=j     /* which word in sub */
                  Partxxx.partXcnt.1.1.1.1.0=ptcnt /* store subj total cnt*/
                  Partxxx.partXcnt.1.1.1.1.ptcnt=subjpt /* store part tot */
                  Partxxx.partXcnt.1.1.1.1.ptcnt.1=j      /* word in subj */
               end
            end
         end
      end
   end

          /*****************************************************/
          /*                                                   */
          /*       Look for partnumbers in form (xx of yy)     */
          /*                                                   */
          /*****************************************************/

   if partnum=missing | parttot=missing | parttot>1 then do 
      do j=2 to words(subjline)-1 by 1          /* loop thru subject line */
         of=word(subjline,j)                      /* copy it for ease     */
         if upper(of)='OF' then do
            pn=word(subjline,j-1)
            pt=word(subjline,j+1)
            pn=translate(pn,'       ','()[]{}/') 
            pt=translate(pt,'       ','()[]{}/') 
            pn=strip(pn)
            pt=strip(pt)
            if datatype(pn,'N') & datatype(pt,'N') then do
               subjpn=strip(pn,'L','0')
               subjpt=strip(pt,'L','0')
               pncnt=pncnt+1                     /* found a subj part num */
               ptcnt=ptcnt+1                     /* found a subj total    */
               if partnum=1 then do              /* from section or begin */
                  Partone.part1cnt.1.1.0=pncnt   /* store subj part numcnt*/
                  Partone.part1cnt.1.1.pncnt=subjpn  /* store  part num   */
                  Partone.part1cnt.1.1.pncnt.1=j-1   /* which word in sub */
                  Partone.part1cnt.1.1.1.1.0=ptcnt /* store subj total cnt*/
                  Partone.part1cnt.1.1.1.1.ptcnt=subjpt /* store part tot */
                  Partone.part1cnt.1.1.1.1.ptcnt.1=j+1    /* word in subj */
               end
               else do
                  Partxxx.partXcnt.1.1.0=pncnt   /* store subj part numcnt*/
                  Partxxx.partXcnt.1.1.pncnt=subjpn  /* store  part num   */
                  Partxxx.partXcnt.1.1.pncnt.1=j-1   /* which word in sub */
                  Partxxx.partXcnt.1.1.1.1.0=ptcnt /* store subj total cnt*/
                  Partxxx.partXcnt.1.1.1.1.ptcnt=subjpt /* store part tot */
                  Partxxx.partXcnt.1.1.1.1.ptcnt.1=j+1    /* word in subj */
               end
            end
         end
      end
   end

          /*****************************************************/
          /*                                                   */
          /*       Look for partnumbers in form (xxofyy)       */
          /*                                                   */
          /*****************************************************/

   if partnum=missing | parttot=missing | parttot>1 then do 
      do j=1 to words(subjline)                 /* loop thru subject line */
         of=word(subjline,j)                      /* copy it for ease     */
         if pos('OF',upper(of))>0 then do
            pn=substr(of,1,pos('OF',upper(of)))
            pt=substr(of,pos('OF',upper(of))+2)
            pn=translate(pn,'       ','()[]{}/') 
            pt=translate(pt,'       ','()[]{}/') 
            pn=strip(pn)
            pt=strip(pt)
            if datatype(pn,'N') & datatype(pt,'N') then do
               subjpn=strip(pn,'L','0')
               subjpt=strip(pt,'L','0')
               pncnt=pncnt+1                     /* found a subj part num */
               ptcnt=ptcnt+1                     /* found a subj total    */
               if partnum=1 then do              /* from section or begin */
                  Partone.part1cnt.1.1.0=pncnt   /* store subj part numcnt*/
                  Partone.part1cnt.1.1.pncnt=subjpn  /* store  part num   */
                  Partone.part1cnt.1.1.pncnt.1=j     /* which word in sub */
                  Partone.part1cnt.1.1.1.1.0=ptcnt /* store subj total cnt*/
                  Partone.part1cnt.1.1.1.1.ptcnt=subjpt /* store part tot */
                  Partone.part1cnt.1.1.1.1.ptcnt.1=j      /* word in subj */
               end
               else do
                  Partxxx.partXcnt.1.1.0=pncnt   /* store subj part numcnt*/
                  Partxxx.partXcnt.1.1.pncnt=subjpn  /* store  part num   */
                  Partxxx.partXcnt.1.1.pncnt.1=j     /* which word in sub */
                  Partxxx.partXcnt.1.1.1.1.0=ptcnt /* store subj total cnt*/
                  Partxxx.partXcnt.1.1.1.1.ptcnt=subjpt /* store part tot */
                  Partxxx.partXcnt.1.1.1.1.ptcnt.1=j      /* word in subj */
               end
            end
         end
      end
   end
  
Return

/**************************************************************************/
/*                                                                        */
/*   Attempt to fill out part 1/y information. The assumption is that if  */
/*   the partname is in the subject and the next word is a valid xx/yy    */
/*   or 'xx of yy' form, and 'xx'=1 THEN the yy portion is probably       */
/*   correct. A person could enter an invalid /yy portion, but unlikely.  */
/*                                                                        */
/*   If we find a word that fits these conditions, store where the part   */
/*   number and total are to be found for the final subject line match    */
/*   logic.                                                               */
/*                                                                        */
/**************************************************************************/
/*     need to handle name in subject but partnums aren't after the pn    */
/*     assume if we have one and only one 1/y then it is correct.         */
/*     with or without a partname in the subject. Done -                  */
/**************************************************************************/
Phase2Files:

If Debug then Say time() 'Starting 1/y condition ...'

/*                   Files                  spart      spart              */
/* Partone.  format: Pointer.partname.sword.number.loc.total.loc.subjline */

   do j=1 to Partone.0
      if Partone.j.1=missing then iterate        /* no partname in subj.  */
      if Partone.j.1.0>0 & Partone.j.1.1.1.1.0>0 then do  
         do k=1 to Partone.j.1.0                 /* check name matches    */   
            do l=1 to Partone.j.1.1.1.1.0        /* against total matches */
               nword=Partone.j.1.k               /* word with name        */
               pword=Partone.j.1.1.l.1           /* word with part number */
               tword=Partone.j.1.1.1.1.l.1       /* word with total value */
               if pword=tword then nword=nword+1 /* an xx/yy or xxofyy    */
                              else nword=nword+3 /* an xx of yy form      */
               testpn=Partone.j.1.1.l            /* xx portion of xx/yy   */
               if nword=tword & testpn=1 then do
                  fptr=Partone.j                 /* pointer to files array*/
                  Files.fptr.1.1.1.1=Partone.j.1.1.1.1.l /* assume correct*/
                  Partone.j.1.1.1.0=l            /* entry of partnumber   */
                  Partone.j.1.1.1.1.1.0=l        /* entry of total number */
                  iterate j                      /* go on to next partone.*/ 
               end               
            end
         end
         if Partone.j.1.1.0=1  & Partone.j.1.1.1.1.0=1 then do   
            testpn=Partone.j.1.1.1            /* xx portion of xx/yy   */
            if testpn=1 then do               /* only one and it is 1/y*/
               fptr=Partone.j                 /* pointer to files array*/
               Files.fptr.1.1.1.1=Partone.j.1.1.1.1.1 /* assume correct*/
               Partone.j.1.1.1.0=1            /* entry of partnumber   */
               Partone.j.1.1.1.1.1.0=1        /* entry of total number */
            end 
         end
      end
   end

/**************************************************************************/
/*                                                                        */
/*   Big Assumption Time: If NO total has been found anywhere (section,   */
/*   mime, or subject) then ASSUME that it is a (1/1). This happens for   */
/*   a lot of files. The subject just says 'xxxx.jpg' and some text.      */
/*   The other form is a subject with 1/1 but without the part name.      */
/*   Consider these valid 1/1 parts also.                                 */
/*                                                                        */
/**************************************************************************/
Phase2Scan:

If Debug then Say time() 'Starting 1/1 Scanning  ...'

   do j=1 to Partone.0                           /* loop thru part names  */
      if Partone.j.1.1.1.1.0=missing then do     /* check all w/o a total */  
         Partone.j.1.1.1.1.0=1                   /* set as if in sub      */
         Partone.j.1.1.1.1.1=1                   /* set to value 1        */
         fptr=Partone.j                          /* pointer to files array*/
         Files.fptr.1.1.1.1=1                    /* fix in files.         */
      end
      else do                                    /* total not missing     */
         /**********************************************************/
         /* only one [1/1] in the subject, but partname is not in  */
         /* a begin line/section/etc. OR not in the subject.       */
         /*   Consider these valid 1/1 parts also.                 */
         /**********************************************************/
         if Partone.j.1.1=missing | Partone.j.1=missing then do
            if Partone.j.1.1.1.1.0=1 & Partone.j.1.1.1.1.1=1 then do
               fptr=Partone.j                    /* pointer to files array*/
               Files.fptr.1.1.1.1=1              /* fix in files.         */
            end
         end
      end
   end

Phase2ScanEnd:

/**************************************************************************/
/*                                                                        */
/*   The last group to process in Partone. are the 1/y with information   */
/*   in the subjects. We will do some comparing against the Partxxx array */
/*   to try to FIRMLY connect the xx/yy parts to the part 1/yy.           */
/*                                                                        */
/**************************************************************************/
Phase2Match:

If Debug then Say time() 'Starting 1/yy to xx/yy matching ...'

   do j=1 to Partone.0                           /* last time thru loop   */
      if Partone.j.1=missing then iterate        /* missing partname      */
      if Partone.j.1.1.1.1.0>0 then do           /* check all with totals */  
         fptr=Partone.j                          /* pointer to files      */
         if Files.fptr.1.1.1.1>1 then do         /* yep, a 1/y, not a 1/1 */
            p1match=Partone.j.1.1.1.1.1.1.1      /* subject line          */
            p1tots=Partone.j.1.1.1.1.0           /* number of tots in sub */
            pval=Partone.j.1.1.1.0  /* identified in Phase2Files as valid */
            if pval=missing then pval=Partone.j.1.1.0 /* use LAST PN      */
            offset=-1                            /* needed for shrinking  */ 
            do k=1 to Partone.j.1.1.0            /* remove xx word subj   */
               offset=offset+1                   /* for next time         */
               p1word=Partone.j.1.1.1.k          /* word to remove        */ 
               p1word=p1word-offset              /* correction factor     */ 
               p1match=delword(p1match,p1word,1) 
            end
            do m=1 to Partxxx.0                  /* now loop thru xx/yy   */
               p2match=Partxxx.m.1.1.1.1.1.1.1   /* subject line          */
               p2tots=Partxxx.m.1.1.1.1.0        /* number of tots in sub */
               if p2tots~=p1tots then iterate m  /* must be different     */
               do n=1 to p1tots                  /* compare totals        */
                 if Partone.j.1.1.1.1.n ~= Partxxx.m.1.1.1.1.n then iterate m
               end
               Xptr=Partxxx.m                    /* pointer to files array*/
               offset=-1                         /* needed for shrinking  */ 
               do k=1 to Partxxx.m.1.1.0         /* remove xx word subj   */
                  offset=offset+1                /* for next time         */
                  p1word=Partone.j.1.1.1.k       /* word to remove        */ 
                  p1word=p1word-offset           /* correction factor     */ 
                  p2match=delword(p2match,p1word,1) /* remove same here   */
               end
               if p1match=p2match then do            /* should be a match */
                  Files.Xptr.1.1=Partone.j.1         /* name from part1   */
                  Files.Xptr.1.1.1=Partxxx.m.1.1.pval
                  Files.Xptr.1.1.1.1=Partxxx.m.1.1.1.1.pval 
                  Partxxx.m.1=Partone.j.1             /* name from part1  */
               end
            end   /* matches do m=1 to Partxxx.0 */
         end   /* matches if Files.fptr.1.1>1    */
      end   /* matches if Partone.j.1.1.1.1.0>0  */
   end   /* matches do j=1 to Partone.0          */

Phase2MatchEnd:

/**************************************************************************/
/*                                                                        */
/*   The final group of files are part x/y that failed matching with a    */
/*   part 1/y. They also had no MIME or Section information available.    */
/*   Let's TRUST the subject for information IFF there is ONLY 1 partname */
/*   possible we will use it. Similarly for x/y information. IFF there is */
/*   only 1 potential partnum/parttot we will use it. If missing or mult- */
/*   iple, we give it up. Do this for the Partones also but only if B64.  */
/*                                                                        */
/**************************************************************************/
Phase2FinalTry:

If Debug then Say time() 'Starting use subject only ...'

   do j=1 to Partxxx.0                           /* last time thru loop   */
      Xptr=Partxxx.j                             /* pointer to files array*/

      /* if unknown partname AND only 1 potential name in subject - use it*/
      if Files.Xptr.1~=missing & Files.Xptr.1.1=missing then do
         pXnams=Partxxx.j.1.0                    /* numb of names in sub  */
         if pXnams=1 then do
            sword=Partxxx.j.1.1
            subject=Partxxx.j.1.1.1.1.1.1.1
            partname=word(subject,sword)
            Files.Xptr.1.1=partname
         end
      end

      /* if unknown partnum AND only 1 potential name in subject - use it*/
      if Files.Xptr.1~=missing & Files.Xptr.1.1.1=missing then do
         pXnums=Partxxx.j.1.1.0                  /* number of nums in sub */
         if pXnums=1 then Files.Xptr.1.1.1=Partxxx.j.1.1.1
      end

      /* if unknown parttot AND only 1 potential name in subject - use it*/
      if Files.Xptr.1~=missing & Files.Xptr.1.1.1.1=missing then do
         pXtots=Partxxx.j.1.1.1.1.0              /* number of tots in sub */
         if pXtots=1 then Files.Xptr.1.1.1.1=Partxxx.j.1.1.1.1.1
      end
   end

   do j=1 to Partone.0                           /* last time thru loop   */
      ptr=Partone.j                              /* pointer to files array*/

      /* if Partname missing AND B64 and only 1 potential name - use it   */
      if Files.ptr.1='64' & Files.ptr.1.1=missing then do
         pnams=Partone.j.1.0                     /* numb of names in sub  */
         if pnams=1 then do
            sword=Partone.j.1.1
            subject=Partone.j.1.1.1.1.1.1.1
            partname=word(subject,sword)
            Files.ptr.1.1=partname
         end
      end
   end

   if DumpPhase2 | Debug then do
      msg=' '
      interpret Saycmd
      msg='(DUMPPHASE2=YES) Dumping Partone array:  ("."=missing)'
      interpret Saycmd
      msg='Format: Subject-line'
      interpret Saycmd
      msg='        Files                  spart      spart'  
      interpret saycmd
      msg='        Pointer partname sword number loc total loc'
      interpret Saycmd
      msg=left(dashes,length(msg))
      interpret Saycmd
      do j=1 to Partone.0
         msg=' '
         interpret Saycmd
         msg=Partone.j.1.1.1.1.1.1.1            /* subjline               */
         interpret Saycmd
         msg=Partone.j Partone.j.0 Partone.j.1.0 Partone.j.1.1.0 Partone.j.1.1.1.0 Partone.j.1.1.1.1.0 Partone.j.1.1.1.1.1.0 Partone.j.1.1.1.1.1.1.0
         interpret Saycmd
         kmax=max(Partone.j.1.0,Partone.j.1.1.0,Partone.j.1.1.1.1.0)  
         do k=1 to kmax                         /* max depth of loops     */
            msg=Partone.j Partone.j.1
            msg=msg||' '||Partone.j.1.k
            msg=msg||' '||Partone.j.1.1.k
            msg=msg||' '||Partone.j.1.1.k.1
            msg=msg||' '||Partone.j.1.1.1.1.k
            msg=msg||' '||Partone.j.1.1.1.1.k.1
            interpret Saycmd
         end
      end
      msg=' '
      interpret Saycmd

      msg=' '
      interpret Saycmd
      msg='(DUMPPHASE2=YES) Dumping Partxxx array:  ("."=missing)'
      interpret Saycmd
      msg='Format: Subject-line'
      interpret Saycmd
      msg='        Files                  spart      spart'  
      interpret saycmd
      msg='        Pointer partname sword number loc total loc'
      interpret Saycmd
      msg=left(dashes,length(msg))
      interpret Saycmd
      do j=1 to Partxxx.0
         msg=' '
         interpret Saycmd
         msg=Partxxx.j.1.1.1.1.1.1.1            /* subjline               */
         interpret Saycmd
         msg=Partxxx.j Partxxx.j.0 Partxxx.j.1.0 Partxxx.j.1.1.0 Partxxx.j.1.1.1.0 Partxxx.j.1.1.1.1.0 Partxxx.j.1.1.1.1.1.0 Partxxx.j.1.1.1.1.1.1.0
         interpret Saycmd
         kmax=max(Partxxx.j.1.0,Partxxx.j.1.1.0,Partxxx.j.1.1.1.1.0)  
         do k=1 to kmax                         /* max depth of loops     */
            msg=Partxxx.j Partxxx.j.1
            msg=msg||' '||Partxxx.j.1.k
            msg=msg||' '||Partxxx.j.1.1.k
            msg=msg||' '||Partxxx.j.1.1.k.1
            msg=msg||' '||Partxxx.j.1.1.1.1.k
            msg=msg||' '||Partxxx.j.1.1.1.1.k.1
            interpret Saycmd
         end
      end
      msg=' '
      interpret Saycmd
   end

Return

/**************************************************************************/
/*                                                                        */
/*               Report File information in this Phase                    */
/*                                                                        */
/* Generate report of all input files for this directory at this point in */
/* the processing.                                                        */
/*                                                                        */
/* Logic: Loop thru Files array picking up the information from the other */
/* arrays as necessary.                                                   */
/*                                                                        */
/**************************************************************************/
ReportFiles:

   if ~ShowFiles then signal ReportFilesEnd
   msg=' '
   interpret Saycmd
   msg=dirlist.dirptr ' Processing: ' Files.0 'File(s)'
   interpret Saycmd   
   msg=left(dashes,length(msg))   
   interpret Saycmd   

   do rptptr=1 to files.0                     /* loop thru files array    */
      msg='Filename:' Files.rptptr               /* report name of file   */
      interpret Saycmd
      msg='Subject: ' Subjinfo.rptptr.1.1        /* report subject line   */
      interpret Saycmd

      select
         when Files.rptptr.1=missing then do 
            msg='Encoding: Not an encoded file'
            interpret Saycmd
            msg=' '
            interpret Saycmd
         end
         when Files.rptptr.1='UU' then do 
            msg='Encoding: UUencode'
            interpret Saycmd
            do pptr=1 to Files.rptptr.1.0
               msg='Name:    ' Files.rptptr.1.pptr
               interpret Saycmd
               msg='Part:    ' Files.rptptr.1.pptr.1 'of' Files.rptptr.1.pptr.1.1
               interpret Saycmd
            end
            msg=' '
            interpret Saycmd
         end
         when Files.rptptr.1='64' then do 
            msg='Encoding: Base64'
            interpret Saycmd
            do pptr=1 to Files.rptptr.1.0
               msg='Name:    ' Files.rptptr.1.pptr
               interpret Saycmd
               msg='Part:    ' Files.rptptr.1.pptr.1 'of' Files.rptptr.1.pptr.1.1
               interpret Saycmd
            end
            msg=' '
            interpret Saycmd
         end
         otherwise encoding=Files.rptptr.1       /* should never happen   */
      end
   end

ReportFilesEnd:

Return

/**************************************************************************/
/*                                                                        */
/*               Create arrays as needed for processing.                  */
/*                                                                        */
/**************************************************************************/
BuildLists:
   
   Temppart.0=0
   if Files.0>0 then do
      msg=' '
      interpret Saycmd 
   end

   errorcnt=0
   pnlen=0                                      /* length of partname     */
   fnlen=0                                      /* length of filename     */
  
   Do fptr=1 to Files.0
      filename=Files.fptr
      encode=Files.fptr.1                       /* encoding method        */
      if encode=missing then iterate            /* not encoded            */
      Do pptr=1 to Files.fptr.1.0               /* loop thru partnames    */
         partname=Files.fptr.1.pptr
         partname=translate(partname,tab,' ')   /* for names with blanks  */
         partnum =Files.fptr.1.pptr.1
         parttot =Files.fptr.1.pptr.1.1
         pnlen=max(pnlen,length(partname))      /* longest length for rpt */
         fnlen=max(fnlen,length(filename))      /* longest length for rpt */

         if partnum~=missing & parttot~=missing & partname~=missing & ,
            filename~=missing then do
               Temppart.0=1+Temppart.0
               ptr=Temppart.0
               Temppart.ptr=partname encode parttot partnum filename fptr pptr
         end
         else do
           if errorcnt=0 then do
              msg='Errors: Filename Encode Partname Partnum Parttot Pptr ("."=missing)'
              interpret saycmd
              msg=left(dashes,length(msg))
              interpret Saycmd
              errorcnt=1
           end
           msg='(E) Missing information for file:' filename encode partname partnum parttot pptr
           interpret saycmd
         end
      end
   end

   call QSORT(1, Temppart.0, Temppart)          /* put into order         */

   if DEBUG=YES then do
      msg=' '
      interpret Saycmd
       msg='Dumping Temppart array:'
       interpret saycmd
       msg=left(dashes,length(msg))
       interpret Saycmd
       do j=1 to Temppart.0
          msg=Temppart.j
          interpret Saycmd
       end
       msg=' '
       interpret Saycmd
   end

   oldname=missing
   oldtotal=missing
   oldencode=missing
   Parts.=missing
   Parts.0=0

   do j=1 to Temppart.0
      if word(Temppart.j,1)~=oldname | word(Temppart.j,2)~=oldencode |,
         word(Temppart.j,3)~=oldtotal then do
         oldname=word(Temppart.j,1)              /* Save to old name      */         
         oldencode=word(Temppart.j,2)            /* Save to old encode    */
         oldtotal=word(Temppart.j,3)             /* Save to old total     */
         Parts.0=1+Parts.0                       /* a new partname        */
         ptr=Parts.0                             /* count it              */
         partname=word(Temppart.j,1)             /* get partname          */
         partname=translate(partname,' ',tab)    /* return blanks to name */
         Parts.ptr=partname                      /* store partname        */     
         Parts.ptr.1=word(Temppart.j,3)          /* Total Parts Expected  */
         partnum=word(Temppart.j,4)              /* part number sets slot */   
         filename=word(Temppart.j,5)             /* filename              */   
         fptr=word(Temppart.j,6)                 /* pointer into Files.   */
         pptr=word(Temppart.j,7)                 /* pointer for partname  */
         Parts.ptr.1.partnum=filename            /* store it in pn slot   */
         Parts.ptr.1.partnum.1=fptr              /* pointer into Files.   */
         Parts.ptr.1.partnum.1.1=pptr            /* pointer to part info  */
         Parts.ptr.1.0=1                         /* indicate 1 part found */
      end
      else do
         partnum=word(Temppart.j,4)              /* part number sets slot */   
         filename=word(Temppart.j,5)             /* filename              */   
         fptr=word(Temppart.j,6)                 /* pointer into Files.   */
         pptr=word(Temppart.j,7)                 /* pointer for partname  */
         if Parts.ptr.1.partnum=missing then do  /* slot not already used */
            Parts.ptr.1.0=1+Parts.ptr.1.0        /* 1 more part found     */
         end  /* don't count mult. but use nth version - fixes Apple/DBL  */
         else do
            oldfptr=Parts.ptr.1.partnum.1
            oldpptr=Parts.ptr.1.partnum.1.1
            miscinfo.oldfptr.oldpptr.1.1.1.1=YES /* mark as duplicate     */
         end
         Parts.ptr.1.partnum=filename            /* put filename in it    */
         Parts.ptr.1.partnum.1=fptr              /* pointer into Files.   */
         Parts.ptr.1.partnum.1.1=pptr            /* pointer to part info  */
      end
   end

   if ~ShowParts then signal BuildListsEnd
   if  parts.0=0 then signal BuildListsEnd

   msg=' '
   interpret Saycmd
   msg='Encoded parts:'
   interpret saycmd
   msg='Output name'
   msg=overlay('xxx of yyy',msg,pnlen+5)
   msg=overlay('Input Name',msg,length(msg)+5)
   interpret saycmd
   msg=left(dashes,length(msg))
   interpret Saycmd


   do j=1 to Parts.0 
      msg=' ' 
      interpret saycmd
      do k=1 to Parts.j.1
         msg=Parts.j
         msg=overlay(k,msg,pnlen+8-length(k))
         msg=overlay('of',msg,length(msg)+2)
         msg=overlay(Parts.j.1,msg,length(msg)+2)
         tfile=right(parts.j.1.k,fnlen)
         msg=overlay(tfile,msg,length(msg)+8-length(Parts.j.1))
         interpret Saycmd
      end
   end
   msg=' '
   interpret Saycmd

BuildListsEnd:

Return

/**************************************************************************/
/*                                                                        */
/*                       Finally do the Decoding.                         */
/*             Strip ALL PATH information prior to decoding.              */
/**************************************************************************/
DecodeFiles:

   if verbose then say time() 'Starting Decoding ...' 

   pragma('D',dest)                    /* change directory to destination */
   curdir=pragma('D')                  /* check to make sure changed      */


   if ShowDecode & parts.0 > 0 then do
      msg=' '
      interpret Saycmd
      msg='Decoding to Directory ... 'curdir
      interpret Saycmd
      msg=left(dashes,length(msg))
      interpret Saycmd
      msg=' '
      interpret Saycmd
   end

   do i=1 to parts.0                       /* loop thru all output files  */
      if parts.i.1=parts.i.1.0 then do     /* we have all necessary parts */
         Filesptr=parts.i.1.1.1            /* pointer into Files array    */
         Pptr=parts.i.1.1.1.1              /* pointer to part within file */
         encode=Files.filesptr.1           /* type of encoding            */
         partname=parts.i                  /* get partname for decoding   */
         if pos('/',partname)>0 then do    /* strip path information      */
            partname=substr(partname,lastpos('/',partname)+1)
         end
         else do
            if pos(':',partname)>0 then do 
               partname=substr(partname,lastpos(':',partname)+1)
            end
         end         
         msg=partname                      /* name of output file         */
         filestr=''                        /* init to null on new partname*/  
         if encode='UU' then msgenc='UU  decoding from -'
                        else msgenc='B64 decoding from -' 
         msg=overlay(msgenc,msg,pnlen+3)

         if replace=NO then do             /* check replace output file   */
            if exists(partname) then do     /* already exists              */
               if Miscinfo.Filesptr.pptr.1=missing then do /* decode~=YES */
                  filestr=''               /* init to null for file list  */
                  do k=1 to parts.i.1      /* build list of files skipped */  
                     tfile=right(parts.i.1.k,fnlen)
                     tfptr=parts.i.k.1.1   /* file pointer for this part  */
                     tpptr=parts.i.k.1.1.1
                     Miscinfo.tfptr.tpptr.1.1.1.1=YES /* duplicate output */ 
                     if filestr='' then filestr=tfile
                                   else filestr=filestr||' '||tfile
                  end  
                  msg=partname              /* reset to just partname      */
                  msg=overlay('exists; skipping  -',msg,pnlen+3)
                  msg=overlay(Filestr,msg,length(msg)+3)
                  if ShowDecode then interpret SayCmd
                  iterate i
               end
               else do  /* we decoded it as part of another partname      */
                  filestr=parts.i.1.1      /* should be 1/1 of another    */
say 'Hit else do in REPLACE=NO of decodefiles: for ' filestr files.filesptr
                  Call IssueDecodeMsg
                  Call FileNoteOut
                  iterate i
               end
            end
         end

         Call BldDecodeStr

         If encode='UU' then Call DecodeUUFiles
                        else Call Decode64Files

      end   /* matches parts.i.1=parts.i.1.0 */
   end   /* matches do i=1 to parts.0 */

/**************************************************************************/
/*                                                                        */
/*   Handle DELETEAFTER and DELETEDUPS options.                           */
/*                                                                        */
/*   Delete any decoded files and any duplicates, but only IF  no errors  */
/*   The CHOPPED files may have duplicate names and decoded in a single   */
/*   file and the possibility there was an error for only 1 of the pieces.*/
/*                                                                        */
/*   The files that weren't chopped only need to be checked if delete     */
/*   duplicates was specified. If so then the dup flag is set in Miscinfo.*/
/*                                                                        */
/**************************************************************************/

   do i=1 to Files.0
      deccnt=0
      dupcnt=0
      delflag=NO
      partcnt=Files.i.1.0
      if partcnt=0 then iterate i
      do j=1 to partcnt
         if Miscinfo.i.j.1=YES then deccnt=deccnt+1
         if Miscinfo.i.j.1.1.1.1=YES then dupcnt=dupcnt+1
      end
      if DeleteAfter & deccnt>0 & deccnt+dupcnt=partcnt then delflag=YES
      if DeleteDups & dupcnt=partcnt then delflag=YES
      if delflag & ~scanonly then do
         Address Command 'Delete ' DWassignIn||Files.i 'QUIET'
      end
   end

   pragma('D',progdir)                     /* change dir back to progdir  */
   curdir=pragma('D')                      /* check to make sure changed  */

   if debug then do
      msg=' '
      interpret Saycmd
      msg='Changing Directory to ... 'curdir
      interpret Saycmd
      msg=' '
      interpret Saycmd
   end

DecodeFilesEnd:

   if verbose then say time() 'Done Decoding ...' 
   
Return
   
/**************************************************************************/
/*                                                                        */
/*                Handle chopping, joining, ect. for decoding             */
/*                                                                        */
/**************************************************************************/
BldDecodeStr:

   joinstr=''                                       /* init to null       */
   chopflag=NO                                      /* no chopping done   */

   Select
      when parts.i.1=1 & Files.filesptr.1.0=1 then do /* a single 1/1 file*/
         filestr=right(parts.i.1.1,fnlen)           /* name of file       */
         filein=DWassignIN||parts.i.1.1             /* with assign path   */
         Miscinfo.Filesptr.pptr.1=YES               /* mark as decoded    */
         Call IssueDecodeMsg
      end         
      when parts.i.1=1 & Files.filesptr.1.0>1 then do
         filein=DWassignIN||parts.i.1.1             /* with assign path   */
         if Miscinfo.Filesptr.pptr.1.1.1=missing then Call ChopFile
         filestr=right(parts.i.1.1,fnlen)
         filein=DWtemp||Files.filesptr||'.'||pptr   /* build chopped name */
         Miscinfo.Filesptr.pptr.1=YES               /* mark as decoded    */
         Call IssueDecodeMsg
         chopflag=YES                            /* filein is a T:CHOPPED */
      end
      when parts.i.1>1 then do
         filestr=''
         do k=1 to parts.i.1          /* loop thru list of files required */              
            Filesptr=parts.i.1.k.1         /* pointer into Files array    */
            do j=1 to Files.Filesptr.1.0   /* mark all multi's as decoded */
               Miscinfo.Filesptr.j.1=YES   /* mark as decoded             */
            end
            tfile=right(parts.i.1.k,fnlen)
            if filestr='' then filestr=tfile
                          else filestr=filestr||' '||tfile
            joinstr=joinstr||' '||DWassignIN||parts.i.1.k
         end  /* matches do k=1 to parts.i.1 */              
         Call IssueDecodeMsg
         filein=DWtemp'DWdecode.temp' 
         Address Command 'Join ' joinstr 'AS' filein
         joinrc=rc
         if joinrc>0 then do
            say '   JOIN returned rc='joinrc 'for 'partname
            say joinstr 'AS' filein
         end
      end
      otherwise do
        say 'Found otherwise in BldDecodeStr for :'parts.i Files.filesptr
        signal BldDecodeStrEnd
      end
   End

BldDecodeStrEnd:

Return

/**************************************************************************/
/*                                                                        */
/*                Handle the UU encoded decoding.                         */
/*                                                                        */
/**************************************************************************/
DecodeUUFiles:

   if scanonly=yes then signal DecodeUUFilesEnd

   UUcmdx=UUcmd                                  /* copy for replacement  */

   do j=1 to words(UUcmdx)
      select
        when upper(word(UUcmdx,j))='%SF' then do
           wptr=wordindex(UUcmdx,j)-1
           UUcmdx=delword(UUcmdx,j,1)
           UUcmdx=insert(filein,UUcmdx,wptr,length(filein)+1,' ')
        end
        when upper(word(UUcmdx,j))='%DF' then do
           wptr=wordindex(UUcmdx,j)-1
           UUcmdx=delword(UUcmdx,j,1)
           destfile=dest||partname
           UUcmdx=insert(destfile,UUcmdx,wptr,length(destfile)+1,' ')
        end
        when upper(word(UUcmdx,j))='%SD' then do
           wptr=wordindex(UUcmdx,j)-1
           UUcmdx=delword(UUcmdx,j,1)
           UUcmdx=insert(source,UUcmdx,wptr,length(source)+1,' ')
        end
        when upper(word(UUcmdx,j))='%DD' then do
           wptr=wordindex(UUcmdx,j)-1
           UUcmdx=delword(UUcmdx,j,1)
           UUcmdx=insert(dest,UUcmdx,wptr,length(dest)+1,' ')
        end
        otherwise nop
      end
   end   

   Address Command UUcmdx 
   decrc=rc

   if decrc >= UUcmdFail then do         /* should be a CATASTROPHIC ERROR */
      say '***** FATAL ERROR LEVEL - exiting .....'
      signal Cleanup                     /* QUIT - DO NOT CONTINUE         */
   end 

   if decrc>0 then do
      msg='*** Decode returned rc='decrc 'for 'partname 'from file(s)' filestr
      interpret SayCmd   
      Miscinfo.Filesptr.pptr.1=NO                   /* DECODE had errors  */
   end

   UUOutCnt=UUOutCnt+1

   Call FileNoteOut

   if chopflag=YES then do             /* delete ALL chopped inputs always*/
      Address Command 'Delete ' filein 'QUIET'
   end 

DecodeUUFilesEnd:

Return

/**************************************************************************/
/*                                                                        */
/*                Handle the Base64 encoded decoding.                     */
/*                                                                        */
/**************************************************************************/
Decode64Files:

   if scanonly=yes then signal Decode64FilesEnd

   B64cmdx=Base64cmd                             /* copy for replacement  */

   do j=1 to words(B64cmdx)
      select
        when upper(word(B64cmdx,j))='%SF' then do
           wptr=wordindex(B64cmdx,j)-1
           B64cmdx=delword(B64cmdx,j,1)
           B64cmdx=insert(filein,B64cmdx,wptr,length(filein)+1,' ')
        end
        when upper(word(B64cmdx,j))='%DF' then do
           wptr=wordindex(B64cmdx,j)-1
           B64cmdx=delword(B64cmdx,j,1)
           destfile='"'||dest||partname||'"'
           B64cmdx=insert(destfile,B64cmdx,wptr,length(destfile)+1,' ')
        end
        when upper(word(B64cmdx,j))='%SD' then do
           wptr=wordindex(B64cmdx,j)-1
           B64cmdx=delword(B64cmdx,j,1)
           B64cmdx=insert(source,B64cmdx,wptr,length(source)+1,' ')
        end
        when upper(word(B64cmdx,j))='%DD' then do
           wptr=wordindex(B64cmdx,j)-1
           B64cmdx=delword(B64cmdx,j,1)
           B64cmdx=insert(dest,B64cmdx,wptr,length(dest)+1,' ')
        end
        otherwise nop
      end
   end   

   Address Command B64cmdx 
   decrc=rc

   if decrc>=B64cmdFail then do
      say '***** FATAL ERROR LEVEL - exiting .....'
      signal Cleanup                     /* QUIT - DO NOT CONTINUE         */
   end

   if decrc>0 then do
      msg='*** Decode returned rc='decrc 'for 'partname 'from file(s)' filestr
      interpret SayCmd   
      Miscinfo.Filesptr.pptr.1=NO                   /* DECODE had errors  */
   end

   B64OutCnt=B64OutCnt+1

   Call FileNoteOut

   if chopflag=YES then do             /* delete ALL chopped inputs always*/
      Address Command 'Delete ' filein 'QUIET'
   end 

Decode64FilesEnd:

Return

/**************************************************************************/
/*                                                                        */
/*  Chop Base64 files into pieces for decoding. Use startlines found prev.*/
/*                                                                        */
/**************************************************************************/
ChopFile:       

   goodopen=open('IN',filein,'R')
   if ~goodopen then do
      msg='(E) Error opening 'filein 'for chopping '
      interpret Saycmd
   end

   start=1                                       /* start with line 1     */

   do j=1 to Files.filesptr.1.0                  /* loop thru partnames   */

If Debug then say 'Chopping ' Files.filesptr ' into ' Files.filesptr.1.0 ' pieces'

      Miscinfo.Filesptr.j.1.1.1=YES           /* indicate file is chopped */ 

      if j=1 then start=1                        /* first entry           */
             else start=Files.filesptr.1.j.1.1.1

      if start=missing then do
         say 'Startline for ' Files.filesptr Files.filesptr.1.j 'is invalid ... exiting'
         exit
      end

      next=j+1

      if j=Files.filesptr.1.0 then stop=999999   /* last entry - no next  */
      else do
         stop=Files.filesptr.1.next.1.1.1
         if stop=missing then do
            say 'Stopline for ' Files.filesptr  Files.filesptr.1.next 'is invalid ... exiting'
            exit
         end
         stop=stop-1
      end

      if Miscinfo.Filesptr.j.1.1.1.1=missing then do
         fileout=DWtemp||Files.filesptr||'.'||j     /* build chopped name */
         goodopen=open('OUT',fileout,'W')
         if ~goodopen then do
            msg='(E) Error opening 'fileout 
            interpret Saycmd
         end
      end

If Debug then say '      Writing ... ' START STOP fileout 

      do k=start to stop                         /* read/write lines out  */
         linein=readln('IN')
         if ~eof('IN') then do
            if Miscinfo.Filesptr.j.1.1.1.1=missing then do
               result=writeln('OUT',linein)
            end 
         end 
         else do 
            k=stop                               /* EOF - quit looping    */
         end 
      end 
      if Miscinfo.Filesptr.j.1.1.1.1=missing then do
         result=close('OUT')                     /* close output file     */
      end
   end

   result=close('IN')

Return

/**************************************************************************/
/*                                                                        */
/*                    Report Decoding operations.                         */
/*                                                                        */
/**************************************************************************/
IssueDecodeMsg:

   msg=overlay(filestr,msg,length(msg)+3)
   if ShowDecode then interpret SayCmd

Return

/**************************************************************************/
/*                                                                        */
/*                Filenote output files as specified.                     */
/*                                                                        */
/* Handle escaping Amiga Special Characters. This requires an apostrophe  */
/* to be placed before #,%,? in filenames.                                */
/*                                                                        */
/**************************************************************************/
FileNoteOut:   

   foundspec=pos("'",partname)
   do while foundspec > 0
      part1=substr(partname,1,foundspec-1)
      part2=substr(partname,foundspec+1)
      partname=part1||"''"||part2
      foundspec=pos("'",part2) 
      if foundspec>0 then foundspec=foundspec+length(part1)+2
   end

   foundspec=pos("%",partname)
   do while foundspec > 0
      part1=substr(partname,1,foundspec-1)
      part2=substr(partname,foundspec+1)
      partname=part1||"''%"||part2
      foundspec=pos("%",part2) 
      if foundspec>0 then foundspec=foundspec+length(part1)+3
   end

   foundspec=pos("#",partname)
   do while foundspec > 0
      part1=substr(partname,1,foundspec-1)
      part2=substr(partname,foundspec+1)
      partname=part1||"''#"||part2
      foundspec=pos("#",part2) 
      if foundspec>0 then foundspec=foundspec+length(part1)+3
   end

   foundspec=pos("?",partname)
   do while foundspec > 0
      part1=substr(partname,1,foundspec-1)
      part2=substr(partname,foundspec+1)
      partname=part1||"''?"||part2
      foundspec=pos("?",part2) 
      if foundspec>0 then foundspec=foundspec+length(part1)+3
   end

   foundspec=pos("~",partname)
   do while foundspec > 0
      part1=substr(partname,1,foundspec-1)
      part2=substr(partname,foundspec+1)
      partname=part1||"''~"||part2
      foundspec=pos("~",part2) 
      if foundspec>0 then foundspec=foundspec+length(part1)+3
   end
  
   if filenote~='' & Miscinfo.Filesptr.pptr.1.1=missing then do
      interpret intfnote fnote
      fnotex=substr(fnotex,1,79)
      fncmd="Address Command 'Filenote "||'"'||partname||'" "'||fnotex||'"'||" '"
      interpret fncmd
      fnrc=rc
      if fnrc>0 then do
         say '   Filenote returned rc='fnrc 'for 'partname 'from 'filein
      end
      Miscinfo.Filesptr.pptr.1.1=YES             /* mark as filenoted     */
   end 

Return

/**************************************************************************/
/*                                                                        */
/*               Issue any Warning  messages we may have                  */
/*                                                                        */
/**************************************************************************/
IssueWarnings:

   if warnings.0>0 then do
      msg=' '
      interpret Saycmd
   end
   do j=1 to warnings.0
      msg=warnings.j
      interpret Saycmd
   end

Return

/**************************************************************************/
/*                                                                        */
/*               Convert Date: line in header to timestamp                */
/*                                                                        */
/**************************************************************************/
TimeStamp:

   datemsg=upper(datemsg)                       /* upper case it          */   
   if pos(',',datemsg)>0 then datemsg=substr(datemsg,pos(',',datemsg)+1)
   datemsg=strip(datemsg)    
  
   Call CalcDays

Return

/**************************************************************************/
/*                                                                        */
/*               Calculate a value for year+month+day                     */
/*                                                                        */
/**************************************************************************/
CalcDays:

   leap=0                                       /* assume not a leap year */
   year=word(datemsg,3)                         /* year portion of msg    */
   if year<100 then do                          /* fix 2 digit years      */
      sdate=date('S')                           /* yyyymmdd               */
      year=left(sdate,4)                        /* get just the yyyy part */
   end
   month=word(datemsg,2)                        /* month portion of msg   */
   day=word(datemsg,1)                          /* day portion of msg     */
   time=word(datemsg,4)                         /* time portion of msg    */
   offset=word(datemsg,5)                       /* offset from GMT        */
   parse var time hour ':' min ':' second       /* get time pieces        */
   Select
      when month='JAN' then month=0
      when month='FEB' then do        /* not worth the cycles for 2100AD  */   
         month=31
         if year//4=0 then leap=1               
      end
      when month='MAR' then month=59+leap       
      when month='APR' then month=90+leap
      when month='MAY' then month=120+leap
      when month='JUN' then month=151+leap
      when month='JUL' then month=181+leap
      when month='AUG' then month=212+leap
      when month='SEP' then month=243+leap
      when month='OCT' then month=273+leap
      when month='NOV' then month=304+leap
      when month='DEC' then month=334+leap
      otherwise do
         msg=' '
         interpret Saycmd
         msg='Date Error processing file' Files.i 
         interpret Saycmd
         msg='     ' datemsg
         interpret Saycmd
      end
   end

   days=day+month+(year*365)

Return

/**************************************************************************/
/*                                                                        */
/*               Do all of the basic initialization stuff.                */
/*                                                                        */
/**************************************************************************/
Init:

   Call ChangeDir                    /* Change to PROGDIR:                */
   Call InternalDefaults             /* init internal default values      */
   Call CmdOverrides                 /* load and test cmd line options    */
   Call ReadPrefs                    /* load and test PrefsFile options   */
   Call SetParms                     /* set values based on final options */
   Call LoadSecTab                   /* load Section: identifier info     */
   Call LoadBase64Types              /* load B64 start line indicators    */
   Call LoadBinTypes                 /* load binary types to handle       */
   Call LoadEncTypes                 /* load MIME encoding information    */
   Call EnsureLibs                   /* add necessary libs if needed      */

   if SkipFrom | DeleteFrom then Call LoadSkipFroms  /* load table        */ 

   if SkipSubject | DeleteSubject then Call LoadSkipSubjects 

   if (DumpOpts | Debug) then Call DumpOpts /* wants options list on rpt  */

   if Recursive then do                     /* Recursive=YES option       */ 
      Call Getdirs                          /* get directories            */
   end

   if (ShowDirs | Debug) then Call DumpDirs /* wants dir listing on rpt   */

Return

/**************************************************************************/
/*                                                                        */
/*     Change directory to that of this program. Ensures that we find     */
/*                        all of the files we need                        */
/*                                                                        */
/**************************************************************************/
ChangeDir:

   
   Parse UPPER source invoked results called resolved ext host
   progdir=substr(resolved,1,pos('DWDECODE',resolved)-1)
   origdir=pragma('D',progdir)

Return

/**************************************************************************/
/*                                                                        */
/*     These values are hard coded and can't be overridden                */
/*                                                                        */
/**************************************************************************/
InternalDefaults:


   YES=1                                           /* a few useful values */
   TRUE=1                                          /* a few useful values */
   ON=1                                            /* a few useful values */
   
   NO=0                                            /* a few useful values */
   FALSE=0                                         /* a few useful values */
   OFF=0                                           /* a few useful values */

   DONE=0                                          /* a few useful values */

   tab='09'x                                       /* tab character value */
   dashes=copies('-',72)              /* dashed line for report divisions */
   missing='.'                                     /* var for array init  */

   infolines=18               /* top lines of this program used for intro */
   delaymsg.0=infolines                        /* startup lines - delayed */
   do i=1 to infolines                         
      delaymsg.i=sourceline(i)
   end

   intfnote='fnotex='               /* used for creating output filenotes */ 

   SayCmd='Say msg'                 /* write messages to console not Log  */


/**************************************************************************/
/*                                                                        */
/*     These values are used if not overridden by the Prefs file          */
/*                     or as command line arguments.                      */
/*                                                                        */
/**************************************************************************/

int.0=64
int.1 ='B64cmdFail        BF     N    20'
int.2 ='Base64Cmd         BC     F    Base64Decode %SF %DF USEMINLEN > nil:'
int.3 ='Base64TypesFile   B64F   F    DWdecode.Base64.Types'
int.4 ='BinTypesFile      BTF    F    DWdecode.Binary.Types'
int.5 ='Debug             DB     B    NO'
int.6 ='DeleteAfter       DELA   B    NO'
int.7 ='DeleteDups        DELD   B    NO'
int.8 ='DeleteFrom        DELF   B    NO'
int.9 ='DeleteOld         DELO   B    NO'
int.10='DeleteSubject     DELS   B    NO'
int.11='DeleteText        DELT   B    NO'
int.12='Dest              D      F    . '
int.13='Dump64Files       D64F   B    NO'        
int.14='DumpBase64Types   D64T   B    NO'        
int.15='DumpBinTypes      DBT    B    NO'
int.16='DumpDates         DD     B    NO'        
int.17='DumpEncTypes      DET    B    NO'
int.18='DumpFiles         DF     B    NO'        
int.19='DumpFroms         DFR    B    NO'        
int.20='DumpMisc          DM     B    NO'        
int.21='DumpOpts          DO     B    NO'
int.22='DumpPhase2        DP2    B    NO'        
int.23='DumpSectionTypes  DST    B    NO'
int.24='DumpSkipFroms     DSF    B    NO'        
int.25='DumpSkipSubjects  DSS    B    NO'        
int.26='DumpSubjects      DS     B    NO'
int.27='DWassignIN        DWI    S    DW:' 
int.28='DWtemp            DWT    F    T:'
int.29='EncTypesFile      ETF    F    DWdecode.Encode.Types'
int.30='FileNote          FN     S    %LLQ2 : %SUBJECT'
int.31='KeepDays          KD     N    30'
int.32='Log               L      B    YES'
int.33='LogFile           LF     S    DWdecode.Log'
int.34='MarkOld           MO     B    YES'
int.35='MaxHeader         MH     N    25'
int.36='MinEncoded        ME     N    4'
int.37='PrefsFile         P      F    DWdecode.Prefs'
int.38='Quiet             Q      B    NO'
int.39='Recursive         REC    B    YES'
int.40='Replace           REP    B    NO' 
int.41='RunBack           RB     S    run > nil:'
int.42='ScanOnly          SO     B    NO'
int.43='ScanProg          SP     F    FlashFind'
int.44='SectionTypesFile  STF    F    DWdecode.Section.Types'
int.45='ShowDecode        SHDE   B    YES'
int.46='ShowDirs          SHDI   B    YES'
int.47='ShowFiles         SHF    B    YES'
int.48='ShowParts         SHP    B    YES'
int.49='ShowStats         SHS    B    YES'
int.50='SkipFrom          SF     B    YES'
int.51='SkipFromFile      SFF    F    DWdecode.Skip.Froms'
int.52='SkipSubject       SS     B    YES'
int.53='SkipSubjectFile   SSF    F    DWdecode.Skip.Subjects'
int.54='Source            S      F    . '
int.55='TrapAllBegs       TAB    B    NO' 
int.56='TrapAllEncs       TAE    B    NO'         
int.57='TrapAllSecs       TAS    B    NO'     
int.58='TrapNewEncs       TNE    B    YES'         
int.59='TrapNewEncsFile   TNEF   S    DWdecode.Trap.Encodes'
int.60='TrapNewSecs       TNS    B    YES'
int.61='TrapNewSecsFile   TNSF   S    DWdecode.Trap.Sections'
int.62='UUcmd             UC     F    UUout %SF BUFSIZE=150 IGNORETERMINATION USEBASENAME > nil:'
int.63='UUcmdFail         UF     N    10'
int.64='XDELETE           XD     B    NO'


   cmd.0=int.0                             /* duplicate number of entires */   

   do i=1 to int.0                         /* loop through them           */
      cmd.i    =word(int.i,1)              /* variable name in program    */
      cmd.i.1  =word(int.i,2)              /* an alias for variable name  */ 
      cmd.i.1.1=word(int.i,3)              /* type of variable B,S,T,F,N  */
      cmd.i.1.1.1=subword(int.i,4)         /* default for the variable    */
      if cmd.i.1.1='N' | cmd.i.1.1='B' then cmdstr=cmd.i||"="||cmd.i.1.1.1 
      else cmdstr=cmd.i||"='"||cmd.i.1.1.1||"'" /* build variable assign  */ 
      interpret cmdstr                     /* do it                       */
   end

   drop int.                               /* done with this array        */

Return

/**************************************************************************/
/*                                                                        */
/*           See what values are specified on the command line.           */
/*          These will override the values in the default file.           */
/*                                                                        */
/**************************************************************************/
/* Load all arguments that have '=' signs in them. Parse strings based on */
/* assuming a beginning quote (either type) and locating the ending one.  */
/* After deleting ALL xxx=yyy type pieces, the remaining ones SHOULD be   */
/* boolean switches. All of the commands will be tested based upon the    */
/* type value in the cmd. array. Strings can be anything; Files must      */
/* already exist; Booleans must be 1/0, YES/NO, ON/OFF; and Numerics must */
/* be numeric. Any that don't match a valid command or its alias are      */
/* reported as errors and we exit after all have been processed.          */
/*                                                                        */
/**************************************************************************/
/* If help requested then display internal defaults and exit.             */
/**************************************************************************/
CmdOverrides:

   if commandline='?' | upper(commandline)='-H' | upper(commandline)='HELP' then do
      do i=1 to delaymsg.0
         msg=delaymsg.i
         interpret Saycmd   
      end
      msg=' '
      interpret Saycmd
      msg='Command-Option   Alias  Internal Value'
      interpret Saycmd
      msg=left(dashes,78)
      interpret Saycmd
      do i=1 to cmd.0
         msg=cmd.i
         msg=overlay(cmd.i.1,msg,18)
         msg=overlay(cmd.i.1.1.1,msg,25)
         interpret Saycmd
      end 
      msg=' '
      interpret Saycmd
      msg='See DWDecode.Defaults.doc for complete description of options'
      interpret Saycmd
      signal cleanup
   end

   say ' '
   say time() 'Determining runtime options ...'

   cmdopt.=missing      
   cmdopt.0=0

   eqpos=pos('=',commandline)
   i=0
   quitflag=NO

   do while eqpos~=0
      cmdpart1=strip(substr(commandline,1,eqpos-1))
      cmdpart2=strip(substr(commandline,eqpos+1))
      i=i+1
      cmdopt.0=i
      cmdopt.i=word(cmdpart1,words(cmdpart1))
      cmdpart1=subword(cmdpart1,1,words(cmdpart1)-1)
      select
         when substr(cmdpart2,1,1)='"' then do
            endquote=pos('"',cmdpart2,2)
            if endquote=0 then do
               delaymsg.0=delaymsg.0 + 1
               dx=delaymsg.0
               delaymsg.dx='(E) Missing ending quote for: ' cmdopt.i
               quitflag=YES
            end
            cmdopt.i.1=substr(cmdpart2,2,endquote-2)
            cmdpart2=substr(cmdpart2,endquote+1)
         end   
         when substr(cmdpart2,1,1)="'" then do
            endquote=pos("'",cmdpart2,2)
            if endquote=0 then do
               delaymsg.0=delaymsg.0 + 1
               dx=delaymsg.0
               delaymsg.dx='(E) Missing ending quote for: ' cmdopt.i
               quitflag=YES
            end
            cmdopt.i.1=substr(cmdpart2,2,endquote-2)
            cmdpart2=substr(cmdpart2,endquote+1)
         end
         otherwise do
            cmdopt.i.1=word(cmdpart2,1)
            cmdpart2=subword(cmdpart2,2)
         end
      end
      commandline=cmdpart1||' '||cmdpart2
      eqpos=pos('=',commandline)
   end

   do j=1 to words(commandline)
      i=i+1
      cmdopt.0=i 
      cmdopt.i=word(commandline,1)
      commandline=subword(commandline,2)
   end 

   do i=1 to cmdopt.0
      matchflag=NO
      do j=1 to cmd.0
         UPO=upper(cmdopt.i)
         UPV=upper(cmdopt.i.1)
         UPC=upper(cmd.j)
         UPA=upper(cmd.j.1)
         UPT=upper(cmd.j.1.1)
         if UPO=UPC | UPO=UPA then do
            matchflag=YES
            select
               when UPT='B' then do
                  select
                     when UPV=missing then cmdopt.i.1='YES'
                     when UPV='YES'   then nop
                     when UPV='ON'    then nop
                     when UPV='TRUE'  then nop
                     when UPV='1'     then nop
                     when UPV='NO'    then nop
                     when UPV='OFF'   then nop
                     when UPV='FALSE' then nop
                     when UPV='0'     then nop
                     otherwise do
                        delaymsg.0=delaymsg.0 + 1
                        dx=delaymsg.0
                        delaymsg.dx='(E) Invalid value for 'UPC 'must be YES/NO'
                        quitflag=YES
                     end
                  end
               end
               when UPT='N' then do
                  if verify(UPV,'0123456789')~=0 then do
                     say '(E) Invalid value for 'UPC 'must be numeric'
                     quitflag=YES
                  end
               end
               otherwise nop
            end 
            cmdopt.i=cmd.j                     /* store real variable name   */
            cmdopt.i.1.1=cmd.j.1.1             /* store variable type        */
            leave j
         end
      end
      if ~matchflag then do
         delaymsg.0=delaymsg.0 + 1
         dx=delaymsg.0
         delaymsg.dx='(E) Unrecognized argument: 'UPO'. See Documentation.'
         quitflag=YES
      end 
   end

/**************************************************************************/
/* Set values from command line, will have to do it again, after values   */
/* are set from PrefsFile. Makes it easier to use cmdline options early.  */
/**************************************************************************/
   do i=1 to cmdopt.0                      /* loop through them           */
      if cmdopt.i.1.1='N' | cmdopt.i.1.1='B' then cmdstr=cmdopt.i||"="||cmdopt.i.1 
      else cmdstr=cmdopt.i||"='"||cmdopt.i.1||"'"   /* build var assign   */ 
      interpret cmdstr                     /* do it                       */
   end

Return

/**************************************************************************/
/*                                                                        */
/*            Read in the information from the Prefs file                 */
/*                                                                        */
/**************************************************************************/
ReadPrefs:

   pcmd.=missing
   i=0

   goodopen=open('Prefs',PrefsFile,'R')
   if ~goodopen then do
      delaymsg.0=delaymsg.0 + 1
      dx=delaymsg.0
      delaymsg.dx='(W) Prefs file not found - using command options & internal values'
   end
   else do
      delaymsg.0=delaymsg.0 + 1
      dx=delaymsg.0
      delaymsg.dx='Using PrefsFile:         ' PrefsFile
      do until eof('Prefs')
         default=readln('Prefs')
         if default~=' ' & default~='#' & default~='' then do
            if pos('#',default)~=1 then do
               if pos('#',default)>2 then do
                  default=substr(default,1,pos('#',default)-1)
               end
               default=strip(default)
               select
                  when pos('=',default)>0 then do
                     i=i+1
                     pcmd.i=substr(default,1,pos('=',default)-1)
                     pval=substr(default,pos('=',default)+1)
                     pval=strip(pval,'B',"'") 
                     pval=strip(pval,'B','"') 
                     pcmd.i.1=pval
                  end
                  when words(default)=1 then do
                     i=i+1
                     pcmd.i=default
                     pcmd.i.1='YES'
                  end 
                  otherwise do
                     delaymsg.0=1+delaymsg.0 
                     dx=delaymsg.0
                     delaymsg.dx='(E) Missing "=" in PrefsFile line: 'default
                     quitflag=YES
                  end 
               end
            end
         end
      end
   end

   result=close('Prefs')

   pcmd.0=i                               /* number of PrefsFile options  */

/**************************************************************************/
/*         Validate options set in the Preferences file.                  */
/**************************************************************************/

   do i=1 to pcmd.0
      matchflag=NO
      do j=1 to cmd.0
         UPO=upper(pcmd.i)
         UPV=upper(pcmd.i.1)
         UPC=upper(cmd.j)
         UPA=upper(cmd.j.1)
         UPT=upper(cmd.j.1.1)
         if UPO=UPC | UPO=UPA then do
            matchflag=YES
            select
               when UPT='B' then do
                  select
                     when UPV=missing then pcmd.i.1='YES'
                     when UPV='YES'   then nop
                     when UPV='ON'    then nop
                     when UPV='TRUE'  then nop
                     when UPV='1'     then nop
                     when UPV='NO'    then nop
                     when UPV='OFF'   then nop
                     when UPV='FALSE' then nop
                     when UPV='0'     then nop
                     otherwise do
                        delaymsg.0=delaymsg.0 + 1
                        dx=delaymsg.0
                        delaymsg.dx='(E) Invalid value for 'UPC 'must be YES/NO'
                        quitflag=YES
                     end
                  end
               end
               when UPT='N' then do
                  if verify(UPV,'0123456789')~=0 then do
                     say '(E) Invalid value for 'UPC 'must be numeric'
                     quitflag=YES
                  end
               end
               otherwise nop
            end 
            pcmd.i=cmd.j                        /* store real variable name   */
            pcmd.i.1.1=cmd.j.1.1                /* store variable type        */
            leave j
         end
      end
      if ~matchflag then do
         delaymsg.0=delaymsg.0 + 1
         dx=delaymsg.0
         delaymsg.dx='(E) Unrecognized argument: 'UPO'. See Documentation.'
         quitflag=YES
      end 
   end

   do i=1 to pcmd.0                        /* loop through them           */
      if pcmd.i.1.1='N' | pcmd.i.1.1='B' then cmdstr=pcmd.i||"="||pcmd.i.1 
      else cmdstr=pcmd.i||"='"||pcmd.i.1||"'"   /* build variable assign  */ 
      interpret cmdstr                     /* do it                       */
   end

   drop pcmd.                                   /* done with this array   */

/**************************************************************************/
/*         Set values from command line for final time.                   */
/**************************************************************************/

   do i=1 to cmdopt.0                      /* loop through them           */
      if cmdopt.i.1.1='N' | cmdopt.i.1.1='B' then cmdstr=cmdopt.i||"="||cmdopt.i.1 
      else cmdstr=cmdopt.i||"='"||cmdopt.i.1||"'"   /* build var assign   */ 
      interpret cmdstr                     /* do it                       */
   end

   drop cmdopt.                                 /* done with this array   */
 
   if DEBUG=YES then QUIET=NO             /* turn on all messages         */
   if QUIET=NO then VERBOSE=YES           /* Make into a positive remark  */
               else VERBOSE=NO

   if verbose then say time() 'Verifying existence of files ...'

   do i=1 to cmd.0                        /* loop thru validating files   */
      if cmd.i.1.1='F' then do
         tstr='tfile=word('||cmd.i||',1)'
         interpret tstr
         if ~exists(tfile) then do 
            delaymsg.0=delaymsg.0 + 1
            dx=delaymsg.0
            delaymsg.dx='(E) File' tfile 'does not exist '  
            quitflag=YES
         end
      end
   end

   if Log=YES then do
      Saycmd="result=writeln('LOG',msg)"
      goodopen=open('LOG',logfile,'W')
      if ~goodopen then do
         delaymsg.0=1+delaymsg.0 
         dx=delaymsg.0
         delaymsg.dx='(E) Unable to open logfile:' logfile
         delaymsg.0=1+delaymsg.0
         dx=delaymsg.0
         delaymsg.dx='Continuing without logfile. Messages displaying on console'
         SayCmd='Say msg'
      end
   end

   do i=1 to delaymsg.0
      msg=delaymsg.i
      interpret Saycmd   
   end

   drop delaymsg.                               /* done with this array   */

   if quitflag then do                          /* command/prefs error(s) */  
      exit 20
   end

Return

/**************************************************************************/
/*                                                                        */
/*           Adjust options based on final values of variables            */
/*                                                                        */
/**************************************************************************/
SetParms:

   if Source='' then do
      msg='(E) SOURCE directory is a REQUIRED parameter. See documentation.'
      interpret Saycmd
      exit
   end
   if Dest='' then do
      msg='(E) DEST directory is a REQUIRED parameter. See documentation.'
      interpret Saycmd
      exit
   end

   dircnt=1                                  /* next directory to process */
   dirlist.0=1                                   /* one directory for now */
   if right(dest,1)~='/' & right(dest,1)~=':' then dest=dest||'/'
   if right(source,1)~='/' & right(source,1)~=':' then source=source||'/'
   dirlist.1=source                     /* the original source directory  */

   if MarkOld | DeleteOld then do               /* need a value for today */
      datemsg= date() ' ' time() ' +900'        /* build a fake Date:     */
      datemsg=upper(datemsg)                    /* force to upper for rtn */         
      Call CalcDays
      today=days
      if KeepDays<1 then do
         msg='(W) KeepDays less than 1. Forcing to KEEPDAYS=30'
         interpret Saycmd
         KeepDays=30
      end
   end 

   if XDELETE then do                          /* turn on ALL delete opts */
      DeleteAfter   =YES
      DeleteDups    =YES
      DeleteFrom    =YES
      DeleteOld     =YES
      DeleteSubject =YES
      DeleteText    =YES
   end

Return

/**************************************************************************/
/*                                                                        */
/*                           Load SECTION table                           */
/*                                                                        */
/*  Load tables for parsing partname, partnum information from external   */
/*  tables. Descriptions are in each and each is required.                */
/*                                                                        */
/**************************************************************************/
LoadSecTab:

   goodopen=open('SecTables',SectionTypesFile,'R')
   if ~goodopen then do
      msg='(E) Required file ('SectionTypesFile') not found. See documentation.'
      interpret Saycmd
      exit
   end
   msg='Using Section Types File:' SectionTypesFile
   if ~DEBUG & ~DUMPOPTS then interpret Saycmd
   i=0                                           /* array pointer         */
   do until eof('SecTables')
      SecTable=readln('SecTables')
      if SecTable~=' ' & SecTable~='#' & SecTable~='' then do
         if pos('#',SecTable) ~= 1 then do
            if pos('#',SecTable)>1 then do
               SecTable=substr(SecTable,1,pos('#',SecTable)-1)
            end
            SecTable=strip(SecTable)
            i=i+1                                /* bump array pointer    */
            j=word(SecTable,1)                   /* number of keys present*/
            Sectiontypes.i=j                     /* load array with value */
            l=2                                  /* first key portion     */
            do k=1 to j                          /* loop thru pairs       */
              Sectiontypes.i.k=word(SecTable,l)       /* key portion      */
              Sectiontypes.i.k.k=word(SecTable,l+1)   /* key location     */
              l=l+2                                   /* set to next pair */
            end
            Sectiontypes.i.1.1.1=word(SecTable,l)      /* part number     */ 
            Sectiontypes.i.1.1.1.1=word(SecTable,l+1)   /* total parts    */
            Sectiontypes.i.1.1.1.1.1=word(SecTable,l+2)  /* filename      */
            Sectiontypes.i.1.1.1.1.1.1=word(SecTable,l+3) /* sep. char.   */
         end
      end
   end

   Sectiontypes.0=i                              /* num in section table */
   result=close('SecTables')

Return

/**************************************************************************/
/*                                                                        */
/*        Get the different start line indicators for Base64 files.       */
/*                                                                        */
/**************************************************************************/
LoadBase64Types:

   goodopen=open('Base64Types',Base64TypesFile,'R')
   if ~goodopen then do
      msg='(E) Required file ('Base64TypesFile') not found. See documentation.'
      interpret Saycmd
      exit
   end
   msg='Using Base64 Types File: ' Base64TypesFile
   if ~DEBUG & ~DUMPOPTS then interpret Saycmd
   i=0
   do until eof('Base64Types')
      Base64type=readln('Base64Types')
      Base64type=strip(Base64type)
      if substr(Base64type,1,1)='#' | Base64type='' | Base64type=' ' then nop
      else do
         if pos('#',Base64type)>1 then do
            Base64type=substr(Base64type,1,pos('#',Base64type)-1)
            Base64type=strip(Base64type)
         end
         i=i+1
         Base64Types.i=Base64Type
      end
   end
   Base64Types.0=i

   result=close('Base64Types')

Return

/**************************************************************************/
/*                                                                        */
/*        Get the types of file extensions we're to try to handle         */
/*                                                                        */
/**************************************************************************/
LoadBinTypes:

   goodopen=open('BinTypes',BinTypesFile,'R')
   if ~goodopen then do
      msg='(E) Required file ('BinTypesFile') not found. See documentation.'
      interpret Saycmd
      exit
   end
   msg='Using Binary Types File: ' BinTypesFile
   if ~DEBUG & ~DUMPOPTS then interpret Saycmd
   i=0
   do until eof('BinTypes')
      bintype=readln('BinTypes')
      bintype=strip(bintype)
      if substr(bintype,1,1)='#' | bintype='' | bintype=' ' then nop
      else do
         if pos('#',bintype)>1 then do
            bintype=substr(bintype,1,pos('#',bintype)-1)
            bintype=strip(bintype)
         end
         i=i+1
         Bintypes.i=upper(bintype)
      end
   end
   Bintypes.0=i

   result=close('BinTypes')

Return

/**************************************************************************/
/*                                                                        */
/*     Get the MIME encoding types that are known and which they are      */
/*                                                                        */
/**************************************************************************/
LoadEncTypes:

   goodopen=open('EncTypes',EncTypesFile,'R')
   if ~goodopen then do
      msg='(E) Required file ('EncTypesFile') not found. See documentation.'
      interpret Saycmd
      exit
   end
   msg='Using Encode Types File: ' EncTypesFile
   if ~DEBUG & ~DUMPOPTS then interpret Saycmd
   i=0
   do until eof('EncTypes')
      enctype=readln('EncTypes')
      enctype=strip(enctype)
      if substr(enctype,1,1)='#' | enctype='' | enctype=' ' then nop
      else do
         if pos('#',enctype)>1 then do
            enctype=substr(enctype,1,pos('#',enctype)-1)
            enctype=strip(enctype)
         end
         i=i+1
         Enctypes.i=upper(word(enctype,1))
         if words(enctype)>1 then Enctypes.i.1=upper(word(enctype,2))
                             else Enctypes.i.1=missing
      end
   end
   Enctypes.0=i

   result=close('EncTypes')

Return

/**************************************************************************/
/*                                                                        */
/*        Load list of users in From: lines to SKIP                       */
/*                                                                        */
/**************************************************************************/
LoadSkipFroms:       

   goodopen=open('SkipFroms',SkipFromFile,'R')
   if ~goodopen then do
      msg=' '
      interpret Saycmd
      msg='(E) Unable to open SkipFromFile "'SkipFromFile'"' 
      interpret Saycmd
      msg='    Setting DELETEFROM=NO SKIPFROM=NO DUMPSKIPFROMS=NO'
      interpret Saycmd
      SkipFrom=NO
      DeleteFrom=NO
      DumpSkipFroms=NO
   end
   else do
      msg='Using SkipFromFile:      ' SkipFromFile   
      if ~DEBUG & ~DUMPOPTS then interpret Saycmd
   end
   i=0
   if goodopen then do until eof('SkipFroms')
      skipuser=readln('SkipFroms')
      skipuser=strip(skipuser)

      if substr(skipuser,1,1)='#' | skipuser='' | skipuser=' ' then nop
      else do
         i=i+1
         SkipFroms.i=skipuser
      end
   end
   SkipFroms.0=i 

   result=close('SkipFroms')

Return

/**************************************************************************/
/*                                                                        */
/*        Load list of words in Subject: lines to SKIP                    */
/*                                                                        */
/**************************************************************************/
LoadSkipSubjects:       

   goodopen=open('SkipSubjects',SkipSubjectFile,'R')
   if ~goodopen then do
      msg=' '
      interpret Saycmd
      msg='(E) Unable to open SkipSubjectFile "'SkipSubjectFile'"' 
      interpret Saycmd
      msg='    Setting DELETESUBJECT=NO SKIPSUBJECT=NO DUMPSKIPSUBJECTS=NO'
      interpret Saycmd
      SkipSubject=NO
      DeleteSubject=NO
      DumpSkipSubjects=NO
   end
   else do
      msg='Using SkipSubjectFile:   ' SkipSubjectFile   
      if ~DEBUG & ~DUMPOPTS then interpret Saycmd
   end
   i=0
   if goodopen then do until eof('SkipSubjects')
      skipuser=readln('SkipSubjects')
      skipuser=strip(skipuser)

      if substr(skipuser,1,1)='#' | skipuser='' | skipuser=' ' then nop
      else do
         i=i+1
         SkipSubjects.i=skipuser
      end
   end
   SkipSubjects.0=i 

   result=close('SkipSubjects')

Return

/**************************************************************************/
/*                                                                        */
/*              Make sure that we have all the libs we need:              */
/*                               RexxArpLib                               */
/*                               QuickSort                                */
/*                                                                        */
/**************************************************************************/
EnsureLibs:

   if ~show('L','rexxarplib.library') then do
      call addlib('rexxarplib.library',0,-30)
   end

   if ~showlist('p','QuickSortPort') then do
      address command runback " quicksort"
      do i = 1 to 10
         if ~showlist('p','QuickSortPort') then call delay 20
         else leave i
      end
   end
   if showlist('p','QuickSortPort') then do
      call addlib('QuickSortPort',-30)
   end
   else do
      msg='(E) Unable to find QuickSort -- check installation instructions'
      interpret Saycmd
   end

Return


/**************************************************************************/
/*                                                                        */
/*          Read Source Directory for list directories to process         */
/*                                                                        */
/* force '/' onto source if not present and not a volume or assign        */
/*                                                                        */
/**************************************************************************/
GetDirs:

   tempdirs.=missing
   tempdirs.0 = FILELIST(source||'*',tempdirs,"D","E")

   do i=1 to tempdirs.0
      dirlist.0=1+dirlist.0
      dirptr=dirlist.0
      dirlist.dirptr=tempdirs.i||'/'      
   end

   dircnt=dircnt+1                               /* next dir to process   */

   if dircnt>dirlist.0 then DONE=YES

   do while ~DONE
      source=dirlist.dircnt                      /* directory to look thru*/
      call GetDirs                 /* Recursive Call to this same routine */ 
   end

   call QSORT(1, dirlist.0, dirlist)            /* sort into pretty order */

Return


/**************************************************************************/
/*                                                                        */
/*           Various routines called for debugging/trace options          */
/*                                                                        */
/**************************************************************************/
DumpArrays:

   if (DumpFiles | Debug) & Files.0 > 0 then call DumpFiles
   if (DumpMisc  | Debug) & Files.0 > 0 then call DumpMiscinfo
   if (DumpFroms | Debug) & Files.0 > 0 then call DumpFrominfo
   if (DumpSubjects | Debug) & Files.0 > 0 then call DumpSubjinfo
   if (DumpDates | Debug) & Files.0 > 0 then call DumpDateinfo 
   if (TrapAllBegs | Debug) & AllBegins.0 > 0 then call DumpBegins
   if (TrapAllEncs | Debug) & AllEncodes.0 > 0 then call DumpEncodes
   if (TrapAllSecs | Debug) & Allsections.0 > 0 then call DumpSections

                        /************************/
                        /*                      */
                        /* Dump these only once */
                        /*        at end        */
                        /************************/

if dirptr=dirlist.0 then do
   if (DumpBinTypes | Debug) & BinTypes.0 > 0 then call DumpBinTypes
   if (DumpBase64Types | Debug) & Base64Types.0 > 0 then call DumpBase64Types
   if (DumpEncTypes | Debug) & EncTypes.0 > 0 then call DumpEncTypes
   if (DumpSectionTypes | Debug) & SectionTypes.0 > 0 then call DumpSectionTypes
   if (DumpSkipFroms | Debug) & SkipFroms.0 > 0 then call DumpSkipFroms
   if (DumpSkipSubjects | Debug) & SkipSubjects.0 > 0 then call DumpSkipSubjects
end

Return

/**************************************************************************/
/*                                                                        */
/*              Dumps array used for directories on Recursive             */
/*                                                                        */
/**************************************************************************/
DumpDirs: 

   msg=' '
   interpret Saycmd
   if dirlist.0=1 then msg=dirlist.0 ' Directory found'
      else msg=dirlist.0 ' Directories found'
   interpret Saycmd
   msg=left(dashes,length(msg))
   interpret Saycmd
   do j=1 to dirlist.0                             /* dump dir list array */
      msg=dirlist.j
      interpret Saycmd
   end
   msg=' '
   interpret Saycmd
   
Return

/**************************************************************************/
/*                   Dumps Files. array for all partnames.                */
/**************************************************************************/
/*               (0)=cnt             (0)=cnt                              */
/* Files. format: filename.encodetype.partname.partnum.parttot.startline  */
/*                        .encodetype.partname.partnum.parttot.startline  */
/**************************************************************************/
DumpFiles:

   msg=' '
   interpret Saycmd
   msg='(DUMPFILES=YES)' Files.0 ' File(s)'
   interpret Saycmd
   msg='Format: Subject line'
   interpret saycmd
   msg='        Filename Encodetype Partname Partnum Parttot Startline ("."=missing)' 
   interpret saycmd
   msg=left(dashes,length(msg))
   interpret Saycmd

   do i=1 to Files.0   
      msg= Subjinfo.i.1.1
      interpret Saycmd
      msg=i Files.i.0 Files.i.1.0 Files.i.1.1.0 Files.i.1.1.1.0 Files.i.1.1.1.1.0
      interpret Saycmd
      if Files.i.1.0=0 then do
         msg=Files.i Files.i.1 Files.i.1.1 Files.i.1.1.1 Files.i.1.1.1.1 Files.i.1.1.1.1.1
         interpret Saycmd
      end
      else do 
         do j=1 to Files.i.1.0
         msg=Files.i Files.i.1 Files.i.1.j Files.i.1.j.1 Files.i.1.j.1.1 Files.i.1.j.1.1.1
         interpret Saycmd
         end
      end
      msg=' '
      interpret Saycmd
   end

Return

/**************************************************************************/
/*                   Dumps Miscinfo array for all entries.                */
/**************************************************************************/
/* Miscinfo. format: filename.mimetype.decoded.filenoted.chopped.dupfile  */
/**************************************************************************/
DumpMiscInfo:

   msg=' '
   interpret Saycmd
   msg='(DUMPMISC=YES)' Files.0 ' File(s)'
   interpret Saycmd
   msg='format: FPtr Filename Mimetype Decoded Filenoted Chopped Dupfile ("."=missing)' 
   interpret saycmd
   msg=left(dashes,length(msg))
   interpret Saycmd
   do i=1 to Files.0   
      if Files.i.1.0=0 then do
         msg=i Files.i
         msg=msg||' '||Miscinfo.i.1 
         msg=msg||' '||Miscinfo.i.1.1
         msg=msg||' '||Miscinfo.i.1.1.1
         msg=msg||' '||Miscinfo.i.1.1.1.1
         msg=msg||' '||Miscinfo.i.1.1.1.1.1
         interpret Saycmd
      end
      else do 
         do j=1 to Files.i.1.0
            msg=i Files.i
            msg=msg||' '||Miscinfo.i.j 
            msg=msg||' '||Miscinfo.i.j.1
            msg=msg||' '||Miscinfo.i.j.1.1
            msg=msg||' '||Miscinfo.i.j.1.1.1
            msg=msg||' '||Miscinfo.i.j.1.1.1.1
            interpret Saycmd
         end
      end
      msg=' '
      interpret Saycmd
   end

Return

/**************************************************************************/
/*                                                                        */
/*                  Dumps array used for From lines                       */
/*                                                                        */
/**************************************************************************/
DumpFrominfo:

   msg=' '
   interpret Saycmd
   msg='(DUMPFROMS=YES)' 
   interpret Saycmd
   msg='Format: Filename SkipFlag DeleteFlag FromLine (0=No 1=Yes)'
   interpret saycmd
   msg=left(dashes,length(msg))
   interpret Saycmd
   do j=1 to Files.0                              /* dump Frominfo array */
      msg=Files.j '  ' Frominfo.j Frominfo.j.1 Frominfo.j.1.1
      interpret Saycmd
   end
   msg=' '
   interpret Saycmd

Return

/**************************************************************************/
/*                                                                        */
/*                  Dumps array used for Subject lines                    */
/*                                                                        */
/**************************************************************************/
DumpSubjinfo:

   msg=' '
   interpret Saycmd
   msg='(DUMPSUBJECTS=YES)' 
   interpret Saycmd
   msg='Format: Filename SkipFlag DeleteFlag SubjectLine (0=No 1=Yes)'
   interpret saycmd
   msg=left(dashes,length(msg))
   interpret Saycmd
   do j=1 to Files.0                              /* dump Subjinfo array */
      msg=Files.j '  ' Subjinfo.j Subjinfo.j.1 Subjinfo.j.1.1
      interpret Saycmd
   end
   msg=' '
   interpret Saycmd

Return

/**************************************************************************/
/*                                                                        */
/*                  Dumps array used for Date lines                       */
/*                                                                        */
/**************************************************************************/
DumpDateinfo:

   msg=' '
   interpret Saycmd
   msg='(DUMPDATES=YES)' 
   interpret Saycmd
   msg='Format: Filename SkipFlag DeleteFlag DateLine (0=No 1=Yes)'
   interpret saycmd
   msg=left(dashes,length(msg))
   interpret Saycmd
   do j=1 to Files.0                              /* dump Dateinfo array */
      msg=Files.j '  ' Dateinfo.j Dateinfo.j.1 Dateinfo.j.1.1
      interpret Saycmd
   end
   msg=' '
   interpret Saycmd

Return

/**************************************************************************/
/*                                                                        */
/*                  Dumps array used for determining BinTypes             */
/*                                                                        */
/**************************************************************************/
DumpBinTypes:

   msg=' '
   interpret Saycmd
   msg='(DUMPBINTYPES=YES)' 
   interpret Saycmd
   msg=BinTypes.0 ' binary types found in:' BinTypesFile
   interpret Saycmd
   msg=left(dashes,length(msg))
   interpret Saycmd
   do j=1 to BinTypes.0                          /* dump BinType array */
      msg=BinTypes.j
      interpret Saycmd
   end
   msg=' '
   interpret Saycmd

Return

/**************************************************************************/
/*                                                                        */
/*                  Dumps array used for determining EncTypes             */
/*                                                                        */
/**************************************************************************/
DumpEncTypes:

   msg=' '
   interpret Saycmd
   msg='(DUMPENCTYPES=YES)' 
   interpret Saycmd
   msg=EncTypes.0 ' Encode types found in:' EncTypesFile
   interpret Saycmd
   msg=left(dashes,length(msg))
   interpret Saycmd
   do j=1 to EncTypes.0                          /* dump Encode  array */
      msg=EncTypes.j EncTypes.j.1
      interpret Saycmd
   end
   msg=' '
   interpret Saycmd

Return

/**************************************************************************/
/*                                                                        */
/*               Dumps array used for determining Base64Types             */
/*                                                                        */
/**************************************************************************/
DumpBase64Types:

   msg=' '
   interpret Saycmd
   msg='(DUMPBASE64TYPES=YES)' 
   interpret Saycmd
   msg=Base64Types.0 ' Base64 types found in:' Base64TypesFile
   interpret Saycmd
   msg=left(dashes,length(msg))
   interpret Saycmd
   do j=1 to Base64Types.0                          /* dump Base64Type array */
      msg=Base64Types.j
      interpret Saycmd
   end
   msg=' '
   interpret Saycmd

Return

/**************************************************************************/
/*                                                                        */
/*                  Dumps array used for Section Line info                */
/*                                                                        */
/**************************************************************************/
DumpSectionTypes:

   msg=' '
   interpret Saycmd
   msg='(DUMPSECTIONTYPES=YES)' 
   interpret Saycmd
   msg=SectionTypes.0 ' section types found in:' SectionTypesFile
   interpret Saycmd
   msg=left(dashes,length(msg))
   interpret Saycmd
   do j=1 to SectionTypes.0                     /* dump SectionType array */
      msg=SectionTypes.j 
      do k=1 to SectionTypes.j
         msg=msg||' '||SectionTypes.j.k SectionTypes.j.k.k
      end
      msg=msg||' '||SectionTypes.j.1.1.1 SectionTypes.j.1.1.1.1 SectionTypes.j.1.1.1.1.1 SectionTypes.j.1.1.1.1.1.1
      interpret Saycmd
   end
   msg=' '
   interpret Saycmd

Return

/**************************************************************************/
/*                                                                        */
/*                Dumps array used for determining SkipFrom               */
/*                                                                        */
/**************************************************************************/
DumpSkipFroms:

   msg=' '
   interpret Saycmd
   msg='(DUMPSKIPFROMS=YES)' 
   interpret Saycmd
   msg=SkipFroms.0 ' userids in SkipFromFile:' SkipFromFile
   interpret Saycmd
   msg=left(dashes,length(msg))
   interpret Saycmd
   do j=1 to SkipFroms.0                          /* dump SkipFrom array */
      msg=SkipFroms.j
      interpret Saycmd
   end
   msg=' '
   interpret Saycmd

Return

/**************************************************************************/
/*                                                                        */
/*              Dumps array used for determining SkipSubject              */
/*                                                                        */
/**************************************************************************/
DumpSkipSubjects:

   msg=' '
   interpret Saycmd
   msg='(DUMPSKIPSUBJECTS=YES)' 
   interpret Saycmd
   msg=SkipSubjects.0 ' keys in SkipSubjectFile:' SkipSubjectFile
   interpret Saycmd
   msg=left(dashes,length(msg))
   interpret Saycmd
   do j=1 to SkipSubjects.0                    /* dump SkipSubject array */
      msg=SkipSubjects.j
      interpret Saycmd
   end
   msg=' '
   interpret Saycmd

Return

/**************************************************************************/
/*                                                                        */
/*                  Dumps array used for lines with 'BEGIN'               */
/*                                                                        */
/**************************************************************************/
DumpBegins:

   msg=' '
   interpret Saycmd
   msg='(TRAPALLBEGS=YES)' 
   interpret Saycmd
   msg='All lines with BEGIN in ' dirlist.dirptr
   interpret Saycmd
   msg=left(dashes,length(msg))
   interpret Saycmd
   do j=1 to AllBegins.0                          /* dump Allbegins array */
      msg=AllBegins.j
      interpret Saycmd
   end
   msg=' '
   interpret Saycmd

Return

/**************************************************************************/
/*                                                                        */
/*                  Dumps array used for lines with 'SECTION'             */
/*                                                                        */
/**************************************************************************/
DumpSections:

   msg=' '
   interpret Saycmd
   msg='(TRAPALLSECS=YES)' 
   interpret Saycmd
   msg='All lines with SECTION in ' dirlist.dirptr
   interpret Saycmd
   msg=left(dashes,length(msg))
   interpret Saycmd
   do j=1 to AllSections.0                         /* dump Frominfo array */
      msg=AllSections.j
      interpret Saycmd
   end
   msg=' '
   interpret Saycmd

Return

/**************************************************************************/
/*                                                                        */
/*                  Dumps array used for MIME encoding lines              */
/*                                                                        */
/**************************************************************************/
DumpEncodes: 

   msg=' '
   interpret Saycmd
   msg='(TRAPALLENCS=YES)' 
   interpret Saycmd
   msg='All MIME encoding Lines in ' dirlist.dirptr
   interpret Saycmd
   msg=left(dashes,length(msg))
   interpret Saycmd
   do j=1 to AllEncodes.0   
      msg=AllEncodes.j
      interpret Saycmd
   end
   msg=' '
   interpret Saycmd

Return

/**************************************************************************/
/*                                                                        */
/*                   Dump all runtime options to output                   */
/*                                                                        */
/**************************************************************************/
DumpOpts:

   msg=' '
   interpret Saycmd
   msg='(DUMPOPTS=YES)'
   interpret Saycmd
   msg='Using these runtime options: (0=NO,1=YES)'
   interpret Saycmd
   msg=left(dashes,length(msg))
   interpret Saycmd
   do i=1 to cmd.0
      tstr='tval='cmd.i
      interpret tstr
      msg='   '||cmd.i||'='||tval
      interpret Saycmd
   end 

Return


IOERR:

   Say 'An I/O error has occurred - exiting'
   exit 20

SYNTAX:

   Say 'An unexpected error has occurred - dumping values and exiting'
   Say 'Try to identify file with error and edit to fix'
   Say 'It is probably the LAST file in one of the arrays'
   Say ' '
   Say 'Line with error' sourceline(SIGL)  
   Say 'Current value of filename:' filename
   Say 'Current value of partname:' partname
   
   Say 'Dumping arrays ... '
   Call DumpDirs
   Call DumpFiles
   Call DumpMiscInfo
   signal Cleanup

===============  END OF ACTIVE CODE ================
