[comp.sources.unix] v22i075: ELM mail syste, release 2.3, Part16/26

rsalz@uunet.uu.net (Rich Salz) (06/05/90)

Submitted-by: Syd Weinstein <syd@dsinc.dsi.com>
Posting-number: Volume 22, Issue 75
Archive-name: elm2.3/part16

---- Cut Here and unpack ----
#!/bin/sh
# this is part 16 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file src/hdrconfg.c continued
#
CurArch=16
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/hdrconfg.c"
sed 's/^X//' << 'SHAR_EOF' >> src/hdrconfg.c
X			(void) build_address(strip_commas(cc), expanded_cc);
X			put_cc();
X			break;
X
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(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
X#ifdef ALLOW_SUBSHELL
X	    case '!':  if (subshell())
X			 display_headers();
X		       continue;
X#endif
X
X	    default  : Centerline(ERROR_LINE, "No such header!");
X		       displayed_error = YES;
X	  }
X	}
X}
X
Xdisplay_headers()
X{
X	char buffer[SLEN];
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 (in_reply_to[0])
X	  put_inreplyto();
X	if (user_defined_header[0])
X	  put_userdefined();
X
X	strcpy(buffer, "Choose first letter of header, u)ser defined header, ");
X#ifdef ALLOW_SUBSHELL
X	strcat(buffer, "!)shell, ");
X#endif
X	strcat(buffer, "or <return>.");
X	Centerline(INSTRUCT_LINE, buffer);
X}
X
Xstatic
Xput_header(hline, hcount, field, value)
Xint     hline, hcount;
Xchar    *field, *value;
X{
X	char    *p;
X	int     x, y;
X
X	MoveCursor(hline, 0);
X
X	if (field) {
X	  for (p = field; *p; ++p)
X	    Writechar(*p);
X	  Writechar(':');
X	  Writechar(' ');
X	}
X
X	GetXYLocation(&x, &y);
X
X	for (p = value; *p; ++p) {
X	  if (x >= (hline + hcount))
X	      break;
X	  /* neat hack alert -- danger will robinson */
X	  if ((x + 1) == (hline + hcount)
X	   && (y + 4) == COLUMNS && strlen(p) > 4)
X	    p = " ...";
X	  Writechar(*p);
X	  ++y;
X	  if (*p < 0x20 || *p >= 0x7F || y >= COLUMNS)
X	    GetXYLocation(&x, &y);
X	}
X
X	if (x < (hline + hcount)) {
X	  CleartoEOLN();
X
X	  while (++x < (hline + hcount)) {
X	    MoveCursor(x, 0);
X	    CleartoEOLN();
X	  }
X	}
X}
X
Xenter_date(datebuf)
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
echo "File src/hdrconfg.c is complete"
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 4.1 90/04/28 22:43:11 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
X *
X * 			Copyright (c) 1986, 1987 Dave Taylor
X * 			Copyright (c) 1988, 1989, 1990 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X *	Syd Weinstein, Elm Coordinator
X *	elm@DSI.COM			dsinc!elm
X *
X *******************************************************************************
X * $Log:	help.c,v $
X * Revision 4.1  90/04/28  22:43:11  syd
X * checkin of Elm 2.3 as of Release PL0
X * 
X *
X ******************************************************************************/
X
X/*** help routine for ELM program 
X
X***/
X
X#include <ctype.h>
X#include "headers.h"
X
Xhelp(pager_help)
Xint pager_help;
X{
X	/** Process the request for help [section] from the user.
X	    If pager_help is TRUE, then act a little differently from
X	    if pager_help 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	static char help_message[] =
X   "Press the key you want help for, '?' for a key list, or '.' to exit help";
X	static char help_prompt[] = "Help for key: ";
X
X	MoveCursor(LINES-4,0);
X	CleartoEOS();
X
X	if(pager_help) {
X	  put_border();
X	  Centerline(LINES, help_message);
X	  prompt_line = LINES-3;
X	} else {
X	  Centerline(LINES-4, "ELM Help System");
X	  Centerline(LINES-3, help_message);
X	  prompt_line = LINES-2;
X	}
X	info_line = prompt_line + 1;
X
X	PutLine0(prompt_line, 0, help_prompt);
X
X	do {
X	  MoveCursor(prompt_line, strlen(help_prompt));
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_help? PAGER_HELP : MAIN_HELP);
X		      return(1);
X
X	    case '$': if(!pager_help) 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_help) 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_help) 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_help)
X		       s = "* = Go to the last message in the current folder.";
X		      break;
X
X	    case '-': if(!pager_help) s = 
X"- = Go to the previous page of messages.  This is the same as the LEFT arrow.";
X		      break;
X
X	    case '=': if(!pager_help) s = 
X			"'=' = Go to the first message in the current folder.";
X		      break;
X
X	    case ' ': if(pager_help) 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_help)
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_help)
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_help) s = 
X	       "^ = Toggle the Delete/Undelete status of the current message.";
X		      break;
X
X	    case 'a': if(!pager_help) 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_help) 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_help) s =
X	      "^D = Mark for deletion all messages with the specified pattern.";
X		      break;
X
X	    case 'e': if(!pager_help) 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_help) 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_help) 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_help)
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_help) 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_help) 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_help) 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_help) s = 
X		"Q = Quick quit the mailer, save read, leave unread, delete deleted.";
X		      break;
X
X	    case '\n':
X	    case '\r': if(pager_help)
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_help) s = "^L = Rewrite the screen.";	
X		       break;
X
X            case ctrl('?'):					    /* DEL */
X	    case ctrl('Q'): if(!pager_help) s = "Exit the mail system quickly.";
X		       break;
X
X	    default : if (isdigit(ch) && !pager_help) 
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.",file);
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 4.1 90/04/28 22:43:13 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
X *
X * 			Copyright (c) 1986, 1987 Dave Taylor
X * 			Copyright (c) 1988, 1989, 1990 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X *	Syd Weinstein, Elm Coordinator
X *	elm@DSI.COM			dsinc!elm
X *
X *******************************************************************************
X * $Log:	in_utils.c,v $
X * Revision 4.1  90/04/28  22:43:13  syd
X * checkin of Elm 2.3 as of Release PL0
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 find out
X			   the current location)
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, escaped = OFF;
X
X	clearerr(stdin);
X
X	if(!passwd) {
X	  if(!(x >=0 && y >= 0))
X	    GetXYLocation(&x, &y);
X	  PutLine1(x, y, "%s", string);	
X	}
X
X	CleartoEOLN();
X
X	if (! append_current) {
X	  MoveCursor(x,y);
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 || (!isprint(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	    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	    if(!passwd) {
X	      MoveCursor(x,y);
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 && !isprint(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 || !isprint(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 (!isprint(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
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.  On BSD systems, the EINTR will never be returned
X	    so we instead longjmp from the signal handler.
X	**/
X
X	int ch;
X
X	if (timeout > 0) {
X	  alarm((unsigned) timeout);
X#ifdef	BSD
X	  if (setjmp(GetPromptBuf)) {
X	    InGetPrompt = 0;
X	    ch = NO_OP_COMMAND;
X	    alarm((unsigned) 0);
X	  }
X	  else {
X	    InGetPrompt = 1;
X	    ch = ReadCh();
X	    InGetPrompt = 0;
X	    alarm((unsigned) 0);
X	  }
X#else
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#endif
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 4.1 90/04/28 22:43:15 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
X *
X * 			Copyright (c) 1986, 1987 Dave Taylor
X * 			Copyright (c) 1988, 1989, 1990 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X *	Syd Weinstein, Elm Coordinator
X *	elm@DSI.COM			dsinc!elm
X *
X *******************************************************************************
X * $Log:	init.c,v $
X * Revision 4.1  90/04/28  22:43:15  syd
X * checkin of Elm 2.3 as of Release PL0
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 TERMIOS
X#  include <termios.h>
X   typedef struct termios term_buff;
X#else
X# ifdef TERMIO
X#  include <termio.h>
X#  define tcgetattr(fd,buf)	ioctl((fd),TCGETA,(buf))
X   typedef struct termio term_buff;
X# else
X#  include <sgtty.h>
X#  define tcgetattr(fd,buf)	ioctl((fd),TIOCGETP,(buf))
X   typedef struct sgttyb term_buff;
X# endif
X#endif
X
X#ifdef PWDINSYS
X#  include <sys/pwd.h>
X#else
X#  include <pwd.h>
X#endif
X
X#ifdef I_TIME
X#  include <time.h>
X#endif
X#ifdef I_SYSTIME
X#  include <sys/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(), *index();
Xunsigned short getgid(), getuid(); 
Xvoid exit();
X#ifndef	_POSIX_SOURCE
Xstruct passwd *getpwuid();
X#endif
Xchar *get_full_name();
X
X#ifdef VOIDSIG
X  void
X#else
X  int
X#endif
X#ifdef SIGTSTP
X	sig_user_stop(), sig_return_from_user_stop(),
X#endif
X	quit_signal(), term_signal(), ill_signal(),
X	fpe_signal(),  bus_signal(),  segv_signal(),
X	alarm_signal(), pipe_signal(), hup_signal();
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;
X	register int i, hostlen, domlen; 
X
X#if defined(SIGVEC) & defined(SV_INTERRUPT)
X	struct sigvec alarm_vec;
X#endif
X	char     buffer[SLEN], *cp;
X
X	sprintf(version_buff, "%s PL%d", VERSION, PATCHLEVEL);
X	Raw(ON);
X
X	/* save original user and group ids */
X	userid  = getuid();
X	groupid = getgid();	
X
X	/* make all newly created files private */
X	original_umask = umask(077);
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	/*
X	 * If debug level is fairly low, ignore keyboard signals
X	 * until the screen is set up.
X	 */
X	if (debug < 5) {
X	  signal(SIGINT,  SIG_IGN);
X	  signal(SIGQUIT, SIG_IGN);
X	}
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(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#if defined(SIGVEC) & defined(SV_INTERRUPT)
X	alarm_vec.sv_handler = alarm_signal;
X	alarm_vec.sv_flags = SV_INTERRUPT;
X	sigvec (SIGALRM, &alarm_vec, (struct sigvec *)0);	/* Process Timer Alarm	    */
X#else
X	signal(SIGALRM, alarm_signal);		/* Process Timer Alarm      */
X#endif
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	/*
X	 * Get the host name as per configured behavior.
X	 */
X#ifdef HOSTCOMPILED
X	strncpy(hostname, HOSTNAME, sizeof(hostname) - 1);
X	hostname[sizeof(hostname) - 1] = '\0';
X#else
X	gethostname(hostname, sizeof(hostname));
X#endif
X
X	/*
X	 * now get the domain name, used to build the full name
X	 */
X	gethostdomain(hostdomain, sizeof(hostdomain));
X
X	/*
X	 * now the tough part:
X	 *	we need to make three variables out of this stuff:
X	 *	hostname = just the hostname, as in bangpaths,
X	 *		this is whatever the user gave us so far,
X	 *		we wont change this one
X	 *	hostdomain = this is the domain considered local to this
X	 *		machine, and should be what we got above.
X	 *	hostfullname = this is the full FQDN of this machine,
X	 *		and is a strange combination of the first two.
X	 *	if tail(hostname) == hostdomain
X	 *		then hostfullname = hostname
X	 *			ie: node.ld.domain.type, ld.domain.type -> node.ld.domain.type
X	 *	else if hostname == hostdomain + 1
X	 *		then hostfullname = hostname
X	 *			ie: domain.type, .domain.type -> domain.type
X	 *	
X	 *	else hostfullname = hostname + hostdomain
X	 *			ie: host, .domain.type -> host.domain.type
X	 * lost yet?
X	 */
X	hostlen = strlen(hostname);
X	domlen = strlen(hostdomain);
X	if (hostlen >= domlen) {
X	  if (strcmp(&hostname[hostlen - domlen], hostdomain) == 0)
X	    strcpy(hostfullname, hostname);
X	  else {
X	    strcpy(hostfullname, hostname);
X	    strcat(hostfullname, hostdomain);
X	  }
X	} else {
X	  if (strcmp(hostname, hostdomain + 1) == 0)
X	    strcpy(hostfullname, hostname);
X	  else {
X	    strcpy(hostfullname, hostname);
X	    strcat(hostfullname, hostdomain);
X	  }
X	}
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 send only mode file */
X	if (! mail_only) {
X	  if ((errno = can_access(requestedmfile, READ_ACCESS)) != 0) {
X	    if (strcmp(requestedmfile, defaultfile) != 0 || errno != ENOENT) {
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
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	term_buff term_buffer;
X
X	if (tcgetattr(STANDARD_INPUT,&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#if defined(TERMIO) || defined(TERMIOS)
X	  backspace = term_buffer.c_cc[VERASE];
X	  kill_line = term_buffer.c_cc[VKILL];
X#else
X	  backspace = term_buffer.sg_erase;
X	  kill_line = term_buffer.sg_kill;
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 4.1 90/04/28 22:43:18 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
X *
X * 			Copyright (c) 1986, 1987 Dave Taylor
X * 			Copyright (c) 1988, 1989, 1990 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X *	Syd Weinstein, Elm Coordinator
X *	elm@DSI.COM			dsinc!elm
X *
X *******************************************************************************
X * $Log:	leavembox.c,v $
X * Revision 4.1  90/04/28  22:43:18  syd
X * checkin of Elm 2.3 as of Release PL0
X * 
X *
X ******************************************************************************/
X
X/** leave current folder, updating etc. as needed...
X  
X**/
X
X#include "headers.h"
X#include <sys/types.h>
X#include <sys/stat.h>
X#ifdef LOCK_BY_FLOCK
X#include <sys/file.h>
X#endif
X#include <errno.h>
X
X/**********
X   Since a number of machines don't seem to bother to define the utimbuf
X   structure for some *very* obscure reason.... 
X
X   Suprise, though, BSD has a different utime() entirely...*sigh*
X**********/
X
X#ifndef BSD
X# ifdef NOUTIMBUF
X
Xstruct utimbuf {
X	time_t	actime;		/** access time       **/ 
X	time_t	modtime;	/** modification time **/
X       };
X
X
X# endif /* NOUTIMBUF */
X#endif /* BSD */
X
Xextern int errno;
X
Xchar *error_name(), *error_description(), *strcpy(), *rindex();
Xunsigned short getegid();
X#ifndef	_POSIX_SOURCE
Xunsigned long sleep();
X#endif
X
Xint
Xleave_mbox(resyncing, quitting, prompt)
Xint resyncing, quitting, prompt;
X{
X	/** Close folder, deleting some messages, storing others in mbox,
X	    and keeping others, as directed by user input and elmrc options.
X
X	    Return	1	Folder altered
X			0	Folder not altered
X			-1	New mail arrived during the process and
X					closing was aborted.
X	    If "resyncing" we are just writing out folder to reopen it. We
X		therefore only consider deletes and keeps, not stores to mbox.
X		Also we don't remove NEW status so that it can be preserved
X		across the resync.
X
X	    If "quitting" and "prompt" is false, then no prompting is done.
X		Otherwise prompting is dependent upon the variable
X		question_me, as set by an elmrc option.  This behavior makes
X		the 'q' command prompt just like 'c' and '$', while
X		retaining the 'Q' command for a quick exit that never
X		prompts.
X	**/
X
X	FILE *temp;
X	char temp_keep_file[SLEN], buffer[SLEN];
X	struct stat    buf;		/* stat command  */
X#ifdef BSD
X	time_t utime_buffer[2];		/* utime command */
X#else
X	struct utimbuf utime_buffer;	/* utime command */
X#endif
X	register int to_delete = 0, to_store = 0, to_keep = 0, i,
X		     marked_deleted, marked_read, marked_unread,
X		     last_sortby, ask_questions,  asked_storage_q,
X		     num_chgd_status, need_to_copy;
X	char answer;
X	long bytes();
X
X	dprint(1, (debugfile, "\n\n-- leaving folder --\n\n"));
X
X	if (message_count == 0)
X	  return(0);	/* nothing changed */
X
X	ask_questions = ((quitting && !prompt) ? FALSE : question_me);
X
X	/* YES or NO on softkeys */
X	if (hp_softkeys && ask_questions) {
X	  define_softkeys(YESNO);
X	  softkeys_on();
X	}
X
X	/* Clear the exit dispositions of all messages, just in case
X	 * they were left set by a previous call to this function
X	 * that was interrupted by the receipt of new mail.
X	 */
X	for(i = 0; i < message_count; i++)
X	  headers[i]->exit_disposition = UNSET;
X	  
X	/* Determine if deleted messages are really to be deleted */
X
X	/* we need to know if there are none, or one, or more to delete */
X	for (marked_deleted=0, i=0; i<message_count && marked_deleted<2; i++)
X	  if (ison(headers[i]->status, DELETED))
X	    marked_deleted++;
X
X        if(marked_deleted) {
X	  answer = (always_del ? 'y' : 'n');	/* default answer */
X	  if(ask_questions) {
X	    sprintf(buffer, "Delete message%s? (y/n) ", plural(marked_deleted));
X	    answer = want_to(buffer, answer);
X	  }
X
X	  if(answer == 'y') {
X	    for (i = 0; i < message_count; i++) {
X	      if (ison(headers[i]->status, DELETED)) {
X		headers[i]->exit_disposition = DELETE;
X		to_delete++;
X	      }
X	    }
X	  }
X	}
X	dprint(3, (debugfile, "Messages to delete: %d\n", to_delete));
X
X	/* If this is a non spool file, or if we are merely resyncing,
X	 * all messages with an unset disposition (i.e. not slated for
X	 * deletion) are to be kept.
X	 * Otherwise, we need to determine if read and unread messages
X	 * are to be stored or kept.
X	 */
X	if(folder_type == NON_SPOOL || resyncing) {
X	  to_store = 0;
X	  for (i = 0; i < message_count; i++) {
X	    if(headers[i]->exit_disposition == UNSET) {
X	      headers[i]->exit_disposition = KEEP;
X	      to_keep++;
X	    }
X	  }
X	} else {
X
X	  /* Let's first see if user wants to store read messages 
X	   * that aren't slated for deletion */
X
X	  asked_storage_q = FALSE;
X
X	  /* we need to know if there are none, or one, or more marked read */
X	  for (marked_read=0, i=0; i < message_count && marked_read < 2; i++) {
X	    if((isoff(headers[i]->status, UNREAD))
X	      && (headers[i]->exit_disposition == UNSET))
X		marked_read++;
X	  }
X	  if(marked_read) {
X	    answer = (always_store ? 'y' : 'n');	/* default answer */
X	    if(ask_questions) {
X	      sprintf(buffer, "Move read message%s to \"received\" folder? (y/n) ",
X	        plural(marked_read));
X	      answer = want_to(buffer, answer);
X	      asked_storage_q = TRUE;
X	    }
X
X	    for (i = 0; i < message_count; i++) {
X	      if((isoff(headers[i]->status, UNREAD)) 
X		&& (headers[i]->exit_disposition == UNSET)) {
X
X		  if(answer == 'y') {
X		    headers[i]->exit_disposition = STORE;
X		    to_store++;
X		  } else {
X		    headers[i]->exit_disposition = KEEP;
X		    to_keep++;
X		  }
X	      }
X	    } 
X	  }
X
X	  /* If we asked the user if read messages should be stored,
X	   * and if the user wanted them kept instead, then certainly the
X	   * user would want the unread messages kept as well.
X	   */
X	  if(asked_storage_q && answer == 'n') {
X
X	    for (i = 0; i < message_count; i++) {
X	      if((ison(headers[i]->status, UNREAD))
X		&& (headers[i]->exit_disposition == UNSET)) {
X		  headers[i]->exit_disposition = KEEP;
X		  to_keep++;
X	      }
X	    }
X
X	  } else {
X
X	    /* Determine if unread messages are to be kept */
X
X	    /* we need to know if there are none, or one, or more unread */
X	    for (marked_unread=0, i=0; i<message_count && marked_unread<2; i++)
X	      if((ison(headers[i]->status, UNREAD))
X		&& (headers[i]->exit_disposition == UNSET))
X		  marked_unread++;
X
X	    if(marked_unread) {
X	      answer = (always_keep ? 'y' : 'n');	/* default answer */
X	      if(ask_questions) {
X		sprintf(buffer,
X		  "Keep unread message%s in incoming mailbox? (y/n) ",
X		  plural(marked_unread));
X		answer = want_to(buffer, answer);
X	      }
X
X	      for (i = 0; i < message_count; i++) {
X		if((ison(headers[i]->status, UNREAD))
X		  && (headers[i]->exit_disposition == UNSET)) {
X
X		    if(answer == 'n') {
X		      headers[i]->exit_disposition = STORE;
X		      to_store++;
X		    } else {
X		      headers[i]->exit_disposition = KEEP;
X		      to_keep++;
X		    }
X	      
X		}
X	      }
X	    }
X	  }
X	}
X
X	dprint(3, (debugfile, "Messages to store: %d\n", to_store));
X	dprint(3, (debugfile, "Messages to keep: %d\n", to_keep));
X
X	if(to_delete + to_store + to_keep != message_count) {
X	  dprint(1, (debugfile,
X	  "Error: %d to delete + %d to store + %d to keep != %d message cnt\n",
X	    to_delete, to_store, to_keep, message_count));
X	  error("Something wrong in message counts! Folder unchanged.");
X	  emergency_exit();
X	}
X	  
X
X	/* If we are not resyncing, we are leaving the mailfile and
X	 * the new messages are new no longer. Note that this changes
X	 * their status.
X	 */
X	if(!resyncing) {
X	  for (i = 0; i < message_count; i++) {
X	    if (ison(headers[i]->status, NEW)) {
X	      clearit(headers[i]->status, NEW);
X	      headers[i]->status_chgd = TRUE;
X	    }
X	  }
X	}
X
X	/* If all messages are to be kept and none have changed status
X	 * we don't need to do anything because the current folder won't
X	 * be changed by our writing it out - unless we are resyncing, in
X	 * which case we force the writing out of the mailfile.
SHAR_EOF
echo "End of part 16"
echo "File src/leavembox.c is continued in part 17"
echo "17" > s2_seq_.tmp
exit 0

exit 0 # Just in case...
-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.