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

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

---- Cut Here and unpack ----
#!/bin/sh
# this is part 20 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file utils/Makefile.mt continued
#
CurArch=20
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/Makefile.mt"
sed 's/^X//' << 'SHAR_EOF' >> utils/Makefile.mt
X	-o ../bin/fastmail
X
X../bin/readmsg: readmsg.c ../src/getopt.o ../src/opt_utils.o ../src/string2.o
X	${CC} ${CFLAGS} ${DEFINE} readmsg.c ../src/getopt.o ../src/string2.o \
X	../src/opt_utils.o -o ../bin/readmsg
X
X../bin/arepdaemon: arepdaem.c
X	${CC} ${CFLAGS} ${DEFINE} arepdaem.c -o ../bin/arepdaemon
X
X../bin/autoreply: autoreply.c ../src/opt_utils.o
X	${CC} ${CFLAGS} ${DEFINE} autoreply.c ../src/opt_utils.o \
X	-o ../bin/autoreply
X
X../bin/printmail: Makefile
X	@echo ': Use /bin/sh'    	   > ../bin/printmail
X	@echo '# printmail: part of the Elm mail system' >> ../bin/printmail
X	@echo ' ' 			  >> ../bin/printmail
X	@echo 'if [ "$$1" = "-p" ]; then' >> ../bin/printmail
X	@echo '  flags="-p";shift'	  >> ../bin/printmail
X	@echo 'fi'		  	  >> ../bin/printmail
X	@echo ' ' 			  >> ../bin/printmail
X	@echo 'if [ "$$1" != "" ]; then'  >> ../bin/printmail
X	@echo '  if [ ! -r $$1 ]; then'   >> ../bin/printmail
X	@echo '    echo printmail: cannot open folder $$1' >> ../bin/printmail
X	@echo '    exit 1'		  >> ../bin/printmail
X	@echo '  else'			  >> ../bin/printmail
X	@echo '    flags="$$flags -f $$1"'>> ../bin/printmail
X	@echo '  fi'			  >> ../bin/printmail
X	@echo 'fi'			  >> ../bin/printmail
X	@echo ' ' 			  >> ../bin/printmail
X	@echo '# and now invoke readmsg'  >> ../bin/printmail
X	@echo 'exec readmsg $$flags \\*'  >> ../bin/printmail
X	@chmod +x ../bin/printmail
X
X../bin/checkalias: Makefile
X	@echo ': Use /bin/sh' 			> ../bin/checkalias
X	@echo '# checkalias: part of the Elm mail system' >> ../bin/checkalias
X	@echo ' ' 			  	>> ../bin/checkalias
X	@echo 'if [ "$$*" = "" ]; then' 	>> ../bin/checkalias
X	@echo '  echo Usage: checkalias alias \[alias ...\]' >>  \
X	      ../bin/checkalias
X	@echo '  exit 1' 			>> ../bin/checkalias
X	@echo 'fi' 				>> ../bin/checkalias
X	@echo ' '  				>> ../bin/checkalias
X	@echo 'exec elm -c $$*' 		>> ../bin/checkalias
X	@chmod +x ../bin/checkalias
X
X../bin/messages: Makefile
X	@echo ': Use /bin/sh' 				 > ../bin/messages
X	@echo '# messages: part of the Elm mail system' >> ../bin/messages
X	@echo ' ' 			  		>> ../bin/messages
X	@echo 'if [ "$$2" != "" ]; then' 		>> ../bin/messages
X	@echo '  echo Usage: messages \{folder-name\}'  >> ../bin/messages
X	@echo '  exit 1' 				>> ../bin/messages
X	@echo 'fi' 					>> ../bin/messages
X	@echo ' '  					>> ../bin/messages
X	@echo 'if [ "$$1" = "" ]; then' 		>> ../bin/messages
X	@echo '  fname=$$MAIL' 				>> ../bin/messages
X	@echo '  optional="in your mailbox"'  		>> ../bin/messages
X	@echo 'else'		 			>> ../bin/messages
X	@echo '  fname=$$1'				>> ../bin/messages
X	@echo '  optional="in folder $$1"' 		>> ../bin/messages
X	@echo 'fi'	       				>> ../bin/messages
X	@echo ' '					>> ../bin/messages
X	@echo 'if [ -f $$fname ]; then'			>> ../bin/messages
X	@echo '  mcount=`egrep "^From " $$fname | wc -l`' >> ../bin/messages
X	@echo 'else'					>> ../bin/messages
X	@echo '  exit 0'				>> ../bin/messages
X	@echo 'fi'					>> ../bin/messages
X	@echo ' '					>> ../bin/messages
X	@echo 'if [ $$mcount = 1 ];then'		>> ../bin/messages
X	@echo '  echo There is $$mcount message $$optional' >> ../bin/messages
X	@echo 'else'					>> ../bin/messages
X	@echo '  echo There are $$mcount messages $$optional' >> ../bin/messages
X	@echo 'fi'					>> ../bin/messages
X	@echo ' '					>> ../bin/messages
X	@echo 'exit $$mcount'				>> ../bin/messages
X	@chmod +x ../bin/messages
X
X../src/validname.o: ../src/validname.c ../hdrs/defs.h
X	@(cd ../src; ${CC} -c ${CFLAGS} ${DEFINE} validname.c; cd ../utils)
X
X../src/opt_utils.o: ../src/opt_utils.c ../hdrs/defs.h
X	@(cd ../src; ${CC} -c ${CFLAGS} ${DEFINE} opt_utils.c; cd ../utils)
X
X../src/getopt.o: ../src/getopt.c ../hdrs/defs.h
X	@(cd ../src; ${CC} -c ${CFLAGS} ${DEFINE} getopt.c; cd ../utils)
X
X../src/string2.o: ../src/string2.c ../hdrs/defs.h
X	@(cd ../src; ${CC} -c ${CFLAGS} ${DEFINE} string2.c; cd ../utils)
X
Xexpand.o: expand.c ../hdrs/defs.h
X	${CC} -c ${CFLAGS} ${DEFINE} expand.c
X
Xclean:
X	${RM} *.o ${OBJS} ../bin/utils
X
Xlint:
X	lint -p -I../hdrs *.c > LINT.OUT
SHAR_EOF
echo "File utils/Makefile.mt is complete"
chmod 0444 utils/Makefile.mt || echo "restore of utils/Makefile.mt fails"
echo "x - extracting utils/answer.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > utils/answer.c &&
X
Xstatic char rcsid[] = "@(#)$Id: answer.c,v 2.1 88/09/15 21:07:24 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:	answer.c,v $
X * Revision 2.1  88/09/15  21:07:24  syd
X * checked in with -k by syd at 88.09.15.21.07.24.
X * 
X * 88/08/27 David Klann <gatech!uwvax.cs.wisc.edu!m5r3!davek>
X *	fix path name to current path
X *
X * Revision 2.1  88/07/21  10:00:54  edc
X * Final hacks and cleanup to the 2.1 alpha test release
X * 
X * Revision 2.0  88/06/27  16:53:43  edc
X * The original 2.0 gamma sources as leaked from HP
X * 
X *
X *
X ******************************************************************************/
X
X/** This program is a phone message transcription system, and
X    is designed for secretaries and the like, to allow them to
X    painlessly generate electronic mail instead of paper forms.
X
X    Note: this program ONLY uses the local alias file, and does not
X	  even read in the system alias file at all.
X
X**/
X
X#include <stdio.h>
X#include <fcntl.h>
X#include <ctype.h>
X
X#include "defs.h"			/* ELM system definitions      */
X
X#define  ELM		"elm"		/* where the elm program lives */
X
X#define  answer_temp_file	"/tmp/answer."
X
Xstatic char ident[] = { WHAT_STRING };
X
Xstruct alias_rec user_hash_table  [MAX_UALIASES];
X
Xint user_data;		/* fileno of user data file   */
X
Xchar *expand_group(), *get_alias_address(), *get_token(), *strip_parens();
X
Xmain()
X{
X	FILE *fd;
X	char *address, buffer[LONG_STRING], tempfile[SLEN];
X	char  name[SLEN], user_name[SLEN];
X	int   msgnum = 0, eof;
X	
X	read_alias_files();
X
X	while (1) {
X	  if (msgnum > 9999) msgnum = 0;
X	
X	  printf("\n-------------------------------------------------------------------------------\n");
X
Xprompt:   printf("\nMessage to: ");
X	  if (gets(user_name) == NULL || user_name[0] == '\0')
X	    goto prompt;
X	  
X	  if ((strcmp(user_name,"quit") == 0) ||
X	      (strcmp(user_name,"exit") == 0) ||
X	      (strcmp(user_name,"done") == 0) ||
X	      (strcmp(user_name,"bye")  == 0))
X	     exit(0);
X
X	  if (translate(user_name, name) == 0)
X	    goto prompt;
X
X	  address = get_alias_address(name, 1, 0);
X
X	  printf("address '%s'\n", address);
X
X	  if (address == NULL || strlen(address) == 0) {
X	    printf("Sorry, could not find '%s' [%s] in list!\n", user_name, 
X		   name);
X	    goto prompt;
X	  }
X
X	  sprintf(tempfile, "%s%d", answer_temp_file, msgnum++);
X
X	  if ((fd = fopen(tempfile,"w")) == NULL)
X	    exit(printf("** Fatal Error: could not open %s to write\n",
X		 tempfile));
X
X
X	  printf("\nEnter message for %s ending with a blank line.\n\n", 
X		 user_name);
X
X	  fprintf(fd,"\n\n");
X
X	  do {
X	   printf("> ");
X	   if (! (eof = (gets(buffer, SLEN) == NULL))) 
X	     fprintf(fd, "%s\n", buffer);
X	  } while (! eof && strlen(buffer) > 0);
X	
X	  fclose(fd);
X 
X	  sprintf(buffer, 
X	     "((%s -s \"While You Were Out\" %s ; %s %s) & ) < %s > /dev/null",
X	     ELM, strip_parens(address), remove, tempfile, tempfile);
X
X	  system(buffer);
X	}
X}
X
Xint
Xtranslate(fullname, name)
Xchar *fullname, *name;
X{
X	/** translate fullname into name..
X	       'first last'  translated to first_initial - underline - last
X	       'initial last' translated to initial - underline - last
X	    Return 0 if error.
X	**/
X	register int i, lastname = 0;
X
X	for (i=0; i < strlen(fullname); i++) {
X
X	  if (isupper(fullname[i]))
X	     fullname[i] = tolower(fullname[i]);
X
X	  if (fullname[i] == ' ') 
X	    if (lastname) {
X	      printf(
X	      "** Can't have more than 'FirstName LastName' as address!\n");
X	      return(0);
X	    }
X	    else
X	      lastname = i+1;
X	
X	}
X
X	if (lastname) 
X	  sprintf(name, "%c_%s", fullname[0], (char *) fullname + lastname);
X	else
X	  strcpy(name, fullname);
X
X	return(1);
X}
X
X	    
Xread_alias_files()
X{
X	/** read the user alias file **/
X
X	char fname[SLEN];
X	int  hash;
X
X	sprintf(fname,  "%s/.elm/aliases.hash", getenv("HOME")); 
X
X	if ((hash = open(fname, O_RDONLY)) == -1) 
X	  exit(printf("** Fatal Error: Could not open %s!\n", fname));
X
X	read(hash, user_hash_table, sizeof user_hash_table);
X	close(hash);
X
X	sprintf(fname,  "%s/.elm/aliases.data", getenv("HOME")); 
X
X	if ((user_data = open(fname, O_RDONLY)) == -1) 
X	  return;
X}
X
Xchar *get_alias_address(name, mailing, depth)
Xchar *name;
Xint   mailing, depth;
X{
X	/** return the line from either datafile that corresponds 
X	    to the specified name.  If 'mailing' specified, then
X	    fully expand group names.  Returns NULL if not found.
X	    Depth is the nesting depth, and varies according to the
X	    nesting level of the routine.  **/
X
X	static char buffer[VERY_LONG_STRING];
X	int    loc;
X
X	if ((loc = find(name, user_hash_table, MAX_UALIASES)) >= 0) {
X	  lseek(user_data, user_hash_table[loc].byte, 0L);
X	  get_line(user_data, buffer);
X	  if (buffer[0] == '!' && mailing)
X	    return( (char *) expand_group(buffer, depth));
X	  else
X	    return( (char *) buffer);
X	}
X	
X	return( (char *) NULL);
X}
X
Xchar *expand_group(members, depth)
Xchar *members;
Xint   depth;
X{
X	/** given a group of names separated by commas, this routine
X	    will return a string that is the full addresses of each
X	    member separated by spaces.  Depth is the current recursion
X	    depth of the expansion (for the 'get_token' routine) **/
X
X	char   buffer[VERY_LONG_STRING];
X	char   buf[LONG_STRING], *word, *address, *bufptr;
X
X	strcpy(buf, members); 	/* parameter safety! */
X	buffer[0] = '\0';	/* nothing in yet!   */
X	bufptr = (char *) buf;	/* grab the address  */
X	depth++;		/* one more deeply into stack */
X
X	while ((word = (char *) get_token(bufptr, "!, ", depth)) != NULL) {
X	  if ((address = (char *) get_alias_address(word, 1, depth)) == NULL) {
X	    fprintf(stderr, "Alias %s not found for group expansion!", word);
X	    return( (char *) NULL);
X	  }
X	  else if (strcmp(buffer,address) != 0) {
X	    sprintf(buffer,"%s %s", buffer, address);
X	  }
X
X	  bufptr = NULL;
X	}
X
X	return( (char *) buffer);
X}
X
Xint
Xfind(word, table, size)
Xchar *word;
Xstruct alias_rec table[];
Xint size;
X{
X	/** find word and return loc, or -1 **/
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 (strcmp(word, table[loc].name) != 0) {
X	  if (table[loc].name[0] == '\0') 
X	    return(-1);
X	  loc = (loc + 1) % size; 
X	}
X
X	return(loc);
X}
X
Xint
Xhash_it(string, table_size)
Xchar *string;
Xint   table_size;
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
Xget_line(fd, buffer)
Xint fd;
Xchar *buffer;
X{
X	/* read from file fd.  End read upon reading either 
X	   EOF or '\n' character (this is where it differs 
X	   from a straight 'read' command!) */
X
X	register int i= 0;
X	char     ch;
X
X	while (read(fd, &ch, 1) > 0)
X	  if (ch == '\n' || ch == '\r') {
X	    buffer[i] = 0;
X	    return;
X	  }
X	  else
X	    buffer[i++] = ch;
X}
X
Xprint_long(buffer, init_len)
Xchar *buffer;
Xint   init_len;
X{
X	/** print buffer out, 80 characters (or less) per line, for
X	    as many lines as needed.  If 'init_len' is specified, 
X	    it is the length that the first line can be.
X	**/
X
X	register int i, loc=0, space, length; 
X
X	/* In general, go to 80 characters beyond current character
X	   being processed, and then work backwards until space found! */
X
X	length = init_len;
X
X	do {
X	  if (strlen(buffer) > loc + length) {
X	    space = loc + length;
X	    while (buffer[space] != ' ' && space > loc + 50) space--;
X	    for (i=loc;i <= space;i++)
X	      putchar(buffer[i]);
X	    putchar('\n');
X	    loc = space;
X	  }
X	  else {
X	    for (i=loc;i < strlen(buffer);i++)
X	      putchar(buffer[i]);
X	    putchar('\n');
X	    loc = strlen(buffer);
X	  }
X	  length = 80;
X	} while (loc < strlen(buffer));
X}
X
X/****
X     The following is a newly chopped version of the 'strtok' routine
X  that can work in a recursive way (up to 20 levels of recursion) by
X  changing the character buffer to an array of character buffers....
X****/
X
X#define MAX_RECURSION		20		/* up to 20 deep recursion */
X
X#undef  NULL
X#define NULL			(char *) 0	/* for this routine only   */
X
Xextern int strspn();
Xextern char *strpbrk();
X
Xchar *get_token(string, sepset, depth)
Xchar *string, *sepset;
Xint  depth;
X{
X
X	/** string is the string pointer to break up, sepstr are the
X	    list of characters that can break the line up and depth
X	    is the current nesting/recursion depth of the call **/
X
X	register char	*p, *q, *r;
X	static char	*savept[MAX_RECURSION];
X
X	/** is there space on the recursion stack? **/
X
X	if (depth >= MAX_RECURSION) {
X	 fprintf(stderr,"Error: Get_token calls nested greated than %d deep!\n",
X			MAX_RECURSION);
X	 exit(1);
X	}
X
X	/* set up the pointer for the first or subsequent call */
X	p = (string == NULL)? savept[depth]: string;
X
X	if(p == 0)		/* return if no tokens remaining */
X		return(NULL);
X
X	q = p + strspn(p, sepset);	/* skip leading separators */
X
X	if (*q == '\0')		/* return if no tokens remaining */
X		return(NULL);
X
X	if ((r = strpbrk(q, sepset)) == NULL)	/* move past token */
X		savept[depth] = 0;	/* indicate this is last token */
X	else {
X		*r = '\0';
X		savept[depth] = ++r;
X	}
X	return(q);
X}
X
Xchar *strip_parens(string)
Xchar *string;
X{
X	/** Return string with all parenthesized information removed.
X	    This is a non-destructive algorithm... **/
X
X	static char  buffer[LONG_STRING];
X	register int i, depth = 0, buffer_index = 0;
X
X	for (i=0; i < strlen(string); i++) {
X	  if (string[i] == '(')
X	    depth++;
X	  else if (string[i] == ')') 
X	    depth--;
X	  else if (depth == 0)
X	    buffer[buffer_index++] = string[i];
X	}
X	
X	buffer[buffer_index] = '\0';
X
X	return( (char *) buffer);
X}
SHAR_EOF
chmod 0444 utils/answer.c || echo "restore of utils/answer.c fails"
echo "x - extracting utils/arepdaem.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > utils/arepdaem.c &&
X
Xstatic char rcsid[] = "@(#)$Id: arepdaem.c,v 2.1 88/09/15 21:07:25 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:	arepdaem.c,v $
X * Revision 2.1  88/09/15  21:07:25  syd
X * checked in with -k by syd at 88.09.15.21.07.25.
X * 
X * Revision 2.1  88/07/21  10:01:21  edc
X * Final hacks and cleanup to the 2.1 alpha test release
X * 
X * Revision 2.0  88/06/27  16:54:02  edc
X * The original 2.0 gamma sources as leaked from HP
X * 
X *
X *
X ******************************************************************************/
X
X/** Keep track of mail as it arrives, and respond by sending a 'recording'
X    file to the sender as new mail is received.
X
X    Note: the user program that interacts with this program is the
X    'autoreply' program and that should be consulted for further
X    usage information.
X
X    This program is part of the 'autoreply' system, and is designed
X    to run every hour and check all mailboxes listed in the file 
X    "/etc/autoreply.data", where the data is in the form:
X
X	username	replyfile	current-mailfile-size
X
X    To avoid a flood of autoreplies, this program will NOT reply to mail 
X    that contains header "X-Mailer: fastmail".  Further, each time the 
X    program responds to mail, the 'mailfile size' entry is updated in
X    the file /etc/autoreply.data to allow the system to be brought 
X    down and rebooted without any loss of data or duplicate messages.
X
X    This daemon also uses a lock semaphore file, /usr/spool/uucp/LCK..arep,
X    to ensure that more than one copy of itself is never running.  For this
X    reason, it is recommended that this daemon be started up each morning
X    from cron, since it will either start since it's needed or simply see
X    that the file is there and disappear.
X
X    Since this particular program is the main daemon answering any
X    number of different users, it must be run with uid root.
X
X    (C) 1985, Dave Taylor, HP Colorado Networks Operation
X**/
X
X#include <stdio.h>
X
X#ifdef BSD
X# include <sys/time.h>
X#else
X# include <time.h>
X#endif
X
X#include <sys/types.h>
X#include <sys/stat.h>
X
X#include "defs.h"
X
Xstatic char ident[] = { WHAT_STRING };
X
X#define arep_lock_file	"/usr/spool/uucp/LCK..arep"
X
X#define autoreply_file	"/etc/autoreply.data"
X#define fastmail	"/usr/local/bin/fastmail"
X
X#define logfile		"/etc/autoreply.log"	/* first choice   */
X#define logfile2	"/tmp/autoreply.log"	/* second choice  */
X
X#define BEGINNING	0		/* see fseek(3S) for info */
X#define SLEEP_TIME	3600		/* run once an hour       */
X#define MAX_PEOPLE	20		/* max number in program  */
X
X#define EXISTS		00		/* lock file exists??     */
X#define MODE		0777		/* lockfile creation mode */
X
X#define remove_return(s)	if (strlen(s) > 0) { \
X			          if (s[strlen(s)-1] == '\n') \
X				    s[strlen(s)-1] = '\0'; \
X		                }
X
Xstruct replyrec {
X	char 	username[NLEN];		/* login name of user */
X	char	mailfile[SLEN];		/* name of mail file  */
X	char    replyfile[SLEN];	/* name of reply file */
X	long    mailsize;		/* mail file size     */
X	int     in_list;		/* for new replies    */
X      } reply_table[MAX_PEOPLE];
X
XFILE  *logfd;				/* logfile (log action)   */
Xlong  autoreply_size = 0L;		/* size of autoreply file */
Xint   active = 0;			/* # of people 'enrolled' */
X
XFILE  *open_logfile();			/* forward declaration    */
X
Xlong  bytes();				/*       ditto 		  */
X
Xmain()
X{
X	long size;
X	int  person, data_changed;
X
X	if (! lock())
X	  exit(0);	/* already running! */
X
X	if (fork()) exit(0);
X
X	while (1) {
X
X	  logfd = open_logfile();	/* open the log */
X
X	  /* 1. check to see if autoreply table has changed.. */
X
X	  if ((size = bytes(autoreply_file)) != autoreply_size) {
X	    read_autoreply_file(); 
X	    autoreply_size = size;
X	  }
X
X	  /* 2. now for each active person... */
X	
X	  data_changed = 0;
X
X	  for (person = 0; person < active; person++) {
X	    if ((size = bytes(reply_table[person].mailfile)) != 
X		reply_table[person].mailsize) {
X	      if (size > reply_table[person].mailsize)
X	        read_newmail(person);
X	      /* else mail removed - resync */
X	      reply_table[person].mailsize = size;
X	      data_changed++;
X	    }
X	  }
X
X	  /* 3. if data changed, update autoreply file */
X
X	  if (data_changed)
X	    update_autoreply_file();
X
X	  close_logfile();		/* close the logfile again */
X
X	  /* 4. Go to sleep...  */
X
X	  sleep(SLEEP_TIME);
X	}
X}
X
Xint
Xread_autoreply_file()
X{
X	/** We're here because the autoreply file has changed size!!  It
X	    could either be because someone has been added or because
X	    someone has been removed...since the list will always be in
X	    order (nice, eh?) we should have a pretty easy time of it...
X	**/
X
X	FILE *file;
X	char username[SLEN], 	replyfile[SLEN];
X	int  person;
X 	long size;
X	
X	log("Autoreply data file has changed!  Reading...");
X
X	if ((file = fopen(autoreply_file,"r")) == NULL) {
X	  log("No-one is using autoreply...");
X	  return(0);
X	}
X	
X	for (person = 0; person < active; person++)
X	  reply_table[person].in_list = 0;
X	
X	while (fscanf(file, "%s %s %dl", username, replyfile, &size) != EOF) {
X	  /* check to see if this person is already in the list */
X	  if ((person = in_list(username)) != -1) {
X	    reply_table[person].in_list = 1;
X	    reply_table[person].mailsize = size;	 /* sync */
X	  }
X	  else { 	/* if not, add them */
X	    if (active == MAX_PEOPLE) {
X	      unlock();
X	      exit(log("Couldn't add %s - already at max people!", 
X		         username));
X	    }
X	    log("adding %s to the active list", username);
X	    strcpy(reply_table[active].username, username);
X	    sprintf(reply_table[active].mailfile, "/usr/mail/%s", username);
X	    strcpy(reply_table[active].replyfile, replyfile);
X	    reply_table[active].mailsize = size;
X	    reply_table[active].in_list = 1;	/* obviously! */
X	    active++;
X	  }
X	}
X
X	/** now check to see if anyone has been removed... **/
X
X	for (person = 0; person < active; person++)
X	  if (reply_table[person].in_list == 0) {
X	     log("removing %s from the active list", 
X		  reply_table[person].username);
X	    strcpy(reply_table[person].username, 
X		   reply_table[active-1].username);
X	    strcpy(reply_table[person].mailfile, 
X		   reply_table[active-1].mailfile);
X	    strcpy(reply_table[person].replyfile, 
X		   reply_table[active-1].replyfile);
X	    reply_table[person].mailsize = reply_table[active-1].mailsize;
X	    active--;
X	  }
X}
X
Xupdate_autoreply_file()
X{
X	/** update the entries in the autoreply file... **/
X
X	FILE *file;
X	register int person;
X
X	if ((file = fopen(autoreply_file,"w")) == NULL) {
X          log("Couldn't update autoreply file!");
X	  return;
X	}
X
X	for (person = 0; person < active; person++)
X	  fprintf(file, "%s %s %ld\n",
X		  reply_table[person].username,
X		  reply_table[person].replyfile,
X		  reply_table[person].mailsize);
X
X	fclose(file);
X
X	printf("updated autoreply file\n");
X	autoreply_size = bytes(autoreply_file);
X}
X
Xint
Xin_list(name)
Xchar *name;
X{
X	/** search the current active reply list for the specified username.
X	    return the index if found, or '-1' if not. **/
X
X	register int index;
X
X	for (index = 0; index < active; index++)
X	  if (strcmp(name, reply_table[index].username) == 0)
X	    return(index);
X	
X	return(-1);
X}
X
Xread_newmail(person)
Xint person;
X{
X	/** Read the new mail for the specified person. **/
X
X	
X	FILE *mailfile;
X	char from_whom[LONG_SLEN], subject[SLEN];
X	int  sendit;
X
X	log("New mail for %s", reply_table[person].username);
X
X        if ((mailfile = fopen(reply_table[person].mailfile,"r")) == NULL)
X           return(log("can't open mailfile for user %s", 
X		    reply_table[person].username));
X
X        if (fseek(mailfile, reply_table[person].mailsize, BEGINNING) == -1)
X           return(log("couldn't seek to %ld in mail file!", 
X	               reply_table[person].mailsize));
X
X	while (get_return(mailfile, person, from_whom, subject, &sendit) != -1)
X	  if (sendit)
X	    reply_to_mail(person, from_whom, subject);
X
X	return;
X}
X
Xint
Xget_return(file, person, from, subject, sendit)
XFILE *file;
Xint  person, *sendit;
Xchar *from, *subject;
X{
X	/** Reads the new message and return the from and subject lines.
X	    sendit is set to true iff it isn't a machine generated msg
X	**/
X	
X    char name1[SLEN], name2[SLEN], lastname[SLEN];
X    char buffer[LONG_SLEN], hold_return[NLEN];
X    int done = 0, in_header = 0;
X
X    from[0] = '\0';
X    *sendit = 1;
X
X    while (! done) {
X
X      if (fgets(buffer, LONG_SLEN, file) == NULL)
X	return(-1);
X
X      if (first_word(buffer, "From ")) {
X	in_header++;
X	sscanf(buffer, "%*s %s", hold_return);
X      }
X      else if (in_header) {
X        if (first_word(buffer, ">From")) {
X	  sscanf(buffer,"%*s %s %*s %*s %*s %*s %*s %*s %*s %s", name1, name2);
X	  add_site(from, name2, lastname);
X        }
X        else if (first_word(buffer,"Subject:")) {
X	  remove_return(buffer);
X	  strcpy(subject, (char *) (buffer + 8));
X        }
X        else if (first_word(buffer,"X-Mailer: fastmail"))
X	  *sendit = 0;
X        else if (strlen(buffer) == 1)
X	  done = 1;
X      }
X    }
X
X    if (from[0] == '\0')
X      strcpy(from, hold_return); /* default address! */
X    else
X      add_site(from, name1, lastname);	/* get the user name too! */
X
X    return(0);
X}
X
Xadd_site(buffer, site, lastsite)
Xchar *buffer, *site, *lastsite;
X{
X	/** add site to buffer, unless site is 'uucp', or the same as 
X	    lastsite.   If not, set lastsite to site.
X	**/
X
X	char local_buffer[LONG_SLEN], *strip_parens();
X
X	if (strcmp(site, "uucp") != 0)
X	  if (strcmp(site, lastsite) != 0) {
X	      if (buffer[0] == '\0')
X	        strcpy(buffer, strip_parens(site));         /* first in list! */
X	      else {
X	        sprintf(local_buffer,"%s!%s", buffer, strip_parens(site));
X	        strcpy(buffer, local_buffer);
X	      }
X	      strcpy(lastsite, strip_parens(site)); /* don't want THIS twice! */
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
Xreply_to_mail(person, from, subject)
Xint   person;
Xchar *from, *subject;
X{
X	/** Respond to the message from the specified person with the
X	    specified subject... **/
X	
X	char buffer[SLEN];
X
X	if (strlen(subject) == 0)
X	  strcpy(subject, "Auto-reply Mail");
X	else if (! first_word(subject,"Auto-reply")) {
X	  sprintf(buffer, "Auto-reply to:%s", subject);
X	  strcpy(subject, buffer);
X	}
X
X	log("auto-replying to '%s'", from);
X
X	mail(from, subject, reply_table[person].replyfile, person);
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}
X
Xlong
Xbytes(name)
Xchar *name;
X{
X	/** return the number of bytes in the specified file.  This
X	    is to check to see if new mail has arrived....  **/
X
X	int ok = 1;
X	extern int errno;	/* system error number! */
X	struct stat buffer;
X
X	if (stat(name, &buffer) != 0)
X	  if (errno != 2) {
X	   unlock();
X	   exit(fprintf(stderr,"Error %d attempting fstat on %s", errno, name));
X	  }
X	  else
X	    ok = 0;
X	
X	return(ok ? buffer.st_size : 0);
X}
X
Xmail(to, subject, filename, person)
Xchar *to, *subject, *filename;
Xint   person;
X{
X	/** Mail 'file' to the user from person... **/
X	
X	char buffer[VERY_LONG_STRING];
X
X	sprintf(buffer, "%s -f '%s [autoreply]' -s '%s' %s %s",
X		fastmail, reply_table[person].username,
X	        subject, filename, to);
X	
X	system(buffer);
X}
X
Xlog(message, arg)
Xchar *message;
Xchar *arg;
X{
X	/** Put log entry into log file.  Use the format:
X	      date-time: <message>
X	**/
X
X	struct tm *localtime(), *thetime;
X	long      time(), clock;
X	char      buffer[SLEN];
X
X	/** first off, get the time and date **/
X
X	clock = time((long *) 0);       /* seconds since ???   */
X	thetime = localtime(&clock);	/* and NOW the time... */
X
X	/** then put the message out! **/
X
X	sprintf(buffer, message, arg);
X
X	fprintf(logfd,"%d/%d-%d:%02d: %s\n", 
X		thetime->tm_mon+1, thetime->tm_mday,
X	        thetime->tm_hour,  thetime->tm_min,
X	        buffer);
X}
X
XFILE *open_logfile()
X{
X	/** open the logfile.  returns a valid file descriptor **/
X
X	FILE *fd;
X
X	if ((fd = fopen(logfile, "a")) == 0)
X	  if ((fd = fopen(logfile2, "a")) == 0) {
X	    unlock();
X	    exit(1);	/* give up! */
X	  }
X
X	return( (FILE *) fd);
X}
X
Xclose_logfile()
X{
X	/** Close the logfile until needed again. **/
X
X	fclose(logfd);
X}
X
Xchar *strip_parens(string)
Xchar *string;
X{
X	/** Return string with all parenthesized information removed.
X	    This is a non-destructive algorithm... **/
X
X	static char  buffer[LONG_SLEN];
X	register int i, depth = 0, buffer_index = 0;
X
X	for (i=0; i < strlen(string); i++) {
X	  if (string[i] == '(')
X	    depth++;
X	  else if (string[i] == ')') 
X	    depth--;
X	  else if (depth == 0)
X	    buffer[buffer_index++] = string[i];
X	}
X	
X	buffer[buffer_index] = '\0';
X
X	return( (char *) buffer);
X}
X
X/*** LOCK and UNLOCK - ensure only one copy of this daemon running at any
X     given time by using a file existance semaphore (wonderful stuff!) ***/
X
Xlock()
X{
X	/** Try to create the lock file.  If it's there, or we can't
X	    create it for some stupid reason, return zero, otherwise,
X	    a non-zero return code indicates success in locking this
X	    process in. **/
X
X	if (access(arep_lock_file, EXISTS) == 0)
X	  return(0); 	/* file already exists!! */
X
X	if (creat(arep_lock_file, MODE) == -1)
X	  return(0);	/* can't create file!!   */
X
X	return(1);
X}
X
Xunlock()
X{
X	/** remove lock file if it's there! **/
X
X	(void) unlink(arep_lock_file);
X}
SHAR_EOF
chmod 0444 utils/arepdaem.c || echo "restore of utils/arepdaem.c fails"
echo "x - extracting utils/autoreply.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > utils/autoreply.c &&
X
Xstatic char rcsid[] = "@(#)$Id: autoreply.c,v 2.1 88/09/15 21:07:27 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:	autoreply.c,v $
X * Revision 2.1  88/09/15  21:07:27  syd
X * checked in with -k by syd at 88.09.15.21.07.27.
X * 
X * Revision 2.1  88/07/21  10:01:25  edc
X * Final hacks and cleanup to the 2.1 alpha test release
X * 
X * Revision 2.0  88/06/27  16:54:05  edc
X * The original 2.0 gamma sources as leaked from HP
X * 
X *
X *
X ******************************************************************************/
X
X/** This is the front-end for the autoreply system, and performs two 
X    functions: it either adds the user to the list of people using the
X    autoreply function (starting the daemon if no-one else) or removes
X    a user from the list of people.
X
X    Usage:  autoreply filename
X	    autoreply "off"
X	or  autoreply		[to find current status]
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
Xstatic char ident[] = { WHAT_STRING };
X
X#define  tempdir	"/tmp/arep"		/* file prefix          */
X#define  autoreply_file	"/etc/autoreply.data"   /* autoreply data file  */
X
Xextern   int errno;				/* system error code    */
Xchar     username[NLEN];			/* login name of user   */
X
Xmain(argc, argv)
Xint    argc;
Xchar *argv[];
X{
X	char filename[SLEN];
X
X	if (argc > 2) {
X	  printf("Usage: %s <filename>\tto start autoreply,\n", argv[0]);
X	  printf("       %s off\t\tto turn off autoreply\n", argv[0]);
X	  printf("   or  %s    \t\tto check current status\n", argv[0]);
X	  exit(1);
X	}
X
X	(void) cuserid(username);
X
X	if (argc == 1 || strcmp(argv[1], "off") == 0) 
X	  remove_user((argc == 1));
X	else {
X	  strcpy(filename, argv[1]);
X	  if (access(filename,READ_ACCESS) != 0) {
X	    printf("Error: Can't read file '%s'\n", filename);
X	    exit(1);
X	  }
X	  
X	  if (filename[0] != '/') /* prefix home directory */
X	    sprintf(filename,"%s/%s", getenv("HOME"), argv[1]);
X
X	  add_user(filename);
X	}
X
X	exit(0);
X}
X
Xremove_user(stat_only)
Xint stat_only;
X{
X	/** Remove the user from the list of currently active autoreply 
X	    people.  If 'stat_only' is set, then just list the name of
X	    the file being used to autoreply with, if any. **/
X
X	FILE *temp, *repfile;
X	char  tempfile[SLEN], user[SLEN], filename[SLEN];
X	int   c, copied = 0, found = 0;
X	long  filesize, bytes();
X
X	if (! stat_only) {
X	  sprintf(tempfile, "%s.%06d", tempdir, getpid());
X
X	  if ((temp = fopen(tempfile, "w")) == NULL) {
X	    printf("Error: couldn't open tempfile '%s'.  Not removed\n",
X		    tempfile);
X	    exit(1);
X	  }
X	}
X
X	if ((repfile = fopen(autoreply_file, "r")) == NULL) {
X	  if (stat_only) {
X	    printf("You're not currently autoreplying to mail.\n");
X	    exit(0);
X	  }
X	  printf("No-one is autoreplying to their mail!\n");
X	  exit(0);
X	}
X
X	/** copy out of real replyfile... **/
X
X	while (fscanf(repfile, "%s %s %ld", user, filename, &filesize) != EOF) 
X
X	  if (strcmp(user, username) != 0) {
X	    if (! stat_only) {
X	      copied++;
X	      fprintf(temp, "%s %s %ld\n", user, filename, filesize);
X	    }
X	  }
X	  else {
X	    if (stat_only) {
X	      printf("You're currently autoreplying to mail with the file %s\n",		      filename); 
X	      exit(0);
X	    }
X	    found++;
X	  }
X
X	fclose(temp);
X	fclose(repfile);
X
X	if (! found) {
X	  printf("You're not currently autoreplying to mail%s\n",
X		  stat_only? "." : "!");
X	  if (! stat_only)
X	    unlink(tempfile);
X	  exit(! stat_only);
X	}
X
X	/** now copy tempfile back into replyfile **/
X
X	if (copied == 0) {	/* removed the only person! */
X	  unlink(autoreply_file);
X	}
X	else {			/* save everyone else   */
X	  
X	  if ((temp = fopen(tempfile,"r")) == NULL) {
X	    printf("Error: couldn't reopen tempfile '%s'.  Not removed.\n",
X		    tempfile);
X	    unlink(tempfile);
X	    exit(1);
X	  }
X
X	  if ((repfile = fopen(autoreply_file, "w")) == NULL) {
X	    printf(
X          "Error: couldn't reopen autoreply file for writing!  Not removed.\n");
X	    unlink(tempfile);
X	    exit(1);
X	  }
X
X	  while ((c = getc(temp)) != EOF)
X	    putc(c, repfile);
X
X	  fclose(temp);
X	  fclose(repfile);
X	
X	}
X	unlink(tempfile);
X
X	if (found > 1)
X	  printf("Warning: your username appeared %d times!!   Removed all\n", 
X		  found);
X	else
X	  printf("You've been removed from the autoreply table.\n");
X}
X
Xadd_user(filename)
Xchar *filename;
X{
X	/** add the user to the autoreply file... **/
X
X	FILE *repfile;
X	char  mailfile[SLEN];
X	long  bytes();
X
X	if ((repfile = fopen(autoreply_file, "a")) == NULL) {
X	  printf("Error: couldn't open the autoreply file!  Not added\n");
X	  exit(1);
X	}
X	
X	sprintf(mailfile,"%s/%s", mailhome, username);
X
X	fprintf(repfile,"%s %s %ld\n", username, filename, bytes(mailfile));
X
X	fclose(repfile);
X
X	printf("You've been added to the autoreply system.\n");
X}
X
X
Xlong
Xbytes(name)
Xchar *name;
X{
X	/** return the number of bytes in the specified file.  This
X	    is to check to see if new mail has arrived....  **/
X
X	int ok = 1;
X	extern int errno;	/* system error number! */
X	struct stat buffer;
X
X	if (stat(name, &buffer) != 0)
X	  if (errno != 2)
X	   exit(fprintf(stderr,"Error %d attempting fstat on %s", errno, name));
X	  else
X	    ok = 0;
X	
X	return(ok ? buffer.st_size : 0L);
X}
SHAR_EOF
chmod 0444 utils/autoreply.c || echo "restore of utils/autoreply.c fails"
echo "x - extracting utils/expand.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > utils/expand.c &&
X
Xstatic char rcsid[] = "@(#)$Id: expand.c,v 2.1 88/09/15 21:07:28 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.1 $   $State: Exp $
X *
X * 			Copyright (c) 1986, 1987 Dave Taylor
X *******************************************************************************
X * Bug reports, patches, comments, suggetions should be sent to:
X *
X *	Eric D. Christensen  -  edc@altnet.ALTOS.COM 
X *				uunet!altnet!edc
X *
X *******************************************************************************
X * $Log:	expand.c,v $
X * Revision 2.1  88/09/15  21:07:28  syd
X * checked in with -k by syd at 88.09.15.21.07.28.
X * 
X * Revision 2.1  88/07/21  10:01:27  edc
X * Final hacks and cleanup to the 2.1 alpha test release
X * 
X * Revision 2.0  88/06/27  16:54:06  edc
X * The original 2.0 gamma sources as leaked from HP
X * 
X *
X *
X ******************************************************************************/
X
X/** This is a library routine for the various utilities that allows
X    users to have the standard 'Elm' folder directory nomenclature
X    for all filenames (e.g. '+', '=' or '%').  It should be compiled
X    and then linked in as needed.
X
X**/
X
X#include <stdio.h>
X#include "defs.h"
X
Xchar *expand_define();
X
Xint
Xexpand(filename)
Xchar *filename;
X{
X	/** Expand the filename since the first character is a meta-
X	    character that should expand to the "maildir" variable
X	    in the users ".elmrc" file...
X
X	    Note: this is a brute force way of getting the entry out 
X	    of the .elmrc file, and isn't recommended for the faint 
X	    of heart!
X	**/
X
X	FILE *rcfile;
X	char  buffer[SLEN], *expanded_dir, *home, *getenv(), *bufptr;
X	int   foundit = 0;
X
X	bufptr = (char *) buffer;		/* same address */
X	
X	if ((home = getenv("HOME")) == NULL) {
X	  printf(
X	     "Can't expand environment variable $HOME to find .elmrc file!\n");
X	  exit(1);
X	}
X
X	sprintf(buffer, "%s/%s", home, elmrcfile);
X
X	if ((rcfile = fopen(buffer, "r")) == NULL) {
X	  printf("Can't open your \".elmrc\" file (%s) for reading!\n",
X		 buffer);
X	  exit(1);
X	}
X
X	while (fgets(buffer, SLEN, rcfile) != NULL && ! foundit) {
X	  if (strncmp(buffer, "maildir", 7) == 0 ||
X	      strncmp(buffer, "folders", 7) == 0) {
X	    while (*bufptr != '=' && *bufptr) 
X	      bufptr++;
X	    bufptr++;			/* skip the equals sign */
X	    while (whitespace(*bufptr) && *bufptr)
X	      bufptr++; 
X	    home = bufptr;		/* remember this address */
X
X	    while (! whitespace(*bufptr) && *bufptr != '\n')
X	      bufptr++;
X
X	    *bufptr = '\0';		/* remove trailing space */
X	    foundit++;
X	  }
X	}
X
X	fclose(rcfile);			/* be nice... */
X
X	if (! foundit) {
X	  printf("Couldn't find \"maildir\" in your .elmrc file!\n");
X	  exit(1);
X	}
X
X	/** Home now points to the string containing your maildir, with
X	    no leading or trailing white space...
X	**/
X
X	expanded_dir = expand_define(home);
X
X	sprintf(buffer, "%s%s%s", expanded_dir, 
X		(expanded_dir[strlen(expanded_dir)-1] == '/' ||
X		filename[0] == '/') ? "" : "/", (char *) filename+1);
X
X	strcpy(filename, buffer);
X}
X
Xchar *expand_define(maildir)
Xchar *maildir;
X{
X	/** This routine expands any occurances of "~" or "$var" in
X	    the users definition of their maildir directory out of
X	    their .elmrc file.
X
X	    Again, another routine not for the weak of heart or staunch
X	    of will!
X	**/
X
X	static char buffer[SLEN];	/* static buffer AIEE!! */
X	char   name[SLEN],		/* dynamic buffer!! (?) */
X	       *nameptr,	       /*  pointer to name??     */
X	       *value;		      /* char pointer for munging */
X
X	if (*maildir == '~') 
X	  sprintf(buffer, "%s%s", getenv("HOME"), ++maildir);
X	else if (*maildir == '$') { 	/* shell variable */
X
X	  /** break it into a single word - the variable name **/
X
X	  strcpy(name, (char *) maildir + 1);	/* hurl the '$' */
X	  nameptr = (char *) name;
X	  while (*nameptr != '/' && *nameptr) nameptr++;
X	  *nameptr = '\0';	/* null terminate */
X	  
X	  /** got word "name" for expansion **/
X
X	  if ((value = getenv(name)) == NULL) {
X	    printf("Couldn't expand shell variable $%s in .elmrc!\n", name);
X	    exit(1);
X	  }
X	  sprintf(buffer, "%s%s", value, maildir + strlen(name) + 1);
X	}
X	else strcpy(buffer, maildir);
X
X	return( ( char *) buffer);
X}
SHAR_EOF
chmod 0444 utils/expand.c || echo "restore of utils/expand.c fails"
echo "x - extracting utils/fastmail.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > utils/fastmail.c &&
X
Xstatic char rcsid[] = "@(#)$Id: fastmail.c,v 2.1 88/09/15 21:07:29 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:	fastmail.c,v $
X * Revision 2.1  88/09/15  21:07:29  syd
X * checked in with -k by syd at 88.09.15.21.07.29.
X * 
X * 88/09/08 Rob Bernardo <rob@pbhyf.PacBell.COM>
X * Remove comma seperation from list of addresses
X * Remove single quotes from command.
X *
X * Revision 2.1  88/07/21  10:01:29  edc
X * Final hacks and cleanup to the 2.1 alpha test release
X * 
X * Revision 2.0  88/06/27  16:54:06  edc
X * The original 2.0 gamma sources as leaked from HP
X * 
X *
X *
X ******************************************************************************/
X
X/** This program is specifically written for group mailing lists and
X    such batch type mail processing.  It does NOT use aliases at all,
X    it does NOT read the /etc/password file to find the From: name
X    of the user and does NOT expand any addresses.  It is meant 
X    purely as a front-end for either /bin/mail or /usr/lib/sendmail
X    (according to what is available on the current system).
X
X         **** This program should be used with CAUTION *****
X
X**/
X
X/** The calling sequence for this program is:
X
X	fastmail {args}  filename full-email-address 
X
X   where args could be any (or all) of;
X
X	   -b bcc-list		(Blind carbon copies to)
X	   -c cc-list		(carbon copies to)
X	   -d			(debug on)
X	   -f from 		(from name)
X	   -F from-addr		(the actual address to be put in the From: line)
X	   -r reply-to-address 	(Reply-To:)
X	   -s subject 		(subject of message)
X**/
X
X#include <stdio.h>
X
X#ifdef BSD
X# ifdef BSD4.1
X#   include <time.h>
X#   include <sys/types.h>
X#   include <sys/timeb.h>
X# else
X#   include <sys/time.h>
X# endif
X#else
X#  include <time.h>
X#endif
X
X#include "defs.h"
X
Xstatic char ident[] = { WHAT_STRING };
X
X#define  binrmail	"/bin/rmail"
X#define  temphome	"/tmp/fastmail."
X
X#define DONE		0
X#define ERROR		-1
X
Xchar *optional_arg;			/* optional argument as we go */
Xint   opt_index;			/* argnum + 1 when we leave   */
X
Xchar *arpa_dayname[] = { "Sun", "Mon", "Tue", "Wed", "Thu",
X		  "Fri", "Sat", "" };
X
Xchar *arpa_monname[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
X		  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""};
X
Xchar *get_arpa_date();
X
X#ifdef BSD
X  char *timezone();
X#else
X  extern char *tzname[];
X#endif
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X
X	FILE *tempfile;
X	char hostname[NLEN], username[NLEN], from_string[SLEN], subject[SLEN];
X	char filename[SLEN], tempfilename[SLEN], command_buffer[256];
X	char replyto[SLEN], cc_list[SLEN], bcc_list[SLEN], to_list[SLEN];
X	char from_addr[SLEN];
X	int  c, sendmail_available, debug = 0;
X
X	replyto[0] = '\0';
X	cc_list[0] = '\0';
X	bcc_list[0] = '\0';
X	from_addr[0] = '\0';
X
X	while ((c = get_options(argc, argv, "b:c:df:F:r:s:")) > 0) {
X	  switch (c) {
X	    case 'b' : strcpy(bcc_list, optional_arg);		break;
X	    case 'c' : strcpy(cc_list, optional_arg);		break;
X	    case 'd' : debug++;					break;	
X	    case 'f' : strcpy(from_string, optional_arg);	break;
X	    case 'F' : strcpy(from_addr, optional_arg);		break;
X	    case 'r' : strcpy(replyto, optional_arg);		break;
X	    case 's' : strcpy(subject, optional_arg);		break;
X 	  }
X	}	
X
X	if (c == ERROR) {
X	  fprintf(stderr,"Usage: fastmail {args} filename address(es)\n");
X	  fprintf(stderr, "   where {args} can be;\n");
X	  fprintf(stderr,"\t-b bcc-list\n\t-c cc-list\n\t-d\n\t-f from-name\n");
X	  fprintf(stderr,"\t-F from-addr\n");
X	  fprintf(stderr, "\t-r reply-to\n\t-s subject\n\n");
X	  exit(1);
X	}
X
X	if (opt_index > argc) {
X	  fprintf(stderr,"Usage: fastmail {args} filename address(es)\n");
X	  fprintf(stderr, "   where {args} can be;\n");
X	  fprintf(stderr,"\t-b bcc-list\n\t-c cc-list\n\t-d\n\t-f from-name\n");
X	  fprintf(stderr,"\t-F from-addr\n");
X	  fprintf(stderr, "\t-r reply-to\n\t-s subject\n\n");
X	  exit(1);
X	}
X
X	strcpy(filename, argv[opt_index++]);
X
X	if (opt_index > argc) {
X	  fprintf(stderr,"Usage: fastmail {args} filename address(es)\n");
X	  fprintf(stderr, "   where {args} can be;\n");
X	  fprintf(stderr,"\t-b bcc-list\n\t-c cc-list\n\t-d\n\t-f from-name\n");
X	  fprintf(stderr,"\t-F from-addr\n");
X	  fprintf(stderr,"\t-r reply-to\n\t-s subject\n\n");
X	  exit(1);
X	}
X
X	gethostname(hostname, sizeof(hostname));
X
X	strcpy(username, getlogin());
X
X	if (strlen(username) == 0)
X	  cuserid(username);
X
X	if (access(filename, READ_ACCESS) == -1)
X	  exit(fprintf(stderr, "Error: can't find file %s!\n", filename));
X
X	sprintf(tempfilename, "%s%d", temphome, getpid());
X
X	if ((tempfile = fopen(tempfilename, "w")) == NULL)
X	  exit(fprintf(stderr, "Couldn't open temp file %s\n", tempfilename));
X
X	if (strlen(from_string) > 0)
X	  if (strlen(from_addr) > 0)
X	      fprintf(tempfile, "From: %s (%s)\n", from_addr, from_string);
X	  else
X	      fprintf(tempfile, "From: %s!%s (%s)\n", hostname, username, 
X		      from_string);
X	else
X	  if (strlen(from_addr) > 0)
X	    fprintf(tempfile, "From: %s\n", from_addr);
X	  else
X	    fprintf(tempfile, "From: %s!%s\n", hostname, username);
X
X	fprintf(tempfile, "Date: %s\n", get_arpa_date());
X
X	if (strlen(subject) > 0)
X	  fprintf(tempfile, "Subject: %s\n", subject);
X
X	if (strlen(replyto) > 0)
X	  fprintf(tempfile, "Reply-To: %s\n", replyto);
X
X	while (opt_index < argc) 
X          sprintf(to_list, "%s%s%s", to_list, (strlen(to_list) > 0? " ":""), 
X		  argv[opt_index++]);
X	
X	fprintf(tempfile, "To: %s\n", to_list);
X
X	if (strlen(cc_list) > 0)
X	  fprintf(tempfile, "Cc: %s\n", cc_list);
X
X	if (strlen(bcc_list) > 0)
X	  fprintf(tempfile, "Bcc: %s\n", bcc_list);	/* trust xport */
X
X	fprintf(tempfile, "X-Mailer: fastmail [version %s]\n", VERSION);
X	fprintf(tempfile, "\n");
X
X	fclose(tempfile);
X
X	/** now we'll cat both files to /bin/rmail or sendmail... **/
X
X	sendmail_available = (access(sendmail, EXECUTE_ACCESS) != -1);
X
X	printf("Mailing to %s%s%s%s%s [via %s]\n", to_list,
X		(strlen(cc_list) > 0 ? " ":""), cc_list,
X		(strlen(bcc_list) > 0 ? " ":""), bcc_list,
X		sendmail_available? "sendmail" : "rmail");
X
X	sprintf(command_buffer, "cat %s %s | %s %s %s %s", 
X		tempfilename, filename, 
X	        sendmail_available? sendmail : mailer,
X		to_list, cc_list, bcc_list);
X
X	if (debug)
X	  printf("%s\n", command_buffer);
X
X	system(command_buffer);
X
X	unlink(tempfilename);
X}
X
X
Xchar *get_arpa_date()
X{
X	/** returns an ARPA standard date.  The format for the date
X	    according to DARPA document RFC-822 is exemplified by;
X
X	       	      Mon, 12 Aug 85 6:29:08 MST
X
X	**/
X
X	static char buffer[SLEN];	/* static character buffer       */
X	struct tm *the_time,		/* Time structure, see CTIME(3C) */
X		  *localtime();
X	long	   junk;		/* time in seconds....		 */
X#ifdef BSD
X#  ifdef BSD4.1
X	struct timeb loc_time;	/* of course this is different! */
X#  else
X	struct  timeval  time_val;		
X	struct  timezone time_zone;
X#  endif
X#endif
X
X#ifdef BSD
X#  ifdef BSD4.1
X	junk = (long) time((long *) 0);
X	ftime(&loc_time);
X#  else
X	gettimeofday(&time_val, &time_zone);
X	junk = time_val.tv_sec;
X#  endif
X#else
X	junk = time(0);	/* this must be here for it to work! */
X#endif
X	the_time = localtime(&junk);
X
X	sprintf(buffer, "%s, %d %s %d %d:%02d:%02d %s",
X	  arpa_dayname[the_time->tm_wday],
X	  the_time->tm_mday % 32,
X	  arpa_monname[the_time->tm_mon],
X	  the_time->tm_year % 100,
X	  the_time->tm_hour % 24,
X	  the_time->tm_min  % 61,
X	  the_time->tm_sec  % 61,
X#ifdef BSD
X#  ifdef BSD4.1
X	  timezone(loc_time.time_zone, the_time->tz_isdst));
X#  else
X	  timezone(time_zone.tz_minuteswest, time_zone.tz_dsttime));
X#  endif
X#else
X	  tzname[the_time->tm_isdst]);
X#endif
X	
X	return( (char *) buffer);
X}
X
X/** Starting argument parsing routine.   
X
X    Called as "get_options(argc, argv, options)" where options is a string
X    of the form "abc:d" indicating that 'a' 'b' and 'd' are flags and
X    'c' is a flag with a trailing argument.   Optional arguments are
X    returned in the external char * variable "optional_arg", and the
X    external int "opt_index" is set to the first entry in the argv list
X    that wasn't processed (ie after the flags). 
X
X    For example, the C compiler would have something of the form 
X    getopt(argc, argv, "Oo:l:") to allow "cc -O -o output -l lib file.c"
X
X    (C) Copyright 1986, Dave Taylor
X**/
X
Xint  _indx = 1, _argnum = 1;
X
Xint
Xget_options(argc, argv, options)
SHAR_EOF
echo "End of part 20"
echo "File utils/fastmail.c is continued in part 21"
echo "21" > 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