From: sources@anomaly.sbs.risc.net
Subject: v01i112 - ELM v2.3.11, Electronic Mail Reader - Part 12/20
Reply-To: sources@anomaly.sbs.risc.net
Organization: The Rhode Island Internet Systems Cooperative Network
Date: Sun, 13 Sep 1992 17:43:05 GMT
Followup-To: biz.sco.general


#!/bin/sh
# this is part.12 (part 12 of a multipart archive)
# do not concatenate these parts, unpack them in order with /bin/sh
# file src/errno.c continued
#
if test ! -r shar3_seq_.tmp; then
	echo "Please unpack part 1 first!"
	exit 1
fi
(read Scheck
 if test "$Scheck" != 12; then
	echo "Please unpack part $Scheck next!"
	exit 1
 else
	exit 0
 fi
) < shar3_seq_.tmp || exit 1
echo "x - Continuing file src/errno.c"
sed 's/^X//' << 'SHAR_EOF' >> src/errno.c &&
X/* 21 */	"EISDIR",  "Is a directory",
X/* 22 */	"EINVAL",  "Invalid argument",
X/* 23 */	"ENFILE",  "File table overflow",
X/* 24 */	"EMFILE",  "Too many open files",
X/* 25 */	"ENOTTY",  "Not a typewriter",
X/* 26 */	"ETXTBSY", "Text file busy",
X/* 27 */	"EFBIG",   "File too large",
X/* 28 */	"ENOSPC",  "No space left on device",
X/* 29 */	"ESPIPE",  "Illegal seek",
X/* 30 */	"EROFS",   "Read only file system",
X/* 31 */	"EMLINK",  "Too many links",
X/* 32 */	"EPIPE",   "Broken pipe",
X/* 33 */	"EDOM",    "Math arg out of domain of func",
X/* 34 */	"ERANGE",  "Math result not representable",
X/* 35 */	"ENOMSG",  "No message of desired type",
X/* 36 */	"EIDRM",   "Identifier removed"
X	};
X
Xchar *strcpy();
X
Xchar *error_name(errnumber)
Xint errnumber;
X{
X	static char buffer[50];
X
X	if (errnumber < 0 || errnumber > 36) 
X	  sprintf(buffer,"ERR-UNKNOWN (%d)", errnumber);
X	else
X	  strcpy(buffer, err_name[2*errnumber]);
X
X	return( (char *) buffer);
X}
X
Xchar *error_description(errnumber)
Xint errnumber;
X{
X	static char buffer[50];
X
X	if (errnumber < 0 || errnumber > 36) 
X	  sprintf(buffer,"Unknown error - %d - No description", errnumber);
X	else
X	  strcpy(buffer, err_name[2*errnumber + 1]);
X
X	return ( (char *) buffer);
X}
SHAR_EOF
echo "File src/errno.c is complete" &&
# ============= src/exitprog.c ==============
echo "x - extracting src/exitprog.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/exitprog.c &&
X
Xstatic char rcsid[] = "@(#)$Id: exitprog.c,v 4.1 90/04/28 22:43:00 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:	exitprog.c,v $
X * Revision 4.1  90/04/28  22:43:00  syd
X * checkin of Elm 2.3 as of Release PL0
X * 
X *
X ******************************************************************************/
X
X#include "headers.h"
X
Xint
Xexit_prog()
X{
X	/** Exit, abandoning all changes to the mailbox (if there were
X	    any, and if the user say's it's ok)
X	**/
X
X	char buffer[SLEN], answer;
X	register int i, changes;
X
X	dprint(1, (debugfile, "\n\n-- exiting --\n\n"));
X
X	/* Determine if any messages are scheduled for deletion, or if
X	 * any message has changed status
X	 */
X	for (changes = 0, i = 0; i < message_count; i++)
X	  if (ison(headers[i]->status, DELETED) || headers[i]->status_chgd)
X	    changes++;
X	
X	if (changes) {
X	  /* YES or NO on softkeys */
X	  if (hp_softkeys) {
X	    define_softkeys(YESNO);
X	    softkeys_on();
X	  }
X	  sprintf(buffer,"Abandon change%s to mailbox? (y/n) ",plural(changes));
X	  answer = want_to(buffer, 'n');
X
X	  if(answer != 'y') return -1;
X	}
X
X	fflush(stdout);
X	return leave(0);
X}
SHAR_EOF
# ============= src/expires.c ==============
echo "x - extracting src/expires.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/expires.c &&
X
Xstatic char rcsid[] = "@(#)$Id: expires.c,v 4.1 90/04/28 22:43:01 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:	expires.c,v $
X * Revision 4.1  90/04/28  22:43:01  syd
X * checkin of Elm 2.3 as of Release PL0
X * 
X *
X ******************************************************************************/
X
X/** This routine is written to deal with the Expires: header on the
X    individual mail coming in.  What it does is to look at the date,
X    compare it to todays date, then set the EXPIRED flag on the
X    current message if it is true...
X**/
X
X#include "headers.h"
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 <ctype.h>
X
X#ifdef BSD
X#undef toupper
X#undef tolower
X#endif
X
Xprocess_expiration_date(date, message_status)
Xchar *date;
Xint  *message_status;
X{
X	struct tm *timestruct;
X	long thetime;
X	char word1[WLEN], word2[WLEN], word3[WLEN], word4[WLEN], word5[WLEN];
X	int  month = 0, day = 0, year = 0, hour = 0, minute = 0;
X#ifndef	_POSIX_SOURCE
X	struct tm *localtime();
X	long time();
X#endif
X
X	/** first step is to break down the date given into MM DD YY HH MM
X	    format:  The possible formats for this field are, by example:
X	
X		(1) Mon, Jun 11, 87
X		(2) Mon, 11 Jun 87
X		(3) Jun 11, 87
X		(4) 11 Jun 87
X		(5) 11/06/87	<- ambiguous - will be ignored!!
X		(6) 8711061248GMT
X		(7) Mon, Jun 11, 87 12:48:35 GMT
X
X	    The reason #5 is considered ambiguous will be made clear
X	    if we consider a message to be expired on Jan 4, 88:
X			01/04/88	in the United States
X			04/01/88	in Europe
X	    so is the first field the month or the day?  Standard prob.
X	**/
X
X	sscanf(date, "%s %s %s %s %s",
X	    word1, word2, word3, word4, word5);
X
X	if (strlen(word5) != 0) {	/* we have form #7 */
X	  day   = atoi(word1);
X	  month = month_number(word2);
X	  year  = atoi(word3);
X	  sscanf(word4, "%02d%*c%02d",
X	       &hour, &minute);
X	}
X	else if (strlen(word2) == 0) {	/* we have form #6 or form #5 */
X	  if (isdigit(word1[1]) && isdigit(word1[2]))	  /* form #6 */
X	    sscanf(word1, "%02d%02d%02d%02d%02d%*c",
X		 &year, &month, &day, &hour, &minute);
X	}
X	else if (strlen(word4) != 0) {		   /* form #1 or form #2 */
X	  if(isdigit(word2[0])) {		   /* form #2 */
X	      month = month_number(word3);
X	      day   = atoi(word2);
X	      year  = atoi(word4);
X	  } else {				   /* form #1 */
X	      month = month_number(word2);
X	      day   = atoi(word3);
X	      year  = atoi(word4);
X	  }
X	}
X	else if (! isdigit(word1[0])) {		   /* form #3 */
X	  month = month_number(word1);
X	  day   = atoi(word2);
X	  year  = atoi(word3);
X	}
X	else {					   /* form #4 */
X	  day   = atoi(word1);
X	  month = month_number(word2);
X	  year  = atoi(word3);
X	}
X
X	if (day == 0 || year == 0)
X	  return;			/* we didn't get a valid date */
X
X	/** next let's get the current time and date, please **/
X
X	thetime = time((long *) 0);
X
X	timestruct = localtime(&thetime);
X
X	/** and compare 'em **/
X
X	if (year > timestruct->tm_year)
X	  return;
X	else if (year < timestruct->tm_year)
X	  goto expire_message;
X
X	if (month > timestruct->tm_mon)
X	  return;
X	else if (month < timestruct->tm_mon)
X	  goto expire_message;
X
X	if (day > timestruct->tm_mday)
X	  return;
X	else if (day < timestruct->tm_mday)
X	  goto expire_message;
X
X	if (hour > timestruct->tm_hour)
X	  return;
X	else if (hour < timestruct->tm_hour)
X	  goto expire_message;
X
X	if (minute > timestruct->tm_min)
X	  return;
X
Xexpire_message:
X
X	/** it's EXPIRED!  Yow!! **/
X
X	(*message_status) |= EXPIRED;
X}
SHAR_EOF
# ============= src/file.c ==============
echo "x - extracting src/file.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/file.c &&
X
Xstatic char rcsid[] = "@(#)$Id: file.c,v 4.1.1.1 90/10/07 19:48:05 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 4.1.1.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:	file.c,v $
X * Revision 4.1.1.1  90/10/07  19:48:05  syd
X * fix the bounce problem reported earlier when using MMDF submit as the MTA.
X * From: Jim Clausing <jac%brahms.tinton.ccur.com@RELAY.CS.NET>
X * 
X * Revision 4.1  90/04/28  22:43:02  syd
X * checkin of Elm 2.3 as of Release PL0
X * 
X *
X ******************************************************************************/
X
X/** File I/O routines, mostly the save to file command...
X
X**/
X
X#ifdef PWDINSYS
X#  include <sys/pwd.h>
X#else
X#  include <pwd.h>
X#endif
X
X#include "headers.h"
X#include <ctype.h>
X#include <errno.h>
X
X#ifdef BSD
X#undef tolower
X#endif
X
Xextern int errno;
X
Xchar *error_name(), *error_description(), *strcpy(), *getenv(), *nameof();
Xunsigned long sleep();
X
Xint
Xsave(redraw, silently, delete)
Xint *redraw, silently, delete;
X{
X	/** Save all tagged messages + current in a folder.  If no messages
X	    are tagged, save the current message instead!  This routine
X	    will return ZERO if the operation failed.
X	    'redraw' is set to TRUE iff we use the '?' and mess up
X	    the screen.  Pretty reasonable, eh?  If "silently" is set,
X	    then don't output the "D" character upon marking for
X	    deletion...
X	    If delete is set, then delete the saved messages, else
X	    we are just copying the messages without deletion.
X	**/
X
X	register int tagged = 0, i, oldstat, appending = 0;
X	int mesgnum;	/* message whose address is used for save-by-name fn */
X	char filename[SLEN], address[LONG_STRING], buffer[LONG_STRING];
X	static char helpmsg[LONG_STRING];
X	FILE *save_file;
X
X	oldstat = headers[current-1]->status;	/* remember */
X	*redraw = FALSE;
X
X	for (i=0; i < message_count; i++) {
X	  if (ison(headers[i]->status, TAGGED)) {
X	    if(!tagged)
X	      mesgnum = i;	/* first tagged msg -  use this one for
X				 * save-by-name folder name */
X	    tagged++;
X	  }
X	}
X
X	if (tagged == 0) {
X	  mesgnum = current-1;	/* use this one for save-by-name folder name */
X	  tagged = 1;
X	  setit(headers[current-1]->status, TAGGED);
X	}
X
X	dprint(4, (debugfile, "%d message%s tagged for saving (save)\n", tagged,
X		plural(tagged)));
X
X	while (1) {
X
X	  PutLine2(LINES-2, 0, "%s message%s to: ",
X	  	(delete ? "Save" : "Copy"), plural(tagged));
X
X	  if (save_by_name) {
X	    /** build default filename to save to **/
X	    get_return(address, mesgnum);
X	    get_return_name(address, buffer, TRUE);
X	    sprintf(filename, "=%s", buffer);
X	  }
X	  else
X	    filename[0] = '\0';
X
X	  if (tagged > 1)
X	    optionally_enter(filename, LINES-2, 19, FALSE, FALSE);
X	  else	
X	    optionally_enter(filename, LINES-2, 18, FALSE, FALSE);
X  
X
X	  if (strlen(filename) == 0) {  /** <return> means 'cancel', right? **/
X	    headers[current-1]->status = oldstat;	/* BACK! */
X	    return(0);
X	  }
X	 
X	  if (strcmp(filename,"?") == 0) {	/* user asked for listing */
X	    *redraw = TRUE;	/* set the flag so we know what to do later */
X	    if(!*helpmsg) {	/* format helpmsg if not yet done */
X
X	      strcpy(helpmsg, "\n\r\n\rEnter: <nothing> to not ");
X	      strcat(helpmsg, (delete ? "save" : "copy"));
X	      strcat(helpmsg, " your message");
X	      strcat(helpmsg, (plural(tagged) ? "s" : ""));
X	      strcat(helpmsg, "\n\r       '>' to ");
X	      strcat(helpmsg, (delete ? "save" : "copy"));
X	      strcat(helpmsg, " your message");
X	      strcat(helpmsg, (plural(tagged) ? "s" : ""));
X	      strcat(helpmsg, " to your \"received\" folder (");
X	      strcat(helpmsg, nameof(recvd_mail));
X	      strcat(helpmsg, ")\n\r       '<' to ");
X	      strcat(helpmsg, (delete ? "save" : "copy"));
X	      strcat(helpmsg, " your message");
X	      strcat(helpmsg, (plural(tagged) ? "s" : ""));
X	      strcat(helpmsg, " to your \"sent\" folder (");
X	      strcat(helpmsg, nameof(sent_mail));
X	      strcat(helpmsg, ") \n\r       a filename");
X	      strcat(helpmsg, " (leading '=' denotes your folder directory ");
X	      strcat(helpmsg, folders);
X	      strcat(helpmsg, ").\n\r");
X	    }
X
X	    list_folders(4, helpmsg);
X	    continue;
X	  }
X
X	  /* else - got a folder name - check it out */
X	  if (! expand_filename(filename, TRUE)) {
X	    dprint(2, (debugfile,
X		  "Error: Failed on expansion of filename %s (save)\n", 
X		  filename));
X	    continue;
X	  }
X	  if ((errno = can_open(filename, "a"))) {
X	    error2("Cannot %s message to folder %s!",
X	      delete ? "save":"copy", filename);
X	    continue;
X	  }
X	  break;	/* got a valid filename */
X	}
X
X	save_file_stats(filename);
X
X	if (access(filename,ACCESS_EXISTS)== 0) 	/* already there!! */
X	  appending = 1;
X	  
X	dprint(4,(debugfile, "Saving mail to folder '%s'...\n", filename));
X
X	if ((save_file = fopen(filename,"a")) == NULL) {
X	  dprint(2, (debugfile,
X		"Error: couldn't append to specified folder %s (save)\n", 
X		filename));
X	  error1("Couldn't append to folder %s!", filename);
X	  headers[current-1]->status = oldstat;	/* BACK! */
X	  return(0); 
X	}
X
X	/* if we need a redraw that means index screen no longer present
X	 * so whatever silently was, now it's true - we can't show those
X	 * delete markings.
X	 */
X	if(*redraw) silently = TRUE;
X
X	for (i=0; i < message_count; i++) 	/* save each tagged msg */
X	  if (headers[i]->status & TAGGED)
X	    save_message(i, filename, save_file, (tagged > 1), appending++, 
X			 silently, delete);
X
X	fclose(save_file);
X
X	restore_file_stats(filename);
X
X	if (tagged > 1)
X	  error2("Message%s %s.", plural(tagged), delete ? "saved": "copied");
X	return(1);
X}
X
Xint
Xsave_message(number, filename, fd, pause, appending, silently, delete)
Xint number, pause, appending, silently, delete;
Xchar *filename;
XFILE *fd;
X{
X	/** Save an actual message to a folder.  This is called by 
X	    "save()" only!  The parameters are the message number,
X	    and the name and file descriptor of the folder to save to.
X	    If 'pause' is true, a sleep(2) will be done after the
X	    saved message appears on the screen...
X	    'appending' is only true if the folder already exists 
X	    If 'delete' is true, mark the message for deletion.
X	**/
X
X	register int save_current, is_new;
X	
X	dprint(4, (debugfile, "\tSaving message %d to folder...\n", number));
X
X	save_current = current;
X	current = number+1;
X
X	/* change status from NEW before copy and reset to what it was
X	 * so that copy doesn't look new, but we can preserve new status
X	 * of message in this mailfile. This is important because if
X	 * user does a resync, we don't want NEW status to be lost.
X	 * I.e. NEW becomes UNREAD when we "really" leave a mailfile.
X	 */
X	if(is_new = ison(headers[number]->status, NEW))
X	  clearit(headers[number]->status, NEW);
X	copy_message("", fd, FALSE, FALSE, TRUE, FALSE, FALSE);
X	if(is_new)
X	  setit(headers[number]->status, NEW);
X	current = save_current;
X
X	if (delete)
X	  setit(headers[number]->status, DELETED); /* deleted, but ...   */
X	clearit(headers[number]->status, TAGGED);  /* not tagged anymore */
X
X	if (appending)
X	  error2("Message %d appended to folder %s.", number+1, filename);
X	else
X	  error3("Message %d %s to folder %s.", number+1,
X	     delete ? "saved" : "copied", filename);
X
X	if (! silently)
X	  show_new_status(number);	/* update screen, if needed */
X
X	if (pause && (!silently) && (!appending))
X	  sleep(2);
X}
X
Xint
Xexpand_filename(filename, use_cursor_control)
Xchar *filename;
Xint use_cursor_control;
X{
X	/** Expands	~/	to the current user's home directory
X			~user/	to the home directory of "user"
X			=,+,%	to the user's folder's directory
X			!	to the user's incoming mailbox
X			>	to the user's received folder
X			<	to the user's sent folder
X			shell variables (begun with $)
X
X	    Returns 	1	upon proper expansions
X			0	upon failed expansions
X	 **/
X
X	char temp_filename[SLEN], varname[SLEN],
X	    env_value[SLEN], logname[SLEN], *ptr;
X	register int iindex;
X	struct passwd *pass, *getpwnam();
X	char *getenv();
X
X	ptr = filename;
X	while (*ptr == ' ') ptr++;	/* leading spaces GONE! */
X	strcpy(temp_filename, ptr);
X
X	/** New stuff - make sure no illegal char as last **/
X	if (lastch(temp_filename) == '\n' || lastch(temp_filename) == '\r')
X	  lastch(temp_filename) = '\0';
X	  
X	/** Strip off any trailing backslashes **/
X	while (lastch(temp_filename) == '\\')
X		lastch(temp_filename) = '\0';
X
X	if (temp_filename[0] == '~') {
X	  if(temp_filename[1] == '/')
X	    sprintf(filename, "%s%s%s",
X		  home, (lastch(home) != '/' ? "/" : ""), &temp_filename[2]);
X	  else {
X	    for(ptr = &temp_filename[1], iindex = 0; *ptr && *ptr != '/'; ptr++, iindex++)
X	      logname[iindex] = *ptr;
X	    logname[iindex] = '\0';
X	    if((pass = getpwnam(logname)) == NULL) {
X	      dprint(3,(debugfile, 
X		      "Error: Can't get home directory for %s (%s)\n",
X		      logname, "expand_filename"));
X	      if(use_cursor_control)
X		error1("Don't know what the home directory of \"%s\" is!",
X			logname);
X	      else
X		printf(
X		    "\n\rDon't know what the home directory of \"%s\" is!\n\r",
X		    logname);
X	      return(0);
X	    }
X	    sprintf(filename, "%s%s", pass->pw_dir, ptr);
X	  }
X
X	}
X	else if (temp_filename[0] == '=' || temp_filename[0] == '+' || 
X	 	 temp_filename[0] == '%') {
X	  sprintf(filename, "%s%s%s", folders, 
X		(temp_filename[1] != '/' && lastch(folders) != '/')? "/" : "",
X	  	&temp_filename[1]);
X	}
X	else if (temp_filename[0] == '$') {	/* env variable! */
X	  for(ptr = &temp_filename[1], iindex = 0; isalnum(*ptr); ptr++, iindex++)
X	    varname[iindex] = *ptr;
X	  varname[iindex] = '\0';
X
X	  env_value[0] = '\0';			/* null string for strlen! */
X	  if (getenv(varname) != NULL)
X	    strcpy(env_value, getenv(varname));
X
X	  if (strlen(env_value) == 0) {
X	    dprint(3,(debugfile, 
X		    "Error: Can't expand environment variable $%s (%s)\n",
X		    varname, "expand_filename"));
X	    if(use_cursor_control)
X	      error1("Don't know what the value of $%s is!", varname);
X	    else
X	      printf("\n\rDon't know what the value of $%s is!\n\r", varname);
X	    return(0);
X	  }
X
X	  sprintf(filename, "%s%s%s", env_value, 
X		(*ptr != '/' && lastch(env_value) != '/')? "/" : "", ptr);
X
X	} else if (strcmp(temp_filename, "!") == 0) {
X	  strcpy(filename, defaultfile);
X	} else if (strcmp(temp_filename, ">") == 0) {
X	  strcpy(filename, recvd_mail);
X	} else if (strcmp(temp_filename, "<") == 0) {
X	  strcpy(filename, sent_mail);
X	} else
X	  strcpy(filename, temp_filename);
X	  
X	return(1);
X}
SHAR_EOF
# ============= src/file_util.c ==============
echo "x - extracting src/file_util.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/file_util.c &&
X
Xstatic char rcsid[] = "@(#)$Id: file_util.c,v 4.1 90/04/28 22:43:04 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:	file_util.c,v $
X * Revision 4.1  90/04/28  22:43:04  syd
X * checkin of Elm 2.3 as of Release PL0
X * 
X *
X ******************************************************************************/
X
X/** File oriented utility routines for ELM 
X
X**/
X
X#include "headers.h"
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <ctype.h>
X#include <errno.h>
X
X#ifdef BSD
X# undef tolower
X#endif
X
X#include <signal.h>
X#include <errno.h>
X
X#ifdef BSD
X# include <sys/wait.h>
X#endif
X
Xextern int errno;		/* system error number */
X
Xchar *error_name(), *error_description(), *strcpy(), *getlogin();
Xlong  fsize();
X
Xlong
Xbytes(name)
Xchar *name;
X{
X	/** return the number of bytes in the specified file.  This
X	    is to check to see if new mail has arrived....  (also
X	    see "fsize()" to see how we can get the same information
X	    on an opened file descriptor slightly more quickly)
X	**/
X
X	int ok = 1;
X	extern int errno;	/* system error number! */
X	struct stat buffer;
X
X	if (stat(name, &buffer) != 0)
X	  if (errno != 2) {
X	    dprint(1,(debugfile,
X		     "Error: errno %s on fstat of file %s (bytes)\n", 
X		     error_name(errno), name));
X	    Write_to_screen("\n\rError attempting fstat on file %s!\n\r",
X		     1, name);
X	    Write_to_screen("** %s - %s. **\n\r", 2, error_name(errno),
X		  error_description(errno));
X	    emergency_exit();
X	  }
X	  else
X	    ok = 0;
X	
X	return(ok ? (long) buffer.st_size : 0L);
X}
X
Xint
Xcan_access(file, mode)
Xchar *file; 
Xint   mode;
X{
X	/** returns ZERO iff user can access file or "errno" otherwise **/
X
X	int the_stat = 0, pid, w; 
X	struct stat stat_buf;
X	void _exit(), exit();
X#if defined(BSD) && !defined(WEXITSTATUS)
X	union wait status;
X#else
X	int status;
X#endif
X#ifdef VOIDSIG
X	register void (*istat)(), (*qstat)();
X#else
X	register int (*istat)(), (*qstat)();
X#endif
X	
X#ifdef VFORK
X	if ((pid = vfork()) == 0) {
X#else
X	if ((pid = fork()) == 0) {
X#endif
X	  setgid(groupid);
X	  setuid(userid);		/** back to normal userid **/
X
X	  errno = 0;
X
X	  if (access(file, mode) == 0) 
X	    _exit(0);
X	  else 
X	    _exit(errno != 0? errno : 1);	/* never return zero! */
X	  _exit(127);
X	}
X
X	istat = signal(SIGINT, SIG_IGN);
X	qstat = signal(SIGQUIT, SIG_IGN);
X
X	while ((w = wait(&status)) != pid && w != -1)
X		;
X
X#if	defined(WEXITSTATUS)
X	/* Use POSIX macro if defined */
X	the_stat = WEXITSTATUS(status);
X#else
X#ifdef BSD
X	the_stat = status.w_retcode;
X#else
X	the_stat = status >> 8;
X#endif
X#endif	/*WEXITSTATUS*/
X
X	signal(SIGINT, istat);
X	signal(SIGQUIT, qstat);
X	if (the_stat == 0) {
X	  if (stat(file, &stat_buf) == 0) {
X	    w = stat_buf.st_mode & S_IFMT;
X#ifdef S_IFLNK
X	    if (w != S_IFREG && w != S_IFLNK)
X#else
X	    if (w != S_IFREG)
X#endif
X	      the_stat = 1;
X	  }
X	}
X
X	return(the_stat);
X}
X
Xint
Xcan_open(file, mode)
Xchar *file, *mode;
X{
X	/** Returns 0 iff user can open the file.  This is not
X	    the same as can_access - it's used for when the file might
X	    not exist... **/
X
X	FILE *fd;
X	int the_stat = 0, pid, w, preexisted = 0; 
X	void _exit(), exit();
X#if defined(BSD) && !defined(WEXITSTATUS)
X	union wait status;
X#else
X	int status;
X#endif
X#ifdef VOIDSIG
X	register void (*istat)(), (*qstat)();
X#else
X	register int (*istat)(), (*qstat)();
X#endif
X	
X#ifdef VFORK
X	if ((pid = vfork()) == 0) {
X#else
X	if ((pid = fork()) == 0) {
X#endif
X	  setgid(groupid);
X	  setuid(userid);		/** back to normal userid **/
X	  errno = 0;
X	  if (access(file, ACCESS_EXISTS) == 0)
X	    preexisted = 1;
X	  if ((fd = fopen(file, mode)) == NULL)
X	    _exit(errno);
X	  else {
X	    fclose(fd);		/* don't just leave it open! */
X	    if(!preexisted)	/* don't leave it if this test created it! */
X	      unlink(file);
X	    _exit(0);
X	  }
X	  _exit(127);
X	}
X
X	istat = signal(SIGINT, SIG_IGN);
X	qstat = signal(SIGQUIT, SIG_IGN);
X
X	while ((w = wait(&status)) != pid && w != -1)
X		;
X
X#ifdef WEXITSTATUS
X	the_stat = WEXITSTATUS(status);
X#else
X#ifdef BSD
X	the_stat = status.w_retcode;
X#else
X	the_stat = status >> 8;
X#endif
X#endif /*WEXITSTATUS*/
X	
X	signal(SIGINT, istat);
X	signal(SIGQUIT, qstat);
X
X	return(the_stat);
X}
X
Xint
Xcopy(from, to)
Xchar *from, *to;
X{
X	/** this routine copies a specified file to the destination
X	    specified.  Non-zero return code indicates that something
X	    dreadful happened! **/
X
X	FILE *from_file, *to_file;
X	char buffer[VERY_LONG_STRING];
X	
X	if ((from_file = fopen(from, "r")) == NULL) {
X	  dprint(1, (debugfile, "Error: could not open %s for reading (copy)\n",
X		 from));
X	  error1("Could not open file %s.", from);
X	  return(1);
X	}
X
X	if ((to_file = fopen(to, "w")) == NULL) {
X	  dprint(1, (debugfile, "Error: could not open %s for writing (copy)\n",
X		 to));
X	  error1("Could not open file %s.", to);
X	  return(1);
X	}
X
X	while (fgets(buffer, VERY_LONG_STRING, from_file) != NULL)
X	  if (fputs(buffer, to_file) == EOF) {
X	      Write_to_screen("\n\rWrite failed to tempfile in copy\n\r", 0);
X	      perror(to);
X	      fclose(to_file);
X	      fclose(from_file);
X	      return(1);
X	  }
X	fclose(from_file);
X        if (fclose(to_file) == EOF) {
X	  Write_to_screen("\n\rClose failed on tempfile in copy\n\r", 0);
X	  perror(to);
X	  return(1);
X	}
X	chown( to, userid, groupid);
X
X	return(0);
X}
X
Xint
Xappend(fd, filename)
XFILE *fd;
Xchar *filename;
X{
X	/** This routine appends the specified file to the already
X	    open file descriptor.. Returns non-zero if fails.  **/
X
X	FILE *my_fd;
X	char buffer[VERY_LONG_STRING];
X	
X	if ((my_fd = fopen(filename, "r")) == NULL) {
X	  dprint(1, (debugfile,
X		"Error: could not open %s for reading (append)\n", filename));
X	  return(1);
X	}
X
X	while (fgets(buffer, VERY_LONG_STRING, my_fd) != NULL)
X	  if (fputs(buffer, fd) == EOF) {
X	      Write_to_screen("\n\rWrite failed to tempfile in append\n\r", 0);
X	      perror(filename);
X	      rm_temps_exit();
X	  }
X
X	if (fclose(my_fd) == EOF) {
X	  Write_to_screen("\n\rClose failed on tempfile in append\n\r", 0);
X	  perror(filename);
X	  rm_temps_exit();
X	}
X
X	return(0);
X}
X
X#define FORWARDSIGN	"Forward to "
Xint
Xcheck_mailfile_size(mfile)
Xchar *mfile;
X{
X	/** Check to ensure we have mail.  Only used with the '-z'
X	    starting option. So we output a diagnostic if there is
X	    no mail to read (including  forwarding).
X	    Return 0 if there is mail,
X		   <0 if no permission to check,
X		   1 if no mail,
X		   2 if no mail because mail is being forwarded.
X	 **/
X
X	char firstline[SLEN];
X	int retcode;
X	struct stat statbuf;
X	FILE *fp;
X
X	/* see if file exists first */
X	if (access(mfile, ACCESS_EXISTS) != 0)
X	  retcode = 1;					/* no file */
X
X	/* exists - now see if user has read access */
X	else if (can_access(mfile, READ_ACCESS) != 0)
X	  retcode = -1;					/* no perm */
X
X	/* read access - now see if file has a reasonable size */
X	else if ((fp = fopen(mfile, "r")) == NULL)
X	  retcode = -1;		/* no perm? should have detected this above! */
X	else if (fstat(fileno(fp), &statbuf) == -1) 
X	  retcode = -1;					/* arg error! */
X	else if (statbuf.st_size < 2)		
X	  retcode = 1;	/* empty or virtually empty, e.g. just a newline */
X
X	/* file has reasonable size - see if forwarding */
X	else if (fgets (firstline, SLEN, fp) == NULL)
X	  retcode = 1;		 /* empty? should have detected this above! */
X	else if (first_word(firstline, FORWARDSIGN))
X	  retcode = 2;					/* forwarding */
X
X	/* not forwarding - so file must have some mail in it */
X	else
X	  retcode = 0;
X
X	/* now display the appropriate message if there isn't mail in it */
X	switch(retcode) {
X
X	case -1:	printf("You have no permission to read %s!\n\r", mfile);
X			break;
X	case 1:		printf("You have no mail.\n\r");
X			break;
X	case 2:		no_ret(firstline) /* remove newline before using */
X			printf("Your mail is being forwarded to %s.\n\r",
X			  firstline + strlen(FORWARDSIGN));
X			break;
X	}
X	return(retcode);
X}
X
Xcreate_readmsg_file()
X{
X	/** Creates the file ".current" in the users home directory
X	    for use with the "readmsg" program.
X	**/
X
X	FILE *fd;
X	char buffer[SLEN];
X
X	sprintf(buffer,"%s/%s", home, readmsg_file);
X
X	if ((fd = fopen (buffer, "w")) == NULL) {
X	  dprint(1, (debugfile, 
X		 "Error: couldn't create file %s - error %s (%s)\n",
X		 buffer, error_name(errno), "create_readmsg_file"));
X	  return;	/* no error to user */
X	}
X
X	if (current)
X	  fprintf(fd, "%d\n", headers[current-1]->index_number);
X	else
X	  fprintf(fd, "\n");
X
X	fclose(fd);
X	chown( buffer, userid, groupid);
X}
X
Xlong fsize(fd)
XFILE *fd;
X{
X	/** return the size of the current file pointed to by the given
X	    file descriptor - see "bytes()" for the same function with
X	    filenames instead of open files...
X	**/
X
X	struct stat buffer;
X
X	(void) fstat(fileno(fd), &buffer);
X
X	return( (long) buffer.st_size );
X}
SHAR_EOF
# ============= src/fileio.c ==============
echo "x - extracting src/fileio.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/fileio.c &&
X
Xstatic char rcsid[] = "@(#)$Id: fileio.c,v 4.1.1.1 90/10/07 19:48:08 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 4.1.1.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:	fileio.c,v $
X * Revision 4.1.1.1  90/10/07  19:48:08  syd
X * fix the bounce problem reported earlier when using MMDF submit as the MTA.
X * From: Jim Clausing <jac%brahms.tinton.ccur.com@RELAY.CS.NET>
X * 
X * Revision 4.1  90/04/28  22:43:06  syd
X * checkin of Elm 2.3 as of Release PL0
X * 
X *
X ******************************************************************************/
X
X/** File I/O routines, including deletion from the folder! 
X
X**/
X
X#include "headers.h"
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <ctype.h>
X#include <errno.h>
X
X#ifdef BSD
X#undef tolower
X#endif
X
Xextern int errno;
X
Xchar *error_name(), *index();
X
Xcopy_message(prefix, 
X	     dest_file, 
X	     remove_header, 
X	     remote, 
X	     update_status, 
X	     mmdf_head,
X	     remail)
Xchar *prefix;
XFILE *dest_file;
Xint  remove_header, remote, update_status, mmdf_head, remail;
X{
X	/** Copy current message to destination file, with optional 'prefix' 
X	    as the prefix for each line.  If remove_header is true, it will 
X	    skip lines in the message until it finds the end of header line...
X	    then it will start copying into the file... If remote is true
X	    then it will append "remote from <hostname>" at the end of the
X	    very first line of the file (for remailing) 
X
X	    If "forwarding" is true then it'll do some nice things to
X	    ensure that the forwarded message looks pleasant; e.g. remove
X	    stuff like ">From " lines and "Received:" lines.
X
X	    If "update_status" is true then it will write a new Status:
X	    line at the end of the headers.  It never copies an existing one.
X	**/
X
X    char buffer[SLEN];
X    register struct header_rec *current_header = headers[current-1];
X    register int  lines, front_line, next_front,
X		  in_header = 1, first_line = TRUE, ignoring = FALSE;
X    int	end_header = 0;
X    int sender_added = 0;
X
X      /** get to the first line of the message desired **/
X
X    if (fseek(mailfile, current_header->offset, 0) == -1) {
X       dprint(1, (debugfile, 
X		"ERROR: Attempt to seek %d bytes into file failed (%s)",
X		current_header->offset, "copy_message"));
X       error1("ELM [seek] failed trying to read %d bytes into file.",
X	     current_header->offset);
X       return;
X    }
X
X    /* how many lines in message? */
X
X    lines = current_header->lines;
X
X    /* set up for forwarding just in case... */
X
X    if (forwarding)
X      remove_header = FALSE;
X
X    /* now while not EOF & still in message... copy it! */
X
X    next_front = TRUE;
X
X    while (lines) {
X      if (fgets(buffer, SLEN, mailfile) == NULL)
X        break;
X
X      front_line = next_front;
X
X      if(buffer[strlen(buffer)-1] == '\n') {
X	lines--;	/* got a full line */
X	next_front = TRUE;
X      }
X      else
X	next_front = FALSE;
X      
X      if (front_line && ignoring)
X	ignoring = whitespace(buffer[0]);
X
X      if (ignoring)
X	continue;
X
X#ifdef MMDF
X      if (mmdf_head && strcmp(buffer, MSG_SEPERATOR) == 0)
X	continue;
X#endif /* MMDF */
X
X      /* are we still in the header? */
X
X      if (in_header && front_line) {
X	if (strlen(buffer) < 2) {
X	  in_header = 0;
X	  end_header = -1;
X	  if (remail && !sender_added) {
X	    if (fprintf(dest_file, "%sSender: %s\n", prefix, username) == EOF) {
X	      Write_to_screen("\n\rWrite in copy_message failed\n\r", 0);
X	      dprint(1, (debugfile,"\n*** Fprint failed on copy_message;\n"));
X	      rm_temps_exit();
X	    }
X	  }
X	}
X	else if (!isspace(*buffer)
X	      && index(buffer, ':') == NULL
X#ifdef MMDF
X	      && strcmp(buffer, MSG_SEPERATOR) != 0
X#endif /* MMDF */
X		) {
X	  in_header = 0;
X	  end_header = 1;
X	  if (remail && !sender_added) {
X	    if (fprintf(dest_file, "%sSender: %s\n", prefix, username) == EOF) {
X	      Write_to_screen("\n\rWrite in copy_message failed\n\r", 0);
X	      dprint(1, (debugfile,"\n*** Fprint failed on copy_message;\n"));
X	      rm_temps_exit();
X	    }
X	  }
X	} else if (in_header && remote && first_word(buffer, "Sender:")) {
X	  if (remail)
X	    if (fprintf(dest_file, "%sSender: %s\n", prefix, username) == EOF) {
X	      Write_to_screen("\n\rWrite in copy_message failed\n\r", 0);
X	      dprint(1, (debugfile,"\n*** Fprint failed on copy_message;\n"));
X	      rm_temps_exit();
X	    }
X	  sender_added = TRUE;
X	  continue;
X	}
X	if (end_header) {
X	  if (update_status) {
X	      if (isoff(current_header->status, NEW)) {
X		if (ison(current_header->status, UNREAD)) {
X		  if (fprintf(dest_file, "%sStatus: O\n", prefix) == EOF) {
X		    Write_to_screen("\n\rWrite in copy_message failed\n\r", 0);
X		    dprint(1, (debugfile,"\n*** Fprint failed on copy_message;\n"));
X		    rm_temps_exit();
X		  }
X		} else	/* read */
X#ifdef BSD
X		  if (fprintf(dest_file, "%sStatus: OR\n", prefix) == EOF) {
X#else
X		  if (fprintf(dest_file, "%sStatus: RO\n", prefix) == EOF) {
X#endif
X		    Write_to_screen("\n\rWrite in copy_message failed\n\r", 0);
X		    dprint(1, (debugfile,"\n*** Fprint failed on copy_message;\n"));
X		    rm_temps_exit();
X		  }
X		update_status = FALSE; /* do it only once */
X	      }	/* else if NEW - indicate NEW with no Status: line. This is
X		 * important if we resync a mailfile - we don't want
X		 * NEW status lost when we copy each message out.
X		 * It is the responsibility of the function that calls
X		 * this function to unset NEW as appropriate to its
X		 * reason for using this function to copy a message
X		 */
X
X		/*
X		 * add the missing newline for RFC 822
X		 */
X	      if (end_header > 0) {
X		/* add the missing newline for RFC 822 */
X		if (fprintf(dest_file, "\n") == EOF) {
X		  Write_to_screen("\n\rWrite in copy_message failed\n\r", 0);
X		  dprint(1, (debugfile,"\n*** Fprint failed on copy_message;\n"));
X		  rm_temps_exit();
X		}
X	      }
X	  }
X	}
X      }
X
X      if (in_header) {
X	/* Process checks while in header area */
X
X	if (remove_header) {
X	  ignoring = TRUE;
X	  continue;
X	}
X
X	/* add remote on to front? */
X	if (first_line && remote) {
X	  no_ret(buffer);
X#ifndef MMDF
X	  if (fprintf(dest_file, "%s%s remote from %s\n",
X		  prefix, buffer, hostname) == EOF) {
X		Write_to_screen("\n\rWrite in copy_message failed\n\r", 0);
X		dprint(1, (debugfile,"\n*** Fprint failed on copy_message;\n"));
X		rm_temps_exit();
X	  }
X#else
X	  if (first_word(buffer, "From ")) {
X	    if (fprintf(dest_file, "%s%s remote from %s\n",
X		    prefix, buffer, hostname) == EOF) {
X		Write_to_screen("\n\rWrite in copy_message failed\n\r", 0);
X		dprint(1, (debugfile,"\n*** Fprint failed on copy_message;\n"));
X		rm_temps_exit();
X	    }
X	  } else {
X	    if (fprintf(dest_file, "%s%s\n", prefix, buffer) == EOF) {
X		Write_to_screen("\n\rWrite in copy_message failed\n\r", 0);
X		dprint(1, (debugfile,"\n*** Fprint failed on copy_message;\n"));
X		rm_temps_exit();
X	    }
X	  }
X#endif /* MMDF */
X	  first_line = FALSE;
X	  continue;
X	}
X
X	if (!forwarding) {
X	  if(! first_word(buffer, "Status:")) {
X	    if (fprintf(dest_file, "%s%s", prefix, buffer) == EOF) {
X              dprint(1, (debugfile,"\n*** Fprint failed on copy_message;\n"));
X	      rm_temps_exit();
X	      }
X	    continue;
X	  } else {
X	    ignoring = TRUE;
X	    continue;	/* we will output a new Status: line later, if desired. */
X	  }
X	}
X	else { /* forwarding */
X
X	  if (first_word(buffer, "Received:"   ) ||
X	      first_word(buffer, ">From"       ) ||
X	      first_word(buffer, "Status:"     ) ||
X	      first_word(buffer, "Return-Path:"))
X	      ignoring = TRUE;
X	  else
X	    if (remail && first_word(buffer, "To:")) {
X	      if (fprintf(dest_file, "%sOrig-%s", prefix, buffer) == EOF) {
X                dprint(1, (debugfile,"\n*** Fprint failed on copy_message;\n"));
X	        rm_temps_exit();
X	      }
X	    } else {
X	      if (fprintf(dest_file, "%s%s", prefix, buffer) == EOF) {
X                dprint(1, (debugfile,"\n*** Fprint failed on copy_message;\n"));
X	        rm_temps_exit();
X	      }
X	    }
X	}
X      }
X      else { /* not in header */
X        /* Process checks that occur after the header area */
X
X#ifndef MMDF
X	if(first_word(buffer, "From ") && (real_from(buffer, NULL))) {
X	  dprint(1, (debugfile,
X		 "\n*** Internal Problem...Tried to add the following;\n"));
X	  dprint(1, (debugfile,
X		 "  '%s'\nto output file (copy_message) ***\n", buffer));
X	  break;	/* STOP NOW! */
X	}
X#endif /* MMDF */
X
X	if (fprintf(dest_file, "%s%s", prefix, buffer) == EOF) {
X	  Write_to_screen("\n\rWrite in copy_message failed\n\r", 0);
X	  dprint(1, (debugfile,"\n*** Fprint failed on copy_message;\n"));
X	  rm_temps_exit();
X	}
X      }
X    }
X#ifndef MMDF
X    if (strlen(buffer) + strlen(prefix) > 1)
X	if (fprintf(dest_file, "\n") == EOF) {	/* blank line to keep mailx happy *sigh* */
X	  Write_to_screen("\n\rWrite in copy_message failed\n\r", 0);
X	  dprint(1, (debugfile,"\n*** Fprint failed on copy_message;\n"));
X	  rm_temps_exit();
X	}
X#endif /* MMDF */
X}
X
Xstatic struct stat saved_buf;
Xstatic char saved_fname[SLEN];
X
Xint
Xsave_file_stats(fname)
Xchar *fname;
X{
X	/* if fname exists, save the owner, group, mode and filename.
X	 * otherwise flag nothing saved. Return 0 if saved, else -1.
X	 */
X
X	if(stat(fname, &saved_buf) != -1) {
X	  (void)strcpy(saved_fname, fname);
X	  dprint(2, (debugfile,
X	    "** saved stats for file owner = %d group = %d mode = %o %s **\n",
X	    saved_buf.st_uid, saved_buf.st_gid, saved_buf.st_mode, fname));
X	  return(0);
X	}
X	dprint(2, (debugfile,
X	  "** couldn't save stats for file %s [errno=%d] **\n",
X	  fname, errno));
X	return(-1);
X
X}
X
Xrestore_file_stats(fname)
Xchar *fname;
X{
X	/* if fname matches the saved file name, set the owner and group
X	 * of fname to the saved owner, group and mode,
X	 * else to the userid and groupid of the user and to 700.
X	 * Return	-1 if the  either mode or owner/group not set
X	 *		0 if the default values were used
X	 *		1 if the saved values were used
X	 */
X
X	int old_umask, i, new_mode, new_owner, new_group, ret_code;
X
X
X	new_mode = 0600;
X	new_owner = userid;
X	new_group = groupid;
X	ret_code = 0;
X
X	if(strcmp(fname, saved_fname) == 0) {
X	  new_mode = saved_buf.st_mode;
X	  new_owner = saved_buf.st_uid;
X	  new_group = saved_buf.st_gid;
X	  ret_code = 1;
X	}
X	dprint(2, (debugfile, "** %s file stats for %s **\n",
X	  (ret_code ? "restoring" : "setting"), fname));
X
X	old_umask = umask(0);
X	if((i = chmod(fname, new_mode & 0777)) == -1)
X	  ret_code = -1;
X
X	dprint(2, (debugfile, "** chmod(%s, %.3o) returns %d [errno=%d] **\n",
X		fname, new_mode & 0777, i, errno));
X
X	(void) umask(old_umask);
X
X#ifdef	BSD
X	/*
X	 * Chown is restricted to root on BSD unix
X	 */
X	(void) chown(fname, new_owner, new_group);
X#else
X	if((i = chown(fname, new_owner, new_group)) == -1)
X	  ret_code = -1;
X
X	dprint(2, (debugfile, "** chown(%s, %d, %d) returns %d [errno=%d] **\n",
X		   fname, new_owner, new_group, i, errno));
X#endif
X
X	return(ret_code);
X
X}
X
X/** and finally, here's something for that evil trick: site hiding **/
X
X#ifdef SITE_HIDING
X
Xint
Xis_a_hidden_user(specific_username)
Xchar *specific_username;
X{
X	/** Returns true iff the username is present in the list of
X	   'hidden users' on the system.
X	**/
X	
X	FILE *hidden_users;
X	char  buffer[SLEN];
X
X        /* 
X	this line is deliberately inserted to ensure that you THINK
X	about what you're doing, and perhaps even contact the author
X	of Elm before you USE this option...
X        */
X
X	if ((hidden_users = fopen (HIDDEN_SITE_USERS,"r")) == NULL) {
X	  dprint(1, (debugfile,
X		  "Couldn't open hidden site file %s [%s]\n",
X		  HIDDEN_SITE_USERS, error_name(errno)));
X	  return(FALSE);
X	}
X
X	while (fscanf(hidden_users, "%s", buffer) != EOF)
X	  if (strcmp(buffer, specific_username) == 0) {
X	    dprint(3, (debugfile, "** Found user '%s' in hidden site file!\n",
X		    specific_username));
X	    fclose(hidden_users);
X	    return(TRUE);
X	  }
X
X	fclose(hidden_users);
X	dprint(3, (debugfile, 
X		"** Couldn't find user '%s' in hidden site file!\n",
X		specific_username));
X
X	return(FALSE);
X}
X
X#endif
SHAR_EOF
# ============= src/forms.c ==============
echo "x - extracting src/forms.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/forms.c &&
X
Xstatic char rcsid[] = "@(#)$Id: forms.c,v 4.1 90/04/28 22:43:08 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:	forms.c,v $
X * Revision 4.1  90/04/28  22:43:08  syd
X * checkin of Elm 2.3 as of Release PL0
X * 
X *
X ******************************************************************************/
X
X/** This set of files supports the 'forms' options (AT&T Mail Forms) to
X    the mail system.  The specs are drawn from a document from AT&T entitled
X    "Standard for Exchanging Forms on AT&T Mail", version 1.9.
X
X**/
X
X/** Some notes on the format of a FORM;
X
X	First off, in AT&T Mail parlance, this program only supports SIMPLE
X	forms, currently.  This means that while each form must have three
X 	sections;
X
X		[options-section]
X		***
X		[form-image]
X		***
X		[rules-section]
X
X	this program will ignore the first and third sections completely.  The
X	program will assume that the user merely enteres the form-image section,
X	and will append and prepend the triple asterisk sequences that *MUST*
X	be part of the message.  The messages are also expected to have a 
X	specific header - "Content-Type: mailform" - which will be added on all
X	outbound mail and checked on inbound...
X**/
X
X#include "headers.h"
X#include <errno.h>
X
Xextern int errno;
X
Xchar *error_name(), *strcat(), *strcpy();
X
Xcheck_form_file(filename)
Xchar *filename;
X{
X	/** This routine returns the number of fields in the specified file,
X	    or -1 if an error is encountered. **/
X
X	FILE *form;
X	char buffer[SLEN];
X	register int field_count = 0;
X
X	if ((form = fopen(filename, "r")) == NULL) {
X	  error2("Error %s trying to open %s to check fields!",
X		  error_name(errno), filename);
X	  return(-1);
X	}
X	
X	while (fgets(buffer, SLEN, form) != NULL) {
X	  field_count += occurances_of(COLON, buffer);
X	}
X
X	fclose(form);
X
X	return(field_count);
X}
X
Xformat_form(filename)
Xchar *filename;
X{
X	/** This routine accepts a validated file that is the middle 
X	    section of a form message and prepends and appends the appropriate 
X	    instructions.  It's pretty simple. 
X	    This returns the number of forms in the file, or -1 on errors
X	**/
X	
X	FILE *form, *newform;
X	char  newfname[SLEN], buffer[SLEN];
X	register form_count = 0;
X
X	dprint(4, (debugfile, "Formatting form file '%s'\n", filename));
X
X	/** first off, let's open the files... **/
X
X	if ((form = fopen(filename, "r")) == NULL) {
X	  error("Can't read the message to validate the form!");
X	  dprint(1, (debugfile,
X              "** Error encountered opening file \"%s\" - %s (check_form) **\n",
X	      filename, error_name(errno)));
X	  return(-1);
X	}
X
X	sprintf(newfname, "%s%s%d", temp_dir, temp_form_file, getpid());
X
X	if ((newform = fopen(newfname, "w")) == NULL) {
X	  error("Couldn't open newform file for form output!");
X	  dprint(1, (debugfile, 
X              "** Error encountered opening file \"%s\" - %s (check_form) **\n",
X	      newfname, error_name(errno)));
X	  return(-1);
X	}
X
X	/** the required header... **/
X
X	/* these are actually the defaults, but let's be sure, okay? */
X
X	fprintf(newform, "WIDTH=78\nTYPE=SIMPLE\nOUTPUT=TEXT\n***\n");
X
X	/** and let's have some fun transfering the stuff across... **/
X
X	while (fgets(buffer, SLEN, form) != NULL) {
X	  fputs(buffer, newform);
X	  form_count += occurances_of(COLON, buffer);
X	}
X
X	fprintf(newform, "***\n");	/* that closing bit! */
X
X	fclose(form);
X	fclose(newform);
X
X	if (form_count > 0) {
X	  if (unlink(filename) != 0) {
X	    error2("Error %s unlinking file %s.", error_name(errno), filename);
X	    return(-1);
X	  }
X	  if (link(newfname, filename)) {
X	    error3("Error %s linking %s to %s.", error_name(errno), 
X		    newfname, filename);
X	    return(-1);
X	  }
X	}
X
X	if (unlink(newfname)) {
X	  error2("Error %s unlinking file %s.", error_name(errno), newfname);
X	  return(-1);	
X	}
X
X	return(form_count);
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%s%d", temp_dir, 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	             }
X	             else 
X		       prompt_for_entries(buffer, fd, count);
X	             break;
X            default: prompt_for_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_entries(buffer, fd, entries)
Xchar *buffer;
XFILE *fd;
Xint  entries;
X{
X	/** deals with lines that have multiple colons on them.  It must first
X	    figure out how many spaces to allocate for each field then prompts
X	    the user, 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 = 78 - (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	  /*  field_size-1 for the space spaces[] starts with  */
X	  for (j = strlen(mybuffer); j < field_size-1; 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
# ============= src/hdrconfg.c ==============
echo "x - extracting src/hdrconfg.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/hdrconfg.c &&
X
Xstatic char rcsid[] = "@(#)$Id: hdrconfg.c,v 4.1.1.2 90/06/05 20:59:30 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 4.1.1.2 $   $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:	hdrconfg.c,v $
X * Revision 4.1.1.2  90/06/05  20:59:30  syd
X * Fix log
X * 
X * Revision 4.1.1.1  90/06/05  20:58:23  syd
X * Fixes when ALLOW_SUBSHELL #define'd and you are in the
X * Message Header Edit Screen and the mail you just composed
X * is not a reply THEN the subshell command is executed.
X * From: zvr@natasha.cs.wisc.EDU (Alexios Zavras)
X * 
X * Revision 4.1  90/04/28  22:43:10  syd
X * checkin of Elm 2.3 as of Release PL0
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#undef tolower
X#endif
X
X/*
X * Allow three lines for To and Cc.
X * Allow two lines for Bcc, Subject and In-reply-to.
X * Allow one line for all others.
X */
X#define TO_LINE			2
X#define CC_LINE                 5
X#define BCC_LINE                8
X#define SUBJECT_LINE            10
X#define REPLY_TO_LINE           12
X#define ACTION_LINE             13
X#define EXPIRES_LINE            14
X#define PRIORITY_LINE           15
X#define IN_REPLY_TO_LINE        16
X#define USER_DEFINED_HDR_LINE   18
X#define INSTRUCT_LINE           LINES-4
X#define EXTRA_PROMPT_LINE	LINES-3
X#define INPUT_LINE		LINES-2
X#define ERROR_LINE		LINES-1
X
Xstatic  put_header();
X
X#define put_to()        put_header(TO_LINE, 3, "To", expanded_to)
X#define put_cc()        put_header(CC_LINE, 3, "Cc", expanded_cc)
X#define put_bcc()       put_header(BCC_LINE, 2, "Bcc", expanded_bcc)
X#define put_subject()   put_header(SUBJECT_LINE, 2, "Subject", subject)
X#define put_replyto()   put_header(REPLY_TO_LINE, 1, "Reply-to", reply_to)
X#define put_action()    put_header(ACTION_LINE, 1, "Action", action)
X#define put_expires()   put_header(EXPIRES_LINE, 1, "Expires", expires)
X#define put_priority()  put_header(PRIORITY_LINE, 1, "Priority", priority)
X#define put_inreplyto() put_header(IN_REPLY_TO_LINE, 2, \
X					"In-reply-to", in_reply_to)
X#define put_userdefined() put_header(USER_DEFINED_HDR_LINE, 1, \
X					(char *) NULL, user_defined_header)
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, displayed_error = NO;
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	while (TRUE) {	/* forever */
X	  PutLine0(INPUT_LINE,0,"Choice: ");
X	  if (displayed_error)
X	    displayed_error = NO;
X	  else
X	    CleartoEOS();
X	  c = getchar();
X	  if (isupper(c))
X	    c = tolower(c);
X	  clear_error();
X	  if (c == EOF)
X		return(0);
X	  switch (c) {
X	    case RETURN:
X	    case LINE_FEED:
X	    case 'q' :  MoveCursor(INSTRUCT_LINE, 0);
X			CleartoEOS();
X			return(0);
X
X	    case ctrl('L') :
X			display_headers();
X			break;
X
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
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
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
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
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#ifdef ALLOW_SUBSHELL
X	    case '!':   if (subshell())
X			  display_headers();
X		        break;
X#endif
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	    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
# ============= src/help.c ==============
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.";
SHAR_EOF
echo "End of  part 12"
echo "File src/help.c is continued in part 13"
echo "13" > shar3_seq_.tmp
exit 0