home *** CD-ROM | disk | FTP | other *** search
/ Aminet 18 / aminetcdnumber181997.iso / Aminet / comm / news / DWdecode.lha / dwdecode / DWdecode < prev    next >
Text File  |  1997-01-02  |  155KB  |  3,692 lines

  1. /**************************************************************************/
  2. /*                                                                        */
  3. /*                             DWDecode v1.0                              */
  4. /*                                                                        */
  5. /*                                                                        */
  6. /*                    Copyright ©1996 by Dick Whiting                     */
  7. /*                                                                        */
  8. /*========================================================================*/
  9. /*                                                                        */
  10. /*                                                                        */
  11. /* Report bugs, comments, etc. to:                                        */
  12. /*                                                                        */
  13. /*                   Dick Whiting <dwhiting@europa.com>                   */
  14. /*                                                                        */
  15. /*                           01 December 1996                             */
  16. /*                                                                        */
  17. /**************************************************************************/
  18.  
  19. Parse arg commandline                    /* get command line options      */
  20.  
  21. options failat 21                        /* block rc<21 from sending msgs */
  22. options results                          /* enable return codes           */
  23.  
  24. SIGNAL ON IOERR
  25. SIGNAL ON SYNTAX
  26.  
  27. Call Init                                /* initialize tables, vars, etc. */
  28.  
  29. Do dirptr=1 to dirlist.0                 /* loop thru all directories     */
  30.    Call BldFileNote                      /* Create filenotes for this dir */
  31.    Call ScanFiles                        /* Scan for key strings          */
  32.    Call ReadUnknowns                     /* Check files w/o encode set    */
  33.    Call Phase2                           /* complete info in Files array  */
  34.    Call ReportFiles                      /* generate file by file report  */
  35.    Call IssueWarnings                    /* issue warnings - none so far  */
  36.    Call FileNoteInFiles                  /* filenote inputs-encode & subj */
  37.    Call BuildLists                       /* build array for decoding use  */   
  38.    Call DecodeFiles                      /* do the actual decoding        */ 
  39.    Call DoOldFiles                       /* handle Delete/Mark old files  */
  40.    Call ListStats                        /* report time & cnts for dir    */
  41.    Call DumpArrays                       /* dump arrays for this dir      */   
  42.    if verbose then do
  43.       say time() 'Done processing 'dirlist.dirptr
  44.       say ' '
  45.    end
  46. end 
  47.  
  48. Cleanup:
  49.  
  50. if exists(DWtemp'DWdecode.scan') then do /* delete the scan file          */
  51.    Address Command 'Delete 'DWtemp'DWdecode.scan QUIET'
  52. end
  53.  
  54. if exists(DWtemp'DWdecode.temp') then do /* delete the join temporary file*/
  55.    Address Command 'Delete 'DWtemp'DWdecode.temp QUIET'
  56. end
  57.  
  58. Address Command 'Assign ' DWassignIN     /* remove the DW assign          */
  59.  
  60. pragma('D',origdir)                      /* reset to original directory   */
  61.  
  62. exit
  63.  
  64. /**************************************************************************/
  65. /*                                                                        */
  66. /*          Build the filenote string as requested in FILENOTE=var        */
  67. /*                                                                        */
  68. /*      Variable fnote may contain variables for later interpretation.    */
  69. /*                                                                        */
  70. /**************************************************************************/
  71. BldFileNote:
  72.  
  73.    if Filenote~='' then do 
  74.       fnote=filenote
  75.       do j=words(filenote) to 1 by -1
  76.          select
  77.             when upper(word(filenote,j))='%SOURCE' then do
  78.                wptr=wordindex(filenote,j)-1
  79.                fnote=delword(fnote,j,1)
  80.                sdir="'"||'dirlist.dirptr'||"'"
  81.                fnote=insert(sdir,fnote,wptr,length(sdir)+1,' ')
  82.             end
  83.             when upper(substr(word(filenote,j),1,4))='%LLQ' then do
  84.                llqnum=substr(word(filenote,j),5)
  85.                if llqnum='' then llqnum=1
  86.                if ~datatype(llqnum,'N') then llqnum=99
  87.                if llqnum<1 then llqnum=99
  88.                llq=translate(dirlist.dirptr,'  ',':/')
  89.                if llqnum>words(llq) then llqnum=words(llq)
  90.                llq=subword(llq,words(llq)-llqnum+1) 
  91.                wptr=wordindex(filenote,j)-1
  92.                fnote=delword(fnote,j,1)
  93.                fnote=insert(llq,fnote,wptr,length(llq)+1,' ')
  94.             end
  95.             when upper(substr(word(filenote,j),1,4))='%HLQ' then do
  96.                hlqnum=substr(word(filenote,j),5)
  97.                if hlqnum='' then hlqnum=1
  98.                if ~datatype(hlqnum,'N') then hlqnum=1 
  99.                if hlqnum<1 then hlqnum=1 
  100.                hlq=translate(dirlist.dirptr,'  ',':/')
  101.                if hlqnum>words(hlq) then hlqnum=words(hlq)
  102.                hlq=subword(hlq,1,hlqnum)             
  103.                wptr=wordindex(filenote,j)-1
  104.                fnote=delword(fnote,j,1)
  105.                fnote=insert(hlq,fnote,wptr,length(hlq)+1,' ')
  106.             end
  107.             when upper(substr(word(filenote,j),1,5))='%QUAL' then do
  108.                qnum1=substr(word(filenote,j),6,1)
  109.                if qnum1='' then qnum1=1
  110.                if ~datatype(qnum1,'N') then qnum1=1
  111.                if qnum1<1 then qnum=1
  112.                qual=translate(dirlist.dirptr,'  ',':/')
  113.                if qnum1>words(qual) then qnum1=words(qual)
  114.                qnum2=substr(word(filenote,j),7,1)
  115.                if qnum2='' then qnum2=words(qual)
  116.                if ~datatype(qnum2,'N') then qnum2=words(qual)
  117.                if qnum2<1 then qnum=words(qual)
  118.                if qnum2>words(qual) then qnum2=words(qual)
  119.                qual=subword(qual,qnum1,qnum2) 
  120.                wptr=wordindex(filenote,j)-1
  121.                fnote=delword(fnote,j,1)
  122.                fnote=insert(qual,fnote,wptr,length(qual)+1,' ')
  123.             end
  124.             when upper(word(filenote,j))='%SUBJECT' then do
  125.                wptr=wordindex(filenote,j)-1
  126.                fnote=delword(fnote,j,1)
  127.                subj="'"||'Subjinfo.Filesptr.1.1'||"'"
  128.                fnote=insert(subj,fnote,wptr,length(subj)+1,' ')
  129.             end
  130.             when upper(word(filenote,j))='%DATE' then do
  131.                wptr=wordindex(filenote,j)-1
  132.                fnote=delword(fnote,j,1)
  133.                date="'"||'Dateinfo.Filesptr.1.1'||"'"
  134.                fnote=insert(date,fnote,wptr,length(date)+1,' ')
  135.             end
  136.             when upper(word(filenote,j))='%FROM' then do
  137.                wptr=wordindex(filenote,j)-1
  138.                fnote=delword(fnote,j,1)
  139.                from="'"||'Frominfo.Filesptr.1.1'||"'"
  140.                fnote=insert(from,fnote,wptr,length(from)+1,' ')
  141.             end
  142.             otherwise nop
  143.          end
  144.       end   
  145.       fnote=strip(fnote)                    /* remove extra blanks        */
  146.       fnote="'"||fnote||"'"                 /* enclose string in quotes   */
  147.    end   /* matches with filenote~='' */
  148.  
  149. Return
  150.  
  151. /**************************************************************************/
  152. /*                                                                        */
  153. /* Scan directory for key strings used for identifying encode type, part  */
  154. /* information and header information.                                    */
  155. /*                                                                        */
  156. /* !! Should allow for multiple search programs, but not sure of output   */
  157. /*    parsing handling. The command could be specified as a template.     */
  158. /*                                                                        */
  159. /**************************************************************************/
  160. /*                                                                        */
  161. /* Read the lines from the sorted scan array. Determine what kind of      */
  162. /* line it is and store appropriately for Date:, From:, and Subject:      */
  163. /*                                                                        */
  164. /* Look for valid Section and begin lines. Get whatever info possible.    */
  165. /* Look for valid Base64 indicators and store info as available.          */
  166. /*                                                                        */
  167. /* The next routine will try to handle completing any parts using the     */
  168. /* information in the subject lines.                                      */
  169. /*                                                                        */
  170. /* ASSUMPTIONS:                                                           */
  171. /*  1) If file has a valid Section or begin line then it is UUencoded.    */
  172. /*  2) If an 'end' line occurs after a begin, it is a 1/1 part.           */
  173. /*  3) If file has a valid Base64 line then the file is Base64 encoded.   */
  174. /*  4) If a nth Base64 marker occurs, assume previous one is complete.    */
  175. /*  5) Files with multiple encoded parts are 1/1 files                    */
  176. /*                                                                        */
  177. /*========================================================================*/
  178. /*                          ARRAY FORMATS                                 */
  179. /*========================================================================*/
  180. /*               (0)=cnt             (0)=cnt                              */
  181. /* Files. format: filename.encodetype.partname.partnum.parttot.startline  */
  182. /*                        .encodetype.partname.partnum.parttot.startline  */
  183. /*                                                                        */
  184. /*                                     (Y/N/.)  (Y/.)     (Y/.)  (Y/.)    */
  185. /* Miscinfo. format: filename.mimetype.decoded.filenoted.chopped.dupfile  */
  186. /*                                                                        */
  187. /*                    (0)=cnt                                             */
  188. /* Subjinfo. format: skipflag.deleteflag.textline                         */
  189. /* Frominfo. format: skipflag.deleteflag.textline                         */
  190. /* Dateinfo. format: skipflag.deleteflag.textline                         */
  191. /*                                                                        */
  192. /*                                   (0)#partname matches in subject line */
  193. /*                                         (0)#partnums in subject line   */
  194. /*                                                    (0)#totals in sub   */
  195. /*                   Files                  spart      spart              */
  196. /* Partone.  format: Pointer.partname.sword.number.loc.total.loc.subjline */
  197. /*                                                                        */
  198. /* Partxxx.=same format as Partone.                                       */
  199. /*                                                                        */
  200. /**************************************************************************/
  201. ScanFiles:
  202.  
  203.    starttm=time('S')          /* start time for processing this directory */
  204.  
  205.    Address Command 'Assign ' DWassignIN dirlist.dirptr /*for shorter lines*/ 
  206.  
  207.    ScanArray.=missing          /* stores parsed information from scan prg */
  208.    ScanArray.0=0                                 /* no scan lines yet     */
  209.  
  210.    Files.=missing              /* stores information for each news file   */
  211.    Files.0=0                                     /* no File info yet      */
  212.  
  213.    Miscinfo. =missing          /* stores additional info for file/parts   */
  214.    Miscinfo.0=0                                  /* no Misc info yet      */
  215.  
  216.    Subjinfo. =missing                            /* init to missing       */
  217.    Subjinfo.0=0                                  /* no Subject lines yet  */
  218.  
  219.    Frominfo. =missing                            /* init to missing       */
  220.    Frominfo.0=0                                  /* no From    lines yet  */
  221.  
  222.    Dateinfo. =missing                            /* init to missing       */
  223.    Dateinfo.0=0                                  /* no Date    lines yet  */
  224.  
  225.    Partone. =missing                             /* init to missing       */
  226.    Partone.0=0                                   /* no partone  lines yet */
  227.    part1cnt=0                                    /* no partone  lines yet */
  228.  
  229.    Partxxx. =missing                             /* init to missing       */
  230.    Partxxx.0=0                                   /* no partxxx  lines yet */
  231.    partXcnt=0                                    /* no partxxx  lines yet */
  232.  
  233.    Parts.0=0                                     /* init to zero - report */
  234.    Temppart.0=0                                  /* init to zero - report */ 
  235.  
  236.    AllBegins.0=0                                 /* lines with begin      */
  237.    AllEncodes.0=0                                /* MIME encoding info    */
  238.    AllSections.0=0                               /* lines with section    */
  239.  
  240.    warnings.0=0                                  /* used for warning msgs */
  241.  
  242. if verbose then say time() 'Scanning ' dirlist.dirptr '...' 
  243.  
  244.    Address Command scanprog dirlist.dirptr 'From:    cs nh num  > ' DWtemp'DWdecode.scan'
  245.    Address Command scanprog dirlist.dirptr 'Subject: cs nh num >> ' DWtemp'DWdecode.scan'
  246.    Address Command scanprog dirlist.dirptr 'Date:    cs nh num >> ' DWtemp'DWdecode.scan'
  247.    Address Command scanprog dirlist.dirptr 'section     nh num >> ' DWtemp'DWdecode.scan'
  248.    Address Command scanprog dirlist.dirptr 'begin    cs nh num >> ' DWtemp'DWdecode.scan'
  249.    Address Command scanprog dirlist.dirptr 'end      cs nh num >> ' DWtemp'DWdecode.scan'
  250.    Address Command scanprog dirlist.dirptr 'Content- cs nh num >> ' DWtemp'DWdecode.scan'
  251.    Address Command scanprog dirlist.dirptr 'number=  cs nh num >> ' DWtemp'DWdecode.scan'
  252.    do i=1 to Base64Types.0
  253.       Address Command scanprog dirlist.dirptr Base64Types.i ' cs nh num >> ' DWtemp'DWdecode.scan'
  254.    end
  255.  
  256. if verbose then say time() 'Reading the scan file ...'
  257.  
  258.    goodopen=open('IN',DWtemp'DWdecode.scan','R')
  259.    if ~goodopen then do
  260.       msg='(E) Error in opening ' DWtemp'DWdecode.scan'
  261.       interpret Saycmd
  262.       msg='    No further processing for this directory possible'
  263.       interpret Saycmd
  264.       exit
  265.    end
  266.    dirname=dirlist.dirptr                        /* name of directory     */
  267.    device=substr(dirname,1,pos(':',dirname))     /* get device portion    */
  268.    directs=substr(dirname,pos(':',dirname)+1)    /* remaining portion     */
  269.    if upper(device)='RAM:' then dirname='Ram Disk:'||directs  /* fix Ram: */
  270.    dirlen=length(dirname)                        /* length of dir name    */
  271.    filename=missing                              /* init to missing       */
  272.    sptr=0                                        /* scanarray pointer     */
  273.  
  274.    do until eof('IN')
  275.       linein=readln('IN')
  276.       select
  277.          when pos(dirname,linein)=1 & word(linein,words(linein))='...' then do
  278.             fullname=subword(linein,1,words(linein)-1) /* name with path  */
  279.             filename=substr(fullname,dirlen+1)   /* just the filename part*/
  280.             if pos('/',filename)>0 then do 
  281.                filename=substr(filename,lastpos('/',filename)+1)
  282.             end
  283.          end
  284.          when words(linein)=2 & word(linein,2)='...' then do
  285.             fullname=word(linein,1)              /* filename with path    */
  286.             filename=substr(fullname,dirlen+1)   /* just the filename part*/
  287.             if pos('/',filename)>0 then do 
  288.                filename=substr(filename,lastpos('/',filename)+1)
  289.             end
  290.          end
  291.          when words(linein) > 0 then do
  292.             linenum=strip(word(linein,1))        /* line number found     */
  293.             linenum=right(linenum,6,'0')         /* put in leading zeros  */
  294.             text=subword(linein,2)               /* remaining string      */
  295.             select 
  296.                when word(text,1)='Newsgroups:' then nop
  297.                when word(text,1)='Xref:' then nop
  298.                when substr(word(text,1),1,2)='X-' then nop
  299.                when word(text,1)='Content-Description:' then nop
  300.                otherwise do
  301.                   sptr=sptr+1                          /* increment cnter */
  302.                   scanarray.0=sptr                     /* store it        */    
  303.                   scanarray.sptr=filename linenum text /* put it in array */   
  304.                end
  305.             end
  306.          end
  307.          otherwise nop /* should be end of file */
  308.       end
  309.    end
  310.  
  311.    result=close('IN')                            /* close the scan file   */
  312.  
  313. if verbose then say time() 'Sorting the scan array ...'
  314.  
  315.  
  316.    call QSORT(1, scanarray.0, scanarray)     /* sort by name, line number */
  317.  
  318.    if DEBUG=YES then do 
  319.       msg=' '
  320.       interpret Saycmd
  321.       msg='Dumping ScanArray ...'
  322.       interpret Saycmd
  323.       msg=left(dashes,length(msg))
  324.       interpret Saycmd
  325.       do i=1 to scanarray.0                          /* for debugging     */ 
  326.          msg=scanarray.i
  327.          interpret Saycmd
  328.       end
  329.       msg=' '
  330.       interpret Saycmd
  331.    end
  332.  
  333.    SkipSubjCnt=0                                 /* used for reporting    */
  334.    SkipFromCnt=0                                 /* used for reporting    */ 
  335.    B64OutCnt=0                                   /* used for reporting    */
  336.    UUOutCnt=0                                    /* used for reporting    */
  337.  
  338.    oldfile=missing                               /* break control on file */
  339.    oldsection=missing                            /* used to trap end sect.*/
  340.    fptr=0                                        /* files array pointer   */
  341.  
  342.    partname=missing                              /* no partname yet       */
  343.    partnum=missing                               /* no partnum yet        */
  344.    parttot=missing                               /* no part total yet     */ 
  345.    partlin=missing                               /* decode start line num */
  346.    pptr=0                                        /* zero to start with    */
  347.    encode=missing                                /* init to missing       */ 
  348.    beginfound=NO                                 /* no begins found yet   */
  349.    CCdata=NO                                     /* NO Content data yet   */
  350.  
  351. if verbose then say time() 'Processing the scan array ...'
  352.  
  353.    do i=1 to scanarray.0
  354.       filename=word(scanarray.i,1)               /* filename in array     */
  355.       linenum=word(scanarray.i,2)                /* line number in array  */       
  356.       text=subword(scanarray.i,3)                /* remainder of line     */
  357.       if filename~=oldfile then do               /* got a level break     */
  358.          if encode~=missing then Call StorePartVars /* do previous part   */
  359.          if oldfile~=missing then do 
  360.             skipflag=NO                          /* didn't do any skips   */
  361.             Call CheckSkips                      /* handle Skip/Deletes   */
  362.             if skipflag=YES then do              /* clear array entries   */
  363.                Files.fptr.1=missing              /* clear encode value    */
  364.                Frominfo.fptr.1.1=missing
  365.                Subjinfo.fptr.1.1=missing
  366.                Dateinfo.fptr.1.1=missing
  367.                encode=missing                    /* clear control vars    */
  368.                fptr=fptr-1                       /* reuse current slot    */ 
  369.                pptr=0                            /* clear control vars    */
  370.             end 
  371.          end
  372.          oldfile=filename                        /* copy for next break   */
  373.          fptr=fptr+1                             /* next files. pointer   */
  374.          Files.0=fptr                            /* count the file        */
  375.          Files.fptr=filename                     /* store filename        */
  376.          Files.fptr.1.0=0                        /* no parts yet          */
  377.          Dateinfo.fptr=0                         /* don't skip            */
  378.          Dateinfo.fptr.1=0                       /* don't delete          */
  379.          Frominfo.fptr=0                         /* don't skip            */
  380.          Frominfo.fptr.1=0                       /* don't delete          */
  381.          Subjinfo.fptr=0                         /* don't skip            */
  382.          Subjinfo.fptr.1=0                       /* don't delete          */
  383.          pptr=0                                  /* partname slot pointer */
  384.          Call ResetPartVars                      /* reset partname vars   */
  385.          oldsection=missing                      /* used to trap end sect.*/
  386.       end
  387.  
  388.       select
  389.          when word(text,1)='From:' & Frominfo.fptr.1.1=missing then do
  390.             text=translate(text,'  ','"`')       /* blank all type quotes */
  391.             text=translate(text,' ',"'")         /* blank all type quotes */
  392.             Frominfo.fptr.1.1=substr(text,7)     /* store From info       */
  393.          end
  394.          when word(text,1)='Subject:' & Subjinfo.fptr.1.1=missing then do
  395.             text=translate(text,'  ','"`')       /* blank all type quotes */
  396.             text=translate(text,' ',"'")         /* blank all type quotes */
  397.             Subjinfo.fptr.1.1=substr(text,10)    /* store Subject info    */
  398.          end
  399.          when word(text,1)='Date:' & Dateinfo.fptr.1.1=missing then do
  400.               Dateinfo.fptr.1.1=substr(text,7)
  401.          end
  402.          when pos('SECTION',upper(word(text,1)))>0 then do
  403.             Call CheckSections
  404.             Call StorePartVars                /* complete set - store  */
  405.          end
  406.          when substr(text,1,6)='begin ' & datatype(word(text,2),'N') then do 
  407.             partnum=1                            /* begins are part ones  */
  408.             if partname~=subword(text,3) then do /* didn't have a section */
  409.                partname=subword(text,3)          /* begin line partname   */ 
  410.                encode='UU'                       /* encode type           */
  411.                partlin=linenum            /* good starting point in file  */
  412.                Call StorePartVars                /* complete set - store  */
  413.             end
  414.             beginfound=YES                       /* indicator for 'end '  */ 
  415.          end
  416.          when word(text,1)='end' & encode='UU' & beginfound=YES then do
  417.             parttot=1                            /* !! total - unused ?   */
  418.             Call StorePartVars                   /* store what we've got  */
  419.             Call ResetPartVars                   /* reset partname vars   */
  420.          end
  421.          when pos('Content-',word(text,1))=1 then do
  422.             Call CheckContent
  423.             if CCdata=YES & Ctype>1 & encode ~=missing then do
  424.                Call StorePartVars                /* store what we've got  */
  425.                Call ResetPartVars                /* reset partname vars   */
  426.             end
  427.          end
  428.          otherwise do
  429.             if encode=missing then do            /* not from a Content-   */
  430.                Call CheckBase64                  /* non-MIME B64 encoding */ 
  431.                if encode='64' then do            /* found a B64 start str */
  432.                   partnum=1                      /* begins are part ones  */
  433.                   encode='64'                    /* encode type           */
  434.                   Call StorePartVars             /* store what we've got  */
  435.                   Call ResetPartVars             /* reset partname vars   */
  436.                end
  437.             end
  438.          end
  439.       end
  440.    end                                  /* matches do i=1 to scanarray.0  */
  441.  
  442.    skipflag=NO                                   /* NO skips yet          */
  443.    Call CheckSkips                               /* check LAST file       */
  444.    if skipflag=YES then fptr=fptr-1              /* don't count last one  */
  445.    if encode~=missing & skipflag=NO then Call StorePartVars /*last part   */
  446.    
  447.    Files.0=fptr                                  /* count of files found  */
  448.    Frominfo.0=fptr                               /* count of files found  */
  449.    Subjinfo.0=fptr                               /* count of files found  */
  450.    Dateinfo.0=fptr                               /* count of files found  */
  451.    Miscinfo.0=fptr                               /* count of files found  */
  452.  
  453. ScanFilesEnd:
  454.  
  455. Return
  456.  
  457. /**************************************************************************/
  458. /*  Check for Skip/Delete based on Subject: or From: lines. If SKIP then  */
  459. /*  filenote the file and reuse Files. slot. If DELETE then delete the    */
  460. /*  file and reuse the slot. Skipped/Deleted will not appear on any rpts  */
  461. /*  or be included in the match logic phases.                             */
  462. /*                                                                        */
  463. /*  Date deletes will be flagged for handling after the Decoding.         */
  464. /**************************************************************************/
  465. DoOldFiles:
  466.  
  467.    If MarkOld | DeleteOld then do
  468.       do fptr=1 to Files.0
  469.          if ~exists(DWassignIN||Files.fptr) then iterate fptr /* gone     */
  470.          if DeleteOld & ~ScanOnly then do
  471.             if Dateinfo.fptr.1=YES then do
  472.                Address Command 'Delete' DWassignIN||Files.fptr 'QUIET'
  473.             end
  474.          end
  475.          else do
  476.             if Dateinfo.fptr.1=YES then do
  477.                fnsubj=Subjinfo.fptr.1.1          /* subject for filenote  */
  478.                fnsubj=substr(fnsubj,1,75)        /* shorten to max length */ 
  479.                if Files.fptr.1=missing then fnsubj='O   '||fnsubj
  480.                                        else fnsubj='O'||Files.fptr.1||' '||fnsubj
  481.                filein=DWassignIN||Files.fptr
  482.                Address Command 'Filenote 'filein '"'fnsubj'" ' 
  483.             end
  484.          end
  485.       end
  486.    end
  487.  
  488. Return
  489.  
  490. /**************************************************************************/
  491. /*                                                                        */
  492. /*           Report counts and time information for this directory        */
  493. /*                                                                        */
  494. /**************************************************************************/
  495. ListStats:
  496.  
  497.    if ShowStats then do 
  498.       totfiles=SkipSubjCnt+SkipFromCnt+Files.0
  499.       if totfiles=0 then signal ListStatsEnd
  500.       maxval=max(Files.0,Parts.0,Temppart.0,totfiles)
  501.       rlen=length(maxval)
  502.       msg=' ' 
  503.       interpret saycmd
  504.       msg=right(totfiles,rlen) 'File(s) in 'dirlist.dirptr
  505.       interpret saycmd
  506.       msg=right(SkipSubjCnt,rlen) 'File(s) skipped/deleted due to Subject: matches'
  507.       interpret saycmd
  508.       msg=right(SkipFromCnt,rlen) 'File(s) skipped/deleted due to From: matches'
  509.       interpret saycmd
  510.       msg=right(Temppart.0,rlen) 'Encoded pieces completely identified'
  511.       interpret saycmd
  512.       complete=0
  513.       do j=1 to parts.0
  514.          if parts.j.1=parts.j.1.0 then complete=complete+1
  515.       end
  516.       msg=right(complete,rlen) 'Complete encoded files (excludes duplicates)'
  517.       interpret saycmd
  518.       msg=right(UUOutCnt,rlen) 'UU Encoded output files written'
  519.       interpret saycmd
  520.       msg=right(B64OutCnt,rlen) 'Base64 Encoded output files written'
  521.       interpret saycmd
  522.  
  523.       endtm=time('S')   
  524.       elapstm=endtm-starttm
  525.       hh=elapstm%3600
  526.       hh=right(hh,2,'0')
  527.       elapstm=elapstm-(3600*hh)
  528.       mm=elapstm%60
  529.       mm=right(mm,2,'0')
  530.       ss=elapstm-(60*mm)
  531.       ss=right(ss,2,'0')
  532.       msg=copies(' ',rlen) 'Processing time for this directory:' hh':'mm':'ss 
  533.       interpret Saycmd
  534.    end
  535.  
  536. ListStatsEnd:
  537.  
  538. Return
  539.  
  540. /**************************************************************************/
  541. /*  Check for Skip/Delete based on Subject: or From: lines. If SKIP then  */
  542. /*  filenote the file and reuse Files. slot. If DELETE then delete the    */
  543. /*  file and reuse the slot. Skipped/Deleted will not appear on any rpts  */
  544. /*  or be included in the match logic phases.                             */
  545. /*                                                                        */
  546. /*  Date deletes will be flagged for handling after the Decoding.         */
  547. /**************************************************************************/
  548. CheckSkips:
  549.  
  550.    If SkipFrom | DeleteFrom then do
  551.       do skipcnt=1 to SkipFroms.0
  552.          if pos(upper(SkipFroms.skipcnt),upper(Frominfo.fptr.1.1))>0 then do
  553.             if DeleteFrom & ~ScanOnly then do 
  554.                Address Command 'Delete' DWassignIN||Files.fptr 'QUIET'
  555.             end
  556.             else do
  557.                fnsubj=Subjinfo.fptr.1.1                   /* subject for filenote  */
  558.                fnsubj=substr(fnsubj,1,75)                 /* shorten to max length */ 
  559.                if Files.fptr.1=missing then fnsubj='F   '||fnsubj
  560.                                        else fnsubj='F'||Files.fptr.1||' '||fnsubj
  561.                filein=DWassignIN||Files.fptr
  562.                Address Command 'Filenote 'filein '"'fnsubj'" ' 
  563.             end
  564.             skipflag=YES
  565.             SkipFromCnt=SkipFromCnt+1
  566.             leave skipcnt         
  567.          end
  568.       end 
  569.    end
  570.    
  571.    If SkipSubject | DeleteSubject then do
  572.       do skipcnt=1 to SkipSubjects.0
  573.          if pos(upper(SkipSubjects.skipcnt),upper(Subjinfo.fptr.1.1))>0 then do
  574.             if DeleteSubject & ~ScanOnly then do
  575.                if exists(DWassignIN||Files.fptr) then do
  576.                   Address Command 'Delete' DWassignIN||Files.fptr 'QUIET'
  577.                end
  578.             end 
  579.             else do
  580.                fnsubj=Subjinfo.fptr.1.1                   /* subject for filenote  */
  581.                fnsubj=substr(fnsubj,1,75)                 /* shorten to max length */ 
  582.                if Files.fptr.1=missing then fnsubj='S   '||fnsubj
  583.                                        else fnsubj='S'||Files.fptr.1||' '||fnsubj
  584.                filein=DWassignIN||Files.fptr
  585.                if ~skipflag then Address Command 'Filenote 'filein '"'fnsubj'" ' 
  586.             end
  587.             if ~skipflag then do
  588.                skipflag=YES
  589.                SkipSubjCnt=SkipSubjCnt+1
  590.             end 
  591.             leave skipcnt         
  592.          end
  593.       end 
  594.    end
  595.    
  596.    If (MarkOld | DeleteOld) & Dateinfo.fptr.1.1~=missing  then do
  597.       datemsg=Dateinfo.fptr.1.1
  598.       Call TimeStamp
  599.       if (today-days)>KeepDays then do
  600.          Dateinfo.fptr.1=YES
  601.       end 
  602.    end
  603.  
  604. Return
  605.  
  606. /**************************************************************************/
  607. /*  Attach a filenote to each of the input files with encode & subject    */
  608. /*  This is the time to DELETE non-binaries if requested to.              */
  609. /**************************************************************************/
  610. FileNoteInFiles:
  611.  
  612. msg='Filenoting input files '
  613. if DeleteText then msg=msg||'and Deleting Text files '
  614. msg=msg||'...'
  615. if verbose then say time() msg
  616.  
  617. do i=1 to Files.0
  618.    filein=DWassignIN||Files.i                    /* name of file w/path   */
  619.    if DeleteText & Files.i.1=missing then do  /* a 'text' file         */
  620.       Address Command 'Delete ' filein ' QUIET'
  621.       iterate i                                  /* go onto next file     */
  622.    end
  623.    fnsubj=Subjinfo.i.1.1                         /* subject for filenote  */
  624.    fnsubj=substr(fnsubj,1,75)                    /* shorten to max length */ 
  625.    select
  626.       when Files.i.1=missing then do
  627.          encoding='Not an encoded file'
  628.          Address Command 'Filenote 'filein '"    '||fnsubj||'" '
  629.          fnrc=rc
  630.       end
  631.       when Files.i.1='UU' then do
  632.          encoding='UUencode'
  633.          Address Command 'Filenote 'filein '" UU '||fnsubj||'" ' 
  634.          fnrc=rc
  635.       end
  636.       when Files.i.1='64' then do
  637.          encoding='Base64'
  638.          Address Command 'Filenote  'filein '" 64 '||fnsubj||'" ' 
  639.          fnrc=rc
  640.       end
  641.       otherwise nop
  642.    end
  643.    if fnrc>0 then do
  644.       say 'Filenote returned RC='fnrc 'for 'filein
  645.       say 'Subject: 'fnsubj
  646.    end
  647. end
  648.  
  649. Return
  650.  
  651. /**************************************************************************/
  652. /*                                                                        */
  653. /*      Reset variables used to identify partnames, number, etc.          */
  654. /*                                                                        */
  655. /**************************************************************************/
  656. ResetPartVars:
  657.  
  658.    if pptr>1 then do                             /* an nth encode in file */
  659.       prev=pptr-1                                /* point to prev part    */
  660.       Files.fptr.1.prev.1.1=1                    /* must be a part 1/1    */
  661.    end
  662.    
  663.    if encode~=missing then Files.fptr.1.0=pptr   /* store partname cnt    */ 
  664.    partname=missing                              /* no partname yet       */
  665.    partnum=missing                               /* no partnum yet        */
  666.    parttot=missing                               /* no part total yet     */ 
  667.    partlin=missing                               /* decode start line num */
  668.    encode=missing                                /* null for encoding     */
  669.    pptr=pptr+1                                   /* NEXT part for filename*/
  670.    beginfound=NO                                 /* no begins found yet   */
  671.    CCdata=NO                                     /* NO Content data yet   */
  672.    Ctype=0                                       /* no Content-type yet   */
  673.  
  674. Return
  675.  
  676. /**************************************************************************/
  677. /*                                                                        */
  678. /*      Store variables used to identify partnames, number, etc.          */
  679. /*                                                                        */
  680. /**************************************************************************/
  681. StorePartVars:
  682.  
  683.    if encode~=missing   then do
  684.       Files.fptr.1.0=pptr
  685.       Files.fptr.pptr=encode 
  686.    end
  687.    if partname~=missing then do
  688.       Files.fptr.1.pptr=partname 
  689.    end
  690.    if partnum~=missing  then do
  691.       Files.fptr.1.pptr.1=partnum 
  692.    end
  693.    if parttot~=missing  then do
  694.       Files.fptr.1.pptr.1.1=parttot 
  695.    end
  696.    if partlin~=missing  then do
  697.       Files.fptr.1.pptr.1.1.1=partlin 
  698.    end
  699.  
  700. Return
  701.  
  702. /**************************************************************************/
  703. /*                                                                        */
  704. /*      See if this one has Section information (we hope so)              */
  705. /*                                                                        */
  706. /**************************************************************************/
  707. CheckSections:
  708.  
  709.    if text=oldsection then signal CheckSectionsEnd  /* a closing section  */
  710.  
  711.    if pos('SECTION',upper(text))>0 & TrapAllSecs then do
  712.       AllSections.0=1+AllSections.0
  713.       secptr=AllSections.0
  714.       AllSections.secptr=filename':'text
  715.    end
  716.  
  717.    do k=1 to sectiontypes.0               /* loop thru various forms      */
  718.       matchctr=0                          /* zero matches at start        */
  719.       do l=1 to sectiontypes.k            /* number of keys to test       */
  720.          key1=sectiontypes.k.l            /* primary search key           */
  721.          key1loc=sectiontypes.k.l.l       /* location of primary key      */
  722.          if word(text,key1loc)=key1 then matchctr=matchctr+1
  723.          else iterate k                   /* on any mismatch quit loop    */
  724.       end
  725.       if matchctr =sectiontypes.k then do        /* found a KNOWN section */
  726.          wpartnum =sectiontypes.k.1.1.1          /* word holding partnum  */
  727.          wparttot =sectiontypes.k.1.1.1.1        /* word holding total    */
  728.          wpartname=sectiontypes.k.1.1.1.1.1      /* name of file          */
  729.          partsep  =sectiontypes.k.1.1.1.1.1.1    /* delimiter char        */
  730.          if wpartnum=wparttot & wpartnum~=missing then do
  731.             partword=word(text,wpartnum)         /* get the word          */
  732.             partnum=substr(partword,1,pos(partsep,partword)-1)
  733.             parttot=substr(partword,pos(partsep,partword)+1)
  734.          end
  735.          else do
  736.             if wpartnum~=missing then partnum=word(text,wpartnum)
  737.             if wparttot~=missing then parttot=word(text,wparttot)
  738.          end
  739.          if wpartname~=missing then partname=word(text,wpartname)
  740.          if ~datatype(partnum,'N') then partnum=missing
  741.          if ~datatype(parttot,'N') then parttot=missing
  742.          encode='UU'                      /* Sections mean UU encoding    */ 
  743.          partlin=linenum                  /* good starting point in file  */
  744.          oldsection=text                  /* use to trap ending section   */
  745.          leave k              /* got everything we could from the SECTION */       
  746.       end  /* if matchctr=sectiontypes.k */
  747.       else do 
  748.          /* !!! should not get here !!! */
  749.          say 'Should not be here--- Check Sections'
  750.       end
  751.    end  /* do k=1 to sectiontypes.0 */
  752.  
  753.    if pos('SECTION',upper(text))>0 then do    /* unknown section found    */
  754.       if TrapNewSecs=YES & k>sectiontypes.0 then do
  755.          if exists(TrapNewSecsFile) then mode='A'
  756.                                     else mode='W'
  757.          goodopen=open('TRAPSECS',TrapNewSecsFile,mode)
  758.          if ~goodopen then do
  759.             msg='(E) Unable to open TrapSecFile:'TrapNewSecsFile
  760.             interpret Saycmd
  761.             msg='    Setting TrapNewSecs=NO'
  762.             interpret Saycmd
  763.          end
  764.          result=writeln('TRAPSECS',text)
  765.          result=close('TRAPSECS')
  766.       end  /* matches if TrapNewSecs=YES */
  767.    end  /* matches unknown section */
  768.  
  769. CheckSectionsEnd:
  770.  
  771. Return
  772.  
  773. /**************************************************************************/
  774. /*                                                                        */
  775. /*                     Handle the Content- type lines                     */
  776. /*                                                                        */
  777. /**************************************************************************/
  778. CheckContent:
  779.  
  780.    Select
  781.       When word(text,1)='Content-Type:' & ,
  782.            CCdata=YES & Ctype>0 & encode~=missing then do
  783.          Ctype=Ctype+1
  784.          i=i-1                         /* redo this line next iteration*/
  785.       end
  786.       When word(text,1)='Content-Type:' then do 
  787.          Ctype=0                       /* any previous wasn't encoded  */
  788.          Call CheckCType
  789.       end
  790.       When word(text,1)='Content-Transfer-Encoding:' then do
  791.          Call CheckCEncoding
  792.       end
  793.            
  794.       When word(text,1)='Content-Disposition:' then do 
  795.          Call CheckCDisp
  796.       end
  797.       Otherwise nop
  798.    end
  799.    
  800. CheckContentEnd:
  801.  
  802. Return
  803.  
  804. /**************************************************************************/
  805. /*                                                                        */
  806. /*                     Handle Content-Type lines                          */
  807. /*                                                                        */
  808. /**************************************************************************/
  809. CheckCType:
  810.  
  811.    Select
  812.       when upper(word(text,2))='MULTIPART/MIXED;' then nop 
  813.       when upper(word(text,2))='MESSAGE/PARTIAL;' then do
  814.          Call NextCline
  815.          if substr(CCword1,1,7)='number=' & substr(CCword2,1,6)='total=' then do
  816.             Call CheckCNumber
  817.          end          
  818.          else do
  819.             if substr(CCword1,1,3)='id=' then do    /* a scan word in id  */ 
  820.                i=i+1                                /* skip over id line  */
  821.                Call NextCline
  822.                if substr(CCword1,1,7)='number=' & substr(CCword2,1,6)='total=' then do
  823.                   Call CheckCNumber
  824.                end          
  825.             end  
  826.          end
  827.       end   /* matches MESSAGE/PARTIAL */
  828.       otherwise do  /* all other content-types for now */
  829.          Ctype=Ctype+1                              /* count Content-type */
  830.          if pos('name=',word(text,3))=1 then do
  831.             partname=subword(text,3)
  832.             squote=pos('"',partname)
  833.             equote=lastpos('"',partname)-(squote+1)
  834.             partname=substr(partname,squote+1,equote)
  835.             CCdata=YES
  836.          end
  837.       end   /* matches otherwise other Content-Types */
  838.    end   /* matches Content-Type Select */
  839.  
  840. CheckCTypeEnd:
  841.  
  842. Return
  843.  
  844. /**************************************************************************/
  845. /*                                                                        */
  846. /*                     Point to next line in scanarray                    */
  847. /*                                                                        */
  848. /**************************************************************************/
  849. NextCline:    
  850.  
  851.    CCi=i+1                               /* temp pointer for next line   */
  852.    CCfile=word(scanarray.CCi,1)
  853.    CCtext=subword(scanarray.CCi,3)
  854.    CCtext=translate(CCtext,'  ',tab)
  855.    CCword1=strip(word(CCtext,1))
  856.    CCword2=strip(word(CCtext,2))
  857.  
  858. Return
  859.  
  860. /**************************************************************************/
  861. /*                                                                        */
  862. /*                     Handle number= for Partials                        */
  863. /*                                                                        */
  864. /**************************************************************************/
  865. CheckCNumber:
  866.  
  867.    partnum=substr(CCword1,8)
  868.    partnum=strip(translate(partnum,' ',';'))
  869.    parttot=substr(CCword2,7)
  870.    parttot=strip(translate(parttot,' ',';'))
  871.    i=CCi
  872.    CCdata=YES
  873.  
  874. Return
  875.  
  876. /**************************************************************************/
  877. /*                                                                        */
  878. /*                     Handle Content-Encoding lines                      */
  879. /*                                                                        */
  880. /**************************************************************************/
  881. CheckCEncoding:
  882.  
  883.    if TrapAllEncs then do
  884.       AllEncodes.0=1+AllEncodes.0
  885.       encptr=AllEncodes.0
  886.       AllEncodes.encptr=filename':'text
  887.    end
  888.  
  889.    do k=1 to EncTypes.0                   /* loop thru various forms      */
  890.       matchctr=0                          /* zero matches at start        */
  891.       if upper(word(text,2))=upper(EncTypes.k) then do
  892.          matchctr=1                       /* found a match                */ 
  893.          if EncTypes.k.1~=missing then do
  894.             encode=upper(EncTypes.k.1)    /* store encode type            */
  895.             partlin=linenum               /* good starting point in file  */
  896.             if partnum=missing & encode='64' then partnum=1
  897.             CCdata=YES
  898.          end
  899.          leave k
  900.       end
  901.    end  /* do k=1 to EncTypes.0 */
  902.  
  903.    if TrapNewEncs=YES & matchctr=0 then do   /* must be a new encode type */ 
  904.       if exists(TrapNewEncsFile) then mode='A'
  905.                                  else mode='W'
  906.       goodopen=open('TRAPENCS',TrapNewEncsFile,mode)
  907.       if ~goodopen then do
  908.          msg='(E) Unable to open TrapEncFile:'TrapNewEncsFile
  909.          interpret Saycmd
  910.          msg='    Setting TrapNewEncs=NO'
  911.          interpret Saycmd
  912.       end
  913.       result=writeln('TRAPENCS',text)
  914.       result=close('TRAPENCS')
  915.    end  /* matches if TrapNewEncs=YES */
  916.  
  917. Return
  918.  
  919. /**************************************************************************/
  920. /*                                                                        */
  921. /*                     Handle Content-Disposition lines                   */
  922. /*                                                                        */
  923. /**************************************************************************/
  924. CheckCDisp:
  925.  
  926.    if pos('filename',word(text,3))=1 then do
  927.       partname=subword(text,3)
  928.       squote=pos('"',partname)
  929.       if squote>0 then do 
  930.          equote=lastpos('"',partname)-(squote+1)
  931.          partname=substr(partname,squote+1,equote)
  932.       end
  933.       else do
  934.          partname=strip(substr(partname,10)) 
  935.       end
  936.       CCdata=YES
  937.    end
  938.  
  939. CheckCDispEnd:
  940.  
  941. Return
  942.  
  943. /**************************************************************************/
  944. /*                                                                        */
  945. /*                     Handle the Base64 - type lines                     */
  946. /*                                                                        */
  947. /**************************************************************************/
  948. CheckBase64:
  949.  
  950.    do k=1 to Base64Types.0                /* loop thru various forms      */
  951.       key1=Base64Types.k                  /* primary search key           */
  952.       key1loc=1                           /* location of primary key      */
  953.       if pos(key1,text)=key1loc then do   /* found a match for Base64     */
  954.          partlin=linenum
  955.          encode='64'                      /* Base64 encoding              */
  956.          leave k                          /* stop looking                 */
  957.       end
  958.    end  /* do k=1 to Base64Types.0 */
  959.  
  960. Return
  961.  
  962. /**************************************************************************/
  963. /*                                                                        */
  964. /*  Read all unidentified files looking for UU encoded lines. Only files  */
  965. /*  with encode=missing are read. Should be part x/y and should only have */
  966. /*  a few lines of header info. Not like part 1/y where leading text may  */
  967. /*  be hundreds of lines. Use MaxHeader=25 or less and should be quick.   */
  968. /*                                                                        */
  969. /**************************************************************************/
  970. ReadUnknowns:
  971.  
  972. if verbose then say time() 'Reading unidentified files for encoded lines ...'
  973.  
  974.    do i=1 to Files.0
  975.       if Files.i.1=missing then do        /* check file for UU lines      */
  976.          filein=DWassignIN||Files.i
  977.  
  978.          goodopen=open('IN',filein,'R')
  979.          if ~goodopen then do
  980.             msg='(E) Error in processing input file' filein
  981.             interpret Saycmd
  982.             msg='    Attempting to continuing with next file'
  983.             interpret Saycmd
  984.             iterate
  985.          end
  986.  
  987.          j=1                                     /* loop control variable */
  988.          mcount=0                                /* reset UU line counter */
  989.          bcount=0                                /* reset 64 line counter */
  990.  
  991.          do until j>MaxHeader | mcount=MinEncoded | eof('IN')
  992.             linein=readln('IN')
  993.             linein=strip(linein,'T')             /* strip trailing blanks */
  994.             if substr(linein,1,1)='M' & pos(' ',linein)=0 then do
  995.                mcount=mcount+1
  996.                bcount=0                          /* if an 'M' then not 64 */
  997.             end 
  998.             else do 
  999.                if length(linein)>40 & pos(' ',linein)=0 then do
  1000.                   bcount=bcount+1 
  1001.                   mcount=0
  1002.                end 
  1003.             end 
  1004.             j=j+1                                /* NEXT line number      */
  1005.          end
  1006.  
  1007.          if mcount>=MinEncoded then do
  1008.             Files.i.1='UU'                       /* a UU encoded file     */
  1009.             Files.i.1.0=1                        /* 1 entry in array      */
  1010.          end 
  1011.          else do
  1012.             if bcount>=MinEncoded then do
  1013.                Files.i.1='64'                    /* Base 64 file?)        */
  1014.                Files.i.1.0=1        
  1015.             end 
  1016.          end 
  1017.  
  1018.          result=close('IN')                      /* close the input file  */
  1019.       end
  1020.    end
  1021.  
  1022. Return
  1023.  
  1024. /**************************************************************************/
  1025. /* First loop thru files and any that have multiples within a single file */
  1026. /* are marked as part 1/1. This assumes we don't have multiple PARTS for  */
  1027. /* files that have multiple encodes within them.                          */
  1028. /*                                                                        */
  1029. /*  Next:                                                                 */
  1030. /*  locate all encoded files with a missing value for name, num, or total */
  1031. /*  To complete this information we need to trust the information in the  */
  1032. /*  subject line and make some 'reasonalbe' assumptions. We will also     */
  1033. /*  use comparing of subject lines to connect part x/y with the part 1/y  */
  1034. /**************************************************************************/
  1035. Phase2:         
  1036.  
  1037. if verbose then say time() 'Starting Phase2 part identification ...'
  1038.  
  1039.    part1cnt=0                               /* count of part 1/. pieces   */
  1040.    partXcnt=0                               /* count of part x/y pieces   */
  1041.  
  1042.    do i=1 to Files.0        
  1043.       Select
  1044.          when Files.i.1=missing then nop    /* not an encoded file - skip */
  1045.          when Files.i.1.0=1 then do
  1046.             partname=Files.i.1.1
  1047.             partnum=Files.i.1.1.1
  1048.             parttot=Files.i.1.1.1.1
  1049.             if partname=missing | partnum=missing | parttot=missing then do
  1050.                Call CheckSubject
  1051.             end
  1052.             else do
  1053.                if parttot > 1 then do
  1054.                   Call CheckSubject
  1055.                end
  1056.             end
  1057.          end
  1058.          when Files.i.1.0>1 then do j=1 to Files.i.1.0
  1059.             if Files.i.1.j.1=1 & Files.i.1.j.1.1=missing then do
  1060.                Files.i.1.j.1.1=1
  1061.             end 
  1062.             else do
  1063.                if Files.i.1.j.1~=1 & Files.i.1.j.1.1=missing then do
  1064.                   Say 'Found multi parts with first not = 1'
  1065.                   Say Files.i Files.i.1 Files.i.1.j Files.i.1.j.1 Files.i.1.j.1.1
  1066.                end
  1067.             end
  1068.          end
  1069.          otherwise do
  1070.             Say 'Found otherwise condition in Phase2'
  1071.             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
  1072.          end
  1073.       end
  1074.    end
  1075.  
  1076.    Call Phase2Files
  1077.  
  1078. Return
  1079.  
  1080. /**************************************************************************/
  1081. /* Scan subject line looking for the partname previously identified. If   */
  1082. /* found mark where it/they occur.                                        */
  1083. /*                                                                        */
  1084. /* If we don't have a partname, then use the bintypes array to locate all */
  1085. /* potential filenames and mark where they occur.                         */
  1086. /*                                                                        */
  1087. /**************************************************************************/
  1088. CheckSubject:
  1089.  
  1090.    subjline=Subjinfo.i.1.1                     /* current subject line    */
  1091.    testword=missing                            /* init to missing         */
  1092.    spctr=0                                     /* counter for spartnames  */
  1093.    spartname.=missing                          /* init to missing         */
  1094.    spartname.0=0                               /* no partnames in subject */
  1095.    subjpn=missing                              /* init to missing         */
  1096.    subjpt=missing                              /* init to missing         */
  1097.    pncnt=0                                     /* counter for subject pns */
  1098.    ptcnt=0                                     /* counter for subject pts */
  1099.  
  1100.           /*****************************************************/
  1101.           /*  Get rid of all the braces, brackets, & parens.   */
  1102.           /*  This should take care of problems where user     */
  1103.           /*  didn't leave a blank between filename and part   */
  1104.           /*  information.                                     */
  1105.           /*                                                   */
  1106.           /*  Locate all possible binary file names in the     */
  1107.           /*  subject line. May be different ones or multiple  */
  1108.           /*  ones of the same name.                           */
  1109.           /*                                                   */
  1110.           /*  If a part 1/x (known from "begin" line) locate   */
  1111.           /*  if and where the partname is in the subject.     */
  1112.           /*  This will be used as a match locator in phase2.  */
  1113.           /*  If we can't locate it we will try to use the     */
  1114.           /*  partname we do find in the subject. (Probably a  */
  1115.           /*  typo by the user). If there isn't any name in    */
  1116.           /*  the subject we will use the entire subject line  */
  1117.           /*  for matches.                                     */
  1118.           /*                                                   */
  1119.           /*  For non 1/x parts, we try to get a subject name  */
  1120.           /*  and part information. This will be for reporting */
  1121.           /*  purposes only if we don't have the part 1 for it.*/
  1122.           /*                                                   */
  1123.           /*****************************************************/
  1124.  
  1125.    subjline=translate(subjline,'      ','()[]{}') 
  1126.  
  1127.           /*****************************************************/
  1128.           /*  Count possible file names in the subject line    */
  1129.           /*****************************************************/
  1130.  
  1131.    do k=1 to words(subjline)                    /* loop thru subject line */
  1132.       sword=word(subjline,k)                    /* copy for ease          */
  1133.       if partname~=missing then do              /* already have a name    */
  1134.          if upper(partname)=upper(sword) then do /* handle as found       */
  1135.             spctr=spctr+1                       /* count another          */
  1136.             spartname.0=spctr                   /* increment .0 ctr       */
  1137.             spartname.spctr=word(subjline,k)    /* store it               */
  1138.             spartname.spctr.1=k                 /* which word it is       */  
  1139.             iterate k                           /* skip bin type search   */
  1140.          end
  1141.       end
  1142.       do l=1 to Bintypes.0                      /* loop thru binary types */
  1143.          if upper(substr(sword,1,7))='HTTP://' then iterate
  1144.          if upper(substr(sword,1,4))='WWW.' & upper(right(sword,4))='.COM' then iterate
  1145.          if upper(right(sword,length(bintypes.l)))=upper(bintypes.l) then do
  1146.             spctr=spctr+1                       /* count another          */
  1147.             spartname.0=spctr                   /* increment .0 ctr       */
  1148.             spartname.spctr=word(subjline,k)    /* store it               */
  1149.             spartname.spctr.1=k                 /* which word it is       */  
  1150.             leave l                             /* only count first match */
  1151.          end
  1152.       end 
  1153.    end
  1154.  
  1155.  
  1156.           /*****************************************************/
  1157.           /*  if a part 1 - see how many subject part names    */
  1158.           /*  match actual begin name and where in subject.    */
  1159.           /*****************************************************/
  1160.    spctr=0                                      /* reset to zero b4 using */
  1161.    if partnum=1 then do                /* found via SECTION or begin line */
  1162.       part1cnt=part1cnt+1                       /* another part one piece */
  1163.       Partone.0=part1cnt                        /* store it               */
  1164.       Partone.part1cnt=i                        /* pointer to file array  */     
  1165.       Partone.part1cnt.1=partname               /* name of binary file    */
  1166.       Partone.part1cnt.1.0=0                    /* no matches yet         */
  1167.       Partone.part1cnt.1.1.1.1.1.1.1=subjline   /* store a copy           */
  1168.       if partname~=missing then do k=1 to spartname.0
  1169.          if upper(partname)=upper(spartname.k) then do
  1170.             spctr=spctr+1                       /* increment match ctr    */
  1171.             Partone.part1cnt.1.0=spctr          /* count it               */
  1172.             Partone.part1cnt.1.spctr=spartname.k.1 /* where in subject    */
  1173.          end
  1174.       end
  1175.       else do /* a part one without a part name */
  1176.          Partone.part1cnt.1.0=spartname.0     /* how many in subject line */
  1177.          do k=1 to spartname.0
  1178.             Partone.part1cnt.1.k=spartname.k.1  /* where in subject line  */
  1179.          end
  1180.       end
  1181.    end
  1182.    else do               /* NOT a part 1 piece -- store info for matching */
  1183.       partXcnt=partXcnt+1                       /* another part xxx piece */
  1184.       Partxxx.0=partXcnt                        /* store it               */
  1185.       Partxxx.partXcnt=i                        /* pointer to file array  */     
  1186.       Partxxx.partXcnt.1.1.1.1.1.1.1=subjline   /* store a copy           */
  1187.       if partname~=missing then Partxxx.partXcnt.1=partname /* know name  */
  1188.       Partxxx.partXcnt.1.0=spartname.0        /* how many in subject line */
  1189.       do k=1 to spartname.0
  1190.          Partxxx.partXcnt.1.k=spartname.k.1     /* where in subject line  */
  1191.       end
  1192.    end    /* matches else do - NOT a part 1 piece */
  1193.  
  1194.  
  1195.           /*****************************************************/
  1196.           /*    Look for x/y, (x/y), [x/y], {x/y} formats      */
  1197.           /*    and count how many occurrences                 */
  1198.           /*****************************************************/
  1199.           /*    IF MORE THAN 1 '/' in word skip that word.     */
  1200.           /*   (it is probably a date in the mm/dd/yy form)    */
  1201.           /*****************************************************/
  1202.  
  1203.    if partnum=missing | parttot=missing | parttot>1 then do 
  1204.       do j=1 to words(subjline)
  1205.          testword=word(subjline,j)
  1206.          if pos('/',testword)>0 then do
  1207.             if pos('/',testword)~=lastpos('/',testword) then iterate j
  1208.             testword=translate(testword,' ','/') /* strip "/" character   */
  1209.             pn=strip(word(testword,1))       
  1210.             pt=strip(word(testword,2))
  1211.             if datatype(pn,'N') & datatype(pt,'N') then do
  1212.                subjpn=strip(pn,'L','0')
  1213.                subjpt=strip(pt,'L','0')
  1214.                pncnt=pncnt+1                     /* found a subj part num */
  1215.                ptcnt=ptcnt+1                     /* found a subj total    */
  1216.                if partnum=1 then do              /* from section or begin */
  1217.                   Partone.part1cnt.1.1.0=pncnt   /* store subj part numcnt*/
  1218.                   Partone.part1cnt.1.1.pncnt=subjpn  /* store  part num   */
  1219.                   Partone.part1cnt.1.1.pncnt.1=j     /* which word in sub */
  1220.                   Partone.part1cnt.1.1.1.1.0=ptcnt /* store subj total cnt*/
  1221.                   Partone.part1cnt.1.1.1.1.ptcnt=subjpt /* store part tot */
  1222.                   Partone.part1cnt.1.1.1.1.ptcnt.1=j      /* word in subj */
  1223.                end
  1224.                else do
  1225.                   Partxxx.partXcnt.1.1.0=pncnt   /* store subj part numcnt*/
  1226.                   Partxxx.partXcnt.1.1.pncnt=subjpn  /* store  part num   */
  1227.                   Partxxx.partXcnt.1.1.pncnt.1=j     /* which word in sub */
  1228.                   Partxxx.partXcnt.1.1.1.1.0=ptcnt /* store subj total cnt*/
  1229.                   Partxxx.partXcnt.1.1.1.1.ptcnt=subjpt /* store part tot */
  1230.                   Partxxx.partXcnt.1.1.1.1.ptcnt.1=j      /* word in subj */
  1231.                end
  1232.             end
  1233.          end
  1234.       end
  1235.    end
  1236.  
  1237.           /*****************************************************/
  1238.           /*                                                   */
  1239.           /*       Look for partnumbers in form (xx of yy)     */
  1240.           /*                                                   */
  1241.           /*****************************************************/
  1242.  
  1243.    if partnum=missing | parttot=missing | parttot>1 then do 
  1244.       do j=2 to words(subjline)-1 by 1          /* loop thru subject line */
  1245.          of=word(subjline,j)                      /* copy it for ease     */
  1246.          if upper(of)='OF' then do
  1247.             pn=word(subjline,j-1)
  1248.             pt=word(subjline,j+1)
  1249.             pn=translate(pn,'       ','()[]{}/') 
  1250.             pt=translate(pt,'       ','()[]{}/') 
  1251.             pn=strip(pn)
  1252.             pt=strip(pt)
  1253.             if datatype(pn,'N') & datatype(pt,'N') then do
  1254.                subjpn=strip(pn,'L','0')
  1255.                subjpt=strip(pt,'L','0')
  1256.                pncnt=pncnt+1                     /* found a subj part num */
  1257.                ptcnt=ptcnt+1                     /* found a subj total    */
  1258.                if partnum=1 then do              /* from section or begin */
  1259.                   Partone.part1cnt.1.1.0=pncnt   /* store subj part numcnt*/
  1260.                   Partone.part1cnt.1.1.pncnt=subjpn  /* store  part num   */
  1261.                   Partone.part1cnt.1.1.pncnt.1=j-1   /* which word in sub */
  1262.                   Partone.part1cnt.1.1.1.1.0=ptcnt /* store subj total cnt*/
  1263.                   Partone.part1cnt.1.1.1.1.ptcnt=subjpt /* store part tot */
  1264.                   Partone.part1cnt.1.1.1.1.ptcnt.1=j+1    /* word in subj */
  1265.                end
  1266.                else do
  1267.                   Partxxx.partXcnt.1.1.0=pncnt   /* store subj part numcnt*/
  1268.                   Partxxx.partXcnt.1.1.pncnt=subjpn  /* store  part num   */
  1269.                   Partxxx.partXcnt.1.1.pncnt.1=j-1   /* which word in sub */
  1270.                   Partxxx.partXcnt.1.1.1.1.0=ptcnt /* store subj total cnt*/
  1271.                   Partxxx.partXcnt.1.1.1.1.ptcnt=subjpt /* store part tot */
  1272.                   Partxxx.partXcnt.1.1.1.1.ptcnt.1=j+1    /* word in subj */
  1273.                end
  1274.             end
  1275.          end
  1276.       end
  1277.    end
  1278.  
  1279.           /*****************************************************/
  1280.           /*                                                   */
  1281.           /*       Look for partnumbers in form (xxofyy)       */
  1282.           /*                                                   */
  1283.           /*****************************************************/
  1284.  
  1285.    if partnum=missing | parttot=missing | parttot>1 then do 
  1286.       do j=1 to words(subjline)                 /* loop thru subject line */
  1287.          of=word(subjline,j)                      /* copy it for ease     */
  1288.          if pos('OF',upper(of))>0 then do
  1289.             pn=substr(of,1,pos('OF',upper(of)))
  1290.             pt=substr(of,pos('OF',upper(of))+2)
  1291.             pn=translate(pn,'       ','()[]{}/') 
  1292.             pt=translate(pt,'       ','()[]{}/') 
  1293.             pn=strip(pn)
  1294.             pt=strip(pt)
  1295.             if datatype(pn,'N') & datatype(pt,'N') then do
  1296.                subjpn=strip(pn,'L','0')
  1297.                subjpt=strip(pt,'L','0')
  1298.                pncnt=pncnt+1                     /* found a subj part num */
  1299.                ptcnt=ptcnt+1                     /* found a subj total    */
  1300.                if partnum=1 then do              /* from section or begin */
  1301.                   Partone.part1cnt.1.1.0=pncnt   /* store subj part numcnt*/
  1302.                   Partone.part1cnt.1.1.pncnt=subjpn  /* store  part num   */
  1303.                   Partone.part1cnt.1.1.pncnt.1=j     /* which word in sub */
  1304.                   Partone.part1cnt.1.1.1.1.0=ptcnt /* store subj total cnt*/
  1305.                   Partone.part1cnt.1.1.1.1.ptcnt=subjpt /* store part tot */
  1306.                   Partone.part1cnt.1.1.1.1.ptcnt.1=j      /* word in subj */
  1307.                end
  1308.                else do
  1309.                   Partxxx.partXcnt.1.1.0=pncnt   /* store subj part numcnt*/
  1310.                   Partxxx.partXcnt.1.1.pncnt=subjpn  /* store  part num   */
  1311.                   Partxxx.partXcnt.1.1.pncnt.1=j     /* which word in sub */
  1312.                   Partxxx.partXcnt.1.1.1.1.0=ptcnt /* store subj total cnt*/
  1313.                   Partxxx.partXcnt.1.1.1.1.ptcnt=subjpt /* store part tot */
  1314.                   Partxxx.partXcnt.1.1.1.1.ptcnt.1=j      /* word in subj */
  1315.                end
  1316.             end
  1317.          end
  1318.       end
  1319.    end
  1320.   
  1321. Return
  1322.  
  1323. /**************************************************************************/
  1324. /*                                                                        */
  1325. /*   Attempt to fill out part 1/y information. The assumption is that if  */
  1326. /*   the partname is in the subject and the next word is a valid xx/yy    */
  1327. /*   or 'xx of yy' form, and 'xx'=1 THEN the yy portion is probably       */
  1328. /*   correct. A person could enter an invalid /yy portion, but unlikely.  */
  1329. /*                                                                        */
  1330. /*   If we find a word that fits these conditions, store where the part   */
  1331. /*   number and total are to be found for the final subject line match    */
  1332. /*   logic.                                                               */
  1333. /*                                                                        */
  1334. /**************************************************************************/
  1335. /*     need to handle name in subject but partnums aren't after the pn    */
  1336. /*     assume if we have one and only one 1/y then it is correct.         */
  1337. /*     with or without a partname in the subject. Done -                  */
  1338. /**************************************************************************/
  1339. Phase2Files:
  1340.  
  1341. If Debug then Say time() 'Starting 1/y condition ...'
  1342.  
  1343. /*                   Files                  spart      spart              */
  1344. /* Partone.  format: Pointer.partname.sword.number.loc.total.loc.subjline */
  1345.  
  1346.    do j=1 to Partone.0
  1347.       if Partone.j.1=missing then iterate        /* no partname in subj.  */
  1348.       if Partone.j.1.0>0 & Partone.j.1.1.1.1.0>0 then do  
  1349.          do k=1 to Partone.j.1.0                 /* check name matches    */   
  1350.             do l=1 to Partone.j.1.1.1.1.0        /* against total matches */
  1351.                nword=Partone.j.1.k               /* word with name        */
  1352.                pword=Partone.j.1.1.l.1           /* word with part number */
  1353.                tword=Partone.j.1.1.1.1.l.1       /* word with total value */
  1354.                if pword=tword then nword=nword+1 /* an xx/yy or xxofyy    */
  1355.                               else nword=nword+3 /* an xx of yy form      */
  1356.                testpn=Partone.j.1.1.l            /* xx portion of xx/yy   */
  1357.                if nword=tword & testpn=1 then do
  1358.                   fptr=Partone.j                 /* pointer to files array*/
  1359.                   Files.fptr.1.1.1.1=Partone.j.1.1.1.1.l /* assume correct*/
  1360.                   Partone.j.1.1.1.0=l            /* entry of partnumber   */
  1361.                   Partone.j.1.1.1.1.1.0=l        /* entry of total number */
  1362.                   iterate j                      /* go on to next partone.*/ 
  1363.                end               
  1364.             end
  1365.          end
  1366.          if Partone.j.1.1.0=1  & Partone.j.1.1.1.1.0=1 then do   
  1367.             testpn=Partone.j.1.1.1            /* xx portion of xx/yy   */
  1368.             if testpn=1 then do               /* only one and it is 1/y*/
  1369.                fptr=Partone.j                 /* pointer to files array*/
  1370.                Files.fptr.1.1.1.1=Partone.j.1.1.1.1.1 /* assume correct*/
  1371.                Partone.j.1.1.1.0=1            /* entry of partnumber   */
  1372.                Partone.j.1.1.1.1.1.0=1        /* entry of total number */
  1373.             end 
  1374.          end
  1375.       end
  1376.    end
  1377.  
  1378. /**************************************************************************/
  1379. /*                                                                        */
  1380. /*   Big Assumption Time: If NO total has been found anywhere (section,   */
  1381. /*   mime, or subject) then ASSUME that it is a (1/1). This happens for   */
  1382. /*   a lot of files. The subject just says 'xxxx.jpg' and some text.      */
  1383. /*   The other form is a subject with 1/1 but without the part name.      */
  1384. /*   Consider these valid 1/1 parts also.                                 */
  1385. /*                                                                        */
  1386. /**************************************************************************/
  1387. Phase2Scan:
  1388.  
  1389. If Debug then Say time() 'Starting 1/1 Scanning  ...'
  1390.  
  1391.    do j=1 to Partone.0                           /* loop thru part names  */
  1392.       if Partone.j.1.1.1.1.0=missing then do     /* check all w/o a total */  
  1393.          Partone.j.1.1.1.1.0=1                   /* set as if in sub      */
  1394.          Partone.j.1.1.1.1.1=1                   /* set to value 1        */
  1395.          fptr=Partone.j                          /* pointer to files array*/
  1396.          Files.fptr.1.1.1.1=1                    /* fix in files.         */
  1397.       end
  1398.       else do                                    /* total not missing     */
  1399.          /**********************************************************/
  1400.          /* only one [1/1] in the subject, but partname is not in  */
  1401.          /* a begin line/section/etc. OR not in the subject.       */
  1402.          /*   Consider these valid 1/1 parts also.                 */
  1403.          /**********************************************************/
  1404.          if Partone.j.1.1=missing | Partone.j.1=missing then do
  1405.             if Partone.j.1.1.1.1.0=1 & Partone.j.1.1.1.1.1=1 then do
  1406.                fptr=Partone.j                    /* pointer to files array*/
  1407.                Files.fptr.1.1.1.1=1              /* fix in files.         */
  1408.             end
  1409.          end
  1410.       end
  1411.    end
  1412.  
  1413. Phase2ScanEnd:
  1414.  
  1415. /**************************************************************************/
  1416. /*                                                                        */
  1417. /*   The last group to process in Partone. are the 1/y with information   */
  1418. /*   in the subjects. We will do some comparing against the Partxxx array */
  1419. /*   to try to FIRMLY connect the xx/yy parts to the part 1/yy.           */
  1420. /*                                                                        */
  1421. /**************************************************************************/
  1422. Phase2Match:
  1423.  
  1424. If Debug then Say time() 'Starting 1/yy to xx/yy matching ...'
  1425.  
  1426.    do j=1 to Partone.0                           /* last time thru loop   */
  1427.       if Partone.j.1=missing then iterate        /* missing partname      */
  1428.       if Partone.j.1.1.1.1.0>0 then do           /* check all with totals */  
  1429.          fptr=Partone.j                          /* pointer to files      */
  1430.          if Files.fptr.1.1.1.1>1 then do         /* yep, a 1/y, not a 1/1 */
  1431.             p1match=Partone.j.1.1.1.1.1.1.1      /* subject line          */
  1432.             p1tots=Partone.j.1.1.1.1.0           /* number of tots in sub */
  1433.             pval=Partone.j.1.1.1.0  /* identified in Phase2Files as valid */
  1434.             if pval=missing then pval=Partone.j.1.1.0 /* use LAST PN      */
  1435.             offset=-1                            /* needed for shrinking  */ 
  1436.             do k=1 to Partone.j.1.1.0            /* remove xx word subj   */
  1437.                offset=offset+1                   /* for next time         */
  1438.                p1word=Partone.j.1.1.1.k          /* word to remove        */ 
  1439.                p1word=p1word-offset              /* correction factor     */ 
  1440.                p1match=delword(p1match,p1word,1) 
  1441.             end
  1442.             do m=1 to Partxxx.0                  /* now loop thru xx/yy   */
  1443.                p2match=Partxxx.m.1.1.1.1.1.1.1   /* subject line          */
  1444.                p2tots=Partxxx.m.1.1.1.1.0        /* number of tots in sub */
  1445.                if p2tots~=p1tots then iterate m  /* must be different     */
  1446.                do n=1 to p1tots                  /* compare totals        */
  1447.                  if Partone.j.1.1.1.1.n ~= Partxxx.m.1.1.1.1.n then iterate m
  1448.                end
  1449.                Xptr=Partxxx.m                    /* pointer to files array*/
  1450.                offset=-1                         /* needed for shrinking  */ 
  1451.                do k=1 to Partxxx.m.1.1.0         /* remove xx word subj   */
  1452.                   offset=offset+1                /* for next time         */
  1453.                   p1word=Partone.j.1.1.1.k       /* word to remove        */ 
  1454.                   p1word=p1word-offset           /* correction factor     */ 
  1455.                   p2match=delword(p2match,p1word,1) /* remove same here   */
  1456.                end
  1457.                if p1match=p2match then do            /* should be a match */
  1458.                   Files.Xptr.1.1=Partone.j.1         /* name from part1   */
  1459.                   Files.Xptr.1.1.1=Partxxx.m.1.1.pval
  1460.                   Files.Xptr.1.1.1.1=Partxxx.m.1.1.1.1.pval 
  1461.                   Partxxx.m.1=Partone.j.1             /* name from part1  */
  1462.                end
  1463.             end   /* matches do m=1 to Partxxx.0 */
  1464.          end   /* matches if Files.fptr.1.1>1    */
  1465.       end   /* matches if Partone.j.1.1.1.1.0>0  */
  1466.    end   /* matches do j=1 to Partone.0          */
  1467.  
  1468. Phase2MatchEnd:
  1469.  
  1470. /**************************************************************************/
  1471. /*                                                                        */
  1472. /*   The final group of files are part x/y that failed matching with a    */
  1473. /*   part 1/y. They also had no MIME or Section information available.    */
  1474. /*   Let's TRUST the subject for information IFF there is ONLY 1 partname */
  1475. /*   possible we will use it. Similarly for x/y information. IFF there is */
  1476. /*   only 1 potential partnum/parttot we will use it. If missing or mult- */
  1477. /*   iple, we give it up. Do this for the Partones also but only if B64.  */
  1478. /*                                                                        */
  1479. /**************************************************************************/
  1480. Phase2FinalTry:
  1481.  
  1482. If Debug then Say time() 'Starting use subject only ...'
  1483.  
  1484.    do j=1 to Partxxx.0                           /* last time thru loop   */
  1485.       Xptr=Partxxx.j                             /* pointer to files array*/
  1486.  
  1487.       /* if unknown partname AND only 1 potential name in subject - use it*/
  1488.       if Files.Xptr.1~=missing & Files.Xptr.1.1=missing then do
  1489.          pXnams=Partxxx.j.1.0                    /* numb of names in sub  */
  1490.          if pXnams=1 then do
  1491.             sword=Partxxx.j.1.1
  1492.             subject=Partxxx.j.1.1.1.1.1.1.1
  1493.             partname=word(subject,sword)
  1494.             Files.Xptr.1.1=partname
  1495.          end
  1496.       end
  1497.  
  1498.       /* if unknown partnum AND only 1 potential name in subject - use it*/
  1499.       if Files.Xptr.1~=missing & Files.Xptr.1.1.1=missing then do
  1500.          pXnums=Partxxx.j.1.1.0                  /* number of nums in sub */
  1501.          if pXnums=1 then Files.Xptr.1.1.1=Partxxx.j.1.1.1
  1502.       end
  1503.  
  1504.       /* if unknown parttot AND only 1 potential name in subject - use it*/
  1505.       if Files.Xptr.1~=missing & Files.Xptr.1.1.1.1=missing then do
  1506.          pXtots=Partxxx.j.1.1.1.1.0              /* number of tots in sub */
  1507.          if pXtots=1 then Files.Xptr.1.1.1.1=Partxxx.j.1.1.1.1.1
  1508.       end
  1509.    end
  1510.  
  1511.    do j=1 to Partone.0                           /* last time thru loop   */
  1512.       ptr=Partone.j                              /* pointer to files array*/
  1513.  
  1514.       /* if Partname missing AND B64 and only 1 potential name - use it   */
  1515.       if Files.ptr.1='64' & Files.ptr.1.1=missing then do
  1516.          pnams=Partone.j.1.0                     /* numb of names in sub  */
  1517.          if pnams=1 then do
  1518.             sword=Partone.j.1.1
  1519.             subject=Partone.j.1.1.1.1.1.1.1
  1520.             partname=word(subject,sword)
  1521.             Files.ptr.1.1=partname
  1522.          end
  1523.       end
  1524.    end
  1525.  
  1526.    if DumpPhase2 | Debug then do
  1527.       msg=' '
  1528.       interpret Saycmd
  1529.       msg='(DUMPPHASE2=YES) Dumping Partone array:  ("."=missing)'
  1530.       interpret Saycmd
  1531.       msg='Format: Subject-line'
  1532.       interpret Saycmd
  1533.       msg='        Files                  spart      spart'  
  1534.       interpret saycmd
  1535.       msg='        Pointer partname sword number loc total loc'
  1536.       interpret Saycmd
  1537.       msg=left(dashes,length(msg))
  1538.       interpret Saycmd
  1539.       do j=1 to Partone.0
  1540.          msg=' '
  1541.          interpret Saycmd
  1542.          msg=Partone.j.1.1.1.1.1.1.1            /* subjline               */
  1543.          interpret Saycmd
  1544.          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
  1545.          interpret Saycmd
  1546.          kmax=max(Partone.j.1.0,Partone.j.1.1.0,Partone.j.1.1.1.1.0)  
  1547.          do k=1 to kmax                         /* max depth of loops     */
  1548.             msg=Partone.j Partone.j.1
  1549.             msg=msg||' '||Partone.j.1.k
  1550.             msg=msg||' '||Partone.j.1.1.k
  1551.             msg=msg||' '||Partone.j.1.1.k.1
  1552.             msg=msg||' '||Partone.j.1.1.1.1.k
  1553.             msg=msg||' '||Partone.j.1.1.1.1.k.1
  1554.             interpret Saycmd
  1555.          end
  1556.       end
  1557.       msg=' '
  1558.       interpret Saycmd
  1559.  
  1560.       msg=' '
  1561.       interpret Saycmd
  1562.       msg='(DUMPPHASE2=YES) Dumping Partxxx array:  ("."=missing)'
  1563.       interpret Saycmd
  1564.       msg='Format: Subject-line'
  1565.       interpret Saycmd
  1566.       msg='        Files                  spart      spart'  
  1567.       interpret saycmd
  1568.       msg='        Pointer partname sword number loc total loc'
  1569.       interpret Saycmd
  1570.       msg=left(dashes,length(msg))
  1571.       interpret Saycmd
  1572.       do j=1 to Partxxx.0
  1573.          msg=' '
  1574.          interpret Saycmd
  1575.          msg=Partxxx.j.1.1.1.1.1.1.1            /* subjline               */
  1576.          interpret Saycmd
  1577.          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
  1578.          interpret Saycmd
  1579.          kmax=max(Partxxx.j.1.0,Partxxx.j.1.1.0,Partxxx.j.1.1.1.1.0)  
  1580.          do k=1 to kmax                         /* max depth of loops     */
  1581.             msg=Partxxx.j Partxxx.j.1
  1582.             msg=msg||' '||Partxxx.j.1.k
  1583.             msg=msg||' '||Partxxx.j.1.1.k
  1584.             msg=msg||' '||Partxxx.j.1.1.k.1
  1585.             msg=msg||' '||Partxxx.j.1.1.1.1.k
  1586.             msg=msg||' '||Partxxx.j.1.1.1.1.k.1
  1587.             interpret Saycmd
  1588.          end
  1589.       end
  1590.       msg=' '
  1591.       interpret Saycmd
  1592.    end
  1593.  
  1594. Return
  1595.  
  1596. /**************************************************************************/
  1597. /*                                                                        */
  1598. /*               Report File information in this Phase                    */
  1599. /*                                                                        */
  1600. /* Generate report of all input files for this directory at this point in */
  1601. /* the processing.                                                        */
  1602. /*                                                                        */
  1603. /* Logic: Loop thru Files array picking up the information from the other */
  1604. /* arrays as necessary.                                                   */
  1605. /*                                                                        */
  1606. /**************************************************************************/
  1607. ReportFiles:
  1608.  
  1609.    if ~ShowFiles then signal ReportFilesEnd
  1610.    msg=' '
  1611.    interpret Saycmd
  1612.    msg=dirlist.dirptr ' Processing: ' Files.0 'File(s)'
  1613.    interpret Saycmd   
  1614.    msg=left(dashes,length(msg))   
  1615.    interpret Saycmd   
  1616.  
  1617.    do rptptr=1 to files.0                     /* loop thru files array    */
  1618.       msg='Filename:' Files.rptptr               /* report name of file   */
  1619.       interpret Saycmd
  1620.       msg='Subject: ' Subjinfo.rptptr.1.1        /* report subject line   */
  1621.       interpret Saycmd
  1622.  
  1623.       select
  1624.          when Files.rptptr.1=missing then do 
  1625.             msg='Encoding: Not an encoded file'
  1626.             interpret Saycmd
  1627.             msg=' '
  1628.             interpret Saycmd
  1629.          end
  1630.          when Files.rptptr.1='UU' then do 
  1631.             msg='Encoding: UUencode'
  1632.             interpret Saycmd
  1633.             do pptr=1 to Files.rptptr.1.0
  1634.                msg='Name:    ' Files.rptptr.1.pptr
  1635.                interpret Saycmd
  1636.                msg='Part:    ' Files.rptptr.1.pptr.1 'of' Files.rptptr.1.pptr.1.1
  1637.                interpret Saycmd
  1638.             end
  1639.             msg=' '
  1640.             interpret Saycmd
  1641.          end
  1642.          when Files.rptptr.1='64' then do 
  1643.             msg='Encoding: Base64'
  1644.             interpret Saycmd
  1645.             do pptr=1 to Files.rptptr.1.0
  1646.                msg='Name:    ' Files.rptptr.1.pptr
  1647.                interpret Saycmd
  1648.                msg='Part:    ' Files.rptptr.1.pptr.1 'of' Files.rptptr.1.pptr.1.1
  1649.                interpret Saycmd
  1650.             end
  1651.             msg=' '
  1652.             interpret Saycmd
  1653.          end
  1654.          otherwise encoding=Files.rptptr.1       /* should never happen   */
  1655.       end
  1656.    end
  1657.  
  1658. ReportFilesEnd:
  1659.  
  1660. Return
  1661.  
  1662. /**************************************************************************/
  1663. /*                                                                        */
  1664. /*               Create arrays as needed for processing.                  */
  1665. /*                                                                        */
  1666. /**************************************************************************/
  1667. BuildLists:
  1668.    
  1669.    Temppart.0=0
  1670.    if Files.0>0 then do
  1671.       msg=' '
  1672.       interpret Saycmd 
  1673.    end
  1674.  
  1675.    errorcnt=0
  1676.    pnlen=0                                      /* length of partname     */
  1677.    fnlen=0                                      /* length of filename     */
  1678.   
  1679.    Do fptr=1 to Files.0
  1680.       filename=Files.fptr
  1681.       encode=Files.fptr.1                       /* encoding method        */
  1682.       if encode=missing then iterate            /* not encoded            */
  1683.       Do pptr=1 to Files.fptr.1.0               /* loop thru partnames    */
  1684.          partname=Files.fptr.1.pptr
  1685.          partname=translate(partname,tab,' ')   /* for names with blanks  */
  1686.          partnum =Files.fptr.1.pptr.1
  1687.          parttot =Files.fptr.1.pptr.1.1
  1688.          pnlen=max(pnlen,length(partname))      /* longest length for rpt */
  1689.          fnlen=max(fnlen,length(filename))      /* longest length for rpt */
  1690.  
  1691.          if partnum~=missing & parttot~=missing & partname~=missing & ,
  1692.             filename~=missing then do
  1693.                Temppart.0=1+Temppart.0
  1694.                ptr=Temppart.0
  1695.                Temppart.ptr=partname encode parttot partnum filename fptr pptr
  1696.          end
  1697.          else do
  1698.            if errorcnt=0 then do
  1699.               msg='Errors: Filename Encode Partname Partnum Parttot Pptr ("."=missing)'
  1700.               interpret saycmd
  1701.               msg=left(dashes,length(msg))
  1702.               interpret Saycmd
  1703.               errorcnt=1
  1704.            end
  1705.            msg='(E) Missing information for file:' filename encode partname partnum parttot pptr
  1706.            interpret saycmd
  1707.          end
  1708.       end
  1709.    end
  1710.  
  1711.    call QSORT(1, Temppart.0, Temppart)          /* put into order         */
  1712.  
  1713.    if DEBUG=YES then do
  1714.       msg=' '
  1715.       interpret Saycmd
  1716.        msg='Dumping Temppart array:'
  1717.        interpret saycmd
  1718.        msg=left(dashes,length(msg))
  1719.        interpret Saycmd
  1720.        do j=1 to Temppart.0
  1721.           msg=Temppart.j
  1722.           interpret Saycmd
  1723.        end
  1724.        msg=' '
  1725.        interpret Saycmd
  1726.    end
  1727.  
  1728.    oldname=missing
  1729.    oldtotal=missing
  1730.    oldencode=missing
  1731.    Parts.=missing
  1732.    Parts.0=0
  1733.  
  1734.    do j=1 to Temppart.0
  1735.       if word(Temppart.j,1)~=oldname | word(Temppart.j,2)~=oldencode |,
  1736.          word(Temppart.j,3)~=oldtotal then do
  1737.          oldname=word(Temppart.j,1)              /* Save to old name      */         
  1738.          oldencode=word(Temppart.j,2)            /* Save to old encode    */
  1739.          oldtotal=word(Temppart.j,3)             /* Save to old total     */
  1740.          Parts.0=1+Parts.0                       /* a new partname        */
  1741.          ptr=Parts.0                             /* count it              */
  1742.          partname=word(Temppart.j,1)             /* get partname          */
  1743.          partname=translate(partname,' ',tab)    /* return blanks to name */
  1744.          Parts.ptr=partname                      /* store partname        */     
  1745.          Parts.ptr.1=word(Temppart.j,3)          /* Total Parts Expected  */
  1746.          partnum=word(Temppart.j,4)              /* part number sets slot */   
  1747.          filename=word(Temppart.j,5)             /* filename              */   
  1748.          fptr=word(Temppart.j,6)                 /* pointer into Files.   */
  1749.          pptr=word(Temppart.j,7)                 /* pointer for partname  */
  1750.          Parts.ptr.1.partnum=filename            /* store it in pn slot   */
  1751.          Parts.ptr.1.partnum.1=fptr              /* pointer into Files.   */
  1752.          Parts.ptr.1.partnum.1.1=pptr            /* pointer to part info  */
  1753.          Parts.ptr.1.0=1                         /* indicate 1 part found */
  1754.       end
  1755.       else do
  1756.          partnum=word(Temppart.j,4)              /* part number sets slot */   
  1757.          filename=word(Temppart.j,5)             /* filename              */   
  1758.          fptr=word(Temppart.j,6)                 /* pointer into Files.   */
  1759.          pptr=word(Temppart.j,7)                 /* pointer for partname  */
  1760.          if Parts.ptr.1.partnum=missing then do  /* slot not already used */
  1761.             Parts.ptr.1.0=1+Parts.ptr.1.0        /* 1 more part found     */
  1762.          end  /* don't count mult. but use nth version - fixes Apple/DBL  */
  1763.          else do
  1764.             oldfptr=Parts.ptr.1.partnum.1
  1765.             oldpptr=Parts.ptr.1.partnum.1.1
  1766.             miscinfo.oldfptr.oldpptr.1.1.1.1=YES /* mark as duplicate     */
  1767.          end
  1768.          Parts.ptr.1.partnum=filename            /* put filename in it    */
  1769.          Parts.ptr.1.partnum.1=fptr              /* pointer into Files.   */
  1770.          Parts.ptr.1.partnum.1.1=pptr            /* pointer to part info  */
  1771.       end
  1772.    end
  1773.  
  1774.    if ~ShowParts then signal BuildListsEnd
  1775.    if  parts.0=0 then signal BuildListsEnd
  1776.  
  1777.    msg=' '
  1778.    interpret Saycmd
  1779.    msg='Encoded parts:'
  1780.    interpret saycmd
  1781.    msg='Output name'
  1782.    msg=overlay('xxx of yyy',msg,pnlen+5)
  1783.    msg=overlay('Input Name',msg,length(msg)+5)
  1784.    interpret saycmd
  1785.    msg=left(dashes,length(msg))
  1786.    interpret Saycmd
  1787.  
  1788.  
  1789.    do j=1 to Parts.0 
  1790.       msg=' ' 
  1791.       interpret saycmd
  1792.       do k=1 to Parts.j.1
  1793.          msg=Parts.j
  1794.          msg=overlay(k,msg,pnlen+8-length(k))
  1795.          msg=overlay('of',msg,length(msg)+2)
  1796.          msg=overlay(Parts.j.1,msg,length(msg)+2)
  1797.          tfile=right(parts.j.1.k,fnlen)
  1798.          msg=overlay(tfile,msg,length(msg)+8-length(Parts.j.1))
  1799.          interpret Saycmd
  1800.       end
  1801.    end
  1802.    msg=' '
  1803.    interpret Saycmd
  1804.  
  1805. BuildListsEnd:
  1806.  
  1807. Return
  1808.  
  1809. /**************************************************************************/
  1810. /*                                                                        */
  1811. /*                       Finally do the Decoding.                         */
  1812. /*             Strip ALL PATH information prior to decoding.              */
  1813. /**************************************************************************/
  1814. DecodeFiles:
  1815.  
  1816.    if verbose then say time() 'Starting Decoding ...' 
  1817.  
  1818.    pragma('D',dest)                    /* change directory to destination */
  1819.    curdir=pragma('D')                  /* check to make sure changed      */
  1820.  
  1821.  
  1822.    if ShowDecode & parts.0 > 0 then do
  1823.       msg=' '
  1824.       interpret Saycmd
  1825.       msg='Decoding to Directory ... 'curdir
  1826.       interpret Saycmd
  1827.       msg=left(dashes,length(msg))
  1828.       interpret Saycmd
  1829.       msg=' '
  1830.       interpret Saycmd
  1831.    end
  1832.  
  1833.    do i=1 to parts.0                       /* loop thru all output files  */
  1834.       if parts.i.1=parts.i.1.0 then do     /* we have all necessary parts */
  1835.          Filesptr=parts.i.1.1.1            /* pointer into Files array    */
  1836.          Pptr=parts.i.1.1.1.1              /* pointer to part within file */
  1837.          encode=Files.filesptr.1           /* type of encoding            */
  1838.          partname=parts.i                  /* get partname for decoding   */
  1839.          if pos('/',partname)>0 then do    /* strip path information      */
  1840.             partname=substr(partname,lastpos('/',partname)+1)
  1841.          end
  1842.          else do
  1843.             if pos(':',partname)>0 then do 
  1844.                partname=substr(partname,lastpos(':',partname)+1)
  1845.             end
  1846.          end         
  1847.          msg=partname                      /* name of output file         */
  1848.          filestr=''                        /* init to null on new partname*/  
  1849.          if encode='UU' then msgenc='UU  decoding from -'
  1850.                         else msgenc='B64 decoding from -' 
  1851.          msg=overlay(msgenc,msg,pnlen+3)
  1852.  
  1853.          if replace=NO then do             /* check replace output file   */
  1854.             if exists(partname) then do     /* already exists              */
  1855.                if Miscinfo.Filesptr.pptr.1=missing then do /* decode~=YES */
  1856.                   filestr=''               /* init to null for file list  */
  1857.                   do k=1 to parts.i.1      /* build list of files skipped */  
  1858.                      tfile=right(parts.i.1.k,fnlen)
  1859.                      tfptr=parts.i.k.1.1   /* file pointer for this part  */
  1860.                      tpptr=parts.i.k.1.1.1
  1861.                      Miscinfo.tfptr.tpptr.1.1.1.1=YES /* duplicate output */ 
  1862.                      if filestr='' then filestr=tfile
  1863.                                    else filestr=filestr||' '||tfile
  1864.                   end  
  1865.                   msg=partname              /* reset to just partname      */
  1866.                   msg=overlay('exists; skipping  -',msg,pnlen+3)
  1867.                   msg=overlay(Filestr,msg,length(msg)+3)
  1868.                   if ShowDecode then interpret SayCmd
  1869.                   iterate i
  1870.                end
  1871.                else do  /* we decoded it as part of another partname      */
  1872.                   filestr=parts.i.1.1      /* should be 1/1 of another    */
  1873. say 'Hit else do in REPLACE=NO of decodefiles: for ' filestr files.filesptr
  1874.                   Call IssueDecodeMsg
  1875.                   Call FileNoteOut
  1876.                   iterate i
  1877.                end
  1878.             end
  1879.          end
  1880.  
  1881.          Call BldDecodeStr
  1882.  
  1883.          If encode='UU' then Call DecodeUUFiles
  1884.                         else Call Decode64Files
  1885.  
  1886.       end   /* matches parts.i.1=parts.i.1.0 */
  1887.    end   /* matches do i=1 to parts.0 */
  1888.  
  1889. /**************************************************************************/
  1890. /*                                                                        */
  1891. /*   Handle DELETEAFTER and DELETEDUPS options.                           */
  1892. /*                                                                        */
  1893. /*   Delete any decoded files and any duplicates, but only IF  no errors  */
  1894. /*   The CHOPPED files may have duplicate names and decoded in a single   */
  1895. /*   file and the possibility there was an error for only 1 of the pieces.*/
  1896. /*                                                                        */
  1897. /*   The files that weren't chopped only need to be checked if delete     */
  1898. /*   duplicates was specified. If so then the dup flag is set in Miscinfo.*/
  1899. /*                                                                        */
  1900. /**************************************************************************/
  1901.  
  1902.    do i=1 to Files.0
  1903.       deccnt=0
  1904.       dupcnt=0
  1905.       delflag=NO
  1906.       partcnt=Files.i.1.0
  1907.       if partcnt=0 then iterate i
  1908.       do j=1 to partcnt
  1909.          if Miscinfo.i.j.1=YES then deccnt=deccnt+1
  1910.          if Miscinfo.i.j.1.1.1.1=YES then dupcnt=dupcnt+1
  1911.       end
  1912.       if DeleteAfter & deccnt>0 & deccnt+dupcnt=partcnt then delflag=YES
  1913.       if DeleteDups & dupcnt=partcnt then delflag=YES
  1914.       if delflag & ~scanonly then do
  1915.          Address Command 'Delete ' DWassignIn||Files.i 'QUIET'
  1916.       end
  1917.    end
  1918.  
  1919.    pragma('D',progdir)                     /* change dir back to progdir  */
  1920.    curdir=pragma('D')                      /* check to make sure changed  */
  1921.  
  1922.    if debug then do
  1923.       msg=' '
  1924.       interpret Saycmd
  1925.       msg='Changing Directory to ... 'curdir
  1926.       interpret Saycmd
  1927.       msg=' '
  1928.       interpret Saycmd
  1929.    end
  1930.  
  1931. DecodeFilesEnd:
  1932.  
  1933.    if verbose then say time() 'Done Decoding ...' 
  1934.    
  1935. Return
  1936.    
  1937. /**************************************************************************/
  1938. /*                                                                        */
  1939. /*                Handle chopping, joining, ect. for decoding             */
  1940. /*                                                                        */
  1941. /**************************************************************************/
  1942. BldDecodeStr:
  1943.  
  1944.    joinstr=''                                       /* init to null       */
  1945.    chopflag=NO                                      /* no chopping done   */
  1946.  
  1947.    Select
  1948.       when parts.i.1=1 & Files.filesptr.1.0=1 then do /* a single 1/1 file*/
  1949.          filestr=right(parts.i.1.1,fnlen)           /* name of file       */
  1950.          filein=DWassignIN||parts.i.1.1             /* with assign path   */
  1951.          Miscinfo.Filesptr.pptr.1=YES               /* mark as decoded    */
  1952.          Call IssueDecodeMsg
  1953.       end         
  1954.       when parts.i.1=1 & Files.filesptr.1.0>1 then do
  1955.          filein=DWassignIN||parts.i.1.1             /* with assign path   */
  1956.          if Miscinfo.Filesptr.pptr.1.1.1=missing then Call ChopFile
  1957.          filestr=right(parts.i.1.1,fnlen)
  1958.          filein=DWtemp||Files.filesptr||'.'||pptr   /* build chopped name */
  1959.          Miscinfo.Filesptr.pptr.1=YES               /* mark as decoded    */
  1960.          Call IssueDecodeMsg
  1961.          chopflag=YES                            /* filein is a T:CHOPPED */
  1962.       end
  1963.       when parts.i.1>1 then do
  1964.          filestr=''
  1965.          do k=1 to parts.i.1          /* loop thru list of files required */              
  1966.             Filesptr=parts.i.1.k.1         /* pointer into Files array    */
  1967.             do j=1 to Files.Filesptr.1.0   /* mark all multi's as decoded */
  1968.                Miscinfo.Filesptr.j.1=YES   /* mark as decoded             */
  1969.             end
  1970.             tfile=right(parts.i.1.k,fnlen)
  1971.             if filestr='' then filestr=tfile
  1972.                           else filestr=filestr||' '||tfile
  1973.             joinstr=joinstr||' '||DWassignIN||parts.i.1.k
  1974.          end  /* matches do k=1 to parts.i.1 */              
  1975.          Call IssueDecodeMsg
  1976.          filein=DWtemp'DWdecode.temp' 
  1977.          Address Command 'Join ' joinstr 'AS' filein
  1978.          joinrc=rc
  1979.          if joinrc>0 then do
  1980.             say '   JOIN returned rc='joinrc 'for 'partname
  1981.             say joinstr 'AS' filein
  1982.          end
  1983.       end
  1984.       otherwise do
  1985.         say 'Found otherwise in BldDecodeStr for :'parts.i Files.filesptr
  1986.         signal BldDecodeStrEnd
  1987.       end
  1988.    End
  1989.  
  1990. BldDecodeStrEnd:
  1991.  
  1992. Return
  1993.  
  1994. /**************************************************************************/
  1995. /*                                                                        */
  1996. /*                Handle the UU encoded decoding.                         */
  1997. /*                                                                        */
  1998. /**************************************************************************/
  1999. DecodeUUFiles:
  2000.  
  2001.    if scanonly=yes then signal DecodeUUFilesEnd
  2002.  
  2003.    UUcmdx=UUcmd                                  /* copy for replacement  */
  2004.  
  2005.    do j=1 to words(UUcmdx)
  2006.       select
  2007.         when upper(word(UUcmdx,j))='%SF' then do
  2008.            wptr=wordindex(UUcmdx,j)-1
  2009.            UUcmdx=delword(UUcmdx,j,1)
  2010.            UUcmdx=insert(filein,UUcmdx,wptr,length(filein)+1,' ')
  2011.         end
  2012.         when upper(word(UUcmdx,j))='%DF' then do
  2013.            wptr=wordindex(UUcmdx,j)-1
  2014.            UUcmdx=delword(UUcmdx,j,1)
  2015.            destfile=dest||partname
  2016.            UUcmdx=insert(destfile,UUcmdx,wptr,length(destfile)+1,' ')
  2017.         end
  2018.         when upper(word(UUcmdx,j))='%SD' then do
  2019.            wptr=wordindex(UUcmdx,j)-1
  2020.            UUcmdx=delword(UUcmdx,j,1)
  2021.            UUcmdx=insert(source,UUcmdx,wptr,length(source)+1,' ')
  2022.         end
  2023.         when upper(word(UUcmdx,j))='%DD' then do
  2024.            wptr=wordindex(UUcmdx,j)-1
  2025.            UUcmdx=delword(UUcmdx,j,1)
  2026.            UUcmdx=insert(dest,UUcmdx,wptr,length(dest)+1,' ')
  2027.         end
  2028.         otherwise nop
  2029.       end
  2030.    end   
  2031.  
  2032.    Address Command UUcmdx 
  2033.    decrc=rc
  2034.  
  2035.    if decrc >= UUcmdFail then do         /* should be a CATASTROPHIC ERROR */
  2036.       say '***** FATAL ERROR LEVEL - exiting .....'
  2037.       signal Cleanup                     /* QUIT - DO NOT CONTINUE         */
  2038.    end 
  2039.  
  2040.    if decrc>0 then do
  2041.       msg='*** Decode returned rc='decrc 'for 'partname 'from file(s)' filestr
  2042.       interpret SayCmd   
  2043.       Miscinfo.Filesptr.pptr.1=NO                   /* DECODE had errors  */
  2044.    end
  2045.  
  2046.    UUOutCnt=UUOutCnt+1
  2047.  
  2048.    Call FileNoteOut
  2049.  
  2050.    if chopflag=YES then do             /* delete ALL chopped inputs always*/
  2051.       Address Command 'Delete ' filein 'QUIET'
  2052.    end 
  2053.  
  2054. DecodeUUFilesEnd:
  2055.  
  2056. Return
  2057.  
  2058. /**************************************************************************/
  2059. /*                                                                        */
  2060. /*                Handle the Base64 encoded decoding.                     */
  2061. /*                                                                        */
  2062. /**************************************************************************/
  2063. Decode64Files:
  2064.  
  2065.    if scanonly=yes then signal Decode64FilesEnd
  2066.  
  2067.    B64cmdx=Base64cmd                             /* copy for replacement  */
  2068.  
  2069.    do j=1 to words(B64cmdx)
  2070.       select
  2071.         when upper(word(B64cmdx,j))='%SF' then do
  2072.            wptr=wordindex(B64cmdx,j)-1
  2073.            B64cmdx=delword(B64cmdx,j,1)
  2074.            B64cmdx=insert(filein,B64cmdx,wptr,length(filein)+1,' ')
  2075.         end
  2076.         when upper(word(B64cmdx,j))='%DF' then do
  2077.            wptr=wordindex(B64cmdx,j)-1
  2078.            B64cmdx=delword(B64cmdx,j,1)
  2079.            destfile='"'||dest||partname||'"'
  2080.            B64cmdx=insert(destfile,B64cmdx,wptr,length(destfile)+1,' ')
  2081.         end
  2082.         when upper(word(B64cmdx,j))='%SD' then do
  2083.            wptr=wordindex(B64cmdx,j)-1
  2084.            B64cmdx=delword(B64cmdx,j,1)
  2085.            B64cmdx=insert(source,B64cmdx,wptr,length(source)+1,' ')
  2086.         end
  2087.         when upper(word(B64cmdx,j))='%DD' then do
  2088.            wptr=wordindex(B64cmdx,j)-1
  2089.            B64cmdx=delword(B64cmdx,j,1)
  2090.            B64cmdx=insert(dest,B64cmdx,wptr,length(dest)+1,' ')
  2091.         end
  2092.         otherwise nop
  2093.       end
  2094.    end   
  2095.  
  2096.    Address Command B64cmdx 
  2097.    decrc=rc
  2098.  
  2099.    if decrc>=B64cmdFail then do
  2100.       say '***** FATAL ERROR LEVEL - exiting .....'
  2101.       signal Cleanup                     /* QUIT - DO NOT CONTINUE         */
  2102.    end
  2103.  
  2104.    if decrc>0 then do
  2105.       msg='*** Decode returned rc='decrc 'for 'partname 'from file(s)' filestr
  2106.       interpret SayCmd   
  2107.       Miscinfo.Filesptr.pptr.1=NO                   /* DECODE had errors  */
  2108.    end
  2109.  
  2110.    B64OutCnt=B64OutCnt+1
  2111.  
  2112.    Call FileNoteOut
  2113.  
  2114.    if chopflag=YES then do             /* delete ALL chopped inputs always*/
  2115.       Address Command 'Delete ' filein 'QUIET'
  2116.    end 
  2117.  
  2118. Decode64FilesEnd:
  2119.  
  2120. Return
  2121.  
  2122. /**************************************************************************/
  2123. /*                                                                        */
  2124. /*  Chop Base64 files into pieces for decoding. Use startlines found prev.*/
  2125. /*                                                                        */
  2126. /**************************************************************************/
  2127. ChopFile:       
  2128.  
  2129.    goodopen=open('IN',filein,'R')
  2130.    if ~goodopen then do
  2131.       msg='(E) Error opening 'filein 'for chopping '
  2132.       interpret Saycmd
  2133.    end
  2134.  
  2135.    start=1                                       /* start with line 1     */
  2136.  
  2137.    do j=1 to Files.filesptr.1.0                  /* loop thru partnames   */
  2138.  
  2139. If Debug then say 'Chopping ' Files.filesptr ' into ' Files.filesptr.1.0 ' pieces'
  2140.  
  2141.       Miscinfo.Filesptr.j.1.1.1=YES           /* indicate file is chopped */ 
  2142.  
  2143.       if j=1 then start=1                        /* first entry           */
  2144.              else start=Files.filesptr.1.j.1.1.1
  2145.  
  2146.       if start=missing then do
  2147.          say 'Startline for ' Files.filesptr Files.filesptr.1.j 'is invalid ... exiting'
  2148.          exit
  2149.       end
  2150.  
  2151.       next=j+1
  2152.  
  2153.       if j=Files.filesptr.1.0 then stop=999999   /* last entry - no next  */
  2154.       else do
  2155.          stop=Files.filesptr.1.next.1.1.1
  2156.          if stop=missing then do
  2157.             say 'Stopline for ' Files.filesptr  Files.filesptr.1.next 'is invalid ... exiting'
  2158.             exit
  2159.          end
  2160.          stop=stop-1
  2161.       end
  2162.  
  2163.       if Miscinfo.Filesptr.j.1.1.1.1=missing then do
  2164.          fileout=DWtemp||Files.filesptr||'.'||j     /* build chopped name */
  2165.          goodopen=open('OUT',fileout,'W')
  2166.          if ~goodopen then do
  2167.             msg='(E) Error opening 'fileout 
  2168.             interpret Saycmd
  2169.          end
  2170.       end
  2171.  
  2172. If Debug then say '      Writing ... ' START STOP fileout 
  2173.  
  2174.       do k=start to stop                         /* read/write lines out  */
  2175.          linein=readln('IN')
  2176.          if ~eof('IN') then do
  2177.             if Miscinfo.Filesptr.j.1.1.1.1=missing then do
  2178.                result=writeln('OUT',linein)
  2179.             end 
  2180.          end 
  2181.          else do 
  2182.             k=stop                               /* EOF - quit looping    */
  2183.          end 
  2184.       end 
  2185.       if Miscinfo.Filesptr.j.1.1.1.1=missing then do
  2186.          result=close('OUT')                     /* close output file     */
  2187.       end
  2188.    end
  2189.  
  2190.    result=close('IN')
  2191.  
  2192. Return
  2193.  
  2194. /**************************************************************************/
  2195. /*                                                                        */
  2196. /*                    Report Decoding operations.                         */
  2197. /*                                                                        */
  2198. /**************************************************************************/
  2199. IssueDecodeMsg:
  2200.  
  2201.    msg=overlay(filestr,msg,length(msg)+3)
  2202.    if ShowDecode then interpret SayCmd
  2203.  
  2204. Return
  2205.  
  2206. /**************************************************************************/
  2207. /*                                                                        */
  2208. /*                Filenote output files as specified.                     */
  2209. /*                                                                        */
  2210. /* Handle escaping Amiga Special Characters. This requires an apostrophe  */
  2211. /* to be placed before #,%,? in filenames.                                */
  2212. /*                                                                        */
  2213. /**************************************************************************/
  2214. FileNoteOut:   
  2215.  
  2216.    foundspec=pos("'",partname)
  2217.    do while foundspec > 0
  2218.       part1=substr(partname,1,foundspec-1)
  2219.       part2=substr(partname,foundspec+1)
  2220.       partname=part1||"''"||part2
  2221.       foundspec=pos("'",part2) 
  2222.       if foundspec>0 then foundspec=foundspec+length(part1)+2
  2223.    end
  2224.  
  2225.    foundspec=pos("%",partname)
  2226.    do while foundspec > 0
  2227.       part1=substr(partname,1,foundspec-1)
  2228.       part2=substr(partname,foundspec+1)
  2229.       partname=part1||"''%"||part2
  2230.       foundspec=pos("%",part2) 
  2231.       if foundspec>0 then foundspec=foundspec+length(part1)+3
  2232.    end
  2233.  
  2234.    foundspec=pos("#",partname)
  2235.    do while foundspec > 0
  2236.       part1=substr(partname,1,foundspec-1)
  2237.       part2=substr(partname,foundspec+1)
  2238.       partname=part1||"''#"||part2
  2239.       foundspec=pos("#",part2) 
  2240.       if foundspec>0 then foundspec=foundspec+length(part1)+3
  2241.    end
  2242.  
  2243.    foundspec=pos("?",partname)
  2244.    do while foundspec > 0
  2245.       part1=substr(partname,1,foundspec-1)
  2246.       part2=substr(partname,foundspec+1)
  2247.       partname=part1||"''?"||part2
  2248.       foundspec=pos("?",part2) 
  2249.       if foundspec>0 then foundspec=foundspec+length(part1)+3
  2250.    end
  2251.  
  2252.    foundspec=pos("~",partname)
  2253.    do while foundspec > 0
  2254.       part1=substr(partname,1,foundspec-1)
  2255.       part2=substr(partname,foundspec+1)
  2256.       partname=part1||"''~"||part2
  2257.       foundspec=pos("~",part2) 
  2258.       if foundspec>0 then foundspec=foundspec+length(part1)+3
  2259.    end
  2260.   
  2261.    if filenote~='' & Miscinfo.Filesptr.pptr.1.1=missing then do
  2262.       interpret intfnote fnote
  2263.       fnotex=substr(fnotex,1,79)
  2264.       fncmd="Address Command 'Filenote "||'"'||partname||'" "'||fnotex||'"'||" '"
  2265.       interpret fncmd
  2266.       fnrc=rc
  2267.       if fnrc>0 then do
  2268.          say '   Filenote returned rc='fnrc 'for 'partname 'from 'filein
  2269.       end
  2270.       Miscinfo.Filesptr.pptr.1.1=YES             /* mark as filenoted     */
  2271.    end 
  2272.  
  2273. Return
  2274.  
  2275. /**************************************************************************/
  2276. /*                                                                        */
  2277. /*               Issue any Warning  messages we may have                  */
  2278. /*                                                                        */
  2279. /**************************************************************************/
  2280. IssueWarnings:
  2281.  
  2282.    if warnings.0>0 then do
  2283.       msg=' '
  2284.       interpret Saycmd
  2285.    end
  2286.    do j=1 to warnings.0
  2287.       msg=warnings.j
  2288.       interpret Saycmd
  2289.    end
  2290.  
  2291. Return
  2292.  
  2293. /**************************************************************************/
  2294. /*                                                                        */
  2295. /*               Convert Date: line in header to timestamp                */
  2296. /*                                                                        */
  2297. /**************************************************************************/
  2298. TimeStamp:
  2299.  
  2300.    datemsg=upper(datemsg)                       /* upper case it          */   
  2301.    if pos(',',datemsg)>0 then datemsg=substr(datemsg,pos(',',datemsg)+1)
  2302.    datemsg=strip(datemsg)    
  2303.   
  2304.    Call CalcDays
  2305.  
  2306. Return
  2307.  
  2308. /**************************************************************************/
  2309. /*                                                                        */
  2310. /*               Calculate a value for year+month+day                     */
  2311. /*                                                                        */
  2312. /**************************************************************************/
  2313. CalcDays:
  2314.  
  2315.    leap=0                                       /* assume not a leap year */
  2316.    year=word(datemsg,3)                         /* year portion of msg    */
  2317.    if year<100 then do                          /* fix 2 digit years      */
  2318.       sdate=date('S')                           /* yyyymmdd               */
  2319.       year=left(sdate,4)                        /* get just the yyyy part */
  2320.    end
  2321.    month=word(datemsg,2)                        /* month portion of msg   */
  2322.    day=word(datemsg,1)                          /* day portion of msg     */
  2323.    time=word(datemsg,4)                         /* time portion of msg    */
  2324.    offset=word(datemsg,5)                       /* offset from GMT        */
  2325.    parse var time hour ':' min ':' second       /* get time pieces        */
  2326.    Select
  2327.       when month='JAN' then month=0
  2328.       when month='FEB' then do        /* not worth the cycles for 2100AD  */   
  2329.          month=31
  2330.          if year//4=0 then leap=1               
  2331.       end
  2332.       when month='MAR' then month=59+leap       
  2333.       when month='APR' then month=90+leap
  2334.       when month='MAY' then month=120+leap
  2335.       when month='JUN' then month=151+leap
  2336.       when month='JUL' then month=181+leap
  2337.       when month='AUG' then month=212+leap
  2338.       when month='SEP' then month=243+leap
  2339.       when month='OCT' then month=273+leap
  2340.       when month='NOV' then month=304+leap
  2341.       when month='DEC' then month=334+leap
  2342.       otherwise do
  2343.          msg=' '
  2344.          interpret Saycmd
  2345.          msg='Date Error processing file' Files.i 
  2346.          interpret Saycmd
  2347.          msg='     ' datemsg
  2348.          interpret Saycmd
  2349.       end
  2350.    end
  2351.  
  2352.    days=day+month+(year*365)
  2353.  
  2354. Return
  2355.  
  2356. /**************************************************************************/
  2357. /*                                                                        */
  2358. /*               Do all of the basic initialization stuff.                */
  2359. /*                                                                        */
  2360. /**************************************************************************/
  2361. Init:
  2362.  
  2363.    Call ChangeDir                    /* Change to PROGDIR:                */
  2364.    Call InternalDefaults             /* init internal default values      */
  2365.    Call CmdOverrides                 /* load and test cmd line options    */
  2366.    Call ReadPrefs                    /* load and test PrefsFile options   */
  2367.    Call SetParms                     /* set values based on final options */
  2368.    Call LoadSecTab                   /* load Section: identifier info     */
  2369.    Call LoadBase64Types              /* load B64 start line indicators    */
  2370.    Call LoadBinTypes                 /* load binary types to handle       */
  2371.    Call LoadEncTypes                 /* load MIME encoding information    */
  2372.    Call EnsureLibs                   /* add necessary libs if needed      */
  2373.  
  2374.    if SkipFrom | DeleteFrom then Call LoadSkipFroms  /* load table        */ 
  2375.  
  2376.    if SkipSubject | DeleteSubject then Call LoadSkipSubjects 
  2377.  
  2378.    if (DumpOpts | Debug) then Call DumpOpts /* wants options list on rpt  */
  2379.  
  2380.    if Recursive then do                     /* Recursive=YES option       */ 
  2381.       Call Getdirs                          /* get directories            */
  2382.    end
  2383.  
  2384.    if (ShowDirs | Debug) then Call DumpDirs /* wants dir listing on rpt   */
  2385.  
  2386. Return
  2387.  
  2388. /**************************************************************************/
  2389. /*                                                                        */
  2390. /*     Change directory to that of this program. Ensures that we find     */
  2391. /*                        all of the files we need                        */
  2392. /*                                                                        */
  2393. /**************************************************************************/
  2394. ChangeDir:
  2395.  
  2396.    
  2397.    Parse UPPER source invoked results called resolved ext host
  2398.    progdir=substr(resolved,1,pos('DWDECODE',resolved)-1)
  2399.    origdir=pragma('D',progdir)
  2400.  
  2401. Return
  2402.  
  2403. /**************************************************************************/
  2404. /*                                                                        */
  2405. /*     These values are hard coded and can't be overridden                */
  2406. /*                                                                        */
  2407. /**************************************************************************/
  2408. InternalDefaults:
  2409.  
  2410.  
  2411.    YES=1                                           /* a few useful values */
  2412.    TRUE=1                                          /* a few useful values */
  2413.    ON=1                                            /* a few useful values */
  2414.    
  2415.    NO=0                                            /* a few useful values */
  2416.    FALSE=0                                         /* a few useful values */
  2417.    OFF=0                                           /* a few useful values */
  2418.  
  2419.    DONE=0                                          /* a few useful values */
  2420.  
  2421.    tab='09'x                                       /* tab character value */
  2422.    dashes=copies('-',72)              /* dashed line for report divisions */
  2423.    missing='.'                                     /* var for array init  */
  2424.  
  2425.    infolines=18               /* top lines of this program used for intro */
  2426.    delaymsg.0=infolines                        /* startup lines - delayed */
  2427.    do i=1 to infolines                         
  2428.       delaymsg.i=sourceline(i)
  2429.    end
  2430.  
  2431.    intfnote='fnotex='               /* used for creating output filenotes */ 
  2432.  
  2433.    SayCmd='Say msg'                 /* write messages to console not Log  */
  2434.  
  2435.  
  2436. /**************************************************************************/
  2437. /*                                                                        */
  2438. /*     These values are used if not overridden by the Prefs file          */
  2439. /*                     or as command line arguments.                      */
  2440. /*                                                                        */
  2441. /**************************************************************************/
  2442.  
  2443. int.0=64
  2444. int.1 ='B64cmdFail        BF     N    20'
  2445. int.2 ='Base64Cmd         BC     F    Base64Decode %SF %DF USEMINLEN > nil:'
  2446. int.3 ='Base64TypesFile   B64F   F    DWdecode.Base64.Types'
  2447. int.4 ='BinTypesFile      BTF    F    DWdecode.Binary.Types'
  2448. int.5 ='Debug             DB     B    NO'
  2449. int.6 ='DeleteAfter       DELA   B    NO'
  2450. int.7 ='DeleteDups        DELD   B    NO'
  2451. int.8 ='DeleteFrom        DELF   B    NO'
  2452. int.9 ='DeleteOld         DELO   B    NO'
  2453. int.10='DeleteSubject     DELS   B    NO'
  2454. int.11='DeleteText        DELT   B    NO'
  2455. int.12='Dest              D      F    . '
  2456. int.13='Dump64Files       D64F   B    NO'        
  2457. int.14='DumpBase64Types   D64T   B    NO'        
  2458. int.15='DumpBinTypes      DBT    B    NO'
  2459. int.16='DumpDates         DD     B    NO'        
  2460. int.17='DumpEncTypes      DET    B    NO'
  2461. int.18='DumpFiles         DF     B    NO'        
  2462. int.19='DumpFroms         DFR    B    NO'        
  2463. int.20='DumpMisc          DM     B    NO'        
  2464. int.21='DumpOpts          DO     B    NO'
  2465. int.22='DumpPhase2        DP2    B    NO'        
  2466. int.23='DumpSectionTypes  DST    B    NO'
  2467. int.24='DumpSkipFroms     DSF    B    NO'        
  2468. int.25='DumpSkipSubjects  DSS    B    NO'        
  2469. int.26='DumpSubjects      DS     B    NO'
  2470. int.27='DWassignIN        DWI    S    DW:' 
  2471. int.28='DWtemp            DWT    F    T:'
  2472. int.29='EncTypesFile      ETF    F    DWdecode.Encode.Types'
  2473. int.30='FileNote          FN     S    %LLQ2 : %SUBJECT'
  2474. int.31='KeepDays          KD     N    30'
  2475. int.32='Log               L      B    YES'
  2476. int.33='LogFile           LF     S    DWdecode.Log'
  2477. int.34='MarkOld           MO     B    YES'
  2478. int.35='MaxHeader         MH     N    25'
  2479. int.36='MinEncoded        ME     N    4'
  2480. int.37='PrefsFile         P      F    DWdecode.Prefs'
  2481. int.38='Quiet             Q      B    NO'
  2482. int.39='Recursive         REC    B    YES'
  2483. int.40='Replace           REP    B    NO' 
  2484. int.41='RunBack           RB     S    run > nil:'
  2485. int.42='ScanOnly          SO     B    NO'
  2486. int.43='ScanProg          SP     F    FlashFind'
  2487. int.44='SectionTypesFile  STF    F    DWdecode.Section.Types'
  2488. int.45='ShowDecode        SHDE   B    YES'
  2489. int.46='ShowDirs          SHDI   B    YES'
  2490. int.47='ShowFiles         SHF    B    YES'
  2491. int.48='ShowParts         SHP    B    YES'
  2492. int.49='ShowStats         SHS    B    YES'
  2493. int.50='SkipFrom          SF     B    YES'
  2494. int.51='SkipFromFile      SFF    F    DWdecode.Skip.Froms'
  2495. int.52='SkipSubject       SS     B    YES'
  2496. int.53='SkipSubjectFile   SSF    F    DWdecode.Skip.Subjects'
  2497. int.54='Source            S      F    . '
  2498. int.55='TrapAllBegs       TAB    B    NO' 
  2499. int.56='TrapAllEncs       TAE    B    NO'         
  2500. int.57='TrapAllSecs       TAS    B    NO'     
  2501. int.58='TrapNewEncs       TNE    B    YES'         
  2502. int.59='TrapNewEncsFile   TNEF   S    DWdecode.Trap.Encodes'
  2503. int.60='TrapNewSecs       TNS    B    YES'
  2504. int.61='TrapNewSecsFile   TNSF   S    DWdecode.Trap.Sections'
  2505. int.62='UUcmd             UC     F    UUout %SF BUFSIZE=150 IGNORETERMINATION USEBASENAME > nil:'
  2506. int.63='UUcmdFail         UF     N    10'
  2507. int.64='XDELETE           XD     B    NO'
  2508.  
  2509.  
  2510.    cmd.0=int.0                             /* duplicate number of entires */   
  2511.  
  2512.    do i=1 to int.0                         /* loop through them           */
  2513.       cmd.i    =word(int.i,1)              /* variable name in program    */
  2514.       cmd.i.1  =word(int.i,2)              /* an alias for variable name  */ 
  2515.       cmd.i.1.1=word(int.i,3)              /* type of variable B,S,T,F,N  */
  2516.       cmd.i.1.1.1=subword(int.i,4)         /* default for the variable    */
  2517.       if cmd.i.1.1='N' | cmd.i.1.1='B' then cmdstr=cmd.i||"="||cmd.i.1.1.1 
  2518.       else cmdstr=cmd.i||"='"||cmd.i.1.1.1||"'" /* build variable assign  */ 
  2519.       interpret cmdstr                     /* do it                       */
  2520.    end
  2521.  
  2522.    drop int.                               /* done with this array        */
  2523.  
  2524. Return
  2525.  
  2526. /**************************************************************************/
  2527. /*                                                                        */
  2528. /*           See what values are specified on the command line.           */
  2529. /*          These will override the values in the default file.           */
  2530. /*                                                                        */
  2531. /**************************************************************************/
  2532. /* Load all arguments that have '=' signs in them. Parse strings based on */
  2533. /* assuming a beginning quote (either type) and locating the ending one.  */
  2534. /* After deleting ALL xxx=yyy type pieces, the remaining ones SHOULD be   */
  2535. /* boolean switches. All of the commands will be tested based upon the    */
  2536. /* type value in the cmd. array. Strings can be anything; Files must      */
  2537. /* already exist; Booleans must be 1/0, YES/NO, ON/OFF; and Numerics must */
  2538. /* be numeric. Any that don't match a valid command or its alias are      */
  2539. /* reported as errors and we exit after all have been processed.          */
  2540. /*                                                                        */
  2541. /**************************************************************************/
  2542. /* If help requested then display internal defaults and exit.             */
  2543. /**************************************************************************/
  2544. CmdOverrides:
  2545.  
  2546.    if commandline='?' | upper(commandline)='-H' | upper(commandline)='HELP' then do
  2547.       do i=1 to delaymsg.0
  2548.          msg=delaymsg.i
  2549.          interpret Saycmd   
  2550.       end
  2551.       msg=' '
  2552.       interpret Saycmd
  2553.       msg='Command-Option   Alias  Internal Value'
  2554.       interpret Saycmd
  2555.       msg=left(dashes,78)
  2556.       interpret Saycmd
  2557.       do i=1 to cmd.0
  2558.          msg=cmd.i
  2559.          msg=overlay(cmd.i.1,msg,18)
  2560.          msg=overlay(cmd.i.1.1.1,msg,25)
  2561.          interpret Saycmd
  2562.       end 
  2563.       msg=' '
  2564.       interpret Saycmd
  2565.       msg='See DWDecode.Defaults.doc for complete description of options'
  2566.       interpret Saycmd
  2567.       signal cleanup
  2568.    end
  2569.  
  2570.    say ' '
  2571.    say time() 'Determining runtime options ...'
  2572.  
  2573.    cmdopt.=missing      
  2574.    cmdopt.0=0
  2575.  
  2576.    eqpos=pos('=',commandline)
  2577.    i=0
  2578.    quitflag=NO
  2579.  
  2580.    do while eqpos~=0
  2581.       cmdpart1=strip(substr(commandline,1,eqpos-1))
  2582.       cmdpart2=strip(substr(commandline,eqpos+1))
  2583.       i=i+1
  2584.       cmdopt.0=i
  2585.       cmdopt.i=word(cmdpart1,words(cmdpart1))
  2586.       cmdpart1=subword(cmdpart1,1,words(cmdpart1)-1)
  2587.       select
  2588.          when substr(cmdpart2,1,1)='"' then do
  2589.             endquote=pos('"',cmdpart2,2)
  2590.             if endquote=0 then do
  2591.                delaymsg.0=delaymsg.0 + 1
  2592.                dx=delaymsg.0
  2593.                delaymsg.dx='(E) Missing ending quote for: ' cmdopt.i
  2594.                quitflag=YES
  2595.             end
  2596.             cmdopt.i.1=substr(cmdpart2,2,endquote-2)
  2597.             cmdpart2=substr(cmdpart2,endquote+1)
  2598.          end   
  2599.          when substr(cmdpart2,1,1)="'" then do
  2600.             endquote=pos("'",cmdpart2,2)
  2601.             if endquote=0 then do
  2602.                delaymsg.0=delaymsg.0 + 1
  2603.                dx=delaymsg.0
  2604.                delaymsg.dx='(E) Missing ending quote for: ' cmdopt.i
  2605.                quitflag=YES
  2606.             end
  2607.             cmdopt.i.1=substr(cmdpart2,2,endquote-2)
  2608.             cmdpart2=substr(cmdpart2,endquote+1)
  2609.          end
  2610.          otherwise do
  2611.             cmdopt.i.1=word(cmdpart2,1)
  2612.             cmdpart2=subword(cmdpart2,2)
  2613.          end
  2614.       end
  2615.       commandline=cmdpart1||' '||cmdpart2
  2616.       eqpos=pos('=',commandline)
  2617.    end
  2618.  
  2619.    do j=1 to words(commandline)
  2620.       i=i+1
  2621.       cmdopt.0=i 
  2622.       cmdopt.i=word(commandline,1)
  2623.       commandline=subword(commandline,2)
  2624.    end 
  2625.  
  2626.    do i=1 to cmdopt.0
  2627.       matchflag=NO
  2628.       do j=1 to cmd.0
  2629.          UPO=upper(cmdopt.i)
  2630.          UPV=upper(cmdopt.i.1)
  2631.          UPC=upper(cmd.j)
  2632.          UPA=upper(cmd.j.1)
  2633.          UPT=upper(cmd.j.1.1)
  2634.          if UPO=UPC | UPO=UPA then do
  2635.             matchflag=YES
  2636.             select
  2637.                when UPT='B' then do
  2638.                   select
  2639.                      when UPV=missing then cmdopt.i.1='YES'
  2640.                      when UPV='YES'   then nop
  2641.                      when UPV='ON'    then nop
  2642.                      when UPV='TRUE'  then nop
  2643.                      when UPV='1'     then nop
  2644.                      when UPV='NO'    then nop
  2645.                      when UPV='OFF'   then nop
  2646.                      when UPV='FALSE' then nop
  2647.                      when UPV='0'     then nop
  2648.                      otherwise do
  2649.                         delaymsg.0=delaymsg.0 + 1
  2650.                         dx=delaymsg.0
  2651.                         delaymsg.dx='(E) Invalid value for 'UPC 'must be YES/NO'
  2652.                         quitflag=YES
  2653.                      end
  2654.                   end
  2655.                end
  2656.                when UPT='N' then do
  2657.                   if verify(UPV,'0123456789')~=0 then do
  2658.                      say '(E) Invalid value for 'UPC 'must be numeric'
  2659.                      quitflag=YES
  2660.                   end
  2661.                end
  2662.                otherwise nop
  2663.             end 
  2664.             cmdopt.i=cmd.j                     /* store real variable name   */
  2665.             cmdopt.i.1.1=cmd.j.1.1             /* store variable type        */
  2666.             leave j
  2667.          end
  2668.       end
  2669.       if ~matchflag then do
  2670.          delaymsg.0=delaymsg.0 + 1
  2671.          dx=delaymsg.0
  2672.          delaymsg.dx='(E) Unrecognized argument: 'UPO'. See Documentation.'
  2673.          quitflag=YES
  2674.       end 
  2675.    end
  2676.  
  2677. /**************************************************************************/
  2678. /* Set values from command line, will have to do it again, after values   */
  2679. /* are set from PrefsFile. Makes it easier to use cmdline options early.  */
  2680. /**************************************************************************/
  2681.    do i=1 to cmdopt.0                      /* loop through them           */
  2682.       if cmdopt.i.1.1='N' | cmdopt.i.1.1='B' then cmdstr=cmdopt.i||"="||cmdopt.i.1 
  2683.       else cmdstr=cmdopt.i||"='"||cmdopt.i.1||"'"   /* build var assign   */ 
  2684.       interpret cmdstr                     /* do it                       */
  2685.    end
  2686.  
  2687. Return
  2688.  
  2689. /**************************************************************************/
  2690. /*                                                                        */
  2691. /*            Read in the information from the Prefs file                 */
  2692. /*                                                                        */
  2693. /**************************************************************************/
  2694. ReadPrefs:
  2695.  
  2696.    pcmd.=missing
  2697.    i=0
  2698.  
  2699.    goodopen=open('Prefs',PrefsFile,'R')
  2700.    if ~goodopen then do
  2701.       delaymsg.0=delaymsg.0 + 1
  2702.       dx=delaymsg.0
  2703.       delaymsg.dx='(W) Prefs file not found - using command options & internal values'
  2704.    end
  2705.    else do
  2706.       delaymsg.0=delaymsg.0 + 1
  2707.       dx=delaymsg.0
  2708.       delaymsg.dx='Using PrefsFile:         ' PrefsFile
  2709.       do until eof('Prefs')
  2710.          default=readln('Prefs')
  2711.          if default~=' ' & default~='#' & default~='' then do
  2712.             if pos('#',default)~=1 then do
  2713.                if pos('#',default)>2 then do
  2714.                   default=substr(default,1,pos('#',default)-1)
  2715.                end
  2716.                default=strip(default)
  2717.                select
  2718.                   when pos('=',default)>0 then do
  2719.                      i=i+1
  2720.                      pcmd.i=substr(default,1,pos('=',default)-1)
  2721.                      pval=substr(default,pos('=',default)+1)
  2722.                      pval=strip(pval,'B',"'") 
  2723.                      pval=strip(pval,'B','"') 
  2724.                      pcmd.i.1=pval
  2725.                   end
  2726.                   when words(default)=1 then do
  2727.                      i=i+1
  2728.                      pcmd.i=default
  2729.                      pcmd.i.1='YES'
  2730.                   end 
  2731.                   otherwise do
  2732.                      delaymsg.0=1+delaymsg.0 
  2733.                      dx=delaymsg.0
  2734.                      delaymsg.dx='(E) Missing "=" in PrefsFile line: 'default
  2735.                      quitflag=YES
  2736.                   end 
  2737.                end
  2738.             end
  2739.          end
  2740.       end
  2741.    end
  2742.  
  2743.    result=close('Prefs')
  2744.  
  2745.    pcmd.0=i                               /* number of PrefsFile options  */
  2746.  
  2747. /**************************************************************************/
  2748. /*         Validate options set in the Preferences file.                  */
  2749. /**************************************************************************/
  2750.  
  2751.    do i=1 to pcmd.0
  2752.       matchflag=NO
  2753.       do j=1 to cmd.0
  2754.          UPO=upper(pcmd.i)
  2755.          UPV=upper(pcmd.i.1)
  2756.          UPC=upper(cmd.j)
  2757.          UPA=upper(cmd.j.1)
  2758.          UPT=upper(cmd.j.1.1)
  2759.          if UPO=UPC | UPO=UPA then do
  2760.             matchflag=YES
  2761.             select
  2762.                when UPT='B' then do
  2763.                   select
  2764.                      when UPV=missing then pcmd.i.1='YES'
  2765.                      when UPV='YES'   then nop
  2766.                      when UPV='ON'    then nop
  2767.                      when UPV='TRUE'  then nop
  2768.                      when UPV='1'     then nop
  2769.                      when UPV='NO'    then nop
  2770.                      when UPV='OFF'   then nop
  2771.                      when UPV='FALSE' then nop
  2772.                      when UPV='0'     then nop
  2773.                      otherwise do
  2774.                         delaymsg.0=delaymsg.0 + 1
  2775.                         dx=delaymsg.0
  2776.                         delaymsg.dx='(E) Invalid value for 'UPC 'must be YES/NO'
  2777.                         quitflag=YES
  2778.                      end
  2779.                   end
  2780.                end
  2781.                when UPT='N' then do
  2782.                   if verify(UPV,'0123456789')~=0 then do
  2783.                      say '(E) Invalid value for 'UPC 'must be numeric'
  2784.                      quitflag=YES
  2785.                   end
  2786.                end
  2787.                otherwise nop
  2788.             end 
  2789.             pcmd.i=cmd.j                        /* store real variable name   */
  2790.             pcmd.i.1.1=cmd.j.1.1                /* store variable type        */
  2791.             leave j
  2792.          end
  2793.       end
  2794.       if ~matchflag then do
  2795.          delaymsg.0=delaymsg.0 + 1
  2796.          dx=delaymsg.0
  2797.          delaymsg.dx='(E) Unrecognized argument: 'UPO'. See Documentation.'
  2798.          quitflag=YES
  2799.       end 
  2800.    end
  2801.  
  2802.    do i=1 to pcmd.0                        /* loop through them           */
  2803.       if pcmd.i.1.1='N' | pcmd.i.1.1='B' then cmdstr=pcmd.i||"="||pcmd.i.1 
  2804.       else cmdstr=pcmd.i||"='"||pcmd.i.1||"'"   /* build variable assign  */ 
  2805.       interpret cmdstr                     /* do it                       */
  2806.    end
  2807.  
  2808.    drop pcmd.                                   /* done with this array   */
  2809.  
  2810. /**************************************************************************/
  2811. /*         Set values from command line for final time.                   */
  2812. /**************************************************************************/
  2813.  
  2814.    do i=1 to cmdopt.0                      /* loop through them           */
  2815.       if cmdopt.i.1.1='N' | cmdopt.i.1.1='B' then cmdstr=cmdopt.i||"="||cmdopt.i.1 
  2816.       else cmdstr=cmdopt.i||"='"||cmdopt.i.1||"'"   /* build var assign   */ 
  2817.       interpret cmdstr                     /* do it                       */
  2818.    end
  2819.  
  2820.    drop cmdopt.                                 /* done with this array   */
  2821.  
  2822.    if DEBUG=YES then QUIET=NO             /* turn on all messages         */
  2823.    if QUIET=NO then VERBOSE=YES           /* Make into a positive remark  */
  2824.                else VERBOSE=NO
  2825.  
  2826.    if verbose then say time() 'Verifying existence of files ...'
  2827.  
  2828.    do i=1 to cmd.0                        /* loop thru validating files   */
  2829.       if cmd.i.1.1='F' then do
  2830.          tstr='tfile=word('||cmd.i||',1)'
  2831.          interpret tstr
  2832.          if ~exists(tfile) then do 
  2833.             delaymsg.0=delaymsg.0 + 1
  2834.             dx=delaymsg.0
  2835.             delaymsg.dx='(E) File' tfile 'does not exist '  
  2836.             quitflag=YES
  2837.          end
  2838.       end
  2839.    end
  2840.  
  2841.    if Log=YES then do
  2842.       Saycmd="result=writeln('LOG',msg)"
  2843.       goodopen=open('LOG',logfile,'W')
  2844.       if ~goodopen then do
  2845.          delaymsg.0=1+delaymsg.0 
  2846.          dx=delaymsg.0
  2847.          delaymsg.dx='(E) Unable to open logfile:' logfile
  2848.          delaymsg.0=1+delaymsg.0
  2849.          dx=delaymsg.0
  2850.          delaymsg.dx='Continuing without logfile. Messages displaying on console'
  2851.          SayCmd='Say msg'
  2852.       end
  2853.    end
  2854.  
  2855.    do i=1 to delaymsg.0
  2856.       msg=delaymsg.i
  2857.       interpret Saycmd   
  2858.    end
  2859.  
  2860.    drop delaymsg.                               /* done with this array   */
  2861.  
  2862.    if quitflag then do                          /* command/prefs error(s) */  
  2863.       exit 20
  2864.    end
  2865.  
  2866. Return
  2867.  
  2868. /**************************************************************************/
  2869. /*                                                                        */
  2870. /*           Adjust options based on final values of variables            */
  2871. /*                                                                        */
  2872. /**************************************************************************/
  2873. SetParms:
  2874.  
  2875.    if Source='' then do
  2876.       msg='(E) SOURCE directory is a REQUIRED parameter. See documentation.'
  2877.       interpret Saycmd
  2878.       exit
  2879.    end
  2880.    if Dest='' then do
  2881.       msg='(E) DEST directory is a REQUIRED parameter. See documentation.'
  2882.       interpret Saycmd
  2883.       exit
  2884.    end
  2885.  
  2886.    dircnt=1                                  /* next directory to process */
  2887.    dirlist.0=1                                   /* one directory for now */
  2888.    if right(dest,1)~='/' & right(dest,1)~=':' then dest=dest||'/'
  2889.    if right(source,1)~='/' & right(source,1)~=':' then source=source||'/'
  2890.    dirlist.1=source                     /* the original source directory  */
  2891.  
  2892.    if MarkOld | DeleteOld then do               /* need a value for today */
  2893.       datemsg= date() ' ' time() ' +900'        /* build a fake Date:     */
  2894.       datemsg=upper(datemsg)                    /* force to upper for rtn */         
  2895.       Call CalcDays
  2896.       today=days
  2897.       if KeepDays<1 then do
  2898.          msg='(W) KeepDays less than 1. Forcing to KEEPDAYS=30'
  2899.          interpret Saycmd
  2900.          KeepDays=30
  2901.       end
  2902.    end 
  2903.  
  2904.    if XDELETE then do                          /* turn on ALL delete opts */
  2905.       DeleteAfter   =YES
  2906.       DeleteDups    =YES
  2907.       DeleteFrom    =YES
  2908.       DeleteOld     =YES
  2909.       DeleteSubject =YES
  2910.       DeleteText    =YES
  2911.    end
  2912.  
  2913. Return
  2914.  
  2915. /**************************************************************************/
  2916. /*                                                                        */
  2917. /*                           Load SECTION table                           */
  2918. /*                                                                        */
  2919. /*  Load tables for parsing partname, partnum information from external   */
  2920. /*  tables. Descriptions are in each and each is required.                */
  2921. /*                                                                        */
  2922. /**************************************************************************/
  2923. LoadSecTab:
  2924.  
  2925.    goodopen=open('SecTables',SectionTypesFile,'R')
  2926.    if ~goodopen then do
  2927.       msg='(E) Required file ('SectionTypesFile') not found. See documentation.'
  2928.       interpret Saycmd
  2929.       exit
  2930.    end
  2931.    msg='Using Section Types File:' SectionTypesFile
  2932.    if ~DEBUG & ~DUMPOPTS then interpret Saycmd
  2933.    i=0                                           /* array pointer         */
  2934.    do until eof('SecTables')
  2935.       SecTable=readln('SecTables')
  2936.       if SecTable~=' ' & SecTable~='#' & SecTable~='' then do
  2937.          if pos('#',SecTable) ~= 1 then do
  2938.             if pos('#',SecTable)>1 then do
  2939.                SecTable=substr(SecTable,1,pos('#',SecTable)-1)
  2940.             end
  2941.             SecTable=strip(SecTable)
  2942.             i=i+1                                /* bump array pointer    */
  2943.             j=word(SecTable,1)                   /* number of keys present*/
  2944.             Sectiontypes.i=j                     /* load array with value */
  2945.             l=2                                  /* first key portion     */
  2946.             do k=1 to j                          /* loop thru pairs       */
  2947.               Sectiontypes.i.k=word(SecTable,l)       /* key portion      */
  2948.               Sectiontypes.i.k.k=word(SecTable,l+1)   /* key location     */
  2949.               l=l+2                                   /* set to next pair */
  2950.             end
  2951.             Sectiontypes.i.1.1.1=word(SecTable,l)      /* part number     */ 
  2952.             Sectiontypes.i.1.1.1.1=word(SecTable,l+1)   /* total parts    */
  2953.             Sectiontypes.i.1.1.1.1.1=word(SecTable,l+2)  /* filename      */
  2954.             Sectiontypes.i.1.1.1.1.1.1=word(SecTable,l+3) /* sep. char.   */
  2955.          end
  2956.       end
  2957.    end
  2958.  
  2959.    Sectiontypes.0=i                              /* num in section table */
  2960.    result=close('SecTables')
  2961.  
  2962. Return
  2963.  
  2964. /**************************************************************************/
  2965. /*                                                                        */
  2966. /*        Get the different start line indicators for Base64 files.       */
  2967. /*                                                                        */
  2968. /**************************************************************************/
  2969. LoadBase64Types:
  2970.  
  2971.    goodopen=open('Base64Types',Base64TypesFile,'R')
  2972.    if ~goodopen then do
  2973.       msg='(E) Required file ('Base64TypesFile') not found. See documentation.'
  2974.       interpret Saycmd
  2975.       exit
  2976.    end
  2977.    msg='Using Base64 Types File: ' Base64TypesFile
  2978.    if ~DEBUG & ~DUMPOPTS then interpret Saycmd
  2979.    i=0
  2980.    do until eof('Base64Types')
  2981.       Base64type=readln('Base64Types')
  2982.       Base64type=strip(Base64type)
  2983.       if substr(Base64type,1,1)='#' | Base64type='' | Base64type=' ' then nop
  2984.       else do
  2985.          if pos('#',Base64type)>1 then do
  2986.             Base64type=substr(Base64type,1,pos('#',Base64type)-1)
  2987.             Base64type=strip(Base64type)
  2988.          end
  2989.          i=i+1
  2990.          Base64Types.i=Base64Type
  2991.       end
  2992.    end
  2993.    Base64Types.0=i
  2994.  
  2995.    result=close('Base64Types')
  2996.  
  2997. Return
  2998.  
  2999. /**************************************************************************/
  3000. /*                                                                        */
  3001. /*        Get the types of file extensions we're to try to handle         */
  3002. /*                                                                        */
  3003. /**************************************************************************/
  3004. LoadBinTypes:
  3005.  
  3006.    goodopen=open('BinTypes',BinTypesFile,'R')
  3007.    if ~goodopen then do
  3008.       msg='(E) Required file ('BinTypesFile') not found. See documentation.'
  3009.       interpret Saycmd
  3010.       exit
  3011.    end
  3012.    msg='Using Binary Types File: ' BinTypesFile
  3013.    if ~DEBUG & ~DUMPOPTS then interpret Saycmd
  3014.    i=0
  3015.    do until eof('BinTypes')
  3016.       bintype=readln('BinTypes')
  3017.       bintype=strip(bintype)
  3018.       if substr(bintype,1,1)='#' | bintype='' | bintype=' ' then nop
  3019.       else do
  3020.          if pos('#',bintype)>1 then do
  3021.             bintype=substr(bintype,1,pos('#',bintype)-1)
  3022.             bintype=strip(bintype)
  3023.          end
  3024.          i=i+1
  3025.          Bintypes.i=upper(bintype)
  3026.       end
  3027.    end
  3028.    Bintypes.0=i
  3029.  
  3030.    result=close('BinTypes')
  3031.  
  3032. Return
  3033.  
  3034. /**************************************************************************/
  3035. /*                                                                        */
  3036. /*     Get the MIME encoding types that are known and which they are      */
  3037. /*                                                                        */
  3038. /**************************************************************************/
  3039. LoadEncTypes:
  3040.  
  3041.    goodopen=open('EncTypes',EncTypesFile,'R')
  3042.    if ~goodopen then do
  3043.       msg='(E) Required file ('EncTypesFile') not found. See documentation.'
  3044.       interpret Saycmd
  3045.       exit
  3046.    end
  3047.    msg='Using Encode Types File: ' EncTypesFile
  3048.    if ~DEBUG & ~DUMPOPTS then interpret Saycmd
  3049.    i=0
  3050.    do until eof('EncTypes')
  3051.       enctype=readln('EncTypes')
  3052.       enctype=strip(enctype)
  3053.       if substr(enctype,1,1)='#' | enctype='' | enctype=' ' then nop
  3054.       else do
  3055.          if pos('#',enctype)>1 then do
  3056.             enctype=substr(enctype,1,pos('#',enctype)-1)
  3057.             enctype=strip(enctype)
  3058.          end
  3059.          i=i+1
  3060.          Enctypes.i=upper(word(enctype,1))
  3061.          if words(enctype)>1 then Enctypes.i.1=upper(word(enctype,2))
  3062.                              else Enctypes.i.1=missing
  3063.       end
  3064.    end
  3065.    Enctypes.0=i
  3066.  
  3067.    result=close('EncTypes')
  3068.  
  3069. Return
  3070.  
  3071. /**************************************************************************/
  3072. /*                                                                        */
  3073. /*        Load list of users in From: lines to SKIP                       */
  3074. /*                                                                        */
  3075. /**************************************************************************/
  3076. LoadSkipFroms:       
  3077.  
  3078.    goodopen=open('SkipFroms',SkipFromFile,'R')
  3079.    if ~goodopen then do
  3080.       msg=' '
  3081.       interpret Saycmd
  3082.       msg='(E) Unable to open SkipFromFile "'SkipFromFile'"' 
  3083.       interpret Saycmd
  3084.       msg='    Setting DELETEFROM=NO SKIPFROM=NO DUMPSKIPFROMS=NO'
  3085.       interpret Saycmd
  3086.       SkipFrom=NO
  3087.       DeleteFrom=NO
  3088.       DumpSkipFroms=NO
  3089.    end
  3090.    else do
  3091.       msg='Using SkipFromFile:      ' SkipFromFile   
  3092.       if ~DEBUG & ~DUMPOPTS then interpret Saycmd
  3093.    end
  3094.    i=0
  3095.    if goodopen then do until eof('SkipFroms')
  3096.       skipuser=readln('SkipFroms')
  3097.       skipuser=strip(skipuser)
  3098.  
  3099.       if substr(skipuser,1,1)='#' | skipuser='' | skipuser=' ' then nop
  3100.       else do
  3101.          i=i+1
  3102.          SkipFroms.i=skipuser
  3103.       end
  3104.    end
  3105.    SkipFroms.0=i 
  3106.  
  3107.    result=close('SkipFroms')
  3108.  
  3109. Return
  3110.  
  3111. /**************************************************************************/
  3112. /*                                                                        */
  3113. /*        Load list of words in Subject: lines to SKIP                    */
  3114. /*                                                                        */
  3115. /**************************************************************************/
  3116. LoadSkipSubjects:       
  3117.  
  3118.    goodopen=open('SkipSubjects',SkipSubjectFile,'R')
  3119.    if ~goodopen then do
  3120.       msg=' '
  3121.       interpret Saycmd
  3122.       msg='(E) Unable to open SkipSubjectFile "'SkipSubjectFile'"' 
  3123.       interpret Saycmd
  3124.       msg='    Setting DELETESUBJECT=NO SKIPSUBJECT=NO DUMPSKIPSUBJECTS=NO'
  3125.       interpret Saycmd
  3126.       SkipSubject=NO
  3127.       DeleteSubject=NO
  3128.       DumpSkipSubjects=NO
  3129.    end
  3130.    else do
  3131.       msg='Using SkipSubjectFile:   ' SkipSubjectFile   
  3132.       if ~DEBUG & ~DUMPOPTS then interpret Saycmd
  3133.    end
  3134.    i=0
  3135.    if goodopen then do until eof('SkipSubjects')
  3136.       skipuser=readln('SkipSubjects')
  3137.       skipuser=strip(skipuser)
  3138.  
  3139.       if substr(skipuser,1,1)='#' | skipuser='' | skipuser=' ' then nop
  3140.       else do
  3141.          i=i+1
  3142.          SkipSubjects.i=skipuser
  3143.       end
  3144.    end
  3145.    SkipSubjects.0=i 
  3146.  
  3147.    result=close('SkipSubjects')
  3148.  
  3149. Return
  3150.  
  3151. /**************************************************************************/
  3152. /*                                                                        */
  3153. /*              Make sure that we have all the libs we need:              */
  3154. /*                               RexxArpLib                               */
  3155. /*                               QuickSort                                */
  3156. /*                                                                        */
  3157. /**************************************************************************/
  3158. EnsureLibs:
  3159.  
  3160.    if ~show('L','rexxarplib.library') then do
  3161.       call addlib('rexxarplib.library',0,-30)
  3162.    end
  3163.  
  3164.    if ~showlist('p','QuickSortPort') then do
  3165.       address command runback " quicksort"
  3166.       do i = 1 to 10
  3167.          if ~showlist('p','QuickSortPort') then call delay 20
  3168.          else leave i
  3169.       end
  3170.    end
  3171.    if showlist('p','QuickSortPort') then do
  3172.       call addlib('QuickSortPort',-30)
  3173.    end
  3174.    else do
  3175.       msg='(E) Unable to find QuickSort -- check installation instructions'
  3176.       interpret Saycmd
  3177.    end
  3178.  
  3179. Return
  3180.  
  3181.  
  3182. /**************************************************************************/
  3183. /*                                                                        */
  3184. /*          Read Source Directory for list directories to process         */
  3185. /*                                                                        */
  3186. /* force '/' onto source if not present and not a volume or assign        */
  3187. /*                                                                        */
  3188. /**************************************************************************/
  3189. GetDirs:
  3190.  
  3191.    tempdirs.=missing
  3192.    tempdirs.0 = FILELIST(source||'*',tempdirs,"D","E")
  3193.  
  3194.    do i=1 to tempdirs.0
  3195.       dirlist.0=1+dirlist.0
  3196.       dirptr=dirlist.0
  3197.       dirlist.dirptr=tempdirs.i||'/'      
  3198.    end
  3199.  
  3200.    dircnt=dircnt+1                               /* next dir to process   */
  3201.  
  3202.    if dircnt>dirlist.0 then DONE=YES
  3203.  
  3204.    do while ~DONE
  3205.       source=dirlist.dircnt                      /* directory to look thru*/
  3206.       call GetDirs                 /* Recursive Call to this same routine */ 
  3207.    end
  3208.  
  3209.    call QSORT(1, dirlist.0, dirlist)            /* sort into pretty order */
  3210.  
  3211. Return
  3212.  
  3213.  
  3214. /**************************************************************************/
  3215. /*                                                                        */
  3216. /*           Various routines called for debugging/trace options          */
  3217. /*                                                                        */
  3218. /**************************************************************************/
  3219. DumpArrays:
  3220.  
  3221.    if (DumpFiles | Debug) & Files.0 > 0 then call DumpFiles
  3222.    if (DumpMisc  | Debug) & Files.0 > 0 then call DumpMiscinfo
  3223.    if (DumpFroms | Debug) & Files.0 > 0 then call DumpFrominfo
  3224.    if (DumpSubjects | Debug) & Files.0 > 0 then call DumpSubjinfo
  3225.    if (DumpDates | Debug) & Files.0 > 0 then call DumpDateinfo 
  3226.    if (TrapAllBegs | Debug) & AllBegins.0 > 0 then call DumpBegins
  3227.    if (TrapAllEncs | Debug) & AllEncodes.0 > 0 then call DumpEncodes
  3228.    if (TrapAllSecs | Debug) & Allsections.0 > 0 then call DumpSections
  3229.  
  3230.                         /************************/
  3231.                         /*                      */
  3232.                         /* Dump these only once */
  3233.                         /*        at end        */
  3234.                         /************************/
  3235.  
  3236. if dirptr=dirlist.0 then do
  3237.    if (DumpBinTypes | Debug) & BinTypes.0 > 0 then call DumpBinTypes
  3238.    if (DumpBase64Types | Debug) & Base64Types.0 > 0 then call DumpBase64Types
  3239.    if (DumpEncTypes | Debug) & EncTypes.0 > 0 then call DumpEncTypes
  3240.    if (DumpSectionTypes | Debug) & SectionTypes.0 > 0 then call DumpSectionTypes
  3241.    if (DumpSkipFroms | Debug) & SkipFroms.0 > 0 then call DumpSkipFroms
  3242.    if (DumpSkipSubjects | Debug) & SkipSubjects.0 > 0 then call DumpSkipSubjects
  3243. end
  3244.  
  3245. Return
  3246.  
  3247. /**************************************************************************/
  3248. /*                                                                        */
  3249. /*              Dumps array used for directories on Recursive             */
  3250. /*                                                                        */
  3251. /**************************************************************************/
  3252. DumpDirs: 
  3253.  
  3254.    msg=' '
  3255.    interpret Saycmd
  3256.    if dirlist.0=1 then msg=dirlist.0 ' Directory found'
  3257.       else msg=dirlist.0 ' Directories found'
  3258.    interpret Saycmd
  3259.    msg=left(dashes,length(msg))
  3260.    interpret Saycmd
  3261.    do j=1 to dirlist.0                             /* dump dir list array */
  3262.       msg=dirlist.j
  3263.       interpret Saycmd
  3264.    end
  3265.    msg=' '
  3266.    interpret Saycmd
  3267.    
  3268. Return
  3269.  
  3270. /**************************************************************************/
  3271. /*                   Dumps Files. array for all partnames.                */
  3272. /**************************************************************************/
  3273. /*               (0)=cnt             (0)=cnt                              */
  3274. /* Files. format: filename.encodetype.partname.partnum.parttot.startline  */
  3275. /*                        .encodetype.partname.partnum.parttot.startline  */
  3276. /**************************************************************************/
  3277. DumpFiles:
  3278.  
  3279.    msg=' '
  3280.    interpret Saycmd
  3281.    msg='(DUMPFILES=YES)' Files.0 ' File(s)'
  3282.    interpret Saycmd
  3283.    msg='Format: Subject line'
  3284.    interpret saycmd
  3285.    msg='        Filename Encodetype Partname Partnum Parttot Startline ("."=missing)' 
  3286.    interpret saycmd
  3287.    msg=left(dashes,length(msg))
  3288.    interpret Saycmd
  3289.  
  3290.    do i=1 to Files.0   
  3291.       msg= Subjinfo.i.1.1
  3292.       interpret Saycmd
  3293.       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
  3294.       interpret Saycmd
  3295.       if Files.i.1.0=0 then do
  3296.          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
  3297.          interpret Saycmd
  3298.       end
  3299.       else do 
  3300.          do j=1 to Files.i.1.0
  3301.          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
  3302.          interpret Saycmd
  3303.          end
  3304.       end
  3305.       msg=' '
  3306.       interpret Saycmd
  3307.    end
  3308.  
  3309. Return
  3310.  
  3311. /**************************************************************************/
  3312. /*                   Dumps Miscinfo array for all entries.                */
  3313. /**************************************************************************/
  3314. /* Miscinfo. format: filename.mimetype.decoded.filenoted.chopped.dupfile  */
  3315. /**************************************************************************/
  3316. DumpMiscInfo:
  3317.  
  3318.    msg=' '
  3319.    interpret Saycmd
  3320.    msg='(DUMPMISC=YES)' Files.0 ' File(s)'
  3321.    interpret Saycmd
  3322.    msg='format: FPtr Filename Mimetype Decoded Filenoted Chopped Dupfile ("."=missing)' 
  3323.    interpret saycmd
  3324.    msg=left(dashes,length(msg))
  3325.    interpret Saycmd
  3326.    do i=1 to Files.0   
  3327.       if Files.i.1.0=0 then do
  3328.          msg=i Files.i
  3329.          msg=msg||' '||Miscinfo.i.1 
  3330.          msg=msg||' '||Miscinfo.i.1.1
  3331.          msg=msg||' '||Miscinfo.i.1.1.1
  3332.          msg=msg||' '||Miscinfo.i.1.1.1.1
  3333.          msg=msg||' '||Miscinfo.i.1.1.1.1.1
  3334.          interpret Saycmd
  3335.       end
  3336.       else do 
  3337.          do j=1 to Files.i.1.0
  3338.             msg=i Files.i
  3339.             msg=msg||' '||Miscinfo.i.j 
  3340.             msg=msg||' '||Miscinfo.i.j.1
  3341.             msg=msg||' '||Miscinfo.i.j.1.1
  3342.             msg=msg||' '||Miscinfo.i.j.1.1.1
  3343.             msg=msg||' '||Miscinfo.i.j.1.1.1.1
  3344.             interpret Saycmd
  3345.          end
  3346.       end
  3347.       msg=' '
  3348.       interpret Saycmd
  3349.    end
  3350.  
  3351. Return
  3352.  
  3353. /**************************************************************************/
  3354. /*                                                                        */
  3355. /*                  Dumps array used for From lines                       */
  3356. /*                                                                        */
  3357. /**************************************************************************/
  3358. DumpFrominfo:
  3359.  
  3360.    msg=' '
  3361.    interpret Saycmd
  3362.    msg='(DUMPFROMS=YES)' 
  3363.    interpret Saycmd
  3364.    msg='Format: Filename SkipFlag DeleteFlag FromLine (0=No 1=Yes)'
  3365.    interpret saycmd
  3366.    msg=left(dashes,length(msg))
  3367.    interpret Saycmd
  3368.    do j=1 to Files.0                              /* dump Frominfo array */
  3369.       msg=Files.j '  ' Frominfo.j Frominfo.j.1 Frominfo.j.1.1
  3370.       interpret Saycmd
  3371.    end
  3372.    msg=' '
  3373.    interpret Saycmd
  3374.  
  3375. Return
  3376.  
  3377. /**************************************************************************/
  3378. /*                                                                        */
  3379. /*                  Dumps array used for Subject lines                    */
  3380. /*                                                                        */
  3381. /**************************************************************************/
  3382. DumpSubjinfo:
  3383.  
  3384.    msg=' '
  3385.    interpret Saycmd
  3386.    msg='(DUMPSUBJECTS=YES)' 
  3387.    interpret Saycmd
  3388.    msg='Format: Filename SkipFlag DeleteFlag SubjectLine (0=No 1=Yes)'
  3389.    interpret saycmd
  3390.    msg=left(dashes,length(msg))
  3391.    interpret Saycmd
  3392.    do j=1 to Files.0                              /* dump Subjinfo array */
  3393.       msg=Files.j '  ' Subjinfo.j Subjinfo.j.1 Subjinfo.j.1.1
  3394.       interpret Saycmd
  3395.    end
  3396.    msg=' '
  3397.    interpret Saycmd
  3398.  
  3399. Return
  3400.  
  3401. /**************************************************************************/
  3402. /*                                                                        */
  3403. /*                  Dumps array used for Date lines                       */
  3404. /*                                                                        */
  3405. /**************************************************************************/
  3406. DumpDateinfo:
  3407.  
  3408.    msg=' '
  3409.    interpret Saycmd
  3410.    msg='(DUMPDATES=YES)' 
  3411.    interpret Saycmd
  3412.    msg='Format: Filename SkipFlag DeleteFlag DateLine (0=No 1=Yes)'
  3413.    interpret saycmd
  3414.    msg=left(dashes,length(msg))
  3415.    interpret Saycmd
  3416.    do j=1 to Files.0                              /* dump Dateinfo array */
  3417.       msg=Files.j '  ' Dateinfo.j Dateinfo.j.1 Dateinfo.j.1.1
  3418.       interpret Saycmd
  3419.    end
  3420.    msg=' '
  3421.    interpret Saycmd
  3422.  
  3423. Return
  3424.  
  3425. /**************************************************************************/
  3426. /*                                                                        */
  3427. /*                  Dumps array used for determining BinTypes             */
  3428. /*                                                                        */
  3429. /**************************************************************************/
  3430. DumpBinTypes:
  3431.  
  3432.    msg=' '
  3433.    interpret Saycmd
  3434.    msg='(DUMPBINTYPES=YES)' 
  3435.    interpret Saycmd
  3436.    msg=BinTypes.0 ' binary types found in:' BinTypesFile
  3437.    interpret Saycmd
  3438.    msg=left(dashes,length(msg))
  3439.    interpret Saycmd
  3440.    do j=1 to BinTypes.0                          /* dump BinType array */
  3441.       msg=BinTypes.j
  3442.       interpret Saycmd
  3443.    end
  3444.    msg=' '
  3445.    interpret Saycmd
  3446.  
  3447. Return
  3448.  
  3449. /**************************************************************************/
  3450. /*                                                                        */
  3451. /*                  Dumps array used for determining EncTypes             */
  3452. /*                                                                        */
  3453. /**************************************************************************/
  3454. DumpEncTypes:
  3455.  
  3456.    msg=' '
  3457.    interpret Saycmd
  3458.    msg='(DUMPENCTYPES=YES)' 
  3459.    interpret Saycmd
  3460.    msg=EncTypes.0 ' Encode types found in:' EncTypesFile
  3461.    interpret Saycmd
  3462.    msg=left(dashes,length(msg))
  3463.    interpret Saycmd
  3464.    do j=1 to EncTypes.0                          /* dump Encode  array */
  3465.       msg=EncTypes.j EncTypes.j.1
  3466.       interpret Saycmd
  3467.    end
  3468.    msg=' '
  3469.    interpret Saycmd
  3470.  
  3471. Return
  3472.  
  3473. /**************************************************************************/
  3474. /*                                                                        */
  3475. /*               Dumps array used for determining Base64Types             */
  3476. /*                                                                        */
  3477. /**************************************************************************/
  3478. DumpBase64Types:
  3479.  
  3480.    msg=' '
  3481.    interpret Saycmd
  3482.    msg='(DUMPBASE64TYPES=YES)' 
  3483.    interpret Saycmd
  3484.    msg=Base64Types.0 ' Base64 types found in:' Base64TypesFile
  3485.    interpret Saycmd
  3486.    msg=left(dashes,length(msg))
  3487.    interpret Saycmd
  3488.    do j=1 to Base64Types.0                          /* dump Base64Type array */
  3489.       msg=Base64Types.j
  3490.       interpret Saycmd
  3491.    end
  3492.    msg=' '
  3493.    interpret Saycmd
  3494.  
  3495. Return
  3496.  
  3497. /**************************************************************************/
  3498. /*                                                                        */
  3499. /*                  Dumps array used for Section Line info                */
  3500. /*                                                                        */
  3501. /**************************************************************************/
  3502. DumpSectionTypes:
  3503.  
  3504.    msg=' '
  3505.    interpret Saycmd
  3506.    msg='(DUMPSECTIONTYPES=YES)' 
  3507.    interpret Saycmd
  3508.    msg=SectionTypes.0 ' section types found in:' SectionTypesFile
  3509.    interpret Saycmd
  3510.    msg=left(dashes,length(msg))
  3511.    interpret Saycmd
  3512.    do j=1 to SectionTypes.0                     /* dump SectionType array */
  3513.       msg=SectionTypes.j 
  3514.       do k=1 to SectionTypes.j
  3515.          msg=msg||' '||SectionTypes.j.k SectionTypes.j.k.k
  3516.       end
  3517.       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
  3518.       interpret Saycmd
  3519.    end
  3520.    msg=' '
  3521.    interpret Saycmd
  3522.  
  3523. Return
  3524.  
  3525. /**************************************************************************/
  3526. /*                                                                        */
  3527. /*                Dumps array used for determining SkipFrom               */
  3528. /*                                                                        */
  3529. /**************************************************************************/
  3530. DumpSkipFroms:
  3531.  
  3532.    msg=' '
  3533.    interpret Saycmd
  3534.    msg='(DUMPSKIPFROMS=YES)' 
  3535.    interpret Saycmd
  3536.    msg=SkipFroms.0 ' userids in SkipFromFile:' SkipFromFile
  3537.    interpret Saycmd
  3538.    msg=left(dashes,length(msg))
  3539.    interpret Saycmd
  3540.    do j=1 to SkipFroms.0                          /* dump SkipFrom array */
  3541.       msg=SkipFroms.j
  3542.       interpret Saycmd
  3543.    end
  3544.    msg=' '
  3545.    interpret Saycmd
  3546.  
  3547. Return
  3548.  
  3549. /**************************************************************************/
  3550. /*                                                                        */
  3551. /*              Dumps array used for determining SkipSubject              */
  3552. /*                                                                        */
  3553. /**************************************************************************/
  3554. DumpSkipSubjects:
  3555.  
  3556.    msg=' '
  3557.    interpret Saycmd
  3558.    msg='(DUMPSKIPSUBJECTS=YES)' 
  3559.    interpret Saycmd
  3560.    msg=SkipSubjects.0 ' keys in SkipSubjectFile:' SkipSubjectFile
  3561.    interpret Saycmd
  3562.    msg=left(dashes,length(msg))
  3563.    interpret Saycmd
  3564.    do j=1 to SkipSubjects.0                    /* dump SkipSubject array */
  3565.       msg=SkipSubjects.j
  3566.       interpret Saycmd
  3567.    end
  3568.    msg=' '
  3569.    interpret Saycmd
  3570.  
  3571. Return
  3572.  
  3573. /**************************************************************************/
  3574. /*                                                                        */
  3575. /*                  Dumps array used for lines with 'BEGIN'               */
  3576. /*                                                                        */
  3577. /**************************************************************************/
  3578. DumpBegins:
  3579.  
  3580.    msg=' '
  3581.    interpret Saycmd
  3582.    msg='(TRAPALLBEGS=YES)' 
  3583.    interpret Saycmd
  3584.    msg='All lines with BEGIN in ' dirlist.dirptr
  3585.    interpret Saycmd
  3586.    msg=left(dashes,length(msg))
  3587.    interpret Saycmd
  3588.    do j=1 to AllBegins.0                          /* dump Allbegins array */
  3589.       msg=AllBegins.j
  3590.       interpret Saycmd
  3591.    end
  3592.    msg=' '
  3593.    interpret Saycmd
  3594.  
  3595. Return
  3596.  
  3597. /**************************************************************************/
  3598. /*                                                                        */
  3599. /*                  Dumps array used for lines with 'SECTION'             */
  3600. /*                                                                        */
  3601. /**************************************************************************/
  3602. DumpSections:
  3603.  
  3604.    msg=' '
  3605.    interpret Saycmd
  3606.    msg='(TRAPALLSECS=YES)' 
  3607.    interpret Saycmd
  3608.    msg='All lines with SECTION in ' dirlist.dirptr
  3609.    interpret Saycmd
  3610.    msg=left(dashes,length(msg))
  3611.    interpret Saycmd
  3612.    do j=1 to AllSections.0                         /* dump Frominfo array */
  3613.       msg=AllSections.j
  3614.       interpret Saycmd
  3615.    end
  3616.    msg=' '
  3617.    interpret Saycmd
  3618.  
  3619. Return
  3620.  
  3621. /**************************************************************************/
  3622. /*                                                                        */
  3623. /*                  Dumps array used for MIME encoding lines              */
  3624. /*                                                                        */
  3625. /**************************************************************************/
  3626. DumpEncodes: 
  3627.  
  3628.    msg=' '
  3629.    interpret Saycmd
  3630.    msg='(TRAPALLENCS=YES)' 
  3631.    interpret Saycmd
  3632.    msg='All MIME encoding Lines in ' dirlist.dirptr
  3633.    interpret Saycmd
  3634.    msg=left(dashes,length(msg))
  3635.    interpret Saycmd
  3636.    do j=1 to AllEncodes.0   
  3637.       msg=AllEncodes.j
  3638.       interpret Saycmd
  3639.    end
  3640.    msg=' '
  3641.    interpret Saycmd
  3642.  
  3643. Return
  3644.  
  3645. /**************************************************************************/
  3646. /*                                                                        */
  3647. /*                   Dump all runtime options to output                   */
  3648. /*                                                                        */
  3649. /**************************************************************************/
  3650. DumpOpts:
  3651.  
  3652.    msg=' '
  3653.    interpret Saycmd
  3654.    msg='(DUMPOPTS=YES)'
  3655.    interpret Saycmd
  3656.    msg='Using these runtime options: (0=NO,1=YES)'
  3657.    interpret Saycmd
  3658.    msg=left(dashes,length(msg))
  3659.    interpret Saycmd
  3660.    do i=1 to cmd.0
  3661.       tstr='tval='cmd.i
  3662.       interpret tstr
  3663.       msg='   '||cmd.i||'='||tval
  3664.       interpret Saycmd
  3665.    end 
  3666.  
  3667. Return
  3668.  
  3669.  
  3670. IOERR:
  3671.  
  3672.    Say 'An I/O error has occurred - exiting'
  3673.    exit 20
  3674.  
  3675. SYNTAX:
  3676.  
  3677.    Say 'An unexpected error has occurred - dumping values and exiting'
  3678.    Say 'Try to identify file with error and edit to fix'
  3679.    Say 'It is probably the LAST file in one of the arrays'
  3680.    Say ' '
  3681.    Say 'Line with error' sourceline(SIGL)  
  3682.    Say 'Current value of filename:' filename
  3683.    Say 'Current value of partname:' partname
  3684.    
  3685.    Say 'Dumping arrays ... '
  3686.    Call DumpDirs
  3687.    Call DumpFiles
  3688.    Call DumpMiscInfo
  3689.    signal Cleanup
  3690.  
  3691. ===============  END OF ACTIVE CODE ================
  3692.