home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume41 / mailagnt / part14 < prev    next >
Encoding:
Text File  |  1993-12-02  |  55.0 KB  |  1,647 lines

  1. Newsgroups: comp.sources.misc
  2. From: Raphael Manfredi <ram@acri.fr>
  3. Subject: v41i014:  mailagent - Flexible mail filtering and processing package, v3.0, Part14/26
  4. Message-ID: <1993Dec2.134033.18900@sparky.sterling.com>
  5. X-Md4-Signature: 4ed1e5b3c27f1a8b62f4fac33a8111b6
  6. Sender: kent@sparky.sterling.com (Kent Landfield)
  7. Organization: Advanced Computer Research Institute, Lyon, France.
  8. Date: Thu, 2 Dec 1993 13:40:33 GMT
  9. Approved: kent@sparky.sterling.com
  10.  
  11. Submitted-by: Raphael Manfredi <ram@acri.fr>
  12. Posting-number: Volume 41, Issue 14
  13. Archive-name: mailagent/part14
  14. Environment: UNIX, Perl
  15. Supersedes: mailagent: Volume 33, Issue 93-109
  16.  
  17. #! /bin/sh
  18. # This is a shell archive.  Remove anything before this line, then feed it
  19. # into a shell via "sh file" or similar.  To overwrite existing files,
  20. # type "sh file -c".
  21. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  22. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  23. # Contents:  agent/mailpatch.SH agent/pl/plsave.pl
  24. #   agent/pl/queue_mail.pl agent/pl/sendfile.pl agent/pl/usrmac.pl
  25. #   misc/unkit/unkit.pl
  26. # Wrapped by ram@soft208 on Mon Nov 29 16:49:56 1993
  27. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  28. echo If this archive is complete, you will see the following message:
  29. echo '          "shar: End of archive 14 (of 26)."'
  30. if test -f 'agent/mailpatch.SH' -a "${1}" != "-c" ; then 
  31.   echo shar: Will not clobber existing file \"'agent/mailpatch.SH'\"
  32. else
  33.   echo shar: Extracting \"'agent/mailpatch.SH'\" \(9188 characters\)
  34.   sed "s/^X//" >'agent/mailpatch.SH' <<'END_OF_FILE'
  35. Xcase $CONFIG in
  36. X'')
  37. X    if test -f config.sh; then TOP=.;
  38. X    elif test -f ../config.sh; then TOP=..;
  39. X    elif test -f ../../config.sh; then TOP=../..;
  40. X    elif test -f ../../../config.sh; then TOP=../../..;
  41. X    elif test -f ../../../../config.sh; then TOP=../../../..;
  42. X    else
  43. X        echo "Can't find config.sh."; exit 1
  44. X    fi
  45. X    . $TOP/config.sh
  46. X    ;;
  47. Xesac
  48. Xcase "$0" in
  49. X*/*) cd `expr X$0 : 'X\(.*\)/'` ;;
  50. Xesac
  51. Xecho "Extracting agent/mailpatch (with variable substitutions)"
  52. X$spitshell >mailpatch <<!GROK!THIS!
  53. X$startperl
  54. X    eval "exec perl -S \$0 \$*"
  55. X        if \$running_under_some_shell;
  56. X
  57. X# $Id: mailpatch.SH,v 3.0 1993/11/29 13:48:25 ram Exp ram $
  58. X#
  59. X#  Copyright (c) 1990-1993, Raphael Manfredi
  60. X#  
  61. X#  You may redistribute only under the terms of the Artistic License,
  62. X#  as specified in the README file that comes with the distribution.
  63. X#  You may reuse parts of this distribution only within the terms of
  64. X#  that same Artistic License; a copy of which may be found at the root
  65. X#  of the source tree for mailagent 3.0.
  66. X#
  67. X# $Log: mailpatch.SH,v $
  68. X# Revision 3.0  1993/11/29  13:48:25  ram
  69. X# Baseline for mailagent 3.0 netwide release.
  70. X#
  71. X
  72. X\$cat = '$cat';
  73. X\$zcat = '$zcat';
  74. X\$mversion = '$VERSION';
  75. X\$patchlevel = '$PATCHLEVEL';
  76. X!GROK!THIS!
  77. X$spitshell >>mailpatch <<'!NO!SUBS!'
  78. X
  79. X$prog_name = $0;                # Who I am
  80. X$prog_name =~ s|^.*/(.*)|$1|;    # Keep only base name
  81. X
  82. X&read_config;        # First, read configuration file (in ~/.mailagent)
  83. X
  84. X# take job number and command from environment
  85. X# (passed by mailagent)
  86. X$jobnum = $ENV{'jobnum'};
  87. X$fullcmd = $ENV{'fullcmd'};
  88. X$pack = $ENV{'pack'};
  89. X$path = $ENV{'path'};
  90. X
  91. X&read_dist;            # Read distributions
  92. X
  93. X$dest = shift;            # Who should the patches be sent to
  94. X$system = shift;        # Which system do patches belong
  95. X$version = shift;        # Which version it is
  96. X
  97. X# A single '-' as first argument stands for return path
  98. X$dest = $path if $dest eq '-';
  99. X
  100. X# A single '-' for version means "highest available" version.
  101. X$version = $Version{$system} if $version eq '-';
  102. X
  103. X# Full name of system for H table access
  104. X$pname = $system . "|" . $version;
  105. X
  106. X$maillist = "To obtain a list of what is available, send me the following mail:
  107. X
  108. X    Subject: Command
  109. X    @SH maillist $path
  110. X        ^ note the l";
  111. X
  112. Xif (!$System{$system}) {
  113. X    open(MAILER, "|$cf'sendmail $cf'mailopt $path $cf'user");
  114. X    print MAILER
  115. X"To: $path
  116. XBcc: $cf'user
  117. XSubject: No program called $system
  118. XX-Mailer: mailagent [version $mversion PL$patchlevel]
  119. X
  120. XI don't know how to send patches for a program called $system.  Sorry.
  121. X
  122. X$maillist
  123. X
  124. XIf $cf'name can figure out what you meant, you'll get the patches anyway.
  125. X
  126. X-- mailpatch speaking for $cf'user
  127. X";
  128. X    close MAILER;
  129. X    &add_log("FAILED (UNKNOWN SYSTEM)") if $loglvl > 1;
  130. X    exit 0;
  131. X}
  132. X
  133. Xif (!$Program{$pname}) {
  134. X    open(MAILER, "|$cf'sendmail $cf'mailopt $path $cf'user");
  135. X    print MAILER
  136. X"To: $path
  137. XBcc: $cf'user
  138. XSubject: No patches for $system version $version
  139. XX-Mailer: mailagent [version $mversion PL$patchlevel]
  140. X
  141. XI don't know how to send patches for version $version of $system.  Sorry.";
  142. X    if ($Version{$system} ne '') {
  143. X        print MAILER "
  144. X
  145. X[The highest version for $system is $Version{$system}.]";
  146. X        &add_log("MSG highest version is $Version{$system}") if $loglvl > 8;
  147. X    } else {
  148. X        print MAILER "
  149. X
  150. X[There is no version number for $system.]";
  151. X        &add_log("MSG no version number") if $loglvl > 8;
  152. X    }
  153. X    print MAILER "
  154. X
  155. X$maillist
  156. X
  157. XIf $cf'name can figure out what you meant, you'll get the patches anyway.
  158. X
  159. X-- mailpatch speaking for $cf'user
  160. X";
  161. X    close MAILER;
  162. X    &add_log("FAILED (BAD SYSTEM NUMBER)") if $loglvl > 1;
  163. X    exit 0;
  164. X}
  165. X
  166. Xif (!($Maintained{$pname} || $Patches{$pname})) {
  167. X    open(MAILER, "|$cf'sendmail $cf'mailopt $path $cf'user");
  168. X    print MAILER
  169. X"To: $path
  170. XBcc: $cf'user
  171. XSubject: $system version $version is not maintained
  172. XX-Mailer: mailagent [version $mversion PL$patchlevel]
  173. X
  174. XI can't send you patches for version $version of $system, because this code
  175. Xis not maintained by $cf'name. There are no official patches available either...
  176. X
  177. X$maillist
  178. X
  179. XAnyway, if you discover a bug or have remarks about \"$system\", please
  180. Xlet me know. Better, if you know where patches for $system can be found,
  181. Xwell... you have my e-mail address ! :->
  182. X
  183. X-- mailpatch speaking for $cf'user
  184. X";
  185. X    close MAILER;
  186. X    &add_log("FAILED (NOT MAINTAINED)") if $loglvl > 1;
  187. X    exit 0;
  188. X}
  189. X
  190. X# Create a temporary directory
  191. X$tmp = "$cf'tmpdir/dmp$$";
  192. Xmkdir($tmp, 0700) || &fatal("cannot create $tmp");
  193. X
  194. X# Need to unarchive the distribution
  195. Xif ($Archived{$pname}) {
  196. X    # Create a temporary directory for distribution
  197. X    $tmp_loc = "$cf'tmpdir/dmpl$$";
  198. X    mkdir($tmp_loc, 0700) || &fatal("cannot create $tmp_loc");
  199. X    $Location{$pname} =
  200. X        &unpack($Location{$pname}, $tmp_loc, $Compressed{$pname});
  201. X}
  202. X
  203. X# Go to bugs sub-directory. It is possible to ask for patches for
  204. X# old systems. Such systems are identified by having the `patches'
  205. X# field from the distrib file set to "old". In that case, patches
  206. X# are taken from a bugs-version directory. Version has to be non null.
  207. X
  208. Xif ($Patch_only{$pname}) {
  209. X    &abort("old system has no version number") if $version eq '';
  210. X    chdir "$Location{$pname}/bugs-$version" ||
  211. X        &abort("cannot go to $Location{$pname}/bugs-$version");
  212. X    # There is no patchlevel to look at -- compute by hand.
  213. X    for ($maxnum = 1; ; $maxnum++) {
  214. X        last unless -f "patch$maxnum" || -f "patch$maxnum.Z";
  215. X    }
  216. X    $maxnum--;        # We've gone too far
  217. X} else {
  218. X    chdir "$Location{$pname}/bugs" ||
  219. X        &abort("cannot go to $Location{$pname}/bugs");
  220. X    open(PATCHLEVEL, "../patchlevel.h") ||
  221. X        &abort("cannot open patchlevel.h");
  222. X    $maxnum = 0;
  223. X    while (<PATCHLEVEL>) {
  224. X        if (/.*PATCHLEVEL[ \t]*(\d+)/) {
  225. X            $maxnum = $1;
  226. X            last;
  227. X        }
  228. X    }
  229. X    close PATCHLEVEL;
  230. X}
  231. X
  232. Xif (!$maxnum) {
  233. X    # If we get here, it must be for one of our systems. Indeed,
  234. X    # if we do not have any patches for a third party program, there
  235. X    # should be a "no" in the patches field of distribution file, and
  236. X    # in that case an error would have been reported before.
  237. X    open(MAILER, "|$cf'sendmail $cf'mailopt $path $cf'user");
  238. X    print MAILER
  239. X"To: $path
  240. XBcc: $cf'user
  241. XSubject: No patches yet for $system version $version
  242. XX-Mailer: mailagent [version $mversion PL$patchlevel]
  243. X
  244. XThere are no patches (yet) for $system version $version. Sorry.
  245. X
  246. X-- mailpatch speaking for $cf'user
  247. X";
  248. X    close MAILER;
  249. X    &add_log("FAILED (NO PATCHES YET)") if $loglvl > 1;
  250. X    &clean_tmp;
  251. X    exit 0;
  252. X}
  253. X
  254. X$patchlist = &rangeargs($maxnum, @ARGV);    # Generate patch list
  255. X
  256. Xif (! ($patchlist =~ /\d/)) {
  257. X    open(MAILER, "|$cf'sendmail $cf'mailopt $path $cf'user");
  258. X    print MAILER
  259. X"To: $path
  260. XBcc: $cf'user
  261. XSubject: Invalid patch request for $system $version
  262. XX-Mailer: mailagent [version $mversion PL$patchlevel]
  263. X";
  264. X    if ($Patches{$pname}) {
  265. X        print MAILER "
  266. XThe highest patch I have for $system version $version is #$maxnum.";
  267. X    } else {
  268. X        print MAILER "
  269. XThe latest patch for $system version $version is #$maxnum.";
  270. X    }
  271. X    print MAILER "
  272. X(Your command was: $fullcmd)";
  273. X    if ($Version{$system} > $version) {
  274. X        print MAILER "
  275. X
  276. XPlease note that the latest version for $system is $Version{$system}.
  277. X
  278. X$maillist";
  279. X    }
  280. X    print MAILER "
  281. X
  282. X-- mailpatch speaking for $cf'user
  283. X";
  284. X    close MAILER;
  285. X    &add_log("FAILED (INVALID PATCH LIST)") if $loglvl > 1;
  286. X    &clean_tmp;
  287. X    exit 0;
  288. X}
  289. X
  290. X@numbers = split(/ /,$patchlist);
  291. X
  292. Xforeach $num (@numbers) {
  293. X    $patchfile = "patch" . $num;    # Base name of the patch
  294. X    if (-f $patchfile) {            # Normal patch
  295. X        $append = $cat;
  296. X        $extent = '';
  297. X    } elsif (-f "$patchfile.Z") {    # Compressed patch
  298. X        if ($zcat ne 'zcat') {        # Zcat found by Configure
  299. X            $append = $zcat;
  300. X            $extent = '.Z';
  301. X        } else {
  302. X            &add_log("ERROR no zcat to uncompress patch #$num ($system)")
  303. X                if $loglvl > 1;
  304. X            next;
  305. X        }
  306. X    } else {
  307. X        &add_log("ERROR no patch #$num ($system)") if $loglvl > 1;
  308. X        next;
  309. X    }
  310. X    open (TMP, ">$tmp/$patchfile");
  311. X    if ($Patches{$pname}) {
  312. X        print TMP "
  313. XThis is an official patch for $system version $version, please apply it.
  314. XThe highest patch I have for that version of $system is #$maxnum.";
  315. X    } else {
  316. X        print TMP "
  317. XThe latest patch for $system version $version is #$maxnum.";
  318. X    }
  319. X    print TMP "
  320. X
  321. X-- mailpatch speaking for $cf'user
  322. X
  323. X";
  324. X    close TMP;
  325. X    system "$append <$patchfile$extent >>$tmp/$patchfile";
  326. X    &add_log("copied file $patchfile into $tmp") if $loglvl > 17;
  327. X}
  328. X
  329. Xif ($#numbers > 0) {
  330. X    $subject = $#numbers + 1;        # Array count starts at 0
  331. X    $subject = "$system $version, $subject patches";
  332. X} else {
  333. X    $subject = "$system $version patch #$numbers[0]";
  334. X}
  335. X&sendfile($dest, $tmp, $pack, $subject);
  336. X&clean_tmp;
  337. X
  338. Xexit 0;        # Ok
  339. X
  340. Xsub clean_tmp {
  341. X    # Do not stay in the directories we are removing...
  342. X    chdir $cf'home;
  343. X    if ($tmp ne '') {
  344. X        system '/bin/rm', '-rf', $tmp;
  345. X        &add_log("removed dir $tmp") if $loglvl > 19;
  346. X    }
  347. X    if ($Archived{$pname}) {
  348. X        system '/bin/rm', '-rf', $tmp_loc;
  349. X        &add_log("removed dir $tmp_loc") if $loglvl > 19;
  350. X    }
  351. X}
  352. X
  353. X# Emergency exit with clean-up
  354. Xsub abort {
  355. X    local($reason) = shift(@_);        # Why we are exiting
  356. X    &clean_tmp;
  357. X    &fatal($reason);
  358. X}
  359. X
  360. X!NO!SUBS!
  361. X$grep -v '^;#' pl/fatal.pl >>mailpatch
  362. X$grep -v '^;#' pl/add_log.pl >>mailpatch
  363. X$grep -v '^;#' pl/read_conf.pl >>mailpatch
  364. X$grep -v '^;#' pl/unpack.pl >>mailpatch
  365. X$grep -v '^;#' pl/rangeargs.pl >>mailpatch
  366. X$grep -v '^;#' pl/sendfile.pl >>mailpatch
  367. X$grep -v '^;#' pl/distribs.pl >>mailpatch
  368. X$grep -v '^;#' pl/secure.pl >>mailpatch
  369. Xchmod 755 mailpatch
  370. X$eunicefix mailpatch
  371. END_OF_FILE
  372.   if test 9188 -ne `wc -c <'agent/mailpatch.SH'`; then
  373.     echo shar: \"'agent/mailpatch.SH'\" unpacked with wrong size!
  374.   fi
  375.   chmod +x 'agent/mailpatch.SH'
  376.   # end of 'agent/mailpatch.SH'
  377. fi
  378. if test -f 'agent/pl/plsave.pl' -a "${1}" != "-c" ; then 
  379.   echo shar: Will not clobber existing file \"'agent/pl/plsave.pl'\"
  380. else
  381.   echo shar: Extracting \"'agent/pl/plsave.pl'\" \(3915 characters\)
  382.   sed "s/^X//" >'agent/pl/plsave.pl' <<'END_OF_FILE'
  383. X;# $Id: plsave.pl,v 3.0 1993/11/29 13:49:06 ram Exp ram $
  384. X;#
  385. X;#  Copyright (c) 1990-1993, Raphael Manfredi
  386. X;#  
  387. X;#  You may redistribute only under the terms of the Artistic License,
  388. X;#  as specified in the README file that comes with the distribution.
  389. X;#  You may reuse parts of this distribution only within the terms of
  390. X;#  that same Artistic License; a copy of which may be found at the root
  391. X;#  of the source tree for mailagent 3.0.
  392. X;#
  393. X;# $Log: plsave.pl,v $
  394. X;# Revision 3.0  1993/11/29  13:49:06  ram
  395. X;# Baseline for mailagent 3.0 netwide release.
  396. X;#
  397. X;#
  398. X;# This file relies on the following external conditions:
  399. X;#    - operation &fatal() available for fatal errors
  400. X;#    - the configuration variables are properly set
  401. X;#    - logging is done via &add_log()
  402. X;#    - routines for locking files are available
  403. X;#
  404. X# Read stored informations for archived systems. The format of
  405. X# the file is the following:
  406. X#    system version patchlevel mtime
  407. X# where:
  408. X#    - system is the name of the system
  409. X#    - version is the version number or --- if none
  410. X#    - patchlevel is the current patchlevel, or -2 if no PL
  411. X#    - mtime is the modification time of the archive
  412. X#
  413. X# The function builds the following associative array, indexed
  414. X# by the system's name and version number (which has to be a null
  415. X# string for systems with no version number, marked '---'):
  416. X#
  417. X# name          indexed by       information
  418. X#
  419. X# %PSystem      name + version   true if line seen
  420. X# %Patch_level  name + version   current patch level
  421. X# %Mtime        name + version   last modification time
  422. X#
  423. X# If the 'plsave' file is not found, a new empty one is created
  424. X#
  425. Xsub read_plsave {
  426. X    local($fullname);
  427. X    if (!open(PATLIST, "$cf'plsave")) {
  428. X        &add_log("creating new patlist file") if $loglvl > 8;
  429. X        system 'cp', '/dev/null', $cf'plsave;
  430. X        open(PATLIST, "$cf'plsave") ||
  431. X            &fatal("cannot open patlist file");
  432. X    }
  433. X    while (<PATLIST>) {
  434. X        next if /^\s*#/;    # skip comments
  435. X        next if /^\s*$/;    # skip empty lines
  436. X        next unless s/^\s*(\w+)\s+([\w\.]+)//;
  437. X        $fullname = $1 . "|" . ($2 eq '---'? "0" : $2);
  438. X        if (defined($PSystem{$fullname})) {
  439. X            &add_log("WARNING duplicate patlist entry $1 $2 ignored")
  440. X                if $loglvl > 5;
  441. X            next;
  442. X        }
  443. X        $PSystem{$fullname}++;
  444. X        unless (/^\s*([\-\d]+)\s+(\d+)/) {
  445. X            &add_log("WARNING bad patlist description line $.")
  446. X                if $loglvl > 5;
  447. X            next;    # Ignore, but it may corrupt further processing
  448. X        }
  449. X        $Patch_level{$fullname} = $1;
  450. X        $Mtime{$fullname} = $2;
  451. X    }
  452. X    close PATLIST;
  453. X}
  454. X
  455. X# Write the new 'plsave', but only if the distributions are found
  456. X# in the %Program array (I assume read_dist() has been called).
  457. X# The 'plsave' file is locked during the updating process, so that
  458. X# no conflicting access occurs. There is a small chance that the
  459. X# file we write is not correct, in case the distribution file changed
  460. X# while we were processing a mail. However, it isn't a big problem.
  461. Xsub write_plsave {
  462. X    local($lockext) = ".lock";        # Needed by checklock (via acs_rqst)
  463. X    local($system);
  464. X    local($version);
  465. X    if (0 != &acs_rqst($cf'plsave)) {
  466. X        &add_log("WARNING updating unlocked patlist file") if $loglvl > 5;
  467. X    }
  468. X    if (!open(PATLIST, ">$cf'plsave")) {
  469. X        &add_log("ERROR unable to update $cf'plsave") if $loglvl;
  470. X        return;
  471. X    }
  472. X    print PATLIST
  473. X"# This file was automatically generated by $prog_name.
  474. X# It records the archived distributions, their patch level if any, and
  475. X# the modification time of the archive, so that these informations can
  476. X# be updated when necessary. Do not edit this file.
  477. X
  478. X";
  479. X    foreach $pname (keys %PSystem) {
  480. X        if ($Archived{$pname}) {
  481. X            ($system, $version) = $pname =~ /^(\w+)\|([\w\.]+)*$/;
  482. X            $version = '---' if $version eq '0';
  483. X            print PATLIST "$system $version ";
  484. X            print PATLIST "$Patch_level{$pname} $Mtime{$pname}\n";
  485. X            &add_log("updated patlist for $system $version") if $loglvl > 18;
  486. X        } else {
  487. X            &add_log("$system $version removed from patlist") if $loglvl > 18;
  488. X        }
  489. X    }
  490. X    close PATLIST;
  491. X    &free_file($cf'plsave);
  492. X}
  493. X
  494. END_OF_FILE
  495.   if test 3915 -ne `wc -c <'agent/pl/plsave.pl'`; then
  496.     echo shar: \"'agent/pl/plsave.pl'\" unpacked with wrong size!
  497.   fi
  498.   # end of 'agent/pl/plsave.pl'
  499. fi
  500. if test -f 'agent/pl/queue_mail.pl' -a "${1}" != "-c" ; then 
  501.   echo shar: Will not clobber existing file \"'agent/pl/queue_mail.pl'\"
  502. else
  503.   echo shar: Extracting \"'agent/pl/queue_mail.pl'\" \(8754 characters\)
  504.   sed "s/^X//" >'agent/pl/queue_mail.pl' <<'END_OF_FILE'
  505. X;# $Id: queue_mail.pl,v 3.0 1993/11/29 13:49:11 ram Exp ram $
  506. X;#
  507. X;#  Copyright (c) 1990-1993, Raphael Manfredi
  508. X;#  
  509. X;#  You may redistribute only under the terms of the Artistic License,
  510. X;#  as specified in the README file that comes with the distribution.
  511. X;#  You may reuse parts of this distribution only within the terms of
  512. X;#  that same Artistic License; a copy of which may be found at the root
  513. X;#  of the source tree for mailagent 3.0.
  514. X;#
  515. X;# $Log: queue_mail.pl,v $
  516. X;# Revision 3.0  1993/11/29  13:49:11  ram
  517. X;# Baseline for mailagent 3.0 netwide release.
  518. X;#
  519. X;#
  520. X;# Queue a mail file. Needs add_log(). Calls fatal() in emergency situations.
  521. X;# Requires a parsed config file.
  522. X;# 
  523. X# Queue mail in a 'fm' file. The mail is held in memory. It returns 0 if the
  524. X# mail was queued, 1 otherwise.
  525. Xsub qmail {
  526. X    local(*array) = @_;            # In which array mail is located.
  527. X    local($queue_file);            # Where we attempt to save the mail
  528. X    local($failed) = 0;            # Be positive and look forward :-)
  529. X    $queue_file = "$cf'queue/Tqm$$";
  530. X    $queue_file = "$cf'queue/Tqmb$$" if -f "$queue_file";    # Paranoid
  531. X    unless (open(QUEUE, ">$queue_file")) {
  532. X        &add_log("ERROR unable to create $queue_file: $!") if $loglvl > 1;
  533. X        return 1;        # Failed
  534. X    }
  535. X    # Write mail on disk, making sure there is a first From line
  536. X    local($first_line) = 1;
  537. X    local($in_header) = 1;        # True while in mail header
  538. X    foreach $line (@array) {
  539. X        if ($first_line) {
  540. X            $first_line = 0;
  541. X            print QUEUE "$FAKE_FROM\n" unless $line =~ /^From\s+\S+/;
  542. X        }
  543. X        next if (print QUEUE $line, "\n");
  544. X        $failed = 1;
  545. X        &add_log("SYSERR write: $!") if $loglvl;
  546. X        last;
  547. X    }
  548. X    close QUEUE;
  549. X    unlink "$queue_file" if $failed;
  550. X    $failed = &queue_mail($queue_file) unless $failed;
  551. X    $failed;            # 0 means success
  552. X}
  553. X
  554. X# Queue mail in a 'fm' file. The mail is supposed to be either on disk or
  555. X# is expected from standard input. Returns 0 for success, 1 if failed.
  556. X# In case mail comes from stdin, may not return at all but raise a fatal error.
  557. Xsub queue_mail {
  558. X    local($file_name) = shift(@_);        # Where mail to-be-queued is
  559. X    local($deferred) = shift(@_);        # True when 'qm' mail wanted instead
  560. X    local($dirname);                    # Directory name of processed file
  561. X    local($tmp_queue);                    # Tempoorary storing of queued file
  562. X    local($queue_file);                    # Final name of queue file
  563. X    local($ok) = 1;                        # Print status
  564. X    local($_);
  565. X    &add_log("queuing mail for delayed processing") if $loglvl > 18;
  566. X    chdir $cf'queue || &fatal("cannot chdir to $cf'queue");
  567. X
  568. X    # The following ensures unique queue mails. As the mailagent itself may
  569. X    # queue intensively throughout the SPLIT command, a queue counter is kept
  570. X    # and is incremented each time a mail is successfully queued.
  571. X    local($base) = $deferred ? 'qm' : 'fm';
  572. X    $queue_file = "$base$$";        # 'fm' stands for Full Mail
  573. X    $queue_file = "$base$$x" . $queue_count if -f "$queue_file";
  574. X    $queue_file = "${queue_file}x" if -f "$queue_file";    # Paranoid
  575. X    ++$queue_count;                    # Counts amount of queued mails
  576. X    &add_log("queue file is $queue_file") if $loglvl > 19;
  577. X
  578. X    # Do not write directly in the fm file, otherwise the main
  579. X    # mailagent process could start its processing on it...
  580. X    $tmp_queue = "Tfm$$";
  581. X    local($sender) = "<someone>";    # Attempt to report the sender of message
  582. X    if ($file_name) {                # Mail is already on file system
  583. X        # Mail already in a file
  584. X        $ok = 0 if &mv($file_name, $tmp_queue);
  585. X        if ($ok && open(QUEUE, $tmp_queue)) {
  586. X            while (<QUEUE>) {
  587. X                $Header{'All'} .= $_ unless defined $Header{'All'};
  588. X                if (1 .. /^$/) {        # While in header of message
  589. X                    /^From:[ \t]*(.*)/ && ($sender = $1 );
  590. X                }
  591. X            }
  592. X            close QUEUE;
  593. X        }
  594. X    } else {
  595. X        # Mail comes from stdin or has already been stored in %Header
  596. X        unless (defined $Header{'All'}) {    # Only if mail was not already read
  597. X            $Header{'All'} = '';            # Needed in case of emergency
  598. X            if (open(QUEUE, ">$tmp_queue")) {
  599. X                while (<STDIN>) {
  600. X                    $Header{'All'} .= $_;
  601. X                    if (1 .. /^$/) {        # While in header of message
  602. X                        /^From:[ \t]*(.*)/ && ($sender = $1);
  603. X                    }
  604. X                    (print QUEUE) || ($ok = 0);
  605. X                }
  606. X                close QUEUE;
  607. X            } else {
  608. X                $ok = 0;        # Signals: was not able to queue mail
  609. X            }
  610. X        } else {                            # Mail already in %Header
  611. X            if (open(QUEUE, ">$tmp_queue")) {
  612. X                local($in_header) = 1;
  613. X                foreach (split(/\n/, $Header{'All'})) {
  614. X                    if ($in_header) {        # While in header of message
  615. X                        $in_header = 0 if /^$/;
  616. X                        /^From:[ \t]*(.*)/ && ($sender = $1);
  617. X                    }
  618. X                    (print QUEUE $_, "\n") || ($ok = 0);
  619. X                }
  620. X                close QUEUE;
  621. X            } else {
  622. X                $ok = 0;        # Signals: was not able to queue mail
  623. X            }
  624. X        }
  625. X    }
  626. X
  627. X    # If there has been some problem (like we ran out of disk space), then
  628. X    # attempt to record the temporary file name into the waiting file. If
  629. X    # mail came from stdin, there is not much we can do, so we panic.
  630. X    if (!$ok) {
  631. X        &add_log("ERROR could not queue message") if $loglvl > 0;
  632. X        unlink "$tmp_queue";
  633. X        if ($file_name) {
  634. X            # The file processed is already on the disk
  635. X            $dirname = $file_name;
  636. X            $dirname =~ s|^(.*)/.*|$1|;    # Keep only basename
  637. X            $cf'user = (getpwuid($<))[0] || "uid$<" if $cf'user eq '';
  638. X            $tmp_queue = $dirname/$cf'user.$$;
  639. X            $tmp_queue = $file_name if &mv($file_name, $tmp_queue);
  640. X            &add_log("NOTICE mail held in $tmp_queue") if $loglvl > 4;
  641. X        } else {
  642. X            &fatal("mail may be lost");    # Mail came from filter via stdin
  643. X        }
  644. X        # If the mail is on the disk, add its name to the file $agent_wait
  645. X        # in the queue directory. This file contains the names of the mails
  646. X        # stored outside of the mailagent's queue and waiting to be processed.
  647. X        $ok = &waiting_mail($tmp_queue);
  648. X        return 1 unless $ok;    # Queuing failed if not ok
  649. X        return 0;
  650. X    }
  651. X
  652. X    # We succeeded in writing the temporary queue mail. Now rename it so that
  653. X    # the mailagent may see it and process it.
  654. X    if (rename($tmp_queue, $queue_file)) {
  655. X        local($bytes) = (stat($queue_file))[7];    # Size of file
  656. X        local($s) = $bytes == 1 ? '' : 's';
  657. X        &add_log("QUEUED [$queue_file] ($bytes byte$s) from $sender")
  658. X            if $loglvl > 3;
  659. X    } else {
  660. X        &add_log("ERROR cannot rename $tmp_queue to $queue_file") if $loglvl;
  661. X        $ok = &waiting_mail($tmp_queue);
  662. X    }
  663. X    return 1 unless $ok;        # Queuing failed if not ok
  664. X    0;
  665. X}
  666. X
  667. X# Adds mail into the agent.wait file, if possible. This file records all the
  668. X# mails queued with a non-standard name or which are stored outside of the
  669. X# queue. Returns 1 if mail was successfully added to this list.
  670. Xsub waiting_mail {
  671. X    local($tmp_queue) = @_;
  672. X    local($status) = 0;
  673. X    if (open(WAITING, ">>$agent_wait")) {
  674. X        if (print WAITING "$tmp_queue\n") {
  675. X            $status = 1;            # Mail more or less safely queued
  676. X            &add_log("NOTICE processing deferred for $tmp_queue")
  677. X                if $loglvl > 3;
  678. X        } else {
  679. X            &add_log("ERROR could not record $tmp_queue in $agent_wait")
  680. X                if $loglvl > 1;
  681. X        }
  682. X        close WAITING;
  683. X    } else {
  684. X        &add_log("ERROR unable to open $agent_wait") if $loglvl > 0;
  685. X        &add_log("WARNING left mail in $tmp_queue") if $loglvl > 1;
  686. X    }
  687. X    $status;        # 1 means success
  688. X}
  689. X
  690. X# Performs a '/bin/mv' operation, but without the burden of an extra process.
  691. Xsub mv {
  692. X    local($from, $to) = @_;        # Original path and destination path
  693. X    # If the two files are on the same file system, then we may use the rename()
  694. X    # system call.
  695. X    if (&same_device($from, $to)) {
  696. X        &add_log("using rename system call") if $loglvl > 19;
  697. X        unless (rename($from, $to)) {
  698. X            &add_log("SYSERR rename: $!") if $loglvl;
  699. X            &add_log("ERROR could not rename $from into $to") if $loglvl;
  700. X            return 1;
  701. X        }
  702. X        return 0;
  703. X    }
  704. X    # Have to emulate a 'cp'
  705. X    &add_log("copying file $from to $to") if $loglvl > 19;
  706. X    unless (open(FROM, $from)) {
  707. X        &add_log("SYSERR open: $!") if $loglvl;
  708. X        &add_log("ERROR cannot open source $from") if $loglvl;
  709. X        return 1;
  710. X    }
  711. X    unless (open(TO, ">$to")) {
  712. X        &add_log("SYSERR open: $!") if $loglvl;
  713. X        &add_log("ERROR cannot open target $to") if $loglvl;
  714. X        close FROM;
  715. X        return 1;
  716. X    }
  717. X    local($ok) = 1;        # Assume all I/O went all right
  718. X    local($_);
  719. X    while (<FROM>) {
  720. X        next if print TO;
  721. X        $ok = 0;
  722. X        &add_log("SYSERR write: $!") if $loglvl;
  723. X        last;
  724. X    }
  725. X    close FROM;
  726. X    close TO;
  727. X    unless ($ok) {
  728. X        &add_log("ERROR could not copy $from to $to") if $loglvl;
  729. X        unlink "$to";
  730. X        return 1;
  731. X    }
  732. X    # Copy succeeded, remove original file
  733. X    unlink "$from";
  734. X    0;                    # Denotes success
  735. X}
  736. X
  737. X# Look whether two paths refer to the same device.
  738. X# Compute basename and directory name for both files, as the file may
  739. X# not exist. However, if both directories are on the same file system,
  740. X# then so is it for the two files beneath each of them.
  741. Xsub same_device {
  742. X    local($from, $to) = @_;        # Original path and destination path
  743. X    local($fromdir, $fromfile) = $from =~ m|^(.*)/(.*)|;
  744. X    ($fromdir, $fromfile) = ('.', $fromdir) if $fromfile eq '';
  745. X    local($todir, $tofile) = $to =~ m|^(.*)/(.*)|;
  746. X    ($todir, $tofile) = ('.', $todir) if $tofile eq '';
  747. X    local($dev1) = stat($fromdir);
  748. X    local($dev2) = stat($todir);
  749. X    $dev1 == $dev2;
  750. X}
  751. X
  752. END_OF_FILE
  753.   if test 8754 -ne `wc -c <'agent/pl/queue_mail.pl'`; then
  754.     echo shar: \"'agent/pl/queue_mail.pl'\" unpacked with wrong size!
  755.   fi
  756.   # end of 'agent/pl/queue_mail.pl'
  757. fi
  758. if test -f 'agent/pl/sendfile.pl' -a "${1}" != "-c" ; then 
  759.   echo shar: Will not clobber existing file \"'agent/pl/sendfile.pl'\"
  760. else
  761.   echo shar: Extracting \"'agent/pl/sendfile.pl'\" \(9154 characters\)
  762.   sed "s/^X//" >'agent/pl/sendfile.pl' <<'END_OF_FILE'
  763. X;# $Id: sendfile.pl,v 3.0 1993/11/29 13:49:16 ram Exp ram $
  764. X;#
  765. X;#  Copyright (c) 1990-1993, Raphael Manfredi
  766. X;#  
  767. X;#  You may redistribute only under the terms of the Artistic License,
  768. X;#  as specified in the README file that comes with the distribution.
  769. X;#  You may reuse parts of this distribution only within the terms of
  770. X;#  that same Artistic License; a copy of which may be found at the root
  771. X;#  of the source tree for mailagent 3.0.
  772. X;#
  773. X;# $Log: sendfile.pl,v $
  774. X;# Revision 3.0  1993/11/29  13:49:16  ram
  775. X;# Baseline for mailagent 3.0 netwide release.
  776. X;#
  777. X;#
  778. X;# This file contains two subroutines:
  779. X;#   - sendfile, sends a set of files
  780. X;#   - abort, called when something got wrong
  781. X;#
  782. X;# A routine clean_tmp must be defined in the program, for removing
  783. X;# possible temporary files in case abort is called.
  784. X;#
  785. X# Send a set of files
  786. Xsub sendfile {
  787. X    local($dest, $cf'tmpdir, $pack, $subject) = @_;
  788. X    &add_log("sending dir $cf'tmpdir to $dest, mode $pack") if $loglvl > 9;
  789. X
  790. X    # A little help message
  791. X    local($mail_help) = "Detailed intructions can be obtained by:
  792. X
  793. X    Subject: Command
  794. X    @SH mailhelp $dest";
  795. X
  796. X    # Go to tmpdir where files are stored
  797. X    chdir $cf'tmpdir || &abort("NO TMP DIRECTORY");
  798. X
  799. X    # Build a list of files to send
  800. X    local($list) = "";        # List of plain files
  801. X    local($dlist) = "";        # List with directories (for makekit)
  802. X    local($nbyte) = 0;
  803. X    local($nsend) = 0;
  804. X    open(FIND, "find . -print |") || &abort("CANNOT RUN FIND");
  805. X    while (<FIND>) {
  806. X        chop;
  807. X        next if $_ eq '.';        # Skip current directory `.'
  808. X        s|^\./||;
  809. X        $dlist .= $_ . " ";        # Save file/dir name
  810. X        if (-f $_) {            # If plain file
  811. X            $list .= $_ . " ";    # Save plain file
  812. X            $nsend++;            # One more file to send
  813. X            ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
  814. X                $blksize,$blocks) = stat($_);
  815. X            $nbyte += $size;    # Update total size
  816. X        }
  817. X    }
  818. X    close FIND;
  819. X
  820. X    &abort("NO FILE TO SEND") unless $nsend;
  821. X    if ($nsend > 1) {
  822. X        &add_log("$nsend files to pack ($nbyte bytes)") if $loglvl > 9;
  823. X    } else {
  824. X        &add_log("1 file to pack ($nbyte bytes)") if $loglvl > 9;
  825. X    }
  826. X
  827. X    # Pack files
  828. X    if ($pack =~ /kit/) {
  829. X        system "kit -n Part $list" || &abort("CANNOT KIT FILES");
  830. X        $packed = "kit";
  831. X    } elsif ($pack =~ /shar/) {
  832. X        # Create a manifest, so that we can easily run maniscan
  833. X        # Leave a PACKNOTES file with non-zero length if problems.
  834. X        local($mani) = $dlist;
  835. X        $mani =~ s/ /\n/g;
  836. X        local($packlist) = "pack.$$";    # Pack list used as manifest
  837. X        if (open(PACKLIST, ">$packlist")) {
  838. X            print PACKLIST $mani;
  839. X            close PACKLIST;
  840. X            system 'maniscan', "-i$packlist",
  841. X                "-o$packlist", '-w0', '-n', '-lPACKNOTES';
  842. X            &add_log("ERROR maniscan returned non-zero status")
  843. X                if $loglvl > 5 && $?;
  844. X            if (-s 'PACKNOTES') {        # Files split or uu-encoded
  845. X                system 'makekit', "-i$packlist", '-t',
  846. X                    "Now run 'sh PACKNOTES'." || &abort("CANNOT SHAR FILES");
  847. X            } else {
  848. X                system 'makekit', "-i$packlist" || &abort("CANNOT SHAR FILES");
  849. X            }
  850. X        } else {
  851. X            &add_log("ERROR cannot create packlist") if $loglvl > 5;
  852. X            system "makekit $dlist" || &abort("CANNOT SHAR FILES");
  853. X        }
  854. X        $packed = "shar";
  855. X    } else {
  856. X        if ($nbyte > $cf'maxsize) {        # Defined in ~/.mailagent
  857. X            system "kit -M -n Part $list" || &abort("CANNOT KIT FILES");
  858. X            $packed = "minikit";        # The minikit is included
  859. X        } else {
  860. X            # Try with makekit first
  861. X            if (system "makekit $dlist") {    # If failed
  862. X                system "kit -M -n Part $list" || &abort("CANNOT KIT FILES");
  863. X                $packed = "minikit";    # The minikit is included
  864. X            } else {
  865. X                $packed = "shar";
  866. X            }
  867. X        }
  868. X    }
  869. X
  870. X    # How many parts are there ?
  871. X    @parts = <Part*>;
  872. X    $npart = $#parts + 1;        # Number of parts made
  873. X    &abort("NO PART TO SEND -- $packed failed") unless $npart;
  874. X    if ($npart > 1) {
  875. X        &add_log("$npart $packed parts to send") if $loglvl > 19;
  876. X    } else {
  877. X    &add_log("$npart $packed part to send") if $loglvl > 19;
  878. X    }
  879. X
  880. X    # Now send the parts
  881. X    $nbyte = 0;                # How many bytes do we send ?
  882. X    $part_num = 0;
  883. X    $signal="";                # To signal parts number if more than 1
  884. X    local($partsent) = 0;    # Number of parts actually sent
  885. X    local($bytesent) = 0;    # Amount of bytes actually sent
  886. X    foreach $part (@parts) {
  887. X        ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
  888. X            $blksize,$blocks) = stat($part);
  889. X        $nbyte += $size;    # Update total size
  890. X
  891. X        &add_log("dealing with $part ($size bytes)") if $loglvl > 19;
  892. X
  893. X        # See if we need to signal other parts
  894. X        $part_num++;            # Update part number
  895. X        if ($npart > 1) {
  896. X            $signal=" (Part $part_num/$npart)";
  897. X        }
  898. X
  899. X        # Send part
  900. X        open(MAILER, "|$cf'sendmail $cf'mailopt $dest");
  901. X        print MAILER
  902. X"To: $dest
  903. XSubject: $subject$signal
  904. XPrecedence: bulk
  905. XX-Mailer: mailagent [version $mversion PL$patchlevel]
  906. X
  907. XHere is the answer to your request:
  908. X
  909. X    $fullcmd
  910. X
  911. X
  912. X";
  913. X        if ($packed eq 'minikit') {        # Kit with minikit included
  914. X            print MAILER
  915. X"This is a kit file. It will be simpler to unkit it if you own the kit
  916. Xpackage (latest patchlevel), but you can use the minikit provided with
  917. Xthis set of file (please see instructions provided by kit itself at the
  918. Xhead of each part). If you wish to get kit, send me the following mail:
  919. X
  920. X";
  921. X        } elsif ($packed eq 'kit') {    # Plain kit files
  922. X            print MAILER
  923. X"This is a kit file. You need the kit package (latest patchlevel) to
  924. Xunkit it. If you do not have kit, send me the following mail:
  925. X
  926. X";
  927. X        }
  928. X        if ($packed =~ /kit/) {        # Kit parts
  929. X            print MAILER
  930. X"    Subject: Command
  931. X    @PACK shar
  932. X    @SH maildist $dest kit -
  933. X
  934. Xand you will get the latest release of kit as shell archives.
  935. X
  936. X$mail_help
  937. X
  938. X";
  939. X            # Repeat instructions which should be provided by kit anyway
  940. X            if ($npart > 1) {
  941. X                print MAILER
  942. X"Unkit:    Save this mail into a file, e.g. \"foo$part_num\" and wait until
  943. X    you have received the $npart parts. Then, do \"unkit foo*\". To see
  944. X    what will be extracted, you may wish to do \"unkit -l foo*\" before.
  945. X";
  946. X            } else {
  947. X                print MAILER
  948. X"Unkit:    Save this mail into a file, e.g. \"foo\". Then do \"unkit foo\". To see
  949. X    what will be extracted, you may wish to do \"unkit -l foo\" before.
  950. X";
  951. X            }
  952. X            # If we used the minikit, signal where instruction may be found
  953. X            if ($packed eq 'minikit') {
  954. X                print MAILER
  955. X"    This kit archive also contains a minikit which will enable you to
  956. X    extract the files even if you do not have kit. Please follow the
  957. X    instructions kit has provided for you at the head of each part. Should
  958. X    the minikit prove itself useless, you may wish to get kit.
  959. X";
  960. X            }
  961. X        } else {            # Shar parts
  962. X            print MAILER
  963. X"This is a shar file. It will be simpler to unshar it if you own the Rich Salz's
  964. Xcshar package. If you do not have it, send me the following mail:
  965. X
  966. X    Subject: Command
  967. X    @PACK shar
  968. X    @SH maildist $dest cshar 3.0
  969. X
  970. Xand you will get cshar as shell archives.
  971. X
  972. X$mail_help
  973. X
  974. X";
  975. X            if (-s 'PACKNOTES') {        # Problems detected by maniscan
  976. X                print MAILER
  977. X"
  978. XWarning:
  979. X    Some minor problems were encountered during the building of the
  980. X    shell archives. Perhaps a big file has been split, a binary has been
  981. X    uu-encoded, or some lines were too long. Once you have unpacked the
  982. X    whole distribution, see file PACKNOTES for more information. You can
  983. X    run it through sh by typing 'sh PACKNOTES' to restore possible splited
  984. X    or encoded files.
  985. X
  986. X";
  987. X            }
  988. X            if ($npart > 1) {
  989. X                print MAILER
  990. X"Unshar: Save this mail into a file, e.g. \"foo$part_num\" and wait until
  991. X    you have received the $npart parts. Then, do \"unshar -n foo*\". If you
  992. X    do not own \"unshar\", edit the $npart files and remove the mail header
  993. X    by hand before feeding into sh.
  994. X";
  995. X            } else {
  996. X                print MAILER
  997. X"Unshar: Save this mail into a file, e.g. \"foo\". Then do \"unshar -n foo\". If
  998. X    you do not own \"unshar\", edit the file and remove the mail header by
  999. X    hand before feeding into sh.
  1000. X";
  1001. X            }
  1002. X        }
  1003. X        print MAILER
  1004. X"
  1005. X-- $prog_name speaking for $cf'user
  1006. X
  1007. X
  1008. X";
  1009. X        open(PART, $part) || &abort("CANNOT OPEN $part");
  1010. X        while (<PART>) {
  1011. X            print MAILER;
  1012. X        }
  1013. X        close PART;
  1014. X        close MAILER;
  1015. X        if ($?) {
  1016. X            &add_log("ERROR couldn't send $size bytes to $dest")
  1017. X                if $loglvl > 1;
  1018. X        } else {
  1019. X            &add_log("SENT $size bytes to $dest") if $loglvl > 2;
  1020. X            $partsent++;
  1021. X            $bytesent += $size;
  1022. X        }
  1023. X    }
  1024. X
  1025. X    # Prepare log message
  1026. X    local($partof) = "";
  1027. X    local($byteof) = "";
  1028. X    local($part);
  1029. X    local($byte);
  1030. X    if ($partsent > 1) {
  1031. X        $part = "parts";
  1032. X    } else {
  1033. X        $part = "part";
  1034. X    }
  1035. X    if ($bytesent > 1) {
  1036. X        $byte = "bytes";
  1037. X    } else {
  1038. X        $byte = "byte";
  1039. X    }
  1040. X    if ($partsent != $npart) {
  1041. X        $partof = " (of $npart)";
  1042. X        $byteof = "/$nbyte";
  1043. X    }
  1044. X    &add_log(
  1045. X        "SENT $partsent$partof $packed $part ($bytesent$byteof $byte) to $dest"
  1046. X    ) if $loglvl > 4;
  1047. X}
  1048. X
  1049. X# In case something got wrong
  1050. X# We call the clean_tmp routine, which must be defined in the
  1051. X# main program that will use abort.
  1052. Xsub abort {
  1053. X    local($reason) = shift;        # Why do we abort ?
  1054. X    local($cmd) = $fullcmd =~ /^(\S+)/;
  1055. X    open(MAILER, "|$cf'sendmail $cf'mailopt $path $cf'user");
  1056. X    print MAILER
  1057. X"To: $path
  1058. XBcc: $cf'user
  1059. XSubject: $cmd failed
  1060. XX-Mailer: mailagent [version $mversion PL$patchlevel]
  1061. X
  1062. XSorry, the $prog_name command failed while sending files.
  1063. X
  1064. XYour command was: $fullcmd
  1065. XError message I got:
  1066. X
  1067. X    >>>> $reason <<<<
  1068. X
  1069. XIf $cf'name can figure out what you meant, he may answer anyway.
  1070. X
  1071. X-- $prog_name speaking for $cf'user
  1072. X";
  1073. X    close MAILER;
  1074. X    &add_log("FAILED ($reason)") if $loglvl > 1;
  1075. X    &clean_tmp;
  1076. X    exit 0;            # Scheduled error
  1077. X}
  1078. X
  1079. END_OF_FILE
  1080.   if test 9154 -ne `wc -c <'agent/pl/sendfile.pl'`; then
  1081.     echo shar: \"'agent/pl/sendfile.pl'\" unpacked with wrong size!
  1082.   fi
  1083.   # end of 'agent/pl/sendfile.pl'
  1084. fi
  1085. if test -f 'agent/pl/usrmac.pl' -a "${1}" != "-c" ; then 
  1086.   echo shar: Will not clobber existing file \"'agent/pl/usrmac.pl'\"
  1087. else
  1088.   echo shar: Extracting \"'agent/pl/usrmac.pl'\" \(9811 characters\)
  1089.   sed "s/^X//" >'agent/pl/usrmac.pl' <<'END_OF_FILE'
  1090. X;# $Id: usrmac.pl,v 3.0 1993/11/29 13:49:19 ram Exp ram $
  1091. X;#
  1092. X;#  Copyright (c) 1990-1993, Raphael Manfredi
  1093. X;#  
  1094. X;#  You may redistribute only under the terms of the Artistic License,
  1095. X;#  as specified in the README file that comes with the distribution.
  1096. X;#  You may reuse parts of this distribution only within the terms of
  1097. X;#  that same Artistic License; a copy of which may be found at the root
  1098. X;#  of the source tree for mailagent 3.0.
  1099. X;#
  1100. X;# $Log: usrmac.pl,v $
  1101. X;# Revision 3.0  1993/11/29  13:49:19  ram
  1102. X;# Baseline for mailagent 3.0 netwide release.
  1103. X;#
  1104. X;# 
  1105. X;# User-defined macros are available. They all begin with %-, followed by one
  1106. X;# character, for instance %-i for user-defined macro i. Once defined, they are
  1107. X;# globally visible. When defining a new macro, it is possible to replace an
  1108. X;# already existing definition or to stack a new definition (that is to say,
  1109. X;# we define some sort of dynamic scope). It is possible to save the macro
  1110. X;# state and then restore it later.
  1111. X;#
  1112. X;# The user may also define multi-character macros, which are then used thusly:
  1113. X;# If the name is mac, then %-(mac) will expand that macro. It is also possible
  1114. X;# to use %-(i) for %-i. Macro names may contain any character but '%' and ().
  1115. X;#
  1116. X;# At the interface level, the following calls (usrmac package) are recognized:
  1117. X;#
  1118. X;#   . new(name, value, type)
  1119. X;#        replace or create a new macro %-(name).
  1120. X;#   . delete(name)
  1121. X;#        delete all values recorded for the macro.
  1122. X;#   . push(name, value, type)
  1123. X;#        stack a new macro, creating it if necessary.
  1124. X;#   . pop(name)
  1125. X;#        remove last macro definition (either push'ed or new'ed).
  1126. X;#   . save
  1127. X;#        save the currently defined macros in an array of names.
  1128. X;#   . restore
  1129. X;#        scan an array of names and keep only those macros listed there,
  1130. X;#        the others being deleted.
  1131. X;#
  1132. X;# When specifying a macro, the value given may be one of the following types:
  1133. X;#
  1134. X;#   . SCALAR
  1135. X;#        a scalar value is given, e.g.: 'red'.
  1136. X;#   . EXPR
  1137. X;#        a perl expression will be eval'ed to get the value, e.g: '$red'.
  1138. X;#   . CONST
  1139. X;#        a perl constant expression, eval'ed only once and then cached.
  1140. X;#   . FN
  1141. X;#        a perl function called with (name), the macro name.
  1142. X;#   . PROG
  1143. X;#        a program to be run to get the actual value. Only trailing newline
  1144. X;#        is chopped, others are preserved. The program is forked each time.
  1145. X;#        In the argument list given to the program, %n is expanded as the
  1146. X;#        macro name we are trying to evaluate.
  1147. X;#   . PROGC
  1148. X;#        same as PROG but the program is forked only once and the value is
  1149. X;#        cached for later perusal. The C stands for Cache or Constant,
  1150. X;#        depending on your taste.
  1151. X;# 
  1152. X;# At the data structure level, we have:
  1153. X;#
  1154. X;#   . %Name
  1155. X;#        returns the name of the array containing the macro stack value for
  1156. X;#        that name. Stacked values are unshift'ed at the beginning so we can
  1157. X;#        always read the first item regardless of the number of defined
  1158. X;#        values.
  1159. X;#   . @gensym
  1160. X;#        the array ('gensym' is a place holder for whatever dynamic name was
  1161. X;#        generated and stored as a value in %Name) containing the macro
  1162. X;#        values, followed by its type.
  1163. X;#   . %Type
  1164. X;#        this table maps a macro type like FN on a function dealing with the
  1165. X;#        macro substitution at this level.
  1166. X;#
  1167. X;# Saving the state means recording all the defined macro names we currently
  1168. X;# have. Restoring the state simply deletes the extra values which may have
  1169. X;# been added since the last save. Thus a function defining macros for its own
  1170. X;# usage will perform a save, then define its own macros and call restore before
  1171. X;# returning. Alternatively, it can call delete for each defined macro.
  1172. X;#
  1173. X;# new/delete should be used normally, and push/pop only when a temporary
  1174. X;# override is needed for a macro. save/restore should not be interleaved with
  1175. X;# push/pop since after the restore, some macros added by push might have
  1176. X;# already been deleted completely. Likewise, pushed values on top of macros
  1177. X;# saved by save will not be poped by a restore.
  1178. X;#
  1179. X#
  1180. X# User-defined macros
  1181. X#
  1182. X
  1183. Xpackage usrmac;
  1184. X
  1185. X$init_done = 0;
  1186. X
  1187. X# Defines known macro types. Each type is associated with a function which will
  1188. X# be called to deal with the macro substitution for that type and returning the
  1189. X# proper value. The arguments passed to it are the glob to the gensym array and
  1190. X# the macro name, in case we have to deal with an FN-type value. The value for
  1191. X# the macro is at index 0 in the gensym array.
  1192. Xsub init {
  1193. X    %Type = (
  1194. X        'SCALAR',    'sub_scalar',        # Scalar value
  1195. X        'EXPR',        'sub_expr',            # Expression to be eval'ed each time
  1196. X        'CONST',    'sub_const',        # Constant eval'ed only once
  1197. X        'FN',        'sub_fn',            # Perl function to be called
  1198. X        'PROG',        'sub_prog',            # A program to call
  1199. X        'PROGC',    'sub_progc',        # Program to call once, result cached
  1200. X    );
  1201. X}
  1202. X
  1203. X# Add a new macro in the table. If one already existed, the new value is pushed
  1204. X# before the old one and will be used in subsequent substitutions.
  1205. Xsub push {
  1206. X    local($name, $value, $type) = @_;    # Name, value and type
  1207. X    local($gensym);                        # Generated array name storing values
  1208. X    &init unless $init_done++;
  1209. X    $gensym = defined $Name{$name} ? $Name{$name} : &'gensym;
  1210. X    $Name{$name} = $gensym;                # Make a nested data structure
  1211. X    eval "unshift(@$gensym, \$value, \$Type{\$type})";
  1212. X}
  1213. X
  1214. X# Create a brand new macro or replace the one currently visible.
  1215. Xsub new {
  1216. X    local($name, $value, $type) = @_;    # Name, value and type
  1217. X    local($gensym);                        # Generated array name storing values
  1218. X    &init unless $init_done++;
  1219. X    $gensym = defined $Name{$name} ? $Name{$name} : &'gensym;
  1220. X    $Name{$name} = $gensym;                # Make a nested data structure
  1221. X    eval "@$gensym[0, 1] = (\$value, \$Type{\$type})";
  1222. X}
  1223. X
  1224. X# Remove topmost macro definition
  1225. Xsub pop {
  1226. X    local($name) = @_;                    # Macro to undefine at this level
  1227. X    return unless defined $Name{$name};    # Nothing here it would seem
  1228. X    local($gensym) = $Name{$name};        # Array storing macro definition
  1229. X    eval "shift(@$gensym); shift(@$gensym)";
  1230. X}
  1231. X
  1232. X# Delete the whole (possibly stacked) macro entries under a given name.
  1233. Xsub delete {
  1234. X    local($name) = @_;
  1235. X    return unless defined $Name{$name};    # Ooops... Has already been done
  1236. X    local($gensym) = $Name{$name};        # Array storing macro definition
  1237. X    eval "undef @$gensym";                # Delete the value array
  1238. X    delete $Name{$name};                # As well as the entry in name table
  1239. X}
  1240. X
  1241. X# Save the valid macro names we currently have. Returns an array of names.
  1242. Xsub save {
  1243. X    keys %Name;        # List of currently defined macros
  1244. X}
  1245. X
  1246. X# Restore the name space we had at the time the save was made, deleting all the
  1247. X# macro names which are now defined and were not present at that time. Note
  1248. X# that stacked macro definitions are deleted in one block.
  1249. Xsub restore {
  1250. X    local(@names) = @_;            # Names we had at that time
  1251. X    local(%saved);                # Tell us whether a name was saved or not
  1252. X    foreach $key (@names) {        # Build a hash table of names for faster access
  1253. X        $saved{$key}++;
  1254. X    }
  1255. X    foreach $key (keys %Name) {    # Delete all macros not defined at save time
  1256. X        &delete($key) unless $saved{$key};
  1257. X    }
  1258. X}
  1259. X
  1260. X#
  1261. X# User-defined substitutions
  1262. X#
  1263. X
  1264. X# Perform the user-defined macro substitution and return the value string.
  1265. X# (called from macros_subst in macros.pl).
  1266. Xsub macro'usr {
  1267. X    local($name) = @_;        # Macro name
  1268. X    return '' unless defined $Name{$name};    # Unknown macro
  1269. X    local($gensym) = $Name{$name};            # Get value array
  1270. X    return '' unless $gensym;                # Key present, but nothing there
  1271. X    local($glob) = eval "*$gensym";            # Type glob to value array
  1272. X    local(*array) = $glob;                    # From now on, @array is set
  1273. X    local($function) = $array[1];            # How to deal with that macro type
  1274. X    $function = $Type{'SCALAR'} unless $function;
  1275. X    &$function($glob, $name);                # Propagate return value
  1276. X}
  1277. X
  1278. X#
  1279. X# Type-dependant substitutions
  1280. X#
  1281. X
  1282. X# Substitute a scalar value, simply return the verbatim value we got.
  1283. Xsub sub_scalar {
  1284. X    local(*ary, $name) = @_;
  1285. X    $ary[0];
  1286. X}
  1287. X
  1288. X# Evaluate a perl expression and return the scalar result
  1289. Xsub sub_expr {
  1290. X    local(*ary, $name) = @_;
  1291. X    eval $ary[0];
  1292. X}
  1293. X
  1294. X# Evaluate a perl expression and cache the result as a scalar value
  1295. Xsub sub_const {
  1296. X    local(*ary, $name) = @_;
  1297. X    local($result) = eval $ary[0];
  1298. X    &cache(*ary, $result);            # Cache and propagate result
  1299. X}
  1300. X
  1301. X# Call a perl function to evaluate the macro. Function should be a fully
  1302. X# qualified name, with package info, unless it is explicitely defined in
  1303. X# the usrmac package.
  1304. Xsub sub_fn {
  1305. X    local(*ary, $name) = @_;
  1306. X    eval "&$ary[0](\$name)";
  1307. X}
  1308. X
  1309. X# Call an external program, grab its output and remove final character. Then
  1310. X# return that as a result of the substitution. That program should execute
  1311. X# quickly. Use a PROGC type to cache the result if the value returned does not
  1312. X# change. In the argument list, %n is taken as the macro name.
  1313. Xsub sub_prog {
  1314. X    local(*ary, $name) = @_;
  1315. X    local($prog) = $ary[0];
  1316. X    $prog =~ s/%%/#%#/g;            # Escape %
  1317. X    $prog =~ s/%n/$name/g;            # Replace %n by macro name
  1318. X    $prog =~ s/#%#/%/g;                # %% turns out as a single %
  1319. X    local($result);                    # To store program output
  1320. X    chop($result = `$prog 2>&1`);    # Invoke program, merge stdout and stderr
  1321. X    $result;                        # Return output
  1322. X}
  1323. X
  1324. X# Same a sub_prog but cache the result as a scalar value to avoid other calls
  1325. X# to that same program.
  1326. Xsub sub_progc {
  1327. X    local(*ary, $name) = @_;
  1328. X    local($result) = &sub_prog(*ary, $name);
  1329. X    &cache(*ary, $result);            # Cache and propagate result
  1330. X}
  1331. X
  1332. X#
  1333. X# Value caching
  1334. X#
  1335. X
  1336. X# Cache computed value by making it a SCALAR-type macro value so that further
  1337. X# calls to evaluate that macro will simply return that cached information.
  1338. X# The result value passed as argument is returned unchanged.
  1339. Xsub cache {
  1340. X    local(*ary, $result) = @_;
  1341. X    $ary[0] = $result;                # Cache result for further invocations
  1342. X    $ary[1] = $Type{'SCALAR'};        # Make value a simple scalar
  1343. X    $result;                        # Return computed value
  1344. X}
  1345. X
  1346. Xpackage main;
  1347. X
  1348. END_OF_FILE
  1349.   if test 9811 -ne `wc -c <'agent/pl/usrmac.pl'`; then
  1350.     echo shar: \"'agent/pl/usrmac.pl'\" unpacked with wrong size!
  1351.   fi
  1352.   # end of 'agent/pl/usrmac.pl'
  1353. fi
  1354. if test -f 'misc/unkit/unkit.pl' -a "${1}" != "-c" ; then 
  1355.   echo shar: Will not clobber existing file \"'misc/unkit/unkit.pl'\"
  1356. else
  1357.   echo shar: Extracting \"'misc/unkit/unkit.pl'\" \(9447 characters\)
  1358.   sed "s/^X//" >'misc/unkit/unkit.pl' <<'END_OF_FILE'
  1359. X# $Id: unkit.pl,v 3.0 1993/11/29 13:50:34 ram Exp ram $
  1360. X#
  1361. X#  Copyright (c) 1990-1993, Raphael Manfredi
  1362. X#  
  1363. X#  You may redistribute only under the terms of the Artistic License,
  1364. X#  as specified in the README file that comes with the distribution.
  1365. X#  You may reuse parts of this distribution only within the terms of
  1366. X#  that same Artistic License; a copy of which may be found at the root
  1367. X#  of the source tree for mailagent 3.0.
  1368. X#
  1369. X# $Log: unkit.pl,v $
  1370. X# Revision 3.0  1993/11/29  13:50:34  ram
  1371. X# Baseline for mailagent 3.0 netwide release.
  1372. X#
  1373. X
  1374. X# This command automatically stores kit parts aside and runs unkit when all
  1375. X# the kits have been received.
  1376. X# Returns success if the file has been successfully stored onto disk, and a
  1377. X# failure if the mail was not a kit part or could not be saved.
  1378. X# The following (optional) config variables are used (~/.mailagent):
  1379. X#
  1380. X#  x_unkit_dir    : ~/tmp/unkit    # Directory where UNKIT works (default ~/kit)
  1381. X#  x_unkit_remove : YES            # Remove temporary files upon exctraction
  1382. X#  x_unkit_pname  : .kpart         # Leading temporary file name (default .kp)
  1383. X#  x_unkit_opt    : -b             # Additional unkit option
  1384. X#  x_unkit_log    : kitlog         # Logfile for UNKIT actions
  1385. X#  x_unkit_notify : ~/mail/kitok   # Message to be sent when kit received
  1386. X#  x_unkit_info   : README         # File name for kit-embeded instructions
  1387. X#
  1388. X# Not done yet but wanted:
  1389. X#  x_unkit_sizemax: 1000000        # Do not automatically unkit past this size
  1390. X#  x_unkit_timeout: 3d             # Timeout before discarding (3 days)
  1391. X#  x_unkit_output : YES            # Do we want any output mailed back if ok?
  1392. X#  x_unkit_trust  : ~/mail/trust   # Trusted people list (regexp form)
  1393. X#
  1394. X# The notify message recognizes the traditional mailagent set of macros, plus
  1395. X# the following specific ones:
  1396. X#
  1397. X#  %-(name)   : kit name of the package received (from Subject: line)
  1398. X#  %-(parts)  : number of parts received
  1399. X#  %-(kitdir) : directory where files for this kit are stored
  1400. X#
  1401. X# Some reasonable defaults are hardwired within the command itself.
  1402. X#
  1403. X# BUGS:
  1404. X#
  1405. X# Will not save instructions embeded in each part, only when made separate as
  1406. X# part #0. Moreover, if that information file arrives after all the other
  1407. X# "real" parts, it will be silently saved and .frm and .cnt files will be
  1408. X# recreated... That's a minor problem though.
  1409. X#
  1410. X
  1411. Xsub unkit {
  1412. X    local($cmd_line) = @_;            # The filter command line
  1413. X
  1414. X    # Options currently available at the ~/.mailagent level
  1415. X    local($kitdir) = $cf'x_unkit_dir || "$cf'home/kit";
  1416. X    local($remove) = $cf'x_unkit_remove =~ /^y/i;
  1417. X    local($sizemax) = $cf'x_unkit_sizemax || 0;
  1418. X    local($timeout) = $cf'x_unkit_timeout || '0d';
  1419. X    local($info) = $cf'x_unkit_info || 'INFO';
  1420. X    local($kl) = 'kitlog';
  1421. X
  1422. X    # If special logfile must be used, then open it right now. Otherwise,
  1423. X    # logs will be redirected to agentlog. The 'kitlog' logfile (that's the
  1424. X    # user-level name, which has "no" link to the x_unkit_log name specified)
  1425. X    # does not cc to the 'default' log agentlog.
  1426. X
  1427. X    &usrlog'new($kl, "$cf'x_unkit_log", 0)
  1428. X        if $cf'x_unkit_log ne '';
  1429. X
  1430. X    # Make sure it is a standard kit subject, otherwise reject mail message
  1431. X    # immediately. Standard subjects follow this template:
  1432. X    # Subject: package name - kit #5 / 7
  1433. X
  1434. X    local($name, $part, $total) = $subject =~ m|^(.*) - kit #(\d+) / (\d+)\s*$|;
  1435. X    if ($name ne '') {
  1436. X        &'usr_log($kl, "receiving $subject") if $'loglvl > 6;
  1437. X    } else {
  1438. X        &'usr_log($kl, "ERROR bad subject line: $subject") if $'loglvl > 1;
  1439. X        return 1;            # Signal failure
  1440. X    }
  1441. X
  1442. X    local($pname) = $cf'x_unkit_pname || '.kp';
  1443. X    local($options) = $cf'x_unkit_opt;
  1444. X    local($origname) = $name;    # Save name before mangling into 14 chars
  1445. X
  1446. X    # Escape all spaces in name, transforming them into '.'. Keep only the
  1447. X    # first 14 characters and use that as a directory name.
  1448. X
  1449. X    $name =~ s/^\s+//;        # Strip leading spaces
  1450. X    $name =~ s/\s+$//;        # Strip trailing spaces
  1451. X    $name =~ s/\s+/./g;        # Escape all other spaces
  1452. X    $name =~ s|/$||g;        # Remove trailing /
  1453. X    $name =~ s|/|_|g;        # And transform all others into _
  1454. X    $name = substr($name, 0, 14) if length($name) > 14;
  1455. X
  1456. X    $kitdir .= "/$name";    # Directory where unkit will proceed
  1457. X    &'makedir($kitdir);        # Make directory if it does not exist
  1458. X
  1459. X    # Problem: we have to make sure there is no alien code in the directory.
  1460. X    # If we were to receive to kits labelled the same way (say 'doc'), we must
  1461. X    # not mix them in the same directory. The heuristic used here is not 100%
  1462. X    # reliable, but at least will not lead to irreversible mixups:
  1463. X    #
  1464. X    # Temporaries are stored in a file 'kp.005' for part #5, and a count
  1465. X    # of the parts already received is kept in 'kp.cnt'. A track of the total
  1466. X    # amount of kits to be received is stored in 'kp.max' and the From: line
  1467. X    # is stored in 'kp.frm'. If we receive a kit from someone else (as computed
  1468. X    # by kp.frm) or we receive some kit with a different part count, we reject
  1469. X    # it.
  1470. X
  1471. X    $pname = substr($pname, 0, 10) if length($pname) > 10;
  1472. X    local($folder) = $kitdir . "/$pname" . sprintf(".%.3d", $part);
  1473. X    $folder = "$kitdir/$info" if $part == 0;    # Part zero is info file
  1474. X
  1475. X    # Compute kp.max and kp.frm if they do not exist already or check if they
  1476. X    # do. It is not really needed to make sure those files are created correctly
  1477. X    # since the next time we'll receive a kit part, we will fail anyway if they
  1478. X    # are not consistent. However, not being able to create them is an obvious
  1479. X    # error we are catching immediately.
  1480. X
  1481. X    local($kmax) = "$kitdir/$pname.max";
  1482. X    local($kfrom) = "$kitdir/$pname.frm";
  1483. X
  1484. X    if (-f $kmax) {
  1485. X        local($sv_kmax, $sv_kfrom);
  1486. X        open(KMAX, $kmax);
  1487. X        chop($sv_kmax = <KMAX>);
  1488. X        close KMAX;
  1489. X        open(KFROM, $kfrom);
  1490. X        chop($sv_kfrom = <KFROM>);
  1491. X        close KFROM;
  1492. X        if ($total != $sv_kmax) {
  1493. X            &'usr_log($kl, "ERROR kit $name had $sv_kmax parts, now has $total")
  1494. X                if $'loglvl > 1;
  1495. X            return 1;
  1496. X        }
  1497. X        if ($from ne $sv_kfrom) {
  1498. X            &'usr_log($kl, "ERROR kit $name was from $sv_kfrm, now from $from")
  1499. X                if $'loglvl > 1;
  1500. X            return 1;
  1501. X        }
  1502. X    } else {
  1503. X        unless (open(KMAX, ">$kmax")) {
  1504. X            &'usr_log($kl, "ERROR cannot create $kmax: $!") if $'loglvl;
  1505. X            return 1;
  1506. X        }
  1507. X        print KMAX "$total\n";
  1508. X        close KMAX;
  1509. X        unless (open(KFROM, ">$kfrom")) {
  1510. X            &'usr_log($kl, "ERROR cannot create $kfrom: $!") if $'loglvl;
  1511. X            return 1;
  1512. X        }
  1513. X        print KFROM "$from\n";
  1514. X        close KFROM;
  1515. X    }
  1516. X
  1517. X    # Make sure there are no duplicates...
  1518. X    if (-f $folder) {
  1519. X        &'usr_log($kl, "WARNING duplicate part #$part for kit $name discarded")
  1520. X            if $'loglvl > 5;
  1521. X        return 1;            # Signal failure
  1522. X    }
  1523. X
  1524. X    # Call the SAVE mailagent routine via the mailhook interface, which return
  1525. X    # a success status, i.e. 0 for failure and 1 if ok.
  1526. X    unless (&mailhook'save($folder)) {
  1527. X        &'usr_log($kl, "ERROR cannot save part #$part for kit $name")
  1528. X            if $'loglvl > 1;
  1529. X        return 1;
  1530. X    }
  1531. X
  1532. X    return 0 if $part == 0;        # Information file does not count...
  1533. X
  1534. X    # Now increase number of received parts
  1535. X    local($received) = &unkit'one_more($kitdir, $pname);
  1536. X    return 0 if $received < $total;        # Some parts still missing
  1537. X
  1538. X    # Everything was received, run unkit. Make sure the PATH variable is
  1539. X    # correctly set by your ~/.mailagent.
  1540. X    unless (opendir(DIR, $kitdir)) {
  1541. X        &'usr_log($kl, "ERROR (unkit) cannot open directory $kitdir: $!")
  1542. X            if $'loglvl > 1;
  1543. X        &unkit'error;
  1544. X        return 0;                        # Not really an UNKIT error
  1545. X    }
  1546. X    local(@contents) = readdir DIR;        # Slurp the whole thing
  1547. X    close DIR;
  1548. X    @contents = grep(/^$pname\.\d+$/, @contents);
  1549. X
  1550. X    # Time to actually run unkit... Its output will be mailed back to the user.
  1551. X
  1552. X    if (0 == &main'shell_command(
  1553. X        "unkit $option -Sd $kitdir @contents",
  1554. X        $'NO_INPUT, $'NO_FEEDBACK)
  1555. X    ) {
  1556. X        &'usr_log($kl, "OK kit $name left in dir $kitdir") if $'loglvl > 2;
  1557. X        if (chdir $kitdir) {
  1558. X            unlink "$pname.cnt";            # Unlink kit count anyway
  1559. X            unlink @contents if $remove;    # Remove parts if unkit successful
  1560. X        } else {
  1561. X            &'usr_log($kl, "WARNING cannot chdir to $kitdir to cleanup: $!")
  1562. X                if $'loglvl > 5;
  1563. X        }
  1564. X
  1565. X        # Send mail to user if x_unkit_notify option is set. Special macros
  1566. X        # needed by the UNKIT context are first declared before calling the
  1567. X        # NOTIFY function via the perl interface.
  1568. X
  1569. X        &usrmac'push('name', $origname, 'SCALAR');
  1570. X        &usrmac'push('parts', $total, 'SCALAR');
  1571. X        &usrmac'push('kitdir', $kitdir, 'SCALAR');
  1572. X
  1573. X        &mailhook'notify($cf'x_unkit_notify, $cf'user) if $cf'x_unkit_notify;
  1574. X        
  1575. X        &usrmac'pop('name');
  1576. X        &usrmac'pop('parts');
  1577. X        &usrmac'pop('kitdir');
  1578. X
  1579. X    } else {
  1580. X        &'usr_log($kl, "FAILED unkit returned non-zero status") if $'loglvl > 1;
  1581. X        &unkit'error;
  1582. X    }
  1583. X    
  1584. X    0;        # If we came here, then no error can really be reported
  1585. X}
  1586. X
  1587. X# Maintain an accurate count of the parts received sofar. Return the actual
  1588. X# number of parts we got.
  1589. Xsub unkit'one_more {
  1590. X    local($dir, $name) = @_;    # Dirname, basename for parts
  1591. X    local($file) = $dir . "/$name.cnt";
  1592. X    local($count) = 0;            # Actual number of files
  1593. X    if (-1 == &main'acs_rqst($file)) {
  1594. X        &'usr_log($kl, "WARNING cannot lock $file") if $'loglvl > 5;
  1595. X    }
  1596. X    if (-f $file) {                # Already a count
  1597. X        open(COUNT, "$file");
  1598. X        $count = int(<COUNT>);
  1599. X        close COUNT;
  1600. X    }
  1601. X    $count++;
  1602. X    unless (open(COUNT, ">$file")) {
  1603. X        &'usr_log($kl, "ERROR cannot create $file: $!") if $'loglvl > 1;
  1604. X    }
  1605. X    local($error) = 0;
  1606. X    (print COUNT "$count\n") || ($error++);
  1607. X    close(COUNT) || ($error++);
  1608. X    if ($error) {
  1609. X        &'usr_log($kl, "ERROR cannot update file count (now $count)")
  1610. X            if $'loglvl > 1;
  1611. X    }
  1612. X    &main'free_file($file);
  1613. X    $count;                        # Return new count
  1614. X}
  1615. X
  1616. X# Report error in unkiting process
  1617. Xsub unkit'error {
  1618. X    &'usr_log($kl, "ERROR package $name left unkited in $kitdir")
  1619. X        if $'loglvl > 1;
  1620. X}
  1621. X
  1622. END_OF_FILE
  1623.   if test 9447 -ne `wc -c <'misc/unkit/unkit.pl'`; then
  1624.     echo shar: \"'misc/unkit/unkit.pl'\" unpacked with wrong size!
  1625.   fi
  1626.   # end of 'misc/unkit/unkit.pl'
  1627. fi
  1628. echo shar: End of archive 14 \(of 26\).
  1629. cp /dev/null ark14isdone
  1630. MISSING=""
  1631. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 ; do
  1632.     if test ! -f ark${I}isdone ; then
  1633.     MISSING="${MISSING} ${I}"
  1634.     fi
  1635. done
  1636. if test "${MISSING}" = "" ; then
  1637.     echo You have unpacked all 26 archives.
  1638.     echo "Now run 'sh PACKNOTES', then read README and type Configure.'"
  1639.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1640. else
  1641.     echo You still must unpack the following archives:
  1642.     echo "        " ${MISSING}
  1643. fi
  1644. exit 0
  1645.  
  1646. exit 0 # Just in case...
  1647.