home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-11-20 | 54.6 KB | 1,844 lines |
- Newsgroups: comp.sources.misc
- From: ram@eiffel.com (Raphael Manfredi)
- Subject: v33i105: mailagent - Rule Based Mail Filtering, Part13/17
- Message-ID: <1992Nov20.230731.26915@sparky.imd.sterling.com>
- X-Md4-Signature: 2714ad43c3825686c788f39a8ef94eaf
- Date: Fri, 20 Nov 1992 23:07:31 GMT
- Approved: kent@sparky.imd.sterling.com
-
- Submitted-by: ram@eiffel.com (Raphael Manfredi)
- Posting-number: Volume 33, Issue 105
- Archive-name: mailagent/part13
- Environment: Perl, Sendmail, UNIX
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then feed it
- # into a shell via "sh file" or similar. To overwrite existing files,
- # type "sh file -c".
- # Contents: Makefile.SH agent/files/chkagent.sh agent/filter/main.c
- # agent/man/Makefile.SH agent/man/mailhelp.SH agent/pl/emergency.pl
- # agent/pl/listqueue.pl agent/pl/macros.pl agent/pl/read_conf.pl
- # agent/test/TEST agent/test/actions
- # Wrapped by kent@sparky on Wed Nov 18 22:42:29 1992
- PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
- echo If this archive is complete, you will see the following message:
- echo ' "shar: End of archive 13 (of 17)."'
- if test -f 'Makefile.SH' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'Makefile.SH'\"
- else
- echo shar: Extracting \"'Makefile.SH'\" \(4878 characters\)
- sed "s/^X//" >'Makefile.SH' <<'END_OF_FILE'
- X: Makefile.SH generated from Jmake.tmpl and Jmakefile [jmake 2.8 PL13]
- X: $X-Id: Jmake.tmpl,v 2.8.1.2 91/11/18 13:22:54 ram Exp $
- X
- Xcase $CONFIG in
- X'')
- X if test ! -f config.sh; then
- X ln ../config.sh . || \
- X ln ../../config.sh . || \
- X ln ../../../config.sh . || \
- X (echo "Can't find config.sh."; exit 1)
- X fi 2>/dev/null
- X . ./config.sh
- X ;;
- Xesac
- Xcase "$0" in
- X*/*) cd `expr X$0 : 'X\(.*\)/'` ;;
- Xesac
- XCURRENT=.
- XDIR=`echo $CURRENT/ | sed -e 's/\.\///g'`
- Xecho "Extracting ${DIR}Makefile (with variable substitutions)"
- XDATE=`date`
- X$spitshell >Makefile <<!GROK!THIS!
- X########################################################################
- X# Makefile generated from Makefile.SH on $DATE
- X
- XSHELL = /bin/sh
- XJMAKE = jmake
- XTOP = .
- XCURRENT = $CURRENT
- XDIR = $DIR
- X
- X########################################################################
- X# Parameters set by Configure -- edit config.sh if changes are needed
- X
- XCTAGS = ctags
- XMAKE = make
- XMV = $mv
- XRM = $rm -f
- X
- X########################################################################
- X# Automatically generated parameters -- do not edit
- X
- XSUBDIRS = agent
- X
- X!GROK!THIS!
- X$spitshell >>Makefile <<'!NO!SUBS!'
- X
- X########################################################################
- X# Jmake rules for building libraries, programs, scripts, and data files
- X# $X-Id: Jmake.rules,v 2.8.1.4 91/11/18 13:19:07 ram Exp $
- X
- X########################################################################
- X# Start of Jmakefile
- X
- X# $X-Id: Jmakefile,v 2.9 92/07/14 16:46:57 ram Exp $
- X#
- X# Copyright (c) 1991, Raphael Manfredi
- X#
- X# You may redistribute only under the terms of the GNU General Public
- X# Licence as specified in the README file that comes with dist.
- X#
- X# $X-Log: Jmakefile,v $
- X# Revision 2.9 92/07/14 16:46:57 ram
- X# 3.0 beta baseline.
- X#
- X
- Xall::
- X
- Xlocal_clobber::
- X $(RM) install mkdep cppstdin
- X
- Xdepend::
- X @case '${MFLAGS}' in *[ik]*) set +e;; esac; \
- X for i in $(SUBDIRS) ;\
- X do \
- X (cd $$i ; echo "Depending" "in $(DIR)$$i..."; \
- X $(MAKE) $(MFLAGS) depend); \
- X done
- X
- X########################################################################
- X# Common rules for all Makefiles -- do not edit
- X
- Xemptyrule::
- X
- Xclean: sub_clean local_clean
- Xrealclean: sub_realclean local_realclean
- Xclobber: sub_clobber local_clobber
- X
- Xlocal_clean::
- X $(RM) core *~ *.o
- X
- Xlocal_realclean:: local_clean
- X $(RM) -r UU
- X
- Xlocal_clobber:: local_realclean
- X $(RM) config.sh config.h
- X $(RM) Makefile
- X
- XMakefile.SH: Jmakefile
- X -@if test -f $(TOP)/.package; then \
- X if test -f Makefile.SH; then \
- X echo " $(RM) Makefile.SH~; $(MV) Makefile.SH Makefile.SH~"; \
- X $(RM) Makefile.SH~; $(MV) Makefile.SH Makefile.SH~; \
- X fi; \
- X echo " $(JMAKE) -DTOPDIR=$(TOP) -DCURDIR=$(CURRENT)" ; \
- X $(JMAKE) -DTOPDIR=$(TOP) -DCURDIR=$(CURRENT) ; \
- X else touch $@; exit 0; fi
- X
- XMakefile: Makefile.SH
- X /bin/sh Makefile.SH
- X
- Xtags::
- X $(CTAGS) -w *.[ch]
- X $(CTAGS) -xw *.[ch] > tags
- X
- Xlocal_clobber::
- X $(RM) tags
- X
- X########################################################################
- X# Rules for building in sub-directories -- do not edit
- X
- Xsubdirs:
- X @case '${MFLAGS}' in *[ik]*) set +e;; esac; \
- X for i in $(SUBDIRS) ;\
- X do \
- X (cd $$i ; echo $(VERB) "in $(DIR)$$i..."; \
- X $(MAKE) $(MFLAGS) $(FLAGS) $(TARGET)); \
- X done
- X
- Xinstall::
- X @$(MAKE) subdirs TARGET=install VERB="Installing" FLAGS=
- X
- Xdeinstall::
- X @$(MAKE) subdirs TARGET=deinstall VERB="Deinstalling" FLAGS=
- X
- Xinstall.man::
- X @$(MAKE) subdirs TARGET=install.man VERB="Installing man pages" FLAGS=
- X
- Xdeinstall.man::
- X @$(MAKE) subdirs TARGET=deinstall.man VERB="Deinstalling man pages" FLAGS=
- X
- Xsub_clean::
- X @$(MAKE) subdirs TARGET=clean VERB="Cleaning" FLAGS=
- X @echo "Back to $(CURRENT) for "clean...
- X
- Xsub_realclean::
- X @$(MAKE) subdirs TARGET=realclean VERB="Real cleaning" FLAGS=
- X @echo "Back to $(CURRENT) for "realclean...
- X
- Xsub_clobber::
- X @$(MAKE) subdirs TARGET=clobber VERB="Clobbering" FLAGS=
- X @echo "Back to $(CURRENT) for "clobber...
- X
- Xtag::
- X @case '${MFLAGS}' in *[ik]*) set +e;; esac; \
- X for i in ;\
- X do \
- X (cd $$i ; echo "Tagging" "in $(DIR)$$i..."; \
- X $(MAKE) $(MFLAGS) tag); \
- X done
- X
- XMakefiles::
- X @case '${MFLAGS}' in *[ik]*) set +e;; esac; \
- X for i in $(SUBDIRS);\
- X do \
- X echo "Making "Makefiles" in $(DIR)$$i..."; \
- X (cd $$i || exit 1; \
- X if test ! -f Makefile; then /bin/sh Makefile.SH; fi; \
- X $(MAKE) $(MFLAGS) Makefiles) \
- X done
- X
- XMakefiles.SH:: Makefile.SH
- X @case '${MFLAGS}' in *[ik]*) set +e;; esac; \
- X for i in $(SUBDIRS);\
- X do \
- X case "$(DIR)$$i/" in \
- X */*/*/*/) newtop=../../../..;; \
- X */*/*/) newtop=../../..;; \
- X */*/) newtop=../..;; \
- X */) newtop=..;; \
- X esac; \
- X case "$(TOP)" in \
- X /*) newtop="$(TOP)" ;; \
- X esac; \
- X echo "Making Makefiles.SH in $(DIR)$$i..."; \
- X (cd $$i || exit 1; $(MAKE) $(MFLAGS) -f ../Makefile \
- X Makefile TOP=$$newtop CURRENT=$(DIR)$$i;\
- X $(MAKE) $(MFLAGS) Makefiles.SH) \
- X done
- X
- Xall::
- X @$(MAKE) subdirs TARGET=all VERB="Making all" FLAGS=
- X
- X!NO!SUBS!
- Xchmod 644 Makefile
- X$eunicefix Makefile
- X
- END_OF_FILE
- if test 4878 -ne `wc -c <'Makefile.SH'`; then
- echo shar: \"'Makefile.SH'\" unpacked with wrong size!
- fi
- # end of 'Makefile.SH'
- fi
- if test -f 'agent/files/chkagent.sh' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'agent/files/chkagent.sh'\"
- else
- echo shar: Extracting \"'agent/files/chkagent.sh'\" \(2256 characters\)
- sed "s/^X//" >'agent/files/chkagent.sh' <<'END_OF_FILE'
- X#!/bin/sh
- X#
- X# Copyright (c) 1992, Raphael Manfredi
- X#
- X# You may redistribute only under the terms of the GNU General Public
- X# Licence as specified in the README file that comes with dist.
- X#
- X# $Id: chkagent.sh,v 2.9 92/07/14 16:47:41 ram Exp $
- X#
- X# $Log: chkagent.sh,v $
- X# Revision 2.9 92/07/14 16:47:41 ram
- X# 3.0 beta baseline.
- X#
- X
- X# Make sure the mailagent is working well
- Xlookat='ERROR|FAILED|WARNING|FATAL|DUMPED'
- X
- Xtrap "rm -f $report $output $todaylog $msg" 1 2 3 15
- X
- X# Interpret the ~/.mailagent configuration file
- Xset X `<$HOME/.mailagent sed -n \
- X -e '/^[ ]*#/d' \
- X -e 's/^[ ]*\([^ :\/]*\)[ ]*:[ ]*\([^#]*\).*/\1="\2";/p'`
- Xshift
- X
- X# Deal with possible white spaces in variables and ~ substitution
- Xcmd=''
- Xfor line in $*; do
- X cmd="$cmd$line"
- Xdone
- Xcmd=`echo $cmd | sed -e "s|~|$HOME|g"`
- Xeval $cmd
- X
- X# Compute location of report file and log file
- Xreport="/tmp/cAg$$"
- Xoutput="/tmp/cAo$$"
- Xlogfile="$logdir/$log"
- Xtodaylog="/tmp/tAg$$"
- X
- X# Current date format to look for in logfile
- Xtoday=`date "+%y/%m/%d"`
- X
- Xif test -f "$logfile"; then
- X grep "$today" $logfile > $todaylog
- X egrep "$lookat" $todaylog > $output
- X if test -s "$output"; then
- X echo "*** Errors from logfile ($logfile):" > $report
- X echo " " >> $report
- X cat $output >> $report
- X fi
- X rm -f $todaylog $output
- Xelse
- X echo "Cannot find $logfile" > $report
- Xfi
- X
- X# ~/.bak is the output from .forward
- Xif test -s "$HOME/.bak"; then
- X echo " " >> $report
- X echo "*** Errors from ~/.bak:" >> $report
- X echo " " >> $report
- X cat $HOME/.bak >> $report
- X cp /dev/null $HOME/.bak
- Xfi
- X
- X# Look for mails in the emergency directory
- Xls -C $emergdir > $output
- Xif test -s "$output"; then
- X echo " " >> $report
- X echo "*** Mails held in lost+mail ($emergdir):" >> $report
- X echo " " >> $report
- X cat $output >> $report
- Xfi
- Xrm -f $output
- X
- X# Spot any unprocessed mails in the queue
- Xcd $queue
- Xls -C qm* fm* > $output 2>/dev/null
- Xif test -s "$output"; then
- X echo " " >> $report
- X echo "*** Unprocessed mails in queue ($queue):" >> $report
- X echo " " >> $report
- X cat $output >> $report
- Xfi
- Xrm -f $output
- X
- Xif test -s "$report"; then
- X msg="/tmp/mAg$$"
- X cat >$msg <<EOM
- XTo: $user
- XSubject: Errors from mailagent system
- X
- XEOM
- X cat $report >>$msg
- X rm -f $report
- X /usr/lib/sendmail -odi -t <$msg
- X rm -f $msg
- Xelse
- X rm -f $report
- Xfi
- X
- Xexit 0
- END_OF_FILE
- if test 2256 -ne `wc -c <'agent/files/chkagent.sh'`; then
- echo shar: \"'agent/files/chkagent.sh'\" unpacked with wrong size!
- fi
- chmod +x 'agent/files/chkagent.sh'
- # end of 'agent/files/chkagent.sh'
- fi
- if test -f 'agent/filter/main.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'agent/filter/main.c'\"
- else
- echo shar: Extracting \"'agent/filter/main.c'\" \(4229 characters\)
- sed "s/^X//" >'agent/filter/main.c' <<'END_OF_FILE'
- X/*
- X
- X # # ## # # # ####
- X ## ## # # # ## # # #
- X # ## # # # # # # # #
- X # # ###### # # # # ### #
- X # # # # # # ## ### # #
- X # # # # # # # ### ####
- X
- X The main entry point.
- X*/
- X
- X/*
- X * $Id: main.c,v 2.9.1.1 92/08/12 21:30:38 ram Exp $
- X *
- X * Copyright (c) 1992, Raphael Manfredi
- X *
- X * You may redistribute only under the terms of the GNU General Public
- X * Licence as specified in the README file that comes with dist.
- X *
- X * $Log: main.c,v $
- X * Revision 2.9.1.1 92/08/12 21:30:38 ram
- X * patch6: option -t disallowed when running setuid (security hole)
- X *
- X * Revision 2.9 92/07/14 16:48:27 ram
- X * 3.0 beta baseline.
- X *
- X */
- X
- X#include "config.h"
- X#include "portable.h"
- X
- X#ifdef I_STRING
- X#include <string.h>
- X#else
- X#include <strings.h>
- X#endif
- X
- X#include <stdio.h>
- X#include <signal.h>
- X#include <sys/types.h>
- X#include "logfile.h"
- X#include "io.h"
- X#include "hash.h"
- X#include "msg.h"
- X#include "parser.h"
- X#include "sysexits.h"
- X
- X#define MAX_STRING 2048 /* Maximum string length */
- X
- Xprivate Signal_t handler(); /* Signal handler */
- Xprivate void set_signal(); /* Set up the signal handler */
- X
- Xextern void env_home(); /* Only for tests */
- X
- Xpublic void main(argc, argv, envp)
- Xint argc;
- Xchar **argv;
- Xchar **envp;
- X{
- X /* This is the main entry point for the mail filter */
- X
- X char *value; /* Symbol value */
- X int euid, uid; /* Current effective and real uid */
- X int egid, gid; /* Effective and real gid */
- X
- X /* Compute program name, removing any leading path to keep only the name
- X * of the executable file.
- X */
- X progname = rindex(argv[0], '/'); /* Only last name if '/' found */
- X if (progname++ == (char *) 0) /* There were no '/' */
- X progname = argv[0]; /* This must be the filename then */
- X progpid = getpid(); /* Program's PID */
- X
- X /* Security precautions. Look who we are and who we pretend to be */
- X uid = getuid();
- X gid = getgid();
- X euid = geteuid();
- X egid = getegid();
- X
- X /* The '-t' option means we are in test mode: set the home directory by
- X * using the environment HOME variable, so that we may provide our own
- X * configuration file elsewhere. Of course, this cannot be used if the
- X * filter is setuid and invoked by an uid different than the owner of the
- X * filter program.
- X */
- X if (argc > 1 && 0 == strcmp(argv[1], "-t")) {
- X if (uid != euid) {
- X fprintf(stderr, "filter: no option allowed when setuid\n");
- X exit(1);
- X }
- X env_home(); /* Get HOME form environment */
- X }
- X
- X set_signal(); /* Set up signal handler */
- X read_conf(".mailagent"); /* Read configuration file */
- X
- X add_log(19, "starting processing");
- X
- X /* We'll be invoking a perl script with the -S switch, and perl will not
- X * allow us to do that if it detects "setuidness". Some sendmail programs
- X * are broken and do not reset the uid/gid correctly when they process
- X * their queue. This is why it is important to set the setuid and setgid
- X * bits on the filter program.
- X */
- X
- X /* Make sure our gid matches the effective gid */
- X if (egid != gid && -1 == setgid(egid)) {
- X add_log(1, "SYSERR setgid: %m (%e)");
- X add_log(4, "WARNING cannot set GID to %d, continuing as %d", egid, gid);
- X } else if (egid != gid)
- X add_log(6, "NOTICE reset GID from %d to %d", gid, egid);
- X
- X /* Make sure our uid matches the effective uid */
- X if (euid != uid && -1 == setuid(euid)) {
- X add_log(1, "SYSERR setuid: %m (%e)");
- X add_log(4, "WARNING cannot set UID to %d, continuing as %d", euid, uid);
- X } else if (euid != uid)
- X add_log(6, "NOTICE reset UID from %d to %d", uid, euid);
- X
- X value = ht_value(&symtab, "queue"); /* Fetch queue location */
- X if (value == (char *) 0)
- X fatal("queue directory not defined");
- X
- X set_env_vars(envp); /* Set environment variables */
- X process(); /* Process mail */
- X
- X exit(EX_OK); /* We did it */
- X}
- X
- Xprivate void set_signal()
- X{
- X /* Set up the signal handler */
- X
- X#ifdef SIGHUP
- X signal(SIGHUP, handler);
- X#endif
- X#ifdef SIGINT
- X signal(SIGINT, handler);
- X#endif
- X#ifdef SIGQUIT
- X signal(SIGQUIT, handler);
- X#endif
- X#ifdef SIGTERM
- X signal(SIGTERM, handler);
- X#endif
- X}
- X
- Xprivate Signal_t handler(sig)
- Xint sig;
- X{
- X /* A signal was caught */
- X
- X fatal("caught signal #%d", sig);
- X}
- X
- END_OF_FILE
- if test 4229 -ne `wc -c <'agent/filter/main.c'`; then
- echo shar: \"'agent/filter/main.c'\" unpacked with wrong size!
- fi
- # end of 'agent/filter/main.c'
- fi
- if test -f 'agent/man/Makefile.SH' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'agent/man/Makefile.SH'\"
- else
- echo shar: Extracting \"'agent/man/Makefile.SH'\" \(3801 characters\)
- sed "s/^X//" >'agent/man/Makefile.SH' <<'END_OF_FILE'
- X: Makefile.SH generated from Jmake.tmpl and Jmakefile [jmake 2.8 PL13]
- X: $X-Id: Jmake.tmpl,v 2.8.1.2 91/11/18 13:22:54 ram Exp $
- X
- Xcase $CONFIG in
- X'')
- X if test ! -f config.sh; then
- X ln ../config.sh . || \
- X ln ../../config.sh . || \
- X ln ../../../config.sh . || \
- X (echo "Can't find config.sh."; exit 1)
- X fi 2>/dev/null
- X . ./config.sh
- X ;;
- Xesac
- Xcase "$0" in
- X*/*) cd `expr X$0 : 'X\(.*\)/'` ;;
- Xesac
- XCURRENT=agent/man
- XDIR=`echo $CURRENT/ | sed -e 's/\.\///g'`
- Xecho "Extracting ${DIR}Makefile (with variable substitutions)"
- XDATE=`date`
- X$spitshell >Makefile <<!GROK!THIS!
- X########################################################################
- X# Makefile generated from Makefile.SH on $DATE
- X
- XSHELL = /bin/sh
- XJMAKE = jmake
- XTOP = ../..
- XCURRENT = $CURRENT
- XDIR = $DIR
- XINSTALL = ../../install
- X
- X########################################################################
- X# Parameters set by Configure -- edit config.sh if changes are needed
- X
- XCTAGS = ctags
- XL = $manext
- XMANSRC = $mansrc
- XMAKE = make
- XMV = $mv
- XRM = $rm -f
- X
- X########################################################################
- X# Automatically generated parameters -- do not edit
- X
- XMANPAGE = \$(MPAGES)
- X
- X########################################################################
- X# New suffixes and associated building rules -- edit with care
- X
- X.SUFFIXES: .SH .$manext
- X
- X.SH.$manext:
- X /bin/sh \$<
- X
- X!GROK!THIS!
- X$spitshell >>Makefile <<'!NO!SUBS!'
- X
- X########################################################################
- X# Jmake rules for building libraries, programs, scripts, and data files
- X# $X-Id: Jmake.rules,v 2.8.1.4 91/11/18 13:19:07 ram Exp $
- X
- X########################################################################
- X# Start of Jmakefile
- X
- X# $X-Id: Jmakefile,v 2.9 92/07/14 16:49:04 ram Exp $
- X#
- X# Copyright (c) 1991, Raphael Manfredi
- X#
- X# You may redistribute only under the terms of the GNU General Public
- X# Licence as specified in the README file that comes with dist.
- X#
- X# $X-Log: Jmakefile,v $
- X# Revision 2.9 92/07/14 16:49:04 ram
- X# 3.0 beta baseline.
- X#
- X
- XMPAGES = mailagent.$(L) maildist.$(L) maillist.$(L) mailhelp.$(L) mailpatch.$(L)
- X
- Xall:: $(MPAGES)
- X
- Xlocal_realclean::
- X $(RM) $(MPAGES)
- X
- Xinstall.man::
- X @if test "$(MANSRC)"; then \
- X case '${MFLAGS}' in *[i]*) set +e;; esac; \
- X for file in $(MPAGES); do \
- X (set -x; $(INSTALL) -c -m 444 $$file $(MANSRC)); \
- X done; \
- X else exit 0; fi
- X
- Xdeinstall.man::
- X @if test "$(MANSRC)"; then \
- X case '${MFLAGS}' in *[i]*) set +e;; esac; \
- X for file in $(MPAGES); do \
- X (set -x; $(RM) $(MANSRC)/$$file); \
- X done; \
- X else exit 0; fi
- X
- X########################################################################
- X# Common rules for all Makefiles -- do not edit
- X
- Xemptyrule::
- X
- Xclean: local_clean
- Xrealclean: local_realclean
- Xclobber: local_clobber
- X
- Xlocal_clean::
- X $(RM) core *~ *.o
- X
- Xlocal_realclean:: local_clean
- X
- Xlocal_clobber:: local_realclean
- X $(RM) Makefile config.sh
- X
- XMakefile.SH: Jmakefile
- X -@if test -f $(TOP)/.package; then \
- X if test -f Makefile.SH; then \
- X echo " $(RM) Makefile.SH~; $(MV) Makefile.SH Makefile.SH~"; \
- X $(RM) Makefile.SH~; $(MV) Makefile.SH Makefile.SH~; \
- X fi; \
- X echo " $(JMAKE) -DTOPDIR=$(TOP) -DCURDIR=$(CURRENT)" ; \
- X $(JMAKE) -DTOPDIR=$(TOP) -DCURDIR=$(CURRENT) ; \
- X else touch $@; exit 0; fi
- X
- XMakefile: Makefile.SH
- X /bin/sh Makefile.SH
- X
- Xtags::
- X $(CTAGS) -w *.[ch]
- X $(CTAGS) -xw *.[ch] > tags
- X
- Xlocal_clobber::
- X $(RM) tags
- X
- X########################################################################
- X# Empty rules for directories with no sub-directories -- do not edit
- X
- Xinstall::
- X @echo "install in $(CURRENT) done."
- X
- Xdeinstall::
- X @echo "deinstall in $(CURRENT) done."
- X
- Xinstall.man::
- X @echo "install.man in $(CURRENT) done."
- X
- Xdeinstall.man::
- X @echo "deinstall.man in $(CURRENT) done."
- X
- XMakefiles::
- X
- XMakefiles.SH::
- X
- X!NO!SUBS!
- Xchmod 644 Makefile
- X$eunicefix Makefile
- X
- END_OF_FILE
- if test 3801 -ne `wc -c <'agent/man/Makefile.SH'`; then
- echo shar: \"'agent/man/Makefile.SH'\" unpacked with wrong size!
- fi
- chmod +x 'agent/man/Makefile.SH'
- # end of 'agent/man/Makefile.SH'
- fi
- if test -f 'agent/man/mailhelp.SH' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'agent/man/mailhelp.SH'\"
- else
- echo shar: Extracting \"'agent/man/mailhelp.SH'\" \(5217 characters\)
- sed "s/^X//" >'agent/man/mailhelp.SH' <<'END_OF_FILE'
- Xcase $CONFIG in
- X'')
- X if test ! -f config.sh; then
- X ln ../config.sh . || \
- X ln ../../config.sh . || \
- X ln ../../../config.sh . || \
- X (echo "Can't find config.sh."; exit 1)
- X fi
- X . config.sh
- X ;;
- Xesac
- Xcase "$0" in
- X*/*) cd `expr X$0 : 'X\(.*\)/'` ;;
- Xesac
- Xecho "Extracting agent/man/mailhelp.$manext (with variable substitutions)"
- X$rm -f mailhelp.$manext
- X$spitshell >mailhelp.$manext <<!GROK!THIS!
- X.TH MAILHELP $manext ram
- X''' @(#) Manual page for mailagent's commands -- (c) ram February 1991
- X'''
- X''' $Id: mailhelp.SH,v 2.9 92/07/14 16:49:18 ram Exp $
- X'''
- X''' Copyright (c) 1991, Raphael Manfredi
- X'''
- X''' You may redistribute only under the terms of the GNU General Public
- X''' Licence as specified in the README file that comes with dist.
- X'''
- X''' $Log: mailhelp.SH,v $
- X''' Revision 2.9 92/07/14 16:49:18 ram
- X''' 3.0 beta baseline.
- X'''
- X.SH NAME
- Xmaildist, mailhelp, maillist, mailpatch \- mailagent's commands
- X.SH SYNOPSIS
- X\fBmaildist\fR \fIaddress\fR \fIsystem\fR [ \fIversion\fR ]
- X.br
- X\fBmailhelp\fR [ \fIaddress\fR ]
- X.br
- X\fBmaillist\fR [ \fIaddress\fR ]
- X.br
- X\fBmailpatch\fR \fIaddress\fR \fIsystem\fR \fIversion\fR \fIpatchlist\fR
- X.SH DESCRIPTION
- XThese commands are not intended to be run directly by a user. They may
- Xappear in any mail whose subject is set to \fICommand\fR. Such a mail
- Xwill be processed by the \fImailagent\fR(1), which will extract all lines
- Xbeginning with \fI@SH\fR, followed by one of the above commands. The
- Xmailagent first sets environment variables that will be used by every
- Xcommands.
- X.PP
- X.I Maildist
- Xis used to mail a whole distribution to the given address. The version
- Xnumber may be ommitted if the system has no version specified !!
- X.I Maildist
- Xlooks for the \fISpool/distribs\fR file to find where the distribution
- Xis located. If it has been archived, the file name extension is used
- Xto guess how the archive will be restored:
- X.sp
- X.PD 0
- X.TP 10
- X.B .cpio
- Xarchive is a \fIcpio\fR archive
- X.TP
- X.B .tar
- Xarchive is in \fItar\fR format
- X.TP
- X.B .cpio.Z
- Xcompressed \fIcpio\fR archive
- X.TP
- X.B .tar.Z
- Xcompressed \fItar\fR archive
- X.PD
- X.PP
- XNote that on file systems with short file names, the final \fB.Z\fR
- Xextension could be dropped. Therefore, compressed archives must be
- Xexplicitely stated in the \fISpool/distribs\fR file.
- X.PP
- XOnce the directory is found (or extracted), \fImaildist\fR looks
- Xfor a \fIMANIFEST\fR file. If it finds one,
- Xonly the files listed therein will be sent. Otherwise,
- Xall the files will be sent, excepted the binary executables and object
- Xfiles, the RCS sub-directories or RCS files, the private \fIU\fR
- Xsubdirectory and the \fI.package\fR file, any \fIcore\fR file or files
- Xin a \fIbugs\fR subdirectory.
- X.PP
- XThen, the following algorithm is used: if no RCS file is found, the
- Xfile is sent as-is. Otherwise, we look for a defined 'lastpat' symbol.
- XIf it is found, the corresponding revision is checked-out and sent.
- XOtherwise, the last-revision on the default branch is exctracted,
- Xprovided that the corresponding working file is not found.
- X.PP
- XThe \fImaildist\fR command will not work if the system is tagged as
- Xan old one (with an \fIo\fR in the patches column of the \fIdistribs\fR
- Xfile). A message will be sent back to the user, explaining that only
- Xpatches are available.
- X.PP
- X.I Mailhelp
- Xsends help to the address (if ommitted, the return path of the mail
- Xis used). The help text is found in \fISpool/agenthelp\fR. It should
- Xhave been correctly set in the installation procedure, as explained
- Xin the \fImailagent\fR($manext) manual page.
- X.PP
- X.I Maillist
- Xsends the list of available distributions, with current patchlevels
- Xif necessary. The \fISpool/distribs\fR and \fISpool/proglist\fR files
- Xare both used to build the list.
- X.PP
- X.I Mailpatch
- Xsends one or more patches for a maintained distribution. The directory
- Xor the archive is found by scanning \fISpool/distribs\fR. The \fIbugs\fR
- Xsub-directory must then hold the available patches. The patches may
- Xbe stored in compressed form (with the ending \fI.Z\fR), as
- X.I mailpatch
- Xknows about them and will uncompress the patch before sending.
- X.PP
- XPatches for old systems are kept in a separate directory, either in normal
- Xor in compressed form. If the version number of the old system is \fIx.y\fR,
- Xthen the directory must be named \fIbugs-x.y\fR and placed in the root
- Xdirectory of the system, just like \fIbugs\fR is.
- X.PP
- XWhenever the user asks for an old system, \fImailpatch\fR inserts a little
- Xnote giving the latest version number for that system.
- X.SH NOTE
- XFor a more accurate description of these commands (user's point of vue),
- Xyou may want to have a look at the help file or send help to yourself
- Xusing the \fImailhelp\fR command.
- X.SH FILES
- X.PD 0
- X.TP 20
- X~/.mailagent
- Xconfiguration file for mailhelp.
- X.TP
- X$privlib
- Xdirectory holding templates and samples.
- X.TP
- XSpool/agenthelp
- Xhelp file
- X.TP
- XSpool/distribs
- Xdistribution list
- X.TP
- XSpool/proglist
- Xcomments for available distributions
- X.TP
- XSpool/plsave
- Xrecords patchlevel of archived distributions
- X.TP
- XLog/agentlog
- Xmailagent's log file
- X.PD
- X.SH BUGS
- XThe \fIproglist\fR file ought to make a distinction between different
- Xversions of a same system.
- X.SH AUTHOR
- XRaphael Manfredi <ram@eiffel.com>
- X.SH "SEE ALSO"
- Xmailagent($manext).
- X!GROK!THIS!
- Xchmod 444 mailhelp.$manext
- END_OF_FILE
- if test 5217 -ne `wc -c <'agent/man/mailhelp.SH'`; then
- echo shar: \"'agent/man/mailhelp.SH'\" unpacked with wrong size!
- fi
- # end of 'agent/man/mailhelp.SH'
- fi
- if test -f 'agent/pl/emergency.pl' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'agent/pl/emergency.pl'\"
- else
- echo shar: Extracting \"'agent/pl/emergency.pl'\" \(4856 characters\)
- sed "s/^X//" >'agent/pl/emergency.pl' <<'END_OF_FILE'
- X;# $Id: emergency.pl,v 2.9.1.1 92/08/12 21:33:04 ram Exp Locker: ram $
- X;#
- X;# Copyright (c) 1992, Raphael Manfredi
- X;#
- X;# You may redistribute only under the terms of the GNU General Public
- X;# Licence as specified in the README file that comes with dist.
- X;#
- X;# $Log: emergency.pl,v $
- X;# Revision 2.9.1.1 92/08/12 21:33:04 ram
- X;# patch6: do not read mail if stdin is connected to a tty
- X;#
- X;# Revision 2.9 92/07/14 16:49:51 ram
- X;# 3.0 beta baseline.
- X;#
- X;#
- X#
- X# Emergency situation routines
- X#
- X
- X# Emergency signal was caught
- Xsub emergency {
- X local($sig) = @_; # First argument is signal name
- X if ($has_option) { # Mailagent was invoked "manually"
- X do resync(); # Resynchronize waiting file if necessary
- X exit 1;
- X }
- X do fatal("trapped SIG$sig");
- X}
- X
- X# In case something got wrong
- Xsub fatal {
- X local($reason) = shift; # Why did we get here ?
- X # Make sure the lock file does not last. We don't need any lock now, as
- X # we are going to die real soon anyway.
- X unlink $lockfile if $locked;
- X # Assume the whole message has not been read yet
- X $fd = STDIN; # Default input
- X if ($file_name ne '') {
- X $Header{'All'} = ''; # We're about to re-read the whole message
- X open(MSG, $file_name); # Ignore errors
- X $fd = MSG;
- X }
- X unless (-t $fd) { # Do not get mail if connected to a tty
- X while (<$fd>) {
- X $Header{'All'} .= $_;
- X }
- X }
- X # It can happen that we get here before configuration file was read
- X if (defined $loglvl) {
- X do add_log("FATAL $reason") if ($loglvl > 0);
- X -t STDIN && print STDERR "$prog_name: $reason\n";
- X }
- X # Try an emergency save, if mail is not empty
- X if ($Header{'All'} ne '' && 0 == &emergency_save) {
- X # The stderr should be redirected to some file
- X $file_name =~ s|.*/(.*)|$1|; # Keep only basename
- X $file_name = "<stdin>" if $file_name eq '';
- X print STDERR "**** $file_name not processed ($reason) ****\n";
- X print STDERR $Header{'All'};
- X ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
- X localtime(time);
- X $date = sprintf("%.2d/%.2d/%.2d %.2d:%.2d:%.2d",
- X $year,++$mon,$mday,$hour,$min,$sec);
- X print STDERR "---- $date ----\n";
- X }
- X do resync(); # Resynchronize waiting file if necessary
- X # Give an error exit status to filter
- X exit 1;
- X}
- X
- X# Emergency saving of message held in $Header{'All'}. If the 'emergdir'
- X# configuration parameter in ~/.mailagent is set to an existing directory, the
- X# first saving attempt is made there (each mail in a separate file).
- Xsub emergency_save {
- X return 0 unless (defined $cf'home); # ~/.mailagent not processed
- X return 1 if -d "$cf'emergdir" && &dump_mbox("$cf'emergdir/ma$$");
- X return 1 if &dump_mbox(&mailbox_name);
- X return 1 if &dump_mbox("$cf'home/mbox.urgent");
- X return 1 if &dump_mbox("$cf'home/mbox.urg$$");
- X return 1 if &dump_mbox("/usr/spool/uucppublic/mbox.$cf'user");
- X return 1 if &dump_mbox("/var/spool/uucppublic/mbox.$cf'user");
- X return 1 if &dump_mbox("/usr/tmp/mbox.$cf'user");
- X return 1 if &dump_mbox("/var/tmp/mbox.$cf'user");
- X return 1 if &dump_mbox("/tmp/mbox.$cf'user");
- X &add_log("ERROR unable to save mail in any emergency mailbox") if $loglvl;
- X 0;
- X}
- X
- X# Dump $Header{'All'} in emergency mailbox
- Xsub dump_mbox {
- X local($mbox) = shift(@_);
- X local($ok) = 0; # printing status
- X local($existed) = 0; # did the mailbox exist already ?
- X $existed = 1 if -f "$mbox";
- X if (open(MBOX, ">>$mbox")) {
- X (print MBOX $Header{'All'}) && ($ok = 1);
- X print MBOX "\n"; # allow parsing by other mail tools
- X close MBOX;
- X if ($ok) {
- X do add_log("DUMPED in $mbox") if $loglvl > 5;
- X return 1;
- X } else {
- X if ($existed) {
- X do add_log("WARNING imcomplete mail appended to $mbox")
- X if $loglvl > 5;
- X } else {
- X unlink "$mbox"; # remove incomplete file
- X }
- X }
- X }
- X 0;
- X}
- X
- X# Resynchronizes the waiting file if necessary (i.e if it exists and %waiting
- X# is not an empty array).
- Xsub resync {
- X local(@key) = keys %waiting; # Keys of H table are file names
- X local($ok) = 1; # Assume resync is ok
- X local($printed) = 0; # Nothing printed yet
- X return if $#key < 0 || "$cf'queue" eq '' || ! -f "$cf'queue/$agent_wait";
- X do add_log("resynchronizing the waiting file") if $loglvl > 11;
- X if (open(WAITING, ">$cf'queue/$agent_wait~")) {
- X foreach (@key) {
- X if ($waiting{$_}) {
- X print WAITING "$_\n" || ($ok = 0);
- X $printed = 1;
- X }
- X }
- X close WAITING;
- X if ($printed) {
- X if (!$ok) {
- X do add_log("ERROR could not update waiting file") if $loglvl;
- X unlink "$cf'queue/$agent_wait~";
- X } elsif (rename("$cf'queue/$agent_wait~","$cf'queue/$agent_wait")) {
- X do add_log("waiting file has been updated") if $loglvl > 18;
- X } else {
- X do add_log("ERROR cannot rename waiting file") if $loglvl > 0;
- X }
- X } else {
- X unlink "$cf'queue/$agent_wait";
- X unlink "$cf'queue/$agent_wait~";
- X do add_log ("removed waiting file") if ($loglvl > 18);
- X }
- X } else {
- X do add_log("ERROR unable to write new waiting file") if $loglvl;
- X }
- X}
- X
- END_OF_FILE
- if test 4856 -ne `wc -c <'agent/pl/emergency.pl'`; then
- echo shar: \"'agent/pl/emergency.pl'\" unpacked with wrong size!
- fi
- # end of 'agent/pl/emergency.pl'
- fi
- if test -f 'agent/pl/listqueue.pl' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'agent/pl/listqueue.pl'\"
- else
- echo shar: Extracting \"'agent/pl/listqueue.pl'\" \(4994 characters\)
- sed "s/^X//" >'agent/pl/listqueue.pl' <<'END_OF_FILE'
- X;# $Id: listqueue.pl,v 2.9.1.1 92/08/26 13:15:36 ram Exp $
- X;#
- X;# Copyright (c) 1992, Raphael Manfredi
- X;#
- X;# You may redistribute only under the terms of the GNU General Public
- X;# Licence as specified in the README file that comes with dist.
- X;#
- X;# $Log: listqueue.pl,v $
- X;# Revision 2.9.1.1 92/08/26 13:15:36 ram
- X;# patch8: now parses only the header of each mail message
- X;#
- X;# Revision 2.9 92/07/14 16:50:12 ram
- X;# 3.0 beta baseline.
- X;#
- X;#
- X# List the current mails held in the queue, if any at all.
- X# See also the pqueue subroutine for other comments about the queue.
- Xsub list_queue {
- X local(@files) = <$cf'queue/fm* $cf'queue/qm*>;
- X if (-f "$cf'queue/$agent_wait") {
- X if (open(WAITING, "$cf'queue/$agent_wait")) {
- X while (<WAITING>) {
- X chop;
- X push(@files, $_);
- X }
- X close WAITING;
- X } else {
- X &add_log("ERROR cannot open $cf'queue/$agent_wait: $!") if $loglvl;
- X }
- X }
- X # The @files array now contains the path name of all the queued mails
- X # (at least those known to the mailagent).
- X if (@files == 0) {
- X print "Mailagent queue is empty.\n";
- X return;
- X }
- X format STDOUT_TOP =
- XFilename Size Queue time Status Sender / Recipient list
- X--------- -------- ----------- --------- --------------------------------------
- X.
- X local($file); # Base name of file (eventually stripped)
- X local($directory); # Directory where queued mail is stored
- X local($queued); # Queuing date
- X local($status); # Status of mail
- X local($sender); # Sender of mail
- X local($star); # The '*' identifies out of queue mails
- X local($recipient); # Recipient of mail
- X local($buffer); # Temporary buffer to build recipient list
- X local($address); # E-mail address candidate for recipient list
- X local(%seen); # Records addresses already seen
- X $: = " ,"; # Break recipients on white space or colon
- X format STDOUT =
- X@<<<<<<<< @>>>>>>>@@<<<<<<<<<< @<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
- X$file $size $star $queued $status $sender
- X ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
- X $recipient
- X~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
- X $recipient
- X~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
- X $recipient
- X~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
- X $recipient
- X~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
- X $recipient
- X~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<...
- X $recipient
- X.
- X local($n) = $#files + 1;
- X local($s) = $n > 1 ? 's' : '';
- X print STDOUT " Mailagent Queue ($n request$s)\n";
- X foreach (@files) {
- X ($directory, $file) = m|^(.*)/(.*)|;
- X &parse_mail($_, 'head_only');
- X next unless defined $Header{'All'};
- X # Remove comments from all the addresses. The From field is used to
- X # identify the (possibly forged) sender while the To and Cc fields
- X # are concatenated to list the recipients;
- X $sender = (&parse_address($Header{'From'}))[0];
- X $buffer = $Header{'To'};
- X $buffer .= ',' . $Header{'Cc'} if $Header{'Cc'};
- X $recipient = '';
- X undef %seen;
- X while ($buffer =~ s/^(.*),(.*)/$1/) {
- X $address = (&parse_address($2))[0];
- X unless ($seen{$address}++) {
- X $recipient .= ', ' if $recipient;
- X $recipient .= $address;
- X }
- X }
- X $address = (&parse_address($buffer))[0];
- X unless ($seen{$address}++) {
- X $recipient .= ', ' if $recipient;
- X $recipient .= $address;
- X }
- X unless (-f $_) {
- X &add_log("WARNING unable to stat $_");
- X next;
- X }
- X ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
- X $atime,$mtime,$ctime,$blksize,$blocks) = stat(_);
- X $status = '';
- X # If file has 'mbox.' as part of its name, then it is an emergency
- X # saving done by the mailagent. If it starts with 'logname', then it
- X # is an emergency saving done by the filter.
- X $file =~ s/^mbox\.// && ($status = 'Backup');
- X $file =~ s/^$cf'user\.// && ($status = 'Backup');
- X if ($file =~ /^qm/ && (time - $mtime) < 1800) {
- X # Queue mails starting with 'qm' have been queued by the filter
- X # program. To avoid race conditions, those mails are skipped for
- X # half an hour (cf to pqueue subroutine).
- X $status = 'Skipped' unless $status; # Filter queued mail
- X } else {
- X # Processing of mail allowed (mailagent -q would flush it)
- X $status = 'Deferred' unless $status;
- X }
- X ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
- X localtime($mtime);
- X $queued = sprintf("%.2d/%.2d-%.2d:%.2d", ++$mon,$mday,$hour,$min);
- X $queued = 'Now' if (time - $mtime) < 60;
- X $star = '';
- X $star = '*' if $directory ne $cf'queue; # Spot out-of-queue mails
- X if ((time - $mtime) > 86400) { # Also spot old mails
- X $star = '#';
- X $star = '@' if $directory ne $cf'queue;
- X }
- X write(STDOUT);
- X }
- X}
- X
- END_OF_FILE
- if test 4994 -ne `wc -c <'agent/pl/listqueue.pl'`; then
- echo shar: \"'agent/pl/listqueue.pl'\" unpacked with wrong size!
- fi
- # end of 'agent/pl/listqueue.pl'
- fi
- if test -f 'agent/pl/macros.pl' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'agent/pl/macros.pl'\"
- else
- echo shar: Extracting \"'agent/pl/macros.pl'\" \(4966 characters\)
- sed "s/^X//" >'agent/pl/macros.pl' <<'END_OF_FILE'
- X;# $Id: macros.pl,v 2.9.1.2 92/08/26 13:16:14 ram Exp $
- X;#
- X;# Copyright (c) 1992, Raphael Manfredi
- X;#
- X;# You may redistribute only under the terms of the GNU General Public
- X;# Licence as specified in the README file that comes with dist.
- X;#
- X;# $Log: macros.pl,v $
- X;# Revision 2.9.1.2 92/08/26 13:16:14 ram
- X;# patch8: added support for external variables (persistent)
- X;#
- X;# Revision 2.9.1.1 92/07/25 12:40:37 ram
- X;# patch1: now discards comments in Reply-To field (macro %r)
- X;#
- X;# Revision 2.9 92/07/14 16:50:16 ram
- X;# 3.0 beta baseline.
- X;#
- X;#
- X# Macros:
- X# %% A real percent sign
- X# %D Day of the week (0-6)
- X# %H Host name (name of the machine on which the mailagent runs)
- X# %L Length of the message in bytes (without header)
- X# %N Full name of sender (login name if none)
- X# %R Subject of orginal message with leading Re: suppressed
- X# %S Re: subject of original message
- X# %T Time of last modification on mailed file (value taken from $macro_T)
- X# %U Full name of the user
- X# %_ A white space
- X# %#reg Value of user-defined variable 'reg'
- X# %& List of selectors which incurred match (among regular-expression ones)
- X# %~ A null character
- X# %1 Value of the corresponding backreference (limited to 99 per rule)
- X# %d Day of the month (01-31)
- X# %f Contents of the "From:" line, something like %N <%r> or %r (%N)
- X# %h Hour of the day (00-23)
- X# %i Message ID if available
- X# %l Number of lines in the message
- X# %m Month of the year (01-12)
- X# %n Lower-case login name of sender
- X# %o Organization (where mailagent runs)
- X# %r Return address of message
- X# %s Subject of original message
- X# %t Current hour and minute (in HH:MM format)
- X# %u Login name of the user
- X# %y Year (last two digits)
- X# %[To] Value of the field in header (here To:)
- X
- X# Macros substitutions (in-place)
- Xsub macros_subst {
- X local(*str) = shift(@_); # The string
- X local($_) = $str; # Work on a copy
- X return unless /%/; # Return immediately if no macros
- X
- X local($sender); # The from field
- X local(@from); # The rfc-822 parsed from line
- X $sender = $Header{'From'}; # Header-derived From address
- X @from = &parse_address($sender); # Get (address, comment)
- X local($login) = &login_name($from[0]); # Keep only login name
- X local($fullname) = $from[1]; # The comment part of address
- X $fullname = $login unless $fullname; # Use login name if no comment part
- X local($reply_to) = $Header{'Reply-To'}; # Return path derived
- X local($subject) = $Header{'Subject'}; # Original subject header
- X $subject =~ s/^\s*Re:\s*(.*)/$1/; # Strip off leading Re:
- X $subject = "<empty subject>" unless $subject;
- X $reply_to = (&parse_address($reply_to))[0]; # Keep only e-mail address
- X
- X # Time computations
- X local($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
- X localtime(time);
- X $mon = sprintf("%.2d", $mon + 1);
- X $mday = sprintf("%.2d", $mday);
- X local($timenow) = sprintf("%.2d:%.2d", $hour, $min);
- X $hour = sprintf("%.2d", $hour);
- X
- X # The following dummy block is here only to force perl interpreting
- X # the $ variables in the substitutions correctly...
- X if (0) {
- X $Header{'a'} = 'a';
- X $Variable{'a'} = 'a';
- X $Backref[0] = 0;
- X }
- X
- X s/%%/##pr##/g; # Protect double percent signs
- X s/%/#%%!/g; # Make sure substitutions do not add %
- X s/#%%!d/$mday/g; # Day of the month (01-31)
- X s/#%%!D/$wday/g; # Day of the week (0-6)
- X s/#%%!f/$Header{'From'}/g; # The "From:" line
- X s/#%%!h/$hour/g; # Hour of the day (00-23)
- X s/#%%!i/$Header{'Message-Id'}/g; # Message-Id (null string if none)
- X s/#%%!l/$Header{'Lines'}/g; # Number if lines in message
- X s/#%%!L/$Header{'Length'}/g; # Length of message, in bytes
- X s/#%%!m/$mon/g; # Month of the year
- X s/#%%!n/$login/g; # Lower-cased login name of sender
- X s/#%%!N/$fullname/g; # Full name of sender (login if none)
- X s/#%%!o/$orgname/g; # Organization name
- X s/#%%!r/$reply_to/g; # Return path of message
- X s/#%%!R/$subject/g; # Subject with leading Re: suppressed
- X s/#%%!s/$Header{'Subject'}/g; # Subject of message
- X s/#%%!S/Re: $Header{'Subject'}/g; # Re: subject of original message
- X s/#%%!t/$timenow/g; # Current time HH:MM
- X s/#%%!T/$macro_T/g; # Time of last modification on file
- X s/#%%!u/$cf'user/go; # User login name (does not change)
- X s/#%%!U/$cf'name/go; # User's name (does not change)
- X s/#%%!y/$year/g; # Year (last two digits)
- X s/#%%!_/ /g; # A white space
- X s/#%%!~//g; # A null character
- X s/#%%!&/$macro_ampersand/g; # List of matched generic selectors
- X s/#%%!(\d\d?)/$Backref[$1 - 1]/g; # A pattern matching backreference
- X s/#%%!#:(\w+)/&extern'val($1)/eg; # A persistent user-defined variable
- X s/#%%!#(\w+)/$Variable{$1}/g; # A user-defined variable
- X s/#%%!\[([\w-]+)\]/$Header{$1}/g; # The %[Field] macro
- X s/#%%!/%/g; # Any remaining percent is kept
- X s/##pr##/%/g; # A double percent expands to %
- X $str = $_; # Update string in-place
- X}
- X
- END_OF_FILE
- if test 4966 -ne `wc -c <'agent/pl/macros.pl'`; then
- echo shar: \"'agent/pl/macros.pl'\" unpacked with wrong size!
- fi
- # end of 'agent/pl/macros.pl'
- fi
- if test -f 'agent/pl/read_conf.pl' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'agent/pl/read_conf.pl'\"
- else
- echo shar: Extracting \"'agent/pl/read_conf.pl'\" \(4036 characters\)
- sed "s/^X//" >'agent/pl/read_conf.pl' <<'END_OF_FILE'
- X;# $Id: read_conf.pl,v 2.9.1.2 92/08/12 21:33:29 ram Exp $
- X;#
- X;# Copyright (c) 1991, 1992, Raphael Manfredi
- X;#
- X;# You may redistribute only under the terms of the GNU General Public
- X;# Licence as specified in the README file that comes with dist.
- X;#
- X;# $Log: read_conf.pl,v $
- X;# Revision 2.9.1.2 92/08/12 21:33:29 ram
- X;# patch6: perform security checks after config file parsing
- X;#
- X;# Revision 2.9.1.1 92/07/25 12:42:08 ram
- X;# patch1: configuration errors now reported on stderr
- X;# patch1: first syntax error also logged for further diagnostic
- X;#
- X;# Revision 2.9 92/07/14 16:50:40 ram
- X;# 3.0 beta baseline.
- X;#
- X;#
- Xpackage cf;
- X
- X# This package is responsible for keeping track of the configuration variables.
- X
- X# Read configuration file (usually in ~/.mailagent)
- Xsub main'read_config {
- X local($file) = @_; # where config file is located
- X local($_);
- X $file = '~/.mailagent' unless $file;
- X local($myhome) = $ENV{'HOME'}; # must be correctly set by filter
- X $file =~ s/~/$myhome/; # ~ substitution
- X local($main'config) = $file; # Save it: could be modified by config
- X open(CONFIG, "$file") ||
- X &'fatal("can't open config file $file");
- X local($config) = ' ' x 2000; # pre-extend to avoid realloc()
- X $config = '';
- X while (<CONFIG>) {
- X next if /^[ \t]*#/; # skip comments
- X next if /^[ \t]*\n/; # skip empy lines
- X $config .= $_;
- X }
- X &parse($config) || &'fatal('bad configuration');
- X close CONFIG;
- X
- X # Security checks, pending of those performed by the C filter. They are
- X # somewhat necessary, even though the mailagent does not run setuid
- X # (because anybody may activate the mailagent for any user by sending him
- X # a mail, and world writable configuration files makes the task too easy
- X # for a potential hacker). The tests are performed once the configuration
- X # file has been parsed, so logging of fatal errors may occur.
- X
- X local($ST_MODE) = 2 + $[; # Field st_mode from inode structure
- X local($S_IWOTH) = 02; # Writable by world (no .ph files here)
- X
- X -O "$'config" || &'fatal("you do not own config file $'config");
- X local($st_mode) = (stat($'config))[$ST_MODE];
- X ($st_mode & $S_IWOTH) && &'fatal("config file $'config is world writable!");
- X
- X return unless -f "$rules"; # No rule file
- X
- X -O "$rules" || &'fatal("you do not own rule file $rules");
- X $st_mode = (stat($rules))[$ST_MODE];
- X ($st_mode & $S_IWOTH) && &'fatal("rule file $rules is world writable!");
- X}
- X
- X# Parse config file held in variable and return 1 if ok, 0 for errors
- Xsub parse {
- X local($config) = @_;
- X local($eval) = ' ' x 1000; # Pre-extend
- X local($myhome) = $ENV{'HOME'}; # must be correctly set by filter
- X local($var, $value);
- X local($_);
- X $eval = '';
- X foreach (split(/\n/, $config)) {
- X if (/^[ \t]*([^ \t\n:\/]*)[ \t]*:[ \t]*([^#\n]*)/) {
- X $var = $1;
- X $value = $2;
- X $value =~ s/\s*$//; # remove trailing spaces
- X $eval .= "\$$var = \"$value\";\n";
- X $eval .= "\$$var =~ s|~|$myhome|g;\n"; # ~ substitution
- X }
- X }
- X eval $eval; # evaluate configuration parameters within package
- X
- X if ($@ ne '') { # Parsing error detected
- X local($error) = $@; # Logged error
- X local($*) = 1;
- X $error = (split(/\n/, $error))[0]; # Keep only first line
- X # Dump error message on stderr, as well as faulty configuration file.
- X # The original is restored out of the perl form to avoid surprise.
- X $eval =~ s/^\$.* =~ s\|~\|.*\n//g; # Remove added ~ substitutions
- X $eval =~ s/^\$//g; # Remove leading '$'
- X $eval =~ s/ = "(.*)";/: $1/g; # Keep only variable value
- X chop($eval);
- X print STDERR <<EOM;
- X**** Syntax error in configuration:
- X$error
- X
- X---- Begin of Faulty Configuration
- X$eval
- X---- End of Faulty Configuration
- X
- XEOM
- X &'add_log("syntax error in configuration: $error") if $'loglvl > 1;
- X return 0;
- X }
- X
- X # Define the mailagent parameters from those in config file
- X $logfile = $logdir . "/$log";
- X $seqfile = $spool . "/$seq";
- X $hashdir = $spool . "/$hash";
- X $main'loglvl = int($level); # This one is visible in the main package
- X $main'track_all = 1 if $track =~ /on/i; # Option -t set by config
- X
- X 1; # Ok
- X}
- X
- Xpackage main;
- X
- END_OF_FILE
- if test 4036 -ne `wc -c <'agent/pl/read_conf.pl'`; then
- echo shar: \"'agent/pl/read_conf.pl'\" unpacked with wrong size!
- fi
- # end of 'agent/pl/read_conf.pl'
- fi
- if test -f 'agent/test/TEST' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'agent/test/TEST'\"
- else
- echo shar: Extracting \"'agent/test/TEST'\" \(4140 characters\)
- sed "s/^X//" >'agent/test/TEST' <<'END_OF_FILE'
- X# feed this into perl
- X eval 'exec perl -S $0 "$@"'
- X if $running_under_some_shell;
- X
- Xchop($pwd = `pwd`);
- X$ENV{'HOME'} = "$pwd/out";
- Xchop($host = `(hostname 2>/dev/null || uname -n) 2>/dev/null`);
- X$host =~ s/^([^.]*)\..*/$1/; # Trim domain name
- X$ENV{'HOST'} = $host;
- X$ENV{'USER'} = 'nobody'; # In case we get mails back from RUN and friends
- X$ENV{'PWD'} = $pwd;
- X$ENV{'LEVEL'} = 0; # Default loglvl for filter and cmd tests
- X
- X@tests = ('basic', 'option', 'filter', 'cmd');
- X$failed = 0;
- X$how_many = 0;
- X
- Xrequire 'getopt.pl';
- X&Getopt;
- X
- X$mailagent = 'mailagent'; # Default program (dataloaded version)
- X$mailagent = 'magent' if $opt_n; # Use non-dataloaded version
- X$ENV{'MAILAGENT'} = $mailagent;
- X$ENV{'PATH'} = "$pwd/..:" . $ENV{'PATH'};
- X
- X-f "../$mailagent" && -x _ || die "No $mailagent.\n";
- X-f "../mailhook" && -x _ || die "No mailhook.\n";
- X-f '../filter/filter' && -x _ || die "No filter.\n";
- X
- X&load_ok; # Don't rerun successful tests if up to date
- X
- X# A level file indicates default loglvl
- Xif (-f 'level') {
- X chop($level = `cat level`);
- X $ENV{'LEVEL'} = int($level);
- X}
- X
- Xunless (-f 'OK') {
- X %Ok = ();
- X `rm -rf out` if -d 'out';
- X}
- X
- X`mkdir out` unless -d 'out';
- Xselect(STDOUT);
- X$| = 1;
- Xopen(OK, ">>OK");
- Xselect(OK);
- X$| = 1; # We may safely interrupt
- Xselect(STDOUT);
- X
- Xumask 022; # Ensure none of the files are world writable
- X
- Xforeach $dir (@tests) {
- X next unless -d $dir;
- X &run($dir);
- X}
- X
- X# Summarize what happened
- X
- Xclose OK;
- X
- Xif ($failed == 0) {
- X print "All tests successful.\n";
- X} else {
- X print "Failed $how_many test", $how_many == 1 ? '' : 's';
- X print " from $failed file", $failed == 1 ? '' : 's', ".\n";
- X}
- X
- X&clean_up;
- Xexit 0; # End of tests
- X
- X#
- X# Subroutines
- X#
- X
- Xsub clean_up {
- X return if $failed || $opt_i; # -i asks for incrementality
- X unlink 'OK';
- X `rm -rf out` if -d 'out';
- X}
- X
- Xsub print {
- X local($dir, $file) = @_;
- X $file =~ s/\.t$//;
- X local($len) = 1 + length($dir) + length($file);
- X print "$dir/$file", '.' x (17 - $len);
- X}
- X
- Xsub num { $a <=> $b; }
- X
- Xsub result {
- X local($test, $output) = @_;
- X local($now) = time;
- X local(@res) = split(/\n/, $output); # Failed test numbers
- X if ($res[0] eq '') {
- X print "FAILED (no test run)\n";
- X ++$failed;
- X } elsif ($res[$#res] == 0 && $#res > 0 && $res[$#res -1] == $#res) {
- X print "FAILED (all tests)\n";
- X ++$failed;
- X $how_many += $#res;
- X } elsif ($res[0] == 0) {
- X print "ok\n";
- X print OK "$test $now\n";
- X } elsif ($res[0] == -1) {
- X print "untested\n";
- X } else {
- X # Program outputs the number of each test failed, and last must be 0
- X local($last) = pop(@res);
- X push(@res, $last) unless $last == 0;
- X local($n) = @res + 0;
- X local($s) = $n == 1 ? '' : 's';
- X print "FAILED ($n test$s:";
- X @res = sort num @res;
- X print ' ', join(',', @res);
- X print " and aborted" unless $last == 0;
- X print ")\n";
- X ++$failed;
- X $how_many += $n;
- X }
- X if ($failed && $opt_s) { # Stop at first error if -s
- X print "Aborted tests.\n";
- X exit 0;
- X }
- X}
- X
- Xsub run {
- X local($dir) = @_;
- X chdir $dir || die "Cannot chdir to $dir: $!\n";
- X local(@files) = <*.t>;
- X local($test);
- X local($output);
- X foreach $file (@files) {
- X &print($dir, $file);
- X $test = "$dir/$file";
- X if ($Ok{$test} >= ((stat($file))[9])) { # Check time stamp
- X print "done\n";
- X next;
- X }
- X $output = `perl $file`;
- X &result($test, $output);
- X &basic_failed if $dir eq 'basic' && $failed;
- X }
- X chdir '..' || die "Cannot chdir back to ..: $!\n";
- X}
- X
- Xsub basic_failed {
- X print "Failed a basic test, cannot continue.\n";
- X unlink 'OK';
- X exit 0;
- X}
- X
- Xsub load_ok {
- X return unless -f 'OK';
- X
- X # Make sure the OK file is up to date, unless -o (outdated)
- X unless ($opt_o) {
- X local($ok_mtime) = (stat('OK'))[9];
- X local($ma_mtime) = (stat("../$mailagent"))[9];
- X local($fi_mtime) = (stat('../filter/filter'))[9];
- X local($restart) = 0;
- X if ($ma_mtime > $ok_mtime) {
- X warn "Mailagent has changed, restarting tests...\n";
- X ++$restart;
- X } elsif ($fi_mtime > $ok_mtime) {
- X warn "Filter has changed, restarting tests...\n";
- X ++$restart;
- X }
- X unlink 'OK' if $restart;
- X }
- X
- X return unless -f 'OK';
- X local($file, $when);
- X open(OK, 'OK') || return;
- X while (<OK>) {
- X chop;
- X ($file, $when) = /^(\S+)\s+(\d+)/;
- X $Ok{$file} = $when if $when;
- X }
- X close OK;
- X
- X}
- X
- END_OF_FILE
- if test 4140 -ne `wc -c <'agent/test/TEST'`; then
- echo shar: \"'agent/test/TEST'\" unpacked with wrong size!
- fi
- chmod +x 'agent/test/TEST'
- # end of 'agent/test/TEST'
- fi
- if test -f 'agent/test/actions' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'agent/test/actions'\"
- else
- echo shar: Extracting \"'agent/test/actions'\" \(4385 characters\)
- sed "s/^X//" >'agent/test/actions' <<'END_OF_FILE'
- Xmaildir = ~;
- X
- XX-Tag: /abort/
- X{
- X ABORT -f;
- X SAVE always;
- X ABORT;
- X SAVE %u.1;
- X}
- X
- XX-Tag: /annotate/
- X{
- X ANNOTATE X-Anno-1: first;
- X ANNOTATE X-Anno-2 second;
- X ANNOTATE X-Anno-3;
- X ANNOTATE -d X-Anno-Error;
- X ANNOTATE -d X-Anno-4 fourth;
- X}
- X
- XX-Tag: /assign #1/,
- XTo: /^(\w+)@/
- X{
- X ASSIGN ram %1;
- X ASSIGN other try;
- X ASSIGN final '%#other.2';
- X ASSIGN :ram 1 + 2;
- X RUN /bin/echo '%#ram,%#other,%#final' > output';
- X}
- X
- XX-Tag: /assign #2/
- X{
- X ASSIGN :ram %#:ram + 4;
- X ASSIGN other '1+2';
- X ASSIGN final %#other + 4;
- X RUN /bin/echo '%#:ram,%#other,%#final' > output';
- X}
- X
- XX-Tag: /back/
- X{
- X BACK RUN ~/pgm;
- X}
- X
- XX-Tag: /begin/
- X{
- X BEGIN ONE;
- X BEGIN TWO;
- X REJECT;
- X}
- X
- X<ONE> { SAVE one };
- X<ONE,TWO,THREE> { SAVE two; BEGIN THREE; REJECT };
- X<THREE> { SAVE three };
- X
- XX-Tag: /delete/ { DELETE };
- X
- XX-Tag: /feed/
- X{
- X FEED grep -v To:;
- X SAVE ok;
- X REJECT;
- X}
- X
- XX-Tag: /feed/, To: ram { SAVE no_resync };
- X
- XX-Tag: /give/ { GIVE wc > output };
- X
- XX-Tag: /keep/
- X{
- X KEEP From: To Subject X-None X-Long-Line;
- X KEEP To Subject X-Long-Line From X-None;
- X KEEP X-Long-Line: X-None: To: Subject: From:;
- X SAVE ok;
- X REJECT;
- X}
- XX-Tag: /keep/, To: ram { SAVE no_resync };
- X
- XX-Tag: /nop/
- X{
- X NOP;
- X DELETE;
- X}
- X
- XX-Tag: /once/
- X{
- X ONCE (ram,tag,1w) SAVE one;
- X ONCE (ram,tag,1w) SAVE two;
- X ONCE (mars,tag,1w) SAVE three;
- X ONCE (other,tag,0m) SAVE four;
- X}
- X
- XX-Tag: /pass/
- X{
- X PASS grep -v and;
- X SAVE output;
- X}
- X
- XX-Tag: /perl/ { REJECT PERL };
- X<PERL> { PERL perl.1; SAVE never };
- X<PERL> { PERL perl.2 'arg 1' "arg 2"; SAVE never };
- X<PERL> { PERL perl.1; SAVE never };
- X<PERL> { PERL no_such_file; ABORT -f; SAVE never };
- X
- XX-Tag: /pipe/ { PIPE wc > output };
- X
- XX-Tag: /purify/
- X{
- X PURIFY grep -v Subject:;
- X SAVE output;
- X}
- X
- XX-Tag: /queue/ { QUEUE; QUEUE; QUEUE; QUEUE };
- X
- XX-Tag: /record #1/ { RECORD; SAVE %u.1 };
- XX-Tag: /record #1/ { SAVE %u.1 };
- X<_SEEN_> X-Tag: /record #1/ { SAVE %u.2 };
- X<RECORD> X-Tag: /record #2/ { SAVE %u.3 };
- XX-Tag: /record #2/ { RECORD -r RECORD; SAVE %u.1 };
- XX-Tag: /record #3/ { RECORD -a; SAVE %u.1 };
- XX-Tag: /record #4/ { RECORD -c; REJECT -f RECORD; SAVE %u.1 };
- X<RECORD> X-Tag: /record #4/ { SAVE %u.2 };
- X
- XX-Tag: /reject/ { REJECT REJ; SAVE %u.1 };
- X<REJ> X-Tag: /reject/ { SAVE always; REJECT -t REJ; SAVE never };
- X
- X<INITIAL> X-Tag: /restart/ { RESTART -t RES; SAVE %u.1; REJECT };
- X<RES> X-Tag: /restart/ { RESTART no_such_mode; SAVE never };
- X
- XX-Tag: /resync/,
- XTo: ram
- X{
- X PURIFY grep -v To:;
- X RESYNC;
- X REJECT;
- X}
- X
- XX-Tag: /resync/, To: ram { SAVE %u.1 };
- XX-Tag: /resync/ { SAVE output };
- X
- XX-Tag: /run/ { RUN /bin/echo Works. > ok; DELETE };
- X
- XX-Tag: /save #1/ { SAVE mbox };
- XX-Tag: /save #2/ { SAVE path/another/third/mbox };
- X
- XX-Tag: /select/
- X{
- X SELECT (Jan 2 1970 .. Jan 1 2001) SAVE one;
- X SELECT (last month .. last minute) SAVE two;
- X SELECT (last minute .. next minute) SAVE three;
- X SELECT (now - 10 seconds .. now + 5 minutes) SAVE four;
- X SELECT (Jan 1 2001 .. Jan 2 1970) SAVE five;
- X}
- X
- XX-Tag: /unknown #1/ { unknown_command; DELETE };
- XX-Tag: /unknown #2/ { DELETE; unknown_command };
- X
- XX-Tag: /split #1/ { SPLIT here; SAVE here };
- XX-Tag: /split #2/ { SPLIT -ida here };
- XX-Tag: /split #3/ { SPLIT -iew here };
- XX-Tag: /split #4/ { SPLIT -iew };
- XX-Tag: /split #5/ { SPLIT -iew here };
- XX-Tag: /digest/ { SAVE here };
- X
- XX-Tag: /store #1/ { STORE mbox };
- XX-Tag: /store #2/ { STORE path/another/third/mbox };
- X
- XX-Tag: /strip/
- X{
- X STRIP X-Long-Line: X-None: Received:;
- X STRIP Received X-Long-Line;
- X SAVE ok;
- X REJECT;
- X}
- XX-Tag: /strip/, To: ram { SAVE no_resync };
- X
- XX-Tag: /subst/,
- XTo: /(.*)/
- X{
- X SUBST 1 /com/fr/g;
- X ASSIGN subject %[Subject];
- X ASSIGN :persistent '%#subject';
- X SUBST #subject /^Re:\s+//;
- X SUBST #:persistent /^Re:\s+//;
- X RUN /bin/echo '%1,%#subject,%#:persistent' >output;
- X DELETE;
- X}
- X
- XX-Tag: /tr/,
- XTo: /(.*)/
- X{
- X TR 1 /a-z/A-Z/;
- X ASSIGN subject %[Subject];
- X ASSIGN :persistent '%#subject';
- X TR #subject /ice/ICE/;
- X TR #:persistent /ice/ICE/;
- X RUN /bin/echo '%1,%#subject,%#:persistent' >output;
- X DELETE;
- X}
- X
- XX-Tag: /unique #1/ { UNIQUE; SAVE %u.1 };
- X<_SEEN_> X-Tag: /unique #1/ { SAVE %u.1 };
- XX-Tag: /unique #1/ { SAVE %u.2 };
- X<UNIQUE> X-Tag: /unique #2/ { SAVE %u.3 };
- XX-Tag: /unique #2/ { UNIQUE -r UNIQUE; SAVE %u.1 };
- XX-Tag: /unique #3/ { UNIQUE -a; SAVE %u.1 };
- XX-Tag: /unique #4/ { UNIQUE -c; REJECT -f UNIQUE; SAVE %u.1 };
- X<UNIQUE> X-Tag: /unique #4/ { SAVE %u.2 };
- X
- XX-Tag: /write #1/ { WRITE mbox };
- XX-Tag: /write #2/ { WRITE path/another/third/mbox };
- X
- END_OF_FILE
- if test 4385 -ne `wc -c <'agent/test/actions'`; then
- echo shar: \"'agent/test/actions'\" unpacked with wrong size!
- fi
- # end of 'agent/test/actions'
- fi
- echo shar: End of archive 13 \(of 17\).
- cp /dev/null ark13isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 17 archives.
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still must unpack the following archives:
- echo " " ${MISSING}
- fi
- exit 0
- exit 0 # Just in case...
-