[comp.mail.elm] Elm 2.1 PL1 part 21 of 22

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

---- Cut Here and unpack ----
#!/bin/sh
# this is part 21 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file utils/fastmail.c continued
#
CurArch=21
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 utils/fastmail.c"
sed 's/^X//' << 'SHAR_EOF' >> utils/fastmail.c
Xint argc;
Xchar *argv[], *options;
X{
X	/** Returns the character argument next, and optionally instantiates 
X	    "argument" to the argument associated with the particular option 
X	**/
X	
X	char       *word, *strchr();
X
X	if (_indx >= strlen(argv[_argnum])) {
X	  _argnum++;
X	  _indx = 1;		/* zeroeth char is '-' */
X	}
X
X	if (_argnum >= argc) {
X	  opt_index = argc;
X	  return(DONE);
X	}
X	
X	if (argv[_argnum][0] != '-') {
X	  opt_index = _argnum;
X	  return(DONE);
X	}
X
X        word = strchr(options, argv[_argnum][_indx++]);
X
X	if (strlen(word) == 0) 
X	  return(ERROR);
X	
X	if (word[1] == ':') {
X
X	  /** Two possibilities - either tailing end of this argument or the 
X	      next argument in the list **/
X
X	  if (_indx < strlen(argv[_argnum])) { /* first possibility */
X	    optional_arg = (char *) (argv[_argnum] + _indx);
X	    _argnum++;
X	    _indx = 1;
X	  }
X	  else {				/* second choice     */
X	    if (++_argnum >= argc) 
X	      return(ERROR);			/* no argument!!     */
X
X	    optional_arg = (char *) argv[_argnum++];
X	    _indx = 1;
X	  }
X	}
X
X	return((int) word[0]);
X}
SHAR_EOF
echo "File utils/fastmail.c is complete"
chmod 0444 utils/fastmail.c || echo "restore of utils/fastmail.c fails"
echo "x - extracting utils/from.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > utils/from.c &&
X
Xstatic char rcsid[] = "@(#)$Id: from.c,v 2.1 88/09/15 21:07:30 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.1 $   $State: Exp $
X *
X * 			Copyright (c) 1986 Dave Taylor
X *******************************************************************************
X * Bug reports, patches, comments, suggetions should be sent to:
X *
X *	Eric D. Christensen  -  edc@altnet.ALTOS.COM 
X *				uunet!altnet!edc
X *
X *******************************************************************************
X * $Log:	from.c,v $
X * Revision 2.1  88/09/15  21:07:30  syd
X * checked in with -k by syd at 88.09.15.21.07.30.
X * 
X * 88/08/27 Rob Bernardo <gatech!pbhyf.PacBell.COM!rob>
X * fixes for non tty processes, unreferenced variable
X *
X * Revision 2.1  88/07/21  10:01:31  edc
X * Final hacks and cleanup to the 2.1 alpha test release
X * 
X * Revision 2.0  88/06/27  16:54:07  edc
X * The original 2.0 gamma sources as leaked from HP
X * 
X *
X *
X ******************************************************************************/
X
X/** print out whom each message is from in the pending folder or specified 
X    one, including a subject line if available.. 
X
X    Added PREFER_UUCP knowledge 6/86
X    Added "-n" flag, 9/86
X    Added "-v" flag, 3/87
X
X**/
X
X#include <stdio.h>
X#include "defs.h"
X
Xstatic char ident[] = { WHAT_STRING };
X
X#define LINEFEED	(char) 10
X
X#define metachar(c)	(c == '=' || c == '+' || c == '%')
X
XFILE *mailfile;
X
Xchar *expand_define();
Xint   number = 0,	/* should we number the messages?? */
X      verbose = 0;	/* and should we prepend a header? */
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	char infile[LONG_SLEN], username[SLEN];
X	int  multiple_files = 0, output_files = 0, c;
X
X	extern int opt_index;
X
X	while ((c = get_options(argc, argv, "nv")) > 0) 
X	  switch (c) {
X	    case (int)'n': number++;		break;
X	    case (int)'v': verbose++;	break;
X	  }
X
X	if (c == -1) {
X	  printf("Usage: %s [-n] [-v] {filename | username}\n", argv[0]);
X	  exit(1);
X	}
X
X	infile[0] = '\0';
X	if (opt_index == argc) {
X	  if (getlogin())
X	    strcpy(username, getlogin());
X	  if (strlen(username) == 0)
X	    cuserid(username);
X	  sprintf(infile,"%s%s",mailhome, username);
X	  opt_index -= 1;	/* ensure one pass through loop */
X	}
X
X	multiple_files = (argc - opt_index > 1);
X
X	while (opt_index < argc) {
X	
X	  if (multiple_files) {
X	    strcpy(infile, argv[opt_index]);
X	    printf("%s%s: \n", output_files++ > 0 ? "\n":"", infile);
X	  }
X	  else if (infile[0] == '\0')
X	    strcpy(infile, argv[opt_index]);
X
X	  if (metachar(infile[0])) {
X	    if (expand(infile) == 0) {
X	       fprintf(stderr, "%s: couldn't expand filename %s!\n", 
X		       argv[0], infile);
X	       exit(1);
X	    }
X	  }
X
X	  if ((mailfile = fopen(infile,"r")) == NULL) {
X	    if (opt_index+1 == argc)
X	      printf("No mail\n");
X	    else {
X	      if (infile[0] == '/') 
X	        printf("Couldn't open folder \"%s\".\n", infile);
X	      else {
X	        sprintf(infile,"%s%s", mailhome, argv[opt_index]);
X	        if ((mailfile = fopen(infile,"r")) == NULL)
X	          printf("Couldn't open folders \"%s\" or \"%s\".\n",
X			 argv[opt_index], infile);
X	        else if (read_headers()==0)
X	          printf("No messages in that folder!\n");
X	       }
X	    }
X	  }
X	  else
X	    if (read_headers(opt_index+1 == argc)==0)
X	      if (opt_index+1 == argc)
X	        printf("No mail\n");
X	      else
X	        printf("No messages in that folder!\n");
X
X	  opt_index++;
X	}
X	exit(0);
X}
X
Xint
Xread_headers(user_mailbox)
Xint user_mailbox;
X{
X	/** Read the headers, output as found.  User-Mailbox is to guarantee
X	    that we get a reasonably sensible message from the '-v' option
X	 **/
X
X	char buffer[LONG_SLEN], from_whom[SLEN], subject[SLEN];
X	register int subj = 0, in_header = 0, count = 0;
X
X	while (fgets(buffer, LONG_SLEN, mailfile) != NULL) {
X	  if (first_word(buffer,"From ")) {
X	    if (real_from(buffer, from_whom)) {
X	      subj = 0;
X	      in_header = 1;
X	    }
X	  }
X	  else if (in_header) {
X	    if (first_word(buffer,">From ")) 
X	      forwarded(buffer, from_whom); /* return address */
X	    else if (first_word(buffer,"Subject:") ||
X		     first_word(buffer,"Re:")) {
X	      if (! subj++) {
X	        remove_first_word(buffer);
X		strcpy(subject, buffer);
X	      }
X	    }
X	    else if (first_word(buffer,"From:") ||
X		    first_word(buffer, ">From:"))
X	      parse_arpa_from(buffer, from_whom);
X	    else if (buffer[0] == LINEFEED) {
X	      if (verbose && count == 0)
X	        printf("%s contains the following messages:\n\n",
X			user_mailbox?"Your mailbox" : "Folder");
X	      in_header = 0;	/* in body of message! */
X	      show_header(count+1, from_whom, subject);
X	      from_whom[0] = 0;
X	      subject[0] = 0;
X	      count++;
X	    }
X	  }
X	}
X	return(count);
X}
X
Xint
Xreal_from(buffer, who)
Xchar *buffer, *who;
X{
X	/***** returns true iff 's' has the seven 'from' fields,
X	       initializing the who to the sender *****/
X
X	char junk[80];
X
X	junk[0] = '\0';
X	sscanf(buffer, "%*s %s %*s %*s %*s %*s %s",
X	            who, junk);
X	return(junk[0] != '\0');
X}
X
Xforwarded(buffer, who)
Xchar *buffer, *who;
X{
X	/** change 'from' and date fields to reflect the ORIGINATOR of 
X	    the message by iteratively parsing the >From fields... **/
X
X	char machine[80], buff[80];
X
X	machine[0] = '\0';
X	sscanf(buffer, "%*s %s %*s %*s %*s %*s %*s %*s %*s %s",
X	            who, machine);
X
X	if (machine[0] == '\0') /* try for srm address */
X	  sscanf(buffer, "%*s %s %*s %*s %*s %*s %*s %*s %s",
X	            who, machine);
X
X	if (machine[0] == '\0')
X	  sprintf(buff,"anonymous");
X	else
X	  sprintf(buff,"%s!%s", machine, who);
X
X	strncpy(who, buff, 80);
X}
X
Xremove_first_word(string)
Xchar *string;
X{	/** removes first word of string, ie up to first non-white space
X	    following a white space! **/
X
X	register int loc;
X
X	for (loc = 0; string[loc] != ' ' && string[loc] != '\0'; loc++) 
X	    ;
X
X	while (string[loc] == ' ' || string[loc] == '\t')
X	  loc++;
X	
X	move_left(string, loc);
X}
X
Xmove_left(string, chars)
Xchar string[];
Xint  chars;
X{
X	/** moves string chars characters to the left DESTRUCTIVELY **/
X
X	register int i;
X
X	chars--; /* index starting at zero! */
X
X	for (i=chars; string[i] != '\0' && string[i] != '\n'; i++)
X	  string[i-chars] = string[i];
X
X	string[i-chars] = '\0';
X}
X
Xshow_header(count, from, subject)
Xint  count;
Xchar *from, *subject;
X{
X	/** output header in clean format, including abbreviation
X	    of return address if more than one machine name is
X	    contained within it! **/
X
X	char buffer[SLEN];
X	int  loc, i=0, exc=0;
X
X#ifdef PREFER_UUCP
X	char *p;
X	
X	if (chloc(from,'!') != -1 && chloc(from,'@') > 0) {
X	  for (p=from;*p != '@'; p++) ;
X	  *p = '\0';
X	}
X#endif
X
X	loc = strlen(from);
X
X	while (exc < 2 && loc > 0)
X	  if (from[--loc] == '!')
X	    exc++;
X
X	if (exc == 2) { /* lots of machine names!  Get last one */
X	  loc++;
X	  while (loc < strlen(from) && loc < SLEN)
X	    buffer[i++] = from[loc++];
X	  buffer[i] = '\0';
X	  if (number)
X	    printf("%3d: %-20s  %s\n", count, buffer, subject);
X	  else
X	    printf("%-20s  %s\n", buffer, subject);
X	}
X	else
X	  if (number)
X	    printf("%3d: %-20s  %s\n", count, from, subject);
X	  else
X	    printf("%-20s  %s\n", from, subject);
X}	
X
Xparse_arpa_from(buffer, newfrom)
Xchar *buffer, *newfrom;
X{
X	/** try to parse the 'From:' line given... It can be in one of
X	    two formats:
X		From: Dave Taylor <hpcnou!dat>
X	    or  From: hpcnou!dat (Dave Taylor)
X	    Change 'newfrom' ONLY if sucessfully parsed this entry and
X	    the resulting name is non-null! 
X	**/
X
X	char temp_buffer[SLEN], *temp;
X	register int i, j = 0;
X
X	temp = (char *) temp_buffer;
X	temp[0] = '\0';
X
X	no_ret(buffer);		/* blow away '\n' char! */
X
X	if (lastch(buffer) == '>') {
X	  for (i=strlen("From: "); buffer[i] != '\0' && buffer[i] != '<' &&
X	       buffer[i] != '('; i++)
X	    temp[j++] = buffer[i];
X	  temp[j] = '\0';
X	}
X	else if (lastch(buffer) == ')') {
X	  for (i=strlen(buffer)-2; buffer[i] != '\0' && buffer[i] != '(' &&
X	       buffer[i] != '<'; i--)
X	    temp[j++] = buffer[i];
X	  temp[j] = '\0';
X	  reverse(temp);
X	}
X	  
X	if (strlen(temp) > 0) {		/* mess with buffer... */
X
X	  /* remove leading spaces... */
X
X	  while (whitespace(temp[0]))
X	    temp = (char *) (temp + 1);		/* increment address! */
X
X	  /* remove trailing spaces... */
X
X	  i = strlen(temp) - 1;
X
X	  while (whitespace(temp[i]))
X	   temp[i--] = '\0';
X
X	  /* remove surrounding paired quotation marks */
X	  if((temp[i] == '"') & (*temp == '"')) {
X	    temp[i] = '\0';
X	    temp++;
X	  }
X
X	  /* if anything is left, let's change 'from' value! */
X
X	  if (strlen(temp) > 0)
X	    strcpy(newfrom, temp);
X	}
X}
X
Xreverse(string)
Xchar *string;
X{
X	/** reverse string... pretty trivial routine, actually! **/
X
X	char buffer[SLEN];
X	register int i, j = 0;
X
X	for (i = strlen(string)-1; i >= 0; i--)
X	  buffer[j++] = string[i];
X
X	buffer[j] = '\0';
X
X	strcpy(string, buffer);
X}
SHAR_EOF
chmod 0444 utils/from.c || echo "restore of utils/from.c fails"
echo "x - extracting utils/getopt.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > utils/getopt.c &&
X
Xstatic char rcsid[] = "@(#)$Id: getopt.c,v 2.1 88/09/15 21:07:32 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.1 $   $State: Exp $
X *
X *******************************************************************************
X * Bug reports, patches, comments, suggetions should be sent to:
X *
X *	Eric D. Christensen  -  edc@altnet.ALTOS.COM 
X *				uunet!altnet!edc
X *
X *******************************************************************************
X * $Log:	getopt.c,v $
X * Revision 2.1  88/09/15  21:07:32  syd
X * checked in with -k by syd at 88.09.15.21.07.32.
X * 
X * Revision 2.1  88/07/21  10:01:34  edc
X * Final hacks and cleanup to the 2.1 alpha test release
X * 
X * Revision 2.0  88/06/27  16:54:08  edc
X * The original 2.0 gamma sources as leaked from HP
X * 
X *
X *
X ******************************************************************************/
X
X/*LINTLIBRARY*/
X#define NULL	0
X#define EOF	(-1)
X#define ERR(s, c)	if(opterr){\
X	extern int strlen(), write();\
X	char errbuf[2];\
X	errbuf[0] = c; errbuf[1] = '\n';\
X	(void) write(2, argv[0], (unsigned)strlen(argv[0]));\
X	(void) write(2, s, (unsigned)strlen(s));\
X	(void) write(2, errbuf, 2);}
X
Xextern int strcmp();
Xextern char *index();
X
Xint	opterr = 1;
Xint	optind = 1;
Xint	optopt;
Xchar	*optarg;
X
Xint
Xgetopt(argc, argv, opts)
Xint	argc;
Xchar	**argv, *opts;
X{
X	static int sp = 1;
X	register int c;
X	register char *cp;
X
X	if(sp == 1)
X		if(optind >= argc ||
X		   argv[optind][0] != '-' || argv[optind][1] == '\0')
X			return(EOF);
X		else if(strcmp(argv[optind], "--") == NULL) {
X			optind++;
X			return(EOF);
X		}
X	optopt = c = argv[optind][sp];
X	if(c == ':' || (cp=index(opts, c)) == NULL) {
X		ERR(": illegal option -- ", c);
X		if(argv[optind][++sp] == '\0') {
X			optind++;
X			sp = 1;
X		}
X		return('?');
X	}
X	if(*++cp == ':') {
X		if(argv[optind][sp+1] != '\0')
X			optarg = &argv[optind++][sp+1];
X		else if(++optind >= argc) {
X			ERR(": option requires an argument -- ", c);
X			sp = 1;
X			return('?');
X		} else
X			optarg = argv[optind++];
X		sp = 1;
X	} else {
X		if(argv[optind][++sp] == '\0') {
X			sp = 1;
X			optind++;
X		}
X		optarg = NULL;
X	}
X	return(c);
X}
X
SHAR_EOF
chmod 0444 utils/getopt.c || echo "restore of utils/getopt.c fails"
echo "x - extracting utils/listalias.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > utils/listalias.c &&
X
Xstatic char rcsid[] = "@(#)$Id: listalias.c,v 2.1 88/09/15 21:07:33 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.1 $   $State: Exp $
X *
X * 			Copyright (c) 1986 Dave Taylor
X *******************************************************************************
X * Bug reports, patches, comments, suggetions should be sent to:
X *
X *	Eric D. Christensen  -  edc@altnet.ALTOS.COM 
X *				uunet!altnet!edc
X *
X *******************************************************************************
X * $Log:	listalias.c,v $
X * Revision 2.1  88/09/15  21:07:33  syd
X * checked in with -k by syd at 88.09.15.21.07.33.
X * 
X * Revision 2.1  88/07/21  10:01:36  edc
X * Final hacks and cleanup to the 2.1 alpha test release
X * 
X * Revision 2.0  88/06/27  16:54:09  edc
X * The original 2.0 gamma sources as leaked from HP
X * 
X *
X *
X ******************************************************************************/
X
X/** Program that lists all the available aliases.  This one uses the pipe 
X    command, feeding the stuff to egrep then sort, or just sort.
X
X**/
X
X#include <stdio.h>
X#include <fcntl.h>
X
X#include "defs.h"
X#include "sysdefs.h"
X
X#ifdef BSD
X  FILE *popen();
X#endif
X
Xchar *getenv();
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	FILE *datafile, *fd_pipe;
X	struct alias_rec hash_record;
X	int hashfile, count = 0;
X	char buffer[LONG_SLEN], fd_hash[SLEN], 
X	     fd_data[SLEN], *home;
X
X	if (argc > 2) {
X	  printf("Usage: listalias <optional-regular-expression>\n");
X	  exit(1);
X	}
X
X	home = getenv("HOME");
X
X	sprintf(fd_hash, "%s/%s", home, ALIAS_HASH);
X	sprintf(fd_data, "%s/%s", home, ALIAS_DATA);
X
X	if (argc > 1)
X	  sprintf(buffer, "egrep \"%s\" | sort", argv[1]);
X	else
X	  sprintf(buffer, "sort");
X
X	if ((fd_pipe = popen(buffer, "w")) == NULL) {
X	  if (argc > 1) 
X	    printf("cannot open pipe to egrep program for expressions!\n");
X	  fd_pipe = stdout;
X	}
X
X	do {
X
X	  if ((hashfile = open(fd_hash, O_RDONLY)) > 0) {
X	    if ((datafile = fopen(fd_data, "r")) == NULL) {
X	      printf("Opened %s hash file, but couldn't open data file!\n",
X		       count? "system" : "user");
X	      goto next_file;
X	    }
X	
X	    /** Otherwise let us continue... **/
X
X	    while (read(hashfile, &hash_record, sizeof (hash_record)) != 0) {
X	      if (strlen(hash_record.name) > 0) {
X	        fseek(datafile, hash_record.byte, 0L);
X	        fgets(buffer, LONG_SLEN, datafile);
X	        fprintf(fd_pipe, "%-15s  %s", hash_record.name, buffer);
X	      }
X	    }
X	  }
X
Xnext_file: strcpy(fd_hash, system_hash_file);
X	   strcpy(fd_data, system_data_file);
X
X	} while (++count < 2);
X
X	pclose(fd_pipe);
X
X	exit(0);
X}
SHAR_EOF
chmod 0444 utils/listalias.c || echo "restore of utils/listalias.c fails"
echo "x - extracting utils/mailrc.awk (Text)"
sed 's/^X//' << 'SHAR_EOF' > utils/mailrc.awk &&
X#
X# @(#)$Id: mailrc.awk,v 2.1 88/09/15 21:08:13 syd Exp $
X#
X# $Log:	mailrc.awk,v $
X# Revision 2.1  88/09/15  21:08:13  syd
X# Initial 2.1 Release
X# 
X# Revision 2.0  88/06/27  16:54:15  edc
X# The original 2.0 gamma sources as leaked from HP
X# 
X#
X#
X
X
XBEGIN { 
X	print "# MSG alias_text file, from a .mailrc file..." 
X	print ""
X      }
X
Xnext_line == 1 { 
X
X	next_line = 0;
X        group = ""
X	for (i = 1; i <= NF; i++) {
X	  if (i == NF && $i == "\\") sep = ""
X	  else                       sep = ", "
X	
X	  if ($i == "\\") {
X	    group = sprintf("%s,", group)
X	    next_line = 1;
X	  }
X	  else if (length(group) > 0)
X	    group = sprintf("%s%s%s", group, sep, $i);
X	  else
X	    group = $i;
X	  }
X	  print "\t" group
X
X	}
X
X$1 ~ /[Aa]lias|[Gg]roup/ { 
X
X	if ( NF == 3)
X	  print $2 " : user alias : " $3;
X	else {
X	  group = ""
X	  for (i = 3; i <= NF; i++) {
X	    if (i == NF && $i == "\\") sep = ""
X	    else        sep = ", "
X	
X	    if ($i == "\\") {
X 	      group = sprintf("%s,", group)
X 	      next_line = 1;
X	    }
X	    else if (length(group) > 0) 
X 	      group = sprintf("%s%s%s", group, sep, $i);
X	    else
X 	      group = $i;
X	    }
X	    print $2 " : group alias : " group;
X	  }
X 	}
SHAR_EOF
chmod 0444 utils/mailrc.awk || echo "restore of utils/mailrc.awk fails"
echo "x - extracting utils/newalias.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > utils/newalias.c &&
X
Xstatic char rcsid[] = "@(#)$Id: newalias.c,v 2.2 88/09/15 21:07:34 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.2 $   $State: Exp $
X *
X * 			Copyright (c) 1986 Dave Taylor
X *******************************************************************************
X * Bug reports, patches, comments, suggetions should be sent to:
X *
X *	Eric D. Christensen  -  edc@altnet.ALTOS.COM 
X *				uunet!altnet!edc
X *
X *******************************************************************************
X * $Log:	newalias.c,v $
X * Revision 2.2  88/09/15  21:07:34  syd
X * checked in with -k by syd at 88.09.15.21.07.34.
X * 
X * Revision 2.2  88/07/21  10:01:38  edc
X * Final hacks and cleanup to the 2.1 alpha test release
X * 
X * Revision 2.1  88/06/28  12:59:44  edc
X * Added code to support systems with no mkdir() call available. This code
X * is used if NOMKDIR is defined in sysdefs.h. (Configure.sh checks this
X * out for us.)
X * 
X * Revision 2.0  88/06/27  16:54:10  edc
X * The original 2.0 gamma sources as leaked from HP
X * 
X *
X *
X ******************************************************************************/
X
X/** Install a new set of aliases for the 'Elm' mailer. 
X
X	If invoked with a specific filename, it assumes that
X  it is working with an individual users alias tables, and
X  generates the .alias.hash and .alias.data files in their
X  home directory.
X	If, however, it is invoked with no arguments, then
X  it assumes that the user is updating the system alias
X  file and uses the defaults for everything.
X
X  The format for the input file is;
X    alias1, alias2, ... = username = address
Xor  alias1, alias2, ... = groupname= member, member, member, ...
X                                     member, member, member, ...
X
X  "-q" flag added: 6/17/86
X  modified for X.400 support: 21-09-87 GND
X**/
X
X#ifdef BSD
X#  include <sys/file.h>
X#else
X#  include <fcntl.h>
X#endif
X
X#include <stdio.h>
X#include "defs.h"
X#include "sysdefs.h"		/* ELM system definitions */
X
Xstatic char ident[] = { WHAT_STRING };
X
X#define group(string)		(strpbrk(string,", ") != NULL)
X
Xstruct alias_rec
Xshash_table[MAX_SALIASES];	/* the actual hash table     */
X
Xstruct alias_rec
Xuhash_table[MAX_UALIASES];	/* the actual hash table     */
X
Xint  hash_table_loaded=0;	/* is system table actually loaded? */
X
Xint  buff_loaded;		/* for file input overlap... */
Xint  error= 0;			/* if errors, don't save!    */
Xint  is_system=0;		/* system file updating?     */
Xint  count=0;			/* how many aliases so far?  */
Xlong offset = 0L;		/* data file line offset!    */
Xchar home[SLEN];		/* the users home directory  */
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	FILE *in, *data;
X	char inputname[SLEN], hashname[SLEN], dataname[SLEN];
X	char buffer[LONG_STRING];
X	int  hash, count = 0, owner, quiet = 0;
X
X	if (argc != 1)
X	  if (strcmp(argv[1], "-q") == 0)
X	    quiet++;
X	  else
X	    exit(printf("Usage: %s [-q]\n", argv[0]));
X
X	owner = getuid();
X
X	if (owner == 0 && ! quiet) {	/* being run by root! */
X	  printf("Would you like to update the system aliases? (y/n)");
X	  gets(buffer);
X	  if (buffer[0] == 'y' || buffer[0] == 'Y') {
X	    printf("Updating the system alias file...\n");
X
X	    strcpy(inputname, system_text_file);
X	    strcpy(hashname,  system_hash_file);
X	    strcpy(dataname,  system_data_file);
X	    is_system++;
X	    init_table(shash_table, MAX_SALIASES); 
X	  }
X	  else 
X	    printf("Updating your personal alias file...\n");
X	}
X	
X	if (! is_system) {
X	  if (strcpy(home, getenv("HOME")) == NULL)
X	    exit(printf("I'm confused - no HOME variable in environment!\n"));
X
X	  sprintf(inputname, "%s/%s", home, ALIAS_TEXT);
X	  sprintf(hashname,  "%s/%s", home, ALIAS_HASH); 
X	  sprintf(dataname,  "%s/%s", home, ALIAS_DATA); 
X
X	  init_table(uhash_table, MAX_UALIASES); 
X
X	  read_in_system(shash_table, sizeof shash_table);
X	}
X
X	if ((in = fopen(inputname,"r")) == NULL) {
X	  /** let's see if they have the files in the old place... **/
X	  sprintf(buffer, "%s/.alias_text", home);
X	  if (access(buffer, ACCESS_EXISTS) != -1) {
X	    update_alias_file_locations();
X	    in = fopen(inputname, "r");
X	  }
X	  else {
X	    printf("Couldn't open %s for input!\n", inputname);
X	    exit(1);
X	  }
X	}
X
X	if ((hash = open(hashname, O_WRONLY | O_CREAT, 0644)) == -1)
X	  exit(printf("Couldn't open %s for output!\n", hashname));
X
X	if ((data = fopen(dataname,"w")) == NULL)
X	  exit(printf("Couldn't open %s for output!\n", dataname));
X
X	buff_loaded = 0; 	/* file buffer empty right now! */
X
X	while (get_alias(in, buffer) != -1) {
X	  if (is_system)
X	    put_alias(data, buffer, shash_table, MAX_SALIASES);	
X	  else
X	    put_alias(data, buffer, uhash_table, MAX_UALIASES);	
X	  count++;
X	}
X
X	if (error) {
X	  printf("\n** Not saving tables!  Please fix and re-run %s!\n",
X		 argv[0]);
X	  exit(1);
X	}
X	else {
X	  if (is_system)
X	    write(hash, shash_table, sizeof shash_table);
X	  else
X	    write(hash, uhash_table, sizeof uhash_table);
X
X	  close(hash);
X	  fclose(data);
X	  close(in);
X	
X	  printf("Processed %d aliases\n", count);
X	  exit(0);
X	}
X}
X
Xint
Xget_alias(file, buffer)
XFILE *file;
Xchar *buffer;
X{
X	/* load buffer with the next complete alias from the file.
X	   (this can include reading in multiple lines and appending
X	   them all together!)  Returns EOF after last entry in file.
X	
X	Lines that start with '#' are assumed to be comments and are
X 	ignored.  White space as the first field of a line is taken
X	to indicate that this line is a continuation of the previous. */
X
X	static char mybuffer[SLEN];
X	int    done = 0, first_read = 1;
X
X	/** get the first line of the entry... **/
X
X	buffer[0] = '\0';			/* zero out line */
X
X	do {
X	  if (get_line(file, mybuffer, first_read) == -1) 
X	    return(-1);
X	  first_read = 0;
X	  if (mybuffer[0] != '#')
X	    strcpy(buffer, mybuffer);
X	} while (strlen(buffer) == 0);	
X
X	/** now read in the rest (if there is any!) **/
X
X	do {
X	  if (get_line(file, mybuffer, first_read) == -1) {
X	    buff_loaded = 0;	/* force a read next pass! */
X	    return(0);	/* okay. let's just hand 'buffer' back! */
X	  }
X	  done = (! whitespace(mybuffer[0]));
X	  if (! done)
X	    strcat(buffer, mybuffer);
X	  done = (done && mybuffer[0] != '#');
X	} while (! done);
X	
X	return(0);	/* no sweat! */
X}
X
Xput_alias(data, buffer, table, size)
XFILE *data;
Xchar *buffer;
Xstruct alias_rec table[];
Xint  size;
X{
X	/** break buffer down into three pieces: aliases, comment, and address.
X	    Make the appropriate entries in the table (size) 
X	**/
X
X	char aliases[LONG_STRING], address[LONG_STRING];
X	char comment[LONG_STRING];
X	int  first, last, i = 0, j = 0;
X
X	remove_all(' ', TAB, buffer);
X
X	for (i=0; buffer[i] != '=' && i < LONG_STRING; i++)
X	  aliases[i] = buffer[i];
X	aliases[i] = '\0';
X
X	for (i=strlen(buffer)-1; buffer[i] != '=' && i > 0; i--)
X	  address[j++] = buffer[i];
X	address[j] = '\0';
X
X	comment[0] = '\0';	/* default to nothing at all... */
X
X	if ((first=strlen(aliases)+1) < (last=(strlen(buffer) - j))) {
X	  extract_comment(comment, buffer, first, last); 
X	}
X
X	reverse(address);
X
X	add_to_table(data, aliases, comment, address, table, size);
X}
X
Xint
Xget_line(file, buffer, first_line)
XFILE *file;
Xchar *buffer;
Xint  first_line;
X{
X	/** read line from file.  If first_line and buff_loaded, 
X	    then just return! **/
X
X	int stat;
X
X	if (first_line && buff_loaded) {
X	  buff_loaded = 1;
X	  return(0);
X	}
X
X	buff_loaded = 1;	/* we're going to get SOMETHING in the buffer */
X
X	stat = fgets(buffer, SLEN, file) == NULL ? -1 : 0;
X
X	if (stat != -1)
X	  no_ret(buffer);
X
X	return(stat);
X}
X
Xreverse(string)
Xchar *string;
X{
X	/** reverse the order of the characters in string... 
X	    uses a bubble-sort type of algorithm!                 **/
X	
X	register int f, l;
X	char     c;
X	
X	f = 0;
X	l = strlen(string) - 1;
X	
X	while (f < l) {
X	  c = string[f];
X 	  string[f] = string[l];
X	  string[l] = c;
X	  f++;
X	  l--;
X	}
X}
X
Xadd_to_table(data, aliases, comment, address, table, size)
XFILE *data;
Xchar *aliases, *comment, *address;
Xstruct alias_rec table[];
Xint  size;
X{
X	/** add address + comment to datafile, incrementing offset count 
X	    (bytes), then for each alias in the aliases string, add to the
X	    hash table, with the associated pointer value! **/
X
X	static char buf[SLEN], *word;
X	long additive = 1L;
X
X	word = buf;	/* use the allocated space! */
X
X	if (group(address)) {
X	  check_group(address, aliases);
X	  if (error) return;	/* don't do work if we aren't to save it! */
X	  fprintf(data, "!%s\n", address);
X	  additive = 2L;
X	}
X	else {
X	  if (error) return;	/* don't do work if we aren't to save it! */
X	  if (strlen(comment) > 0) {
X	    fprintf(data, "%s (%s)\n", address, comment);
X	    additive = (long) (strlen(comment) + 4);
X	  }
X	  else
X	    fprintf(data, "%s\n", address, comment);
X	}
X
X	while ((word = (char *) strtok(aliases,", ")) != NULL) {
X	  add_to_hash_table(word, offset, table, size);
X	  aliases = NULL;	/* let's get ALL entries via 'strtok' */
X	  count++;
X	}
X
X	if ( is_system ? count > MAX_SALIASES-35 : count > MAX_UALIASES-21) {
X	  printf("** Too many aliases in file! **\n");
X	  error++;
X	}
X
X	offset = (offset + (long) strlen(address) + additive);
X}	
X
Xremove_all(c1, c2, string)
Xchar c1, c2, *string;
X{
X	/* Remove all occurances of character 'c1' or 'c2' from the string.
X	   Hacked (literally) to NOT remove ANY characters from within the
X	   equals fields.  This will only be used if the line contains TWO
X	   equalss (and comments with equalss in them are the kiss of death!)
X	 */
X
X	char buffer[LONG_STRING];
X	register int i = 0, j = 0, first_equals = -1, last_equals = -1;
X	
X	for (i = 0; string[i] != '\0' && i < LONG_STRING; i++) {
X	  if (string[i] != c1 && string[i] != c2)
X	    buffer[j++] = string[i];
X
X	  if (first_equals == -1 && string[i] == '=') {
X	    first_equals = i;
X	    for (last_equals=strlen(string);string[last_equals] != '='; 
X		last_equals--) ;
X	  }
X	  else if (i > first_equals && i < last_equals)
X	   if (string[i] == c1 || string[i] == c2)
X	     buffer[j++] = string[i];
X	}
X	
X	buffer[j] = '\0';
X	strcpy(string, buffer);
X}
X
Xadd_to_hash_table(word, offset, table, size)
Xchar *word;
Xlong  offset;
Xstruct alias_rec table[];
Xint   size;
X{
X	/** add word and offset to current hash table. **/
X	register int loc;
X	
X	if (strlen(word) > 20)
X	  exit(printf("Bad alias name: %s.  Too long.\n", word));
X
X	loc = hash_it(word, size);
X
X	while (table[loc].name[0] != '\0' && strcmp(table[loc].name, word) != 0)
X	  loc = loc + 1 % size; 
X
X	if (table[loc].name[0] == '\0') {
X	  strcpy(table[loc].name, word);
X	  table[loc].byte = offset;
X	}
X	else 
X	  printf("** Duplicate alias '%s' in file.  Multiples ignored.\n",
X	         word);
X}
X
Xint
Xhash_it(string, table_size)
Xchar *string;
X{
X	/** compute the hash function of the string, returning
X	    it (mod table_size) **/
X
X	register int i, sum = 0;
X	
X	for (i=0; string[i] != '\0'; i++)
X	  sum += (int) string[i];
X
X	return(sum % table_size);
X}
X
Xinit_table(table, size)
Xstruct alias_rec table[];
Xint size;
X{
X	/** initialize hash table! **/
X
X	register int i;
X
X	for (i=0; i < size; i++)
X	  table[i].name[0] = '\0';
X}
X
Xread_in_system(table, size)
Xstruct alias_rec table[];
Xint size;
X{
X	/** read in the system hash table...to check for group aliases
X	    from the user alias file (to ensure that there are no names
X	    in the user group files that are not purely contained within
X	    either alias table) **/
X	
X	int  fd;
X	char fname[SLEN];
X
X	sprintf(fname, "%s/%s", mailhome, ALIAS_HASH);
X
X	if ((fd = open(fname, O_RDONLY)) == -1)
X	  return;	/* no sweat: flag 'hash_table_loaded' not set! */
X
X	(void) read(fd, table, size);
X	close(fd);
X	hash_table_loaded++;
X}
X	
Xcheck_group(names, groupname)
Xchar *names, *groupname;
X{
X	/** one by one make sure each name in the group is defined
X	    in either the system alias file or the user alias file.
X	    This search is linearly dependent, so all group aliases
X	    in the source file should appear LAST, after all the user
X	    aliases! **/
X
X	char *word, *bufptr, buffer[LONG_STRING];
X
X	strcpy(buffer, names);
X	bufptr = (char *) buffer;
X
X	while ((word = (char *) strtok(bufptr,", ")) != NULL) {
X	  if (! can_find(word)) 
X	    if (! valid_name(word)) {
X	      error++;
X	      printf("** Alias %s in group %s is bad!\n", word, groupname);
X	    }
X	  bufptr = NULL;
X	}
X}
X
Xint
Xcan_find(name)
Xchar *name;
X{	
X	/** find name in either hash table...use 'is_system' variable to
X	    determine if we should look in both or just system....    **/
X
X	register int loc;
X	
X	if (strlen(name) > 20) {
X	  error++;
X	  printf("** Bad alias name: %s.  Too long.\n", name);
X	  return(1);	/* fake out: don't want 2 error messages! */
X	}
X
X	/** system alias table... **/
X	if (hash_table_loaded || is_system) {
X	  loc = hash_it(name, MAX_SALIASES);
X
X	  while (strcmp(name, shash_table[loc].name) != 0 && 
X                 shash_table[loc].name[0] != '\0')
X	    loc = (loc + 1) % MAX_SALIASES; 
X  
X	  if (strcmp(name, shash_table[loc].name) == 0)
X	    return(1);	/* found it! */
X	}
X
X	if (! is_system) {	/* okay! Let's check the user alias file! */
X	  loc = hash_it(name, MAX_UALIASES);
X
X	  while (strcmp(name, uhash_table[loc].name) != 0 && 
X                 uhash_table[loc].name[0] != '\0')
X	    loc = (loc + 1) % MAX_UALIASES; 
X
X	  if (strcmp(name, uhash_table[loc].name) == 0)
X	    return(1);	/* found it! */
X	}
X
X	return(0);
X}
X
Xextract_comment(comment, buffer, first, last)
Xchar *comment, *buffer;
Xint first, last;
X{
X	/** Buffer contains a comment, located between the first and last
X	    values.  Copy that into 'comment', but remove leading and
X	    trailing white space.  Note also that it doesn't copy past
X	    a comma, so `unpublishable' comments can be of the form;
X		dave: Dave Taylor, HP Labs : taylor@hplabs
X	    and the output will be "taylor@hplabs (Dave Taylor)".
X	**/
X
X	register int loc = 0; 
X
X	/** first off, skip the LEADING white space... **/
X
X	while (whitespace(buffer[first])) first++;
X	
X	/** now let's backup the 'last' value until we hit a non-whitespace **/
X
X	last -= 2;	/* starts at ch AFTER equals.. */
X	while (whitespace(buffer[last])) last--;
X
X	/** now a final check to make sure we're still talking about a 
X	    reasonable string (rather than a "joe :: joe@dec" type string) **/
X
X	if (first < last) {
X	  /* one more check - let's find the comma, if present... */
X	  for (loc=first; loc < last; loc++)
X	    if (buffer[loc] == ',') {
X	      last = loc-1;
X	      break;
X	  }
X	  loc = 0;
X	  while (first <= last)
X	    comment[loc++] = buffer[first++];
X	  comment[loc] = '\0';
X	}
X}
X
Xupdate_alias_file_locations()
X{
X	/** a short-term routine to ensure that the data files are
X	    moved into the correct directory... **/
X
X	char source[SLEN], dest[SLEN];
X
X	/** first let's create the directory if it ain't there... **/
X
X	sprintf(source, "%s/.elm", home);
X
X	/** Some systems don't have a mkdir call - how inconvienient! **/
X#ifdef NOMKDIR
X	system("mkdir $HOME/.elm");
X	system("chmod 700 $HOME/.elm");
X#else
X	(void) mkdir(source, 0700);
X#endif NOMKDIR
X
X	/** now *link* the files... **/
X
X	sprintf(source, "%s/.alias_text", home);
X	sprintf(dest,   "%s/%s",          home, ALIAS_TEXT);
X	link(source, dest);
X
X	sprintf(source, "%s/.alias_hash", home);
X	sprintf(dest,   "%s/%s",          home, ALIAS_HASH);
X	link(source, dest);
X
X	sprintf(source, "%s/.alias_data", home);
X	sprintf(dest,   "%s/%s",          home, ALIAS_DATA);
X	link(source, dest);
X
X	printf("\n*** Moved all data files into %s/.elm directory ***\n\n",
X		home);
X}
SHAR_EOF
chmod 0444 utils/newalias.c || echo "restore of utils/newalias.c fails"
echo "x - extracting utils/newmail.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > utils/newmail.c &&
X
Xstatic char rcsid[] = "@(#)$Id: newmail.c,v 2.1 88/09/15 21:07:35 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.1 $   $State: Exp $
X *
X * 			Copyright (c) 1986 Dave Taylor
X *******************************************************************************
X * Bug reports, patches, comments, suggetions should be sent to:
X *
X *	Eric D. Christensen  -  edc@altnet.ALTOS.COM 
X *				uunet!altnet!edc
X *
X *******************************************************************************
X * $Log:	newmail.c,v $
X * Revision 2.1  88/09/15  21:07:35  syd
X * checked in with -k by syd at 88.09.15.21.07.35.
X * 
X * 88/09/01  Rob Bernardo <gatech!pbhyf.PacBell.COM!rob>
X *	The buffer that contains the prefix string of a file spec was
X *	undersized.
X *
X * 88/08/27 nicmad!brown (Mike Brown)
X *	add extern int errno for BSD ifdef
X *
X * Revision 2.1  88/07/21  10:01:54  edc
X * Final hacks and cleanup to the 2.1 alpha test release
X * 
X * Revision 2.0  88/06/27  16:54:11  edc
X * The original 2.0 gamma sources as leaked from HP
X * 
X *
X *
X ******************************************************************************/
X
X/** This is actually two programs folded into one - 'newmail()' and
X    'wnewmail()'.  They perform essentially the same function, to
X    monitor the mail arriving in a set of/a mailbox or folder, but
X    newmail is designed to run in background on a terminal, and
X    wnewmail is designed to have a window of its own to run in.
X
X    The main difference is that wnewmail checks for mail more often.
X
X    The usage parameters are:
X
X	-i <interval>  		how often to check for mail
X				(default: 60 secs if newmail,
X					  10 secs if wnewmail)
X
X	<filename>		name of a folder to monitor
X				(can prefix with '+'/'=', or can
X			 	default to the incoming mailbox)
X
X	<filename>=prefix	file to monitor, output with specified
X				prefix when mail arrives.
X
X    If we're monitoring more than one mailbox the program will prefix
X    each line output (if 'newmail') or each cluster of mail (if 'wnewmail')
X    with the basename of the folder the mail has arrived in.  In the 
X    interest of exhaustive functionality, you can also use the "=prefix"
X    suffix (eh?) to specify your own strings to prefix messages with.
X
X    The output format is either:
X
X	  newmail:
X	     >> New mail from <user> - <subject>
X	     >> Priority mail from <user> - <subject>
X
X	     >> <folder>: from <user> - <subject>
X	     >> <folder>: Priority from <user> - <subject>
X
X	  wnewmail:
X	     <user> - <subject>
X	     Priority: <user> - <subject>
X
X	     <folder>: <user> - <subject>
X	     <folder>: Priority: <user> - <subject>\fR
X
X**/
X
X#include <stdio.h>
X#include <errno.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X
X#include "defs.h"
X
X#ifdef AUTO_BACKGROUND
X#include <signal.h>	/* background jobs ignore some signals... */
X#endif
X
Xstatic char ident[] = { WHAT_STRING };
X
X#define LINEFEED		(char) 10
X#define BEGINNING		0			/* seek fseek(3S) */
X#define DEFAULT_INTERVAL	60
X
X#define MAX_FOLDERS		25		/* max we can keep track of */
X
X#define NO_SUBJECT	"(No Subject Specified)"
X
X#define metachar(c)	(c == '+' || c == '=' || c == '%')
X
Xchar  *getusername();
Xlong  bytes();
X
Xstruct folder_struct {
X	  char		foldername[SLEN];
X	  char		prefix[SHORT_SLEN];
X	  FILE 		*fd;
X	  long		filesize;
X       } folders[MAX_FOLDERS];
X
Xint  interval_time;		/* how long to sleep between checks */
X     debug = 0,			/* include verbose debug output?    */
X     in_window = 0;		/* are we running as 'wnewmail'?    */
X     total_folders = 0,		/* # of folders we're monitoring    */
X     current_folder = 0;	/* struct pointer for looping       */
X
X#ifdef BSD
Xextern int errno;
X#endif
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	extern char *optarg;
X	extern int   optind, opterr;
X	char *ptr;
X	int c, i, done;
X	long lastsize,
X	     newsize;			/* file size for comparison..      */
X
X	interval_time = DEFAULT_INTERVAL;
X	opterr = 0;
X
X	/** let's see if the first character of the basename of the
X	    command invoked is a 'w' (e.g. have we been called as
X	    'wnewmail' rather than just 'newmail'?)
X	**/
X
X	for (i=0, ptr=(argv[0] + strlen(argv[0])-1); !i && ptr > argv[0]; ptr--)
X	  if (*ptr == '/') {
X	    in_window = (*(ptr+1) == 'w');
X	    i++;
X	  }
X
X	if (ptr == argv[0] && i == 0 && argv[0][0] == 'w')
X	  in_window = 1;
X
X	while ((c = getopt(argc, argv, "di:w")) != EOF) {
X	  switch (c) {
X	    case 'd' : debug++;					break;
X	    case 'i' : interval_time = atoi(optarg);		break;
X	    case 'w' : in_window = 1;				break;
X	    default  : usage();					exit(1);
X	 }
X	}
X
X	if (interval_time < 10)
X	  fprintf(stderr,
X"Warning: interval set to %d second%s.  I hope you know what you're doing!\n",
X	  interval_time, interval_time == 1 ? "" : "s");
X
X	/* now let's parse the foldernames, if any are given */
X
X	if (optind >= argc) /* get default */
X	  add_default_folder();
X	else {
X	  while (optind < argc)
X	    add_folder(argv[optind++]);
X	  pad_prefixes();			/* for nice output...*/
X	}
X
X#ifdef AUTO_BACKGROUND
X	if (! in_window) {
X	  if (fork())	    /* automatically puts this task in background! */
X	    exit(0);
X
X	  signal(SIGINT, SIG_IGN);
X	  signal(SIGQUIT, SIG_IGN);
X	}
X#endif
X
X	if (in_window && ! debug)
X	  printf("Incoming mail:\n");
X
X	while (1) {
X	
X#ifndef AUTO_BACKGROUND		/* won't work if we're nested this deep! */
X	  if (getppid() == 1) 	/* we've lost our shell! */
X	    exit();
X#endif
X	  if (! isatty(1))	/* we're not sending output to a tty any more */
X	     exit();
X
X	  if (debug) printf("\n----\n");
X
X	  for (i = 0; i < total_folders; i++) {
X
X	    if (debug)
X	      printf("[checking folder #%d: %s]\n", i, folders[i].foldername);
X
X	    if (folders[i].fd == (FILE *) NULL) {
X
X	      if ((folders[i].fd = fopen(folders[i].foldername,"r")) == NULL)
X	        if (errno == EACCES) {
X		   fprintf(stderr, "\nPermission to monitor %s denied!\n\n",
X			 folders[i].foldername);
X	           sleep(5);
X	           exit(1);
X	        }
X	    }
X
X	    if ((newsize = bytes(folders[i].foldername)) > 
X	        folders[i].filesize) {	/* new mail has arrived! */
X
X	      if (debug)
X	        printf(
X		   "\tnew mail has arrived!  old size = %ld, new size=%ld\n",
X		   folders[i].filesize, newsize);
X
X	      /* skip what we've read already... */
X
X	      if (fseek(folders[i].fd, folders[i].filesize, 
X			BEGINNING) != 0)
X	        perror("fseek()");
X
X	      folders[i].filesize = newsize;
X
X	      if (in_window)
X	        putchar((char) 007);		/* BEEP!*/
X	      else
X	        printf("\n\r");	/* blank lines surrounding message */
X
X	      read_headers(i);		/* read and display new mail! */
X
X	      if (! in_window)
X	        printf("\n\r");
X	    }
X	    else if (newsize != folders[i].filesize) {	/* file SHRUNK! */
X
X	      folders[i].filesize = bytes(folders[i].foldername);
X	      (void) fclose(folders[i].fd);	/* close it and ...         */
X	      folders[i].fd = (FILE *) NULL;	/* let's reopen the file    */
X
X	      lastsize = folders[i].filesize;
X	      done     = 0;
X
X	      while (! done) {
X	        sleep(0);	/* basically gives up our CPU slice */
X	        newsize = bytes(folders[i].foldername);
X	        if (newsize != lastsize)
X	          lastsize = newsize;
X		else
X	          done++;
X	      } 
X	        
X	      folders[i].filesize = newsize;
X	    }
X	  }
X
X	  sleep(interval_time);
X	}
X}
X
Xint
Xread_headers(current_folder)
Xint current_folder;
X{
X	/** read the headers, output as found given current_folder,
X	    the prefix of that folder, and whether we're in a window
X	    or not.
X	**/
X
X	char buffer[LONG_SLEN], from_whom[SLEN], subject[SLEN];
X	register int subj = 0, in_header = 1, count = 0, priority=0;
X
X	while (fgets(buffer, LONG_SLEN, folders[current_folder].fd) != NULL) {
X	  if (first_word(buffer,"From ")) {
X	    if (real_from(buffer, from_whom)) {
X	      subj = 0;
X	      in_header = 1;
X	    }
X	  }
X	  else if (in_header) {
X	    if (first_word(buffer,">From")) 
X	      forwarded(buffer, from_whom); /* return address */
X	    else if (first_word(buffer,"Subject:") ||
X		     first_word(buffer,"Re:")) {
X	      if (! subj++) {
X	        remove_first_word(buffer);
X		strcpy(subject, buffer);
X	      }
X	    }
X	    else if (first_word(buffer,"Priority:")) 
X	      priority++;
X	    else if (first_word(buffer,"From:")) 
X	      parse_arpa_from(buffer, from_whom);
X	    else if (buffer[0] == LINEFEED) {
X	      in_header = 0;	/* in body of message! */
X	      show_header(priority, from_whom, subject, current_folder);
X	      from_whom[0] = 0;
X	      subject[0] = 0;
X	      count++;
X	    }
X	  }
X	}
X	return(count);
X}
X
Xadd_folder(name)
Xchar *name;
X{
X	/* add the specified folder to the list of folders...ignore any
X	   problems we may having finding it (user could be monitoring
X	   a mailbox that doesn't currently exist, for example)
X	*/
X
X	char *cp, buf[SLEN];
X
X	if (current_folder > MAX_FOLDERS) {
X	  fprintf(stderr,
X              "Sorry, but I can only keep track of %d folders.\n", MAX_FOLDERS);
X	  exit(1);
X	}
X
X	/* now let's rip off the suffix "=<string>" if it's there... */
X
X	for (cp = name + strlen(name); cp > name+1 && *cp != '=' ; cp--)
X	  /* just keep stepping backwards */ ;
X
X	/* if *cp isn't pointing to the first character we'e got something! */
X
X	if (cp > name+1) {
X
X	  *cp++ = '\0';		/* null terminate the filename & get prefix */
X
X	  if (metachar(*cp)) cp++;
X
X	  strcpy(folders[current_folder].prefix, cp);
X	}
X	else {			/* nope, let's get the basename of the file */
X	  for (cp = name + strlen(name); cp > name && *cp != '/'; cp--)
X	    /* backing up a bit... */ ;
X
X	  if (metachar(*cp)) cp++;
X	  if (*cp == '/') cp++;
X
X	  strcpy(folders[current_folder].prefix, cp);
X	}
X
X	/* and next let's see what kind of weird prefix chars this user
X	   might be testing us with.  We can have '+'|'='|'%' to expand
X	   or a file located in the incoming mail dir...
X	*/
X
X	if (metachar(name[0]))
X	  expand_filename(name, folders[current_folder].foldername);
X	else if (access(name, 00) == -1) {
X	  /* let's try it in the mail home directory */
X	  sprintf(buf, "%s%s", mailhome, name);
X	  if (access(buf, 00) != -1) 		/* aha! */
X	    strcpy(folders[current_folder].foldername, buf);
X	  else
X	    strcpy(folders[current_folder].foldername, name);
X	}
X	else
X	  strcpy(folders[current_folder].foldername, name);
X
X	/* now let's try to actually open the file descriptor and grab
X	   a size... */
X
X	if ((folders[current_folder].fd = 
X	      fopen(folders[current_folder].foldername, "r")) == NULL)
X          if (errno == EACCES) {
X	    fprintf(stderr, "\nPermission to monitor \"%s\" denied!\n\n",
X			 folders[current_folder].foldername);
X	    exit(1);
X	  }
X
X	folders[current_folder].filesize = 
X	      bytes(folders[current_folder].foldername);
X
X	/* and finally let's output what we did */
X
X	if (debug)
X	  printf("folder %d: \"%s\" <%s> %s, size = %ld\n",
X	      current_folder,
X	      folders[current_folder].foldername,
X	      folders[current_folder].prefix,
X	      folders[current_folder].fd == NULL? "not found" : "opened",
X	      folders[current_folder].filesize);
X
X	/* and increment current-folder please! */
X
X	current_folder++;
X	total_folders++;
X}
X
Xadd_default_folder()
X{
X	/* this routine will add the users home mailbox as the folder
X	   to monitor.  Since there'll only be one folder we'll never
X	   prefix it either...
X	*/
X
X	sprintf(folders[0].foldername, "%s%s", mailhome, getusername());
X	
X	folders[0].fd       = fopen(folders[0].foldername, "r");
X	folders[0].filesize = bytes(folders[0].foldername);
X
X	if (debug)
X	  printf("default folder: \"%s\" <%s> %s, size = %ld\n",
X	      folders[0].foldername,
X	      folders[0].prefix,
X	      folders[0].fd == NULL? "not found" : "opened",
X	      folders[0].filesize);
X
X	total_folders = 1;
X}
X
Xint
Xreal_from(buffer, who)
Xchar *buffer, *who;
X{
X	/***** returns true iff 's' has the seven 'from' fields,
X	       initializing the who to the sender *****/
X
X	char junk[80];
X
X	junk[0] = '\0';
X	sscanf(buffer, "%*s %s %*s %*s %*s %*s %s",
X	            who, junk);
X	return(junk[0] != '\0');
X}
X
Xforwarded(buffer, who)
Xchar *buffer, *who;
X{
X	/** change 'from' and date fields to reflect the ORIGINATOR of 
X	    the message by iteratively parsing the >From fields... **/
X
X	char machine[80], buff[80];
X
X	machine[0] = '\0';
X	sscanf(buffer, "%*s %s %*s %*s %*s %*s %*s %*s %*s %s",
X	            who, machine);
X
X	if (machine[0] == '\0') /* try for srm address */
X	  sscanf(buffer, "%*s %s %*s %*s %*s %*s %*s %*s %s",
X	            who, machine);
X
X	if (machine[0] == '\0')
X	  sprintf(buff,"anonymous");
X	else
X	  sprintf(buff,"%s!%s", machine, who);
X
X	strncpy(who, buff, 80);
X}
X
X
Xremove_first_word(string)
Xchar *string;
X{	/** removes first word of string, ie up to first non-white space
X	    following a white space! **/
X
X	register int loc;
X
X	for (loc = 0; string[loc] != ' ' && string[loc] != '\0'; loc++) 
X	    ;
X
X	while (string[loc] == ' ' || string[loc] == '\t')
X	  loc++;
X	
X	move_left(string, loc);
X}
X
Xmove_left(string, chars)
Xchar string[];
Xint  chars;
X{
X	/** moves string chars characters to the left DESTRUCTIVELY **/
X
X	register int i;
X
X	chars--; /* index starting at zero! */
X
X	for (i=chars; string[i] != '\0' && string[i] != '\n'; i++)
X	  string[i-chars] = string[i];
X
X	string[i-chars] = '\0';
X}
X
Xshow_header(priority, from, subject, current_folder)
Xint   priority;
Xchar *from, *subject;
Xint   current_folder;
X{
X	/** output header in clean format, including abbreviation
X	    of return address if more than one machine name is
X	    contained within it! **/
X	char buffer[SLEN];
X	int  loc, i=0, exc=0;
X
X#ifdef PREFER_UUCP
X
X	if (chloc(from, '!') != -1 && in_string(from, BOGUS_INTERNET))
X	  from[strlen(from) - strlen(BOGUS_INTERNET)] = '\0';
X
X#endif
X
X	loc = strlen(from);
X
X	while (exc < 2 && loc > 0)
X	  if (from[--loc] == '!')
X	    exc++;
X
X	if (exc == 2) { /* lots of machine names!  Get last one */
X	  loc++;
X	  while (loc < strlen(from) && loc < SLEN)
X	    buffer[i++] = from[loc++];
X	  buffer[i] = '\0';
X	  strcpy(from, buffer);
X	}
X
X	if (strlen(subject) < 2)
X	  strcpy(subject, NO_SUBJECT);
X	
X	if (in_window)
X	  if (total_folders > 1)
X	    printf("%s: %s%s -- %s\n",
X		   folders[current_folder].prefix,
X		   priority? "Priority " : "", from, subject);
X	  else
X	    printf("%s%s -- %s\n",
X		   priority? "Priority " : "", from, subject);
X	else
X	  if (total_folders > 1)
X	    printf(">> %s: %sail from %s - %s\n\r", 
X		  folders[current_folder].prefix,
X		  priority? "Priority m" : "M", from, subject);
X	  else
X	    printf(">> %sail from %s - %s\n\r", 
X		  priority? "Priority m" : "M", from, subject);
X}	
X
Xparse_arpa_from(buffer, newfrom)
Xchar *buffer, *newfrom;
X{
X	/** try to parse the 'From:' line given... It can be in one of
X	    two formats:
X		From: Dave Taylor <hpcnou!dat>
X	    or  From: hpcnou!dat (Dave Taylor)
X	    Change 'newfrom' ONLY if sucessfully parsed this entry and
X	    the resulting name is non-null! 
X	**/
X
X	char temp_buffer[SLEN], *temp;
X	register int i, j = 0;
X
X	temp = (char *) temp_buffer;
X	temp[0] = '\0';
X
X	no_ret(buffer);		/* blow away '\n' char! */
X
X	if (lastch(buffer) == '>') {
X	  for (i=strlen("From: "); buffer[i] != '\0' && buffer[i] != '<' &&
SHAR_EOF
echo "End of part 21"
echo "File utils/newmail.c is continued in part 22"
echo "22" > s2_seq_.tmp
exit 0
-- 
=====================================================================
Sydney S. Weinstein, CDP, CCP                   Elm Coordinator
Datacomp Systems, Inc.				Voice: (215) 947-9900
{allegra,bellcore,bpa,vu-vlsi}!dsinc!syd	FAX:   (215) 938-0235