home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / bbs102e.zip / bbs.cmd < prev    next >
OS/2 REXX Batch file  |  1997-11-16  |  114KB  |  3,501 lines

  1. /*  BBS add-on for the SRE-http WWW server, ver 1.02e
  2.     This is the Directory listing, and download component.
  3.     See BBSUP.CMD for upload,
  4.     and BBSNEWU.CMD for new user registration.
  5.  
  6. Written by:
  7.   Primary author: Daniel Hellerstein (danielh@econ.ag.gov)
  8.   Primary collaborator: Juho Risku (jrisku@paju.oulu.fi)
  9.  
  10.  
  11.                  **** IMPORTANT INSTALLATION NOTE ***
  12.  
  13. 1)  For BBS downloads to work, you MUST add the following entries to your
  14.     SRE-http "alias" file (they may already be there..)
  15.          bbs/download/ *  bbs?download=*
  16.          bbs/zipdownload/ *  bbs?zipdownload=*
  17.  
  18.   (do NOT include a space between the / and *,, but I needed to put it
  19.    in do prevent a REXX comment!)
  20.  
  21.   To do this, you can either run the SRE-http configurator 
  22.   or edit ALIASES.IN in the /DATA subdirectory of the GoServe working
  23.   directory.
  24.  
  25. 2) A BBS.INI file MUST exist in the same directory BBS.CMD is installed
  26.    to.
  27.  
  28.                 --- END OF INSTALLATION NOTE --------
  29.  
  30. */
  31.  
  32.  
  33. /*A few User changeable non bbs.ini  parameters ... */
  34.  
  35. authorization_mode=0  /* if  =1, check authorization field for username/password,
  36.                          and use SRE-http privileges. If 0, use users.in files
  37.                         THIS SHOULD AGREE WITH THE VALUE IN BBSUP.CMD  */
  38.  
  39.  
  40. send_piece=1         /* if =1, then "send pieces" as they become available.
  41.                         if=0, then send the entire file when it's ready 
  42.                         Note: send_pieces is used in the make_dirlist procedure */
  43.  
  44.  
  45. imagesize="width=24 height=24"   /* size of icons */
  46.  
  47.  
  48. not_tvfs=0      /* if you are NOT running the TVFS (toronto virtual file system)
  49.                     you can set this to 1 (tvfs has an odd bug that requires
  50.                     some extra file checking to fix) */
  51.  
  52. /** End of user changeable  "non-BBS.INI parameters " *****************************/
  53.  
  54. /* from bbscache.cmd -- this is called as 
  55. call bbs(0,tempfile,cache.!cookver,list0,'CACHE',list0,'USER', ,
  56.          basedir,0,'*',0,0,1, ,
  57.          servername,0,0)
  58. */
  59.  
  60. /* get the list of values sent from SRE-http, or bbscache.cmd */
  61. parse arg  ddir, tempfile, reqstrg,list0,verb ,uri,user, ,
  62.           basedir ,workdir,privset,enmadd,transaction,verbose, ,
  63.          servername,host_nickname,homedir
  64.  
  65. if verb="" then do
  66.    say " This is an add-on for the SRE-http web server. "
  67.    say " It is NOT meant be run from the command line! "
  68.    exit
  69. end  /* Do */
  70.  
  71. /* special stuff if bbscache.cmd caller */
  72. cache_mode=0
  73. if verb="CACHE" then do
  74.     cache_mode=1
  75.     cache_mode_cookver=reqstrg
  76.     send_piece=0
  77. end  /* Do */
  78.  
  79.  
  80. if verbose>3 then say " BBS URI: " uri
  81.  
  82. foo=rxfuncquery('UZLoadFuncs')   /* load UNZIP dll */
  83. if foo=1 then do
  84.   call RxFuncAdd 'UZLoadFuncs', 'UNZIPAPI', 'UZLoadFuncs'
  85.   call UZLoadFuncs
  86. end
  87. foo=rxfuncquery('UZLoadFuncs')
  88. if foo=1 then do
  89.      say " Can not find UNZIP procedure library: UNZIPAPI.DLL"
  90.      foo=responsebbs('forbid','BBS is unavailable (no UNZIPAPI)')
  91.      return foo||' No UNZIPAPI.DLL '
  92. end  /* Do */
  93.  
  94. basedir=strip(basedir,'t','\')||'\'
  95.  
  96. /* Now readin bbs.ini file  */
  97.  
  98. inifile=basedir||'bbs.ini'
  99.  
  100. isit=fileread(inifile,inilines,,'E')
  101.  
  102. if isit<0 then do
  103.      say " ERROR: no BBS initialization file:" inifile
  104.      foo=responsebbs('forbid','BBS is unavailable (no ' inifile ')')
  105.      return foo||' Error in BBS parameters file '
  106. end  /* Do */
  107.  
  108. signal on syntax name bad1
  109. signal on error name bad1
  110. mm=0
  111.  
  112. gobot:                  /* process each line of bbs.ini */
  113. mm=mm+1
  114. if mm > inilines.0 then signal good1
  115. aline=inilines.mm
  116. interpret aline
  117. signal gobot
  118.  
  119. bad1:
  120. signal off error ; signal off syntax ;
  121. say " ERROR: error in BBS initialization file: " aline
  122. foo=responsebbs('forbid','error in BBS initialization file:<br>' aline)
  123. return foo||' Error in BBS parameters file '
  124.  
  125. /* ------  bbs_ini okay.  Check, various values, directories */
  126. good1:
  127. signal off error ; signal off syntax ;
  128.  
  129. call check_params
  130. if amess<>"" then return amess
  131.  
  132. /* get options list */
  133. if cache_mode=1 then do
  134.    action='BBS'
  135.    list=list0
  136. end
  137. else do
  138.    parse var uri action '?' list   /* parameters are pulled from list */
  139.    action=upper(action)
  140. end
  141. if verb='POST' then list=list0
  142.  
  143. /* 1) check for "initialization" command: bbs?INIT=1*/
  144. if cache_mode=0 then do
  145.   if  do_init(list)=1 then  return ' '
  146. end
  147.  
  148. /* 2) initializae client set options  */
  149. do mm=1 to words(option_list)           /*initialize all options to 0 */
  150.    foo='!'||word(option_list,mm)
  151.    arglist.foo=0
  152. end
  153. arglist.!bin_text_links=def_bin_text_links  /* default "binary and text links */
  154. arglist.!oldstuff=''            /* and olstuff to blank */
  155. arglist.!index_list=0        /* index_list is a special case */
  156. arglist.!index_days=0
  157. arglist.!altstart=0
  158. index_mode=0
  159. thisuri=' '
  160.  
  161. /* 3) get the user's options -- but check for special cases: ZIPDOWNLOAD and DOWNLOAD */
  162. /* should never happen if bbscache call */
  163.  
  164. select
  165.    when  abbrev(upper(list0),'DOWNLOAD=')=1 then do    /* 3.01 --- a download */
  166.  
  167.        istext=0 ; isbinary=0
  168.        eek=translate(uri,' ','=/\') 
  169.        action=strip(word(eek,1))
  170.        eek=subword(eek,3)
  171.        t1=word(eek,1)
  172.        if pos(':',t1)>0 then do  /* look for username:password */
  173.                parse upper var t1 arglist.!user ':' arglist.!pwd ;
  174.                eek=delword(eek,1,1)
  175.        end  /* Do */
  176.        leek=words(eek)
  177.        arglist.!file=word(eek,leek) ; eek=delword(eek,leek)
  178.        gdir='/' ; 
  179.        if eek<>' ' then do  /* remainder is probably directory */
  180.          if strip(upper(word(eek,1)))='_FORCE_TEXT_' then do /* check for directive */
  181.             istext=1 ; eek=delword(eek,1,1)
  182.          end
  183.          if strip(upper(word(eek,1)))='_FORCE_BINARY_' then do /* check for directive */
  184.             isbinary=1 ; eek=delword(eek,1,1)
  185.          end
  186.          if eek<>' ' then gdir=translate(strip(eek),'/',' ')
  187.        end
  188.        arglist.!dir=gdir
  189.        arglist.!forcetext=istext
  190.        arglist.!forcebinary=isbinary
  191.    end  /* Do */
  192.  
  193.    when abbrev(upper(list0),'ZIPDOWNLOAD=')>0  then do /* 3.02 --  a zip extraction download */
  194.        istext=0 ; isbinary=0
  195.          eek=translate(uri,' ','=/\') /* list is list from uri */
  196.          action=strip(word(eek,1))
  197.          eek=subword(eek,3)
  198.  
  199.         t1=word(eek,1)
  200.         if pos(':',t1)>0 then do /* look for username:password */
  201.              parse upper var t1 arglist.!user ':' arglist.!pwd
  202.              eek=delword(eek,1,1)
  203.         end  /* Do */
  204.         leek=words(eek)
  205.         arglist.!file=word(eek,leek) ; eek=delword(eek,leek)
  206.         arglist.!zipfile=word(eek,leek-1)||'.ZIP' ; eek=delword(eek,leek-1)
  207.         gdir='/' 
  208.         if eek<>' ' then do
  209.           if strip(upper(word(eek,1)))='_FORCE_TEXT_' then do
  210.               istext=1 ; eek=delword(eek,1,1)
  211.            end
  212.           if strip(upper(word(eek,1)))='_FORCE_BINARY_' then do /* check for directive */
  213.              isbinary=1 ; eek=delword(eek,1,1)
  214.           end
  215.           if eek<>' ' then gdir=translate(strip(eek),'/',' ')
  216.        end
  217.        arglist.!dir=gdir
  218.        arglist.!forcetext=istext
  219.        arglist.!forcebinary=isbinary
  220.    end
  221.  
  222.    otherwise do                 /*3.03 ---  a directory  or index_list request */
  223.        do until list=""                /* get the options -- from UN-modified url  */
  224.           parse var list a0 '&' list
  225.           parse var a0 a1 '=' a2  ; a1=upper(a1)
  226.           if wordpos(a1,option_list)=0 then iterate  /* unknown option */
  227.           foo='!'||a1
  228.           if cache_mode=0 then
  229.               arglist.foo=upper(strip(packur(translate(a2,' ','+'))))
  230.           else
  231.               arglist.foo=upper(strip(translate(a2,' ','+')))
  232.           arglist.foo=strip(arglist.foo,,'"')
  233.        end
  234.    end                  /*otherwise */
  235. end                     /* select */
  236.  
  237.  
  238. /* 3a) set dir and rootdir */
  239. arglist.!dir=translate(arglist.!dir,'/','\')
  240. if arglist.!dir='' | arglist.!dir=0 then arglist.!dir='/'
  241. arglist.!dir='/'||strip(arglist.!dir,'l','/')
  242. arglist.!dir=strip(arglist.!dir,'t','/')||'/'
  243.  
  244. if arglist.!rootdir=1 then arglist.!rootdir=arglist.!dir
  245.  
  246.  
  247. /* 4: Check for "eariler calls" options (used if user:pwd were requestd
  248.       (should never happen if cache_mode */
  249. if arglist.!oldstuff<>' ' then do  /* oldstuff contains more option, space delimited */
  250.    oo=arglist.!oldstuff
  251.    do until oo=""
  252.       parse var oo a0 oo   /* oldstuff is space delimited */
  253.       parse var a0 a1 '=' a2  ; a1=upper(a1)
  254.       if wordpos(a1,option_list)=0 then iterate  /* unknown option */
  255.       foo='!'||a1
  256.       if cache_mode=0 then
  257.          arglist.foo=upper(strip(packur(translate(a2,' ','+'))))
  258.        else
  259.          arglist.foo=upper(strip(translate(a2,' ','+')))
  260.       arglist.foo=strip(arglist.foo,,'"')
  261.    end
  262. end
  263.  
  264.  
  265. /* 5) double check options for goofinesses */
  266. if datatype(arglist.!dircols)<>'NUM' then arglist.!dircols=0
  267. arglist.!short=wordpos(upper(arglist.!short),'Y YES 1')>0
  268. arglist.!notable=wordpos(upper(arglist.!notable),'Y YES 1')>0
  269. arglist.!nosort=wordpos(upper(arglist.!nosort),'Y YES 1')>0
  270. arglist.!noicons=wordpos(upper(arglist.!noicons),'Y YES 1')>0
  271. arglist.!forcetext=wordpos(upper(arglist.!forcetext),'Y YES 1')>0
  272. arglist.!forcebinary=wordpos(upper(arglist.!forcebinary),'Y YES 1')>0
  273. arglist.!bin_text_links=wordpos(upper(arglist.!bin_text_links),'Y YES 1')>0
  274.  
  275. arglist.!nodir=wordpos(upper(arglist.!nodir),'Y YES 1')>0
  276.  
  277. arglist.!notime=wordpos(upper(arglist.!notime),'Y YES 1')>0
  278. arglist.!natime=wordpos(upper(arglist.!natime),'Y YES 1')>0
  279. arglist.!notime=max(arglist.!notime,arglist.!natime)
  280. arglist.!natime=arglist.!notime
  281. arglist.!nosize=wordpos(upper(arglist.!nosize),'Y YES 1')>0
  282. arglist.!nodate=wordpos(upper(arglist.!nodate),'Y YES 1')>0
  283. arglist.!nodesc=wordpos(upper(arglist.!nodesc),'Y YES 1')>0
  284.  
  285. if arglist.!short<>0 then arglist.!notable=1
  286.  
  287. arglist.!user=strip(UPPER(ARGLIST.!user)) 
  288. arglist.!pwd=strip(UPPER(ARGLIST.!pwd))
  289.  
  290.  
  291. header_file.!abs=0
  292. footer_file.!abs=0
  293.  
  294. /* is this a request for a "recent files list"  (should never happen if cache_mode)*/
  295. if arglist.!index_list<>" " & arglist.!index_list<>0 then do
  296.   afoo=cvread(basedir||arglist.!index_list,index_list)
  297.   if afoo=" " then do
  298.      foo=responsebbs('notfound','No such recent files list',arglist.!index_list)
  299.      return foo||' No such recent files list ' arglist.!index_list
  300.   end
  301.   arglist.!nocache=1
  302.   index_mode=1
  303.   if symbol('index_list.!hdrfile')='VAR' then do
  304.      header_file.!abs=1
  305.      header_file=index_list.!hdrfile
  306.   end
  307.   if symbol('index_list.!ftrfile')='VAR' then do
  308.        footer_file.!abs=1
  309.        footer_file=index_list.!ftrfile
  310.   end
  311.   if datatype(arglist.!index_days)<>"NUM" then arglist.!index_days=0
  312. end  /* Do */
  313.  
  314. /* if explicitly no caching, then reset the appropriate flag */
  315. if arglist.!nocache=1 then do   /* but are we explicitily told not to use cache */
  316.   cache.!files=0 
  317. end
  318. else do
  319.    thisuri=make_a_url(cache_opts,' ')
  320. /* vars transfered to cache procedure  -- depends on cookie status */
  321.   cache.!uri=thisuri
  322. end
  323.  
  324. if cache_mode=1 then do
  325.    cache.!cookver=cache_mode_cookver
  326.    is_cookies=cache_mode_cookver
  327. end  /* Do */
  328. else do
  329.   cache.!cookver=0
  330.   if is_cookies=1 then cache.!cookver=1
  331. end
  332.  
  333. if verbose>3  then Say "BBS vars: User pwd dir zipfile file: " arglist.!user ', ' arglist.!pwd  ', ' ,
  334.   arglist.!dir ', ' arglist.!zipfile ', ' arglist.!file
  335.  
  336. /* at this point, arglist contains the true values of the options --
  337.   with decoding done and corrections made */
  338.  
  339. /* 6) Check for user and pwd in the cookie, and possibly add a cookie */
  340. /* Check for username/password cookie -- but only if not explicitly set in url*/
  341.  
  342. if cache_mode=1 then do
  343.     arglist.!user='USER' ; arglist.!pwd='PWD'
  344. end  /* Do */
  345.  
  346. if cache_mode=0 & is_cookies=1 & arglist.!user=0 then do
  347.     t1=sref_get_cookie('BBS_USER_PWD',1)
  348.     if t1<>' ' then do
  349.        parse upper var t1 user ':' pwd ;user=strip(user); pwd=strip(pwd)
  350.        if pwd<>'' then do
  351.           arglist.!user=upper(strip(user))
  352.           arglist.!pwd=upper(strip(pwd))
  353.        END
  354.     end
  355. end
  356. if cache_mode=0 &  is_cookies=1 then do         /* reset the cookie */
  357.      boo=upper('BBS_USER_PWD='||arglist.!user||':'||arglist.!pwd)
  358.      'header add set-cookie: '|| boo
  359. end
  360. /* if authorization mode, also check the username/password field */
  361. if cache_mode=0 & authorization_mode=1 & (arglist.!user=0 | arglist.!user='' | arglist.!user='USER' ) then do
  362.   goo=reqfield('AUTHORIZATION:')
  363.   if goo<>" " then do
  364.        parse var goo . m64 .              /* get the encoded cookie */
  365.        dec=pack64(m64)                       /* and decode it */
  366.        parse upper var dec user ':' pwd      /* split to userid and password */
  367.        arglist.!user=strip(upper(user)) ; arglist.!pwd=strip(upper(pwd))
  368.   end
  369. end
  370.  
  371.  
  372. /*7) check for valid username/pasword.
  373.  If none, check_user will send a prompt file; or will create a
  374.  users.in file (only if authenticate_mode=1).
  375.  Also, will check ctlfile, if one exists.
  376.  And check for download_dir, with possible changes to arglist.!dir.
  377.  Check_user will also return several "globals" (user_header.,
  378.  userlog_lines, privset, file_dir,  reqratio
  379.  Note that file_dir may ALSO contain "strip prefix" flag.
  380. Alternatively: if index_MODE=1, then fix up index_list */
  381.  
  382. wimpy=check_user(arglist.!user,arglist.!pwd,thisuri,ctlfile,defratio,index_mode,cache_mode)
  383. if wimpy=0 then  return '401 0  BBS: Logon problem '
  384. if wimpy=-1  then       return '302 0  Redirect to logon file '
  385.  
  386. if verbose > 2 & index_mode=0 then say arglist.!user  " download/upload ratios & weight = " reqratio ',' download_weight
  387.  
  388. if arglist.!nocache=1 then cache.!files=0
  389.  
  390. /* 8) Access allowed,so now do something useful (ratio check are still required.. */
  391. select
  392.  
  393. /* -- an alternate "screeen" (i.e.; a personallized start screen) */
  394.   when arglist.!altstart<>0 then do
  395.       'RESPONSE HTTP/1.0 302 Moved Temporarily'  /* Set HTTP response line */
  396.       call lineout tempfile, '<!doctype html public "-//IETF//DTD HTML 2.0//EN">'
  397.       call lineout tempfile, "<html><head><title>BBS redirected to alternate  document</title></head>"
  398.       'HEADER ADD Location:' arglist.!altstart
  399.       call lineout tempfile, "<body><h2>BBS redirected to alternate  document/h2>"
  400.       call lineout tempfile, '<a href="'arglist.!altstart'"></a>.'
  401.       call lineout tempfile, "</body></html>"
  402.       call lineout tempfile  /* close */
  403.       'FILE ERASE TYPE text/html NAME ' tempfile
  404.       return '302 0  Redirect to alternate start '
  405.   end  /* Do */
  406.  
  407.  
  408. /* ---- send an "inclusion mode preview"  */
  409.    when index_mode=0 & inclusion_mode_file<>0 & arglist.!preview<>0 then do   /* preview inclusion file */
  410.       a=send_preview(uri)
  411.       return a
  412.    end  /* Do */
  413.  
  414. /* ---- Transfer a file */
  415.    when index_mode=0 & arglist.!file<>0 & arglist.!zipfile=0 & arglist.!dir<>0 then do
  416.      foo=send_file(reqratio,download_weight)          /* expose arglist. tempfile */
  417.      return 'BBS file request '
  418.    end  /* Do */
  419.  
  420. /* -- Show contents of a .ZIP archive */
  421.    when index_mode=0 & arglist.!zipfile<>0  & arglist.!file=0 &  arglist.!dir<>0 then do
  422.       foo=show_zipdir(arglist.!zipfile,arglist.!dir,arglist.!forcetext,arglist.!forcebinary,arglist.!bin_text_links)
  423.       if foo=0 then
  424.          return 'BBS filelist sent '
  425.       else
  426.          return 'BBS filelist sent from cache '
  427.  
  428.    end
  429.  
  430. /* --- extract and send a file from a .ZIP  */
  431.    when index_mode=0 & arglist.!zipfile<>0  & arglist.!file<>0 &  arglist.!dir<>0 then do
  432.       foo=send_zipfile(arglist.!zipfile,arglist.!dir,arglist.!file, ,
  433.                       arglist.!forcetext,arglist.!forcebinary,reqratio,download_weight)
  434.       return ' BBS zip extraction '
  435.    end
  436.  
  437. /* --- send a directory listing */
  438.    when arglist.!dir<>0 | index_mode=1 then do
  439.  
  440.     if send_piece=1 & fixexpire>0 then do  /* do fix expire now or never*/
  441.           fpp=sref_expire_response(fixexpire)
  442.      end
  443.  
  444.      foo=make_dirlist(diropts)          /* expose arglist. tempfile */
  445.  
  446.      if foo=0 then do           /* 0 means not sent from cache */
  447.        if send_piece=0 then do          /* send entire file */
  448.           if cache_mode=0 & fixexpire>0 then do   /* do fix expire */
  449.              ncc=chars(tempfile)
  450.              aa=stream(tempfile,'c','close')
  451.             fpp=sref_expire_response(fixexpire,ncc) 
  452.           end 
  453.           foo=stream(tempfile,'c','close')
  454.           if cache_mode=0 then
  455.              'FILE ERASE TYPE text/html nocache NAME ' tempfile
  456.           else
  457.              foo=sysfiledelete(tempfile)
  458.           return 'BBS filelist sent '
  459.        end
  460.        else do                  /* close of send in piecs */
  461.            'send complete '
  462.             return 'BBS filelist sent in pieces '
  463.         end  /* Do */
  464.      end
  465.      else do
  466.         return 'BBS filelist sent from cache '
  467.      end
  468.   end
  469.  
  470. /* --- error */
  471.   otherwise do
  472.      foo=responsebbs('notfound','No such BBS command',' No BBS command ')
  473.      return foo||' Unknown BBS command '
  474.  
  475.   end
  476. end  /* Do */
  477.  
  478.  
  479.  
  480. return ' '
  481.  
  482. /* ----------  end of main portion of bbs  ----------- */
  483.  
  484.  
  485. /* -------------------------------- */
  486. /* Check parameters. call as subroutine (many globals */
  487. check_params:
  488.  
  489.  
  490. bbs_param=translate(bbs_param_dir,'\','/')
  491. if abbrev(strip(bbs_param,'l','\'),'\') =0 & pos(':',bbs_param)=0 then /* must be relative dir*/
  492.    bbsdir=basedir||strip(bbs_param,'t','\')||'\'
  493. else
  494.    bbsdir=strip(bbs_param,'t','\')'\'
  495.  
  496. /* the "directory" icon */
  497. dirgif='<img src="'ImagePath'menu.gif"' imagesize '  align=top alt="[dir] ">'
  498. /* the "back to parent" icon */
  499. backgif='<img src="'ImagePath'back.gif"' imagesize ' align=top alt="[..] ">'
  500. /* The "expand this .ZIP file" icone */
  501. unzipme='<img src="'ImagePath'expand.gif"' imagesize '  align=top alt="[unzip]"></a>'
  502.  
  503. userlog_dir=translate(userlog_dir,'\','/')
  504. if abbrev(strip(userlog_dir,'l','\'),'\')=0 & pos(':',userlog_dir)=0 then /* must be relative dir*/
  505.    userlog_dir=bbsdir||strip(userlog_dir,'t','\')||'\'
  506. else
  507.    userlog_dir=strip(userlog_dir,'t','\')||'\'
  508.  
  509. bbscache_dir=translate(bbscache_dir,'\','/')
  510. if abbrev(strip(bbscache_dir,'l','\'),'\')=0 & pos(':',bbscache_dir)=0 then /* must be relative dir*/
  511.    bbscache_dir=bbsdir||strip(bbscache_dir,'t','\')||'\'
  512. else
  513.    bbscache_dir=strip(bbscache_dir,'t','\')'\'
  514.  
  515. cache.!dir=bbscache_dir
  516. cache.!duration=cache_duration
  517. cache.!files=cache_files
  518.  
  519. if datatype(must_wait)<>'NUM' then must_wait=1
  520.  
  521. defratio=default_ratio||' '||default_byte_ratio
  522. DEFAULT_DATEFMT=UPPER(DEFAULT_DATEFMT)
  523. if wordpos(default_datefmt,'B C D E M N O S U W')=0 then default_datefmt='N'
  524.  
  525. DEFAULT_SORT_BY=UPPER(DEFAULT_SORT_BY)                                           
  526. if wordpos(default_sort_by,'DATE EXT NAME SIZE NOSORT')=0 then default_sort_by='NAME'     
  527.  
  528. imagepath='/'||strip(imagepath,,'/')||'/'
  529.  
  530. if cache_mode=0 then fixexpire=value(enmadd||'FIX_EXPIRE',,'os2environment')
  531.  
  532. privset=upper(privset)
  533. user_header.0=' '
  534.  
  535. /* a time  date stamp */
  536.  d1=date('b')
  537.  t1=time('m')/(24*60)
  538.  nowtime=d1+t1
  539.  
  540.  user='USER' ; pwd='PWD'
  541.  
  542. if dosisdir(strip(bbsdir,'t','\'))=0 then do
  543.      say " ERROR: no BBS parameters directory:" bbsdir
  544.      foo=responsebbs('forbid','BBS is unavailable (no ' bbsdir ')')
  545.      amess=' BBS unavailable '
  546.      return foo||amess
  547. end
  548.  
  549. if dosisdir(strip(userlog_dir,'t','\'))=0 then do
  550.      say " ERROR: no BBS user log directory:" userlog_dir
  551.      foo=responsebbs('forbid','BBS is unavailable (no ' userlog_dir ')')
  552.      amess=' BBS unavailable '
  553.      return foo||amess
  554. end
  555.  
  556. if dosisdir(strip(bbscache_dir,'t','\'))=0 then do
  557.      say " ERROR: no BBS user log directory:" bbscache_dir
  558.      foo=responsebbs('forbid','BBS is unavailable (no ' bbscache_dir ')')
  559.      amess=' BBS unavailable '
  560.      return foo||amess
  561. end
  562.  
  563.  
  564.  
  565.  
  566. /* check on counter file */
  567. counter_file=bbsdir||'BBS.CNT'
  568. if stream(counter_file,'c','query exists')=" " then do  /* doesn't exist, create it */
  569.     call lineout counter_file,'; BBS counter file -- all downloads '
  570.     call lineout counter_file
  571. end
  572.  
  573. ctlfile=stream(bbsdir||'BBS.CTL','c','query exists') /* blank means none */
  574.  
  575. /* fix up the icons list */
  576.  if icons.1=0 then do
  577.       icons.0=0
  578.  end
  579.  else do
  580.      nn=0
  581.      do forever
  582.          nn=nn+1
  583.          if symbol('ICONS.'||nn)<>'VAR' then leave
  584.          if icons.nn=0 then  leave
  585.     end /* do */
  586.     icons.0=nn-1
  587.  end
  588.  
  589.  
  590. if symbol('USE_SERVERNAME')='VAR' then do
  591.   if  use_servername="" | use_servername=0 then do
  592.      use_servername=servername
  593.   end
  594. end
  595. else do
  596.        use_servername=servername
  597. end
  598.  
  599.  
  600. if cache_mode=0 then is_cookies=0
  601. if cache_mode=0 & use_cookies=1 then do
  602.    ook=reqfield('cookie')
  603.    if ook<>""  then    is_cookies=1
  604. end
  605.  
  606. option_list='USER PWD DIR FILE SHORT NOSORT NOTABLE NOICONS SORTBY ZIPFILE '
  607. option_list=option_list||' FORCETEXT FORCEBINARY BIN_TEXT_LINKS NODIR NOTIME NODATE NOSIZE NODESC OLDSTUFF PREVIEW PREVIEWDIRS '
  608. option_list=option_list||' SIZEFMT DATEFMT TIMEFMT  ROOTDIR NATIME DIRCOLS NOCACHE '
  609. option_list=option_list||' INDEX_LIST INDEX_DAYS  ALTSTART '
  610.  
  611. cache_opts='DIR ZIPFILE ROOTDIR NOSORT NOTABLE NOICONS NODIR NOTIME NODATE NODESC NOSIZE '
  612. CACHE_OPTS=CACHE_OPTS||' SHORT SORTBY FORCETEXT BIN_TEXT_LINKS FORCEBINARY SIZEFMT DATEFMT TIMEFMT DIRCOLS PREVIEWDIRS '
  613.  
  614. if is_cookies=0 & authorization_mode<>1 then do
  615.    dd='USER PWD DIR ZIPFILE  ROOTDIR NOSORT NOTABLE NOICONS NODIR NATIME NODATE NODESC NOSIZE '
  616.    dd=dd||' SHORT SORTBY FORCETEXT BIN_TEXT_LINKS FORCEBINARY SIZEFMT DATEFMT TIMEFMT DIRCOLS NOCACHE '
  617. end 
  618. else do
  619.    dd='DIR ROOTDIR ZIPFILE NOSORT NOTABLE NOICONS NODIR NATIME NODATE NODESC NOSIZE '
  620.    dd=dd||' SHORT SORTBY FORCETEXT BIN_TEXT_LINKS FORCEBINARY SIZEFMT DATEFMT TIMEFMT DIRCOLS NOCACHE INDEX_LIST INDEX_DAYS '
  621. end
  622. diropts=dd
  623. /* if inclusion_mode_file, then modify some others */
  624. if inclusion_mode_file=' ' then inclusion_mode_file=0
  625. if inclusion_mode_file<>0 then do
  626.    description_file=inclusion_mode_file
  627.    auto_describe=0
  628. end  /* Do */
  629.  
  630.  
  631. amess=""
  632. return amess
  633.  
  634. /*********************/
  635. /* create a url, from arglist. and a cache_opts */
  636. make_a_url:procedure expose arglist.
  637. parse arg theopts,thesep
  638. thisuri=""
  639. do mm=1 to words(theopts)
  640.      a0=strip(word(theopts,mm)) ;aa='!'||a0
  641.      if arglist.aa=0 then iterate         /* ignore if default value is used */
  642.      bc=a0||'='||arglist.aa
  643.      if thisuri="" then
  644.         thisuri=bc
  645.      else
  646.        thisuri=thisuri||thesep||bc   /* use thesep as seperator */
  647. end /* do */
  648. return thisuri
  649.  
  650.  
  651.  
  652. /********************/
  653. /* perform an initialization */
  654. do_init:procedure expose bbscache_dir
  655. parse arg list
  656. if abbrev(upper(list),'INIT=')=1 then do   /* reset time ! */
  657.  wow=sysfiletree(bbscache_dir||'$*.HTM',boys,'F')
  658.  dels=0
  659.  do mm=1 to boys.0
  660.      parse var boys.mm a b c d e
  661.      foo=sysfiledelete(strip(e))
  662.      if foo=0 then dels=dels+1
  663.  end
  664.  foo=sysfiledelete(bbscache_dir||'BBSCACHE.IDX')
  665.  if foo=0 then dels=dels+1
  666.  string ' BBS cache has been initialized (' dels ' old entries were deleted) '
  667.  return 1
  668. end  /* ?INIT= command */
  669. return 0
  670.  
  671.  
  672.  
  673.  
  674.  
  675. /********************************************/
  676. @ display file list.  Use a table, unless NOTABLE=YES appears.
  677. Show time, date, size; unless SHORT=YES appears.
  678. Note use of header file, and descrpiption file */
  679.  
  680. send_file:procedure expose arglist. send_piece tempfile  bbsdir  servername footer_file ,
  681.                              header_file footer_text header_text file_dir ,
  682.                                description_file userlog_dir,
  683.                              imagepath imagesize dirgif backgif must_wait write_details ,
  684.                              exclusion_file counter_file bytes_newuser files_newuser ,
  685.                              nowtime userlog_lines. user_header. userfile use_servername
  686. parse arg aratio,aweight
  687.  
  688. thedir=strip(translate(arglist.!dir,'\','/'),'l','\')
  689.  
  690. gets=make_adir(file_dir,thedir)
  691. /*gets=strip(file_dir,'t','\')||'\'||thedir*/
  692.  
  693. if dosisdir(gets)=0 then do
  694.   call lineout tempfile, '<!doctype html public "-//IETF//DTD HTML 2.0//EN">'
  695.   call lineout tempfile, "<html><head><title>Can not find directory</title></head>"
  696.   call lineout tempfile, "<body><h2>Sorry...</h2>"
  697.   call lineout tempfile,' Could not find directory: ' arglist.!dir
  698.   call lineout tempfile, "</body></html>"
  699.   call lineout tempfile  /* close */
  700.   'FILE ERASE TYPE text/html NAME ' tempfile
  701.   return 0
  702. end
  703.  
  704. dofile=translate(arglist.!file,' ','\/')
  705. dofile=strip(word(dofile,1))
  706.  
  707. absfile=strip(gets||'\'||dofile)
  708. yip=stream(absfile,'c','query exists')=' '
  709. if yip=' 'then do
  710.   call lineout tempfile, '<!doctype html public "-//IETF//DTD HTML 2.0//EN">'
  711.   call lineout tempfile, "<html><head><title>Can not find file</title></head>"
  712.   call lineout tempfile, "<body><h2>Sorry...</h2>"
  713.   call lineout tempfile,' Could not find file: ' arglist.!file
  714.   call lineout tempfile, "</body></html>"
  715.   call lineout tempfile  /* close */
  716.   'FILE ERASE TYPE text/html NAME ' tempfile
  717.   return 0
  718. end
  719.  
  720. if download_okay(must_wait,aratio)=0 then return 0
  721.  
  722. /* if here, file transfer is allowed ! */
  723. select
  724.    when  arglist.!forcetext<>0 then
  725.       atype='text/plain'
  726.    when arglist.!forcebinary<>0 then
  727.      atype='application/octet-stream'  
  728.    otherwise
  729.      atype=sref_mediatype(absfile)
  730. end
  731.  
  732.  
  733. 'FILE TYPE ' atype ' NOCACHE NAME ' ABSFILE
  734.  
  735. foo=add_userinfo(aweight,chars(absfile),' ')
  736. return 0
  737.  
  738.  
  739.  
  740. /****************/
  741. /* is user allowed to download? */
  742. download_okay:procedure expose send_piece tempfile user_header. bytes_newuser files_newuser ,
  743.         nowtime user_header.
  744.  
  745.  
  746. parse arg must_wait,aratio
  747. if wordpos('STATUS',user_header.0)=0 then
  748.    statline='0 0 0 0 0 '
  749. else
  750.   statline=user_header.!status
  751.  
  752. parse var aratio ratiof ratiob
  753. parse var statline  downloads uploads downloadb uploadb index_Time
  754.  
  755. /* check ratio */
  756. if (ratiof<>0 | ratiob<>0) & downloads+downloadb>0 then do
  757.    tupl=uploads
  758.    if tupl=0 then tupl=max(1,files_newuser)  /* give him one to start */
  759.    tuplb=uploadb
  760.    if tuplb=0 then tuplb=max(bytes_newuser,1)
  761.    myratio=downloads/tupl
  762.    myratiob=downloadb/tuplb
  763.    if index_time+must_wait > nowtime then do /* he's out of his gracep period */
  764.       if (ratiof<>0 & myratio>ratiof) | (ratiob<>0  & myratiob>ratiob) then do
  765.          call lineout tempfile, "<body><h2>Sorry...</h2>"
  766.          call lineout tempfile,'<b> Your download to upload ratio is too high! </b> <br>'
  767.          towait=(index_time+must_wait)-nowtime
  768.          if towait<1  then do
  769.              towait=format(towait*24,2,1)
  770.              call lineout tempfile,' <blockquote> You can download 1 file in ' towait ' hours , <br>'
  771.          end
  772.          else do
  773.             towait=format(towait,,1)
  774.             call lineout tempfile,' <blockquote> You can download 1 file in ' towait 'days, <br>'
  775.          end
  776.          call lineout tempfile,' ... or you can upload some files! </blockquote> '
  777.          call lineout tempfile,' <!-- Files (req. ratio,download upload: ' ratiof ', ' downloads uploads  ' -->'
  778.          call lineout tempfile,' <!-- Bytes (req. ratio,download uploadd: ' ratiob ', ' downloadb uploadb  ' -->'
  779.          call lineout tempfile, "</body></html>"
  780.          call lineout tempfile  /* close */
  781.          'FILE ERASE TYPE text/html NAME  ' tempfile
  782.          return 0
  783.       end
  784.    end  /* Do */
  785. end
  786. return 1
  787.  
  788.  
  789.  
  790. /**********************/
  791. /* add info to user file */
  792.  
  793. add_userinfo:procedure expose user_header. userlog_lines. userfile ,
  794.             write_details arglist. counter_file nowtime
  795.  
  796. parse arg aweight,thesize,extrainfo,isfile2
  797.  
  798.  
  799. isdir=arglist.!dir
  800. isfile=arglist.!file
  801.  
  802. if wordpos('STATUS',user_header.0)=0 then
  803.   infoat='0 0 0 0 0 '
  804. else
  805.   infoat=user_header.!status
  806.  
  807. parse var infoat dl ul dlb ulb .
  808.  
  809. dl=dl+aweight ; dlb=dlb+(aweight*thesize)
  810.  
  811. ii=userlog_lines.statusat
  812. userlog_lines.ii='Status: 'dl' 'ul' 'dlb' 'ulb' 'nowtime
  813.  
  814. if write_details=1 then do
  815.     vv=userlog_lines.0+1
  816.     userlog_lines.0=vv
  817.     isdir2=upper(strip(translate(isdir,'/','\'),,'/')||'/')
  818.     if isfile2<>' ' then
  819.         userlog_lines.vv=isfile2 ' ' extrainfo ' ' time('n') date('n')
  820.     else
  821.        userlog_lines.vv=isdir2 ' ' extrainfo ' ' isfile ' ' time('n') date('n')
  822.     userlog_lines.0=vv
  823. end  /* Do */
  824.  
  825. /* save userlog file */
  826. aa=filewrite(userfile,userlog_lines)
  827. if aa=0 & verbose>0 then
  828.   call pmprintf( " Could not augment&update BBS userfile: " userfile)
  829.  
  830.  
  831. /* augment counter file */
  832. if extrainfo=' ' then
  833.    putme=strip(isdir,'t','/')||'/'||isfile
  834. else
  835.    putme=strip(isdir,'t','/')||'/'extrainfo||':'||isfile
  836. putme=strip(putme,'l','\')
  837. putme=strip(putme,'l','/')
  838. stuff=sref_lookup_count(counter_file,putme,'ADD','*',2)
  839.  
  840. return ' '
  841.  
  842.  
  843. /***********************************/
  844. /* send a preview, using the inclusion_mode_file "as is" */
  845. send_preview:procedure expose arglist. inclusion_mode_file file_dir send_piece tempfile
  846. parse arg theuri
  847.  
  848. thedir=strip(translate(arglist.!dir,'\','/'),'l','\')
  849. gets=make_adir(file_dir,thedir)
  850. /*gets=strip(file_dir,'t','\')||'\'||thedir*/
  851.  
  852. /* if here, either no caching, or no matching $dircach file */
  853. fungo='/'strip(translate(arglist.!dir,'/','\'),'l','/')
  854. call lineout tempfile, "<html><head><title> BBS: Preview of " fungo"</title></head>"
  855.  
  856. if dosisdir(gets)=0 then do             /* no such directory */
  857.   call lineout tempfile, '<!doctype html public "-//IETF//DTD HTML 2.0//EN">'
  858.   call lineout tempfile, "<html><head><title> BBS: Can not find  " fungo"</title></head>"
  859.   call lineout tempfile, "<body><h2>Sorry...</h2>"
  860.   call lineout tempfile,' * Could not find the directory: ' arglist.!dir
  861.   call lineout tempfile, "</body></html>"
  862.   call lineout tempfile  /* close */
  863.   'FILE ERASE TYPE text/html NAME ' tempfile
  864.   return 'BBS: No directory to preview '
  865. end
  866.  
  867. doit=gets||'\'||inclusion_mode_file
  868. if stream(doit,'c','query exist')=' ' then do
  869.   call lineout tempfile, '<!doctype html public "-//IETF//DTD HTML 2.0//EN">'
  870.   call lineout tempfile, "<html><head><title>No preview file</title></head>"
  871.   call lineout tempfile, "<body><h2>Sorry...</h2>"
  872.   call lineout tempfile,' Could not find preview file.'
  873.   call lineout tempfile, "</body></html>"
  874.   call lineout tempfile  /* close */
  875.   'FILE ERASE TYPE text/html NAME ' tempfile
  876.   return 'BBS: No INCLUSION_MODE_FILE: '||inclusion_mode_file
  877. end
  878.  
  879. /* got the file.  Read it in, add a "return link", and ship it */
  880.   call lineout tempfile, "<html><head><title>Previewing: " fungo "</title></head>"
  881.  
  882. aa=fileread(doit,dolines,,'E')
  883. if dolines.0=0 then do
  884.   call lineout tempfile, '<!doctype html public "-//IETF//DTD HTML 2.0//EN">'
  885.   call lineout tempfile, "<html><head><title>Incorrect preview file</title></head>"
  886.   call lineout tempfile, "<body><h2>Sorry...</h2>"
  887.   call lineout tempfile,' Could not read preview file.'
  888.   call lineout tempfile, "</body></html>"
  889.   call lineout tempfile  /* close */
  890.   'FILE ERASE TYPE text/html NAME ' tempfile
  891.   return 'BBS: bad inclusion mode file: ' inclusion_mode_file
  892. end
  893.  
  894. /* send this file */
  895.   call lineout tempfile, '<!doctype html public "-//IETF//DTD HTML 2.0//EN">'
  896.   call lineout tempfile, "<html><head><title>Incorrect preview file</title></head>"
  897.  
  898. call lineout tempfile,'<pre>'
  899. do mm=1 to dolines.0
  900.    call lineout tempfile,dolines.mm
  901. end /* do */
  902.  
  903. call lineout tempfile,'</pre><hr>'
  904.  
  905. /* add a link back */
  906. if wordpos(upper(arglist.!preview),'NOLINK 2')=0 then do
  907.    theuri=sref_replacestrg(theuri,'PREVIEW=','PREVIEWDIRS=','ALL')
  908.    ali='<hr> Do you want to <a href="'
  909.    ali=ali||theuri
  910.    ali=ali||'">download files from '||fungo||'</a>'
  911.    call lineout tempfile,ali
  912. end
  913. call lineout tempfile, "</body></html>"
  914. call lineout tempfile  /* close */
  915.  
  916. 'FILE ERASE TYPE text/html NAME ' tempfile
  917. return 'BBS: previewing: ' fungo
  918.  
  919.  
  920. /********************************************/
  921. /* display file list.  Use a table, unless NOTABLE=YES appears.
  922. Show time, date, size; unless SHORT=YES, (or vaious Noxxx options selected)
  923. Note use of header file, and descrpiption file
  924. Also, send pieces as available if send_piece=1
  925. First, see if a cache file is present and useable for this request */
  926.  
  927. make_dirlist:procedure expose arglist. send_piece tempfile  bbsdir  servername footer_file,
  928.                        header_file footer_text header_text file_dir description_file ,
  929.                        imagepath imagesize dirgif backgif exclusion_file table_border cell_spacing ,
  930.                        continuation_flag default_description_dir  nowtime ,
  931.                        default_description description_text action icons. ,
  932.                        unzipme cache.  uri authorization_mode fixexpire verbose use_servername ,
  933.                        cache_check  option_list description_text_length auto_describe ,
  934.                        zip_descriptor_file default_dateFMT default_sort_by inclusion_mode_file ,
  935.                        description_text_length_1LINE index_list. index_mode ,
  936.                        header_File.!abs footer_file.!abs cache_mode
  937.  
  938. parse arg diropts
  939.  
  940. crlf='0d0a'x
  941. udircols=arglist.!dircols
  942. if udircols=0 then udircols=3
  943. if datatype(table_border)<>"NUM" then table_border=0
  944. if datatype(cell_spacing)<>"NUM" then cell_spacing=0
  945.  
  946.  
  947.  
  948. if index_mode=0 then do                /* skip if "use recent list */
  949.    thedir=strip(translate(arglist.!dir,'\','/'),'l','\')
  950.    gets=make_adir(file_dir,thedir)
  951. /*   gets=strip(file_dir,'t','\')||'\'||thedir*/
  952.  
  953.   /* check cache? */
  954.   if cache.!files>0 then do
  955.      okay=send_from_cache(gets||'\*.*',cache_check)  /* cache_check controls if check timedate crc */
  956.      if okay=1 then return -1
  957.   end  /*  otherwise, create it */
  958. end
  959.  
  960. if cache_mode=1 then say "   -- processing: " gets
  961.  
  962. /* if here, index_mode, or no caching, or no matching $dircach file */
  963.  
  964. if send_piece=1 then do         /* set up "sending pieces" mode */
  965.           'SET NETBUFFER OFF '
  966.           'SEND TYPE text/html as INDXSRCH '
  967. end
  968.  
  969. if index_mode=0 then do    /* check existence of this directory */
  970.   fungo='/'strip(translate(arglist.!dir,'/','\'),'l','/')
  971.   call dumpit("<html><head><title> BBS: Listing " fungo"</title></head>")
  972.   if dosisdir(gets)=0 then do
  973.      aa="<body><h2>Sorry...</h2>"crlf
  974.      aa=aa||' ** Could not find the directory: ' arglist.!dir||crlf
  975.      aa=aa||"</body></html>"
  976.      call dumpit(aa)
  977.      if send_piece=0  then call lineout tempfile
  978.      return 0
  979.    end
  980. end
  981. else do         /* use preset title */
  982.   call dumpit("<html><head><title> " index_list.!title"</title></head>")
  983. end  /* Do */
  984.  
  985.  
  986.  
  987. call write_the_header  /* write out header now (reassure impatient clients ) */
  988.  
  989. if index_mode=0 then do                /* standard mode, get the file lsit */
  990. /* read descriptions from .dsc files */
  991.    foo=make_dsc_descriptions(gets)
  992.  
  993. /* create an array containing file info, and descritions */
  994.  
  995.   auto_describe.!alen=0           /*first, fix up auto_describe parameter */
  996.   if auto_describe>0 then do
  997.     if auto_describe=1 then auto_describe=120
  998.     auto_describe.!alen=auto_describe
  999.   end
  1000. end             /* else, use description stored in the index_list */
  1001.  
  1002. /* get_filelist will call find_description */
  1003. wow=get_filelist(gets,arglist.!nosort,arglist.!sortby,arglist.!dir,arglist.!forcetext,arglist.!forcebinary,arglist.!bin_text_links, ,
  1004.                 arglist.!sizefmt,arglist.!datefmt,arglist.!timefmt,cache.!cookver,index_mode,arglist.!Noicons)
  1005.  
  1006. excludes=get_exclusions(exclusion_file,gets,bbsdir)
  1007. excludes=translate(excludes,'\','/')
  1008.  
  1009. /* Inclusions_mode_file? Then redo filelist. */
  1010. if index_mode=0 & inclusion_mode_file<>0 then do
  1011.      foo=inclusions_redo(gets,inclusion_mode_file)
  1012. end  /* Do */
  1013.  
  1014. wewrote=0               /* used to signal when to write header */
  1015. if index_mode=1 then do
  1016.    call write_table_header
  1017.    wewrote=1
  1018. end
  1019.  
  1020. do yy=1 to filelist.0  /* ---------- LOOP THROUGH FILE/CMT ENTRIES ---- */
  1021.    tname=filelist.yy.name
  1022.    if tname=' '  then do    /* comment line */
  1023.        if arglist.!notable<>0 | wewrote=0 then do    /* use  <PRE> for names/date/etc */
  1024.             call dumpit(filelist.yy.dastuff '<br>')
  1025.        end
  1026.        else do
  1027.            call dumpit('<td valign=top colspan='ntds'> ' filelist.yy.dastuff '</td><tr valign=top>')
  1028.        end  /* Do */
  1029.        iterate
  1030.    end  /* Do */
  1031.  
  1032. /* if tname is in exclusion list, skip */
  1033.     if index_mode=0 then do
  1034.       if is_excluded(tname,excludes)=1 then do
  1035.          iterate
  1036.       end
  1037.     end
  1038.     if tname<>' ' then do
  1039.       tdate=left(filelist.yy.date,12)
  1040.       ttime=right(filelist.yy.time,7)
  1041.       tsize=right(filelist.yy.size,14)
  1042.       if arglist.!nosize<>0 then tsize=' '
  1043.       if arglist.!nodate<>0 then tdate=' '
  1044.       if arglist.!notime<>0 | arglist.!nodate<>0 then ttime=' '
  1045.    end
  1046.  
  1047.    wewrote=wewrote+1
  1048.    if wewrote=1 then  call write_table_header
  1049.  
  1050. /* create the link, etc for this file */
  1051.    if filelist.yy.aurl<>' ' then do
  1052.        if arglist.!noicons=0 then do
  1053.           if filelist.yy.aurl.0<>0 then DO
  1054.              APIC='<a href="'||filelist.yy.aurl.1||'">'||IMAGETYPE('FOO.TXT')||'</a>'
  1055.              APIC=APIC||'  <a href="'||filelist.yy.aurl.2||'">'||IMAGETYPE('FOO.BIN')||'</a>  '
  1056.           END
  1057.           ELSE DO
  1058.              select
  1059.                 when arglist.!forcetext=1 then
  1060.                     APIC='<a href="'||filelist.yy.aurl.!inner||'">'||IMAGETYPE('foo.txt')||'</a>'
  1061.                 when arglist.!forcebinary=1 then
  1062.                     APIC='<a href="'||filelist.yy.aurl.!inner||'">'||IMAGETYPE('foo.bin')||'</a>'
  1063.                  otherwise
  1064.                     APIC='<a href="'||filelist.yy.aurl.!inner||'">'||IMAGETYPE(tname)||'</a>'
  1065.              end
  1066.           END
  1067.        end
  1068.        else do          /* no icons */
  1069.           if filelist.yy.aurl.0<>0 then DO
  1070.              APIC='<a href="'||filelist.yy.aurl.1||'">'||'[text]'||'</a>'
  1071.              APIC=APIC||'  <a href="'||filelist.yy.aurl.2||'">'||'[bin]'||'</a>  '
  1072.           END
  1073.           else do
  1074.              apic=' '
  1075.           end  /* Do */
  1076.        end  /* Do */
  1077.        booger='<a href="'||filelist.yy.aurl||'">'||tname||'</a>'
  1078.     end
  1079.     else do                     /* no url for this name */
  1080.         booger='<code><u>'||tname||'</u></code>'
  1081.         apic='xx'
  1082.     end
  1083.  
  1084.     ae=extension(tname)
  1085.     if ae='ZIP' & filelist.yy.aurl<>' 'then do         /* CREATE A ZIP EXPANSION LINK */
  1086.       ezip=arglist.!zipfile
  1087.       arglist.!zipfile=tname
  1088.       if index_mode=1 then arglist.!dir=filespec('p',filelist.yy)
  1089.       dirlink=make_a_url(diropts,' ')
  1090.       if pos('&',dirlink)>0 then do  /* prevent & in filename bug */
  1091.            frog3=sref_replacestrg(dirlink,'%','%25','ALL')
  1092.            dirlink=sref_replacestrg(frog3,'&','%26','ALL')
  1093.       end  /* Do */
  1094.       dirlink=translate(dirlink,'&',' ')
  1095.       arglist.!zipfile=ezip
  1096.       ahref='<a href="'||action||'?'||dirlink||'">'
  1097.       ahref=ahref||unzipme
  1098.     end
  1099.     else do
  1100.        ahref=" "
  1101.     end
  1102.  
  1103. /* write it out, in one of 3 forms */
  1104.    if arglist.!short<>0 then do                 /* simple mode */
  1105.        call dumpit(booger)
  1106.        iterate
  1107.    end
  1108.  
  1109.    if arglist.!notable<>0 then do            /* notable mode */
  1110.          zblanks=' '
  1111.          if length(tname)<18 then zblanks=copies(' ',19-length(tname))
  1112.          if notes.0>0 & arglist.!nodesc<>1 then do           /* do descriptions too */
  1113.             if description_text=1 then do  /* pre text */
  1114.                aa=ahref' 'apic' 'booger' 'zblanks' 'tdate' 'ttime' 'tsize||crlf
  1115.                useme=format_desc(filelist.yy.dastuff,description_text_length,description_text_length_1line,1)
  1116.                USEME=AA||ADD_SPACE_TO_LINE(USEME)
  1117.             end
  1118.             else do             /* html text */
  1119.                useme='<pre>'ahref' 'apic' 'booger' 'zblanks' 'tdate' 'ttime' 'tsize'</pre>'
  1120.                useme=useme||'<MENU><LI>'||filelist.yy.dastuff||'</MENU>'
  1121.             end
  1122.             call dumpit(useme)
  1123.          end
  1124.          else do                /* no descriptoins */
  1125.               call dumpit(ahref' 'apic' 'booger' 'zblanks' 'tdate' 'ttime' 'tsize)
  1126.          end
  1127.         iterate
  1128.    end
  1129.  
  1130.   if arglist.!notable=0 then do            /*TABLE mode */
  1131.          aa='<td valign=top> '  ahref  '</td> 'crlf
  1132.          aa=aa||'<td nowrap valign=top> '   apic booger '</td> 'crlf
  1133.          if arglist.!nodate=0 then
  1134.               aa=aa||'<td valign=top> '  tdate ttime '</td> 'crlf
  1135.          if arglist.!nosize=0 then
  1136.               aa=aa||'<td valign=top > '  tsize '</td> 'crlf
  1137.          if notes.0>0 & arglist.!nodesc<>1 then do
  1138.             useme=filelist.yy.dastuff
  1139.             if description_text=1 then do
  1140.                 useme=format_desc(filelist.yy.dastuff,description_text_length,description_text_length_1line,0)
  1141.                 aa=aa||'<td valign=top><pre>' useme '</pre></td> 'crlf
  1142.             end
  1143.             else do
  1144.                aa=aa||'<td valign=top> ' useme '</td> 'crlf
  1145.             end
  1146.          end
  1147.          if yy< filelist.0 then aa=aa||'<tr valign=top> 'crlf
  1148.          call dumpit(aa)
  1149.  
  1150.    end  /* table */
  1151.  
  1152. end /* all the files */
  1153.  
  1154. if usingpre<>0  then    call dumpit('</pre>')
  1155. if usingtable<>0 then   call dumpit('</table>')
  1156. if index_mode=1 then do
  1157.    call dumpit("<br><em> # entries= " index_list.!okay '</em>')
  1158. end  /* Do */
  1159.  
  1160. if arglist.!nodir<>0 then signal dofooter
  1161.  
  1162. aa='<hr>'
  1163.  
  1164. call dumpit(aa)
  1165.  
  1166. /* skip dirs if recent mode=1 */
  1167. if index_mode=1 then signal dofooter
  1168.  
  1169. /* -=--------  now display directories */
  1170. wow=sysfiletree(gets||'\*.*','dirlist','OD')
  1171. if not_tvfs<>1 then do           /* check for tvfs bug unless explicitliy told not to */
  1172.   iok=0
  1173.    do nn=1 to dirlist.0
  1174.        arf=dosisdir(strip(word(dirlist.nn,words(dirlist.nn))))
  1175.        if arf=1 then do
  1176.            iok=iok+1
  1177.            dirlist.iok=dirlist.nn
  1178.         end
  1179.   end
  1180.   dirlist.0=iok
  1181. end
  1182.  
  1183. frogdir=translate(arglist.!dir,'/','\')
  1184.  
  1185. if arglist.!notable=0 then do
  1186.    fpp='/'strip(translate(arglist.!dir,'/','\'),'l','/')
  1187.    call dumpit('<Table width=80% ><th nowrap colspan='udircols '> Directories of ' fpp  ' </th><tr valign=top>')
  1188. end  /* Do */
  1189.  
  1190. twrote=0 ; adesc=' '
  1191. olddir=arglist.!dir; olddir1=strip(olddir,'t','/')||'/'
  1192.  
  1193. /* Inclusions_mode_file? Then redo dirlist. */
  1194.  
  1195. if inclusion_mode_file<>0 then do
  1196.    foo=inclusions_redo_dir(gets,inclusion_mode_file)
  1197. end  /* Do */
  1198.  
  1199. dirlist.0.iscmt=0
  1200. do yy=0 to dirlist.0                    /* write directory info */
  1201.    if inclusion_mode_file=0 then dirlist.yy.iscmt=0 
  1202.  
  1203.    if yy=0  then do             /* linkt to parent */
  1204.       isroot=strip(translate(arglist.!dir,' ','\/'))
  1205.       adesc=' '
  1206. /* but see if arglist.!rootdir is binding */
  1207.       aroot=translate(arglist.!rootdir,' ','/\')
  1208.       if aroot<>0 then do
  1209.            if abbrev(upper(strip(isroot)),upper(strip(aroot)))<>1 then iterate  /* rootdir violated*/
  1210.            if words(isroot) = words(aroot) then iterate
  1211.       end  /* Do */
  1212.       if isroot='' then iterate  /* no parent of root */
  1213.       frogdir=arglist.!dir
  1214.       adir0=subword(isroot,1,words(isroot)-1)
  1215.       if adir0="" then adir0='/'
  1216.       arglist.!dir=translate(adir0,'/',' ')
  1217.       dirlink=make_a_url(diropts,' ')
  1218.       if pos('&',dirlink)>0 then do  /* prevent & in filename bug */
  1219.            frog3=sref_replacestrg(dirlink,'%','%25','ALL')
  1220.            dirlink=sref_replacestrg(frog3,'&','%26','ALL')
  1221.       end  /* Do */
  1222.       dirlink=translate(dirlink,'&',' ')
  1223.       adir1='parent directory '
  1224.       agif=backgif
  1225.    end
  1226.    else do                      /* link to subdirectory */
  1227.       adir=dirlist.yy
  1228.       tmp=translate(adir,' ','/\:')
  1229.       adir1=word(tmp,words(tmp))
  1230.  
  1231.       if is_excluded('/'||adir1,excludes)=1 then
  1232.           iterate
  1233.  
  1234.       adesc=find_description('/'||adir1)
  1235.       if dirlist.yy.iscmt<>1 then do
  1236.          agif=imagetype('/'||adir1)
  1237.          arglist.!dir=olddir1||adir1
  1238.          dirlink=make_a_url(diropts,' ')
  1239.       end
  1240.       else do
  1241.            dirlink='<u>'adir1'</u>'
  1242.        end  /* Do */
  1243.       if pos('&',dirlink)>0 then do  /* prevent & in filename bug */
  1244.            frog3=sref_replacestrg(dirlink,'%','%25','ALL')
  1245.            dirlink=sref_replacestrg(frog3,'&','%26','ALL')
  1246.       end  /* Do */
  1247.       dirlink=translate(dirlink,'&',' ')
  1248.       if dirlist.yy.iscmt<>1 & (arglist.!PREVIEWDIRS=1 | arglist.!preview=1) then
  1249.            dirlink=dirlink||'&preview=1'
  1250.  
  1251.    end
  1252.  
  1253.    if dirlist.yy.iscmt<>1 then do
  1254.       uri2=action||'?'||dirlink
  1255.       aurl='<a href="'||uri2'">'||adir1||'</a>'
  1256.    end
  1257.    else do
  1258.       aurl='<code><u>'dirlink'</u></code>'
  1259.       agif='[xx]'
  1260.    end
  1261.  
  1262.    if arglist.!notable=0 then do        /*write link in a table */
  1263.       if arglist.!noicons=0 then
  1264.          call dumpit('<td valign=top>' agif' 'aurl' 'adesc ' </td>')
  1265.      else
  1266.          call dumpit('<td valign=top>' aurl' 'adesc '  </td>')
  1267.  
  1268.      twrote=twrote+1
  1269.      uy=yy//max(1,udircols)
  1270.      if  ((twrote)//udircols)=0 | udircols=1 then
  1271.           call dumpit("<tr valign=top>")
  1272.    end  /* table */
  1273.    else do              /* non table */
  1274.       if adesc<>' ' then adesc='  : 'adesc
  1275.       if arglist.!short=0 & arglist.!noicons=0 then
  1276.         call dumpit(agif' 'aurl' 'adesc' <br>')
  1277.      else
  1278.          call dumpit(aurl' 'adesc)
  1279.   end
  1280. end
  1281. if arglist.!notable=0 then do
  1282.    call dumpit('</Table>')
  1283. end  /* Do */
  1284. arglist.!dir=olddir
  1285.  
  1286. dofooter:  /* here if arglist.!nodir<>0 */
  1287. /* get footer info file */
  1288. if footer_file<>' ' then do
  1289.     call dumpit('<p>')
  1290.    if footer_file.!abs=0 then do
  1291.       t1=stream(gets||'\'||footer_file,'c','query exists')
  1292.       if t1=' ' then
  1293.           t1=stream(bbsdir||footer_file,'c','query exists')
  1294.    end
  1295.    else do
  1296.        t1=stream(footer_file,'c','query exists')
  1297.    end  /* Do */
  1298.    if t1<>' ' then do
  1299.          eeko=fileread(t1,'eek',,'E')
  1300.    end
  1301.     else do
  1302.        eek.0=1
  1303.        eek.1='  '
  1304.    end
  1305.    if footer_text<>0 then
  1306.       aa='<pre>'crlf
  1307.       do  mm=1 to eek.0
  1308.          aline=eek.mm
  1309.          aline=sref_replacestrg(aline,'$DIR',upper(arglist.!dir),'ALL')
  1310.          aline=sref_replacestrg(aline,'$SERVERNAME',use_servername,'ALL')
  1311. /* no longer supported -- messes up caching
  1312.          aline=sref_replacestrg(aline,'$USER',arglist.!user,'ALL')
  1313.          aline=sref_replacestrg(aline,'$PWD',arglist.!pwd,'ALL')
  1314. */
  1315.          aa=aa||aline||crlf
  1316.      end /* do */
  1317.      if footer_text<>0 then do
  1318.          aa=aa||'</pre>'||crlf
  1319.      end
  1320.      else do
  1321.         aa=aa||'<br>'||crlf
  1322.      end
  1323.      call dumpit(aa)
  1324. end
  1325.  
  1326.  
  1327. call dumpit("</body></html>")
  1328. if send_piece=0 | CACHE.!FILES>0 then
  1329.    call lineout tempfile  /* close */
  1330.  
  1331. /* if do_cache, copy to cache_file */
  1332. if index_mode=0 & cache.!files>0  then do
  1333.    pig=write_to_cache(tempfile,gets||'\*.*',cache_check)
  1334. end  /* Do */
  1335.  
  1336. return 0
  1337.  
  1338.  
  1339. /* ---------------- */
  1340. /* write table header (call as routine */
  1341. write_table_header:  /* use globals */
  1342. usingpre=0; usingtable=0
  1343.  
  1344. if arglist.!notable<>0  then DO
  1345.        select
  1346.          when arglist.!NODATE=0 & arglist.!Notime=0 then
  1347.                  kitten='<U>Last Modified</U>      '
  1348.           when arglist.!nodate=0 & arglist.!Notime<>0 then
  1349.                  kitten='<U>Last Modified</U>   '
  1350.           otherwise
  1351.              kitten='    '
  1352.        end
  1353.        puppy='   <u>Size</u>'
  1354.        if arglist.!nosize<>0 then puppy=''
  1355.        if arglist.!nodate=0 then icky=14
  1356.        if arglist.!notime<>0 then icky=icky-6
  1357.        if description_text=1 | arglist.!nodesc<>0 then do
  1358.           if arglist.!bin_text_links=1 then
  1359.               call dumpit('<PRE><b> <i>(text,bin)</i>   <u>Name</U>            'kitten' 'puppy'</b>')
  1360.           else
  1361.               call dumpit('<PRE>            <b> <u>Name</U>            'kitten' 'puppy'</b>')
  1362.            useingpre=1
  1363.        end
  1364.        else do
  1365.           if arglist.!bin_text_links=1 then
  1366.              call dumpit('<pre><b> <i>(text, bin)</i>  <u>Name</U>            'kitten' 'puppy'</b></pre>')
  1367.           else
  1368.              call dumpit('<pre>            <b> <u>Name</U>            'kitten' 'puppy'</b></pre>')
  1369.        end  /* Do */
  1370.      return 0
  1371. end                        /* no table */
  1372.  
  1373. /* else, a table */
  1374. aa="<table border="table_border"  cellspacing=" cell_spacing "> "crlf
  1375. usingtable=1
  1376. aa=aa||' <th nowrap align="center"> </th> 'crlf
  1377.  
  1378.   if arglist.!bin_text_links=1 then 
  1379.     aa=aa||' <th  nowrap align="left" >(text bin) File name  </th>'crlf
  1380.   else
  1381.     aa=aa||' <th  nowrap align="center" >  File name .. </th>'crlf
  1382.   ntds=2
  1383.   dots='..';if arglist.!notime<>0 then dots=''
  1384.   if arglist.!nodate=0 then do
  1385.           ntds=ntds+1
  1386.           aa=aa||' <th nowrap  align="center">  Last Modified'dots' </th> '
  1387.   end
  1388.   if arglist.!nosize=0 then do
  1389.           ntds=ntds+1
  1390.           aa=aa||' <th nowrap align="center">  Size   </th>'
  1391.   end
  1392.   if notes.0>0 & arglist.!nodesc<>1 then do
  1393.           ntds=ntds+1
  1394.           aa=aa||' <th nowrap align="center">  Description  </th> '
  1395.   end
  1396.   aa=aa||'<tr valign=top>'
  1397.  
  1398.   call dumpit(aa)
  1399.  
  1400.   return 0
  1401.  
  1402.  
  1403. /*******************/
  1404. /* write to tempfile, or VAR it */
  1405. dumpit:
  1406. parse arg aa
  1407. crlf='0d0a'x
  1408.  
  1409. if send_piece=0  | cache.!files>0 then do
  1410.  
  1411.   call lineout tempfile,aa
  1412. end
  1413. if send_piece=1 then do
  1414.     aa=aa||crlf
  1415.    'VAR NAME AA '
  1416. end
  1417. return 0
  1418.  
  1419.  
  1420. /***************/
  1421. /* write the header (might be a index_list header file  */
  1422. write_the_header:
  1423. /* get header info file */
  1424.  IF HEADER_FILE<>' ' then DO
  1425.     if header_file.!abs=0 then do
  1426.         t1=stream(gets||'\'||header_file,'c','query exists')
  1427.         if t1=' ' then t1=stream(bbsdir||header_file,'c','query exists')
  1428.     end
  1429.     else do
  1430.         t1=stream(header_file,'c','query exists')
  1431.     end  /* Do */
  1432.     if t1<>' ' then eeko=fileread(t1,'eek',,'E')
  1433.   end
  1434.   else do               /* no header file */
  1435.      eek.0=1
  1436.      if index_mode=0 then do
  1437.         eek.1=' <body> <h2> List of files for: 'arglist.!dir '</h2>'
  1438.      end
  1439.      else do
  1440.         if symbol('index_list.!header')="VAR" then
  1441.            eek.1=index_list.!header
  1442.         else
  1443.            eek.1=' <body> <h2> Files from: ' index_list.!filedir '</h2>'
  1444.      end
  1445.   end
  1446.   if header_text<>0 then do
  1447.      eek.1=sref_insert_block(eek.1,'body','<pre> ',1,'<','>')
  1448.   end
  1449.   aa="" ; crlf='0d0a'x
  1450.   do  mm=1 to eek.0
  1451.      aline=eek.mm
  1452.      aline=sref_replacestrg(aline,'$DIR',upper(arglist.!dir),'ALL')
  1453.      aline=sref_replacestrg(aline,'$SERVERNAME',use_servername,'ALL')
  1454. /* no longer supported --messes up caching
  1455.      aline=sref_replacestrg(aline,'$USER',arglist.!user,'ALL')
  1456.      aline=sref_replacestrg(aline,'$PWD',arglist.!pwd,'ALL')
  1457. */
  1458.      aa=aa||aline||crlf
  1459.   end /* do */
  1460.   if header_text<>0 then
  1461.      aa=aa||' </pre>'
  1462.   else
  1463.      aa=aa||' <br>'
  1464.   call dumpit(aa)
  1465.  
  1466. return 0
  1467.  
  1468. /*********/
  1469. /* perhaps break up overlong lines? */
  1470. format_desc:procedure
  1471. parse arg todo,nlen,for1,notable
  1472. crlf='0d0a'x
  1473.  
  1474. todo=translate(todo,' ','1a'x)
  1475. if nlen=0 then return todo   /* do NOT breakup  long lines */
  1476.  
  1477. if nlen=1 then nlen=40
  1478. if nlen<50 & notable=1 then nlen=nlen+35   /* pre mode gets 35 extra characters */
  1479.  
  1480. if length(TODO)<nlen then return todo
  1481.  
  1482. /* special case: if for1=1 and is multi line (embedded crlfs), then
  1483.   return as is (for1=1 signals "only break up long 1 line descriptions */
  1484.  
  1485. if for1=1 then do       /* check for special "break up 1 liners only " condition */
  1486.    aa=todo ;ills=0 
  1487.    do until aa=""
  1488.        parse var aa aa1 (crlf) aa
  1489.        if aa1=""  then iterate 
  1490.        ills=ills+1 
  1491.        if ills>1 then return todo /* more then one line, leave it be */
  1492.    end /* do */
  1493. end
  1494.  
  1495. /* candidate for break up. So do it (retain preexisting crlfs ) */
  1496. aa=clip_line(todo,NLEN,1)
  1497. RETURN AA
  1498.  
  1499.  
  1500. /********************************/
  1501. ADD_SPACE_TO_LINE:PROCEDURE
  1502. PARSE ARG AA
  1503. CRLF='0D0A'X
  1504. /* ADD SPACES TO A LINE? */
  1505.  ills=0;TLL.1=''
  1506.  notemp=0
  1507.  do until aa=""
  1508.     parse var aa aa1 (crlf) aa
  1509.     if aa1="" & ILLS=0  then iterate
  1510.     ills=ills+1 
  1511.     TLL.ILLS='      '||AA1
  1512.     IF AA1<>"" then NOTEMP=ILLS
  1513.   end /* do */
  1514.  
  1515.   AA2=TLL.1
  1516.   DO MM=2 TO NOTEMP
  1517.      AA2=AA2||CRLF||TLL.MM
  1518.   end /* do */
  1519. return aa2
  1520.  
  1521.  
  1522. /************************/
  1523. /* inclusions_mode_file processing-- sort filelist to match
  1524. entries in inclusions_mode_file, dropping entries that do
  1525. not appear in inclusions_mode_file. In addition, add "n.a."
  1526. entries for files that are in inclusions_mode_file, but not
  1527. in filelist.
  1528. The variables to set are:
  1529. filelist.0
  1530. filelist.n.name. filelist.n.date, filelist.n.time filelist.n.size
  1531. filelist.n.aurl  filelist.n.dastuff
  1532. (We might create some additional listings with:
  1533.   name=filename, aurl=' ',time =' ', date ='n.a.', and size='n.a.'
  1534. if a file appears in the inclusion_mode_file but does not
  1535. exist.
  1536. */
  1537.  
  1538.  
  1539. inclusions_redo:procedure expose filelist. verbose continuation_flag
  1540.  
  1541. parse arg gets, incfile,isdir
  1542. if filelist.0=0 then return 0           /* nothing to do */
  1543.  
  1544. /* 1) read in inclusions_mode_file (in this directory only!)
  1545. Only retain file name (first word) from lines NOT beginning with
  1546. a space! */
  1547. jfile=gets||'\'||strip(incfile,'l','\')
  1548. foo2=fileread(jfile,tmp1,,'E')
  1549. ninc=0
  1550. do ii=1 to tmp1.0
  1551.    if translate(left(tmp1.ii,1),' ','\/')<>' '  then do  /* leading space means "comment", ,/\ means dir */
  1552.       ninc=ninc+1
  1553.       parse var tmp1.ii inclines.ninc inclines.ninc.cmt
  1554.       inclines.ninc.iscmt=0
  1555.       iterate
  1556.    end  /* Do */
  1557.    if left(tmp1.ii,1)=' ' & left(strip(tmp1.ii),1)<>strip(continuation_flag) then do
  1558.       ninc=ninc+1
  1559.       inclines.ninc.cmt=tmp1.ii
  1560.       inclines.ninc.iscmt=1
  1561.    end  /* Do */
  1562. end /* do */
  1563. if ninc=0 then do       /* no files, or no valid entries */
  1564.    filelist.0=0         /* so show nothing */
  1565.    if verbose>2 then say " Missing or empty inclusion mode file: " jfile
  1566.    return 0
  1567. end  /* Do */
  1568. inclines.0=ninc
  1569. drop tmp1.
  1570.  
  1571. /* 2) create reference list */
  1572. do mm=1 to filelist.0
  1573.     fnames.mm=filelist.mm.name
  1574. end /* do */
  1575. fnames.0=filelist.0
  1576. foo=arraysort(fnames)
  1577.  
  1578. /* scan through inclines, match to fnames. If match,
  1579. copy line from filelist to tmplist. If no match, create
  1580. a n.a. entry. Entries in filelist but not inclines will
  1581. not be includee in tmplist */
  1582.  
  1583. ntmp=0
  1584. do mm=1 to inclines.0
  1585.   tryit=inclines.mm
  1586.   ntmp=ntmp+1
  1587.  
  1588.   if inclines.mm.iscmt=1 then do                /* full comment line */
  1589.       tmplist.ntmp.dastuff=strip(inclines.mm.cmt)
  1590.       tmplist.ntmp.name=' '
  1591.       iterate
  1592.   end
  1593.   foo=arraysearch(fnames,founds,tryit,'S')
  1594.   if foo=0 then do  /* no match, create a n.a. entry */
  1595.       tmplist.ntmp.name=''tryit''
  1596.       tmplist.ntmp.aurl=' '
  1597.       tmplist.ntmp.size='<em>n.a.</em>'
  1598.       tmplist.ntmp.date=' '
  1599.       tmplist.ntmp.time=' '
  1600.       tmplist.ntmp.dastuff='<code>'||strip(inclines.mm.cmt)||'</code>'
  1601.       iterate
  1602.   end  /* Do */
  1603. /* it's a file match */
  1604.    is1=founds.1
  1605.    tmplist.ntmp.name=filelist.is1.name
  1606.    tmplist.ntmp.aurl=filelist.is1.aurl
  1607.    tmplist.ntmp.time=filelist.is1.time
  1608.    tmplist.ntmp.date=filelist.is1.date
  1609.    tmplist.ntmp.size=filelist.is1.size
  1610.    tmplist.ntmp.dastuff=filelist.is1.dastuff
  1611.  end /* do */
  1612.  
  1613. /* now copy tmplist to filelist, and we are done */
  1614. drop filelist.
  1615. filelist.0=ntmp
  1616. do mm=1 to ntmp
  1617.    filelist.mm.name=tmplist.mm.name
  1618.    filelist.mm.aurl=tmplist.mm.aurl
  1619.    filelist.mm.time=tmplist.mm.time
  1620.    filelist.mm.date=tmplist.mm.date
  1621.    filelist.mm.size=tmplist.mm.size
  1622.    filelist.mm.dastuff=tmplist.mm.dastuff
  1623. end /* do */
  1624. return ntmp
  1625.  
  1626.  
  1627.  
  1628. /************************/
  1629. /* dirlist version of inclusions_redo
  1630. */
  1631.  
  1632.  
  1633. inclusions_redo_dir:procedure expose dirlist. continuation_flag
  1634.  
  1635. parse arg gets, incfile
  1636. if dirlist.0=0 then return 0           /* nothing to do */
  1637.  
  1638. /* 1) read in inclusions_mode_file (in this directory only!)
  1639. Only retain file name (first word) from lines NOT beginning with
  1640. a space! */
  1641. jfile=gets||'\'||strip(incfile,'l','\')
  1642. foo2=fileread(jfile,tmp1,,'E')
  1643. ninc=0
  1644.  
  1645. do ii=1 to tmp1.0
  1646.    a1=translate(left(tmp1.ii,1),'/','\')
  1647.    if a1<>'/' then iterate
  1648.    ninc=ninc+1
  1649.    parse var tmp1.ii inclines.ninc inclines.ninc.cmt
  1650. end /* do */
  1651.  
  1652. if ninc=0 then do       /* no files, or no valid entries */
  1653.    dirlist.0=0         /* so show nothing */
  1654.    if verbose>2 then say " Missing or empty inclusion mode file: " jfile
  1655.    return 0
  1656. end  /* Do */
  1657. inclines.0=ninc
  1658. drop tmp1.
  1659.  
  1660. /* 2) create reference list */
  1661. do mm=1 to dirlist.0
  1662.       adir=dirlist.mm
  1663.       tmp=translate(adir,' ','/\:')
  1664.       adir1=word(tmp,words(tmp))
  1665.     fnames.mm='/'||strip(adir1)
  1666. end /* do */
  1667. fnames.0=dirlist.0
  1668. foo=arraysort(fnames)
  1669. /* scan through inclines, match to fnames. If match,
  1670. copy line from dirlist to tmplist. If no match, create
  1671. a n.a. entry. Entries in dirlist but not inclines will
  1672. not be includee in tmplist */
  1673.  
  1674. ntmp=0
  1675. do mm=1 to inclines.0
  1676.   tryit=inclines.mm
  1677.   ntmp=ntmp+1
  1678.   foo=arraysearch(fnames,founds,tryit,'S')
  1679.   if foo=0 then do  /* no match, create a n.a. entry */
  1680.       tmplist.ntmp=tryit
  1681.       tmplist.ntmp.iscmt=1
  1682.       iterate
  1683.   end  /* Do */
  1684. /* it's a match */
  1685.    is1=founds.1
  1686.    tmplist.ntmp=tryit
  1687.    tmplist.ntmp.iscmt=0
  1688.  end /* do */
  1689.  
  1690. /* now copy tmplist to dirlist, and we are done */
  1691. drop dirlist.
  1692. dirlist.0=ntmp
  1693. do mm=1 to ntmp
  1694.    dirlist.mm=tmplist.mm
  1695.    dirlist.mm.iscmt=tmplist.mm.iscmt
  1696. end /* do */
  1697. return ntmp
  1698.  
  1699.  
  1700. /*******************************/
  1701. /* see if current request has been cached, and is not "out of date " */
  1702.  
  1703. send_from_cache:procedure expose  cache. nowtime verbose arglist. authorization_mode ,
  1704.                         fixexpire   cache_mode
  1705.  
  1706.  
  1707. if cache_mode=1 then return 0
  1708. else
  1709.  
  1710. parse arg mama,docheck
  1711.  
  1712. astamp=0
  1713. if docheck=1 then do        /* check file/dir crc stamp */
  1714.     booboo=sysfiletree(mama,yeepers,'BT')
  1715.     if yeepers.0>0 then do
  1716.         oo=arraysort(yeepers,1,,1,15,'A','I')  /* avoid arbitrary order problem)*/
  1717.         as1=""
  1718.         do jou=1 to yeepers.0
  1719.              as1=as1||space(yeepers.jou,1)
  1720.         end /* do */
  1721.         astamp=stringcrc(upper(as1))            /* save crc, not entire string */
  1722.     end
  1723. end  /* Do */
  1724.  
  1725.  cache_file=cache.!dir'bbscache.idx'
  1726.  if stream(cache_File,'c','query exists')=' ' then return 0 /* no indesx, nocache */
  1727.  
  1728.  foo=cvread(cache_file,clines)
  1729.  if foo=0 | clines.0=0 then return 0               /* problem with cache file */
  1730.  
  1731. /* cache file entries:  clines.0 = # of entries:
  1732.                         clines.hi = simple comment
  1733.                         clines.m.time = date of creation
  1734.                         clines.m.cookie= 1 if a "cookie" version
  1735.                         clines.m.uri = request string this is caching (capitalized)
  1736.                         clines.m.name = name of file containing cache
  1737.                         clines.m.filedir = string invoking file/dir of this listing
  1738.                         clines.m.stamp = crc stamp from sysfiletree of .filedir
  1739. */
  1740.  
  1741.    if clines.0=0 then return 0  /* should never happen, but .. */
  1742.  
  1743. if verbose>3 then say " Looking for: " cache.!uri ' ,  cookie=' cache.!cookver authorization_mode
  1744.  
  1745. /* search 1 to clines.1 for matching uri */
  1746. do mm=1 to min(cache.!files,clines.0)
  1747.      if clines.mm.time+cache.!duration<nowtime then iterate /* too old */
  1748.      if cache.!uri<>clines.mm.uri then iterate     /* not a match */
  1749.      grodie=max(authorization_mode,cache.!cookver)
  1750.      if grodie<>clines.mm.cookie then iterate  /* wrong cookie type */
  1751.      if docheck=1 then do
  1752.         if clines.mm.stamp<>astamp then iterate
  1753.      end  /* Do */
  1754.      if stream(clines.mm.name,'c','query exists')=' '  then return 0 /* missing*/
  1755.      foo=sref_open_read(clines.mm.name,30)
  1756.      if foo<0 then return 0   /* problem */
  1757.      mostuff=charin(clines.mm.name,1,chars(clines.mm.name))
  1758.      fpp=stream(clines.mm.name,'c','close')
  1759.  
  1760. /* if non-cookie version, fix up username/password stuff */
  1761.     if cache.!cookver=0  & authorization_mode<>1 then do
  1762.            userpwd='/'||arglist.!user||':'||arglist.!pwd||'/'
  1763.            mostuff=sref_replacestrg(mostuff,'/USER:PWD/',userpwd,'ALL')
  1764.            bubba1='USER='||arglist.!user
  1765.            mostuff=sref_replacestrg(mostuff,'USER=USER',bubba1,'ALL')
  1766.            bubba2='PWD='||arglist.!PWD
  1767.            mostuff=sref_replacestrg(mostuff,'PWD=PWD',bubba2,'ALL')
  1768.     end
  1769.     if fixexpire>0 then do
  1770.           ncc=chars(mostuff)
  1771.           fpp=sref_expire_response(fixexpire,ncc)
  1772.      end
  1773.     'VAR TYPE text/html  Name  MOSTUFF '
  1774.     if verbose>2 then say " Using cached file: " clines.mm.name
  1775.     return 1
  1776. end /* do */
  1777. return 0                /* if here, no match */
  1778.  
  1779.  
  1780.  
  1781. /* --------------------------- */
  1782. /* write a cache file, and update index */
  1783. write_to_cache:procedure expose do_cache cache. nowtime verbose ARGLIST. AUTHORIZATION_MODE verbose  send_piece
  1784.  
  1785.  
  1786.  parse upper arg tempfile,mama,docheck
  1787.  astamp=0
  1788.  if docheck=1 then do     /* save a "date" stamp */
  1789.     booboo=sysfiletree(mama,yeepers,'BT')
  1790.     if yeepers.0>0 then do
  1791.         oo=arraysort(yeepers,1,,1,15,'A','I')  /* avoid arbitrary order problem)*/
  1792.         as1=""
  1793.         do jou=1 to yeepers.0
  1794.              as1=as1||space(yeepers.jou,1)
  1795.         end /* do */
  1796.         astamp=stringcrc(upper(as1))            /* save crc, not entire string */
  1797.     end
  1798.  end  /* Do */
  1799.  
  1800.  
  1801.  if verbose>3 then say " Saving to cache: " cache.!uri
  1802.  
  1803.  cache_file=cache.!dir'bbscache.idx'
  1804.  foo=sref_open_read(cache_file,30,'BOTH')
  1805.  
  1806.  if foo= -2 then do
  1807.       if verbose>2 then say " writetocache error open read " foo
  1808.      return 0               /* problem, give up */
  1809.  end
  1810.  if foo=-1 then do
  1811.     clines.0=0
  1812.  end
  1813.  else do
  1814.     foo=stream(cache_file,'c','close')
  1815.     foo=cvread(cache_file,clines)
  1816.     if foo=0 then do
  1817.           if verbose>2 then say " write cache cvread error "
  1818.           else
  1819.           return 0              /* problem, give up */
  1820.     end  /* Do */
  1821.  end
  1822.  
  1823.  foo=sref_open_read(cache_file,30,'BOTH')  /* lock it */
  1824.  if foo=-2 then do
  1825.    if verbose>2 then say " write to cache open read both error "
  1826.     return 0                /* give up */
  1827.  end
  1828.  
  1829. grodie=max(cache.!cookver,authorization_mode)
  1830.  
  1831. /* check for older version (if it matches, it's older) */
  1832. do ido=1 to min(cache.!files,clines.0)
  1833.    if clines.ido.uri<>cache.!uri then iterate
  1834.    if grodie<>clines.ido.cookie then iterate  /* wrong cookie type */
  1835.  
  1836.    foo=set_cache_file(tempfile,clines.ido.name)
  1837.    if foo=0 then do
  1838.        if verbose>2 then say " Write cache error, set cache file "
  1839.        return 0
  1840.    end
  1841.    clines.ido.time=nowtime
  1842.    clines.ido.uri=cache.!uri
  1843.    clines.ido.filedir=mama
  1844.    clines.ido.stamp=astamp
  1845.    clines.ido.cookie=max(authorization_mode,cache.!cookver)
  1846.  
  1847.    foo=stream(cache_file,'c','close') /* unlock */
  1848.    foo=cvwrite(cache_file,clines)
  1849.    if verbose>2 then say  ido " Rewrite old entry, to cache: " clines.ido.name
  1850.    return clines.ido.name
  1851. end /* do */
  1852.  
  1853. /* no preexising, but cache not full -- then just add an entry */
  1854.  if clines.0<cache.!files then do
  1855.  
  1856.      aa=dostempname(cache.!dir||'$?????.HTM') /* use this file as the cache */
  1857.      foo=set_cache_file(tempfile,aa)
  1858.      if foo=0 then return 0        /* error, give up */
  1859.  
  1860.      ido=clines.0+1
  1861.      clines.0=ido
  1862.      clines.ido.uri=cache.!uri
  1863.      clines.ido.time=nowtime
  1864.      clines.ido.name=AA
  1865.      clines.ido.filedir=mama
  1866.      clines.ido.stamp=astamp
  1867.      clines.ido.cookie=max(authorization_mode,cache.!cookver)
  1868.  
  1869.      foo=stream(cache_file,'c','close') /* unlock */
  1870.      foo=cvwrite(cache_file,clines)
  1871.      if verbose>2 then say " New entry, results to cache: " aa
  1872.      return aa
  1873.  end
  1874.  
  1875. /* otherwise, remove oldest entry */
  1876.  useme=1 ; usetime=clines.1.time ; oldname=clines.1.name
  1877.  do mm=2 to min(cache.!files,clines.0)
  1878.     if clines.mm.time<usetime then do
  1879.         useme=mm
  1880.         usetime=clines.mm.time
  1881.         oldname=clines.mm.name
  1882.     end  /* Do */
  1883.  end /* do */
  1884.  
  1885.  foo=doscopy(tempfile,OLDNAME,'R')   /* copy results to it */
  1886.  foo=set_cache_file(tempfile,oldname)
  1887.  if foo=0 then return 0        /* error, give up */
  1888.  
  1889.  clines.useme.time=nowtime
  1890.  clines.useme.name=OLDNAME
  1891.  clines.useme.uri=cache.!uri
  1892.  clines.ido.filedir=mama
  1893.  clines.ido.stamp=astamp
  1894.  clines.ido.cookie=cache.!cookver
  1895.  clines.ido.cookie=max(authorization_mode,cache.!cookver)
  1896.  
  1897.  foo=stream(cache_file,'c','close') /* unlock */
  1898.  foo=cvwrite(cache_file,clines)
  1899.  foo=sysfiledelete(oldname)
  1900.  if verbose>2 then say " Oldest removed, BBS results to cache: " oldname
  1901.  
  1902.  return aa
  1903.  
  1904. /* -------------- */
  1905. /* write to a cached file (with possible changes of user:pwd */
  1906. set_cache_file:procedure expose arglist. authorization_mode verbose cache. send_piece
  1907. parse arg tempfile,youfile
  1908.    if Authorization_mode=1 | cache.!cookver=1 then do
  1909.          foo=doscopy(tempfile,youfile,'R')   /* copy results to it */
  1910.          if foo<>0 then return 0        /* error, give up */
  1911.    end
  1912.    else do            /* gotta change user:pwd to GENERIC values */
  1913.         mostuff=charin(tempfile,1,chars(tempfile))
  1914.         userpwd='/'||arglist.!user||':'||arglist.!pwd||'/'
  1915.         mostuff=sref_replacestrg(mostuff,userpwd,'/USER:PWD/','ALL')
  1916.         bubba='USER='||arglist.!user
  1917.         mostuff=sref_replacestrg(mostuff,bubba,'USER=USER','ALL')
  1918.         bubba='PWD='||arglist.!PWD
  1919.         mostuff=sref_replacestrg(mostuff,bubba,'PWD=PWD','ALL')
  1920.         foo=sysfiledelete(youfile)
  1921.         if stream(youfile,'c','query exists')<>' ' then do
  1922.              if verbose>2 then say " SYSFILEDELETE problem in BBS set_cache file "
  1923.              return 0
  1924.         end
  1925.         foo=charout(youfile,mostuff,1)
  1926.         if foo>0 then do
  1927.            if verbose>2 then say " CHAROUT problem in bbs set cache file "
  1928.            return 0
  1929.         end
  1930.         foo=stream(youfile,'c','close')
  1931.    end  /* Do */
  1932.    return 1
  1933.  
  1934. /*****************/
  1935. is_excluded:procedure
  1936. parse upper arg aname, exnames
  1937. aname=translate(aname,'\','/')
  1938. /* check exacts */
  1939.   if  wordpos(aname,exnames)>0 then return 1
  1940. /* check for wildcards */
  1941. if pos('*',exnames)=0 then return 0
  1942.  
  1943. /* got some, check them */
  1944. do mm=1 to words(exnames)
  1945.    bword=word(exnames,mm)
  1946.    if pos('*',bword)=0 then iterate
  1947.    ares=sref_wildcard(aname,bword||' '||bword,0)
  1948.    parse var ares astat "," . ; astat=strip(astat)
  1949.    if astat<>0 then  return 1
  1950. end
  1951. return 0
  1952.  
  1953.  
  1954.  
  1955. /***************/
  1956. @ get list of exclusions. Use own directory version if available,
  1957. or bbs_param_dir if not (they are NOT cumulative)*/
  1958. get_exclusions:procedure
  1959. parse arg thefile,gets,bbsdir
  1960. t1=stream(gets||'\'||thefile,'c','query exists')
  1961. if t1=' ' then
  1962.     t1=stream(bbsdir||thefile,'c','query exists')
  1963.  
  1964. if t1=' ' then
  1965.    return ' '
  1966. oo=linein(t1,1,0)
  1967. exlist=""
  1968. /* else, read the list */
  1969. do while lines(t1)=1
  1970.    oo=strip(linein(t1))
  1971.    if abbrev(oo,';')=1 then iterate
  1972.    exlist=exlist||' '||oo
  1973. end /* do */
  1974. tt=translate(exlist,' ',','||'1a090a0d'x)
  1975. return tt
  1976.  
  1977.  
  1978. /**********/
  1979. /* return file list in filelist. stem variable */
  1980. get_filelist:procedure expose filelist. notes. action wildnotes. DEFAULT_DATEFMT default_sort_by ,
  1981.                         arglist. authorization_mode auto_describe. zip_descriptor_file index_list. default_description
  1982. parse upper arg gets,nosort,sortby,thedir,forcet,forceb,links2,sizefmt,datefmt,timefmt,is_cookie,index_mode,noicons
  1983.  
  1984. if index_mode=0 then do                /* not recent mode */
  1985.   if wordpos(sortby,'DATE NAME EXT SIZE NOSORT')=0 then sortby=default_sort_by
  1986.   if wordpos(datefmt,'B C D E M N O S U W')=0 then datefmt=DEFAULT_DATEFMT
  1987.   if timefmt=0 then timefmt=24
  1988.   if sizefmt=0 then sizefmt=3
  1989.   juy=gets||"\*.*"
  1990.   wow=sysfiletree(juy,'alist','FT')
  1991.  
  1992.   if alist.0=0 then  do
  1993.     filelist.0=0
  1994.     return 0
  1995.   end
  1996.  
  1997. /* Convert to universal, and absolute date, date/time format
  1998. 12/14/95   1:12a         160  A----  c:\DOERS.BAT
  1999. 91/04/09/05/00       33430  A-HRS  c:\IO.SYS
  2000. */
  2001.   ponies=30
  2002.   do iff=1 to alist.0
  2003.      parse var alist.iff ddd sss aaa fff
  2004.      ddd1=left(ddd,8); ddd2=substr(ddd,10)
  2005.      juldate=dateconv(ddd1,'o','b')
  2006.      parse var ddd2 ahr '/' amin
  2007.      juldate=juldate+ (((ahr*60)+amin)/(24*60))
  2008.      usedate=dateconv(ddd1,'O',datefmt)
  2009.      if timefmt=24 then
  2010.         usetime=ahr':'amin
  2011.      else do
  2012.         if ahr<12 then
  2013.               usetime=ahr':'amin'a'
  2014.         if ahr=12 then
  2015.              usetime=ahr':'amin'p'
  2016.         if ahr>12  then do
  2017.            ahr=ahr-12
  2018.            usetime=ahr':'amin'p'
  2019.         end  /* Do */
  2020.      end
  2021.      USEDATE=TRANSLATE(USEDATE,'~',' ')
  2022.      sss2=fixup_size(sizefmt,sss)
  2023.      alist.iff=usedate' 'usetime' 'sss2' 'aaa' 'fff
  2024.    if  nosort=1   then iterate
  2025.    select               /* create a "sorters" array */
  2026.       WHEN SORTBY='NAME' | sortby=0 then
  2027.           sorters=filespec('n',fff)
  2028.       when sortby='DATE' then
  2029.           sorters=juldate
  2030.       when sortby='SIZE' then
  2031.           sorters=sss
  2032.       when sortby='EXT' then do
  2033.            ape=lastpos('.',fff)
  2034.            if ape=0 | ape=length(fff) then
  2035.               sorters=' '
  2036.            else
  2037.               sorters=substr(fff,ape+1)
  2038.       end  /* Do */
  2039.       otherwise
  2040.           sorters=filespec('n',fff)
  2041.      end  /* select */
  2042.      alist.iff=left(sorters,ponies)' 'alist.iff   /* prepend sort criteria */
  2043.   end /* do */
  2044.  
  2045.   if nosort=0 then do     /* sort, using sorters modified array */
  2046.     select
  2047.       when sortby='SIZE' then
  2048.          wow=arraysort('alist',1,,,20,'A','N')  /* sort on criteria */
  2049.       when sortby='DATE' then
  2050.          wow=arraysort('alist',1,,,20,'D','I')  /* sort on criteria */
  2051.       otherwise
  2052.          wow=arraysort('alist',1,,,20,'A','I')  /* sort on criteria */
  2053.     end
  2054.     do iff=1 to alist.0
  2055.        alist.iff=substr(alist.iff,ponies+1)   /* strip out criteria */
  2056.     END
  2057.   end           /* nosort=0 */
  2058. end                     /* recent mode=0 */
  2059.  
  2060.  
  2061. /* Set up filelist variable */
  2062. if index_mode=1 then do
  2063.    iir=0
  2064.    do ii=1 to index_list.0
  2065.       if index_list.ii=-1 then iterate
  2066.       iir=iir+1
  2067.       filelist.iir=index_list.ii
  2068.       filelist.iir.name=filespec('n',index_list.ii)
  2069.       filelist.iir.date=index_list.ii.!ndate
  2070.       filelist.iir.size=index_list.ii.!size
  2071.       filelist.iir.time=index_list.ii.!time
  2072.       filelist.iir.dastuff=' '
  2073.       if symbol('index_list.ii.!desc')="VAR" then
  2074.          filelist.iir.dastuff=index_list.ii.!desc
  2075.  
  2076.       snoopy='/'||strip(index_list.ii,,'/')
  2077.       call make_aurl iir,snoopy
  2078.  
  2079.    end /* do */
  2080.    filelist.0=iir
  2081.    return iir
  2082. end  /* Do */
  2083.  
  2084.  
  2085. /* if here, not recent list */
  2086. thedir2='/'strip(translate(thedir,'/','\'),'l','/')
  2087. if right(thedir2,1)<>'/' then thedir2=thedir2'/'
  2088. do mm= 1 to alist.0
  2089.     parse var alist.mm fOOdate filelist.mm.time asize aaaa ,
  2090.                 filelist.mm.name .
  2091.     FILELIST.MM.DATE=TRANSLATE(FOODATE,' ','~')
  2092. /* convert to xxx,yyy,zzz */
  2093.    filelist.mm.size=asize
  2094.    filelist.mm.absname=filelist.mm.name
  2095.    filelist.mm.name=filespec('N',filelist.mm.name)
  2096.    filelist.mm=filelist.mm.name
  2097.    itis0=thedir2||filelist.mm.name
  2098.    call make_aurl mm ,itis0           /* arglist.mm.aurl etc. */
  2099.  
  2100. end /* do */
  2101. filelist.0=alist.0
  2102.  
  2103. if notes.0=0 | arglist.!nodesc<>0 then
  2104.    return alist.0
  2105.  
  2106. /* add descriptions */
  2107. do ifi=1 to alist.0
  2108.    chkme=upper(filelist.ifi.name) ; filelist.ifi.dastuff=' '
  2109.    filelist.ifi.dastuff=find_description(chkme,filelist.ifi.absname)
  2110. end /* do */
  2111.  
  2112. return alist.0
  2113.  
  2114.  
  2115. /*********/
  2116. /* make the url, with possible "multiple links */
  2117. make_aurl:           /* routine, many globals */
  2118.  parse arg mm0,itis
  2119.  dw='/download'
  2120.  if authorization_mode<>1 & is_cookie=0 then
  2121.     dw=dw||'/'||arglist.!user||':'||arglist.!pwd
  2122.  
  2123.  filelist.mm0.aurl.0=0
  2124.  if links2=1 then do                  /* optional binary/text links */
  2125.        dw1=dw||'/_force_text_'
  2126.        dw2=dw||'/_force_binary_'
  2127.        FILELIST.MM0.AURL.0=2
  2128.        filelist.mm0.aurl.1='/'action||dw1||itis
  2129.        filelist.mm0.aurl.2='/'action||dw2||itis
  2130.   end  /* Do */
  2131.   filelist.mm0.aurl='/'action||dw||itis
  2132.   select                      /* the file link */
  2133.      when forcet>0  then  do
  2134.        dw=dw||'/_force_text_'
  2135.        filelist.mm0.aurl.!inner='/'action||dw||itis
  2136.      end
  2137.      when forceb>0 then do
  2138.        dw=dw||'/_force_binary_'
  2139.        filelist.mm0.aurl.!inner='/'action||dw||itis
  2140.      end  /* Do */
  2141.      otherwise do
  2142.        filelist.mm0.aurl.!inner='/'action||dw||itis
  2143.      end
  2144.   end   /* select */
  2145.   if arglist.!Noicons=1 then filelist.mm0.aurl=filelist.mm0.aurl.!inner
  2146.  
  2147.  
  2148.  
  2149.   return 1              /* useful stuff in globals */
  2150.  
  2151.  
  2152.  
  2153. /**********/
  2154. @ fix up notes. info */
  2155. fix_notes:procedure expose notes. description_text_length_1LINE arglist.
  2156. parse arg daflag
  2157. if notes.0=0 | arglist.!nodesc=1 then return 0
  2158. isnew=1
  2159. crlf='0d0a'x
  2160.  
  2161. stripme=0
  2162. if left(daflag,1)=' ' & left(daflag,2)<>' ' then do
  2163.    stripme=1
  2164.    daflag=strip(daflag)
  2165. end
  2166. tmps.1=notes.1
  2167. tmps.1.!nlines=1
  2168. do mm=2 to notes.0
  2169.    iscont=0
  2170.    if stripme=0 then do   /* not a ' x' continution flag, so must be exact match */
  2171.       iscont=abbrev(notes.mm,daflag)
  2172.    end
  2173.    else do              /* strip spaces from 2..n, then match the "stripped" flag*/
  2174.       if left(notes.mm,1)=' ' then   /* if not first space, not a match */
  2175.          iscont=abbrev(strip(notes.mm),daflag)
  2176.    end
  2177.    if iscont=0 then do     /* not a continuation line */
  2178.         isnew=isnew+1
  2179.         tmps.isnew.!nlines=1
  2180.         tmps.isnew=notes.mm
  2181.     end
  2182.     else do
  2183.         milk=pos(daflag,notes.mm)
  2184.         tmps.isnew=tmps.isnew||crlf||substr(notes.mm,milk+length(daflag))
  2185.         tmps.isnew.!nlines=tmps.isnew.!nlines+1
  2186.     end
  2187. end
  2188. do mm=1 to isnew        /* pull out filename and it's comment */
  2189.     parse var tmps.mm  notes.mm.DANAME  notes.mm.daSTUFF
  2190.     notes.mm.DANAME=upper(notes.mm.daname)
  2191.     notes.mm.!nlines=tmps.mm.!nlines
  2192. end
  2193.  
  2194.  
  2195. notes.0=isnew
  2196.  
  2197. return 0
  2198.  
  2199.  
  2200. /********************************************/
  2201. responsebbs:procedure expose cache_Mode
  2202.  parse arg  request,atext,stuff
  2203.  
  2204.  
  2205. if cache_mode=1 then do
  2206.     say " BBS-cache-mode ERROR: " request " ," atext ", " stuff
  2207.     exit
  2208. end  /* Do */
  2209.  
  2210.   select
  2211.     when request='badreq'   then use='400 Bad request syntax'
  2212.     when request='notfound' then use='404 Not found'
  2213.     when request='forbid'   then use='403 Forbidden'
  2214.     when request='unauth'   then use='401 Unauthorized'
  2215.     when request='notallowed' then use='405 Method not allowed'
  2216.     when request='notimplemented' then use='501 Not implemented'
  2217.     otherwise do
  2218.         use='406 Not acceptable'
  2219.         call pmprintf('weird response '|| request||' '|| message)
  2220.       end
  2221.     end  /* Add others to this list as needed */
  2222.  
  2223.  
  2224.   /* Now set the response and build the response file */
  2225.   'RESPONSE HTTP/1.0' use     /* Set HTTP response line */
  2226.   parse var use code text
  2227.   if request='notallowed' then do
  2228.      'HEADER ADD Allow:HEAD '
  2229.   end
  2230.  
  2231.   call lineout tempfile, '<!doctype html public "-//IETF//DTD HTML 2.0//EN">'
  2232.   call lineout tempfile, "<html><head><title>"text"</title></head>"
  2233.   call lineout tempfile, "<body><h2>Sorry...</h2>"
  2234.   select
  2235.     when request='unauth' then do
  2236.         'header add WWW-Authenticate: Basic Realm=<'atext'>'  /* challenge */
  2237.        if stuff=' ' then
  2238.          call lineout tempfile,' You are not authorized to visit this area of the bulletin board '
  2239.        else
  2240.          call lineout tempfile,' You must supply a Username if you wish to use this BBS '
  2241.     end
  2242.     when request='notfound' then
  2243.       call lineout tempfile,' File is unavailable: ' stuff
  2244.     when request='forbid' then
  2245.       call lineout tempfile,' BBS is unavailable :' atext
  2246.     otherwise
  2247.        call lineout tempfile,' Request denied: ' stuff
  2248.   end
  2249.   call lineout tempfile, "</body></html>"
  2250.   call lineout tempfile  /* close */
  2251.  
  2252.  
  2253.   iia=dosdir(tempfile,'s')
  2254.   'FILE ERASE TYPE text/html NAME ' tempfile
  2255.  
  2256.  
  2257.  
  2258.   return word(use,1)||' '||iia
  2259.  
  2260.  
  2261. end  /* Do */
  2262.  
  2263. return ' '
  2264.  
  2265.  
  2266. /*******/
  2267. /* IMAGETYPE: Return the name of the image file to use based on file type */
  2268. /*******/
  2269.  
  2270. imagetype: procedure expose imagepath ImageSize icons. dirgif
  2271.  
  2272. parse arg chkme
  2273. chkme=translate(chkme,'\','/')
  2274. size = ImageSize
  2275.  
  2276. /* if blank, return dummypic */
  2277. if chkme=' ' then 
  2278.     return '<img src="'ImagePath'dummypic.gif"' size '  align=top alt="[n.a.]">'
  2279.  
  2280. /* first, check custom list icons. */
  2281.  useline=''
  2282.  starat=0 ;  afterstar=0
  2283.  do mm=1 to icons.0
  2284.     aline=strip(icons.mm)
  2285.     if aline='' | abbrev(aline,';')=1  then iterate
  2286.     parse upper var aline aurl .
  2287.     aurl=translate(aurl,'\','/')
  2288.     ares=sref_wildcard(chkme,aurl||' '||aurl,0)
  2289.     parse var ares astat "," . ;  astat=strip(astat)
  2290.     if astat=0 then iterate   /* no match */
  2291.     if astat=1 then do
  2292.         gotit=1
  2293.         useline=aline
  2294.         leave
  2295.     end
  2296.     else  do
  2297.        parse var aurl ma1a ma1b
  2298.        t1=pos('*',ma1a)
  2299.        t33=length(ma1a)-t1
  2300.        if t1 >= starat  then do
  2301.           if t1 > starat | t33>afterstar then do
  2302.              starat=t1 ; afterstar=t33
  2303.              gotit=mm ; useline=aline
  2304.           end
  2305.        end
  2306.     end         /* wildcard match */
  2307.  end            /* do loop */
  2308. if useline<>' ' then do         /* got a match */
  2309.    parse var useline foo theimage
  2310.    return theimage
  2311. end  /* Do */
  2312. /* try generic -- (check if a dir entry first) */
  2313. if abbrev(chkme,'\')=1  then
  2314.  return dirgif
  2315.  
  2316. /* try generic entries */
  2317.  
  2318.   e=extension(chkme)
  2319.   select
  2320.     when e='TXT' | e='CMD' | e='DOC' | e='FAQ' | e='SAS'
  2321.       then return '<img src="'ImagePath'text.gif"' size ' align=top alt="[text]">'
  2322.     when e='HTM' | e='HTML'
  2323.       then return '<img src="'ImagePath'text.gif"' size '  align=top alt="[html]">'
  2324.     when e='PS'
  2325.       then return '<img src="'ImagePath'text.gif"' size '  align=top alt="[ps]  ">'
  2326.     when e='EXE' | e='ZIP' | e='ARC' | e='ARJ' | E='BIN'
  2327.       then return '<img src="'ImagePath'binary.gif"' size '  align=top alt="[bin] ">'
  2328.     when e="AU" | e="WAV" | e="MID"  | e="SND"
  2329.       then return '<img src="'ImagePath'sound.gif"' size '  align=top alt="[snd] ">'
  2330.     when e="GIF" | e="JPG" | e="JPEG" | e="TIF" | e="TIFF" | e="BMP"
  2331.       then return '<img src="'ImagePath'image.gif"' size '  align=top alt="[img] ">'
  2332.     when e="MPG" | e="MPEG" | e="AVI"
  2333.       then return '<img src="'ImagePath'movie.gif"' size '  align=top alt="[mov] ">'
  2334.     otherwise
  2335.       return '<img src="'ImagePath'unknown.gif"' size ' align=top alt="[file]">'
  2336.   end
  2337.  
  2338.  
  2339. extension: procedure
  2340. arg filename
  2341. /* If no period or only period is first char, then return "" */
  2342. if lastpos(".",filename)<2 then return ""
  2343. return translate(substr(filename, lastpos('.',filename)+1))
  2344.  
  2345.  
  2346.  
  2347. /**************/
  2348. /* Show contents of zip file.  Make use of the unzipapi.dll
  2349. (ftp://quest.jpl.nasa.gov/pub/os2/unz520d2.zip)
  2350.  
  2351. zipfile: The "local" file to be unzipped
  2352. zipdir: url- directory of the zipfile
  2353.  
  2354. Note: 3 types of headers may be displayed:
  2355. 1) ZIP_HEADER_FILE -- if specified, MUST contain <BODY> element
  2356.         (it's always intererpted as html )
  2357. 2) -z comments in the .ZIP file -- not displayed if get_z_zip_description=0
  2358. 3) ZIP_DESCRIPTOR_FILE
  2359. */
  2360. show_zipdir:procedure expose  send_piece tempfile imagesize imagepath file_dir ,
  2361.                     action icons. fixexpire cache. nowtime ,
  2362.                    arglist. authorization_mode  zip_descriptor_file ,
  2363.                  get_z_zip_description zip_header_file bbsdir servername use_servername ,
  2364.                  cache_check diropts cache_mode
  2365.  
  2366.  
  2367.  
  2368. parse arg  zipfile ,zipdir,forcet,forceb,links2
  2369.  
  2370. gets=translate(file_dir,'\','/')
  2371. zipdir=translate(zipdir,'\','/')
  2372.  
  2373. gets=make_adir(file_dir,zipdir)
  2374. /*gets=strip(file_dir,'t','\')||'\'||strip(zipdir,'l','\')*/
  2375.  
  2376. zipfile=strip(zipfile)
  2377. mkit=gets||'\'||zipfile
  2378.  
  2379. if cache_mode=1 then say "    -- processing: " mkit
  2380.  
  2381.  
  2382. /* check cache? */
  2383. if cache.!files>0 then do
  2384.    okay=send_from_cache(mkit,cache_check)
  2385.    if okay=1 then return -1
  2386. end  /*  otherwise, create it */
  2387.  
  2388.  
  2389. if dosisdir(gets)=0 then do
  2390.  
  2391.   if cache_Mode=1 then do
  2392.        say " BBS-cache-mode error : could not find dir : " arglist.!dir
  2393.        exit
  2394.   end  /* Do */
  2395.   call lineout tempfile, "<body><h2>Sorry...</h2>"
  2396.   call lineout tempfile,' *** Could not find directory: ' arglist.!dir
  2397.   call lineout tempfile, "</body></html>"
  2398.   call lineout tempfile  /* close */
  2399.   'FILE ERASE TYPE text/html NAME ' tempfile
  2400.   return 0
  2401. end
  2402.  
  2403.  
  2404. /* get header info file */
  2405.  boi=bbsdir||zip_header_file
  2406. IF ZIP_HEADER_FILE<>' ' then DO
  2407.   t1=stream(gets||'\'||ZIP_header_file,'c','query exists')
  2408.   if t1=' ' then
  2409.       t1=stream(bbsdir||ZIP_header_file,'c','query exists')
  2410.   if t1<>' ' then do
  2411.      eeko=fileread(t1,'zhf',,'E')
  2412.   end
  2413.   else do
  2414.      zhf.0=1
  2415.      zhf.1='<BODY> <H2>Contents of 'zipfile'</H2>'
  2416.   end
  2417. END             /* HEADER */
  2418.  
  2419. if arglist.!noicons=1 then do
  2420.         txtimg='text';binimg='bin'
  2421. end  /* Do */
  2422. else do
  2423.   txtimg=imagetype('foo.txt')
  2424.   binimg=imagetype('foo.bin')
  2425. end
  2426.  
  2427.  
  2428. /* get -z comments */
  2429. zipcmts.0=0
  2430. if get_z_zip_description=1 then do
  2431.   /* get zipfile comment, if it exists */
  2432.   rc=uzunzip(' -z '||mkit,'zipcmts.')
  2433.   if rc<>0 then zipcmts.0=0
  2434. end
  2435.  
  2436. /* get zip file list and info */
  2437. rc=uzfiletree(mkit,getem,,,'Z')
  2438.  
  2439.  
  2440. /* get "file_id.diz" file */
  2441. ziphdr.0=0
  2442.  
  2443. /* get "file_id.diz" file */
  2444. if getem.0>0 & zip_descriptor_file<>0 & zip_descriptor_file<>' ' then do
  2445.   nww=words(getem.1)
  2446.   do km=1 to getem.0
  2447.      af3=strip(word(getem.km,nww))
  2448.  
  2449.       if upper(af3)=upper(zip_descriptor_file) then do
  2450.          rc=uzunziptovar(mkit,strip(af3),ziphdr)
  2451.          if rc<>0 then ziphdr.0=0
  2452.          leave
  2453.       end  /* found zipdescriptor */
  2454.   end   /* look at getems */
  2455. end  /* look for zip descriptor */
  2456.  
  2457. /* no longer used 
  2458. rc=uzunziptovar(mkit,zip_descriptor_file,ziphdr)
  2459. if rc<>0 then ziphdr.0=0
  2460. */
  2461.  
  2462. lineno=1
  2463. anzfiles=0
  2464.  
  2465. call lineout tempfile, '<!doctype html public "-//IETF//DTD HTML 2.0//EN">'
  2466. call lineout tempfile, "<HTML>"
  2467. call lineout tempfile, "<HEAD>"
  2468. call lineout tempfile, "<TITLE>BBS: Contents of "zipfile"</TITLE>"
  2469. call lineout tempfile, "</HEAD>"
  2470.  
  2471. /* display header (generic or from file) -- must contain <BODY> */
  2472. do pp=1 to zhf.0
  2473.     aline=sref_replacestrg(zhf.pp,'$DIR',upper(arglist.!dir),'ALL')
  2474.     aline=sref_replacestrg(aline,'$SERVERNAME',use_servername,'ALL')
  2475.     aline=sref_replacestrg(aline,'$ZIPFILE',zipfile,'ALL')
  2476.     call lineout tempfile,aline
  2477. end /* do */
  2478.  
  2479. /* display -z */
  2480. if zipcmts.0>1 then do
  2481.     call lineout tempfile,'<blockquote> <H4> Comment from .ZIP file:</h4> <code>'
  2482.     do mi=2 to zipcmts.0
  2483.         call lineout tempfile,zipcmts.mi'  <br>'
  2484.     end
  2485.     call lineout tempfile,' </code> </blockquote>'
  2486. end
  2487.  
  2488. /* display file_id */
  2489. if ziphdr.0>0  then do
  2490.   call lineout tempfile,' <pre>'
  2491.   do mm=1 to ziphdr.0
  2492.      call lineout tempfile,ziphdr.mm
  2493.   end
  2494.   call lineout tempfile,' </pre>'
  2495. end
  2496.  
  2497. if links2=0 then
  2498.   call lineout tempfile, '<pre><img src="'imagepath'dummypic.gif"  align=top alt="      " ' imagesize ' align=middle> <b>'left("Name",19)||left("Last Modified",17)||right("Size",8)'</b></pre>'
  2499. else
  2500.   call lineout tempfile, '<pre> ' txtimg || binimg ' <b>'left(" Name",19)||left("Last Modified",17)||right("Size",8)'</b></pre>'
  2501.  
  2502. call lineout tempfile, '<hr>'
  2503.    tt=arglist.!zipfile
  2504.     arglist.!zipfile=0
  2505.      dirlink=make_a_url(diropts,' ')
  2506.      if pos('&',dirlink)>0 then do  /* prevent & in filename bug */
  2507.            frog3=sref_replacestrg(dirlink,'%','%25','ALL')
  2508.            dirlink=sref_replacestrg(frog3,'&','%26','ALL')
  2509.      end  /* Do */
  2510.      dirlink=translate(dirlink,'&',' ')
  2511.      arglist.!zipfile=tt
  2512. call lineout tempfile, '<dt><pre><a href="'action||'?'||dirlink'"><img src="'imagepath'/back.gif" alt="[back]" width=32 height=32 align=middle>Back</a></pre>'
  2513. call lineout tempfile, '<HR>'
  2514.  
  2515.  
  2516. do mm=1 to getem.0
  2517.     aline=getem.mm
  2518.     Fname=word(aline,8)
  2519.     Ftime=word(aline,6)
  2520.     Fdate=word(aline,5)
  2521.     fdate=dateconv(translate(fdate,'/','-'),'U','N')
  2522.     Fsize=word(aline,1)
  2523.     if links2=1 then do
  2524.                 nop
  2525.     end  /* Do */
  2526.    zw='zipdownload/'
  2527.    if authorization_mode<>1 & cache.!cookver<>1 then
  2528.        zw=zw||arglist.!user||':'||arglist.!pwd||'/'
  2529.  
  2530.     zw0=zw              /* if forcebinary or text, text link is to mime type */
  2531.  
  2532.     if links2=1 then do                 /* include text/binary links ?*/
  2533.        zw1=zw||'_force_text_/'
  2534.        zw2=zw||'_force_binary_/'
  2535.     end
  2536.    
  2537.     select                      /* check on force text/binary directives */
  2538.        when forcet>0 then zw=zw||'_force_text_/'
  2539.        when forceb>0 then zw=zw||'_force_binary_/'
  2540.        otherwise nop
  2541.     end
  2542.  
  2543.     if arglist.!Noicons=1 then zw0=zw  /* no icons -- text link is forcebinary/text */
  2544.  
  2545.     z2='/'||action||'/'||zw
  2546.     z20='/'||action||'/'||zw0
  2547.  
  2548.     z2a=strip(translate(zipdir,'/','\'),,'/')
  2549.     if z2a<>"" then do
  2550.        z3=z2||z2a||'/'
  2551.        z30=z20||z2a||'/'
  2552.     end
  2553.     else do
  2554.         z3=z2;z30=z20
  2555.     end
  2556.  
  2557.     if links2=1 then do
  2558.        z21='/'||action||'/'||zw1
  2559.        z22='/'||action||'/'||zw2
  2560.        if z2a<>"" then do
  2561.           z31=z21||z2a||'/'
  2562.           z32=z22||z2a||'/'
  2563.        end
  2564.        else do
  2565.           z31=z21 ; z3s=z22
  2566.        end
  2567.     end  /* Do */
  2568.  
  2569.     eef=delstr(strip(zipfile),length(strip(zipfile))-3)
  2570.     eef=strip(eef,,'/')
  2571.     feeb2=z3||eef||'/'||fname
  2572.     feeb20=z30||eef||'/'||fname
  2573.  
  2574.     feeb3='<a href="'feeb2'">'||fname||'</a>'
  2575.     feeb30='<a href="'feeb20'">'||fname||'</a>'
  2576.  
  2577.      if arglist.!noicons=1 then
  2578.          myimg=' '
  2579.      else
  2580.         myimg=imagetype(fname)
  2581.  
  2582.      feebpic=' '
  2583.      if arglist.!noicons=0 then do
  2584.         select
  2585.            when forcet=1 then
  2586.               feebpic='<a href="'feeb2'">'||txtimg||'</a>'
  2587.            when forceb=1 then
  2588.               feebpic='<a href="'feeb2'">'||binimg||'</a>'
  2589.            otherwise
  2590.               feebpic='<a href="'feeb2'">'||myimg||'</a>'
  2591.          end  /* select */
  2592.       end
  2593.  
  2594.       if links2=1 then do
  2595.            feeb21=z31||eef||'/'||fname
  2596.            feebpic1='<a href="'feeb21'">'||txtimg||'</a>'
  2597.            feeb22=z32||eef||'/'||fname
  2598.             feebpic2='<a href="'feeb22'">'||binimg||'</a>'
  2599.            feebpic=feebpic1||' '||feebpic2
  2600.       end
  2601.       if forcet+forceb>0 then
  2602.         call lineout tempfile, '<dt><pre>' feebpic' 'feeb30''copies(' ',max(0,20-length(Fname)))''right(Fdate,10)''right(Ftime,6)' 'right(Fsize,10)'</pre></dt>'
  2603.       else
  2604.         call lineout tempfile, '<dt><pre>' feebpic' 'feeb3''copies(' ',max(0,20-length(Fname)))''right(Fdate,10)''right(Ftime,6)' 'right(Fsize,10)'</pre></dt>'
  2605. end
  2606.  
  2607. /* call rxqueue 'DELETE', queue_name */
  2608. call lineout tempfile, "</BODY>"
  2609. call lineout tempfile, "</HTML>"
  2610. call lineout tempfile
  2611.  
  2612.  
  2613. /*  copy to cache_file? */
  2614. if cache.!files>0  then do
  2615.    pig=write_to_cache(tempfile,mkit,cache_check)
  2616. end  /* Do */
  2617.  
  2618. if cache_mode=0 & fixexpire>0 then do
  2619.          ncc=chars(tempfile)
  2620.          fpp=sref_expire_response(fixexpire)
  2621.  end
  2622.  
  2623. aa=stream(tempfile,'c','close')
  2624.  
  2625. if cache_mode=0 then
  2626.    'FILE ERASE TYPE text/html NAME ' tempfile
  2627. else
  2628.   foo=sysfiledelete(tempfile)
  2629.  
  2630. return 0
  2631.  
  2632.  
  2633.  
  2634. /**************/
  2635. /* Extract and send a zip file.
  2636. zipfile: The "local" file to be unzipped
  2637. zipdir:  url-directory of the zipfile
  2638. */
  2639. send_zipfile:procedure expose send_piece tempfile imagesize imagepath file_dir bbsdir ,
  2640.                 must_wait arglist. write_details counter_file userlog_dir ,
  2641.                 bytes_newuser files_newuser nowtime ,
  2642.                 user_header. userlog_lines. userfile
  2643.  
  2644. parse upper arg  zipfile ,zipdir,getfile,forcetext,forcebinary,aratio,aweight
  2645. zipdir='\'||strip(translate(zipdir,'\','/'),'l','\')
  2646.  
  2647. gets=make_adir(file_Dir,zipdir)
  2648. /*gets=strip(file_dir,'t','\')||zipdir*/
  2649.  
  2650. if dosisdir(gets)=0 then do
  2651.   call lineout tempfile, "<body><h2>Sorry...</h2>"
  2652.   call lineout tempfile,' **** Could not find directory: ' zipdir
  2653.   call lineout tempfile, "</body></html>"
  2654.   call lineout tempfile  /* close */
  2655.   'FILE ERASE TYPE text/html NAME ' tempfile
  2656.   return 0
  2657. end
  2658.  
  2659. if download_okay(must_wait,aratio)=0 then return 0
  2660.  
  2661.  
  2662. zipfile=strip(zipfile)
  2663.  
  2664. mkit=gets||'\'||zipfile
  2665. /* make sure it exists */
  2666. if stream(mkit,'c','query exists')=' ' then  do
  2667.   call lineout tempfile, "<body><h2>Sorry...</h2>"
  2668.   call lineout tempfile,' Could not find .ZIP file: ' zipfile
  2669.   call lineout tempfile, "</body></html>"
  2670.   call lineout tempfile  /* close */
  2671.   'FILE ERASE TYPE text/html NAME ' tempfile
  2672.   return 0
  2673. end
  2674. rc=uzunziptostem(mkit,'sook.',getfile)
  2675. if sook.0=1 then do
  2676.   arf=strip(sook.1)
  2677.   thesize=length(sook.arf)
  2678.   if thesize=0 then do  /* hack to get around unzip.dll ?bug? */
  2679.      sook.arf=uzunziptovar(mkit,getfile)
  2680.      thesize=length(sook.arf)
  2681.   end
  2682.  
  2683.   select
  2684.      when forcetext<>0 then
  2685.          atype='text/plain'
  2686.      when forcebinary<>0 then
  2687.          atype='appplication/octet-stream'
  2688.      otherwise
  2689.          atype=sref_mediatype(getfile)
  2690.   end
  2691.   'VAR TYPE ' atype ' as ' getfile ' name sook.arf '
  2692.   foo=add_userinfo(aweight,thesize,' Extract from '||zipfile)
  2693. end
  2694. else do
  2695.   call lineout tempfile, "<body><h2>Sorry...</h2>"
  2696.   call lineout tempfile,' Could not find Zipped file: ' getfile
  2697.   call lineout tempfile, "</body></html>"
  2698.   call lineout tempfile  /* close */
  2699.   'FILE ERASE TYPE text/html NAME ' tempfile
  2700. end
  2701.  
  2702.  
  2703. return 0
  2704.  
  2705.  
  2706. /* fix up size, given format */
  2707. fixup_size:procedure
  2708. parse upper arg sizefmt,asize
  2709.  if translate(sizefmt)="ABBREV" then do
  2710.                if asize>=1000000 then
  2711.                        return format(asize/1000000,,0)||'M'
  2712.                if asize>=1000 then
  2713.                       return format(asize/1000,,0)||'K'
  2714.  end
  2715. /* convert to xxx,yyy,zzz */
  2716.  il=length(asize)
  2717.  if il>3 then do
  2718.            oop=""
  2719.            do mm=il to 3 by -3
  2720.                tt=substr(asize,mm-2,3)
  2721.                if mm=il then
  2722.                   oop=tt
  2723.                else
  2724.                  oop=tt||','||oop
  2725.            end /* do */
  2726.            if mm<>0 then oop=substr(asize,1,mm)||','||oop
  2727.            asize=oop
  2728.         end
  2729.         return asize    /* not abbrev, or < 1000 */
  2730.  end
  2731.  
  2732.  
  2733. /*****************************//
  2734. /* get file descriptions from .dsc files (does NOT do auto descriptions) */
  2735. make_dsc_descriptions:procedure expose continuation_flag default_description ,
  2736.         default_description_dir description_text_length  description_text_length_1LINE ,
  2737.         description_text notes. wildnotes. bbsdir description_file arglist.
  2738. parse arg gets
  2739. notes1.0=0
  2740. notes.0=0
  2741.  
  2742. if description_file<>' ' then do
  2743.   t1=stream(gets||'\'||description_file,'c','query exists')
  2744.   if t1<>' ' then do
  2745.      eek=fileread(t1,'notes',,'E')
  2746.      ekk=fix_notes(continuation_flag)
  2747.   end
  2748. end
  2749. /* copy to a temporary array, and do it again below */
  2750. do arf=1 to notes.0
  2751.    notes1.arf.dastuff=notes.arf.dastuff
  2752.    notes1.arf.daname=translate(notes.arf.daname,'/','\')
  2753. end /* do */
  2754. notes1.0=notes.0
  2755. notes.0=0               /* get next set */
  2756. if description_file<>' ' then do
  2757.   yipper=bbsdir||description_File
  2758.   t1=stream(bbsdir||description_file,'c','query exists')
  2759.   if t1<>' ' then do
  2760.      eek=fileread(t1,'notes',,'E')
  2761.      ekk=fix_notes(continuation_flag)
  2762.   end
  2763. end
  2764. /* add this set to notes1 */
  2765. if notes.0>0 then do
  2766.   obie=notes1.0
  2767.   do mm=1 to notes.0
  2768.     obie2=obie+mm
  2769.     notes1.obie2.daname=translate(notes.mm.daname,'/','\')
  2770.     notes1.obie2.dastuff=notes.mm.dastuff
  2771.   end
  2772.   notes1.0=obie2
  2773. end
  2774. drop notes.     /* copy to notes. */
  2775. do pp=1 to notes1.0
  2776.   notes.pp.daname=notes1.pp.daname
  2777.   notes.pp.dastuff=notes1.pp.dastuff
  2778.   notes.pp=notes1.pp.daname  /* used for searching */
  2779. end /* do */
  2780. notes.0=notes1.0
  2781. drop notes1.
  2782.  
  2783. if default_description<>' ' then do
  2784.    ii=notes.0+1
  2785.    notes.ii.daname='/*'
  2786.    notes.ii.dastuff=default_description_dir
  2787.    notes.ii=default_description_dir
  2788.    ii=ii+1
  2789.  
  2790.    notes.ii=default_description
  2791.    notes.ii.daname='*'
  2792.    notes.ii.dastuff=default_description
  2793.  
  2794.    notes.0=ii
  2795. end  /* Do */
  2796. /* create the "wildcarded" notes list */
  2797. /* create wildcarded list */
  2798. nwilds=0
  2799. do mm=1 to notes.0
  2800.    if pos('*',notes.mm.daname)>0 then do
  2801.        nwilds=nwilds+1
  2802.        wildnotes.nwilds.daname=notes.mm.daname
  2803.        wildnotes.nwilds.dastuff=notes.mm.dastuff
  2804.    end  /* Do */
  2805. end /* do */
  2806. wildnotes.0=nwilds
  2807. return 0
  2808.  
  2809.  
  2810. /******************/
  2811. /* find a description -- either from .dsc file, or auto describe */
  2812. find_description:procedure expose notes. wildnotes. auto_describe. zip_descriptor_file
  2813.  
  2814. parse arg chkme,absname
  2815.  
  2816. if notes.0=0 then return ' '
  2817. tt=arraysearch(notes.,yikes,chkme,'X')
  2818. if tt>0 then do
  2819.        poop=yikes.1
  2820.        return notes.poop.dastuff
  2821.  end  /* Do */
  2822.  
  2823. if auto_describe.!alen>0 then do
  2824.   oo=do_auto_describe(absname)
  2825.   if oo<>' ' then return oo
  2826. end
  2827.  
  2828. /* else, try wildcard match */
  2829.  do ini=1 to wildnotes.0
  2830.        oo=sref_wildcard(chkme,wildnotes.ini.daname,0)
  2831.        parse var oo stat ',' . ; stat=strip(stat)
  2832.        if stat<>0 then return wildnotes.ini.dastuff
  2833.  end
  2834.  
  2835.  return ' '
  2836.  
  2837.  
  2838. /* ------------------------------- */
  2839. /* check for username/password.
  2840. IF none, or incorrect, (username=USER or username=" "),
  2841. then redirect to LOGON_FILE, with the Arglist.!uri as an ? option.
  2842. Note that the LOGON_FILE can be customized, but should contain some
  2843. basic structure.
  2844.  
  2845. Note the use of .in files to store information "by user", rather then
  2846. central registry
  2847.  
  2848. If not authorization mode, then reqratio, download_weight, user_header. 
  2849.   file_dir userlog_lines. privset   are also "returned"
  2850. If authorization mode, then a www-authenticate, or a "redirect to logon file"
  2851.   have already occured.
  2852.  
  2853. */
  2854.  
  2855. check_user:procedure expose userlog_dir userlog_lines. bbs_logon_file ,
  2856.         servername serverport send_piece tempfile verbose arglist.  user_header. ,
  2857.         privset reqratio file_dir userfile verbose own_name_privilege option_list ,
  2858.         priv_weight. priv_ratio. authorization_mode use_servername index_list. nowtime download_weight
  2859.  
  2860. parse arg auser,apwd,thisuri,ctlfile,defratio,isindex,cache_mode
  2861.  
  2862. /* special cache mode action */
  2863. if cache_mode=1  then do
  2864.   ok0=fig_access(ctlfile,arglist.!dir,'SUPERUSER')   /* if ctlfile=' ', then fig_access does not check */
  2865.   parse upper var ok0 ok  reqprivs  ','  avirtual
  2866.   if avirtual<>0 & avirtual<>' ' then file_dir=strip(avirtual)
  2867.   return 1
  2868. end
  2869.  
  2870.  
  2871. if upper(auser)="USER" | auser=0 | auser="" then do
  2872.     mess2='You did not specify a username and password'
  2873.     signal nonesuch
  2874. end
  2875.  
  2876. /* check for .in file */
  2877. userfile=userlog_dir||auser||'.in'
  2878. shtread=0
  2879.  
  2880. newread:
  2881. if arglist.!file=' ' & shtread=0 then do
  2882.    ww=fileread(userfile,userlog_lines,40,'E')   /*assume header within 40 lines*/
  2883.    shtread=1
  2884. end
  2885. else do
  2886.    ww=fileread(userfile,userlog_lines,,'E')
  2887. end
  2888. mess2='Access denied.  '
  2889.  
  2890. if userlog_lines.0>500 & verbose>1 then
  2891.  say "BBS Warning: the user-log for " auser " is getting large. "
  2892.  
  2893. /* if no user file, then either redirect to registration form,
  2894.  or if authorizationmode, create a basic file */
  2895. if userlog_lines.0=0 then do
  2896.   if authorization_mode=1 then do
  2897.      foo=create_user_log(userfile,auser,apwd,privset,defratio)
  2898.   end  /* Do */
  2899.   else do
  2900.      if auser=0 then
  2901.         mess2= " Username and password were not specified "
  2902.      else
  2903.         mess2= " No such user:" auser
  2904.      if verbose>2 then say  mess2
  2905.      signal nonesuch
  2906.   end
  2907. end
  2908.  
  2909. /* if here, got userlog lines-- either from file, or just created
  2910.  So extract headers from userlog_lines. */
  2911.  
  2912.  daheaders=get_user_header(userfile)
  2913.  if wordpos('MESSAGES',daheaders)=0 and shtread=1 then do /* gotta read all of file*/
  2914.      signal newread
  2915.  end
  2916.  
  2917. /* check username password */
  2918.  
  2919.  if wordpos('USER',daheaders)=0 then do  /* no user/pwd info */
  2920.       mess2=" Missing username/password info for:" auser
  2921.      if verbose>2 then say  mess2
  2922.      signal nonesuch
  2923.  end  /* Do */
  2924.  else do
  2925.     parse upper var user_header.!user  buser bpwd
  2926.     if strip(auser)<>strip(buser) | strip(apwd)<>strip(bpwd) then  do
  2927.          mess2=" Password mismatch for:" auser
  2928.         if verbose>2 then say  mess2
  2929.         signal nonesuch
  2930.     end  /* pwd and user match */
  2931.  end
  2932.  
  2933. /* what are the user privileges ? */
  2934. if authentication_mode<>1 then do  /* =1, then use SRE-http privset */
  2935.   if wordpos('PRIVILEGES',user_header.0)=0 then do
  2936.      privset='NEWUSER'
  2937.   end
  2938.   else do
  2939.       privset=user_header.!privileges
  2940.       if own_name_privilege=1 then privset=privset||' !'||auser
  2941.   end
  2942. end
  2943.  
  2944. /*what are the personal_download_directories */
  2945.  if wordpos('DOWNLOAD_DIR',user_header.0)=0 then do
  2946.      own_download_dirs=' '
  2947.   end
  2948.   else do
  2949.       own_download_dirs=user_header.!download_dir
  2950.   end
  2951.  
  2952.  
  2953. /* if recent files list, then go through index_list, remove files
  2954. for which privileges are not available, and then return.
  2955. Also, remove "too old" files (jdate + index_days < nowtime), if
  2956. index_days>0 */
  2957.  
  2958. if isindex=1 then do
  2959.   nogood=0
  2960.   if verbose>2 then say " Examining  index_list entries=" index_list.0
  2961.   ppset.0=words(privset)
  2962.   do jj=1 to ppset.0
  2963.      ppset.jj=upper(strip(word(privset,jj)))
  2964.   end /* do */
  2965.   do ll=1 to index_list.0
  2966.      if index_list.ll=' ' then iterate /* leave comment as is */
  2967.      else
  2968.      if arglist.!index_days>0 then do  /* check for expiration info */
  2969.         sink=index_list.ll.!jdate +arglist.!index_days
  2970.         if sink<nowtime then do
  2971.             index_list.ll=-1 ; nogood=nogood+1; iterate
  2972.         end  /* Do */
  2973.      end  /* Do */
  2974.      pset=upper(index_list.ll.!privs)
  2975.      if wordpos('*',pset)>0  | pset=" " then iterate /* okay */
  2976.      do ll2 =1 to ppset.0       /* check for a privilege */
  2977.           if wordpos(ppset.ll2,pset)>0 then iterate ll
  2978.      end /* do */
  2979.      nogood=nogood+1            /* no priv, so no good */
  2980.      index_list.ll=-1          /* if here, no matching priv */
  2981.   end /* do */
  2982.   index_list.!okay=index_list.0-nogood
  2983.   if verbose > 2 then say " BBS Index mode, Useable entries:: " index_list.!okay
  2984.   return 1              /* it's now fixed up */
  2985. end
  2986.  
  2987. /* else, regular mode--- get bbs.ctl entry (request-specific) or
  2988. download_dir from user.in.  These also contain "privileges" which
  2989. are used to extract ratios and weights */
  2990.  
  2991. ok=0 
  2992. if own_download_dirs<>' ' then do   /* is this a personal directory */
  2993.    ok0=check_personal_dir(arglist.!dir,own_download_Dirs)
  2994.    parse upper var ok0 ok  avirtual reqprivs /* avirtual will contain "strip prefix" flag */
  2995. end /* do */
  2996.  
  2997. if ok=1 then do                 /* do NOT cache personal directories */
  2998.      arglist.!nocache=1
  2999. end  /* Do */
  3000.  
  3001. if ok=0 then do           /* not a personal -- perhaps a bbs.ctl */
  3002.   ok0=fig_access(ctlfile,arglist.!dir,privset)   /* if ctlfile=' ', then fig_access does not check */
  3003.   parse upper var ok0 ok  reqprivs  ','  avirtual
  3004.   if ok=0 then do
  3005.      if verbose>2 then say arglist.!user " does not have rights to " arglist.!dir
  3006.      if authentication_mode=1 then do
  3007.        foo=responsebbs('unauth',arglist.!dir,'Authorization required for 'arglist.!dir)
  3008.        return 0
  3009.      end  /* Do */
  3010.      else do
  3011.         mess2=auser||' does not have access rights to:' arglist.!dir
  3012.         signal nonesuch
  3013.      end
  3014.   end
  3015. end
  3016.  
  3017. /* change  file_dir */
  3018. if avirtual<>0 & avirtual<>' ' then file_dir=strip(avirtual)
  3019. if verbose>3 then say " Using file_dir = " file_dir 
  3020.  
  3021. /* Now determine download/upload ratios required for this file's directory */
  3022. if wordpos('RATIO',user_header.0)=0 then
  3023.    aratio=defratio
  3024. else
  3025.   aratio=user_header.!ratio
  3026. parse var aratio fratio bratio
  3027. if datatype(fratio)<>'NUM'  then fratio=0
  3028. if datatype(bratio)<>'NUM'  then bratio=0
  3029. aweight=1
  3030.  
  3031. /* See if a "privilege" specific ratio & weight applies (compare user's privset
  3032. to the  reqprivs, and if a match, extract (if one exists)
  3033.  the values of an associated priv_ratio.! and priv_weight.! variables  */
  3034. if reqprivs<>' ' then do
  3035.   do gn=1 to words(privset)
  3036.     ap1=upper(strip(word(privset,gn)))
  3037.     if wordpos(ap1,reqprivs)=0 then iterate
  3038.     wow='!'||ap1
  3039.     if symbol('PRIV_RATIO.'||wow)='VAR' then do   /*check for ratios */
  3040.        parse var priv_ratio.wow r1 r2
  3041.        if datatype(r1)='NUM' & datatype(r2)='NUM' then do
  3042.           fratio=max(fratio,r1)
  3043.           bratio=max(bratio,r2)
  3044.        end
  3045.     end
  3046.     if symbol('PRIV_WEIGHT.'||wow)='VAR' then do   /* check for a download weight */
  3047.        if datatype(priv_weight.wow)='NUM' then do
  3048.            aweight=min(priv_weight.wow,aweight)
  3049.        end
  3050.     end
  3051.  
  3052.   end
  3053. end /* do */
  3054. reqratio=fratio' 'bratio
  3055. download_weight=aweight
  3056.  
  3057.  
  3058.  
  3059. return 1                /* 1 signals success */
  3060.  
  3061.  
  3062. nonesuch:  /* jump here to redirect to logon file */
  3063.  
  3064. if authorization_mode=1 then do   /* if it is authorization mode ... */
  3065.    foo=responsebbs('unauth','BBS@'||use_servername,'Username/password required')
  3066.    return 0
  3067. end  /* Do */
  3068.  
  3069. /* set up stuff for redirection to logon_file */
  3070.  serverport=extract('serverport')
  3071.  sel='http://'||servername
  3072.  if serverport<>80 then sel=sel||':'||serverport
  3073.  if thisuri=' ' then
  3074.     thisuri=make_a_url(option_list,' ')
  3075.  tname=sref_replacestrg(thisuri,'%','%25','ALL')
  3076.  tname=sref_replacestrg(tname,'&','%26','ALL')
  3077.  tname=translate(tname,'+',' ')
  3078.  
  3079.   sel=sel||'/'||bbs_logon_file||'?'||tname
  3080.   if mess2<>' ' then sel=sel'&'translate(mess2,'+',' ')
  3081.  
  3082.  'RESPONSE HTTP/1.0 302 Moved Temporarily'  /* Set HTTP response line */
  3083.   call lineout tempfile, '<!doctype html public "-//IETF//DTD HTML 2.0//EN">'
  3084.   call lineout tempfile, "<html><head><title>Username/password required</title></head>"
  3085.  'HEADER ADD Location:' sel
  3086.   call lineout tempfile, "<body><h2>You must provide username and password ...</h2>"
  3087.    call lineout tempfile, '<a href="'sel'">here<a>.'
  3088.    call lineout tempfile, "</body></html>"
  3089.   call lineout tempfile  /* close */
  3090.  
  3091.  'FILE ERASE TYPE text/html NAME ' tempfile
  3092. if verbose>2 then say " redirecting to " sel
  3093.  
  3094.  return -1
  3095.  
  3096.  
  3097.  
  3098.  
  3099. /* ---------- */
  3100. /* check bbs.ctl AND look for a matching download_dir (in the user.in file) */
  3101. check_personal_dir:procedure expose arglist.
  3102. parse upper arg thedir,own_dirs
  3103.  
  3104.  
  3105. t1=translate(thedir,' ','\/')
  3106. if t1="" then
  3107.   prefix=''
  3108. else
  3109.   prefix=strip(upper(word(t1,1)))
  3110.  
  3111.  
  3112. /* look for download_dir entries in user.in */
  3113.  parse upper var own_dirs own_dirs_sel ',' own_dirs_dir ',' own_dirs_info
  3114.  
  3115. /* look for match to thedir in own_dirs_sel */
  3116.  igot=0; igotlen=0 ;igotd=0
  3117.  do ij=1 to words(own_dirs_sel)
  3118.       asel=strip(word(own_dirs_sel,ij))
  3119.       if prefix=asel then do
  3120.             igot=ij
  3121.             leave
  3122.       end  /* Do */
  3123.       if asel="DEFAULT" then igotd=ij
  3124.  end
  3125.  
  3126.  if igotd<>0 & igot=0 then do
  3127.     adir=strip(word(own_dirs_dir,igotd))   
  3128.     ainfo=strip(word(own_dirs_info,igotd)) 
  3129.     return '1 '||adir||' '|| ainfo
  3130.  end
  3131.  if igot=0 then return 0
  3132.  
  3133.  adir=strip(word(own_dirs_dir,igot))
  3134.  ainfo=strip(word(own_dirs_info,igot))
  3135.  
  3136.  return '1 *'||adir||' '|| ainfo
  3137.  
  3138.  
  3139.  
  3140.  
  3141. /* ---------- */
  3142. /* check bbs.ctl AND look for a matching download_dir (in the user.in file) */
  3143. fig_access:procedure expose arglist.
  3144. parse upper arg thefile,thedir,cprivs
  3145.  
  3146. thedir=upper(translate(thedir,'\','/'))
  3147. if thedir=' ' then thedir='\'
  3148. if thedir<>'\' then
  3149.    thedir='\'||strip(thedir,,'\')||'\'
  3150.  
  3151. if thefile=' ' then return ' '   /* nothing to do */
  3152.  
  3153. wow=fileread(thefile,'acclines',,'E')
  3154. if wow=0  then return 0        /* empty -- do not allow access */
  3155.  
  3156.  
  3157. /* got a request -- look for a match */
  3158.  gotit=0
  3159.  starat=0 ;  afterstar=0
  3160.  do mm=1 to acclines.0
  3161.     aline=strip(acclines.mm)
  3162.     if aline='' | abbrev(aline,';')=1  then iterate
  3163.     parse upper var aline aurl .
  3164.     aurl=translate(aurl,'\','/')
  3165.     aurl='\'||strip(aurl,,'\')
  3166.     if pos('*',aurl)=0 then aurl=aurl||'\'
  3167.     ares=sref_wildcard(thedir,aurl||' '||aurl,0)
  3168.     parse var ares astat "," aurl2 ;  astat=strip(astat)
  3169.     if astat=0 then iterate   /* no match */
  3170.     if astat=1 then do
  3171.         gotit=1
  3172.         useline=aline
  3173.         leave
  3174.     end
  3175.     else  do
  3176.        parse var aurl ma1a ma1b
  3177.        t1=pos('*',ma1a)
  3178.        t33=length(ma1a)-t1
  3179.        if t1 >= starat  then do
  3180.           if t1 > starat | t33>afterstar then do
  3181.              starat=t1 ; afterstar=t33
  3182.              gotit=mm ; useline=aline
  3183.           end
  3184.        end
  3185.     end
  3186.  end
  3187.  
  3188. if gotit=0 then   return 0  /* no match, no access */
  3189. parse upper var useline foo aprivs ','  avirt
  3190.  
  3191. if wordpos('*',aprivs)>0 | aprivs=""  | wordpos('SUPERUSER',cprivs)>0 then
  3192.        return 1 aprivs ','  avirt
  3193. do ii=1 to words(cprivs)
  3194.    if wordpos(word(cprivs,ii),aprivs)>0 then return 1  aprivs ',' avirt
  3195. end
  3196.  
  3197. return 0
  3198.  
  3199.  
  3200.  
  3201.  
  3202. /*************/
  3203. /* extract user header from userlog_lines. */
  3204. get_user_header:procedure expose userlog_lines. user_header.
  3205.  
  3206. /* get header info. ; lines are ignored. User_header.0 contains list of
  3207.    .extensions found (i.e.; user_header.!status, user_header.!privileges
  3208.    yield user_header.0='STATUS PRIVILEGES '
  3209. */
  3210. user_header.0=' '
  3211. dsels=" " ; ddirs=" " ; dinfos=' '
  3212. do mm=1 to userlog_lines.0
  3213.      aline=strip(userlog_lines.mm)
  3214.      if abbrev(aline,';')=1 | aline=' ' then iterate
  3215.      parse var aline atype ':' aval ; uatype=upper(strip(atype))
  3216.      user_header.0=user_header.0||' '||uatype
  3217.      if uatype='MESSAGES' then leave
  3218.      if uatype="DOWNLOAD_DIR" then do
  3219.           aval=translate(aval,'\','/')
  3220.           parse upper var aval d1 d2 d3
  3221.           dsels=dsels||' '||d1
  3222.           ddirs=ddirs||' '||d2
  3223.           dinfos=dinfos||' '||d3
  3224.      end  /* Do */
  3225.      else do
  3226.         fo='!'||uatype
  3227.         user_header.fo=aval
  3228.         if uatype='STATUS' then userlog_lines.statusat=mm
  3229.     end
  3230.  end /* do */
  3231.  
  3232.  if dsels<>" " then
  3233.     user_header.!DOWNLOAD_DIR=dsels||' , '||ddirs||', '||dinfos
  3234.  
  3235.  return user_header.0
  3236.  
  3237.  
  3238. /***** Create a very basic userlog file */
  3239. create_user_log:procedure expose userlog_lines.
  3240. parse arg userfile,user,pwd,privs.defratio
  3241.  
  3242. drop userlog_lines.
  3243.  userlog_lines.1='; BBS user file: ' user
  3244.         userlog_lines.2='User: ' user pwd
  3245.         userlog_lines.3='Status: 0 0 0 0 0 '
  3246.         userlog_lines.4='Privileges:  NEWUSER '||privs
  3247.         userlog_lines.5='Name: Unknown '
  3248.         userlog_lines.6='Email: Unknown '
  3249.         userlog_lines.7='Ratio:  ' defratio
  3250.         userlog_lines.8='; '
  3251.         userlog_lines.9='Messages: '
  3252.    userlog_lines.0=8
  3253.    userlog_lines.statusat=3
  3254.   aa=filewrite(userfile,userlog_lines)
  3255.   if aa=0 & verbose>0 then say " Warning: error creating BBS userfile: " userfile
  3256.  
  3257. return 0
  3258.  
  3259.  
  3260. /****************/
  3261. do_auto_describe:procedure expose auto_describe. zip_descriptor_file
  3262. parse arg athing
  3263. ALINE0=DO_auto_describe2(ATHING,zip_descriptor_file)
  3264. aline0=sref_replacestrg(aline0,'<','<','ALL')
  3265. aline0=sref_replacestrg(aline0,'>','>','ALL')
  3266. aline0=strip(left(aline0,min(length(aline0),auto_describe.!alen)))
  3267. aa=aline0 ;ills=0 ;notemp=0 
  3268. crlf='0d0a'x
  3269. do until aa=""
  3270.   parse var aa aa1 (crlf) aa
  3271.   if aa1="" & ills=0 then iterate /* skip leading blank lines */
  3272.   ills=ills+1 ;  tlls.ills=aa1
  3273.   if aa1<>"" then notemp=ills   /* the last non-blank line */
  3274. end /* do */
  3275. if notemp=0 then return ' '
  3276.  
  3277. /* clip into max of 80 character lines */
  3278. aa=clip_line(tlls.1,80)
  3279.  
  3280. do mm=2 to notemp
  3281.    aa=aa||crlf||clip_line(tlls.mm,80)
  3282. end /* do */
  3283. return aa
  3284.  
  3285.  
  3286.  
  3287.  
  3288. /***************/
  3289. /* clip todo to lines of maximum nll chars */
  3290. clip_line:procedure
  3291. parse arg todo,nll,keepcrlf
  3292. crlf='0d0a'x
  3293. if length(todo)<nll then return todo
  3294. if keepcrlf<>1 then todo=translate(todo,' ','000d0a09'x)
  3295. t1=""; aa=""
  3296. do wwi=1 to words(todo)
  3297.    t1=t1||' '||word(todo,wwi)
  3298.    if length(t1)>nll then do
  3299.       if aa="" then
  3300.           aa=t1
  3301.        else
  3302.           aa=aa||crlf||t1
  3303.        t1=' '
  3304.    end  /* Do */
  3305. end
  3306. if t1<>" " & aa<>"" then  aa=aa||crlf||t1
  3307. if t1<>" " & aa="" then aa=t1
  3308. return aa
  3309.  
  3310.  
  3311. /**********************************/
  3312. /* Construct a description of a file.
  3313.   Requires the unzipapi.dll 
  3314.   Note that a maximum of about 1000 characters (or 15 lines)
  3315.   is returned in a string:
  3316.  
  3317.  header_string=sref_auto_describe(filename.ext)
  3318.  
  3319. Note: if a badly formatted html file is investigated (no
  3320. <HEAD>, or no <TITLE>, then it will be treated as a plain
  3321. text file.
  3322.  
  3323. ----------- */
  3324. do_AUTO_DESCRIBE2:procedure 
  3325. /* construct a description from html, text, or .zip files */
  3326. crlf='0d0a'x
  3327. parse arg thefile,zdf
  3328.  
  3329. thefile=strip(thefile)
  3330. /* is it a .zip file? */
  3331. if right(upper(thefile),4)='.ZIP'   then do
  3332.    zipcmts.0=0     /* is there a file_id.diz file */
  3333.    rc=uzfiletree(thefile,getem)
  3334.    do km=1 to getem.0
  3335.       if upper(getem.km)=zdf then do
  3336.          rc=uzunziptovar(thefile,getem.km,zipcmts)
  3337.          if rc<>0 then zipcmts.0=0
  3338.          leave
  3339.       end
  3340.    end
  3341.    if zipcmts.0>0 then do   /* use first 15 lines of file_id.diz */
  3342.       oof=zipcmts.1
  3343.       do te=2 to min(15,zipcmts.0)
  3344.          oof=oof||crlf||zipcmts.te
  3345.       end /* do */
  3346.       return oof
  3347.    end
  3348.  
  3349.    zipcmts.0=0              /* no file_id.zip file, try to get -z comments */
  3350.    rc=uzunzip(' -z '||thefile,'zipcmts.')
  3351.    if rc<>0 then zipcmts.0=0
  3352.    if zipcmts.0>1 then do   /* use -z comments if available, skip generic line */
  3353.       oof=zipcmts.2
  3354.       do te=3 to zipcmts.0
  3355.          oof=oof||crlf||zipcmts.te
  3356.       end /* do */
  3357.       return oof
  3358.    end
  3359.  
  3360.    return ' '           /* no -z, and no file_id.diz */
  3361. end  /* .ZIP file */
  3362.  
  3363.  
  3364. /* TEXT plain file ?*/
  3365. atype=upper(sref_mediatype(thefile))
  3366. if atype='TEXT/PLAIN' then do  /*grab first 15 lines */
  3367.     oof=""
  3368.     if lines(thefile)=1 then 
  3369.           oof=linein(tempfile)
  3370.     do mm=1 to 14   /* read first 15 lines */
  3371.         if lines(thefile)=0 then leave
  3372.         tt=linein(thefile)
  3373.         oof=oof||crlf||tt
  3374.     end
  3375.     foo=stream(thefile,'c','close')
  3376.     return oof
  3377. end  /* Do */
  3378.  
  3379. if atype='TEXT/HTML' then do  /* parse html, look for title or description */
  3380.    oof=get_html_descript(thefile)
  3381.    if oof="" then do  /* must be badly formatted, treat as text file */
  3382.      oof=""
  3383.      aa=stream(thefile,'c','close')
  3384.      if lines(thefile)=1 then
  3385.           oof=linein(tempfile)
  3386.      do mm=1 to 14   /* read first 15 lines */
  3387.         if lines(thefile)=0 then leave
  3388.         tt=linein(thefile)
  3389.         oof=oof||crlf||tt
  3390.      end
  3391.      foo=stream(thefile,'c','close')
  3392.    end
  3393.    return oof
  3394. end
  3395.  
  3396. return ' '   /* other type, give up */
  3397.  
  3398.  
  3399. /**************************************/
  3400. /* Extract description from text/html file */
  3401. get_html_descript:procedure
  3402. parse arg filename
  3403.  
  3404. alen=min(chars(filename),2000)
  3405. stuff=charin(filename,1,alen)
  3406.  
  3407. stuff=space(translate(stuff,' ','00090a0d1a1b'x))
  3408.  
  3409. wow=look_header(filename)
  3410. astring=""
  3411. if url_title<>' ' then
  3412.    astring=strip(strip(url_title),'t','.')||'.  '
  3413. if url_content<>' ' then
  3414.    astring=astring||'0d0a'x||url_content
  3415. return astring||'0d0a'x
  3416.  
  3417.  
  3418.  
  3419.  
  3420. /* ----------------------------------------------------------------------- */
  3421. /* Look for "desc" field in header  
  3422. sets url_title and url_content exposed variables  */
  3423. /* ----------------------------------------------------------------------- */
  3424.  
  3425. look_header: procedure expose stuff url_title url_content
  3426. parse arg afile
  3427.  
  3428. url_title=""
  3429. url_content=""
  3430. dowrite=0
  3431.  
  3432. do until stuff=""
  3433.  
  3434.     parse var stuff  p1 '<' tag '>' stuff
  3435.     if  translate(word(tag,1))="HEAD" then do   /* now in head !*/
  3436.             dowrite=1
  3437.             iterate
  3438.     end
  3439.     if dowrite=0 then iterate    /* wait till we get into head .. */
  3440.  
  3441.     if  translate(word(tag,1))="/HEAD" then  /* out of head, all done ! */
  3442.         leave
  3443.  
  3444. /* IT IS A TITLE TAG?  */
  3445.      if translate(word(tag,1))="TITLE" then do
  3446.         parse var stuff url_title '<' footag '>' stuff
  3447.         if url_content<>' ' then return 0
  3448.      end
  3449.  
  3450. /* is it a  META HTTP-EQUIV or a META NAME ? */
  3451.     if translate(word(tag,1))="META" then do
  3452.         parse var tag ameta atype '=' rest
  3453.         tatype=translate(atype)
  3454.         if tatype="HTTP-EQUIV" | tatype="NAME" then do
  3455.            parse var rest aval1 rest
  3456.            REST=STRIP(REST)
  3457.  
  3458.            aval1=strip(aval1) ;
  3459.            aval1=strip(aval1,,'"')
  3460.            if abbrev(translate(aval1),'DESC')<>1 then iterate
  3461.  
  3462.            aval2=" "
  3463.            foo1=ABBREV(translate(rest),'CONTENT')
  3464.            if foo1>0 then do
  3465.                 PARSE VAR REST FOO '=' AVAL2
  3466.                 aval2=strip(aval2)
  3467.                 aval2=strip(aval2,'b','"')
  3468.                 url_content=LEFT(AVAL2,1000)
  3469.                 if url_title<>' ' then return 0
  3470.                 iterate
  3471.            end
  3472.         end             /* name or http-equiv */
  3473.     end         /* meta */
  3474. end             /* stuff */
  3475.  
  3476.  
  3477. return 0
  3478.  
  3479.  
  3480. /******************/
  3481. /* combine root directory with user directory, perhaps recognizing
  3482. "personal directory" prefix removal */
  3483.  
  3484. make_adir:procedure
  3485. parse arg dir1,fil1 ;dir1=strip(dir1); fil1=strip(fil1)
  3486.  
  3487. fil1=strip(translate(fil1,'\','/'),,'\')
  3488. dir1=strip(translate(dir1,'\','/'),,'\')
  3489.  
  3490. if abbrev(dir1,'*')=1 then do
  3491.     dir1=strip(substr(dir1,2))
  3492.     ii=pos('\',fil1)
  3493.     if ii>0 then 
  3494.       fil1=substr(fil1,ii+1)
  3495.     else
  3496.       fil1='\'
  3497. end
  3498. aa=strip(dir1||'\'||fil1,,'\')
  3499. return aa
  3500.  
  3501.