[mod.sources] Msg Shar.part.4

sources-request@panda.UUCP (03/02/86)

Mod.sources:  Volume 4, Issue 8
Submitted by: decvax!hplabs!hpcnou!dat (Dave Taylor)

# Msg Shar part 4 of 7

# Shell Archive created by hpcnou!dat at Wed Feb 26 15:56:20 1986

# 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

# This archive contains;
#  src/file_utils.c src/fileio.c        src/hdrconfg.c      src/help.c
#  src/initialize.c src/input_utils.c   src/leavembox.c     src/mailout.c
#  src/mailtime.c   src/mkhdrs.c        src/msg.c


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

# ---------- file src/file_utils.c ----------


if [ -f src/file_utils.c ]
then
  echo File 'src/file_utils.c' already exists\!
  exit 1
fi

echo extracting file src/file_utils.c...
cat << 'END-OF-FILE' > src/file_utils.c
/**			file_utils.c			**/

/** File oriented utility routines for MSG 

    (C) Copyright 1986 Dave Taylor
**/

#include "headers.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>

#ifdef BSD
#undef tolower
#endif
#include <signal.h>
#include <errno.h>

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) {
	    dprint2("\n\n*** bytes() Error %d on fstat(%s)\n\n", errno, name);
	    leave(error2("Error %d attempting fstat on %s", errno, name));
	  }
	  else
	    ok = 0;
	
	return(ok ? (long) buffer.st_size : 0L);
}

int
can_access(file, mode)
char *file, *mode;
{
	/** returns TRUE iff user can access file **/

	int status, pid, w;
	register int (*istat)(), (*qstat)();
	
	if ((pid = fork()) == 0) {
	  setuid(userid);		/** back to normal userid **/
	  exit(fopen(file, mode) != NULL);
	  _exit(127);
	}

	istat = signal(SIGINT, SIG_IGN);
	qstat = signal(SIGQUIT, SIG_IGN);

	while ((w = wait(&status)) != pid && w != -1)
		;

	if (w == -1) status = FALSE;
	
	signal(SIGINT, istat);
	signal(SIGQUIT, qstat);

	return(status);
}


int
copy(from, to)
char *from, *to;
{
	/** this routine copies a specified file to the destination
	    specified.  Non-zero return code indicates that something
	    dreadful happened! **/

	FILE *from_file, *to_file;
	char buffer[VERY_LONG_STRING];
	
	dprint2("copy(from='%s', to='%s')\n", from, to);

	if ((from_file = fopen(from, "r")) == NULL)
	  return(error1("could not open file %s", from));

	if ((to_file = fopen(to, "w")) == NULL)
	  return(error1("could not open file %s", to));

	while (fgets(buffer, VERY_LONG_STRING, from_file) != NULL)
	  fputs(buffer, to_file);

	fclose(from_file);
	fclose(to_file);

	return(0);
}

check_mailfile_size()
{
	/** Check to ensure we have mail.  Only used with the '-z'
	    starting option. **/

	char filename[SLEN], username[NLEN];
	struct stat buffer;

	strcpy(username,getlogin());
	if (strlen(username) == 0)
	  cuserid(username);

	sprintf(filename,"%s/%s", mailhome, username);

	if (stat(filename, &buffer) == -1) {
	  printf(" You have no mail.\n");
	  exit(0);
	}
	else if (buffer.st_size < 2) { 		/* maybe one byte??? */
	  printf("You have no mail to read.\n");
	  exit(0);
	}
}
END-OF-FILE

size=`wc -c < src/file_utils.c`

if [ $size != 2421 ]
then
  echo Warning: src/file_utils.c changed - should be 2421 bytes, not $size bytes
fi

chmod 644 src/file_utils.c

# ---------- file src/fileio.c ----------


if [ -f src/fileio.c ]
then
  echo File 'src/fileio.c' already exists\!
  exit 1
fi

echo extracting file src/fileio.c...
cat << 'END-OF-FILE' > src/fileio.c
/**			fileio.c			**/

/** File I/O routines, including deletion from the mailbox! 

    (C) Copyright 1986 Dave Taylor
**/

#include "headers.h"
#include <ctype.h>

#ifdef BSD
#undef tolower
#endif

copy_message(prefix, dest_file, remove_header)
char *prefix;
FILE *dest_file;
int  remove_header;
{
	/** Copy current message to destination file, with optional 'prefix' 
	    as the prefix for each line.  If remove_header is true, it will 
	    skip lines in the message until it finds the end of header line...
            then it will start copying into the file... **/

    char buffer[LONG_SLEN];
    int ok = 1, lines, in_header = 1;

    dprint2("copy_message(prefix='%s', <file>, remove-header=%s)\n", prefix,
	    remove_header? "ON" : "OFF");

    /** get to the first line of the message desired **/

    if (fseek(mailfile, header_table[current-1].offset, 0) == -1) {
       error1("msg [seek] failed trying to read %d bytes into file",
	     header_table[current-1].offset);
       return;
    }

    /* how many lines in message? */

    lines = header_table[current-1].lines;

    dprint2("\tAbout to read %d lines from msg #%d\n",
	    lines, current);

    /* now while not EOF & still in message... copy it! */

    while (ok && lines--) {
      ok = (int) (fgets(buffer, LONG_SLEN, mailfile) != NULL);
      if (strlen(buffer) < 2) in_header = 0;
      if (ok) 
	if (! (remove_header && in_header))
	  fprintf(dest_file, "%s%s", prefix, buffer);
    }
}
END-OF-FILE

size=`wc -c < src/fileio.c`

if [ $size != 1472 ]
then
  echo Warning: src/fileio.c changed - should be 1472 bytes, not $size bytes
fi

chmod 644 src/fileio.c

# ---------- file src/hdrconfg.c ----------


if [ -f src/hdrconfg.c ]
then
  echo File 'src/hdrconfg.c' already exists\!
  exit 1
fi

echo extracting file src/hdrconfg.c...
cat << 'END-OF-FILE' > src/hdrconfg.c

/**			hdrconfg.c			**/

/**   This file contains the routines necessary to be able to modify
      the mail headers of messages on the way off the machine.  The
      headers currently supported for modification are:

	Subject:
	To:
	Cc:

	Expiration-Date:
	Priority:
        In-Reply-To:
	Action:
	Security:
	
      (C) Copyright 1985, Dave Taylor
**/

#include <stdio.h>
#include "headers.h"

#include <ctype.h>

#ifdef BSD
#undef toupper
#endif

/* these are all defined in the mailout file! */

extern char subject[SLEN], action[SLEN], reply_to[SLEN], expires[SLEN], 
	    priority[SLEN];
extern char to[VERY_LONG_STRING], cc[VERY_LONG_STRING];

edit_headers(original_msg_num)
int   original_msg_num;
{
	/** edit headers, R)eturn to continue with mailing **/

	int unexpanded_to = TRUE, unexpanded_cc = TRUE;
	char c, expanded_to[VERY_LONG_STRING], expanded_cc[VERY_LONG_STRING];
	
	dprint1("edit_headers(original-msg-number=%d)\n", original_msg_num);


	if (! edit_outbound || mail_only) goto outta_here;

	display_headers();

	do {
	  PutLine(LINES-1,0,"Choice: ");
	  CleartoEOLN();
	  c = toupper(getchar());
	  clear_error();
	  switch (c) {
	    case ctrl('M'):
	    case 'R' :
	    case 'Q' : goto outta_here;
	    case ctrl('L') : display_headers();
		       break;
	    case 'T' : if (optionally_enter(to, 2, 9, TRUE) == -1)
	                 goto outta_here;
	    	       build_address(strip_commas(to), expanded_to);
		       unexpanded_to = FALSE; 
		       break;
	    case 'S' : if (optionally_enter(subject, 3, 9, FALSE) == -1)
			 goto outta_here;
		       break;
	    case 'C' : if (optionally_enter(cc, 4, 9, TRUE) == -1)
			 goto outta_here;
	  	       build_address(strip_commas(cc), expanded_cc);
		       unexpanded_cc = FALSE;
		       break;
	    case 'A' : if (optionally_enter(action, 6, 9, FALSE) == -1)
			 goto outta_here;
		       break;
	    case 'E' : enter_date(7, 17, expires);
		       break;
	    case 'P' : if (optionally_enter(priority, 9,10, FALSE) == -1)
			 goto outta_here;
		       break;
	    case 'I' : if (original_msg_num != -1) {
	                 if (optionally_enter(reply_to, 8,13, FALSE) == -1)
			   goto outta_here;
			 break;		
		       }
		       /** else fall through as an error **/
	    default  : error("Unknown header being specified!");
	  }
	} while (TRUE);

outta_here:	/* this section re-expands aliases before we leave... */

	if (unexpanded_to)
	  build_address(strip_commas(to), expanded_to);
	if (unexpanded_cc)
	  build_address(strip_commas(cc), expanded_cc);

	strcpy(to, expanded_to);
	strcpy(cc, expanded_cc);

	return;
}

display_headers()
{
	ClearScreen();

	Centerline(0,"Message Header Edit Screen");

	PutLine(2,0,"To     : %s", to);
	PutLine(3,0,"Subject: %s", subject);
	PutLine(4,0,"Cc     : %s", cc);
	PutLine(6,0,"Action :");
	PutLine(7,0,"Expiration-Date:");
	if (strlen(reply_to) > 0)
	  PutLine(8,0,"In-Reply-To: %s", reply_to);
	PutLine(9,0,"Priority:");

	Centerline(LINES-5, 
		"Pick the First Letter of the Header or R)eturn from Editing");
}

enter_date(x, y, buffer)
int x, y;
char *buffer;
{
	/** Enter the number of days this message is valid for, then
	    display at (x,y) the actual date of expiration.  This 
	    routine relies heavily on the routine 'days_ahead()' in
	    the file date.c
	**/

	int days;

	PutLine(LINES-1,0, "How many days in the future should it expire? ");
	CleartoEOLN();
	Raw(OFF);
	gets(buffer, SLEN);
	Raw(ON);
	sscanf(buffer, "%d", &days);
	if (days < 1)
	  error("That doesn't make sense!");
	else if (days > 14)
	  error("Expiration date must be within two weeks of today");
	else {
	  error1("days_ahead(%d)", days);
	  days_ahead(days, buffer);
	  PutLine(x, y, buffer);
	}
}
END-OF-FILE

size=`wc -c < src/hdrconfg.c`

if [ $size != 3711 ]
then
  echo Warning: src/hdrconfg.c changed - should be 3711 bytes, not $size bytes
fi

chmod 644 src/hdrconfg.c

# ---------- file src/help.c ----------


if [ -f src/help.c ]
then
  echo File 'src/help.c' already exists\!
  exit 1
fi

echo extracting file src/help.c...
cat << 'END-OF-FILE' > src/help.c
/**			help.c			**/

/*** help routine for MSG program 

     (C) Copyright 1985, Dave Taylor

***/

#include "headers.h"

help()
{
	/*** help me!  Read file 'helpfile' and echo to screen ***/

	FILE *hfile;
	char buffer[SLEN];
	int  lines=0;

	dprint0("help()\n");

	sprintf(buffer, "%s/%s", helphome, helpfile);
	if ((hfile = fopen(buffer,"r")) == NULL) {
	  error1("couldn't open helpfile %s",buffer);
	  return(FALSE);
	}
	
	ClearScreen();

	while (fgets(buffer, SLEN, hfile) != NULL) {
	  if (lines > LINES-3) {
	    PutLine(LINES,0,"Press any key to continue: ");
	    (void) ReadCh();
	    lines = 0;
	    ClearScreen();
	    printf("%s\r", buffer);
	  }
	  else 
	    printf("%s\r", buffer);
	  lines++;
	}

	PutLine(LINES,0,"Please type <space> to return: ");

	(void) ReadCh();
	clear_error();

	return(TRUE);
}
END-OF-FILE

size=`wc -c < src/help.c`

if [ $size != 821 ]
then
  echo Warning: src/help.c changed - should be 821 bytes, not $size bytes
fi

chmod 644 src/help.c

# ---------- file src/initialize.c ----------


if [ -f src/initialize.c ]
then
  echo File 'src/initialize.c' already exists\!
  exit 1
fi

echo extracting file src/initialize.c...
cat << 'END-OF-FILE' > src/initialize.c
/**		initialize.c		**/

/***** Initialize - read in all the defaults etc etc 
       (C) Copyright 1985 Dave Taylor
*****/

#include <stdio.h>
#ifndef BSD
#  include <termio.h>
#endif
#include <pwd.h>
#ifdef BSD
#  include <sys/time.h>
#else
#  include <time.h>
#endif
#include <signal.h>
#include <errno.h>
#include <ctype.h>

#ifdef BSD
#undef tolower
#endif

#include "headers.h"

extern int errno;		/* system error number on failure */

initialize()
{
	struct passwd *pass, *getpwnam();

	register int i;
	int      leave();
	char     buffer[SLEN];
	
	userid = getuid();
	progid = geteuid();	

	strcpy(home,getenv("HOME"));
	strcpy(shell,getenv("SHELL"));

	if (debug) {		/* setup for dprintf statements! */
	  char filename[SLEN];
	  sprintf(filename, "%s/%s", home, DEBUG);
	  if ((debugfile = fopen(filename, "w")) == NULL) {
	    debug = 0;	/* otherwise 'leave' will try to log! */
	    leave(fprintf(stderr,"Could not open file %s for debug output!\n",
		  filename));
	  }
	  chown(filename, userid, getgid()); /* file owned by user */

	  fprintf(stderr,"\r\n** Debug output going to '%s' **\n\r", filename);
	  sleep(2);
	  fprintf(debugfile, "\nDebug output of MSG program, version %s\n\n",
		  VERSION);
	}

	signal(SIGINT,  SIG_IGN);
	signal(SIGQUIT, leave);
	signal(SIGTERM, leave); 

	read_lsys();

	get_term_chars();
	
	gethostname(hostname, sizeof(hostname));
	strcpy(username,getlogin());
	if (strlen(username) == 0)
	  cuserid(username);

	/* now let's get the full username.. */

	if ((pass = getpwnam(username)) == NULL) {
	  error("Couldn't read password entry??");
	  strcpy(full_username, username);
	}
	else {
	  for (i=0; pass->pw_gecos[i] != '\0' && pass->pw_gecos[i] != ',';
	       i++)
	      full_username[i] = pass->pw_gecos[i];
	  full_username[i] = '\0'; 
	}

	editor[0] = '\0';
	strcpy(editor,getenv("EDITOR"));
	if (editor[0] == '\0')
	  strcpy(editor,default_editor);

	if (! mail_only) {
	  mailbox[0] = '\0';
	  strcpy(prefixchars, "> "); 	/* default message prefix */
	}

	read_rc_file();		/* reading the .msgrc next... */

	/** check to see if the user has defined a LINES or COLUMNS
	    value different to that in the termcap entry (for
	    windowing systems, of course!) **/

	strcpy(buffer, getenv("LINES"));
	if (isdigit(buffer[0]))
	  sscanf(buffer, "%d", &LINES);

	strcpy(buffer, getenv("COLUMNS"));
	if (isdigit(buffer[0]))
	  sscanf(buffer, "%d", &COLUMNS);

	/** fix the shell if needed **/

	if (shell[0] != '/') {
	   sprintf(buffer, "/bin/%s", shell);
	   strcpy(shell, buffer);
	}

	if (! mail_only) {
	  mailbox_defined = (mailbox[0] != '\0'); 

	  /* now get the inverse video sequences from the termcap... */
	
	  strcpy(start_highlight, return_value_of("so"));
	  strcpy(end_highlight, return_value_of("se"));
  
	  /* get the cursor control keys... */

	  strcpy(up, return_value_of("ku"));

	  if (strlen(up) != 2)	 	/* don't want arbitrary length! */
	    cursor_control = FALSE;
	  else {
	    strcpy(down, return_value_of("kd"));
	    cursor_control = TRUE;
	    transmit_functions(ON);
	  }
	}

	if (read_aliases)
  	  read_alias_files();

	if (! mail_only) {
	  if (! mbox_specified)
	    newmbox(1,FALSE);	/* read the incoming mail mailbox! */
	  else
	    newmbox(0,FALSE);	/* read the specified mail file!   */

	  if (mini_menu)
	    headers_per_page = LINES - 13;
	  else
	    headers_per_page = LINES -  8;	/* 5 more headers! */
	}

	init_findnode();	/* set up the path alias stuff */

	dprint0("\n\n------ Past the Initialization stuff ------\n\n");

	dprint3("\nhostname = '%s'   username = '%s'   full_username = '%s'\n",
	         hostname, username, full_username);

	dprint3("home = '%s'   editor = '%s'   mailbox = '%s'\n",
		 home, editor, mailbox);
	
	dprint3("hp_terminal = %s, hp_softkeys = %s, and cursor_control=%s\n\n",
		onoff(hp_terminal), onoff(hp_softkeys), onoff(cursor_control));

}

get_term_chars()
{
	/** This routine sucks out the special terminal characters
	    ERASE and KILL for use in the input routine.  The meaning 
            of the characters are (dare I say it?) fairly obvious... **/

#ifndef BSD
	struct termio term_buffer;

	if (ioctl(STANDARD_INPUT, TCGETA, &term_buffer) == -1) {
	  dprint1("** Error %d encountered on initial ioctl call **\n", errno);
	  /* set to defaults for terminal driver */
#endif
	  backspace = BACKSPACE;
	  kill_line = ctrl('U');
#ifndef BSD
	}
	else {
	  backspace = term_buffer.c_cc[VERASE];
	  kill_line = term_buffer.c_cc[VKILL];
	}
#endif
}

read_lsys()
{
	/** Read the system L.sys file and put all the machine names in
	    the talk-to-sys linked list structure! **/

	FILE *lsysfile;
	char  buffer[SLEN], sysname[NLEN];
	struct lsys_rec *system_record, *previous_record;

	previous_record = NULL;

	if ((lsysfile = fopen(Lsys,"r")) == NULL) {
	  dprint1("\nCan't open L.sys file '%s' for reading!!\n\n",
		  Lsys);
	  error("Warning: couldn't read L.sys file...");
	  talk_to_sys = NULL;
	  return;
	}

	while (fgets(buffer, SLEN, lsysfile) != NULL) {
	  sscanf(buffer,"%s", sysname);

	  if (previous_record == NULL) {
	    dprint1("\tread '%s' out of L.sys file\n", sysname);
	    previous_record = (struct lsys_rec *) malloc(sizeof *talk_to_sys);

	    strcpy(previous_record->name, sysname);
	    previous_record->next = NULL;
	    talk_to_sys = previous_record;
	  }
	  else if (! talk_to(sysname)) {
	    dprint1("\tread '%s' out of L.sys file\n", sysname);
	    system_record = (struct lsys_rec *) malloc(sizeof *talk_to_sys);
	  
	    strcpy(system_record->name, sysname);
	    system_record->next = NULL;
	    previous_record->next = system_record;
	    previous_record = system_record;
	  }
	}

	fclose(lsysfile);
}
END-OF-FILE

size=`wc -c < src/initialize.c`

if [ $size != 5676 ]
then
  echo Warning: src/initialize.c changed - should be 5676 bytes, not $size bytes
fi

chmod 644 src/initialize.c

# ---------- file src/input_utils.c ----------


if [ -f src/input_utils.c ]
then
  echo File 'src/input_utils.c' already exists\!
  exit 1
fi

echo extracting file src/input_utils.c...
cat << 'END-OF-FILE' > src/input_utils.c
/**			input_utils.c			**/

/** Mindless I/O routines for MSG 
	
    (C) Copyright 1985 Dave Taylor
**/

#include "headers.h"

int
want_to(s, def, echo_answer)
char *s, def;
int  echo_answer;
{
	/** ask 's' at 20,40, return answer in lower case.
	    If 'echo_answer', then echo answer.  'def' is the
  	    default answer if <return> is pressed.
	**/
	register char ch;

	if (strlen(s) < 30)
	  MoveCursor(LINES-3, COLUMNS-40);
	else
	  MoveCursor(LINES-3, COLUMNS-50);
	printf("%s%c%c", s, def, BACKSPACE);
	fflush(stdout);
	ch = tolower(ReadCh());

	if (echo_answer && ch > (char) ' ')
	  putchar(ch);

	return(ch);
}

int
read_number(ch, max)
char ch;
int max;
{
	/** read a number, where 'ch' is the leading digit! 
	    If max < 10 then just return 'ch' **/
	
	char buff[SHORT_SLEN];
	int  num;

	if (max < 10)
	  return( (int) ch - '0' );
	
	buff[0] = ch;
	buff[1] = '\0';

	PutLine(LINES-3, COLUMNS-40,"Set current message to :");
	if (optionally_enter(buff, LINES-3, COLUMNS-15, TRUE) == -1)
	  return(current);

	sscanf(buff,"%d", &num);
	return(num);
}

int
optionally_enter(string, x, y, append_current)
char *string;
int  x,y, append_current;
{
	/** Display the string on the screen and if RETURN is pressed, return 
	    it.  Otherwise, allow standard text input, including backspaces 
	    and such until RETURN is hit.  
	    If "append_current" is set, then leave the default string in 
	    place and edit AFTER it...assume 'x,y' is placing us at the
	    beginning of the string...
	    This routine returns zero unless INTERRUPT hit, then it returns
	    -1 and must be treated accordingly.
	**/

	char ch;
	register index = 0;

	MoveCursor(x,y);
	printf("%s", string);	
	CleartoEOLN();
	if (! append_current)
	  MoveCursor(x,y);

	if (cursor_control)
	  transmit_functions(OFF);

	ch = getchar();

	if (ch == '\n' || ch == '\r') {
	  if (cursor_control)
	    transmit_functions(ON);
	  return(0);	/* we're done.  No change needed */
	}
	
	CleartoEOLN();

	index = (append_current? strlen(string) : 0);

	if (ch == kill_line) {
	  if (! mail_only)
	    MoveCursor(x,y);
          CleartoEOLN();
	  index = 0;
	}
	else if (ch != backspace) {
	  putchar(ch);
	  string[index++] = ch;
	}
	else if (index > 0) {
	  index--;
	  putchar(BACKSPACE);
	  putchar(' ');
	  putchar(BACKSPACE);
	  fflush(stdout);
	}
	else {
	  putchar(' ');
	  putchar(BACKSPACE);
	  fflush(stdout);
	}

	do {
	  ch = getchar();

	  /* the following is converted from a case statement to
	     allow the variable characters (backspace, kill_line
	     and break) to be processed.  Case statements in
	     C require constants as labels, so it failed ...
	  */

	    if (ch == backspace) {
              if (index > 0) {
		index--;
		putchar(BACKSPACE);
		putchar(' ');
		putchar(BACKSPACE);
	        fflush(stdout);
	      }
	      else {
		putchar(' ');
		putchar(BACKSPACE);
	        fflush(stdout);
	      }
	    }
	    else if (ch == '\n' || ch == '\r') {
	      string[index] = '\0';
	      if (cursor_control)
	        transmit_functions(ON);
	      return(0);
	    }
	    else if (ch == kill_line) {
	      if (mail_only)
	        back_up(index+1);
	      else
	        MoveCursor(x,y);
              CleartoEOLN();
	      index = 0;
	    }
	    else if (ch == NULL) {
	      if (cursor_control)
	        transmit_functions(ON);
	      fflush(stdin); 	/* remove extraneous chars, if any */
	      string[0] = '\0'; /* clean up string, and... */
	      return(-1);
	    }
	    else {  /* default case */
		        
	      string[index++] = ch;
	      putchar(ch);
	   }
	} while (index < SLEN);

	string[index] = '\0';

	if (cursor_control)
	  transmit_functions(ON);
	return(0);
}


int
pattern_enter(string, alt_string, x, y, alternate_prompt)
char *string, *alt_string, *alternate_prompt;
int  x,y;
{
	/** This function is functionally similar to the routine
	    optionally-enter, but if the first character pressed
	    is a '/' character, then the alternate prompt and string
	    are used rather than the normal one.  This routine 
	    returns 1 if alternate was used, 0 if not
	**/

	char ch;
	register index = 0;

	dprint4("pattern_enter(string='%s', alt_string='%s', x=%d, y=%d,\n", 
		string, alt_string, x, y);
	dprint1("              alt-prompt='%s')\n", alternate_prompt);

	MoveCursor(x,y);
	printf("%s", string);	
	CleartoEOLN();
	MoveCursor(x,y);

	if (cursor_control)
	  transmit_functions(OFF);

	ch = getchar();

	if (ch == '\n' || ch == '\r') {
	  if (cursor_control)
	    transmit_functions(ON);
	  return(0);	/* we're done.  No change needed */
	}
	
	if (ch == '/') {
	  MoveCursor(x, 0);
	  CleartoEOLN();
	  printf("%s", alternate_prompt);
	  (void) optionally_enter(alt_string, x, strlen(alternate_prompt)+1,
		 FALSE);
	  return(1);
	}

	CleartoEOLN();

	index = 0;

	if (ch == kill_line) {
	  MoveCursor(x,y);
          CleartoEOLN();
	  index = 0;
	}
	else if (ch != backspace) {
	  putchar(ch);
	  string[index++] = ch;
	}
	else if (index > 0) {
	  index--;
	  putchar(BACKSPACE);
	  putchar(' ');
	  putchar(BACKSPACE);
	}
	else {
	  putchar(' ');
	  putchar(BACKSPACE);
	}

	do {
	  fflush(stdout);
	  ch = getchar();

	  /* the following is converted from a case statement to
	     allow the variable characters (backspace, kill_line
	     and break) to be processed.  Case statements in
	     C require constants as labels, so it failed ...
	  */

	    if (ch == backspace) {
              if (index > 0) {
		index--;
		putchar(BACKSPACE);
		putchar(' ');
		putchar(BACKSPACE);
	      }
	      else {
		putchar(' ');
		putchar(BACKSPACE);
	      }
	    }
	    else if (ch == '\n' || ch == '\r') {
	      string[index] = '\0';
	      if (cursor_control)
	        transmit_functions(ON);
	      return(0);
	    }
	    else if (ch == kill_line) {
	      MoveCursor(x,y);
              CleartoEOLN();
	      index = 0;
	    }
	    else if (ch == NULL) {
	      if (cursor_control)
	        transmit_functions(ON);
	      fflush(stdin); 	/* remove extraneous chars, if any */
	      string[0] = '\0'; /* clean up string, and... */
	      return(-1);
	    }
	    else {  /* default case */
		        
	      string[index++] = ch;
	      putchar(ch);
	   }
	} while (index < SLEN);

	string[index] = '\0';

	if (cursor_control)
	  transmit_functions(ON);
	return(0);
}

back_up(spaces)
int spaces;
{
	/** this routine is to replace the goto x,y call for when sending
	    mail without starting the entire "msg" system up... **/
	
	dprint1("back-up(spaces=%d)\n", spaces);

	while (spaces--) {
	  putchar(BACKSPACE);
	  putchar(' ');
	  putchar(BACKSPACE);
	}

	fflush(stdout);
}
END-OF-FILE

size=`wc -c < src/input_utils.c`

if [ $size != 6604 ]
then
  echo Warning: src/input_utils.c changed - should be 6604 bytes, not $size bytes
fi

chmod 644 src/input_utils.c

# ---------- file src/leavembox.c ----------


if [ -f src/leavembox.c ]
then
  echo File 'src/leavembox.c' already exists\!
  exit 1
fi

echo extracting file src/leavembox.c...
cat << 'END-OF-FILE' > src/leavembox.c
/**			leavembox.c			**/

/** leave current mailbox, updating etc. as needed...
  
    (C) Copyright 1985, Dave Taylor
**/

#include "headers.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>

#define  ECHOIT 	1	/* echo on for prompting! */

/** added due to a bug in the 2.1 OS **/

struct utimbuf {
	time_t	actime;		/** access time **/
	time_t  modtime;	/** modification */
       };

extern int errno;

int
leave_mbox(quitting)
int quitting;
{
	/** Exit, saving files into mbox and deleting specified, or simply 
	    delete specified mail... If "quitting" is true, then output status 
            regardless of what happens.  Returns TRUE iff mailfile was
	    changed (ie messages deleted from file)
	**/

	FILE *temp;
	char outfile[SLEN], buffer[SLEN];
	struct stat buf;		/* stat command  */
	struct utimbuf times;		/* utime command */
	register int to_delete = 0, to_save = 0, i, mode = 00644,
		     pending = 0;

	dprint0("leave_mbox()\n");

	if (message_count == 0)
	  return(FALSE);	/* nothing changed */

	for (i = 0; i < message_count; i++)
	  if (header_table[i].delete) to_delete++;
	  else                        to_save++;

	dprint2("\t%d messages to delete and %d to save\n", to_delete, to_save);

	if (mbox_specified == 0) 
	  update_mailtime();

	if (to_delete)
	  if (to_save) {
	    sprintf(buffer, "Delete message%s? (y/n) ", to_save == 1? "" : "s");
	    if (want_to(buffer, 'n', ECHOIT) != 'y') {
	      if (mbox_specified == 0) unlock();	/* remove lock! */
	      dprint0("\tNothing deleted ('n' to delete messages)\n");
	      error("Nothing deleted");
	      return(FALSE);	/* nothing was deleted! */
	    }
	  }
	  else if (! to_save) 
	    if (want_to("Delete all messages? (y/n) ", 'n', ECHOIT) != 'y') {
	      if (mbox_specified == 0) unlock();	/* remove lock! */
	      dprint0("\tNothing deleted (don't want to delete all msgs)\n");
	      error("Nothing deleted");
	      return(FALSE);   /* nothing was deleted */
	    }
	  
	if (to_save && mbox_specified == 0) 
	  if (want_to("Keep mail in incoming mailbox? (y/n) ",'n',ECHOIT)=='y') 
	    if (to_delete)	/* okay - keep undeleted as pending! */
	      pending++;
	    else {		/* gag! nothing to delete, don't save!  */	
	      unlock();		/* remove mailfile lock!		*/
	      dprint0("\tIncoming mailbox unchanged (nothing to delete\n");
	      error("Mailbox unchanged");
	      return(FALSE);	/* nothing changed! */
	    }

	/** okay...now lets do it! **/

	if (to_save > 0) {
	  if (to_delete > 0)
	    sprintf(buffer ,"[%s %d message%s, and deleting %d]", 
	          pending? "keeping" : "storing", 
		  to_save, plural(to_save), to_delete);
	  else if (quitting)
	    sprintf(buffer,"[%s %s]",
	          pending? "keeping" : "storing",
		  to_save > 1? "all messages" : "message");
	  else
	    buffer[0] = '\0';	/* no string! */
	}
	else {
	  if (to_delete > 0)
	    sprintf(buffer, "[deleting all messages]");
	  else if (quitting)
	    sprintf(buffer, "[no messages to %s, and none to delete]",
	            pending? "keep" : "save");
	  else
	    buffer[0] = '\0';
	}

	error(buffer);

	if (! mbox_specified) {
	  if (pending) {                /* keep some messages pending! */
	    sprintf(outfile,"%s%d", temp_mbox, getpid());
	    unlink(outfile);
	  }
	  else if (mailbox_defined)	/* save to specified mailbox */
	    strcpy(outfile, mailbox);
	  else				/* save to $home/mbox */
	    sprintf(outfile,"%s/mbox", home);
	}
	else {
	  if (! to_delete) return(FALSE);	/* no work to do! */
          sprintf(outfile, "%s%d", temp_file, getpid());
	  unlink(outfile); /* ensure it's empty! */
	}

	if (to_save) {
	  if ((temp = fopen(outfile,"a")) == NULL) {
	    if (mbox_specified == 0)
	      unlock();		/* remove mailfile lock! */
	    dprint1("\tCould not append to file %s!\n", outfile);
	    sprintf(buffer, "           Could not append to file %s!          ",
		    outfile);
	    leave(Centerline(LINES-1, buffer));
	  }
  
	  for (i = 0; i < message_count; i++)
	    if (header_table[i].delete == 0) {
	      current = i+1;
	      dprint1("\tsaving message %d\n", current);
	      copy_message("", temp, FALSE);
	    }
	  fclose(temp);
	}

	/* remove source file...either default mailbox or original copy of 
           specified one! */

	if (mbox_specified == 0) {
	  /** let's grab the original mode and date/time of the mailfile 
	      before removing it **/

          if (stat(infile, &buf) == 0)
	    mode = buf.st_mode & 00777;
	  else {
	    dprint2("\tencountered error #%d on stat(%s)\n", errno, infile);
            error2("Error %d on stat(%s)!", errno, infile);
	  }
	}

	fclose(mailfile);	/* close the baby... */
	unlink(infile); 	/* and BLAMO!        */

	if (to_save && (mbox_specified || pending)) {
	  if (link(outfile, infile) != 0) 
	    if (errno == EXDEV) { /** different file devices!  Use copy! **/
	      if (copy(outfile, infile) != 0) {
	        dprint2("\tCouldn't modify mail file: copy(%s, %s) failed!\n",
			outfile, infile);
	        error("couldn't modify mail file!");
	        sleep(1);
	        sprintf(infile,"%s/%s", home, unedited_mail);
		if (copy(outfile, infile) != 0) {
	          dprint1("\tcouldn't copy to %s either!!  Help!\n", infile);
	          error("something godawful is happening to me!!!");
		  emergency_exit();
	        }
		else {
	          dprint1("\tsaved mailbox as file %s\n", infile);
	          error1("saved mailbox as %s", infile);
	        }
	      }	
	    }
	    else {
	      dprint3("\tlink(%s, %s) failed with error %d\n", outfile, 
		      infile, errno);
	      error1("link failed for unknown reasons [errno=%d!!", errno);
	      emergency_exit();
	    }
	  unlink(outfile);
	}

	if (mbox_specified == 0) {
	  if (mode != 00644) { /* if not the default mail access mode... */
	    if (! pending) { /* if none still being saved */
	      temp = fopen(infile, "w");
	      fclose(temp);
	    }
	    chmod(infile,mode);
	
	    /* let's set the access times of the new mail file to be
	       the same as the OLD one (still sitting in 'buf') ! */

	    times.actime = buf.st_atime;
	    times.modtime= buf.st_mtime;
	    if (utime(infile, &times) != 0) {
	      dprint2("\tencountered error %d on utime(%s)\n", 
		      errno, infile);
	      error1("Error %d trying utime", errno);
	    }
	  }
	  unlock();	/* remove the lock on the file ASAP! */

	  /** finally, let's change the ownership of the default
	      outgoing mailbox, if needed **/

	  if (to_save) {
	    dprint3("\tchown(%s, %d, %d)\n", outfile, userid, getgid());
	    chown(outfile, userid, getgid());
	  }
	}

	dprint3("\tchown(%s, %d, %d)\n", infile, userid, getgid());

	chown(infile, userid, getgid());	/* file owned by user */

	return(to_delete);	
}

char lock_name[SLEN];
extern int errno;	/* system error number! */

lock(direction)
int direction;
{
	/** Create lock file to ensure that we don't get any mail 
	    while altering the mailbox contents!
	    If it already exists sit and spin until 
               either the lock file is removed...indicating new mail
	    or
	       we have iterated MAX_ATTEMPTS times, in which case we
	       either fail or remove it and make our own (determined
	       by if REMOVE_AT_LAST is defined in header file

	    If direction == INCOMING then DON'T remove the lock file
	    on the way out!  (It'd mess up whatever created it!).
	**/

	register int iteration = 0, stat_val;
	struct stat buffer;

	dprint1("lock(direction=%s)\n", direction? "INCOMING" : "OUTGOING");

	sprintf(lock_name,"%s%s.lock", mailhome, username);

	stat_val = stat(lock_name, &buffer);

	while (stat_val != -1 && iteration++ < MAX_ATTEMPTS) {
	  dprint2("\tstat(%s) returned %d\n",
		   lock_name, stat_val);
	  if (direction == INCOMING)
	    fprintf(stderr,"Mail being received!\nwaiting...");
	  else
	    error2("Attempt %d: Mail being received (%d)...waiting", 
                   iteration, stat_val);
	  sleep(5);
	  stat_val = stat(lock_name, &buffer);
	}
	
	if (stat_val != -1) {
#ifdef REMOVE_AT_LAST
	  /** time to waste the lock file!  Must be there in error! **/
	  error("Throwing away the current lock file!");
	  dprint0("\tthrowing away current lock file!\n");
	  if (unlink(lock_name) != 0) {
	    dprint0("\tcouldn't unlink!!  Error was %d\n", errno);
	    leave(error("could not remove current lock file!"));
	  }
	  
	  /* everything is okay, so lets act as if nothing had happened... */
#else
	  /* okay...we die and leave, not updating the mailfile mbox or
	     any of those! */
	  if (direction == INCOMING) {
	    printf("Giving up after %d iterations...\n", iteration);
	    printf("Try again later, please.\n");
	    dprint1("\tbailing out after %d iterations...\n", iteration);
	    leave_locked();
	  }
	  else {
	    dprint1("\ttimed out on lock file reads.  Iterations=%d\n", 
	            iteration);
	    leave(error("Timed out on lock file reads.  Bye!"));
	  }
#endif
	}

	/* if we get here we can create the lock file, so lets do it! */

	if (creat(lock_name, 0) == -1) {
	  dprint2("\tCan't create lock file: creat(%s) raises error %d\n", 
		  lock_name, errno);
	  if (errno == EACCES)
	    leave(error(
                 "Can't create lock file!  Make sure I'm setuid root!\n\r"));
	  else
	    leave(error1("error %d attempting to create lock file!", errno));
	}

}

unlock()
{
	/** Remove the lock file!    This must be part of the interrupt
	    processing routine to ensure that the lock file is NEVER
	    left sitting in the mailhome directory! **/

	dprint0("unlock()\n");

	(void) unlink(lock_name);
}
END-OF-FILE

size=`wc -c < src/leavembox.c`

if [ $size != 9540 ]
then
  echo Warning: src/leavembox.c changed - should be 9540 bytes, not $size bytes
fi

chmod 644 src/leavembox.c

# ---------- file src/mailout.c ----------


if [ -f src/mailout.c ]
then
  echo File 'src/mailout.c' already exists\!
  exit 1
fi

echo extracting file src/mailout.c...
cat << 'END-OF-FILE' > src/mailout.c
/** 			mailout.c			**/

/** Interface to allow mail to be sent to users.  Part of MSG  **/

/** (C) Copyright 1986, Dave Taylor 			       **/

/** System output is a line of the form;

	sendmail -oi addresses < tempfile
    or
	mailer addresses < tempfile

    Changed 8/12 to conform to RFC-822 style headers (ARPA and so on)
    Changed 9/23 to deal with commas, and other bug fixes
    Changed 9/24 to add reading the users .mailheaders file
    Changed 10/26 to use the shared subject, to, cc, etc fields
    Changed 2/20 to use batch_subject, if specified 
**/

#include "headers.h"

/** strings defined for the hdrconfg routines **/

char subject[SLEN], action[SLEN], reply_to[SLEN], expires[SLEN], priority[SLEN];
char to[VERY_LONG_STRING], cc[VERY_LONG_STRING];

char *format_long(), *strip_commas(), *tail_of_string();

int gotten_key = 0;

int
send(given_to, given_subject, edit_message)
char *given_to, *given_subject;
int   edit_message;
{
	/** Prompt for fields and then call mail() to send the specified
	    message.  If 'edit_message' is true then don't allow the
            message to be edited. **/

	char address[VERY_LONG_STRING];  /* BIG address! */
	char addressII[VERY_LONG_STRING];
	char *buffer;			/* misc, for I/O */

	int  copy_msg = FALSE, is_a_response = FALSE;

	dprint2("send(to='%s', subject='%s')\n", given_to, given_subject);

	/* zero all current global message strings */

	cc[0] = action[0] = reply_to[0] = expires[0] = priority[0] = '\0';

	addressII[0] = '\0';

	/* initialize 'to' and 'subject' according to what we were given */

	strcpy(subject, given_subject);
	strcpy(to, given_to);

	/** Copy message? **/

	if (strlen(to) > 0 && !mail_only) {	/* predefined 'to' line! */
	  if (auto_copy) 
	    copy_msg = TRUE;
	  else 
	    copy_msg = (want_to("Copy message? (y/n) ", 'n', TRUE) == 'y');
	  is_a_response = TRUE;
	}
	else
	  if (strlen(subject) > 0)  	/* predefined 'subject' (Forward) */
	    copy_msg = TRUE;

	/**  To:  **/
 
	if (strlen(to) == 0) {
	  PutLine(LINES-2, 0, "To: ");
	  (void) optionally_enter(to, LINES-2, 4, FALSE); 
	  if (strlen(to) == 0) {
	    MoveCursor(LINES-2,0);	CleartoEOLN();
	    error("mail not sent");
	    return(0);
	  }
	  build_address(strip_commas(to), address); 
	}
	else if (mail_only) 
	  build_address(strip_commas(to), address); 
	else 
	  strcpy(address, to);
	
	if (strlen(address) == 0) {	/* bad address!  Removed!! */
	  if (! mail_only)
	    ClearLine(LINES-2);
	  return(0);
	}

	if (! mail_only) {
	  MoveCursor(LINES-3, COLUMNS-50);
	  CleartoEOLN();
	  printf("          "); 	/* 10 spaces */
	}

	if (mail_only && strlen(batch_subject) > 0) {

	  /** User wants to send the mail without editing or anything...
	      just suck in stdin for the file and don't prompt for anything! 
	  **/

	  strcpy(subject, batch_subject);

	  mail(address, NULL, FALSE, FALSE, FALSE, TRUE);
	
	  return;
	}

	if (mail_only && check_only) {
	  printf("Expands to: %s\n", format_long(address, 12));
	  leave();
	}

	if (mail_only)
	  printf("To: %s\n\r", format_long(address));
	else {
	  if (strlen(address) > COLUMNS-50) {
	    buffer = tail_of_string(address, COLUMNS-50);
	    printf("To: (%s)", buffer);
	  }
	  else
	    printf("To: %s", address);
	}
  
	/** Subject: **/

	if (mail_only)
	  printf("Subject: ");
	else 
	  PutLine(LINES-2,0,"Subject: ");
	CleartoEOLN();
	if (optionally_enter(subject, LINES-2, 9, TRUE) == -1) {
	  MoveCursor(LINES-2,0); 	CleartoEOLN();
	  error("mail not sent");
	  return(0);
	}

	if (strlen(subject) == 0) {
	  if (mail_only) 
	    printf("\n\rNo subject - Continue with message? (y/n) ");
	  else
	    PutLine(LINES-2,0,"No subject - Continue with message? (y/n) ");
	  printf("n%c", BACKSPACE);
	  fflush(stdout);
	  if (tolower(ReadCh()) != 'y') {
	    if (mail_only) {
	      printf("\n\r\n\rMail Cancelled!\n\r");
	      return(0);
	    }
	    MoveCursor(LINES-2,0);	CleartoEOLN();
	    error("mail not sent");
	    return(0);
	  }
	  else if (! mail_only) {
	    PutLine(LINES-2,0,"Subject: <none>");
	    CleartoEOLN();
	  }
	}

	/** Copies to: **/

	if (mail_only)
	  printf("\n\rCopies To: ");
	else
	  PutLine(LINES-1,0,"Copies To: ");

	fflush(stdout);

	if (optionally_enter(cc, LINES-1, 11, FALSE) == -1) {
	  if (mail_only) {
	    printf("\n\r\n\rMail not sent!\n\r");
	    return(0);
	  }
	  MoveCursor(LINES-2,0); 	CleartoEOLN();
	  MoveCursor(LINES-1,0); 	CleartoEOLN();
	  error("mail not sent");
	  return(0);
	}
	  
	build_address(strip_commas(cc), addressII);

	if (strlen(address) + strlen(addressII) > VERY_LONG_STRING) {
	  error("Too many people.  Copies ignored");
	  cc[0] = '\0';
	}
	
	if (mail_only) 
	  printf("\n\r");
	else
	  MoveCursor(LINES,0);	/* you know you're hit <return> ! */

	/* and mail that puppy outta here! */

	mail(address, addressII, copy_msg, is_a_response, edit_message, FALSE);
	
	return(edit_message);
}

mail(expanded_to, expanded_cc, copy_msg, is_a_response, edit_message, batch)
char *expanded_to, *expanded_cc;
int  copy_msg, is_a_response, edit_message, batch;
{
	/** Given the addresses and various other miscellany (specifically, 
	    'copy-msg' indicates whether a copy of the current message should 
	    be included, 'is-a-response' indicates if 'In-Reply-To:' should be 
	    generated for this message, 'edit_message' indicates whether the
	    message should be edited and 'batch' indicates that the message
	    should be read from stdin) this routine will invoke an editor for
	    the user and then actually mail off the message.
	**/

	FILE *reply, *real_reply; /* second is post-input buffer */
	FILE *headerfile;	  /* copy default headers        */
	char buffer[LONG_SLEN], filename[SLEN], filename2[SLEN],
             very_long_buffer[VERY_LONG_STRING];
	char hfname[SLEN], ret_ch;
	register int i, crypted=0, encoded_lines = 0, retransmit = 0;

	static int cancelled_msg = 0;
	
	dprint6("mail(to='%s', cc='%s', copy-msg=%s, is-a-response=%s, edit-message=%s, batch=%s)\n", 
	         expanded_to, expanded_cc, onoff(copy_msg), 
	         onoff(is_a_response), onoff(edit_message), onoff(batch));

	sprintf(filename,"%s%d",temp_file, getpid());

	if (! batch) {
	  if ((reply = fopen(filename,"r")) != NULL && cancelled_msg) {
	    Raw(ON);
	    if (copy_msg)
	      PutLine(LINES-1,0,"Recall last kept message instead? (y/n) ");
	    else
	      PutLine(LINES-1,0,"Recall last kept message? (y/n) ");
	    CleartoEOS();
	    printf("y%c", BACKSPACE);
	    fflush(stdout);
	    if (tolower(ReadCh()) != 'n') {
	      printf("Yes");	fflush(stdout);
              retransmit++;
	    }
	    else {
	      printf("No");	fflush(stdout);
              fclose(reply);
	    }
	    cancelled_msg = 0;
	  }
	}

	if (! retransmit)
	  if ((reply = fopen(filename,"w")) == NULL)
	    return(error1("Could not create file %s",filename));

	if (copy_msg) 
	  if (edit_message) 
	    copy_message(prefixchars, reply, noheader);
	  else
	    copy_message("", reply, noheader);
	
	if (batch) {
	  Raw(OFF);
	  ret_ch = '\n';
	  if (isatty(fileno(stdin))) {
	    printf("To: %s\nSubject: %s\n", expanded_to, subject);
	    printf("\nPlease enter your message, ending with a ^D:\n\n");
	    ret_ch = '\0';
	  }
	  while (gets(very_long_buffer, VERY_LONG_STRING) != NULL) 
	    fprintf(reply, "%s%c", very_long_buffer, ret_ch);

	  if (isatty(fileno(stdin))) 
	    printf("\n<end-of-message>\n");
	}

	fclose(reply);

	if (edit_message) {
	  sprintf(buffer,"%s %s", editor, filename);

	  Raw(OFF);
	  chown(filename, userid, getgid());
	  if ((i =system_call(buffer,SH)) != 0)	{ 	/* edit mail as user */
	    error1("Problems with the editor: error %d", i);
	    MoveCursor(LINES-1,0); CleartoEOLN();
	    sleep(2);
	  }
	
	  Raw(ON);
	}

	if ((reply = fopen(filename,"r")) == NULL)
	  return(error("Could not open reply file"));

	/* make sure this twit really wants to send mail before we go any 
	   further! */

	generate_reply_to((is_a_response? current-1 : -1));

	edit_headers((is_a_response? current-1 : -1));

	if (check_first && ! batch) {
	  if (mail_only) {
	    printf("\n\rAre you sure you want to send this? (y/n) ");
	    CleartoEOLN();
	    printf("y%c", BACKSPACE);
	    fflush(stdin);	/* wait for answer! */
	    fflush(stdout);
	    if (tolower(ReadCh()) == 'n') { /* sigh... */
	      printf("No\n\r\n\r\n\rMail not sent!!\n\r");
	      return(0);
	    }
	    else
	      printf("Yes\n\r\n\r");
	  }
	  else {
	    MoveCursor(LINES,0);
	    CleartoEOLN();
	    MoveCursor(LINES-1,0);
	    printf("Are you sure you want to send this? (y/n) ");
	    CleartoEOLN();
	    printf("y%c", BACKSPACE);
	    fflush(stdin);	/* wait for answer! */
	    fflush(stdout);
	    if (tolower(ReadCh()) == 'n') { /* sigh... */
	      printf("No");
	      set_error(
           "Message kept - Can be restored at next F)orward, M)ail or R)eply ");
	      cancelled_msg = 1;
	      fclose(reply);
	      return(1);
	    }
	    printf("Yes!");
	    fflush(stdout);
	  }
	}

	cancelled_msg = 0;	/* it ain't cancelled, is it? */

	/** grab a copy if the user so desires... **/

	if (auto_cc && ! batch)
	  save_copy(subject, expanded_to, expanded_cc, filename, to);

	/** write all header information into real_reply **/

	sprintf(filename2,"%s%d",temp_file, getpid()+1);
	
	if ((real_reply = fopen(filename2,"w")) == NULL) {
	  /* contingency: use mailx... */
	  if (cc[0] != '\0')  		/* copies! */
	    sprintf(to,"%s %s", to, cc);

	  sprintf(very_long_buffer, "(%s -s \"%s\" %s < %s ; %s %s)&",
                  mailx, subject, strip_commas(to), filename, remove, filename);
	  error1("couldn't open %s for writing!", filename2);
	  sleep(2);	/* ensure time to see this prompt! */
	  
	}
	else {
	  /* write header to file then message... */

	  fprintf(real_reply, "To: %s\n", format_long(to, strlen("To:")));

	  fprintf(real_reply,"Date: %s\n", (char *) get_arpa_date());

	  fprintf(real_reply,"From: %s!%s (%s)\n", hostname, username,
		  full_username);

	  fprintf(real_reply, "Subject: %s\n", subject);

	  if (cc[0] != '\0')
	    fprintf(real_reply, "Cc: %s\n", 
		    format_long(cc, strlen("Cc: ")));

	  if (strlen(action) > 0)
	    fprintf(real_reply, "Action: %s\n", action);
	
	  if (strlen(priority) > 0)
	    fprintf(real_reply, "Priority: %s\n", priority);
	
	  if (strlen(expires) > 0)
	    fprintf(real_reply, "Expiration-Date: %s\n", expires);
	
	  if (strlen(reply_to) > 0)
	    fprintf(real_reply, "In-Reply-To: %s\n", reply_to);
	
	  /*** add the users .mailheaders file if available ***/

	  sprintf(hfname, "%s/%s", home, mailheaders);

	  if ((headerfile = fopen(hfname, "r")) != NULL) {
	    while (fgets(buffer, LONG_SLEN, headerfile) != NULL)
	      fprintf(real_reply, "%s", buffer);
	    fclose(headerfile);
	  }

	  fprintf(real_reply, "X-Mailer: msg [version %s]\n", VERSION);
	  fprintf(real_reply, "\n");

 	  /** now copy message across! **/

	  while (fgets(buffer, LONG_SLEN, reply) != NULL) {
	    if (buffer[0] == '[') {
	      if (strncmp(buffer, START_ENCODE, strlen(START_ENCODE))==0)
	        crypted = 1;
	       else if (strncmp(buffer, END_ENCODE, strlen(END_ENCODE))==0)
	        crypted = 0;
	       else if (strncmp(buffer, DONT_SAVE, strlen(DONT_SAVE)) == 0)
	        continue;	/* next line? */
	      }
	      else if (crypted) {
	        if (! gotten_key++)
	          getkey(ON);
	        else if (! encoded_lines++)
	          get_key_no_prompt();		/* reinitialize.. */
	        
		encode(buffer);
	      }
	    fputs(buffer, real_reply);
	  }

	  fclose(reply);
	  fclose(real_reply);

	  if (cc[0] != '\0')  /* copies! */
	    sprintf(to,"%s %s", to, cc);

	  if (access(sendmail, EXECUTE_ACCESS) == 0)	/* yeah!  Sendmail! */
	    sprintf(very_long_buffer,"(%s %s %s < %s ; %s %s) &",
                  sendmail, sendmailflags, strip_commas(to), filename2, 
		  remove, filename2);
	  else /* oh well, use default mailer... */
            sprintf(very_long_buffer,"(%s %s < %s ; %s %s) &", 
                  mailer, strip_commas(to), filename2, 
		  remove, filename2);
	}
	
	if (mail_only) {
	  if (! batch) {
	    printf("sending mail...");
	    fflush(stdout);
	  }
	}
	else {	
	  PutLine(LINES,0,"sending mail...");
	  CleartoEOLN();
	}

	dprint1("\n\n\t%s\n\n", very_long_buffer);
	system(very_long_buffer);

	if (mail_only) {
	  if (! batch)
	    printf("\rmail sent!      \n\r");
	}
	else 
	  set_error("Mail sent!");

	return(TRUE);
}
END-OF-FILE

size=`wc -c < src/mailout.c`

if [ $size != 12387 ]
then
  echo Warning: src/mailout.c changed - should be 12387 bytes, not $size bytes
fi

chmod 644 src/mailout.c

# ---------- file src/mailtime.c ----------


if [ -f src/mailtime.c ]
then
  echo File 'src/mailtime.c' already exists\!
  exit 1
fi

echo extracting file src/mailtime.c...
cat << 'END-OF-FILE' > src/mailtime.c
/**			mailtime.c			**/

/** This set of routines is used to figure out when the user last read
    their mail and to also figure out if a given message is new or not.

    (C) Copyright 1986 Dave Taylor
**/

#include "headers.h"

#include <sys/types.h>
#include <sys/stat.h>
#ifdef BSD
#  include <sys/time.h>
#else
#  include <time.h>
#endif

resolve_received(entry)
struct header_rec *entry;
{
	/** Entry has the data for computing the time and date the 
	    message was received.  Fix it and return **/

	dprint0("resolve_received(<entry>)\n");

	switch (tolower(entry->month[0])) {
	  case 'j' : if (tolower(entry->month[1]) == 'a')
		       entry->received.month = JANUARY;
		     else if (tolower(entry->month[2]) == 'n')
	               entry->received.month = JUNE;
		     else
	               entry->received.month = JULY;
	             break;
	  case 'f' : entry->received.month = FEBRUARY;
	 	     break;
	  case 'm' : if (tolower(entry->month[2]) == 'r')
	               entry->received.month = MARCH;
		     else
		       entry->received.month = MAY;
	             break;
	  case 'a' : if (tolower(entry->month[1]) == 'p')
	               entry->received.month = APRIL;
	             else
	               entry->received.month = AUGUST;
		     break;
	  case 's' : entry->received.month = SEPTEMBER;
		     break;
	  case 'o' : entry->received.month = OCTOBER;
		     break;
	  case 'n' : entry->received.month = NOVEMBER;
	  	     break;
	  case 'd' : entry->received.month = DECEMBER;
		     break;
	}

	sscanf(entry->day, "%d", &(entry->received.day));

	sscanf(entry->year, "%d", &(entry->received.year));
	if (entry->received.year > 100) entry->received.year -= 1900;

	sscanf(entry->time, "%d:%d", &(entry->received.hour),
	       &(entry->received.minute));

	dprint3("\tthis message received %d/%d/%d at", 
		entry->received.month,
		entry->received.day,
		entry->received.year);
	dprint2("%d:%d\n", entry->received.hour, entry->received.minute);
}

get_mailtime()
{
	/** Instantiate the values of the last_read_mail stat
	    variable based on the file access time/date of the
	    file mailtime_file.  IF the file doesn't exist,
	    then assume all mail is new. **/

	struct stat buffer;
	struct tm   *timebuf;
	char   filename[SLEN];

	dprint0("get_mailtime()\n");

	sprintf(filename, "%s/%s", home, mailtime_file);

	if (stat(filename, &buffer) == -1) {
	  last_read_mail.month = 0;
	  last_read_mail.day = 0;
	  last_read_mail.year = 0;
	  last_read_mail.hour = 0;
	  last_read_mail.minute = 0;
	}
	else {	/* stat okay... */
	  timebuf = (struct tm *) localtime(&(buffer.st_mtime));
	  
	  last_read_mail.month = timebuf->tm_mon;
	  last_read_mail.day = timebuf->tm_mday;
	  last_read_mail.year = timebuf->tm_year;
	  last_read_mail.hour = timebuf->tm_hour;
	  last_read_mail.minute = timebuf->tm_min;
	}

	dprint3("\tmail time set to %d/%d/%d at ", last_read_mail.month, 
	        last_read_mail.day, last_read_mail.year);
	dprint2("%d:%02d\n", last_read_mail.hour, last_read_mail.minute);
}

update_mailtime()
{
	/** This routine updates the last modified time of the 
	    .last_read_mail file in the users home directory.
	    If the file doesn't exist, it creates it!! **/

	char filename[SLEN];
	
	sprintf(filename, "%s/%s", home, mailtime_file);

	if (utime(filename, NULL) == -1)
	  creat(filename, 0777);
}

new_msg(entry)
struct header_rec *entry;
{
	/** Return true if the current message is NEW.  This can be
	    easily tested by seeing 1) if we're reading the incoming
	    mailbox and then, if so, 2) if the received_on_machine
	    date is more recent than the last_read_mail date.
	**/

	if (mbox_specified != 0) return(FALSE);		/* not incoming */
	
	/** Two tests - if received is OLDER than last read mail, then
	    immediately return FALSE.  If received is NEWER than last
	    read mail then immediately return TRUE **/

	if (entry->received.year < last_read_mail.year) 
	  return(FALSE);				
	
	if (entry->received.year > last_read_mail.year) 
	  return(TRUE);				
	
	if (entry->received.month < last_read_mail.month)
	  return(FALSE);			

	if (entry->received.month > last_read_mail.month)
	  return(TRUE);			

	if (entry->received.day < last_read_mail.day)
	  return(FALSE);

	if (entry->received.day > last_read_mail.day)
	  return(TRUE);

	if (entry->received.hour < last_read_mail.hour)		
	  return(FALSE);		
	
	if (entry->received.hour > last_read_mail.hour)		
	  return(TRUE);		
	
	if (entry->received.minute < last_read_mail.minute)
	  return(FALSE);	

	return(TRUE);
}
END-OF-FILE

size=`wc -c < src/mailtime.c`

if [ $size != 4529 ]
then
  echo Warning: src/mailtime.c changed - should be 4529 bytes, not $size bytes
fi

chmod 644 src/mailtime.c

# ---------- file src/mkhdrs.c ----------


if [ -f src/mkhdrs.c ]
then
  echo File 'src/mkhdrs.c' already exists\!
  exit 1
fi

echo extracting file src/mkhdrs.c...
cat << 'END-OF-FILE' > src/mkhdrs.c
/**			mkhdrs.c		**/

/** This contains all the header generating routines for the MSG
    program.

    (C) Copyright 1985 Dave Taylor

**/

#include <stdio.h>
#include "headers.h"

extern char reply_to[SLEN];

generate_reply_to(msg)
int msg;
{
	/** Generate an 'in-reply-to' message... **/
	char buffer[SLEN];


	if (msg == -1)		/* not a reply! */
	  reply_to[0] = '\0';
	else {
	  if (chloc(header_table[msg].from, '!') != -1)
	    tail_of(header_table[msg].from, buffer, FALSE);
	  else
	    strcpy(buffer, header_table[msg].from);
	  sprintf(reply_to, "Message from \"%s\" of %s %s, %s at %s",
		  buffer,
		  header_table[msg].month,
		  header_table[msg].day,
		  header_table[msg].year,
		  header_table[msg].time);
	}
}
END-OF-FILE

size=`wc -c < src/mkhdrs.c`

if [ $size != 728 ]
then
  echo Warning: src/mkhdrs.c changed - should be 728 bytes, not $size bytes
fi

chmod 644 src/mkhdrs.c

# ---------- file src/msg.c ----------


if [ -f src/msg.c ]
then
  echo File 'src/msg.c' already exists\!
  exit 1
fi

echo extracting file src/msg.c...
cat << 'END-OF-FILE' > src/msg.c
/**			msg.c			**/

/* main program of the MSG mail system! 

   This file and all associated files and documentation:
	(C) Copyright 1986 Dave Taylor
*/

#include "msg.h"

main(argc, argv)
int argc;
char *argv[];
{
	char ch, address[SLEN], to_whom[LONG_SLEN];
	int  redraw, /** do we need to rewrite the entire screen? **/
	     nuhead, /** or perhaps just the headers section...   **/
	     nucurr, /** or just the current message pointer...   **/
	     nufoot; /** clear lines 16 thru bottom and new menu  **/
	int  i, size;/** number of bytes in file.  Only mailbox!  **/
	int  pageon; /** for when we receive new mail...          **/

	parse_arguments(argc, argv, to_whom);

	if (mail_only) {

	   initialize();

	   Raw(ON);
	   dprint1("\n\n\tmail-only: mailing to %s\n\n", to_whom);
	   (void) send(to_whom, "", TRUE); 
	   leave(0);
	}

	InitScreen();

	ScreenSize(&LINES, &COLUMNS);

	initialize();
	
	showscreen();

	size = bytes(infile);

	dprint1("\tStarting mailbox size = %d bytes\n", size);

	Raw(ON);
	while (1) {
	  redraw = 0;
	  nuhead = 0;
	  nufoot = 0;
	  nucurr = 0;
	  if ((i = bytes(infile)) != size) {
	    if (debug) 
	      error1("New mail in this file: %d bytes more", i - size);
	    else
	      error("New mail has arrived!   Hang on...");
	    dprint1("\tnew mail in mailbox: %d bytes\n", i - size);
	    pageon = header_page;
	    newmbox(2, FALSE);
	    clear_error();
	    header_page = pageon;
	    showscreen();
	    size = i;
	    transmit_functions(ON);	/* insurance */
	  }

	  prompt("Mail :");

	  CleartoEOLN();
	  ch = tolower(ReadCh()); 
	  CleartoEOS();
	  set_error("");	/* clear error buffer */
	  MoveCursor(LINES-3,COLUMNS-74);

	  dprint1("\n\nEntered command: %c\n\n\n", ch);

	  switch (ch) {

	    case '?' 	:  redraw = help();	        break;

	    case ' '    : 
	    case '+'	:  header_page++; nuhead++;	
			   if (move_when_paged)
			     current = header_page*headers_per_page + 1;
			   break;

	    case '-'    :  header_page--; nuhead++;	
			   if (move_when_paged)
			     current = header_page*headers_per_page + 1;
			   break;

	    case '='    :  if (current != 1) {
			     current = 1;
	                     if (get_page(current))
			       nuhead++;	
			     else
			       nucurr++;
			   }				break;

	    case '*'    :  if (current != message_count) {
			     current = message_count;	
	                     if (get_page(current))
			       nuhead++;	
			     else
			       nucurr++;
			   }				break;

	    case '|'    :  putchar('|'); 
	    		   softkeys_off();
                           redraw = pipe();		
	                   softkeys_on(); 		break;

	    case '!'    :  putchar('!'); 
	    		   softkeys_off();
                           redraw = subshell();		
	                   softkeys_on(); 		break;

	    case '%'    :  get_return(address);
			   clear_error();
			   MoveCursor(LINES,(COLUMNS-strlen(address))/2);
			   printf("%.78s", address);	break;
	    case '/'    :  if (pattern_match()) {
	                      if (get_page(current))
			        nuhead++;
	                      else
	                        nucurr++;
	                   }
			   else
			      error("pattern not found!");
			   break;

	    case 'a'    :  alias();     
			   nufoot++; 	
			   define_softkeys(MAIN); 	break;
			
	    case 'c'    :  printf("Change mailbox");
			   define_softkeys(CHANGE);
			   file_changed = leave_mbox(FALSE);
			   dprint1("\tleave_mbox returned %s\n",
				   file_changed? "TRUE": "FALSE");
	                   redraw = newmbox(0, TRUE);
			   size = bytes(infile);	
			   define_softkeys(MAIN);
			   break;

	    case '^'    :
 	    case 'd'    :  delete((ch == 'd'));			
			   if (resolve_mode) 	/* move after mail resolved */
			     if (current < message_count) {
	                       current++;  		
			       if (get_page(current))
			         nuhead++;
			       else
			         nucurr++;
			     }
			   break;

	    case 'f'    :  printf("Forward");
			   define_softkeys(YESNO);
			   if (current > 0)  
	                     redraw = forward();   
			   else
	                     error("No mail to forward!");
			   define_softkeys(MAIN);
			   break;

	    case 'g'    :  printf("Group reply");
			   define_softkeys(YESNO);
		           fflush(stdout);
			   if (current > 0) {
			     PutLine(LINES-3,COLUMNS-40,
                                     "building addresses...");
	                     redraw = reply_to_everyone();	
	                   }
			   else
			     error("No mail to reply to!"); 
			   define_softkeys(MAIN);
			   break;

	    case 'h'    :  if (filter)
	                     printf("Message with headers...");
	                   else
			     printf("Next message");
			   fflush(stdout);
			   i = filter;
			   filter = FALSE;
			   redraw = show_msg(current);
			   filter = i;
			   break;

	    case 'm'    :  printf("Mail");
			   redraw = send("", "", TRUE); 
			   break;

	    case ctrl('J'):
	    case ctrl('M'):printf("Read Message");	fflush(stdout);
			   define_softkeys(READ);
			   redraw = show_msg(current);
			   break;

	    case 'n'    :  printf("Next Message");
			   fflush(stdout);
			   define_softkeys(READ);
			   redraw = show_msg(current);  
			   current += redraw;		
			   (void) get_page(current); /* rewrites ANYway */
			   if (current > message_count)
			     current = message_count;
			   break;

	    case 'j'    :  current++;  
			   if (get_page(current))
			     nuhead++;
			   else
			     nucurr++;			break;

	    case 'k'    :  current--;  
			   if (get_page(current))
			     nuhead++;
			   else
			     nucurr++;			break;

	    case 'p'    :  printf("Print message");
			   fflush(stdout);
			   printmsg();			break;

	    case 'r'    :  printf("Reply to message");
			   if (current > 0) 
	                     redraw = reply();	
			   else
			     error("No mail to reply to!"); break;

	    case '>'    : /** backwards compatibility **/

	    case 's'    :  printf("Save Message"); 
			   if (save() && resolve_mode) {
			     delete(TRUE);		/* mark for deletion */
			     if (current < message_count) {
			       current++;	/* move to next message */
			       if (get_page(current))
			         nuhead++;
			       else
			         nucurr++;		
			     }
			   }
			   ClearLine(LINES-2);		break;

	    case 't'    :  error1("%s",(char *) get_date());break;

	    case 'q'    :  printf("Quit");  fflush(stdout);
			   if (mbox_specified == 0) {
			     lock(OUTGOING);
			     if (size != bytes(infile)) {
			       error("New Mail!  Quit cancelled...");
	                       unlock();
	                     }
		             else
			       quit();		
			   }
		           else 
			     quit();
			   break;
	    case 'u'    :  undelete();		        
			   if (resolve_mode) 	/* move after mail resolved */
			     if (current < message_count) {
	                       current++;  		
			       if (get_page(current))
			         nuhead++;
			       else
			         nucurr++;
			     }
			   break;

	    case ctrl('Q') :
	    case ctrl('Z') : /* exit fast! */
	    case ctrl('?') : 
	    case 'x'    :  printf("Exit");  
                           fflush(stdout);              leave();

	    case ctrl('L') : redraw++;	break;
	    
	    case '@'    : debug_screen();  redraw++;	break;
	
	    case '#'    : debug_message(); redraw++;	break;

	    case ESCAPE : if (cursor_control) {
			    ch = ReadCh(); 
	                    if (ch == up[1]) {
			      current--;
			      if (get_page(current))
			        nuhead++;
			      else
			        nucurr++;			
	                    }
			    else if (ch == down[1]) {
			      current++;
			      if (get_page(current))
			        nuhead++;
			      else
			        nucurr++;			
			    }
			    else if (hp_terminal) {	/* kludge! */
			      if (ch == 'U') {	/* <NEXT> */
	    			header_page++; 
				nuhead++;
			        if (move_when_paged)
			          current = header_page*headers_per_page + 1;
			      }
			      else if (ch == 'V') {  /* <PREV> */
	    			header_page--; 
				nuhead++;
			        if (move_when_paged)
			          current = header_page*headers_per_page + 1;
			      }
			      else if (ch == 'h') {  /* <HOME UP> */
			        current = 1;
	                        if (get_page(current))
			          nuhead++;
	                        else
	                          nucurr++;
			      }
			      else if (ch == 'F') {  /* <HOME DOWN> */
			        current = message_count;
	                        if (get_page(current))
			          nuhead++;
	                        else
	                          nucurr++;
			      }
			      else /* what DID they hit??? */
				 printf("%c%c", ESCAPE, ch);
			    }
			    else /* false hit - output */
			      printf("%c%c", ESCAPE, ch);
			    break;
			  }
				/* else fall into default.. */

	    default	: if (ch > '0' && ch <= '9') {
			    printf("New Current Message");
			    current = read_number(ch, message_count);
	                    if (get_page(current))
			      nuhead++;
	                    else
	                      nucurr++;
			  }
			  else
	 		    error("Unknown command: Use '?' for commands");
	  }
	  if (redraw)
	    showscreen();

	  if (current < 1) {
	    if (message_count > 0) {
	      error("already at message #1!");
	      current = 1;
	    }
	    else if (current < 0) {
	      error("No messages to read!");
	      current = 0;
	    }
	  }
	  else if (current > message_count) {
	    if (message_count > 0) {
	      error2("only %d message%s!", message_count, 
		     plural(message_count));
	      current = message_count;
	    }
	    else {
	      error("No messages to read!");
	      current = 0;
	    }
	  }

	  if (nuhead) 
	    show_headers();
	  else if (nucurr)
	    show_current();
	  else if (nufoot) {
	    MoveCursor(LINES-7, 0);  
            CleartoEOS();
	    if (mini_menu)
	      show_menu();
	  }

	} /* the BIG while loop! */
}


debug_screen()
{
	/**** spit out all the current variable settings and the table
	      entries for the current 'n' items displayed. ****/

	register int i, j;

	ClearScreen();
	Raw(OFF);

	printf("Current message number = %d\t\t%d message(s) total\n\n",
	        current, message_count);
	printf("Header_page = %d           \t\t%d possible page(s)\n",
		header_page, (int) (message_count / headers_per_page) + 1);

	printf("\nCurrent mailfile is %s.\n\n", infile);

	i = header_page*headers_per_page;	/* starting header */

	if ((j = i + (headers_per_page-1)) >= message_count) 
	  j = message_count-1;

	printf(
"Num      From                 	Subject                         Lines  Offset\n\n");

	while (i <= j) {
	   printf(
	   "%3d  %-16.16s  %-40.40s  %4d  %d\n",
		    i+1,
	            header_table[i].from, 
	            header_table[i].subject,
		    header_table[i].lines,
		    header_table[i].offset);
	  i++;
	}
	
	Raw(ON);

	PutLine(LINES,0,"Press any key to return: ");
	(void) ReadCh();
}


debug_message()
{
	/**** Spit out the current message record.  Include EVERYTHING
	      in the record structure. **/

	ClearScreen();
	Raw(OFF);

	printf("\t\t\t----- Message %d -----\n\n\n\n", 
		current);

	printf("Lines : %-5d\t\t\t\tPriority message? %s\n\n",
		header_table[current-1].lines, 
		header_table[current-1].priority? "YES" : "NO");

	printf("Offset: %ld\t\t\t\t  Delete message? %s\n\n\n",
		header_table[current-1].offset,
		header_table[current-1].delete? "YES" : "NO");

	printf("Received on: %d/%d/%d at %d:%02d\n\n",
	        header_table[current-1].received.month+1,
	        header_table[current-1].received.day,
	        header_table[current-1].received.year,
	        header_table[current-1].received.hour,
	        header_table[current-1].received.minute);

	printf("Msg sent on: %s, %s %s, %s at %s\n\n",
	        header_table[current-1].dayname,
	        header_table[current-1].month,
	        header_table[current-1].day,
	        header_table[current-1].year,
	        header_table[current-1].time);
	
	printf("\nFrom: %s\n\nSubject: %s",
		header_table[current-1].from,
	        header_table[current-1].subject);
	
	Raw(ON);

	PutLine(LINES,0,"Press any key to return: ");
	(void) ReadCh();
}
END-OF-FILE

size=`wc -c < src/msg.c`

if [ $size != 12135 ]
then
  echo Warning: src/msg.c changed - should be 12135 bytes, not $size bytes
fi

chmod 644 src/msg.c

echo done

exit 0