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

  1. Newsgroups: comp.sources.misc
  2. From: ram@eiffel.com (Raphael Manfredi)
  3. Subject:  v33i101:  mailagent - Rule Based Mail Filtering, Part09/17
  4. Message-ID: <1992Nov20.050626.14244@sparky.imd.sterling.com>
  5. X-Md4-Signature: 53a058f70412d3e236c9f9b061221874
  6. Date: Fri, 20 Nov 1992 05:06:26 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: ram@eiffel.com (Raphael Manfredi)
  10. Posting-number: Volume 33, Issue 101
  11. Archive-name: mailagent/part09
  12. Environment: Perl, Sendmail, UNIX
  13.  
  14. #! /bin/sh
  15. # This is a shell archive.  Remove anything before this line, then feed it
  16. # into a shell via "sh file" or similar.  To overwrite existing files,
  17. # type "sh file -c".
  18. # Contents:  MANIFEST PACKLIST agent/filter/parser.c agent/pl/dbr.pl
  19. #   agent/test/cmd/run.t
  20. # Wrapped by kent@sparky on Wed Nov 18 22:42:24 1992
  21. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
  22. echo If this archive is complete, you will see the following message:
  23. echo '          "shar: End of archive 9 (of 17)."'
  24. if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  25.   echo shar: Will not clobber existing file \"'MANIFEST'\"
  26. else
  27.   echo shar: Extracting \"'MANIFEST'\" \(11685 characters\)
  28.   sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
  29. XConfigure                  Portability tool
  30. XCopying                    The GNU General Public Licence Version 2
  31. XJmakefile                  Description of the main Makefile
  32. XMANIFEST                   This list of files
  33. XMakefile.SH                A makefile to run subsidiary makefiles
  34. XREADME                     Basic instructions
  35. Xagent/                     Where mailagent support files are located
  36. Xagent/Jmakefile            High level description of Makefile
  37. Xagent/Makefile.SH          Makefile which builds and installs mailagent
  38. Xagent/README               Welcome to mailagent
  39. Xagent/examples/            A set of files from my own environment
  40. Xagent/examples/README      Explains what the examples are
  41. Xagent/examples/daemon      Rules for "vacation" emulation
  42. Xagent/examples/mailfolders A copy of my ~/.mailfolders
  43. Xagent/examples/mchk        Checks for new mail
  44. Xagent/examples/mhinc       Call the MH inc command to incorporate new mail
  45. Xagent/examples/nocmds      Message you currently get if you send me a command
  46. Xagent/examples/profile     What I added to my onw ~/.profile
  47. Xagent/examples/rules       The rules I am currently using
  48. Xagent/examples/vacation    A sample vacation message
  49. Xagent/files/               Mailagent's configuration files
  50. Xagent/files/Jmakefile      High level description for Makefile
  51. Xagent/files/Makefile.SH    Makefile for subsidiary files
  52. Xagent/files/README         Notes about files found in this directory
  53. Xagent/files/agenthelp      Help file used by mailhelp
  54. Xagent/files/chkagent.sh    Cron script to spot problems in the mailagent system
  55. Xagent/files/commands       Allowed commands for mailagent
  56. Xagent/files/distribs       Example of distribution list
  57. Xagent/files/filter.sh      Shell script version of the mail filter
  58. Xagent/files/mailagent.cf   Example of configuration file
  59. Xagent/files/proglist       Example of description file
  60. Xagent/filter/              The C version of the mail filter
  61. Xagent/filter/Jmakefile     Generic makefile template
  62. Xagent/filter/Makefile.SH   Makefile for C filter
  63. Xagent/filter/README        Introduction to filter
  64. Xagent/filter/environ.c     Environment management routines
  65. Xagent/filter/environ.h     Declarations for environment management routines
  66. Xagent/filter/hash.c        Symbol table handling
  67. Xagent/filter/hash.h        Declarations for symbol table
  68. Xagent/filter/io.c          I/O routines
  69. Xagent/filter/io.h          Header for I/O routines
  70. Xagent/filter/lock.c        File locking
  71. Xagent/filter/lock.h        Declarations for file locking routines
  72. Xagent/filter/logfile.c     Logging facilities
  73. Xagent/filter/logfile.h     Header for logging routines
  74. Xagent/filter/main.c        The main entry point for filter
  75. Xagent/filter/misc.c        Miscellaneous routines
  76. Xagent/filter/msg.c         Handles fatal messages
  77. Xagent/filter/msg.h         Declarations for user messages
  78. Xagent/filter/parser.c      Parse the config file with variable substitutions
  79. Xagent/filter/parser.h      About config file parsing
  80. Xagent/filter/portable.h    Portable declarations
  81. Xagent/filter/sysexits.h    Standard exit codes
  82. Xagent/filter/user.c        To get login name from user
  83. Xagent/magent.SH            The main processor
  84. Xagent/maildist.SH          Mails a whole distribution
  85. Xagent/mailhelp.SH          Mails some help
  86. Xagent/maillist.SH          Mails a list of available distributions
  87. Xagent/mailpatch.SH         Mails patches for a given distribution
  88. Xagent/man/                 Manual pages for mailagent
  89. Xagent/man/Jmakefile        Makefile description for jmake
  90. Xagent/man/Makefile.SH      Makefile for manual pages extraction
  91. Xagent/man/mailagent.SH     Produces a manual page for mailagent
  92. Xagent/man/maildist.SH      Produces a manual page for maildist
  93. Xagent/man/mailhelp.SH      Produces a manual page for mailhelp
  94. Xagent/man/maillist.SH      Produces a manual page for maillist
  95. Xagent/man/mailpatch.SH     Produces a manual page for mailpatch
  96. Xagent/mhook.SH             The mail hook wrapper
  97. Xagent/pl/                  Perl files used by mailagent scripts
  98. Xagent/pl/acs_rqst.pl       Perl library to ask for private file access
  99. Xagent/pl/actions.pl        Implementation of mailagent's actions
  100. Xagent/pl/add_log.pl        Perl library to add logs to logfile
  101. Xagent/pl/analyze.pl        Perl library analyzing the incoming mail
  102. Xagent/pl/builtins.pl       Perl library dealing with builtins
  103. Xagent/pl/checklock.pl      Perl library to check for long lasting locks
  104. Xagent/pl/context.pl        Mailagent context file handling
  105. Xagent/pl/dbr.pl            Internal database management
  106. Xagent/pl/distribs.pl       Perl library to scan the distribs file
  107. Xagent/pl/emergency.pl      Perl library dealing with emergencies
  108. Xagent/pl/eval.pl           A little expression interpreter
  109. Xagent/pl/extern.pl         Perl library to handle persistent variables
  110. Xagent/pl/fatal.pl          Perl library to deal with fatal errors
  111. Xagent/pl/filter.pl         Running the filtering commands
  112. Xagent/pl/free_file.pl      Perl library to free file access
  113. Xagent/pl/getdate.pl        Richard Ohnemus's getdate package
  114. Xagent/pl/header.pl         Header-related routines
  115. Xagent/pl/history.pl        Perl library to implement history mechanism
  116. Xagent/pl/hook.pl           Mail hook wrapping functions
  117. Xagent/pl/interface.pl      Perl interface with filter commands
  118. Xagent/pl/jobnum.pl         Perl library to compute a job number
  119. Xagent/pl/lexical.pl        Perl library for lexical analysis
  120. Xagent/pl/listqueue.pl      Perl library to list the queue
  121. Xagent/pl/locate.pl         Perl library to locate loaded patterns/addresses
  122. Xagent/pl/macros.pl         Perl library for macros expansion
  123. Xagent/pl/mailhook.pl       Initializing and running hooks
  124. Xagent/pl/makedir.pl        Perl library for making a directory
  125. Xagent/pl/matching.pl       Matching routines used by filter
  126. Xagent/pl/mbox.pl           Getting mails from a mailbox file
  127. Xagent/pl/once.pl           Dealing with once commands
  128. Xagent/pl/parse.pl          Perl library to parse a mail message
  129. Xagent/pl/period.pl         Perl library to compute periods
  130. Xagent/pl/plsave.pl         Perl library to handle the plsave cache file
  131. Xagent/pl/pqueue.pl         Processing the queued mails
  132. Xagent/pl/queue_mail.pl     Queuing mails
  133. Xagent/pl/rangeargs.pl      Perl library to expand a list of patches
  134. Xagent/pl/read_conf.pl      Perl library to read configuration file
  135. Xagent/pl/rfc822.pl         Perl library to parse RFC822 addresses
  136. Xagent/pl/rules.pl          Compiles the filtering rules
  137. Xagent/pl/runcmd.pl         Filter commands ran from here
  138. Xagent/pl/sendfile.pl       Perl library to send files in shar / kit mode
  139. Xagent/pl/stats.pl          Mailagent's statistics recording and printing
  140. Xagent/pl/unpack.pl         Perl library to unpack archive files
  141. Xagent/test/                Regression test suite
  142. Xagent/test/Jmakefile       Generic makefile for test suite
  143. Xagent/test/Makefile.SH     Makefile for test suite
  144. Xagent/test/README          About the regression tests
  145. Xagent/test/TEST            Runs the full test suite
  146. Xagent/test/actions         Rule file for cmd tests
  147. Xagent/test/basic/              Basic tests
  148. Xagent/test/basic/config.t      Main test initialization and sanity checks
  149. Xagent/test/basic/filter.t      Make sure C filter works
  150. Xagent/test/basic/mailagent.t   Make sure mailagent basically works
  151. Xagent/test/cmd/                Tests of mailagent's filtering commands
  152. Xagent/test/cmd/abort.t         Test ABORT command
  153. Xagent/test/cmd/annotate.t      Test ANNOTATE command
  154. Xagent/test/cmd/assign.t        Test ASSIGN command
  155. Xagent/test/cmd/back.t          Test BACK command
  156. Xagent/test/cmd/begin.t         Test BEGIN command
  157. Xagent/test/cmd/bounce.t        Test BOUNCE command
  158. Xagent/test/cmd/delete.t        Test DELETE command
  159. Xagent/test/cmd/feed.t          Test FEED command
  160. Xagent/test/cmd/forward.t       Test FORWARD command
  161. Xagent/test/cmd/give.t          Test GIVE command
  162. Xagent/test/cmd/keep.t          Test KEEP command
  163. Xagent/test/cmd/leave.t         Test LEAVE command
  164. Xagent/test/cmd/message.t       Test MESSAGE command
  165. Xagent/test/cmd/nop.t           Test NOP command
  166. Xagent/test/cmd/notify.t        Test NOTIFY command
  167. Xagent/test/cmd/once.t          Test ONCE command
  168. Xagent/test/cmd/pass.t          Test PASS command
  169. Xagent/test/cmd/perl.t          Test PERL command
  170. Xagent/test/cmd/pipe.t          Test PIPE command
  171. Xagent/test/cmd/post.t          Test POST command
  172. Xagent/test/cmd/process.t       Test PROCESS command
  173. Xagent/test/cmd/purify.t        Test PURIFY command
  174. Xagent/test/cmd/queue.t         Test QUEUE command
  175. Xagent/test/cmd/record.t        Test RECORD command
  176. Xagent/test/cmd/reject.t        Test REJECT command
  177. Xagent/test/cmd/restart.t       Test RESTART command
  178. Xagent/test/cmd/resync.t        Test RESYNC command
  179. Xagent/test/cmd/run.t           Test RUN command
  180. Xagent/test/cmd/save.t          Test SAVE command
  181. Xagent/test/cmd/select.t        Test SELECT command
  182. Xagent/test/cmd/split.t         Test SPLIT command
  183. Xagent/test/cmd/store.t         Test STORE command
  184. Xagent/test/cmd/strip.t         Test STRIP command
  185. Xagent/test/cmd/subst.t         Test SUBST command
  186. Xagent/test/cmd/tr.t            Test TR command
  187. Xagent/test/cmd/unique.t        Test UNIQUE command
  188. Xagent/test/cmd/unknown.t       Make sure unknown command defaults correctly
  189. Xagent/test/cmd/vacation.t      Test VACATION command
  190. Xagent/test/cmd/write.t         Test WRITE command
  191. Xagent/test/filter/             Testing the filtering capabilities
  192. Xagent/test/filter/backref.t    Check backreferences
  193. Xagent/test/filter/case.t       Normalized header case tests
  194. Xagent/test/filter/default.t    Check default behaviour when mail not saved
  195. Xagent/test/filter/escape.t     Escape sequences within actions
  196. Xagent/test/filter/group.t      Selector combination tests
  197. Xagent/test/filter/hook.t       Ensure hooks are correctly invoked
  198. Xagent/test/filter/list.t       Check matching on lists like To and Newsgroups
  199. Xagent/test/filter/loop.t       Check loop detection
  200. Xagent/test/filter/multiple.t   Check multiple selectors
  201. Xagent/test/filter/not.t        Negated pattern tests
  202. Xagent/test/filter/pattern.t    Check patterns specification and loading
  203. Xagent/test/filter/status.t     Action status updating tests
  204. Xagent/test/level               Default logging level for tests
  205. Xagent/test/mail                The mail used by testing routines
  206. Xagent/test/option/             Tests the options to the mailagent program
  207. Xagent/test/option/L.t          Test -L option
  208. Xagent/test/option/V.t          Test -V option
  209. Xagent/test/option/c.t          Test -c option
  210. Xagent/test/option/d.t          Test -d option
  211. Xagent/test/option/e.t          Test -e option
  212. Xagent/test/option/f.t          Test -f option
  213. Xagent/test/option/h.t          Test -h option
  214. Xagent/test/option/i.t          Test -i option
  215. Xagent/test/option/l.t          Test -l option
  216. Xagent/test/option/o.t          Test -o option
  217. Xagent/test/option/q.t          Test -q option
  218. Xagent/test/option/r.t          Test -r option
  219. Xagent/test/option/s.t          Test -s option
  220. Xagent/test/option/t.t          Test -t option
  221. Xagent/test/option/what.t       Ensure good behaviour with unknown option
  222. Xagent/test/pl/                 Perl libraries for the regression test suite
  223. Xagent/test/pl/cmd.pl           Initializes command paths
  224. Xagent/test/pl/filter.pl        Set up environment for filter tests
  225. Xagent/test/pl/init.pl          Variable initializations
  226. Xagent/test/pl/logfile.pl       Logging file checking
  227. Xagent/test/pl/mail.pl          Modifies mail components
  228. Xagent/test/rules               Rules used by filtering tests
  229. Xbin/perload                The dataloading/autoloading perl translator
  230. Xconfig.h.SH                Produces config.h
  231. Xinstall.SH                 Installation script
  232. Xpatchlevel.h               Current version number and patch level
  233. END_OF_FILE
  234.   if test 11685 -ne `wc -c <'MANIFEST'`; then
  235.     echo shar: \"'MANIFEST'\" unpacked with wrong size!
  236.   fi
  237.   # end of 'MANIFEST'
  238. fi
  239. if test -f 'PACKLIST' -a "${1}" != "-c" ; then 
  240.   echo shar: Will not clobber existing file \"'PACKLIST'\"
  241. else
  242.   echo shar: Extracting \"'PACKLIST'\" \(11453 characters\)
  243.   sed "s/^X//" >'PACKLIST' <<'END_OF_FILE'
  244. XAfter all the mailagent kits are run you should have the following files:
  245. X
  246. XFilename                   Kit Description
  247. X--------                   --- -----------
  248. XConfigure                    2 Portability tool
  249. XCopying                      5 The GNU General Public Licence Version 2
  250. XJmakefile                   14 Description of the main Makefile
  251. XMANIFEST                     8 This list of files
  252. XMakefile.SH                 11 A makefile to run subsidiary makefiles
  253. XPACKLIST                     8 Which files came with which kits
  254. XREADME                       1 Basic instructions
  255. Xagent/                         Where mailagent support files are located
  256. Xagent/Jmakefile             14 High level description of Makefile
  257. Xagent/Makefile.SH           11 Makefile which builds and installs mailagent
  258. Xagent/README                 1 Welcome to mailagent
  259. Xagent/examples/                A set of files from my own environment
  260. Xagent/examples/README        1 Explains what the examples are
  261. Xagent/examples/daemon       15 Rules for "vacation" emulation
  262. Xagent/examples/mailfolders  15 A copy of my ~/.mailfolders
  263. Xagent/examples/mchk         14 Checks for new mail
  264. Xagent/examples/mhinc        14 Call the MH inc command to incorporate new mail
  265. Xagent/examples/nocmds       14 Message you currently get if you send me a comm
  266. Xagent/examples/profile      14 What I added to my onw ~/.profile
  267. Xagent/examples/rules         1 The rules I am currently using
  268. Xagent/examples/vacation     14 A sample vacation message
  269. Xagent/files/                   Mailagent's configuration files
  270. Xagent/files/Jmakefile       14 High level description for Makefile
  271. Xagent/files/Makefile.SH     12 Makefile for subsidiary files
  272. Xagent/files/agenthelp       10 Help file used by mailhelp
  273. Xagent/files/chkagent.sh     13 Cron script to spot problems in the mailagent s
  274. Xagent/files/commands        15 Allowed commands for mailagent
  275. Xagent/files/distribs        14 Example of distribution list
  276. Xagent/files/filter.sh       10 Shell script version of the mail filter
  277. Xagent/files/mailagent.cf    13 Example of configuration file
  278. Xagent/files/proglist        13 Example of description file
  279. Xagent/filter/                  The C version of the mail filter
  280. Xagent/filter/Jmakefile      14 Generic makefile template
  281. Xagent/filter/Makefile.SH    11 Makefile for C filter
  282. Xagent/filter/README          1 Introduction to filter
  283. Xagent/filter/environ.c      10 Environment management routines
  284. Xagent/filter/environ.h      14 Declarations for environment management routine
  285. Xagent/filter/hash.c          9 Symbol table handling
  286. Xagent/filter/hash.h         13 Declarations for symbol table
  287. Xagent/filter/io.c            7 I/O routines
  288. Xagent/filter/io.h           14 Header for I/O routines
  289. Xagent/filter/lock.c          7 File locking
  290. Xagent/filter/lock.h         14 Declarations for file locking routines
  291. Xagent/filter/logfile.c      11 Logging facilities
  292. Xagent/filter/logfile.h      13 Header for logging routines
  293. Xagent/filter/main.c         12 The main entry point for filter
  294. Xagent/filter/misc.c         14 Miscellaneous routines
  295. Xagent/filter/msg.c          13 Handles fatal messages
  296. Xagent/filter/msg.h          14 Declarations for user messages
  297. Xagent/filter/parser.c        6 Parse the config file with variable substitutio
  298. Xagent/filter/parser.h       14 About config file parsing
  299. Xagent/filter/portable.h     13 Portable declarations
  300. Xagent/filter/sysexits.h     14 Standard exit codes
  301. Xagent/filter/user.c         13 To get login name from user
  302. Xagent/magent.SH              6 The main processor
  303. Xagent/maildist.SH            4 Mails a whole distribution
  304. Xagent/mailhelp.SH           13 Mails some help
  305. Xagent/maillist.SH           10 Mails a list of available distributions
  306. Xagent/mailpatch.SH           9 Mails patches for a given distribution
  307. Xagent/man/                     Manual pages for mailagent
  308. Xagent/man/Jmakefile         14 Makefile description for jmake
  309. Xagent/man/Makefile.SH       12 Makefile for manual pages extraction
  310. Xagent/man/mailagent.SH       3 Produces a manual page for mailagent
  311. Xagent/man/maildist.SH       14 Produces a manual page for maildist
  312. Xagent/man/mailhelp.SH       11 Produces a manual page for mailhelp
  313. Xagent/man/maillist.SH       14 Produces a manual page for maillist
  314. Xagent/man/mailpatch.SH      14 Produces a manual page for mailpatch
  315. Xagent/pl/                      Perl files used by mailagent scripts
  316. Xagent/pl/acs_rqst.pl        13 Perl library to ask for private file access
  317. Xagent/pl/actions.pl          4 Implementation of mailagent's actions
  318. Xagent/pl/add_log.pl         14 Perl library to add logs to logfile
  319. Xagent/pl/analyze.pl          8 Perl library analyzing the incoming mail
  320. Xagent/pl/builtins.pl        12 Perl library dealing with builtins
  321. Xagent/pl/checklock.pl       14 Perl library to check for long lasting locks
  322. Xagent/pl/context.pl         12 Mailagent context file handling
  323. Xagent/pl/dbr.pl              8 Internal database management
  324. Xagent/pl/distribs.pl        12 Perl library to scan the distribs file
  325. Xagent/pl/emergency.pl       12 Perl library dealing with emergencies
  326. Xagent/pl/eval.pl            11 A little expression interpreter
  327. Xagent/pl/fatal.pl           14 Perl library to deal with fatal errors
  328. Xagent/pl/filter.pl           6 Running the filtering commands
  329. Xagent/pl/free_file.pl       14 Perl library to free file access
  330. Xagent/pl/getdate.pl          1 Richard Ohnemus's getdate package
  331. Xagent/pl/header.pl          11 Header-related routines
  332. Xagent/pl/history.pl         13 Perl library to implement history mechanism
  333. Xagent/pl/lexical.pl         12 Perl library for lexical analysis
  334. Xagent/pl/listqueue.pl       11 Perl library to list the queue
  335. Xagent/pl/locate.pl          14 Perl library to locate loaded patterns/addresse
  336. Xagent/pl/macros.pl          12 Perl library for macros expansion
  337. Xagent/pl/makedir.pl         14 Perl library for making a directory
  338. Xagent/pl/matching.pl         7 Matching routines used by filter
  339. Xagent/pl/mbox.pl            13 Getting mails from a mailbox file
  340. Xagent/pl/once.pl            13 Dealing with once commands
  341. Xagent/pl/period.pl          13 Perl library to compute periods
  342. Xagent/pl/plsave.pl          11 Perl library to handle the plsave cache file
  343. Xagent/pl/pqueue.pl          13 Processing the queued mails
  344. Xagent/pl/queue_mail.pl       9 Queuing mails
  345. Xagent/pl/rangeargs.pl       14 Perl library to expand a list of patches
  346. Xagent/pl/read_conf.pl       13 Perl library to read configuration file
  347. Xagent/pl/rfc822.pl          13 Perl library to parse RFC822 addresses
  348. Xagent/pl/rules.pl            9 Compiles the filtering rules
  349. Xagent/pl/runcmd.pl          10 Filter commands ran from here
  350. Xagent/pl/sendfile.pl         9 Perl library to send files in shar / kit mode
  351. Xagent/pl/stats.pl            5 Mailagent's statistics recording and printing
  352. Xagent/pl/unpack.pl          13 Perl library to unpack archive files
  353. Xagent/test/                    Regression test suite
  354. Xagent/test/Jmakefile        14 Generic makefile for test suite
  355. Xagent/test/Makefile.SH      12 Makefile for test suite
  356. Xagent/test/README            1 About the regression tests
  357. Xagent/test/TEST             12 Runs the full test suite
  358. Xagent/test/actions          12 Rule file for cmd tests
  359. Xagent/test/basic/              Basic tests
  360. Xagent/test/basic/config.t   13 Main test initialization and sanity checks
  361. Xagent/test/basic/filter.t   13 Make sure C filter works
  362. Xagent/test/basic/mailagent.t 13 Make sure mailagent basically works
  363. Xagent/test/cmd/                Tests of mailagent's filtering commands
  364. Xagent/test/cmd/abort.t      15 Test ABORT command
  365. Xagent/test/cmd/annotate.t   15 Test ANNOTATE command
  366. Xagent/test/cmd/assign.t     15 Test ASSIGN command
  367. Xagent/test/cmd/back.t       11 Test BACK command
  368. Xagent/test/cmd/begin.t      15 Test BEGIN command
  369. Xagent/test/cmd/bounce.t     15 Test BOUNCE command
  370. Xagent/test/cmd/delete.t     15 Test DELETE command
  371. Xagent/test/cmd/feed.t       15 Test FEED command
  372. Xagent/test/cmd/forward.t     7 Test FORWARD command
  373. Xagent/test/cmd/give.t       14 Test GIVE command
  374. Xagent/test/cmd/keep.t       14 Test KEEP command
  375. Xagent/test/cmd/leave.t      14 Test LEAVE command
  376. Xagent/test/cmd/message.t    15 Test MESSAGE command
  377. Xagent/test/cmd/nop.t        15 Test NOP command
  378. Xagent/test/cmd/notify.t     15 Test NOTIFY command
  379. Xagent/test/cmd/once.t       13 Test ONCE command
  380. Xagent/test/cmd/pass.t       15 Test PASS command
  381. Xagent/test/cmd/pipe.t       14 Test PIPE command
  382. Xagent/test/cmd/post.t       15 Test POST command
  383. Xagent/test/cmd/process.t    15 Test PROCESS command
  384. Xagent/test/cmd/purify.t     14 Test PURIFY command
  385. Xagent/test/cmd/queue.t      15 Test QUEUE command
  386. Xagent/test/cmd/record.t     14 Test RECORD command
  387. Xagent/test/cmd/reject.t     15 Test REJECT command
  388. Xagent/test/cmd/restart.t    15 Test RESTART command
  389. Xagent/test/cmd/resync.t     15 Test RESYNC command
  390. Xagent/test/cmd/run.t        14 Test RUN command
  391. Xagent/test/cmd/save.t       14 Test SAVE command
  392. Xagent/test/cmd/select.t     15 Test SELECT command
  393. Xagent/test/cmd/split.t       5 Test SPLIT command
  394. Xagent/test/cmd/store.t      14 Test STORE command
  395. Xagent/test/cmd/strip.t      14 Test STRIP command
  396. Xagent/test/cmd/subst.t      15 Test SUBST command
  397. Xagent/test/cmd/tr.t         15 Test TR command
  398. Xagent/test/cmd/unique.t     12 Test UNIQUE command
  399. Xagent/test/cmd/unknown.t    15 Make sure unknown command defaults correctly
  400. Xagent/test/cmd/vacation.t    4 Test VACATION command
  401. Xagent/test/cmd/write.t      13 Test WRITE command
  402. Xagent/test/filter/             Testing the filtering capabilities
  403. Xagent/test/filter/backref.t 15 Check backreferences
  404. Xagent/test/filter/default.t 14 Check default behaviour when mail not saved
  405. Xagent/test/filter/list.t    14 Check matching on lists like To and Newsgroups
  406. Xagent/test/filter/loop.t    15 Check loop detection
  407. Xagent/test/filter/multiple.t 14 Check multiple selectors
  408. Xagent/test/filter/pattern.t 15 Check patterns specification and loading
  409. Xagent/test/level            15 Default logging level for tests
  410. Xagent/test/mail             13 The mail used by testing routines
  411. Xagent/test/option/             Tests the options to the mailagent program
  412. Xagent/test/option/L.t        8 Test -L option
  413. Xagent/test/option/V.t       15 Test -V option
  414. Xagent/test/option/c.t       14 Test -c option
  415. Xagent/test/option/d.t       14 Test -d option
  416. Xagent/test/option/e.t       14 Test -e option
  417. Xagent/test/option/f.t       14 Test -f option
  418. Xagent/test/option/h.t       15 Test -h option
  419. Xagent/test/option/i.t       15 Test -i option
  420. Xagent/test/option/l.t       14 Test -l option
  421. Xagent/test/option/o.t       15 Test -o option
  422. Xagent/test/option/q.t       14 Test -q option
  423. Xagent/test/option/r.t       15 Test -r option
  424. Xagent/test/option/s.t        9 Test -s option
  425. Xagent/test/option/t.t       14 Test -t option
  426. Xagent/test/option/what.t    15 Ensure good behaviour with unknown option
  427. Xagent/test/pl/                 Perl libraries for the regression test suite
  428. Xagent/test/pl/cmd.pl        15 Initializes command paths
  429. Xagent/test/pl/filter.pl     15 Set up environment for filter tests
  430. Xagent/test/pl/init.pl       15 Variable initializations
  431. Xagent/test/pl/logfile.pl    13 Logging file checking
  432. Xagent/test/pl/mail.pl       14 Modifies mail components
  433. Xagent/test/rules            14 Rules used by filtering tests
  434. Xbin/perload                  7 The dataloading/autoloading perl translator
  435. Xconfig.h.SH                 10 Produces config.h
  436. Xinstall.SH                  10 Installation script
  437. Xpatchlevel.h                15 Current version number and patch level
  438. END_OF_FILE
  439.   if test 11453 -ne `wc -c <'PACKLIST'`; then
  440.     echo shar: \"'PACKLIST'\" unpacked with wrong size!
  441.   fi
  442.   # end of 'PACKLIST'
  443. fi
  444. if test -f 'agent/filter/parser.c' -a "${1}" != "-c" ; then 
  445.   echo shar: Will not clobber existing file \"'agent/filter/parser.c'\"
  446. else
  447.   echo shar: Extracting \"'agent/filter/parser.c'\" \(16295 characters\)
  448.   sed "s/^X//" >'agent/filter/parser.c' <<'END_OF_FILE'
  449. X/*
  450. X
  451. X #####     ##    #####    ####   ######  #####            ####
  452. X #    #   #  #   #    #  #       #       #    #          #    #
  453. X #    #  #    #  #    #   ####   #####   #    #          #
  454. X #####   ######  #####        #  #       #####    ###    #
  455. X #       #    #  #   #   #    #  #       #   #    ###    #    #
  456. X #       #    #  #    #   ####   ######  #    #   ###     ####
  457. X
  458. X    Parse a configuration file.
  459. X*/
  460. X
  461. X/*
  462. X * $Id: parser.c,v 2.9.1.2 92/11/01 15:42:10 ram Exp $
  463. X *
  464. X *  Copyright (c) 1992, Raphael Manfredi
  465. X *
  466. X *  You may redistribute only under the terms of the GNU General Public
  467. X *  Licence as specified in the README file that comes with dist.
  468. X *
  469. X * $Log:    parser.c,v $
  470. X * Revision 2.9.1.2  92/11/01  15:42:10  ram
  471. X * patch11: forgot inclusion of <sys/types.h> for possible pid_t
  472. X * 
  473. X * Revision 2.9.1.1  92/08/12  21:31:37  ram
  474. X * patch6: added security checks
  475. X * patch6: moved logfile initialization from main.c
  476. X * 
  477. X * Revision 2.9  92/07/14  16:48:36  ram
  478. X * 3.0 beta baseline.
  479. X * 
  480. X */
  481. X
  482. X#include "config.h"
  483. X#include "portable.h"
  484. X#include "hash.h"
  485. X#include "msg.h"
  486. X#include <sys/types.h>
  487. X#include "logfile.h"
  488. X#include "environ.h"
  489. X#include <stdio.h>
  490. X#include <ctype.h>
  491. X#include <pwd.h>
  492. X#include <sys/types.h>
  493. X#include <sys/stat.h>
  494. X
  495. X#ifdef I_STRING
  496. X#include <string.h>
  497. X#else
  498. X#include <strings.h>
  499. X#endif
  500. X
  501. X#ifndef GETHOSTNAME
  502. X#ifdef UNAME
  503. X#include <sys/utsname.h>
  504. X#endif
  505. X#endif
  506. X
  507. X#define MAX_STRING    2048            /* Maximum length for strings */
  508. X#define SYMBOLS        50                /* Expected number of symbols */
  509. X
  510. X/* Function declarations */
  511. Xpublic void read_conf();            /* Read configuration file */
  512. Xpublic void set_env_vars();            /* Set envrionment variables */
  513. Xprivate void secure();                /* Perform basic security checks on file */
  514. Xprivate void check_perm();            /* Check permissions on file */
  515. Xprivate void get_home();            /* Extract home from /etc/passwd */
  516. Xprivate void substitute();            /* Variable and ~ substitutions */
  517. Xprivate void add_home();            /* Replace ~ with home directory */
  518. Xprivate void add_variable();        /* Replace $var by its value */
  519. Xprivate void insert_value();        /* Record variable value in H table */
  520. Xprivate char *machine_name();        /* Return the machine name */
  521. Xprivate char *strip_down();            /* Strip down domain name from host name */
  522. Xprivate void strip_comment();        /* Strip trailing comment in config line */
  523. Xprivate void start_log();            /* Start up logging */
  524. X
  525. Xprivate char *home = (char *) 0;    /* Location of the home directory */
  526. Xpublic struct htable symtab;        /* Symbol table */
  527. X
  528. Xextern char *strsave();                /* Save string value in memory */
  529. Xextern struct passwd *getpwuid();    /* Fetch /etc/passwd entry from uid */
  530. Xextern char *getenv();                /* Get environment variable */
  531. X
  532. Xpublic void read_conf(file)
  533. Xchar *file;
  534. X{
  535. X    /* Read file in the home directory and build a symbol H table on the fly.
  536. X     * The ~ substitution and usual $var substitution occur (but not ${var}).
  537. X     */
  538. X    
  539. X    char path[MAX_STRING];            /* Full path of the config file */
  540. X    char *rules;                    /* Path of the rule file, if any */
  541. X    char mailagent[MAX_STRING];        /* Path of the configuration file */
  542. X    FILE *fd;                        /* File descriptor used for config file */
  543. X    int line = 0;                    /* Line number */
  544. X
  545. X    if (home == (char *) 0)            /* Home not already artificially set */
  546. X        get_home();                    /* Get home directory via /etc/passwd */
  547. X
  548. X    /* Build full path for configuration file, based on $HOME */
  549. X    strcpy(path, home);
  550. X    strcat(path, "/");
  551. X    strcat(path, file);
  552. X    strcpy(mailagent, path);        /* Save configuration path for later */
  553. X
  554. X    fd = fopen(path, "r");
  555. X    if (fd == (FILE *) 0)
  556. X        fatal("cannot open config file %s", path);
  557. X
  558. X    /* Initialize the H table */
  559. X    if (-1 == ht_create(&symtab, SYMBOLS))
  560. X        fatal("cannot create symbol table");
  561. X
  562. X    while((char *) 0 != fgets(path, MAX_STRING - 1, fd)) {
  563. X        line ++;                    /* One more line */
  564. X        substitute(path);            /* Standard parameter substitutions */
  565. X        insert_value(path, line);    /* Record value in hash table */
  566. X    }
  567. X    fclose(fd);
  568. X
  569. X
  570. X    /* Some security checks are in order here, or someone could set up a fake
  571. X     * a config file for us and then let the mailagent execute arbitrary 
  572. X     * commands under our uid. These tests are performed after the parsing of
  573. X     * the file, to allow logging of errors.
  574. X     */
  575. X
  576. X    start_log();                    /* Start up loging */
  577. X    secure(mailagent);                /* Perform basic security checks */
  578. X
  579. X    /* Final security check on the rule file, if provided. The constraints are
  580. X     * the same as those for the ~/.mailagent configuration file. This is
  581. X     * because a rule can specify a RUN command, which will start a process
  582. X     * with the user's privileges.
  583. X     */
  584. X
  585. X    rules = ht_value(&symtab, "rules");    /* Fetch rules location */
  586. X    if (rules == (char *) 0)            /* No rule file, that's fine */
  587. X        return;
  588. X
  589. X    check_perm(rules);                /* Might not exist, don't use secure() */
  590. X}
  591. X
  592. Xprivate void start_log()
  593. X{
  594. X    /* Start up logging, if possible. Note that not defining a logging
  595. X     * directory or a logging level is a fatal error.
  596. X     */
  597. X
  598. X    char logfile[MAX_STRING];        /* Location of logfile */
  599. X    char *value;                    /* Symbol value */
  600. X    int level = 0;                    /* Logging level wanted */
  601. X
  602. X    value = ht_value(&symtab, "logdir");    /* Fetch logging directory */
  603. X    if (value == (char *) 0)
  604. X        fatal("logging directory not defined");
  605. X    strcpy(logfile, value);
  606. X    strcat(logfile, "/");
  607. X
  608. X    value = ht_value(&symtab, "log");        /* Basename of the log file */
  609. X    if (value == (char *) 0)
  610. X        fatal("logfile not defined");
  611. X    strcat(logfile, value);
  612. X
  613. X    value = ht_value(&symtab, "level");        /* Fetch logging level */
  614. X    if (value == (char *) 0)
  615. X        fatal("no logging level defined");
  616. X    sscanf(value, "%d", &level);
  617. X
  618. X    set_loglvl(level);                        /* Logging level wanted */
  619. X    if (-1 == open_log(logfile))
  620. X        fprintf(stderr, "%s: cannot open logfile %s\n", progname, logfile);
  621. X}
  622. X
  623. Xprivate void secure(file)
  624. Xchar *file;
  625. X{
  626. X    /* Make sure the file is owned by the effective uid, and that it is not
  627. X     * world writable. Otherwise, simply abort with a fatal error.
  628. X     * Returning from this routine implies that the security checks succeeded.
  629. X     */
  630. X
  631. X    struct stat buf;        /* Statistics buffer */
  632. X
  633. X    if (-1 == stat(file, &buf)) {
  634. X        add_log(1, "SYSERR stat: %m (%e)");
  635. X        fatal("cannot stat file %s", file);
  636. X    }
  637. X
  638. X    check_perm(file);        /* Check permissions */
  639. X}
  640. X
  641. Xprivate void check_perm(file)
  642. Xchar *file;
  643. X{
  644. X    /* Check basic permissions on the specified file. If cannot be world
  645. X     * writable and must be owned by the user. If the file specified does not
  646. X     * exist, no error is reported however.
  647. X     */
  648. X
  649. X    struct stat buf;        /* Statistics buffer */
  650. X
  651. X    if (-1 == stat(file, &buf))
  652. X        return;
  653. X
  654. X#ifndef S_IWOTH
  655. X#define S_IWOTH 00002        /* Write permissions for other */
  656. X#endif
  657. X
  658. X    if (buf.st_mode & S_IWOTH)
  659. X        fatal("file %s is world writable!", file);
  660. X
  661. X    if (buf.st_uid != geteuid())
  662. X        fatal("file %s not owned by user!", file);
  663. X}
  664. X
  665. Xpublic char *homedir()
  666. X{
  667. X    return home;            /* Location of the home directory */
  668. X}
  669. X
  670. Xpublic void env_home()
  671. X{
  672. X    home = getenv("HOME");        /* For tests only -- see main.c */
  673. X    if (home != (char *) 0)
  674. X        home = strsave(home);    /* POSIX getenv() returns ptr to static data */
  675. X}
  676. X
  677. Xprivate void get_home()
  678. X{
  679. X    /* Get home directory out of /etc/passwd file */
  680. X
  681. X    struct passwd *pp;                /* Pointer to passwd entry */
  682. X
  683. X    pp = getpwuid(geteuid());
  684. X    if (pp == (struct passwd *) 0)
  685. X        fatal("cannot locate home directory");
  686. X    home = strsave(pp->pw_dir);
  687. X    if (home == (char *) 0)
  688. X        fatal("no more memory");
  689. X}
  690. X
  691. Xpublic void set_env_vars(envp)
  692. Xchar **envp;                /* The environment pointer */
  693. X{
  694. X    /* Set the all environment variable correctly. If the configuration file
  695. X     * defines a variable of the form 'p_host' where "host" is the lowercase
  696. X     * name of the machine (domain name stripped), then that value is prepended
  697. X     * to the current value of the PATH variable. We also set HOME and TZ if
  698. X     * there is a 'timezone' variable in the config file.
  699. X     */
  700. X
  701. X    char *machine = machine_name();        /* The machine name */
  702. X    char *path_val;                        /* Path value to append */
  703. X    char *tz;                            /* Time zone value */
  704. X    char name[MAX_STRING];                /* Built 'p_host' */
  705. X
  706. X    init_env(envp);                        /* Built the current environment */
  707. X
  708. X    /* If there is a path: entry in the ~/.mailagent, it is used to replace
  709. X     * then current PATH value. This entry is of course not mandatory. If not
  710. X     * present, we'll simply prepend the added path 'p_host' to the existing
  711. X     * value provided by sendmail, cron, or whoever invoked us.
  712. X     */
  713. X    path_val = ht_value(&symtab, "path");
  714. X    if (path_val != (char *) 0) {
  715. X        if (-1 == set_env("PATH", path_val))
  716. X            fatal("cannot initialize PATH");
  717. X    }
  718. X
  719. X    sprintf(name, "p_%s", machine);        /* Name of field in ~/.mailagent */
  720. X    path_val = ht_value(&symtab, name);    /* Exists ? */
  721. X    if (path_val != (char *) 0) {        /* Yes, prepend its value */
  722. X        add_log(19, "updating PATH with '%s' from config file", name);
  723. X        if (-1 == prepend_env("PATH", ":"))
  724. X            fatal("cannot set PATH variable");
  725. X        if (-1 == prepend_env("PATH", path_val))
  726. X            fatal("cannot set PATH variable");
  727. X    }
  728. X
  729. X    /* Also set a correct value for the home directory */
  730. X    if (-1 == set_env("HOME", home))
  731. X        fatal("cannot set HOME variable");
  732. X
  733. X    /* If there is a 'timezone' variable, set TZ accordingly */
  734. X    tz = ht_value(&symtab, "timezone");    /* Exists ? */
  735. X    if (tz != (char *) 0) {
  736. X        if (-1 == set_env("TZ", tz))
  737. X            add_log(1, "ERROR cannot set TZ variable");
  738. X    }
  739. X}
  740. X
  741. Xprivate void substitute(value)
  742. Xchar *value;
  743. X{
  744. X    /* Run parameter and ~ substitution in-place */
  745. X
  746. X    char buffer[MAX_STRING];        /* Copy on which we work */
  747. X    char *ptr = buffer;                /* To iterate over the buffer */
  748. X    char *origin = value;            /* Save origin pointer */
  749. X
  750. X    strcpy(buffer, value);            /* Make a copy of original line */
  751. X    while (*value++ = *ptr)            /* Line is updated in-place */
  752. X        switch(*ptr++) {
  753. X        case '~':                    /* Replace by home directory */
  754. X            add_home(&value);
  755. X            break;
  756. X        case '$':                    /* Variable substitution */
  757. X            add_variable(&value, &ptr);
  758. X            break;
  759. X        }
  760. X}
  761. X
  762. Xprivate void add_home(to)
  763. Xchar **to;                        /* Pointer to address in substituted text */
  764. X{
  765. X    /* Add home directory at the current location. If the 'home' symbol has
  766. X     * been found, use that instead.
  767. X     */
  768. X
  769. X    char *value = *to - 1;        /* Go back to overwrite the '~' */
  770. X    char *ptr = home;            /* Where home directory string is stored */
  771. X    char *symbol;                /* Symbol entry for 'home' */
  772. X
  773. X    if (strlen(home) == 0)        /* As a special case, this is empty when */
  774. X        ptr = "/";                /* referring to the root directory */
  775. X
  776. X    symbol = ht_value(&symtab, "home");        /* Maybe we saw  'home' already */
  777. X    if (symbol != (char *) 0)                /* Yes, we did */
  778. X        ptr = symbol;                        /* Use it for ~ substitution */
  779. X
  780. X    while (*value++ = *ptr++)    /* Copy string */
  781. X        ;
  782. X
  783. X    *to = value - 1;            /* Update position in substituted string */
  784. X}
  785. X
  786. Xprivate void add_variable(to, from)
  787. Xchar **to;                        /* Pointer to address in substituted text */
  788. Xchar **from;                    /* Pointer to address in original text */
  789. X{
  790. X    /* Add value of variable at the current location */
  791. X
  792. X    char *value = *to - 1;        /* Go back to overwrite the '$' */
  793. X    char *ptr = *from;            /* Start of variable's name */
  794. X    char buffer[MAX_STRING];    /* To hold the name of the variable */
  795. X    char *name = buffer;        /* To advance in buffer */
  796. X    char *dol_value;            /* $value of variable */
  797. X
  798. X    /* Get variable's name */
  799. X    while (*name++ = *ptr) {
  800. X        if (isalnum(*ptr))
  801. X            ptr++;
  802. X        else
  803. X            break;
  804. X    }
  805. X
  806. X    *(name - 1) = '\0';            /* Ensure null terminated string */
  807. X    *from = ptr;                /* Update pointer in original text */
  808. X
  809. X    /* Fetch value of variable recorded so far */
  810. X    dol_value = ht_value(&symtab, buffer);
  811. X    if (dol_value == (char *) 0)
  812. X        return;
  813. X
  814. X    /* Do the variable substitution */
  815. X    while (*value++ = *dol_value++)
  816. X        ;
  817. X    
  818. X    *to = value - 1;            /* Update pointer to substituted text */
  819. X}
  820. X
  821. Xprivate void insert_value(path, line)
  822. Xchar *path;                        /* The whole line */
  823. Xint line;                        /* The line number, for error reports */
  824. X{
  825. X    /* Analyze the line after parameter substitution and record the value of
  826. X     * the variable in the hash table. The line has the following format:
  827. X     *    name  :  value    # trailing comment
  828. X     * If only spaces are encoutered or if the first non blank value is a '#',
  829. X     * then the line is ignored. Otherwise, any error in parsing is reported.
  830. X     */
  831. X
  832. X    char name[MAX_STRING];                /* The name of the variable */
  833. X    char *nptr = name;                    /* To fill in the name buffer */
  834. X
  835. X    while (isspace(*path))                /* Skip leading spaces */
  836. X        path++;
  837. X
  838. X    if (*path == '#')                    /* A comment */
  839. X        return;                            /* Ignore the whole line */
  840. X    if (*path == '\0')                    /* A line full of spaces */
  841. X        return;                            /* Ignore it */
  842. X
  843. X    while (*nptr++ = *path) {            /* Copy everything until non alphanum */
  844. X        if (*path == '_') {                /* '_' is valid in variable names */
  845. X            path++;                        /* But is not an alphanumeric char */
  846. X            continue;
  847. X        } else if (!isalnum(*path++))    /* Reached a non-alphanumeric char */
  848. X            break;                        /* We got variable name */
  849. X    }
  850. X    *(nptr - 1) = '\0';                    /* Overwrite the ':' with '\0' */
  851. X    path--;                                /* Go back on non-alphanum char */
  852. X    while (*path)                        /* Now go and find the ':' */
  853. X        if (*path++ == ':')                /* Found it */
  854. X            break;
  855. X
  856. X    /* We reached the end of the string without seeing a ':' */
  857. X    if (*path == '\0') {
  858. X        fprintf(stderr, "syntax error in config file, line %d\n", line);
  859. X        return;
  860. X    }
  861. X
  862. X    while (isspace(*path))                    /* Skip leading spaces in value */
  863. X        path++;
  864. X    path[strlen(path) - 1] = '\0';            /* Chop final newline */
  865. X    strip_comment(path);                    /* Remove trailing comment */
  866. X    (void) ht_put(&symtab, name, path);        /* Add value into symbol table */
  867. X}
  868. X
  869. Xprivate void strip_comment(line)
  870. Xchar *line;
  871. X{
  872. X    /* Remove anything after first '#' on line (trailing comment) and also
  873. X     * strip any trailing spaces (including those right before the '#'
  874. X     * character).
  875. X     */
  876. X
  877. X    char *first = (char *) 0;        /* First space in sequence */
  878. X    char c;                            /* Character at current position */
  879. X
  880. X    while (c = *line++) {
  881. X        if (isspace(c) && first != (char *) 0)
  882. X            continue;
  883. X        if (c == '#') {                    /* This has to be a comment */
  884. X            if (first != (char *) 0)    /* Position of first preceding space */
  885. X                *first = '\0';            /* String ends at first white space */
  886. X            *(line - 1) = '\0';            /* Also truncate at '#' position */
  887. X            return;                        /* Done */
  888. X        }
  889. X        if (isspace(c))
  890. X            first = line - 1;            /* Record first space position */
  891. X        else
  892. X            first = (char *) 0;            /* Signal: no active first space */
  893. X    }
  894. X
  895. X    /* We have not found any '#' sign, so there is no comment in this line.
  896. X     * However, there might be trailing white spaces... Trim them.
  897. X     */
  898. X    
  899. X    if (first != (char *) 0)
  900. X        *first = '\0';                    /* Get rid of trailing white spaces */
  901. X}
  902. X
  903. Xprivate char *machine_name()
  904. X{
  905. X    /* Compute the local machine name, using only lower-cased names and
  906. X     * stipping down any domain name. The result points on a freshly allocated
  907. X     * string. A null pointer is returned in case of error.
  908. X     */
  909. X    
  910. X#ifdef GETHOSTNAME
  911. X    char name[MAX_STRING + 1];        /* The host name */
  912. X#else
  913. X#ifdef UNAME
  914. X    struct utsname un;                /* The internal uname structure */
  915. X#else
  916. X#ifdef PHOSTNAME
  917. X    char *command = PHOSTNAME;        /* Shell command to get hostname */
  918. X    FILE *fd;                        /* File descriptor on popen() */
  919. X    char name[MAX_STRING + 1];        /* The host name read from command */
  920. X    char buffer[MAX_STRING + 1];    /* Input buffer */
  921. X#endif
  922. X#endif
  923. X#endif
  924. X
  925. X#ifdef GETHOSTNAME
  926. X    if (-1 != gethostname(name, MAX_STRING))
  927. X        return strip_down(name);
  928. X
  929. X    add_log(1, "SYSERR gethostname: %m (%e)");
  930. X    return (char *) 0;
  931. X#else
  932. X#ifdef UNAME
  933. X    if (-1 != uname(&un))
  934. X        return strip_down(un.nodename);
  935. X
  936. X    add_log(1, "SYSERR uname: %m (%e)");
  937. X    return (char *) 0;
  938. X#else
  939. X#ifdef PHOSTNAME
  940. X    fd = popen(PHOSTNAME, "r");
  941. X    if (fd != (FILE *) 0) {
  942. X        fgets(buffer, MAX_STRING, fd);
  943. X        fclose(fd);
  944. X        sscanf(buffer, "%s", name);
  945. X        return strip_down(name);
  946. X    }
  947. X
  948. X    add_log(1, "SYSERR cannot run %s: %m (%e)", PHOSTNAME);
  949. X#endif
  950. X    return strip_down(HOSTNAME);
  951. X#endif
  952. X#endif
  953. X}
  954. X
  955. Xprivate char *strip_down(host)
  956. Xchar *host;
  957. X{
  958. X    /* Return a freshly allocated string containing the host name. The string
  959. X     * is lower-cased and the domain part is removed from the name.
  960. X     */
  961. X    
  962. X    char name[MAX_STRING + 1];        /* Constructed name */
  963. X    char *ptr = name;
  964. X    char c;
  965. X
  966. X    if (host == (char *) 0)
  967. X        return (char *) 0;
  968. X
  969. X    while (c = *host) {                /* Lower-case name */
  970. X        if (isupper(c))
  971. X            *ptr = tolower(c);
  972. X        else
  973. X            *ptr = c;
  974. X        if (c != '.') {                /* Found a domain delimiter? */
  975. X            host++;                    /* No, continue */
  976. X            ptr++;
  977. X        } else
  978. X            break;                    /* Yes, we end processing there */
  979. X    }
  980. X    *ptr = '\0';                    /* Ensure null-terminated string */
  981. X
  982. X    add_log(19, "hostname is %s", name);
  983. X
  984. X    return strsave(name);            /* Save string in memory */
  985. X}
  986. X
  987. END_OF_FILE
  988.   if test 16295 -ne `wc -c <'agent/filter/parser.c'`; then
  989.     echo shar: \"'agent/filter/parser.c'\" unpacked with wrong size!
  990.   fi
  991.   # end of 'agent/filter/parser.c'
  992. fi
  993. if test -f 'agent/pl/dbr.pl' -a "${1}" != "-c" ; then 
  994.   echo shar: Will not clobber existing file \"'agent/pl/dbr.pl'\"
  995. else
  996.   echo shar: Extracting \"'agent/pl/dbr.pl'\" \(10851 characters\)
  997.   sed "s/^X//" >'agent/pl/dbr.pl' <<'END_OF_FILE'
  998. X;# $Id: dbr.pl,v 2.9.1.3 92/11/10 10:13:10 ram Exp $
  999. X;#
  1000. X;#  Copyright (c) 1992, Raphael Manfredi
  1001. X;#
  1002. X;#  You may redistribute only under the terms of the GNU General Public
  1003. X;#  Licence as specified in the README file that comes with dist.
  1004. X;#
  1005. X;# $Log:    dbr.pl,v $
  1006. X;# Revision 2.9.1.3  92/11/10  10:13:10  ram
  1007. X;# patch12: unfortunate typo transformed all tags into UNKNOWN
  1008. X;# 
  1009. X;# Revision 2.9.1.2  92/11/01  15:46:56  ram
  1010. X;# patch11: now ensures correct hashed name and tags or uses defaults
  1011. X;# patch11: (reported by Nigel Metheringham <nigelm@ohm.york.ac.uk>)
  1012. X;# 
  1013. X;# Revision 2.9.1.1  92/08/26  13:09:51  ram
  1014. X;# patch8: update now recognizes undef parameters
  1015. X;# patch8: added a delete interface function
  1016. X;# 
  1017. X;# Revision 2.9  92/07/14  16:49:45  ram
  1018. X;# 3.0 beta baseline.
  1019. X;# 
  1020. X;# 
  1021. X;# This is a simple database. Items are sorted by key, and have a tag
  1022. X;# associated with it. Both are necessary to access the database. Every record
  1023. X;# also carries a time stamp and associated values.
  1024. X;#
  1025. X;# The hashing is done like that: If the key is shorter than two characters,
  1026. X;# an X is appended. Then, let 'a' and 'b' be the first and second character of
  1027. X;# the name. Then the file 'b' is stored under directory 'a', and in 'b' there
  1028. X;# are entries with the following format (separtion is the TAB character).
  1029. X;#
  1030. X;#     key tag timestamp <values>
  1031. X;#
  1032. Xpackage dbr;
  1033. X
  1034. X# Compute the relative path under the once directory for a given name
  1035. Xsub hash_path {
  1036. X    local($hname) = @_;
  1037. X    # Ensure at least 2 characters. Fill in missing chars with 'X'.
  1038. X    $hname .= "X" if (length($hname) < 2);
  1039. X    $hname .= "X" if (length($hname) < 2);
  1040. X    $hname =~ s/[^A-Za-z0-9_]/X/g;    # Don't want funny chars in path name
  1041. X    # Get only the 2 first characters
  1042. X    local(@chars) = split(//, substr($hname, 0, 2));
  1043. X    '/' . join('/', @chars);
  1044. X}
  1045. X
  1046. X# Fetch the entry in a dbr file and return the value of the timestamp and
  1047. X# the line number in the file. Return (0,0) if no previous record was found
  1048. X# for the name/tag association. An error is signaled by (-1,0). A line number
  1049. X# different from 0, as in (0, 10), indicates that an entry was found but the
  1050. X# selection did not succeed. Note that the timestamp returned is > 0 iff the
  1051. X# entry was found and the selection was done completely.
  1052. X# All the attached values are returned at the end of the list. It is possible
  1053. X# to filter among those values by specifying a list of regular expressions, at
  1054. X# the end of the argument list. An empty regular expression means the item is
  1055. X# not to be filtered on (equivalent of '/.*/'). Expressions provided are
  1056. X# taken as exact values to be matched against unless they start with '/' or '&'.
  1057. X# A '/' denotes a regular expression to be applied, whilst '&' denotes function
  1058. X# to be called with the actual value argument: function should return zero
  1059. X# for rejection or any other value for selection.
  1060. Xsub info {
  1061. X    local($hname, $tag, @what) = @_;
  1062. X    local($file);                        # DBR file associated with '$hname'
  1063. X    local(@values);                        # Attached values to the item
  1064. X    local($_);
  1065. X    ($hname, $tag) = &default($hname, $tag);
  1066. X    $file = $cf'hashdir . &hash_path($hname);
  1067. X    return (0,0) unless -f "$file";
  1068. X    unless (open(DBR, $file)) {
  1069. X        &'add_log("ERROR could not open dbr file $file: $!") if $'loglvl;
  1070. X        return (-1, 0);
  1071. X    }
  1072. X    local($linenum) = 0;                # Value of line if found
  1073. X    local($timestamp) = 0;                # Associated time stamp
  1074. X    &'acs_rqst($file);                    # Lock file (avoid concurrent updating)
  1075. X    while (<DBR>) {
  1076. X        if (s/^(\S+)\s([\w-]+)\s(\d+)\t*//) {
  1077. X            next unless $1 eq $hname;
  1078. X            next unless $2 eq $tag;
  1079. X            $linenum = $.;                # Record line number
  1080. X            $timestamp = int($3);        # And timestamp
  1081. X            last if &match;                # Found it if matches @what filter
  1082. X            $timestamp = 0;                # Not found yet
  1083. X        } else {                        # Invalid entry
  1084. X            &'add_log("ERROR $file corrupted, line $.") if $'loglvl;
  1085. X            $timestamp = -1;            # Signals error
  1086. X            last;                        # Abort processing
  1087. X        }
  1088. X    }
  1089. X    &'free_file($file);                    # Remove lock on file
  1090. X    close DBR;                            # Close file
  1091. X    ($timestamp, $linenum, @values);    # Return item information
  1092. X}
  1093. X
  1094. X# Apply match from @what, and fill in @values as a side effect if matched.
  1095. Xsub match {
  1096. X    local(@target) = split(/\t|\n/);    # Get values from line
  1097. X    local($idx) = -1;                    # Index within @target
  1098. X    local($matched) = 1;                # Assume selection will match
  1099. X    local($res);                        # Eval result
  1100. X    local($@);                            # Eval error report string
  1101. X    foreach $what (@what) {
  1102. X        $idx++;                            # Advance in @target
  1103. X        next if $what eq '';            # Skip empty selection
  1104. X        if ($what =~ m|^/|) {            # Regular expression
  1105. X            $res = eval '$target[$idx] =~ ' . $what;
  1106. X            &'add_log("WARNING dbr error: $@") if $@ && $'loglvl > 5;
  1107. X            next if $@;
  1108. X            $matched = $res;
  1109. X        } elsif ($what =~ m|^&|) {        # Function to apply
  1110. X            $res = eval "$what('" . $target[$idx] . "')";
  1111. X            &'add_log("WARNING dbr error: $@") if chop($@) && $'loglvl > 5;
  1112. X            next if $@;
  1113. X            $matched = $res;
  1114. X        } else {                        # Regular string comparaison
  1115. X            $matched = $target[$idx] eq $what;
  1116. X        }
  1117. X        last unless $matched;
  1118. X    }
  1119. X    @values = @target if $matched;        # Fill in values if selection ok
  1120. X    $matched;                            # Return matching status
  1121. X}
  1122. X
  1123. X# Update the entry ($hname, $tag) in file to hold the current timestamp. If the
  1124. X# $linenum parameter is non-null, we know we may copy the old file until that
  1125. X# line (excluded), then replace the current line with the new timestamp.
  1126. X# If $linenum is null, then we may safely append the entry in the file. If
  1127. X# the $linenum parameter is 'undef', then the user does not have it precomputed
  1128. X# or wishes to have the line number re-computed.
  1129. X# The new values held in @values replace the old ones for the entry. If 'undef'
  1130. X# is given instead, then the corresponding entry is deleted from the database.
  1131. Xsub update {
  1132. X    local($hname, $tag, $linenum, @values) = @_;
  1133. X    local($now) = time;                    # Current time
  1134. X    local($file);                        # DBR file associated with '$hname'
  1135. X    local($_);
  1136. X    ($hname, $tag) = &default($hname, $tag);
  1137. X    $file = $cf'hashdir . &hash_path($hname);
  1138. X    unless (-f "$file") {
  1139. X        local($dirname) = $file =~ m|^(.*)/.*|;
  1140. X        &'makedir($dirname);
  1141. X    }
  1142. X    $linenum = (&info($hname, $tag))[1] unless defined($linenum);
  1143. X    if ($linenum == 0) {                # No entry previously recorded
  1144. X        return unless defined(@values);    # Nothing to delete
  1145. X        unless(open(DBR, ">>$file")) {
  1146. X            &'add_log("ERROR cannot append in $file: $!") if $'loglvl;
  1147. X            return;
  1148. X        }
  1149. X        &'acs_rqst($file);                # Lock file (avoid concurrent updating)
  1150. X        print DBR "$hname $tag $now\t";    # The name, command tag and timestamp
  1151. X        print DBR join("\t", @values);    # Associated values
  1152. X        print DBR "\n";
  1153. X        close DBR;
  1154. X        &'free_file($file);                # Remove lock on file
  1155. X    } else {                            # An entry existed already
  1156. X        unless (open(DBR, ">$file.x")) {
  1157. X            &'add_log("ERROR cannot create $file.x: $!") if $'loglvl;
  1158. X            return;
  1159. X        }
  1160. X        unless (open(OLD, "$file")) {
  1161. X            &'add_log("ERROR couldn't reopen $file: $!") if $'loglvl;
  1162. X            close DBR;
  1163. X            return;
  1164. X        }
  1165. X        &'acs_rqst($file);                # Lock file (avoid concurrent updating)
  1166. X        while (<OLD>) {
  1167. X            if ($. < $linenum) {        # Before line to update
  1168. X                print DBR;                # Print line verbatim
  1169. X            } elsif ($. == $linenum) {    # We reached line to be updated
  1170. X                next unless defined(@values);
  1171. X                print DBR "$hname $tag $now\t";
  1172. X                print DBR join("\t", @values);
  1173. X                print DBR "\n";
  1174. X            } else {                    # Past updating point
  1175. X                print DBR;                # Print line verbatim
  1176. X            }
  1177. X        }
  1178. X        close OLD;
  1179. X        close DBR;
  1180. X        unless (rename("$file.x", "$file")) {
  1181. X            &'add_log("ERROR cannot rename $file.x to $file: $!") if $'loglvl;
  1182. X        }
  1183. X        &'free_file($file);                # Remove lock on file
  1184. X    }
  1185. X}
  1186. X
  1187. X# Delete entry. This is really a wrapper to the more general update routine
  1188. X# and is provided as a convenience only.
  1189. Xsub delete {
  1190. X    local($hname, $tag, $linenum) = @_;
  1191. X    &update($hname, $tag, defined($linenum) ? $linenum : undef, undef);
  1192. X}
  1193. X
  1194. X# Make sure the hashing name and the tag are correct, or use default values.
  1195. Xsub default {
  1196. X    local($hname, $tag) = @_;
  1197. X    $hname =~ s/^\s+//;                    # Leading blanks would perturb dbr
  1198. X    $hname =~ s/\s/_/g;                    # All other spaces replaced by _
  1199. X    $hname = 'X' unless $hname;            # Hashing name cannot be empty
  1200. X    $tag =~ s/\s/_/g;                    # Tag has to be a single word
  1201. X    $tag = 'UNKNOWN' unless $tag;        # Tag cannot be empty
  1202. X    ($hname, $tag);
  1203. X}
  1204. X
  1205. X# Cleaning operation. Remove all the entries in the file whose timestamp is
  1206. X# older than the supplied date limit.
  1207. Xsub clean {
  1208. X    local($agemax) = @_;
  1209. X    local($limit) = time - $agemax;        # Everything newer is kept
  1210. X    &recursive_clean($cf'hashdir);        # Recursively scan directory
  1211. X}
  1212. X
  1213. X# Recursively scan the direcroy and deal with each file
  1214. Xsub recursive_clean {
  1215. X    local($dir) = @_;                    # Directory to scan
  1216. X    local(@contents);                    # Contents of the directory
  1217. X    unless (opendir(DIR, $dir)) {
  1218. X        &'add_log("WARNING cannot open directory $dir: $!") if $'loglvl > 5;
  1219. X        return;
  1220. X    }
  1221. X    @contents = readdir(DIR);            # Slurp the whole thing
  1222. X    close DIR;                            # And close dir, ready for recursion
  1223. X    local($_);
  1224. X    foreach (@contents) {
  1225. X        next if $_ eq '.' || $_ eq '..';
  1226. X        if (-d "$dir/$_") {
  1227. X            &recursive_clean("$dir/$_");
  1228. X            next;
  1229. X        }
  1230. X        &clean_file("$dir/$_");
  1231. X    }
  1232. X    unless (opendir(DIR, $dir)) {
  1233. X        &'add_log("WARNING cannot re-open directory $dir: $!") if $'loglvl > 5;
  1234. X        return;
  1235. X    }
  1236. X    @contents = readdir(DIR);            # Slurp the whole thing
  1237. X    close DIR;
  1238. X    unless (@contents > 2) {            # Has at least . and ..
  1239. X        unless (rmdir($dir)) {            # Don't leave empty directories
  1240. X            &'add_log("SYSERR rmdir: $!") if $'loglvl;
  1241. X            &'add_log("ERROR could not remove directory $file") if $'loglvl;
  1242. X        }
  1243. X    }
  1244. X}
  1245. X
  1246. X# Clean single dbr file, using $limit as the oldest allowed time stamp
  1247. Xsub clean_file {
  1248. X    local($file) = @_;            # File to be cleaned
  1249. X    &'add_log("processing $file") if $'loglvl > 18;
  1250. X    unless (open(FILE, $file)) {
  1251. X        &'add_log("WARNING cannot open file $file: $!") if $'loglvl > 5;
  1252. X        return;
  1253. X    }
  1254. X    unless (open(NEW, ">$file.x")) {
  1255. X        &'add_log("ERROR cannot create $file.x: $!") if $'loglvl > 1;
  1256. X        close FILE;
  1257. X        return;
  1258. X    }
  1259. X    &'acs_rqst($file);            # Lock file to prevent concurrent mods
  1260. X    local($warns) = 0;            # Avoid cascade warnings
  1261. X    local($_, $.);
  1262. X    while (<FILE>) {
  1263. X        if (/^(\S+)\s([\w-]+)\s(\d+)\t*/) {
  1264. X            # Variable $limit was set in 'clean'
  1265. X            if ($3 > $limit) {            # File new enough
  1266. X                next if (print NEW);    # Copy line verbatim
  1267. X                &'add_log("SYSERR write: $!") if $'loglvl;
  1268. X                &'add_log("WARNING truncated $file at line $.") if $'loglvl > 5;
  1269. X                last;
  1270. X            }
  1271. X        } else {
  1272. X            # Skip bad lines, up to a maximum of 10
  1273. X            if (++$warns > 10) {
  1274. X                &'add_log("WARNING $file truncated at line $.") if $'loglvl > 5;
  1275. X                last;
  1276. X            } else {
  1277. X                &'add_log("NOTICE $file corrupted, line $.") if $'loglvl > 6;
  1278. X                next;
  1279. X            }
  1280. X        }
  1281. X    }
  1282. X    close FILE;
  1283. X    close NEW;
  1284. X    unless (rename("$file.x", $file)) {
  1285. X        &'add_log("ERROR cannot rename $file.x to $file: $!") if $'loglvl;
  1286. X    }
  1287. X    unless (-s "$file") {
  1288. X        unless (unlink($file)) {    # Don't leave empty files behind
  1289. X            &'add_log("SYSERR unlink: $!") if $'loglvl;
  1290. X            &'add_log("ERROR could not remove $file") if $'loglvl;
  1291. X        }
  1292. X    }
  1293. X    &'free_file($file);                # Remove lock on file
  1294. X}
  1295. X
  1296. Xpackage main;
  1297. X
  1298. END_OF_FILE
  1299.   if test 10851 -ne `wc -c <'agent/pl/dbr.pl'`; then
  1300.     echo shar: \"'agent/pl/dbr.pl'\" unpacked with wrong size!
  1301.   fi
  1302.   # end of 'agent/pl/dbr.pl'
  1303. fi
  1304. if test -f 'agent/test/cmd/run.t' -a "${1}" != "-c" ; then 
  1305.   echo shar: Will not clobber existing file \"'agent/test/cmd/run.t'\"
  1306. else
  1307.   echo shar: Extracting \"'agent/test/cmd/run.t'\" \(294 characters\)
  1308.   sed "s/^X//" >'agent/test/cmd/run.t' <<'END_OF_FILE'
  1309. X# The RUN command
  1310. Xdo '../pl/cmd.pl';
  1311. Xunlink 'ok';
  1312. X
  1313. X&add_header('X-Tag: run');
  1314. X`$cmd`;
  1315. X$? == 0 || print "1\n";
  1316. X-f "$user" && print "2\n";        # Mail not saved
  1317. X-f 'ok' || print "3\n";            # Output of /bin/echo
  1318. X&get_log(4, 'ok');
  1319. X&check_log('Works.', 5);        # It works
  1320. X
  1321. Xunlink 'ok', 'mail';
  1322. Xprint "0\n";
  1323. END_OF_FILE
  1324.   if test 294 -ne `wc -c <'agent/test/cmd/run.t'`; then
  1325.     echo shar: \"'agent/test/cmd/run.t'\" unpacked with wrong size!
  1326.   fi
  1327.   # end of 'agent/test/cmd/run.t'
  1328. fi
  1329. echo shar: End of archive 9 \(of 17\).
  1330. cp /dev/null ark9isdone
  1331. MISSING=""
  1332. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ; do
  1333.     if test ! -f ark${I}isdone ; then
  1334.     MISSING="${MISSING} ${I}"
  1335.     fi
  1336. done
  1337. if test "${MISSING}" = "" ; then
  1338.     echo You have unpacked all 17 archives.
  1339.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1340. else
  1341.     echo You still must unpack the following archives:
  1342.     echo "        " ${MISSING}
  1343. fi
  1344. exit 0
  1345. exit 0 # Just in case...
  1346.