home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume33 / mailagnt / part13 < prev    next >
Encoding:
Text File  |  1992-11-20  |  54.6 KB  |  1,844 lines

  1. Newsgroups: comp.sources.misc
  2. From: ram@eiffel.com (Raphael Manfredi)
  3. Subject:  v33i105:  mailagent - Rule Based Mail Filtering, Part13/17
  4. Message-ID: <1992Nov20.230731.26915@sparky.imd.sterling.com>
  5. X-Md4-Signature: 2714ad43c3825686c788f39a8ef94eaf
  6. Date: Fri, 20 Nov 1992 23:07:31 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: ram@eiffel.com (Raphael Manfredi)
  10. Posting-number: Volume 33, Issue 105
  11. Archive-name: mailagent/part13
  12. Environment: Perl, Sendmail, UNIX
  13.  
  14. #! /bin/sh
  15. # This is a shell archive.  Remove anything before this line, then feed it
  16. # into a shell via "sh file" or similar.  To overwrite existing files,
  17. # type "sh file -c".
  18. # Contents:  Makefile.SH agent/files/chkagent.sh agent/filter/main.c
  19. #   agent/man/Makefile.SH agent/man/mailhelp.SH agent/pl/emergency.pl
  20. #   agent/pl/listqueue.pl agent/pl/macros.pl agent/pl/read_conf.pl
  21. #   agent/test/TEST agent/test/actions
  22. # Wrapped by kent@sparky on Wed Nov 18 22:42:29 1992
  23. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
  24. echo If this archive is complete, you will see the following message:
  25. echo '          "shar: End of archive 13 (of 17)."'
  26. if test -f 'Makefile.SH' -a "${1}" != "-c" ; then 
  27.   echo shar: Will not clobber existing file \"'Makefile.SH'\"
  28. else
  29.   echo shar: Extracting \"'Makefile.SH'\" \(4878 characters\)
  30.   sed "s/^X//" >'Makefile.SH' <<'END_OF_FILE'
  31. X: Makefile.SH generated from Jmake.tmpl and Jmakefile [jmake 2.8 PL13]
  32. X: $X-Id: Jmake.tmpl,v 2.8.1.2 91/11/18 13:22:54 ram Exp $
  33. X
  34. Xcase $CONFIG in
  35. X'')
  36. X    if test ! -f config.sh; then
  37. X        ln ../config.sh . || \
  38. X        ln ../../config.sh . || \
  39. X        ln ../../../config.sh . || \
  40. X        (echo "Can't find config.sh."; exit 1)
  41. X    fi 2>/dev/null
  42. X    . ./config.sh
  43. X    ;;
  44. Xesac
  45. Xcase "$0" in
  46. X*/*) cd `expr X$0 : 'X\(.*\)/'` ;;
  47. Xesac
  48. XCURRENT=.
  49. XDIR=`echo $CURRENT/ | sed -e 's/\.\///g'`
  50. Xecho "Extracting ${DIR}Makefile (with variable substitutions)"
  51. XDATE=`date`
  52. X$spitshell >Makefile <<!GROK!THIS!
  53. X########################################################################
  54. X# Makefile generated from Makefile.SH on $DATE
  55. X
  56. XSHELL = /bin/sh
  57. XJMAKE = jmake
  58. XTOP = .
  59. XCURRENT = $CURRENT
  60. XDIR = $DIR
  61. X
  62. X########################################################################
  63. X# Parameters set by Configure -- edit config.sh if changes are needed
  64. X
  65. XCTAGS = ctags
  66. XMAKE = make
  67. XMV = $mv
  68. XRM = $rm -f
  69. X
  70. X########################################################################
  71. X# Automatically generated parameters -- do not edit
  72. X
  73. XSUBDIRS = agent
  74. X
  75. X!GROK!THIS!
  76. X$spitshell >>Makefile <<'!NO!SUBS!'
  77. X
  78. X########################################################################
  79. X# Jmake rules for building libraries, programs, scripts, and data files
  80. X# $X-Id: Jmake.rules,v 2.8.1.4 91/11/18 13:19:07 ram Exp $
  81. X
  82. X########################################################################
  83. X# Start of Jmakefile
  84. X
  85. X# $X-Id: Jmakefile,v 2.9 92/07/14 16:46:57 ram Exp $
  86. X#
  87. X#  Copyright (c) 1991, Raphael Manfredi
  88. X#
  89. X#  You may redistribute only under the terms of the GNU General Public
  90. X#  Licence as specified in the README file that comes with dist.
  91. X#
  92. X# $X-Log:    Jmakefile,v $
  93. X# Revision 2.9  92/07/14  16:46:57  ram
  94. X# 3.0 beta baseline.
  95. X#
  96. X
  97. Xall::
  98. X
  99. Xlocal_clobber::
  100. X    $(RM) install mkdep cppstdin
  101. X
  102. Xdepend::
  103. X    @case '${MFLAGS}' in *[ik]*) set +e;; esac; \
  104. X    for i in $(SUBDIRS) ;\
  105. X    do \
  106. X        (cd $$i ; echo "Depending" "in $(DIR)$$i..."; \
  107. X            $(MAKE) $(MFLAGS)  depend); \
  108. X    done
  109. X
  110. X########################################################################
  111. X# Common rules for all Makefiles -- do not edit
  112. X
  113. Xemptyrule::
  114. X
  115. Xclean: sub_clean local_clean
  116. Xrealclean: sub_realclean local_realclean
  117. Xclobber: sub_clobber local_clobber
  118. X
  119. Xlocal_clean::
  120. X    $(RM) core *~ *.o
  121. X
  122. Xlocal_realclean:: local_clean
  123. X    $(RM) -r UU
  124. X
  125. Xlocal_clobber:: local_realclean
  126. X    $(RM) config.sh config.h
  127. X    $(RM) Makefile
  128. X
  129. XMakefile.SH: Jmakefile
  130. X    -@if test -f $(TOP)/.package; then \
  131. X        if test -f Makefile.SH; then \
  132. X            echo "    $(RM) Makefile.SH~; $(MV) Makefile.SH Makefile.SH~"; \
  133. X            $(RM) Makefile.SH~; $(MV) Makefile.SH Makefile.SH~; \
  134. X        fi; \
  135. X        echo "    $(JMAKE) -DTOPDIR=$(TOP) -DCURDIR=$(CURRENT)" ; \
  136. X        $(JMAKE) -DTOPDIR=$(TOP) -DCURDIR=$(CURRENT) ; \
  137. X    else touch $@; exit 0; fi
  138. X
  139. XMakefile: Makefile.SH
  140. X    /bin/sh Makefile.SH
  141. X
  142. Xtags::
  143. X    $(CTAGS) -w *.[ch]
  144. X    $(CTAGS) -xw *.[ch] > tags
  145. X
  146. Xlocal_clobber::
  147. X    $(RM) tags
  148. X
  149. X########################################################################
  150. X# Rules for building in sub-directories -- do not edit
  151. X
  152. Xsubdirs:
  153. X    @case '${MFLAGS}' in *[ik]*) set +e;; esac; \
  154. X    for i in $(SUBDIRS) ;\
  155. X    do \
  156. X        (cd $$i ; echo $(VERB) "in $(DIR)$$i..."; \
  157. X            $(MAKE) $(MFLAGS) $(FLAGS) $(TARGET)); \
  158. X    done
  159. X
  160. Xinstall::
  161. X    @$(MAKE) subdirs TARGET=install VERB="Installing" FLAGS=
  162. X
  163. Xdeinstall::
  164. X    @$(MAKE) subdirs TARGET=deinstall VERB="Deinstalling" FLAGS=
  165. X
  166. Xinstall.man::
  167. X    @$(MAKE) subdirs TARGET=install.man VERB="Installing man pages" FLAGS=
  168. X
  169. Xdeinstall.man::
  170. X    @$(MAKE) subdirs TARGET=deinstall.man VERB="Deinstalling man pages" FLAGS=
  171. X
  172. Xsub_clean::
  173. X    @$(MAKE) subdirs TARGET=clean VERB="Cleaning" FLAGS=
  174. X    @echo "Back to $(CURRENT) for "clean...
  175. X
  176. Xsub_realclean::
  177. X    @$(MAKE) subdirs TARGET=realclean VERB="Real cleaning" FLAGS=
  178. X    @echo "Back to $(CURRENT) for "realclean...
  179. X
  180. Xsub_clobber::
  181. X    @$(MAKE) subdirs TARGET=clobber VERB="Clobbering" FLAGS=
  182. X    @echo "Back to $(CURRENT) for "clobber...
  183. X
  184. Xtag::
  185. X    @case '${MFLAGS}' in *[ik]*) set +e;; esac; \
  186. X    for i in  ;\
  187. X    do \
  188. X        (cd $$i ; echo "Tagging" "in $(DIR)$$i..."; \
  189. X            $(MAKE) $(MFLAGS)  tag); \
  190. X    done
  191. X
  192. XMakefiles::
  193. X    @case '${MFLAGS}' in *[ik]*) set +e;; esac; \
  194. X    for i in $(SUBDIRS);\
  195. X    do \
  196. X        echo "Making "Makefiles" in $(DIR)$$i..."; \
  197. X        (cd $$i || exit 1; \
  198. X        if test ! -f Makefile; then /bin/sh Makefile.SH; fi; \
  199. X        $(MAKE) $(MFLAGS) Makefiles) \
  200. X    done
  201. X
  202. XMakefiles.SH:: Makefile.SH
  203. X    @case '${MFLAGS}' in *[ik]*) set +e;; esac; \
  204. X    for i in $(SUBDIRS);\
  205. X    do \
  206. X        case "$(DIR)$$i/" in \
  207. X        */*/*/*/) newtop=../../../..;; \
  208. X        */*/*/) newtop=../../..;; \
  209. X        */*/) newtop=../..;; \
  210. X        */) newtop=..;; \
  211. X        esac; \
  212. X        case "$(TOP)" in \
  213. X        /*) newtop="$(TOP)" ;; \
  214. X        esac; \
  215. X        echo "Making Makefiles.SH in $(DIR)$$i..."; \
  216. X        (cd $$i || exit 1; $(MAKE) $(MFLAGS) -f ../Makefile \
  217. X        Makefile TOP=$$newtop CURRENT=$(DIR)$$i;\
  218. X        $(MAKE) $(MFLAGS) Makefiles.SH) \
  219. X    done
  220. X
  221. Xall::
  222. X    @$(MAKE) subdirs TARGET=all VERB="Making all" FLAGS=
  223. X
  224. X!NO!SUBS!
  225. Xchmod 644 Makefile
  226. X$eunicefix Makefile
  227. X
  228. END_OF_FILE
  229.   if test 4878 -ne `wc -c <'Makefile.SH'`; then
  230.     echo shar: \"'Makefile.SH'\" unpacked with wrong size!
  231.   fi
  232.   # end of 'Makefile.SH'
  233. fi
  234. if test -f 'agent/files/chkagent.sh' -a "${1}" != "-c" ; then 
  235.   echo shar: Will not clobber existing file \"'agent/files/chkagent.sh'\"
  236. else
  237.   echo shar: Extracting \"'agent/files/chkagent.sh'\" \(2256 characters\)
  238.   sed "s/^X//" >'agent/files/chkagent.sh' <<'END_OF_FILE'
  239. X#!/bin/sh
  240. X#
  241. X#  Copyright (c) 1992, Raphael Manfredi
  242. X#
  243. X#  You may redistribute only under the terms of the GNU General Public
  244. X#  Licence as specified in the README file that comes with dist.
  245. X#
  246. X# $Id: chkagent.sh,v 2.9 92/07/14 16:47:41 ram Exp $
  247. X#
  248. X# $Log:    chkagent.sh,v $
  249. X# Revision 2.9  92/07/14  16:47:41  ram
  250. X# 3.0 beta baseline.
  251. X# 
  252. X
  253. X# Make sure the mailagent is working well
  254. Xlookat='ERROR|FAILED|WARNING|FATAL|DUMPED'
  255. X
  256. Xtrap "rm -f $report $output $todaylog $msg" 1 2 3 15
  257. X
  258. X# Interpret the ~/.mailagent configuration file
  259. Xset X `<$HOME/.mailagent sed -n \
  260. X    -e '/^[     ]*#/d' \
  261. X    -e 's/^[     ]*\([^     :\/]*\)[     ]*:[     ]*\([^#]*\).*/\1="\2";/p'`
  262. Xshift
  263. X
  264. X# Deal with possible white spaces in variables and ~ substitution
  265. Xcmd=''
  266. Xfor line in $*; do
  267. X    cmd="$cmd$line"
  268. Xdone
  269. Xcmd=`echo $cmd | sed -e "s|~|$HOME|g"`
  270. Xeval $cmd
  271. X
  272. X# Compute location of report file and log file
  273. Xreport="/tmp/cAg$$"
  274. Xoutput="/tmp/cAo$$"
  275. Xlogfile="$logdir/$log"
  276. Xtodaylog="/tmp/tAg$$"
  277. X
  278. X# Current date format to look for in logfile
  279. Xtoday=`date "+%y/%m/%d"`
  280. X
  281. Xif test -f "$logfile"; then
  282. X    grep "$today" $logfile > $todaylog
  283. X    egrep "$lookat" $todaylog > $output
  284. X    if test -s "$output"; then
  285. X        echo "*** Errors from logfile ($logfile):" > $report
  286. X        echo " " >> $report
  287. X        cat $output >> $report
  288. X    fi
  289. X    rm -f $todaylog $output
  290. Xelse
  291. X    echo "Cannot find $logfile" > $report
  292. Xfi
  293. X
  294. X# ~/.bak is the output from .forward
  295. Xif test -s "$HOME/.bak"; then
  296. X    echo " " >> $report
  297. X    echo "*** Errors from ~/.bak:" >> $report
  298. X    echo " " >> $report
  299. X    cat $HOME/.bak >> $report
  300. X    cp /dev/null $HOME/.bak
  301. Xfi
  302. X
  303. X# Look for mails in the emergency directory
  304. Xls -C $emergdir > $output
  305. Xif test -s "$output"; then
  306. X    echo " " >> $report
  307. X    echo "*** Mails held in lost+mail ($emergdir):" >> $report
  308. X    echo " " >> $report
  309. X    cat $output >> $report
  310. Xfi
  311. Xrm -f $output
  312. X
  313. X# Spot any unprocessed mails in the queue
  314. Xcd $queue
  315. Xls -C qm* fm* > $output 2>/dev/null
  316. Xif test -s "$output"; then
  317. X    echo " " >> $report
  318. X    echo "*** Unprocessed mails in queue ($queue):" >> $report
  319. X    echo " " >> $report
  320. X    cat $output >> $report
  321. Xfi
  322. Xrm -f $output
  323. X
  324. Xif test -s "$report"; then
  325. X    msg="/tmp/mAg$$"
  326. X    cat >$msg <<EOM
  327. XTo: $user
  328. XSubject: Errors from mailagent system
  329. X
  330. XEOM
  331. X    cat $report >>$msg
  332. X    rm -f $report
  333. X    /usr/lib/sendmail -odi -t <$msg
  334. X    rm -f $msg
  335. Xelse
  336. X    rm -f $report
  337. Xfi
  338. X
  339. Xexit 0
  340. END_OF_FILE
  341.   if test 2256 -ne `wc -c <'agent/files/chkagent.sh'`; then
  342.     echo shar: \"'agent/files/chkagent.sh'\" unpacked with wrong size!
  343.   fi
  344.   chmod +x 'agent/files/chkagent.sh'
  345.   # end of 'agent/files/chkagent.sh'
  346. fi
  347. if test -f 'agent/filter/main.c' -a "${1}" != "-c" ; then 
  348.   echo shar: Will not clobber existing file \"'agent/filter/main.c'\"
  349. else
  350.   echo shar: Extracting \"'agent/filter/main.c'\" \(4229 characters\)
  351.   sed "s/^X//" >'agent/filter/main.c' <<'END_OF_FILE'
  352. X/*
  353. X
  354. X #    #    ##       #    #    #           ####
  355. X ##  ##   #  #      #    ##   #          #    #
  356. X # ## #  #    #     #    # #  #          #
  357. X #    #  ######     #    #  # #   ###    #
  358. X #    #  #    #     #    #   ##   ###    #    #
  359. X #    #  #    #     #    #    #   ###     ####
  360. X
  361. X    The main entry point.
  362. X*/
  363. X
  364. X/*
  365. X * $Id: main.c,v 2.9.1.1 92/08/12 21:30:38 ram Exp $
  366. X *
  367. X *  Copyright (c) 1992, Raphael Manfredi
  368. X *
  369. X *  You may redistribute only under the terms of the GNU General Public
  370. X *  Licence as specified in the README file that comes with dist.
  371. X *
  372. X * $Log:    main.c,v $
  373. X * Revision 2.9.1.1  92/08/12  21:30:38  ram
  374. X * patch6: option -t disallowed when running setuid (security hole)
  375. X * 
  376. X * Revision 2.9  92/07/14  16:48:27  ram
  377. X * 3.0 beta baseline.
  378. X * 
  379. X */
  380. X
  381. X#include "config.h"
  382. X#include "portable.h"
  383. X
  384. X#ifdef I_STRING
  385. X#include <string.h>
  386. X#else
  387. X#include <strings.h>
  388. X#endif
  389. X
  390. X#include <stdio.h>
  391. X#include <signal.h>
  392. X#include <sys/types.h>
  393. X#include "logfile.h"
  394. X#include "io.h"
  395. X#include "hash.h"
  396. X#include "msg.h"
  397. X#include "parser.h"
  398. X#include "sysexits.h"
  399. X
  400. X#define MAX_STRING    2048    /* Maximum string length */
  401. X
  402. Xprivate Signal_t handler();    /* Signal handler */
  403. Xprivate void set_signal();    /* Set up the signal handler */
  404. X
  405. Xextern void env_home();        /* Only for tests */
  406. X
  407. Xpublic void main(argc, argv, envp)
  408. Xint argc;
  409. Xchar **argv;
  410. Xchar **envp;
  411. X{
  412. X    /* This is the main entry point for the mail filter */
  413. X
  414. X    char *value;                        /* Symbol value */
  415. X    int euid, uid;                        /* Current effective and real uid */
  416. X    int egid, gid;                        /* Effective and real gid */
  417. X
  418. X    /* Compute program name, removing any leading path to keep only the name
  419. X     * of the executable file.
  420. X     */
  421. X    progname = rindex(argv[0], '/');    /* Only last name if '/' found */
  422. X    if (progname++ == (char *) 0)        /* There were no '/' */
  423. X        progname = argv[0];                /* This must be the filename then */
  424. X    progpid = getpid();                    /* Program's PID */
  425. X
  426. X    /* Security precautions. Look who we are and who we pretend to be */
  427. X    uid = getuid();
  428. X    gid = getgid();
  429. X    euid = geteuid();
  430. X    egid = getegid();
  431. X
  432. X    /* The '-t' option means we are in test mode: set the home directory by
  433. X     * using the environment HOME variable, so that we may provide our own
  434. X     * configuration file elsewhere. Of course, this cannot be used if the
  435. X     * filter is setuid and invoked by an uid different than the owner of the
  436. X     * filter program.
  437. X     */
  438. X    if (argc > 1 && 0 == strcmp(argv[1], "-t")) {
  439. X        if (uid != euid) {
  440. X            fprintf(stderr, "filter: no option allowed when setuid\n");
  441. X            exit(1);
  442. X        }
  443. X        env_home();                        /* Get HOME form environment */
  444. X    }
  445. X
  446. X    set_signal();                        /* Set up signal handler */
  447. X    read_conf(".mailagent");            /* Read configuration file */
  448. X
  449. X    add_log(19, "starting processing");
  450. X
  451. X    /* We'll be invoking a perl script with the -S switch, and perl will not
  452. X     * allow us to do that if it detects "setuidness". Some sendmail programs
  453. X     * are broken and do not reset the uid/gid correctly when they process
  454. X     * their queue. This is why it is important to set the setuid and setgid
  455. X     * bits on the filter program.
  456. X     */
  457. X
  458. X    /* Make sure our gid matches the effective gid */
  459. X    if (egid != gid && -1 == setgid(egid)) {
  460. X        add_log(1, "SYSERR setgid: %m (%e)");
  461. X        add_log(4, "WARNING cannot set GID to %d, continuing as %d", egid, gid);
  462. X    } else if (egid != gid)
  463. X        add_log(6, "NOTICE reset GID from %d to %d", gid, egid);
  464. X
  465. X    /* Make sure our uid matches the effective uid */
  466. X    if (euid != uid && -1 == setuid(euid)) {
  467. X        add_log(1, "SYSERR setuid: %m (%e)");
  468. X        add_log(4, "WARNING cannot set UID to %d, continuing as %d", euid, uid);
  469. X    } else if (euid != uid)
  470. X        add_log(6, "NOTICE reset UID from %d to %d", uid, euid);
  471. X
  472. X    value = ht_value(&symtab, "queue");        /* Fetch queue location */
  473. X    if (value == (char *) 0)
  474. X        fatal("queue directory not defined");
  475. X
  476. X    set_env_vars(envp);                        /* Set environment variables */
  477. X    process();                                /* Process mail */
  478. X
  479. X    exit(EX_OK);        /* We did it */
  480. X}
  481. X
  482. Xprivate void set_signal()
  483. X{
  484. X    /* Set up the signal handler */
  485. X
  486. X#ifdef SIGHUP
  487. X    signal(SIGHUP, handler);
  488. X#endif
  489. X#ifdef SIGINT
  490. X    signal(SIGINT, handler);
  491. X#endif
  492. X#ifdef SIGQUIT
  493. X    signal(SIGQUIT, handler);
  494. X#endif
  495. X#ifdef SIGTERM
  496. X    signal(SIGTERM, handler);
  497. X#endif
  498. X}
  499. X
  500. Xprivate Signal_t handler(sig)
  501. Xint sig;
  502. X{
  503. X    /* A signal was caught */
  504. X
  505. X    fatal("caught signal #%d", sig);
  506. X}
  507. X
  508. END_OF_FILE
  509.   if test 4229 -ne `wc -c <'agent/filter/main.c'`; then
  510.     echo shar: \"'agent/filter/main.c'\" unpacked with wrong size!
  511.   fi
  512.   # end of 'agent/filter/main.c'
  513. fi
  514. if test -f 'agent/man/Makefile.SH' -a "${1}" != "-c" ; then 
  515.   echo shar: Will not clobber existing file \"'agent/man/Makefile.SH'\"
  516. else
  517.   echo shar: Extracting \"'agent/man/Makefile.SH'\" \(3801 characters\)
  518.   sed "s/^X//" >'agent/man/Makefile.SH' <<'END_OF_FILE'
  519. X: Makefile.SH generated from Jmake.tmpl and Jmakefile [jmake 2.8 PL13]
  520. X: $X-Id: Jmake.tmpl,v 2.8.1.2 91/11/18 13:22:54 ram Exp $
  521. X
  522. Xcase $CONFIG in
  523. X'')
  524. X    if test ! -f config.sh; then
  525. X        ln ../config.sh . || \
  526. X        ln ../../config.sh . || \
  527. X        ln ../../../config.sh . || \
  528. X        (echo "Can't find config.sh."; exit 1)
  529. X    fi 2>/dev/null
  530. X    . ./config.sh
  531. X    ;;
  532. Xesac
  533. Xcase "$0" in
  534. X*/*) cd `expr X$0 : 'X\(.*\)/'` ;;
  535. Xesac
  536. XCURRENT=agent/man
  537. XDIR=`echo $CURRENT/ | sed -e 's/\.\///g'`
  538. Xecho "Extracting ${DIR}Makefile (with variable substitutions)"
  539. XDATE=`date`
  540. X$spitshell >Makefile <<!GROK!THIS!
  541. X########################################################################
  542. X# Makefile generated from Makefile.SH on $DATE
  543. X
  544. XSHELL = /bin/sh
  545. XJMAKE = jmake
  546. XTOP = ../..
  547. XCURRENT = $CURRENT
  548. XDIR = $DIR
  549. XINSTALL = ../../install
  550. X
  551. X########################################################################
  552. X# Parameters set by Configure -- edit config.sh if changes are needed
  553. X
  554. XCTAGS = ctags
  555. XL = $manext
  556. XMANSRC = $mansrc
  557. XMAKE = make
  558. XMV = $mv
  559. XRM = $rm -f
  560. X
  561. X########################################################################
  562. X# Automatically generated parameters -- do not edit
  563. X
  564. XMANPAGE =  \$(MPAGES)
  565. X
  566. X########################################################################
  567. X# New suffixes and associated building rules -- edit with care
  568. X
  569. X.SUFFIXES: .SH .$manext
  570. X
  571. X.SH.$manext:
  572. X    /bin/sh \$<
  573. X
  574. X!GROK!THIS!
  575. X$spitshell >>Makefile <<'!NO!SUBS!'
  576. X
  577. X########################################################################
  578. X# Jmake rules for building libraries, programs, scripts, and data files
  579. X# $X-Id: Jmake.rules,v 2.8.1.4 91/11/18 13:19:07 ram Exp $
  580. X
  581. X########################################################################
  582. X# Start of Jmakefile
  583. X
  584. X# $X-Id: Jmakefile,v 2.9 92/07/14 16:49:04 ram Exp $
  585. X#
  586. X#  Copyright (c) 1991, Raphael Manfredi
  587. X#
  588. X#  You may redistribute only under the terms of the GNU General Public
  589. X#  Licence as specified in the README file that comes with dist.
  590. X#
  591. X# $X-Log:    Jmakefile,v $
  592. X# Revision 2.9  92/07/14  16:49:04  ram
  593. X# 3.0 beta baseline.
  594. X#
  595. X
  596. XMPAGES = mailagent.$(L) maildist.$(L) maillist.$(L) mailhelp.$(L) mailpatch.$(L)
  597. X
  598. Xall:: $(MPAGES)
  599. X
  600. Xlocal_realclean::
  601. X    $(RM) $(MPAGES)
  602. X
  603. Xinstall.man::
  604. X    @if test "$(MANSRC)"; then \
  605. X        case '${MFLAGS}' in *[i]*) set +e;; esac; \
  606. X        for file in $(MPAGES); do \
  607. X            (set -x; $(INSTALL) -c -m 444 $$file $(MANSRC)); \
  608. X        done; \
  609. X    else exit 0; fi
  610. X
  611. Xdeinstall.man::
  612. X    @if test "$(MANSRC)"; then \
  613. X        case '${MFLAGS}' in *[i]*) set +e;; esac; \
  614. X        for file in $(MPAGES); do \
  615. X            (set -x; $(RM) $(MANSRC)/$$file); \
  616. X        done; \
  617. X    else exit 0; fi
  618. X
  619. X########################################################################
  620. X# Common rules for all Makefiles -- do not edit
  621. X
  622. Xemptyrule::
  623. X
  624. Xclean: local_clean
  625. Xrealclean: local_realclean
  626. Xclobber: local_clobber
  627. X
  628. Xlocal_clean::
  629. X    $(RM) core *~ *.o
  630. X
  631. Xlocal_realclean:: local_clean
  632. X
  633. Xlocal_clobber:: local_realclean
  634. X    $(RM) Makefile config.sh
  635. X
  636. XMakefile.SH: Jmakefile
  637. X    -@if test -f $(TOP)/.package; then \
  638. X        if test -f Makefile.SH; then \
  639. X            echo "    $(RM) Makefile.SH~; $(MV) Makefile.SH Makefile.SH~"; \
  640. X            $(RM) Makefile.SH~; $(MV) Makefile.SH Makefile.SH~; \
  641. X        fi; \
  642. X        echo "    $(JMAKE) -DTOPDIR=$(TOP) -DCURDIR=$(CURRENT)" ; \
  643. X        $(JMAKE) -DTOPDIR=$(TOP) -DCURDIR=$(CURRENT) ; \
  644. X    else touch $@; exit 0; fi
  645. X
  646. XMakefile: Makefile.SH
  647. X    /bin/sh Makefile.SH
  648. X
  649. Xtags::
  650. X    $(CTAGS) -w *.[ch]
  651. X    $(CTAGS) -xw *.[ch] > tags
  652. X
  653. Xlocal_clobber::
  654. X    $(RM) tags
  655. X
  656. X########################################################################
  657. X# Empty rules for directories with no sub-directories -- do not edit
  658. X
  659. Xinstall::
  660. X    @echo "install in $(CURRENT) done."
  661. X
  662. Xdeinstall::
  663. X    @echo "deinstall in $(CURRENT) done."
  664. X
  665. Xinstall.man::
  666. X    @echo "install.man in $(CURRENT) done."
  667. X
  668. Xdeinstall.man::
  669. X    @echo "deinstall.man in $(CURRENT) done."
  670. X
  671. XMakefiles::
  672. X
  673. XMakefiles.SH::
  674. X
  675. X!NO!SUBS!
  676. Xchmod 644 Makefile
  677. X$eunicefix Makefile
  678. X
  679. END_OF_FILE
  680.   if test 3801 -ne `wc -c <'agent/man/Makefile.SH'`; then
  681.     echo shar: \"'agent/man/Makefile.SH'\" unpacked with wrong size!
  682.   fi
  683.   chmod +x 'agent/man/Makefile.SH'
  684.   # end of 'agent/man/Makefile.SH'
  685. fi
  686. if test -f 'agent/man/mailhelp.SH' -a "${1}" != "-c" ; then 
  687.   echo shar: Will not clobber existing file \"'agent/man/mailhelp.SH'\"
  688. else
  689.   echo shar: Extracting \"'agent/man/mailhelp.SH'\" \(5217 characters\)
  690.   sed "s/^X//" >'agent/man/mailhelp.SH' <<'END_OF_FILE'
  691. Xcase $CONFIG in
  692. X'')
  693. X    if test ! -f config.sh; then
  694. X        ln ../config.sh . || \
  695. X        ln ../../config.sh . || \
  696. X        ln ../../../config.sh . || \
  697. X        (echo "Can't find config.sh."; exit 1)
  698. X    fi
  699. X    . config.sh
  700. X    ;;
  701. Xesac
  702. Xcase "$0" in
  703. X*/*) cd `expr X$0 : 'X\(.*\)/'` ;;
  704. Xesac
  705. Xecho "Extracting agent/man/mailhelp.$manext (with variable substitutions)"
  706. X$rm -f mailhelp.$manext
  707. X$spitshell >mailhelp.$manext <<!GROK!THIS!
  708. X.TH MAILHELP $manext ram
  709. X''' @(#) Manual page for mailagent's commands -- (c) ram February 1991
  710. X'''
  711. X''' $Id: mailhelp.SH,v 2.9 92/07/14 16:49:18 ram Exp $
  712. X'''
  713. X'''  Copyright (c) 1991, Raphael Manfredi
  714. X'''
  715. X'''  You may redistribute only under the terms of the GNU General Public
  716. X'''  Licence as specified in the README file that comes with dist.
  717. X'''
  718. X''' $Log:    mailhelp.SH,v $
  719. X''' Revision 2.9  92/07/14  16:49:18  ram
  720. X''' 3.0 beta baseline.
  721. X''' 
  722. X.SH NAME
  723. Xmaildist, mailhelp, maillist, mailpatch \- mailagent's commands
  724. X.SH SYNOPSIS
  725. X\fBmaildist\fR \fIaddress\fR \fIsystem\fR [ \fIversion\fR ]
  726. X.br
  727. X\fBmailhelp\fR [ \fIaddress\fR ]
  728. X.br
  729. X\fBmaillist\fR [ \fIaddress\fR ]
  730. X.br
  731. X\fBmailpatch\fR \fIaddress\fR \fIsystem\fR \fIversion\fR \fIpatchlist\fR
  732. X.SH DESCRIPTION
  733. XThese commands are not intended to be run directly by a user. They may
  734. Xappear in any mail whose subject is set to \fICommand\fR. Such a mail
  735. Xwill be processed by the \fImailagent\fR(1), which will extract all lines
  736. Xbeginning with \fI@SH\fR, followed by one of the above commands. The
  737. Xmailagent first sets environment variables that will be used by every
  738. Xcommands.
  739. X.PP
  740. X.I Maildist
  741. Xis used to mail a whole distribution to the given address. The version
  742. Xnumber may be ommitted if the system has no version specified !!
  743. X.I Maildist
  744. Xlooks for the \fISpool/distribs\fR file to find where the distribution
  745. Xis located. If it has been archived, the file name extension is used
  746. Xto guess how the archive will be restored:
  747. X.sp
  748. X.PD 0
  749. X.TP 10
  750. X.B .cpio
  751. Xarchive is a \fIcpio\fR archive
  752. X.TP
  753. X.B .tar
  754. Xarchive is in \fItar\fR format
  755. X.TP
  756. X.B .cpio.Z
  757. Xcompressed \fIcpio\fR archive
  758. X.TP
  759. X.B .tar.Z
  760. Xcompressed \fItar\fR archive
  761. X.PD
  762. X.PP
  763. XNote that on file systems with short file names, the final \fB.Z\fR
  764. Xextension could be dropped. Therefore, compressed archives must be
  765. Xexplicitely stated in the \fISpool/distribs\fR file.
  766. X.PP
  767. XOnce the directory is found (or extracted), \fImaildist\fR looks
  768. Xfor a \fIMANIFEST\fR file. If it finds one,
  769. Xonly the files listed therein will be sent. Otherwise,
  770. Xall the files will be sent, excepted the binary executables and object
  771. Xfiles, the RCS sub-directories or RCS files, the private \fIU\fR
  772. Xsubdirectory and the \fI.package\fR file, any \fIcore\fR file or files
  773. Xin a \fIbugs\fR subdirectory.
  774. X.PP
  775. XThen, the following algorithm is used: if no RCS file is found, the
  776. Xfile is sent as-is. Otherwise, we look for a defined 'lastpat' symbol.
  777. XIf it is found, the corresponding revision is checked-out and sent.
  778. XOtherwise, the last-revision on the default branch is exctracted,
  779. Xprovided that the corresponding working file is not found.
  780. X.PP
  781. XThe \fImaildist\fR command will not work if the system is tagged as
  782. Xan old one (with an \fIo\fR in the patches column of the \fIdistribs\fR
  783. Xfile). A message will be sent back to the user, explaining that only
  784. Xpatches are available.
  785. X.PP
  786. X.I Mailhelp
  787. Xsends help to the address (if ommitted, the return path of the mail
  788. Xis used). The help text is found in \fISpool/agenthelp\fR. It should
  789. Xhave been correctly set in the installation procedure, as explained
  790. Xin the \fImailagent\fR($manext) manual page.
  791. X.PP
  792. X.I Maillist
  793. Xsends the list of available distributions, with current patchlevels
  794. Xif necessary. The \fISpool/distribs\fR and \fISpool/proglist\fR files
  795. Xare both used to build the list.
  796. X.PP
  797. X.I Mailpatch
  798. Xsends one or more patches for a maintained distribution. The directory
  799. Xor the archive is found by scanning \fISpool/distribs\fR. The \fIbugs\fR
  800. Xsub-directory must then hold the available patches. The patches may
  801. Xbe stored in compressed form (with the ending \fI.Z\fR), as
  802. X.I mailpatch
  803. Xknows about them and will uncompress the patch before sending.
  804. X.PP
  805. XPatches for old systems are kept in a separate directory, either in normal
  806. Xor in compressed form. If the version number of the old system is \fIx.y\fR,
  807. Xthen the directory must be named \fIbugs-x.y\fR and placed in the root
  808. Xdirectory of the system, just like \fIbugs\fR is.
  809. X.PP
  810. XWhenever the user asks for an old system, \fImailpatch\fR inserts a little
  811. Xnote giving the latest version number for that system.
  812. X.SH NOTE
  813. XFor a more accurate description of these commands (user's point of vue),
  814. Xyou may want to have a look at the help file or send help to yourself
  815. Xusing the \fImailhelp\fR command.
  816. X.SH FILES
  817. X.PD 0
  818. X.TP 20
  819. X~/.mailagent
  820. Xconfiguration file for mailhelp.
  821. X.TP
  822. X$privlib
  823. Xdirectory holding templates and samples.
  824. X.TP
  825. XSpool/agenthelp
  826. Xhelp file
  827. X.TP
  828. XSpool/distribs
  829. Xdistribution list
  830. X.TP
  831. XSpool/proglist
  832. Xcomments for available distributions
  833. X.TP
  834. XSpool/plsave
  835. Xrecords patchlevel of archived distributions
  836. X.TP
  837. XLog/agentlog
  838. Xmailagent's log file
  839. X.PD
  840. X.SH BUGS
  841. XThe \fIproglist\fR file ought to make a distinction between different
  842. Xversions of a same system.
  843. X.SH AUTHOR
  844. XRaphael Manfredi <ram@eiffel.com>
  845. X.SH "SEE ALSO"
  846. Xmailagent($manext).
  847. X!GROK!THIS!
  848. Xchmod 444 mailhelp.$manext
  849. END_OF_FILE
  850.   if test 5217 -ne `wc -c <'agent/man/mailhelp.SH'`; then
  851.     echo shar: \"'agent/man/mailhelp.SH'\" unpacked with wrong size!
  852.   fi
  853.   # end of 'agent/man/mailhelp.SH'
  854. fi
  855. if test -f 'agent/pl/emergency.pl' -a "${1}" != "-c" ; then 
  856.   echo shar: Will not clobber existing file \"'agent/pl/emergency.pl'\"
  857. else
  858.   echo shar: Extracting \"'agent/pl/emergency.pl'\" \(4856 characters\)
  859.   sed "s/^X//" >'agent/pl/emergency.pl' <<'END_OF_FILE'
  860. X;# $Id: emergency.pl,v 2.9.1.1 92/08/12 21:33:04 ram Exp Locker: ram $
  861. X;#
  862. X;#  Copyright (c) 1992, Raphael Manfredi
  863. X;#
  864. X;#  You may redistribute only under the terms of the GNU General Public
  865. X;#  Licence as specified in the README file that comes with dist.
  866. X;#
  867. X;# $Log:    emergency.pl,v $
  868. X;# Revision 2.9.1.1  92/08/12  21:33:04  ram
  869. X;# patch6: do not read mail if stdin is connected to a tty
  870. X;# 
  871. X;# Revision 2.9  92/07/14  16:49:51  ram
  872. X;# 3.0 beta baseline.
  873. X;# 
  874. X;# 
  875. X#
  876. X# Emergency situation routines
  877. X#
  878. X
  879. X# Emergency signal was caught
  880. Xsub emergency {
  881. X    local($sig) = @_;            # First argument is signal name
  882. X    if ($has_option) {            # Mailagent was invoked "manually"
  883. X        do resync();            # Resynchronize waiting file if necessary
  884. X        exit 1;
  885. X    }
  886. X    do fatal("trapped SIG$sig");
  887. X}
  888. X
  889. X# In case something got wrong
  890. Xsub fatal {
  891. X    local($reason) = shift;        # Why did we get here ?
  892. X    # Make sure the lock file does not last. We don't need any lock now, as
  893. X    # we are going to die real soon anyway.
  894. X    unlink $lockfile if $locked;
  895. X    # Assume the whole message has not been read yet
  896. X    $fd = STDIN;                # Default input
  897. X    if ($file_name ne '') {
  898. X        $Header{'All'} = '';    # We're about to re-read the whole message
  899. X        open(MSG, $file_name);    # Ignore errors
  900. X        $fd = MSG;
  901. X    }
  902. X    unless (-t $fd) {            # Do not get mail if connected to a tty
  903. X        while (<$fd>) {
  904. X            $Header{'All'} .= $_;
  905. X        }
  906. X    }
  907. X    # It can happen that we get here before configuration file was read
  908. X    if (defined $loglvl) {
  909. X        do add_log("FATAL $reason") if ($loglvl > 0);
  910. X        -t STDIN && print STDERR "$prog_name: $reason\n";
  911. X    }
  912. X    # Try an emergency save, if mail is not empty
  913. X    if ($Header{'All'} ne '' && 0 == &emergency_save) {
  914. X        # The stderr should be redirected to some file
  915. X        $file_name =~ s|.*/(.*)|$1|;    # Keep only basename
  916. X        $file_name = "<stdin>" if $file_name eq '';
  917. X        print STDERR "**** $file_name not processed ($reason) ****\n";
  918. X        print STDERR $Header{'All'};
  919. X        ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
  920. X            localtime(time);
  921. X        $date = sprintf("%.2d/%.2d/%.2d %.2d:%.2d:%.2d",
  922. X            $year,++$mon,$mday,$hour,$min,$sec);
  923. X        print STDERR "---- $date ----\n";
  924. X    }
  925. X    do resync();        # Resynchronize waiting file if necessary
  926. X    # Give an error exit status to filter
  927. X    exit 1;
  928. X}
  929. X
  930. X# Emergency saving of message held in $Header{'All'}. If the 'emergdir'
  931. X# configuration parameter in ~/.mailagent is set to an existing directory, the
  932. X# first saving attempt is made there (each mail in a separate file).
  933. Xsub emergency_save {
  934. X    return 0 unless (defined $cf'home);    # ~/.mailagent not processed
  935. X    return 1 if -d "$cf'emergdir" && &dump_mbox("$cf'emergdir/ma$$");
  936. X    return 1 if &dump_mbox(&mailbox_name);
  937. X    return 1 if &dump_mbox("$cf'home/mbox.urgent");
  938. X    return 1 if &dump_mbox("$cf'home/mbox.urg$$");
  939. X    return 1 if &dump_mbox("/usr/spool/uucppublic/mbox.$cf'user");
  940. X    return 1 if &dump_mbox("/var/spool/uucppublic/mbox.$cf'user");
  941. X    return 1 if &dump_mbox("/usr/tmp/mbox.$cf'user");
  942. X    return 1 if &dump_mbox("/var/tmp/mbox.$cf'user");
  943. X    return 1 if &dump_mbox("/tmp/mbox.$cf'user");
  944. X    &add_log("ERROR unable to save mail in any emergency mailbox") if $loglvl;
  945. X    0;
  946. X}
  947. X
  948. X# Dump $Header{'All'} in emergency mailbox
  949. Xsub dump_mbox {
  950. X    local($mbox) = shift(@_);
  951. X    local($ok) = 0;                        # printing status
  952. X    local($existed) = 0;                # did the mailbox exist already ?
  953. X    $existed = 1 if -f "$mbox";
  954. X    if (open(MBOX, ">>$mbox")) {
  955. X        (print MBOX $Header{'All'}) && ($ok = 1);
  956. X        print MBOX "\n";                # allow parsing by other mail tools
  957. X        close MBOX;
  958. X        if ($ok) {
  959. X            do add_log("DUMPED in $mbox") if $loglvl > 5;
  960. X            return 1;
  961. X        } else {
  962. X            if ($existed) {
  963. X                do add_log("WARNING imcomplete mail appended to $mbox")
  964. X                    if $loglvl > 5;
  965. X            } else {
  966. X                unlink "$mbox";            # remove incomplete file
  967. X            }
  968. X        }
  969. X    }
  970. X    0;
  971. X}
  972. X
  973. X# Resynchronizes the waiting file if necessary (i.e if it exists and %waiting
  974. X# is not an empty array).
  975. Xsub resync {
  976. X    local(@key) = keys %waiting;    # Keys of H table are file names
  977. X    local($ok) = 1;                    # Assume resync is ok
  978. X    local($printed) = 0;            # Nothing printed yet
  979. X    return if $#key < 0 || "$cf'queue" eq '' || ! -f "$cf'queue/$agent_wait";
  980. X    do add_log("resynchronizing the waiting file") if $loglvl > 11;
  981. X    if (open(WAITING, ">$cf'queue/$agent_wait~")) {
  982. X        foreach (@key) {
  983. X            if ($waiting{$_}) {
  984. X                print WAITING "$_\n" || ($ok = 0);
  985. X                $printed = 1;
  986. X            }
  987. X        }
  988. X        close WAITING;
  989. X        if ($printed) {
  990. X            if (!$ok) {
  991. X                do add_log("ERROR could not update waiting file") if $loglvl;
  992. X                unlink "$cf'queue/$agent_wait~";
  993. X            } elsif (rename("$cf'queue/$agent_wait~","$cf'queue/$agent_wait")) {
  994. X                do add_log("waiting file has been updated") if $loglvl > 18;
  995. X            } else {
  996. X                do add_log("ERROR cannot rename waiting file") if $loglvl > 0;
  997. X            }
  998. X        } else {
  999. X            unlink "$cf'queue/$agent_wait";
  1000. X            unlink "$cf'queue/$agent_wait~";
  1001. X            do add_log ("removed waiting file") if ($loglvl > 18);
  1002. X        }
  1003. X    } else {
  1004. X        do add_log("ERROR unable to write new waiting file") if $loglvl;
  1005. X    }
  1006. X}
  1007. X
  1008. END_OF_FILE
  1009.   if test 4856 -ne `wc -c <'agent/pl/emergency.pl'`; then
  1010.     echo shar: \"'agent/pl/emergency.pl'\" unpacked with wrong size!
  1011.   fi
  1012.   # end of 'agent/pl/emergency.pl'
  1013. fi
  1014. if test -f 'agent/pl/listqueue.pl' -a "${1}" != "-c" ; then 
  1015.   echo shar: Will not clobber existing file \"'agent/pl/listqueue.pl'\"
  1016. else
  1017.   echo shar: Extracting \"'agent/pl/listqueue.pl'\" \(4994 characters\)
  1018.   sed "s/^X//" >'agent/pl/listqueue.pl' <<'END_OF_FILE'
  1019. X;# $Id: listqueue.pl,v 2.9.1.1 92/08/26 13:15:36 ram Exp $
  1020. X;#
  1021. X;#  Copyright (c) 1992, Raphael Manfredi
  1022. X;#
  1023. X;#  You may redistribute only under the terms of the GNU General Public
  1024. X;#  Licence as specified in the README file that comes with dist.
  1025. X;#
  1026. X;# $Log:    listqueue.pl,v $
  1027. X;# Revision 2.9.1.1  92/08/26  13:15:36  ram
  1028. X;# patch8: now parses only the header of each mail message
  1029. X;# 
  1030. X;# Revision 2.9  92/07/14  16:50:12  ram
  1031. X;# 3.0 beta baseline.
  1032. X;# 
  1033. X;# 
  1034. X# List the current mails held in the queue, if any at all.
  1035. X# See also the pqueue subroutine for other comments about the queue.
  1036. Xsub list_queue {
  1037. X    local(@files) = <$cf'queue/fm* $cf'queue/qm*>;
  1038. X    if (-f "$cf'queue/$agent_wait") {
  1039. X        if (open(WAITING, "$cf'queue/$agent_wait")) {
  1040. X            while (<WAITING>) {
  1041. X                chop;
  1042. X                push(@files, $_);
  1043. X            }
  1044. X            close WAITING;
  1045. X        } else {
  1046. X            &add_log("ERROR cannot open $cf'queue/$agent_wait: $!") if $loglvl;
  1047. X        }
  1048. X    }
  1049. X    # The @files array now contains the path name of all the queued mails
  1050. X    # (at least those known to the mailagent).
  1051. X    if (@files == 0) {
  1052. X        print "Mailagent queue is empty.\n";
  1053. X        return;
  1054. X    }
  1055. X    format STDOUT_TOP =
  1056. XFilename      Size Queue time  Status    Sender / Recipient list
  1057. X--------- -------- ----------- --------- --------------------------------------
  1058. X.
  1059. X    local($file);                # Base name of file (eventually stripped)
  1060. X    local($directory);            # Directory where queued mail is stored
  1061. X    local($queued);                # Queuing date
  1062. X    local($status);                # Status of mail
  1063. X    local($sender);                # Sender of mail
  1064. X    local($star);                # The '*' identifies out of queue mails
  1065. X    local($recipient);            # Recipient of mail
  1066. X    local($buffer);                # Temporary buffer to build recipient list
  1067. X    local($address);            # E-mail address candidate for recipient list
  1068. X    local(%seen);                # Records addresses already seen
  1069. X    $: = " ,";                    # Break recipients on white space or colon
  1070. X    format STDOUT =
  1071. X@<<<<<<<< @>>>>>>>@@<<<<<<<<<< @<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  1072. X$file     $size $star $queued  $status   $sender
  1073. X                                         ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  1074. X                                         $recipient
  1075. X~                                        ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  1076. X                                         $recipient
  1077. X~                                        ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  1078. X                                         $recipient
  1079. X~                                        ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  1080. X                                         $recipient
  1081. X~                                        ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  1082. X                                         $recipient
  1083. X~                                        ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<...
  1084. X                                         $recipient
  1085. X.
  1086. X    local($n) = $#files + 1;
  1087. X    local($s) = $n > 1 ? 's' : '';
  1088. X    print STDOUT "                   Mailagent Queue ($n request$s)\n";
  1089. X    foreach (@files) {
  1090. X        ($directory, $file) = m|^(.*)/(.*)|;
  1091. X        &parse_mail($_, 'head_only');
  1092. X        next unless defined $Header{'All'};
  1093. X        # Remove comments from all the addresses. The From field is used to
  1094. X        # identify the (possibly forged) sender while the To and Cc fields
  1095. X        # are concatenated to list the recipients;
  1096. X        $sender = (&parse_address($Header{'From'}))[0];
  1097. X        $buffer = $Header{'To'};
  1098. X        $buffer .= ',' . $Header{'Cc'} if $Header{'Cc'};
  1099. X        $recipient = '';
  1100. X        undef %seen;
  1101. X        while ($buffer =~ s/^(.*),(.*)/$1/) {
  1102. X            $address = (&parse_address($2))[0];
  1103. X            unless ($seen{$address}++) {
  1104. X                $recipient .= ', ' if $recipient;
  1105. X                $recipient .= $address;
  1106. X            }
  1107. X        }
  1108. X        $address = (&parse_address($buffer))[0];
  1109. X        unless ($seen{$address}++) {
  1110. X            $recipient .= ', ' if $recipient;
  1111. X            $recipient .= $address;
  1112. X        }
  1113. X        unless (-f $_) {
  1114. X            &add_log("WARNING unable to stat $_");
  1115. X            next;
  1116. X        }
  1117. X        ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
  1118. X            $atime,$mtime,$ctime,$blksize,$blocks) = stat(_);
  1119. X        $status = '';
  1120. X        # If file has 'mbox.' as part of its name, then it is an emergency
  1121. X        # saving done by the mailagent. If it starts with 'logname', then it
  1122. X        # is an emergency saving done by the filter.
  1123. X        $file =~ s/^mbox\.// && ($status = 'Backup');
  1124. X        $file =~ s/^$cf'user\.// && ($status = 'Backup');
  1125. X        if ($file =~ /^qm/ && (time - $mtime) < 1800) {
  1126. X            # Queue mails starting with 'qm' have been queued by the filter
  1127. X            # program. To avoid race conditions, those mails are skipped for
  1128. X            # half an hour (cf to pqueue subroutine).
  1129. X            $status = 'Skipped' unless $status;        # Filter queued mail
  1130. X        } else {
  1131. X            # Processing of mail allowed (mailagent -q would flush it)
  1132. X            $status = 'Deferred' unless $status;
  1133. X        }
  1134. X        ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
  1135. X            localtime($mtime);
  1136. X        $queued = sprintf("%.2d/%.2d-%.2d:%.2d", ++$mon,$mday,$hour,$min);
  1137. X        $queued = 'Now' if (time - $mtime) < 60;
  1138. X        $star = '';
  1139. X        $star = '*' if $directory ne $cf'queue;    # Spot out-of-queue mails
  1140. X        if ((time - $mtime) > 86400) {            # Also spot old mails
  1141. X            $star = '#';
  1142. X            $star = '@' if $directory ne $cf'queue;
  1143. X        }
  1144. X        write(STDOUT);
  1145. X    }
  1146. X}
  1147. X
  1148. END_OF_FILE
  1149.   if test 4994 -ne `wc -c <'agent/pl/listqueue.pl'`; then
  1150.     echo shar: \"'agent/pl/listqueue.pl'\" unpacked with wrong size!
  1151.   fi
  1152.   # end of 'agent/pl/listqueue.pl'
  1153. fi
  1154. if test -f 'agent/pl/macros.pl' -a "${1}" != "-c" ; then 
  1155.   echo shar: Will not clobber existing file \"'agent/pl/macros.pl'\"
  1156. else
  1157.   echo shar: Extracting \"'agent/pl/macros.pl'\" \(4966 characters\)
  1158.   sed "s/^X//" >'agent/pl/macros.pl' <<'END_OF_FILE'
  1159. X;# $Id: macros.pl,v 2.9.1.2 92/08/26 13:16:14 ram Exp $
  1160. X;#
  1161. X;#  Copyright (c) 1992, Raphael Manfredi
  1162. X;#
  1163. X;#  You may redistribute only under the terms of the GNU General Public
  1164. X;#  Licence as specified in the README file that comes with dist.
  1165. X;#
  1166. X;# $Log:    macros.pl,v $
  1167. X;# Revision 2.9.1.2  92/08/26  13:16:14  ram
  1168. X;# patch8: added support for external variables (persistent)
  1169. X;# 
  1170. X;# Revision 2.9.1.1  92/07/25  12:40:37  ram
  1171. X;# patch1: now discards comments in Reply-To field (macro %r)
  1172. X;# 
  1173. X;# Revision 2.9  92/07/14  16:50:16  ram
  1174. X;# 3.0 beta baseline.
  1175. X;# 
  1176. X;# 
  1177. X# Macros:
  1178. X# %%     A real percent sign
  1179. X# %D     Day of the week (0-6)
  1180. X# %H     Host name (name of the machine on which the mailagent runs)
  1181. X# %L     Length of the message in bytes (without header)
  1182. X# %N     Full name of sender (login name if none)
  1183. X# %R     Subject of orginal message with leading Re: suppressed
  1184. X# %S     Re: subject of original message
  1185. X# %T     Time of last modification on mailed file (value taken from $macro_T)
  1186. X# %U     Full name of the user
  1187. X# %_     A white space
  1188. X# %#reg  Value of user-defined variable 'reg'
  1189. X# %&     List of selectors which incurred match (among regular-expression ones) 
  1190. X# %~     A null character
  1191. X# %1     Value of the corresponding backreference (limited to 99 per rule)
  1192. X# %d     Day of the month (01-31)
  1193. X# %f     Contents of the "From:" line, something like %N <%r> or %r (%N)
  1194. X# %h     Hour of the day (00-23)
  1195. X# %i     Message ID if available
  1196. X# %l     Number of lines in the message
  1197. X# %m     Month of the year (01-12)
  1198. X# %n     Lower-case login name of sender
  1199. X# %o     Organization (where mailagent runs)
  1200. X# %r     Return address of message
  1201. X# %s     Subject of original message
  1202. X# %t     Current hour and minute (in HH:MM format)
  1203. X# %u     Login name of the user
  1204. X# %y     Year (last two digits)
  1205. X# %[To]  Value of the field in header (here To:)
  1206. X
  1207. X# Macros substitutions (in-place)
  1208. Xsub macros_subst {
  1209. X    local(*str) = shift(@_);            # The string
  1210. X    local($_) = $str;                    # Work on a copy
  1211. X    return unless /%/;                    # Return immediately if no macros
  1212. X
  1213. X    local($sender);                            # The from field
  1214. X    local(@from);                            # The rfc-822 parsed from line
  1215. X    $sender = $Header{'From'};                # Header-derived From address
  1216. X    @from = &parse_address($sender);        # Get (address, comment)
  1217. X    local($login) = &login_name($from[0]);    # Keep only login name
  1218. X    local($fullname) = $from[1];            # The comment part of address
  1219. X    $fullname = $login unless $fullname;    # Use login name if no comment part
  1220. X    local($reply_to) = $Header{'Reply-To'}; # Return path derived
  1221. X    local($subject) = $Header{'Subject'};    # Original subject header
  1222. X    $subject =~ s/^\s*Re:\s*(.*)/$1/;        # Strip off leading Re:
  1223. X    $subject = "<empty subject>" unless $subject;
  1224. X    $reply_to = (&parse_address($reply_to))[0];    # Keep only e-mail address
  1225. X
  1226. X    # Time computations
  1227. X    local($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
  1228. X            localtime(time);
  1229. X    $mon = sprintf("%.2d", $mon + 1);
  1230. X    $mday = sprintf("%.2d", $mday);
  1231. X    local($timenow) = sprintf("%.2d:%.2d", $hour, $min);
  1232. X    $hour = sprintf("%.2d", $hour);
  1233. X
  1234. X    # The following dummy block is here only to force perl interpreting
  1235. X    # the $ variables in the substitutions correctly...
  1236. X    if (0) {
  1237. X        $Header{'a'} = 'a';
  1238. X        $Variable{'a'} = 'a';
  1239. X        $Backref[0] = 0;
  1240. X    }
  1241. X
  1242. X    s/%%/##pr##/g;                        # Protect double percent signs
  1243. X    s/%/#%%!/g;                            # Make sure substitutions do not add %
  1244. X    s/#%%!d/$mday/g;                    # Day of the month (01-31)
  1245. X    s/#%%!D/$wday/g;                    # Day of the week (0-6)
  1246. X    s/#%%!f/$Header{'From'}/g;            # The "From:" line
  1247. X    s/#%%!h/$hour/g;                    # Hour of the day (00-23)
  1248. X    s/#%%!i/$Header{'Message-Id'}/g;    # Message-Id (null string if none)
  1249. X    s/#%%!l/$Header{'Lines'}/g;            # Number if lines in message
  1250. X    s/#%%!L/$Header{'Length'}/g;        # Length of message, in bytes
  1251. X    s/#%%!m/$mon/g;                        # Month of the year
  1252. X    s/#%%!n/$login/g;                    # Lower-cased login name of sender
  1253. X    s/#%%!N/$fullname/g;                # Full name of sender (login if none)
  1254. X    s/#%%!o/$orgname/g;                    # Organization name
  1255. X    s/#%%!r/$reply_to/g;                # Return path of message
  1256. X    s/#%%!R/$subject/g;                    # Subject with leading Re: suppressed
  1257. X    s/#%%!s/$Header{'Subject'}/g;        # Subject of message
  1258. X    s/#%%!S/Re: $Header{'Subject'}/g;    # Re: subject of original message
  1259. X    s/#%%!t/$timenow/g;                    # Current time HH:MM
  1260. X    s/#%%!T/$macro_T/g;                    # Time of last modification on file
  1261. X    s/#%%!u/$cf'user/go;                # User login name (does not change)
  1262. X    s/#%%!U/$cf'name/go;                # User's name (does not change)
  1263. X    s/#%%!y/$year/g;                    # Year (last two digits)
  1264. X    s/#%%!_/ /g;                        # A white space
  1265. X    s/#%%!~//g;                            # A null character
  1266. X    s/#%%!&/$macro_ampersand/g;            # List of matched generic selectors
  1267. X    s/#%%!(\d\d?)/$Backref[$1 - 1]/g;    # A pattern matching backreference
  1268. X    s/#%%!#:(\w+)/&extern'val($1)/eg;    # A persistent user-defined variable
  1269. X    s/#%%!#(\w+)/$Variable{$1}/g;        # A user-defined variable
  1270. X    s/#%%!\[([\w-]+)\]/$Header{$1}/g;    # The %[Field] macro
  1271. X    s/#%%!/%/g;                            # Any remaining percent is kept
  1272. X    s/##pr##/%/g;                        # A double percent expands to %
  1273. X    $str = $_;                            # Update string in-place
  1274. X}
  1275. X
  1276. END_OF_FILE
  1277.   if test 4966 -ne `wc -c <'agent/pl/macros.pl'`; then
  1278.     echo shar: \"'agent/pl/macros.pl'\" unpacked with wrong size!
  1279.   fi
  1280.   # end of 'agent/pl/macros.pl'
  1281. fi
  1282. if test -f 'agent/pl/read_conf.pl' -a "${1}" != "-c" ; then 
  1283.   echo shar: Will not clobber existing file \"'agent/pl/read_conf.pl'\"
  1284. else
  1285.   echo shar: Extracting \"'agent/pl/read_conf.pl'\" \(4036 characters\)
  1286.   sed "s/^X//" >'agent/pl/read_conf.pl' <<'END_OF_FILE'
  1287. X;# $Id: read_conf.pl,v 2.9.1.2 92/08/12 21:33:29 ram Exp $
  1288. X;#
  1289. X;#  Copyright (c) 1991, 1992, Raphael Manfredi
  1290. X;#
  1291. X;#  You may redistribute only under the terms of the GNU General Public
  1292. X;#  Licence as specified in the README file that comes with dist.
  1293. X;#
  1294. X;# $Log:    read_conf.pl,v $
  1295. X;# Revision 2.9.1.2  92/08/12  21:33:29  ram
  1296. X;# patch6: perform security checks after config file parsing
  1297. X;# 
  1298. X;# Revision 2.9.1.1  92/07/25  12:42:08  ram
  1299. X;# patch1: configuration errors now reported on stderr
  1300. X;# patch1: first syntax error also logged for further diagnostic
  1301. X;# 
  1302. X;# Revision 2.9  92/07/14  16:50:40  ram
  1303. X;# 3.0 beta baseline.
  1304. X;# 
  1305. X;#
  1306. Xpackage cf;
  1307. X
  1308. X# This package is responsible for keeping track of the configuration variables.
  1309. X
  1310. X# Read configuration file (usually in ~/.mailagent)
  1311. Xsub main'read_config {
  1312. X    local($file) = @_;                # where config file is located
  1313. X    local($_);
  1314. X    $file = '~/.mailagent' unless $file;
  1315. X    local($myhome) = $ENV{'HOME'};    # must be correctly set by filter
  1316. X    $file =~ s/~/$myhome/;            # ~ substitution
  1317. X    local($main'config) = $file;    # Save it: could be modified by config
  1318. X    open(CONFIG, "$file") ||
  1319. X        &'fatal("can't open config file $file");
  1320. X    local($config) = ' ' x 2000;    # pre-extend to avoid realloc()
  1321. X    $config = '';
  1322. X    while (<CONFIG>) {
  1323. X        next if /^[ \t]*#/;            # skip comments
  1324. X        next if /^[ \t]*\n/;        # skip empy lines
  1325. X        $config .= $_;
  1326. X    }
  1327. X    &parse($config) || &'fatal('bad configuration');
  1328. X    close CONFIG;
  1329. X
  1330. X    # Security checks, pending of those performed by the C filter. They are
  1331. X    # somewhat necessary, even though the mailagent does not run setuid
  1332. X    # (because anybody may activate the mailagent for any user by sending him
  1333. X    # a mail, and world writable configuration files makes the task too easy
  1334. X    # for a potential hacker). The tests are performed once the configuration
  1335. X    # file has been parsed, so logging of fatal errors may occur.
  1336. X
  1337. X    local($ST_MODE) =  2 + $[;        # Field st_mode from inode structure
  1338. X    local($S_IWOTH) = 02;            # Writable by world (no .ph files here)
  1339. X
  1340. X    -O "$'config" || &'fatal("you do not own config file $'config");
  1341. X    local($st_mode) = (stat($'config))[$ST_MODE];
  1342. X    ($st_mode & $S_IWOTH) && &'fatal("config file $'config is world writable!");
  1343. X
  1344. X    return unless -f "$rules";        # No rule file
  1345. X
  1346. X    -O "$rules" || &'fatal("you do not own rule file $rules");
  1347. X    $st_mode = (stat($rules))[$ST_MODE];
  1348. X    ($st_mode & $S_IWOTH) && &'fatal("rule file $rules is world writable!");
  1349. X}
  1350. X
  1351. X# Parse config file held in variable and return 1 if ok, 0 for errors
  1352. Xsub parse {
  1353. X    local($config) = @_;
  1354. X    local($eval) = ' ' x 1000;        # Pre-extend
  1355. X    local($myhome) = $ENV{'HOME'};    # must be correctly set by filter
  1356. X    local($var, $value);
  1357. X    local($_);
  1358. X    $eval = '';
  1359. X    foreach (split(/\n/, $config)) {
  1360. X        if (/^[ \t]*([^ \t\n:\/]*)[ \t]*:[ \t]*([^#\n]*)/) {
  1361. X            $var = $1;
  1362. X            $value = $2;
  1363. X            $value =~ s/\s*$//;                        # remove trailing spaces
  1364. X            $eval .= "\$$var = \"$value\";\n";
  1365. X            $eval .= "\$$var =~ s|~|$myhome|g;\n";    # ~ substitution
  1366. X        }
  1367. X    }
  1368. X    eval $eval;            # evaluate configuration parameters within package
  1369. X
  1370. X    if ($@ ne '') {                # Parsing error detected
  1371. X        local($error) = $@;        # Logged error
  1372. X        local($*) = 1;
  1373. X        $error = (split(/\n/, $error))[0];        # Keep only first line
  1374. X        # Dump error message on stderr, as well as faulty configuration file.
  1375. X        # The original is restored out of the perl form to avoid surprise.
  1376. X        $eval =~ s/^\$.* =~ s\|~\|.*\n//g;        # Remove added ~ substitutions
  1377. X        $eval =~ s/^\$//g;                        # Remove leading '$'
  1378. X        $eval =~ s/ = "(.*)";/: $1/g;            # Keep only variable value
  1379. X        chop($eval);
  1380. X        print STDERR <<EOM;
  1381. X**** Syntax error in configuration:
  1382. X$error
  1383. X
  1384. X---- Begin of Faulty Configuration
  1385. X$eval
  1386. X---- End of Faulty Configuration
  1387. X
  1388. XEOM
  1389. X        &'add_log("syntax error in configuration: $error") if $'loglvl > 1;
  1390. X        return 0;
  1391. X    }
  1392. X
  1393. X    # Define the mailagent parameters from those in config file
  1394. X    $logfile = $logdir . "/$log";
  1395. X    $seqfile = $spool . "/$seq";
  1396. X    $hashdir = $spool . "/$hash";
  1397. X    $main'loglvl = int($level);        # This one is visible in the main package
  1398. X    $main'track_all = 1 if $track =~ /on/i;        # Option -t set by config
  1399. X
  1400. X    1;        # Ok
  1401. X}
  1402. X
  1403. Xpackage main;
  1404. X
  1405. END_OF_FILE
  1406.   if test 4036 -ne `wc -c <'agent/pl/read_conf.pl'`; then
  1407.     echo shar: \"'agent/pl/read_conf.pl'\" unpacked with wrong size!
  1408.   fi
  1409.   # end of 'agent/pl/read_conf.pl'
  1410. fi
  1411. if test -f 'agent/test/TEST' -a "${1}" != "-c" ; then 
  1412.   echo shar: Will not clobber existing file \"'agent/test/TEST'\"
  1413. else
  1414.   echo shar: Extracting \"'agent/test/TEST'\" \(4140 characters\)
  1415.   sed "s/^X//" >'agent/test/TEST' <<'END_OF_FILE'
  1416. X# feed this into perl
  1417. X    eval 'exec perl -S $0 "$@"'
  1418. X        if $running_under_some_shell;
  1419. X
  1420. Xchop($pwd = `pwd`);
  1421. X$ENV{'HOME'} = "$pwd/out";
  1422. Xchop($host = `(hostname 2>/dev/null || uname -n) 2>/dev/null`);
  1423. X$host =~ s/^([^.]*)\..*/$1/;    # Trim domain name
  1424. X$ENV{'HOST'} = $host;
  1425. X$ENV{'USER'} = 'nobody';    # In case we get mails back from RUN and friends
  1426. X$ENV{'PWD'} = $pwd;
  1427. X$ENV{'LEVEL'} = 0;            # Default loglvl for filter and cmd tests
  1428. X
  1429. X@tests = ('basic', 'option', 'filter', 'cmd');
  1430. X$failed = 0;
  1431. X$how_many = 0;
  1432. X
  1433. Xrequire 'getopt.pl';
  1434. X&Getopt;
  1435. X
  1436. X$mailagent = 'mailagent';            # Default program (dataloaded version)
  1437. X$mailagent = 'magent' if $opt_n;    # Use non-dataloaded version
  1438. X$ENV{'MAILAGENT'} = $mailagent;
  1439. X$ENV{'PATH'} = "$pwd/..:" . $ENV{'PATH'};
  1440. X
  1441. X-f "../$mailagent" && -x _ || die "No $mailagent.\n";
  1442. X-f "../mailhook" && -x _ || die "No mailhook.\n";
  1443. X-f '../filter/filter' && -x _ || die "No filter.\n";
  1444. X
  1445. X&load_ok;        # Don't rerun successful tests if up to date
  1446. X
  1447. X# A level file indicates default loglvl
  1448. Xif (-f 'level') {
  1449. X    chop($level = `cat level`);
  1450. X    $ENV{'LEVEL'} = int($level);
  1451. X}
  1452. X
  1453. Xunless (-f 'OK') {
  1454. X    %Ok = ();
  1455. X    `rm -rf out` if -d 'out';
  1456. X}
  1457. X
  1458. X`mkdir out` unless -d 'out';
  1459. Xselect(STDOUT);
  1460. X$| = 1;
  1461. Xopen(OK, ">>OK");
  1462. Xselect(OK);
  1463. X$| = 1;        # We may safely interrupt
  1464. Xselect(STDOUT);
  1465. X
  1466. Xumask 022;        # Ensure none of the files are world writable
  1467. X
  1468. Xforeach $dir (@tests) {
  1469. X    next unless -d $dir;
  1470. X    &run($dir);
  1471. X}
  1472. X
  1473. X# Summarize what happened
  1474. X
  1475. Xclose OK;
  1476. X
  1477. Xif ($failed == 0) {
  1478. X    print "All tests successful.\n";
  1479. X} else {
  1480. X    print "Failed $how_many test", $how_many == 1 ? '' : 's';
  1481. X    print " from $failed file", $failed == 1 ? '' : 's', ".\n";
  1482. X}
  1483. X
  1484. X&clean_up;
  1485. Xexit 0;        # End of tests
  1486. X
  1487. X#
  1488. X# Subroutines
  1489. X#
  1490. X
  1491. Xsub clean_up {
  1492. X    return if $failed || $opt_i;    # -i asks for incrementality
  1493. X    unlink 'OK';
  1494. X    `rm -rf out` if -d 'out';
  1495. X}
  1496. X
  1497. Xsub print {
  1498. X    local($dir, $file) = @_;
  1499. X    $file =~ s/\.t$//;
  1500. X    local($len) = 1 + length($dir) + length($file);
  1501. X    print "$dir/$file", '.' x (17 - $len);
  1502. X}
  1503. X
  1504. Xsub num { $a <=> $b; }
  1505. X
  1506. Xsub result {
  1507. X    local($test, $output) = @_;
  1508. X    local($now) = time;
  1509. X    local(@res) = split(/\n/, $output);    # Failed test numbers
  1510. X    if ($res[0] eq '') {
  1511. X        print "FAILED (no test run)\n";
  1512. X        ++$failed;
  1513. X    } elsif ($res[$#res] == 0 && $#res > 0 && $res[$#res -1] == $#res) {
  1514. X        print "FAILED (all tests)\n";
  1515. X        ++$failed;
  1516. X        $how_many += $#res;
  1517. X    } elsif ($res[0] == 0) {
  1518. X        print "ok\n";
  1519. X        print OK "$test $now\n";
  1520. X    } elsif ($res[0] == -1) {
  1521. X        print "untested\n";
  1522. X    } else {
  1523. X        # Program outputs the number of each test failed, and last must be 0
  1524. X        local($last) = pop(@res);
  1525. X        push(@res, $last) unless $last == 0;
  1526. X        local($n) = @res + 0;
  1527. X        local($s) = $n == 1 ? '' : 's';
  1528. X        print "FAILED ($n test$s:";
  1529. X        @res = sort num @res;
  1530. X        print ' ', join(',', @res);
  1531. X        print " and aborted" unless $last == 0;
  1532. X        print ")\n";
  1533. X        ++$failed;
  1534. X        $how_many += $n;
  1535. X    }
  1536. X    if ($failed && $opt_s) {    # Stop at first error if -s
  1537. X        print "Aborted tests.\n";
  1538. X        exit 0;
  1539. X    }
  1540. X}
  1541. X
  1542. Xsub run {
  1543. X    local($dir) = @_;
  1544. X    chdir $dir || die "Cannot chdir to $dir: $!\n";
  1545. X    local(@files) = <*.t>;
  1546. X    local($test);
  1547. X    local($output);
  1548. X    foreach $file (@files) {
  1549. X        &print($dir, $file);
  1550. X        $test = "$dir/$file";
  1551. X        if ($Ok{$test} >= ((stat($file))[9])) {    # Check time stamp
  1552. X            print "done\n";
  1553. X            next;
  1554. X        }
  1555. X        $output = `perl $file`;
  1556. X        &result($test, $output);
  1557. X        &basic_failed if $dir eq 'basic' && $failed;
  1558. X    }
  1559. X    chdir '..' || die "Cannot chdir back to ..: $!\n";
  1560. X}
  1561. X
  1562. Xsub basic_failed {
  1563. X    print "Failed a basic test, cannot continue.\n";
  1564. X    unlink 'OK';
  1565. X    exit 0;
  1566. X}
  1567. X
  1568. Xsub load_ok {
  1569. X    return unless -f 'OK';
  1570. X
  1571. X    # Make sure the OK file is up to date, unless -o (outdated)
  1572. X    unless ($opt_o) {
  1573. X        local($ok_mtime) = (stat('OK'))[9];
  1574. X        local($ma_mtime) = (stat("../$mailagent"))[9];
  1575. X        local($fi_mtime) = (stat('../filter/filter'))[9];
  1576. X        local($restart) = 0;
  1577. X        if ($ma_mtime > $ok_mtime) {
  1578. X            warn "Mailagent has changed, restarting tests...\n";
  1579. X            ++$restart;
  1580. X        } elsif ($fi_mtime > $ok_mtime) {
  1581. X            warn "Filter has changed, restarting tests...\n";
  1582. X            ++$restart;
  1583. X        }
  1584. X        unlink 'OK' if $restart;
  1585. X    }
  1586. X
  1587. X    return unless -f 'OK';
  1588. X    local($file, $when);
  1589. X    open(OK, 'OK') || return;
  1590. X    while (<OK>) {
  1591. X        chop;
  1592. X        ($file, $when) = /^(\S+)\s+(\d+)/;
  1593. X        $Ok{$file} = $when if $when;
  1594. X    }
  1595. X    close OK;
  1596. X
  1597. X}
  1598. X
  1599. END_OF_FILE
  1600.   if test 4140 -ne `wc -c <'agent/test/TEST'`; then
  1601.     echo shar: \"'agent/test/TEST'\" unpacked with wrong size!
  1602.   fi
  1603.   chmod +x 'agent/test/TEST'
  1604.   # end of 'agent/test/TEST'
  1605. fi
  1606. if test -f 'agent/test/actions' -a "${1}" != "-c" ; then 
  1607.   echo shar: Will not clobber existing file \"'agent/test/actions'\"
  1608. else
  1609.   echo shar: Extracting \"'agent/test/actions'\" \(4385 characters\)
  1610.   sed "s/^X//" >'agent/test/actions' <<'END_OF_FILE'
  1611. Xmaildir = ~;
  1612. X
  1613. XX-Tag: /abort/
  1614. X{
  1615. X    ABORT -f;
  1616. X    SAVE always;
  1617. X    ABORT;
  1618. X    SAVE %u.1;
  1619. X}
  1620. X
  1621. XX-Tag: /annotate/
  1622. X{
  1623. X    ANNOTATE X-Anno-1: first;
  1624. X    ANNOTATE X-Anno-2 second;
  1625. X    ANNOTATE X-Anno-3;
  1626. X    ANNOTATE -d X-Anno-Error;
  1627. X    ANNOTATE -d X-Anno-4 fourth;
  1628. X}
  1629. X
  1630. XX-Tag: /assign #1/,
  1631. XTo: /^(\w+)@/
  1632. X{
  1633. X    ASSIGN ram %1;
  1634. X    ASSIGN other try;
  1635. X    ASSIGN final '%#other.2';
  1636. X    ASSIGN :ram 1 + 2;
  1637. X    RUN /bin/echo '%#ram,%#other,%#final' > output';
  1638. X}
  1639. X
  1640. XX-Tag: /assign #2/
  1641. X{
  1642. X    ASSIGN :ram %#:ram + 4;
  1643. X    ASSIGN other '1+2';
  1644. X    ASSIGN final %#other + 4;
  1645. X    RUN /bin/echo '%#:ram,%#other,%#final' > output';
  1646. X}
  1647. X
  1648. XX-Tag: /back/
  1649. X{
  1650. X    BACK RUN ~/pgm;
  1651. X}
  1652. X
  1653. XX-Tag: /begin/
  1654. X{
  1655. X    BEGIN ONE;
  1656. X    BEGIN TWO;
  1657. X    REJECT;
  1658. X}
  1659. X
  1660. X<ONE> { SAVE one };
  1661. X<ONE,TWO,THREE> { SAVE two; BEGIN THREE; REJECT };
  1662. X<THREE> { SAVE three };
  1663. X
  1664. XX-Tag: /delete/                { DELETE };
  1665. X
  1666. XX-Tag: /feed/
  1667. X{
  1668. X    FEED grep -v To:;
  1669. X    SAVE ok;
  1670. X    REJECT;
  1671. X}
  1672. X
  1673. XX-Tag: /feed/, To: ram        { SAVE no_resync };
  1674. X
  1675. XX-Tag: /give/                { GIVE wc > output };
  1676. X
  1677. XX-Tag: /keep/
  1678. X{
  1679. X    KEEP From: To Subject X-None X-Long-Line;
  1680. X    KEEP To Subject X-Long-Line From X-None;
  1681. X    KEEP X-Long-Line: X-None: To: Subject: From:;
  1682. X    SAVE ok;
  1683. X    REJECT;
  1684. X}
  1685. XX-Tag: /keep/, To: ram        { SAVE no_resync };
  1686. X
  1687. XX-Tag: /nop/
  1688. X{
  1689. X    NOP;
  1690. X    DELETE;
  1691. X}
  1692. X
  1693. XX-Tag: /once/
  1694. X{
  1695. X    ONCE (ram,tag,1w) SAVE one;
  1696. X    ONCE (ram,tag,1w) SAVE two;
  1697. X    ONCE (mars,tag,1w) SAVE three;
  1698. X    ONCE (other,tag,0m) SAVE four;
  1699. X}
  1700. X
  1701. XX-Tag: /pass/
  1702. X{
  1703. X    PASS grep -v and;
  1704. X    SAVE output;
  1705. X}
  1706. X
  1707. XX-Tag: /perl/    { REJECT PERL };
  1708. X<PERL>            { PERL perl.1; SAVE never };
  1709. X<PERL>            { PERL perl.2 'arg 1' "arg 2"; SAVE never };
  1710. X<PERL>            { PERL perl.1; SAVE never };
  1711. X<PERL>            { PERL no_such_file; ABORT -f; SAVE never };
  1712. X
  1713. XX-Tag: /pipe/                { PIPE wc > output };
  1714. X
  1715. XX-Tag: /purify/
  1716. X{
  1717. X    PURIFY grep -v Subject:;
  1718. X    SAVE output;
  1719. X}
  1720. X
  1721. XX-Tag: /queue/    { QUEUE; QUEUE; QUEUE; QUEUE };
  1722. X
  1723. XX-Tag: /record #1/                { RECORD; SAVE %u.1 };
  1724. XX-Tag: /record #1/                { SAVE %u.1 };
  1725. X<_SEEN_> X-Tag: /record #1/        { SAVE %u.2 };
  1726. X<RECORD> X-Tag: /record #2/        { SAVE %u.3 };
  1727. XX-Tag: /record #2/                { RECORD -r RECORD; SAVE %u.1 };
  1728. XX-Tag: /record #3/                { RECORD -a; SAVE %u.1 };
  1729. XX-Tag: /record #4/                { RECORD -c; REJECT -f RECORD; SAVE %u.1 };
  1730. X<RECORD> X-Tag: /record #4/        { SAVE %u.2 };
  1731. X
  1732. XX-Tag: /reject/            { REJECT REJ; SAVE %u.1 };
  1733. X<REJ> X-Tag: /reject/    { SAVE always; REJECT -t REJ; SAVE never };
  1734. X
  1735. X<INITIAL> X-Tag: /restart/    { RESTART -t RES; SAVE %u.1; REJECT };
  1736. X<RES> X-Tag: /restart/        { RESTART no_such_mode; SAVE never };
  1737. X
  1738. XX-Tag: /resync/,
  1739. XTo: ram
  1740. X{
  1741. X    PURIFY grep -v To:;
  1742. X    RESYNC;
  1743. X    REJECT;
  1744. X}
  1745. X
  1746. XX-Tag: /resync/, To: ram    { SAVE %u.1 };
  1747. XX-Tag: /resync/                { SAVE output };
  1748. X
  1749. XX-Tag: /run/        { RUN /bin/echo Works. > ok; DELETE };
  1750. X
  1751. XX-Tag: /save #1/    { SAVE mbox };
  1752. XX-Tag: /save #2/    { SAVE path/another/third/mbox };
  1753. X
  1754. XX-Tag: /select/
  1755. X{
  1756. X    SELECT (Jan 2 1970 .. Jan 1 2001) SAVE one;
  1757. X    SELECT (last month .. last minute) SAVE two;
  1758. X    SELECT (last minute .. next minute) SAVE three;
  1759. X    SELECT (now - 10 seconds .. now + 5 minutes) SAVE four;
  1760. X    SELECT (Jan 1 2001 .. Jan 2 1970) SAVE five;
  1761. X}
  1762. X
  1763. XX-Tag: /unknown #1/    { unknown_command; DELETE };
  1764. XX-Tag: /unknown #2/    { DELETE; unknown_command };
  1765. X
  1766. XX-Tag: /split #1/    { SPLIT here; SAVE here };
  1767. XX-Tag: /split #2/    { SPLIT -ida here };
  1768. XX-Tag: /split #3/    { SPLIT -iew here };
  1769. XX-Tag: /split #4/    { SPLIT -iew };
  1770. XX-Tag: /split #5/    { SPLIT -iew here };
  1771. XX-Tag: /digest/        { SAVE here };
  1772. X
  1773. XX-Tag: /store #1/    { STORE mbox };
  1774. XX-Tag: /store #2/    { STORE path/another/third/mbox };
  1775. X
  1776. XX-Tag: /strip/
  1777. X{
  1778. X    STRIP X-Long-Line: X-None: Received:;
  1779. X    STRIP Received X-Long-Line;
  1780. X    SAVE ok;
  1781. X    REJECT;
  1782. X}
  1783. XX-Tag: /strip/, To: ram        { SAVE no_resync };
  1784. X
  1785. XX-Tag: /subst/,
  1786. XTo: /(.*)/
  1787. X{
  1788. X    SUBST 1 /com/fr/g;
  1789. X    ASSIGN subject %[Subject];
  1790. X    ASSIGN :persistent '%#subject';
  1791. X    SUBST #subject /^Re:\s+//;
  1792. X    SUBST #:persistent /^Re:\s+//;
  1793. X    RUN /bin/echo '%1,%#subject,%#:persistent' >output;
  1794. X    DELETE;
  1795. X}
  1796. X
  1797. XX-Tag: /tr/,
  1798. XTo: /(.*)/
  1799. X{
  1800. X    TR 1 /a-z/A-Z/;
  1801. X    ASSIGN subject %[Subject];
  1802. X    ASSIGN :persistent '%#subject';
  1803. X    TR #subject /ice/ICE/;
  1804. X    TR #:persistent /ice/ICE/;
  1805. X    RUN /bin/echo '%1,%#subject,%#:persistent' >output;
  1806. X    DELETE;
  1807. X}
  1808. X
  1809. XX-Tag: /unique #1/                { UNIQUE; SAVE %u.1 };
  1810. X<_SEEN_> X-Tag: /unique #1/        { SAVE %u.1 };
  1811. XX-Tag: /unique #1/                { SAVE %u.2 };
  1812. X<UNIQUE> X-Tag: /unique #2/        { SAVE %u.3 };
  1813. XX-Tag: /unique #2/                { UNIQUE -r UNIQUE; SAVE %u.1 };
  1814. XX-Tag: /unique #3/                { UNIQUE -a; SAVE %u.1 };
  1815. XX-Tag: /unique #4/                { UNIQUE -c; REJECT -f UNIQUE; SAVE %u.1 };
  1816. X<UNIQUE> X-Tag: /unique #4/        { SAVE %u.2 };
  1817. X
  1818. XX-Tag: /write #1/    { WRITE mbox };
  1819. XX-Tag: /write #2/    { WRITE path/another/third/mbox };
  1820. X
  1821. END_OF_FILE
  1822.   if test 4385 -ne `wc -c <'agent/test/actions'`; then
  1823.     echo shar: \"'agent/test/actions'\" unpacked with wrong size!
  1824.   fi
  1825.   # end of 'agent/test/actions'
  1826. fi
  1827. echo shar: End of archive 13 \(of 17\).
  1828. cp /dev/null ark13isdone
  1829. MISSING=""
  1830. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ; do
  1831.     if test ! -f ark${I}isdone ; then
  1832.     MISSING="${MISSING} ${I}"
  1833.     fi
  1834. done
  1835. if test "${MISSING}" = "" ; then
  1836.     echo You have unpacked all 17 archives.
  1837.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1838. else
  1839.     echo You still must unpack the following archives:
  1840.     echo "        " ${MISSING}
  1841. fi
  1842. exit 0
  1843. exit 0 # Just in case...
  1844.