[comp.sources.unix] v18i094: Elm mail system, release 2.2, Part15/24

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

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

#!/bin/sh
# this is part 15 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file src/forms.c continued
#
CurArch=15
if test ! -r s2_seq_.tmp
then echo "Please unpack part 1 first!"
     exit 1; fi
( read Scheck
  if test "$Scheck" != $CurArch
  then echo "Please unpack part $Scheck next!"
       exit 1;
  else exit 0; fi
) < s2_seq_.tmp || exit 1
echo "x - Continuing file src/forms.c"
sed 's/^X//' << 'SHAR_EOF' >> src/forms.c
X}
X
Xint
Xmail_filled_in_form(address, subject)
Xchar *address, *subject;
X{
X	/** This is the interesting routine.  This one will read the
X	    message and prompt the user, line by line, for each of
X	    the fields...returns non-zero if it succeeds
X	**/
X
X	FILE  	     *fd;
X	register int lines = 0, count;
X	char         buffer[SLEN], *ptr;
X
X	dprint(4, (debugfile, 
X		"replying to form with;\n\taddress=%s and\n\t subject=%s\n",
X		 address, subject));
X
X        if (fseek(mailfile, headers[current-1]->offset, 0) == -1) {
X	  dprint(1, (debugfile,
X		   "Error: seek %ld resulted in errno %s (%s)\n", 
X		   headers[current-1]->offset, error_name(errno), 
X		   "mail_filled_in_form"));
X	  error2("ELM [seek] couldn't read %d bytes into file (%s).",
X	         headers[current-1]->offset, error_name(errno));
X	  return(0);
X        }
X 
X	/* now we can fly along and get to the message body... */
X
X	while ((ptr = fgets(buffer, SLEN, mailfile)) != NULL) {
X	  if (strlen(buffer) == 1)	/* <return> only */
X	    break;
X	  else if (strncmp(buffer,"From ", 5) == 0 && lines++ > 0) {
X	    error("No form in this message!?");
X	    return(0);
X	  }
X	}
X
X	if (ptr == NULL) {
X	  error("No form in this message!?");
X	  return(0);
X	}
X
X	dprint(6, (debugfile, "- past header of form message -\n"));
X	
X	/* at this point we're at the beginning of the body of the message */
X
X	/* now we can skip to the FORM-IMAGE section by reading through a 
X	   line with a triple asterisk... */
X
X	while ((ptr = fgets(buffer, SLEN, mailfile)) != NULL) {
X	  if (strcmp(buffer, "***\n") == 0)
X	    break;	/* we GOT it!  It's a miracle! */	
X	  else if (strncmp(buffer, "From ",5) == 0) {
X	    error("Badly constructed form.  Can't reply!");
X	    return(0);
X	  }
X	}
X
X	if (ptr == NULL) {
X	  error("Badly constructed form.  Can't reply!");
X	  return(0);
X	}
X
X	dprint(6, (debugfile, "- skipped the non-forms-image stuff -\n"));
X	
X	/* one last thing - let's open the tempfile for output... */
X	
X	sprintf(buffer, "%s%d", temp_form_file, getpid());
X
X	dprint(2, (debugfile,"-- forms sending using file %s --\n", buffer));
X
X	if ((fd = fopen(buffer,"w")) == NULL) {
X	  error2("Can't open \"%s\" as output file! (%s).", buffer,
X		 error_name(errno));
X	  dprint(1, (debugfile,
X		  "** Error %s encountered trying to open temp file %s;\n",
X		  error_name(errno), buffer));
X	  return(0);
X	}
X
X	/* NOW we're ready to read the form image in and start prompting... */
X
X	Raw(OFF);
X	ClearScreen();
X
X	while ((ptr = fgets(buffer, SLEN, mailfile)) != NULL) {
X	  dprint(9, (debugfile, "- read %s", buffer));
X	  if (strcmp(buffer, "***\n") == 0) /* end of form! */
X	    break;
X	 
X	  switch ((count = occurances_of(COLON, buffer))) {
X	    case 0 : printf("%s", buffer);		/* output line */
X		     fprintf(fd, "%s", buffer); 	
X		     break;
X            case 1 : if (buffer[0] == COLON) {
X	             printf(
X"(Enter as many lines as needed, ending with a '.' by itself on a line)\n");
X                     while (fgets(buffer, SLEN, stdin) != NULL)
X		       no_ret(buffer);
X	               if (strcmp(buffer, ".") == 0)
X	                 break;
X	               else 
X			 fprintf(fd,"%s\n", buffer);
X	             }
X	             else 
X		       prompt_for_entry(buffer, fd);
X	             break;
X            default: prompt_for_multiple_entries(buffer, fd, count);
X	  }
X	}
X
X	Raw(ON);
X	fclose(fd);
X
X	/** let's just mail this off now... **/
X
X	mail_form(address, subject);
X
X	return(1);
X}
X
Xprompt_for_entry(buffer, fd)
Xchar *buffer;
XFILE *fd;
X{
X	/** This is called with an entry of the form "prompt:" and will 
X	    display the prompt and save the prompt and the user reply
X	    in the file "fd"
X	**/
X	
X	char mybuffer[SLEN];
X
X	no_ret(buffer);
X
X	dprint(7, (debugfile, "prompt-for-entry \"%s\"\n", buffer));
X
X	printf("%s ", buffer);	fflush(stdout);
X
X	fgets(mybuffer, SLEN, stdin);
X
X	fprintf(fd, "%s: %s", buffer, mybuffer);
X}
X
Xprompt_for_multiple_entries(buffer, fd, entries)
Xchar *buffer;
XFILE *fd;
Xint  entries;
X{
X	/** Almost the same as the above routine, this one deals with lines
X	    that have multiple colons on them.  It must first figure out how
X	    many spaces to allocate for each field then prompts the user, 
X	    line by line, for the entries...
X	**/
X
X	char mybuffer[SLEN], prompt[SLEN], spaces[SLEN];
X	register int  field_size, i, j, offset = 0, extra_tabs = 0;
X
X	dprint(7, (debugfile, 
X		"prompt-for-multiple [%d] -entries \"%s\"\n", entries,
X		buffer));
X
X	strcpy(prompt, "No Prompt Available:");
X
X	while (entries--) {
X	  j=0; 
X	  i = chloc((char *) buffer + offset, COLON) + 1;
X	  while (j < i - 1) {
X	    prompt[j] = buffer[j+offset];
X	    j++;
X	  }
X	  prompt[j] = '\0';
X
X	  field_size = 0;
X
X	  while (whitespace(buffer[i+offset])) {
X	    if (buffer[i+offset] == TAB) {
X	      field_size += 8 - (i % 8);
X	      extra_tabs += (8 - (i % 8)) - 1;
X	    }
X	    else
X	      field_size += 1;
X	    i++;
X	  }
X
X	  offset += i;
X	
X	  if (field_size == 0) 	/* probably last prompt in line... */
X	    field_size = 80 - (offset + extra_tabs);
X
X	  prompt_for_sized_entry(prompt, mybuffer, field_size);
X
X	  spaces[0] = ' ';	/* always at least ONE trailing space... */
X	  spaces[1] = '\0';
X
X	  for (j = strlen(mybuffer); j < field_size; j++)
X	    strcat(spaces, " ");
X
X	  fprintf(fd, "%s: %s%s", prompt, mybuffer, spaces);
X	  fflush(fd);
X	}
X
X	fprintf(fd, "\n");
X}
X
Xprompt_for_sized_entry(prompt, buffer, field_size)
Xchar *prompt, *buffer;
Xint   field_size;
X{
X	/* This routine prompts for an entry of the size specified. */
X
X	register int i;
X
X	dprint(7, (debugfile, "prompt-for-sized-entry \"%s\" %d chars\n", 
X		prompt, field_size));
X
X	printf("%s : ", prompt);
X	
X	for (i=0;i<field_size; i++)
X	  putchar('_');
X	for (i=0;i<field_size; i++)
X	  putchar(BACKSPACE);
X	fflush(stdout);
X
X	fgets(buffer, SLEN, stdin);
X	no_ret(buffer);
X
X	if (strlen(buffer) > field_size) buffer[field_size-1] = '\0';
X}
SHAR_EOF
echo "File src/forms.c is complete"
chmod 0444 src/forms.c || echo "restore of src/forms.c fails"
echo "x - extracting src/hdrconfg.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/hdrconfg.c &&
X
Xstatic char rcsid[] = "@(#)$Id: hdrconfg.c,v 2.12 89/03/25 21:46:24 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.12 $   $State: Exp $
X *
X * 			Copyright (c) 1986, 1987 Dave Taylor
X * 			Copyright (c) 1988, 1989 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X *	Syd Weinstein, Elm Coordinator
X *	elm@dsinc.UUCP			dsinc!elm
X *
X *******************************************************************************
X * $Log:	hdrconfg.c,v $
X * Revision 2.12  89/03/25  21:46:24  syd
X * Initial 2.2 Release checkin
X * 
X *
X ******************************************************************************/
X
X/**   This file contains the routines necessary to be able to modify
X      the mail headers of messages on the way off the machine.  The
X      headers currently supported for modification are:
X
X	Subject:
X	To:
X	Cc:
X	Bcc:
X	Reply-To:
X	Expires:
X	Priority:
X        In-Reply-To:
X	Action:
X
X	<user defined>
X**/
X
X#include "headers.h"
X
X#include <ctype.h>
X
X#ifdef BSD
X#undef toupper
X#endif
X
X/* allow two lines for address-type headers, subject, and in-reply-to */
X/* allow one line for all others - unlikely to exceed one line */
X#define TO_LINE			2
X#define CC_LINE			4
X#define BCC_LINE		6
X#define	SUBJECT_LINE		8
X#define REPLY_TO_LINE		10
X#define	ACTION_LINE		11
X#define	EXPIRES_LINE		12
X#define	PRIORITY_LINE		13
X#define IN_REPLY_TO_LINE	14
X#define USER_DEFINED_HDR_LINE	16
X#define INSTRUCT_LINE		LINES-5
X#define EXTRA_PROMPT_LINE	LINES-3
X#define INPUT_LINE		LINES-2
X#define ERROR_LINE		LINES-1
X
X#define put_to() {ClearLine(TO_LINE+1);\
X  PutLine1(TO_LINE,0,"To: %s",expanded_to);CleartoEOLN();}
X
X#define put_cc() {ClearLine(CC_LINE+1);\
X  PutLine1(CC_LINE,0,"Cc: %s", expanded_cc);CleartoEOLN();}
X
X#define put_bcc() {ClearLine(BCC_LINE+1);\
X  PutLine1(BCC_LINE,0,"Bcc: %s",expanded_bcc);CleartoEOLN();}
X
X#define put_replyto() {PutLine1(REPLY_TO_LINE,0,"Reply-to: %s",reply_to);\
X  CleartoEOLN();}
X
X#define put_subject() {ClearLine(SUBJECT_LINE+1);\
X  PutLine1(SUBJECT_LINE,0,"Subject: %s",subject);CleartoEOLN();}
X
X#define put_action() {PutLine1(ACTION_LINE,0,"Action: %s",action);\
X  CleartoEOLN();}
X
X#define put_expires() {PutLine1(EXPIRES_LINE,0,"Expires: %s",expires);\
X  CleartoEOLN();}
X
X#define put_priority() {PutLine1(PRIORITY_LINE,0,"Priority: %s",priority);\
X  CleartoEOLN();}
X
X#define put_inreplyto() {ClearLine(IN_REPLY_TO_LINE+1);\
X  PutLine1(IN_REPLY_TO_LINE,0,"In-reply-to: %s",in_reply_to);CleartoEOLN();}
X
X#define put_userdefined() {PutLine1(USER_DEFINED_HDR_LINE,0,"%s",\
X  user_defined_header);CleartoEOLN();}
X
X/* these are all defined in the mailmsg file! */
Xextern char subject[SLEN], in_reply_to[SLEN], expires[SLEN], 
X            action[SLEN], priority[SLEN], reply_to[SLEN], to[VERY_LONG_STRING], 
X	    cc[VERY_LONG_STRING], expanded_to[VERY_LONG_STRING], 
X	    expanded_cc[VERY_LONG_STRING], user_defined_header[SLEN],
X	    bcc[VERY_LONG_STRING], expanded_bcc[VERY_LONG_STRING];
X
Xchar *strip_commas(), *strcpy();
X
Xedit_headers()
X{
X	/** Edit headers.  **/
X	int c;
X
X	/*  Expand address-type headers for main part of display */
X	/*  (Unexpanded ones are used on the 'edit-line') */
X	(void) build_address(strip_commas(to), expanded_to);
X	(void) build_address(strip_commas(cc), expanded_cc);
X	(void) build_address(strip_commas(bcc), expanded_bcc);
X	
X	display_headers();
X
X	clearerr(stdin);
X
X	clearerr(stdin);
X
X	while (TRUE) {	/* forever */
X	  PutLine0(INPUT_LINE,0,"Choice: ");
X	  CleartoEOS();
X	  c = getchar();
X	  c = toupper(c);
X	  clear_error();
X	  if (c == EOF)
X		return(0);
X	  switch (c) {
X	    case RETURN:
X	    case LINE_FEED:
X	    case 'Q' :	return(0);
X	    case ctrl('L') : display_headers();
X			break;
X	    case 'T' :	PutLine0(INPUT_LINE, 0, "To: "); CleartoEOLN();
X	             	if (optionally_enter(to, INPUT_LINE, 4, TRUE, FALSE) == -1)
X			  return(0);
X			(void) build_address(strip_commas(to), expanded_to);
X			put_to();
X			break;
X	    case 'S' :	PutLine0(INPUT_LINE, 0, "Subject: "); CleartoEOLN();
X	    		if (optionally_enter(subject,
X			      INPUT_LINE, 9, FALSE, FALSE) == -1)
X			  return(0);
X			put_subject();
X			break;
X	    case 'B' :	PutLine0(INPUT_LINE, 0, "Bcc: "); CleartoEOLN();
X	    		if (optionally_enter(bcc,
X			      INPUT_LINE, 5, TRUE, FALSE) == -1)
X			  return(0);
X			(void) build_address(strip_commas(bcc), expanded_bcc);
X			put_bcc();
X			break;
X	    case 'C' :	PutLine0(INPUT_LINE, 0, "Cc: "); CleartoEOLN();
X	    		if (optionally_enter(cc, INPUT_LINE, 4, TRUE, FALSE) == -1)
X			  return(0);
X			(void) build_address(strip_commas(cc), expanded_cc);
X			put_cc();
X			break;
X	    case 'R' :	PutLine0(INPUT_LINE, 0, "Reply-To: "); CleartoEOLN();
X	    		if(optionally_enter(reply_to,
X			      INPUT_LINE, 10, FALSE, FALSE) == -1)
X			  return(0);
X			put_replyto();
X			break;
X
X	    case 'A' :	PutLine0(INPUT_LINE, 0, "Action: "); CleartoEOLN();
X	    		if (optionally_enter(action,
X			      INPUT_LINE, 8, FALSE, FALSE) == -1)
X			  return(0);
X			put_action();
X			break;
X
X	    case 'P' :	PutLine0(INPUT_LINE, 0, "Priority: "); CleartoEOLN();
X	    		if (optionally_enter(priority,
X			      INPUT_LINE, 10, FALSE, FALSE)==-1)
X			  return(0);
X			put_priority();
X			break;
X
X	    case 'E' :	enter_date(INPUT_LINE, 9, expires);
X			put_expires();
X			break;
X
X	    case 'U' :	PutLine0(EXTRA_PROMPT_LINE, 0, "User defined header: ");
X			CleartoEOLN();
X	   	 	if (optionally_enter(user_defined_header,
X			     INPUT_LINE, 0, FALSE, FALSE)==-1)
X			  return(0);
X			check_user_header(user_defined_header);
X			put_userdefined();
X			ClearLine(EXTRA_PROMPT_LINE);
X			break;
X
X	    case 'I' : if (strlen(in_reply_to) > 0) {
X			 PutLine0(INPUT_LINE, 0, "In-Reply-To: "); CleartoEOLN();
X	                 if (optionally_enter(in_reply_to,
X			     INPUT_LINE, 13, FALSE, FALSE) == -1)
X			   return(0);
X			 put_inreplyto();
X			 break;		
X		       }
X		       /** else fall through as an error **/
X	    default  : Centerline(ERROR_LINE, "Unknown header being specified!");
X	  }
X	} 
X}
X
Xdisplay_headers()
X{
X	ClearScreen();
X
X	Centerline(0,"Message Header Edit Screen");
X
X	put_to();
X	put_cc();
X	put_bcc();
X	put_subject();
X	put_replyto();
X	put_action();
X	put_expires();
X	put_priority();
X	if (strlen(in_reply_to) > 0) put_inreplyto();
X	if (strlen(user_defined_header) > 0) put_userdefined();
X
X	Centerline(INSTRUCT_LINE,
X"Choose first letter of existing header, u)ser defined header, or <return>.");
X}
X
Xenter_date(x, y, datebuf)
Xint x, y;
Xchar *datebuf;
X{
X	/** Enter the number of days this message is valid for, then
X	    display at (x,y) the actual date of expiration.  This 
X	    routine relies heavily on the routine 'days_ahead()' in
X	    the file date.c
X	**/
X
X	int days;
X	char numdaysbuf[SLEN];
X
X	static char prompt[] =
X	  "How many days in the future should this message expire? ";
X
X	PutLine0(INPUT_LINE,0, prompt);
X	CleartoEOLN();
X	*datebuf = *numdaysbuf = '\0';
X
X	optionally_enter(numdaysbuf, INPUT_LINE, strlen(prompt), FALSE, FALSE);
X	sscanf(numdaysbuf, "%d", &days);
X	if (days < 1)
X	  Centerline(ERROR_LINE, "That doesn't make sense!");
X	else if (days > 56)
X	  Centerline(ERROR_LINE, 
X	     "Expiration date must be within eight weeks of today.");
X	else {
X	  days_ahead(days, datebuf);
X	}
X}
X
Xcheck_user_header(header)
Xchar *header;
X{
X	/** check the header format...if bad print error and erase! **/
X
X	register int i = -1;
X
X	if (strlen(header) == 0)
X	   return;
X
X	if (whitespace(header[0])) {
X	  error ("You can't have leading white space in a header!");
X	  header[0] = '\0';
X	  ClearLine(USER_DEFINED_HDR_LINE);
X	  return;
X	}
X
X	if (header[0] == ':') {
X	  error ("You can't have a colon as the first character!");
X	  header[0] = '\0';
X	  ClearLine(USER_DEFINED_HDR_LINE);
X	  return;
X	}
X
X	while (header[++i] != ':') {
X	  if (header[i] == '\0') {
X	    Centerline(ERROR_LINE, "You need to have a colon ending the field name!");
X	    header[0] = '\0';
X	    ClearLine(USER_DEFINED_HDR_LINE);
X	    return;
X	  }
X	  else if (whitespace(header[i])) {
X	    Centerline(ERROR_LINE, "You can't have white space imbedded in the header name!");
X	    header[0] = '\0';
X	    ClearLine(USER_DEFINED_HDR_LINE);
X	    return;
X	  }
X	}
X	
X	return;
X}
SHAR_EOF
chmod 0444 src/hdrconfg.c || echo "restore of src/hdrconfg.c fails"
echo "x - extracting src/help.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/help.c &&
X
Xstatic char rcsid[] = "@(#)$Id: help.c,v 2.13 89/03/25 21:46:26 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.13 $   $State: Exp $
X *
X * 			Copyright (c) 1986, 1987 Dave Taylor
X * 			Copyright (c) 1988, 1989 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X *	Syd Weinstein, Elm Coordinator
X *	elm@dsinc.UUCP			dsinc!elm
X *
X *******************************************************************************
X * $Log:	help.c,v $
X * Revision 2.13  89/03/25  21:46:26  syd
X * Initial 2.2 Release checkin
X * 
X *
X ******************************************************************************/
X
X/*** help routine for ELM program 
X
X***/
X
X#include <ctype.h>
X#include "headers.h"
X
Xhelp(pager)
Xint pager;
X{
X	/** Process the request for help [section] from the user.
X	    If pager is TRUE, then act a little differently from
X	    if pager is FALSE (index screen)
X	 **/
X
X	char ch;		/* character buffer for input */
X	char *s;		/* string pointer...	      */
X	int prompt_line, info_line;
X
X	MoveCursor(LINES-4,0);
X	CleartoEOS();
X
X	if(pager) {
X	  put_border();
X	  Centerline(LINES,
X	     "Press keys you want help for, '?' for a list, or '.' to end.");
X	  prompt_line = LINES-3;
X	} else {
X	  Centerline(LINES-4, "ELM Help System");
X	  Centerline(LINES-3,
X	     "Press keys you want help for, '?' for a list, or '.' to end.");
X	  prompt_line = LINES-2;
X	}
X	info_line = prompt_line + 1;
X
X	PutLine0(prompt_line, 0, "Help on key: ");
X
X	do {
X	  MoveCursor(prompt_line, strlen("Help on key: "));
X	  ch = ReadCh();
X	  
X	  if (ch == '.') return(0);	/* zero means footer rewrite only */
X
X	  s = "Unknown command.  Use '?' for a list of commands.";
X
X	  switch (ch) {
X
X	    case '?': display_helpfile(pager? PAGER_HELP : MAIN_HELP);
X		      return(1);
X
X	    case '$': if(!pager) s =
X"$ = Force resynchronization of the current folder. This will purge deleted mail.";
X		      break;
X
X	    case '!': s = 
X     "! = Escape to the Unix shell of your choice, or just to enter commands.";
X	              break;
X
X	    case '@': if(!pager) s = 
X	   "@ = Debug - display a summary of the messages on the header page.";
X		      break;
X
X	    case '|': s = 
X   "| = Pipe the current message or tagged messages to the command specified.";
X		      break;
X
X	    case '#': if(!pager) s = 
X	    "# = Debug - display all information known about current message.";
X		      break;
X
X	    case '%': s = 
X     "% = Debug - display the computed return address of the current message.";
X		      break;
X
X	    case '*': if(!pager)
X		       s = "* = Go to the last message in the current folder.";
X		      break;
X
X	    case '-': if(!pager) s = 
X"- = Go to the previous page of messages.  This is the same as the LEFT arrow.";
X		      break;
X
X	    case '=': if(!pager) s = 
X			"'=' = Go to the first message in the current folder.";
X		      break;
X
X	    case ' ': if(pager) s =
X  "<space> = Display next screen of current message (or first screen of next).";
X		      else s = "<space> = Display the current message.";
X		      break;
X
X	    case '+': if(!pager)
X	    		s = 
X  "+ = Go to the next page of messages.  This is the same as the RIGHT arrow.";
X		      break;
X
X	    case '/': if(!pager)
X			s = "/ = Search for specified pattern in folder.";
X		      break;
X
X	    case '<': s = 
X	       "< = Scan current message for calendar entries (if enabled).";
X		      break;
X
X	    case '>': s = 
X	       "> = Save current message or tagged messages to specified file.";
X		      break;
X
X	    case '^': if(!pager) s = 
X	       "^ = Toggle the Delete/Undelete status of the current message.";
X		      break;
X
X	    case 'a': if(!pager) s = 
X	   "a = Enter the alias sub-menu section.  Create and display aliases.";
X		      break;
X
X	    case 'b': s = 
X      "b = Bounce (remail) a message to someone as if you have never seen it.";
X		      break;
X
X	    case 'C': s = 
X               "C = Copy current message or tagged messages to specified file.";
X		      break;
X
X	    case 'c': if(!pager) s = 
X	 "c = Change folders, leaving the current folder as if 'quitting'.";
X		      break;
X
X	    case 'd': s = "d = Mark the current message for future deletion.";
X		      break;
X
X	    case ctrl('D') : if(!pager) s =
X	      "^D = Mark for deletion all messages with the specified pattern.";
X		      break;
X
X	    case 'e': if(!pager) s = 
X     "e = Invoke the editor on the entire folder, resynchronizing when done.";
X		      break;
X
X	    case 'f': s = 
X	"f = Forward the current message to someone, return address is yours.";
X		      break;
X
X	    case 'g': s = 
X   "g = Group reply not only to the sender, but to everyone who received msg.";
X		      break;
X
X	    case 'h': s = 
X		 "h = Display message with all Headers (ignore weedout list).";
X	              break;
X
X	    case 'i': if(pager) s = "i = Return to the index.";
X		      break;
X
X	    case 'J': s = "J = Go to the next message.";
X		      break;
X
X	    case 'j': s = 
X  "j = Go to the next undeleted message.  This is the same as the DOWN arrow.";
X		      break;
X
X	    case 'K': s = "K = Go to the previous message.";
X		      break;
X
X	    case 'k': s = 
X"k = Go to the previous undeleted message.  This is the same as the UP arrow.";
X		      break;
X
X	    case 'l': if(!pager) s =
X               "l = Limit displayed messages based on the specified criteria.";
X		      break;
X
X	    case 'm': s = 
X		 "m = Create and send mail to the specified person or persons.";
X		      break;
X
X	    case 'n': if(pager)
X			s = "n = Display the next message.";
X		      else
X			s = 
X	   "n = Display the current message, then move current to next messge.";
X		      break;
X
X	    case 'o': if(!pager) s = "o = Go to the options submenu.";
X	              break;
X
X	    case 'p': s = 
X		      "p = Print the current message or the tagged messages.";
X	              break;
X
X	    case 'q': if(pager) s = 
X			"q = Quit the pager and return to the index.";
X		      else s =
X		    "q = Quit the mailer, asking about deletion, saving, etc.";
X		      break;
X
X	    case 'r': s = 
X"r = Reply to the message.  This only sends to the originator of the message.";
X	              break;
X
X	    case 's': s = 
X               "s = Save current message or tagged messages to specified file.";
X		      break;
X
X	    case 't': s = 
X               "t = Tag a message for further operations (or untag if tagged).";
X		      break;
X
X	    case ctrl('T') : if(!pager) s =
X			    "^T = Tag all messages with the specified pattern.";
X		      break;
X
X	    case 'u': s =
X		      "u = Undelete - remove the deletion mark on the message.";
X		      break;
X
X	    case 'x': s = "x = Exit the mail system quickly.";
X		      break;
X
X	    case 'Q': if(!pager) s = 
X		"Q = Quick quit the mailer, save read, leave unread, delete deleted.";
X		      break;
X
X	    case '\n':
X	    case '\r': if(pager)
X			 s =
X  "<return> = Display current message, or (builtin pager only) scroll forward.";
X		       else
X			 s = "<return> = Display the current message.";
X		       break;
X
X	    case ctrl('L'): if(!pager) s = "^L = Rewrite the screen.";	
X		       break;
X
X            case ctrl('?'):					    /* DEL */
X	    case ctrl('Q'): if(!pager) s = "Exit the mail system quickly.";
X		       break;
X
X	    default : if (isdigit(ch) && !pager) 
X	            s = "<number> = Make specified number the current message.";
X	  }
X
X	  ClearLine(info_line);
X	  Centerline(info_line, s);
X
X	} while (ch != '.');
X	
X	/** we'll never actually get here, but that's okay... **/
X
X	return(0);
X}
X
Xdisplay_helpfile(section)
Xint section;
X{
X	/*** Help me!  Read file 'helpfile.<section>' and echo to screen ***/
X
X	char buffer[SLEN];
X
X	sprintf(buffer, "%s/%s.%d", helphome, helpfile, section);
X	return(display_file(buffer));
X}
X
Xdisplay_file(file)
Xchar *file;
X{
X	/*** Display file to screen ***/
X
X	FILE *fileptr;
X	int  lines=0;
X	char buffer[SLEN];
X
X	if ((fileptr = fopen(file,"r")) == NULL) {
X	  dprint(1, (debugfile,
X		 "Error: Couldn't open file %s (help)\n", file));
X	  error1("Couldn't open file %s.",buffer);
X	  return(FALSE);
X	}
X	
X	ClearScreen();
X
X	while (fgets(buffer, SLEN, fileptr) != NULL) {
X	  if (lines > LINES-3) {
X	    PutLine0(LINES,0,"Press <space> to continue, 'q' to return.");
X	    if(ReadCh() == 'q') {
X	      clear_error();
X	      fclose(fileptr);
X	      return(TRUE);
X	    }
X	    lines = 0;
X	    ClearScreen();
X	    Write_to_screen("%s\r", 1, buffer);
X	  }
X	  else 
X	    Write_to_screen("%s\r", 1, buffer);
X
X	  lines += strlen(buffer)/COLUMNS + 1;
X	}
X
X        PutLine0(LINES,0,"Press any key to return.");
X
X	(void) ReadCh();
X	clear_error();
X
X	fclose(fileptr);
X	return(TRUE);
X}
SHAR_EOF
chmod 0444 src/help.c || echo "restore of src/help.c fails"
echo "x - extracting src/in_utils.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/in_utils.c &&
X
Xstatic char rcsid[] = "@(#)$Id: in_utils.c,v 2.13 89/03/25 21:46:28 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.13 $   $State: Exp $
X *
X * 			Copyright (c) 1986, 1987 Dave Taylor
X * 			Copyright (c) 1988, 1989 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X *	Syd Weinstein, Elm Coordinator
X *	elm@dsinc.UUCP			dsinc!elm
X *
X *******************************************************************************
X * $Log:	in_utils.c,v $
X * Revision 2.13  89/03/25  21:46:28  syd
X * Initial 2.2 Release checkin
X * 
X *
X ******************************************************************************/
X
X/** Mindless I/O routines for ELM 
X	
X**/
X
X#include "headers.h"
X#include <errno.h>
X#include <ctype.h>
X
X#ifdef BSD
X#  undef tolower
X#endif
X
Xextern int errno;		/* system error number */
X
Xunsigned alarm();
X
X#define isstopchar(c)		(c == ' ' || c == '\t' || c == '/')
X#define isslash(c)		(c == '/')
X#define erase_a_char()		{ Writechar(BACKSPACE); Writechar(' '); \
X			          Writechar(BACKSPACE); fflush(stdout); }
X
Xint
Xwant_to(question, dflt)
Xchar *question, dflt;
X{
X	/** Ask 'question' on LINES-2 left enough to just leave room for an
X	    answer, returning the answer in lower case.
X	    Echo answer as full "Yes" or "No".  'dflt' is the 
X	    default answer if <return> is pressed. (Note: 'dflt' is also what 
X	    will be returned if <return> is pressed!)
X	**/
X	register int ch, cols;
X
X	cols = COLUMNS - (strlen(question) + 5 );	/* 5 for "Yes." + 1 */
X
X	MoveCursor(LINES-3, cols);
X	CleartoEOLN();
X	PutLine3(LINES-3, cols,"%s%c%c", question, dflt, BACKSPACE);
X	fflush(stdout);
X	fflush(stdin);
X
X	ch = ReadCh();
X	ch = tolower(ch);
X
X	while (!( ch == 'y' || ch == 'n' || ch == '\n' || ch == '\r')) {
X	  ch = ReadCh();
X	  ch = tolower(ch);
X	}
X	if(ch == '\n' || ch == '\r')
X	  ch = dflt;
X
X	if(ch == 'y')
X	  Write_to_screen("Yes.", 0);
X	else
X	  Write_to_screen("No.", 0);
X
X	return(ch);
X}
X
Xint
Xread_number(ch)
Xchar ch;
X{
X	/** Read a number, where 'ch' is the leading digit! **/
X	
X	char buff[NLEN];
X	int  num;
X
X	buff[0] = ch;
X	buff[1] = '\0';
X
X	PutLine0(LINES-3, COLUMNS-40,"Set current message to :");
X	if (optionally_enter(buff, LINES-3, COLUMNS-15, TRUE, FALSE) == -1)
X	  return(current);
X
X	sscanf(buff,"%d", &num);
X	return(num);
X}
X
Xint
Xoptionally_enter(string, x, y, append_current, passwd)
Xchar *string;
Xint  x,y, append_current, passwd;
X{
X	/** This will display the string on the screen and allow the user to
X	    either accept it (by pressing RETURN) or alter it according to
X	    what the user types.   The various flags are:
X	         string    is the buffer to use (with optional initial value)
X	 	 x,y	   is the location we're at on the screen (-1,-1 means
X			   that we can't use this info and need to explicitly
X			   use backspace-space-backspace sequences)
X		 append_current  means that we have an initial string and that
X			   the cursor should be placed at the END of the line,
X			   not the beginning (the default).
X		 passwd	   accept non-printing characters and do not echo
X			   entered characters.
X	      
X	    If we hit an interrupt or EOF we'll return non-zero.
X	**/
X
X	int ch;
X	register int ch_count = 0, iindex = 0,
X	  use_cursor_control, escaped = OFF;
X
X	clearerr(stdin);
X
X	if(!passwd) {
X	  if(use_cursor_control = (x >=0 && y >= 0))
X	    PutLine1(x, y, "%s", string);	
X	  else
X	    printf("%s", string);
X	}
X
X	CleartoEOLN();
X
X	if (! append_current) {
X	  if (use_cursor_control)
X	    MoveCursor(x,y);
X	  else if(!passwd)
X	    non_destructive_back_up(strlen(string));
X	}
X	else
X	  iindex = strlen(string);
X
X	if (cursor_control)
X	  transmit_functions(OFF);
X
X	/** now we have the screen as we want it and the cursor in the 
X	    right place, we can loop around on the input and return the
X	    string as soon as the user presses <RETURN>
X	**/
X
X	do {
X	  ch = getchar();
X
X	  if (ch == ctrl('D') || ch == EOF) {		/* we've hit EOF */
X	    if (cursor_control)
X	      transmit_functions(ON);
X	    return(1);
X	  }
X
X	  if (ch_count++ == 0) {
X	    if (ch == '\n' || ch == '\r') {
X	      if (cursor_control)
X	        transmit_functions(ON);
X	      return(0);
X	    }
X	    else if (! append_current) {
X	      CleartoEOLN();
X	      iindex = (append_current? strlen(string) : 0);
X	    }
X	  }
X
X	  /* the following is converted from a case statement to
X	     allow the variable characters (backspace, kill_line
X	     and break) to be processed.  Case statements in
X	     C require constants as labels, so it failed ...
X	  */
X
X	  if (ch == backspace &&
X	    (!escaped || (ch < ' ' || ch >  '~' && !passwd))) {
X	    /* This is tricky. Here we are dealing with all situations
X	     * under which a backspace (really whatever erase char is
X	     * set to, not necessarily \b) erases the previous character.
X	     * It will erase unless escaped, because if it's escaped
X	     * it is taken literally. There is one exception to that --
X	     * if backspace would be rejected (we don't accept non-printing
X	     * characters in non-passwd mode), we accept it here as an
X	     * erasing character, for it if got rejected there would
X	     * be no way of erasing a preceding backslash. */
X	    escaped = OFF;
X	    if (iindex > 0) {
X	      if(!passwd)
X		Writechar(BACKSPACE);
X  	      iindex--;
X	    }
X	    if(!passwd) {
X	      Writechar(' ');
X	      Writechar(BACKSPACE);
X	      fflush(stdout);
X	    }
X	  }
X	  else if (ch == EOF || ch == '\n' || ch == '\r') {
X	    escaped = OFF;
X	    string[iindex] = '\0';
X	    if (cursor_control)
X	      transmit_functions(ON);
X	    return(0);
X	  }
X	  else if (!passwd && ch == ctrl('W')) {	/* back up a word! */
X	    escaped = OFF;
X	    if (iindex == 0)
X	      continue;		/* no point staying here.. */
X	    iindex--;
X	    if (isslash(string[iindex])) {
X	      erase_a_char();
X	    }
X	    else {
X	      while (iindex >= 0 && isspace(string[iindex])) {
X	        iindex--;
X	        erase_a_char();
X	      }
X
X	      while (iindex >= 0 && ! isstopchar(string[iindex])) {
X	        iindex--;
X	        erase_a_char();
X	      }
X	      iindex++;	/* and make sure we point at the first AVAILABLE slot */
X	    }
X	  }
X	  else if (!passwd && ch == ctrl('R')) {
X	    escaped = OFF;
X	    string[iindex] = '\0';
X	    if (use_cursor_control) {
X	      PutLine1(x,y, "%s", string);	
X	      CleartoEOLN();
X	    }
X	    else
X	      printf("\n\r%s", string);	
X	  }
X	  else if (!escaped && ch == kill_line) {
X	    /* needed to test if escaped since kill_line character could
X	     * be a desired valid printing character */
X	    escaped = OFF;
X	    if(!passwd) {
X	      if (use_cursor_control)
X		 MoveCursor(x,y);
X	      else
X		 back_up(iindex);
X	      CleartoEOLN();
X	    }
X	    iindex = 0;
X	  }
X	  else if (ch == '\0') {
X	    escaped = OFF;
X	    if (cursor_control)
X	      transmit_functions(ON);
X	    fflush(stdin); 	/* remove extraneous chars, if any */
X	    string[0] = '\0'; /* clean up string, and... */
X	    return(-1);
X	  }
X	  else if (!passwd && (ch < ' ' || ch > '~')) {
X	    /* non-printing character - warn with bell*/
X	    /* don't turn off escaping backslash since current character
X	     * doesn't "use it up".
X	     */
X	    Writechar('\007');
X	  }
X	  else {  /* default case */
X	      if(escaped && (ch == backspace || ch == kill_line)) {
X		/* if last character was a backslash,
X		 * and if this character is escapable
X		 * simply write this character over it even if
X		 * this character is a backslash.
X		 */
X		if(!passwd)
X		  Writechar(BACKSPACE);
X		iindex--;
X		string[iindex++] = ch;
X		if(!passwd)
X		  Writechar(ch);
X	        escaped = OFF;
X	      } else {
X		string[iindex++] = ch;
X		if(!passwd)
X		  Writechar(ch);
X		escaped = ( ch == '\\' ? ON : OFF);
X	      }
X	  }
X	} while (iindex < SLEN);
X
X	string[iindex] = '\0';
X
X	if (cursor_control)
X	  transmit_functions(ON);
X
X	return(0);
X}
X
Xint
Xpattern_enter(string, alt_string, x, y, alternate_prompt)
Xchar *string, *alt_string, *alternate_prompt;
Xint  x,y;
X{
X	/** This function is functionally similar to the routine
X	    optionally-enter, but if the first character pressed
X	    is a '/' character, then the alternate prompt and string
X	    are used rather than the normal one.  This routine 
X	    returns 1 if alternate was used, 0 if not
X	**/
X
X	int ch;
X	register iindex = 0, escaped = OFF;
X
X	PutLine1(x, y, "%s", string);	
X	CleartoEOLN();
X	MoveCursor(x,y);
X
X	if (cursor_control)
X	  transmit_functions(OFF);
X
X	ch = getchar();
X
X	if (ch == '\n' || ch == '\r') {
X	  if (cursor_control)
X	    transmit_functions(ON);
X	  return(0);	/* we're done.  No change needed */
X	}
X	
X	if (ch == '/') {
X	  PutLine1(x, 0, "%s", alternate_prompt);
X	  CleartoEOLN();
X	  (void) optionally_enter(alt_string, x, strlen(alternate_prompt)+1,
X		 FALSE, FALSE);
X	  return(1);
X	}
X
X	CleartoEOLN();
X
X	iindex = 0;
X
X	if (ch == kill_line) {
X	  MoveCursor(x,y);
X          CleartoEOLN();
X	  iindex = 0;
X	}
X	else if (ch != backspace) {
X	  if(ch == '\\') escaped = ON;
X	  Writechar(ch);
X	  string[iindex++] = ch;
X	}
X	else if (iindex > 0) {
X	  iindex--;
X	  erase_a_char();
X	}
X	else {
X	  Writechar(' ');
X	  Writechar(BACKSPACE);
X	}
X
X	do {
X	  fflush(stdout);
X	  ch = getchar();
X
X	  /* the following is converted from a case statement to
X	     allow the variable characters (backspace, kill_line
X	     and break) to be processed.  Case statements in
X	     C require constants as labels, so it failed ...
X	  */
X
X	    if (ch == backspace &&
X	      (!escaped || (ch < ' ' || ch >  '~'))) {
X	      /* This is tricky. Here we are dealing with all situations
X	       * under which a backspace (really whatever erase char is
X	       * set to, not necessarily \b) erases the previous character.
X	       * It will erase unless escaped, because if it's escaped
X	       * it is taken literally. There is one exception to that --
X	       * if backspace would be rejected (we don't accept non-printing
X	       * characters in non-passwd mode), we accept it here as an
X	       * erasing character, for it if got rejected there would
X	       * be no way of erasing a preceding backslash. */
X	      escaped = OFF;
X              if (iindex > 0) {
X		iindex--;
X		erase_a_char();
X	      }
X	      else {
X		Writechar(' ');
X		Writechar(BACKSPACE);
X	      }
X	    }
X	    else if (ch == '\n' || ch == '\r') {
X	      escaped = OFF;
X	      string[iindex] = '\0';
X	      if (cursor_control)
X	        transmit_functions(ON);
X	      return(0);
X	    }
X	    else if (ch == ctrl('W')) {
X	      escaped = OFF;
X	      if (iindex == 0)
X	        continue;		/* no point staying here.. */
X	      iindex--;
X	      if (isslash(string[iindex])) {
X	        erase_a_char();
X	      }
X	      else {
X	        while (iindex >= 0 && isspace(string[iindex])) {
X	          iindex--;
X	          erase_a_char();
X	        }
X
X	        while (iindex >= 0 && ! isstopchar(string[iindex])) {
X	          iindex--;
X	          erase_a_char();
X	        }
X	        iindex++;/* and make sure we point at the first AVAILABLE slot */
X	      }
X	    }
X	    else if (ch == ctrl('R')) {
X	      escaped = OFF;
X	      string[iindex] = '\0';
X	      PutLine1(x,y, "%s", string);	
X	      CleartoEOLN();
X	    }
X	    else if (!escaped && ch == kill_line) {
X	      /* needed to test if escaped since kill_line character could
X	       * be a desired valid printing character */
X	      escaped = OFF;
X	      MoveCursor(x,y);
X              CleartoEOLN();
X	      iindex = 0;
X	    }
X	    else if (ch == '\0') {
X	      escaped = OFF;
X	      if (cursor_control)
X	        transmit_functions(ON);
X	      fflush(stdin); 	/* remove extraneous chars, if any */
X	      string[0] = '\0'; /* clean up string, and... */
X	      return(-1);
X	    }
X	    else if (ch < ' ' || ch > '~') {
X	      /* non-printing character - warn with bell*/
X	      /* don't turn off escaping backslash since current character
X	       * doesn't "use it up".
X	       */
X	      Writechar('\007');
X	    }
X	    else {  /* default case */
X		if(escaped && (ch == backspace || ch == kill_line)) {
X		  /* if last character was a backslash,
X		   * and if this character is escapable
X		   * simply write this character over it even if
X		   * this character is a backslash.
X		   */
X		  Writechar(BACKSPACE);
X		  iindex--;
X		  string[iindex++] = ch;
X		  Writechar(ch);
X		  escaped = OFF;
X		} else {
X		  string[iindex++] = ch;
X		  Writechar(ch);
X		  escaped = ( ch == '\\' ? ON : OFF);
X		}
X	    }
X	} while (iindex < SLEN);
X
X	string[iindex] = '\0';
X
X	if (cursor_control)
X	  transmit_functions(ON);
X	return(0);
X}
X
Xback_up(spaces)
Xint spaces;
X{
X	/** this routine is to replace the goto x,y call for when sending
X	    mail without starting the entire "elm" system up... **/
X	
X	while (spaces--) {
X	  erase_a_char();
X	}
X}
X
Xnon_destructive_back_up(spaces)
Xint spaces;
X{
X	/** same as back_up() but doesn't ERASE the characters on the screen **/
X
X	while (spaces--)
X	  Writechar(BACKSPACE); 
X        fflush(stdout); 
X}
X
Xint
XGetPrompt()
X{
X	/** This routine does a read/timeout for a single character.
X	    The way that this is determined is that the routine to
X	    read a character is called, then the "errno" is checked
X	    against EINTR (interrupted call).  If they match, this
X	    returns NO_OP_COMMAND otherwise it returns the normal
X	    command.	
X	**/
X
X	int ch;
X
X	if (timeout > 0) {
X	  alarm((unsigned) timeout);
X	  errno = 0;	/* we actually have to do this.  *sigh*  */
X	  ch = ReadCh();
X	  if (errno == EINTR) ch = NO_OP_COMMAND;
X	  alarm((unsigned) 0);
X	}
X	else
X	  ch = ReadCh();
X
X	return(ch);
X}
SHAR_EOF
chmod 0444 src/in_utils.c || echo "restore of src/in_utils.c fails"
echo "x - extracting src/init.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/init.c &&
X
Xstatic char rcsid[] = "@(#)$Id: init.c,v 2.24 89/03/25 21:46:31 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.24 $   $State: Exp $
X *
X * 			Copyright (c) 1986, 1987 Dave Taylor
X * 			Copyright (c) 1988, 1989 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X *	Syd Weinstein, Elm Coordinator
X *	elm@dsinc.UUCP			dsinc!elm
X *
X *******************************************************************************
X * $Log:	init.c,v $
X * Revision 2.24  89/03/25  21:46:31  syd
X * Initial 2.2 Release checkin
X * 
X *
X ******************************************************************************/
X
X/***** Initialize - read in all the defaults etc etc 
X*****/
X
X#include "headers.h"
X#include "patchlevel.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 toupper
X#undef tolower
X#endif
X
Xextern int errno;		/* system error number on failure */
Xextern char version_buff[];
X
Xchar *error_name(), *error_description();
X
Xchar *getenv(), *getlogin(), *strcpy(), *strcat();
Xunsigned short getgid(), getuid(); 
Xvoid exit();
X
Xinitialize(requestedmfile)
Xchar *requestedmfile;	/* first mail file to open, empty if the default */
X{
X	/** initialize the whole ball of wax.
X	**/
X	struct passwd *pass, *getpwuid();
X	char *getenv(), *get_full_name();
X
X	register int i, j; 
X#ifdef VOIDSIG
X	void     quit_signal(), term_signal(), ill_signal(),
X		 fpe_signal(),  bus_signal(),  segv_signal(),
X	         alarm_signal(), pipe_signal(), hup_signal();
X#else
X	int      quit_signal(), term_signal(), ill_signal(),
X		 fpe_signal(),  bus_signal(),  segv_signal(),
X	         alarm_signal(), pipe_signal(), hup_signal();
X#endif
X#ifdef SIGTSTP
X#ifdef VOIDSIG
X	int sig_user_stop(), sig_return_from_user_stop();
X#else
X	int sig_user_stop(), sig_return_from_user_stop();
X#endif
X#endif
X	char     buffer[SLEN], *cp;
X
X	sprintf(version_buff, "%s PL%d", VERSION, PATCHLEVEL);
X	Raw(ON);
X
X	userid  = getuid();
X	groupid = getgid();	
X
X	(void)umask(077);	/* make all newly created files private */
X
X	/* Get username (logname), home (login directory), and full_username
X	 * (part of GCOS) field from the password entry for this user id.
X	 * Full_username will get overridden by fullname in elmrc, if defined.
X	 */
X
X	if((pass = getpwuid(userid)) == NULL) {
X	  error("You have no password entry!");
X	  Raw(OFF);
X	  exit(1);
X	}
X	strcpy(username, pass->pw_name);
X	strcpy(home, pass->pw_dir);
X
X	if((cp = get_full_name(username)) != NULL)
X	  strcpy(full_username, cp);
X	else
X	  strcpy(full_username, username);	/* fall back on logname */
X
X#ifdef DEBUG
X	if (debug) {		/* setup for dprint() statements! */
X	  char newfname[SLEN], filename[SLEN];
X
X	  sprintf(filename, "%s/%s", home, DEBUGFILE);
X	  if (access(filename, ACCESS_EXISTS) == 0) {	/* already one! */
X	    sprintf(newfname,"%s/%s", home, OLDEBUG);
X	    (void) rename(filename, newfname);
X	  }
X
X	  /* Note what we just did up there: we always save the old
X	     version of the debug file as OLDEBUG, so users can mail
X	     copies of bug files without trashing 'em by starting up
X	     the mailer.  Dumb, subtle, but easy enough to do!
X 	  */
X
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	  chown(filename, userid, groupid); /* file owned by user */
X
X	  fprintf(debugfile, 
X     "Debug output of the ELM program (at debug level %d).  Version %s\n\n",
X		  debug, version_buff);
X	}
X#endif
X
X	if(!check_only && !batch_only) {
X	  if ((i = InitScreen()) < 0) {
X	    if (i == -1) {
X	      printf( 
X"Sorry, but you must specify what type of terminal you're on if you want to\n");
X	      printf( 
X"run the \"elm\" program. (You need your environment variable \"TERM\" set.)\n"
X		     );
X	      dprint(1,(debugfile,"No $TERM variable in environment!\n"));
X	    }
X	    else if (i == -2) {
X	      printf(
X"You need a cursor-addressable terminal to run \"elm\" and I can't find any\n");
X	      printf(
X"kind of termcap entry for \"%s\" - check your \"TERM\" setting...\n",
X		   getenv("TERM"));
X	      dprint(1,
X		(debugfile,"$TERM variable is an unknown terminal type!\n"));
X	    } else {
X	      printf("Failed trying to initialize your terminal entry: unknown return code %d\n", i);
X	      dprint(1, (debugfile, "Initscreen returned unknown code: %d\n",
X		  i));
X	    }
X	    Raw(OFF);
X	    exit(1);	/* all the errors share this exit statement */
X	  }
X	}
X
X	if (debug < 5) {	/* otherwise let the system trap 'em! */
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	  signal(SIGHUP,  hup_signal);		/* HangUp (line dropped)    */
X	}
X	else {
X	  dprint(3,(debugfile,
X  "\n*** Elm-Internal Signal Handlers Disabled due to debug level %d ***\n\n",
X		    debug));
X	}
X	
X	signal(SIGALRM, alarm_signal);		/* Process Timer Alarm	    */
X	signal(SIGPIPE, pipe_signal);		/* Illegal Pipe Operation   */
X#ifdef SIGTSTP
X	signal(SIGTSTP, sig_user_stop);		/* Suspend signal from tty  */
X	signal(SIGCONT, sig_return_from_user_stop);	/* Continue Process */
X#endif
X
X	get_term_chars();
X	
X#ifdef HOSTCOMPILED
X	strncpy(hostname, HOSTNAME, sizeof(hostname));
X#else
X	gethostname(hostname, sizeof(hostname));
X#endif
X	gethostdomain(hostdomain, sizeof(hostdomain));
X
X	/* Determine the default mail file name.
X	 * 
X	 * First look for an environment variable MAIL, then
X	 * use then mailhome if it is not found
X	 */
X	if ((cp = getenv("MAIL")) == NULL)
X		sprintf(defaultfile, "%s%s", mailhome, username);
X	else
X		strcpy(defaultfile, cp);
X
X	/* Determine options that might be set in the .elm/elmrc */
X	read_rc_file();
X
X	/* Determine the mail file to read */
X	if (*requestedmfile == '\0')
X	  strcpy(requestedmfile, defaultfile);
X	else if(!expand_filename(requestedmfile, FALSE)) {
X	    Raw(OFF);
X	    exit(0);
X        }
X	if (check_size)
X	  if(check_mailfile_size(requestedmfile) != 0) {
X	      Raw(OFF);
X	      exit(0);
X	  }
X
X	/* check for permissions only if not default mail file */
X	if(strcmp(requestedmfile, defaultfile) != 0) {
X	  if ((errno = can_access(requestedmfile, READ_ACCESS))) {
X	    dprint(1, (debugfile,
X		  "Error: given file %s as folder - unreadable (%s)!\n", 
X		  requestedmfile, error_name(errno)));
X	    fprintf(stderr,"Can't open folder '%s' for reading!\n",
X	    	  requestedmfile);
X	    Raw(OFF);
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	ScreenSize(&LINES, &COLUMNS);
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 && ! check_only) {
X
X	  /* get the cursor control keys... */
X
X	  cursor_control = FALSE;
X
X	  if ((cp = return_value_of("ku")) != NULL) {
X	    strcpy(up, cp);
X	    if ((cp = return_value_of("kd")) != NULL) {
X	      strcpy(down, cp);
X	      if ((cp = return_value_of("kl")) != NULL) {
X		strcpy(left, cp);
X		if ((cp = return_value_of("kr")) != NULL) {
X		  strcpy(right, cp);
X		  cursor_control = TRUE;
X		  transmit_functions(ON);
X		}
X	      }
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	/** clear the screen **/
X	if(!check_only && !batch_only)
X	  ClearScreen();
X
X	if (! mail_only && ! check_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(requestedmfile, FALSE);	/* read in the folder! */
X	}
X
X#ifdef DEBUG
X	if (debug >= 2 && debug < 10) {
X	  fprintf(debugfile,
X"hostname = %-20s \tusername = %-20s \tfullname = %-20s\n",
X	         hostname, username, full_username);
X
X	  fprintf(debugfile,
X"home     = %-20s \teditor   = %-20s \trecvd_mail  = %-20s\n",
X		 home, editor, recvd_mail);
X
X	  fprintf(debugfile,
X"cur_folder   = %-20s \tfolders  = %-20s \tprintout = %-20s\n",
X		 cur_folder, folders, printout);
X	
X	  fprintf(debugfile,
X"sent_mail = %-20s \tprefix   = %-20s \tshell    = %-20s\n\n",
X		sent_mail, prefixchars, shell);
X	
X	  if (local_signature[0])
X	    fprintf(debugfile, "local_signature = \"%s\"\n",
X			local_signature);
X	  if (remote_signature[0])
X	    fprintf(debugfile, "remote_signature = \"%s\"\n",
X			remote_signature);
X	  if (local_signature[0] || remote_signature[0])
X	    fprintf(debugfile, "\n");
X	}
X#endif
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	  dprint(1, (debugfile,
X		   "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}
SHAR_EOF
chmod 0444 src/init.c || echo "restore of src/init.c fails"
echo "x - extracting src/leavembox.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/leavembox.c &&
X
Xstatic char rcsid[] = "@(#)$Id: leavembox.c,v 2.26 89/03/25 21:46:33 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.26 $   $State: Exp $
X *
X * 			Copyright (c) 1986, 1987 Dave Taylor
X * 			Copyright (c) 1988, 1989 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X *	Syd Weinstein, Elm Coordinator
X *	elm@dsinc.UUCP			dsinc!elm
X *
SHAR_EOF
echo "End of part 15"
echo "File src/leavembox.c is continued in part 16"
echo "16" > s2_seq_.tmp
exit 0

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