[mod.sources] v06i039: Elm mail system

sources-request@mirror.UUCP (07/02/86)

Submitted by: Dave Taylor <pyramid!hplabs!hpldat!taylor>
Mod.sources: Volume 6, Issue 39
Archive-name: elm/Part14

[  Last time, when MSG was posted, the moderator posted copies of the
   documentation.  With Dave's cooperation, this time we are making
   available laser-printer hardcopy.  People in the Northeast corner of
   North America can get copies by mailing me their name and postal
   address; I will send out a copy, and forward their name on to Dave
   so he can maintain a list of users.  People in other parts of the
   world should send Dave their address; he will add other "regional
   distributors" as necessary.  --r$  ]

# Continuation of Shell Archive, created by hpldat!taylor

# This is part 14

# To unpack the enclosed files, please use this file as input to the
# Bourne (sh) shell.  This can be most easily done by the command;
#     sh < thisfilename


if [ ! -d utils ]
then
  echo creating directory utils
  mkdir utils
fi

# ---------- file utils/readmsg.c ----------

filename="utils/readmsg.c"

if [ -f $filename ]
then
  echo File \"$filename\" already exists\!  Skipping...
  filename=/dev/null		# throw it away
else
  echo extracting file utils/readmsg.c...
fi

cat << 'END-OF-FILE' > $filename
/**			readmsg.c			**/

/** This routine adds the functionality of the "~r" command to the Elm mail 
    system while still allowing the user to use the editor of their choice.

    The program, without any arguments, tries to read a file in the users home 
    directory called ".readmsg" (actually defined in the sysdefs.h system 
    defines file) and if it finds it reads the current message.  If it doesn't 
    find it, it will return a usage error.

    The program can also be called with an explicit message number, list of 
    message numbers, or a string to match in the message (including the header).
    NOTE that when you use the string matching option it will match the first 
    message containing that EXACT (case sensitive) string and then exit.

    Changed 5/86 to SORT the input list of message numbers to ensure that
    they're in first-to-last order...

    Added the "weed" option as the default.  This is inspired by the mail
    system used at NASA RIACS.  If THEY can do it, so can we!!

    (C) Copyright 1985, Dave Taylor

**/

#include <stdio.h>
#include <ctype.h>

#include "defs.h"

/** three defines for what level of headers to display **/

#define ALL		1
#define WEED		2
#define NONE		3

static char ident[] = { WHAT_STRING };

#define  MAX_LIST	25		/* largest single list of arguments */

#define  LAST_MESSAGE	9999		/* last message in list ('$' char)  */
#define  LAST_CHAR	'$'		/* char to delimit last message..   */

int read_message[MAX_LIST]; 		/* list of messages to read	    */
int messages = 0;			/* index into list of messages      */

int numcmp();				/* strcmp, but for numbers          */
char *words();				/* function defined below...        */

#define DONE	0			/* for use with the getopt	    */
#define ERROR   -1			/*   library call...		    */

extern char *optional_arg;		/* for parsing the ... 		    */
extern int   opt_index;			/*  .. starting arguments           */

main(argc, argv)
int argc;
char *argv[];
{
	FILE *file;			        /* generic file descriptor! */
	char filename[SLEN], 			/* filename buffer          */
	     infile[SLEN],			/* input filename	    */
	     buffer[SLEN], 			/* file reading buffer      */
	     string[SLEN];			/* string match buffer      */

	int current_in_queue = 0, 		/* these are used for...     */
	    current = 0,			/* ...going through msgs     */
	    num, 				/* for argument parsing      */
	    page_breaks = 0,			/* use "^L" breaks??         */
            total,				/* number of msgs current    */
	    include_headers = WEED, 		/* flag: include msg header? */
	    last_message = 0, 			/* flag: read last message?  */
	    not_in_header = 0,			/* flag: in msg header?      */
	    string_match = 0;			/* flag: using string match? */

	/**** start of the actual program ****/

	while ((num = get_options(argc, argv, "nhf:p")) > 0) {
	  switch (num) {
	    case 'n' : include_headers = NONE;		break;
	    case 'h' : include_headers = ALL;		break;
	    case 'f' : strcpy(infile, optional_arg);	break;
	    case 'p' : page_breaks++;			break;
	  }
	}
	
	if (num == ERROR) {
	  printf("Usage: %s [-n|-h] [-f filename] [-p] <message list>\n",
		  argv[0]);
	  exit(1);
	}

	/** whip past the starting arguments so that we're pointing
	    to the right stuff... **/

	*argv++;	/* past the program name... */

	while (opt_index-- > 1) {
	  *argv++;
	  argc--;
	}

	/** now let's figure out the parameters to the program... **/

	if (argc == 1) {	/* no arguments... called from 'Elm'? */
	  sprintf(filename, "%s/%s", getenv("HOME"), readmsg_file);
	  if ((file = fopen(filename, "r")) != NULL) {
	    fscanf(file, "%d", &(read_message[messages++]));
	    fclose(file);
	  }
	  else {	/* no arguments AND no .readmsg file!! */
	    fprintf(stderr,
	        "Usage: readmsg [-n|-h] [-f filename] [-p] <message list>\n");
	    exit(1);
	  }
	}
	else if (! isdigit(*argv[0]) && *argv[0] != LAST_CHAR) {  
	  string_match++;
	 
	  while (*argv)
	    sprintf(string, "%s%s%s", string, string[0] == '\0'? "" : " ",
		    *argv++);
	}
	else { 					    /* list of nums   */

	  while (--argc > 0) {
	    num = -1;

	    sscanf(*argv,"%d", &num);

	    if (num < 0) {
	      if (*argv[0] == LAST_CHAR) {
	        last_message++;
		num = LAST_MESSAGE;
	      }
	      else {
	        fprintf(stderr,"I don't understand what '%s' means...\n",
			*argv); 
	       	exit(1); 
	      }
	    }
	    else if (num == 0) {	/* another way to say "last" */
	      last_message++;
	      num = LAST_MESSAGE;
	    }

	    *argv++; 

	    read_message[messages++] = num;
	  }

	  /** and now sort 'em to ensure they're in a reasonable order... **/

	  qsort(read_message, messages, sizeof(int), numcmp);
	}

	/** Now let's get to the mail file... **/

	if (strlen(infile) == 0) 
	  sprintf(infile, "%s/%s", mailhome, getenv("LOGNAME"));

	if ((file = fopen(infile, "r")) == NULL) {
	  printf("But you have no mail!\n");
	  exit(0);
	}

	/** Now it's open, let's display some 'ole messages!! **/

	if (string_match || last_message) {   /* pass through it once */

	  if (last_message) {
	    total = count_messages(file);	/* instantiate count */
	    for (num=0; num < messages; num++)
	      if (read_message[num] == LAST_MESSAGE)
		read_message[num] = total;
	  }
	  else if (string_match)
	    match_string(file, string);		/* stick msg# in list */

	  if (total == 0 && ! string_match) {
	    printf("There aren't any messages to read!\n");
	    exit(0);
	  }
	}

 	/** now let's have some fun! **/
	
	while (fgets(buffer, SLEN, file) != NULL) {
	  if (strncmp(buffer, "From ", 5) == 0) {
	    if (current == read_message[current_in_queue])
	      current_in_queue++;
	    if (current_in_queue >= messages) 
	      exit(0);
	    current++;
	    if (current == read_message[current_in_queue] && page_breaks
	       && current_in_queue > 0) 
	      putchar(FORMFEED);
	    not_in_header = 0;	/* we're in the header! */
	  }
	  if ((current == read_message[current_in_queue]))
	    if (include_headers==ALL || not_in_header)
	      printf("%s", buffer);
	    else if (strlen(buffer) < 2) {
	      not_in_header++;
	      if (include_headers==WEED) 
		list_saved_headers();
	    }
	    else if (include_headers==WEED)
	      possibly_save(buffer); 	/* check to see if we want this */ 
	}
	
	exit(0);
}

int
count_messages(file)
FILE *file;
{
	/** Returns the number of messages in the file **/

	char buffer[SLEN];
	int  count = 0;

	while (fgets(buffer, SLEN, file) != NULL)
	  if (strncmp(buffer, "From ", 5) == 0)
	    count++;

	rewind( file );
	return( count );
}

match_string(mailfile, string)
FILE *mailfile;
char *string;
{
	/** Increment "messages" and put the number of the message
	    in the message_count[] buffer until we match the specified 
	    string... **/

	char buffer[SLEN];
	int  message_count;

	while (fgets(buffer, SLEN, mailfile) != NULL) {
	  if (strncmp(buffer, "From ", 5) == 0)
	    message_count++;

	  if (in_string(buffer, string)) {
	    read_message[messages++] = message_count;
	    rewind(mailfile);	
	    return;
	  }
	}

	fprintf(stderr,"Couldn't find message containing '%s'\n", string);
	exit(1);
}

int 
in_string(buffer, pattern)
char *buffer, *pattern;
{
	/** Returns TRUE iff pattern occurs IN IT'S ENTIRETY in buffer. **/ 

	register int i = 0, j = 0;
	
	while (buffer[i] != '\0') {
	  while (buffer[i++] == pattern[j++]) 
	    if (pattern[j] == '\0') 
	      return(TRUE);
	  i = i - j + 1;
	  j = 0;
	}
	return(FALSE);
}

int 
numcmp(a, b)
int *a, *b;
{
	/** compare 'a' to 'b' returning less than, equal, or greater
	    than, accordingly.
	 **/

	return(*a - *b);
}

static char from[SLEN], subject[SLEN], date[SLEN];

possibly_save(buffer)
char *buffer;
{
	/** Check to see what "buffer" is...save it if it looks 
	    interesting... We'll always try to get SOMETHING
	    by tearing apart the "From " line...  **/

	if (strncmp(buffer, "Date:", 5) == 0)
	  strcpy(date, buffer);
	else if (strncmp(buffer, "Subject:", 8) == 0)
	  strcpy(subject,buffer);
	else if (strncmp(buffer,"From:", 5) == 0)
	  strcpy(from, buffer);
	else if (strncmp(buffer,"From ", 5) == 0) {
	  sprintf(from, "From: %s\n", words(2,1, buffer));	
	  sprintf(date,"Date: %s",    words(3,7, buffer));
	}
}

list_saved_headers()
{
	/** This routine will display the information saved from the
	    message being listed...If it displays anything it'll end
	    with a blank line... **/

	register int displayed_line = FALSE;

	if (strlen(from)    > 0) { printf("%s", from);    displayed_line++;}
	if (strlen(subject) > 0) { printf("%s", subject); displayed_line++;}
	if (strlen(date)    > 0) { printf("%s", date);    displayed_line++;}
	
	if (displayed_line)
	   putchar('\n');
}

char *words(word, num_words, buffer)
int word, num_words;
char *buffer;
{
	/** Return a buffer starting at 'word' and containing 'num_words'
	    words from buffer.  Assume white space will delimit each word.
	**/

	static char internal_buffer[SLEN];
	char   *wordptr, *bufptr, mybuffer[SLEN], *strtok();
	int    wordnumber = 0, copying_words = 0;

	internal_buffer[0] = '\0';	/* initialize */

	strcpy(mybuffer, buffer);
	bufptr = (char *) mybuffer;	/* and setup */

	while ((wordptr = strtok(bufptr, " \t")) != NULL) {
	  if (++wordnumber == word) {
	    strcpy(internal_buffer, wordptr);
	    copying_words++;
	    num_words--;
	  }
	  else if (copying_words) {
	    strcat(internal_buffer, " ");
	    strcat(internal_buffer, wordptr);
	    num_words--;
	  }

	  if (num_words < 1) 
	    return((char *) internal_buffer);

	  bufptr = NULL;
	}

	return( (char *) internal_buffer);
}


	
END-OF-FILE

if [ "$filename" != "/dev/null" ]
then
  size=`wc -c < $filename`

  if [ $size != 9564 ]
  then
    echo $filename changed - should be 9564 bytes, not $size bytes
  fi

  chmod 666 $filename
fi

# ---------- file utils/Makefile ----------

filename="utils/Makefile"

if [ -f $filename ]
then
  echo File \"$filename\" already exists\!  Skipping...
  filename=/dev/null		# throw it away
else
  echo extracting file utils/Makefile...
fi

cat << 'END-OF-FILE' > $filename
#
#  Makefile for the MSG system utilities
#
#         (C) Copyright 1986, Dave Taylor
#
#  Last modification: March 5th, 1986

SHELL=/bin/sh

##############################
#
# if on a BSD system;
#   DEFINE=-DBSD
#   LIB2  = -lcurses
# else if on a UTS system;
#   DEFINE=-DUTS
#   LIB2  = -la
# else if on a SUN system;
#   DEFINE=-DBSD -DSUN
#   LIB2  = -lcurses
# else if on a Pyramid system;
#   DEFINE=-DBSD -DNO_VAR_ARGS
#   LIB2  = -lcurses
# else

    DEFINE=
    LIB2  =

##############################

CFLAGS= -O -I../hdrs
CC=	/bin/cc
RM= 	/bin/rm
ECHO=  /bin/echo

OBJS=	../bin/newalias ../bin/from ../bin/newmail ../bin/answer       \
	../bin/printmail ../bin/fastmail ../bin/readmsg                \
	../bin/checkalias ../bin/arepdaemon ../bin/autoreply ../bin/wnewmail

all: ${OBJS}

../bin/newalias:  ../hdrs/defs.h newalias.c ../src/validname.o \
	../src/opt_utils.o
	${CC} ${CFLAGS} ${DEFINE} newalias.c ../src/validname.o \
	../src/opt_utils.o -o ../bin/newalias 

../bin/from: from.c ../src/opt_utils.o ../src/string2.o
	${CC} ${CFLAGS} ${DEFINE} from.c ../src/opt_utils.o \
	../src/string2.o -o ../bin/from

../bin/newmail: ../src/opt_utils.c newmail.c ../src/string2.o
	${CC} ${CFLAGS} ${DEFINE} newmail.c \
	../src/string2.o -o ../bin/newmail

../bin/wnewmail: ../src/opt_utils.c wnewmail.c ../src/string2.o
	${CC} ${CFLAGS} ${DEFINE} ../src/opt_utils.o \
	../src/string2.o wnewmail.c -o ../bin/wnewmail

../bin/answer: answer.c ../src/opt_utils.o
	${CC} ${CFLAGS} ${DEFINE} answer.c ../src/opt_utils.o -o ../bin/answer

../bin/printmail: printmail.c ../src/opt_utils.o
	${CC} ${CFLAGS} ${DEFINE} printmail.c ../src/opt_utils.o \
	-o ../bin/printmail

../bin/fastmail: fastmail.c 
	${CC} ${CFLAGS} ${DEFINE} fastmail.c ../src/opt_utils.o \
	-o ../bin/fastmail

../bin/readmsg: readmsg.c ../src/getopt.o ../src/opt_utils.o
	${CC} ${CFLAGS} ${DEFINE} readmsg.c ../src/getopt.o \
	../src/opt_utils.o -o ../bin/readmsg

../bin/arepdaemon: arepdaemon.c
	${CC} ${CFLAGS} ${DEFINE} arepdaemon.c -o ../bin/arepdaemon

../bin/autoreply: autoreply.c ../src/opt_utils.o
	${CC} ${CFLAGS} ${DEFINE} autoreply.c ../src/opt_utils.o \
	-o ../bin/autoreply

../bin/checkalias: 
	@echo '#!/bin/sh' > ../bin/checkalias
	@echo 'if [ -z "$$*" ]; then' >> ../bin/checkalias
	@echo '  echo Usage: checkalias alias \[or aliases\]' >>  \
	      ../bin/checkalias
	@echo '  exit 1' >> ../bin/checkalias
	@echo 'fi' >> ../bin/checkalias
	@echo ' '  >> ../bin/checkalias
	@echo 'exec elm -c $*' >> ../bin/checkalias
	@chmod +x ../bin/checkalias

../src/validname.o: ../src/validname.c
	@(cd ../src; ${CC} -c ${CFLAGS} ${DEFINE} validname.c; cd ../utils)

../src/opt_utils.o: ../src/opt_utils.c
	@(cd ../src; ${CC} -c ${CFLAGS} ${DEFINE} opt_utils.c; cd ../utils)

../src/getopt.o: ../src/getopt.c
	@(cd ../src; ${CC} -c ${CFLAGS} ${DEFINE} getopt.c; cd ../utils)

../src/string2.o: ../src/string2.c
	@(cd ../src; ${CC} -c ${CFLAGS} ${DEFINE} string2.c; cd ../utils)

clean:
	${RM} *.o ${OBJS}

lint:
	lint -p -I../hdrs *.c > LINT.OUT
END-OF-FILE

if [ "$filename" != "/dev/null" ]
then
  size=`wc -c < $filename`

  if [ $size != 3031 ]
  then
    echo $filename changed - should be 3031 bytes, not $size bytes
  fi

  chmod 666 $filename
fi

# ---------- file utils/breakup.c ----------

filename="utils/breakup.c"

if [ -f $filename ]
then
  echo File \"$filename\" already exists\!  Skipping...
  filename=/dev/null		# throw it away
else
  echo extracting file utils/breakup.c...
fi

cat << 'END-OF-FILE' > $filename
/**			breakup.c			**/

/** This program reads in a rather LARGE number of mail files (folders)
    from a directory OTHER THAN THE CURRENT ONE and breaks each into
    a file per message (each message being put into the directory
    MESSAGES) and adds entries for each message in a mailbox with the
    same name as the source mailbox.  The format of each new mailbox
    is;

	FILE: <filename>
	SUBJECT: <subject>
	FROM: <from>
	TO: <to>
	SENT: <sent date>
	RECEIVED: <received date>
	
    (enough information so that indexes can be generated without actually
     having to reference the files in question...)

	filename is "YY-MM-DD.number" where YY-MM-DD is the date the
	         message was received (in this order for sorting)
	from is the persons name or machine!user address ONLY
	dates are MM-DD-YY, HH:MM ONLY.

    (C) Copyright 1986, Dave Taylor
**/

#include <stdio.h>
#include <errno.h>

#include "defs.h"

static int ident[] = { WHAT_STRING };

extern int errno;

#define  first_word(s,w)	strncmp(s, w, strlen(w))

#define  MESSAGES		"MESSAGES"
#define  seqfile		"MESSAGES/.msg_sequence"
#define  SLEN			80

char *monthnames[] = { "month-zero",
	"January", "February", "March", "April", "May", "June",
	"July", "August", "September", "October", "November", "December",
	"month-thirteen" };

FILE *boxfd;
int  messagenum = 1;

char *strtok();

main(argc, argv)
int argc;
char *argv[];
{
	FILE *fd, *outfd;
	char filename[SLEN], *basename(), *box_name;
	int  start;

	if (argc == 1)
	  exit(printf("Usage: breakup <list of files>\n"));

	if (access(MESSAGES, 00) == -1)
	  exit(printf("Need 'MESSAGES' directory in this directory!\n"));

	if ((fd = fopen(seqfile, "r")) == NULL)
	  printf("Warning: No sequence file.  Starting with sequence #1\n");
	else {
	  fscanf(fd,"%d", &messagenum);
	  printf("Starting sequencing with #%d\n", messagenum);
	  fclose(fd);
	}

	*argv++;

	start = messagenum;

	while (--argc) {
	  if ((fd = fopen(*argv, "r")) == NULL) 
	    leave(printf("\nCouldn't open file '%s' for reading!\n", *argv));
	  
	  box_name = basename(*argv);
	
	  if ((boxfd = fopen(box_name, "w")) == NULL)
	    leave(printf("\nCouldn't open box '%s' for writing!\n", box_name));

	  printf("%s...", *argv);  fflush(stdout);

	  break_up(fd, &messagenum);

	  *argv++;
	  fclose(boxfd);
	  fclose(fd);
	}

	printf("\nSuccessfully broke into %d messages!\n", messagenum - start);

	leave();
}

leave()
{
	/** leave, updating messagenum **/

	FILE *fd;

	if ((fd = fopen(seqfile, "w")) == NULL) 
	  printf("Warning: couldn't update sequence file '%s'\n", seqfile);
	else {
	  fprintf(fd, "%d", messagenum);
	  fclose(fd);
	}

	exit(0);
}

break_up(msgfd, messagenum)
FILE *msgfd;
int  *messagenum;
{
	/** break up the mailbox into it's component messages,
	    writing each one to a file as we go along **/

	FILE *outfd;
	char filename[SLEN], buffer[SLEN], save_buffer[SLEN];
	char *get_fdate(), *get_sdate(), *get_rdate();
	char *extract_from(), *extract_date();
	int  in_header = 0, file_open = 0, from_obtained=0;
	int  date_obtained = 0;

	while (fgets(buffer, SLEN, msgfd) != NULL) {
	  if (first_word(buffer, "From ") == 0) {
	    sprintf(filename, "%s/%s.%d", MESSAGES, get_fdate(buffer, '/'), 
		   (*messagenum)++);
	    if (file_open) fclose(outfd);
	    check_for_dirs(filename);
	    if ((outfd = fopen(filename, "w")) == NULL)
	      leave(printf("Could not open file '%s' as message file!\n",
		    filename));

	    fprintf(outfd, "%s", buffer);
 	    fprintf(boxfd, "\nFile: %s\nReceived: %s\n", 
		    filename, get_rdate(buffer));
	    file_open++;
	    in_header++;
	    date_obtained = 0;
	    from_obtained = 0;
	    strcpy(save_buffer, buffer);
	  }
	  else if (file_open) {
	      if (in_header) {
	        if (first_word(buffer, "Subject:") == 0) 
	          fprintf(boxfd, "%s", buffer);
		else if (first_word(buffer, "Date:") == 0) {
		  date_obtained++;
	          fprintf(boxfd, "Sent: %s\n", get_sdate());
		}
		else if (first_word(buffer, "From:") == 0) {
	          from_obtained++;
		  fprintf(boxfd, "%s", buffer);
	        }
	  	else if (first_word(buffer,">From") == 0)
	          strcpy(save_buffer, buffer);
		else if (strlen(buffer) < 2) {
		  in_header = 0;
		  if (! from_obtained) 
		    fprintf(boxfd, "%s\n", extract_from(save_buffer));
		  if (! date_obtained)
		    fprintf(boxfd, "Sent: %s\n", extract_date(save_buffer));
		}
	      }
	      fprintf(outfd, "%s", buffer);
	   }
	}

	if (file_open) {
	  if (! from_obtained) 
	    fprintf(boxfd, "From: %s", extract_from(save_buffer));
	  if (! date_obtained)
	    fprintf(boxfd, "Date: %s", extract_date(save_buffer));
	  fclose(msgfd);
	}
}

char *get_fdate(buffer, separator)
char *buffer, separator;
{
	/** given a "From xyz" buffer, return the date in the format
	    YY?MM?DD for filenaming, where ? = the separator char. **/

	static char mybuf[SLEN];
	char   monthname[SLEN];
	int    month=0, day=0, year=0;

	sscanf(buffer, "%*s %*s %*s %s %d %*s %d", monthname, &day, &year);

	year = year % 1900;

	switch (tolower(monthname[0])) {
	  case 'j' : if (tolower(monthname[1]) == 'a')
			month = 1;
		     else if (tolower(monthname[2]) == 'n')
	                month = 6;
		     else
	                month = 7;
		     break;
	  case 'f' : month = 2;		break;
	  case 'm' : if (tolower(monthname[2]) == 'r')
	               month = 3;
		     else
		       month = 5;
		     break;
	  case 'a' : if (tolower(monthname[1]) == 'p')
	               month = 4;
		     else
		       month = 8;
		     break;
	  case 's' : month = 9;		break;
	  case 'o' : month = 10;	break;
	  case 'n' : month = 11;	break;
	  case 'd' : month = 12;	break;
	}

	sprintf(mybuf, "%d%c%s%c%d", year+1900, separator, 
		monthnames[month], separator, day);

	return( (char *) mybuf);
}

char *get_rdate(buffer)
char *buffer;
{
	/** return buffer "From xyz <date>" in the format:
	    MM-DD-YY, HH:MM **/

	static char mybuf[SLEN];
	char   monthname[20];
	int    month=0, day=0, year=0, hour, minute;

	sscanf(buffer, "%*s %*s %*s %s %d %d:%d:%*d %d", 
	       monthname, &day, &hour, &minute, &year);

	year = year % 1900;

	switch (tolower(monthname[0])) {
	  case 'j' : if (tolower(monthname[1]) == 'a')
			month = 1;
		     else if (tolower(monthname[2]) == 'n')
	                month = 6;
		     else
	                month = 7;
		     break;
	  case 'f' : month = 2;		break;
	  case 'm' : if (tolower(monthname[2]) == 'r')
	               month = 3;
		     else
		       month = 5;
		     break;
	  case 'a' : if (tolower(monthname[1]) == 'p')
	               month = 4;
		     else
		       month = 8;
		     break;
	  case 's' : month = 9;		break;
	  case 'o' : month = 10;	break;
	  case 'n' : month = 11;	break;
	  case 'd' : month = 12;	break;
	}

	sprintf(mybuf, "%d-%d-%d, %d:%d", month, day, year, hour, minute);

	return( (char *) mybuf);
}

char *get_sdate()
{
	return( NULL );
}

char *extract_from(buffer)
char *buffer;
{
	/** extract machine!userid from ">From buffer.. and return From: x!z **/
	/** if userid = To: <someone>, then return that field instead **/

	static char mybuf[SLEN];
	char   name[SLEN], machine[SLEN];

	sscanf(buffer,"%*s %s %*s %*s %*s %*s %*s %*s %*s %s", name, machine);

	if (strncmp(name, "To:", 3) == 0)
	  strcpy(mybuf, name);
	else if (strlen(machine) > 0)
	  sprintf(mybuf, "From: %s!%s", machine, name);
	else
	  sprintf(mybuf, "From: ", name);

	return( (char *) mybuf);
}

char *extract_date(buffer)
char *buffer;
{
	/** extract the date, mm/dd/yy, hh:mm from the '>From' buffer **/

	static char mybuf[SLEN];
	char   month[10], time[10];
	int    day, year;

	sscanf(buffer, "%*s %*s %*s %s %d %s %d", month, &day, time, &year);

	year = year % 1900;

	sprintf(mybuf,"%s %d %d, %s", month, day, year, time);

	return( (char *) mybuf);
}

check_for_dirs(fname)
char *fname;
{
	/** Given a filename of the form x/y/z check for the existence of
	    the directories 'x' and 'y', and create them if they're not
	    currently there!  **/

	char buffer[SLEN], *dirname, dirbuf[SLEN], *bufptr;
	int  loc, i;

	strcpy(buffer, fname);

	for (loc = strlen(fname)-1; buffer[loc] != '/'; loc--)
		;

	buffer[loc] = '\0';	/* broken into directories only! */

	bufptr = (char *) buffer;
	dirbuf[0]= '\0';

	while ((dirname = strtok(bufptr,"/")) != NULL) {
	  if (strlen(dirbuf) > 0)
	    strcat(dirbuf, "/");
	  strcat(dirbuf, dirname);
	  if (access(dirbuf, 00) == -1) 
	    mkdir(dirbuf, 0700);
	  bufptr = NULL;
	}
}

char *basename(filename)
char *filename;
{
	/** returns a string that is the BASENAME of the filename! **/

	static char mybuffer[SLEN];
	register int loc, firstch = 0;

	for (loc = 0; filename[loc] != '\0'; loc++)	
	  if (filename[loc] == '/')
	    firstch = loc+1;

	loc = 0;

	while (filename[firstch] != '\0')
	  mybuffer[loc++] = filename[firstch++];
	mybuffer[loc] = '\0';

	return ( (char *) mybuffer);
}
END-OF-FILE

if [ "$filename" != "/dev/null" ]
then
  size=`wc -c < $filename`

  if [ $size != 8868 ]
  then
    echo $filename changed - should be 8868 bytes, not $size bytes
  fi

  chmod 666 $filename
fi

# ---------- file utils/mailrc.awk ----------

filename="utils/mailrc.awk"

if [ -f $filename ]
then
  echo File \"$filename\" already exists\!  Skipping...
  filename=/dev/null		# throw it away
else
  echo extracting file utils/mailrc.awk...
fi

cat << 'END-OF-FILE' > $filename
BEGIN { 
	print "# MSG alias_text file, from a .mailrc file..." 
	print ""
      }

next_line == 1 { 

	next_line = 0;
        group = ""
	for (i = 1; i <= NF; i++) {
	  if (i == NF && $i == "\\") sep = ""
	  else                       sep = ", "
	
	  if ($i == "\\") {
	    group = sprintf("%s,", group)
	    next_line = 1;
	  }
	  else if (length(group) > 0)
	    group = sprintf("%s%s%s", group, sep, $i);
	  else
	    group = $i;
	  }
	  print "\t" group

	}

$1 ~ /[Aa]lias|[Gg]roup/ { 

	if ( NF == 3)
	  print $2 " : user alias : " $3;
	else {
	  group = ""
	  for (i = 3; i <= NF; i++) {
	    if (i == NF && $i == "\\") sep = ""
	    else        sep = ", "
	
	    if ($i == "\\") {
 	      group = sprintf("%s,", group)
 	      next_line = 1;
	    }
	    else if (length(group) > 0) 
 	      group = sprintf("%s%s%s", group, sep, $i);
	    else
 	      group = $i;
	    }
	    print $2 " : group alias : " group;
	  }
 	}
END-OF-FILE

if [ "$filename" != "/dev/null" ]
then
  size=`wc -c < $filename`

  if [ $size != 930 ]
  then
    echo $filename changed - should be 930 bytes, not $size bytes
  fi

  chmod 666 $filename
fi

# ---------- file utils/wnewmail.c ----------

filename="utils/wnewmail.c"

if [ -f $filename ]
then
  echo File \"$filename\" already exists\!  Skipping...
  filename=/dev/null		# throw it away
else
  echo extracting file utils/wnewmail.c...
fi

cat << 'END-OF-FILE' > $filename
/**			wnewmail.c			**/

/** Same as newmail.c but for a windowing system...
    
    (C) Copyright 1986, Dave Taylor
**/

#ifdef AUTO_BACKGROUND
#include <signal.h>	/* background jobs ignore some signals... */
#endif

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>

#include "defs.h"

static char ident[] = { WHAT_STRING };

#define LINEFEED	(char) 10
#define BEGINNING	0			/* seek fseek(3S) */
#define SLEEP_TIME	10		

#define NO_SUBJECT	"(No Subject Specified)"

FILE *mailfile;

long  bytes();
char  *getusername();

main(argc, argv)
int argc;
char *argv[];
{
	char filename[LONG_SLEN];
	long size, newsize;

	if (argc > 2) 
	  fprintf(stderr, "Usage: %s [filename] &\n", argv[0]);
	else if (argc == 2) {
	  strcpy(filename, argv[1]);
	  if (access(filename, ACCESS_EXISTS) == -1) {
	    fprintf(stderr,"%s: Can't open file %s to keep track of!\n",
		    argv[0], filename);
	    exit(1);
	  }
	}
	else
	  sprintf(filename,"%s%s",mailhome, getusername());

#ifdef AUTO_BACKGROUND
	if (fork())	    /* automatically puts this task in background! */
	  exit(0);

	signal(SIGINT, SIG_IGN);
	signal(SIGQUIT, SIG_IGN);
	signal(SIGHUP,  SIG_DFL);	/* so we exit when logged out */
#endif

	size = bytes(filename);

	mailfile = (FILE *) NULL;

	printf("Incoming Mail;\n");

	while (1) {
	
#ifndef AUTO_BACKGROUND		/* won't work if we're nested this deep! */
	  if (getppid() == 1) 	/* we've lost our shell! */
	    exit();
#endif
	
	/** Note the lack of error checking on the fopen() (Philip Peake
	    did!) - this is okay since if it fails we don't have any 
	    mail and we can sleep(60) and try again later... 
	**/

	  if (mailfile == (FILE *) NULL) 
	    mailfile = fopen(filename,"r");

	  if ((newsize = bytes(filename)) > size) {	/* new mail */
	    fseek(mailfile, size, BEGINNING); /* skip all current mail */
	    size = newsize;
	    printf("%c", 007);	/* beep for new mail! */
	    read_headers();
	  }
	  else if (newsize != size) {
	    size = newsize; 		/* mail's been removed... */
	    (void) fclose(mailfile);	/* close it and ...       */
	    mailfile = (FILE *) NULL;	/* let's reopen the file  */
	  }

	  sleep(SLEEP_TIME);
	}
}

int
read_headers()
{
	/** read the headers, output as found **/

	char buffer[LONG_SLEN], from_whom[SLEN], subject[SLEN];
	register int subj = 0, in_header = 1, count = 0;

	while (fgets(buffer, LONG_SLEN, mailfile) != NULL) {
	  if (first_word(buffer,"From ")) {
	    if (real_from(buffer, from_whom)) {
	      subj = 0;
	      in_header = 1;
	    }
	  }
	  else if (in_header) {
	    if (first_word(buffer,">From")) 
	      forwarded(buffer, from_whom); /* return address */
	    else if (first_word(buffer,"Subject:") ||
		     first_word(buffer,"Re:")) {
	      if (! subj++) {
	        remove_first_word(buffer);
		strcpy(subject, buffer);
	      }
	    }
	    else if (first_word(buffer,"From:")) 
	      parse_arpa_from(buffer, from_whom);
	    else if (buffer[0] == LINEFEED) {
	      in_header = 0;	/* in body of message! */
	      show_header(from_whom, subject);
	      from_whom[0] = 0;
	      subject[0] = 0;
	      count++;
	    }
	  }
	}
	return(count);
}

int
real_from(buffer, who)
char *buffer, *who;
{
	/***** returns true iff 's' has the seven 'from' fields,
	       initializing the who to the sender *****/

	char junk[80];

	junk[0] = '\0';
	sscanf(buffer, "%*s %s %*s %*s %*s %*s %s",
	            who, junk);
	return(junk[0] != '\0');
}

forwarded(buffer, who)
char *buffer, *who;
{
	/** change 'from' and date fields to reflect the ORIGINATOR of 
	    the message by iteratively parsing the >From fields... **/

	char machine[80], buff[80];

	machine[0] = '\0';
	sscanf(buffer, "%*s %s %*s %*s %*s %*s %*s %*s %*s %s",
	            who, machine);

	if (machine[0] == '\0') /* try for srm address */
	  sscanf(buffer, "%*s %s %*s %*s %*s %*s %*s %*s %s",
	            who, machine);

	if (machine[0] == '\0')
	  sprintf(buff,"anonymous");
	else
	  sprintf(buff,"%s!%s", machine, who);

	strncpy(who, buff, 80);
}


remove_first_word(string)
char *string;
{	/** removes first word of string, ie up to first non-white space
	    following a white space! **/

	register int loc;

	for (loc = 0; string[loc] != ' ' && string[loc] != '\0'; loc++) 
	    ;

	while (string[loc] == ' ' || string[loc] == '\t')
	  loc++;
	
	move_left(string, loc);
}

move_left(string, chars)
char string[];
int  chars;
{
	/** moves string chars characters to the left DESTRUCTIVELY **/

	register int i;

	chars--; /* index starting at zero! */

	for (i=chars; string[i] != '\0' && string[i] != '\n'; i++)
	  string[i-chars] = string[i];

	string[i-chars] = '\0';
}

show_header(from, subject)
char *from, *subject;
{
	/** Output header in clean format, including abbreviation
	    of return address if more than one machine name is
	    contained within it! **/

	char buffer[SLEN];
	int  loc, i=0, exc=0;

#ifdef PREFER_UUCP
	
	if (chloc(from,'!') != -1 && in_string(from, BOGUS_INTERNET))
	  from[strlen(from) - strlen(BOGUS_INTERNET)] = '\0';

#endif

	loc = strlen(from);

	while (exc < 2 && loc > 0)
	  if (from[--loc] == '!')
	    exc++;

	if (exc == 2) { /* lots of machine names!  Get last one */
	  loc++;
	  while (loc < strlen(from) && loc < SLEN)
	    buffer[i++] = from[loc++];
	  buffer[i] = '\0';
	  strcpy(from, buffer);
	}

	if (strlen(subject) < 2)
	  strcpy(subject, NO_SUBJECT);
	
	  if (strlen(from) > 0)	/* last final check... */
	    printf("Mail from %s -- %s\n", from, subject);
}	

parse_arpa_from(buffer, newfrom)
char *buffer, *newfrom;
{
	/** try to parse the 'From:' line given... It can be in one of
	    two formats:
		From: Dave Taylor <hpcnou!dat>
	    or  From: hpcnou!dat (Dave Taylor)
	    Change 'newfrom' ONLY if sucessfully parsed this entry and
	    the resulting name is non-null! 
	**/

	char temp_buffer[SLEN], *temp;
	register int i, j = 0;

	temp = (char *) temp_buffer;
	temp[0] = '\0';

	no_ret(buffer);		/* blow away '\n' char! */

	if (lastch(buffer) == '>') {
	  for (i=strlen("From: "); buffer[i] != '\0' && buffer[i] != '<' &&
	       buffer[i] != '('; i++)
	    temp[j++] = buffer[i];
	  temp[j] = '\0';
	}
	else if (lastch(buffer) == ')') {
	  for (i=strlen(buffer)-2; buffer[i] != '\0' && buffer[i] != '(' &&
	       buffer[i] != '<'; i--)
	    temp[j++] = buffer[i];
	  temp[j] = '\0';
	  reverse(temp);
	}
	  
	if (strlen(temp) > 0) {		/* mess with buffer... */

	  /* remove leading spaces... */

	  while (whitespace(temp[0]))
	    temp = (char *) (temp + 1);		/* increment address! */

	  /* remove trailing spaces... */

	  i = strlen(temp) - 1;

	  while (whitespace(temp[i]))
	   temp[i--] = '\0';

	  /* if anything is left, let's change 'from' value! */

	  if (strlen(temp) > 0)
	    strcpy(newfrom, temp);
	}
}

reverse(string)
char *string;
{
	/** reverse string... pretty trivial routine, actually! **/

	char buffer[SLEN];
	register int i, j = 0;

	for (i = strlen(string)-1; i >= 0; i--)
	  buffer[j++] = string[i];

	buffer[j] = '\0';

	strcpy(string, buffer);
}

long
bytes(name)
char *name;
{
	/** return the number of bytes in the specified file.  This
	    is to check to see if new mail has arrived....  **/

	int ok = 1;
	extern int errno;	/* system error number! */
	struct stat buffer;

	if (stat(name, &buffer) != 0)
	  if (errno != 2)
	   exit(fprintf(stderr,"Error %d attempting fstat on %s", errno, name));
	  else
	    ok = 0;
	
	return(ok ? (long) buffer.st_size : 0L);
}

char  *getusername()
{
	/** Getting the username on some systems is a real pain, so...
	   This routine is guaranteed to return a usable username **/

	char *return_value, *cuserid(), *getlogin();

	if ((return_value = cuserid(NULL)) == NULL)
	  if ((return_value = getlogin()) == NULL)
	    exit(printf("Newmail: I can't get username!\n"));

	return( (char *) return_value);
}
END-OF-FILE

if [ "$filename" != "/dev/null" ]
then
  size=`wc -c < $filename`

  if [ $size != 7804 ]
  then
    echo $filename changed - should be 7804 bytes, not $size bytes
  fi

  chmod 666 $filename
fi

# ---------- file utils/page.c ----------

filename="utils/page.c"

if [ -f $filename ]
then
  echo File \"$filename\" already exists\!  Skipping...
  filename=/dev/null		# throw it away
else
  echo extracting file utils/page.c...
fi

cat << 'END-OF-FILE' > $filename
/**			page.c			**/

/** This is an alternative method of wandering through a file
    and is essentially a "read-only" editor.

    This is part of the Elm mail system, although it can be
    used by itself...

    The functions available are;

	h	help

	-,b	back a page
	u	back 1/2 a page

	^M,+,f  forward a page
	d	forward 1/2 a page

	r	reread file (start over)

	/	skip forward to pattern
	?	skip backwards to pattern (with no arg, same as "h")

	q	quit

   The starting flags are:
	
	-s	Use scrolling rather than paging
	
   Page is also smart enough to know that if it's reading stdin
   that it needs to open a temp file to stream the input into
   to allow paging AND also knows that it then needs to read 
   /dev/tty rather than stdin (think about it).

   (C) Copyright 1986 Dave Taylor
**/

#include <stdio.h>

#define SLEN		100

#define TOP_OF_PAGE	0
#define MIDDLE_OF_PAGE	1
#define MAX_PAGES	200	/* indicates how far back we'll remember  */

#define MIDDLE		0
#define END		1

#define TEMPFILENAME	"/tmp/page."

FILE *keyboard;			/* always read keyboard with this...       */
FILE *infile;			/* the file we're reading...		   */
FILE *tempfile;			/* temp file for streaming input 	   */

int scrolling = 0,		/* Flag: should we scroll instead of page? */
    streaming = 0;		/* Flag: are we reading stdin for file?    */

long offsets[2][MAX_PAGES];	/* offsets into file as we go along        */

long current_offset;		/* offset into file currently		   */
int  current_page,		/* what page we're on...		   */
     loc_on_page,		/* where are we (HALF ON, or FULLY ON)	   */
     line_on_page,		/* what line on the page (Screen)	   */
     lines_per_page = 24;	/* lines per page on terminal		   */

main(argc, argv)
int argc;
char *argv[];
{
	char filename[SLEN], buffer[SLEN];

	if (argc > 1) {
	  strcpy(filename, argv[1]);
	  keyboard = stdin;
	}
	else if (isatty(fileno(stdin))) 
	  exit(printf("Nothing to page through!\n"));
	else {
	  sprintf(filename, "%s.%d", TEMPFILENAME, getpid());
	  streaming++;
	  keyboard = fopen("/dev/tty", "r");
	}

	/** now let's open the file accordingly... **/

	if (streaming) {
	  infile = stdin;
	  if ((tempfile = fopen(filename, "w")) == NULL) 
	    exit(printf("Can't open tempfile %s for paging!\n", filename));
	}
	else {
	  if ((infile = fopen(filename, "r")) == NULL)
	    exit(printf("Can't open file %s for reading!\n", filename));
	}

	/** initialize our variables... **/

	current_page = 0;
	current_offset = 0L;
	line_on_page = 0;
	loc_on_page  = TOP_OF_PAGE;
 
 	if (getenv("LINES") != NULL) 
 	  lines_per_page = atoi(getenv("LINES")) - 2;
 
 	offsets[TOP_OF_PAGE][current_page] = current_offset;	/* init */
 
 	while (gets(buffer, SLEN, infile) != NULL) {
 	  line_on_page++;
 	  if (line_on_page == (int) (lines_per_page / 2)) 
 	    offsets[MIDDLE_OF_PAGE][current_page] = current_offset;
 	  else if (line_on_page == lines_per_page) {
 	    offsets[TOP_OF_PAGE][++current_page] = current_offset;
 	    next_page(MIDDLE);	/* could do a "seek" remember! */
 	  }
 	}
 	
 	next_page(END);
 
 	exit(0);
 }
 	
 next_page(where)
 int where;
 {
 	/** End of page processing..where is either "MIDDLE", indicating
 	    that we're in the middle of a file, or "END", indicating that
 	    we've already hit the EOF mark **/
 
 	char buffer[3];

top:	printf("\n%s Command? ", where == MIDDLE? "More..." : 
	       "End of Message -");

	fgets(buffer,2, keyboard);

	line_on_page = 0;

	switch (buffer[0]) {
	  case '+'  :
	  case 'f'  : 
	  case '\n' : return;		/* scroll to next page */
	  
	  case 'd'  : line_on_page = (int) (lines_per_page / 2);
		      return;		/* scroll 1/2 next page */

	  case 'u'  : getto(offsets[MIDDLE_OF_PAGE][current_page-1]);
		      return;

	  case 'b'  :
	  case '-'  : getto(offsets[TOP_OF_PAGE][current_page-1]);
	 	      return;

	  case 'q'  : exit(0);	/* we're outta here!! */

	  case 'h'  : help();	goto top;	/* this again? */

	  default   : printf("Unknown command.  Please use \"h\" for help\n");
		      goto top;
	}
}

getto(offset)
long offset;
{
	/** This routine seeks to the specified point in the file and
	    sets current page accordingly... 	**/

	if (fseek(infile, offset, 0) != -1) 
	  current_offset = offset;	/* whee! */
}

help()
{
	printf("\nThe following options are available;\n\n");

	printf("   h	         help\n\n");

	printf("   -,b	         back a page\n");
	printf("   u	         back 1/2 a page\n\n");

	printf("   <return>,+,f  forward a page\n");
	printf("   d	         forward 1/2 a page\n\n");

	printf("   r	         reread file (start over)\n\n");

	printf("   /	         skip forward to pattern\n");
	printf("   ?	         skip backwards to pattern (with no arg, same as \"h\")\n\n");

	printf("   q	         quit\n\n");
}
END-OF-FILE

if [ "$filename" != "/dev/null" ]
then
  size=`wc -c < $filename`

  if [ $size != 4759 ]
  then
    echo $filename changed - should be 4759 bytes, not $size bytes
  fi

  chmod 666 $filename
fi

echo done

exit 0