rsalz@uunet.uu.net (Rich Salz) (05/26/90)
Submitted-by: Syd Weinstein <syd@dsinc.dsi.com> Posting-number: Volume 22, Issue 68 Archive-name: elm2.3/part09 ---- Cut Here and unpack ---- #!/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 <time.h> X#endif X#ifdef I_SYSTIME X# include <sys/time.h> X#endif X#include <fcntl.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 *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 <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 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 <stdio.h> X#include <fcntl.h> X#include <errno.h> 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 <sys/types.h> X#include <sys/file.h> 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 <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 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 startFrom syd@dsinc.dsi.com Sat Apr 28 23:37:13 1990 Received: from BBN.COM by pineapple.bbn.com id <AA11646@pineapple.bbn.com>; Sat, 28 Apr 90 23:36:26 -0400 Received: from dsinc.dsi.com by BBN.COM id aa11584; 28 Apr 90 23:34 EDT Received: by dsinc.dsi.com (/\=-/\ Smail3.1.18.1 #18.14) id <m0hP53M-0000K8C@dsinc.dsi.com>; Sat, 28 Apr 90 23:34 EDT Message-Id: <m0hP53M-0000K8C@dsinc.dsi.com> Date: Sat, 28 Apr 90 23:34 EDT From: Syd Weinstein <syd@dsinc.dsi.com> To: rsalz@BBN.COM Subject: Elm 2.3 PL 0 release for comp.sources.unix, Part 10/26 ---- Cut Here and unpack ---- #!/bin/sh # this is part 10 of a multipart archive # do not concatenate these parts, unpack them in order with /bin/sh # file hdrs/defs.h continued # CurArch=10 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 hdrs/defs.h" sed 's/^X//' << 'SHAR_EOF' >> hdrs/defs.h X/** a few for the usage of function keys... **/ X X#define f1 1 X#define f2 2 X#define f3 3 X#define f4 4 X#define f5 5 X#define f6 6 X#define f7 7 X#define f8 8 X X#define MAIN 0 X#define ALIAS 1 X#define YESNO 2 X#define CHANGE 3 X#define READ 4 X X#define MAIN_HELP 0 X#define OPTIONS_HELP 1 X#define ALIAS_HELP 2 X#define PAGER_HELP 3 X X/** types of folders **/ X#define NO_NAME 0 /* variable contains no file name */ X#define NON_SPOOL 1 /* mailfile not in mailhome */ X#define SPOOL 2 /* mailfile in mailhome */ X X/* the following is true if the current mailfile is the user's spool file*/ X#define USERS_SPOOL (strcmp(cur_folder, defaultfile) == 0) X X/** some possible sort styles... **/ X X#define REVERSE - /* for reverse sorting */ X#define SENT_DATE 1 /* the date message was sent */ X#define RECEIVED_DATE 2 /* the date message was received */ X#define SENDER 3 /* the name/address of sender */ X#define SIZE 4 /* the # of lines of the message */ X#define SUBJECT 5 /* the subject of the message */ X#define STATUS 6 /* the status (deleted, etc) */ X#define MAILBOX_ORDER 7 /* the order it is in the file */ X X/* some stuff for our own malloc call - pmalloc */ X X#define PMALLOC_THRESHOLD 256 /* if greater, then just use malloc */ X#define PMALLOC_BUFFER_SIZE 2048 /* internal [memory] buffer size... */ X X/** the following macro is as suggested by Larry McVoy. Thanks! **/ X X# ifdef DEBUG X# define dprint(n,x) { \ X if (debug >= n) { \ X fprintf x ; \ X fflush(debugfile); \ X } \ X } X# else X# define dprint(n,x) X# endif X X/* some random structs... */ X Xstruct date_rec { X int month; /** this record stores a **/ X int day; /** specific date and **/ X int year; /** time... **/ X int hour; X int minute; X }; X Xstruct header_rec { X int lines; /** # of lines in the message **/ X int status; /** Urgent, Deleted, Expired? **/ X int index_number; /** relative loc in file... **/ X int encrypted; /** whether msg has encryption **/ X int exit_disposition; /** whether to keep, store, delete **/ X int status_chgd; /** whether became read or old, etc. **/ X long offset; /** offset in bytes of message **/ X struct date_rec received; /** when elm received here **/ X char from[STRING]; /** who sent the message? **/ X char to[STRING]; /** who it was sent to **/ X char messageid[STRING]; /** the Message-ID: value **/ X char dayname[8]; /** when the **/ X char month[10]; /** message **/ X char day[3]; /** was **/ X char year[5]; /** sent **/ X char time[NLEN]; /** to you! **/ X char time_zone[12]; /** incl. tz */ X long time_sent; /** gmt when sent for sorting **/ X char subject[STRING]; /** The subject of the mail **/ X char mailx_status[WLEN];/** mailx status flags (RO...) **/ X }; X Xstruct alias_rec { X char name[NLEN]; /* alias name */ X long byte; /* offset into data file for address */ X }; X Xstruct lsys_rec { X char name[NLEN]; /* name of machine connected to */ X struct lsys_rec *next; /* linked list pointer to next */ X }; X Xstruct addr_rec { X char address[NLEN]; /* machine!user you get mail as */ X struct addr_rec *next; /* linked list pointer to next */ X }; X X#ifdef SHORTNAMES /* map long names to shorter ones */ X# include <shortname.h> X#endif X X/** Let's make sure that we're not going to have any annoying problems with X int pointer sizes versus char pointer sizes by guaranteeing that every- X thing vital is predefined... (Thanks go to Detlev Droege for this one) X**/ X X#ifdef STRINGS X# include <strings.h> X#else X# include <string.h> X#endif X X/* X * Macros for network/external number representation conversion. X */ X#ifdef NETWORK_ORDER Xunsigned short ntohs(), htons(); Xunsigned long ntohl(), htonl(); X#else X#define ntohl(x) (x) X#define ntohs(x) (x) X#define htonl(x) (x) X#define htons(x) (x) X#endif X Xchar *argv_zero(); Xchar *bounce_off_remote(); Xchar *ctime(); Xchar *error_description(); Xchar *error_name(); Xchar *error_number(); Xchar *expand_address(); Xchar *expand_domain(); Xchar *expand_group(); Xchar *expand_logname(); Xchar *expand_system(); Xchar *find_path_to(); Xchar *format_long(); Xchar *get_alias_address(); Xchar *get_arpa_date(); Xchar *get_ctime_date(); Xchar *get_date(); Xchar *get_token(); Xchar *getenv(); Xchar *getlogin(); Xchar *level_name(); Xchar *match_and_expand_domain(); Xchar *shift_lower(); Xchar *strip_commas(); Xchar *strip_parens(); Xchar *strpbrk(); Xchar *strtok(); Xchar *tail_of_string(); Xchar *tgetstr(); Xchar *pmalloc(); X Xlong lseek(); Xlong times(); Xlong ulimit(); SHAR_EOF echo "File hdrs/defs.h is complete" chmod 0444 hdrs/defs.h || echo "restore of hdrs/defs.h fails" echo "x - extracting hdrs/elm.h (Text)" sed 's/^X//' << 'SHAR_EOF' > hdrs/elm.h && X X/* $Id: elm.h,v 4.1 90/04/28 22:42:08 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 Coordinator X * elm@DSI.COM dsinc!elm X * X ******************************************************************************* X * $Log: elm.h,v $ X * Revision 4.1 90/04/28 22:42:08 syd X * checkin of Elm 2.3 as of Release PL0 X * X * X ******************************************************************************/ X X/** Main header file for ELM mail system. **/ X X X#include <stdio.h> X#include <fcntl.h> X#include <errno.h> X X#include "../hdrs/curses.h" X#include "../hdrs/defs.h" X X#ifdef BSD X#include <setjmp.h> X#endif X X/******** static character string containing the version number *******/ X Xstatic char ident[] = { WHAT_STRING }; X X/******** and another string for the copyright notice ********/ X Xstatic char copyright[] = { X "@(#) (C) Copyright 1986, 1987, Dave Taylor\n@(#) (C) Copyright 1988, 1989, 1990, The Usenet Community Trust\n" }; X X/******** global variables accessable by all pieces of the program *******/ X Xint check_size = 0; /* don't start mailer if no mail */ Xint current = 0; /* current message number */ Xint header_page = 0; /* current header page */ Xint last_header_page = -1; /* last header page */ Xint message_count = 0; /* max message number */ Xint headers_per_page; /* number of headers/page */ Xint original_umask = 0; /* original umask, for restore before subshell */ Xint sendmail_verbose = 0; /* Extended mail debugging */ Xchar cur_folder[SLEN]; /* name of current folder */ Xchar cur_tempfolder[SLEN]; /* name of temp folder open for a mailbox */ Xchar defaultfile[SLEN]; /* name of default folder */ Xchar temp_dir[SLEN] = {0}; /* name of temp directory */ Xchar hostname[SLEN]; /* name of machine we're on*/ Xchar hostdomain[SLEN]; /* name of domain we're in */ Xchar hostfullname[SLEN]; /* name of FQDN we're in */ Xchar username[SLEN]; /* return address name! */ Xchar full_username[SLEN]; /* Full username - gecos */ Xchar home[SLEN]; /* home directory of user */ Xchar folders[SLEN]; /* folder home directory */ Xchar raw_folders[SLEN]; /* unexpanded folder home directory */ Xchar recvd_mail[SLEN]; /* folder for storing received mail */ Xchar raw_recvdmail[SLEN]; /* unexpanded recvd_mail name */ Xchar editor[SLEN]; /* editor for outgoing mail*/ Xchar raw_editor[SLEN]; /* unexpanded editor for outgoing mail*/ Xchar alternative_editor[SLEN]; /* alternative editor... */ Xchar printout[SLEN]; /* how to print messages */ Xchar raw_printout[SLEN]; /* unexpanded how to print messages */ Xchar sent_mail[SLEN]; /* name of file to save copies to */ Xchar raw_sentmail[SLEN]; /* unexpanded name of file to save to */ Xchar calendar_file[SLEN]; /* name of file for clndr */ Xchar raw_calendar_file[SLEN]; /* unexpanded name of file for clndr */ Xchar attribution[SLEN]; /* attribution string for replies */ Xchar prefixchars[SLEN] = "> "; /* prefix char(s) for msgs */ Xchar shell[SLEN]; /* current system shell */ Xchar raw_shell[SLEN]; /* unexpanded current system shell */ Xchar pager[SLEN]; /* what pager to use */ Xchar raw_pager[SLEN]; /* unexpanded what pager to use */ Xchar batch_subject[SLEN]; /* subject buffer for batchmail */ Xchar local_signature[SLEN]; /* local msg signature file */ Xchar raw_local_signature[SLEN]; /* unexpanded local msg signature file */ Xchar remote_signature[SLEN]; /* remote msg signature file */ Xchar raw_remote_signature[SLEN];/* unexpanded remote msg signature file */ Xchar version_buff[SLEN]; /* version buffer */ X Xchar backspace, /* the current backspace char */ X escape_char = TILDE_ESCAPE,/* '~' or something else.. */ X kill_line; /* the current kill-line char */ X Xchar up[SHORT], down[SHORT], /* cursor control seq's */ X left[SHORT], right[SHORT]; Xint cursor_control = FALSE; /* cursor control avail? */ X Xchar start_highlight[SHORT], X end_highlight[SHORT]; /* stand out mode... */ X Xint has_highlighting = FALSE; /* highlighting available? */ X Xchar *weedlist[MAX_IN_WEEDLIST]; Xint weedcount; X Xint allow_forms = NO; /* flag: are AT&T Mail forms okay? */ Xint mini_menu = 1; /* flag: menu specified? */ Xint prompt_after_pager = 1; /* flag: prompt after pager exits */ Xint folder_type = 0; /* flag: type of folder */ Xint auto_copy = 0; /* flag: automatically copy source? */ Xint filter = 1; /* flag: weed out header lines? */ Xint resolve_mode = 1; /* flag: delete saved mail? */ Xint auto_cc = 0; /* flag: mail copy to user? */ Xint noheader = 1; /* flag: copy + header to file? */ Xint title_messages = 1; /* flag: title message display? */ Xint forwarding = 0; /* flag: are we forwarding the msg? */ Xint hp_terminal = 0; /* flag: are we on HP term? */ Xint hp_softkeys = 0; /* flag: are there softkeys? */ Xint save_by_name = 1; /* flag: save mail by login name? */ Xint force_name = 0; /* flag: save by name forced? */ Xint mail_only = 0; /* flag: send mail then leave? */ Xint check_only = 0; /* flag: check aliases then leave? */ Xint batch_only = 0; /* flag: send without prompting? */ Xint move_when_paged = 0; /* flag: move when '+' or '-' used? */ Xint point_to_new = 1; /* flag: start pointing at new msg? */ Xint bounceback = 0; /* flag: bounce copy off remote? */ Xint always_keep = 1; /* flag: always keep unread msgs? */ Xint always_store = 0; /* flag: always store read msgs? */ Xint always_del = 0; /* flag: always delete marked msgs? */ Xint arrow_cursor = 0; /* flag: use "->" cursor regardless?*/ Xint debug = 0; /* flag: default is no debug! */ Xint warnings = 1; /* flag: output connection warnings?*/ Xint user_level = 0; /* flag: how good is the user? */ Xint selected = 0; /* flag: used for select stuff */ Xint names_only = 1; /* flag: display user names only? */ Xint question_me = 1; /* flag: ask questions as we leave? */ Xint keep_empty_files = 0; /* flag: leave empty folder files? */ Xint clear_pages = 0; /* flag: act like "page" (more -c)? */ Xint prompt_for_cc = 1; /* flag: ask user for "cc:" value? */ Xint sig_dashes = 1; /* flag: include dashes above sigs? */ X Xint sortby = REVERSE SENT_DATE; /* how to sort incoming mail... */ X Xlong timeout = 600L; /* timeout (secs) on main prompt */ X X/** set up some default values for a 'typical' terminal *snicker* **/ X Xint LINES=23; /** lines per screen **/ Xint COLUMNS=80; /** columns per page **/ X Xlong size_of_pathfd; /** size of pathfile, 0 if none **/ X XFILE *mailfile; /* current folder */ XFILE *debugfile; /* file for debug output */ XFILE *pathfd; /* path alias file */ XFILE *domainfd; /* domain file */ X Xlong mailfile_size; /* size of current mailfile */ X Xint max_headers; /* number of headers allocated */ X Xstruct header_rec **headers; /* array of header structure pointers */ X Xstruct alias_rec user_hash_table[MAX_UALIASES]; Xstruct alias_rec system_hash_table[MAX_SALIASES]; X Xstruct lsys_rec *talk_to_sys = NULL; /* what machines do we talk to? */ X Xstruct addr_rec *alternative_addresses; /* how else do we get mail? */ X Xint system_data = -1; /* fileno of system data file */ Xint user_data = -1; /* fileno of user data file */ X Xint userid; /* uid for current user */ Xint groupid; /* groupid for current user */ X X#ifdef BSD Xjmp_buf GetPromptBuf; /* setjmp buffer */ Xint InGetPrompt; /* set if in GetPrompt() in read() */ X#endif SHAR_EOF chmod 0444 hdrs/elm.h || echo "restore of hdrs/elm.h fails" echo "x - extracting hdrs/filter.h (Text)" sed 's/^X//' << 'SHAR_EOF' > hdrs/filter.h && X X/* $Id: filter.h,v 4.1 90/04/28 22:42:09 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 Coordinator X * elm@DSI.COM dsinc!elm X * X ******************************************************************************* X * $Log: filter.h,v $ X * Revision 4.1 90/04/28 22:42:09 syd X * checkin of Elm 2.3 as of Release PL0 X * X * X ******************************************************************************/ X X/** Headers for the filter program. X X**/ X X#ifdef BSD X# undef tolower X#endif X X/** define a few handy macros for later use... **/ X X#define the_same(a,b) (strncmp(a,b,strlen(b)) == 0) X X#define relationname(x) (x == 1?"<=":x==2?"<":x==3?">=":x==4?">":x==5?"!=":"=") X X#define quoteit(x) (x == LINES? "" : "\"") X X#define remove_return(s) { if (s[strlen(s)-1] == '\n') \ X s[strlen(s)-1] = '\0'; \ X } X X/** some of the files we'll be using, where they are, and so on... **/ X X#define filter_temp "/tmp/filter" X#define filterfile ".elm/filter-rules" X#define filterlog ".elm/filterlog" X#define filtersum ".elm/filtersum" X X#define EMERGENCY_MAILBOX "EMERGENCY_MBOX" X#define EMERG_MBOX "MBOX.EMERGENCY" X X/** and now the hardwired constraint of the program.. **/ X X#define MAXRULES 25 /* can't have more den dis, boss! */ X X/** some random defines for mnemonic stuff in the program... **/ X X#ifdef SUBJECT X# undef SUBJECT X#endif X X#define TO 1 X#define FROM 2 X#define LINES 3 X#define SUBJECT 4 X#define CONTAINS 5 X#define ALWAYS 6 X X#define DELETE_MSG 7 X#define SAVE 8 X#define SAVECC 9 X#define FORWARD 10 X#define LEAVE 11 X#define EXEC 12 X X#define FAILED_SAVE 20 X X/** Some conditionals... **/ X X#define LE 1 X#define LT 2 X#define GE 3 X#define GT 4 X#define NE 5 X#define EQ 6 X X/** A funky way to open a file using open() to avoid file locking hassles **/ X X#define FOLDERMODE O_WRONLY | O_APPEND | O_CREAT | O_SYNCIO X X/** cheap but easy way to have two files share the same #include file **/ X X#ifdef MAIN_ROUTINE X Xchar home[SLEN], /* the users home directory */ X hostname[SLEN], /* the machine name... */ X username[SLEN]; /* the users login name... */ X Xchar to[VERY_LONG_STRING], X from[LONG_STRING], X subject[LONG_STRING]; /* from current message */ X XFILE *outfd; Xchar outfname[SLEN]; X Xint total_rules = 0, /* how many rules to check */ X show_only = FALSE, /* just for show? */ X long_summary = FALSE, /* what sorta summary?? */ X verbose = FALSE, /* spit out lots of stuff */ X lines = 0, /* lines in message.. */ X clear_logs = FALSE, /* clear files after sum? */ X already_been_forwarded = FALSE, /* has this been filtered? */ X log_actions_only = FALSE, /* log actions | everything */ X printing_rules = FALSE, /* are we just using '-r'? */ X rule_choosen; /* which one we choose */ X X#else X Xextern char home[SLEN], /* the users home directory */ X hostname[SLEN], /* the machine name... */ X username[SLEN]; /* the users login name... */ X Xextern char to[VERY_LONG_STRING], X from[LONG_STRING], X subject[LONG_STRING]; /* from current message */ X Xextern FILE *outfd; Xextern char outfname[SLEN]; X Xextern int total_rules, /* how many rules to check */ X show_only, /* just for show? */ X long_summary, /* what sorta summary?? */ X verbose, /* spit out lots of stuff */ X lines, /* lines in message.. */ X clear_logs, /* clear files after sum? */ X already_been_forwarded, /* has this been filtered? */ X log_actions_only, /* log actions | everything */ X printing_rules, /* are we just using '-r'? */ X rule_choosen; /* which one we choose */ X#endif X X/** and our ruleset record structure... **/ X Xstruct condition_rec { X int matchwhat; /* type of 'if' clause */ X int relation; /* type of match (eq, etc) */ X char argument1[SLEN]; /* match against this */ X struct condition_rec *next; /* next condition... */ X }; X Xstruct ruleset_record { X char printable[SLEN]; /* straight from file... */ X struct condition_rec *condition; X int action; /* what action to take */ X char argument2[SLEN]; /* argument for action */ X }; X X#ifdef MAIN_ROUTINE X struct ruleset_record rules[MAXRULES]; X#else X extern struct ruleset_record rules[MAXRULES]; X#endif X X/** finally let's keep LINT happy with the return values of all these pups! ***/ X Xchar *itoa(); X X#ifdef _POSIX_SOURCE /*{_POSIX_SOURCE*/ X#include <string.h> X#include <unistd.h> X#include <stdlib.h> X#else /*}_POSIX_SOURCE{*/ Xunsigned short getuid(); X Xunsigned long sleep(); X Xchar *malloc(), *strcpy(), *strcat(); X Xvoid exit(); X X#ifdef BSD X X FILE *popen(); X X#ifdef MAIN_ROUTINE X char _vbuf[5*BUFSIZ]; /* space for file buffering */ X#else X extern char _vbuf[5*BUFSIZ]; /* space for file buffering */ X#endif X X#ifndef _IOFBF X# define _IOFBF 0 /* doesn't matter - ignored */ X#endif X X# define setvbuf(fd,a,b,c) setbuffer(fd, _vbuf, 5*BUFSIZ) X X#endif X#endif /*}_POSIX_SOURCE*/ SHAR_EOF chmod 0444 hdrs/filter.h || echo "restore of hdrs/filter.h fails" echo "x - extracting hdrs/headers.h (Text)" sed 's/^X//' << 'SHAR_EOF' > hdrs/headers.h && X X/* $Id: headers.h,v 4.1 90/04/28 22:42:11 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 Coordinator X * elm@DSI.COM dsinc!elm X * X ******************************************************************************* X * $Log: headers.h,v $ X * Revision 4.1 90/04/28 22:42:11 syd X * checkin of Elm 2.3 as of Release PL0 X * X * X ******************************************************************************/ X X/** This is the header file for ELM mail system. **/ X X X#include <stdio.h> X#include <fcntl.h> X X#include "curses.h" X#include "defs.h" X X#ifdef BSD X#include <setjmp.h> X#endif X X#ifndef clearerr X#define clearerr(p) (void)((p)->_flag &= ~(_IOERR|_IOEOF)) X#endif X X/******** global variables accessable by all pieces of the program *******/ X Xextern int check_size; /* don't start mailer if no mail */ Xextern int current; /* current message number */ Xextern int header_page; /* current header page */ Xextern int last_header_page; /* last header page */ Xextern int message_count; /* max message number */ Xextern int headers_per_page; /* number of headers/page */ Xextern int original_umask; /* original umask, for restore before subshell */ Xextern int sendmail_verbose; /* Allow extended debugging on sendmail */ Xextern char cur_folder[SLEN]; /* name of current folder */ Xextern char cur_tempfolder[SLEN]; /* name of temp folder open for a mailbox */ Xextern char defaultfile[SLEN]; /* name of default folder */ Xextern char temp_dir[SLEN]; /* name of temp directory */ Xextern char hostname[SLEN]; /* name of machine we're on*/ Xextern char hostdomain[SLEN]; /* name of domain we're in */ Xextern char hostfullname[SLEN]; /* name of FQDN we're in */ Xextern char username[SLEN]; /* return address name! */ Xextern char full_username[SLEN];/* Full username - gecos */ Xextern char home[SLEN]; /* home directory of user */ Xextern char folders[SLEN]; /* folder home directory */ Xextern char raw_folders[SLEN]; /* unexpanded folder home directory */ Xextern char recvd_mail[SLEN]; /* folder for storing received mail */ Xextern char raw_recvdmail[SLEN];/* unexpanded recvd_mail name */ Xextern char editor[SLEN]; /* default editor for mail */ Xextern char raw_editor[SLEN]; /* unexpanded default editor for mail */ Xextern char alternative_editor[SLEN];/* the 'other' editor */ Xextern char printout[SLEN]; /* how to print messages */ Xextern char raw_printout[SLEN]; /* unexpanded how to print messages */ Xextern char sent_mail[SLEN]; /* name of file to save copies to */ Xextern char raw_sentmail[SLEN]; /* unexpanded name of file to save to */ Xextern char calendar_file[SLEN];/* name of file for clndr */ Xextern char raw_calendar_file[SLEN];/* unexpanded name of file for clndr */ Xextern char attribution[SLEN]; /* attribution string for replies */ Xextern char prefixchars[SLEN]; /* prefix char(s) for msgs */ Xextern char shell[SLEN]; /* default system shell */ Xextern char raw_shell[SLEN]; /* unexpanded default system shell */ Xextern char pager[SLEN]; /* what pager to use... */ Xextern char raw_pager[SLEN]; /* unexpanded what pager to use... */ Xextern char batch_subject[SLEN];/* subject buffer for batchmail */ Xextern char local_signature[SLEN];/* local msg signature file */ Xextern char raw_local_signature[SLEN];/* unexpanded local msg signature file */ Xextern char remote_signature[SLEN];/* remote msg signature file */ Xextern char raw_remote_signature[SLEN];/* unexpanded remote msg signature file*/ X Xextern char backspace, /* the current backspace char */ X escape_char, /* '~' or something else... */ X kill_line; /* the current kill_line char */ X Xextern char up[SHORT], X down[SHORT], X left[SHORT], X right[SHORT]; /* cursor control seq's */ Xextern int cursor_control; /* cursor control avail? */ X Xextern char start_highlight[SHORT], X end_highlight[SHORT]; /* standout mode... */ X Xextern int has_highlighting; /* highlighting available? */ X X/** the following two are for arbitrary weedout lists.. **/ X Xextern char *weedlist[MAX_IN_WEEDLIST]; Xextern int weedcount; /* how many headers to check? */ X Xextern int allow_forms; /* flag: are AT&T Mail forms okay? */ Xextern int prompt_after_pager; /* flag: prompt after pager exits */ Xextern int mini_menu; /* flag: display menu? */ Xextern int folder_type; /* flag: type of folder */ Xextern int auto_copy; /* flag: auto copy source into reply? */ Xextern int filter; /* flag: weed out header lines? */ Xextern int resolve_mode; /* flag: resolve before moving mode? */ Xextern int auto_cc; /* flag: mail copy to yourself? */ Xextern int noheader; /* flag: copy + header to file? */ Xextern int title_messages; /* flag: title message display? */ Xextern int forwarding; /* flag: are we forwarding the msg? */ Xextern int hp_terminal; /* flag: are we on an hp terminal? */ Xextern int hp_softkeys; /* flag: are there softkeys? */ Xextern int save_by_name; /* flag: save mail by login name? */ Xextern int force_name; /* flag: save by name forced? */ Xextern int mail_only; /* flag: send mail then leave? */ Xextern int check_only; /* flag: check aliases and leave? */ Xextern int batch_only; /* flag: send without prompting? */ Xextern int move_when_paged; /* flag: move when '+' or '-' used? */ Xextern int point_to_new; /* flag: start pointing at new msgs? */ Xextern int bounceback; /* flag: bounce copy off remote? */ Xextern int always_keep; /* flag: always keep unread msgs? */ Xextern int always_store; /* flag: always store read mail? */ Xextern int always_del; /* flag: always delete marked msgs? */ Xextern int arrow_cursor; /* flag: use "->" regardless? */ Xextern int debug; /* flag: debugging mode on? */ Xextern int warnings; /* flag: output connection warnings? */ Xextern int user_level; /* flag: how knowledgable is user? */ Xextern int selected; /* flag: used for select stuff */ Xextern int names_only; /* flag: display names but no addrs? */ Xextern int question_me; /* flag: ask questions as we leave? */ Xextern int keep_empty_files; /* flag: keep empty files?? */ Xextern int clear_pages; /* flag: clear screen w/ builtin pgr? */ Xextern int prompt_for_cc; /* flag: prompt user for 'cc' value? */ Xextern int sig_dashes; /* flag: put dashes above signature? */ X Xextern int sortby; /* how to sort folders */ X Xextern long timeout; /* seconds for main level timeout */ X Xextern int LINES; /** lines per screen **/ Xextern int COLUMNS; /** columns per line **/ X Xextern long size_of_pathfd; /** size of pathfile, 0 if none **/ X Xextern FILE *mailfile; /* current folder */ Xextern FILE *debugfile; /* file for debut output */ Xextern FILE *pathfd; /* path alias file */ Xextern FILE *domainfd; /* domains file */ X Xextern long mailfile_size; /* size of current mailfile */ X Xextern int max_headers; /* number of headers currently allocated */ X Xextern struct header_rec **headers; /* array of header structure pointers */ X Xextern struct alias_rec user_hash_table [MAX_UALIASES]; Xextern struct alias_rec system_hash_table[MAX_SALIASES]; X Xextern struct lsys_rec *talk_to_sys; /* who do we talk to? */ X Xextern struct addr_rec *alternative_addresses; /* how else do we get mail? */ X Xextern int system_data; /* fileno of system data file */ Xextern int user_data; /* fileno of user data file */ X Xextern int userid; /* uid for current user */ Xextern int groupid; /* groupid for current user */ X X#ifdef BSD Xextern jmp_buf GetPromptBuf; /* setjmp buffer */ Xextern int InGetPrompt; /* set if in GetPrompt() in read() */ X#endif SHAR_EOF chmod 0444 hdrs/headers.h || echo "restore of hdrs/headers.h fails" echo "x - extracting hdrs/patchlevel.h (Text)" sed 's/^X//' << 'SHAR_EOF' > hdrs/patchlevel.h && X#define PATCHLEVEL 0 SHAR_EOF chmod 0666 hdrs/patchlevel.h || echo "restore of hdrs/patchlevel.h fails" echo "x - extracting hdrs/save_opts.h (Text)" sed 's/^X//' << 'SHAR_EOF' > hdrs/save_opts.h && X X/* @(#)$Id: save_opts.h,v 4.1 90/04/28 22:42:12 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 Coordinator X * elm@DSI.COM dsinc!elm X * X ******************************************************************************* X * $Log: save_opts.h,v $ X * Revision 4.1 90/04/28 22:42:12 syd X * checkin of Elm 2.3 as of Release PL0 X * X * X ******************************************************************************/ X X/** Some crazy includes for the save-opts part of the Elm program! X X**/ X X#define ALTERNATIVES 0 X#define ALWAYSDELETE 1 X#define ALWAYSKEEP 2 X#define ALWAYSSTORE 3 X#define ARROW 4 X#define ASK 5 X#define ASKCC 6 X#define ATTRIBUTION 7 X#define AUTOCOPY 8 X#define BOUNCEBACK 9 X#define CALENDAR 10 X#define COPY 11 X#define EDITOR 12 X#define ESCAPECHAR 13 X#define FORCENAME 14 X#define FORMS 15 X#define FULLNAME 16 X#define KEEPEMPTY 17 X#define KEYPAD 18 X#define LOCALSIGNATURE 19 X#define MAILDIR 20 X#define MENU 21 X#define MOVEPAGE 22 X#define NAMES 23 X#define NOHEADER 24 X#define PAGER 25 X#define POINTNEW 26 X#define PREFIX 27 X#define PRINT 28 X#define PROMPTAFTER 29 X#define RECEIVEDMAIL 30 X#define REMOTESIGNATURE 31 X#define RESOLVE 32 X#define SAVENAME 33 X#define SENTMAIL 34 X#define SHELL 35 X#define SIGDASHES 36 X#define SIGNATURE 37 X#define SOFTKEYS 38 X#define SORTBY 39 X#define TIMEOUT 40 X#define TITLES 41 X#define TMPDIR 42 X#define USERLEVEL 43 X#define WARNINGS 44 X#define WEED 45 X#define WEEDOUT 46 X X#define NUMBER_OF_SAVEABLE_OPTIONS WEEDOUT+1 X Xstruct save_info_recs { X char name[NLEN]; /* name of instruction */ X long offset; /* offset into elmrc-info file */ X } save_info[NUMBER_OF_SAVEABLE_OPTIONS] = X{ X { "alternatives", -1L }, X { "alwaysdelete", -1L }, X { "alwayskeep", -1L }, X { "alwaysstore", -1L }, X { "arrow", -1L}, X { "ask", -1L }, X { "askcc", -1L }, X { "attribution", -1L }, X { "autocopy", -1L }, X { "bounceback", -1L }, X { "calendar", -1L }, X { "copy", -1L }, X { "editor", -1L }, X { "escape", -1L }, X { "forcename", -1L }, X { "forms", -1L }, X { "fullname", -1L }, X { "keepempty", -1L }, X { "keypad", -1L }, X { "localsignature", -1L }, X { "maildir", -1L }, X { "menu", -1L }, X { "movepage", -1L }, X { "names", -1L }, X { "noheader", -1L }, X { "pager", -1L }, X { "pointnew", -1L}, X { "prefix", -1L }, X { "print", -1L }, X { "promptafter", -1L }, X { "receivedmail", -1L }, X { "remotesignature",-1L}, X { "resolve", -1L }, X { "savename", -1L }, X { "sentmail", -1L }, X { "shell", -1L }, X { "sigdashes", -1L }, X { "signature", -1L }, X { "softkeys", -1L }, X { "sortby", -1L }, X { "timeout", -1L }, X { "titles", -1L }, X { "tmpdir", -1L }, X { "userlevel", -1L }, X { "warnings", -1L }, X { "weed", -1L }, X { "weedout", -1L }, X}; SHAR_EOF chmod 0444 hdrs/save_opts.h || echo "restore of hdrs/save_opts.h fails" echo "x - extracting hdrs/sysdefs.SH (Text)" sed 's/^X//' << 'SHAR_EOF' > hdrs/sysdefs.SH && Xcase $CONFIG in X'') X if test ! -f config.sh; then X ln ../config.sh . || \ X ln ../../config.sh . || \ X ln ../../../config.sh . || \ X (echo "Can't find config.sh."; exit 1) X echo "Using config.sh from above..." X fi X . ./config.sh X ;; Xesac Xecho "Extracting hdrs/sysdefs.h (with variable substitutions)" Xsed <<!GROK!THIS! >sysdefs.h -e 's!^#undef!/\*#undef!' X/* $Id: sysdefs.SH,v 4.1 90/04/28 22:42:14 syd Exp $ */ 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 Coordinator X * elm@DSI.COM dsinc!elm X * X ******************************************************************************* X * $Log: sysdefs.SH,v $ X * Revision 4.1 90/04/28 22:42:14 syd X * checkin of Elm 2.3 as of Release PL0 X * X * X ******************************************************************************/ X X/** System level, configurable, defines for the ELM mail system. **/ X X X#define FIND_DELTA 10 /* byte region where the binary search X on the path alias file is fruitless X (can't be within this boundary) */ X X#define MAX_IN_WEEDLIST 150 /* max headers to weed out */ X X#define MAX_HOPS 35 /* max hops in return addr to E)veryone */ X X#define DEFAULT_BATCH_SUBJECT "$defbatsub" X X#define DEFAULT_DOMAIN "$mydomain" /* if mydomain file is missing */ X X/** If you want to implement 'site hiding' in the mail, then you'll need to X uncomment the following lines and set them to reasonable values. See X the configuration guide for more details....(actually these are undoc- X umented because they're fairly dangerous to use. Just ignore 'em and X perhaps one day you'll find out what they do, ok?) X**/ X X/**************************************************************************** X X#define SITE_HIDING X#define HIDDEN_SITE_NAME "fake-machine-name" X#define HIDDEN_SITE_USERS "/usr/mail/lists/hidden_site_users" X X****************************************************************************/ X X#define system_text_file "$lib/aliases.text" X#define system_hash_file "$lib/aliases.hash" X#define system_data_file "$lib/aliases.data" X X#define ALIAS_TEXT ".elm/aliases.text" X#define ALIAS_HASH ".elm/aliases.hash" X#define ALIAS_DATA ".elm/aliases.data" X X#define pathfile "$pathalias" X#define domains "$domains" X#define hostdomfile "$lib/domain" X X/** where to put the output of the elm -d command... (in home dir) **/ X#define DEBUGFILE "ELM:debug.info" X#define OLDEBUG "ELM:debug.last" X X#define default_temp "$tmpdir/" X#define temp_file "snd." X#define temp_form_file "form." X#define temp_mbox "mbox." X#define temp_print "print." X#define temp_edit "elm-edit" X#define temp_uuname "uuname." X#define readmsg_file ".elm/readmsg" X X#define emacs_editor "$emacs" X X#define default_editor "$defeditor" X#define mailhome "$maildir/" X X#define default_shell "$prefshell" X#define default_pager "$pager" X#define default_printout "$cat %s | $linepr" X X#define sendmail "$sendmail" X#define smflags "-oi -oem" /* ignore dots and mail back errors */ X#define smflagsv "-oi -oem -v" /* Verbose voyuer mode */ X#define mailer "$mailer" X X#define mailx "$mailx" X X#define helphome "$lib" X#define helpfile "elm-help" X X#define ELMRC_INFO "$lib/elmrc-info" X X#define elmrcfile ".elm/elmrc" X#define old_elmrcfile ".elm/elmrc.old" X#define mailheaders ".elm/elmheaders" X#define dead_letter "Cancelled.mail" X X#define unedited_mail "emergency.mbox" X X#define newalias "newalias 1>&2 > /dev/null" X#define readmsg "readmsg" X X#define remove_cmd "$rm -f" /* how to remove a file */ X#define cat "$cat" /* how to display files */ X#define sed_cmd "$sed" /* how to access sed */ X#define move_cmd "$mv" /* how to access sed */ X#define uuname "$uuname" /* how to get a uuname */ X X#define MSG_SEPERATOR "\001\001\001\001\n" /* mmdf message seperator */ X!GROK!THIS! SHAR_EOF chmod 0444 hdrs/sysdefs.SH || echo "restore of hdrs/sysdefs.SH fails" echo "x - extracting src/Makefile.SH (Text)" sed 's/^X//' << 'SHAR_EOF' > src/Makefile.SH && Xcase $CONFIG in X'') X if test ! -f config.sh; then X ln ../config.sh . || \ X ln ../../config.sh . || \ X ln ../../../config.sh . || \ X (echo "Can't find config.sh."; exit 1) X fi X . ./config.sh X ;; Xesac Xcase "$0" in X*/*) cd `expr X$0 : 'X\(.*\)/'` ;; Xesac X Xecho "Extracting src/Makefile (with variable substitutions)" Xcat >Makefile <<!GROK!THIS! X# $Id: Makefile.SH,v 4.1 90/04/28 22:42:16 syd Exp $ X# X# Makefile for the ELM mail program. 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# $Log: Makefile.SH,v $ X# Revision 4.1 90/04/28 22:42:16 syd X# checkin of Elm 2.3 as of Release PL0 X# X# X# Variables X# Variables established by Configure XCC = $cc XCCFLAGS = $ccflags $xencf XCHGRP = $chgrp XCHMOD = $chmod XCP = $cp XDEST = $bin XECHO = $echo XLFLAGS = $ldflags $xenlf XLIB = $lib XLIB2 = $libs XLIBS = $cryptlib $termlib $dbm XLINT = $lint XMAILGRP = $mailgrp XMAILERMODE = $mailermode XMV = $mv XOPTIMIZE = $optimize XRM = $rm -f XTOUCH = $touch X X!GROK!THIS! X Xcat >>Makefile <<'!NO!SUBS!' X X# Variables you may want to manually edit X# If you want debug logging then you'll X# want to uncomment the following. X#DEBUG = -DDEBUG X X# If you're on an ACSnet system (Australia) then X# you'll want to uncomment the following. X# DACSNET = -DACSNET X X# Other general variables XBIN = ../bin XCFLAGS = $(CCFLAGS) $(OPTIMIZE) -I$(INCLDIR) $(DEBUG) $(DACSNET) XINCLDIR = ../hdrs XLINTFLAGS = -I$(INCLDIR) XSHELL = /bin/sh X X# Lists XELM_SRC = addr_util.c \ X alias.c \ X aliasdb.c \ X aliaslib.c \ X args.c \ X bouncebk.c \ X builtin.c \ X calendar.c \ X conn_to.c \ X curses.c \ X date.c \ X delete.c \ X domains.c \ X edit.c \ X editmsg.c \ X elm.c \ X encode.c \ X errno.c \ X exitprog.c \ X expires.c \ X file.c \ X file_util.c \ X fileio.c \ X forms.c \ X hdrconfg.c \ X help.c \ X init.c \ X in_utils.c \ X leavembox.c \ X limit.c \ X mailmsg1.c \ X mailmsg2.c \ X mailtime.c \ X mkhdrs.c \ X newmbox.c \ X opt_utils.c \ X options.c \ X out_utils.c \ X pattern.c \ X pmalloc.c \ X quit.c \ X read_rc.c \ X remail.c \ X reply.c \ X returnadd.c \ X save_opts.c \ X savecopy.c \ X screen.c \ X showmsg.c \ X showmsg_c.c \ X signals.c \ X softkeys.c \ X sort.c \ X string2.c \ X strings.c \ X syscall.c \ X utils.c \ X validname.c X XELM_OBJ = addr_util.o \ X alias.o \ X aliasdb.o \ X aliaslib.o \ X args.o \ X bouncebk.o \ X builtin.o \ X calendar.o \ X conn_to.o \ X curses.o \ X date.o \ X delete.o \ X domains.o \ X edit.o \ X editmsg.o \ X elm.o \ X encode.o \ X errno.o \ X exitprog.o \ X expires.o \ X file.o \ X file_util.o \ X fileio.o \ X forms.o \ X hdrconfg.o \ X help.o \ X init.o \ X in_utils.o \ X leavembox.o \ X limit.o \ X mailmsg1.o \ X mailmsg2.o \ X mailtime.o \ X mkhdrs.o \ X newmbox.o \ X opt_utils.o \ X options.o \ X out_utils.o \ X pattern.o \ X pmalloc.o \ X quit.o \ X read_rc.o \ X remail.o \ X reply.o \ X returnadd.o \ X save_opts.o \ X savecopy.o \ X screen.o \ X showmsg.o \ X showmsg_c.o \ X signals.o \ X softkeys.o \ X sort.o \ X string2.o \ X strings.o \ X syscall.o \ X utils.o \ X validname.o X X# Standard targets Xall: $(BIN)/elm X Xinstall: $(DEST)/elm X Xuninstall: X $(RM) $(DEST)/elm X X# This is the only target that gets installed even if not out-of-date X# with respect the files from which it is installed. Xrmt-install: rmt-defined X -$(MV) $(DEST)/elm $(DEST)/elm.old X -$(RM) $(DEST)/elm.old X $(CP) $(REMOTE)$(DEST)/elm $(DEST)/elm X $(CHGRP) $(MAILGRP) $(DEST)/elm X $(CHMOD) $(MAILERMODE) $(DEST)/elm X Xrmt-defined: X @(if [ "$(REMOTE)" = "" ];\ X then\ X $(ECHO) "You need to define 'REMOTE' as the remote file system";\ X $(ECHO) "for this particular command. The easiest way to do this";\ X $(ECHO) "to type:";\ X $(ECHO) " make REMOTE=<remote file system> rmt-install";\ X exit 1;\ X fi); X Xlint: X $(LINT) $(LINTFLAGS) $(ELM_SRC) > LINT.OUT X Xclean: X $(RM) $(ELM_OBJ) $(BIN)/elm X X# Dependencies and rules X# Dependencies of header files upon other header files they include X.PRECIOUS: $(INCLDIR)/defs.h $(INCLDIR)/elm.h $(INCLDIR)/headers.h X X$(INCLDIR)/defs.h: $(INCLDIR)/../config.h $(INCLDIR)/sysdefs.h X $(CHMOD) u+w $@ X $(TOUCH) $@ X X$(INCLDIR)/elm.h: $(INCLDIR)/curses.h $(INCLDIR)/defs.h X $(CHMOD) u+w $@ X $(TOUCH) $@ X X$(INCLDIR)/headers.h: $(INCLDIR)/curses.h $(INCLDIR)/defs.h X $(CHMOD) u+w $@ X $(TOUCH) $@ X X# Dependencies of C object files Xaddr_util.o: $(INCLDIR)/headers.h Xalias.o: $(INCLDIR)/headers.h Xaliasdb.o: $(INCLDIR)/headers.h Xaliaslib.o: $(INCLDIR)/headers.h Xargs.o: $(INCLDIR)/headers.h $(INCLDIR)/patchlevel.h Xbouncebk.o: $(INCLDIR)/headers.h Xbuiltin.o: $(INCLDIR)/headers.h Xcalendar.o: $(INCLDIR)/headers.h Xconn_to.o: $(INCLDIR)/headers.h Xcurses.o: $(INCLDIR)/headers.h Xdate.o: $(INCLDIR)/headers.h Xdelete.o: $(INCLDIR)/headers.h Xdomains.o: $(INCLDIR)/headers.h Xedit.o: $(INCLDIR)/headers.h Xeditmsg.o: $(INCLDIR)/headers.h Xelm.o: $(INCLDIR)/elm.h Xencode.o: $(INCLDIR)/headers.h Xerrno.o: $(INCLDIR)/headers.h Xexitprog.o: $(INCLDIR)/headers.h Xexpires.o: $(INCLDIR)/headers.h Xfile.o: $(INCLDIR)/headers.h Xfile_util.o: $(INCLDIR)/headers.h Xfileio.o: $(INCLDIR)/headers.h Xforms.o: $(INCLDIR)/headers.h Xhdrconfg.o: $(INCLDIR)/headers.h Xhelp.o: $(INCLDIR)/headers.h Xin_utils.o: $(INCLDIR)/headers.h Xinit.o: $(INCLDIR)/headers.h $(INCLDIR)/patchlevel.h Xleavembox.o: $(INCLDIR)/headers.h Xlimit.o: $(INCLDIR)/headers.h Xmailmsg1.o: $(INCLDIR)/headers.h Xmailmsg2.o: $(INCLDIR)/headers.h Xmailtime.o: $(INCLDIR)/headers.h Xmkhdrs.o: $(INCLDIR)/headers.h Xnewmbox.o: $(INCLDIR)/headers.h Xopt_utils.o: $(INCLDIR)/headers.h Xoptions.o: $(INCLDIR)/headers.h Xout_utils.o: $(INCLDIR)/headers.h Xpattern.o: $(INCLDIR)/headers.h Xpmalloc.o: $(INCLDIR)/defs.h Xquit.o: $(INCLDIR)/headers.h Xread_rc.o: $(INCLDIR)/headers.h Xremail.o: $(INCLDIR)/headers.h Xreply.o: $(INCLDIR)/headers.h Xreturnadd.o: $(INCLDIR)/headers.h Xsave_opts.o: $(INCLDIR)/save_opts.h $(INCLDIR)/headers.h Xsavecopy.o: $(INCLDIR)/headers.h Xscreen.o: $(INCLDIR)/headers.h Xshowmsg.o: $(INCLDIR)/headers.h Xshowmsg_c.o: $(INCLDIR)/headers.h Xsignals.o: $(INCLDIR)/headers.h Xsoftkeys.o: $(INCLDIR)/headers.h Xsort.o: $(INCLDIR)/headers.h Xstring2.o: $(INCLDIR)/headers.h Xstrings.o: $(INCLDIR)/headers.h Xsyscall.o: $(INCLDIR)/headers.h Xutils.o: $(INCLDIR)/headers.h Xvalidname.o: $(INCLDIR)/defs.h X X# Dependencies and rules for compiling C programs X$(BIN)/elm: $& $(ELM_OBJ) X $(CC) $(LFLAGS) -o $@ $(ELM_OBJ) $(LIBS) $(LIB2) X X# Dependencies and rules for installing C programs X$(DEST)/elm: $(BIN)/elm X -$(MV) $@ $@.old X -$(RM) $@.old X $(CP) $(BIN)/elm $@ X $(CHGRP) $(MAILGRP) $@ X $(CHMOD) $(MAILERMODE) $@ X X!NO!SUBS! SHAR_EOF chmod 0444 src/Makefile.SH || echo "restore of src/Makefile.SH fails" echo "x - extracting src/addr_util.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/addr_util.c && X Xstatic char rcsid[] = "@(#)$Id: addr_util.c,v 4.1 90/04/28 22:42:21 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 Coordinator X * elm@DSI.COM dsinc!elm X * X ******************************************************************************* X * $Log: addr_util.c,v $ X * Revision 4.1 90/04/28 22:42:21 syd X * checkin of Elm 2.3 as of Release PL0 X * X * X ******************************************************************************/ X X/** This file contains addressing utilities X X**/ X X#include "headers.h" X X#include <sys/types.h> X#include <sys/stat.h> X#ifdef PWDINSYS X# include <sys/pwd.h> X#else X# include <pwd.h> X#endif X X#include <ctype.h> X X#ifdef BSD X#undef tolower X#undef toupper X#endif X Xchar *get_alias_address(), *get_token(); Xchar *strtok(), *strcpy(), *strcat(), *strncpy(), *index(), *rindex(); X X X#define SKIP_WS(p) while (isspace(*p)) p++ X#define SKIP_ALPHA(p) while (isalpha(*p)) p++ X#define SKIP_DIGITS(p) while (isdigit(*p)) p++ X Xstatic char *day_name[8] = { X "sun", "mon", "tue", "wed", "thu", "fri", "sat", 0 X}; X Xstatic char *month_name[13] = { X "jan", "feb", "mar", "apr", X "may", "jun", "jul", "aug", X "sep", "oct", "nov", "dec", 0 X}; X Xstatic int month_len[12] = { X 31, 28, 31, 30, 31, 30, 31, X 31, 30, 31, 30, 31 }; X X/* The following time zones are taken from a variety of sources. They X * are by no means exhaustive, but seem to include most of those X * in common usage. A comprehensive list is impossible, since the same X * abbreviation is sometimes used to mean different things in different X * parts of the world. X */ Xstatic struct tzone { X char *str; X int offset; /* offset, in minutes, EAST of GMT */ X} tzone_info[] = { X /* the following are from rfc822 */ X "ut", 0, "gmt", 0, X "est", -5*60, "edt", -4*60, X "cst", -6*60, "cdt", -5*60, X "mst", -7*60, "mdt", -6*60, X "pst", -8*60, "pdt", -7*60, X "z", 0, /* zulu time (the rest of the military codes are bogus) */ X X /* these are also popular in Europe */ X "wet", 0*60, "wet dst", 1*60, /* western european */ X "met", 1*60, "met dst", 2*60, /* middle european */ X "eet", 2*60, "eet dst", 3*60, /* eastern european */ X "bst", 1*60, /* ??? british summer time (=+0100) */ X X /* ... and Canada */ X "ast", -4*60, "adt", -3*60, /* atlantic */ X "nst", -3*60-30, "ndt", -2*60-30, /* newfoundland */ X "yst", -9*60, "ydt", -8*60, /* yukon */ X "hst", -10*60, /* hawaii (not really canada) */ X X /* ... and Asia */ X "jst", 9*60, /* japan */ X "sst", 8*60, /* singapore */ X X /* ... and the South Pacific */ X "nzst", 12*60, "nzdt", 13*60, /* new zealand */ X "wst", 8*60, "wdt", 9*60, /* western australia */ X /* there's also central and eastern australia, but they insist on using X * cst, est, etc., which would be indistinguishable for the us zones */ X (char *) 0, 0 X}; X Xchar * Xgcos_name(gcos_field, logname) Xchar *logname, *gcos_field; X{ X /** Return the full name found in a passwd file gcos field **/ X X#ifdef BERKNAMES X X static char fullname[SLEN]; X register char *fncp, *gcoscp, *lncp, *end; X X X /* full name is all chars up to first ',' (or whole gcos, if no ',') */ X /* replace any & with logname in upper case */ X X for(fncp = fullname, gcoscp= gcos_field, end = fullname + SLEN - 1; X (*gcoscp != ',' && *gcoscp != '\0' && fncp != end); X gcoscp++) { X X if(*gcoscp == '&') { X for(lncp = logname; *lncp; fncp++, lncp++) X *fncp = toupper(*lncp); X } else { X *fncp++ = *gcoscp; X } X } X X *fncp = '\0'; X return(fullname); X#else X#ifdef USGNAMES X X char *firstcp, *lastcp; X X /* The last character of the full name is the one preceding the first X * '('. If there is no '(', then the full name ends at the end of the X * gcos field. X */ X if(lastcp = index(gcos_field, '(')) X *lastcp = '\0'; X X /* The first character of the full name is the one following the X * last '-' before that ending character. NOTE: that's why we X * establish the ending character first! X * If there is no '-' before the ending character, then the fullname X * begins at the beginning of the gcos field. X */ X if(firstcp = rindex(gcos_field, '-')) X firstcp++; X else X firstcp = gcos_field; X X return(firstcp); X X#else X /* use full gcos field */ X return(gcos_field); X#endif X#endif X} X Xchar * Xget_full_name(logname) Xchar *logname; X{ X /* return a pointer to the full user name for the passed logname X * or NULL if cannot be found X * If PASSNAMES get it from the gcos field, otherwise get it X * from ~/.fullname. X */ X X#ifndef PASSNAMES X FILE *fp; X char fullnamefile[SLEN]; X#endif X static char fullname[SLEN]; X struct passwd *getpwnam(), *pass; X X if((pass = getpwnam(logname)) == NULL) X return(NULL); X#ifdef PASSNAMES /* get full_username from gcos field */ X strcpy(fullname, gcos_name(pass->pw_gecos, logname)); X#else /* get full_username from ~/.fullname file */ X sprintf(fullnamefile, "%s/.fullname", pass->pw_dir); SHAR_EOF echo "End of part 10" echo "File src/addr_util.c is continued in part 11" echo "11" > s2_seq_.tmp exit 0 exit 0 # Just in case... -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net. Use a domain-based address or give alternate paths, or you may lose out.
rsalz@bbn.com (Rich Salz) (05/31/90)
Submitted-by: Syd Weinstein <syd@dsinc.dsi.com> 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 <time.h> X#endif X#ifdef I_SYSTIME X# include <sys/time.h> X#endif X#include <fcntl.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 *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 <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 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 <stdio.h> X#include <fcntl.h> X#include <errno.h> 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 <sys/types.h> X#include <sys/file.h> 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 <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 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 <stdio.h> X#include <pwd.h> X#include <ctype.h> X#include "defs.h" X#ifdef I_TIME X# include <time.h> X#endif X#ifdef I_SYSTIME X# include <sys/time.h> X#endif X#include <fcntl.h> 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 "<day-of-month>" 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, "<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_MSG : 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 i = strlen(rule); X buffer[i] = '\0'; X while (--i >= 0) X buffer[i] = (rule[i] == '_' ? ' ' : rule[i]); 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 4.1 90/04/28 22:42:02 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: summarize.c,v $ X * Revision 4.1 90/04/28 22:42:02 syd X * checkin of Elm 2.3 as of Release PL0 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[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, 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 */ X X fprintf(outfd, X "\n\t\t\tA Summary of Filter Activity\n"); X fprintf(outfd, X "\t\t\t----------------------------\n\n"); X X fprintf(outfd,"A total of %d message%s %s filtered:\n\n", X messages_filtered, plural(messages_filtered), X messages_filtered > 1 ? "were" : "was"); X X if (erroneous_rules) X fprintf(outfd, X "[Warning: %d erroneous rule%s logged and ignored!]\n\n", X erroneous_rules, erroneous_rules > 1? "s were" : " was"); X X if (default_rules) { X fprintf(outfd, X "The default rule of putting mail into your mailbox\n"); X fprintf(outfd, "\tapplied %d time%s (%d%%)\n\n", X default_rules, plural(default_rules), X (default_rules*100+(messages_filtered>>1))/messages_filtered X ); X } X X /** and now for each rule we used... **/ X X for (rule = 0; rule < total_rules; rule++) { X if (applied[rule]) { X fprintf(outfd, "Rule #%d: ", rule+1); X switch (rules[rule].action) { X case LEAVE: fprintf(outfd, "(leave mail in mailbox)"); X break; X case DELETE_MSG: fprintf(outfd, "(delete message)"); X break; X case SAVE : fprintf(outfd, "(save in \"%s\")", X rules[rule].argument2); break; X case SAVECC: fprintf(outfd, X "(left in mailbox and saved in \"%s\")", X rules[rule].argument2); break; X case FORWARD: fprintf(outfd, "(forwarded to \"%s\")", X rules[rule].argument2); break; X case EXEC : fprintf(outfd, "(given to command \"%s\")", X rules[rule].argument2); break; X } X fprintf(outfd, "\n\tapplied %d time%s (%d%%)\n\n", X applied[rule], plural(applied[rule]), X (applied[rule]*100+(messages_filtered>>1))/messages_filtered X ); X } X } X X if (long_summary) { X X /* next, after a ^L, include the actual log file... */ X X sprintf(filename, "%s/%s", home, filterlog); X X if ((fd = fopen(filename, "r")) == NULL) { X fprintf(outfd,"filter (%s): Can't open filterlog file %s!\n", X username, filename); X } X else { X fprintf(outfd, "\n\n\n%c\n\nExplicit log of each action;\n\n", X (char) 12); X while (fgets(buffer, SLEN, fd) != NULL) X fprintf(outfd, "%s", buffer); X fprintf(outfd, "\n-----\n"); X fclose(fd); X } X } X X /* now remove the log files, please! */ X X if (clear_logs) { X sprintf(filename, "%s/%s", home, filterlog); X unlink(filename); X sprintf(filename, "%s/%s", home, filtersum); X unlink(filename); X } X X return; X} SHAR_EOF chmod 0444 filter/summarize.c || echo "restore of filter/summarize.c fails" echo "x - extracting filter/utils.c (Text)" sed 's/^X//' << 'SHAR_EOF' > filter/utils.c && X Xstatic char rcsid[] ="@(#)$Id: utils.c,v 4.1 90/04/28 22:42:03 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: utils.c,v $ X * Revision 4.1 90/04/28 22:42:03 syd X * checkin of Elm 2.3 as of Release PL0 X * X * X ******************************************************************************/ X X/** Utility routines for the filter program... X 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 Xleave(reason) Xchar *reason; X{ X if (outfd != NULL) X fprintf(outfd,"filter (%s): LEAVE %s\n", username, reason); X if (outfd != NULL) fclose(outfd); X exit(1); X} X Xlog(what) Xint what; X{ X /** make an entry in the log files for the specified entry **/ X X FILE *fd; X char filename[SLEN]; X X if (! show_only) { X sprintf(filename, "%s/%s", home, filtersum); /* log action once! */ X if ((fd = fopen(filename, "a")) == NULL) { X if (outfd != NULL) X fprintf(outfd, "filter (%s): Couldn't open log file %s\n", X filename); X fd = stdout; X } X fprintf(fd, "%d\n", rule_choosen); X fclose(fd); X } X X sprintf(filename, "%s/%s", home, filterlog); X X if (show_only) X fd = stdout; X else if ((fd = fopen(filename, "a")) == NULL) { X if (outfd != NULL) X fprintf(outfd, "filter (%s): Couldn't open log file %s\n", X filename); X fd = stdout; X } X X#ifdef _IOFBF X setvbuf(fd, NULL, _IOFBF, BUFSIZ); X#endif X X if (strlen(from) + strlen(subject) > 60) X fprintf(fd, "\nMail from %s\n\tabout %s\n", from, subject); X else X fprintf(fd, "\nMail from %s about %s\n", from, subject); X X if (rule_choosen != -1) X if (rules[rule_choosen].condition->matchwhat == TO) X fprintf(fd, "\t(addressed to %s)\n", to); X X switch (what) { X case DELETE_MSG : fprintf(fd, "\tDELETED"); break; X case SAVE : fprintf(fd, "\tSAVED in file \"%s\"", X rules[rule_choosen].argument2); break; X case SAVECC : fprintf(fd,"\tSAVED in file \"%s\" AND PUT in mailbox", X rules[rule_choosen].argument2); break; X case FORWARD : fprintf(fd, "\tFORWARDED to \"%s\"", X rules[rule_choosen].argument2); break; X case EXEC : fprintf(fd, "\tEXECUTED \"%s\"", X rules[rule_choosen].argument2); break; X case LEAVE : fprintf(fd, "\tPUT in mailbox"); break; X } X X if (rule_choosen != -1) X fprintf(fd, " by rule #%d\n", rule_choosen+1); X else X fprintf(fd, ": the default action\n"); X X fflush(fd); X fclose(fd); X} X Xint Xcontains(string, pattern) Xchar *string, *pattern; X{ X /** Returns TRUE iff pattern occurs IN IT'S ENTIRETY in buffer. **/ X X register int i = 0, j = 0; X X while (string[i] != '\0') { X while (tolower(string[i++]) == tolower(pattern[j++])) X if (pattern[j] == '\0') X return(TRUE); X i = i - j + 1; X j = 0; X } X return(FALSE); X} X Xchar *itoa(i, two_digit) Xint i, two_digit; X{ X /** return 'i' as a null-terminated string. If two-digit use that X size field explicitly! **/ X X static char value[10]; X X if (two_digit) X sprintf(value, "%02d", i); X else X sprintf(value, "%d", i); X X return( (char *) value); X} X Xlowercase(string) Xchar *string; X{ X /** translate string into all lower case **/ X X register int i; X X for (i= strlen(string); --i >= 0; ) X if (isupper(string[i])) X string[i] = tolower(string[i]); X} SHAR_EOF chmod 0444 filter/utils.c || echo "restore of filter/utils.c fails" echo "x - extracting hdrs/curses.h (Text)" sed 's/^X//' << 'SHAR_EOF' > hdrs/curses.h && X X/* $Id: curses.h,v 4.1 90/04/28 22:42:05 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 Coordinator X * elm@DSI.COM dsinc!elm X * X ******************************************************************************* X * $Log: curses.h,v $ X * Revision 4.1 90/04/28 22:42:05 syd X * checkin of Elm 2.3 as of Release PL0 X * X * X ******************************************************************************/ X X /*** Include file for seperate compilation. ***/ X X#define OFF 0 X#define ON 1 X Xint InitScreen(), /* This must be called before anything else!! */ X X ClearScreen(), CleartoEOLN(), X X MoveCursor(), X X StartBold(), EndBold(), X StartUnderline(), EndUnderline(), X StartHalfbright(), EndHalfbright(), X StartInverse(), EndInverse(), X X transmit_functions(), X X Raw(), RawState(), X ReadCh(); X Xchar *return_value_of(); SHAR_EOF chmod 0444 hdrs/curses.h || echo "restore of hdrs/curses.h fails" echo "x - extracting hdrs/defs.h (Text)" sed 's/^X//' << 'SHAR_EOF' > hdrs/defs.h && X X/* $Id: defs.h,v 4.1 90/04/28 22:42:06 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 Coordinator X * elm@DSI.COM dsinc!elm X * X ******************************************************************************* X * $Log: defs.h,v $ X * Revision 4.1 90/04/28 22:42:06 syd X * checkin of Elm 2.3 as of Release PL0 X * X * X ******************************************************************************/ X X/** define file for ELM mail system. **/ X X X#include "../config.h" X#include "sysdefs.h" /* system/configurable defines */ X X X# define VERSION "2.3" /* Version number... */ X# define VERS_DATE "May 1, 1990" /* for elm -v option */ X# define WHAT_STRING \ X "@(#) Version 2.3, USENET supported version, released May 1990" X X#define KLICK 25 X X#define SLEN 256 /* long for ensuring no overwrites... */ X#define SHORT 10 /* super short strings! */ X#define NLEN 48 /* name length for aliases */ X#define WLEN 20 X#define STRING 128 /* reasonable string length for most.. */ X#define LONG_STRING 512 /* even longer string for group expansion */ X#define VERY_LONG_STRING 2560 /* huge string for group alias expansion */ X#define MAX_LINE_LEN 5120 /* even bigger string for "filter" prog.. */ X X#define BREAK '\0' /* default interrupt */ X#define BACKSPACE '\b' /* backspace character */ X#define TAB '\t' /* tab character */ X#define RETURN '\r' /* carriage return char */ X#define LINE_FEED '\n' /* line feed character */ X#define FORMFEED '\f' /* form feed (^L) char */ X#define COMMA ',' /* comma character */ X#define SPACE ' ' /* space character */ X#define DOT '.' /* period/dot character */ X#define BANG '!' /* exclaimation mark! */ X#define AT_SIGN '@' /* at-sign character */ X#define PERCENT '%' /* percent sign char. */ X#define COLON ':' /* the colon .. */ X#define BACKQUOTE '`' /* backquote character */ X#define TILDE_ESCAPE '~' /* escape character~ */ X#define ESCAPE '\033' /* the escape */ X X#define NO_OP_COMMAND '\0' /* no-op for timeouts */ X X#define STANDARD_INPUT 0 /* file number of stdin */ X X#ifndef TRUE X#define TRUE 1 X#define FALSE 0 X#endif X X#define NO 0 X#define YES 1 X#define MAYBE 2 /* a definite define, eh? */ X#define FORM 3 /* <nevermind> */ X#define PREFORMATTED 4 /* forwarded form... */ X X#define SAME_PAGE 1 /* redraw current only */ X#define NEW_PAGE 2 /* redraw message list */ X#define ILLEGAL_PAGE 0 /* error in page list, punt */ X X#define PAD 0 /* for printing name of */ X#define FULL 1 /* the sort we're using */ X X#define OUTGOING 0 /* defines for lock file */ X#define INCOMING 1 /* creation..see lock() */ X X#define SH 0 /* defines for system_call */ X#define USER_SHELL 1 /* to work correctly! */ X X#define EXECUTE_ACCESS 01 /* These five are */ X#define WRITE_ACCESS 02 /* for the calls */ X#define READ_ACCESS 04 /* to access() */ X#define ACCESS_EXISTS 00 /* <etc> */ X#define EDIT_ACCESS 06 /* (this is r+w access) */ X X#define BIG_NUM 999999 /* big number! */ X#define BIGGER_NUM 9999999 /* bigger number! */ X X#define START_ENCODE "[encode]" X#define END_ENCODE "[clear]" X X#define DONT_SAVE "[no save]" X#define DONT_SAVE2 "[nosave]" X X#define alias_file ".aliases" X#define group_file ".groups" X#define system_file ".systems" X X#define default_folders "Mail" X#define default_recvdmail "=received" X#define default_sentmail "=sent" X X/** some defines for the 'userlevel' variable... **/ X X#define RANK_AMATEUR 0 X#define AMATEUR 1 X#define OKAY_AT_IT 2 X#define GOOD_AT_IT 3 X#define EXPERT 4 X#define SUPER_AT_IT 5 X X/** some defines for the "status" field of the header record **/ X X#define ACTION 1 /* bit masks, of course */ X#define CONFIDENTIAL 2 X#define DELETED 4 X#define EXPIRED 8 X#define FORM_LETTER 16 X#define NEW 32 X#define PRIVATE 64 X#define TAGGED 128 X#define URGENT 256 X#define VISIBLE 512 X#define UNREAD 1024 X#define STATUS_CHANGED 2048 X X#define UNDELETE 0 /* purely for ^U function... */ X X/** values for headers exit_disposition field */ X#define UNSET 0 X#define KEEP 1 X#define STORE 2 X#define DELETE 3 X X/** some months... **/ X X#define JANUARY 0 /* months of the year */ X#define FEBRUARY 1 X#define MARCH 2 X#define APRIL 3 X#define MAY 4 X#define JUNE 5 X#define JULY 6 X#define AUGUST 7 X#define SEPTEMBER 8 X#define OCTOBER 9 X#define NOVEMBER 10 X#define DECEMBER 11 X X#define equal(s,w) (strcmp(s,w) == 0) X#define min(a,b) a < b? a : b X#define ctrl(c) c - 'A' + 1 /* control character mapping */ X#define plural(n) n == 1 ? "" : "s" X#define lastch(s) s[strlen(s)-1] X X/* find tab stops preceding or following a given column position 'a', where X * the column position starts counting from 1, NOT 0! X * The external integer "tabspacing" must be declared to use this. */ X#define prev_tab(a) (((((a-1)/tabspacing))*tabspacing)+1) X#define next_tab(a) (((((a-1)/tabspacing)+1)*tabspacing)+1) X X#define movement_command(c) (c == 'j' || c == 'k' || c == ' ' || \ X c == BACKSPACE || c == ESCAPE || c == '*' || \ X c == '-' || c == '+' || c == '=' || \ X c == '#' || c == '@' || c == 'x' || \ X c == 'a' || c == 'q') X X#define no_ret(s) { register int xyz; /* varname is for lint */ \ X for (xyz=strlen(s)-1; xyz >= 0 && \ X (s[xyz] == '\r' || s[xyz] == '\n'); ) \ X s[xyz--] = '\0'; \ X } X X#define first_word(s,w) (strncmp(s,w, strlen(w)) == 0) X#define ClearLine(n) MoveCursor(n,0); CleartoEOLN() X#define whitespace(c) (c == ' ' || c == '\t') X#define ok_rc_char(c) (isalnum(c) || c == '-' || c == '_') X#define ok_alias_char(c) (isalnum(c) || c == '-' || c == '_' || c == '.') X#define quote(c) (c == '"' || c == '\'') X#define onoff(n) (n == 0 ? "OFF" : "ON") X X/** The next function is so certain commands can be processed from the showmsg X routine without rewriting the main menu in between... **/ X X#define special(c) (c == 'j' || c == 'k') X X/** and a couple for dealing with status flags... **/ X X#define ison(n,mask) (n & mask) X#define isoff(n,mask) (!ison(n, mask)) X X#define setit(n,mask) n |= mask X#define clearit(n, mask) n &= ~mask X SHAR_EOF echo "End of part 9" echo "File hdrs/defs.h is continued in part 10" echo "10" > s2_seq_.tmp exit 0 -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net. Use a domain-based address or give alternate paths, or you may lose out.