home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume18 / elm2.2 / part08 < prev    next >
Encoding:
Internet Message Format  |  1989-04-12  |  49.2 KB

  1. Subject:  v18i087:  Elm mail system, release 2.2, Part08/24
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: dsinc!syd@uunet.UU.NET (Syd Weinstein)
  7. Posting-number: Volume 18, Issue 87
  8. Archive-name: elm2.2/part08
  9.  
  10. #!/bin/sh
  11. # this is part 8 of a multipart archive
  12. # do not concatenate these parts, unpack them in order with /bin/sh
  13. # file doc/tmac.n continued
  14. #
  15. CurArch=8
  16. if test ! -r s2_seq_.tmp
  17. then echo "Please unpack part 1 first!"
  18.      exit 1; fi
  19. ( read Scheck
  20.   if test "$Scheck" != $CurArch
  21.   then echo "Please unpack part $Scheck next!"
  22.        exit 1;
  23.   else exit 0; fi
  24. ) < s2_seq_.tmp || exit 1
  25. echo "x - Continuing file doc/tmac.n"
  26. sed 's/^X//' << 'SHAR_EOF' >> doc/tmac.n
  27. X.    ef                \" short and sweet ...
  28. X.\}
  29. X..
  30. X.de ux                    \" print "UNIX"
  31. X.ie \\n(ux \\&\\$2\\s-1UNIX\\s0\\$1
  32. X.el \{\
  33. X.    nr ux +1            \" mark footnote as dropped
  34. X\\&\\$2\\s-1UNIX\\s0\\*(rg\\$1
  35. X.    fn                \" put out the footnote
  36. X\\&\\*(rgUNIX is a registered trademark of AT&T.
  37. X.    ef                \" short and sweet ...
  38. X.\}
  39. X..
  40. X.de vx                    \" print "VAX"
  41. X.ie \\n(vx \\&\\$2\\s-1VAX\\s0\\$1
  42. X.el \{\
  43. X.    nr vx +1            \" mark footnote as dropped
  44. X\\&\\$2\\s-1VAX\\s0\\*(rg\\$1
  45. X.    fn                \" put out the footnote
  46. X\\&\\*(rgVAX is a trademark of Digital Equipment Corporation.
  47. X.    ef                \" short and sweet ...
  48. X.\}
  49. X..
  50. X.\" **********
  51. X.\" set up string and number registers
  52. X.                    \" set up for the date
  53. X.if \n(mo=1  .ds mo January
  54. X.if \n(mo=2  .ds mo February
  55. X.if \n(mo=3  .ds mo March
  56. X.if \n(mo=4  .ds mo April
  57. X.if \n(mo=5  .ds mo May
  58. X.if \n(mo=6  .ds mo June
  59. X.if \n(mo=7  .ds mo July
  60. X.if \n(mo=8  .ds mo August
  61. X.if \n(mo=9  .ds mo September
  62. X.if \n(mo=10 .ds mo October
  63. X.if \n(mo=11 .ds mo November
  64. X.if \n(mo=12 .ds mo December
  65. X.ds dy "\*(mo \n(dy, 19\n(yr
  66. X.if \n(dw=1  .ds dw Sunday
  67. X.if \n(dw=2  .ds dw Monday
  68. X.if \n(dw=3  .ds dw Tuesday
  69. X.if \n(dw=4  .ds dw Wednesday
  70. X.if \n(dw=5  .ds dw Thursday
  71. X.if \n(dw=6  .ds dw Friday
  72. X.if \n(dw=7  .ds dw Saturday
  73. X.                    \" NROFF dependencies
  74. X.if n \{\
  75. X.                    \" string registers
  76. X.    ds rg (R)
  77. X.    ds lq ""
  78. X.    ds rq ""
  79. X.    ds f1 "\*(dy
  80. X.                    \" number registers
  81. X.    nr hs 1v            \" space before section header
  82. X.    nr pd 1v            \" inter-paragraph spacing
  83. X.    nr bm 1.0i            \" height of bottom margin
  84. X.\}
  85. X.                    \" NROFF dependencies
  86. X.if t \{\
  87. X.                    \" string registers
  88. X.    ds rg \\u\\s-2\\(rg\\s0\\d
  89. X.    ds lq ``
  90. X.    ds rq ''
  91. X.                    \" number registers
  92. X.    nr hs 1v            \" space before section header
  93. X.    nr pd 0.3v            \" inter-paragraph spacing
  94. X.    nr bm 1.0i+1v            \" height of bottom margin (wacky laser)
  95. X.\}
  96. X.                    \" these are the same for [NT]ROFF
  97. X.ds dg \(dg
  98. X.ds vr "News Version B2.11
  99. X.ds pv "News macros 1.5
  100. X.ds h1 - % -
  101. X.nr bt 0.5i+1v                \" bottom of page to footer
  102. X.nr cm 0                \" no cut marks
  103. X.nr fc 0 1                \" init footnote count
  104. X.nr fl 5.5i                \" footnote line length
  105. X.nr fp 0-\n(bmu                \" fo macro trap location
  106. X.nr h0 0                \" init section header level 0
  107. X.nr h1 0                \" init section header level 1
  108. X.nr h2 0                \" init section header level 2
  109. X.nr h3 0                \" init section header level 3
  110. X.nr id 0                \" 1 in display
  111. X.nr if 0                \" 1 in keep
  112. X.nr it 0                \" 1 when beyond title, etc.
  113. X.nr li 5n                \" indent for labelled paragraph
  114. X.nr ll 6.5i                \" line length
  115. X.nr lm 0                \" left margin
  116. X.nr l0 0                \" first indent level
  117. X.nr mt 1.5i+1v                \" title goes down this far
  118. X.nr pi 5n                \" regular paragraph indent
  119. X.nr po 1.0i                \" page offset
  120. X.nr ps 10                \" point size
  121. X.nr tm 1.0i                \" height of top margin
  122. X.nr tt 0.5i-0.5v            \" top of page to header
  123. X.nr p1 0                \" no PDP-TM message yet
  124. X.nr ux 0                \" no UNIX-TM message yet
  125. X.nr vx 0                \" no VAX-TM message yet
  126. X.nr vs 12                \" vertical spacing
  127. X.\" set things up
  128. X.\" DSINC changes for XROFF
  129. X.nr f1 1
  130. X.nr f2 1
  131. X.nr s1 10
  132. X.nr s2 10
  133. X.nr v1 12
  134. X.nr v2 12
  135. X.ps 10
  136. X.vs 12
  137. X.\" DSINC end changes for XROFF
  138. X.po \n(pou                \" set page offset
  139. X.ps \n(ps                \" set previous, current
  140. X.ps \n(ps                \"   point sizes
  141. X.vs \n(vs                \" set previous, current
  142. X.vs \n(vs                \"   vertical spacings
  143. X.ll \n(llu                \" set line length
  144. X.lt \n(llu                \" set title line length
  145. X.ev 1                    \" *** footnote environment
  146. X.ps \n(ps-2p                \" set previous, current
  147. X.ps \n(ps-2p                \"   point sizes
  148. X.vs \n(vs-2p                \" set previous, current
  149. X.vs \n(vs-2p                \"   vertical spacings
  150. X.ll \n(flu                \" set line length
  151. X.lt \n(flu                \" set title line length
  152. X.ev                    \" *** pop environment
  153. X.ev 2                    \" *** footnote environment
  154. X.ps \n(ps                \" set previous, current
  155. X.ps \n(ps                \"   point sizes
  156. X.vs \n(vs                \" set previous, current
  157. X.vs \n(vs                \"   vertical spacings
  158. X.ll \n(llu                \" set line length
  159. X.lt \n(llu                \" set title line length
  160. X.ev                    \" *** pop environment
  161. X.\" now set internal registers (for the first header section)
  162. X.nr f1 \n(.f                \" saved font #1
  163. X.nr f2 \n(.f                \" saved font #2
  164. X.nr s1 \n(.s                \" saved point size #1
  165. X.nr s2 \n(.s                \" saved point size #2
  166. X.nr v1 \n(.v                \" saved vertical spacing #1
  167. X.nr v2 \n(.v                \" saved vertical spacing #2
  168. X.\" install traps
  169. X.wh 0i hd                \" position header trap
  170. X.wh -\n(bmu fo                \" position footer trap
  171. X.wh \n(.pu+1i fx            \" put footnote overflow trap here
  172. X.ch fx -\n(bmu                \" move it over fo
  173. X.wh -\n(btu pf                \" print the bottom margin here
  174. X.em et                    \" at end of file, call et
  175. X.\" couple of miscellaneous requests
  176. X.bd S 3 3                \" embolden special font chars if B
  177. X.hy 2                    \" don't hyphenate last lines
  178. SHAR_EOF
  179. echo "File doc/tmac.n is complete"
  180. chmod 0444 doc/tmac.n || echo "restore of doc/tmac.n fails"
  181. echo "x - extracting doc/wnewmail.1 (Text)"
  182. sed 's/^X//' << 'SHAR_EOF' > doc/wnewmail.1 &&
  183. X.TH WNEWMAIL 1L "Elm Version 2.2" "USENET Community Trust"
  184. X.ad b
  185. X.SH NAME
  186. Xwnewmail - daemon to asynchronously notify of new mail
  187. X.SH SYNOPSIS
  188. X.B wnewmail
  189. X.br
  190. X.B wnewmail
  191. Xfilename
  192. X.PP
  193. X.SH DESCRIPTION
  194. X.I Wnewmail\^
  195. Xis a daemon designed to run in \fBa window\fR on a windowing
  196. Xsystem (such as an HP or Sun system) and check every 10 seconds
  197. Xto see if there is any new mail for the user that
  198. Xstarted it up.
  199. X.P
  200. XIf there is new mail, the program will "beep", and write to
  201. Xthe window for each of the new messages;
  202. X.nf
  203. X
  204. X   Mail from <name> -- <subject>
  205. X
  206. X.fi
  207. Xwhere <name> is either the name of the person sending it,
  208. Xif available (the ARPA 'From:' line) or machine!login where
  209. Xmachine is the machine the mail was sent from.  If there
  210. Xis no subject, the message "<no subject>" will appear on
  211. Xthe screen.
  212. X.P
  213. XIf the message is a \fIpriority\fR message (that is, the
  214. Xheader contains a line "Priority:"), then the line output
  215. Xwill be "PRIORITY mail from ..." rather than just "Mail from".
  216. X.P
  217. XThis program will run forever, and can internally reset 
  218. Xitself if mail is deleted from the incoming mailbox while
  219. Xtrying to monitor it.
  220. X.P
  221. XIf \fBwnewmail\fR is started up with a filename, it will
  222. Xperform exactly the same, but with the specified file as
  223. Xthe one to check rather than the default users mailbox.
  224. X.SH AUTHOR
  225. XDave Taylor, Hewlett-Packard Laboratories.
  226. X.SH SEE ALSO
  227. Xnotify in sh(1) or csh(1), newmail(1L)
  228. X.SH NOTE
  229. XThis is almost identical to the program \fBnewmail\fR...
  230. X.SH BUG REPORTS TO
  231. XSyd Weinstein    elm@dsinc.UUCP    (dsinc!elm)
  232. X.SH COPYRIGHTS
  233. X.ps 18
  234. X\fB\(co\fR\s12 Copyright 1986, 1987 by Dave Taylor
  235. X.br
  236. X.ps 18
  237. X\fB\(co\fR\s12 Copyright 1988, 1989 by The USENET Community Trust
  238. SHAR_EOF
  239. chmod 0444 doc/wnewmail.1 || echo "restore of doc/wnewmail.1 fails"
  240. echo "x - extracting filter/Makefile.SH (Text)"
  241. sed 's/^X//' << 'SHAR_EOF' > filter/Makefile.SH &&
  242. Xcase $CONFIG in
  243. X'')
  244. X    if test ! -f config.sh; then
  245. X    ln ../config.sh . || \
  246. X    ln ../../config.sh . || \
  247. X    ln ../../../config.sh . || \
  248. X    (echo "Can't find config.sh."; exit 1)
  249. X    fi
  250. X    . ./config.sh
  251. X    ;;
  252. Xesac
  253. Xcase "$0" in
  254. X*/*) cd `expr X$0 : 'X\(.*\)/'` ;;
  255. Xesac
  256. X
  257. Xecho "Extracting filter/Makefile (with variable substitutions)"
  258. Xcat >Makefile <<!GROK!THIS!
  259. X#
  260. X# @(#)$Id: Makefile.SH,v 2.11 89/03/25 21:45:09 syd Exp $
  261. X#  Makefile for the Elm system filter program
  262. X#
  263. X#    Copyright (c) 1986, 1987 Dave Taylor
  264. X#    Copyright (c) 1988, 1989 USENET Community Trust
  265. X#
  266. X# Bug reports, patches, comments, suggestions should be sent to:
  267. X#
  268. X#    Syd Weinstein - elm@dsinc.UUCP
  269. X#            dsinc!elm
  270. X#
  271. X#  $Log:    Makefile.SH,v $
  272. X# Revision 2.11  89/03/25  21:45:09  syd
  273. X# Initial 2.2 Release checkin
  274. X# 
  275. X#
  276. X# Variables
  277. X#    Variables established by Configure
  278. XCC        =    $cc
  279. XCCFLAGS        =    $ccflags $xencf
  280. XCHGRP        =    $chgrp
  281. XCHMOD        =    $chmod
  282. XCP        =    $cp
  283. XDEST        =    $bin
  284. XECHO        =    $echo
  285. XLFLAGS        =    $ldflags $xenlf
  286. XLIB        =    $lib
  287. XLIB2        =     $libs
  288. XLIBS        =    $termlib $dbm
  289. XLINT        =    $lint
  290. XMAILGRP        =    $mailgrp
  291. XMAILERMODE    =    $mailermode
  292. XMAKE        =    $make
  293. XMV        =    $mv
  294. XOPTIMIZE    =    $optimize
  295. XRM        =     $rm -f
  296. XTOUCH        =    $touch
  297. X
  298. X!GROK!THIS!
  299. X
  300. Xcat >>Makefile <<'!NO!SUBS!'
  301. X#    Variables you may want to manually edit
  302. X#        If you want debug logging then you'll
  303. X#        want to uncomment the following.
  304. X#DEBUG        =    -DDEBUG
  305. X
  306. X#    Other variables
  307. XBIN        =    ../bin
  308. XINCLDIR        =    ../hdrs
  309. XCFLAGS        =    $(CCFLAGS) $(OPTIMIZE) -I$(INCLDIR) $(DEBUG) $(DACSNET) 
  310. XLINTFLAGS    =    -I$(INCLDIR)
  311. XSHELL        =    /bin/sh
  312. X
  313. X# Definitions of variables
  314. XFILTER_SRC    =    actions.c    \
  315. X            buffer.c    \
  316. X            filter.c    \
  317. X            lock.c        \
  318. X            parse.c        \
  319. X            rules.c        \
  320. X            summarize.c    \
  321. X            utils.c        \
  322. X            ../src/opt_utils.c
  323. X
  324. XFILTER_OBJ    =    actions.o    \
  325. X            buffer.o    \
  326. X            filter.o    \
  327. X            lock.o        \
  328. X            parse.o        \
  329. X            rules.o        \
  330. X            summarize.o    \
  331. X            utils.o        \
  332. X            ../src/opt_utils.o
  333. X
  334. X# Standard targets
  335. Xall:        $(BIN)/filter
  336. X        
  337. Xinstall:    $(DEST)/filter
  338. X
  339. Xuninstall:    
  340. X        $(RM) $(DEST)/filter
  341. X
  342. X#    This is the only target that gets installed even if not out-of-date
  343. X#    with respect the files from which it is installed.
  344. Xrmt-install:    rmt-defined
  345. X        -$(MV) $(DEST)/filter $(DEST)/filter.old
  346. X        -$(RM) $(DEST)/filter.old
  347. X        $(CP) $(REMOTE)$(DEST)/filter $(DEST)/filter
  348. X        $(CHGRP) $(MAILGRP) $(DEST)/filter
  349. X        $(CHMOD) $(MAILERMODE) $(DEST)/filter
  350. X
  351. Xrmt-defined:
  352. X    @(if [ "$(REMOTE)" = "" ];\
  353. X      then\
  354. X        $(ECHO) "You need to define 'REMOTE' as the remote file system";\
  355. X        $(ECHO) "for this particular command. The easiest way to do this";\
  356. X        $(ECHO) "to type:";\
  357. X        $(ECHO) "        make REMOTE=<remote file system> rmt-install";\
  358. X        exit 1;\
  359. X      fi);
  360. X
  361. Xlint:        
  362. X        $(LINT) $(LINTFLAGS) $(FILTER_SRC) > LINT.OUT
  363. X
  364. Xclean:        
  365. X        $(RM) $(FILTER_OBJ) $(BIN)/filter
  366. X
  367. X# Dependencies and rules
  368. X#    Dependencies of header files upon other header files they include
  369. X$(INCLDIR)/defs.h:    $(INCLDIR)/../config.h $(INCLDIR)/sysdefs.h
  370. X            $(CHMOD) u+w $@
  371. X            $(TOUCH) $@
  372. X
  373. X$(INCLDIR)/elm.h:    $(INCLDIR)/curses.h $(INCLDIR)/defs.h
  374. X            $(CHMOD) u+w $@
  375. X            $(TOUCH) $@
  376. X
  377. X$(INCLDIR)/headers.h:    $(INCLDIR)/curses.h $(INCLDIR)/defs.h
  378. X            $(CHMOD) u+w $@
  379. X            $(TOUCH) $@
  380. X
  381. X#    Dependencies and rules for C object files
  382. Xactions.o:        $(INCLDIR)/defs.h $(INCLDIR)/filter.h
  383. Xfilter.o:        $(INCLDIR)/defs.h $(INCLDIR)/filter.h
  384. Xlock.o:            $(INCLDIR)/defs.h $(INCLDIR)/filter.h
  385. Xparse.o:        $(INCLDIR)/defs.h $(INCLDIR)/filter.h
  386. Xrules.o:        $(INCLDIR)/defs.h $(INCLDIR)/filter.h
  387. Xsummarize.o:        $(INCLDIR)/defs.h $(INCLDIR)/filter.h
  388. Xutils.o:        $(INCLDIR)/defs.h $(INCLDIR)/filter.h
  389. X../src/opt_utils.o:
  390. X            cd ../src; $(MAKE) -$(MAKEFLAGS) $(@F)
  391. X
  392. X#    Dependencies and rules for compiling programs
  393. X$(BIN)/filter:    $& $(FILTER_OBJ)
  394. X        $(CC) $(LFLAGS) -o $@ $(FILTER_OBJ) $(LIB2)
  395. X
  396. X#    Dependencies and rules for installing programs from bin directory
  397. X$(DEST)/filter:        $(BIN)/filter
  398. X            -$(MV) $(DEST)/filter $(DEST)/filter.old
  399. X            -$(RM) $(DEST)/filter.old
  400. X            $(CP) $? $@
  401. X            $(CHGRP) $(MAILGRP) $@
  402. X            $(CHMOD) $(MAILERMODE) $@
  403. X!NO!SUBS!
  404. SHAR_EOF
  405. chmod 0444 filter/Makefile.SH || echo "restore of filter/Makefile.SH fails"
  406. echo "x - extracting filter/actions.c (Text)"
  407. sed 's/^X//' << 'SHAR_EOF' > filter/actions.c &&
  408. X
  409. Xstatic char rcsid[] ="@(#)$Id: actions.c,v 2.4 89/03/25 21:45:10 syd Exp $";
  410. X
  411. X/*******************************************************************************
  412. X *  The Elm Mail System  -  $Revision: 2.4 $   $State: Exp $
  413. X *
  414. X *             Copyright (c) 1986, 1987 Dave Taylor
  415. X *             Copyright (c) 1988, 1989 USENET Community Trust
  416. X *******************************************************************************
  417. X * Bug reports, patches, comments, suggestions should be sent to:
  418. X *
  419. X *    Syd Weinstein - elm@dsinc.UUCP
  420. X *            dsinc!elm
  421. X *
  422. X *******************************************************************************
  423. X * $Log:    actions.c,v $
  424. X * Revision 2.4  89/03/25  21:45:10  syd
  425. X * Initial 2.2 Release checkin
  426. X * 
  427. X *
  428. X ******************************************************************************/
  429. X
  430. X
  431. X/** RESULT oriented routines *chuckle*.  These routines implement the
  432. X    actions that result from either a specified rule being true or from
  433. X    the default action being taken.
  434. X**/
  435. X
  436. X#include <stdio.h>
  437. X#include <pwd.h>
  438. X#include <ctype.h>
  439. X#include <fcntl.h>
  440. X
  441. X#include "defs.h"
  442. X#include "filter.h"
  443. X
  444. XFILE *emergency_local_delivery();
  445. X
  446. Xmail_message(address)
  447. Xchar *address;
  448. X{
  449. X    /** Called with an address to send mail to.   For various reasons
  450. X        that are too disgusting to go into herein, we're going to actually
  451. X        open the users mailbox and by hand add this message.  Yech.
  452. X        NOTE, of course, that if we're going to MAIL the message to someone
  453. X        else, that we'll try to do nice things with it on the fly...
  454. X    **/
  455. X
  456. X    FILE *pipefd, *tempfd, *mailfd;
  457. X    int  in_header = TRUE, line_count = 0;
  458. X    char tempfile[SLEN], mailbox[SLEN], lockfile[SLEN],
  459. X         buffer[VERY_LONG_STRING];
  460. X
  461. X    if (verbose && ! log_actions_only && outfd != NULL)
  462. X      fprintf(outfd, "filter (%s): Mailing message to %s\n", 
  463. X           username, address);
  464. X
  465. X    if (! show_only) {
  466. X      sprintf(tempfile, "%s.%d", filter_temp, getpid());
  467. X
  468. X      if ((tempfd = fopen(tempfile, "r")) == NULL) {
  469. X        if (outfd != NULL)
  470. X          fprintf(outfd, "filter (%s): Can't open temp file %s!!\n", 
  471. X            username, tempfile);
  472. X        if (outfd != NULL) fclose(outfd);
  473. X        exit(1);
  474. X      }
  475. X         
  476. X      if (strcmp(address, username) != 0) {    /* mailing to someone else */
  477. X        
  478. X        if (already_been_forwarded) {    /* potential looping! */
  479. X          if (contains(from, username)) {
  480. X        if (outfd != NULL)
  481. X              fprintf(outfd, 
  482. X    "filter (%s): Filter loop detected!  Message left in file %s.%d\n", 
  483. X            username, filter_temp, getpid());
  484. X            if (outfd != NULL) fclose(outfd);
  485. X            exit(0);
  486. X          }
  487. X        }
  488. X
  489. X        sprintf(buffer, "%s %s %s", sendmail, smflags, address);
  490. X
  491. X        if ((pipefd = popen(buffer, "w")) == NULL) {
  492. X          if (outfd != NULL)
  493. X            fprintf(outfd, "filter (%s): popen %s failed!\n", buffer);
  494. X          sprintf(buffer, "((%s %s %s ; %s %s) & ) < %s &",
  495. X              sendmail , smflags, address, remove_cmd, tempfile, tempfile);
  496. X          system(buffer);
  497. X          return;
  498. X        }
  499. X
  500. X        fprintf(pipefd, "Subject: \"%s\"\n", subject);
  501. X        fprintf(pipefd, "From: The Filter of %s@%s <%s>\n", 
  502. X            username, hostname, username);
  503. X        fprintf(pipefd, "To: %s\n", address);
  504. X        fprintf(pipefd, "X-Filtered-By: filter, version %s\n\n", VERSION);
  505. X
  506. X        fprintf(pipefd, "-- Begin filtered message --\n\n");
  507. X    
  508. X        while (fgets(buffer, SLEN, tempfd) != NULL)
  509. X          if (already_been_forwarded && in_header)
  510. X            in_header = (strlen(buffer) == 1? 0 : in_header);
  511. X          else
  512. X            fprintf(pipefd," %s", buffer);
  513. X
  514. X        fprintf(pipefd, "\n-- End of filtered message --\n");
  515. X        fclose(pipefd);
  516. X        fclose(tempfd);
  517. X    
  518. X        return;        /* YEAH!  Wot a slick program, eh? */
  519. X      
  520. X      }
  521. X      
  522. X      /** OTHERWISE it is to the current user... **/
  523. X
  524. X      sprintf(mailbox,  "%s%s", mailhome, username);
  525. X      
  526. X      if (! lock()) {
  527. X        if (outfd != NULL) {
  528. X          fprintf(outfd, "filter (%s): Couldn't create lockfile %s\n",
  529. X            username, lockfile);
  530. X          fprintf(outfd, "filter (%s): Can't open mailbox %s!\n",
  531. X            username, mailbox);
  532. X        }
  533. X        if ((mailfd = emergency_local_delivery()) == NULL)
  534. X          exit(1);
  535. X      }
  536. X      else if ((mailfd = fopen(mailbox,"a")) == NULL)
  537. X        if ((mailfd = emergency_local_delivery()) == NULL)
  538. X          exit(1);
  539. X
  540. X      while (fgets(buffer, sizeof(buffer), tempfd) != NULL) {
  541. X        line_count++;
  542. X        if (the_same(buffer, "From ") && line_count > 1)
  543. X          fprintf(mailfd, ">%s", buffer);
  544. X        else
  545. X          fputs(buffer, mailfd);
  546. X      }
  547. X
  548. X      fputs("\n", mailfd);
  549. X
  550. X      fclose(mailfd);
  551. X      unlock();        /* blamo or not?  Let it decide! */
  552. X      fclose(tempfd);
  553. X    } /* end if show only */
  554. X}
  555. X
  556. Xsave_message(foldername)
  557. Xchar *foldername;
  558. X{
  559. X    /** Save the message in a folder.  Use full file buffering to
  560. X        make this work without contention problems **/
  561. X
  562. X    FILE  *fd, *tempfd;
  563. X    char  filename[SLEN], buffer[SLEN];
  564. X
  565. X    if (verbose && outfd != NULL)
  566. X      fprintf(outfd, "filter (%s): Message saved in folder %s\n", 
  567. X          username, foldername);
  568. X    
  569. X    if (!show_only) {
  570. X      sprintf(filename, "%s.%d", filter_temp, getpid());
  571. X
  572. X      if ((fd = fopen(foldername, "a")) == NULL) {
  573. X        if (outfd != NULL)
  574. X          fprintf(outfd, 
  575. X         "filter (%s): can't save message to requested folder %s!\n",
  576. X            username, foldername);
  577. X        return(1);
  578. X      }
  579. X
  580. X      if ((tempfd = fopen(filename, "r")) == NULL) {
  581. X        if (outfd != NULL)
  582. X          fprintf(outfd, 
  583. X             "filter (%s): can't open temp file for reading!\n",
  584. X             username);
  585. X         return(1);
  586. X      }
  587. X
  588. X      while (fgets(buffer, sizeof(buffer), tempfd) != NULL)
  589. X        fputs(buffer, fd);
  590. X    
  591. X      fclose(fd);
  592. X      fclose(tempfd);
  593. X    }
  594. X
  595. X     return(0);
  596. X}
  597. X
  598. Xexecute(command)
  599. Xchar *command;
  600. X{
  601. X    /** execute the indicated command, feeding as standard input the
  602. X        message we have.
  603. X    **/
  604. X
  605. X    char buffer[SLEN];
  606. X
  607. X    if (verbose && outfd != NULL)
  608. X      fprintf(outfd, "filter (%s): Executing %s\n", 
  609. X          username, command);
  610. X
  611. X    if (! show_only) {
  612. X      sprintf(buffer, "%s %s.%d | %s", cat, filter_temp, getpid(), command);
  613. X      system(buffer);
  614. X    }
  615. X}
  616. X
  617. XFILE *
  618. Xemergency_local_delivery()
  619. X{
  620. X    /** This is called when we can't deliver the mail to the usual
  621. X        mailbox in the usual way ...
  622. X    **/
  623. X
  624. X    FILE *tempfd;
  625. X    char  mailbox[SLEN];
  626. X
  627. X    sprintf(mailbox, "%s/%s", home, EMERGENCY_MAILBOX);
  628. X
  629. X    if ((tempfd = fopen(mailbox, "a")) == NULL) {
  630. X      if (outfd != NULL)
  631. X        fprintf(outfd, "filter (%s): Can't open %s either!!\n",
  632. X            username, mailbox);
  633. X
  634. X      sprintf(mailbox,"%s/%s", home, EMERG_MBOX); 
  635. X
  636. X      if ((tempfd = fopen(mailbox, "a")) == NULL) {
  637. X
  638. X        if (outfd != NULL) {
  639. X          fprintf(outfd,"filter (%s): Can't open %s either!!!!\n",
  640. X              username, mailbox);
  641. X          fprintf(outfd, 
  642. X              "filter (%s): I can't open ANY mailboxes!  Augh!!\n",
  643. X               username);
  644. X         }
  645. X
  646. X         fclose(tempfd);
  647. X         leave("Cannot open any mailbox");        /* DIE DIE DIE DIE!! */
  648. X       }
  649. X       else
  650. X         if (outfd != NULL)
  651. X           fprintf(outfd, "filter (%s): Using %s as emergency mailbox\n",
  652. X               username, mailbox);
  653. X      }
  654. X      else
  655. X        if (outfd != NULL)
  656. X          fprintf(outfd, "filter (%s): Using %s as emergency mailbox\n",
  657. X              username, mailbox);
  658. X
  659. X    return((FILE *) tempfd);
  660. X}
  661. SHAR_EOF
  662. chmod 0444 filter/actions.c || echo "restore of filter/actions.c fails"
  663. echo "x - extracting filter/buffer.c (Text)"
  664. sed 's/^X//' << 'SHAR_EOF' > filter/buffer.c &&
  665. X
  666. Xstatic char rcsid[] ="@(#)$Id: buffer.c,v 2.3 89/03/25 21:45:12 syd Exp $";
  667. X
  668. X/*******************************************************************************
  669. X *  The Elm Mail System  -  $Revision: 2.3 $   $State: Exp $
  670. X *
  671. X *             Copyright (c) 1986, 1987 Dave Taylor
  672. X *             Copyright (c) 1988, 1989 USENET Community Trust
  673. X *******************************************************************************
  674. X * Bug reports, patches, comments, suggestions should be sent to:
  675. X *
  676. X *    Syd Weinstein - elm@dsinc.UUCP
  677. X *            dsinc!elm
  678. X *
  679. X *******************************************************************************
  680. X * $Log:    buffer.c,v $
  681. X * Revision 2.3  89/03/25  21:45:12  syd
  682. X * Initial 2.2 Release checkin
  683. X * 
  684. X *
  685. X ******************************************************************************/
  686. X
  687. X#include <stdio.h>
  688. X
  689. Xchar  _vbuf[5*BUFSIZ];        /* space for file buffering */
  690. SHAR_EOF
  691. chmod 0444 filter/buffer.c || echo "restore of filter/buffer.c fails"
  692. echo "x - extracting filter/filter.c (Text)"
  693. sed 's/^X//' << 'SHAR_EOF' > filter/filter.c &&
  694. X
  695. Xstatic char rcsid[] ="@(#)$Id: filter.c,v 2.6 89/03/25 21:45:13 syd Exp $";
  696. X
  697. X/*******************************************************************************
  698. X *  The Elm Mail System  -  $Revision: 2.6 $   $State: Exp $
  699. X *
  700. X *             Copyright (c) 1986, 1987 Dave Taylor
  701. X *             Copyright (c) 1988, 1989 USENET Community Trust
  702. X *******************************************************************************
  703. X * Bug reports, patches, comments, suggestions should be sent to:
  704. X *
  705. X *    Syd Weinstein - elm@dsinc.UUCP
  706. X *            dsinc!elm
  707. X *
  708. X *******************************************************************************
  709. X * $Log:    filter.c,v $
  710. X * Revision 2.6  89/03/25  21:45:13  syd
  711. X * Initial 2.2 Release checkin
  712. X * 
  713. X *
  714. X ******************************************************************************/
  715. X
  716. X
  717. X/** This program is used as a filter within the users ``.forward'' file
  718. X    and allows intelligent preprocessing of mail at the point between
  719. X    when it shows up on the machine and when it is actually put in the
  720. X    mailbox.
  721. X
  722. X    The program allows selection based on who the message is FROM, TO, or
  723. X    what the subject is.  Acceptable actions are for the program to DELETE_MSG
  724. X    the message, SAVE the message in a specified folder, FORWARD the message
  725. X    to a specified user, SAVE the message in a folder, but add a copy to the
  726. X    users mailbox anyway, or simply add the message to the incoming mail.
  727. X
  728. X    Filter also keeps a log of what it does as it goes along, and at the
  729. X    end of each `quantum' mails a summary of actions, if any, to the user.
  730. X
  731. X    Uses the files: $HOME/.filter for instructions to this program, and
  732. X    $HOME/.filterlog for a list of what has been done since last summary.
  733. X
  734. X    Rev 2.0: knows about From: and Reply-To: 
  735. X    Fix: knows that mail lines are approx. ~5K or greater...
  736. X    enhanced to have the '-o output-file' specifier
  737. X
  738. X**/
  739. X
  740. X#include <stdio.h>
  741. X#include <pwd.h>
  742. X#include <ctype.h>
  743. X#include <time.h>
  744. X#include <fcntl.h>
  745. X
  746. X#include "defs.h"
  747. X
  748. X#define  MAIN_ROUTINE            /* for the filter.h file, of course! */
  749. X#include "filter.h"
  750. X
  751. Xmain(argc, argv)
  752. Xint argc;
  753. Xchar *argv[];
  754. X{
  755. X    extern char *optarg;
  756. X    FILE   *fd;                /* for output to temp file! */
  757. X    struct passwd  *passwd_entry, 
  758. X               *getpwuid();        /* for /etc/passwd          */
  759. X    char filename[SLEN],            /* name of the temp file    */
  760. X         buffer[MAX_LINE_LEN];        /* input buffer space       */
  761. X    int  in_header = TRUE,            /* for header parsing       */
  762. X         in_to     = FALSE,            /* are we on 'n' line To: ? */
  763. X         summary   = FALSE,            /* a summary is requested?  */
  764. X         c;                    /* var for getopt routine   */
  765. X
  766. X    /* first off, let's get the info from /etc/passwd */ 
  767. X    
  768. X    if ((passwd_entry = getpwuid(getuid())) == NULL) 
  769. X      leave("Cannot get password entry for this uid!");
  770. X
  771. X    strcpy(home, passwd_entry->pw_dir);
  772. X    strcpy(username, passwd_entry->pw_name);
  773. X    outfname[0] = to[0] = '\0';    /* nothing read in yet, right? */
  774. X
  775. X#ifdef HOSTCOMPILED
  776. X    strncpy(hostname, HOSTNAME, sizeof(hostname));
  777. X#else
  778. X    gethostname(hostname, sizeof(hostname));
  779. X#endif
  780. X
  781. X    /* now parse the starting arguments... */
  782. X
  783. X    while ((c = getopt(argc, argv, "clno:rSsv")) != EOF) {
  784. X      switch (c) {
  785. X        case 'c' : clear_logs = TRUE;            break;
  786. X        case 'l' : log_actions_only = TRUE;            break;
  787. X        case 'o' : strcpy(outfname, optarg);        break;
  788. X        case 'r' : printing_rules = TRUE;            break;
  789. X    
  790. X        case 's' : summary = TRUE;                break;
  791. X        case 'S' : long_summary = TRUE;            break;
  792. X
  793. X        case 'n' : show_only = TRUE;            break;
  794. X        case 'v' : verbose = TRUE;                break;
  795. X        case '?' : fprintf(stderr, 
  796. X               "Usage: | filter [-nrv]\n   or: filter [-c] -[s|S]\n");
  797. X                     exit(1);
  798. X      }
  799. X    }
  800. X
  801. X    if (c < 0) {
  802. X    }
  803. X
  804. X    /* let's open our outfd logfile as needed... */
  805. X
  806. X    if (outfname[0] == '\0')     /* default is stdout */
  807. X      outfd = stdout;
  808. X    else 
  809. X      if ((outfd = fopen(outfname, "a")) == NULL) {
  810. X        if (isatty(fileno(stderr)))
  811. X          fprintf(stderr,"filter (%s): couldn't open log file %s\n",
  812. X              username, outfname);
  813. X      }
  814. X
  815. X    if (summary || long_summary) {
  816. X          if (get_filter_rules() == -1) {
  817. X        exit(1);
  818. X        if (outfd != NULL) fclose(outfd);
  819. X      }
  820. X      show_summary();
  821. X      if (outfd != NULL) fclose(outfd);
  822. X      exit(0);
  823. X    }
  824. X
  825. X    if (printing_rules) {
  826. X          if (get_filter_rules() == -1)
  827. X        fprintf(outfd,"filter (%s): Couldn't get rules!\n", username);
  828. X          else
  829. X        print_rules();
  830. X      if (outfd != NULL) fclose(outfd);
  831. X          exit(0);
  832. X    }
  833. X
  834. X    /* next, create the tempfile and save the incoming message */
  835. X
  836. X    sprintf(filename, "%s.%d", filter_temp, getpid());
  837. X
  838. X    if ((fd = fopen(filename,"w")) == NULL)
  839. X      leave("Cannot open temporary file!");
  840. X
  841. X    while (fgets(buffer, MAX_LINE_LEN, stdin) != NULL) {
  842. X
  843. X      remove_return(buffer);
  844. X
  845. X      if (in_header) {
  846. X
  847. X        if (! whitespace(buffer[0])) 
  848. X        in_to = FALSE;
  849. X
  850. X        if (the_same(buffer, "From ")) 
  851. X          save_from(buffer);
  852. X        else if (the_same(buffer, "Subject:")) 
  853. X          save_subject(buffer);
  854. X        else if (the_same(buffer, "To:") || the_same(buffer, "Cc:")) {
  855. X          in_to++;
  856. X          save_to(buffer);
  857. X        }
  858. X        else if (the_same(buffer, "X-Filtered-By:")) 
  859. X          already_been_forwarded++;    /* could be a loop here! */
  860. X#ifdef USE_EMBEDDED_ADDRESSES
  861. X        else if (the_same(buffer, "From:"))
  862. X          save_embedded_address(buffer, "From:");
  863. X        else if (the_same(buffer, "Reply-To:"))
  864. X          save_embedded_address(buffer, "Reply-To:");
  865. X#endif
  866. X        else if (strlen(buffer) < 2) 
  867. X          in_header = 0;
  868. X        else if (whitespace(buffer[0]) && in_to)
  869. X          strcat(to, buffer);
  870. X      }
  871. X    
  872. X          fprintf(fd, "%s\n", buffer);    /* and save it regardless! */
  873. X      fflush(fd);
  874. X      lines++;
  875. X    }
  876. X
  877. X    fclose(fd);
  878. X
  879. X    /** next let's see if the user HAS a filter file, and if so what's in
  880. X            it (and so on) **/
  881. X
  882. X    if (get_filter_rules() == -1)
  883. X      mail_message(username);
  884. X    else {
  885. X      switch (action_from_ruleset()) {
  886. X
  887. X        case DELETE_MSG : if (verbose && outfd != NULL)
  888. X                fprintf(outfd, "filter (%s): Message deleted\n",
  889. X                    username);
  890. X              log(DELETE_MSG);                break;
  891. X
  892. X        case SAVE   : if (save_message(rules[rule_choosen].argument2)) {
  893. X                mail_message(username);
  894. X                log(FAILED_SAVE);
  895. X              }
  896. X              else
  897. X                 log(SAVE);                    break;
  898. X
  899. X        case SAVECC : if (save_message(rules[rule_choosen].argument2))
  900. X                log(FAILED_SAVE);
  901. X              else
  902. X                    log(SAVECC);                    
  903. X              mail_message(username);            break;
  904. X
  905. X        case FORWARD: mail_message(rules[rule_choosen].argument2);
  906. X              log(FORWARD);                    break;
  907. X
  908. X        case EXEC   : execute(rules[rule_choosen].argument2);
  909. X              log(EXEC);                    break;
  910. X
  911. X        case LEAVE  : mail_message(username);
  912. X              log(LEAVE);                    break;
  913. X      }
  914. X    }
  915. X
  916. X    (void) unlink(filename);    /* remove the temp file, please! */
  917. X    if (outfd != NULL) fclose(outfd);
  918. X    exit(0);
  919. X}
  920. X
  921. Xsave_from(buffer)
  922. Xchar *buffer;
  923. X{
  924. X    /** save the SECOND word of this string as FROM **/
  925. X
  926. X    register int i, j;
  927. X
  928. X    for (i=0; buffer[i] != ' '; i++)     ;    /* get to word     */
  929. X
  930. X    for (i++, j=0; buffer[i] != ' ' && i < strlen(buffer); i++) 
  931. X      from[j++] = buffer[i];            /* copy it and     */
  932. X
  933. X    from[j++] = '\0';                /* Null terminate! */
  934. X}
  935. X
  936. Xsave_subject(buffer)
  937. Xchar *buffer;
  938. X{
  939. X    /** save all but the word "Subject:" for the subject **/
  940. X
  941. X    register int skip = 8;  /* skip "Subject:" initially */
  942. X
  943. X    while (buffer[skip] == ' ') skip++;
  944. X
  945. X    strcpy(subject, (char *) buffer + skip);
  946. X}
  947. X
  948. Xsave_to(buffer)
  949. Xchar *buffer;
  950. X{
  951. X    /** save all but the word "To:" or "Cc:" for the to list **/
  952. X
  953. X    register int skip = 3;    /* skip "To:" or "Cc:" initially */
  954. X
  955. X    while (buffer[skip] == ' ') skip++;
  956. X
  957. X    strcat(to, (char *) buffer + skip);
  958. X}
  959. X
  960. X#ifdef USE_EMBEDDED_ADDRESSES
  961. X
  962. Xsave_embedded_address(buffer, fieldname)
  963. Xchar *buffer, *fieldname;
  964. X{
  965. X    /** this will replace the 'from' address with the one given, 
  966. X        unless the address is from a 'reply-to' field (which overrides 
  967. X        the From: field).  The buffer given to this routine can have one 
  968. X            of three forms:
  969. X        fieldname: username <address>
  970. X        fieldname: address (username)
  971. X        fieldname: address
  972. X    **/
  973. X    
  974. X    static int processed_a_reply_to = 0;
  975. X    char address[LONG_STRING];
  976. X    register int i, j = 0;
  977. X
  978. X    /** first let's extract the address from this line.. **/
  979. X
  980. X    if (buffer[strlen(buffer)-1] == '>') {    /* case #1 */
  981. X      for (i=strlen(buffer)-1; buffer[i] != '<' && i > 0; i--)
  982. X        /* nothing - just move backwards .. */ ;
  983. X      i++;    /* skip the leading '<' symbol */
  984. X      while (buffer[i] != '>')
  985. X        address[j++] = buffer[i++];
  986. X      address[j] = '\0';
  987. X    }
  988. X    else {    /* get past "from:" and copy until white space or paren hit */
  989. X      for (i=strlen(fieldname); whitespace(buffer[i]); i++)
  990. X         /* skip past that... */ ;
  991. X      while (buffer[i] != '(' && ! whitespace(buffer[i]) && buffer[i]!='\0')
  992. X        address[j++] = buffer[i++];
  993. X      address[j] = '\0';
  994. X    }
  995. X
  996. X    /** now let's see if we should overwrite the existing from address
  997. X        with this one or not.. **/
  998. X
  999. X    if (processed_a_reply_to)
  1000. X      return;    /* forget it! */
  1001. X
  1002. X    strcpy(from, address);            /* replaced!! */
  1003. X
  1004. X    if (strcmp(fieldname, "Reply-To:") == 0)
  1005. X      processed_a_reply_to++;
  1006. X}
  1007. X#endif
  1008. SHAR_EOF
  1009. chmod 0444 filter/filter.c || echo "restore of filter/filter.c fails"
  1010. echo "x - extracting filter/lock.c (Text)"
  1011. sed 's/^X//' << 'SHAR_EOF' > filter/lock.c &&
  1012. X
  1013. Xstatic char rcsid[] ="@(#)$Id: lock.c,v 2.4 89/03/25 21:45:14 syd Exp $";
  1014. X
  1015. X/*******************************************************************************
  1016. X *  The Elm Mail System  -  $Revision: 2.4 $   $State: Exp $
  1017. X *
  1018. X *             Copyright (c) 1986, 1987 Dave Taylor
  1019. X *             Copyright (c) 1988, 1989 USENET Community Trust
  1020. X *******************************************************************************
  1021. X * Bug reports, patches, comments, suggestions should be sent to:
  1022. X *
  1023. X *    Syd Weinstein - elm@dsinc.UUCP
  1024. X *            dsinc!elm
  1025. X *
  1026. X *******************************************************************************
  1027. X * $Log:    lock.c,v $
  1028. X * Revision 2.4  89/03/25  21:45:14  syd
  1029. X * Initial 2.2 Release checkin
  1030. X * 
  1031. X *
  1032. X ******************************************************************************/
  1033. X
  1034. X
  1035. X/** The lock() and unlock() routines herein duplicate exactly the
  1036. X    equivalent routines in the Elm Mail System, and should also be
  1037. X    compatible with sendmail, rmail, etc etc.
  1038. X
  1039. X  
  1040. X**/
  1041. X
  1042. X#include <stdio.h>
  1043. X#include <fcntl.h>
  1044. X#include "defs.h"
  1045. X#include "filter.h"
  1046. X
  1047. Xint  we_locked_it = 0;
  1048. Xchar lockfile[SLEN];
  1049. X
  1050. Xint
  1051. Xlock()
  1052. X{
  1053. X    /** This routine will return 1 if we could lock the mailfile,
  1054. X        zero otherwise.
  1055. X    **/
  1056. X
  1057. X    int attempts = 0, ret;
  1058. X
  1059. X    sprintf(lockfile,  "%s%s.lock", mailhome, username);
  1060. X
  1061. X    while ((ret = open(lockfile, O_WRONLY | O_CREAT | O_EXCL, 0777)) < 0 
  1062. X           && attempts++ < 10) {
  1063. X      sleep(3);    /* wait three seconds each pass, okay?? */
  1064. X    }
  1065. X
  1066. X    if (ret > 0) {
  1067. X      we_locked_it++;
  1068. X      close(ret);            /* no need to keep it open! */
  1069. X    }
  1070. X
  1071. X    return( (ret >= 0) );
  1072. X}
  1073. X
  1074. Xunlock()
  1075. X{
  1076. X    /** this routine will remove the lock file, but only if we were
  1077. X        the people that locked it in the first place... **/
  1078. X
  1079. X    if (we_locked_it)
  1080. X      unlink(lockfile);    /* blamo! */
  1081. X
  1082. X    we_locked_it = 0;
  1083. X}
  1084. SHAR_EOF
  1085. chmod 0444 filter/lock.c || echo "restore of filter/lock.c fails"
  1086. echo "x - extracting filter/parse.c (Text)"
  1087. sed 's/^X//' << 'SHAR_EOF' > filter/parse.c &&
  1088. X
  1089. Xstatic char rcsid[] ="@(#)$Id: parse.c,v 2.4 89/03/25 21:45:16 syd Exp $";
  1090. X
  1091. X/*******************************************************************************
  1092. X *  The Elm Mail System  -  $Revision: 2.4 $   $State: Exp $
  1093. X *
  1094. X *             Copyright (c) 1986, 1987 Dave Taylor
  1095. X *             Copyright (c) 1988, 1989 USENET Community Trust
  1096. X *******************************************************************************
  1097. X * Bug reports, patches, comments, suggestions should be sent to:
  1098. X *
  1099. X *    Syd Weinstein - elm@dsinc.UUCP
  1100. X *            dsinc!elm
  1101. X *
  1102. X *******************************************************************************
  1103. X * $Log:    parse.c,v $
  1104. X * Revision 2.4  89/03/25  21:45:16  syd
  1105. X * Initial 2.2 Release checkin
  1106. X * 
  1107. X *
  1108. X ******************************************************************************/
  1109. X
  1110. X
  1111. X/** This is the parser for the filter program.  It accepts a wide variety of
  1112. X    constructs, building the ruleset table as it goes along.  Check the 
  1113. X    data structure in filter.h for more information on how the rules are
  1114. X    stored.  The parser is a cunning state-table based program.
  1115. X
  1116. X**/
  1117. X
  1118. X#include <stdio.h>
  1119. X#include <ctype.h>
  1120. X
  1121. X#include "defs.h"
  1122. X#include "filter.h"
  1123. X
  1124. X#define NONE            0
  1125. X#define AND            10
  1126. X
  1127. X#define NEXT_CONDITION        0
  1128. X#define GETTING_OP        1
  1129. X#define READING_ARGUMENT    2
  1130. X#define READING_ACTION        3
  1131. X#define ACTION_ARGUMENT        4
  1132. X
  1133. Xchar *strtok(), *whatname(), *actionname();
  1134. X
  1135. Xint
  1136. Xget_filter_rules()
  1137. X{
  1138. X    /** Given the users home directory, open and parse their rules table,
  1139. X        building the data structure as we go along.
  1140. X        returns -1 if we hit an error of any sort...
  1141. X    **/
  1142. X
  1143. X    FILE *fd;                /* the file descriptor     */
  1144. X    char  buffer[SLEN],             /* fd reading buffer       */
  1145. X          *str,                 /* ptr to read string      */
  1146. X          *word,                /* ptr to 'token'          */
  1147. X          filename[SLEN],             /* the name of the ruleset */
  1148. X          action_argument[SLEN],         /* action arg, per rule    */
  1149. X          cond_argument[SLEN];        /* cond arg, per condition */
  1150. X    int   not_condition = FALSE,         /* are we in a "not" ??    */
  1151. X          type=NONE,             /* what TYPE of condition? */
  1152. X          lasttype,             /* and the previous TYPE?  */
  1153. X          state = NEXT_CONDITION,        /* the current state       */
  1154. X          in_single, in_double,         /* for handling spaces.    */
  1155. X          i,                 /* misc integer for loops  */
  1156. X          relop = NONE,            /* relational operator     */
  1157. X          action,                 /* the current action type */
  1158. X          line = 0;                /* line number we're on    */
  1159. X
  1160. X    struct condition_rec    *cond, *newcond;
  1161. X
  1162. X    sprintf(filename,"%s/%s", home, filterfile);
  1163. X
  1164. X    if ((fd = fopen(filename,"r")) == NULL) {
  1165. X      if (outfd != NULL)
  1166. X       fprintf(outfd,"filter (%s): Couldn't read user filter rules file!\n",
  1167. X          username);
  1168. X      return(-1);
  1169. X    }
  1170. X
  1171. X    cond_argument[0] = action_argument[0] = '\0';
  1172. X
  1173. X    /* Now, for each line... **/
  1174. X
  1175. X    if ((cond = (struct condition_rec *) 
  1176. X             malloc(sizeof(struct condition_rec))) == NULL) {
  1177. X      if (outfd != NULL)
  1178. X        fprintf(outfd,"filter (%s): couldn't malloc first condition rec!\n",
  1179. X            username);
  1180. X      return(-1);
  1181. X    }
  1182. X    
  1183. X    rules[total_rules].condition = cond;    /* hooked in! */
  1184. X
  1185. X    while (fgets(buffer, SLEN, fd) != NULL) {
  1186. X      line++;
  1187. X
  1188. X      if (buffer[0] == '#' || strlen(buffer) < 2)
  1189. X        continue;        /* nothing to look at! */
  1190. X
  1191. X      in_single = in_double = 0;
  1192. X
  1193. X      for (i=0; i < strlen(buffer); i++) {
  1194. X        if (buffer[i] == '"') 
  1195. X          in_double = ! in_double;
  1196. X        else if (buffer[i] == '\'')
  1197. X          in_single = ! in_single;
  1198. X        if ((in_double || in_single) && buffer[i] == ' ')
  1199. X          buffer[i] = '_';
  1200. X      }
  1201. X
  1202. X      lasttype = type;
  1203. X      type = NONE;
  1204. X      str = (char *) buffer;
  1205. X
  1206. X      /** Three pieces to this loop - get the `field', the 'relop' (if
  1207. X          there) then, if needed, get the argument to check against (not 
  1208. X          needed for errors or the AND, of course)
  1209. X      **/
  1210. X
  1211. X      while ((word = strtok(str, " ()[]:\t\n")) != NULL) {
  1212. X
  1213. X        str = (char *) NULL;        /* we can start stomping! */
  1214. X      
  1215. X        lowercase(word);
  1216. X
  1217. X        if (strcmp(word, "if") == 0) {    /* only ONE 'if' allowed */
  1218. X          if ((word = strtok(str, " ()[]:\t\n")) == NULL)    /* NEXT! */
  1219. X            continue;
  1220. X          lowercase(word);
  1221. X        }
  1222. X    
  1223. X        if (state == NEXT_CONDITION) {
  1224. X          lasttype = type;
  1225. X          type = NONE;
  1226. X
  1227. X          if (the_same(word, "not") || the_same(word, "!")) {
  1228. X            not_condition = TRUE;
  1229. X            if ((word = strtok(str, " ()[]'\"\t\n")) == NULL)
  1230. X              continue;
  1231. X          }
  1232. X
  1233. X               if (the_same(word, "from"))         type = FROM;
  1234. X          else if (the_same(word, "to"))         type = TO;
  1235. X          else if (the_same(word, "subject"))   type = SUBJECT;
  1236. X          else if (the_same(word, "lines"))     type = LINES;
  1237. X          else if (the_same(word, "contains"))  type = CONTAINS;
  1238. X          else if (the_same(word, "and") || 
  1239. X                   the_same(word, "&&"))         type = AND;
  1240. X
  1241. X          else if (the_same(word,"?") || the_same(word, "then") || 
  1242. X               the_same(word, "always")) {
  1243. X
  1244. X        /** shove THIS puppy into the structure and let's continue! **/
  1245. X
  1246. X            if (lasttype == AND) {
  1247. X          if (outfd != NULL)
  1248. X                fprintf(outfd,
  1249. X         "filter (%s): Error reading line %d of rules - badly placed \"and\"\n",
  1250. X            username, line);
  1251. X          return(-1);
  1252. X            }
  1253. X
  1254. X            if (the_same(word, "always"))
  1255. X          cond->matchwhat = ALWAYS;    /* so it's a hack... */
  1256. X        else
  1257. X          cond->matchwhat = lasttype;
  1258. X
  1259. X            if (relop == NONE) relop = EQ;    /* otherwise can't do -relop */
  1260. X            cond->relation  = (not_condition? - (relop) : relop);
  1261. X
  1262. X        for (i=0;i<strlen(cond_argument);i++)
  1263. X              if (cond_argument[i] == '_') cond_argument[i] = ' ';
  1264. X
  1265. X        strcpy(cond->argument1, cond_argument);
  1266. X            if ((newcond = (struct condition_rec *)
  1267. X             malloc(sizeof(struct condition_rec))) == NULL) {
  1268. X          if (outfd != NULL)
  1269. X                fprintf(outfd,
  1270. X                     "filter (%s): Couldn't malloc new cond rec!!\n",
  1271. X                    username);
  1272. X          return(-1);
  1273. X            }
  1274. X            cond->next = NULL;
  1275. X
  1276. X            relop = EQ;    /* default relational condition */
  1277. X
  1278. X            state = READING_ACTION;
  1279. X            if ((word = strtok(str, " ()[]'\"\t\n")) == NULL)
  1280. X              continue;
  1281. X            goto get_outta_loop;
  1282. X          }
  1283. X
  1284. X          if (type == NONE) {
  1285. X        if (outfd != NULL)
  1286. X              fprintf(outfd,
  1287. X      "filter (%s): Error reading line %d of rules - field \"%s\" unknown!\n",
  1288. X             username, line, word);
  1289. X        return(-1);
  1290. X          }
  1291. X
  1292. X          if (type == AND) {
  1293. X
  1294. X        /** shove THIS puppy into the structure and let's continue! **/
  1295. X
  1296. X        cond->matchwhat = lasttype;
  1297. X            cond->relation  = (not_condition? - (relop) : relop);
  1298. X        strcpy(cond->argument1, cond_argument);
  1299. X            if ((newcond = (struct condition_rec *)
  1300. X                 malloc(sizeof(struct condition_rec))) == NULL) {
  1301. X          if (outfd != NULL)
  1302. X                fprintf(outfd,
  1303. X            "filter (%s): Couldn't malloc new cond rec!!\n",
  1304. X            username);
  1305. X          return(-1);
  1306. X            }
  1307. X            cond->next = newcond;
  1308. X        cond = newcond;
  1309. X        cond->next = NULL;
  1310. X
  1311. X            not_condition = FALSE;
  1312. X            state = NEXT_CONDITION;
  1313. X          }
  1314. X          else {
  1315. X            state = GETTING_OP;
  1316. X          }
  1317. X        }
  1318. X
  1319. Xget_outta_loop:     /* jump out when we change state, if needed */
  1320. X
  1321. X        if (state == GETTING_OP) {
  1322. X
  1323. X           if ((word = strtok(str, " ()[]'\"\t\n")) == NULL)
  1324. X             continue;
  1325. X
  1326. X           lowercase(word);
  1327. X
  1328. X           relop = NONE;
  1329. X
  1330. X           if (the_same(word, "=") || the_same(word, "in") || 
  1331. X                   the_same(word, "contains")) {
  1332. X                 state = READING_ARGUMENT;
  1333. X             relop = EQ;
  1334. X           }
  1335. X           else {
  1336. X             if (the_same(word, "<="))     relop = LE;
  1337. X             else if (the_same(word, ">="))    relop = GE;
  1338. X             else if (the_same(word, ">"))    relop = GT;
  1339. X             else if (the_same(word, "<>")||
  1340. X                  the_same(word, "!="))    relop = NE;
  1341. X             else if (the_same(word, "<"))    relop = LT;
  1342. X
  1343. X         /* maybe there isn't a relop at all!! */
  1344. X
  1345. X         state=READING_ARGUMENT;
  1346. X
  1347. X           }
  1348. X        }
  1349. X         
  1350. X        if (state == READING_ARGUMENT) {
  1351. X          if (relop != NONE) {
  1352. X            if ((word = strtok(str, " ()[]'\"\t\n")) == NULL)
  1353. X              continue;
  1354. X          }
  1355. X          for (i=0;i<strlen(word);i++)
  1356. X            if (word[i] == '_') word[i] = ' ';
  1357. X
  1358. X          strcpy(cond_argument, word);
  1359. X          state = NEXT_CONDITION;
  1360. X        }
  1361. X
  1362. X        if (state == READING_ACTION) {
  1363. X          action = NONE;
  1364. X
  1365. X          not_condition = FALSE;
  1366. X
  1367. X          if (the_same(word, "delete"))       action = DELETE_MSG;
  1368. X          else if (the_same(word, "savec"))   action = SAVECC;
  1369. X          else if (the_same(word, "save"))    action = SAVE;
  1370. X          else if (the_same(word, "forward")) action = FORWARD;
  1371. X          else if (the_same(word, "exec"))    action = EXEC;
  1372. X          else if (the_same(word, "leave"))   action = LEAVE;
  1373. X          else {
  1374. X        if (outfd != NULL)
  1375. X              fprintf(outfd,
  1376. X    "filter (%s): Error on line %d of rules - action \"%s\" unknown\n",
  1377. X            username, line, word);
  1378. X          }
  1379. X
  1380. X          if (action == DELETE_MSG || action == LEAVE) {
  1381. X            /** add this to the rules section and alloc next... **/
  1382. X
  1383. X            rules[total_rules].action = action;
  1384. X        rules[total_rules].argument2[0] = '\0';    /* nothing! */
  1385. X            total_rules++;
  1386. X             
  1387. X            if ((cond = (struct condition_rec *)
  1388. X             malloc(sizeof(struct condition_rec))) == NULL) {
  1389. X          if (outfd != NULL)
  1390. X                fprintf(outfd,
  1391. X            "filter (%s): couldn't malloc first condition rec!\n",
  1392. X            username);
  1393. X              return(-1);
  1394. X            }
  1395. X    
  1396. X            rules[total_rules].condition = cond;    /* hooked in! */
  1397. X            state = NEXT_CONDITION;    
  1398. X          }
  1399. X          else {
  1400. X            state = ACTION_ARGUMENT;
  1401. X          }
  1402. X
  1403. X          if ((word = strtok(str, " ()[]'\"\t\n")) == NULL)
  1404. X            continue;
  1405. X
  1406. X        }
  1407. X    
  1408. X        if (state == ACTION_ARGUMENT) {
  1409. X          strcpy(action_argument, word);
  1410. X
  1411. X          /** add this to the rules section and alloc next... **/
  1412. X
  1413. X          rules[total_rules].action = action;
  1414. X          expand_macros(action_argument, rules[total_rules].argument2,line,
  1415. X                printing_rules);
  1416. X          total_rules++;
  1417. X             
  1418. X          if ((cond = (struct condition_rec *)
  1419. X             malloc(sizeof(struct condition_rec))) == NULL) {
  1420. X        if (outfd != NULL)
  1421. X              fprintf(outfd,
  1422. X              "filter (%s): couldn't malloc first condition rec!\n",
  1423. X              username);
  1424. X            return(-1);
  1425. X          }
  1426. X    
  1427. X          rules[total_rules].condition = cond;    /* hooked in! */
  1428. X
  1429. X          state = NEXT_CONDITION;
  1430. X          if ((word = strtok(str, " ()[]'\"\t\n")) == NULL)
  1431. X            continue;
  1432. X        }
  1433. X      }
  1434. X    }
  1435. X
  1436. X    return(0);
  1437. X}
  1438. SHAR_EOF
  1439. chmod 0444 filter/parse.c || echo "restore of filter/parse.c fails"
  1440. echo "x - extracting filter/rules.c (Text)"
  1441. sed 's/^X//' << 'SHAR_EOF' > filter/rules.c &&
  1442. X
  1443. Xstatic char rcsid[] ="@(#)$Id: rules.c,v 2.4 89/03/25 21:45:17 syd Exp $";
  1444. X
  1445. X/*******************************************************************************
  1446. X *  The Elm Mail System  -  $Revision: 2.4 $   $State: Exp $
  1447. X *
  1448. X *             Copyright (c) 1986, 1987 Dave Taylor
  1449. X *             Copyright (c) 1988, 1989 USENET Community Trust
  1450. X *******************************************************************************
  1451. X * Bug reports, patches, comments, suggestions should be sent to:
  1452. X *
  1453. X *    Syd Weinstein - elm@dsinc.UUCP
  1454. X *            dsinc!elm
  1455. X *
  1456. X *******************************************************************************
  1457. X * $Log:    rules.c,v $
  1458. X * Revision 2.4  89/03/25  21:45:17  syd
  1459. X * Initial 2.2 Release checkin
  1460. X * 
  1461. X *
  1462. X ******************************************************************************/
  1463. X
  1464. X/** This file contains all the rule routines, including those that apply the
  1465. X    specified rules and the routine to print the rules out.
  1466. X
  1467. X**/
  1468. X
  1469. X#include <stdio.h>
  1470. X#include <pwd.h>
  1471. X#include <ctype.h>
  1472. X#include <time.h>
  1473. X#include <fcntl.h>
  1474. X
  1475. X#include "defs.h"
  1476. X#include "filter.h"
  1477. X
  1478. Xchar *listrule();
  1479. X
  1480. Xint
  1481. Xaction_from_ruleset()
  1482. X{
  1483. X    /** Given the set of rules we've read in and the current to, from, 
  1484. X        and subject, try to match one.  Return the ACTION of the match
  1485. X            or LEAVE if none found that apply.
  1486. X    **/
  1487. X
  1488. X    register int iindex = 0, not, relation, try_next_rule, x;
  1489. X    struct condition_rec *cond;
  1490. X
  1491. X    while (iindex < total_rules) {
  1492. X      cond = rules[iindex].condition;
  1493. X      try_next_rule = 0;
  1494. X
  1495. X      while (cond != NULL && ! try_next_rule) {
  1496. X        
  1497. X        not = (cond->relation < 0);
  1498. X        relation = abs(cond->relation);
  1499. X    
  1500. X        switch (cond->matchwhat) {
  1501. X
  1502. X          case TO     : x = contains(to, cond->argument1);         break;
  1503. X          case FROM   : x = contains(from, cond->argument1);     break;
  1504. X          case SUBJECT: x = contains(subject, cond->argument1);    break;
  1505. X          case LINES  : x = compare(lines, relation, cond->argument1);break;
  1506. X               
  1507. X          case CONTAINS: if (outfd != NULL) fprintf(outfd,
  1508. X       "filter (%s): Error: rules based on 'contains' are not implemented!\n",
  1509. X                username);
  1510. X                if (outfd != NULL) fclose(outfd);
  1511. X                exit(0);         
  1512. X
  1513. X          case ALWAYS: not = FALSE; x = TRUE;            break;
  1514. X        }
  1515. X
  1516. X        if ((not && x) || ((! not) && (! x))) /* this test failed (LISP?) */
  1517. X          try_next_rule++;
  1518. X        else
  1519. X          cond = cond->next;          /* next condition, if any?  */
  1520. X      }
  1521. X
  1522. X      if (! try_next_rule) {
  1523. X        rule_choosen = iindex;
  1524. X         return(rules[rule_choosen].action);
  1525. X      }
  1526. X      iindex++;
  1527. X    }
  1528. X
  1529. X    rule_choosen = -1;
  1530. X    return(LEAVE);
  1531. X}
  1532. X
  1533. X#define get_the_time()    if (!gotten_time) {           \
  1534. X               thetime = time( (long *) 0);   \
  1535. X               timerec = localtime(&thetime); \
  1536. X               gotten_time++;           \
  1537. X            }
  1538. X
  1539. Xexpand_macros(word, buffer, line, display)
  1540. Xchar *word, *buffer;
  1541. Xint  line, display;
  1542. X{
  1543. X    /** expand the allowable macros in the word;
  1544. X        %d    = day of the month  
  1545. X        %D    = day of the week  
  1546. X            %h    = hour (0-23)     
  1547. X        %m    = month of the year
  1548. X        %r    = return address of sender
  1549. X           %s    = subject of message
  1550. X           %S    = "Re: subject of message"  (only add Re: if not there)
  1551. X        %t    = hour:minute     
  1552. X        %y    = year          
  1553. X        or simply copies word into buffer. If "display" is set then
  1554. X        instead it puts "<day-of-month>" etc. etc. in the output.
  1555. X    **/
  1556. X
  1557. X    struct tm *localtime(), *timerec;
  1558. X    long     time(), thetime;
  1559. X    register int i, j=0, gotten_time = 0, reading_a_percent_sign = 0;
  1560. X
  1561. X    for (i = 0; i < strlen(word); i++) {
  1562. X      if (reading_a_percent_sign) {
  1563. X        reading_a_percent_sign = 0;
  1564. X        switch (word[i]) {
  1565. X
  1566. X          case 'r' : buffer[j] = '\0';
  1567. X             if (display)
  1568. X                strcat(buffer, "<return-address>");
  1569. X             else
  1570. X               strcat(buffer, from);
  1571. X                     j = strlen(buffer);
  1572. X             break;
  1573. X
  1574. X          case 's' : buffer[j] = '\0';
  1575. X             if (display)
  1576. X                strcat(buffer, "<subject>");
  1577. X             else {
  1578. X               strcat(buffer, "\"");
  1579. X               strcat(buffer, subject);
  1580. X               strcat(buffer, "\"");
  1581. X             }
  1582. X                     j = strlen(buffer);
  1583. X             break;
  1584. X
  1585. X          case 'S' : buffer[j] = '\0';
  1586. X             if (display)
  1587. X                strcat(buffer, "<Re: subject>");
  1588. X             else {
  1589. X               if (! the_same(subject, "Re:")) 
  1590. X                 strcat(buffer, "\"Re: ");
  1591. X               strcat(buffer, subject);
  1592. X               strcat(buffer, "\"");
  1593. X             }
  1594. X                     j = strlen(buffer);
  1595. X             break;
  1596. X
  1597. X          case 'd' : get_the_time(); buffer[j] = '\0';
  1598. X             if (display)
  1599. X               strcat(buffer, "<day-of-month>");
  1600. X             else
  1601. X               strcat(buffer, itoa(timerec->tm_mday,FALSE));
  1602. X                     j = strlen(buffer);
  1603. X             break;
  1604. X
  1605. X          case 'D' : get_the_time(); buffer[j] = '\0';
  1606. X             if (display)
  1607. X               strcat(buffer, "<day-of-week>");
  1608. X             else
  1609. X               strcat(buffer, itoa(timerec->tm_wday,FALSE));
  1610. X                     j = strlen(buffer);
  1611. X             break;
  1612. X
  1613. X          case 'm' : get_the_time(); buffer[j] = '\0';
  1614. X             if (display)
  1615. X               strcat(buffer, "<month>");
  1616. X             else
  1617. X               strcat(buffer, itoa(timerec->tm_mon+1,FALSE));
  1618. X                     j = strlen(buffer);
  1619. X             break;
  1620. X
  1621. X          case 'y' : get_the_time(); buffer[j] = '\0';
  1622. X             if (display)
  1623. X               strcat(buffer, "<year>");
  1624. X             else
  1625. X               strcat(buffer, itoa(timerec->tm_year,FALSE));
  1626. X                     j = strlen(buffer);
  1627. X             break;
  1628. X
  1629. X          case 'h' : get_the_time(); buffer[j] = '\0';
  1630. X             if (display)
  1631. X               strcat(buffer, "<hour>");
  1632. X             else
  1633. X               strcat(buffer, itoa(timerec->tm_hour,FALSE));
  1634. X                     j = strlen(buffer);
  1635. X             break;
  1636. X
  1637. X          case 't' : get_the_time(); buffer[j] = '\0';
  1638. X             if (display)
  1639. X               strcat(buffer, "<time>");
  1640. X                 else {
  1641. X               strcat(buffer, itoa(timerec->tm_hour,FALSE));
  1642. X               strcat(buffer, ":");
  1643. X               strcat(buffer, itoa(timerec->tm_min,TRUE));
  1644. X             }
  1645. X                     j = strlen(buffer);
  1646. X             break;
  1647. X
  1648. X          default  : if (outfd != NULL) fprintf(outfd,
  1649. X   "filter (%s): Error on line %d translating %%%c macro in word \"%s\"!\n",
  1650. X                     username, line, word[i], word);
  1651. X             if (outfd != NULL) fclose(outfd);
  1652. X             exit(1);
  1653. X        }
  1654. X      }
  1655. X      else if (word[i] == '%') 
  1656. X        reading_a_percent_sign++;
  1657. X      else 
  1658. X        buffer[j++] = (word[i] == '_' ? ' ' : word[i]);
  1659. X    }
  1660. X    buffer[j] = '\0';
  1661. X}
  1662. X
  1663. Xprint_rules()
  1664. X{
  1665. X    /** print the rules out.  A double check, of course! **/
  1666. X
  1667. X    register int i = -1;
  1668. X    char     *whatname(), *actionname();
  1669. X    struct   condition_rec *cond;
  1670. X
  1671. X    if (outfd == NULL) return;    /* why are we here, then? */
  1672. X
  1673. X    while (++i < total_rules) {
  1674. X      if (rules[i].condition->matchwhat == ALWAYS) {
  1675. X        fprintf(outfd, "\nRule %d:  ** always ** \n\t%s %s\n", i+1,
  1676. X         actionname(rules[i].action), listrule(rules[i].argument2));
  1677. X        continue;
  1678. X      }
  1679. X
  1680. X      fprintf(outfd, "\nRule %d:  if (", i+1);
  1681. X
  1682. X      cond = rules[i].condition;
  1683. X
  1684. X      while (cond != NULL) {
  1685. X        if (cond->relation < 0)
  1686. X          fprintf(outfd, "not %s %s %s%s%s", 
  1687. X              whatname(cond->matchwhat),
  1688. X              relationname(- (cond->relation)),
  1689. X              quoteit(cond->matchwhat),
  1690. X              cond->argument1,
  1691. X              quoteit(cond->matchwhat));
  1692. X        else
  1693. X          fprintf(outfd, "%s %s %s%s%s",
  1694. X              whatname(cond->matchwhat),
  1695. X              relationname(cond->relation),
  1696. X              quoteit(cond->matchwhat),
  1697. X              cond->argument1,
  1698. X              quoteit(cond->matchwhat));
  1699. X
  1700. X        cond = cond->next;
  1701. X
  1702. X        if (cond != NULL) fprintf(outfd, " and ");
  1703. X      }
  1704. X        
  1705. X      fprintf(outfd, ") then\n\t  %s %s\n", 
  1706. X         actionname(rules[i].action), 
  1707. X         listrule(rules[i].argument2));
  1708. X    }
  1709. X    fprintf(outfd, "\n");
  1710. X}
  1711. X
  1712. Xchar *whatname(n)
  1713. Xint n;
  1714. X{
  1715. X    static char buffer[10];
  1716. X
  1717. X    switch(n) {
  1718. X      case FROM   : return("from");
  1719. X      case TO     : return("to");
  1720. X      case SUBJECT: return("subject");
  1721. X      case LINES  : return ("lines");
  1722. X      case CONTAINS: return("contains");
  1723. X      default     : sprintf(buffer, "?%d?", n); return((char *)buffer);
  1724. X    }
  1725. X}
  1726. X
  1727. Xchar *actionname(n)
  1728. Xint n;
  1729. X{
  1730. X    switch(n) {
  1731. X      case DELETE_MSG : return("Delete");
  1732. X      case SAVE       : return("Save");
  1733. X      case SAVECC     : return("Copy and Save");
  1734. X      case FORWARD    : return("Forward");
  1735. SHAR_EOF
  1736. echo "End of part 8"
  1737. echo "File filter/rules.c is continued in part 9"
  1738. echo "9" > s2_seq_.tmp
  1739. exit 0
  1740.  
  1741.