home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume31 / dlhunter / part01 < prev    next >
Encoding:
Text File  |  1992-08-13  |  41.1 KB  |  1,402 lines

  1. Newsgroups: comp.sources.misc
  2. From: middle@cse.uta.edu  (William Middleton)
  3. Subject:  v31i070:  dlhunter - news binary extraction utility v2.02, Part01/01
  4. Message-ID: <1992Aug2.025304.9353@sparky.imd.sterling.com>
  5. X-Md4-Signature: 31f01253e66c626d7d097e87421466c0
  6. Date: Sun, 2 Aug 1992 02:53:04 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: middle@cse.uta.edu  (William Middleton)
  10. Posting-number: Volume 31, Issue 70
  11. Archive-name: dlhunter/part01
  12. Environment: perl, news
  13.  
  14. dlhunter is an automated news binary extraction utility.  
  15.  
  16. dlhunter is designed to run as a bckgd process, preferably daily by cron.
  17. It hunts for uuencoded files in the binary news directories that you specify.
  18. It uses (preferably) links, in its own queue directory.  When a given picture 
  19. or tool has all parts posted, it attempts to assemble it, if successful the 
  20. complete binary is placed in a download directory.  A short blurb, with the 
  21. info from part 01, is placed in a blurb directory when a binary is successfully
  22. decoded.  All directories are expired according to your specification. Note 
  23. that the download directory should have lots of space available.  
  24.  
  25. This version has a -i flag which starts dlhunter in interactive mode, to allow
  26. the admin (user) to manually assemble postings with ungrokkable subject lines.
  27.  
  28. You (admin preferably) MUST edit the configuration area in the script.  You 
  29. MUST also create the relevant directories. I've tried to make it as easy as 
  30. possible.  Send me mail if you have trouble.  Alternatively, learn perl.
  31.  
  32. ---
  33. #! /bin/sh
  34. # This is a shell archive.  Remove anything before this line, then feed it
  35. # into a shell via "sh file" or similar.  To overwrite existing files,
  36. # type "sh file -c".
  37. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  38. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  39. # Contents:  README dlhunter dlhunter.1 myuud.c
  40. # Wrapped by kent@sparky on Sat Aug  1 21:34:33 1992
  41. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  42. echo If this archive is complete, you will see the following message:
  43. echo '          "shar: End of archive 1 (of 1)."'
  44. if test -f 'README' -a "${1}" != "-c" ; then 
  45.   echo shar: Will not clobber existing file \"'README'\"
  46. else
  47.   echo shar: Extracting \"'README'\" \(1913 characters\)
  48.   sed "s/^X//" >'README' <<'END_OF_FILE'
  49. X
  50. XDLHUNTER - 
  51. X  dlhunter is designed to run as a bckgd process, preferably daily
  52. Xby cron.  It hunts for uuencoded files in the binary news directories
  53. Xthat you specify.  It uses (preferably) links, in its own queue directory.
  54. XWhen a given picture/tool has all parts posted, it attempts to
  55. Xassemble it, if successful the complete binary is placed in a download
  56. Xdirectory.  A short blurb, with the info from part 01, is placed in a
  57. Xblurb directory when a binary is successfully decoded.  All directories
  58. Xare expired according to your specification. Note that the download
  59. Xdirectory should have lots of space available.  And watch the errors
  60. Xfiles, they grow.
  61. X  This second version has a -i flag which starts dlhunter in interactive 
  62. Xmode, to allow the admin (user) to manually assemble postings with un-
  63. Xgrokkable subject lines.
  64. X  You (admin preferably) MUST edit the configuration area in the script.  
  65. XYou MUST also create the relevant directories. I've tried
  66. Xto make it as easy as possible.  Send me mail if you have trouble.
  67. XAlternatively, learn perl.
  68. X
  69. X
  70. X Update : July 17,1992
  71. X    You must now specify your own decoder in the configuration area.
  72. X
  73. X Update : July 22, 1992
  74. X    myuud.c is now bundled with the release.  
  75. X
  76. XTODO: 
  77. X*  someone has already started to hack this thing to work across NNTP
  78. X
  79. X*  noone has beat my regexp match for parsing subject lines, yet.
  80. X   Of course, that'd save more time in interactive mode.
  81. X
  82. X*  do an analogous thing for the news sources directories, unpacking and
  83. X   tarzeeing them.  volunteers?  I'm gettin kinda bored.
  84. X
  85. X  Enjoy, and save disk space.  Hack at will, but let me know.
  86. X  If you do hack you gotta share.
  87. X
  88. XThanks to:  
  89. X     6o25@sdf.lonestar.org  ( Stephen Jones, the man with the idea )
  90. X     sbw@naucse.cse.nau.edu ( Steve Wampler, turned me on to perl )
  91. X            
  92. X
  93. XbILL
  94. Xwjm@sdf.lonestar.org, middle@cse.uta.edu, wjmi@lightnin.lonestar.org
  95. Xperl, what else?  hmmm?
  96. X
  97. END_OF_FILE
  98.   if test 1913 -ne `wc -c <'README'`; then
  99.     echo shar: \"'README'\" unpacked with wrong size!
  100.   fi
  101.   # end of 'README'
  102. fi
  103. if test -f 'dlhunter' -a "${1}" != "-c" ; then 
  104.   echo shar: Will not clobber existing file \"'dlhunter'\"
  105. else
  106.   echo shar: Extracting \"'dlhunter'\" \(17539 characters\)
  107.   sed "s/^X//" >'dlhunter' <<'END_OF_FILE'
  108. X#!/usr/local/bin/perl
  109. X#eval 'exec /usr/local/bin/perl -S $0 ${1+"$@"}'
  110. X#if 0;
  111. X#
  112. X# July 4, 1992 - First release ( version 1.00 ) 
  113. X#
  114. X# July 7, 1992  -  First revision, ( version 1.01 ) 
  115. X# repair an expire bug that deleted all
  116. X# the files once the script completed.
  117. X#
  118. X# July 13, 1992 -  Second Revision, ( version 2.00 ) 
  119. X# added several new features, including interactive mode
  120. X# to allow the admin ( or his DA ) to easily grok through the
  121. X# remaining links in the queue, assembling binaries with 
  122. X# un-grokkable subject lines, or other things the daemon doesn't like. 
  123. X# You can also (optionally) use a subdirectory structure for downloads.
  124. X# Further, dlhunter has a better decoder now. 
  125. X#  
  126. X# July 16, 1992  - third revision,  (version 2.01)
  127. X# well, i'm sick of try_to_decode screwing up, so i've decided to
  128. X# use a user supplied routine as the exec.  you must now edit the 
  129. X# configuration area to specify the path to the uudecoder of your preference.
  130. X# dlhunter will pass all parts thereto, and use the return value of 0
  131. X# as an indication of success.  there are many decoders out there, this
  132. X# version is released with a call to uud.  ( maman@cosinus.inria.fr )
  133. X# which works pretty good. The decoder must be of the type that will
  134. X# strip all necessary junk.
  135. X# 
  136. X# July 22, 1992  - fourth revision  (version 2.02)
  137. X# now includes a man page and README.  small bugs taken out of
  138. X# sub hunt (interactive mode), which printed zero-length blurbs.
  139. X# and died on expired links.  Now includes myuud, by permission.
  140. X# added one more regexp to try to grok subject lines, and took
  141. X# a little rigor out of the parts verification.
  142. X# 
  143. X#
  144. X# 
  145. X# --------------------------------------------------------------------- 
  146. X# General Info:
  147. X# dlhunter is designed to run as a bckgd process, by cron. 
  148. X#
  149. X# But it now has an interactive mode, invoked as dlhunter -i.  
  150. X# you will see the older links in the queue printed on the screen,
  151. X# with their corresponding subject lines.  These are the ones that dlhunter,
  152. X# or try_to_decode couldnt handle.  You must give filenumbers to the prompt
  153. X# after the listing.  It will then try to do its regular thing with them.
  154. X# If successful, the links will be removed from the queue. 
  155. X#
  156. X# You must edit the following variables.   MUST!
  157. X# You must create relevant directories if necessary.  MUST!
  158. X# Your queue must be on the same fs as news. 
  159. X# if you insist on using symlinks, clear the queue before each run.
  160. X#
  161. X# dlhunter will find binaries in any dir you care to give it.
  162. X# 
  163. X#***************************  Edit these   ***********************************
  164. X#******************* and create relevant directories!!! ***********************
  165. X#
  166. X#  Which decoder do you wanna use?  It's got to be the kind that will
  167. X# strip off all the junk!  the myuud bundled is good, use the -v option.
  168. X$usr_decode = '/usr/local/bin/myuud  -v ';
  169. X
  170. X#  where are the binaries directories, the news directories where
  171. X#  binary files are posted 
  172. X@tooldirs =(
  173. X         '/var/spool/news/alt/binaries/pictures',
  174. X         '/var/spool/news/alt/binaries/pictures/erotica',
  175. X         '/var/spool/news/alt/binaries/pictures/misc',
  176. X         '/var/spool/news/alt/binaries/pictures/utilities',
  177. X         '/var/spool/news/comp/binaries/os2',
  178. X         '/var/spool/news/comp/binaries/ibm/pc'
  179. X           );
  180. X
  181. X# we need an extension for each tooldir, to assure uniqueness in the queue
  182. X@exts = ('.pc1','.ero','.misc','.util','.os2','.ibm');
  183. X
  184. X# Next, by special request, we include an optional associative array to
  185. X# allow dlhunter to put the binaries in a sub directory structure below  
  186. X# the actual download directory.  If you wish to use this feature, you must
  187. X# uncomment and edit the following lines, which define the associative array.
  188. X# Then, create the download dirs corresponding to the exts.  dlhunter will then
  189. X# automatically dump the binaries in the associated subdir.  Remember to also
  190. X# create the blurb directories, beneath each respective download directory.
  191. X# To edit this array declaration, be sure to associate your download/blurb dir
  192. X# with its corresponding extension (key). Separate the download dir from its
  193. X# corresponding blurb dir with a colon.  Send me mail at cse with questions.
  194. X#                     
  195. X# %dldirs = (
  196. X#         '.pc1' , '/tmp/downloads/pictures:/tmp/downloads/pictures/blurbs' ,
  197. X#          '.ero' , '/tmp/downloads/erot:/tmp/downloads/erot/blurbs' ,
  198. X#          '.misc' , '/tmp/downloads/misc:/tmp/downloads/misc/blurbs' ,
  199. X#          '.util' , '/tmp/downloads/util:/tmp/downloads/util/blurbs' ,
  200. X#          '.os2' , '/tmp/downloads/os2:/tmp/downloads/os2/blurbs' ,
  201. X#          '.ibm' , '/tmp/downloads/ibm:/tmp/downloads/ibm/blurbs'
  202. X#           );
  203. X#
  204. X# The queue directory, for links to uu postings, until all parts have arrived.
  205. X#  IMPORTANT!!  This directory MUST be on the same filesystem as the news
  206. X# directories. (@tooldirs)  For a number of good reasons...
  207. X$quedir = '/var/spool/news/dl_hunter/queue';
  208. X
  209. X# Now, where are the assembled tools/pictures to go?  This is 
  210. X# still the default location for the extracted binaries.
  211. X$dloaddir = '/tmp/downloads';
  212. X
  213. X# We also need an associated blurb directory.  This is also the default.
  214. X$blurbdir = '/tmp/downloads/blurbs';
  215. X
  216. X# Expire times correspond to number of days since created, for the queue,
  217. X# and number of days since last accessed, for the downloads (binaries).
  218. X$qkill = 3;    # queue
  219. X$dlkill = 3;  # downloads
  220. X
  221. X###################  END OF CONFIGURATION   ##############################
  222. X
  223. X#  First, if we are running in interactive mode, 
  224. X#  just call the hunt routine and exit.
  225. X#
  226. Xif (@ARGV[0] eq "-i"){
  227. X&hunt();
  228. Xexit(0);
  229. X}
  230. X
  231. X# Next, link (copy) the new postings that are (probably) uuencoded to the queue
  232. X# Pass 1 
  233. X
  234. XT1: for (0 .. $#tooldirs){          
  235. X      $i = $_;
  236. X      opendir(TOOLS,$tooldirs[$i]);
  237. X      @uufiles =grep(!/^\.\.?$/ , readdir(TOOLS)); # get all current postings 
  238. X      closedir(TOOLS);
  239. XM1:   foreach $file (@uufiles){
  240. X        open(CURR,"$tooldirs[$i]/$file")||next M1;      
  241. X        $count = 0;
  242. XL1:       while(<CURR>){    #  check to see if its a uuencoded file
  243. X          if($count > 3){ 
  244. X            close CURR; 
  245. X
  246. X# IMPORTANT : use link here, ( DONT USE SYMLINKS ) otherwise, you must
  247. X# ^^^^^^^^^   hack a copy in here if your queue is not on the same fs as news 
  248. X#             if you can only use symlinks, clear the queue before each run
  249. X
  250. X             if( !(-e "$quedir/$file$exts[$i]")){
  251. X              link ("$tooldirs[$i]/$file","$quedir/$file$exts[$i]") ||
  252. X                die " You cant use hard links in this queue directory.\n";}
  253. X            next M1;}
  254. X            next L1 if /[a-z]/;
  255. X            next L1 unless /(^M.*$)|(^X.*$)/;# if there are 3 lines that beginh
  256. X            $count++;                 # with an M or an X, count it as a encode
  257. X          }                           # or shar, respectively
  258. X        next M1;
  259. X         }
  260. X     next T1;
  261. X      } 
  262. X
  263. X# Now hunt through the files in the queue, build an assoc array
  264. X# of filenames in the queue, keyed on title of the tool/picture
  265. X# (*.zip, *.zoo, *.jpg, *.gif, etc.) given in the Subject: line.
  266. X# Now, this is trivial for moderated groups, but not so easy for alt. 
  267. X# Also, obtain the part number, (m of n, m/n, m|n, etc.) and the total
  268. X# number of parts.  
  269. X# Pass 2
  270. X
  271. Xopendir(UUS,$quedir)||die ("cant open directory $dir");
  272. X@allfiles = grep(!/^\.\.?$/ , readdir(UUS));   
  273. Xclosedir(UUS);
  274. XT2: foreach $file (@allfiles) {
  275. X      open(CURR,"$quedir/$file")||warn "cant open file $file";
  276. XM2:  while (<CURR>){
  277. X        study;
  278. X        next M2 unless 
  279. X#  try to find the standard "name.ext" followed
  280. X#  by the word "part" then the numbers.
  281. X# try to beat the number of matches i get from these by twiddlin the regexps.
  282. X# let me know how it turns out.  always use the part keyword in subject!
  283. X
  284. X(/^Subject:.*\s(\S+\.\S+).*[Pp][Aa][Rr][Tt]\D*[0]*([1-9][0-9]?)\D+[0]?([1-9][0-9]?).+$/) 
  285. X
  286. X# maybe we can match the whole line, followed by the part keyword.
  287. X||(/^Subject:(.*)[Pp][Aa][Rr][Tt]\D*[0]*([1-9][0-9]?)\D+[0]?([1-9][0-9]?).+$/) 
  288. X
  289. X# oh well, default match
  290. X|| /^Subject:.*\s(\S+\.\S+)\s*[,]*\D*[0]?([1-9][0-9]?)\D+[0]?([1-9][0-9]?).+$/;
  291. X
  292. X        $name=$1;$part=$2;$total=$3;
  293. X        $titles{$name} .= "$quedir/$file"." "."$part"." "."$total"." ".":";
  294. X        next T2;
  295. X     }
  296. X    }
  297. X# ok, now work the assoc array. For each title (key) in the associative array 
  298. X# that we filled in the last loop, verify all parts are in, then check
  299. X# to see if the file has already been decoded, try to decode and, if successful,
  300. X# move to download directory.  Then add a blurb file to blurb dir, telling
  301. X# about the new tool or picture.  Make the blurb world writable for comments.
  302. X# Pass 3
  303. X
  304. Xopen(TEST,"> tst.out");            # when done, tst.out tells you how it went.
  305. X@uu_tools = sort(keys(%titles));   # i like things sorted.
  306. XT3: foreach $tool (@uu_tools){
  307. X      @order = "";     # clear the ordered array. 
  308. X      @parts = "";
  309. X      @rel_files = split(/:/,$titles{$tool});   # relevant files to each title
  310. X      print TEST "$tool \n";
  311. X      foreach $tmp2 (@rel_files) {print TEST "$tmp2\n";}
  312. X       print TEST "\n\n I chose this order for them....\n";
  313. XM3A:  foreach $part (@rel_files){
  314. X         @tmp = split(/\s/,$part);
  315. X         $parts[$tmp[1]] = $tmp[2];               # save the total parts
  316. X         if(defined $order[$tmp[1]]){           # may be a repost, use new one 
  317. X          if (-M $tmp[0] < -M $order[$tmp[1]]){
  318. X           unlink $order[$tmp[1]];               # and get rid of the old.
  319. X           $order[$tmp[1]] = $tmp[0]; 
  320. X           }} 
  321. X         else{                                
  322. X           $order[$tmp[1]] = $tmp[0];  }
  323. X      }
  324. X# Now test the order array to make sure all parts are available.
  325. X
  326. X      foreach $tmp2 (@order) {print TEST "$tmp2\n";}
  327. X       print TEST "\n\n";
  328. X       $ck = $#order;   
  329. XM3B:  for (1..$#order){
  330. X        next T3 unless defined $order[$_];
  331. X#        next T3 unless $parts[$_] == $ck ;  
  332. X      }
  333. X
  334. X# If we make it this far, we might have a complete encode.  
  335. X# First check to see if the encode is already available,     
  336. X# then try to decode it if not.  If successful, mv and write a blurb.
  337. X
  338. Xif (&dont_have($dloaddir,$order[1])){         # if no got, try to decode
  339. X  if ($new = &try_to_decode(@order)){        # returns the decode's name or 0
  340. X      &write_blurb($new,$blurbdir,$order[1]);# a short blurb written out
  341. X      unlink @order;                        # remove the queue links
  342. X}}                                   
  343. Xelse{
  344. X   unlink @order;}         # unlink the queue links if already decoded.
  345. X
  346. X}    # end of third pass
  347. X
  348. X# Finally, expire the old stuff.  We use last modification dates for the queue,
  349. X# and last-access dates for the download directory, and blurb directory. 
  350. X
  351. Xif(defined (%dldirs)){      # if using the option...
  352. X  foreach $ext (@exts){
  353. X   ($dir1,$dir2) = split(/:/,$dldirs{$ext});
  354. X   &expire($dir1,$dlkill,'-A');
  355. X   &expire($dir2,$dlkill,'-A');
  356. X  }
  357. X   &expire($quedir,$qkill,'-M');
  358. X}
  359. Xelse{                          # the one dir approach.
  360. X&expire($quedir,$qkill,'-M');
  361. X&expire($dloaddir,$dlkill,'-A');  
  362. X&expire($blurbdir,$dlkill,'-M');
  363. X}
  364. Xclose(TEST);
  365. Xexit(0);      # thats it, nice job.
  366. X
  367. X##########################################################################
  368. X
  369. Xsub dont_have{          # checks if the decoded file already exists
  370. X  local ($name) = $_[1];
  371. X  local($dir,$junk) = &which_dir( $name);
  372. X  open (CK, "$name")||die "couldnt open the file $_[1]";
  373. X  while(<CK>){          # find the begin line and name
  374. X    next unless
  375. X     /^begin\s*\d*\s*(\S*)/;
  376. X     if (-e "$dir/$1"){ return 0;}   # already exists
  377. X     else{ return 1;}
  378. X  }
  379. Xreturn 0;        # begin not found
  380. X}
  381. X
  382. X############################################################################
  383. X
  384. Xsub try_to_decode{       # a semi-bulletproof decoder.
  385. X   local($cur) = `pwd`;  # now calls myuud  (Thanks Maman!)
  386. X   local($tmpf) = 'tmp';
  387. X   local(@files) = @_;
  388. X   local($dl,$junk) = &which_dir($files[1]); # for the optional download sub-dir
  389. X   chdir $dl;
  390. X   open(BEGIN,"<$files[1]");
  391. X   open(ENCODE,">$tmpf");
  392. X   $_ = <BEGIN> until ($mode,$file) = /^begin\s*(\d*)\s*(\S*)/i;
  393. X   for (1..$#files){        #build up a temporary file from the parts
  394. X    $val = open(IN,"< $files[$_]");
  395. X    if(! $val){ warn "couldnt open $files[$_]"; return 0;}
  396. X    while(<IN>){ next unless /^\s*$/;last;}  # skip the header.
  397. X    while (<IN>){
  398. X      print ENCODE $_;
  399. X   }}
  400. X  close(ENCODE);
  401. X# implicit child, to handle errors from uudecode, as recommended by lwall.
  402. X  $pid = open(PIPE, "|-");
  403. X   die "Fork failure" unless defined $pid;
  404. X   if(!$pid){
  405. X    exec "$usr_decode $tmpf >> errors  2>> errors";  # spawn it on the child.
  406. X   }
  407. X  close (PIPE);
  408. X  if($?){unlink($tmpf,$file);           # uudecode didnt like it.
  409. X        system "echo $file >>errors";   # a line to the errors file
  410. X        chdir $cur;
  411. X        return 0;} # error in the decoding, rm and return
  412. X  chmod 0644, $file;
  413. X  unlink ($tmpf);
  414. X  chdir $cur;
  415. X  return $file;                        # return the name.
  416. X}                 
  417. X
  418. X#########################################################################
  419. X
  420. Xsub write_blurb{   # makes a file with the info on the tool/picture
  421. X  local($name,$dir,$file) = @_;
  422. X  local($junk) = 0;
  423. X  ($junk,$dir) = &which_dir($file);
  424. X  open(BLURB,"> $dir/$name")||die "couldnt open blurb $name";
  425. X  open(IN, "< $file");  # stuff from part 1 up to the begin line
  426. X   while(<IN>){
  427. X    last if /^begin/;
  428. X    print BLURB $_;}
  429. X close BLURB;   
  430. X chmod 0666, "$dir/$name";   # make it available to comments
  431. X}
  432. X########################################################################## 
  433. X
  434. Xsub expire{                # delete old files from the downloads, blurbs,
  435. X  local($dir,$days,$how) = @_; # and queue directories. $how is the method. 
  436. X  opendir(UL,$dir);
  437. X  local(@allfiles) = grep(!/^\.\.?$/ , readdir(UL));   
  438. X  closedir(UL);
  439. X  local($file) = "";
  440. X  foreach $file (@allfiles){
  441. X  if ( $how eq '-A'){
  442. X   unlink "$dir/$file" unless  (-A "$dir/$file" < $days);}
  443. X  elsif ( $how eq '-M'){
  444. X   unlink "$dir/$file" unless  (-M "$dir/$file" < $days);}
  445. X  elsif ($how eq '-C'){
  446. X   unlink "$dir/$file" unless  (-C "$dir/$file" < $days);}
  447. X  }
  448. X  } 
  449. X ##########################################################################
  450. X
  451. Xsub hunt
  452. X# hunt for and manually assemble the older links in the queue.
  453. X# open the queue directory, and report on the articles
  454. X# that have not been deleted, and are greater than 1 day
  455. X# old. Then give the user the opportunity to assemble
  456. X# uuencoded binaries from the various articles. 
  457. X{
  458. Xlocal($ldir,$file,$ans,$tmp,$subject,$wait,$tmpo) = (0,0,0,0,0,0,0);
  459. Xlocal(@allfiles)=();
  460. Xlocal(@order) = ();
  461. Xlocal(@number) = ();
  462. Xlocal(@forder) = ();
  463. X$= = 22;          # a screenful at a time
  464. XT: while (1) 
  465. X{
  466. X  system "clear";
  467. X  $- = 0;
  468. X  opendir(QUEUE,$quedir);
  469. X  @allfiles = grep(!/^\.\.?$/ , readdir(QUEUE)); # get all the current postings 
  470. X  closedir(QUEUE);
  471. X  $i = 0;
  472. XMID: foreach $file (@allfiles) {
  473. X      next MID unless -M "$quedir/$file" > 1;   # dont bother with the new ones
  474. X      open(CURR,"$quedir/$file");
  475. XLOW:  while (<CURR>){
  476. X        next LOW unless /^Subject:(.*$)/;
  477. X        $subject = $1;
  478. X        $number[$i] = "$quedir/$file";
  479. X        #feed a screenful at a time.  crude.
  480. X        if($- == 0){ print "<CR> to continue...";chop($wait=<STDIN>);write;}
  481. X        else{write;}
  482. X        $i++;
  483. X        next MID; 
  484. X  }
  485. X }    # still in the T loop...
  486. X    print "\nEnter the article numbers which make up the tool/pict\n";
  487. X    print "\n             IN THE CORRECT ORDER \n\n";
  488. X    print "     separated by a space, and followed by a <CR>.\n";
  489. X    print "     Or just enter a carriage return to quit.\n ";
  490. X     chop($tmp =<STDIN>);
  491. X     if ($tmp eq ""){ return;}
  492. X     @order = split(/ /,$tmp);        
  493. X     $i=1;
  494. X     foreach $tmpo (@order){ $forder[$i] = $number[$tmpo];
  495. X                            print $forder[$i],"\n"; $i++;} #whew
  496. X
  497. X     if(!&dont_have(0,$forder[1])){
  498. X       print "already got that one, deleting links\n"; 
  499. X       print "<CR> to continue...";chop($wait=<STDIN>);
  500. X       unlink @forder;
  501. X       next T;}
  502. X     else{          # if the tool/picture is not already present
  503. X       if ($name = &try_to_decode(@forder)){    # try to decode it
  504. X         print " successful decode, new file is named $name\n" ;
  505. X         print " writing a new blurb now\n";
  506. X         print "<CR> to continue...";chop($wait=<STDIN>);
  507. X         &write_blurb($name,$ldir,$forder[1]);
  508. X         unlink @forder;
  509. X         next T;}
  510. X       else{
  511. X         print " decoding unsuccessful, try to find out what the prob is.";
  512. X         print "\n<CR> to continue...";chop($wait=<STDIN>);
  513. X         next T;}
  514. X }
  515. X}
  516. X} 
  517. X###########################################################################
  518. Xsub which_dir{   # determine which dir to dump binaries in.
  519. X                
  520. Xlocal($name,$ext) = (@_[0],0);
  521. X$name =~ /.*(\..*\b).*/;
  522. X$ext = $1;
  523. Xif(defined $dldirs{$ext}){    #  if the option is in use.
  524. X  ($dl,$bl) = split(/:/,$dldirs{$ext});
  525. X  return ($dl,$bl);}
  526. Xelse{
  527. X  return ($dloaddir,$blurbdir);}
  528. X}
  529. X#########################################################################
  530. Xformat STDOUT_TOP =
  531. XThese are the current postings in @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 
  532. X$quedir
  533. Xwhich MAY be tools/picts.  You must give me the article 
  534. Xnumbers, in the CORRECT order, for me to feed to uudecode.
  535. XFirst I will list them for you. 
  536. X
  537. XARTICLE 
  538. XNUMBER     SUBJECT
  539. X------   ----------------------------------------------------------------------
  540. X. 
  541. Xformat STDOUT =
  542. X@>>>    @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  543. X$i, $subject
  544. X. 
  545. X
  546. X #  Bill Middleton
  547. X #  wjm@sdf.lonestar.org, middle@cse.uta.edu
  548. X #  let me know what you think...
  549. X
  550. X
  551. X
  552. END_OF_FILE
  553.   if test 17539 -ne `wc -c <'dlhunter'`; then
  554.     echo shar: \"'dlhunter'\" unpacked with wrong size!
  555.   fi
  556.   chmod +x 'dlhunter'
  557.   # end of 'dlhunter'
  558. fi
  559. if test -f 'dlhunter.1' -a "${1}" != "-c" ; then 
  560.   echo shar: Will not clobber existing file \"'dlhunter.1'\"
  561. else
  562.   echo shar: Extracting \"'dlhunter.1'\" \(1318 characters\)
  563.   sed "s/^X//" >'dlhunter.1' <<'END_OF_FILE'
  564. X.TH dlhunter 1
  565. X.SH Name
  566. Xdlhunter \- automated news binary extraction utility. 
  567. X.SH Syntax
  568. X.B dlhunter
  569. X[\fB\-i\fR]
  570. X.SH Description
  571. X.PN dlhunter 
  572. Xis designed to run as a background process, by cron.  It will find 
  573. Xand extract uuencoded binaries in the news directories where they
  574. Xare posted. In fact, it will find uuencoded files in any directory, and 
  575. Xassemble them if the Subject lines give the correct part numbers.
  576. XThe command,
  577. X.PN  dlhunter 
  578. X\fB\-i\fR, starts 
  579. Xdlhunter in interactive mode, allowing the user to assemble those postings 
  580. Xwhich had Subject lines which 
  581. X.PN dlhunter 
  582. Xcould not grok.  All directories are expired according to the 
  583. Xuser-defined variables.  The code is
  584. X.PN perl
  585. Xand the script must be edited to suit the individual site.
  586. X.PN dlhunter
  587. Xuses hard links to the files it thinks are uuencoded.  And thus,
  588. Xthe queue directory, where the links are created, 
  589. X.PN must 
  590. Xbe on the
  591. Xsame fs as news.  
  592. X.PP
  593. X.PN dlhunter
  594. Xrequires a SMART uudecoder.  There are many available.
  595. X.PN myuud
  596. Xis bundled with version 2.02.
  597. XWhen you edit the configuration variables, you must specify
  598. Xthe path to one.
  599. X.PN
  600. X.PN  NOTE:  
  601. Xdlhunter is designed to save disk space and time.
  602. XThus, it should be run by 
  603. X.PN ONE 
  604. Xuser, and the binaries placed in a 
  605. X.PN PUBLIC 
  606. Xdirectory.  
  607. X.PN DONT
  608. X.PN BE
  609. X.PN A
  610. X.PN DISK
  611. X.PN HOG!
  612. X.PP
  613. END_OF_FILE
  614.   if test 1318 -ne `wc -c <'dlhunter.1'`; then
  615.     echo shar: \"'dlhunter.1'\" unpacked with wrong size!
  616.   fi
  617.   # end of 'dlhunter.1'
  618. fi
  619. if test -f 'myuud.c' -a "${1}" != "-c" ; then 
  620.   echo shar: Will not clobber existing file \"'myuud.c'\"
  621. else
  622.   echo shar: Extracting \"'myuud.c'\" \(16085 characters\)
  623.   sed "s/^X//" >'myuud.c' <<'END_OF_FILE'
  624. X/*
  625. X * Uud -- decode a uuencoded file back to binary form.
  626. X *
  627. X * From the Berkeley original, modified by MSD, RDR, JPHD & WLS.
  628. X * The Atari GEMDOS version compiled with MWC 2.x.
  629. X * The MSDOS version with TurboC.
  630. X * The Unix version with cc.
  631. X * this version is made: 25 Nov 1988.
  632. X *
  633. X * $Id: myuud.c,v 1.1 92/05/06 22:48:06 maman Exp Locker: maman $
  634. X *
  635. X * Mods :
  636. X * ------ 16 May 1991 ------ maman@cosinus.inria.fr ------
  637. X *    Table is reinitialised at the end of files in order to
  638. X *    avoid a table modification effect for next files.
  639. X * ------ 21 Feb 1991 ------ maman@cosinus.inria.fr ------
  640. X *    Now if the file is unwritable, opens /dev/null instead
  641. X *    to avoid breaking a multiple files run.
  642. X * ------ 14 Feb 1991 ------ maman@cosinus.inria.fr ------
  643. X *    (-c) dochmod added for UNIX.
  644. X * ------ 24 Jan 1991 ------ maman@cosinus.inria.fr ------
  645. X *    No use of ceil. (cdlen[] is already there).
  646. X *    valid_char, valid_length and valid_chars used.
  647. X *    (-v) verify flag added for more tests and more verbose,
  648. X *    exactly the way I like it ;-)
  649. X * ------ 23 Jan 1991 ------ maman@cosinus.inria.fr ------
  650. X *    I've taken this from ftp at sics.se:/mailserver/uudecode.shar
  651. X *    It was said Wrapped by Edwin Kremer <edwin@zlotty> on \
  652. X *    Wed Dec 20 17:06:37 1989
  653. X *
  654. X *    Checks the declared length and the effective length
  655. X *    in order to skip the header/signature of different
  656. X *    files and test the range validity of one character
  657. X *    in the middle of the buffer.
  658. X *    Works almost all the time.
  659. X *    Tolerate one more byte at the end for another count
  660. X *    (should be given as a parameter ?).
  661. X *    UNIX compilation: cc [-O] -o uud uud.c
  662. X */
  663. X
  664. X/*
  665. X * Be sure to have the proper symbol at this point. (GEMDOS, MSDOS, UNIX...)
  666. X */
  667. X/*
  668. X#ifndef GEMDOS
  669. X#define GEMDOS 1
  670. X#endif
  671. X */
  672. X#ifndef UNIX
  673. X#define UNIX 1
  674. X#endif
  675. X/*
  676. X#ifndef MSDOS
  677. X#define MSDOS 1
  678. X#endif
  679. X */
  680. X
  681. X#undef GWMDOS
  682. X#undef MSDOS
  683. X
  684. X#ifdef GEMDOS
  685. X#define SYSNAME "gemdos"
  686. X#define SMALL 1
  687. X#endif
  688. X#ifdef MSDOS
  689. X#define SYSNAME "msdos"
  690. X#define SMALL 1
  691. X#endif
  692. X#ifdef UNIX
  693. X#define SYSNAME "unix"
  694. X#define format printf
  695. X#define TEST_LENGTH
  696. X#endif
  697. X
  698. X#include <stdio.h>
  699. X
  700. X#ifdef GEMDOS
  701. X#include <osbind.h>
  702. X#define Error(n)  { Bconin(2); exit(n); }
  703. X#define WRITE      "wb"
  704. X#else
  705. X#define Error(n)  exit(n)
  706. X#define WRITE      "w"
  707. X#endif
  708. X
  709. X#define loop    while (1)
  710. X
  711. Xextern FILE *fopen();
  712. Xextern char *strcpy();
  713. Xextern char *strcat();
  714. X
  715. Xchar *getnword();
  716. X
  717. X#define MAXCHAR 256
  718. X#define LINELEN 256
  719. X#define FILELEN 64
  720. X#define NORMLEN 60    /* allows for 80 encoded chars per line */
  721. X
  722. X#define SEQMAX 'z'
  723. X#define SEQMIN 'a'
  724. Xchar seqc;
  725. Xint first, secnd, check, numl;
  726. X#ifdef TEST_LENGTH
  727. Xint numlbad = -1;
  728. X#endif
  729. X
  730. XFILE *in, *out;
  731. Xchar *pos;
  732. Xchar ifname[FILELEN], ofname[FILELEN];
  733. Xchar *source = NULL, *target = NULL;
  734. Xchar blank, part = '\0';
  735. Xint partn, lens;
  736. Xint debug = 0, nochk = 0, onedone = 0, verify = 0;
  737. X#ifdef UNIX
  738. Xint dochmod = 1;
  739. X#endif
  740. Xint chtbl[MAXCHAR], cdlen[NORMLEN + 3];
  741. X
  742. Xmain(argc, argv) int argc; char *argv[];
  743. X{
  744. X    int mode;
  745. X    register int i, j;
  746. X    char *curarg;
  747. X    char dest[FILELEN], buf[LINELEN];
  748. X
  749. X    if (argc < 2) {
  750. X        format("Almost foolproof uudecode v3.4.2 (%s) 14-Feb-91\n",
  751. X            SYSNAME);
  752. X        format("\n");
  753. X#ifdef UNIX
  754. X        format("Usage: uud [-n] [-d] [-v] [-c] %s\n",
  755. X               "[-s dir] [-t dir] input-file");
  756. X#else
  757. X        format("Usage: uud [-n] [-d] [-v] %s\n",
  758. X               "[-s dir] [-t dir] input-file");
  759. X#endif
  760. X        format("\n");
  761. X        format("Option: -n -> No line sequence check\n");
  762. X        format("Option: -d -> Debug/verbose mode\n");
  763. X        format("Option: -v -> Verify all chars\n");
  764. X#ifdef UNIX
  765. X        format("Option: -c -> chmod not performed (umask used)\n");
  766. X#endif
  767. X        format("Option: -s + Source directory for all input files\n");
  768. X        format("  (MUST be terminated by directory separator)\n");
  769. X        format("Option: -t + Target directory for all output files\n");
  770. X        format("  (MUST be terminated by directory separator)\n");
  771. X        format("If input-file is - then stdin is used as input-file\n");
  772. X        Error(1);
  773. X    }
  774. X
  775. X    curarg = argv[1];
  776. X    
  777. X    while (curarg[0] == '-') {
  778. X        if (((curarg[1] == 'd') || (curarg[1] == 'D')) &&
  779. X            (curarg[2] == '\0')) {
  780. X            debug = 1;
  781. X#ifdef UNIX
  782. X        } else if (((curarg[1] == 'c') || (curarg[1] == 'C')) &&
  783. X               (curarg[2] == '\0')) {
  784. X            dochmod = 0;
  785. X#endif
  786. X        } else if (((curarg[1] == 'v') || (curarg[1] == 'V')) &&
  787. X               (curarg[2] == '\0')) {
  788. X            verify = 1;
  789. X        } else if (((curarg[1] == 'n') || (curarg[1] == 'N')) &&
  790. X               (curarg[2] == '\0')) {
  791. X            nochk = 1;
  792. X        } else if (((curarg[1] == 't') || (curarg[1] == 'T')) &&
  793. X               (curarg[2] == '\0')) {
  794. X            argv++;
  795. X            argc--;
  796. X            if (argc < 2) {
  797. X                format("uud: Missing target directory.\n");
  798. X                Error(15);
  799. X            }
  800. X            target = argv[1];
  801. X            if (debug||verify)
  802. X                format("Target dir = %s\n",target);
  803. X        } else if (((curarg[1] == 's') || (curarg[1] == 'S')) &&
  804. X               (curarg[2] == '\0')) {
  805. X            argv++;
  806. X            argc--;
  807. X            if (argc < 2) {
  808. X                format("uud: Missing source directory.\n");
  809. X                Error(15);
  810. X            }
  811. X            source = argv[1];
  812. X            if (debug||verify)
  813. X                format("Source dir = %s\n",source);
  814. X        } else if (curarg[1] != '\0') {
  815. X            format("uud: Unknown option <%s>\n", curarg);
  816. X            Error(15);
  817. X        } else
  818. X            break;
  819. X        argv++;
  820. X        argc--;
  821. X        if (argc < 2) {
  822. X            format("uud: Missing file name.\n");
  823. X            Error(15);
  824. X        }
  825. X        curarg = argv[1];
  826. X    }
  827. X
  828. X    if ((curarg[0] == '-') && (curarg[1] == '\0')) {
  829. X        in = stdin;
  830. X        strcpy(ifname, "<stdin>");
  831. X    } else {
  832. X        if (source != NULL) {
  833. X            strcpy(ifname, source);
  834. X            strcat(ifname, curarg);
  835. X        } else
  836. X            strcpy(ifname, curarg);
  837. X        if ((in = fopen(ifname, "r")) == NULL) {
  838. X            format("uud: Can't open %s\n", ifname);
  839. X            Error(2);
  840. X        }
  841. X        numl = 0;
  842. X    }
  843. X
  844. X    settable();
  845. X
  846. X/*
  847. X * set up the line length table, to avoid computing lotsa * and / ...
  848. X */
  849. X    cdlen[0] = 1;
  850. X    for (i = 1, j = 5; i <= NORMLEN; i += 3, j += 4)
  851. X        cdlen[i] = (cdlen[i + 1] = (cdlen[i + 2] = j));
  852. X/*
  853. X * search for header or translation table line.
  854. X */
  855. X    loop {    /* master loop for multiple decodes in one file */
  856. X        partn = 'a';
  857. X        loop {
  858. X            if (fgets(buf, sizeof buf, in) == NULL) {
  859. X                if (onedone) {
  860. X                    if (debug||verify)
  861. X                       format("End of file.\n");
  862. X                    exit(0);
  863. X                } else {
  864. X                    format("uud: No begin line.\n");
  865. X                    Error(3);
  866. X                }
  867. X            }
  868. X            numl++;
  869. X            if (strncmp(buf, "table", 5) == 0 &&
  870. X                buf[5] == '\n' ) {
  871. X                gettable();
  872. X                continue;
  873. X            }
  874. X            if (strncmp(buf, "begin ", 6) == 0) {
  875. X                break;
  876. X            }
  877. X        }
  878. X        lens = strlen(buf);
  879. X        if (lens) buf[--lens] = '\0';
  880. X#ifdef SMALL
  881. X        if ((pos = getnword(buf, 3))) {
  882. X            strcpy(dest, pos);
  883. X        } else
  884. X#else
  885. X        if(sscanf(buf,"begin%o%s", &mode, dest) != 2)
  886. X#endif
  887. X        {
  888. X            format("uud: Missing filename in begin line.\n");
  889. X            Error(10);
  890. X        }
  891. X
  892. X        if (target != NULL) {
  893. X            strcpy(ofname, target);
  894. X            strcat(ofname, dest);
  895. X        } else
  896. X            strcpy(ofname, dest);
  897. X
  898. X        if((out = fopen(ofname, WRITE)) == NULL) {
  899. X            format("uud: Cannot open output file: %s\n", ofname);
  900. X            format("uud: Sending to /dev/null.\n");
  901. X            strcpy(ofname, "/dev/null");
  902. X            out = fopen(ofname, WRITE);
  903. X        }
  904. X        if (debug||verify) format("Begin uudecoding: %s\n", ofname);
  905. X        seqc = SEQMAX;
  906. X        check = nochk ? 0 : 1;
  907. X        first = 1;
  908. X        secnd = 0;
  909. X        decode();
  910. X        fclose(out);
  911. X#ifdef UNIX
  912. X        if(dochmod) chmod(ofname, mode);
  913. X#endif
  914. X        onedone = 1;
  915. X        if (debug||verify) format("End uudecoding: %s\n", ofname);
  916. X        settable();
  917. X    }    /* master loop for multiple decodes in one file */
  918. X}
  919. X
  920. X/*
  921. X * Bring back a pointer to the start of the nth word.
  922. X */
  923. Xchar *getnword(str, n) register char *str; register int n;
  924. X{
  925. X    while((*str == '\t') || (*str == ' ')) str++;
  926. X    if (! *str) return NULL;
  927. X    while(--n) {
  928. X        while ((*str != '\t') && (*str != ' ') && (*str)) str++;
  929. X        if (! *str) return NULL;
  930. X        while((*str == '\t') || (*str == ' ')) str++;
  931. X        if (! *str) return NULL;
  932. X    }
  933. X    return str;
  934. X}
  935. X
  936. X/*
  937. X * Install the table in memory for later use.
  938. X */
  939. Xgettable()
  940. X{
  941. X    char buf[LINELEN];
  942. X    register int c, n = 0;
  943. X    register char *cpt;
  944. X
  945. X    if(debug) format("Getting new table.\n");
  946. X
  947. X    for (c = 0; c <= MAXCHAR; c++) chtbl[c] = -1;
  948. X
  949. Xagain:    if (fgets(buf, sizeof buf, in) == NULL) {
  950. X        format("uud: EOF while in translation table.\n");
  951. X        Error(5);
  952. X    }
  953. X    numl++;
  954. X    if (strncmp(buf, "begin", 5) == 0) {
  955. X        format("uud: Incomplete translation table.\n");
  956. X        format("uud: Using default one.\n");
  957. X        settable();
  958. X        return;
  959. X    }
  960. X    cpt = buf + strlen(buf) - 1;
  961. X    *cpt = ' ';
  962. X    while (*(cpt) == ' ') {
  963. X        *cpt = 0;
  964. X        cpt--;
  965. X    }
  966. X    cpt = buf;
  967. X    while (c = *cpt) {
  968. X        if (chtbl[c] != -1) {
  969. X            format("uud: Duplicate char in translation table.\n");
  970. X            format("uud: Using default one.\n");
  971. X            settable();
  972. X            return;
  973. X        }
  974. X        if (n == 0) blank = c;
  975. X        chtbl[c] = n++;
  976. X        if (n >= 64)
  977. X        {
  978. X            if(debug) format("End of getting table.\n");
  979. X            return;
  980. X        }
  981. X        cpt++;
  982. X    }
  983. X    goto again;
  984. X}
  985. X
  986. X/*
  987. X * Set up the default translation table.
  988. X */
  989. Xsettable()
  990. X{
  991. X    int i, j;
  992. X
  993. X    for (i = 0; i < ' '; i++) chtbl[i] = -1;
  994. X    for (i = ' ', j = 0; i < ' ' + 64; i++, j++) chtbl[i] = j;
  995. X    for (i = ' ' + 64; i < MAXCHAR; i++) chtbl[i] = -1;
  996. X    chtbl['`'] = chtbl[' '];    /* common mutation */
  997. X    chtbl['~'] = chtbl['^'];    /* an other common mutation */
  998. X    blank = ' ';
  999. X}
  1000. X
  1001. X/*
  1002. X * Testing functions
  1003. X */
  1004. X
  1005. X#ifdef TEST_LENGTH
  1006. Xvalid_length(l,n)
  1007. X     int l,n;
  1008. X{
  1009. X    int k, resp;
  1010. X    k = cdlen[n];
  1011. X    /*    k = n % 3;
  1012. X     *    k = ( n + (k ? 3-k : 0) )*4/3;
  1013. X     */
  1014. X    resp = ( (l-k >= 0) && (l-k <= 1) );
  1015. X    if(debug && !resp && !verify)
  1016. X    format("Bad length at line %d\n", numl);
  1017. X    return(resp);
  1018. X}
  1019. X
  1020. Xvalid_char(c)
  1021. X     char c;
  1022. X{
  1023. X    int resp;
  1024. X    resp = ( (chtbl[c]<0) ? 0 : 1 );
  1025. X    if(debug && !resp && !verify)
  1026. X    format("Bad char <%c> at line %d\n", c, numl);
  1027. X    return(resp);
  1028. X}
  1029. X#endif
  1030. X
  1031. Xvalid_chars(s,l)
  1032. X     char *s;
  1033. X     int l;
  1034. X{
  1035. X    int resp, k = 0;
  1036. X    while( (k<l) && valid_char(s[k]) ) k++;
  1037. X    resp = (k==l);
  1038. X    return( resp );
  1039. X}
  1040. X
  1041. X/*
  1042. X * copy from in to out, decoding as you go along.
  1043. X */
  1044. X
  1045. Xdecode()
  1046. X{
  1047. X    char buf[LINELEN], outl[LINELEN];
  1048. X    register char *bp, *ut;
  1049. X    register int *trtbl = chtbl;
  1050. X    register int n, c, rlen;
  1051. X    register unsigned int len;
  1052. X#ifdef TEST_LENGTH
  1053. X    int efflen;
  1054. X#endif
  1055. X
  1056. X    loop {
  1057. X        if (fgets(buf, sizeof buf, in) == NULL) {
  1058. X            format("uud: EOF before end.\n");
  1059. X            fclose(out);
  1060. X            Error(8);
  1061. X        }
  1062. X        numl++;
  1063. X        len = strlen(buf);
  1064. X        if (len) buf[--len] = '\0';
  1065. X/*
  1066. X * Is it an unprotected empty line before the end line ?
  1067. X */
  1068. X        if (len == 0) continue;
  1069. X/*
  1070. X * Get the binary line length.
  1071. X */
  1072. X        n = trtbl[buf[0]];
  1073. X/*
  1074. X * end of uuencoded file ?
  1075. X */
  1076. X        if (strncmp(buf, "end", 3) == 0) return;
  1077. X        if (   (strncmp(buf, "begin ", 6) == 0)
  1078. X            || (strncmp(buf, "table", 5) == 0) )
  1079. X        {
  1080. X            format("uud: BEGIN or TABLE before END.\n");
  1081. X            /* puts back the line */
  1082. X            fseek(in,(long) - (strlen(buf)+1) , 1);
  1083. X            return;
  1084. X        }
  1085. X/*
  1086. X * end of current file ? : get next one.
  1087. X */
  1088. X        if (strncmp(buf, "include", 7) == 0) {
  1089. X            getfile(buf);
  1090. X            continue;
  1091. X        }
  1092. X#ifdef TEST_LENGTH
  1093. X/*
  1094. X * good length ?
  1095. X */
  1096. X        efflen = len;
  1097. X
  1098. X        /* Suppress bad chars at the end */
  1099. X        while(   (n >= 0)
  1100. X              && (efflen > 0)
  1101. X              && ! valid_char(buf[efflen-1])
  1102. X              ) efflen--;
  1103. X
  1104. X        if(   (n >= 0)
  1105. X           && (efflen > 0)
  1106. X           && valid_length(efflen,n)
  1107. X           && ((debug||verify)
  1108. X               ? valid_chars(buf,efflen)
  1109. X               : valid_char(buf[efflen/2]))
  1110. X           )
  1111. X        {
  1112. X            if (debug||verify) {
  1113. X            if((numlbad!=-1) && (numlbad<numl-1))
  1114. X            {
  1115. X                format("Bad lines %d--%d\n",
  1116. X                   numlbad, numl-1);
  1117. X            }
  1118. X            }
  1119. X            numlbad = -1;
  1120. X            goto decod;
  1121. X        }
  1122. X
  1123. X        if(numlbad<0) {
  1124. X            numlbad = numl;
  1125. X            if (debug)
  1126. X            {
  1127. X            format("Bad line %d =%s\n", numl, buf);
  1128. X            format("n=%d --> %d, len=%d\n", n, cdlen[n], len);
  1129. X            }
  1130. X        }
  1131. X        continue;
  1132. X#else /* !TEST_LENGTH */
  1133. X        if (n >= 0) goto decod;
  1134. X        format("uud: Bad prefix line %d in file: %s\n",numl, ifname);
  1135. X        if (debug) format("Bad line =%s\n",buf);
  1136. X        Error(11);
  1137. X#endif /* TEST_LENGTH */
  1138. X/*
  1139. X * Sequence checking ?
  1140. X */
  1141. Xdecod:        rlen = cdlen[n];
  1142. X/*
  1143. X * Is it the empty line before the end line ?
  1144. X */
  1145. X        if (n == 0) continue;
  1146. X/*
  1147. X * Pad with blanks.
  1148. X */
  1149. X        for (bp = &buf[c = len];
  1150. X            c < rlen; c++, bp++) *bp = blank;
  1151. X
  1152. X#if  !defined(TEST_LENGTH)
  1153. X/*
  1154. X * Verify if asked for.
  1155. X */
  1156. X        if (debug||verify) {
  1157. X            for (len = 0, bp = buf; len < rlen; len++) {
  1158. X                if (trtbl[*bp] < 0) {
  1159. X                    format(
  1160. X    "Non uuencoded char <%c>, line %d in file: %s\n", *bp, numl, ifname);
  1161. X                    format("Bad line =%s\n",buf);
  1162. X                    Error(16);
  1163. X                }
  1164. X                bp++;
  1165. X            }
  1166. X        }
  1167. X#endif
  1168. X
  1169. X/*
  1170. X * All this just to check for uuencodes that append a 'z' to each line....
  1171. X */
  1172. X        if (secnd && check) {
  1173. X            secnd = 0;
  1174. X            if (buf[rlen] == SEQMAX) {
  1175. X                check = 0;
  1176. X                if (debug) format("Sequence check turned off (2).\n");
  1177. X            } else
  1178. X                if (debug) format("Sequence check on (2).\n");
  1179. X        } else if (first && check) {
  1180. X            first = 0;
  1181. X            secnd = 1;
  1182. X            if (buf[rlen] != SEQMAX) {
  1183. X                check = 0;
  1184. X                if (debug) format("No sequence check (1).\n");
  1185. X            } else
  1186. X                if (debug) format("Sequence check on (1).\n");
  1187. X        }
  1188. X/*
  1189. X * There we check.
  1190. X */
  1191. X        if (check) {
  1192. X            if (buf[rlen] != seqc) {
  1193. X                format("uud: Wrong sequence line %d in %s\n",
  1194. X                    numl, ifname);
  1195. X                if (debug)
  1196. X                    format(
  1197. X    "Sequence char is <%c> instead of <%c>.\n", buf[rlen], seqc);
  1198. X                Error(18);
  1199. X            }
  1200. X            seqc--;
  1201. X            if (seqc < SEQMIN) seqc = SEQMAX;
  1202. X        }
  1203. X/*
  1204. X * output a group of 3 bytes (4 input characters).
  1205. X * the input chars are pointed to by p, they are to
  1206. X * be output to file f.n is used to tell us not to
  1207. X * output all of them at the end of the file.
  1208. X */
  1209. X        ut = outl;
  1210. X        len = n;
  1211. X        bp = &buf[1];
  1212. X        while (n > 0) {
  1213. X            *(ut++) = trtbl[*bp] << 2 | trtbl[bp[1]] >> 4;
  1214. X            n--;
  1215. X            if (n) {
  1216. X                *(ut++) = (trtbl[bp[1]] << 4) |
  1217. X                      (trtbl[bp[2]] >> 2);
  1218. X                n--;
  1219. X            }
  1220. X            if (n) {
  1221. X                *(ut++) = trtbl[bp[2]] << 6 | trtbl[bp[3]];
  1222. X                n--;
  1223. X            }
  1224. X            bp += 4;
  1225. X        }
  1226. X        if ((n = fwrite(outl, 1, len, out)) <= 0) {
  1227. X            format("uud: Error on writing decoded file.\n");
  1228. X            Error(18);
  1229. X        }
  1230. X    }
  1231. X}
  1232. X
  1233. X/*
  1234. X * Find the next needed file, if existing, otherwise try further
  1235. X * on next file.
  1236. X */
  1237. Xgetfile(buf) register char *buf;
  1238. X{
  1239. X    if ((pos = getnword(buf, 2)) == NULL) {
  1240. X        format("uud: Missing include file name.\n");
  1241. X        Error(17);
  1242. X    } else
  1243. X        if (source != NULL) {
  1244. X            strcpy(ifname, source);
  1245. X            strcat(ifname, pos);
  1246. X        } else
  1247. X            strcpy(ifname, pos);
  1248. X#ifdef GEMDOS
  1249. X    if (Fattrib(ifname, 0, 0) < 0)
  1250. X#else
  1251. X    if (access(ifname, 04))
  1252. X#endif
  1253. X    {
  1254. X        if (debug) {
  1255. X            format("Cant find: %s\n", ifname);
  1256. X            format("Continuing to read same file.\n");
  1257. X        }
  1258. X    }
  1259. X    else {
  1260. X        if (freopen(ifname, "r", in) == in) {
  1261. X            numl = 0;
  1262. X            if (debug||verify) 
  1263. X                format("Reading next section from: %s\n", ifname);
  1264. X        } else {
  1265. X            format("uud: Freopen abort: %s\n", ifname);
  1266. X            Error(9);
  1267. X        }
  1268. X    }
  1269. X    loop {
  1270. X        if (fgets(buf, LINELEN, in) == NULL) {
  1271. X            format("uud: No begin line after include: %s\n", ifname);
  1272. X            Error(12);
  1273. X        }
  1274. X        numl++;
  1275. X        if (strncmp(buf, "table", 5) == 0) {
  1276. X            gettable();
  1277. X            continue;
  1278. X        }
  1279. X        if (strncmp(buf, "begin", 5) == 0) break;
  1280. X    }
  1281. X    lens = strlen(buf);
  1282. X    if (lens) buf[--lens] = '\0';
  1283. X/*
  1284. X * Check the part suffix.
  1285. X */
  1286. X    if ((pos = getnword(buf, 3)) == NULL ) {
  1287. X        format("uud: Missing part name, in included file: %s\n", ifname);
  1288. X        Error(13);
  1289. X    } else {
  1290. X        part = *pos;
  1291. X        partn++;
  1292. X        if (partn > 'z') partn = 'a';
  1293. X        if (part != partn) {
  1294. X            format("uud: Part suffix mismatch: <%c> instead of <%c>.\n",
  1295. X                part, partn);
  1296. X            Error(14);
  1297. X        }
  1298. X        if (debug||verify) format("Reading part %c\n", *pos);
  1299. X    }
  1300. X}
  1301. X
  1302. X#ifndef UNIX
  1303. X/*
  1304. X * Printf style formatting. (Borrowed from MicroEmacs by Dave Conroy.) 
  1305. X * A lot smaller than the full fledged printf.
  1306. X */
  1307. X/* VARARGS1 */
  1308. Xformat(fp, args) char *fp;
  1309. X{
  1310. X    doprnt(fp, (char *)&args);
  1311. X}
  1312. X
  1313. Xdoprnt(fp, ap)
  1314. Xregister char    *fp;
  1315. Xregister char    *ap;
  1316. X{
  1317. X    register int    c, k;
  1318. X    register char    *s;
  1319. X
  1320. X    while ((c = *fp++) != '\0') {
  1321. X        if (c != '%')
  1322. X            outc(c);
  1323. X        else {
  1324. X            c = *fp++;
  1325. X            switch (c) {
  1326. X            case 'd':
  1327. X                puti(*(int *)ap, 10);
  1328. X                ap += sizeof(int);
  1329. X                break;
  1330. X
  1331. X            case 's':
  1332. X                s = *(char **)ap;
  1333. X                while ((k = *s++) != '\0')
  1334. X                    outc(k);
  1335. X                ap += sizeof(char *);
  1336. X                break;
  1337. X
  1338. X            case 'c':
  1339. X                outc(*(int *)ap);
  1340. X                ap += sizeof(int);
  1341. X                break;
  1342. X
  1343. X            default:
  1344. X                outc(c);
  1345. X            }
  1346. X        }
  1347. X    }
  1348. X}
  1349. X
  1350. X/*
  1351. X * Put integer, in radix "r".
  1352. X */
  1353. Xputi(i, r)
  1354. Xregister unsigned int    i;
  1355. Xregister unsigned int    r;
  1356. X{
  1357. X    register unsigned int    q, s;
  1358. X
  1359. X    if ((q = i / r) != 0)
  1360. X        puti(q, r);
  1361. X    s = i % r;
  1362. X    if (s <= 9)
  1363. X        outc(s + '0');
  1364. X    else
  1365. X        outc(s - 10 + 'A');
  1366. X}
  1367. Xoutc(c) register char c;
  1368. X{
  1369. X#ifdef GEMDOS
  1370. X    if (c == '\n') Bconout(2, '\r');
  1371. X    Bconout(2, c);
  1372. X#else
  1373. X    putchar(c);
  1374. X#endif
  1375. X}
  1376. X
  1377. X#endif
  1378. END_OF_FILE
  1379.   if test 16085 -ne `wc -c <'myuud.c'`; then
  1380.     echo shar: \"'myuud.c'\" unpacked with wrong size!
  1381.   fi
  1382.   # end of 'myuud.c'
  1383. fi
  1384. echo shar: End of archive 1 \(of 1\).
  1385. cp /dev/null ark1isdone
  1386. MISSING=""
  1387. for I in 1 ; do
  1388.     if test ! -f ark${I}isdone ; then
  1389.     MISSING="${MISSING} ${I}"
  1390.     fi
  1391. done
  1392. if test "${MISSING}" = "" ; then
  1393.     echo You have the archive.
  1394.     rm -f ark[1-9]isdone
  1395. else
  1396.     echo You still must unpack the following archives:
  1397.     echo "        " ${MISSING}
  1398. fi
  1399. exit 0
  1400. exit 0 # Just in case...
  1401.