[comp.mail.elm] Elm 2.1 PL 1 part 6 of 22

syd@dsinc.UUCP (Syd Weinstein) (12/12/88)

---- Cut Here and unpack ----
#!/bin/sh
# this is part 6 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file doc/readmsg.1 continued
#
CurArch=6
if test ! -r s2_seq_.tmp
then echo "Please unpack part 1 first!"
     exit 1; fi
( read Scheck
  if test "$Scheck" != $CurArch
  then echo "Please unpack part $Scheck next!"
       exit 1;
  else exit 0; fi
) < s2_seq_.tmp || exit 1
echo "x - Continuing file doc/readmsg.1"
sed 's/^X//' << 'SHAR_EOF' >> doc/readmsg.1
X   Joe
X   
X   From john Jun 3 1986 4:48:20 MST
X   Subject: Dinner at Eight
X   From: John Dinley <xyz!john>
X
X   Remember you should show up about eight, okay?
X
X		   - John D -
X
X   From xxzyz!cron Jun 3 1986 5:02:43 MST
X
X   Cannot connect to server: blob
X   Job 43243 deleted from queue.
X   
X.fi
XThe following commands will result in;
X.nf
X
X  $ readmsg 2		
X  [ display the second message, from John ]
X
X  $ readmsg 		
X  [ an error, unless we're calling from \fIelm\fR ]
X
X  $ readmsg BLOB	
X  [ no match - case sensitive! ]
X
X  $ readmsg -h connect to server 
X  [ displays third message, including headers ]
X
X.fi
X.SH FILES
X/usr/mail/<username>   		The incoming mail
X.br
X$home/.readmsg			The temp file from \fIelm\fR
X.SH AUTHOR
XDave Taylor, Hewlett-Packard Laboratories
X.SH SEE\ ALSO
Xnewmail(1L), elm(1L)
X.SH BUGS
XThe '*' metacharacter doesn't always work as expected!
X.br
XPerhaps the pattern matching should be case insensitive?
X.SH BUG REPORTS TO
XSyd Weinstein	syd@dsinc.UUCP	(dsinc!syd)
SHAR_EOF
echo "File doc/readmsg.1 is complete"
chmod 0444 doc/readmsg.1 || echo "restore of doc/readmsg.1 fails"
echo "x - extracting doc/wnewmail.1 (Text)"
sed 's/^X//' << 'SHAR_EOF' > doc/wnewmail.1 &&
X.TH WNEWMAIL 1L 
X.ad b
X.SH NAME
Xwnewmail - daemon to asynchronously notify of new mail
X.SH SYNOPSIS
X.B wnewmail
X.br
X.B wnewmail
Xfilename
X.PP
X.SH HP-UX COMPATIBILITY
X.TP 10
XLevel:
XHP-UX/CONTRIBUTED
X.TP
XOrigin:
XHewlett-Packard
X.SH DESCRIPTION
X.I Wnewmail\^
Xis a daemon designed to run in \fBa window\fR on a windowing
Xsystem (such as an HP or Sun system) and check every 10 seconds
Xto see if there is any new mail for the user that
Xstarted it up.
X.P
XIf there is new mail, the program will "beep", and write to
Xthe window for each of the new messages;
X.nf
X
X   Mail from <name> -- <subject>
X
X.fi
Xwhere <name> is either the name of the person sending it,
Xif available (the ARPA 'From:' line) or machine!login where
Xmachine is the machine the mail was sent from.  If there
Xis no subject, the message "<no subject>" will appear on
Xthe screen.
X.P
XIf the message is a \fIpriority\fR message (that is, the
Xheader contains a line "Priority:"), then the line output
Xwill be "PRIORITY mail from ..." rather than just "Mail from".
X.P
XThis program will run forever, and can internally reset 
Xitself if mail is deleted from the incoming mailbox while
Xtrying to monitor it.
X.P
XIf \fBwnewmail\fR is started up with a filename, it will
Xperform exactly the same, but with the specified file as
Xthe one to check rather than the default users mailbox.
X.SH AUTHOR
XDave Taylor, Hewlett-Packard Laboratories.
X.SH SEE ALSO
Xnotify in sh(1) or csh(1), newmail(1L)
X.SH NOTE
XThis is almost identical to the program \fBnewmail\fR...
X.SH BUG REPORTS TO
XSyd Weinstein	syd@dsinc.UUCP	(dsinc!syd)
SHAR_EOF
chmod 0444 doc/wnewmail.1 || echo "restore of doc/wnewmail.1 fails"
echo "x - extracting filter/Makefile.mt (Text)"
sed 's/^X//' << 'SHAR_EOF' > filter/Makefile.mt &&
X#
X# @(#)$Id: Makefile.mt,v 2.1 88/09/15 21:26:44 syd Exp $
X#  Makefile for the Elm system filter program
X#
X#         (C) Copyright 1986, Dave Taylor
X#
X#  $Log:	Makefile.mt,v $
X# Revision 2.1  88/09/15  21:26:44  syd
X# Initial 2.1 Release
X# 
X#
X#  88/08/27 nicmad!brown (Mike Brown)
X#	change to add buffer.c/o as a dependency for __vbuf
X#
X#  Original 2.1 version: June 29th, 1988 - Eric Christensen
X
XSHELL=/bin/sh
X
XDEFINE= >os-define<
XLIB2  = >lib2<
X
XCFLAGS= -O -I../hdrs
XCC=	>cc<
XRM= 	>rm<
XECHO=  /bin/echo
X
XOBJ     =   ../bin/filter
XHDRS    =   ../hdrs/defs.h ../hdrs/sysdefs.h ../hdrs/filter.h
XBINARIES=   buffer.o actions.o filter.o lock.o parse.o rules.o 	\
X	    summarize.o utils.o utils2.o
XSRC     =   buffer.c actions.c filter.c lock.c parse.c rules.c 	\
X	    summarize.c utils.c utils2.c
X
Xall: ${OBJ}
X
X../bin/filter  : ${HDRS} ${BINARIES}
X	${CC} ${CFLAGS} ${DEFINE} ${BINARIES} -o ${OBJ}
X
Xbuffer.o : ${HDRS} buffer.c
X	${CC} -c ${CFLAGS} ${DEFINE} buffer.c
X
Xactions.o : ${HDRS} actions.c
X	${CC} -c ${CFLAGS} ${DEFINE} actions.c
X
Xfilter.o : ${HDRS} filter.c
X	${CC} -c ${CFLAGS} ${DEFINE} filter.c
X
Xlock.o : ${HDRS} lock.c
X	${CC} -c ${CFLAGS} ${DEFINE} lock.c
X
Xparse.o : ${HDRS} parse.c
X	${CC} -c ${CFLAGS} ${DEFINE} parse.c
X
Xutils.o : ${HDRS} utils.c
X	${CC} -c ${CFLAGS} ${DEFINE} utils.c
X
Xutils2.o : ${HDRS} utils2.c
X	${CC} -c ${CFLAGS} ${DEFINE} utils2.c
X
Xrules.o : ${HDRS} rules.c
X	${CC} -c ${CFLAGS} ${DEFINE} rules.c
X
Xsummarize.o : ${HDRS} summarize.c
X	${CC} -c ${CFLAGS} ${DEFINE} summarize.c
X
Xlint    : 
X	lint -I../hdrs ${SRC} > LINT.OUT
X
Xclean	:
X	${RM} ${BINARIES} ../bin/filter
X
Xindex   :
X	index ${SRC} > INDEX
X
SHAR_EOF
chmod 0444 filter/Makefile.mt || echo "restore of filter/Makefile.mt fails"
echo "x - extracting filter/actions.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > filter/actions.c &&
X
Xstatic char rcsid[] ="@(#)$Id: actions.c,v 2.1 88/09/15 21:28:04 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.1 $   $State: Exp $
X *
X * 			Copyright (c) 1986 Dave Taylor
X *******************************************************************************
X * Bug reports, patches, comments, suggetions should be sent to:
X *
X *	Eric D. Christensen  -  edc@altnet.ALTOS.COM 
X *				uunet!altnet!edc
X *
X *******************************************************************************
X * $Log:	actions.c,v $
X * Revision 2.1  88/09/15  21:28:04  syd
X * checked in with -k by syd at 88.09.15.21.28.04.
X * 
X * Revision 2.1  88/07/21  09:55:04  edc
X * Final hacks and cleanup to the 2.1 alpha test release.
X * 
X * Revision 2.0  88/06/27  16:00:05  edc
X * This is the original 2.0 gamma source which leaked from HP
X * 
X *
X *
X ******************************************************************************/
X
X
X/** RESULT oriented routines *chuckle*.  These routines implement the
X    actions that result from either a specified rule being true or from
X    the default action being taken.
X**/
X
X#include <stdio.h>
X#include <pwd.h>
X#include <ctype.h>
X#include <fcntl.h>
X
X#include "defs.h"
X#include "filter.h"
X
XFILE *emergency_local_delivery();
X
Xmail_message(address)
Xchar *address;
X{
X	/** Called with an address to send mail to.   For various reasons
X	    that are too disgusting to go into herein, we're going to actually
X	    open the users mailbox and by hand add this message.  Yech.
X	    NOTE, of course, that if we're going to MAIL the message to someone
X	    else, that we'll try to do nice things with it on the fly...
X	**/
X
X	FILE *pipefd, *tempfd, *mailfd;
X	int  in_header = TRUE, line_count = 0;
X	char tempfile[SLEN], mailbox[SLEN], lockfile[SLEN],
X	     buffer[VERY_LONG_STRING];
X
X	if (verbose && ! log_actions_only && outfd != NULL)
X	  fprintf(outfd, "filter (%s): Mailing message to %s\n", 
X		   username, address);
X
X	if (! show_only) {
X	  sprintf(tempfile, "%s.%d", filter_temp, getpid());
X
X	  if ((tempfd = fopen(tempfile, "r")) == NULL) {
X	    if (outfd != NULL)
X	      fprintf(outfd, "filter (%s): Can't open temp file %s!!\n", 
X		    username, tempfile);
X	    if (outfd != NULL) fclose(outfd);
X	    exit(1);
X	  }
X	 	
X	  if (strcmp(address, username) != 0) {	/* mailing to someone else */
X	    
X	    if (already_been_forwarded) {	/* potential looping! */
X	      if (contains(from, username)) {
X		if (outfd != NULL)
X	          fprintf(outfd, 
X	"filter (%s): Filter loop detected!  Message left in file %s.%d\n", 
X			username, filter_temp, getpid());
X	        if (outfd != NULL) fclose(outfd);
X	        exit(0);
X	      }
X	    }
X
X	    sprintf(buffer, "%s %s %s", sendmail, smflags, address);
X
X	    if ((pipefd = popen(buffer, "w")) == NULL) {
X	      if (outfd != NULL)
X	        fprintf(outfd, "filter (%s): popen %s failed!\n", buffer);
X	      sprintf(buffer, "((%s %s %s ; %s %s) & ) < %s &",
X		      sendmail , smflags, address, remove, tempfile, tempfile);
X	      system(buffer);
X	      return;
X	    }
X
X	    fprintf(pipefd, "Subject: \"%s\"\n", subject);
X	    fprintf(pipefd, "From: The Filter of %s@%s <%s>\n", 
X		    username, hostname, username);
X	    fprintf(pipefd, "To: %s\n", address);
X	    fprintf(pipefd, "X-Filtered-By: filter, version %s\n\n", VERSION);
X
X	    fprintf(pipefd, "-- Begin filtered message --\n\n");
X	
X	    while (fgets(buffer, LONG_SLEN, tempfd) != NULL)
X	      if (already_been_forwarded && in_header)
X	        in_header = (strlen(buffer) == 1? 0 : in_header);
X	      else
X	        fprintf(pipefd," %s", buffer);
X
X	    fprintf(pipefd, "\n-- End of filtered message --\n");
X	    fclose(pipefd);
X	    fclose(tempfd);
X	
X	    return;		/* YEAH!  Wot a slick program, eh? */
X	  
X	  }
X	  
X	  /** OTHERWISE it is to the current user... **/
X
X	  sprintf(mailbox,  "%s%s", mailhome, username);
X	  
X	  if (! lock()) {
X	    if (outfd != NULL) {
X	      fprintf(outfd, "filter (%s): Couldn't create lockfile %s\n",
X		    username, lockfile);
X	      fprintf(outfd, "filter (%s): Can't open mailbox %s!\n",
X			username, mailbox);
X	    }
X	    if ((mailfd = emergency_local_delivery()) == NULL)
X	      exit(1);
X	  }
X	  else if ((mailfd = fopen(mailbox,"a")) == NULL)
X	    if ((mailfd = emergency_local_delivery()) == NULL)
X	      exit(1);
X
X	  while (fgets(buffer, sizeof(buffer), tempfd) != NULL) {
X	    line_count++;
X	    if (the_same(buffer, "From ") && line_count > 1)
X	      fprintf(mailfd, ">%s", buffer);
X	    else
X	      fputs(buffer, mailfd);
X	  }
X
X	  fputs("\n", mailfd);
X
X	  fclose(mailfd);
X	  unlock();		/* blamo or not?  Let it decide! */
X	  fclose(tempfd);
X	} /* end if show only */
X}
X
Xsave_message(foldername)
Xchar *foldername;
X{
X	/** Save the message in a folder.  Use full file buffering to
X	    make this work without contention problems **/
X
X	FILE  *fd, *tempfd;
X	char  filename[SLEN], buffer[LONG_SLEN];
X
X	if (verbose && outfd != NULL)
X	  fprintf(outfd, "filter (%s): Message saved in folder %s\n", 
X		  username, foldername);
X	
X	if (!show_only) {
X	  sprintf(filename, "%s.%d", filter_temp, getpid());
X
X	  if ((fd = fopen(foldername, "a")) == NULL) {
X	    if (outfd != NULL)
X	      fprintf(outfd, 
X		 "filter (%s): can't save message to requested folder %s!\n",
X		    username, foldername);
X	    return(1);
X	  }
X
X	  if ((tempfd = fopen(filename, "r")) == NULL) {
X	    if (outfd != NULL)
X	      fprintf(outfd, 
X		     "filter (%s): can't open temp file for reading!\n",
X		     username);
X	     return(1);
X	  }
X
X	  while (fgets(buffer, sizeof(buffer), tempfd) != NULL)
X	    fputs(buffer, fd);
X	
X	  fclose(fd);
X	  fclose(tempfd);
X	}
X
X 	return(0);
X}
X
Xexecute(command)
Xchar *command;
X{
X	/** execute the indicated command, feeding as standard input the
X	    message we have.
X	**/
X
X	char buffer[LONG_SLEN];
X
X	if (verbose && outfd != NULL)
X	  fprintf(outfd, "filter (%s): Executing %s\n", 
X		  username, command);
X
X	if (! show_only) {
X	  sprintf(buffer, "%s %s.%d | %s", cat, filter_temp, getpid(), command);
X	  system(buffer);
X	}
X}
X
XFILE *
Xemergency_local_delivery()
X{
X	/** This is called when we can't deliver the mail to the usual
X	    mailbox in the usual way ...
X	**/
X
X	FILE *tempfd;
X	char  mailbox[SLEN];
X
X	sprintf(mailbox, "%s/%s", home, EMERGENCY_MAILBOX);
X
X	if ((tempfd = fopen(mailbox, "a")) == NULL) {
X	  if (outfd != NULL)
X	    fprintf(outfd, "filter (%s): Can't open %s either!!\n",
X		    username, mailbox);
X
X	  sprintf(mailbox,"%s/%s", home, EMERG_MBOX); 
X
X	  if ((tempfd = fopen(mailbox, "a")) == NULL) {
X
X	    if (outfd != NULL) {
X	      fprintf(outfd,"filter (%s): Can't open %s either!!!!\n",
X		      username, mailbox);
X	      fprintf(outfd, 
X		      "filter (%s): I can't open ANY mailboxes!  Augh!!\n",
X		       username);
X	     }
X
X	     fclose(tempfd);
X	     leave("Cannot open any mailbox");		/* DIE DIE DIE DIE!! */
X	   }
X	   else
X	     if (outfd != NULL)
X	       fprintf(outfd, "filter (%s): Using %s as emergency mailbox\n",
X		       username, mailbox);
X	  }
X	  else
X	    if (outfd != NULL)
X	      fprintf(outfd, "filter (%s): Using %s as emergency mailbox\n",
X		      username, mailbox);
X
X	return((FILE *) tempfd);
X}
SHAR_EOF
chmod 0444 filter/actions.c || echo "restore of filter/actions.c fails"
echo "x - extracting filter/buffer.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > filter/buffer.c &&
X
Xstatic char rcsid[] ="@(#)$Id: buffer.c,v 2.1 88/09/15 21:28:06 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.1 $   $State: Exp $
X *
X * 			Copyright (c) 1986 Dave Taylor
X *******************************************************************************
X * Bug reports, patches, comments, suggetions should be sent to:
X *
X *	Eric D. Christensen  -  edc@altnet.ALTOS.COM 
X *				uunet!altnet!edc
X *
X *******************************************************************************
X * $Log:	buffer.c,v $
X * Revision 2.1  88/09/15  21:28:06  syd
X * checked in with -k by syd at 88.09.15.21.28.06.
X * 
X * Revision 2.1  88/07/21  09:55:30  edc
X * Final hacks and cleanup to the 2.1 alpha test release.
X * 
X * Revision 2.0  88/06/27  16:00:24  edc
X * This is the original 2.0 gamma source which leaked from HP
X * 
X *
X *
X ******************************************************************************/
X
X#include <stdio.h>
X
Xchar  _vbuf[5*BUFSIZ];		/* space for file buffering */
SHAR_EOF
chmod 0444 filter/buffer.c || echo "restore of filter/buffer.c fails"
echo "x - extracting filter/filter.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > filter/filter.c &&
X
Xstatic char rcsid[] ="@(#)$Id: filter.c,v 2.1 88/09/15 21:28:07 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.1 $   $State: Exp $
X *
X * 			Copyright (c) 1986, 1987 Dave Taylor
X *******************************************************************************
X * Bug reports, patches, comments, suggetions should be sent to:
X *
X *	Eric D. Christensen  -  edc@altnet.ALTOS.COM 
X *				uunet!altnet!edc
X *
X *******************************************************************************
X * $Log:	filter.c,v $
X * Revision 2.1  88/09/15  21:28:07  syd
X * checked in with -k by syd at 88.09.15.21.28.07.
X * 
X * Revision 2.1  88/07/21  09:55:34  edc
X * Final hacks and cleanup to the 2.1 alpha test release.
X * 
X * Revision 2.0  88/06/27  16:00:27  edc
X * This is the original 2.0 gamma source which leaked from HP
X * 
X *
X *
X ******************************************************************************/
X
X
X/** This program is used as a filter within the users ``.forward'' file
X    and allows intelligent preprocessing of mail at the point between
X    when it shows up on the machine and when it is actually put in the
X    mailbox.
X
X    The program allows selection based on who the message is FROM, TO, or
X    what the subject is.  Acceptable actions are for the program to DELETE
X    the message, SAVE the message in a specified folder, FORWARD the message
X    to a specified user, SAVE the message in a folder, but add a copy to the
X    users mailbox anyway, or simply add the message to the incoming mail.
X
X    Filter also keeps a log of what it does as it goes along, and at the
X    end of each `quantum' mails a summary of actions, if any, to the user.
X
X    Uses the files: $HOME/.filter for instructions to this program, and
X    $HOME/.filterlog for a list of what has been done since last summary.
X
X    Rev 2.0: knows about From: and Reply-To: 
X    Fix: knows that mail lines are approx. ~5K or greater...
X    enhanced to have the '-o output-file' specifier
X
X**/
X
X#include <stdio.h>
X#include <pwd.h>
X#include <ctype.h>
X#include <time.h>
X#include <fcntl.h>
X
X#include "defs.h"
X
X#define  MAIN_ROUTINE			/* for the filter.h file, of course! */
X#include "filter.h"
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	extern char *optional_arg;		/* for getopt() params      */
X	FILE   *fd;				/* for output to temp file! */
X	struct passwd  *passwd_entry, 
X		       *getpwuid();		/* for /etc/passwd          */
X	char filename[SLEN],			/* name of the temp file    */
X	     buffer[MAX_LINE_LEN];		/* input buffer space       */
X	int  in_header = TRUE,			/* for header parsing       */
X	     in_to     = FALSE,			/* are we on 'n' line To: ? */
X	     summary   = FALSE,			/* a summary is requested?  */
X	     c;					/* var for getopt routine   */
X
X	/* first off, let's get the info from /etc/passwd */ 
X	
X	if ((passwd_entry = getpwuid(getuid())) == NULL) 
X	  leave("Cannot get password entry for this uid!");
X
X	strcpy(home, passwd_entry->pw_dir);
X	strcpy(username, passwd_entry->pw_name);
X	outfname[0] = to[0] = '\0';	/* nothing read in yet, right? */
X
X	gethostname(hostname, sizeof(hostname));
X
X	/* now parse the starting arguments... */
X
X	while ((c = getopt(argc, argv, "clno:rSsv")) > 0) {
X	  switch (c) {
X	    case 'c' : clear_logs = TRUE;			break;
X	    case 'l' : log_actions_only = TRUE;			break;
X	    case 'o' : strcpy(outfname, optional_arg);		break;
X	    case 'r' : printing_rules = TRUE;			break;
X	
X	    case 's' : summary = TRUE;				break;
X	    case 'S' : long_summary = TRUE;			break;
X
X	    case 'n' : show_only = TRUE;			break;
X	    case 'v' : verbose = TRUE;				break;
X	  }
X	}
X
X	if (c < 0) {
X	  fprintf(stderr, 
X		  "Usage: | filter [-nrv]\n\   or: filter [-c] -[s|S]\n");
X          exit(1);
X	}
X
X	/* let's open our outfd logfile as needed... */
X
X	if (outfname[0] == '\0') 	/* default is stdout */
X	  outfd = stdout;
X	else 
X	  if ((outfd = fopen(outfname, "a")) == NULL) {
X	    if (isatty(fileno(stderr)))
X	      fprintf(stderr,"filter (%s): couldn't open log file %s\n",
X		      username, outfname);
X	  }
X
X	if (summary || long_summary) {
X          if (get_filter_rules() == -1) {
X	    exit(1);
X	    if (outfd != NULL) fclose(outfd);
X	  }
X	  show_summary();
X	  if (outfd != NULL) fclose(outfd);
X	  exit(0);
X	}
X
X	if (printing_rules) {
X          if (get_filter_rules() == -1)
X	    fprintf(outfd,"filter (%s): Couldn't get rules!\n", username);
X          else
X	    print_rules();
X	  if (outfd != NULL) fclose(outfd);
X          exit(0);
X	}
X
X	/* next, create the tempfile and save the incoming message */
X
X	sprintf(filename, "%s.%d", filter_temp, getpid());
X
X	if ((fd = fopen(filename,"w")) == NULL)
X	  leave("Cannot open temporary file!");
X
X	while (fgets(buffer, MAX_LINE_LEN, stdin) != NULL) {
X
X	  remove_return(buffer);
X
X	  if (in_header) {
X
X	    if (! whitespace(buffer[0])) 
X		in_to = FALSE;
X
X	    if (the_same(buffer, "From ")) 
X	      save_from(buffer);
X	    else if (the_same(buffer, "Subject:")) 
X	      save_subject(buffer);
X	    else if (the_same(buffer, "To:") || the_same(buffer, "Cc:")) {
X	      in_to++;
X	      save_to(buffer);
X	    }
X	    else if (the_same(buffer, "X-Filtered-By:")) 
X	      already_been_forwarded++;	/* could be a loop here! */
X#ifdef USE_EMBEDDED_ADDRESSES
X	    else if (the_same(buffer, "From:"))
X	      save_embedded_address(buffer, "From:");
X	    else if (the_same(buffer, "Reply-To:"))
X	      save_embedded_address(buffer, "Reply-To:");
X#endif
X	    else if (strlen(buffer) < 2) 
X	      in_header = 0;
X	    else if (whitespace(buffer[0]) && in_to)
X	      strcat(to, buffer);
X	  }
X	
X          fprintf(fd, "%s\n", buffer);	/* and save it regardless! */
X	  fflush(fd);
X	  lines++;
X	}
X
X	fclose(fd);
X
X	/** next let's see if the user HAS a filter file, and if so what's in
X            it (and so on) **/
X
X	if (get_filter_rules() == -1)
X	  mail_message(username);
X	else {
X	  switch (action_from_ruleset()) {
X
X	    case DELETE : if (verbose && outfd != NULL)
X			    fprintf(outfd, "filter (%s): Message deleted\n",
X				    username);
X			  log(DELETE);					break;
X
X	    case SAVE   : if (save_message(rules[rule_choosen].argument2)) {
X			    mail_message(username);
X			    log(FAILED_SAVE);
X			  }
X			  else
X		 	    log(SAVE);					break;
X
X	    case SAVECC : if (save_message(rules[rule_choosen].argument2))
X			    log(FAILED_SAVE);
X			  else
X		            log(SAVECC);					
X			  mail_message(username);			break;
X
X	    case FORWARD: mail_message(rules[rule_choosen].argument2);
X			  log(FORWARD);					break;
X
X	    case EXEC   : execute(rules[rule_choosen].argument2);
X			  log(EXEC);					break;
X
X	    case LEAVE  : mail_message(username);
X			  log(LEAVE);					break;
X	  }
X	}
X
X	(void) unlink(filename);	/* remove the temp file, please! */
X	if (outfd != NULL) fclose(outfd);
X	exit(0);
X}
X
Xsave_from(buffer)
Xchar *buffer;
X{
X	/** save the SECOND word of this string as FROM **/
X
X	register int i, j;
X
X	for (i=0; buffer[i] != ' '; i++) 	;	/* get to word     */
X
X	for (i++, j=0; buffer[i] != ' ' && i < strlen(buffer); i++) 
X	  from[j++] = buffer[i];			/* copy it and     */
X
X	from[j++] = '\0';				/* Null terminate! */
X}
X
Xsave_subject(buffer)
Xchar *buffer;
X{
X	/** save all but the word "Subject:" for the subject **/
X
X	register int skip = 8;  /* skip "Subject:" initially */
X
X	while (buffer[skip] == ' ') skip++;
X
X	strcpy(subject, (char *) buffer + skip);
X}
X
Xsave_to(buffer)
Xchar *buffer;
X{
X	/** save all but the word "To:" or "Cc:" for the to list **/
X
X	register int skip = 3;	/* skip "To:" or "Cc:" initially */
X
X	while (buffer[skip] == ' ') skip++;
X
X	strcat(to, (char *) buffer + skip);
X}
X
X#ifdef USE_EMBEDDED_ADDRESSES
X
Xsave_embedded_address(buffer, fieldname)
Xchar *buffer, *fieldname;
X{
X	/** this will replace the 'from' address with the one given, 
X	    unless the address is from a 'reply-to' field (which overrides 
X	    the From: field).  The buffer given to this routine can have one 
X            of three forms:
X		fieldname: username <address>
X		fieldname: address (username)
X		fieldname: address
X	**/
X	
X	static int processed_a_reply_to = 0;
X	char address[LONG_STRING];
X	register int i, j = 0;
X
X	/** first let's extract the address from this line.. **/
X
X	if (buffer[strlen(buffer)-1] == '>') {	/* case #1 */
X	  for (i=strlen(buffer)-1; buffer[i] != '<' && i > 0; i--)
X		/* nothing - just move backwards .. */ ;
X	  i++;	/* skip the leading '<' symbol */
X	  while (buffer[i] != '>')
X	    address[j++] = buffer[i++];
X	  address[j] = '\0';
X	}
X	else {	/* get past "from:" and copy until white space or paren hit */
X	  for (i=strlen(fieldname); whitespace(buffer[i]); i++)
X	     /* skip past that... */ ;
X	  while (buffer[i] != '(' && ! whitespace(buffer[i]) && buffer[i]!='\0')
X	    address[j++] = buffer[i++];
X	  address[j] = '\0';
X	}
X
X	/** now let's see if we should overwrite the existing from address
X	    with this one or not.. **/
X
X	if (processed_a_reply_to)
X	  return;	/* forget it! */
X
X	strcpy(from, address);			/* replaced!! */
X
X	if (strcmp(fieldname, "Reply-To:") == 0)
X	  processed_a_reply_to++;
X}
X#endif
SHAR_EOF
chmod 0444 filter/filter.c || echo "restore of filter/filter.c fails"
echo "x - extracting filter/lock.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > filter/lock.c &&
X
Xstatic char rcsid[] ="@(#)$Id: lock.c,v 2.2 88/09/15 21:28:08 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.2 $   $State: Exp $
X *
X *   (C) Copyright 1986, 1987, 1988, Dave Taylor
X *******************************************************************************
X * Bug reports, patches, comments, suggetions should be sent to:
X *
X *	Eric D. Christensen  -  edc@altnet.ALTOS.COM 
X *				uunet!altnet!edc
X *
X *******************************************************************************
X * $Log:	lock.c,v $
X * Revision 2.2  88/09/15  21:28:08  syd
X * checked in with -k by syd at 88.09.15.21.28.08.
X * 
X * 14 Sep 88 Chip Rosenthal <chip@vector>
X * This file contains the patches for Elm 2.1b to run on XENIX System V.
X * The general issues with running Elm on such a machine are:
X *
X * Revision 2.2  88/07/21  09:55:41  edc
X * Final hacks and cleanup to the 2.1 alpha test release.
X * 
X * Revision 2.1  88/06/28  12:57:35  edc
X * Added include for sys/types.h before sys/file.h. Some systems need this to
X * define cnt_t for sys/file.h. This shouldn't bother systems that don't
X * need it.
X * 
X * Revision 2.0  88/06/27  16:00:28  edc
X * This is the original 2.0 gamma source which leaked from HP
X * 
X *
X *
X ******************************************************************************/
X
X
X/** The lock() and unlock() routines herein duplicate exactly the
X    equivalent routines in the Elm Mail System, and should also be
X    compatible with sendmail, rmail, etc etc.
X
X  
X**/
X
X#include <stdio.h>
X#include <sys/types.h> /* some sys need this to define cnt_t for sys/file.h */
X#include <fcntl.h>
X#ifdef XENIX		/* XENIX 286 barfs on the "far" in sys/file.h */
X# define far
X#endif
X#include <sys/file.h>
X
X#include "defs.h"
X#include "filter.h"
X
Xint  we_locked_it = 0;
Xchar lockfile[SLEN];
X
Xint
Xlock()
X{
X	/** This routine will return 1 if we could lock the mailfile,
X	    zero otherwise.
X	**/
X
X	int attempts = 0, ret;
X
X	sprintf(lockfile,  "%s%s.lock", mailhome, username);
X
X	while ((ret = open(lockfile, O_WRONLY | O_CREAT | O_EXCL, 0777)) < 0 
X	       && attempts++ < 10) {
X	  sleep(3);	/* wait three seconds each pass, okay?? */
X	}
X
X	if (ret > 0) {
X	  we_locked_it++;
X	  close(ret);			/* no need to keep it open! */
X	}
X
X	return( (ret >= 0) );
X}
X
Xunlock()
X{
X	/** this routine will remove the lock file, but only if we were
X	    the people that locked it in the first place... **/
X
X	if (we_locked_it)
X	  unlink(lockfile);	/* blamo! */
X
X	we_locked_it = 0;
X}
SHAR_EOF
chmod 0444 filter/lock.c || echo "restore of filter/lock.c fails"
echo "x - extracting filter/parse.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > filter/parse.c &&
X
Xstatic char rcsid[] ="@(#)$Id: parse.c,v 2.1 88/09/15 21:28:09 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.1 $   $State: Exp $
X *
X * 			Copyright (c) 1986 Dave Taylor
X *******************************************************************************
X * Bug reports, patches, comments, suggetions should be sent to:
X *
X *	Eric D. Christensen  -  edc@altnet.ALTOS.COM 
X *				uunet!altnet!edc
X *
X *******************************************************************************
X * $Log:	parse.c,v $
X * Revision 2.1  88/09/15  21:28:09  syd
X * checked in with -k by syd at 88.09.15.21.28.09.
X * 
X * Revision 2.1  88/07/21  09:55:43  edc
X * Final hacks and cleanup to the 2.1 alpha test release.
X * 
X * Revision 2.0  88/06/27  16:00:28  edc
X * This is the original 2.0 gamma source which leaked from HP
X * 
X *
X *
X ******************************************************************************/
X
X
X/** This is the parser for the filter program.  It accepts a wide variety of
X    constructs, building the ruleset table as it goes along.  Check the 
X    data structure in filter.h for more information on how the rules are
X    stored.  The parser is a cunning state-table based program.
X
X**/
X
X#include <stdio.h>
X#include <ctype.h>
X
X#include "defs.h"
X#include "filter.h"
X
X#define NONE			0
X#define AND			10
X
X#define NEXT_CONDITION		0
X#define GETTING_OP		1
X#define READING_ARGUMENT	2
X#define READING_ACTION		3
X#define ACTION_ARGUMENT		4
X
Xchar *strtok(), *whatname(), *actionname();
X
Xint
Xget_filter_rules()
X{
X	/** Given the users home directory, open and parse their rules table,
X	    building the data structure as we go along.
X	    returns -1 if we hit an error of any sort...
X	**/
X
X	FILE *fd;				/* the file descriptor     */
X	char  buffer[SLEN], 			/* fd reading buffer       */
X	      *str, 				/* ptr to read string      */
X	      *word,				/* ptr to 'token'          */
X	      filename[SLEN], 			/* the name of the ruleset */
X	      action_argument[SLEN], 		/* action arg, per rule    */
X	      cond_argument[SLEN];		/* cond arg, per condition */
X	int   not_condition = FALSE, 		/* are we in a "not" ??    */
X	      type=NONE, 			/* what TYPE of condition? */
X	      lasttype, 			/* and the previous TYPE?  */
X	      state = NEXT_CONDITION,		/* the current state       */
X	      in_single, in_double, 		/* for handling spaces.    */
X	      i, 				/* misc integer for loops  */
X	      relop = NONE,			/* relational operator     */
X	      action, 				/* the current action type */
X	      line = 0;				/* line number we're on    */
X
X	struct condition_rec	*cond, *newcond;
X
X	sprintf(filename,"%s/%s", home, filterfile);
X
X	if ((fd = fopen(filename,"r")) == NULL) {
X	  if (outfd != NULL)
X	   fprintf(outfd,"filter (%s): Couldn't read user filter rules file!\n",
X		  username);
X	  return(-1);
X	}
X
X	cond_argument[0] = action_argument[0] = '\0';
X
X	/* Now, for each line... **/
X
X	if ((cond = (struct condition_rec *) 
X		     malloc(sizeof(struct condition_rec))) == NULL) {
X	  if (outfd != NULL)
X	    fprintf(outfd,"filter (%s): couldn't malloc first condition rec!\n",
X		    username);
X	  return(-1);
X	}
X	
X	rules[total_rules].condition = cond;	/* hooked in! */
X
X	while (fgets(buffer, SLEN, fd) != NULL) {
X	  line++;
X
X	  if (buffer[0] == '#' || strlen(buffer) < 2)
X	    continue;		/* nothing to look at! */
X
X	  in_single = in_double = 0;
X
X	  for (i=0; i < strlen(buffer); i++) {
X	    if (buffer[i] == '"') 
X	      in_double = ! in_double;
X	    else if (buffer[i] == '\'')
X	      in_single = ! in_single;
X	    if ((in_double || in_single) && buffer[i] == ' ')
X	      buffer[i] = '_';
X	  }
X
X	  lasttype = type;
X	  type = NONE;
X	  str = (char *) buffer;
X
X	  /** Three pieces to this loop - get the `field', the 'relop' (if
X	      there) then, if needed, get the argument to check against (not 
X	      needed for errors or the AND, of course)
X	  **/
X
X	  while ((word = strtok(str, " ()[]:\t\n")) != NULL) {
X
X	    str = (char *) NULL;		/* we can start stomping! */
X	  
X	    lowercase(word);
X
X	    if (strcmp(word, "if") == 0) {	/* only ONE 'if' allowed */
X	      if ((word = strtok(str, " ()[]:\t\n")) == NULL)	/* NEXT! */
X	        continue;
X	      lowercase(word);
X	    }
X	
X	    if (state == NEXT_CONDITION) {
X	      lasttype = type;
X	      type = NONE;
X
X	      if (the_same(word, "not") || the_same(word, "!")) {
X	        not_condition = TRUE;
X	        if ((word = strtok(str, " ()[]'\"\t\n")) == NULL)
X	          continue;
X	      }
X
X	           if (the_same(word, "from")) 	    type = FROM;
X	      else if (the_same(word, "to")) 	    type = TO;
X	      else if (the_same(word, "subject"))   type = SUBJECT;
X	      else if (the_same(word, "lines"))     type = LINES;
X	      else if (the_same(word, "contains"))  type = CONTAINS;
X	      else if (the_same(word, "and") || 
X	               the_same(word, "&&")) 	    type = AND;
X
X	      else if (the_same(word,"?") || the_same(word, "then") || 
X		       the_same(word, "always")) {
X
X		/** shove THIS puppy into the structure and let's continue! **/
X
X	        if (lasttype == AND) {
X		  if (outfd != NULL)
X	            fprintf(outfd,
X         "filter (%s): Error reading line %d of rules - badly placed \"and\"\n",
X		    username, line);
X		  return(-1);
X	        }
X
X	        if (the_same(word, "always"))
X		  cond->matchwhat = ALWAYS;	/* so it's a hack... */
X		else
X		  cond->matchwhat = lasttype;
X
X	        if (relop == NONE) relop = EQ;	/* otherwise can't do -relop */
X	        cond->relation  = (not_condition? - (relop) : relop);
X
X		for (i=0;i<strlen(cond_argument);i++)
X	          if (cond_argument[i] == '_') cond_argument[i] = ' ';
X
X		strcpy(cond->argument1, cond_argument);
X	        if ((newcond = (struct condition_rec *)
X		     malloc(sizeof(struct condition_rec))) == NULL) {
X		  if (outfd != NULL)
X	            fprintf(outfd,
X		     	    "filter (%s): Couldn't malloc new cond rec!!\n",
X		            username);
X		  return(-1);
X	        }
X	        cond->next = NULL;
X
X	        relop = EQ;	/* default relational condition */
X
X	        state = READING_ACTION;
X	        if ((word = strtok(str, " ()[]'\"\t\n")) == NULL)
X	          continue;
X	        goto get_outta_loop;
X	      }
X
X	      if (type == NONE) {
X		if (outfd != NULL)
X	          fprintf(outfd,
X      "filter (%s): Error reading line %d of rules - field \"%s\" unknown!\n",
X		     username, line, word);
X		return(-1);
X	      }
X
X	      if (type == AND) {
X
X		/** shove THIS puppy into the structure and let's continue! **/
X
X		cond->matchwhat = lasttype;
X	        cond->relation  = (not_condition? - (relop) : relop);
X		strcpy(cond->argument1, cond_argument);
X	        if ((newcond = (struct condition_rec *)
X	             malloc(sizeof(struct condition_rec))) == NULL) {
X		  if (outfd != NULL)
X	            fprintf(outfd,
X			"filter (%s): Couldn't malloc new cond rec!!\n",
X			username);
X		  return(-1);
X	        }
X	        cond->next = newcond;
X		cond = newcond;
X		cond->next = NULL;
X
X	        not_condition = FALSE;
X	        state = NEXT_CONDITION;
X	      }
X	      else {
X	        state = GETTING_OP;
X	      }
X	    }
X
Xget_outta_loop: 	/* jump out when we change state, if needed */
X
X	    if (state == GETTING_OP) {
X
X	       if ((word = strtok(str, " ()[]'\"\t\n")) == NULL)
X	         continue;
X
X	       lowercase(word);
X
X	       relop = NONE;
X
X	       if (the_same(word, "=") || the_same(word, "in") || 
X                   the_same(word, "contains")) {
X                 state = READING_ARGUMENT;
X	         relop = EQ;
X	       }
X	       else {
X	         if (the_same(word, "<=")) 	relop = LE;
X	         else if (the_same(word, ">="))	relop = GE;
X	         else if (the_same(word, ">"))	relop = GT;
X	         else if (the_same(word, "<>")||
X		          the_same(word, "!="))	relop = NE;
X	         else if (the_same(word, "<"))	relop = LT;
X
X		 /* maybe there isn't a relop at all!! */
X
X		 state=READING_ARGUMENT;
X
X	       }
X	    }
X		 
X	    if (state == READING_ARGUMENT) {
X	      if (relop != NONE) {
X	        if ((word = strtok(str, " ()[]'\"\t\n")) == NULL)
X	          continue;
X	      }
X	      for (i=0;i<strlen(word);i++)
X	        if (word[i] == '_') word[i] = ' ';
X
X	      strcpy(cond_argument, word);
X	      state = NEXT_CONDITION;
X	    }
X
X	    if (state == READING_ACTION) {
X	      action = NONE;
X
X	      not_condition = FALSE;
X
X	      if (the_same(word, "delete"))       action = DELETE;
X	      else if (the_same(word, "savec"))   action = SAVECC;
X	      else if (the_same(word, "save"))    action = SAVE;
X	      else if (the_same(word, "forward")) action = FORWARD;
X	      else if (the_same(word, "exec"))    action = EXEC;
X	      else if (the_same(word, "leave"))   action = LEAVE;
X	      else {
X		if (outfd != NULL)
X	          fprintf(outfd,
X	"filter (%s): Error on line %d of rules - action \"%s\" unknown\n",
X			username, line, word);
X	      }
X
X	      if (action == DELETE || action == LEAVE) {
X	        /** add this to the rules section and alloc next... **/
X
X	        rules[total_rules].action = action;
X		rules[total_rules].argument2[0] = '\0';	/* nothing! */
X	        total_rules++;
X	         
X	        if ((cond = (struct condition_rec *)
X		     malloc(sizeof(struct condition_rec))) == NULL) {
X		  if (outfd != NULL)
X	            fprintf(outfd,
X			"filter (%s): couldn't malloc first condition rec!\n",
X			username);
X	          return(-1);
X	        }
X	
X	        rules[total_rules].condition = cond;	/* hooked in! */
X	        state = NEXT_CONDITION;	
X	      }
X	      else {
X	        state = ACTION_ARGUMENT;
X	      }
X
X	      if ((word = strtok(str, " ()[]'\"\t\n")) == NULL)
X	        continue;
X
X	    }
X	
X	    if (state == ACTION_ARGUMENT) {
X	      strcpy(action_argument, word);
X
X	      /** add this to the rules section and alloc next... **/
X
X	      rules[total_rules].action = action;
X	      expand_macros(action_argument, rules[total_rules].argument2,line,
X			    printing_rules);
X	      total_rules++;
X	         
X	      if ((cond = (struct condition_rec *)
X		     malloc(sizeof(struct condition_rec))) == NULL) {
X		if (outfd != NULL)
X	          fprintf(outfd,
X			  "filter (%s): couldn't malloc first condition rec!\n",
X			  username);
X	        return(-1);
X	      }
X	
X	      rules[total_rules].condition = cond;	/* hooked in! */
X
X	      state = NEXT_CONDITION;
X	      if ((word = strtok(str, " ()[]'\"\t\n")) == NULL)
X	        continue;
X	    }
X	  }
X	}
X
X	return(0);
X}
SHAR_EOF
chmod 0444 filter/parse.c || echo "restore of filter/parse.c fails"
echo "x - extracting filter/rules.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > filter/rules.c &&
X
Xstatic char rcsid[] ="@(#)$Id: rules.c,v 2.1 88/09/15 21:28:11 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.1 $   $State: Exp $
X *
X * 			Copyright (c) 1986 Dave Taylor
X *******************************************************************************
X * Bug reports, patches, comments, suggetions should be sent to:
X *
X *	Eric D. Christensen  -  edc@altnet.ALTOS.COM 
X *				uunet!altnet!edc
X *
X *******************************************************************************
X * $Log:	rules.c,v $
X * Revision 2.1  88/09/15  21:28:11  syd
X * checked in with -k by syd at 88.09.15.21.28.11.
X * 
X * 88/08/27 gatech!cos.COM!To.eric (Paul A. Ebersman)
X *	fix month number offset
X *
X * Revision 2.1  88/07/21  09:55:46  edc
X * Final hacks and cleanup to the 2.1 alpha test release.
X * 
X * Revision 2.0  88/06/27  16:00:29  edc
X * This is the original 2.0 gamma source which leaked from HP
X * 
X *
X *
X ******************************************************************************/
X
X/** This file contains all the rule routines, including those that apply the
X    specified rules and the routine to print the rules out.
X
X**/
X
X#include <stdio.h>
X#include <pwd.h>
X#include <ctype.h>
X#include <time.h>
X#include <fcntl.h>
X
X#include "defs.h"
X#include "filter.h"
X
Xchar *listrule();
X
Xint
Xaction_from_ruleset()
X{
X	/** Given the set of rules we've read in and the current to, from, 
X	    and subject, try to match one.  Return the ACTION of the match
X            or LEAVE if none found that apply.
X	**/
X
X	register int index = 0, not, relation, try_next_rule, x;
X	struct condition_rec *cond;
X
X	while (index < total_rules) {
X	  cond = rules[index].condition;
X	  try_next_rule = 0;
X
X	  while (cond != NULL && ! try_next_rule) {
X	    
X	    not = (cond->relation < 0);
X	    relation = abs(cond->relation);
X	
X	    switch (cond->matchwhat) {
X
X	      case TO     : x = contains(to, cond->argument1); 		break;
X	      case FROM   : x = contains(from, cond->argument1); 	break;
X	      case SUBJECT: x = contains(subject, cond->argument1);	break;
X	      case LINES  : x = compare(lines, relation, cond->argument1);break;
X		       
X	      case CONTAINS: if (outfd != NULL) fprintf(outfd,
X       "filter (%s): Error: rules based on 'contains' are not implemented!\n",
X			    username);
X			    if (outfd != NULL) fclose(outfd);
X			    exit(0); 		
X
X	      case ALWAYS: not = FALSE; x = TRUE;			break;
X	    }
X
X	    if ((not && x) || ((! not) && (! x))) /* this test failed (LISP?) */
X	      try_next_rule++;
X	    else
X	      cond = cond->next;		  /* next condition, if any?  */
X	  }
X
X	  if (! try_next_rule) {
X	    rule_choosen = index;
X 	    return(rules[rule_choosen].action);
X	  }
X	  index++;
X	}
X
X	rule_choosen = -1;
X	return(LEAVE);
X}
X
X#define get_the_time()	if (!gotten_time) { 		  \
X			   thetime = time( (long *) 0);   \
X			   timerec = localtime(&thetime); \
X			   gotten_time++; 		  \
X			}
X
Xexpand_macros(word, buffer, line, display)
Xchar *word, *buffer;
Xint  line, display;
X{
X	/** expand the allowable macros in the word;
X		%d	= day of the month  
X		%D	= day of the week  
X	        %h	= hour (0-23)	 
X		%m	= month of the year
X		%r	= return address of sender
X	   	%s	= subject of message
X	   	%S	= "Re: subject of message"  (only add Re: if not there)
X		%t	= hour:minute 	
X		%y	= year		  
X	    or simply copies word into buffer. If "display" is set then
X	    instead it puts "<day-of-month>" etc. etc. in the output.
X	**/
X
X	struct tm *localtime(), *timerec;
X	long     time(), thetime;
X	register int i, j=0, gotten_time = 0, reading_a_percent_sign = 0;
X
X	for (i = 0; i < strlen(word); i++) {
X	  if (reading_a_percent_sign) {
X	    reading_a_percent_sign = 0;
X	    switch (word[i]) {
X
X	      case 'r' : buffer[j] = '\0';
X			 if (display)
X	 		   strcat(buffer, "<return-address>");
X			 else
X			   strcat(buffer, from);
X	                 j = strlen(buffer);
X			 break;
X
X	      case 's' : buffer[j] = '\0';
X			 if (display)
X	 		   strcat(buffer, "<subject>");
X			 else {
X			   strcat(buffer, "\"");
X			   strcat(buffer, subject);
X			   strcat(buffer, "\"");
X			 }
X	                 j = strlen(buffer);
X			 break;
X
X	      case 'S' : buffer[j] = '\0';
X			 if (display)
X	 		   strcat(buffer, "<Re: subject>");
X			 else {
X			   if (! the_same(subject, "Re:")) 
X			     strcat(buffer, "\"Re: ");
X			   strcat(buffer, subject);
X			   strcat(buffer, "\"");
X			 }
X	                 j = strlen(buffer);
X			 break;
X
X	      case 'd' : get_the_time(); buffer[j] = '\0';
X			 if (display)
X			   strcat(buffer, "<day-of-month>");
X			 else
X			   strcat(buffer, itoa(timerec->tm_mday,FALSE));
X	                 j = strlen(buffer);
X			 break;
X
X	      case 'D' : get_the_time(); buffer[j] = '\0';
X			 if (display)
X			   strcat(buffer, "<day-of-week>");
X			 else
X			   strcat(buffer, itoa(timerec->tm_wday,FALSE));
X	                 j = strlen(buffer);
X			 break;
X
X	      case 'm' : get_the_time(); buffer[j] = '\0';
X			 if (display)
X			   strcat(buffer, "<month>");
X			 else
X			   strcat(buffer, itoa(timerec->tm_mon+1,FALSE));
X	                 j = strlen(buffer);
X			 break;
X
X	      case 'y' : get_the_time(); buffer[j] = '\0';
X			 if (display)
X			   strcat(buffer, "<year>");
X			 else
X			   strcat(buffer, itoa(timerec->tm_year,FALSE));
X	                 j = strlen(buffer);
X			 break;
X
X	      case 'h' : get_the_time(); buffer[j] = '\0';
X			 if (display)
X			   strcat(buffer, "<hour>");
X			 else
X			   strcat(buffer, itoa(timerec->tm_hour,FALSE));
X	                 j = strlen(buffer);
X			 break;
X
X	      case 't' : get_the_time(); buffer[j] = '\0';
X			 if (display)
X			   strcat(buffer, "<time>");
X		         else {
X			   strcat(buffer, itoa(timerec->tm_hour,FALSE));
X			   strcat(buffer, ":");
X			   strcat(buffer, itoa(timerec->tm_min,TRUE));
X			 }
X	                 j = strlen(buffer);
X			 break;
X
X	      default  : if (outfd != NULL) fprintf(outfd,
X   "filter (%s): Error on line %d translating %%%c macro in word \"%s\"!\n",
X			         username, line, word[i], word);
X			 if (outfd != NULL) fclose(outfd);
X			 exit(1);
X	    }
X	  }
X	  else if (word[i] == '%') 
X	    reading_a_percent_sign++;
X	  else 
X	    buffer[j++] = (word[i] == '_' ? ' ' : word[i]);
X	}
X	buffer[j] = '\0';
X}
X
Xprint_rules()
X{
X	/** print the rules out.  A double check, of course! **/
X
X	register int i = -1;
X	char     *whatname(), *actionname();
X	struct   condition_rec *cond;
X
X	if (outfd == NULL) return;	/* why are we here, then? */
X
X	while (++i < total_rules) {
X	  if (rules[i].condition->matchwhat == ALWAYS) {
X	    fprintf(outfd, "\nRule %d:  ** always ** \n\t%s %s\n", i+1,
X		 actionname(rules[i].action), listrule(rules[i].argument2));
X	    continue;
X	  }
X
X	  fprintf(outfd, "\nRule %d:  if (", i+1);
X
X	  cond = rules[i].condition;
X
X	  while (cond != NULL) {
X	    if (cond->relation < 0)
X	      fprintf(outfd, "not %s %s %s%s%s", 
X		      whatname(cond->matchwhat),
X		      relationname(- (cond->relation)),
X		      quoteit(cond->matchwhat),
X		      cond->argument1,
X		      quoteit(cond->matchwhat));
X	    else
X	      fprintf(outfd, "%s %s %s%s%s",
X		      whatname(cond->matchwhat),
X		      relationname(cond->relation),
X		      quoteit(cond->matchwhat),
X		      cond->argument1,
X		      quoteit(cond->matchwhat));
X
X	    cond = cond->next;
X
X	    if (cond != NULL) fprintf(outfd, " and ");
X	  }
X	    
X	  fprintf(outfd, ") then\n\t  %s %s\n", 
X		 actionname(rules[i].action), 
X		 listrule(rules[i].argument2));
X	}
X	fprintf(outfd, "\n");
X}
X
Xchar *whatname(n)
Xint n;
X{
X	static char buffer[10];
X
X	switch(n) {
X	  case FROM   : return("from");
X	  case TO     : return("to");
X	  case SUBJECT: return("subject");
X	  case LINES  : return ("lines");
X	  case CONTAINS: return("contains");
X	  default     : sprintf(buffer, "?%d?", n); return((char *)buffer);
X	}
X}
X
Xchar *actionname(n)
Xint n;
X{
X	switch(n) {
X	  case DELETE  : return("Delete");
X	  case SAVE    : return("Save");
X	  case SAVECC  : return("Copy and Save");
X	  case FORWARD : return("Forward");
X	  case LEAVE   : return("Leave"); 
X	  case EXEC    : return("Execute");
X	  default      : return("?action?");
X	}
X}
X
Xint
Xcompare(line, relop, arg)
Xint line, relop;
Xchar *arg;
X{
X	/** Given the actual number of lines in the message, the relop
X	    relation, and the number of lines in the rule, as a string (!),
X   	    return TRUE or FALSE according to which is correct.
X	**/
X
X	int rule_lines;
X
X	rule_lines = atoi(arg);
X
X	switch (relop) {
X	  case LE: return(line <= rule_lines);
X	  case LT: return(line <  rule_lines);
X	  case GE: return(line >= rule_lines);
X	  case GT: return(line >  rule_lines);
X	  case NE: return(line != rule_lines);
X	  case EQ: return(line == rule_lines);
X	}
X	return(-1);
X}
X
Xchar *listrule(rule)
Xchar *rule;
X{
X	/** simply translates all underscores into spaces again on the
X	    way past... **/
X
X	static char buffer[SLEN];
X	register int i;
X
X	for (i=0; i < strlen(rule); i++)
X	  buffer[i] = (rule[i] == '_' ? ' ' : rule[i]);
X	buffer[i] = '\0';
X
X	return( (char *) buffer);
X}
SHAR_EOF
chmod 0444 filter/rules.c || echo "restore of filter/rules.c fails"
echo "x - extracting filter/summarize.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > filter/summarize.c &&
X
Xstatic char rcsid[] ="@(#)$Id: summarize.c,v 2.1 88/09/15 21:28:13 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.1 $   $State: Exp $
X *
X * 			Copyright (c) 1986 Dave Taylor
X *******************************************************************************
X * Bug reports, patches, comments, suggetions should be sent to:
X *
X *	Eric D. Christensen  -  edc@altnet.ALTOS.COM 
X *				uunet!altnet!edc
X *
X *******************************************************************************
X * $Log:	summarize.c,v $
X * Revision 2.1  88/09/15  21:28:13  syd
X * checked in with -k by syd at 88.09.15.21.28.13.
X * 
X * 88/08/27 gatech!cos.COM!To.eric (Paul A. Ebersman)
X *	fix error message
X *
X * Revision 2.1  88/07/21  09:55:48  edc
X * Final hacks and cleanup to the 2.1 alpha test release.
X * 
X * Revision 2.0  88/06/27  16:00:30  edc
X * This is the original 2.0 gamma source which leaked from HP
X * 
X *
X *
X ******************************************************************************/
X
X/** This routine is called from the filter program (or can be called
X    directly with the correct arguments) and summarizes the users filterlog
X    file.  To be honest, there are two sorts of summaries that are
X    available - either the '.filterlog' file can be output (filter -S) 
X    or a summary by rule and times acted upon can be output (filter -s).
X    Either way, this program will delete the two associated files each
X    time ($HOME/.filterlog and $HOME/.filtersum) *if* the -c option is
X    used to the program (e.g. clear_logs is set to TRUE).
X
X**/
X
X#include <stdio.h>
X
X#include "defs.h"
X
X#include "filter.h"
X
Xshow_summary()
X{
X	/* Summarize usage of the program... */
X
X	FILE   *fd;				/* for output to temp file! */
X	char filename[SLEN],			/* name of the temp file    */
X	     buffer[LONG_SLEN];			/* input buffer space       */
X	int  erroneous_rules = 0,
X	     default_rules   = 0,
X	     messages_filtered = 0,		/* how many have we touched? */
X	     rule,
X	     applied[MAXRULES];
X
X	sprintf(filename, "%s/%s", home, filtersum);
X
X	if ((fd = fopen(filename, "r")) == NULL) {
X	  if (outfd != NULL)
X	    fprintf(outfd,"filter (%s): Can't open filtersum file %s!\n",
X
X		    username, filename);
X	  if (outfd != NULL) fclose(outfd);
X	  exit(1);
X	}
X
X	for (rule=0;rule < MAXRULES; rule++)
X	  applied[rule] = 0;			/* initialize it all! */
X
X	/** Next we need to read it all in, incrementing by which rule
X	    was used.  The format is simple - each line represents a 
X	    single application of a rule, or '-1' if the default action
X	    was taken.  Simple stuff, eh?  But oftentimes the best.  
X	**/
X
X	while (fgets(buffer, LONG_SLEN, fd) != NULL) {
X	  if ((rule = atoi(buffer)) > total_rules || rule < -1) {
X	    if (outfd != NULL)
X	      fprintf(outfd,
X      "filter (%s): Warning - rule #%d is invalid data for short summary!!\n",
X	            username, rule);
X	    erroneous_rules++;
X	  }
X	  else if (rule == -1)
X	    default_rules++;
X	  else
X	    applied[rule]++;
X	  messages_filtered++;
X	}
X	
X	fclose(fd);
X
X	/** now let's summarize the data... **/
X
X	if (outfd == NULL) return;		/* no reason to go further */
SHAR_EOF
echo "End of part 6"
echo "File filter/summarize.c is continued in part 7"
echo "7" > s2_seq_.tmp
exit 0
-- 
=====================================================================
Sydney S. Weinstein, CDP, CCP                   Elm Coordinator
Datacomp Systems, Inc.				Voice: (215) 947-9900
{allegra,bellcore,bpa,vu-vlsi}!dsinc!syd	FAX:   (215) 938-0235