[comp.sources.unix] v18i102: Elm mail system, release 2.2, Part23/24

rsalz@uunet.uu.net (Rich Salz) (04/14/89)

Submitted-by: dsinc!syd@uunet.UU.NET (Syd Weinstein)
Posting-number: Volume 18, Issue 102
Archive-name: elm2.2/part23

#!/bin/sh
# this is part 23 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file utils/arepdaem.c continued
#
CurArch=23
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/arepdaem.c"
sed 's/^X//' << 'SHAR_EOF' >> utils/arepdaem.c
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")) == NULL)
X	  if ((fd = fopen(logfile2, "a")) == NULL) {
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[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
echo "File utils/arepdaem.c is complete"
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.3 89/03/25 21:47:41 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.3 $   $State: Exp $
X *
X * 			Copyright (c) 1986, 1987 Dave Taylor
X * 			Copyright (c) 1988, 1989 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X *	Syd Weinstein, Elm Coordinator
X *	elm@dsinc.UUCP			dsinc!elm
X *
X *******************************************************************************
X * $Log:	autoreply.c,v $
X * Revision 2.3  89/03/25  21:47:41  syd
X * Initial 2.2 Release checkin
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/checkalias (Text)"
sed 's/^X//' << 'SHAR_EOF' > utils/checkalias &&
X: Use /bin/sh
X# checkalias: part of the Elm mail system
X# @(#)$Id: checkalias,v 2.1 89/03/03 17:46:56 syd Exp $
X 
Xif [ "$*" = "" ]; then
X  echo Usage: checkalias alias \[alias ...\] 1>&2
X  exit 1
Xfi
X 
Xexec elm -c $*
SHAR_EOF
chmod 0444 utils/checkalias || echo "restore of utils/checkalias 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.3 89/03/25 21:47:43 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.3 $   $State: Exp $
X *
X * 			Copyright (c) 1986, 1987 Dave Taylor
X * 			Copyright (c) 1988, 1989 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X *	Syd Weinstein, Elm Coordinator
X *	elm@dsinc.UUCP			dsinc!elm
X *
X *******************************************************************************
X * $Log:	expand.c,v $
X * Revision 2.3  89/03/25  21:47:43  syd
X * Initial 2.2 Release checkin
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.5 89/03/25 21:47:44 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.5 $   $State: Exp $
X *
X * 			Copyright (c) 1986, 1987 Dave Taylor
X * 			Copyright (c) 1988, 1989 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X *	Syd Weinstein, Elm Coordinator
X *	elm@dsinc.UUCP			dsinc!elm
X *
X *******************************************************************************
X * $Log:	fastmail.c,v $
X * Revision 2.5  89/03/25  21:47:44  syd
X * Initial 2.2 Release checkin
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#include "defs.h"
X#include "patchlevel.h"
X
X#ifdef BSD
X# ifdef TMINSYS
X#   include <sys/time.h>
X# else
X#   include <time.h>
X#   include <sys/types.h>
X#   include <sys/timeb.h>
X# endif
X#else
X#  include <time.h>
X#endif
X
Xstatic char ident[] = { WHAT_STRING };
X
X#define  binrmail	"/bin/rmail"
X#define  temphome	"/tmp/fastmail."
X
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	extern char *optarg;
X	extern int optind;
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	subject[0] = '\0';
X	replyto[0] = '\0';
X	cc_list[0] = '\0';
X	bcc_list[0] = '\0';
X	from_addr[0] = '\0';
X
X	while ((c = getopt(argc, argv, "b:c:df:F:r:s:")) != EOF) {
X	  switch (c) {
X	    case 'b' : strcpy(bcc_list, optarg);		break;
X	    case 'c' : strcpy(cc_list, optarg);		break;
X	    case 'd' : debug++;					break;	
X	    case 'f' : strcpy(from_string, optarg);	break;
X	    case 'F' : strcpy(from_addr, optarg);		break;
X	    case 'r' : strcpy(replyto, optarg);		break;
X	    case 's' : strcpy(subject, optarg);		break;
X	    case '?' :
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");
X	      fprintf(stderr,"\t-f from-name\n\t-F from-addr\n");
X	      fprintf(stderr, "\t-r reply-to\n\t-s subject\n\n");
X	      exit(1);
X 	  }
X	}	
X
X	if (optind > 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[optind++]);
X
X	if (optind > 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#ifdef HOSTCOMPILED
X	strncpy(hostname, HOSTNAME, sizeof(hostname));
X#else
X	gethostname(hostname, sizeof(hostname));
X#endif
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	/** Subject must appear even if "null" and must be first
X	    at top of headers for mail because the
X	    pure System V.3 mailer, in its infinite wisdom, now
X	    assumes that anything the user sends is part of the 
X	    message body unless either:
X		1. the "-s" flag is used (although it doesn't seem
X		   to be supported on all implementations??)
X		2. the first line is "Subject:".  If so, then it'll
X		   read until a blank line and assume all are meant
X		   to be headers.
X	    So the gory solution here is to move the Subject: line
X	    up to the top.  I assume it won't break anyone elses program
X	    or anything anyway (besides, RFC-822 specifies that the *order*
X	    of headers is irrelevant).  Gahhhhh....
X	**/
X	fprintf(tempfile, "Subject: %s\n", subject);
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(replyto) > 0)
X	  fprintf(tempfile, "Reply-To: %s\n", replyto);
X
X	while (optind < argc) 
X          sprintf(to_list, "%s%s%s", to_list, (strlen(to_list) > 0? " ":""), 
X		  argv[optind++]);
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	fprintf(tempfile, "X-Mailer: fastmail [version %s PL%d]\n",
X	  VERSION, PATCHLEVEL);
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#  ifndef TMINSYS
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#  ifndef TMINSYS
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#  ifndef TMINSYS
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}
SHAR_EOF
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.9 89/03/25 21:47:46 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.9 $   $State: Exp $
X *
X * 			Copyright (c) 1986, 1987 Dave Taylor
X * 			Copyright (c) 1988, 1989 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X *	Syd Weinstein, Elm Coordinator
X *	elm@dsinc.UUCP			dsinc!elm
X *
X *******************************************************************************
X * $Log:	from.c,v $
X * Revision 2.9  89/03/25  21:47:46  syd
X * Initial 2.2 Release checkin
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**/
X
X#include <stdio.h>
X#include <pwd.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[SLEN], *cp ;
X	int  multiple_files = 0, output_files = 0, c;
X	struct passwd *pass, *getpwuid();
X
X	extern int optind;
X
X	while ((c = getopt(argc, argv, "nv")) != EOF) 
X	  switch (c) {
X	    case (int)'n': number++;		break;
X	    case (int)'v': verbose++;	break;
X	    case (int)'?': printf("Usage: %s [-n] [-v] {filename | username}\n",
X			     argv[0]);
X	                   exit(1);
X	  }
X
X	infile[0] = '\0';
X	if (optind == argc) {
X	/*
X	 *	determine mail file from environment variable if found,
X	 *	else use password entry
X	 */
X	  if ((cp = getenv("MAIL")) == NULL) {
X	    if((pass = getpwuid(getuid())) == NULL) {
X	      printf("You have no password entry!");
X	      exit(1);
X	    }
X	    sprintf(infile,"%s%s",mailhome, pass->pw_name);
X	  }
X	  else
X	    strcpy(infile, cp);
X	  optind -= 1;	/* ensure one pass through loop */
X	}
X
X	multiple_files = (argc - optind > 1);
X
X	while (optind < argc) {
X	
X	  if (multiple_files) {
X	    strcpy(infile, argv[optind]);
X	    printf("%s%s: \n", output_files++ > 0 ? "\n":"", infile);
X	  }
X	  else if (infile[0] == '\0')
X	    strcpy(infile, argv[optind]);
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 (optind+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[optind]);
X	        if ((mailfile = fopen(infile,"r")) == NULL)
X	          printf("Couldn't open folders \"%s\" or \"%s\".\n",
X			 argv[optind], infile);
X	        else if (read_headers()==0)
X	          printf("No messages in that folder!\n");
X	       }
X	    }
X	  }
X	  else
X	    if (read_headers(optind+1 == argc)==0)
X	      if (optind+1 == argc)
X	        printf("No mail\n");
X	      else
X	        printf("No messages in that folder!\n");
X
X	  optind++;
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[SLEN], from_whom[SLEN], subject[SLEN];
X	register int subj = 0, in_header = 0, count = 0;
X
X	while (fgets(buffer, 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[SLEN];
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[SLEN], buff[SLEN], holding_from[SLEN];
X
X	machine[0] = '\0';
X	holding_from[0] = '\0';
X	sscanf(buffer, "%*s %s %*s %*s %*s %*s %*s %*s %*s %*s %s",
X	            holding_from, machine);
X
X	if(machine[0] == '\0')	/* try for address with timezone in date */
X	sscanf(buffer, "%*s %s %*s %*s %*s %*s %*s %*s %*s %s",
X	            holding_from, machine);
X
X	if (machine[0] == '\0') /* try for srm address */
X	  sscanf(buffer, "%*s %s %*s %*s %*s %*s %*s %*s %s",
X	            holding_from, machine);
X
X	if (machine[0] == '\0')
X	  sprintf(buff, holding_from[0] ? holding_from : "anonymous");
X	else
X	  sprintf(buff,"%s!%s", machine, holding_from);
X
X	strncpy(who, buff, SLEN);
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#ifndef INTERNET
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, in_parens;
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	  in_parens = 1;
X	  for (i=strlen(buffer)-2; buffer[i] != '\0' && buffer[i] != '<'; i--) {
X	    switch(buffer[i]) {
X	    case ')':	in_parens++;
X			break;
X	    case '(':	in_parens--;
X			break;
X	    }
X	    if(!in_parens) break;
X	    temp[j++] = buffer[i];
X	  }
X	  temp[j] = '\0';
X	  reverse(temp);
X	}
X
X/* this stuff copied from src/addr_util.c */
X#ifdef USE_EMBEDDED_ADDRESSES
X
X	/** if we have a null string at this point, we must just have a 
X	    From: line that contains an address only.  At this point we
X	    can have one of a few possibilities...
X
X		From: address
X		From: <address>
X		From: address ()
X	**/
X	  
X	if (strlen(temp) == 0) {
X	  if (lastch(buffer) != '>') {       
X	    for (i=strlen("From:");buffer[i] != '\0' && buffer[i] != '('; i++)
X	      temp[j++] = buffer[i];
X	    temp[j] = '\0';
X	  }
X	  else {	/* get outta '<>' pair, please! */
X	    for (i=strlen(buffer)-2;buffer[i] != '<' && buffer[i] != ':';i--)
X	      temp[j++] = buffer[i];
X	    temp[j] = '\0';
X	    reverse(temp);
X	  }
X	}
X#endif
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/listalias.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > utils/listalias.c &&
X
Xstatic char rcsid[] = "@(#)$Id: listalias.c,v 2.3 89/03/25 21:47:50 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.3 $   $State: Exp $
X *
X * 			Copyright (c) 1986, 1987 Dave Taylor
X * 			Copyright (c) 1988, 1989 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X *	Syd Weinstein, Elm Coordinator
X *	elm@dsinc.UUCP			dsinc!elm
X *
X *******************************************************************************
X * $Log:	listalias.c,v $
X * Revision 2.3  89/03/25  21:47:50  syd
X * Initial 2.2 Release checkin
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[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, 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.3 89/03/25 21:47:51 syd Exp $
X#	Copyright (c) 1986, 1987 Dave Taylor
X#	Copyright (c) 1988, 1989 USENET Community Trust
X# Bug reports, patches, comments, suggestions should be sent to:
X#
X#	Syd Weinstein, Elm Coordinator - elm@dsinc.UUCP
X#					 dsinc!elm
X#
X# $Log:	mailrc.awk,v $
X# Revision 2.3  89/03/25  21:47:51  syd
X# Initial 2.2 Release checkin
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/messages (Text)"
sed 's/^X//' << 'SHAR_EOF' > utils/messages &&
X: Use /bin/sh
X# messages: part of the Elm mail system
X# @(#)$Id: messages,v 2.1 89/03/03 17:46:59 syd Exp $
X 
Xif [ "$2" != "" ]; then
X  echo Usage: messages \{folder-name\} 1>&2
X  exit 1
Xfi
X 
Xif [ "$1" = "" ]; then
X  fname=$MAIL
X  optional="in your mailbox"
Xelse
X  fname=$1
X  optional="in folder $1"
Xfi
X 
Xif [ -f "$fname" ]; then
X  mcount=`egrep -c "^From " $fname`
Xelse
X  exit 0
Xfi
X 
Xif [ "$mcount" -eq 1 ]; then
X  echo There is $mcount message $optional.
Xelse
X  echo There are $mcount messages $optional.
Xfi
X 
Xexit $mcount
SHAR_EOF
chmod 0444 utils/messages || echo "restore of utils/messages 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.7 89/03/25 21:47:53 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.7 $   $State: Exp $
X *
X * 			Copyright (c) 1986, 1987 Dave Taylor
X * 			Copyright (c) 1988, 1989 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X *	Syd Weinstein, Elm Coordinator
X *	elm@dsinc.UUCP			dsinc!elm
X *
X *******************************************************************************
X * $Log:	newalias.c,v $
X * Revision 2.7  89/03/25  21:47:53  syd
X * Initial 2.2 Release checkin
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**/
X
X#include <stdio.h>
X#include "defs.h"
X#include "sysdefs.h"		/* ELM system definitions */
X
X#ifdef BSD
X#  include <sys/file.h>
X#else
X#  include <fcntl.h>
X#endif
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  a, hash, count = 0, owner;
X
X	for (a = 1; a < argc; ++a) {
X	  if (strcmp(argv[a], "-g") == 0)
X	    is_system = 1;
X	  else {
X	    printf("Usage: %s [-g]\n", argv[0]);
X	    exit(1);
X	  }
X	}
X
X	if (is_system) {   /* update system aliases */
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	  init_table(shash_table, MAX_SALIASES);
X	}
X	else
X	  printf("Updating your personal alias file...\n");
X	
X	if (! is_system) {
X	  if (strcpy(home, getenv("HOME")) == NULL) {
X	    printf("I'm confused - no HOME variable in environment!\n");
X	    exit(1);
X	  }
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	  printf("Couldn't open %s for output!\n", hashname);
X	  exit(1);
X	}
X
X	if ((data = fopen(dataname,"w")) == NULL) {
X	  printf("Couldn't open %s for output!\n", dataname);
X	  exit(1);
X	}
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	  printf("Bad alias name: %s.  Too long.\n", word);
SHAR_EOF
echo "End of part 23"
echo "File utils/newalias.c is continued in part 24"
echo "24" > s2_seq_.tmp
exit 0

-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.