Path: utzoo!attcan!uunet!papaya.bbn.com!rsalz From: rsalz@bbn.com (Rich Salz) Newsgroups: comp.sources.unix Subject: v22i068: ELM mail syste, release 2.3, Part09/26 Message-ID: <2584@papaya.bbn.com> Date: 31 May 90 14:12:06 GMT Organization: BBN Systems and Technologies, Cambridge MA Lines: 1750 Approved: rsalz@uunet.UU.NET X-Checksum-Snefru: 6ea2f43a 59ab3060 4770da06 e5fc5cb9 Supercedes: <2580@papaya.bbn.com> Submitted-by: Syd Weinstein Posting-number: Volume 22, Issue 68 Archive-name: elm2.3/part09 #!/bin/sh # this is part 9 of a multipart archive # do not concatenate these parts, unpack them in order with /bin/sh # file filter/filter.c continued # CurArch=9 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 filter/filter.c" sed 's/^X//' << 'SHAR_EOF' >> filter/filter.c X#include "defs.h" X#ifdef I_TIME X# include X#endif X#ifdef I_SYSTIME X# include X#endif X#include 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 *optarg; X FILE *fd; /* for output to temp file! */ X struct passwd *passwd_entry; X#ifndef _POSIX_SOURCE X struct passwd *getpwuid(); /* for /etc/passwd */ X#endif 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#ifdef HOSTCOMPILED X strncpy(hostname, HOSTNAME, sizeof(hostname)); X#else X gethostname(hostname, sizeof(hostname)); X#endif X X /* now parse the starting arguments... */ X X while ((c = getopt(argc, argv, "clno:rSsv")) != EOF) { X switch (c) { X case 'c' : clear_logs = TRUE; break; X case 'l' : log_actions_only = TRUE; break; X case 'o' : strcpy(outfname, optarg); 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 case '?' : fprintf(stderr, X "Usage: | filter [-nrv]\n or: filter [-c] -[s|S]\n"); X exit(1); X } X } X X if (c < 0) { 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_MSG : if (verbose && outfd != NULL) X fprintf(outfd, "filter (%s): Message deleted\n", X username); X log(DELETE_MSG); 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 char *f = from; X X while (*buffer != ' ') X buffer++; /* get to word */ X X for (buffer++; *buffer != ' ' && *buffer; buffer++, f++) X *f = *buffer; /* copy it and */ X X *f = '\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
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 echo "File filter/filter.c is complete" 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 4.1 90/04/28 22:41:57 syd Exp $"; X X/******************************************************************************* X * The Elm Mail System - $Revision: 4.1 $ $State: Exp $ X * X * Copyright (c) 1986, 1987 Dave Taylor X * Copyright (c) 1988, 1989, 1990 USENET Community Trust X ******************************************************************************* X * Bug reports, patches, comments, suggestions should be sent to: X * X * Syd Weinstein - elm@DSI.COM X * dsinc!elm X * X ******************************************************************************* X * $Log: lock.c,v $ X * Revision 4.1 90/04/28 22:41:57 syd X * checkin of Elm 2.3 as of Release PL0 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 X#include X#include X#include "defs.h" X#include "filter.h" X Xstatic int we_locked_it; Xstatic char lockfile[SLEN]; X X#ifdef LOCK_BY_FLOCK X#include X#include Xstatic flock_fd = -1; Xstatic char flock_name[SLEN]; X#endif X Xextern int errno; 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#ifndef LOCK_FLOCK_ONLY /* { !LOCK_FLOCK_ONLY */ X sprintf(lockfile, "%s%s.lock", mailhome, username); X#ifdef PIDCHECK X /** first, try to read the lock file, and if possible, check the pid. X If we can validate that the pid is no longer active, then remove X the lock file. X **/ X if((ret=open(lockfile,O_RDONLY)) != -1) { X char pid_buffer[SHORT]; X if (read(ret, pid_buffer, SHORT) > 0) { X attempts = atoi(pid_buffer); X if (attempts) { X if (kill(attempts, 0)) { X close(ret); X if (unlink(lockfile) != 0) X return(1); X } X } X } X attempts = 0; X } X#endif X X while ((ret = open(lockfile, O_WRONLY | O_CREAT | O_EXCL, 0444)) < 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 ret = 1; X } else { X ret = 0; X } X X#endif /* } !LOCK_FLOCK_ONLY */ X#ifdef LOCK_BY_FLOCK /* { LOCK_BY_FLOCK */ X (void)sprintf(flock_name,"%s%s",mailhome,username); X flock_fd = open(flock_name,O_RDONLY); X if ( flock_fd >= 0 ) X for (attempts = 0; attempts < 10; attempts++) { X if ( (ret = flock(flock_fd,LOCK_NB|LOCK_EX)) != -1 ) X break; X if ( errno != EWOULDBLOCK && errno != EAGAIN ) X break; X (void)sleep((unsigned)3); X } X if ( flock_fd >= 0 && ret == 0 ) { X we_locked_it++; X ret = 1; X } else { X we_locked_it = 0; X if ( lockfile[0] ) { X (void)unlink(lockfile); X lockfile[0] = 0; X } X if ( flock_fd >= 0 ) { X (void)close(flock_fd); X flock_fd = -1; X } X ret = 0; X } X#endif X return(ret); 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#ifndef LOCK_FLOCK_ONLY X if (we_locked_it && lockfile[0]) { X unlink(lockfile); /* blamo! */ X lockfile[0] = 0; X } X#endif X#ifdef LOCK_BY_FLOCK X if (we_locked_it && flock_fd >= 0) { X (void)close(flock_fd); X flock_fd = -1; X } X#endif 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 4.1 90/04/28 22:41:58 syd Exp $"; X X/******************************************************************************* X * The Elm Mail System - $Revision: 4.1 $ $State: Exp $ X * X * Copyright (c) 1986, 1987 Dave Taylor X * Copyright (c) 1988, 1989, 1990 USENET Community Trust X ******************************************************************************* X * Bug reports, patches, comments, suggestions should be sent to: X * X * Syd Weinstein - elm@DSI.COM X * dsinc!elm X * X ******************************************************************************* X * $Log: parse.c,v $ X * Revision 4.1 90/04/28 22:41:58 syd X * checkin of Elm 2.3 as of Release PL0 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 X#include 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 buflen, /* the length of buffer */ 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] == '#' || (buflen = strlen(buffer)) < 2) X continue; /* nothing to look at! */ X X in_single = in_double = 0; X X for (i=0; i < buflen; 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=strlen(cond_argument); --i >= 0;) 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=strlen(word); --i>=0;) 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_MSG; 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_MSG || 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 4.1 90/04/28 22:42:00 syd Exp $"; X X/******************************************************************************* X * The Elm Mail System - $Revision: 4.1 $ $State: Exp $ X * X * Copyright (c) 1986, 1987 Dave Taylor X * Copyright (c) 1988, 1989, 1990 USENET Community Trust X ******************************************************************************* X * Bug reports, patches, comments, suggestions should be sent to: X * X * Syd Weinstein - elm@DSI.COM X * dsinc!elm X * X ******************************************************************************* X * $Log: rules.c,v $ X * Revision 4.1 90/04/28 22:42:00 syd X * checkin of Elm 2.3 as of Release PL0 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 X#include X#include X#include "defs.h" X#ifdef I_TIME X# include X#endif X#ifdef I_SYSTIME X# include X#endif X#include X 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 iindex = 0, not, relation, try_next_rule, x; X struct condition_rec *cond; X X while (iindex < total_rules) { X cond = rules[iindex].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 = iindex; X return(rules[rule_choosen].action); X } X iindex++; 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 "" etc. etc. in the output. X **/ X X#ifndef _POSIX_SOURCE X struct tm *localtime(); X long time(); X#endif X struct tm *timerec; X long thetime; X register int i, j=0, gotten_time = 0, reading_a_percent_sign = 0, len; X X for (i = 0, len = strlen(word); i < len; 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, ""); 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, ""); 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, ""); 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, ""); 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, ""); 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, ""); 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, ""); 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, ""); 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, "