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

  1. Newsgroups: comp.sources.misc
  2. From: Raphael Manfredi <ram@acri.fr>
  3. Subject: v41i016:  mailagent - Flexible mail filtering and processing package, v3.0, Part16/26
  4. Message-ID: <1993Dec3.213249.22396@sparky.sterling.com>
  5. X-Md4-Signature: 70f1f5b8185230e1ae8fd6cf2430e6c8
  6. Sender: kent@sparky.sterling.com (Kent Landfield)
  7. Organization: Advanced Computer Research Institute, Lyon, France.
  8. Date: Fri, 3 Dec 1993 21:32:49 GMT
  9. Approved: kent@sparky.sterling.com
  10.  
  11. Submitted-by: Raphael Manfredi <ram@acri.fr>
  12. Posting-number: Volume 41, Issue 16
  13. Archive-name: mailagent/part16
  14. Environment: UNIX, Perl
  15. Supersedes: mailagent: Volume 33, Issue 93-109
  16.  
  17. #! /bin/sh
  18. # This is a shell archive.  Remove anything before this line, then feed it
  19. # into a shell via "sh file" or similar.  To overwrite existing files,
  20. # type "sh file -c".
  21. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  22. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  23. # Contents:  agent/Makefile.SH agent/files/filter.sh
  24. #   agent/pl/compress.pl agent/pl/hook.pl agent/pl/macros.pl
  25. #   agent/pl/parse.pl agent/test/cmd/split.t misc/shell/server.cf
  26. # Wrapped by ram@soft208 on Mon Nov 29 16:49:57 1993
  27. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  28. echo If this archive is complete, you will see the following message:
  29. echo '          "shar: End of archive 16 (of 26)."'
  30. if test -f 'agent/Makefile.SH' -a "${1}" != "-c" ; then 
  31.   echo shar: Will not clobber existing file \"'agent/Makefile.SH'\"
  32. else
  33.   echo shar: Extracting \"'agent/Makefile.SH'\" \(6989 characters\)
  34.   sed "s/^X//" >'agent/Makefile.SH' <<'END_OF_FILE'
  35. X: Makefile.SH generated from Jmake.tmpl and Jmakefile [jmake 3.0 PL14]
  36. X: $X-Id: Jmake.tmpl,v 3.0.1.1 1993/08/20 07:36:36 ram Exp ram $
  37. X
  38. Xcase $CONFIG in
  39. X'')
  40. X    if test -f config.sh; then TOP=.;
  41. X    elif test -f ../config.sh; then TOP=..;
  42. X    elif test -f ../../config.sh; then TOP=../..;
  43. X    elif test -f ../../../config.sh; then TOP=../../..;
  44. X    elif test -f ../../../../config.sh; then TOP=../../../..;
  45. X    else
  46. X        echo "Can't find config.sh."; exit 1
  47. X    fi
  48. X    . $TOP/config.sh
  49. X    ;;
  50. Xesac
  51. Xcase "$0" in
  52. X*/*) cd `expr X$0 : 'X\(.*\)/'` ;;
  53. Xesac
  54. XCURRENT=agent
  55. XDIR=`echo $CURRENT/ | sed -e 's/\.\///g'`
  56. Xecho "Extracting ${DIR}Makefile (with variable substitutions)"
  57. XDATE=`date`
  58. X$spitshell >Makefile <<!GROK!THIS!
  59. X########################################################################
  60. X# Makefile generated from Makefile.SH on $DATE
  61. X
  62. XSHELL = /bin/sh
  63. XJMAKE = jmake
  64. XTOP = ..
  65. XCURRENT = $CURRENT
  66. XDIR = $DIR
  67. XINSTALL = ../install
  68. X
  69. X########################################################################
  70. X# Parameters set by Configure -- edit config.sh if changes are needed
  71. X
  72. XBINDIR = $installbin
  73. XCTAGS = ctags
  74. XL = $manext
  75. XMANSRC = $installmansrc
  76. XMAKE = make
  77. XMKDEP = $mkdep \$(DPFLAGS) --
  78. XMV = $mv
  79. XRM = $rm -f
  80. XSCRIPTDIR = $installscript
  81. XSED = $sed
  82. X
  83. X########################################################################
  84. X# Automatically generated parameters -- do not edit
  85. X
  86. XSUBDIRS = files filter man test
  87. XSCRIPTS =  \$(BIN)
  88. X
  89. X!GROK!THIS!
  90. X$spitshell >>Makefile <<'!NO!SUBS!'
  91. X########################################################################
  92. X# Jmake rules for building libraries, programs, scripts, and data files
  93. X# $X-Id: Jmake.rules,v 3.0 1993/08/18 12:04:14 ram Exp ram $
  94. X
  95. X########################################################################
  96. X# Force 'make depend' to be performed first -- do not edit
  97. X
  98. X.FORCE_DEPEND::
  99. X
  100. Xall:: .FORCE_DEPEND
  101. X
  102. X########################################################################
  103. X# Start of Jmakefile
  104. X
  105. X# $X-Id: Jmakefile,v 2.9.1.2 92/08/26 12:33:22 ram Exp $
  106. X#
  107. X#  Copyright (c) 1990-1993, Raphael Manfredi
  108. X#  
  109. X#  You may redistribute only under the terms of the Artistic License,
  110. X#  as specified in the README file that comes with the distribution.
  111. X#  You may reuse parts of this distribution only within the terms of
  112. X#  that same Artistic License; a copy of which may be found at the root
  113. X#  of the source tree for mailagent 3.0.
  114. X#
  115. X# $X-Log$
  116. X
  117. XBIN = mailpatch mailhelp maillist maildist package
  118. X
  119. Xall:: $(BIN)
  120. X
  121. Xlocal_realclean::
  122. X    $(RM) $(BIN)
  123. X
  124. Xmailpatch: mailpatch.SH
  125. X    /bin/sh mailpatch.SH
  126. X
  127. Xmailhelp: mailhelp.SH
  128. X    /bin/sh mailhelp.SH
  129. X
  130. Xmaillist: maillist.SH
  131. X    /bin/sh maillist.SH
  132. X
  133. Xmaildist: maildist.SH
  134. X    /bin/sh maildist.SH
  135. X
  136. Xpackage: package.SH
  137. X    /bin/sh package.SH
  138. X
  139. X
  140. Xinstall:: $(SCRIPTS) $(LSCRIPTS)
  141. X    @for file in $(SCRIPTS) $(LSCRIPTS); do \
  142. X        case '${MFLAGS}' in *[i]*) set +e;; esac; \
  143. X        (set -x; $(INSTALL) -c -m 555 $$file $(SCRIPTDIR)); \
  144. X    done
  145. X
  146. Xdeinstall::
  147. X    @for file in $(SCRIPTS) $(LSCRIPTS); do \
  148. X        case '${MFLAGS}' in *[i]*) set +e;; esac; \
  149. X        (set -x; $(RM) $(SCRIPTDIR)/$$file); \
  150. X    done
  151. X
  152. X
  153. Xall:: magent
  154. X
  155. Xlocal_realclean::
  156. X    $(RM) magent
  157. X
  158. Xmagent: magent.SH
  159. X    /bin/sh magent.SH
  160. X
  161. X
  162. Xall:: mailagent
  163. X
  164. Xlocal_realclean::
  165. X    $(RM) mailagent
  166. Xmailagent: magent
  167. X    perl $(TOP)/bin/perload -o magent > $@
  168. X    chmod +rx $@
  169. X
  170. Xinstall:: mailagent
  171. X    $(INSTALL) -c -m 555  mailagent $(BINDIR)
  172. X
  173. Xdeinstall::
  174. X    $(RM) $(BINDIR)/mailagent
  175. X
  176. Xdepend::
  177. X    @case '${MFLAGS}' in *[ik]*) set +e;; esac; \
  178. X    for i in filter ;\
  179. X    do \
  180. X        (cd $$i ; echo "Depending" "in $(DIR)$$i..."; \
  181. X            $(MAKE) $(MFLAGS)  depend); \
  182. X    done
  183. X
  184. XBINSH = \
  185. X    mailpatch.SH \
  186. X    mailhelp.SH \
  187. X    maillist.SH \
  188. X    maildist.SH \
  189. X    package.SH \
  190. X    magent.SH 
  191. X
  192. Xdepend::
  193. X    ($(SED) '/^# DO NOT DELETE/q' Makefile && \
  194. X    grep '^\$$grep' $(BINSH) | \
  195. X    $(SED) -e "s/^.*' \([^ ]*\) >>\(.*\)/\2: \1/" \
  196. X    ) > Makefile.new
  197. X    cp Makefile Makefile.bak
  198. X    cp Makefile.new Makefile
  199. X    $(RM) Makefile.new
  200. X
  201. X########################################################################
  202. X# Common rules for all Makefiles -- do not edit
  203. X
  204. Xemptyrule::
  205. X
  206. Xclean: sub_clean local_clean
  207. Xrealclean: sub_realclean local_realclean
  208. Xclobber: sub_clobber local_clobber
  209. X
  210. Xlocal_clean::
  211. X    $(RM) core *~ *.o
  212. X
  213. Xlocal_realclean:: local_clean
  214. X
  215. Xlocal_clobber:: local_realclean
  216. X    $(RM) Makefile config.sh
  217. X
  218. XMakefile.SH: Jmakefile
  219. X    -@if test -f $(TOP)/.package; then \
  220. X        if test -f Makefile.SH; then \
  221. X            echo "    $(RM) Makefile.SH~; $(MV) Makefile.SH Makefile.SH~"; \
  222. X            $(RM) Makefile.SH~; $(MV) Makefile.SH Makefile.SH~; \
  223. X        fi; \
  224. X        echo "    $(JMAKE) -DTOPDIR=$(TOP) -DCURDIR=$(CURRENT)" ; \
  225. X        $(JMAKE) -DTOPDIR=$(TOP) -DCURDIR=$(CURRENT) ; \
  226. X    else touch $@; exit 0; fi
  227. X
  228. XMakefile: Makefile.SH
  229. X    /bin/sh Makefile.SH
  230. X
  231. Xtags::
  232. X    $(CTAGS) -w *.[ch]
  233. X    $(CTAGS) -xw *.[ch] > tags
  234. X
  235. Xlocal_clobber::
  236. X    $(RM) tags
  237. X
  238. X########################################################################
  239. X# Rules for building in sub-directories -- do not edit
  240. X
  241. Xsubdirs:
  242. X    @case '${MFLAGS}' in *[ik]*) set +e;; esac; \
  243. X    for i in $(SUBDIRS) ;\
  244. X    do \
  245. X        (cd $$i ; echo $(VERB) "in $(DIR)$$i..."; \
  246. X            $(MAKE) $(MFLAGS) $(FLAGS) $(TARGET)); \
  247. X    done
  248. X
  249. Xinstall::
  250. X    @$(MAKE) subdirs TARGET=install VERB="Installing" FLAGS=
  251. X
  252. Xdeinstall::
  253. X    @$(MAKE) subdirs TARGET=deinstall VERB="Deinstalling" FLAGS=
  254. X
  255. Xinstall.man::
  256. X    @$(MAKE) subdirs TARGET=install.man VERB="Installing man pages" FLAGS=
  257. X
  258. Xdeinstall.man::
  259. X    @$(MAKE) subdirs TARGET=deinstall.man VERB="Deinstalling man pages" FLAGS=
  260. X
  261. Xsub_clean::
  262. X    @$(MAKE) subdirs TARGET=clean VERB="Cleaning" FLAGS=
  263. X    @echo "Back to $(CURRENT) for "clean...
  264. X
  265. Xsub_realclean::
  266. X    @$(MAKE) subdirs TARGET=realclean VERB="Real cleaning" FLAGS=
  267. X    @echo "Back to $(CURRENT) for "realclean...
  268. X
  269. Xsub_clobber::
  270. X    @$(MAKE) subdirs TARGET=clobber VERB="Clobbering" FLAGS=
  271. X    @echo "Back to $(CURRENT) for "clobber...
  272. X
  273. Xtag::
  274. X    @case '${MFLAGS}' in *[ik]*) set +e;; esac; \
  275. X    for i in $(SUBDIRS) ;\
  276. X    do \
  277. X        (cd $$i ; echo "Tagging" "in $(DIR)$$i..."; \
  278. X            $(MAKE) $(MFLAGS)  tag); \
  279. X    done
  280. X
  281. XMakefiles::
  282. X    @case '${MFLAGS}' in *[ik]*) set +e;; esac; \
  283. X    for i in $(SUBDIRS);\
  284. X    do \
  285. X        echo "Making "Makefiles" in $(DIR)$$i..."; \
  286. X        (cd $$i || exit 1; \
  287. X        if test ! -f Makefile; then /bin/sh Makefile.SH; fi; \
  288. X        $(MAKE) $(MFLAGS) Makefiles) \
  289. X    done
  290. X
  291. XMakefiles.SH:: Makefile.SH
  292. X    @case '${MFLAGS}' in *[ik]*) set +e;; esac; \
  293. X    for i in $(SUBDIRS);\
  294. X    do \
  295. X        case "$(DIR)$$i/" in \
  296. X        */*/*/*/) newtop=../../../..;; \
  297. X        */*/*/) newtop=../../..;; \
  298. X        */*/) newtop=../..;; \
  299. X        */) newtop=..;; \
  300. X        esac; \
  301. X        case "$(TOP)" in \
  302. X        /*) newtop="$(TOP)" ;; \
  303. X        esac; \
  304. X        echo "Making Makefiles.SH in $(DIR)$$i..."; \
  305. X        (cd $$i || exit 1; $(MAKE) $(MFLAGS) -f ../Makefile \
  306. X        Makefile TOP=$$newtop CURRENT=$(DIR)$$i;\
  307. X        $(MAKE) $(MFLAGS) Makefiles.SH) \
  308. X    done
  309. X
  310. Xall::
  311. X    @$(MAKE) subdirs TARGET=all VERB="Making all" FLAGS=
  312. X
  313. X########################################################################
  314. X# Dependencies generated by make depend
  315. X# DO NOT DELETE THIS LINE -- make depend relies on it
  316. X
  317. X# Put nothing here or make depend will gobble it up
  318. X.FORCE_DEPEND::
  319. X    @echo "You must run 'make depend' in $(TOP) first."; exit 1
  320. X!NO!SUBS!
  321. Xchmod 644 Makefile
  322. X$eunicefix Makefile
  323. X
  324. END_OF_FILE
  325.   if test 6989 -ne `wc -c <'agent/Makefile.SH'`; then
  326.     echo shar: \"'agent/Makefile.SH'\" unpacked with wrong size!
  327.   fi
  328.   chmod +x 'agent/Makefile.SH'
  329.   # end of 'agent/Makefile.SH'
  330. fi
  331. if test -f 'agent/files/filter.sh' -a "${1}" != "-c" ; then 
  332.   echo shar: Will not clobber existing file \"'agent/files/filter.sh'\"
  333. else
  334.   echo shar: Extracting \"'agent/files/filter.sh'\" \(7691 characters\)
  335.   sed "s/^X//" >'agent/files/filter.sh' <<'END_OF_FILE'
  336. X#!/bin/sh
  337. X
  338. X# $Id: filter.sh,v 3.0 1993/11/29 13:47:51 ram Exp ram $
  339. X#
  340. X#  Copyright (c) 1990-1993, Raphael Manfredi
  341. X#  
  342. X#  You may redistribute only under the terms of the Artistic License,
  343. X#  as specified in the README file that comes with the distribution.
  344. X#  You may reuse parts of this distribution only within the terms of
  345. X#  that same Artistic License; a copy of which may be found at the root
  346. X#  of the source tree for mailagent 3.0.
  347. X#
  348. X# $Log: filter.sh,v $
  349. X# Revision 3.0  1993/11/29  13:47:51  ram
  350. X# Baseline for mailagent 3.0 netwide release.
  351. X#
  352. X
  353. X# You'll have to delete comments by yourself if your shell doesn't grok them
  354. X
  355. X# You should install a .forward in your home directory to activate the
  356. X# process (sendmail must be used as a MTA). Mine looks like this:
  357. X#    "|exec /users/ram/mail/filter >>/users/ram/.bak 2>&1"
  358. X
  359. X# Variable HOME *must* correctly be set to your home directory
  360. XHOME=/york/ram
  361. Xexport HOME
  362. X
  363. X# The PATH variable must also correctly be set. This variable will be
  364. X# used by all the mailagent-related programs. If you have chosen to put
  365. X# the mailagent scripts in a dedicated directory (e.g. $HOME/mailagent),
  366. X# be sure to put that directory in the PATH variable.
  367. X# The mailagent scripts could also have been stored in a directory like
  368. X# /usr/local/scripts by your system administrator, because each user does
  369. X# not need to have a private copy of theese scrips.
  370. XPATH="/bin:/usr/bin:/usr/ucb:$HOME/bin/mailagent:$HOME/bin"
  371. X
  372. X# The following will set the right path for some architecture-specific
  373. X# directories. For instance, if you have your home directory viewed on
  374. X# some different machines (e.g. it is NFS-mounted), then you must be
  375. X# sure the mailagent will be invoked with the right executables.
  376. XHOST=`(uname -n || hostname) 2>/dev/null`
  377. Xcase "$HOST" in
  378. Xyork) PATH="$HOME/bin/rs2030:$PATH" ;;
  379. Xeiffel) PATH="/base/common/sun4/bin:$PATH" ;;
  380. X*) ;;
  381. Xesac
  382. Xexport PATH
  383. X
  384. X# The TZ may not correctly be set when sendmail is invoking the filter, hence
  385. X# funny date could appear in the log message (from GMT zone usually).
  386. XTZ='PST8PDT'
  387. Xexport TZ
  388. X
  389. X# You should not have to edit below this line
  390. X
  391. X# This variable, when eval'ed, adds a log message at the end of the log file
  392. X# if any. Assumes the ~/.mailagent file was successfully parsed.
  393. Xaddlog='umask 077; if test -f $logdir/$log;
  394. Xthen /bin/echo "`date \"+%y/%m/%d %H:%M:%S\"` filter[$$]: $1" >> $logdir/$log;
  395. Xelse echo "`date \"+%y/%m/%d %H:%M:%S\"` filter[$$]: $1";
  396. Xfi; umask 277
  397. X'
  398. X
  399. X# This variable, when eval'ed, dumps the message on stdout. For this
  400. X# reason, error messages should be redirected into a file.
  401. Xemergency='echo "*** Could not process the following ($1) ***";
  402. Xcat $temp;
  403. Xecho "----------- `date` -----------";
  404. Xset "FATAL $1";
  405. Xeval $addlog;
  406. Xrm -f $spool/filter.lock $torm
  407. X'
  408. X
  409. X# This is for safety reasons (mailagent may abort suddenly). Save the
  410. X# whole mail in a temporary file, which has very restrictive permissions
  411. X# (prevents unwanted removal). This will be eventually moved to the
  412. X# mailagent's queue if we can locate it.
  413. Xumask 277
  414. Xtemp=/tmp/Fml$$
  415. Xtorm="$temp"
  416. X
  417. X# The magic number '74' is EX_IOERR as understood by sendmail and means that
  418. X# an I/O error occurred. The mail is left in sendmail's queue. I expect "cat"
  419. X# to give a meaningful exit code.
  420. Xcat > $temp || exit 74
  421. X
  422. X# The following is done in a subshell put in background, so that this
  423. X# process can exit with a zero status immediately, which will make
  424. X# sendmail think that the delivery was successful. Hopefully we can
  425. X# do our own error recovery now.
  426. X
  427. X(
  428. X# Script used to save the processed mail in an emergency situation
  429. Xsaver='umask 077; if (cat $temp; echo ""; echo "") >> $HOME/mbox.filter; then
  430. X    set "DUMPED in ~/mbox.filter"; eval $addlog; rm -f $torm; else
  431. X    set "unable to dump in ~/mbox.filter"; eval $emergency;
  432. Xfi'
  433. X
  434. X# Set a trap in case of interruption. Mail will be dumped in ~/mbox.filter
  435. Xtrap 'eval $saver; exit 0' 1 2 3 15
  436. X
  437. X# Look for the ~/.mailagent file, exit if none found
  438. Xif test ! -f $HOME/.mailagent; then
  439. X    set 'FATAL no ~/.mailagent'
  440. X    eval $addlog
  441. X    eval $saver
  442. X    exit 0
  443. Xfi
  444. X
  445. X# Parse ~/.mailagent to get the queue location
  446. Xset X `<$HOME/.mailagent sed -n \
  447. X    -e '/^[     ]*#/d' \
  448. X    -e 's/[     ]*#/#/' \
  449. X    -e 's/^[     ]*\([^     :\/]*\)[     ]*:[     ]*\([^#]*\).*/\1="\2";/p'`
  450. Xshift
  451. X
  452. X# Deal with possible white spaces in variables
  453. Xcmd=''
  454. Xfor line in $*; do
  455. X    cmd="$cmd$line"
  456. Xdone
  457. Xcmd=`echo $cmd | sed -e "s|~|$HOME|g"`
  458. Xeval $cmd
  459. X
  460. X# It would be too hazardous to continue without a valid queue directory
  461. Xif test ! -d "$queue"; then
  462. X    set 'FATAL no valid queue directory'
  463. X    eval $addlog
  464. X    eval $saver
  465. X    exit 0
  466. Xfi
  467. X
  468. X# If there is already a filter.lock file, then we set busy to true. Otherwise,
  469. X# we create the lock file. Note that this scheme is a little lousy (race
  470. X# conditions may occur), but that's not really important because the mailagent
  471. X# will do its own tests with the perl.lock file.The motivation here is to avoid
  472. X# a myriad of filter+perl processes spawned when a lot of mail is delivered
  473. X# via SMTP (for instance after a uucp connection).
  474. Xbusy=''
  475. Xif test -f $spool/filter.lock; then
  476. X    busy='true'
  477. Xelse
  478. X    # Race condition may (and will) occur, but the permissions are kept by 'cp',
  479. X    # so the following will not raise any error message.
  480. X    cp /dev/null $spool/filter.lock >/dev/null 2>&1 || busy='true'
  481. Xfi
  482. X
  483. X# Copy tmp file to the queue directory and call the mailagent. If the file
  484. X# already exists (very unlikely, but...), we append a 'b' for bis.
  485. Xqtemp=$queue/qm$$
  486. Xtqtemp=$queue/Tqm$$
  487. Xif test -f $qtemp; then
  488. X    qtemp=$queue/qmb$$
  489. X    tqtemp=$queue/Tqmb$$
  490. Xfi
  491. X
  492. X# Do not write in a 'qm' file directly, or the mailagent might start
  493. X# its processing on an incomplete file.
  494. Xif cp $temp $tqtemp; then
  495. X    mv $tqtemp $qtemp
  496. X    if test x = "x$busy"; then
  497. X        sleep 60
  498. X        if perl -S mailagent $qtemp; then
  499. X            rm -f $temp $qtemp $spool/filter.lock
  500. X            exit 0
  501. X        fi
  502. X    fi
  503. Xelse
  504. X    set 'ERROR unable to queue mail before processing'
  505. X    eval $addlog
  506. X    if test x = "x$busy"; then
  507. X        sleep 60
  508. X        if perl -S mailagent $temp; then
  509. X            rm -f $temp $spool/filter.lock
  510. X            exit 0
  511. X        fi
  512. X    fi
  513. Xfi
  514. X
  515. X# We come here only if the mailagent failed its processing. The unprocessed
  516. X# mail either left in the queue or is given a meaningful name.
  517. Xif cmp $temp $qtemp >/dev/null 2>&1; then
  518. X    base=`echo $qtemp | sed -e 's/.*\/\(.*\)/\1/'`
  519. X    if test x = "x$busy"; then
  520. X        set "ERROR mailagent failed, [$base] left in queue"
  521. X        rm -f $spool/filter.lock
  522. X    else
  523. X        # Make file a fm* one, so that it will get processed immediately by
  524. X        # the main mailagent when it is ready to deal with the queue.
  525. X        fmbase=`echo $base | sed -e 's/qm/fmx/'`
  526. X        if mv $queue/$base $queue/$fmbase; then
  527. X            set "NOTICE filter busy, [$fmbase] left in queue"
  528. X        else
  529. X            set "NOTICE filter busy, [$base] left in queue"
  530. X        fi
  531. X    fi
  532. X    eval $addlog
  533. X    rm -f $temp
  534. X    exit 0
  535. Xfi
  536. X
  537. X# Change the name of the temporary file.
  538. Xuser=`(logname || whoami) 2>/dev/null`
  539. Xtmpdir=`echo $temp | sed -e 's/\(.*\)\/.*/\1/'`
  540. Xmv $temp $tmpdir/$user.$$
  541. Xtemp="$tmpdir/$user.$$"
  542. Xif test x = "x$busy"; then
  543. X    set "ERROR mailagent failed, mail left in $temp"
  544. X    rm -f $spool/filter.lock
  545. Xelse
  546. X    set "WARNING filter busy, mail left in $temp"
  547. Xfi
  548. Xeval $addlog
  549. X
  550. X# Give the mailagent a clue as to where the mail has been stored. As this
  551. X# should be very very unlikely, no test is done to see whether a mailagent
  552. X# is already updating the agent.wait file. The worse that could result from
  553. X# this shallowness would be having an unprocessed mail.
  554. Xumask 077
  555. Xset 'WARNING mailagent ignores where mail was left'
  556. Xif /bin/echo "$temp" >> $queue/agent.wait; then
  557. X    if grep "$temp" $queue/agent.wait >/dev/null 2>&1; then
  558. X        set "NOTICE $temp memorized into agent.wait"
  559. X    fi
  560. Xfi
  561. Xeval $addlog
  562. Xrm -f $qtemp
  563. X
  564. X# Attempt an emergency saving
  565. Xeval $saver
  566. Xexit 0
  567. X) &
  568. X
  569. X# Delivery was ok -- for sendmail
  570. Xexit 0
  571. END_OF_FILE
  572.   if test 7691 -ne `wc -c <'agent/files/filter.sh'`; then
  573.     echo shar: \"'agent/files/filter.sh'\" unpacked with wrong size!
  574.   fi
  575.   chmod +x 'agent/files/filter.sh'
  576.   # end of 'agent/files/filter.sh'
  577. fi
  578. if test -f 'agent/pl/compress.pl' -a "${1}" != "-c" ; then 
  579.   echo shar: Will not clobber existing file \"'agent/pl/compress.pl'\"
  580. else
  581.   echo shar: Extracting \"'agent/pl/compress.pl'\" \(7102 characters\)
  582.   sed "s/^X//" >'agent/pl/compress.pl' <<'END_OF_FILE'
  583. X;# $Id: compress.pl,v 3.0 1993/11/29 13:48:37 ram Exp ram $
  584. X;#
  585. X;#  Copyright (c) 1990-1993, Raphael Manfredi
  586. X;#  
  587. X;#  You may redistribute only under the terms of the Artistic License,
  588. X;#  as specified in the README file that comes with the distribution.
  589. X;#  You may reuse parts of this distribution only within the terms of
  590. X;#  that same Artistic License; a copy of which may be found at the root
  591. X;#  of the source tree for mailagent 3.0.
  592. X;#
  593. X;# $Log: compress.pl,v $
  594. X;# Revision 3.0  1993/11/29  13:48:37  ram
  595. X;# Baseline for mailagent 3.0 netwide release.
  596. X;#
  597. X;# 
  598. X;# This module handles compressed folders. Each folder specified in the file
  599. X;# 'compress' from the configuration file is candidate for compression checks.
  600. X;# The file specifies folders using shell patterns. If the pattern does not
  601. X;# start with a /, the match is only attempted to the basename of the folder.
  602. X;# 
  603. X;# Folder uncompressed are recompressed only before the mailagent is about
  604. X;# to exit, so that the burden of successive decompressions is avoided should
  605. X;# two or more mails be delivered to the same compressed folder. However, if
  606. X;# there is not enough disk space to hold all the uncompressed folder, the
  607. X;# mailagent will try to recompress them to try to make some room.
  608. X;#
  609. X;# The initial patterns are held in the @compress array, while the compression
  610. X;# status is stored within %compress. The key is the file name, and the value
  611. X;# is 0 if uncompression was attempted but failed somehow so recompression must
  612. X;# not be done, or 1 if uncompression was successful and the folder is flagged
  613. X;# for delayed recompression.
  614. X#
  615. X# Folder compression
  616. X#
  617. X
  618. Xpackage compress;
  619. X
  620. X# Read in the compression file into the @compress array. As usual, shell
  621. X# comments are ignored.
  622. Xsub init {
  623. X    unless (open(COMPRESS, "$cf'compress")) {
  624. X        &'add_log("WARNING cannot open compress file $cf'compress: $!")
  625. X            if $'loglvl > 5;
  626. X        return;
  627. X    }
  628. X    while (<COMPRESS>) {
  629. X        chop;
  630. X        next if /^\s*#/;            # Skip comments
  631. X        next if /^\s*$/;            # And blank lines
  632. X        $_ = &'perl_pattern($_);    # Shell pattern to perl one
  633. X        s/^~/$cf'home/;                # ~ substitution
  634. X        $_ = '.*/'.$_ unless m|^/|;    # Focus on basename unless absolute path
  635. X        push(@compress, $_);        # Record pattern
  636. X    }
  637. X    close COMPRESS;
  638. X}
  639. X
  640. X# Uncompress a folder, and record it in the %compress array for further
  641. X# recompression at the end of the mailagent processing. Return 1 for success.
  642. X# If the $retry parameter is set, other folders will be recompressed should
  643. X# this particular uncompression fail.
  644. Xsub uncompress {
  645. X    local($folder, $retry) = @_;    # Folder to be decompressed
  646. X    return if defined $compress{$folder};    # We already dealt with that folder
  647. X    # Lock folder, in case someone is trying to deliver to the uncompressed
  648. X    # folder while we're decompressing it...
  649. X    if (0 != &'acs_rqst($folder)) {
  650. X        &'add_log("NOTICE unable to lock compressed folder $folder")
  651. X            if $'loglvl > 6;
  652. X        return 0;                # Failure, don't uncompress, sorry
  653. X    }
  654. X    # Make sure there is a .Z file, and that the corresponding folder is not
  655. X    # already present. If there is no .Z file but the folder already exists,
  656. X    # mark it uncompressed.
  657. X    if (-f "$folder.Z") {        # A compressed form exists
  658. X        if (-f $folder) {        # As well as an uncompressed form
  659. X            &'add_log("WARNING both folders $folder and $folder.Z exist")
  660. X                if $'loglvl > 5;
  661. X            &'add_log("NOTICE ignoring compressed file") if $'loglvl > 6;
  662. X            $compress{$folder} = 0;        # Do not recompress it
  663. X            &'free_file($folder);        # Unlock folder
  664. X            return 1;
  665. X        }
  666. X        # Normal case: there is a compressed file and no uncompressed version
  667. X        local($status) = system("uncompress $folder.Z");
  668. X        if ($status) {            # Uncompression failed
  669. X            local($retrying);
  670. X            $retrying = " (retrying)" if $retry;
  671. X            &'add_log("ERROR cannot uncompress $folder$retrying") if $'loglvl;
  672. X            # Maybe there is not enough disk space, and maybe we can get some
  673. X            # by recompressing the folders we have decompressed so far.
  674. X            if ($retry) {                # Attempt is to be retried
  675. X                &recompress;            # Recompress other folders, if any
  676. X                &'free_file($folder);    # Unlock folder
  677. X                return 0;                # And report failure
  678. X            }
  679. X            &'add_log("WARNING $folder present before delivery")
  680. X                if -f $folder && $'loglvl > 5;
  681. X            &'add_log("ERROR original $folder.Z lost")
  682. X                if ! -f "$folder.Z" && $'loglvl;
  683. X            $compress{$folder} = 0;        # Do not recompress it
  684. X        } else {                # Folder should be decompressed
  685. X            if (-f "$folder.Z") {
  686. X                &'add_log("WARNING compressed $folder still present")
  687. X                    if $'loglvl > 5;
  688. X                $compress{$folder} = 0;    # Do not recompress it
  689. X            } else {
  690. X                $compress{$folder} = 1;    # Will be recompressed after delivery
  691. X            }
  692. X            &'add_log("uncompressed $folder") if $'loglvl > 8;
  693. X        }
  694. X    } else {
  695. X        $compress{$folder} = 1;        # Folder will be compressed after creation
  696. X    }
  697. X    &'free_file($folder);    # Unlock folder
  698. X    1;                        # Success
  699. X}
  700. X
  701. X# Compress a folder
  702. Xsub compress {
  703. X    local($folder) = @_;        # Folder to be compressed
  704. X    return unless $compress{$folder};    # Folder not to be recompressed
  705. X    delete $compress{$folder};            # Mark it compressed anyway
  706. X    if (-f "$folder.Z") {        # A compressed form exists
  707. X        &'add_log("ERROR compressed $folder already present") if $'loglvl;
  708. X        return;
  709. X    }
  710. X    if (0 != &'acs_rqst($folder)) {        # Cannot compress if not locked
  711. X        &'add_log("NOTICE $folder locked, skiping compression") if $'loglvl > 6;
  712. X        return;
  713. X    }
  714. X    local($status) = system("compress $folder");
  715. X    if ($status) {
  716. X        &'add_log("ERROR cannot compress $folder") if $'loglvl;
  717. X        if (-f $folder) {
  718. X            unless (unlink "$folder.Z") {
  719. X                &'add_log("ERROR cannot remove $folder.Z: $!") if $'loglvl;
  720. X            } else {
  721. X                &'add_log("NOTICE removing $folder.Z") if $'loglvl > 6;
  722. X            }
  723. X        } else {
  724. X            &'add_log("ERROR original $folder lost") if $'loglvl;
  725. X        }
  726. X    } else {
  727. X        &'add_log("WARNING uncompressed $folder still present")
  728. X            if -f $folder && $'loglvl > 5;
  729. X        &'add_log("compressed $folder") if $'loglvl > 8;
  730. X    }
  731. X    &'free_file($folder);
  732. X}
  733. X
  734. X# Recompress all folders which have been delivered to
  735. Xsub recompress {
  736. X    foreach $file (keys %compress) {
  737. X        &compress($file);
  738. X    }
  739. X}
  740. X
  741. X# Restore uncompressed folder if listed in the compression list
  742. Xsub restore {
  743. X    return unless $cf'compress;        # Do nothing if no compress parameter
  744. X    return unless -s $cf'compress;    # No compress list file, or empty
  745. X    &init unless defined @compress;    # Initialize array only once
  746. X    local($folder) = @_;            # Folder candidate for uncompression
  747. X    &'add_log("candidate folder is $folder") if $'loglvl > 18;
  748. X
  749. X    # Loop over each pattern in the compression file and see if the folder
  750. X    # matches one of them. As soon as one matches, the folder is uncompressed
  751. X    # if necessary and the processing is over.
  752. X    foreach $pattern (@compress) {
  753. X        &'add_log("matching against '$pattern'") if $'loglvl > 19;
  754. X        if ($folder =~ /^$pattern$/) {
  755. X            &'add_log("matched '$pattern'") if $'loglvl > 18;
  756. X            # Give it two shots. The second parameter is a retrying flag.
  757. X            # The difference between the two is that recompression of other
  758. X            # uncompressed folders is attempted the first time if the folder
  759. X            # cannot be uncompressed (assuming low disk space).
  760. X            &uncompress($folder, 0) unless &uncompress($folder, 1);
  761. X            last;
  762. X        }
  763. X    }
  764. X}
  765. X
  766. Xpackage main;
  767. X
  768. END_OF_FILE
  769.   if test 7102 -ne `wc -c <'agent/pl/compress.pl'`; then
  770.     echo shar: \"'agent/pl/compress.pl'\" unpacked with wrong size!
  771.   fi
  772.   # end of 'agent/pl/compress.pl'
  773. fi
  774. if test -f 'agent/pl/hook.pl' -a "${1}" != "-c" ; then 
  775.   echo shar: Will not clobber existing file \"'agent/pl/hook.pl'\"
  776. else
  777.   echo shar: Extracting \"'agent/pl/hook.pl'\" \(7356 characters\)
  778.   sed "s/^X//" >'agent/pl/hook.pl' <<'END_OF_FILE'
  779. X;# $Id: hook.pl,v 3.0 1993/11/29 13:48:51 ram Exp ram $
  780. X;#
  781. X;#  Copyright (c) 1990-1993, Raphael Manfredi
  782. X;#  
  783. X;#  You may redistribute only under the terms of the Artistic License,
  784. X;#  as specified in the README file that comes with the distribution.
  785. X;#  You may reuse parts of this distribution only within the terms of
  786. X;#  that same Artistic License; a copy of which may be found at the root
  787. X;#  of the source tree for mailagent 3.0.
  788. X;#
  789. X;# $Log: hook.pl,v $
  790. X;# Revision 3.0  1993/11/29  13:48:51  ram
  791. X;# Baseline for mailagent 3.0 netwide release.
  792. X;#
  793. X;# 
  794. X;# A mail hook (in the mailagent terminology) is an external file which
  795. X;# transparently influences some of the mailagent actions by injecting user-
  796. X;# defined actions at some well-defined places. Currently, the only hooks
  797. X;# available are executable folders, activated via the SAVE, STORE, and LEAVE
  798. X;# commands.
  799. X;#
  800. X;# The hook_type function parses the top of the hook file, looking for magic
  801. X;# token which will give hints regarding the type of the hook. Then the
  802. X;# corresponding hook function will be called with the file name where the mail
  803. X;# is stored given as first argument (an empty string meaning the mail is to be
  804. X;# fetched from stdin), the second argument being the hook file name.
  805. X;#
  806. X;# Five types of hooks are currently supported:
  807. X;#   - Simple program: the mail is simply fed to the standard input of the
  808. X;#     program. The exit status is propagated to the mailagent.
  809. X;#   - Rule file: the mail is to be re-analyzed according to the new rules
  810. X;#     held in the hook file. The APPLY command is used, and mode is reset to
  811. X;#       the default INITIAL state.
  812. X;#   - Audit script: This is a perl script. Following the spirit of Martin
  813. X;#     Streicher's audit.pl package, some special variables are magically set
  814. X;#     prior to the invocation of script within the special mailhook package,
  815. X;#     in which the script is compiled.
  816. X;#   - Deliver script: Same as an audit script, excepted that the output of the
  817. X;#     script is monitored and taken as mailagent commands, which will then
  818. X;#     be executed on the original message upon completion of the script.
  819. X;#   - Perl script: This is an audit script with full access to the mailagent
  820. X;#     primitives for filtering (same as the ones provided with a PERL command).
  821. X;#
  822. X#
  823. X# Mailhook handling
  824. X#
  825. X
  826. Xpackage hook;
  827. X
  828. X# Hooks constants definitions
  829. Xsub init {
  830. X    $HOOK_UNKNOWN = "hook'unknown";        # Hook type was not recognized
  831. X    $HOOK_PROGRAM = "hook'program";        # Hook is a filter program
  832. X    $HOOK_AUDIT = "hook'audit";            # Hook is an audit-like script
  833. X    $HOOK_DELIVER = "hook'deliver";        # Hook is a deliver-like script
  834. X    $HOOK_RULES = "hook'rules";            # Hook is a rule file
  835. X    $HOOK_PERL = "hook'perl";            # Hook is a perl script
  836. X}
  837. X
  838. X# Deal with the hook
  839. Xsub process {
  840. X    &init unless $init_done++;            # Initialize hook constants
  841. X    local($hook) = @_;
  842. X    local($type) = &type($hook);        # Get hook type
  843. X    &hooking($hook, $type);                # Print log message
  844. X    unless (chdir $cf'home) {
  845. X        &'add_log("WARNING cannot chdir to $cf'home: $!") if $'loglvl > 5;
  846. X    }
  847. X    eval '&$type($hook)';                # Call hook (inside eval to allow die)
  848. X    &'eval_error;                        # Report errors and propagate status
  849. X}
  850. X
  851. X# Determine the nature of the hook. The top 128 bytes are scanned for a magic
  852. X# number starting with #: and followed by some words. The type of the hook
  853. X# is determined by the first word (case insensitively).
  854. Xsub type {
  855. X    local($file) = @_;            # Name of hook file
  856. X    -f "$file" || return $HOOK_UNKNOWN;        
  857. X    -x _ || return $HOOK_UNKNOWN;
  858. X    open(HOOK, $file) || return $HOOK_PROGRAM;
  859. X    local($hook) = ' ' x 128;    # Consider only top 128 bytes
  860. X    sysread(HOOK, $hook, 128);
  861. X    close(HOOK);
  862. X    local($name) = $hook =~ /^#:\s*(\w+)/;
  863. X    $name =~ tr/A-Z/a-z/;
  864. X    return $HOOK_AUDIT if $name eq 'audit';
  865. X    return $HOOK_DELIVER if $name eq 'deliver';
  866. X    return $HOOK_RULES if $name eq 'rules';
  867. X    return $HOOK_PERL if $name eq 'perl';
  868. X    $HOOK_PROGRAM;                # No magic token found
  869. X}
  870. X
  871. X#
  872. X# Hook functions
  873. X#
  874. X
  875. X# The hook file is not valid
  876. Xsub unknown {
  877. X    local($hook) = @_;
  878. X    die("$hook is not a hook file");
  879. X}
  880. X
  881. X# Mail is to be piped to the hook program (on stdin)
  882. Xsub program {
  883. X    local($hook) = @_;
  884. X    &'add_log("hook is a plain program") if $'loglvl > 17;
  885. X    local($failed) = &'shell_command($hook, $'MAIL_INPUT, $'NO_FEEDBACK);
  886. X    die("cannot run $hook") if $failed;
  887. X}
  888. X
  889. X# Mail is to be filetered with rules from hook file
  890. Xsub rules {
  891. X    local($hook) = @_;
  892. X    &'add_log("hook contains mailagent rules") if $'loglvl > 17;
  893. X    local($wmode) = 'INITIAL';        # Force working mode of INITIAL
  894. X    local($failed, $saved) = &'apply($hook);
  895. X    die("cannot apply rules") if $failed;
  896. X    unless ($saved) {
  897. X        &'add_log("NOTICE not saved, leaving in mailbox") if $loglvl > 5;
  898. X        &'xeqte("LEAVE");
  899. X    }
  900. X}
  901. X
  902. X# Mail is to be filtered through a perl script
  903. Xsub perl {
  904. X    local($hook) = @_;
  905. X    &'add_log("hook is a perl script") if $'loglvl > 17;
  906. X    local($failed) = &'run_perl("PERL $hook");
  907. X    die("cannot run perl hook") if $failed;
  908. X}
  909. X
  910. X# Hook is an audit script. Set up a suitable environment and execute the
  911. X# script after having forked a new process. To avoid name clashes, the script
  912. X# is compiled in a dedicated 'mailhook' package and executed.
  913. X# Note: the only difference with the perl hook is that we need to fork an
  914. X# extra process to run the hook, since it might use a plain 'exit', which would
  915. X# be desastrous on the mailagent.
  916. Xsub audit {
  917. X    local($hook) = @_;
  918. X    &'add_log("hook is an audit script") if $'loglvl > 17;
  919. X    local($pid) = fork;
  920. X    $pid = -1 unless defined $pid;
  921. X    if ($pid == 0) {                # Child process
  922. X        &initvar('mailhook');        # Initialize special variables
  923. X        &run($hook);                # Load hook and run it
  924. X        exit(0);
  925. X    } elsif ($pid == -1) {
  926. X        &'add_log("ERROR cannot fork: $!") if $'loglvl;
  927. X        die("cannot audit with hook");
  928. X    }
  929. X    # Parent process comes here
  930. X    wait;
  931. X    die("audit hook failed") unless $? == 0;
  932. X}
  933. X
  934. X# A delivery script is about the same as an audit script, except that the
  935. X# output on stdout is monitored and understood as mailagent commands to be
  936. X# executed upon successful return.
  937. Xsub deliver {
  938. X    local($hook) = @_;
  939. X    &'add_log("hook is a deliver script") if $'loglvl > 17;
  940. X    # Fork and let the child do all the work. The parent simply captures the
  941. X    # output from child's stdout.
  942. X    local($pid);
  943. X    $pid = open(HOOK, "-|");    # Implicit fork
  944. X    unless (defined $pid) {
  945. X        &'add_log("ERROR cannot fork: $!") if $'loglvl;
  946. X        die("cannot deliver to hook");
  947. X    }
  948. X    if (0 == $pid) {            # Child process
  949. X        &initvar('mailhook');    # Initialize special variables
  950. X        &run($hook);            # Load hook and run it
  951. X        exit(0);                # Everything went well
  952. X    }
  953. X    # Parent process comes here
  954. X    local($output) = ' ' x (-s HOOK);
  955. X    {
  956. X        local($/) = undef;        # We wish to slurp the whole output
  957. X        $output = <HOOK>;
  958. X    }
  959. X    close HOOK;                    # An implicit wait -- status put in $?
  960. X    unless (0 == $?) {
  961. X        &'add_log("ERROR hook script failed") if $'loglvl;
  962. X        die("non-zero exit status") unless $output;
  963. X        die("commands ignored");
  964. X    }
  965. X    if ($output eq '') {
  966. X        &'add_log("WARNING no commands from delivery hook") if $'loglvl > 5;
  967. X    } else {
  968. X        &main'xeqte($output);    # Run mailagent commands
  969. X    }
  970. X}
  971. X
  972. X# Log hook operation before it happens, as we may well exec() another program.
  973. Xsub hooking {
  974. X    local($hook, $type) = @_;
  975. X    local($home) = $cf'home;
  976. X    $home =~ s/(\W)/\\$1/g;        # Escape possible meta-characters
  977. X    $type =~ s/^hook'//;
  978. X    $hook =~ s/^$home/~/;
  979. X    &'add_log("HOOKING [$'mfile] to $hook ($type)") if $'loglvl > 4;
  980. X}
  981. X
  982. Xpackage main;
  983. X
  984. END_OF_FILE
  985.   if test 7356 -ne `wc -c <'agent/pl/hook.pl'`; then
  986.     echo shar: \"'agent/pl/hook.pl'\" unpacked with wrong size!
  987.   fi
  988.   # end of 'agent/pl/hook.pl'
  989. fi
  990. if test -f 'agent/pl/macros.pl' -a "${1}" != "-c" ; then 
  991.   echo shar: Will not clobber existing file \"'agent/pl/macros.pl'\"
  992. else
  993.   echo shar: Extracting \"'agent/pl/macros.pl'\" \(6718 characters\)
  994.   sed "s/^X//" >'agent/pl/macros.pl' <<'END_OF_FILE'
  995. X;# $Id: macros.pl,v 3.0 1993/11/29 13:48:57 ram Exp ram $
  996. X;#
  997. X;#  Copyright (c) 1990-1993, Raphael Manfredi
  998. X;#  
  999. X;#  You may redistribute only under the terms of the Artistic License,
  1000. X;#  as specified in the README file that comes with the distribution.
  1001. X;#  You may reuse parts of this distribution only within the terms of
  1002. X;#  that same Artistic License; a copy of which may be found at the root
  1003. X;#  of the source tree for mailagent 3.0.
  1004. X;#
  1005. X;# $Log: macros.pl,v $
  1006. X;# Revision 3.0  1993/11/29  13:48:57  ram
  1007. X;# Baseline for mailagent 3.0 netwide release.
  1008. X;#
  1009. X;# 
  1010. X;# Macros:
  1011. X;# %%     A real percent sign
  1012. X;# %A     Sender's main address (host.domain.ct in user@loc.host.domain.ct)
  1013. X;# %C     CPU name, fully qualified with domain name
  1014. X;# %D     Day of the week (0-6)
  1015. X;# %H     Host name (name of the machine on which the mailagent runs)
  1016. X;# %I     Internet domain from sender (domain.ct in user@host.domain.ct)
  1017. X;# %L     Length of the message in bytes (without header)
  1018. X;# %N     Full name of sender (login name if none)
  1019. X;# %O     Organization name from sender address (domain in user@host.domain.ct)
  1020. X;# %R     Subject of orginal message with leading Re: suppressed
  1021. X;# %S     Re: subject of original message
  1022. X;# %T     Time of last modification on mailed file (value taken from $macro_T)
  1023. X;# %U     Full name of the user
  1024. X;# %_     A white space
  1025. X;# %#reg  Value of user-defined variable 'reg'
  1026. X;# %&     List of selectors which incurred match (among regexps ones) 
  1027. X;# %~     A null character
  1028. X;# %1     Value of the corresponding backreference (limited to 99 per rule)
  1029. X;# %d     Day of the month (01-31)
  1030. X;# %f     Contents of the "From:" line, something like %N <%r> or %r (%N)
  1031. X;# %h     Hour of the day (00-23)
  1032. X;# %i     Message ID if available
  1033. X;# %l     Number of lines in the message
  1034. X;# %m     Month of the year (01-12)
  1035. X;# %n     Lower-case login name of sender
  1036. X;# %o     Organization (where mailagent runs)
  1037. X;# %r     Return address of message
  1038. X;# %s     Subject of original message
  1039. X;# %t     Current hour and minute (in HH:MM format)
  1040. X;# %u     Login name of the user
  1041. X;# %y     Year (last two digits)
  1042. X;# %[To]  Value of the field in header (here To:)
  1043. X;# %=var  Value of the configuration variable (from ~/.mailagent)
  1044. X;# %-(x)  User-defined macro (x stands for an arbitrary name)
  1045. X;# %-x    Short-cut for single letter user-defined macros
  1046. X#
  1047. X# Macro handling (system)
  1048. X#
  1049. X
  1050. X# Macros substitutions (in-place)
  1051. Xsub macros_subst {
  1052. X    local(*str) = shift(@_);            # The string
  1053. X    local($_) = $str;                    # Work on a copy
  1054. X    return unless /%/;                    # Return immediately if no macros
  1055. X
  1056. X    local($sender);                            # The from field
  1057. X    local(@from);                            # The rfc-822 parsed from line
  1058. X    $sender = $Header{'From'};                # Header-derived From address
  1059. X    @from = &parse_address($sender);        # Get (address, comment)
  1060. X    local($login) = &login_name($from[0]);    # Keep only login name
  1061. X    local($fullname) = $from[1];            # The comment part of address
  1062. X    $fullname = $login unless $fullname;    # Use login name if no comment part
  1063. X    local($reply_to) = $Header{'Reply-To'}; # Return path derived
  1064. X    local($subject) = $Header{'Subject'};    # Original subject header
  1065. X    $subject =~ s/^\s*Re:\s*(.*)/$1/;        # Strip off leading Re:
  1066. X    $subject = "<empty subject>" unless $subject;
  1067. X    $reply_to = (&parse_address($reply_to))[0];    # Keep only e-mail address
  1068. X
  1069. X    # Time computations
  1070. X    local($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
  1071. X            localtime(time);
  1072. X    $mon = sprintf("%.2d", $mon + 1);
  1073. X    $mday = sprintf("%.2d", $mday);
  1074. X    local($timenow) = sprintf("%.2d:%.2d", $hour, $min);
  1075. X    $hour = sprintf("%.2d", $hour);
  1076. X
  1077. X    # The following dummy block is here only to force perl interpreting
  1078. X    # the $ variables in the substitutions correctly...
  1079. X    if (0) {
  1080. X        $Header{'a'} = 'a';
  1081. X        $Variable{'a'} = 'a';
  1082. X        $Backref[0] = 0;
  1083. X    }
  1084. X
  1085. X    s/%%/##pr##/g;                        # Protect double percent signs
  1086. X    s/%/#%%!/g;                            # Make sure substitutions do not add %
  1087. X    s/#%%!A/¯o'internet/eg;            # Main internet address of sender
  1088. X    s/#%%!d/$mday/g;                    # Day of the month (01-31)
  1089. X    s/#%%!C/&domain_addr/eg;            # CPU name, fully qualified with domain
  1090. X    s/#%%!D/$wday/g;                    # Day of the week (0-6)
  1091. X    s/#%%!f/$Header{'From'}/g;            # The "From:" line
  1092. X    s/#%%!h/$hour/g;                    # Hour of the day (00-23)
  1093. X    s/#%%!H/&myhostname/eg;                # Hostname on which mailagent runs
  1094. X    s/#%%!i/$Header{'Message-Id'}/g;    # Message-Id (null string if none)
  1095. X    s/#%%!I/¯o'domain/eg;            # Internet domain name of sender
  1096. X    s/#%%!l/$Header{'Lines'}/g;            # Number if lines in message
  1097. X    s/#%%!L/$Header{'Length'}/g;        # Length of message, in bytes
  1098. X    s/#%%!m/$mon/g;                        # Month of the year
  1099. X    s/#%%!n/$login/g;                    # Lower-cased login name of sender
  1100. X    s/#%%!N/$fullname/g;                # Full name of sender (login if none)
  1101. X    s/#%%!o/$orgname/g;                    # Organization name
  1102. X    s/#%%!O/¯o'org/eg;                # Organization part of sender's address
  1103. X    s/#%%!r/$reply_to/g;                # Return path of message
  1104. X    s/#%%!R/$subject/g;                    # Subject with leading Re: suppressed
  1105. X    s/#%%!s/$Header{'Subject'}/g;        # Subject of message
  1106. X    s/#%%!S/Re: $Header{'Subject'}/g;    # Re: subject of original message
  1107. X    s/#%%!t/$timenow/g;                    # Current time HH:MM
  1108. X    s/#%%!T/$macro_T/g;                    # Time of last modification on file
  1109. X    s/#%%!u/$cf'user/go;                # User login name (does not change)
  1110. X    s/#%%!U/$cf'name/go;                # User's name (does not change)
  1111. X    s/#%%!y/$year/g;                    # Year (last two digits)
  1112. X    s/#%%!_/ /g;                        # A white space
  1113. X    s/#%%!~//g;                            # A null character
  1114. X    s/#%%!&/$macro_ampersand/g;            # List of matched generic selectors
  1115. X    s/#%%!(\d\d?)/$Backref[$1 - 1]/g;    # A pattern matching backreference
  1116. X    s/#%%!#:(\w+)/&extern'val($1)/eg;    # A persistent user-defined variable
  1117. X    s/#%%!#(\w+)/$Variable{$1}/g;        # A user-defined variable
  1118. X    s/#%%!\[([\w-]+)\]/$Header{$1}/g;    # The %[Field] macro
  1119. X    s/#%%!=(\w+)/eval("\$cf'$1")/ge;    # The %=config_var variable
  1120. X    s/#%%!-([^\s(])/¯o'usr($1)/ge;    # A %-x single letter user macro
  1121. X    s/#%%!-\(([^\s)]+)\)/¯o'usr($1)/ge;    # A %-(complex) user-defined macro
  1122. X    s/#%%!/%/g;                            # Any remaining percent is kept
  1123. X    s/##pr##/%/g;                        # A double percent expands to %
  1124. X    $str = $_;                            # Update string in-place
  1125. X}
  1126. X
  1127. Xpackage macro;
  1128. X
  1129. X# Return the internet information of the From address
  1130. Xsub info {
  1131. X    local($addr) = (&'parse_address($'Header{'From'}))[0];
  1132. X    &'internet_info($addr);
  1133. X}
  1134. X
  1135. X# Return the organization name
  1136. Xsub org {
  1137. X    local($host, $domain, $country) = &info;
  1138. X    $domain;
  1139. X}
  1140. X
  1141. X# Return the domain name
  1142. Xsub domain {
  1143. X    local($host, $domain, $country) = &info;
  1144. X    $domain .'.'. $country;
  1145. X}
  1146. X
  1147. X# Return the qualified internet address
  1148. Xsub internet {
  1149. X    local($host, $domain, $country) = &info;
  1150. X    $host ne '' ? $host .'.'. $domain .'.'. $country : $domain .'.'. $country;
  1151. X}
  1152. X
  1153. X;#
  1154. X;# User-defined macro handled by ¯o'usr, which is defined in the usrmac.pl
  1155. X;# file to emphasize there the link with ¯os_subst.
  1156. X;#
  1157. X
  1158. Xpackage main;
  1159. X
  1160. END_OF_FILE
  1161.   if test 6718 -ne `wc -c <'agent/pl/macros.pl'`; then
  1162.     echo shar: \"'agent/pl/macros.pl'\" unpacked with wrong size!
  1163.   fi
  1164.   # end of 'agent/pl/macros.pl'
  1165. fi
  1166. if test -f 'agent/pl/parse.pl' -a "${1}" != "-c" ; then 
  1167.   echo shar: Will not clobber existing file \"'agent/pl/parse.pl'\"
  1168. else
  1169.   echo shar: Extracting \"'agent/pl/parse.pl'\" \(6649 characters\)
  1170.   sed "s/^X//" >'agent/pl/parse.pl' <<'END_OF_FILE'
  1171. X;# $Id: parse.pl,v 3.0 1993/11/29 13:49:05 ram Exp ram $
  1172. X;#
  1173. X;#  Copyright (c) 1990-1993, Raphael Manfredi
  1174. X;#  
  1175. X;#  You may redistribute only under the terms of the Artistic License,
  1176. X;#  as specified in the README file that comes with the distribution.
  1177. X;#  You may reuse parts of this distribution only within the terms of
  1178. X;#  that same Artistic License; a copy of which may be found at the root
  1179. X;#  of the source tree for mailagent 3.0.
  1180. X;#
  1181. X;# $Log: parse.pl,v $
  1182. X;# Revision 3.0  1993/11/29  13:49:05  ram
  1183. X;# Baseline for mailagent 3.0 netwide release.
  1184. X;#
  1185. X;# 
  1186. X#
  1187. X# Parsing mail
  1188. X#
  1189. X
  1190. X# Parse the mail and fill-in the Header associative array. The special entries
  1191. X# All, Body and Head respectively hold the whole message, the body and the
  1192. X# header of the message.
  1193. Xsub parse_mail {
  1194. X    local($file_name) = shift(@_);    # Where mail is stored ("" for stdin)
  1195. X    local($head_only) = shift(@_);    # Optional parameter: parse only header
  1196. X    local($last_header) = "";        # Name of last header (for continuations)
  1197. X    local($first_from) = "";        # The first From line in mails
  1198. X    local($lines) = 0;                # Number of lines in the body
  1199. X    local($length) = 0;                # Length of body, in bytes
  1200. X    local($last_was_nl) = 1;        # True when last line was a '\n' (1 for EOH)
  1201. X    local($fd) = STDIN;                # Where does the mail come from ?
  1202. X    local($value);                    # Value of current field line
  1203. X    local($_);
  1204. X    undef %Header;                    # Reset the all structure holding message
  1205. X
  1206. X    if ($file_name ne '') {            # Mail spooled in a file
  1207. X        unless(open(MAIL, $file_name)) {
  1208. X            &add_log("ERROR cannot open $file_name: $!");
  1209. X            return;
  1210. X        }
  1211. X        $fd = MAIL;
  1212. X    }
  1213. X    $Userpath = "";                    # Reset path from possible previous @PATH 
  1214. X
  1215. X    # Pre-extend 'All', 'Body' and 'Head'
  1216. X    $Header{'All'} = ' ' x 5000;
  1217. X    $Header{'Body'} = ' ' x 4500;
  1218. X    $Header{'Head'} = ' ' x 500;
  1219. X    $Header{'All'} = '';
  1220. X    $Header{'Body'} = '';
  1221. X    $Header{'Head'} = '';
  1222. X
  1223. X    &add_log ("parsing mail") if $loglvl > 18;
  1224. X    while (<$fd>) {
  1225. X        $Header{'All'} .= $_;
  1226. X        if (1../^$/) {                        # EOH is a blank line
  1227. X            next if /^$/;                    # Skip EOH marker
  1228. X            $Header{'Head'} .= $_;            # Record line in header
  1229. X
  1230. X            if (/^\s/) {                    # It is a continuation line
  1231. X                s/^\s+/ /;                    # Swallow multiple spaces
  1232. X                chop;                        # Remove final new-line
  1233. X                $Header{$last_header} .= "\n$_" if $last_header ne '';
  1234. X                &add_log("WARNING bad continuation in header, line $.")
  1235. X                    if $last_header eq '' && $loglvl > 4;
  1236. X            } elsif (/^([\w-]+):\s*(.*)/) {    # We found a new header
  1237. X                # Guarantee only one From: header line. If multiple From: are
  1238. X                # found, keep the last one.
  1239. X                # Multiple headers like 'Received' are separated by a new-
  1240. X                # line character. All headers end on a non new-line.
  1241. X                # Case is normalized before recording, so apparently-to will
  1242. X                # be recorded as Apparently-To but header is not changed.
  1243. X                $value = $2;                # Bug in perl 4.0 PL19
  1244. X                $last_header = &header'normalize($1);    # Normalize case
  1245. X                if ($last_header eq 'From' && defined $Header{$last_header}) {
  1246. X                    $Header{$last_header} = $value;
  1247. X                    &add_log("WARNING duplicate From in header, line $.")
  1248. X                        if $loglvl > 4;
  1249. X                } elsif ($Header{$last_header} ne '') {
  1250. X                    $Header{$last_header} .= "\n$value";
  1251. X                } else {
  1252. X                    $Header{$last_header} .= $value;
  1253. X                }
  1254. X            } elsif (/^From\s+(\S+)/) {        # The very first From line
  1255. X                $first_from = $1;
  1256. X            }
  1257. X
  1258. X        } else {
  1259. X            last if $head_only;        # Stop parsing if only header wanted
  1260. X            $lines++;                                # One more line in body
  1261. X            $length += length($_);                    # Update length of message
  1262. X            s/^From(\s)/>From$1/ if $last_was_nl;    # Escape From keyword
  1263. X            $last_was_nl = /^$/;                    # Keep track of single '\n'
  1264. X            $Header{'Body'} .= $_;
  1265. X            chop;
  1266. X            # Deal with builtin commands
  1267. X            if (s/^@(\w+)\s*//) {                    # A builtin command ?
  1268. X                local($subroutine) = $Builtin{$1};
  1269. X                &$subroutine($_) if $subroutine;
  1270. X            }
  1271. X        }
  1272. X    }
  1273. X    close MAIL if $file_name ne '';
  1274. X    $Header{'Head'} = "$FAKE_FROM\n" .  $Header{'Head'} unless $first_from;
  1275. X    &header_check($first_from, $lines);    # Sanity checks
  1276. X}
  1277. X
  1278. X# Now do some sanity checks:
  1279. X# - if there is no From: header, fill it in with the first From
  1280. X# - if there is no To: but an Apparently-To:, copy it also as a To:
  1281. X# - if an Envelope field was defined in the header, override it (sorry)
  1282. X#
  1283. X# We guarantee the following header entries:
  1284. X#   From:         the value of the From field
  1285. X#   To:           to whom the mail was sent
  1286. X#   Lines:        number of lines in the message
  1287. X#   Length:       number of bytes in the message
  1288. X#   Reply-To:     the address we may use to reply
  1289. X#   Sender:       the value of the Sender field, same as From usually
  1290. X#   Envelope:     the actual sender of the message, empty if cannot compute
  1291. X
  1292. Xsub header_check {
  1293. X    local($first_from, $lines) = @_;    # First From line, number of lines
  1294. X    unless (defined $Header{'From'}) {
  1295. X        &add_log("WARNING no From: field, assuming $first_from") if $loglvl > 4;
  1296. X        $Header{'From'} = $first_from;
  1297. X    }
  1298. X
  1299. X    # There is usually one Apparently-To line per address. Remove all new lines
  1300. X    # in the header line and replace them with ','. Likewise for To: and Cc:.
  1301. X    # although it is far less likely to occur.
  1302. X    local($*) = 1;
  1303. X    foreach $field ('Apparently-To', 'To', 'Cc') {
  1304. X        $Header{$field} =~ s/\n/,/g;    # Remove new-lines
  1305. X        $Header{$field} =~ s/,$/\n/;    # Restore last new-line
  1306. X    }
  1307. X    $* = 0;
  1308. X
  1309. X    # If no To: field, then maybe there is an Apparently-To: instead. If so,
  1310. X    # make them identical. Otherwise, assume the mail was directed to the user.
  1311. X    if (!$Header{'To'} && $Header{'Apparently-To'}) {
  1312. X        $Header{'To'} = $Header{'Apparently-To'};
  1313. X    }
  1314. X    unless ($Header{'To'}) {
  1315. X        &add_log("WARNING no To: field, assuming $cf'user") if $loglvl > 4;
  1316. X        $Header{'To'} = $cf'user;
  1317. X    }
  1318. X
  1319. X    # Set number of lines in body, unless there is already a Lines:
  1320. X    # header in which case we trust it. Same for Length.
  1321. X    $Header{'Lines'} = $lines unless defined($Header{'Lines'});
  1322. X    $Header{'Length'} = $length unless defined($Header{'Length'});
  1323. X
  1324. X    # If there is no Reply-To: line, then take the address in From, if any.
  1325. X    # Otherwise use the address found in the return-path
  1326. X    if (!$Header{'Reply-To'}) {
  1327. X        local($tmp) = (&parse_address($Header{'From'}))[0];
  1328. X        $Header{'Reply-To'} = $tmp if $tmp ne '';
  1329. X        $Header{'Reply-To'} = (&parse_address($Header{'Return-Path'}))[0]
  1330. X            if $tmp eq '';
  1331. X    }
  1332. X
  1333. X    # Unless there is already a sender line, fake one using From field
  1334. X    if (!$Header{'Sender'}) {
  1335. X        $Header{'Sender'} = $first_from;
  1336. X        $Header{'Sender'} = $Header{'From'} unless $first_from;
  1337. X    }
  1338. X
  1339. X    # Now override any Envelope header and grab it from the first From field
  1340. X    # If such a field was defined in the message header, then sorry but it
  1341. X    # was a mistake: RFC 822 doesn't define it, so it should have been
  1342. X    # an X-Envelope instead.
  1343. X
  1344. X    $Header{'Envelope'} = $first_from;
  1345. X}
  1346. X
  1347. END_OF_FILE
  1348.   if test 6649 -ne `wc -c <'agent/pl/parse.pl'`; then
  1349.     echo shar: \"'agent/pl/parse.pl'\" unpacked with wrong size!
  1350.   fi
  1351.   # end of 'agent/pl/parse.pl'
  1352. fi
  1353. if test -f 'agent/test/cmd/split.t' -a "${1}" != "-c" ; then 
  1354.   echo shar: Will not clobber existing file \"'agent/test/cmd/split.t'\"
  1355. else
  1356.   echo shar: Extracting \"'agent/test/cmd/split.t'\" \(6596 characters\)
  1357.   sed "s/^X//" >'agent/test/cmd/split.t' <<'END_OF_FILE'
  1358. X# The SPLIT command
  1359. X
  1360. X# $Id: split.t,v 3.0 1993/11/29 13:49:50 ram Exp ram $
  1361. X#
  1362. X#  Copyright (c) 1990-1993, Raphael Manfredi
  1363. X#  
  1364. X#  You may redistribute only under the terms of the Artistic License,
  1365. X#  as specified in the README file that comes with the distribution.
  1366. X#  You may reuse parts of this distribution only within the terms of
  1367. X#  that same Artistic License; a copy of which may be found at the root
  1368. X#  of the source tree for mailagent 3.0.
  1369. X#
  1370. X# $Log: split.t,v $
  1371. X# Revision 3.0  1993/11/29  13:49:50  ram
  1372. X# Baseline for mailagent 3.0 netwide release.
  1373. X#
  1374. X
  1375. Xdo '../pl/cmd.pl';
  1376. X
  1377. X&add_header('X-Tag: digest #2');
  1378. X&make_digest;
  1379. X
  1380. X# First time, normal split: one (empty) header plus 3 digest items.
  1381. X# A single 'SPLIT here' is run
  1382. X&add_header('X-Tag: split #1', 'digest');
  1383. X`cp digest mail`;
  1384. X`$cmd`;
  1385. X$? == 0 || print "1\n";
  1386. X-f "$user" && print "2\n";            # Was not split in-place, but also saved
  1387. X-f 'here' || print "3\n";            # Where digest was split...
  1388. X&get_log(4, 'here');                # Slurp folder in @log
  1389. X&check_log('^X-Tag: digest #1', 5) == 2 || print "6\n";
  1390. X&check_log('^X-Tag: digest #2', 7) == 2 || print "8\n";
  1391. X&check_log('^X-Tag: digest #3', 9) == 2 || print "10\n";
  1392. X&check_log('^X-Tag: split #1', 11) == 2 || print "12\n";
  1393. X&check_log('^X-Filter-Note:', 13) == 2 || print "14\n";
  1394. Xunlink 'here';
  1395. X
  1396. X# Seconde time: a single 'SPLIT -id here' is run
  1397. X&replace_header('X-Tag: split #2', 'digest');
  1398. X`cp digest mail`;
  1399. X`$cmd`;
  1400. X$? == 0 || print "15\n";
  1401. X-f "$user" && print "16\n";            # Was not split in-place, but in folder
  1402. X-f 'here' || print "17\n";            # Where digest was split...
  1403. X&get_log(18, 'here');                # Slurp folder in @log
  1404. X&check_log('^X-Tag: digest #1', 19) == 1 || print "20\n";
  1405. X&check_log('^X-Tag: digest #2', 21) == 1 || print "22\n";
  1406. X&check_log('^X-Tag: digest #3', 23) == 1 || print "24\n";
  1407. X¬_log('^X-Tag: split #2', 25);    # Header was deleted by -d
  1408. X&check_log('^X-Filter-Note:', 26) == 2 || print "27\n";
  1409. X&check_log('^X-Digest-To:', 84) == 3 || print "85\n";
  1410. Xunlink 'here';
  1411. X
  1412. X# Third time: a single 'SPLIT -iew here' is run
  1413. X&replace_header('X-Tag: split #3', 'digest');
  1414. X`cp digest mail`;
  1415. X`$cmd`;
  1416. X$? == 0 || print "28\n";
  1417. X-f "$user" && print "29\n";            # Was not split in-place, but in folder
  1418. X-f 'here' || print "30\n";            # Where digest was split...
  1419. X&get_log(31, 'here');                # Slurp folder in @log
  1420. X&check_log('^X-Tag: digest #1', 32) == 1 || print "33\n";
  1421. X&check_log('^X-Tag: digest #2', 34) == 1 || print "35\n";
  1422. X&check_log('^X-Tag: digest #3', 36) == 1 || print "37\n";
  1423. X¬_log('^X-Tag: split #3', 38);    # Header was deleted by -e
  1424. X&check_log('^X-Filter-Note:', 39) == 3 || print "40\n";    # Trailing garbage...
  1425. X&check_log('anticonstitutionellement', 41) == 1 || print "42\n";
  1426. Xunlink 'here';
  1427. X
  1428. X# Fourth time: a single 'SPLIT -iew' is run. All the digest items will still
  1429. X# be saved in 'here' because they all bear a X-Tag: header. The trailing
  1430. X# garbage will not match anything and will be left in the mailbox.
  1431. X&replace_header('X-Tag: split #4', 'digest');
  1432. X`cp digest mail`;
  1433. X`$cmd`;
  1434. X$? == 0 || print "43\n";
  1435. X-f "$user" || print "44\n";            # That must be the trailing garbage
  1436. X-f 'here' || print "45\n";            # Where digest was split...
  1437. X&get_log(46, 'here');                # Slurp folder in @log
  1438. X&check_log('^X-Tag: digest #1', 47) == 1 || print "48\n";
  1439. X&check_log('^X-Tag: digest #2', 49) == 1 || print "50\n";
  1440. X&check_log('^X-Tag: digest #3', 51) == 1 || print "52\n";
  1441. X¬_log('^X-Tag: split #3', 53);    # Header was deleted by -e
  1442. X&check_log('^X-Filter-Note:', 54) == 2 || print "55\n";    # No trailing garbage...
  1443. X¬_log('anticonstitutionellement', 56);
  1444. X&get_log(57, "$user");
  1445. X&check_log('anticonstitutionellement', 58) == 1 || print "59\n";
  1446. X&check_log('^X-Filter-Note:', 60) == 1 || print "61\n";
  1447. Xunlink 'here', "$user";
  1448. X
  1449. X# Fifth time: a single 'SPLIT -iew here', but this time header is not empty...
  1450. X# Besides, there will be an empty message between encapsulation boundaries
  1451. X# and we want to make sure SPLIT deals correctly with it. Trailing garbage
  1452. X# is removed.
  1453. Xopen(MAIL, ">mail");
  1454. Xclose MAIL;
  1455. X&make_digest('Not empty digest header');
  1456. X`cp digest mail`;
  1457. X&add_header('X-Tag: split #5');
  1458. X`$cmd`;
  1459. X$? == 0 || print "62\n";
  1460. X-f 'here' || print "63\n";            # Where digest was split...
  1461. X&get_log(64, 'here');                # Slurp folder in @log
  1462. X&check_log('^X-Tag: digest #1', 65) == 1 || print "66\n";
  1463. X&check_log('^X-Tag: digest #3', 67) == 1 || print "68\n";
  1464. X¬_log('^X-Tag: digest #2', 69);    # Empty second message
  1465. X¬_log('Mailagent-Test-Suite', 70);    # No trailing garbage
  1466. X&check_log('^X-Filter-Note:', 71) == 2 || print "72\n";
  1467. X&check_log('^From ', 73) == 4 || print "74\n";    # One built up for last item
  1468. X&check_log('^Message-Id:', 75) == 1 || print "76\n";
  1469. X&check_log('^>From', 80) == 2 || print "81\n";
  1470. X&check_log('^From which', 82) == 1 || print "83\n";
  1471. X
  1472. X# Sixth time: mail is not in digest format.
  1473. X`cp ../mail .`;
  1474. X$? == 0 || print "77\n";        # Fool guard for myself
  1475. X&add_header('X-Tag: split #5');
  1476. X`$cmd`;
  1477. X$? == 0 || print "78\n";
  1478. X-f 'here' || print "79\n";        # Where mail was saved (not in digest format)
  1479. X
  1480. Xunlink 'mail', 'here', 'digest';
  1481. X# Last is 85
  1482. Xprint "0\n";
  1483. X
  1484. X# Build digest out of mail
  1485. Xsub make_digest {
  1486. X    local($msg) = @_;        # Optional, first line in header
  1487. X    &get_log(100, 'mail');    # Slurp mail in @log
  1488. X    open(DIGEST, ">digest");
  1489. X    print DIGEST <<EOH;
  1490. XReceived: from eiffel.eiffel.com by lyon.eiffel.com (5.61/1.34)
  1491. X    id AA25370; Fri, 10 Jul 92 23:48:30 -0700
  1492. XReceived: by eiffel.eiffel.com (4.0/SMI-4.0)
  1493. X    id AA27809; Fri, 10 Jul 92 23:45:14 PDT
  1494. XDate: Fri, 10 Jul 92 23:45:14 PDT
  1495. XFrom: root@eiffel.com (Postmaster)
  1496. XMessage-Id: <9207110645.AA27809@eiffel.eiffel.com>
  1497. XTo: postmaster@eiffel.com
  1498. XSubject: Mail Report - 10/07
  1499. X
  1500. X$msg
  1501. X----------------------------------------------
  1502. XFrom ram Sun Jul 12 18:20:27 PDT 1992
  1503. XFrom: ram
  1504. XSubject: Notice
  1505. XX-Tag: digest #1
  1506. X
  1507. XJust to tell you there was no digest header... unless $msg set
  1508. X
  1509. X----
  1510. X
  1511. XEOH
  1512. X    print DIGEST @log;
  1513. X    print DIGEST <<'EOM';
  1514. X----
  1515. XFrom: ram
  1516. XX-Tag: digest #3
  1517. X
  1518. XFrom line should be >escaped.
  1519. XAnother message with a really minimum set of header!!
  1520. XFrom which should NOT be
  1521. X
  1522. XFrom escaped again...
  1523. X----
  1524. X
  1525. XEOM
  1526. X    if ($msg eq '') {
  1527. X        print DIGEST <<'EOM';
  1528. XThis is trailing garbage. I will use the SPLIT command with the '-w'
  1529. Xoption and this will be saved is a separate mail with the subject
  1530. Xtaken from that of the whole digest, with the words (trailing garbage)
  1531. Xappended to it... This token, "anticonstitutionellement " will make
  1532. Xit obvious for grep -- it's the longest word in French, and it means
  1533. Xthe government is not doing its job, roughly speaking :-).
  1534. XEOM
  1535. X    } else {
  1536. X        print DIGEST <<'EOM';
  1537. XEnd of digest Mailagent-Test-Suite
  1538. X**********************************
  1539. XEOM
  1540. X    }
  1541. X    close DIGEST;
  1542. X}
  1543. X
  1544. END_OF_FILE
  1545.   if test 6596 -ne `wc -c <'agent/test/cmd/split.t'`; then
  1546.     echo shar: \"'agent/test/cmd/split.t'\" unpacked with wrong size!
  1547.   fi
  1548.   # end of 'agent/test/cmd/split.t'
  1549. fi
  1550. if test -f 'misc/shell/server.cf' -a "${1}" != "-c" ; then 
  1551.   echo shar: Will not clobber existing file \"'misc/shell/server.cf'\"
  1552. else
  1553.   echo shar: Extracting \"'misc/shell/server.cf'\" \(118 characters\)
  1554.   sed "s/^X//" >'misc/shell/server.cf' <<'END_OF_FILE'
  1555. X#
  1556. X# Add the following to your 'comserver' file to allow shell processing.
  1557. X#
  1558. X
  1559. Xshell        shell    -    y    shell
  1560. Xshell        var        -    -    -
  1561. END_OF_FILE
  1562.   if test 118 -ne `wc -c <'misc/shell/server.cf'`; then
  1563.     echo shar: \"'misc/shell/server.cf'\" unpacked with wrong size!
  1564.   fi
  1565.   # end of 'misc/shell/server.cf'
  1566. fi
  1567. echo shar: End of archive 16 \(of 26\).
  1568. cp /dev/null ark16isdone
  1569. MISSING=""
  1570. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 ; do
  1571.     if test ! -f ark${I}isdone ; then
  1572.     MISSING="${MISSING} ${I}"
  1573.     fi
  1574. done
  1575. if test "${MISSING}" = "" ; then
  1576.     echo You have unpacked all 26 archives.
  1577.     echo "Now run 'sh PACKNOTES', then read README and type Configure.'"
  1578.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1579. else
  1580.     echo You still must unpack the following archives:
  1581.     echo "        " ${MISSING}
  1582. fi
  1583. exit 0
  1584.  
  1585. exit 0 # Just in case...
  1586.