[mod.sources] v06i035: Elm mail system

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

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

# Continuation of Shell Archive, created by hpldat!taylor

# This is part 10

# 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 src ]
then
  echo creating directory src
  mkdir src
fi

# ---------- file src/mailmsg1.c ----------

filename="src/mailmsg1.c"

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

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

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

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

#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], in_reply_to[SLEN];

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

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], addressII[VERY_LONG_STRING];
	int  copy_msg = FALSE, is_a_response = FALSE;

	/* First: zero all current global message strings */

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

	strcpy(subject, given_subject);		/* copy given subject */
	strcpy(to, given_to);			/* copy given to:     */

	/******* And now the real stuff! *******/

	copy_msg=copy_the_msg(&is_a_response); /* copy msg into edit buffer? */

	if (get_to(to, address) == 0)	    /* get the To: address and expand */
	  return(0);

	/** are we by any chance just checking the addresses? **/

	if (check_only) {
	  printf("Expands to: %s\n", format_long(address, 12));
	  putchar('\r');	/* don't ask... */
	  leave();
	}

	/** if we're batchmailing, let's send it and GET OUTTA HERE! **/

	if (mail_only && strlen(batch_subject) > 0) { 
	  strcpy(subject, batch_subject);	/* get the batch subject */
	  return(mail(address, NULL, FALSE, FALSE, TRUE));
	}

	display_to(address);	/* display the To: field on screen... */

	dprint1(3,"\nMailing to %s\n", address);
  
	if (get_subject(subject) == 0)	    /* get the Subject: field */
	  return(0);

	dprint1(4,"Subject is %s\n", subject);

	if (get_copies(cc, address, addressII) == 0)	/* get the cc: field */
	  return(0);

	if (strlen(cc) > 0)
	  dprint1(4,"Copies to %s\n", cc);

	if (mail_only) 				/* indicate next step... */
	  printf("\n\r");
	else
	  MoveCursor(LINES,0);	/* you know you're hit <return> ! */

	/** generate the In-Reply-To: header... **/

	if (is_a_response)
	  generate_reply_to(current-1);

	/* and mail that puppy outta here! */

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

get_to(to_field, address)
char *to_field, *address;
{
	/** prompt for the "To:" field, expanding into address if possible.
	    This routine returns ZERO if errored, or non-zero if okay **/

	if (strlen(to_field) == 0) {
	  PutLine0(LINES-2, 0, "To: ");
	  (void) optionally_enter(to_field, LINES-2, 4, FALSE); 
	  if (strlen(to_field) == 0) {
	    ClearLine(LINES-2);	
	    return(0);
	  }
	  build_address(strip_commas(to_field), address); 
	}
	else if (mail_only) 
	  build_address(strip_commas(to_field), address); 
	else 
	  strcpy(address, to_field);
	
	if (strlen(address) == 0) {	/* bad address!  Removed!! */
	  if (! mail_only)
	    ClearLine(LINES-2);
	  return(0);
	}

	return(1);		/* everything is okay... */
}

get_subject(subject_field)
char *subject_field;
{
	/** get the subject and return non-zero if all okay... **/

	if (mail_only)
	  printf("Subject: ");
	else 
	  PutLine0(LINES-2,0,"Subject: ");

	CleartoEOLN();

	if (optionally_enter(subject_field, LINES-2, 9, TRUE) == -1) {
	  /** User hit the BREAK key! **/
	  MoveCursor(LINES-2,0); 	
	  CleartoEOLN();
	  dprint0(3,"User responded to \"Subject:\" with BREAK (get_subject)\n");
	  error("mail not sent");
	  return(0);
	}

	if (strlen(subject_field) == 0) {	/* zero length subject?? */
	  if (mail_only) 
	    printf("\n\rNo subject - Continue with message? (y/n) n%c",
		  BACKSPACE);
	  else
	    PutLine1(LINES-2,0,"No subject - Continue with message? (y/n) n%c",
		  BACKSPACE);

	  if (tolower(ReadCh()) != 'y') {	/* user says no! */
	    if (mail_only) {
	      printf("\n\r\n\rMail Cancelled!\n\r");
	      return(0);
	    }
	    ClearLine(LINES-2);
	    dprint0(3,
		"User reponded to \"Subject:\" with RETURN (get_subject)\n");
	    error("mail not sent");
	    return(0);
	  }
	  else if (! mail_only) {
	    PutLine0(LINES-2,0,"Subject: <none>");
	    CleartoEOLN();
	  }
	}

	return(1);		/** everything is cruising along okay **/
}

get_copies(cc_field, address, addressII)
char *cc_field, *address, *addressII;
{
	/** Get the list of people that should be cc'd, returning ZERO if
	    any problems arise.  Address and AddressII are for expanding
	    the aliases out after entry! 
	    If 'bounceback' is nonzero, add a cc to ourselves via the remote
	    site, but only if hops to machine are > bounceback threshold.
	**/

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

	fflush(stdout);

	if (optionally_enter(cc_field, LINES-1, 11, FALSE) == -1) {
	  if (mail_only) {
	    printf("\n\r\n\rMail not sent!\n\r");
	    return(0);
	  }
	  ClearLine(LINES-2);
	  ClearLine(LINES-1);
	  
	  dprint0(3,
 "User responded to \"Copies To:\" with BREAK.  Mail cancelled (get_copies)\n");
	  error("mail not sent");
	  return(0);
	}
	
	build_address(strip_commas(cc_field), addressII);

	if (strlen(address) + strlen(addressII) > VERY_LONG_STRING) {
	  dprint0(2,
		"String length of \"To:\" + \"Cc\" too long! (get_copies)\n");
	  error("Too many people.  Copies ignored");
	  sleep(2);
	  cc_field[0] = '\0';
	}

	return(1);		/* everything looks okay! */
}
	
int
copy_the_msg(is_a_response)
int *is_a_response;
{
	/** Returns True iff the user wants to copy the message being
	    replied to into the edit buffer before invoking the editor! 
	    Sets "is_a_response" to true if message is a response...
	**/

	int answer = FALSE;

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

	return(answer);
}

display_to(address)
char *address;
{
	/** Simple routine to display the "To:" line according to the
	    current configuration (etc) 			      
	 **/

	if (mail_only)
	  printf("To: %s\n\r", format_long(address));
	else {
	  if (strlen(address) > COLUMNS-50) 
	    PutLine1(LINES-3, COLUMNS-50, "To: (%s)", 
		tail_of_string(address, COLUMNS-50));
	  else {
	    PutLine1(LINES-3, COLUMNS-50, "          To: %s", address);
	    CleartoEOLN();
	  }
	}
}
END-OF-FILE

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

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

  chmod 644 $filename
fi

# ---------- file src/connect_to.c ----------

filename="src/connect_to.c"

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

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

/** This contains the routine(s) needed to have the Elm mailer figure
    out what machines the current machine can talk to.   This can be
    done in one of two ways - either the program can read the L.sys
    file, or (if it fails or "UUNAME" define is present) will invoke
    uuname to a file, then read the file in!

    (C) Copyright Dave Taylor, 1986
**/

#include "headers.h"

get_connections()
{

	/** get the direct connections that this machine has, by hook
	    or by crook (so to speak) 
	**/

#ifndef USE_UUNAME
	FILE *lsysfile;
	char  buffer[SLEN], sysname[NLEN];
	struct lsys_rec *system_record, *previous_record;
	int    loc_on_line;

	previous_record = NULL;
	if ((lsysfile = fopen(Lsys,"r")) == NULL) {
	  dprint1(1, "Warning: Can't open L.sys file %s (read_lsys)\n", Lsys);
#endif

	  if (read_uuname() == -1) {
	    error("Warning: couldn't figure out system connections...");
	    talk_to_sys = NULL;
	  }

#ifndef USE_UUNAME
	  /** ELSE: already read in uuname() output if we're here!! **/
	  return;
	}

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

	  if (previous_record == NULL) {
	    dprint1(2, "L.sys\tdirect connection to %s, ", sysname);
	    loc_on_line = 30 + strlen(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) && sysname[0] != '#') {
	    if (loc_on_line + strlen(sysname) > 80) {
	      dprint0(2, "\n\t");
	      loc_on_line = 8;
	    }
	    dprint1(2, "%s, ", sysname);
	    loc_on_line += (strlen(sysname) + 2);
	    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);

	if (loc_on_line != 8)
	  dprint0(2, "\n");

	dprint0(2, "\n");			/* for a nice format! Yeah! */
#endif
}

int
read_uuname()
{
	/** This routine trys to use the uuname routine to get the names of
	    all the machines that this machine connects to...it returns
	    -1 on failure.
	**/

	FILE *fd;
	char  buffer[SLEN], filename[SLEN];
	struct lsys_rec *system_record, *previous_record;
	int   loc_on_line;

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

	if (system_call(buffer, SH) != 0) {
	  dprint0(1, "Can't get uuname info - system call failed!\n");
	  unlink(filename);	/* insurance */
	  return(-1);
	}
	
	if ((fd = fopen(filename, "r")) == NULL) {
	  dprint1(1, "Can't get uuname info - can't open file %s for reading\n",
		   filename);
	  unlink(filename);	/* insurance */
	  return(-1);
	}
	
	previous_record = NULL;

	while (fgets(buffer, SLEN, fd) != NULL) {
	  no_ret(buffer);
	  if (previous_record == NULL) {
	    dprint1(2, "uuname\tdirect connection to %s, ", buffer);
	    loc_on_line = 30 + strlen(buffer);
	    previous_record = (struct lsys_rec *) malloc(sizeof *talk_to_sys);

	    strcpy(previous_record->name, buffer);
	    previous_record->next = NULL;
	    talk_to_sys = previous_record;
	  }
	  else {	/* don't have to check uniqueness - uuname does that! */
	    if (loc_on_line + strlen(buffer) > 80) {
	      dprint0(2, "\n\t");
	      loc_on_line = 8;
	    }
	    dprint1(2, "%s, ", buffer);
	    loc_on_line += (strlen(buffer) + 2);
	    system_record = (struct lsys_rec *) malloc(sizeof *talk_to_sys);
	  
	    strcpy(system_record->name, buffer);
	    system_record->next = NULL;
	    previous_record->next = system_record;
	    previous_record = system_record;
	  }
	}

	fclose(fd);

	(void) unlink(filename);		/* kill da temp file!! */

	dprint0(2, "\n");			/* for a nice format! Yeah! */

	return(0);				/* it all went okay... */
}
END-OF-FILE

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

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

  chmod 644 $filename
fi

# ---------- file src/remail.c ----------

filename="src/remail.c"

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

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

/** For those cases when you want to have a message continue along
    to another person in such a way as they end up receiving it with
    the return address the person YOU received the mail from (does
    this comment make any sense yet??)...

    (C) Copyright 1986  Dave Taylor
**/

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

extern int errno;

int
remail()
{
	/** remail a message... returns TRUE if new foot needed ... **/
	
	FILE *mailfd;
	char entered[VERY_LONG_STRING], expanded[VERY_LONG_STRING];
	char filename[SLEN], buffer[VERY_LONG_STRING];

	entered[0] = '\0';

	get_to(entered, expanded);
	if (strlen(entered) == 0)
	  return(0);

	display_to(expanded);

	/** now the munge... **/

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

	if ((mailfd = fopen(filename, "w")) == NULL) {
	  dprint1(1,"couldn't open temp file %s! (remail)\n", filename);
	  dprint2(1,"** %s - %s **\n", error_name(errno),
		  error_description(errno));
	  sprintf(buffer, "Sorry - couldn't open file %s for writing (%s)",
		  error_name(errno));
	  set_error(buffer);
	  return(1);
	}

	/** now let's copy the message into the newly opened
	    buffer... **/

	copy_message("", mailfd, FALSE, TRUE);  

	fclose(mailfd);

	/** Got the messsage, now let's ensure the person really wants to 
	    remail it... **/

	ClearLine(LINES-1);
	ClearLine(LINES);
	PutLine1(LINES-1,0,
	    "Are you sure you want to remail this message (y/n) ? y%c",
	    BACKSPACE);
	fflush(stdin);
	fflush(stdout);
	if (tolower(ReadCh()) == 'n') { /* another day, another No... */
	  Write_to_screen("No", 0);
	  set_error("Bounce of message cancelled");
          return(1);
	}
	Write_to_screen("Yes!", 0);

	sprintf(buffer, "%s %s < %s", mailer, expanded, filename);

	PutLine0(LINES,0,"resending mail...");

	if ((errno = system_call(buffer)) != 0) 
	  set_error("Remail failed with error %d!", errno);
	else
	  set_error("mail resent");

	return(1);
}
END-OF-FILE

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

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

  chmod 644 $filename
fi

# ---------- file src/signals.c ----------

filename="src/signals.c"

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

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

/** This set of routines traps various signals and informs the
    user of the error, leaving the program in a nice, graceful
    manner.

	(C) Copyright 1986 Dave Taylor
**/

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

extern int pipe_abort;		/* set to TRUE if receive SIGPIPE */

quit_signal()
{
	dprint0(2,"\n** Received SIGQUIT **\n\n");
	leave();
}

term_signal() 
{
	dprint0(2,"\n** Received SIGTERM **\n\n");
	leave();
}

ill_signal()
{
	dprint0(1,"\n** Received SIGILL **\n\n");
	PutLine0(LINES, 0, "\n\rIllegal Instruction signal!\n\r");
	emergency_exit();
}

fpe_signal()  
{
	dprint0(1,"\n** Received SIGFPE **\n\n");
	PutLine0(LINES, 0,"\n\rFloating Point Exception signal!\n\r");
	emergency_exit();
}

bus_signal()
{
	dprint0(1,"\n** Received SIGBUS **\n\n");
	PutLine0(LINES, 0,"\n\rBus Error signal!\n\r");
	emergency_exit();
}

segv_signal()
{
	dprint0(1,"\n** Received SIGSEGV **\n\n");
	PutLine0(LINES, 0,"\n\rSegment Violation signal!\n\r");
	emergency_exit();
}

alarm_signal()
{	
	/** silently process alarm signal for timeouts... **/

	int alarm_signal();

	signal(SIGALRM, alarm_signal);
}

pipe_signal()
{
	/** silently process pipe signal... **/

	int pipe_signal();

	dprint0(2,"*** received SIGPIPE ***\n");
	
	pipe_abort = TRUE;	/* internal signal ... wheeee!  */

	signal(SIGPIPE, pipe_signal);
}
END-OF-FILE

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

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

  chmod 644 $filename
fi

# ---------- file src/curses.q ----------

filename="src/curses.q"

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

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

/**  This library gives programs the ability to easily access the
     termcap information and write screen oriented and raw input
     programs.  The routines can be called as needed, except that
     to use the cursor / screen routines there must be a call to
     InitScreen() first.  The 'Raw' input routine can be used
     independently, however.

     Modified 2/86 to work (hopefully) on Berkeley systems.  If
     there are any problems with BSD Unix, please report them to
     the author at hpcnoe!dat@HPLABS (fixed, if possible!)

     (C) Copyright 1985 Dave Taylor, HP Colorado Networks
**/

#include "headers.h"

#ifdef RAWMODE
# ifdef BSD
#  include <sgtty.h>
# else
#  include <termio.h>
# endif
#endif

#include <ctype.h>

#ifdef BSD
#undef tolower
#endif
#include "curses.h"

#ifdef BSD
# include "/usr/include/curses.h"  	/* don't ask! */
#endif

#ifdef RAWMODE
# define TTYIN	0
#endif

extern int debug;

#ifdef RAWMODE
#  ifndef BSD
    struct termio _raw_tty, 
                _original_tty;
#  endif

static int _inraw = 0;                  /* are we IN rawmode?    */
static int _line  = -1,			/* initialize to "trash" */
	   _col   = -1;

#ifdef UTS
static int _clear_screen = 0;		/* Next i/o clear screen? */
static char _null_string[SLEN];		/* a string of nulls...   */
#endif

#endif

static int _intransmit;			/* are we transmitting keys? */

static
char *_clearscreen, *_moveto, *_up, *_down, *_right, *_left,
     *_setbold, *_clearbold, *_setunderline, *_clearunderline, 
     *_sethalfbright, *_clearhalfbright, *_setinverse, *_clearinverse,
     *_cleartoeoln, *_cleartoeos, *_transmit_on, *_transmit_off;
static
int
     _lines, _columns;

static char _terminal[1024];              /* Storage for terminal entry */
static char _capabilities[256];           /* String for cursor motion */

static char *ptr = _capabilities;	/* for buffering         */

int    outchar();			/* char output for tputs */

InitScreen()
{
   /* Set up all this fun stuff: returns zero if all okay, or;
        -1 indicating no terminal name associated with this shell,
        -2..-n  No termcap for this terminal type known
   */

   int  tgetent(),      /* get termcap entry */
        error;
   char *tgetstr(),     /* Get termcap capability */
        termname[40];

#ifdef SUN
   if (getenv("TERM") == NULL)
     return(-1);
#endif

#ifdef UTS

    /* use _line for lack of a better variable, what the heck! */

    for (_line = 0; _line < SLEN; _line++)
	_null_string[_line] = '\0';
#endif

   if (strcpy(termname, getenv("TERM")) == NULL)
     return(-1);

   if ((error = tgetent(_terminal, termname)) != 1)
     return(error-2);

   _line  =  1;		/* where are we right now?? */
   _col   =  1;		/* assume zero, zero...     */

   /* load in all those pesky values */
   _clearscreen       = tgetstr("cl", &ptr);
   _moveto            = tgetstr("cm", &ptr);
   _up                = tgetstr("up", &ptr);
   _down              = tgetstr("do", &ptr);
   _right             = tgetstr("nd", &ptr);
   _left              = tgetstr("bs", &ptr); 
   _setbold           = tgetstr("so", &ptr);
   _clearbold         = tgetstr("se", &ptr);
   _setunderline      = tgetstr("us", &ptr);
   _clearunderline    = tgetstr("ue", &ptr);
   _setinverse        = tgetstr("so", &ptr);
   _clearinverse      = tgetstr("se", &ptr);
   _sethalfbright     = tgetstr("hs", &ptr);
   _clearhalfbright   = tgetstr("he", &ptr);
   _cleartoeoln       = tgetstr("ce", &ptr);
   _cleartoeos        = tgetstr("cd", &ptr);
   _lines	      = tgetnum("li");
   _columns	      = tgetnum("co");
   _transmit_on	      = tgetstr("ks", &ptr);
   _transmit_off      = tgetstr("ke", &ptr);


   if (!_left) {
      _left = ptr;
      *ptr++ = '\b';
      *ptr++ = '\0';
   }

#ifdef BSD
	initscr();	/* initalize curses too! */
#endif

   return(0);
}

char *return_value_of(termcap_label)
char *termcap_label;
{
	/** This will return the string kept by termcap for the 
	    specified capability. Modified to ensure that if 
	    tgetstr returns a pointer to a transient address	
	    that we won't bomb out with a later segmentation
	    fault (thanks to Dave@Infopro for this one!) **/

	static char escape_sequence[20];	

   	char *tgetstr();     		/* Get termcap capability */

	strcpy(escape_sequence, tgetstr(termcap_label, &ptr));
	return( (char *) escape_sequence);
}

transmit_functions(newstate)
int newstate;
{
	/** turn function key transmission to ON | OFF **/
	
	if (newstate != _intransmit) {
	  _intransmit = ! _intransmit;
	  if (newstate == ON)
   	    tputs(_transmit_on, 1, outchar);
	  else 
   	    tputs(_transmit_off, 1, outchar);

   	  fflush(stdout);      /* clear the output buffer */
	}
}

/****** now into the 'meat' of the routines...the cursor stuff ******/

ScreenSize(lines, columns)
int *lines, *columns;
{
	/** returns the number of lines and columns on the display. **/

	*lines = _lines - 1;		/* assume index from zero */
	*columns = _columns;
}

ClearScreen()
{
        /* clear the screen: returns -1 if not capable */

#ifdef UTS
   if (isatube) {
     _clear_screen++;	/* queue up for clearing... */
     return(0);
   }
#endif

   if (!_clearscreen) 
     return(-1);

   tputs(_clearscreen, 1, outchar);
   fflush(stdout);      /* clear the output buffer */
   return(0);
}

MoveCursor(row, col)
int row, col;
{
        /** move cursor to the specified row column on the screen.
            0,0 is the top left! **/

           char *tgoto();
	   char *stuff;

	_line = row;		/* update current location... */
	_col  = col;

#ifdef UTS
	if (isatube) {
	  at row, col;
	  return(0);
	}
#endif
        if (!_moveto) 
          return(-1);

        stuff = (char *) tgoto(_moveto, col, row);
	tputs(stuff, 1, outchar);
        fflush(stdout);
        return(0);
}


CursorUp()
{
        /** move the cursor up one line **/

	_line = (_line> 0? _line - 1: _line);	/* up one line... */

#ifdef UTS
	if (isatube) {
	  at _line, _col;
	  return(0);
	}
#endif
        if (!_up)
           return(-1);

   	tputs(_up, 1, outchar);
	fflush(stdout);
        return(0);
}


CursorDown()
{
        /** move the cursor down one line **/

	_line = (_line< LINES? _line + 1: _line);	/* up one line... */

#ifdef UTS
	if (isatube) {
	  at _line, _col ;
	  return(0);
	}
#endif

       if (!_down) 
          return(-1);

       tputs(_down, 1, outchar);
       fflush(stdout);
       return(0);
}


CursorLeft()
{
        /** move the cursor one character to the left **/

	_col = (_col > 0? _col - 1: _col);	/* up one line... */

#ifdef UTS
	if (isatube) {
	  at _line, _col;
	  return(0);
	}
#endif

       if (!_left) 
          return(-1);

       tputs(_left, 1, outchar);
       fflush(stdout);
       return(0);
}


CursorRight()
{
        /** move the cursor one character to the right (nondestructive) **/

	_col = (_col < COLUMNS? _col + 1: _col);	/* up one line... */

#ifdef UTS
	if (isatube) {
	  at _line, _col;
	  return(0);
	}
#endif

       if (!_right) 
          return(-1);

       tputs(_right, 1, outchar);
       fflush(stdout);
       return(0);
}


StartBold()
{
        /** start boldface/standout mode **/

       if (!_setbold) 
         return(-1);

       tputs(_setbold, 1, outchar);
       fflush(stdout);
       return(0);
}


EndBold()
{
        /** compliment of startbold **/

        if (!_clearbold) 
           return(-1);

       tputs(_clearbold, 1, outchar);
       fflush(stdout);
       return(0);
}


StartUnderline()
{
        /** start underline mode **/

       if (!_setunderline) 
          return(-1);

       tputs(_setunderline, 1, outchar);
       fflush(stdout);
       return(0);
}


EndUnderline()
{
        /** the compliment of start underline mode **/

       if (!_clearunderline) 
          return(-1);

       tputs(_clearunderline, 1, outchar);
       fflush(stdout);
       return(0);
}


StartHalfbright()
{
        /** start half intensity mode **/

       if (!_sethalfbright) 
         return(-1);

       tputs(_sethalfbright, 1, outchar);
       fflush(stdout);
       return(0);
}

EndHalfbright()
{
        /** compliment of starthalfbright **/

       if (!_clearhalfbright) 
          return(-1);

       tputs(_clearhalfbright, 1, outchar);
       fflush(stdout);
       return(0);
}

StartInverse()
{
        /** set inverse video mode **/

       if (!_setinverse) 
         return(-1);

       tputs(_setinverse, 1, outchar);
       fflush(stdout);
       return(0);
}


EndInverse()
{
        /** compliment of startinverse **/

       if (!_clearinverse) 
         return(-1);

       tputs(_clearinverse, 1, outchar);
       fflush(stdout);
       return(0);
}

PutLine0(x, y, line)
int x,y;
char *line;
{
	/** Write a zero argument line at location x,y **/

	_line = x;
	_col  = y;

#ifdef UTS
	if (isatube) {
	  panel (erase=_clear_screen, cursor=_line, _col) {
	    #ON, line, strlen(line)-1#
	  }
	  _clear_screen = 0;
	  _col += (printable_chars(line) - 1);
	  return(0);
	}
#endif
	MoveCursor(x,y);
	printf("%s", line);	/* to avoid '%' problems */
	fflush(stdout);
	_col += (printable_chars(line) - 1);
}

PutLine1(x,y, line, arg1)
int x,y;
char *line;
char *arg1;
{
	/** write line at location x,y - one argument... **/

	char buffer[SLEN];
	
	sprintf(buffer, line, arg1);

	PutLine0(x, y, buffer);
}

PutLine2(x,y, line, arg1, arg2)
int x,y;
char *line;
char *arg1, *arg2;
{
	/** write line at location x,y - one argument... **/

	char buffer[SLEN];
	
	sprintf(buffer, line, arg1, arg2);

	PutLine0(x, y, buffer);
}

PutLine3(x,y, line, arg1, arg2, arg3)
int x,y;
char *line;
char *arg1, *arg2, *arg3;
{
	/** write line at location x,y - one argument... **/

	char buffer[SLEN];
	
	sprintf(buffer, line, arg1, arg2, arg3);

	PutLine0(x, y, buffer);
}

CleartoEOLN()
{
        /** clear to end of line **/
#ifdef UTS
	char buffer[SLEN];
	register int cols, i = 0;

	if (isatube) {

	  for (cols = _col; cols < COLUMNS; cols++)
	    buffer[i++] = ' ';

	  buffer[i] = '\0';
	
	  panel (noerase, cursor=_line, _col) {
	    #ON, buffer, strlen(buffer)-1#
	  }
	}
#endif

       if (!_cleartoeoln) 
         return(-1);

       tputs(_cleartoeoln, 1, outchar);
       fflush(stdout);  /* clear the output buffer */
       return(0);
}

CleartoEOS()
{
        /** clear to end of screen **/

#ifdef UTS
	register int line_at;

	for (line_at = _line; line_at < LINES-1; line_at++) {
	  panel (noerase) { 
	    #ON, _null_string, COLUMNS# 
	  }
	}
	return(0);

#endif

       if (!_cleartoeos) 
         return(-1);

       tputs(_cleartoeos, 1, outchar);
       fflush(stdout);  /* clear the output buffer */
       return(0);
}

#ifdef RAWMODE

Raw(state)
int state;
{
	/** state is either ON or OFF, as indicated by call **/

        if (state == OFF && _inraw) {
#ifdef BSD
	  echo();
	  nocrmode();
#else
	  (void) ioctl(TTYIN, TCSETAW, &_original_tty);
#endif
          _inraw = 0;
	}
        else if (state == ON && ! _inraw) {
#ifdef BSD
	   noecho();
	   crmode();
#else
	  (void) ioctl(TTYIN, TCGETA, &_original_tty);	/** current setting **/
	  	
	  (void) ioctl(TTYIN, TCGETA, &_raw_tty);    /** again! **/
	  _raw_tty.c_iflag &= ~(INLCR | ICRNL |BRKINT);
	  _raw_tty.c_iflag |= IXON;
	  _raw_tty.c_oflag |= OPOST;
	  _raw_tty.c_oflag &= ~(OLCUC | ONLCR | OCRNL | ONOCR | ONLRET);
	  _raw_tty.c_lflag &= ~(ICANON | ECHO);
	  _raw_tty.c_cc[VMIN] = '\01';
	  _raw_tty.c_cc[VTIME] = '\0';
	  (void) ioctl(TTYIN, TCSETAW, &_raw_tty);
#endif

          _inraw = 1;
        }
}

int
ReadCh()
{
        /** read a character with Raw mode set! **/

        register int result;
        char ch;

        result = read(0, &ch, 1);
	
	return(result == 0? EOF : ch);
}

#endif

outchar(c)
char c;
{
	/** output the given character.  From tputs... **/
	/** Note: this CANNOT be a macro!              **/

	putc(c, stdout);
}
END-OF-FILE

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

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

  chmod 644 $filename
fi

# ---------- file src/initialize.uts ----------

filename="src/initialize.uts"

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

sed 's/^X//' << 'END-OF-FILE' > $filename
XFrom hpccc!mcgregor@hplabs.ARPA Fri May  9 16:05:10 1986
XReceived: from hplabs.ARPA by hpldat ; Fri, 9 May 86 16:05:01 pdt
XMessage-Id: <8605092305.AA00689@hpldat>
XReceived: by hplabs.ARPA ; Fri, 9 May 86 16:01:29 pdt
XFrom: Scott McGregor <hpccc!mcgregor@hplabs.ARPA>
XTo: taylor@hplabs
XDate: Fri, 9 May 86 15:23:16 PDT
XSubject: initialize.c
XX-Mailer: msg [version 3.3a]
X
X/**		initialize.c		**/
X
X/***** Initialize - read in all the defaults etc etc 
X       (C) Copyright 1985 Dave Taylor
X*****/
X
X#include "headers.h"
X
X#ifdef BSD
X#  include <sgtty.h>
X#else
X#  include <termio.h>
X#endif
X
X#include <pwd.h>
X
X#ifdef BSD
X#  include <sys/time.h>
X#else
X#  include <time.h>
X#endif
X
X#include <signal.h>
X#include <ctype.h>
X#include <errno.h>
X
X#ifdef BSD
X#undef tolower
X#endif
X
X
Xextern int errno;		/* system error number on failure */
X
Xchar *error_name(), *error_description();
X
Xchar *expand_logname(), *getenv(), *getlogin();
X
Xinitialize(InitScreen_to)
Xint InitScreen_to;
X{
X	struct passwd *pass, *getpwnam();
X
X	register int i;
X	int      quit_signal(), term_signal(), ill_signal(),
X		 fpe_signal(),  bus_signal(),  segv_signal(),
X	         alarm_signal();
X	char     buffer[SLEN], *cp;
X	
X	userid  = getuid();
X	groupid = getgid();	
X
X	strcpy(home,((cp = getenv("HOME")) == NULL)? "" : cp);
X	strcpy(shell,((cp = getenv("SHELL")) == NULL)? "" : cp);
X
X	if (debug) {		/* setup for dprintf statements! */
X	  char filename[SLEN];
X	  sprintf(filename, "%s/%s", home, DEBUG);
X	  if ((debugfile = fopen(filename, "w")) == NULL) {
X	    debug = 0;	/* otherwise 'leave' will try to log! */
X	    leave(fprintf(stderr,"Could not open file %s for debug output!\n",
X		  filename));
X	  }
X	  if (InitScreen_to) {
X		  InitScreen();
X	  }
X	  chown(filename, userid, groupid); /* file owned by user */
X
X	  fprintf(debugfile, "Debug output of the MSG program.  Version %s\n\n",
X		  VERSION);
X	}
X#ifndef UTS
X	signal(SIGINT,  SIG_IGN);
X	signal(SIGQUIT, quit_signal);		/* Quit signal 	            */
X	signal(SIGTERM, term_signal); 		/* Terminate signal         */
X	signal(SIGILL,  ill_signal);		/* Illegal instruction      */
X	signal(SIGFPE,  fpe_signal);		/* Floating point exception */
X	signal(SIGBUS,  bus_signal);		/* Bus error  		    */
X	signal(SIGSEGV, segv_signal);		/* Segmentation Violation   */
X#endif
X	signal(SIGALRM, alarm_signal);		/* Process Timer Alarm	    */
X
X	if (isa3270()) {
X	  isatube++;
X	  dprint0(1, "** We're using a 3270 tube!! **\n");
X	}
X
X#ifndef UTS
X	get_connections();	      /* who do we talk to directly?? */
X#endif
X	open_domain_file();		/* if we got it, we want it!  */
X
X	get_term_chars();
X	
X	gethostname(hostname, sizeof(hostname));
X	if ((cp = getlogin()) == NULL)
X	  cuserid(username);
X	else
X	  strcpy(username, cp);
X
X	/* now let's get the full username.. */
X
X	if ((pass = getpwnam(username)) == NULL) {
X	  error("Couldn't read password entry??");
X	  strcpy(full_username, username);
X	}
X	else {
X	  for (i=0; pass->pw_gecos[i] != '\0' && pass->pw_gecos[i] != ',';
X	       i++)
X	      if (pass->pw_gecos[i] == '&') {
X	        full_username[i] = '\0';
X	        strcat(full_username, expand_logname());
X	        i = strlen(full_username) - 2;
X	      }
X	      else
X	        full_username[i] = pass->pw_gecos[i];
X	  full_username[i] = '\0'; 
X	}
X
X	if ((cp = getenv("EDITOR")) == NULL)
X	  strcpy(editor,default_editor);
X	else
X	  strcpy(editor, cp);
X
X	if (! mail_only) {
X	  mailbox[0] = '\0';
X	  strcpy(prefixchars, "> "); 	/* default message prefix */
X	}
X
X	read_rc_file();		/* reading the .msgrc next... */
X
X	/** now try to expand the specified filename... **/
X
X	if (strlen(infile) > 0) {
X	  (void) expand_filename(infile);
X	  if ((errno = can_access(infile, READ_ACCESS))) {
X	    dprint2(1,"Error: given file %s as mailbox - unreadable (%s)!\n", 
X		     infile, error_name(errno));
X	    fprintf(stderr,"Can't open mailbox '%s' for reading!\n", infile);
X	    exit(1);
X	  }
X	}
X
X	/** check to see if the user has defined a LINES or COLUMNS
X	    value different to that in the termcap entry (for
X	    windowing systems, of course!) **/
X
X	if ((cp = getenv("LINES")) != NULL && isdigit(*cp)) {
X	  sscanf(cp, "%d", &LINES);
X	  LINES -= 1;	/* kludge for HP Window system? ... */
X	}
X
X	if ((cp = getenv("COLUMNS")) != NULL && isdigit(*cp))
X	  sscanf(cp, "%d", &COLUMNS);
X
X	/** fix the shell if needed **/
X
X	if (shell[0] != '/') {
X	   sprintf(buffer, "/bin/%s", shell);
X	   strcpy(shell, buffer);
X	}
X
X	if (! mail_only) {
X	  mailbox_defined = (mailbox[0] != '\0'); 
X
X	  /* get the cursor control keys... */
X
X	  if ((cp = return_value_of("ku")) == NULL || strlen(cp) != 2)
X	    cursor_control = FALSE;
X	  else {
X	    strcpy(up, cp);
X	    if ((cp = return_value_of("kd")) == NULL || strlen(cp) != 2)
X	      cursor_control = FALSE;
X	    else {
X	      strcpy(down, cp);
X	      cursor_control = TRUE;
X	      transmit_functions(ON);
X	    }
X	  }
X
X	  strcpy(start_highlight, "->");
X	  end_highlight[0] = '\0';
X
X	  if (!arrow_cursor) {	/* try to use inverse bar instead */
X	    if ((cp = return_value_of("so")) != NULL) {
X	      strcpy(start_highlight, cp);
X	      if ((cp = return_value_of("se")) == NULL)
X	        strcpy(start_highlight, "->");
X	      else {
X	        strcpy(end_highlight, cp);
X	        has_highlighting = TRUE;
X	      }
X	    }
X	  }
X	}
X
X	if (read_aliases)
X  	  read_alias_files();
X
X	if (! mail_only) {
X	  if (mini_menu)
X	    headers_per_page = LINES - 13;
X	  else
X	    headers_per_page = LINES -  8;	/* 5 more headers! */
X
X	  newmbox(1,FALSE, TRUE);	/* read in the mailbox! */
X	}
X
X	init_findnode();	/* set up the path alias stuff */
X
X	dprint0(2,"\n-- end of initialization phase --\n");
X
X	dprint3(2,"\thostname = %s\n\tusername = %s\n\tfull_username = \"%s\"\n",
X	         hostname, username, full_username);
X
X	dprint3(2,"\thome = %s\n\teditor = %s\n\tmailbox = %s\n",
X		 home, editor, mailbox);
X
X	dprint3(2,"\tinfile = %s\n\tfolder-dir = %s\n\tprintout = \"%s\"\n",
X		 infile, folders, printout);
X	
X	dprint3(2,"\tsavefile = %s\n\tprefix = \"%s\"\n\tshell = %s\n",
X		savefile, prefixchars, shell);
X	
X	dprint0(1,"-- beginning execution phase --\n\n");
X}
X
Xget_term_chars()
X{
X	/** This routine sucks out the special terminal characters
X	    ERASE and KILL for use in the input routine.  The meaning 
X            of the characters are (dare I say it?) fairly obvious... **/
X
X#ifdef BSD
X	struct sgttyb term_buffer;
X
X# define TCGETA	TIOCGETP
X
X#else 
X	struct termio term_buffer;
X#endif
X
X	if (ioctl(STANDARD_INPUT, TCGETA, &term_buffer) == -1) {
X	  dprint1(1,"Error: %s encountered on ioctl call (get_term_chars)\n", 
X		   error_name(errno));
X	  /* set to defaults for terminal driver */
X	  backspace = BACKSPACE;
X	  kill_line = ctrl('U');
X	}
X	else {
X#ifdef BSD
X	  backspace = term_buffer.sg_erase;
X	  kill_line = term_buffer.sg_kill;
X#else
X	  backspace = term_buffer.c_cc[VERASE];
X	  kill_line = term_buffer.c_cc[VKILL];
X#endif
X	}
X}
X
Xchar *expand_logname()
X{
X	/** Return logname in a nice format (for expanding "&" in the
X	    /etc/passwd file) **/
X
X	static char buffer[SLEN];
X	register int i;
X
X	if (strlen(username) == 0)
X	  buffer[0] = '\0';
X	else {
X	  buffer[0] = toupper(username[0]);
X
X	  for (i=1; username[i] != '\0'; i++)
X	    buffer[i] = tolower(username[i]);
X
X	  buffer[i] = '\0';
X	}
X
X	return( (char *) buffer);	
X}
X
END-OF-FILE

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

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

  chmod 666 $filename
fi

# ---------- file src/edit.c ----------

filename="src/edit.c"

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

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

/** This routine is for allowing the user to edit their current mailbox
    as they wish. 

    (C) Copyright 1986 Dave Taylor
**/

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

extern int errno;

char   *error_name(), *error_description();

edit_mailbox()
{
	/** Allow the user to edit their mailbox, always resynchronizing
	    afterwards.   Due to intense laziness on the part of the
	    programmer, this routine will invoke $EDITOR on the entire
	    file.  The mailer will ALWAYS resync on the mailbox file
	    even if nothing has changed since, not unreasonably, it's
	    hard to figure out what occurred in the edit session...
	
	    Also note that if the user wants to edit their incoming
	    mailbox they'll actually be editing the tempfile that is
	    an exact copy.  More on how we resync in that case later
	    in this code.
	**/

	FILE     *real_mailbox, *temp_mailbox;
	char     filename[SLEN], buffer[LONG_SLEN], temp_infile[SLEN];

	PutLine0(LINES-1,0,"invoking editor...");

	if (mbox_specified == 0)
	  sprintf(filename, "%s%s", temp_mbox, username);
	else
	  strcpy(filename, infile);

	sprintf(buffer, "%s %s", editor, filename);

	Raw(OFF);

	if (system_call(buffer, SH) != 0) {
	  error1("Problems invoking editor %s!", editor);
	  Raw(ON);
	  sleep(2);
	  return(0);
	}

	Raw(ON);

	if (mbox_specified == 0) {	/* uh oh... now the toughie...  */

	  sprintf(temp_infile, "%s%s.temp", mailhome, username);
	  unlink(temp_infile);	/* remove it if it's there... */

	  if (bytes(infile) != mailfile_size) {

	     /* SIGH.  We've received mail since we invoked the editor
		on the mailbox.  We'll have to do some strange stuff to
	        remedy the problem... */

	     PutLine0(LINES, 0, "Warning: new mail received...");
	     CleartoEOLN();

	     if ((temp_mailbox = fopen(filename, "a")) == NULL) {
		dprint2(1, "Attempt to open %s to append failed! (%s)\n", 
			filename, "edit_mailbox");
	       set_error("Couldn't reopen tempfile.  Edit LOST!");
	       return(1);
	     }
	     /** Now let's lock the mailbox up and stream the new stuff 
		 into the temp file... **/

	     lock();	
	     if ((real_mailbox = fopen(infile, "r")) == NULL) {
	       dprint2(1, 
		       "Attempt to open %s for reading new mail failed! (%s)\n",
 		 	infile, "edit_mailbox");
	       sprintf(buffer, "Couldn't open %s for reading!  Edit LOST!", 
		       infile);
	       set_error(buffer);
	       unlock();
	       return(1);
	     }
	     if (fseek(real_mailbox, mailfile_size, 0) != 0) {
	       dprint2(1, "Couldn't seek to end of infile (offset %ld) (%s)\n",
			mailfile_size, "edit_mailbox");
	       set_error("Couldn't seek to end of mailbox.  Edit LOST!");
	       unlock();
	       return(1);
	     }
	
	     /** Now we can finally stream the new mail into the tempfile **/

	     while (fgets(buffer, LONG_SLEN, real_mailbox) != NULL)
	       fprintf(temp_mailbox, "%s", buffer);

	     fclose(real_mailbox);
	     fclose(temp_mailbox);
 	   }
	   else
	     lock();	/* create a lock file if we're replacing mailbox */

	   /** link to the temporary mailbox in the mailhome directory... **/

	   if (link(filename, temp_infile) != 0) 
	     if (errno == EXDEV) {   /* attempt to link across file systems */
   	       if (copy(filename, temp_infile) != 0) {
	         error("Couldn't copy temp file to mailbox!");
	   	 emergency_exit();
	       }
	     }
	     else {
		Write_to_screen("\n\rCouldn't link %s to mailfile %s...\n\r",2,
			filename, temp_infile);
		Write_to_screen("** %s - %s **\n\r", 2,
			error_name(errno), error_description(errno));
	        emergency_exit();
	     }
	
	   /***  G U L P ... let's remove the incoming mail file... ***/
	     
	   unlink(infile);

	   /** and quickly now... **/

	   if (link(temp_infile, infile) != 0) {
	     Write_to_screen(
		    "\n\rCouldn't internally link %s to mailfile %s...\n\r",
		    2, temp_infile, infile);
	     Write_to_screen(
		    "\n\rYou'll need to check out %s for your mail...\n\r",
		    1, temp_infile);
	     Write_to_screen("** %s - %s **\n\r", 2,
		    error_name(errno), error_description(errno));
	     emergency_exit();
	   }

	   /** And let's remove the lock file!  We're DONE!!!  **/

	   unlock();
	   unlink(temp_infile);	/* remove the temp file too */
	   error("edit changes incorporated into new mail...");
	}
	else
	  error("Resynchronizing with new version of mailbox...");

	sleep(2);
	resync();

	return(1);
}
END-OF-FILE

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

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

  chmod 644 $filename
fi

# ---------- file src/errno.c ----------

filename="src/errno.c"

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

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

/** This routine maps error numbers to error names and error messages.
    These are all directly ripped out of the include file errno.h, and
    are HOPEFULLY standardized across the different breeds of Unix!!

    If (alas) yours are different, you should be able to use awk to
    mangle your errno.h file quite simply...

   (C) Copyright 1986 Dave Taylor
**/

#include "headers.h"

char *err_name[] = { 
/* 0 */	        "NOERROR", "No error status currently",
/* 1 */		"EPERM",   "Not super-user",
/* 2 */		"ENOENT",  "No such file or directory",
/* 3 */		"ESRCH",   "No such process",
/* 4 */		"EINTR",   "Interrupted system call",
/* 5 */		"EIO",     "I/O error",
/* 6 */		"ENXIO",   "No such device or address",
/* 7 */		"E2BIG",   "Arg list too long",
/* 8 */		"ENOEXEC", "Exec format error",
/* 9 */		"EBADF",   "Bad file number",
/* 10 */	"ECHILD",  "No children",
/* 11 */	"EAGAIN",  "No more processes",
/* 12 */	"ENOMEM",  "Not enough core",
/* 13 */	"EACCES",  "Permission denied",
/* 14 */	"EFAULT",  "Bad address",
/* 15 */	"ENOTBLK", "Block device required",
/* 16 */	"EBUSY",   "Mount device busy",
/* 17 */	"EEXIST",  "File exists",
/* 18 */	"EXDEV",   "Cross-device link",
/* 19 */	"ENODEV",  "No such device",
/* 20 */	"ENOTDIR", "Not a directory",
/* 21 */	"EISDIR",  "Is a directory",
/* 22 */	"EINVAL",  "Invalid argument",
/* 23 */	"ENFILE",  "File table overflow",
/* 24 */	"EMFILE",  "Too many open files",
/* 25 */	"ENOTTY",  "Not a typewriter",
/* 26 */	"ETXTBSY", "Text file busy",
/* 27 */	"EFBIG",   "File too large",
/* 28 */	"ENOSPC",  "No space left on device",
/* 29 */	"ESPIPE",  "Illegal seek",
/* 30 */	"EROFS",   "Read only file system",
/* 31 */	"EMLINK",  "Too many links",
/* 32 */	"EPIPE",   "Broken pipe",
/* 33 */	"EDOM",    "Math arg out of domain of func",
/* 34 */	"ERANGE",  "Math result not representable",
/* 35 */	"ENOMSG",  "No message of desired type",
/* 36 */	"EIDRM",   "Identifier removed"
	};

char *error_name(errnumber)
int errnumber;
{
	static char buffer[50];

	dprint1(1,"Error Name called with error %d\n", errnumber);

	if (errnumber < 0 || errnumber > 36) 
	  sprintf(buffer,"ERR-UNKNOWN (%d)", errnumber);
	else
	  strcpy(buffer, err_name[2*errnumber]);

	return( (char *) buffer);
}

char *error_description(errnumber)
int errnumber;
{
	static char buffer[50];

	dprint1(1,"Error Description called with error %d\n", errnumber);

	if (errnumber < 0 || errnumber > 36) 
	  sprintf(buffer,"Unknown error - %d - No description", errnumber);
	else
	  strcpy(buffer, err_name[2*errnumber + 1]);

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

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

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

  chmod 644 $filename
fi

# ---------- file src/sort.c ----------

filename="src/sort.c"

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

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

/** Sort mailbox header table by the field specified in the global
    variable "sortby"...if we're sorting by something other than
    the default SENT_DATE, also put some sort of indicator on the
    screen.

    (C) Copyright 1986, Dave Taylor
**/

#include "headers.h"

char *sort_name();

sort_mailbox(entries, visible)
int entries, visible;
{
	/** Sort the header_table definitions... If 'visible', then
	    put the status lines etc **/
	
	int last_index = -1;
	int compare_headers();	/* for sorting */

	dprint1(2,"\n** sorting mailbox by %s **\n\n", sort_name(FALSE));

	if (entries > 0)
	  last_index = header_table[current-1].index_number;

	if (entries > 30 && visible)  
	  error1("sorting messages by %s", sort_name(FALSE));
	
	qsort(header_table, entries, sizeof (struct header_rec), 
	      compare_headers);

	if (last_index > -1)
	  find_old_current(last_index);

	clear_error();
}

int
compare_headers(first, second)
struct header_rec *first, *second;
{
	/** compare two headers according to the sortby value.

	    Sent Date uses a routine to compare two dates,
	    Received date is keyed on the file offsets (think about it)
	    Sender uses the truncated from line, same as "build headers",
	    and size and subject are trivially obvious!!
	 **/

	char from1[SLEN], from2[SLEN];	/* sorting buffers... */
	int  sign = 1;

	
	if (sortby < 0)
	  sign = -1;

	switch (abs(sortby)) {

	  case SENT_DATE : return( sign*compare_dates(first, second) );

	  case RECEIVED_DATE: return ( 
		   sign*(first->index_number - second->index_number) );

	  case SENDER    : tail_of(first->from, from1, TRUE);
			   tail_of(second->from, from2, TRUE);
	  		   return( sign*strcmp(from1, from2));

	  case SIZE      : return( sign*(first->lines - second->lines));

	  case SUBJECT   : return( sign*strcmp(first->subject,second->subject));

	  case STATUS    : return( sign*(first->status - second->status));
	}
}

char *sort_name(pad)
int pad;
{
	/** return the name of the current sort option...
	    If 'pad' is set, then ensure all are the same length by
	    using trailing spaces... 
	**/

	if (sortby < 0) {
	  switch (- sortby) {
	    case SENT_DATE    : return( 
		              pad?     "Reverse Date Mail Sent  " : 
				       "Reverse Date Mail Sent");
	    case RECEIVED_DATE: return("Reverse Date Mail Rec'vd");
	    case SENDER       : return(
			      pad?     "Reverse Message Sender  " : 
				       "Reverse Message Sender");
	    case SIZE         : return("Reverse Lines in Message");
	    case SUBJECT      : return(
			      pad?     "Reverse Message Subject " : 
				       "Reverse Message Subject");
	    case STATUS	      : return(
			      pad?     "Reverse Message Status  " :
			               "Reverse Message Status");
	  }
	}
	else {
	  switch (sortby) {
	    case SENT_DATE    : return( 
		                pad?   "Date Mail Sent          " : 
				       "Date Mail Sent");
	    case RECEIVED_DATE: return(
	                        pad?   "Date Mail Rec'vd        " :
	                               "Date Mail Rec'vd");
	    case SENDER       : return(
			        pad?   "Message Sender          " : 
				       "Message Sender");
	    case SIZE         : return(
	    			pad?   "Lines in Message        " :
	    			       "Lines in Message");
	    case SUBJECT      : return(
			        pad?   "Message Subject         " : 
				       "Message Subject");
	    case STATUS	      : return(
			      pad?     "Message Status          " :
			               "Message Status");
	  }
	}

	return("*UNKNOWN-SORT-PARAMETER*");
}

find_old_current(index)
int index;
{
	/** Set current to the message that has "index" as it's 
	    index number.  This is to track the current message
	    when we resync... **/

	register int i;

	dprint1(2,"find-old-current(%d)\n", index);

	for (i = 0; i < message_count; i++)
	  if (header_table[i].index_number == index) {
	    current = i+1;
	    dprint1(2,"\tset current to %d!\n", current);
	    return;
	  }

	dprint1(2,"\tcouldn't find current index.  Current left as %d\n",
		current);
	return;		/* can't be found.  Leave it alone, then */
}
END-OF-FILE

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

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

  chmod 666 $filename
fi

# ---------- file src/showmsg_cmd.c ----------

filename="src/showmsg_cmd.c"

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

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

/** This is an interface for the showmsg command line.  The possible
    functions that could be invoked from the showmsg command line are
    almost as numerous as those from the main command line and include
    the following;

	   |    = pipe this message to command...
	   !    = call Unix command
	   <    = scan message for calendar info
	   b    = bounce (remail) message
	   d    = mark message for deletion
	   e    = edit entire mailbox
	   f    = forward message
	   g    = group reply
	   j,n  = move to body of next message
	   k    = move to body of previous message
	   p    = print this (all tagged) message
	   r    = reply to this message
	   s    = save this message to a maibox/folder 
	   t    = tag this message
	   x    = Exit Elm NOW

    all commands not explicitly listed here are returned as unprocessed
    to be dealt with at the main command level.

    This function returns 0 if it dealt with the command, or the command
    otherwise.
**/

#include "headers.h"

process_showmsg_command(command)
char command;
{
	switch (command) {
	  case '|' : clear_bottom_of_screen();
		     PutLine0(LINES-3,0,"Command: pipe");
		     softkeys_off();
		     (void) pipe();	/* do pipe regardless */
		     softkeys_on();
		     return(0);		/* must have new screen */

	  case '!' : clear_bottom_of_screen();
		     PutLine0(LINES-3,0,"Command: system call");
		     softkeys_off();
		     (void) subshell();	/* do shell regardless */
		     softkeys_on();
		     return(0);		/* must have new screen */

	  case '<' : 
#ifdef ENABLE_CALENDAR
		     scan_calendar();
#else
		     error("can't scan for calendar entries!");
#endif
		    break;

	  case 'b' : clear_bottom_of_screen();
		     PutLine0(LINES-3,0,"Command: bounce message");
		     remail();
		     return(0);		/* must have new screen */

	  case 'd' : delete(TRUE);
		     break;

	  case 'e' : edit_mailbox();
		     return(0);		/* must have new screen */

	  case 'f' : clear_bottom_of_screen();
		     PutLine0(LINES-3,0,"Command: forward message");
		     (void) forward();
		     return(0);		/* must have new screen */

	  case 'g' : clear_bottom_of_screen();
		     PutLine0(LINES-3,0,"Command: group reply");
		     (void) reply_to_everyone();
		     return(0);		/* must have new screen */

	  case 'j' :
	  case 'n' : if (current < message_count)
		       show_msg(++current);
		     return(0);	

	  case 'k' : if (current > 0)
		       show_msg(--current);
		     return(0);


	  case 'p' : printmsg();	
		     break;

	  case 'r' : clear_bottom_of_screen();
		     PutLine0(LINES-3,0,"Command: reply to message");
		     (void) reply();
		     return(0);		/* must have new screen */

	  case 's' : clear_bottom_of_screen();
		     PutLine0(LINES-3,0,"Command: save message");
		     (void) save();
		     break;

	  case 't' : tag_message();	
		     break;

	  case 'x' : leave();

	  case '\n':
	  case '\r': return(0);		/* avoid <return> looping */

	  default  : return(command);	/* couldn't deal with it! */
	}

	return(1);	/* done with it! */
}

clear_bottom_of_screen()
{
	/** clear the last 4 lines of the screen... **/

	MoveCursor(LINES-4, 0);
	CleartoEOS();
}
END-OF-FILE

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

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

  chmod 666 $filename
fi

echo end of this archive file....
exit 0