home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / cheklink.zip / cheklink.cmd < prev    next >
OS/2 REXX Batch file  |  1998-05-11  |  96KB  |  3,130 lines

  1. /* Check htmllinks
  2.    See CHEKLINK.DOC for installation and useage details.
  3. */
  4.  
  5. cheklink:
  6.  
  7.  
  8. /***  BEGIN USER CONFIGURABLE PARAMETERS     */
  9. /* these can be used to tune performance and modify the output.  */
  10.  
  11. /* used to in <BODY back_n> element (n=1 part 1 or 2) */
  12. back_1='bgcolor="#668a78"'   
  13. back_2='bgcolor="#bbbbdd"'   /* used for both if use_multi=0 */
  14.  
  15. /* If check_robot=1, then check starter-url site for a /robots.txt file, and use it to
  16.    control extent of search. */
  17. check_robot=1
  18.  
  19. /* URL pointing to cheklink.htm (used for a "do it again" option)
  20.    set cheklink_htm='' to not include this option.
  21.    Should be fully qualified */
  22. cheklink_htm='/cheklink.htm'
  23.  
  24. /* if 0, do NOT double check "n.a. servers" */
  25. double_check=1
  26.  
  27.  
  28. /* If get_query=0, then use HEAD request for querying. 
  29.    Although more efficient, some servers do not support HEAD requests.
  30.    If you are likely to encounter such sites, set get_query=1 and 
  31.    short GET requests will be used
  32. */
  33. get_query=0
  34.  
  35.  
  36. linkfile_dir=''    /* directory to store "linkages" file */
  37.  
  38. maxatonce=6        /* max threads active (in QUERY section */
  39. maxatonce_get=2   /* max active threads (in GET section */
  40.  
  41. maxage=60       /* maximum age of a HEAD thread */
  42. maxage2=80      /* maximum age of a GET thread */
  43.  
  44. /* used to bgcolor (or background) the rows of the results TABLEs */
  45. row_color1='bgcolor="#bbcc66"'   /* odd rows, on-site */
  46. row_color2='bgcolor="#aaccdd"'   /* even rows */
  47.  
  48. row_color1a='bgcolor="#bbaa44"'  /* odd rows, off-site */
  49. row_color2a='bgcolor="#aaccdd"'  /* even rows */
  50.  
  51. /* standalone mode intermediate output : 0=none, 1=tiny bit  2 = just a little, 3=steady stream
  52.    Note that verbose output is sent to the "pmprintf" window */
  53. standalone_verbose=3
  54.  
  55.  
  56. /* if =1, then only SUPERUSERs can invoke CHEKLINK. Otherwise, anyone can
  57.     (give other sre-http access rights are satisfied). This is ignored
  58.     in standalone mode */
  59. superusers_only=0
  60.  
  61. /* A fully qualified file containing "header" information for each part.
  62.   If ='', then a generic header is used 
  63.   If specified, the file MUST contain at least:
  64.        <HTML><HEAD>.... </HEAD> <BODY ...> <h1>... </h1> 
  65.   Note: use of user_intro1a (user_intro1b) means that back_1 (back_2) are NOT used 
  66. */
  67. user_intro1a=''
  68. user_intro1b=''
  69.  
  70. /**************** END USER CONFIGURABLE PARAMETERS */
  71.  
  72.  
  73. parse arg  ddir, tempfile, reqstrg,list,verb ,uri,user, ,
  74.           basedir ,workdir,privset,enmadd,transaction,verbose, ,
  75.          servername,host_nickname,homedir,aparam,semqueue,prog_file
  76.  
  77. servername=strip(servername)
  78.  
  79. call load               /* load dlls */
  80.  
  81. if linkfile_dir=0 | linkfile_dir='' then
  82.     linkfile_dir=value('TEMP',,'os2environment')
  83. linkfile_dir=strip(linkfile_dir,'t','\')'\'
  84.  
  85. foo=time('r')
  86. call make_get_url
  87.  
  88. second_output=''
  89. dscmax=300
  90. crlf='0d0a'x
  91. imgs.0=0 ; hrefs.0=0 ; hrefs.!start=1
  92. totgot=0
  93. ascgi=0
  94. doing_results=0
  95. parse var semqueue mysem myqueue
  96.  
  97. if get_query<>1 then
  98.   query_method='HEAD'
  99. else
  100.   query_method='HEADGET'
  101.  
  102. /* aparam is obsolete. Semqueue is semaphore/queue information
  103. that can be used by some sre-daemon procedures */
  104.  
  105. standalone=0
  106. if verb=" " then do
  107.    call ask_opts
  108. end  /* Do */
  109.  
  110. if standalone=0 then do
  111.   if superusers_only=1 & wordpos('SUPERUSER',privset)=0 then do
  112.  
  113.       call lineout tempfile, '<!doctype html public "-//IETF//DTD HTML 3.0//EN">'
  114.       call lineout tempfile, "<html><head><title>Not authorized </title>"
  115.       call lineout tempfile, '</head><body> '
  116.       call lineout tempfile,' </body> </html> '
  117.       call lineout tempfile
  118.       iia=dosdir(tempfile,'s')
  119.  
  120.       is13=value('SREF_PREFIX',,'os2environment')
  121.       if is13='' then do
  122.         'RESPONSE HTTP/1.0 401 Unauthorized '     /* Set HTTP response line */
  123.         'header add WWW-Authenticate: Basic Realm=<CheckLink>'  /* challenge */
  124.         return 'FILE ERASE TYPE text/html NAME' tempfile
  125.      end
  126.      else do
  127.         foo=sref_response('unauth CheckLink','You do not have privileges to use CheckLink',servername,1)
  128.         return foo
  129.      end
  130.   end
  131. end
  132. if standalone=0 then do
  133.   isauth=reqfield('Authorization')
  134.   isref=reqfield('Refered')
  135. end
  136.  
  137. /* read parameters from request */
  138.  
  139. if verb='GET' then parse var uri . '?' list
  140. list=strip(list)
  141. baseonly=0      /* check url's relative to the base of the request (NOT to the root */
  142. siteonly=1      /* if =1 ,no HEAD check on off-site urls' */
  143. aurl=''
  144. exclusion_list='!*  *?* *MAPIMAGE/* CGI*'  /* space delimited list of wildcardable selectors to NOT check */
  145. exclusion_list2=''
  146. use_multi=1       /* use multi-part documents */
  147. outtype='ALL'
  148. linkfile=''
  149. outfilel=''
  150. queryonly=0  /* just query, do not read (subsumes baseonly */
  151. treename=''
  152. make_descrip=2   /*1=non, 2=text/html, 3=text/html and text/plain */
  153. result_file=''
  154. do until list=''
  155.    parse var list a1 '&' list
  156.    parse var a1 avar '=' aval ; tavar=translate(avar)
  157.    aaval=packur2(translate(aval,' ','+'))
  158.    select
  159.      when tavar='URL' then aurl=packur2(translate(aval,' ','+'))
  160.      when abbrev(tavar,'BASE')=1 then baseonly=is_yes_no(aaval,baseonly)
  161.      when abbrev(tavar,'QUERY')=1 then queryonly=is_yes_no(aaval,queryonly)
  162.      when abbrev(tavar,'USEMULTI')=1 then do
  163.             ag=wordpos(aaval,'0 1 2') 
  164.             if ag>0 then use_multi=ag-1
  165.      end /* do */
  166.      when abbrev(tavar,'SITE')=1 then siteonly=is_yes_no(aaval,siteonly)
  167.      when abbrev(tavar,'EXCLUS')=1 then  exclusion_list=aaval
  168.      when abbrev(tavar,'OUTTYPE')=1 then do 
  169.           if aaval<>'' & aaval<>0 then outtype=translate(aaval)
  170.      end
  171.      when abbrev(tavar,'LINKFILE')=1 then linkfile=translate(aaval)
  172.      when abbrev(tavar,'NAME')=1 then treename=aaval
  173.      when abbrev(tavar,'RESULT')=1 then result_file=aaval
  174.      when abbrev(tavar,'DESCRIP')=1 then make_descrip=wordpos(aaval,'0 1 2')
  175.      otherwise nop
  176.   end
  177. end /* do */
  178.  
  179. if make_descrip=0 then make_descrip=1
  180.  
  181. if result_File=0 then result_file=''
  182.  
  183. /* if result_file<>'', then just send it */
  184. if result_file<>'' then do
  185.    outfilel=linkfile_dir||result_file
  186.    return 'FILE type text/html nocache name ' outfilel
  187. end
  188.  
  189. if linkfile=0 then linkfile=''
  190. if linkfile<>'' then do
  191.    outfilel=linkfile_dir||linkfile||'.STM'
  192.    if pos('.',outfilel)=0 then outfilel=outfilel'.STM'
  193. end /* do */
  194. if pos('?',outfilel)>0 then do
  195.     outfilel=dostempname(outfilel)
  196.     eek=filespec('n',outfilel); parse var eek linkfile '.' .
  197. end
  198.  
  199. hold_doing=do_doing(linkfile_dir,use_multi)  /* instructions for multi_send */
  200.  
  201. if exclusion_list=0 then exclusion_list=''
  202. aurl=strip(aurl)
  203.  
  204. if standalone<>0 then use_multi=0       /* simplify my life */
  205.  
  206. /* check to see if the browser understands multi-part documents */
  207. if use_multi=1 then do 
  208.   a=translate(strip(reqfield('Connection')))
  209.   a2=translate(strip(reqfield('PROXY-Connection')))
  210.   if a<>'KEEP-ALIVE' & a<>'MAINTAIN' & a2<>'KEEP-ALIVE' & a2<>'MAINTAIN' then do
  211.      use_multi=2                       /* multi-part not supported by browser */
  212.   end
  213. end  /* Do */
  214. if use_multi=0 then back_1=back_2
  215.  
  216. if abbrev(translate(aurl),'HTTP://')=0 then do
  217.    request=aurl
  218.    server=servername
  219. end 
  220. else do
  221.   parse var aurl . '//' server '/' request
  222.   if server='' then server=servername
  223. end
  224. server=strip(server)
  225.  
  226. fixexpire=value(enmadd||'FIX_EXPIRE',,'os2environment')
  227.  
  228. stype='1S'
  229. if use_multi=1 then stype='SS'
  230.  
  231. /* send start of part1 */
  232. user_intro1=''
  233. if user_intro1a<>'' then do
  234.   afil=stream(user_intro1a,'c','query exists')
  235.   if afil='' then do
  236.      user_intro1=''
  237.   end
  238.   else do
  239.      foo=stream(afil,'c','open read')
  240.      user_intro1=charin(afil,1,chars(afil))
  241.      foo=stream(afil,'c','close')
  242.   end
  243. end
  244.  
  245. if user_intro1='' then do       /* the generic intro */
  246.   foo='<html><head><title> Running: CheckLink of ' server ' </title> ' crlf 
  247. /* add "refresh" meta-http? */  
  248.   if use_multi=2 then do
  249.      parse var hold_doing . clm 
  250.      second_output=filespec('n',clm)
  251.      clm='http://'servername'/cheklink?result='||filespec('n',clm)
  252.      foo=foo' <META HTTP-EQUIV="Refresh" Content="9 ; URL='clm'">'
  253.   end /* do */
  254.  
  255.   foo=foo'</head> <body ' back_1'>'
  256.   user_intro1=foo||crlf'<h2 align="center"> CheckLink: creating a web-tree ... </h2>' crlf 
  257. end
  258.  
  259. rcode=multi_send(user_intro1,'text/html',stype,0,verbose,fixexpire,'CheckLink')
  260.  
  261. noyes.0='NO' ; noyes.1='YES'
  262. is_descrip.1='None created' ; is_descrip.2='text/html only' ;is_descrip.3='text/html & text/plain '
  263.  
  264. /* intro1 is also used in part2 */
  265. intro2=' <h3>Parameters</h3>'crlf'<ul>' ,
  266.     ' <li>Name= 'treename || crlf ,
  267.     ' <li>BASEONLY = ' noyes.baseonly '    (YES= only read text/htmls in/under <em>base-url</em>)'crlf ,
  268.     ' <li>QUERYONLY = ' noyes.queryonly '    (YES= query, but do not read, links)' crlf ,
  269.     ' <li>SITEONLY = ' noyes.siteonly '    (YES= do <em>not </em> verify off-site links)'crlf ,
  270.     ' <li>DESCRIPTIONS= ' is_descrip.make_descrip || crlf ,
  271.     ' <LI>EXCLUSION_LIST = <b>' exclusion_list '</b>     (* are wildcards)'crlf ,
  272.     ' <LI>USE_MULTI = ' use_multi '    (0=1 part doc, 1=2 part doc, 2=two docs 'crlf ,
  273.     ' <li>OUTTYPE = <b>' outtype '</b>    (types of results to report 'crlf 
  274.     if linkfile<>'' then intro2=intro2'<li> LinkFile= 'linkfile ||crlf
  275.     if second_output<>'' then intro2=intro2'<li> Temporary Output to= 'second_output||crlf
  276.     intro2=intro2||'</ul>' crlf ,
  277.     ' <b> CheckLink start at: ' aurl' </b><br>' crlf ,
  278.     '     <tt>server</tt>=<u>' server '</u>, <tt>selector</tt>=<u>' request '</u><br>'
  279. rcode=multi_send(intro2)
  280.  
  281. stuff=get_url(query_method,server,request,isauth)            /* get HEAD info */
  282. /* no such resource or no such server? */
  283. if stuff="" then  do
  284.     vop='<B>No such resource:</b><tt> 'aurl' </tt></body></html>'
  285.     if use_multi=1 then 
  286.         rcode=multi_send(vop,,'E')
  287.     else
  288.         rcode=multi_send(vop,,'1E')
  289.     call outdone 
  290.     return '200 '||extract2('bytessent')
  291. end /* do */
  292.  
  293. call extracts                   /* create headers. and body variables */
  294. parse var response ht num amess
  295.  
  296. /* error code (or redirect) */
  297. if num<200 | num>399 then do
  298.   vop='<p><B>Resource not available</b>: 'num ' 'amess
  299.   if use_multi=1 then 
  300.         rcode=multi_send(vop,,'E')
  301.   else
  302.         rcode=multi_send(vop,,'1E')
  303.   call outdone 
  304.   return '200 '||extract2('bytessent')
  305. end /* do */
  306.  
  307. /* extract basic info */
  308. type='text/html'
  309. asize=''
  310.  
  311. if wordpos('!CONTENT-TYPE',headers.0)>0 then do
  312.     foo='!CONTENT-TYPE'
  313.     type=headers.foo
  314.     asize=0
  315. end
  316. if wordpos('!CONTENT-LENGTH',headers.0)>0 then do
  317.         foo='!CONTENT-LENGTH'
  318.         asize=headers.foo
  319. end
  320.  
  321. if translate(type)<>'TEXT/HTML' then do
  322.    vop='<h3>Not an HTML document </h3> <em>Nothing to check! </em> </body></html>'
  323.    if use_multi=1 then 
  324.         rcode=multi_send(vop,,'E')
  325.    else
  326.         rcode=multi_send(vop,,'1E')
  327.   call outdone 
  328.   return '200 '||extract2('bytessent'
  329. end /* do */
  330.  
  331.  
  332. /* text/html: get the body and find links */
  333.  stuff=get_url('GET',server,request,isauth)  /* get head and body */
  334.  
  335.  call extracts                  /* get body (skip headers)  */
  336.  call set_base_root
  337.  rc=multi_send(intro3)
  338.  
  339.  rc=multi_send('<p>     For ' request': Mime type= ' type ', size='||length(body))
  340.  
  341. if use_multi=2 then do
  342.    aa='<blockquote><b>Output note:</b> The <em>tables of results </em> will be written ' crlf ,
  343.       ' to an output file. On most browsers, this file will be automatically retrieved ' crlf,
  344.       ' about 10 seconds after CheckLink finishes processing. Alternatively, you can ' crlf ,
  345.       ' manually click on a link to this output file.  This link <font color="RED">will</font> be ' ,
  346.       ' placed at the <a href="#BOTTOM">bottom of this page</a> ' crlf ,
  347.       ' (but wait until processing is complete and  all the status info has been written!) ' crlf ,
  348.       ' </blockquote> ' crlf
  349.       rcode=multi_send(aa)
  350. end /* do */
  351.  
  352.  
  353.  if asize='' then asize=length(body)
  354.  hrefs.0=1
  355.  hrefs.1='http://'server'/'||strip(request,'l','/')
  356.  hrefs.1.!type='text/html' ; hrefs.1.!size=asize ; hrefs.1.!refered='!starter-URL!'
  357.  hrefs.1.!status=0 ; hrefs.1.!nrefs=0 ; hrefs.1.!queried=0
  358.  hrefs.1.!nlinks=0
  359.  hrefs.1.!reflist=''  ; hrefs.1.!appearin='' ; hrefs.1.!Imglist=''
  360.  
  361.  arf=strip(translate(hrefs.1))
  362.  hrefs.!list.arf=1
  363.  
  364. /* check for robots.txt, and augment exclusion list */
  365. if check_robot=1 then do
  366.    stuff=get_url('GET',server,'ROBOTS.TXT',isauth) 
  367.    if stuff<>'' then do
  368.       call extracts 
  369.       parse var response . hcode .
  370.       if datatype(hcode)<>'NUM' then hcode=400
  371.       if hcode>199 & hcode<300 then do             
  372.          exclusion_list2=add_robot(exclusion_list,body)
  373.          aa='<p><b>ROBOTS.TXT found.<br></b> Modified exclusion_list= <tt>' exclusion_list2 '</tt>'
  374.          rc=multi_send(aa)
  375.       end /* do */
  376.    end
  377. end /* do */
  378.  
  379.  
  380. if standalone <>0 then do  /* suppress output of  status info (standalone mode) */
  381.     call lineout outfilex,' <br> <a href="#SUMMARY">Skip to Results </a> '
  382. end
  383.  
  384. /* now recurse down list of links (in hrefs list ================ */
  385. /* start with the "starter-url" */
  386.  
  387. mustpre=rooturl
  388. if baseonly=1 then mustpre=base
  389. mustpre=strip(translate(mustpre))
  390. rc=multi_send('<HR><H2>Traversing links  -- displaying status information ...</h2> <ul>')
  391. if rc<0  then return ''
  392.  
  393. /* Prepare for thread launchs... clean up quque */
  394.  
  395. myqueue2=translate(myqueue||'_HREF')
  396. oo=rxqueue('c',myqueue2)
  397. if oo<>myqueue2 then foo=rxqueue('d',oo)
  398. foy=rxqueue('s',myqueue2)
  399. ii=queued()
  400. do ii0=1 to ii ;   pull gg ; end 
  401.  
  402. liminact=extract2('limittimeinactive')
  403.  
  404. /* do this batch of hrefs */
  405. do forever
  406.  
  407.    call get_Url_q        /* launch, and get whatever may be on queue */
  408.    if result=-1 then return ''              /* client killed connection */
  409.    if result=0 then do
  410.       call syssleep 1
  411.       iterate         /* nothing to do, loop */
  412.    end
  413.    if result=-2 then leave          /* all done! */
  414.  
  415. /* if here, stuff and anind have been set as globals */
  416.    if stuff="" then do
  417.      rc=multi_send(crlf'<br> No body! ' hrefs.anind)
  418.      if rc<0 then return ' '
  419.      iterate
  420.   end
  421.   
  422.   call extracts                   /* get body variable  */
  423.   rc=multi_send('<br><tt>'anind')</tt> Length ('hrefs.anind')=== '||length(body))
  424.   if rc<0 then return ''
  425.   nowimg=imgs.0 ; nowhref=hrefs.0
  426.   parse var hrefs.anind . '//' .'/' request 
  427.   ijoe=lastpos('/',hrefs.anind)
  428.   base=delstr(hrefs.anind,ijoe+1)
  429.   oo=findurls(body,base,rooturl,request,anind)   /* find links in this document */
  430.   hrefs.anind.!nlinks=oo
  431.   hrefs.anind.!queried=1
  432.   if nowimg=imgs.0 & nowhref=hrefs.0 then iterate /* no new links */
  433.   oo=query_types(rooturl,nowimg+1,nowhref+1,hrefs.anind,anind)         /* determine types of these links*/
  434.   if queryonly=1 then leave                             /* finish after querying starter-url */
  435. end /* do */
  436. rc=multi_send('</ul>')
  437.  
  438. /* double check? */
  439. if double_check<>0 then call double_check_it
  440.  
  441. /* get text/plain descriptions */
  442. if queryonly=0 & make_descrip=3 then call make_text_descrip
  443.  
  444.  
  445. /* !!!!!  At this point, we start a new document (if use_multi=1 ) 
  446.           If use_multi=2, save results to temporary file    */
  447.  
  448. doing_results=hold_doing                /* created at top of program */
  449. if use_multi=1 then do
  450.    rc=multi_send('</body></html>',,'SE') /* close first part */
  451. end
  452. if use_Multi>0 then do
  453.    user_intro1=''
  454. /* send start of part2 */
  455.    if user_intro1b<>'' then do
  456.       afil=stream(user_intro1b,'c','query exists')
  457.       if afil='' then do
  458.          user_intro1=''
  459.       end
  460.       else do
  461.          foo=stream(afil,'c','open read')
  462.          user_intro1=charin(afil,1,chars(afil))
  463.          foo=stream(afil,'c','close')
  464.       end
  465.     end
  466.     if user_intro1='' then do
  467.        foo='<html><head><title> Results: CheckLink of ' server ' </title></head><body 'back_2'>'
  468.        if linkfile<>'' then foo=foo||'<A name="TOP">'jump_bar(linkfile,cheklink_htm)'</a>'
  469.        user_intro1=foo||'<h1 align="center"> CheckLink results </h1>' crlf 
  470.     end
  471.     if use_multi=1 then
  472.        rcode=multi_send(user_intro1,'text/html','ES')
  473.     else
  474.        rcode=multi_send(user_intro1)
  475.  
  476. /* repeat basic info */
  477.    rc=multi_send(intro2)
  478.    if rc<0 then do 
  479.       call outdone
  480.       return ' '
  481.    end /* do */
  482.  
  483.    rc=multi_send(intro3)
  484.  
  485. end             /* if not multi part, don't do any of the above */
  486.  
  487. /* ready to write tables of results */
  488.  
  489. fop='<hr> '
  490. if use_multi=0 then 
  491.   fop=fop||'<center><h2>Anchors and Imgs</h2> </center>' crlf
  492. rc=multi_send(fop)
  493. if rc<0 then do 
  494.     call outdone
  495.     return ' '
  496. end /* do */
  497.  
  498.  
  499. call write_summary
  500. if result<0 then do
  501.    call outdone
  502.    return ' '
  503. end
  504.  
  505. /* do several sets of tables */
  506. do ut=1 to words(outtype)
  507.       aut=strip(word(outtype,ut))
  508.       typedo=wordpos(aut,'OK NOSITE NOURL OFFSITE x EXCLUDED ALL')
  509.       if typedo=0 then  do
  510.          typedo=wordpos(aut,'0 1 2 3 4 5 6')
  511.          if typedo=0 then iterate
  512.       end
  513.       tcode=strip(word('!OK 1 2 3 4 5 !ALL',typedo))
  514.       foo=write_img_href(1,1,tcode)
  515.       if foo<0 then do 
  516.            call outdone       end /* do */
  517.            return ' '
  518.       end
  519. end /* do */
  520.  
  521.  
  522. /* write column descriptions */
  523. vop='<hr><a name="DESCRIBE"><h3>Description of Columns</h3></a>'crlf'<dl>'crlf
  524. vop=vop' Note that each row of the tables describes a "resource on the web-tree", ', 
  525.        ' where "resources" can be documents, images, scripts, etc. <p>'crlf
  526. if linkfile<>'' then 
  527.    vop=vop'<dt><u>?</u> <dd> Examine links <b>to</b> and <u>from</u> this resource 'crlf
  528. vop=vop'<dt> Image Location, or URL <dd> A link to the resource, as encounted while building ' ,
  529.        ' the web-tree. If the resource is inaccessible, it will ',
  530.        ' just be underlined; but the immediately preceding number will be linked ' ,
  531.        ' to the resource (so as you can double check) '
  532. vop=vop'<dt><b>#</b><dd><em>for text/html documents...</em> Number of links contained in this html document ' crlf
  533. vop=vop'<dt>Mimetype <dd> The mime type of the resource' crlf
  534. vop=vop'<dt>Size or error code <dd>The size (in bytes) of the resource (as reported ' crlf ,
  535.        ' by it''s server); or an error code indicating why the resource could not be accessed. ' crlf ,
  536.        '<br> Error codes include: <menu> ' crlf ,
  537.       '<li><tt>Server n.a.</tt> :  Server was inaccessible. Since this might be a '  ,
  538.       ' temporary condition (say, if the server was exceptionally busy), you probably should ' crlf ,
  539.       ' double-check these links (i.e.; click on the number immediately preceding the URL)  ' crlf ,
  540.       ' <li><tt>Missing resource </tt> The server reports that this link is unavailable ' crlf ,
  541.       '<li><tt>Off-site :</tt> This URL is off-site, and off-site URLs were not checked ' crlf ,
  542.       '<li><tt>Excluded </tt>: This is a CGI-BIN, or some other, "excluded" URL that are not checked ' crlf ,
  543.       '</menu> ' crlf
  544.       
  545. vop=vop'<dt>Number of references <dd>Number of times that links (URLs) pointing to <b>this resource</b> </u> appeared  ' crlf ,
  546.         'in other html documents (on this web-tree) ' crlf
  547. vop=vop'<dt>First reference <dd>Link to an HTML document that contains a URL pointing to this resource 'crlf  ,
  548.        ' (the first one encountered when building the web-tree) </dl>' crlf
  549. vop=vop'<p><a href="#TOP">Top of document</a> 'crlf
  550.  
  551. oo=time('e')
  552. vop=vop'<hr>Elapsed time= '||addcomma(oo,1) ' seconds.' crlf ,
  553.     ' Total bytes downloaded='ADDCOMMA(totgot)||crlf
  554.  
  555. rcode=multi_send(vop,,'EE')
  556.  
  557. if use_multi=2 then do
  558.    parse var doing_results . dd1
  559.    og=filespec('n',dd1)
  560.    doing_results=1       /* 'VAR, but not lineout */
  561.    vop=vop' <hr> <a name="BOTTOM"> View the </a> <a href="/CHEKLINK?result='og'"> results tables? </a>'crlf
  562. end /* do */
  563.  
  564. vop=vop'</body></html>'
  565.  
  566. if use_multi=1 then 
  567.         rcode=multi_send(vop,,'EE')
  568. else
  569.         rcode=multi_send(vop,,'1E')
  570.  
  571. call outdone 1
  572. return '200 '||extract2('bytessent')
  573.  
  574. /********** END OF MAIN ***************/
  575.  
  576.  
  577.  
  578. /****/
  579. outdone:
  580. parse arg isdone
  581.    if use_multi=2 then do
  582.        parse var doing_results d1 d2 ; d2=strip(d2)
  583.        call lineout d2
  584.        if isdone<>1 then foo=sysfiledelete(d2)  /* premature error */
  585.    end /* do */
  586.  
  587.    if standalone<>0 then do
  588.       call lineout outfilex
  589.       say 
  590.       say bold " Reminder: Result tables were written to "||stream(outfilex,'c','query exists')||normal
  591.     end
  592.  
  593.    if outfilel<>'' & isdone=1 then do
  594.         aa=stream(outfilel,'c','close')
  595.         hh=cvtails(imgs,kins)          /* drop some superfulous stuff */
  596.         if hh>0 then do
  597.            do nz=1 to kins.0
  598.                pup=translate(kins.nz)
  599.                if abbrev(pup,'!LIST.')=1 | right(pup,7)='.!BIRTH' |  ,
  600.                          right(pup,8)='.!STATUS' | right(pup,6)='.!SOCK'  | ,
  601.                          right(pup,9)='.!REFERED'    then 
  602.                   drop imgs.pup
  603.            end /* do */
  604.         end /* do */
  605.         a1=cvcopy(imgs,bbg.!imgs)
  606.  
  607.         hh=cvtails(hrefs,kins)          /* drop some superfulous stuff */
  608.         if hh>0 then do
  609.            do nz=1 to kins.0
  610.                pup=translate(kins.nz)
  611.                if abbrev(pup,'!LIST.')=1 | right(pup,7)='.!BIRTH' | ,
  612.                        right(pup,8)='.!STATUS' | right(pup,6)='.!SOCK' | ,
  613.                        right(pup,9)='.!REFERED' then
  614.                     drop hrefs.pup
  615.            end /* do */
  616.         end /* do */
  617.  
  618. /* add name */
  619.         if name='' then do
  620.             parse var hrefs.1 . '//' sname '/' rname
  621.             treename='Starting at /'rname ' on ' sname 
  622.         end /* do */
  623.         hrefs.!name=treename
  624.  
  625.         a2=cvcopy(hrefs,bbg.!hrefs)
  626.         if pos('.',outfilel)=0 then outfilel=outfilel'.stm'
  627.         a3=cvwrite(outfilel,BBG)
  628.         IF STANDALONE<>0 then DO
  629.           if (a1*a2*a3)=0 then 
  630.             say " Warning: could not save IMGS and HREFS to " outfilel
  631.           else
  632.              SAY BOLD "Saved images and anchors  to " normal outfilel
  633.         END
  634.    end /* do */
  635.  
  636.    return 1
  637.  
  638.  
  639. /*********************/
  640. /* set up the doing_results variable -- perhaps with a temp file name
  641. if use-multi=2 */
  642. do_doing:procedure
  643. parse arg ldir,bb
  644.  
  645. if bb<2 then return 1
  646. lfile=dostempname(ldir||'LNKCH???.HTM')
  647. return '2 'lfile
  648.  
  649.  
  650.  
  651. /****************/
  652. /* make a jumpbar */
  653. jump_bar:procedure expose crlf
  654. parse arg aff,af2
  655. foo='<a href="#SUMMARY">Summary</a>   ||   ' crlf ,
  656.     '<a href="#DESCRIBE">Description</a>   ||   ' crlf  ,
  657.     '<a href="/CHEKLNK2?linkfile='aff'&entrynum=1">Synopsis of starter-URL</a> || ' crlf ,
  658.     '<a href="/CHEKLNK2?linkfile='aff'&entrynum=0">View all HTMLs in this web-tree </a> || ' crlf 
  659. if af2<>'' then
  660.     foo=foo'<a href="'af2'">Create another web-tree </a>   || ' 
  661.  
  662. return foo
  663.  
  664. /*******************/
  665. /* write summayr info */
  666. write_summary:
  667.  
  668.  ioki=0
  669.  do jj=1 to imgs.0
  670.     if imgs.jj.!size>=0 then ioki=ioki+1
  671.  end /* do */
  672.  
  673.  iok.0=0;iok.1=0;iok.2=0;iok.3=0;iok.4=0;iok.5=0;iok.!html=0
  674.  do mm=1 to hrefs.0
  675.     select 
  676.         when hrefs.mm.!size>=0 then do 
  677.           iok.0=iok.0+1
  678.           if translate(strip(hrefs.mm.!type))='TEXT/HTML' then iok.!html=iok.!html+1
  679.         end /* do */
  680.         otherwise do
  681.           if datatype(hrefs.mm.!size)='NUM' then do
  682.              ool=abs(hrefs.mm.!size)
  683.              iok.ool=iok.ool+1
  684.           end
  685.         end             /* otherwise */
  686.      end                /* select  */
  687.   end                   /* hrefs. */
  688.  
  689.  
  690. /* NOW display this summary */
  691.  
  692. codes.1='<u>Server not available</u> '
  693. codes.2='<b>No such resource on server</b>'
  694. codes.3='Off-site (did not check) '
  695. codes.4=''
  696. codes.5='Excluded selectors (did not check) '
  697.  
  698.  
  699. anames.!OK='OKS'
  700. anames.1='NOSITE'
  701. anames.2='NOURL'
  702. anames.3='OFFSITE'
  703. anames.4=''
  704. anames.5='EXCLUDED'
  705. anames.!ALL='ALL'
  706.  
  707. vl1='OK NOSITE NOURL OFFSITE x EXCLUDED ALL'
  708.  
  709. fop='<center><a name="SUMMARY"><h3>Summary of Results </h3></a></center>' crlf ,
  710.     ' Starter-URL: <b> ' aurl '</b> <p>' crlf ,
  711.      '<blockquote><tt><b>Title</b>:' hrefs.1.!title '</tt>'  crlf
  712.      if symbol('HREFS.1.!DESCRIP')='VAR' then
  713.         fop=fop'<br><b>Description</b>:' hrefs.1.!descrip '</tt>'  crlf
  714.      fop=fop||'</blockquote><B>Images</b>: 'ioki', of ' imgs.0 ', images were readable.'  crlf 
  715.  
  716. if pos('ALL',outtype)+pos('6',outtype)>0 then
  717.       fop2='<a href="#ALL">Anchors</a>:'
  718.  else
  719.       fop2='<B>Anchors</b>:'
  720.  
  721. fop=fop||' <p>'fop2' of ' hrefs.0' anchors:' crlf 
  722.  
  723. if pos('OK',outtype)+pos('0',outtype)>0 then
  724.       fop2='<a href="#OKS">obtainable</a>'
  725.  else
  726.       fop2='obtainable'
  727.  
  728. fop=fop||'<ul> <li> 'iok.0 ' were 'fop2' ( text/html='iok.!html')' crlf
  729.  
  730. do mmk=1 to 5
  731.       if mmk=4  then iterate
  732.       aa2=word('OK NOSITE NOURL OFFSITE x EXCLUDED ALL',mmk+1)
  733.       if wordpos(aa2,outtype)+wordpos(mmk,outtype)>0 then
  734.            ttc='<a href="#'||anames.mmk'">'codes.mmk'</a>'
  735.       else      
  736.            ttc=codes.mmk
  737.       fop=fop||'<li>' ttc ': ' iok.mmk
  738. end
  739. fop=fop'</ul>'
  740. rc=multi_send(fop)
  741. if rc<0 then return -1
  742. return 1
  743.  
  744.  
  745. /************/
  746. /* ADD COMMAS TO A NUMBER */
  747. addcomma:procedure
  748. parse arg aval,ndec
  749. parse var aval p1 '.' p2
  750.  
  751. if ndec='' then do
  752.    p2=''
  753. end
  754. else do
  755.    p2='.'||left(p2,ndec,'0')
  756. end /* do */
  757.  
  758. plen=length(p1)
  759. p1new=''
  760. do i=1 to 10000 while plen>3
  761.    p1new=','right(p1,3)||p1new
  762.    p1=delstr(p1,plen-2)
  763.    plen=plen-3
  764. end /* do */
  765.  
  766. return p1||p1new||p2
  767.  
  768.  
  769. /******************************/
  770. /* parse a robots.txt file, and add appropriate disallows to the exclusion_list.
  771. The algorithim:
  772. 1 ignore # lines (comments)
  773. 2a look for user-agent: checklink lines
  774. 2b if none, look for user-agent:*  lines
  775. 3 if 2a or 2b don't work, exit with no changes
  776. 4 otherwise, from the look for disallow lines going starting from 
  777.   the user-agent line, until the first empty line (use 0a as line delimiter,
  778.   and throw away the 0d)
  779. 5 take asel from each disallow: asel, add a * to the end, and append to
  780.   exclusion_list
  781.  
  782. ---------------
  783. # samples robots.txt -- will add cgi-* to exclusion_list
  784.  
  785. user-agent: mozilla
  786. Disallow: /samples
  787. Disallow: /stuff/
  788.  
  789. #user-agent: checklink
  790. user-agent:gizmo
  791. disallow:fes/
  792.  
  793. user-agent:*
  794. disallow:cgi-
  795.  
  796. ---------------
  797.  
  798. */
  799. add_robot:procedure expose standalone verbose 
  800. parse arg exlist,abody
  801.  
  802. cr='0a'x
  803. nn=0
  804. do forever
  805.   if abody='' then leave
  806.   parse var abody al1 (cr) abody
  807.   al1=strip(al1,,'0d'x)
  808.   if al1='#' then iterate
  809.   parse var al1 al1a '#' .
  810.   nn=nn+1
  811.   lins.nn=al1a
  812. end
  813. if nn=0 then return exlist /* empty, so ignore */
  814.  
  815. lins.0=nn
  816.  
  817. /* look for CHECKLINK or *  user-agent */
  818. iat=0
  819. do mm=1 to lins.0
  820.    al=strip(lins.mm)
  821.    if abbrev(translate(al),'USER-AGENT')=0 then iterate
  822.    parse var al . ':' dagent ; dagent=translate(strip(dagent))
  823.    if abbrev(dagent,'CHECKLINK')=1 then do
  824.        iat=mm
  825.        leave
  826.    end
  827.    if dagent='*' then do
  828.        iat=mm
  829.    end /* do */
  830. end /* do */
  831.  
  832. exlist2=''
  833. if iat=0 then return exlist /* no matching user-agent */
  834. do mm=iat+1 to lins.0
  835.   al=translate(strip(lins.mm))
  836.   if al='' then leave   /* blank line signals end of "record" */
  837.   if abbrev(al,'DISALLOW')<>1 then iterate
  838.   parse var al  . ':' dasel ; dasel=strip(dasel)
  839.   if dasel<>'' then exlist2=exlist2||' '||dasel||'* '
  840. end /* do */
  841.  
  842. do ik=1 to words(exlist2)
  843.    aw=strip(word(exlist2,ik))
  844.    aw=strip(aw,'l','/')
  845.    exlist=exlist' 'aw
  846. end /* do */
  847.  
  848. return exlist
  849.  
  850.  
  851. /**************************************/
  852. /* multi threaded GETs */
  853. get_url_q:
  854.  
  855. lastgoo=basesec
  856. nowactive=0
  857. alldone=0
  858. stuff=''
  859. lastgoo=time('e')
  860. ii1=hrefs.!start
  861.  
  862. do oj=hrefs.!start to hrefs.0                   /* keep maxatonce_get threads busy */
  863.      nowsec=time('e')
  864.  
  865.      if hrefs.oj.!status=2 then do     /* done */
  866.          alldone=alldone+1 ; iterate
  867.          if oj=ii1  then ii1=oj+1
  868.      end /* do */
  869.      if hrefs.oj.!status=1 then do      /*being done */
  870.           nowactive=nowactive+1
  871.           iterate
  872.      end /* do */
  873.      iss=is_this1(oj)           /* shouldn't do ? */
  874.  
  875.      if iss<0 then return -1      /* client killed the connection */
  876.      if iss=0 then do
  877.         hrefs.oj.!status=2      /* can't be done */
  878.         iterate 
  879.      end /* do */
  880.  
  881.      if nowactive>(maxatonce_get) then leave
  882.      tmp=get_url_0('GET',hrefs.oj,isauth,oj,myqueue2)
  883.      parse var tmp hrefs.oj.!sock','.
  884.      IF VERBOSE>2 THEN say ' CheckLink:GET 'hrefs.oj ' on socket: ' hrefs.oj.!sock
  885.      rc=multi_send('<li><b>  checking:</b> ' hrefs.oj)
  886.      if rc<0 then return -1
  887.      hrefs.oj.!status=1
  888.      hrefs.oj.!birth=nowsec
  889.      nowactive=nowactive+1
  890. end                  /* or leave when at end of hrefs. */
  891.  
  892. a=rxqueue('s',myqueue2)
  893. nq=queued()     
  894. hrefs.!start=ii1
  895.  
  896. if alldone=hrefs.0 then return -2   /* all done with  hrefs */
  897.  
  898. if (nowsec-lastgoo)> min(15,(0.75*liminact)) then do   /* intermediate status report? */
  899.        rc=multi_send('<br>   ...('alldone' of 'hrefs.0')')
  900.        if rc<0 then return 0
  901.        lastgoo=nowsec
  902. end /* do */
  903.  
  904.      
  905. /* any new results? */
  906. if nq=0 then do      /* nothing to do -- so check for old age */
  907.       do bb=1 to hrefs.0
  908.          if hrefs.bb.!status=1 then do   /* it's active, check age */
  909.              if (nowsec-hrefs.bb.!birth)>maxage2 then do 
  910.                 ssk=hrefs.bb.!sock
  911.                 rcc0=sockshutdown(ssk,2)
  912.                 rcc=sockclose(ssk)
  913.                 hrefs.bb.!status=2   /* done */
  914.                 if verbose>2 then
  915.                    say 'CheckLink: Killing socket 'ssk '(' hrefs.mm
  916.                 hrefs.mm.!size=-1     /* server n.a. */
  917.              end                      /* do >maxage */
  918.          end                    /* do status=1 */
  919.       end                       /* do bb */
  920.       return 0         
  921.  end /* do  nq=0*/
  922.  
  923. /* if here, something in queue */
  924.    
  925.    parse pull yow
  926.   totgot=totgot+length(yow)
  927.  
  928.    anid=left(yow,25)
  929.    parse var anid atrans','anind ; atrans=strip(atrans); anind=strip(anind)
  930.    if anind>hrefs.0 then return 0 /* ignore  -- impossible hrefs index */
  931.    if transaction<>atrans then return 0 /* ignore -- bad transaction */
  932.  
  933.    hrefs.anind.!status=2              /* mark that this is done */
  934.  
  935.    stuff=substr(yow,26)
  936.    return 1
  937.  
  938.  
  939. /**************************************/
  940. /* double check n.a. servers */
  941. make_text_descrip:procedure  expose myqueue hrefs. stuff imgs. isauth siteonly  verbose ,
  942.        standalone query_method mustpre dscmax ,
  943.        exclusion_list2 exclusion_list maxatonce maxage  totgot thread_string badsites. doing_results
  944.  
  945.  
  946. liminact=extract2('limittimeinactive')
  947. tocheck.0=0
  948. /* find all local text/plain hrefs to lookup; copy to the tocheck array */
  949. drop tocheck.
  950. tocheck.0=0
  951. do mm=1 to hrefs.0
  952.    att=strip(translate(hrefs.mm.!type))
  953.    if att<>'TEXT/PLAIN' then iterate
  954.    if abbrev(translate(hrefs.mm),mustpre)<>1 then iterate  /* offsite or offdir */
  955.  
  956. /* check this href */
  957.    uu=tocheck.0+1
  958.    tocheck.uu=hrefs.mm
  959.    tocheck.uu.!indx=mm
  960.    tocheck.uu.!status=0  /* 0=not done,1=being done, 2=done */
  961.    tocheck.0=uu
  962. end
  963. if tocheck.0=0 then return 1  
  964.  
  965. if verbose>2 then say 'Checklink. ' tocheck.0 ' text/plain descriptions  '
  966. rc=multi_send('<br>Checklink. ' tocheck.0 ' text/plain descriptions  ')
  967. if rc<0 then return 0
  968.  
  969. /* check all of the "tochecks"  -- do atonce "threads" at a time */
  970. nowactive=0
  971. basesec=time('e') ; lastgoo=basesec
  972. alldone=0
  973.  
  974. /* Prepare for thread launchs... clean up quque */
  975. foy=rxqueue('s',myqueue)
  976. ii=queued()
  977. do ii0=1 to ii ;   pull gg ; end 
  978.  
  979. do forever            /* until all tochecks are complete or timedout */
  980.  
  981.    nq=queued()          
  982.    nowsec=time('e')
  983.    alldone=0
  984.  
  985.    do oj=1 to tocheck.0     /* keep maxatonce threads busy */
  986.       if nowactive>maxatonce then leave
  987.       astat=tocheck.oj.!status
  988.       if astat=2 then alldone=alldone+1
  989.       if astat<>0 then iterate    /* active or done, ignore */
  990.  
  991.       tmp=get_url_0('DSCGET',tocheck.oj,isauth,oj,myqueue)
  992.       parse var tmp tocheck.oj.!sock','tocheck.oj.!trans','.
  993.       IF VERBOSE>2 THEN say ' CheckLink: text/plain description 'tocheck.oj ' on socket: ' tocheck.oj.!sock
  994.       tocheck.oj.!status=1
  995.       tocheck.oj.!birth=nowsec
  996.  
  997.       nowactive=nowactive+1
  998.    end                  /* or leave when at end of tocheck */
  999.  
  1000.    if alldone=tocheck.0 then leave   /* all done with tocheck hrefs */
  1001.    if (nowsec-lastgoo)> min(15,(0.75*liminact)) then do   /* intermediate status report? */
  1002.        rc=multi_send('<br>   ...('alldone' of 'tocheck.0')')
  1003.        if rc<0 then return 0
  1004.        lastgoo=nowsec
  1005.    end /* do */
  1006.  
  1007.  
  1008. /* any new results? */
  1009.    if nq=0 then do      /* nothing to do -- so check for old age */
  1010.       do bb=1 to tocheck.0
  1011.          if tocheck.bb.!status=1 then do   /* it's active, check age */
  1012.              if (nowsec-tocheck.bb.!birth)>maxage then do 
  1013.                 ssk=tocheck.bb.!sock
  1014.                 rcc=sockshutdown(ssk,2)
  1015.                 rcc=sockclose(ssk)
  1016.                 tocheck.bb.!status=2   /* done */
  1017.                 mm=tocheck.bb.!indx
  1018.                 if verbose>2 then
  1019.                    say 'CheckLink: Killing socket 'ssk '(' hrefs.mm
  1020.                 nowactive=nowactive-1  /* not active any more! */
  1021.              end /* do >maxage */
  1022.          end /* do status=1 */
  1023.       end /* do bb */
  1024.       call syssleep 1           /* sleep for a second */
  1025.       iterate                   /* and back to top of forever loop */
  1026.    end /* do  nq=0*/
  1027.  
  1028. /* if here, something in queue */
  1029.    parse pull yow
  1030.    totgot=totgot+length(yow)
  1031.  
  1032.    anid=left(yow,25)
  1033.    parse var anid atrans','anind ; atrans=strip(atrans); anind=strip(anind)
  1034.    if anind>tocheck.0 then iterate /* ignore  -- impossible tocheck index */
  1035.    if tocheck.anind.!trans<>atrans then iterate /* ignore -- bad transaction */
  1036.  
  1037.    tocheck.anind.!status=2              /* mark that this is done */
  1038.    nowactive=nowactive-1  /* not active any more! */
  1039.    stuff=substr(yow,26)
  1040.    mm=tocheck.anind.!indx
  1041.  
  1042. /* process stuff */
  1043.   if stuff="" then iterate
  1044.  
  1045. /* extract type and length */
  1046.    call extracts                   /* create headers. and body */
  1047.    parse var response ht num amess
  1048.  
  1049.   if num<200 | num>399 then iterate
  1050.  
  1051.   hrefs.mm.!descrip=translate(left(body,min(dscmax,length(body))),' ','0d0a0009'x)
  1052.  
  1053. end             /* OF TOCHECKS */
  1054. return 1
  1055.  
  1056.  
  1057.  
  1058. /*****************************/
  1059. /* a text/html to be GETten */
  1060. is_this1:procedure expose hrefs. mustpre standalone verbose doing_results
  1061. parse arg jj
  1062.  
  1063. if hrefs.jj.!size<0 then return 0       /* not on site */
  1064.  
  1065. if translate(hrefs.jj.!type)<>'TEXT/HTML' then do
  1066.        rc=multi_send('<li> <em>'jj') </em> Not text/html: ' hrefs.jj '=' hrefs.jj.!type)
  1067.        if rc<0 then return -1
  1068.        return 0
  1069. end /* do */
  1070.  
  1071. /* compare against root or baseurl */
  1072. if abbrev(translate(hrefs.jj),mustpre)=0 then do
  1073.        rc=multi_send('<li> <em> ' JJ ') </em> Not checking contents: ' hrefs.jj)
  1074.        if rc<0 then return -1
  1075.        return 0
  1076. end /* do */
  1077. return 1
  1078.  
  1079.  
  1080. /*******************/
  1081. /* head to find out types */
  1082. query_types:procedure expose myqueue hrefs. stuff imgs. isauth siteonly  verbose standalone query_method ,
  1083.             exclusion_list2 exclusion_list maxatonce maxage  totgot thread_string badsites. doing_results
  1084.  
  1085. parse upper arg daroot,img1,href1,paurl,anind
  1086.  
  1087. tmpanind=anind
  1088. liminact=extract2('limittimeinactive')
  1089.  
  1090. if href1<=hrefs.0 then call query_types_a
  1091.  
  1092. anind=tmpanind
  1093. if img1<=imgs.0 then call query_types_i
  1094.  
  1095. return  1
  1096.  
  1097.  
  1098. /**************************************/
  1099. /* query types of anchors */
  1100. query_types_a:
  1101.  
  1102. rc=multi_send('<br> Getting header info (for anchors ' href1 ' to ' hrefs.0 ')' )
  1103. IF RC<0 then EXIT ''
  1104.  
  1105. tocheck.0=0
  1106. /* find all hrefs to lookup; copy to the tocheck array */
  1107. do mm=href1 to hrefs.0
  1108.    hrefs.mm.!type='n.a.' ; hrefs.mm.!size=-1 ; hrefs.mm.!refered=paurl
  1109.    hrefs.mm.!status=0 ; hrefs.mm.!nrefs=1 ; hrefs.mm.!queried=0
  1110.    hrefs.mm.!nlinks=0  
  1111.    hrefs.mm.!appearin=anind
  1112.    hrefs.mm.!imglist='' 
  1113.    hrefs.mm.!reflist='' 
  1114.  
  1115. /* special size codes:
  1116.  -1 : server not available 
  1117.  -2 : no such resource on sever
  1118.  -3 : siteonly violation
  1119.  -4 : reserved
  1120.  -5 : excluded
  1121. */
  1122.  
  1123. /* suppress this link? */
  1124.    if siteonly=1 then do
  1125.       if abbrev(translate(hrefs.mm),daroot)=0 then do 
  1126.           hrefs.mm.!size=-3             
  1127.           iterate
  1128.       end /* do */
  1129.    end
  1130.    if exclusion_list||exclusion_list2<>'' then do
  1131.        parse var hrefs.mm . '//' . '/' arr
  1132.        if exclude_me(arr,exclusion_list,exclusion_list2,hrefs.mm,daroot)=1 then do
  1133.            hrefs.mm.!size=-5
  1134.            iterate 
  1135.        end
  1136.    end /* do */
  1137.  
  1138. /* is this server known to be down? */   
  1139.    parse var hrefs.mm '//' aserv '/' 
  1140.    aserv=translate(aserv)
  1141.    if datatype('BADSITES.'aserv)='NUM' then do
  1142.         if badsites.aserv>1 then do             /* check twice before marking as bad */
  1143.             hrefs.mm.!size=-1
  1144.             iterate
  1145.         end
  1146.    end /* do */
  1147.  
  1148. /* check this href */
  1149.    uu=tocheck.0+1
  1150.    tocheck.uu=hrefs.mm
  1151.    tocheck.uu.!indx=mm
  1152.    tocheck.uu.!status=0  /* 0=not done,1=being done, 2=done */
  1153.    tocheck.0=uu
  1154. end
  1155.  
  1156. /* check all of the "tochecks"  -- do atonce "threads" at a time */
  1157. nowactive=0
  1158. basesec=time('e') ; lastgoo=basesec
  1159. alldone=0
  1160.  
  1161. /* Prepare for thread launchs... clean up quque */
  1162. foy=rxqueue('s',myqueue)
  1163. ii=queued()
  1164. do ii0=1 to ii ;   pull gg ; end 
  1165.  
  1166. do forever            /* until all tochecks are complete or timedout */
  1167.  
  1168.    nq=queued()          
  1169.    nowsec=time('e')
  1170.    alldone=0
  1171.  
  1172.    do oj=1 to tocheck.0     /* keep maxatonce threads busy */
  1173.       if nowactive>maxatonce then leave
  1174.       astat=tocheck.oj.!status
  1175.       if astat=2 then alldone=alldone+1
  1176.       if astat<>0 then iterate    /* active or done, ignore */
  1177.  
  1178.       tmp=get_url_0(query_method,tocheck.oj,isauth,oj,myqueue)
  1179.       parse var tmp tocheck.oj.!sock','tocheck.oj.!trans','.
  1180.       IF VERBOSE>2 THEN say ' CheckLink: 'query_method ' 'tocheck.oj ' on socket: ' tocheck.oj.!sock
  1181.       tocheck.oj.!status=1
  1182.       tocheck.oj.!birth=nowsec
  1183.  
  1184.       nowactive=nowactive+1
  1185.    end                  /* or leave when at end of tocheck */
  1186.  
  1187.    if alldone=tocheck.0 then leave   /* all done with tocheck hrefs */
  1188.  
  1189.    if (nowsec-lastgoo)> min(15,(0.75*liminact)) then do   /* intermediate status report? */
  1190.        rc=multi_send('<br>   ...('alldone' of 'tocheck.0')')
  1191.        if rc<0 then return 0
  1192.        lastgoo=nowsec
  1193.    end /* do */
  1194.  
  1195.  
  1196. /* any new results? */
  1197.    if nq=0 then do      /* nothing to do -- so check for old age */
  1198.       do bb=1 to tocheck.0
  1199.          if tocheck.bb.!status=1 then do   /* it's active, check age */
  1200.              if (nowsec-tocheck.bb.!birth)>maxage then do 
  1201.                 ssk=tocheck.bb.!sock
  1202.                 rcc=sockshutdown(ssk,2)
  1203.                 rcc=sockclose(ssk)
  1204.                 tocheck.bb.!status=2   /* done */
  1205.                 mm=tocheck.bb.!indx
  1206.                 if verbose>2 then
  1207.                    say 'CheckLink: Killing socket 'ssk '(' hrefs.mm
  1208.                 hrefs.mm.!size=-1     /* server n.a. */
  1209.                 if datatype('BADSITES.'aserv)<>'NUM' then
  1210.                         badsites.aserv=1
  1211.                 else
  1212.                         badsites.aserv=badsites.aserv+1
  1213.                 nowactive=nowactive-1  /* not active any more! */
  1214.              end /* do >maxage */
  1215.          end /* do status=1 */
  1216.       end /* do bb */
  1217.       call syssleep 1           /* sleep for a second */
  1218.       iterate                   /* and back to top of forever loop */
  1219.    end /* do  nq=0*/
  1220.  
  1221. /* if here, something in queue */
  1222.    parse pull yow
  1223.    totgot=totgot+length(yow)
  1224.  
  1225.    anid=left(yow,25)
  1226.    parse var anid atrans','anind ; atrans=strip(atrans); anind=strip(anind)
  1227.    if anind>tocheck.0 then iterate /* ignore  -- impossible tocheck index */
  1228.    if tocheck.anind.!trans<>atrans then iterate /* ignore -- bad transaction */
  1229.  
  1230.    tocheck.anind.!status=2              /* mark that this is done */
  1231.    nowactive=nowactive-1  /* not active any more! */
  1232.    stuff=substr(yow,26)
  1233.    mm=tocheck.anind.!indx
  1234.  
  1235. /* process stuff */
  1236.   if stuff="" then do
  1237.       hrefs.mm.!size=-1
  1238.       if datatype('BADSITES.'aserv)<>'NUM' then
  1239.             badsites.aserv=1
  1240.       else
  1241.            badsites.aserv=badsites.aserv+1
  1242.       hrefs.mm.!type='n.a.' 
  1243.       iterate
  1244.    end /* do */
  1245.  
  1246. /* extract type and length */
  1247.    call extracts                   /* create headers. (there should not be a body( */
  1248.    parse var response ht num amess
  1249.  
  1250.   if num<200 | num>399 then do
  1251.       hrefs.mm.!size=-2
  1252.       iterate
  1253.   end
  1254.   hrefs.mm.!type='unknown'
  1255.   hrefs.mm.!size=0
  1256.  
  1257.   if wordpos('!CONTENT-TYPE',headers.0)>0 then do
  1258.     foo='!CONTENT-TYPE'
  1259.     hrefs.mm.!type=headers.foo
  1260.     hrefs.mm.!size=0
  1261.   end
  1262.   if wordpos('!CONTENT-LENGTH',headers.0)>0 then do
  1263.         foo='!CONTENT-LENGTH'
  1264.         hrefs.mm.!size=headers.foo
  1265.   end
  1266.  
  1267. end             /* OF TOCHECKS */
  1268. return 1
  1269.  
  1270.  
  1271. /**************************************/
  1272. /* query types of images */
  1273. query_types_i:
  1274.  
  1275. rc=multi_send('<br> Getting header info (for in-line images ' img1 ' to ' imgs.0 ')' )
  1276. IF RC<0 then EXIT ''
  1277.  
  1278. tocheck.0=0
  1279.  
  1280. /* find all hrefs to lookup; copy to the tocheck array */
  1281. do mm=img1 to imgs.0
  1282.    imgs.mm.!type='n.a.' ;  imgs.mm.!size=0 ;  imgs.mm.!refered=paurl
  1283.    imgs.mm.!nrefs=1
  1284.    imgs.mm.!appearin=anind
  1285.  
  1286. /* special size codes:
  1287.  -1 : server not available 
  1288.  -2 : no such resource on sever
  1289.  -3 : siteonly violation
  1290.  -4 : reserved
  1291.  -5 : exclusion violate
  1292. */
  1293.  
  1294. /* suppress this link? */
  1295.    if siteonly=1 then do
  1296.       if abbrev(translate(imgs.mm),daroot)=0 then do 
  1297.           imgs.mm.!size=-3             
  1298.           iterate
  1299.       end /* do */
  1300.    end
  1301.  
  1302.    if exclusion_list||exclusion_list2<>'' then do
  1303.        parse var imgs.mm . '//' . '/' arr
  1304.        if exclude_me(arr,exclusion_list,exclusion_list2,hrefs.mm,daroot)=1 then do
  1305.          imgs.mm.!size=-5
  1306.          iterate 
  1307.        end
  1308.    end /* do */
  1309.  
  1310. /* is this server known to be down? */   
  1311.    parse var imgs.mm '//' aserv '/' 
  1312.    aserve=translate(aserv)
  1313.    if datatype('BADSITES.'aserv)='NUM' then do
  1314.         if badsites.aserv>1 then do             /* check twice before marking as bad */
  1315.             imgs.mm.!size=-1
  1316.             iterate
  1317.         end
  1318.    end /* do */
  1319.  
  1320. /* check this href */
  1321.    uu=tocheck.0+1
  1322.    tocheck.uu=imgs.mm
  1323.    tocheck.uu.!indx=mm
  1324.    tocheck.uu.!status=0  /* 0=not done,1=being done, 2=done */
  1325.    tocheck.0=uu
  1326. end
  1327.  
  1328. /* check all of the "tochecks"  -- do atonce "threads" at a time */
  1329. nowactive=0
  1330. basesec=time('e') ; lastgoo=basesec
  1331. alldone=0
  1332.  
  1333. /* Prepare for thread launchs... clean up quque */
  1334. foy=rxqueue('s',myqueue)
  1335. ii=queued()
  1336. do ii0=1 to ii ;   pull gg ; end 
  1337.  
  1338. do forever            /* until all tochecks are complete or timedout */
  1339.  
  1340.    nq=queued()          
  1341.    nowsec=time('e')
  1342.    alldone=0
  1343.  
  1344.    do oj=1 to tocheck.0     /* keep maxatonce threads busy */
  1345.       if nowactive>maxatonce then leave
  1346.       astat=tocheck.oj.!status
  1347.       if astat=2 then alldone=alldone+1
  1348.       if astat<>0 then iterate    /* active or done, ignore */
  1349.  
  1350.       tmp=get_url_0(query_method,tocheck.oj,isauth,oj,myqueue)
  1351.       parse var tmp tocheck.oj.!sock','tocheck.oj.!trans','.
  1352.       IF VERBOSE>2 THEN say ' CheckLink: HEAD 'tocheck.oj ' on socket: ' tocheck.oj.!sock
  1353.       tocheck.oj.!status=1
  1354.       tocheck.oj.!birth=nowsec
  1355.  
  1356.       nowactive=nowactive+1
  1357.    end                  /* or leave when at end of tocheck */
  1358.  
  1359.    if alldone=tocheck.0 then leave   /* all done with tocheck imgss */
  1360.  
  1361.    if (nowsec-lastgoo)> min(15,(0.75*liminact)) then do   /* intermediate status report? */
  1362.        rc=multi_send('<br>   ...('alldone' of 'tocheck.0')')
  1363.        if rc<0 then return 0
  1364.        lastgoo=nowsec
  1365.    end /* do */
  1366.  
  1367.  
  1368. /* any new results? */
  1369.    if nq=0 then do      /* nothing to do -- so check for old age */
  1370.       do bb=1 to tocheck.0
  1371.          if tocheck.bb.!status=1 then do   /* it's active, check age */
  1372.              if (nowsec-tocheck.bb.!birth)>maxage then do 
  1373.                 ssk=tocheck.bb.!sock
  1374.                 rcc=sockshutdown(ssk,2)
  1375.                 rcc=sockclose(ssk)
  1376.                 tocheck.bb.!status=2   /* done */
  1377.                 mm=tocheck.bb.!indx
  1378.                 if verbose>2 then
  1379.                    say 'CheckLink: Killing socket 'ssk '(' imgs.mm
  1380.                 imgs.mm.!size=-1     /* server n.a. */
  1381.                 if datatype('BADSITES.'aserv)<>'NUM' then
  1382.                         badsites.aserv=1
  1383.                 else
  1384.                         badsites.aserv=badsites.aserv+1
  1385.  
  1386.                 nowactive=nowactive-1  /* not active any more! */
  1387.              end /* do >maxage */
  1388.          end /* do status=1 */
  1389.       end /* do bb */
  1390.       call syssleep 1           /* sleep for a second */
  1391.       iterate                   /* and back to top of forever loop */
  1392.    end /* do  nq=0*/
  1393.  
  1394. /* if here, something in queue */
  1395.    parse pull yow
  1396.    totgot=totgot+length(yow)
  1397.  
  1398.    anid=left(yow,25)
  1399.    parse var anid atrans','anind ; atrans=strip(atrans); anind=strip(anind)
  1400.    if anind>tocheck.0 then iterate              /* ignore  -- impossible tocheck index */
  1401.    if tocheck.anind.!trans<>atrans then iterate /* ignore -- bad transaction */
  1402.  
  1403.    tocheck.anind.!status=2              /* mark that this is done */
  1404.    nowactive=nowactive-1  /* not active any more! */
  1405.    stuff=substr(yow,26)
  1406.    mm=tocheck.anind.!indx
  1407.  
  1408. /* process stuff */
  1409.   if stuff="" then do
  1410.       imgs.mm.!type='n.a.'  ; imgs.mm.!size=-1
  1411.       if datatype('BADSITES.'aserv)<>'NUM' then
  1412.               badsites.aserv=1
  1413.       else
  1414.              badsites.aserv=badsites.aserv+1
  1415.       iterate
  1416.    end /* do */
  1417.  
  1418. /* extract type and length */
  1419.    call extracts                   /* create headers. (there should not be a body( */
  1420.    parse var response ht num amess
  1421.  
  1422.   if num<200 | num>399 then do
  1423.       imgs.mm.!size=-2
  1424.       iterate
  1425.   end
  1426.  
  1427.   imgs.mm.!type='unknown'
  1428.   imgs.mm.!size=0
  1429.  
  1430.   if wordpos('!CONTENT-TYPE',headers.0)>0 then do
  1431.     foo='!CONTENT-TYPE'
  1432.      imgs.mm.!type=headers.foo
  1433.      imgs.mm.!size=0
  1434.   end
  1435.   if wordpos('!CONTENT-LENGTH',headers.0)>0 then do
  1436.     foo='!CONTENT-LENGTH'
  1437.     imgs.mm.!size=headers.foo
  1438.   end
  1439.  
  1440. end             /* OF TOCHECKS */
  1441.  
  1442. return 1
  1443.  
  1444.  
  1445. /**************************************/
  1446. /* double check n.a. servers */
  1447. double_check_it:procedure  expose myqueue hrefs. stuff imgs. isauth siteonly  verbose ,
  1448.        standalone query_method ,
  1449.        exclusion_list2 exclusion_list maxatonce maxage  totgot thread_string badsites. doing_results
  1450.  
  1451.  
  1452. liminact=extract2('limittimeinactive')
  1453.  
  1454. tocheck.0=0
  1455. /* find all hrefs to lookup; copy to the tocheck array */
  1456. drop tocheck.
  1457. tocheck.0=0
  1458. do mm=1 to hrefs.0
  1459.   if hrefs.mm.!size<>-1 then iterate
  1460.  
  1461. /* check this href */
  1462.    uu=tocheck.0+1
  1463.    tocheck.uu=hrefs.mm
  1464.    tocheck.uu.!indx=mm
  1465.    tocheck.uu.!status=0  /* 0=not done,1=being done, 2=done */
  1466.    tocheck.0=uu
  1467. end
  1468. if tocheck.0=0 then return 1  
  1469.  
  1470. if verbose>2 then say 'Checklink. Double checking ' tocheck.0  ' server n.a. URLS.'
  1471. rc=multi_send('<br>Double checking 'tocheck.0)
  1472. if rc<0 then return 0
  1473.  
  1474. /* check all of the "tochecks"  -- do atonce "threads" at a time */
  1475. nowactive=0
  1476. basesec=time('e') ; lastgoo=basesec
  1477. alldone=0
  1478.  
  1479. /* Prepare for thread launchs... clean up quque */
  1480. foy=rxqueue('s',myqueue)
  1481. ii=queued()
  1482. do ii0=1 to ii ;   pull gg ; end 
  1483.  
  1484. do forever            /* until all tochecks are complete or timedout */
  1485.  
  1486.    nq=queued()          
  1487.    nowsec=time('e')
  1488.    alldone=0
  1489.  
  1490.    do oj=1 to tocheck.0     /* keep maxatonce threads busy */
  1491.       if nowactive>maxatonce then leave
  1492.       astat=tocheck.oj.!status
  1493.       if astat=2 then alldone=alldone+1
  1494.       if astat<>0 then iterate    /* active or done, ignore */
  1495.  
  1496.       tmp=get_url_0('HEADGET',tocheck.oj,isauth,oj,myqueue)
  1497.       parse var tmp tocheck.oj.!sock','tocheck.oj.!trans','.
  1498.       IF VERBOSE>2 THEN say ' CheckLink: Double check 'tocheck.oj ' on socket: ' tocheck.oj.!sock
  1499.       tocheck.oj.!status=1
  1500.       tocheck.oj.!birth=nowsec
  1501.  
  1502.       nowactive=nowactive+1
  1503.    end                  /* or leave when at end of tocheck */
  1504.  
  1505.    if alldone=tocheck.0 then leave   /* all done with tocheck hrefs */
  1506.    if (nowsec-lastgoo)> min(15,(0.75*liminact)) then do   /* intermediate status report? */
  1507.        rc=multi_send('<br>   ...('alldone' of 'tocheck.0')')
  1508.        if rc<0 then return 0
  1509.        lastgoo=nowsec
  1510.    end /* do */
  1511.  
  1512.  
  1513. /* any new results? */
  1514.    if nq=0 then do      /* nothing to do -- so check for old age */
  1515.       do bb=1 to tocheck.0
  1516.          if tocheck.bb.!status=1 then do   /* it's active, check age */
  1517.              if (nowsec-tocheck.bb.!birth)>maxage then do 
  1518.                 ssk=tocheck.bb.!sock
  1519.                 rcc=sockshutdown(ssk,2)
  1520.                 rcc=sockclose(ssk)
  1521.                 tocheck.bb.!status=2   /* done */
  1522.                 mm=tocheck.bb.!indx
  1523.                 if verbose>2 then
  1524.                    say 'CheckLink: Killing socket 'ssk '(' hrefs.mm
  1525.                 nowactive=nowactive-1  /* not active any more! */
  1526.              end /* do >maxage */
  1527.          end /* do status=1 */
  1528.       end /* do bb */
  1529.       call syssleep 1           /* sleep for a second */
  1530.       iterate                   /* and back to top of forever loop */
  1531.    end /* do  nq=0*/
  1532.  
  1533. /* if here, something in queue */
  1534.    parse pull yow
  1535.    totgot=totgot+length(yow)
  1536.  
  1537.    anid=left(yow,25)
  1538.    parse var anid atrans','anind ; atrans=strip(atrans); anind=strip(anind)
  1539.    if anind>tocheck.0 then iterate /* ignore  -- impossible tocheck index */
  1540.    if tocheck.anind.!trans<>atrans then iterate /* ignore -- bad transaction */
  1541.  
  1542.    tocheck.anind.!status=2              /* mark that this is done */
  1543.    nowactive=nowactive-1  /* not active any more! */
  1544.    stuff=substr(yow,26)
  1545.    mm=tocheck.anind.!indx
  1546.  
  1547. /* process stuff */
  1548.   if stuff="" then iterate
  1549.  
  1550. /* extract type and length */
  1551.    call extracts                   /* create headers.  */
  1552.    parse var response ht num amess
  1553.  
  1554.   if num<200 | num>399 then do
  1555.       hrefs.mm.!size=-2
  1556.       iterate
  1557.   end
  1558.   hrefs.mm.!type='unknown'
  1559.   hrefs.mm.!size=0
  1560.  
  1561.   if wordpos('!CONTENT-TYPE',headers.0)>0 then do
  1562.     foo='!CONTENT-TYPE'
  1563.     hrefs.mm.!type=headers.foo
  1564.     hrefs.mm.!size=0
  1565.   end
  1566.   if wordpos('!CONTENT-LENGTH',headers.0)>0 then do
  1567.         foo='!CONTENT-LENGTH'
  1568.         hrefs.mm.!size=headers.foo
  1569.   end
  1570.  
  1571. end             /* OF TOCHECKS */
  1572. return 1
  1573.  
  1574.  
  1575.  
  1576.  
  1577.  
  1578.  
  1579. /************************/
  1580. /* write stuff */
  1581. write_img_href:procedure expose imgs. hrefs. crlf totgot baseonly standalone linkfile ,
  1582.                 row_color1 row_color2 row_color1a row_color2a verbose doing_results ascgi ,
  1583.                 rooturl server
  1584. parse arg i1,h1,outtype
  1585.  
  1586. acodes.!OK='<tt><b>Successfully</b> checked links</tt> '
  1587. acodes.1='<tt>Problem links: <u>Server not available</u></tt> '
  1588. acodes.2='<tt>Problem links:<u>No such resource on server</u></tt>'
  1589. acodes.3='<tt>Not checked links: <em>Off-site </em></tt> '
  1590. acodes.4=''
  1591. acodes.5='<tt>Not checked links:<em>Excluded selectors </em></tt> '
  1592. acodes.!ALL='<tt><b>All the links</b></tt> '
  1593.  
  1594. anames.!OK='OKS'
  1595. anames.1='NOSITE'
  1596. anames.2='NOURL'
  1597. anames.3='OFFSITE'
  1598. anames.4=''
  1599. anames.5='EXCLUDED'
  1600. anames.!ALL='ALL'
  1601.  
  1602.  
  1603. codesb.0='<tt>size n.a.</tt>'
  1604. codesb.1='Server n.a.'
  1605. codesb.2='Missing resource'
  1606. codesb.3='Off-site '
  1607. codesb.4=''
  1608. codesb.5='Excluded '
  1609.  
  1610. chlink='CHEKLNK2'
  1611. if ascgi=1 then chlink='/CGI-BIN/CHEKLNK2'
  1612.  
  1613.  aa='<P><hr width="66%"> ' crlf ,
  1614.     ' <center> <a name="'anames.outtype'"> ' acodes.outtype '</a></center> <p>' crlf ,
  1615.      '<b>IM</b>a<b>G</b>es: ' crlf
  1616.  
  1617.  rc=multi_send(aa)
  1618.  if rc<0 then return rc
  1619.  
  1620. stable0=' There are  <b>no</b> "<em> 'acodes.outtype '"</em>     Image links.'
  1621. /* write this if not any matches */
  1622.  
  1623. stable='<table> '
  1624. if linkfile<>'' then do
  1625.    stable='<table><th>? </th> '
  1626. end /* do */
  1627. stable=stable'<th>IMG Location</th><th>mimetype</th><th>size<br><em>or error code</em></th> ' crlf ,
  1628.            '<th><tt>number of references, <em>1st reference </em></th> ' crlf 
  1629.  
  1630. call sort_nhref 1  /* sort imgs */
  1631.  
  1632.  
  1633. iwrote=0
  1634. do mm0=i1 to imgs.0
  1635.  
  1636.    mm=sortlist.mm0
  1637.  
  1638. /* skip this one ? */
  1639.    ssiz=imgs.mm.!size
  1640.    if outtype<>'!ALL' then do          /* not an ALL links report */
  1641.       if ssiz>0  then do 
  1642.         if outtype<>'!OK' then iterate
  1643.       end /* do */
  1644.       else do
  1645.          if abs(ssiz)<>outtype then iterate
  1646.       end /* do */
  1647.    end /* do */
  1648.  
  1649. /* write stuff to table */
  1650.     if stable<>'' then do               /*write table header */
  1651.          rc=multi_send(stable); stable=''
  1652.          if rc<0 then return rc
  1653.     end
  1654.  
  1655.     iwrote=iwrote+1
  1656.     ismiss=0
  1657.      if imgs.mm.!size=-2 | imgs.mm.!size=-1 then ismiss=1
  1658.  
  1659.      ack=breakup(imgs.mm,36,rooturl)
  1660.  
  1661.      bgc=choose_row_color(iwrote,row_color1,row_color2,row_color1a,row_color2a,ack)
  1662.  
  1663.      aa=crlf'<TR ' bgc '> <td>'
  1664.      if linkfile<>'' then do
  1665.          cl2=' <a href="'chlink'?linkfile='linkfile'&isimg=1&entrynum='mm'"> ? </a>   '
  1666.          aa=aa||cl2 '</td><td> '
  1667.       end
  1668.  
  1669.      if imgs.mm.!size>=0 then do
  1670.        aa=aa||'<font size=-1>'mm'. </font> <a href="'imgs.mm'">'ack'</a></td>' crlf
  1671.      end
  1672.      else do
  1673.        iwrote2='<a href="'imgs.mm'">'mm'</a>'
  1674.        aa=aa||' <font size=-1>'iwrote2'. </font> <u>'ack'</u></td>' crlf
  1675.      end
  1676.  
  1677.      ack=imgs.mm.!type
  1678.      if length(ack)>20 then do
  1679.         parse var ack a1 '/' a2 ; ack=a1'/<br>'a2
  1680.      end /* do */
  1681.      aa=aa||'<td> <tt>'ack'</tt></td> ' crlf
  1682.  
  1683.      if imgs.mm.!size>0 then do
  1684.        aa=aa||'<td> <tt>'imgs.mm.!size '</tt> ' crlf
  1685.      end
  1686.      else do
  1687.        mam=abs(imgs.mm.!size)
  1688.        mamo=codesb.mam
  1689.        if ismiss=1 then 
  1690.           mamo='<b>'mamo'</b>'
  1691.        else
  1692.           mamo='<em>'mamo'</em>'
  1693.        aa=aa||'<td> 'mamo' </td>' crlf
  1694.      end
  1695.  
  1696.      nhh=addcomma(imgs.mm.!nrefs)                       /* the refered by stuff */
  1697.      lhh=lower(imgs.mm.!refered) ; lhh2=lhh
  1698.      lhh2=breakup(lhh,35,rooturl)
  1699.      aa=aa||'<td><tt>'nhh'</tt>, <em><a href="'lhh'">'lhh2'</a></em></td>'
  1700.      rc=multi_send(aa)
  1701.      if rc<0 then return rc
  1702. end /* do */
  1703.  
  1704. if stable='' then
  1705.   rc=multi_send('</table>')
  1706. else
  1707.   rc=multi_send(stable0)
  1708. if rc<0 then return rc
  1709.  
  1710. /* --------------- now do anchors */
  1711.  
  1712. ifc=''
  1713. /* if wordpos(outtype,'!ALL !OK 0 6')>0 then
  1714.   ifc=' (if checked, # <tt><A href</tt>s)' */
  1715.  
  1716. aa='<P><hr width="30%">' crlf
  1717. aa=aa||'<b>A</b>nchors:'
  1718. rc=multi_send(aa)
  1719. if rc<0 then return rc
  1720.  
  1721. stable0=' There are  <b>no</b> "<em> 'acodes.outtype '"</em>     Anchor links.'
  1722.  
  1723. stable='<table> '
  1724. if linkfile<>'' then do
  1725.    stable='<table><th>? </th> '
  1726. end /* do */
  1727. stable=stable'<th>URL      'ifc' </th><th><u>#</u></th> ' crlf ,
  1728.          ' <th>mimetype</th><th>size<br><em>or error code</em></th> ' crlf ,
  1729.            '<th><tt>number of references, <em>1st reference </em></th> ' crlf 
  1730.  
  1731. iwrote=0
  1732.  
  1733. /* sort 'em */
  1734. call sort_nhref 0
  1735.  
  1736. do mmn=h1 to hrefs.0
  1737.    mm=strip(sortlist.mmn)
  1738.  
  1739. /* skip this one ? */
  1740.    ssiz=hrefs.mm.!size
  1741.    if outtype<>'!ALL' then do          /* not an ALL links report */
  1742.       if ssiz>0  then do 
  1743.         if outtype<>'!OK' then iterate
  1744.       end /* do */
  1745.       else do
  1746.          if abs(ssiz)<>outtype then iterate
  1747.       end /* do */
  1748.    end /* do */
  1749.  
  1750. /* write stuff */
  1751.     if stable<>'' then do               /*write table header */
  1752.          rc=multi_send(stable); stable=''
  1753.          if rc<0 then return -1
  1754.     end
  1755.   
  1756. /* write this one */
  1757.     iwrote=iwrote+1  
  1758.      ack=breakup(hrefs.mm,36,rooturl)
  1759.  
  1760.      bgc=choose_row_color(iwrote,row_color1,row_color2,row_color1a,row_color2a,ack)
  1761.  
  1762.      aa=crlf'<TR ' bgc '> <td>'         /* write a link to cheklnk2 ? */
  1763.      if linkfile<>'' then do
  1764.          cl2=' <a href="'chlink'?linkfile='linkfile'&isimg=0&entrynum='mm'"> ? </a>   '
  1765.          aa=aa||cl2 '</td><td> '
  1766.       end
  1767.  
  1768.      if hrefs.mm.!size>=0 then do               /* number, or linked number */
  1769.         aa=aa||' <font size=-1>'mm'. </font> <a href="'hrefs.mm'">'ack'</a></td>' crlf
  1770.      end
  1771.      else do
  1772.         iwrote2=' <a href="'hrefs.mm'">'mm'</a>'
  1773.         aa=aa||' <font size=-1>'iwrote2'. </font> <u>'ack'</u></td>' crlf
  1774.      end
  1775.  
  1776.      xx='  ' ;if hrefs.mm.!queried=1 then xx='<em>'hrefs.mm.!nlinks'</em>';  /* links in this document */
  1777.      aa=aa||'<td>'xx'</td>'||crlf               
  1778.  
  1779.      ack=hrefs.mm.!type
  1780.      if length(ack)>20 then do
  1781.         parse var ack a1 '/' a2 ; ack=a1'/<br>'a2
  1782.      end /* do */
  1783.      aa=aa||'<td> <tt>'ack'</tt></td> ' crlf
  1784.  
  1785.      if hrefs.mm.!size>0 then do
  1786.        aa=aa||'<td> <tt>'hrefs.mm.!size '</tt> ' crlf
  1787.      end
  1788.      else do
  1789.        mam=abs(hrefs.mm.!size)
  1790.        mamo=codesb.mam
  1791.        if hrefs.mm.!size=-2 | hrefs.mm.!size=-1 then
  1792.             mamo='<b>'mamo'</b>'
  1793.        else
  1794.             mamo='<em>'mamo'</em>'
  1795.        aa=aa||'<td> 'mamo' </td>' crlf
  1796.      end
  1797.  
  1798.      nhh=addcomma(hrefs.mm.!nrefs)              /* the refered by column */
  1799.      lhh=lower(hrefs.mm.!refered);lhh2=lhh
  1800.      lhh2=breakup(lhh,36,rooturl)
  1801.      aa=aa||'<td> <tt>'nhh'</tt>, <em><a href="'lhh'">'lhh2'</a></em></td>'
  1802.      rc=multi_send(aa)
  1803.      if rc<0 then return rc
  1804.  
  1805. end /* do hrefs.mm */
  1806.  
  1807. if stable='' then
  1808.   rc=multi_send('</table>')
  1809. else
  1810.   rc=multi_send(stable0)
  1811. if rc<0 then return rc
  1812.  
  1813. rc=multi_send('<br><a href="#SUMMARY">... back to summary </a>')
  1814. if rc<0 then return rc
  1815.   
  1816. return 1
  1817.  
  1818. /* end of WRITE_IMG_HREF */
  1819.  
  1820. /***********/
  1821. /* choose color for this row, depending on  row# and type of lin (off or on site */
  1822. choose_row_color:procedure
  1823. parse arg nth,c1,c2,c3,c4,alink
  1824.  
  1825. if abbrev(alink,'/')=1 then do  /* on-site */
  1826.      bgc=c3
  1827.      if nth//2=0 then bgc=c4
  1828. end
  1829. else do
  1830.      bgc=c1
  1831.      if nth//2=0 then bgc=c2
  1832. end /* do */
  1833. return bgc
  1834.    
  1835.  
  1836.  
  1837. /*********************************/
  1838. /********************************/
  1839. /* sort nhrefs. list of urls --- subdirectory sensitive */
  1840. sort_nhref:procedure expose hrefs. sortlist. crlf imgs. server
  1841. parse arg iimg
  1842.  
  1843. if iimg<>1 then do
  1844.   do mn=1 to hrefs.0
  1845.      nhrefs.mn=hrefs.mn
  1846.   end /* do */
  1847.   nhrefs.0=hrefs.0 ;maxssn=0
  1848. end
  1849. else do
  1850.   do mn=1 to imgs.0
  1851.      nhrefs.mn=imgs.mn
  1852.   end /* do */
  1853.   nhrefs.0=imgs.0 ;maxssn=0
  1854. end /* do */
  1855.  
  1856. /* make an array with sortable elements in portions of each record */
  1857. elemsizes.0=0 ; maxfname=0
  1858. do jj=1 to 40
  1859.    elemsizes.jj=0
  1860. end /* do */
  1861. do is=1 to nhrefs.0
  1862.      aa1=strip(strip(nhrefs.is,'l','/'))
  1863.      parse var  aa1 . '//' ssn '/' a1
  1864.      if translate(ssn)=translate(server) then ssn=''
  1865.      biglist.is.!srv=ssn  
  1866.      maxssn=max(maxssn,length(ssn))
  1867.      h1=lastpos('/',a1)         /* pluck off "file name" */
  1868.      biglist.is.0=0
  1869.      if h1>0 then do
  1870.         biglist.is=substr(a1,h1+1)
  1871.         maxfname=max(maxfname,length(biglist.is))
  1872.      end
  1873.      else do
  1874.         biglist.is=a1
  1875.         maxfname=max(maxfname,length(biglist.is))
  1876.         iterate         /* no dirs, get net entry */
  1877.      end
  1878.      a1=delstr(a1,h1)           /* the remainder is the path */
  1879.      idirs=0
  1880.      do forever                 /* pluck out directories in path */
  1881.        if a1='' then leave      /* got all directories */
  1882.        parse var a1 dx '/' a1
  1883.        idirs=idirs+1
  1884.        biglist.is.idirs=dx
  1885.        elemsizes.idirs=max(length(dx),elemsizes.idirs)
  1886.      end /* do */
  1887.      biglist.is.0=idirs
  1888.      elemsizes.0=max(elemsizes.0,idirs)
  1889. end
  1890. do ipp=1 to elemsizes.0
  1891.    elemsizes.ipp=elemsizes.ipp+1
  1892. end /* do */
  1893. /* make the big elements array */
  1894. do ii=1 to NHREFS.0
  1895.   oo.ii=left(ii,6)' 'left(biglist.ii.!srv,maxssn+1)
  1896.   do mm=1 to ELEMSIZES.0
  1897.       if mm<=biglist.ii.0 then 
  1898.          oo.ii=oo.ii||left(biglist.ii.mm,elemsizes.mm)
  1899.      else
  1900.          oo.ii=oo.ii||left(' ',elemsizes.mm)
  1901.   end /* do */
  1902.   oo.ii=oo.ii||left(biglist.ii,maxfname)
  1903. end /* do */
  1904.  
  1905. OO.0=NHREFS.0
  1906. sortlist.0=0
  1907. if oo.0=0 then return 0
  1908.  
  1909. EEF=ARRAYSORT(OO,,,7,,'A','I')         /* sort the names */
  1910.  
  1911. DO MM=1 TO NHREFS.0
  1912.    sortlist.mm=strip(left(oo.mm,6))
  1913. end /* do */
  1914. sortlist.0=nhrefs.0
  1915. return 1
  1916.  
  1917.  
  1918. /*********************************/
  1919. /* search for a <BASE element in the HEAD */
  1920. base_element:procedure expose standalone verbose
  1921. parse arg stuff
  1922. crlf='0d0a'x
  1923.  
  1924. if stuff=0 | stuff="" then return ""
  1925.  
  1926. dowrite=0
  1927.  
  1928. do until stuff=""
  1929.  
  1930.     parse var stuff  p1 '<' tag '>' stuff
  1931.     if  translate(word(tag,1))="HEAD" then do   /* now in head !*/
  1932.             dowrite=1
  1933.             iterate
  1934.     end
  1935.     if dowrite=0 then iterate    /* wait till we get into head .. */
  1936.     if  translate(word(tag,1))="/HEAD" then  /* out of head, all done ! */
  1937.         leave
  1938.  
  1939.     if (translate(word(tag,1)))='BASE' then do
  1940.          parse var tag . '=' . '"' ee '"'
  1941.          return ee
  1942.     end
  1943.  
  1944. end
  1945. return ""
  1946.  
  1947.  
  1948. /*******************************/
  1949. /* get/head a url, do not wait for response */
  1950. GET_URL_0:procedure expose verbose   totgot thread_string standalone  doing_results
  1951. parse arg type,a1,isauth,indid,aqueue
  1952.  
  1953. crlf='0d0a'x
  1954.  
  1955. parse var a1 . '//' server '/' request
  1956. tt=extract2('transaction')   /* used as a queue entry id */
  1957. family  ='AF_INET'
  1958. gosock = SockSocket(family, "SOCK_STREAM", 0)
  1959. iid=left(tt','indid,25,' ')
  1960. att=rexxthread('t',thread_string,gosock,type,server,request,,
  1961.                     isauth,verbose,aqueue,iid)
  1962. return gosock','iid
  1963.  
  1964.  
  1965.  
  1966.  
  1967. /*******************************/
  1968. /* get/head a url */ 
  1969. get_url:procedure expose verbose myqueue  totgot  thread_string maxage standalone doing_results
  1970. parse arg type,server,request,isauth,amaxage
  1971. crlf='0d0a'x
  1972.  
  1973. if amaxage<>'' & datatype(amaxage)='NUM' then 
  1974.   mxage=amaxage
  1975. else
  1976.   mxage=maxage
  1977.  
  1978. stuff=''
  1979.  
  1980. /* clear the queue, then launch a thread */
  1981. foo=rxqueue('s',myqueue)
  1982. ii=queued()
  1983. do ii0=1 to ii ;   pull gg ; end 
  1984.  
  1985. tt=extract2('transaction')
  1986. family  ='AF_INET'
  1987. gosock = SockSocket(family, "SOCK_STREAM", "IPPROTO_TCP")
  1988. tt=left(tt,25,' ')
  1989.  
  1990. att=rexxthread('t',thread_string,gosock,type,server,request,,
  1991.                isauth,verbose,myqueue,tt)
  1992.  
  1993. do mm=1 to mxage   /*wait maxage  */
  1994. ll=queued()
  1995.    if queued()>0  then do
  1996.        parse pull yow
  1997.        totgot=totgot+length(yow)
  1998.        anid=left(yow,25)
  1999.        if strip(anid)<>tt then iterate
  2000.        return substr(yow,26)
  2001.    end /* do */
  2002.    call syssleep 1
  2003. end /* do */
  2004.  
  2005. return ""
  2006.  
  2007.  
  2008.  
  2009.  
  2010. /*************************************/
  2011. /* extract headers and body */
  2012. extracts:
  2013. parse arg noheaders
  2014.  
  2015. cr='0a'x
  2016. parse var stuff response (cr) stuff
  2017. response=strip(response,,'0d'x)
  2018.   headers.0=''
  2019.   do forever
  2020.     parse var stuff  ahead  (cr) stuff
  2021.     ahead=strip(ahead,,'0d'x)
  2022.     if ahead='' then leave
  2023.     parse var ahead name ':' aval
  2024.     nn=translate('!'||name)
  2025.     headers.0=headers.0' 'nn
  2026.     headers.nn=aval
  2027.   end /* do */
  2028.  
  2029. /* remove html comments */
  2030. body=""
  2031. stuff2x=stuff
  2032. do forever              /*no comments within comments are allowed */
  2033.    if stuff2x="" then leave
  2034.    parse var stuff2x t1 '<!-- ' t2 '-->' stuff2x
  2035.    body=body||t1
  2036. end /* do */
  2037. return 1
  2038.  
  2039.  
  2040. /* --- Load the function library, if necessary --- */
  2041. load:
  2042. if \RxFuncQuery("SockLoadFuncs") then return      /* already there */
  2043. call RxFuncAdd "SockLoadFuncs","rxSock","SockLoadFuncs"
  2044. call SockLoadFuncs
  2045.  
  2046. foo=rxfuncquery('sysloadfuncs')
  2047. if foo=1 then do
  2048.   call RxFuncAdd 'SysLoadFuncs', 'RexxUtil', 'SysLoadFuncs'
  2049.   call SysLoadFuncs
  2050. end
  2051.  
  2052. foo=rxfuncquery('rexxlibregister')
  2053. if foo=1 then do
  2054.  call rxfuncadd 'rexxlibregister','rexxlib', 'rexxlibregister'
  2055.  call rexxlibregister
  2056. end
  2057. foo=rxfuncquery('rexxlibregister')
  2058. if foo=1 then do
  2059.     say " Could not find REXXLIB "
  2060.     exit
  2061. end /* do */
  2062. return 1
  2063.  
  2064.  
  2065.  
  2066.  
  2067. /***********************************/
  2068. /* search a file, find IMG SRC=, FRAME SRC=, and A HREF= urls. Add BASEURL if
  2069.    no / or http://.../ at beginning of URL 
  2070.    Return results in hrefs. and imgs. */
  2071.  
  2072. findurls:procedure expose  imgs. hrefs. totgot crlf standalone verbose doing_results dscmax make_descrip
  2073.  
  2074. parse arg stuff, baseurl,rooturl,burl,the_anind
  2075.  
  2076. nf=0
  2077. liminact=extract2('limittimeinactive')
  2078.  
  2079. basegoo=time('e')
  2080. /* convert '< x' to '<x' */
  2081. stuff=translate(stuff,' ','0d0a0900'x)
  2082. do forever
  2083.  wow=pos('< ',stuff)
  2084.  if wow=0 then leave
  2085.  newstuff=''
  2086.  do forever
  2087.      parse var stuff a1 '< '  stuff
  2088.      newstuff=newstuff||a1
  2089.      if stuff<>""  then 
  2090.           newstuff=newstuff||'<'
  2091.      else
  2092.          leave
  2093.  end /* do */
  2094.  stuff=newstuff
  2095. end
  2096. tstuff=translate(stuff)
  2097.  
  2098.  
  2099. /* find TITLE element */
  2100. a1=pos('</HEAD',tstuff)
  2101. if a1>0 then do
  2102.    a2=pos('<TITLE',tstuff)
  2103.    if a2<a1 & a2<>0  then do            /* <TITLE in <HEAD */
  2104.       a3=pos('</TITLE',tstuff,a2)
  2105.       IF A3=0 then DO                   /* NOT </TITLE ! */
  2106.          HREFS.THE_ANIND.!TITLE='no_title'
  2107.       end /* do */
  2108.       else DO
  2109.         a4=substr(stuff,a2,1+a3-a2)
  2110.         parse var a4 . '>' atitle '<' .
  2111.         atitle=space(strip(atitle),1)
  2112.         hrefs.the_anind.!title=left(atitle,min(80,length(atitle)))
  2113.       END
  2114.    end /* do */
  2115. end /* do */
  2116.  
  2117. /* find description  */
  2118. if  make_descrip>1 then do
  2119.    goo=fig_descript(a1)
  2120.    if goo<>'' then hrefs.the_anind.!descrip=goo
  2121. end /* do */
  2122.  
  2123. /* find all  FRAME SRC=, IMG SRC= and A HREF=, throw away internal links */
  2124. lookfor.1='<BODY '
  2125. lookfor.2='<IMG '
  2126. lookfor.3='<A '
  2127. lookfor.4='<FRAME '
  2128. lookfor.5='<AREA '
  2129. lookfor.6='<EMBED '
  2130. lookfor.7='<LINK '
  2131. lookfor.8='<APPLET '
  2132. lookfor.9='<OBJECT '
  2133.  
  2134. do anctype=1 to 9
  2135. nowtarg=lookfor.anctype
  2136. strt=1
  2137.  
  2138. do forever
  2139.     s1a=pos(nowtarg,tstuff,strt)
  2140.     if s1a=0 then leave
  2141.     s2a=pos('>',tstuff,s1a)
  2142.     if s2a=0 then leave         /* error, give up on this one */
  2143.     anarg=substr(stuff,s1a+1,(s2a-s1a)-1)
  2144.     anarg=translate(anarg,' ','0d0a0900'x)
  2145.     strt=s2a+1
  2146.  
  2147.     select 
  2148.  
  2149.        when anctype=1 then do           /* body background */
  2150.          do forever
  2151.             if anarg=''  then leave
  2152.             parse var anarg a1 anarg ; a1=strip(a1)
  2153.             if abbrev(translate(a1),'BACKGROUND=')=0 then iterate
  2154.             parse var a1 . '=' gotimg . ; gotimg=strip(strip(gotimg),,'"')
  2155.             if left(gotimg,2)='//' then gotimg='http://'gotimg
  2156.  
  2157.             nf=nf+1
  2158.             fileurls.nf=fix_url(gotimg,baseurl,rooturl)
  2159.             fileurls.nf.!img=1
  2160.             leave
  2161.          end /* do */
  2162.        end                              /* i3>0 */
  2163.        when anctype=2 then do                /* img */
  2164.          do forever
  2165.             if anarg=''  then leave
  2166.             parse var anarg a1 anarg ; a1=strip(a1)
  2167.             if abbrev(translate(a1),'SRC=')=0 then iterate
  2168.             parse var a1 . '=' gotimg . ; gotimg=strip(strip(gotimg),,'"')
  2169.             if left(gotimg,2)='//' then gotimg='http://'gotimg
  2170.  
  2171.             nf=nf+1
  2172.             fileurls.nf=fix_url(gotimg,baseurl,rooturl)
  2173.             fileurls.nf.!img=1
  2174.             leave
  2175.          end /* do */
  2176.        end
  2177.  
  2178.        when anctype=3 | anctype=5  | anctype=7 then do /* A AREA LINK */
  2179.          do forever
  2180.             if anarg=''  then leave
  2181.             parse var anarg a1 anarg ; a1=strip(a1)
  2182.             if abbrev(translate(a1),'HREF=')=0 then iterate
  2183.             parse var a1 . '=' gothref . ; gothref=strip(strip(gothref),,'"')
  2184.  
  2185.             parse var gothref gothref '#' .     /* toss out internal jumps */
  2186.             if gothref="" then iterate
  2187.             if abbrev(upper(gothref),'JAVASCRIPT:')=1 then iterate /* don't do "javascript:" entries */
  2188.  
  2189.             if left(gothref,2)='//' then gothref='http://'gothref
  2190.  
  2191.             parse upper var  gothref uaref ':' .        /* non -http are discarded */
  2192.             if wordpos(uaref,'MAILTO FTP FILE GOPHER TELNET')>0 then iterate
  2193.                
  2194.             nf=nf+1
  2195.             fileurls.nf=fix_url(gothref,baseurl,rooturl)
  2196.  
  2197.             fileurls.nf.!img=0
  2198.             leave
  2199.          end /* do */
  2200.        end
  2201.  
  2202.        when anctype=4 | anctype=6 then do   /* FRAME EMBED */
  2203.          do forever
  2204.             if anarg=''  then leave
  2205.             parse var anarg a1 anarg ; a1=strip(a1)
  2206.             if abbrev(translate(a1),'SRC=')=0 then iterate
  2207.             parse var a1 . '=' gothref . ; gothref=strip(strip(gothref),,'"')
  2208.             if left(gothref,2)='//' then gothref='http://'gothref
  2209.  
  2210.             parse var gothref gothref '#' .     /* toss out internal jumps */
  2211.             if gothref="" then iterate
  2212.  
  2213.             nf=nf+1
  2214.             fileurls.nf=fix_url(gothref,baseurl,rooturl)
  2215.             fileurls.nf.!img=0
  2216.             leave
  2217.          end /* do */
  2218.        end
  2219.  
  2220.        when anctype=8 then do   /* APPLET */
  2221.          abase=''; aref=''
  2222.          do forever
  2223.             if anarg=''  then leave
  2224.             parse var anarg a1 anarg ; a1=strip(a1)
  2225.             if abbrev(translate(a1),'CODE=') + ,
  2226.                abbrev(translate(a1),'CODEBASE=')=0 then iterate
  2227.                 
  2228.             if abbrev(translate(a1),'CODEBASE=')=1 then do
  2229.                     parse var a1 '"' abase '"' .
  2230.              end /* do */
  2231.              else do                  /* CODE */
  2232.                    parse var a1 '"' aref '"'
  2233.              end /* do */
  2234.              if aref<>'' & abase<>'' then leave
  2235.  
  2236.           end
  2237.           if aref='' then iterate       /* no CODE= found */
  2238.           if left(abase,2)='//' then abase='http://'abase
  2239.            
  2240.           if abase<>'' then
  2241.               tmp1=abase||strip(aref,'l','/')
  2242.           else
  2243.             tmp1=fix_url(aref,baseurl,rooturl)
  2244.  
  2245.           nf=nf+1
  2246.           fileurls.nf=tmp1
  2247.           fileurls.nf.!img=0
  2248.  
  2249.        end
  2250.  
  2251.        when anctype=9 then do   /* OBJECT */
  2252.          do forever
  2253.             if anarg=''  then leave
  2254.             parse var anarg a1 anarg ; a1=strip(a1)
  2255.             if abbrev(translate(a1),'CODEBASE=')=0 then iterate
  2256.             parse var a1 . '=' gothref . ; gothref=strip(strip(gothref),,'"')
  2257.  
  2258.             if left(gothref,2)='//' then gothref='http://'gothref
  2259.  
  2260.             parse var gothref gothref '#' .     /* toss out internal jumps */
  2261.             if gothref="" then iterate
  2262.  
  2263.             nf=nf+1
  2264.             fileurls.nf=fix_url(gothref,baseurl,rooturl)
  2265.             fileurls.nf.!img=0
  2266.             leave
  2267.          end /* do */
  2268.        end
  2269.  
  2270.         
  2271.        otherwise nop
  2272.    end                  /* select */
  2273.    goo=time('e')
  2274.    if (goo-basegoo)> min(15,(0.75*liminact)) then do
  2275.         rc=multi_send('<br> .... found 'nf)
  2276.         if rc<0 then return 0
  2277.         basegoo=goo
  2278.    end /* do */
  2279. end             /* search tstuff */
  2280.  
  2281. end             /* anctype */
  2282.  
  2283. iurls=nf
  2284.  
  2285. if iurls=0 then return 0        /* no links */
  2286.  
  2287. /* remove duplicates */
  2288. rc=multi_send('<br> .... removing duplicates from ' iurls ' links ')
  2289. if rc<0 then return 0
  2290.  
  2291. okays=make_isdup(iurls)
  2292.  
  2293. if okays=0 then return 0
  2294.  
  2295. /* isdup=1 means "this is a duplicate of prior entry in this document" 
  2296.    use this, and list of prior hrefs and imgs, to remove duplicates */
  2297.  
  2298. iurls1=0 ; nimgs=imgs.0 ; nhrefs=hrefs.0
  2299. fop='<br> Check 'okays' links against (' nimgs ' & ' nhrefs ') prior links '
  2300. rc=multi_send(fop)
  2301.  
  2302. oo=time('e')
  2303.  
  2304. /* if prior exists, don't add new entry, but do augment "!nrefs" field */
  2305. do mm=1 to iurls
  2306.    if isdup.mm=1 then iterate   /* this is duplicated in this document, so ignore it */
  2307.  
  2308.    if fileurls.mm.!img=1 then do               /* check image list */
  2309.      arf=strip(translate(fileurls.mm))
  2310.      if datatype(imgs.!list.arf)='NUM' then do    /* match, so don't add */
  2311.         nn=imgs.!list.arf
  2312.         imgs.nn.!nrefs=imgs.nn.!nrefs+1
  2313.         imgs.nn.!appearin=imgs.nn.!appearin' 'the_anind
  2314.         hrefs.the_anind.!imglist=hrefs.the_anind.!imglist' 'nn
  2315.         iterate               
  2316.      end /* do */
  2317.      nimgs=nimgs+1                /* no match, so add */
  2318.      imgs.nimgs=fileurls.mm
  2319.      imgs.!list.arf=nimgs
  2320.      hrefs.the_anind.!imglist=hrefs.the_anind.!imglist' 'nimgs
  2321.  
  2322.    end
  2323.    else do                      /* check hrefs list */
  2324.       arf=strip(translate(fileurls.mm))
  2325.       if datatype(hrefs.!list.arf)='NUM' then do    /* match, so don't add */
  2326.           nn=hrefs.!list.arf
  2327.           hrefs.nn.!nrefs=hrefs.nn.!nrefs+1    /* # of times this is referenced */
  2328.           if nn<>the_anind then hrefs.nn.!appearin=hrefs.nn.!appearin' 'the_anind        /* this appears in the_anind's */
  2329.           if nn<>the_anind then hrefs.the_anind.!reflist=hrefs.the_anind.!reflist' 'nn
  2330.           iterate               
  2331.       end /* do */
  2332.       nhrefs=nhrefs+1                /* no match, so add */
  2333.       hrefs.nhrefs=fileurls.mm
  2334.       hrefs.!list.arf=nhrefs
  2335.       hrefs.the_anind.!reflist=hrefs.the_anind.!reflist' 'nhrefs
  2336.  
  2337.    end /* do */
  2338. end             /* mm */
  2339.  
  2340. oo2=time('e')
  2341. imgs.0=nimgs ; hrefs.0=nhrefs
  2342. return okays
  2343.  
  2344. /* end of FINDURLS .. anind hrefs. */
  2345.  
  2346.  
  2347. /*****************/
  2348. /* extract descripiton from <head> */
  2349. fig_descript:procedure expose dscmax make_descrip stuff
  2350. parse arg a1
  2351.  
  2352. s2=stuff
  2353.  
  2354. dowrite=1
  2355. do until s2=""
  2356.  
  2357.     parse var s2  p1 '<' tag '>' s2
  2358.  
  2359. /* is it a  META HTTP-EQUIV or a META NAME ? */
  2360.     if translate(word(tag,1))="/HEAD" then leave
  2361.  
  2362.     if translate(word(tag,1))="META" then do
  2363.         parse var tag ameta atype '=' rest
  2364.         tatype=translate(atype)
  2365.         
  2366.         if tatype="HTTP-EQUIV" | tatype="NAME" then do
  2367.            parse var rest aval1 rest
  2368.            REST=STRIP(REST)
  2369.  
  2370.            aval1=strip(aval1) ;
  2371.            aval1=strip(aval1,,'"')
  2372.            if abbrev(translate(aval1),'DESC')<>1 then iterate
  2373.  
  2374.            aval2=" "
  2375.            foo1=ABBREV(translate(rest),'CONTENT')
  2376.            if foo1>0 then do
  2377.                 PARSE VAR REST FOO '=' AVAL2
  2378.                 aval2=strip(aval2)
  2379.                 aval2=strip(aval2,'b','"')
  2380.                 url_content=LEFT(AVAL2,dscmax)
  2381.                 return url_content
  2382.            end
  2383.         end             /* name or http-equiv */
  2384.     end         /* meta */
  2385. end             /* stuff */
  2386.  
  2387. /* look for <h1 and <h2 headers? */
  2388. if make_descrip<>3 then  return ''
  2389. if s2=''  then s2=stuff  /* no /head */
  2390. bb=look_Htag(s2)
  2391. return bb
  2392.  
  2393.  
  2394. /* ----------------------------------------------------------------------- */
  2395. /* Extract <hn> fields     */
  2396. /* ----------------------------------------------------------------------- */
  2397.  
  2398. look_htag: procedure expose dscmax
  2399. parse arg stuff
  2400.  
  2401. amessage=""
  2402. dowrite=0
  2403. do until stuff=""
  2404.     parse var stuff  p1 '<' tag '>' stuff
  2405.     ttag=translate(word(tag,1))
  2406.     if wordpos(ttag,' H1 H2 H3 H4 TITLE')>0 THEN DO   /* grab stuff */
  2407.         parse var stuff  amess '<' tag2 '>' stuff
  2408.         amessage=amessage||amess||'<b> | </b>'
  2409.         if length(amessage)>dscmax then leave
  2410.     end
  2411. end
  2412.  
  2413. if amessage="" then do  /* getting desperate -- grab any old words! */
  2414.    stuff0=left(stuff,1000)
  2415.    do until stuff0=""
  2416.       parse var stuff0 p1 '<' tag '>' stuff0
  2417.       amessage=amessage||' '||p1
  2418.       if length(amessage)>dscmax then leave
  2419.    end
  2420. end
  2421.  
  2422. return amessage
  2423.  
  2424.  
  2425.  
  2426.  
  2427.  
  2428.  
  2429. /************************/
  2430. /* make the isdup "duplicates" array */
  2431. make_isdup:procedure expose isdup. fileurls. standalone verbose
  2432. parse arg iurls
  2433.  
  2434. oo=time('e')
  2435. drop tmps.
  2436. okays=0
  2437. do mm=1 to iurls
  2438.    a1=space(translate(fileurls.mm.!img||'_'fileurls.mm),0)
  2439.  
  2440.    if tmps.a1=1 then do
  2441.       isdup.mm=1
  2442.    end
  2443.    else do
  2444.       isdup.mm=0
  2445.       tmps.a1=1
  2446.       okays=okays+1
  2447.    end
  2448. end
  2449. oo2=time('e')
  2450. return okays
  2451.  
  2452.  
  2453. /****************************/
  2454. /* add baseurl if needed */
  2455. fix_url:procedure
  2456. parse arg aref,baseurl,rooturl
  2457.  
  2458. if abbrev(translate(aref),'HTTP://') then return aref
  2459. if abbrev(aref,'/')=0  then 
  2460.     aref1=baseurl||aref
  2461. else
  2462.     aref1=rooturl||strip(aref,'l','/')
  2463. return aref1
  2464.  
  2465.  
  2466. /********************************/
  2467. /* set base and root */
  2468. set_base_root:
  2469. server=strip(server,,'/')   
  2470. ii=lastpos('/',request)
  2471.   if ii=0 then 
  2472.      base='http://'server'/'
  2473.   else
  2474.      base='http://'server'/'strip(delstr(request,ii+1),'l','/')
  2475.   base2=base_element(body)
  2476.   if base2<>'' then base=base2
  2477.   
  2478.   parse var base . '//' rooturl '/' .
  2479.   rooturl='http://'rooturl'/'
  2480.  
  2481.   intro3=' <br>     <em>base-url </em>   = ' base ' ; root= ' rooturl 
  2482.  
  2483. return 1
  2484.  
  2485. /***************/
  2486. /* return 0 for no, 1 for yes, default otherwise */
  2487. is_yes_no:procedure
  2488. parse arg aval,def
  2489. tdef=strip(translate(aval))
  2490. if wordpos(tdef,'Y YES 1')>0 then return 1
  2491. if wordpos(tdef,'N NO 0')>0 then return 0
  2492. return def
  2493.  
  2494. /***************/
  2495. /* check selector for match to one of the exclusion lists */
  2496. exclude_me:procedure
  2497. parse upper arg asel,alist1,alist2,ahref,aroot
  2498.  
  2499. alist=alist1
  2500. if abbrev(translate(ahref),aroot)=1 & alist2<>'' then  
  2501.    alist=alist2
  2502.  
  2503. do mm=1 to words(alist)
  2504.    a1=strip(word(alist,mm)) 
  2505.    oo=wild_match(asel,a1)
  2506.    if oo<>0 then return 1
  2507. end
  2508. return 0
  2509.  
  2510.  
  2511. /*******************/
  2512. /* create thread_string -- tokenized string containing get_url thread */
  2513. /* this is the "thread" used to get resources from other servers */
  2514.  
  2515. make_get_url:
  2516. crlf='0d0a'x
  2517. dathread=' parse arg gosock,type,server,request,isauth,verbose,myqueue,transaction ' crlf ,
  2518. ' signal on error name iserr ; signal on syntax name iserr  ' crlf ,
  2519. ' stuff=bget_url(type,server,request,isauth)  ' crlf ,
  2520. ' a10=transaction||stuff '  crlf ,
  2521. ' foo=rxqueue('s',myqueue) ' crlf ,
  2522. ' queue a10 '  crlf ,
  2523. ' arf=queued() ' crlf ,
  2524. ' exit " " '  crlf ,
  2525. ' iserr: tt=rxqueue("g") ' crlf ,
  2526. ' exit ""  ' crlf ,
  2527. 'bget_url:procedure expose verbose  gosock ' crlf , 
  2528. 'parse arg type,server,request,isauth ' crlf ,
  2529. ' if verbose>4 then call pmprintf(" Bgeturl: look for  "server " "request)' crlf,
  2530. 'crlf="0d0a"x ; maxchar=1000000000 ' crlf ,
  2531. 'httpport=80 ' crlf ,
  2532. ' parse var server server ":" bport' crlf ,
  2533. 'if bport<>"" then httpport=bport ' crlf ,
  2534. 'family  ="AF_INET" ' crlf ,
  2535. 'rc=1 ;if verify(server,'1234567890.')>0 then do ' crlf ,
  2536. '   rc=sockgethostbyname(strip(server), "serv.0")  ' crlf ,
  2537. ' end   'crlf,
  2538. 'else do ' crlf ,
  2539. '  serv.0addr=strip(server) ' crlf ,
  2540. 'end 'crlf,
  2541. 'if verbose>4 & rc=0 then call pmprintf(" rc in bgeturl= "rc)' crlf,
  2542. 'if rc=0 then do ' crlf ,
  2543. '    rc1=sockshutdown(gosock,2) ' crlf ,
  2544. '    rc = SockClose(gosock) ' crlf ,
  2545. '    return "" ' crlf ,
  2546. 'end ' crlf ,
  2547. 'dotserver=serv.0addr ' crlf ,
  2548. 'gosaddr.0family=family     ' crlf ,  
  2549. 'gosaddr.0port  =httpport ' crlf ,
  2550. 'gosaddr.0addr  =dotserver ' crlf ,
  2551. 'if gosock="" then      ' crlf ,
  2552. '  gosock = SockSocket(family, "SOCK_STREAM", 0) ' crlf ,
  2553. 'request=strip(request,"l","/") ' crlf ,
  2554. ' if type='HEADGET' then do ; type='GET' ; maxchar=999 ; end ' crlf ,
  2555. ' if type='DSCGET' then do ; type='GET' ; maxchar=1500 ; end ' crlf ,
  2556. ' message=type" /"request" HTTP/1.0"crlf"HOST: "server||crlf ' crlf ,
  2557. ' message=message||"Referer: checklink@"||mehost||crlf ' crlf ,
  2558. 'if isauth<>"" then message=message||"Authorization: "isauth||crlf ' crlf ,
  2559. 'message=message||crlf ' crlf ,
  2560. ' got="" ' crlf ,
  2561. 'rc = SockConnect(gosock,"gosaddr.0") ' crlf ,
  2562. 'if rc<0 then do ' crlf ,
  2563. '  rc1=sockshutdown(gosock,2) ' crlf ,
  2564. '  rc = SockClose(gosock) ' crlf ,
  2565. '  if verbose>2 then call pmprintf(" CheckLink: error connecting to " server "=" rc) ' crlf ,
  2566. '  return "" ' crlf ,
  2567. 'end ' crlf ,
  2568. 'rc = SockSend(gosock, message) ' crlf ,
  2569. 'iok=1 ' crlf ,
  2570. 'do r=1 by 1 ' crlf ,
  2571. '  rc = SockRecv(gosock, "response", 1000) ' crlf ,
  2572. '  got=got||response ' crlf ,
  2573. '  if rc<0 then iok=0 ' crlf ,
  2574. '  if rc<=0 then leave ' crlf ,
  2575. '  if length(got)>maxchar then leave ' crlf ,
  2576. ' end r ' crlf ,
  2577. ' if iok=0 then  do ' crlf ,
  2578. '  rc=sockshutdown(gosock,2) ' crlf ,
  2579. '  rc = SockClose(gosock) ' crlf ,
  2580. '  return ""  ' crlf ,
  2581. 'end ' crlf ,
  2582. 'rc=sockshutdown(gosock,2) ' crlf ,
  2583. 'rc = SockClose(gosock) ' crlf ,
  2584. ' if verbose > 2 then ' crlf ,
  2585. ' call pmprintf("CheckLink: ("rc") "type"; got" length(got) "bytes of response from:" server " "request) ' crlf ,
  2586. 'return got '
  2587.  
  2588. aa=tokenizestring(dathread,thread_string)
  2589. return
  2590.  
  2591. /**********************/
  2592. /* send to client, or to screen */
  2593. multi_send:procedure expose standalone verbose doing_results
  2594. parse arg a1,a2,a3,a4,a5,a6,a7
  2595. parse var standalone ss ofile ttime
  2596. ofile=strip(ofile) ; ss=strip(ss)
  2597.  
  2598. parse var doing_results doo1 doo2
  2599. if ss=0 then do
  2600.    doo2=strip(doo2)
  2601.    if doo1=2 then do
  2602.        call lineout doo2,a1
  2603.        return 1
  2604.    end
  2605.    else do
  2606.      if a2='' & a3='' & a4='' then
  2607.         rc=sref_multi_send(a1)
  2608.      else
  2609.         rc=sref_multi_send(a1,a2,a3,a4,a5,a6,a7)
  2610.      return rc
  2611.    end
  2612. end /* do */
  2613.  
  2614. /* if here, standalone mode... */
  2615.  call lineout ofile,a1          /* standalone output file*/
  2616.  
  2617. /* if verbose>0, write to screen.. but remove <elements> */
  2618. if verbose=0 | doo=1 then return  1
  2619.  
  2620. aa=''
  2621. do forever
  2622.     if a1='' then leave
  2623.     parse var a1 t1 '<' t2 '>' a1
  2624.     aa=aa||t1
  2625.     if translate(t2)='LI' then aa=aa' * '
  2626.     if translate(t2)='P' | translate(t2)='BR' then aa=aa||'0d0a'x
  2627.     if abbrev(strip(translate(t2)),'A')=1 then aa=aa' >> '
  2628. end
  2629. aaa=''
  2630. do forever
  2631.   if aa=' ' then leave
  2632.   parse var aa a1 ' ' aa
  2633.   aaa=aaa' 'a1
  2634. end /* do */
  2635. say aaa
  2636.  
  2637. return 1
  2638.  
  2639. /*********************/
  2640. /* standalone mode */
  2641. ask_opts:
  2642.  
  2643. SIGNAL OFF  ERROR ; SIGNAL OFF SYNTAX
  2644. SIGNAL ON ERROR NAME ASKV 
  2645.  SIGNAL ON SYNTAX NAME ASKV 
  2646.  
  2647. ansion=checkansi()
  2648. if ansion=1 then do
  2649.   aesc='1B'x
  2650.   cy_ye=aesc||'[37;46;m'
  2651.   normal=aesc||'[0;m'
  2652.   bold=aesc||'[1;m'
  2653.   re_wh=aesc||'[31;47;m'
  2654.   reverse=aesc||'[7;m'
  2655. end
  2656. else do
  2657.   say " Warning: Could not detect ANSI....  output will look ugly ! "
  2658.   cy_ye="" ; normal="" ; bold="" ;re_wh="" ;
  2659.   reverse=""
  2660. end  /* Do */
  2661.  
  2662. cls
  2663. say  " " ; say
  2664.  
  2665. call lineout, bold cy_ye
  2666. call lineout, "CheckLink: check & verify HTML links -- stand alone mode "
  2667. call lineout, normal
  2668.  
  2669.  
  2670. say " Although designed primarily as an SRE-http addon, you can use CheckLink "
  2671. say " in a stand-alone mode."
  2672. say
  2673. say "      "||cy_ye||"CheckLink's standalone-mode's final results are written to an    "normal
  2674. say "      "||cy_ye||"HTML file.  You should view it with a browser (using Open File). "normal
  2675. call lineout, normal
  2676.  
  2677. say "  "
  2678.  
  2679. if yesno(" Are you ready to continue ")=1 then
  2680.  nop
  2681. else do
  2682.  say " See you later?.. "
  2683.  exit
  2684. end
  2685.  
  2686.  
  2687. say
  2688. say " We recommend reading the documentation (CHEKLINK.DOC) before  "
  2689. say " running this program.  On the other hand, you can always learn by "
  2690. say " making mistakes .... "
  2691. say
  2692.  
  2693. say  "Enter a fully specified "bold "starter-URL: " normal
  2694. call charout, bold "     ? "normal
  2695. parse pull aurl
  2696.  
  2697. call charout,bold' Web-tree name:'normal
  2698. parse pull treename
  2699.  
  2700. isauth=''
  2701. call charout, " A (space seperated) "bold "USERNAME PASSWORD "normal " (ENTER=None):"
  2702. parse pull upwd
  2703. if upwd<>' ' then do
  2704.     upwd=space(strip(upwd))
  2705.     upwd=mk_base64(translate(upwd,':',' '))
  2706.    isauth='Authorization: Basic '||upwd
  2707. end
  2708.  
  2709. call charout, " URL pointing to " bold " CHEKLINK.HTM "normal ":"
  2710. parse pull cheklink_htm
  2711.  
  2712. queryonly=0
  2713. baseonly=yesno(" Only read documents in or under this starter-URL ",'Y')
  2714. if baseonly=1 then do
  2715.    queryonly=yesno(normal" ..."reverse"only look at this URL (query links, but do NOT recurse)",'Y')
  2716. end /* do */
  2717. siteonly=yesno(' Query resources on other sites (N=do not)','Y')
  2718. siteonly=1-siteonly
  2719.  
  2720. call charout,' Make descriptions (1=NO, 2=text/html, 3=html and plaintext):'
  2721. pull maked
  2722.  
  2723. call charout , "Exclusion list (ENTER="bold'!*  *?* *MAPIMAGE/* CGI*'normal'): '
  2724. parse pull exclus
  2725. if exclus='' then exclus='!*  *?* *MAPIMAGE/* CGI*' 
  2726. do forever
  2727.   call charout,' Select output tables (?=Help,ENTER='bold'ALL'normal'): ' 
  2728.   pull outtype
  2729.   if outtype='' then outtype='ALL'
  2730.   if outtype='?' then do
  2731.       say cy_ye" Valid codes for output tables"normal' (you can use them in any combination): 'normal
  2732. say '        'bold'OK'normal' ) Display succesfully found links'
  2733. say '    'bold'NOSITE'normal' ) Display links to unreachable sites'
  2734. say '     'bold'NOURL'normal' ) Display links missing resources>'
  2735. say '   'bold'OFFSITE'normal' ) Display links to off-site URLs'
  2736. say '  'bold'EXCLUDED'normal' ) Display links to excluded URLs (specified in the EXCLUSION_LIST)'
  2737. say '       'bold'ALL'normal' ) Display all links'
  2738.       iterate
  2739.   end /* do */
  2740.   leave
  2741. end
  2742.  
  2743.  
  2744. myqueue='CHEKLINK_STD1'
  2745. foo=rxqueue('C',myqueue)
  2746. if foo<>myqueue then aa=rxqueue('d',foo)
  2747.  
  2748. servername=get_hostname()
  2749.  
  2750. say "The output file will be an HTML document containing the tables of results."
  2751. do forever
  2752.   call charout, 'Output file: '
  2753.   pull outfileX
  2754.   if outfilex='' then iterate
  2755.   if pos('.',outfilex)=0 then outfilex=outfilex'.htm'
  2756.   if stream(outfileX,'c','query exists')<>' ' then do
  2757.          goo=yesno(' File exists. Overwrite? ')
  2758.          if goo=1 then do
  2759.             goo=sysfiledelete(outfilex)
  2760.             leave
  2761.          end
  2762.          iterate
  2763.   end  
  2764.   oo=stream(outfileX,'c','open write')
  2765.   if abbrev(translate(oo),'READY')=1 then leave
  2766.   say "Can't open file, try a different name"
  2767. end
  2768.  
  2769. say
  2770.  
  2771.  say 'The "links" file stores information on what links appear in the HTML'
  2772.  say 'documents, and what HTML documents each resource "appears in"'
  2773.  say " (note: the links file will be stored in: " linkfile_dir ')'
  2774.  do forever
  2775.    call charout, '   Links file, name only (0=do not create): '
  2776.    pull linkfile
  2777.    if linkfile=0 then leave
  2778.    outfilel=linkfile_dir||linkfile'.STM'
  2779.    if pos('.',outfilel)=0 then outfilel=outfilel'.STM'
  2780.    if stream(outfilel,'c','query exists')<>' ' then do
  2781.          goo=yesno(' File exists. Overwrite? ')
  2782.          if goo=1 then do
  2783.             goo=sysfiledelete(outfilel)
  2784.             leave
  2785.          end
  2786.          say " Using: " outfilel
  2787.          ascgi=yesno(" Use CGI-BIN to specify CHEKLNK2 (web traversal) links ")
  2788.          iterate
  2789.    end  
  2790.    oo=stream(outfilel,'c','open write')
  2791.    if abbrev(translate(oo),'READY')=1 then do
  2792.          say " Using: " outfilel
  2793.          ascgi=yesno(" Use CGI-BIN to specify CHEKLNK2 (web traversal) links ")
  2794.          oo=stream(outfilel,'c','close')
  2795.          leave
  2796.    end
  2797.    say "Can't open " outfilel ", try a different name"
  2798.  end
  2799.  
  2800. treename=translate(treename,'+',' ')
  2801. list='url='aurl'&baseonly='baseonly'&siteonly='siteonly'&exclus='exclus'&outtype='outtype|| ,
  2802.              '&queryonly='queryonly'&linkfile='linkfile'&treename='treename'&make_descrip='maked
  2803.  
  2804. verbose=standalone_verbose
  2805. transaction=(10*dospid())+dostid()
  2806.  
  2807. standalone=1' 'outfilex
  2808.  
  2809. return list
  2810.  
  2811.  
  2812.  
  2813.  /* ------------------------------------------------------------------ */
  2814.  /* function: Check if ANSI is activated                               */
  2815.  /*                                                                    */
  2816.  /* call:     CheckAnsi                                                */
  2817.  /*                                                                    */
  2818.  /* where:    -                                                        */
  2819.  /*                                                                    */
  2820.  /* returns:  1 - ANSI support detected                                */
  2821.  /*           0 - no ANSI support available                            */
  2822.  /*          -1 - error detecting ansi                                 */
  2823.  /*                                                                    */
  2824.  /* note:     Tested with the German and the US version of OS/2 3.0    */
  2825.  /*                                                                    */
  2826.  /*                                                                    */
  2827.  CheckAnsi: PROCEDURE
  2828.    thisRC = -1
  2829.  
  2830.    trace off
  2831.                          /* install a local error handler              */
  2832.    SIGNAL ON ERROR Name InitAnsiEnd
  2833.  
  2834.    "@ANSI 2>NUL | rxqueue 2>NUL"
  2835.  
  2836.    thisRC = 0
  2837.  
  2838.    do while queued() <> 0
  2839.      queueLine = lineIN( "QUEUE:" )
  2840.      if pos( " on.", queueLine ) <> 0 | ,                       /* USA */
  2841.         pos( " (ON).", queueLine ) <> 0 then                    /* GER */
  2842.        thisRC = 1
  2843.    end /* do while queued() <> 0 */
  2844.  
  2845.  InitAnsiEnd:
  2846.  signal off error
  2847.  RETURN thisRC
  2848.  
  2849.  
  2850.  
  2851.  
  2852.  
  2853.  
  2854. /* -------------------- */
  2855. /* get a yes or no , return 1 if yes */
  2856. yesno:procedure expose normal reverse bold
  2857. parse arg fooa , allopt,altans
  2858. if altans<>" " & words(altans)>1 then do
  2859.    w1=strip(word(altans,1))
  2860.    w2=strip(word(altans,2))
  2861.    a1=left(w1,1) ; a2=left(w2,1)
  2862.    a1a=substr(w1,2) ; a2a=substr(w2,2)
  2863. end
  2864. else do
  2865.     a1='Y' ; a1a='es'
  2866.     a2='N' ; a2a='o'
  2867. end  /* Do */
  2868. ayn='  '||bold||a1||normal||a1a||'\'||bold||a2||normal||a2a
  2869. if allopt=1 then  ayn=ayn||'\'||bold||'A'||normal||'ll'
  2870.  
  2871. do forever
  2872.  foo1=normal||reverse||fooa||normal||ayn
  2873.  call charout,  foo1 normal ':'
  2874.  pull anans
  2875.  if abbrev(anans,a1)=1 then return 1
  2876.  if abbrev(anans,a2)=1 then return 0
  2877.  if allopt=1 & abbrev(anans,'A')=1 then return 2
  2878. end
  2879.  
  2880.  
  2881.  
  2882. nocon:
  2883. if rc=-7 then return 0
  2884. exit 0
  2885.  
  2886. /* get the hostname (aa.bb.cc) for this machine */
  2887. get_hostname: procedure
  2888.     do queued(); pull .; end                   /* flush */
  2889.     address cmd '@hostname | rxqueue'
  2890.  
  2891.     parse pull hostname
  2892.     return hostname
  2893.  
  2894.  
  2895.  
  2896. /*********/
  2897. packur2:procedure expose standalone
  2898. parse arg a1b0
  2899.  
  2900. if standalone=0 then
  2901.    return packur(translate(a1b0,' ','+'))
  2902. else
  2903.    return decodekeyval(translate(a1b0,' ','+'))
  2904.  
  2905.  
  2906. /************************************************/
  2907. /* procedure from TEST-CGI.CMD by  Frankie Fan <kfan@netcom.com>  7/11/94 */
  2908. DecodeKeyVal: procedure
  2909.   parse arg Code
  2910.   Text=''
  2911.   Code=translate(Code, ' ', '+')
  2912.   rest='%'
  2913.   do while (rest\='')
  2914.      Parse var Code T '%' rest
  2915.      Text=Text || T
  2916.      if (rest\='' ) then
  2917.       do
  2918.         ch = left( rest,2)
  2919.         if verify(ch,'01234567890ABCDEF')=0 then
  2920.            c=X2C(ch)
  2921.         else
  2922.            c=ch
  2923.         Text=Text || c
  2924.         Code=substr( rest, 3)
  2925.       end
  2926.   end
  2927.   return Text
  2928.  
  2929. /************************/
  2930. /* extract */
  2931. extract2:procedure expose standalone
  2932. parse upper arg aa
  2933. if  standalone=0 then do
  2934.    foo=extract(aa)
  2935.    return foo
  2936. end
  2937.  
  2938. select
  2939.    when aa='TRANSACTION' then return (10*dospid())+dostid()
  2940.    when aa='LIMITTIMEINACTIVE' then return 20
  2941.    otherwise return 0
  2942. end
  2943.  
  2944.  
  2945.  
  2946. /************************/
  2947. /* wild card match, with comparision against prior wild card match */
  2948. /* needle : what to look for 
  2949.    haytack : what to compare it to. Haystack may contain numerous * wildcard 
  2950.              characters
  2951.    oldresu : prior return from sref_wild_match; or empty.
  2952. Return (depends on oldresu):
  2953.   If needle is exact match to haystack: return -1
  2954.   If needle does not match haystack (even with wild card checking) : return 0
  2955.   If needle wildcard matches haystack, and oldresu='': returns match information
  2956.   If needle wildcard matches haystack, and if oldresu<>'' (is a prior 
  2957.    return from sref_wild_match), then the current match is compared to
  2958.    this oldresu.  If the current match is "better" (has more matching 
  2959.    characters early in the string), then : return match info
  2960.    If it's worse (or the same): return 0
  2961.  
  2962. Basically, -1 means "exact match", 0 means "no match" or "not better match"
  2963. (if oldresu not specified, 0 always means "no match"), and everything else
  2964. means "wild card match".
  2965. */
  2966.  
  2967. wild_match:procedure
  2968. parse upper arg needle, haystack,oldresu
  2969.  
  2970.  
  2971.  aresu=awild_match(needle,haystack)
  2972.  if aresu=0 then return aresu     /* no match */
  2973.  if aresu=-1 | oldresu=' ' then return aresu  /* exact match, or first wildcard match */
  2974.  
  2975. /* Is this a better WILDCARD MATCH */
  2976.    wrdsnew=words(ARESU);wrdsold=words(oldRESU)
  2977.    useold=1
  2978.    do Nmm=1 to max(wrdsold,wrdsnew)
  2979.        if Nmm>wrdsnew then leave
  2980.        if Nmm>wrdsold then do
  2981.              useold=0; leave
  2982.        end  
  2983.        a1=strip(word(oldresu,Nmm))
  2984.        a2=strip(word(aresu,Nmm))
  2985.        if a1=a2  then iterate
  2986.        if a2>a1 then leave  /* new matching element > old matching element, thus new is worse match */
  2987.        useold=0           /* found a matching element in new < then corresponding element in old*/
  2988.        leave            /* thus, new is better match */
  2989.     end
  2990.  
  2991.     IF USEold=0 THEN return aresu
  2992.      return 0           /* non superior match (might be same, in which case old is used*/
  2993.  
  2994.  
  2995.  
  2996.  
  2997. awild_match:procedure
  2998. parse upper arg needle, haystack ; haystack=strip(haystack)
  2999. needle=strip(needle)
  3000.  
  3001. if needle=haystack then return -1        /* -1 signals exact match */
  3002. ast1=pos('*',haystack)
  3003. if ast1=0 then return 0                 /* 0 means no match */
  3004. if haystack='*' then  do
  3005.    if length(needle)=0 then 
  3006.        return 100000
  3007.     else 
  3008.         return length(needle)
  3009. end
  3010. ff=haystack
  3011. ii=0
  3012. do until ff=""
  3013.   ii=ii+1
  3014.   parse var ff hw.ii '*'  ff
  3015.   hw.ii=strip(hw.ii)
  3016. end
  3017. if hw.ii='' then ii=ii-1
  3018. hw.0=ii
  3019.  
  3020.  
  3021. /* check each component of haystackw against needle -- all components
  3022. must be there */
  3023.  
  3024. resu=' '
  3025. istart=1 ; ido=2
  3026. if ast1>1 then do       /* first check abbrev */
  3027.   if abbrev(needle,hw.1)=0 then return 0
  3028.   aresu=length(hw.1)
  3029.   if hw.0=1 then do
  3030.      do nm=1 to aresu
  3031.         resu=resu||' '||nm
  3032.      end /* do */
  3033.      return resu         /* if haystacy of form abc*, we have a match */
  3034.   end
  3035.   ido=2 ; istart=aresu+1
  3036.   do mm=1 to aresu
  3037.         resu=resu||' '||mm
  3038.   end /* do */
  3039. end
  3040. /* if here, then first part (a non wildcard) of haystack matches first
  3041. part of needle
  3042. Now check sequentially that each remaining part also exists
  3043. */
  3044. do mm=ido to hw.0
  3045.   igoo=pos(hw.mm,needle,istart)
  3046.   if igoo=0 then return 0
  3047.   tres=length(hw.mm)
  3048.   istart=igoo+tres
  3049.   do nn=igoo to (istart-1)
  3050.      resu=resu||' '||nn
  3051.   end /* do */
  3052. end
  3053. if istart >= length(needle) | right(haystack,1)='*' then
  3054.    return resu
  3055. return 0
  3056.  
  3057.  
  3058.  
  3059.  
  3060. /************/
  3061. /* create a base64 packing of a message */
  3062. mk_base64:procedure
  3063.  
  3064. do mm=0 to 25           /* set base 64 encoding keys */
  3065.    a.mm=d2c(65+mm)
  3066. end /* do */
  3067. do mm=26 to 51
  3068.    a.mm=d2c(97+mm-26)
  3069. end /* do */
  3070. do mm=52 to 61
  3071.    a.mm=d2c(48+mm-52)
  3072. end /* do */
  3073. a.62='+'
  3074. a.63='/'
  3075.  
  3076. parse arg mess
  3077. s2=x2b(c2x(mess))
  3078. ith=0
  3079. do forever
  3080.    ith=ith+1
  3081.    a1=substr(s2,1,6,0)
  3082.    ms.ith=x2d(b2x(a1))
  3083.    if length(s2)<7 then leave
  3084.    s2=substr(s2,7)
  3085. end /* do */
  3086. pint=""
  3087. do kk=1 to ith
  3088.     oi=ms.kk ; pint=pint||a.oi
  3089. end /* do */
  3090. j1=length(pint)//4
  3091. if j1<>0 then pint=pint||copies('=',4-j1)
  3092. return pint
  3093.  
  3094. /************/
  3095. /* <BR>eak a long url (for use in cell of table as target of link)
  3096.    alen -- max width (between <BR>
  3097.    nosn -- strip out http://xxx.yy/ portion 
  3098. */
  3099.  
  3100. breakup:procedure
  3101. parse arg aword,alen,homesite
  3102. parse upper var homesite . '//' homesite '/' .
  3103. homesite=translate(homesite)
  3104. parse var aword . '//' aword
  3105. nosn=0
  3106. if homesite<>'' then do
  3107.    if abbrev(translate(aword),homesite)=1 then nosn=1
  3108. end /* do */
  3109.  
  3110. if nosn=1 then do
  3111.    parse var aword '/' aword
  3112.    if length(aword)<=alen then return '/'aword
  3113.    asn='' ; req='/'aword
  3114. end /* do */
  3115. else do
  3116.    if length(aword)<=alen then return aword
  3117.    parse var aword asn '/'  req ; asn=asn'/<br>'
  3118. end   
  3119.  
  3120. parse var req  rq '?' opts
  3121.  
  3122. if length(rq)>alen then rq=left(rq,alen)||'...<br>'
  3123. if length(opts)>alen then opts=left(opts,alen)'...'
  3124. if opts<>'' then rq=rq'?'
  3125.  
  3126. return asn||rq||opts
  3127.  
  3128.  
  3129.  
  3130.