[comp.mail.elm] Elm 2.1 PL1 Part 14 of 22

syd@dsinc.UUCP (Syd Weinstein) (12/13/88)

---- Cut Here and unpack ----
#!/bin/sh
# this is part 14 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file src/leavembox.c continued
#
CurArch=14
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/leavembox.c"
sed 's/^X//' << 'SHAR_EOF' >> src/leavembox.c
X * Fix for bug when you leave an empty mailfile for a non-existent one
X *
X * 88/08/27 ssw
X *	add deluth patches
X *
X * 88/08/27 nicmad!brown (Mike Brown)
X *	move extern int errno out of BSD ifdef
X *
X * 88/08/27 ssw
X * Changes due to alpha testing at dsinc
X *	remove header file unistd - not present and not used
X *
X * Revision 2.2  88/07/21  09:58:48  edc
X * Final hacks and cleanup to the 2.1 alpha test release.
X * 
X * Revision 2.1  88/06/28  12:52:07  edc
X * Added NOUTIMBUF define. Automatically defines utimbuf on non-bsd systems if
X * set. This is checked for in Configure.sh since it seems that many systems
X * don't define utimbuf for some non-obvious reason.
X * 					
X * 
X * Revision 2.0  88/06/27  17:25:13  edc
X * The original 2.0 gamma sources as leaked from HP
X * 
X *
X *
X ******************************************************************************/
X
X/** leave current mailbox, updating etc. as needed...
X  
X**/
X
X#include "headers.h"
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/file.h>
X#include <errno.h>
X
X#define  ECHOIT 	1	/* echo on for prompting! */
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();
Xunsigned short getegid();
Xunsigned long sleep();
X
Xint
Xleave_mbox(quitting)
Xint quitting;
X{
X	/** Exit, saving files into mbox and deleting specified, or simply 
X	    delete specified mail... If "quitting" is true, then output status 
X            regardless of what happens.  Returns 1 iff mailfile was
X	    changed (ie messages deleted from file), 0 if not, and -1 if new
X	    mail has arrived in the meantime...
X	**/
X
X	FILE *temp;
X	char outfile[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_save = 0, i,
X		     pending = 0, number_saved = 0, last_sortby;
X	char answer;
X	long bytes();
X
X	dprint(1, (debugfile, "\n\n-- leaving_mailbox --\n\n"));
X
X	if (message_count == 0) {
X	  if (mbox_specified == 0)	/* null mailbox lock? */
X	    unlock();
X
X	  return(FALSE);	/* nothing changed */
X	}
X
X	for (i = 0; i < message_count; i++)
X	  if (ison(header_table[i].status, DELETED)) to_delete++;
X	  else                                       to_save++;
X
X	dprint(2, (debugfile,
X		"Count: %d to delete and %d to save\n", to_delete, to_save));
X
X	if (mbox_specified == 0) 
X	  update_mailtime();
X
X	if (hp_softkeys && question_me) {
X	  define_softkeys(YESNO);		/* YES or NO on softkeys */
X	  softkeys_on();
X	}
X
X	if (to_delete) {
X	  if (always_del) 	/* set up the default answer... */
X	    answer = 'y';
X	  else 
X	    answer = 'n';
X
X	  if (to_save) {
X	    if (question_me) {
X	      fflush(stdin);
X	      sprintf(buffer, "Delete message%s? (y/n) ", plural(to_delete));
X	      answer = want_to(buffer, answer, ECHOIT);
X	    }
X	    if (answer != 'y') {
X	      if (mbox_specified == 0) unlock();	/* remove lock! */
X	      dprint(3, (debugfile, "\tDelete message%s? - answer was NO\n", 
X			plural(to_delete)));
X	      error("Nothing deleted");
X	      return(FALSE);	/* nothing was deleted! */
X	    }
X	  }
X	  else if (! to_save) {		/* nothing to save!! */
X	    if (question_me) {
X	      fflush(stdin);
X	      answer = want_to("Delete all mail? (y/n) ", answer, ECHOIT);
X	    }
X	    if (answer != 'y') {
X	      if (mbox_specified == 0) unlock();	/* remove lock! */
X	      dprint(3, (debugfile, "Delete all mail? - answer was NO\n"));
X	      error("Nothing deleted");
X	      return(FALSE);   /* nothing was deleted */
X	    }
X	  }
X	}
X
X	/** we have to check to see what the sorting order was...so that
X	    the order of saved messages is the same as the order of the
X	    messages originally (a subtle point...) **/
X
X	if (sortby != RECEIVED_DATE) {	/* what we want anyway! */
X	  last_sortby = sortby;
X	  sortby = RECEIVED_DATE;
X	  sort_mailbox(message_count, FALSE);
X	  sortby = last_sortby;
X	}
X
X	if (to_save && mbox_specified == 0) {
X	  if (always_leave) 		/* set up default answer */
X	    answer = 'y';
X	  else
X	    answer = 'n';
X	  if (question_me) {
X	    fflush(stdin);
X	    answer = want_to("Keep mail in incoming mailbox? (y/n) ", 
X		     answer, ECHOIT);
X	  }
X	  if (answer == 'y') {
X	    if (to_delete)	    /* okay - keep undeleted as pending!    */
X	      pending++;
X	    else {	   	    /* gag! nothing to delete, don't save!  */	
X	      unlock();	    /* remove mailfile lock!	   	    */
X	      dprint(3, (debugfile,
X		     "Keep mail in incoming mailbox? -- answer was YES\n"));
X	      error("Mailbox unchanged");
X	      return(FALSE);	/* nothing changed! */
X	    }
X	  }
X	}
X
X	/** next, let's lock the file up and make one last size check **/
X
X	if (mbox_specified == 0) lock(OUTGOING);
X	
X	if (mailfile_size != bytes(infile)) {
X	  unlock();
X	  error("New mail has just arrived - resyncing");
X	  return(-1);
X	}
X	
X	/** okay...now lets do it! **/
X
X	if (to_save > 0) {
X	  if (to_delete > 0)
X	    sprintf(buffer ,"[%s %d message%s, and deleting %d]", 
X	          pending? "keeping" : "storing", 
X		  to_save, plural(to_save), to_delete);
X	  else if (quitting)
X	    sprintf(buffer,"[%s %s]",
X	          pending? "keeping" : "storing",
X		  to_save > 1? "all messages" : "message");
X	  else
X	    buffer[0] = '\0';	/* no string! */
X	}
X	else {
X	  if (to_delete > 0)
X	    sprintf(buffer, "[deleting all messages]");
X	  else if (quitting)
X	    sprintf(buffer, "[no messages to %s, and none to delete]",
X	            pending? "keep" : "save");
X	  else
X	    buffer[0] = '\0';
X	}
X
X	dprint(2, (debugfile, "Action: %s\n", buffer));
X
X	error(buffer);
X
X	if (! mbox_specified) {
X	  if (pending) {                /* keep some messages pending! */
X	    sprintf(outfile,"%s%d", temp_mbox, getpid());
X	    unlink(outfile);
X	  }
X	  else if (mailbox_defined)	/* save to specified mailbox */
X	    strcpy(outfile, mailbox);
X	  else				/* save to $home/mbox */
X	    sprintf(outfile,"%s/mbox", home);
X	}
X	else {
X	  if (! to_delete) return(FALSE);	/* no work to do! */
X          sprintf(outfile, "%s%d", temp_file, getpid());
X	  unlink(outfile); /* ensure it's empty! */
X	}
X
X	if (to_save) {
X	  if ((errno = can_open(outfile, "a"))) {
X	    error1(
X	         "Permission to append to %s denied!  Leaving mailbox intact\n",
X		 outfile);
X	    dprint(1, (debugfile, 
X		 "Error: Permission to append to outfile %s denied!! (%s)\n",
X		 outfile, "leavembox"));
X	    dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
X		 error_description(errno)));
X	    unlock();
X	    return(0);
X	  }
X	  if ((temp = fopen(outfile,"a")) == NULL) {
X	    if (mbox_specified == 0)
X	      unlock();		/* remove mailfile lock! */
X	    dprint(1, (debugfile, "Error: could not append to file %s\n", 
X		    outfile));
X	    dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
X		 error_description(errno)));
X	    sprintf(buffer, "           Could not append to file %s!          ",
X		    outfile);
X	    Centerline(LINES-1, buffer);
X	    emergency_exit();
X	  }
X  
X	  for (i = 0; i < message_count; i++)
X	    if (! (header_table[i].status & DELETED)) {
X	      current = i+1;
X	      if (! number_saved++) {
X	        dprint(3, (debugfile, "Saving message%s #%d, ", 
X		       plural(to_save), current));
X	      }
X	      else {
X		dprint(3, (debugfile, "#%d, ", current));
X	      }
X	      copy_message("", temp, FALSE, FALSE);
X	    }
X	  fclose(temp);
X	  dprint(2, (debugfile, "\n\n"));
X	}
X
X	/* remove source file...either default mailbox or original copy of 
X           specified one! */
X
X        if (stat(infile, &buf) != 0) {	/* grab original times... */
X	  dprint(1, (debugfile, "Error: errno %s attempting to stat file %s\n", 
X		     error_name(errno), infile));
X          error3("Error %s (%s) on stat(%s)", error_name(errno), 
X		error_description(errno), infile);
X	}
X
X	fclose(mailfile);	/* close the baby... */
X	
X	if (mailfile_size != bytes(infile)) {
X	  sort_mailbox(message_count, FALSE);	/* display sorting order! */
X	  unlock();
X	  error("New mail has just arrived - resyncing...");
X	  return(-1);
X	}
X
X
X	if (infile != NULL)
X	  unlink(infile); 	/* and BLAMO!        */
X
X	if (to_save && (mbox_specified || pending)) {
X	  if (link(outfile, infile) != 0) 
X	    if (errno == EXDEV ||
X		errno == EEXIST ) { /** different file devices!  Use copy! **/
X	      if (copy(outfile, infile) != 0) {
X	        dprint(1, (debugfile, "leavembox: copy(%s, %s) failed;",
X			outfile, infile));
X	        dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
X		     error_description(errno)));
X	        error("couldn't modify mail file!");
X	        sleep(1);
X	        sprintf(infile,"%s/%s", home, unedited_mail);
X		if (copy(outfile, infile) != 0) {
X	          dprint(1, (debugfile, 
X			  "leavembox: couldn't copy to %s either!!  Help;", 
X			  infile));
X	          dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
X		          error_description(errno)));
X	          error("something godawful is happening to me!!!");
X		  emergency_exit();
X	        }
X		else {
X	          dprint(1, (debugfile,
X			  "\nWoah! Confused - Saved mail in %s (leavembox)\n", 
X			  infile));
X	          error1("saved mail in %s", infile);
X	        }
X	      }	
X	    }
X	    else {
X	      dprint(1, (debugfile, "link(%s, %s) failed (leavembox)\n", 
X		     outfile, infile));
X	      dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
X			error_description(errno)));
X	      error2("link failed! %s - %s", error_name(errno),
X		error_description(errno));
X	      emergency_exit();
X	    }
X
X	  unlink(outfile);
X	  restore_file_stats(infile);
X	}
X	else if (keep_empty_files) {
X	  sleep(1);
X	  error1("..keeping empty mail file '%s'..", infile);
X	  temp = fopen(infile, "w");
X	  fclose(temp);
X	  restore_file_stats(infile);
X	}
X
X	if (mbox_specified == 0) {
X	  if (! pending) { /* if none still being saved */
X	    temp = fopen(infile, "w");
X	    fclose(temp);
X	  }
X	
X	  restore_file_stats(infile);
X
X	  /* let's set the access times of the new mail file to be
X	     the same as the OLD one (still sitting in 'buf') ! */
X
X#ifdef BSD
X	  utime_buffer[0]     = buf.st_atime;
X	  utime_buffer[1]     = buf.st_mtime;
X#else
X	  utime_buffer.actime = buf.st_atime;
X	  utime_buffer.modtime= buf.st_mtime;
X#endif
X
X#ifdef BSD
X	  if (utime(infile, utime_buffer) != 0) {
X#else
X	  if (utime(infile, &utime_buffer) != 0) {
X#endif
X	    dprint(1, (debugfile, 
X		   "Error: encountered error doing utime (leavmbox)\n"));
X	    dprint(1, (debugfile, "** %s - %s **\n", error_name(errno), 
X		     error_description(errno)));
X	    error2("Error %s trying to change file %s access time", 
X		     error_name(errno), infile);
X	  }
X
X	  unlock();	/* remove the lock on the file ASAP! */
X
X	  /** finally, let's change the ownership of the default
X	      outgoing mailbox, if needed **/
X
X	  if (to_save) 
X	    chown(outfile, userid, groupid);
X	}
X
X	mailfile_size = bytes(infile);
X	return(to_delete);	
X}
X
Xchar lock_name[SLEN];
Xint  we_created_lock = 0;		/* set to true iff we create it */
X
Xlock(direction)
Xint direction;
X{
X	/** Create lock file to ensure that we don't get any mail 
X	    while altering the mailbox contents!
X	    If it already exists sit and spin until 
X               either the lock file is removed...indicating new mail
X	    or
X	       we have iterated MAX_ATTEMPTS times, in which case we
X	       either fail or remove it and make our own (determined
X	       by if REMOVE_AT_LAST is defined in header file
X
X	    If direction == INCOMING then DON'T remove the lock file
X	    on the way out!  (It'd mess up whatever created it!).
X	**/
X
X	register int iteration = 0, lock_fd;
X
X	sys_lock_file(lock_name, username);
X	lock_fd = open(lock_name, O_WRONLY | O_CREAT | O_EXCL, 0777);
X
X	if (lock_fd < 0 && errno == EACCES) {
X	  if (direction == OUTGOING) {
X	    dprint(1, (debugfile, 
X		  "Error encountered attempting to create lock %s\n", 
X		  lock_name));
X	    dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
X		  error_description(errno)));
X	    MoveCursor(LINES, 0);
X	    printf(
X         "\n\rError encountered while attempting to create lock file %s;\n\r", 
X		  lock_name);
X	    printf("** %s - %s **\n\r\n\r", error_name(errno),
X		  error_description(errno));
X	    leave();
X	  }
X	  else {	/* permission denied in the middle?  Odd... */
X	    dprint(1, (debugfile,
X		 "Can't create lock file: creat(%s) raises error %s (lock)\n", 
X		  lock_name, error_name(errno)));
X	    leave(error1(
X               "Can't create lock file!  I need write permission in \"%s\"\n\r",
X	        mailhome));
X	  }
X	}
X
X	/** if lock_fd is not a valid file descriptor at this point, it
X	    means that we're circling because someone *else* has the 	
X   	    file descriptor.  We'll keep iterating until something 
X	    new and exciting happens or we give up.
X	**/
X
X	while (lock_fd < 0 && iteration++ < MAX_ATTEMPTS) {
X
X	  dprint(2, (debugfile,"File '%s' already exists!  Waiting...(lock)\n", 
X		  lock_name));
X
X	  if (direction == INCOMING) {
X	    if (iteration == 1)
X	      PutLine0(LINES, 0, "Mail being received...\t\twaiting...1 ");
X	    else
X	      printf("%d ", iteration);
X	    fflush(stdout);
X	  }
X	  else
X	    error1("  Attempt #%d: Mail being received...waiting  ", iteration);
X	  sleep(5);
X
X	  lock_fd = open(lock_name, O_WRONLY | O_CREAT | O_EXCL, 0777);
X	}
X	
X	if (lock_fd < 0) {	/* we tried.  We really did.  But noooo */
X
X#ifdef REMOVE_AT_LAST
X
X	  /** time to waste the lock file!  Must be there in error! **/
X
X	  dprint(2, (debugfile, 
X	     "Warning: I'm giving up waiting - removing lock file(lock)\n"));
X	  if (direction == INCOMING)
X	    PutLine0(LINES, 0,"\nTimed out - removing current lock file...");
X	  else
X	    error("Throwing away the current lock file!");
X
X	  if (unlink(lock_name) != 0) {
X	    dprint(1, (debugfile,
X		  "Error %s (%s)\n\ttrying to unlink file %s (%s)\n", 
X		     error_name(errno), error_description(errno), lock_name));
X	    PutLine1(LINES, 0, 
X		   "\n\rI couldn't remove the current lock file %s\n\r", 
X		   lock_name);
X	    PutLine2(LINES, 0, "** %s - %s **\n\r", error_name(errno),
X		   error_description(errno));
X	    if (direction == INCOMING)
X	      leave();
X	    else
X	      emergency_exit();
X	  }
X	  
X	  /* everything is okay, so lets act as if nothing had happened... */
X
X#else
X
X	  /* Okay...we die and leave, not updating the mailfile mbox or
X	     any of those! */
X
X	  if (direction == INCOMING) {
X	    PutLine1(LINES, 0, "\n\r\n\rGiving up after %d iterations...\n\r", 
X		     iteration);
X	    PutLine0(LINES, 0, 
X    "\n\rPlease try to read your mail again in a few minutes.\n\r\n\r");
X	    dprint(1, (debugfile, 
X		    "Warning: bailing out after %d iterations...(lock)\n", 
X		    iteration));
X	    leave_locked(0);
X	  }
X	  else {
X	    dprint(1, (debugfile, 
X		   "Warning: after %d iterations, timed out! (lock)\n", 
X		   iteration));
X	    leave(error("Timed out on lock file reads.  Leaving program."));
X	  }
X
X#endif
X	}
X
X	/* if we get here we've created the lock file, so lets just split */
X
X	close(lock_fd);	/* close it.  We don't want to KEEP the thing! */
X}
X
Xunlock()
X{
X	/** Remove the lock file!    This must be part of the interrupt
X	    processing routine to ensure that the lock file is NEVER
X	    left sitting in the mailhome directory! **/
X
X	(void) unlink(lock_name);
X}
SHAR_EOF
echo "File src/leavembox.c is complete"
chmod 0444 src/leavembox.c || echo "restore of src/leavembox.c fails"
echo "x - extracting src/limit.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/limit.c &&
X
Xstatic char rcsid[] = "@(#)$Id: limit.c,v 2.1 88/07/21 09:58:51 edc Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.1 $   $State: Exp $
X *
X * 			Copyright (c) 1986 Dave Taylor
X *******************************************************************************
X * Bug reports, patches, comments, suggetions should be sent to:
X *
X *	Syd Weinstein, Elm Corrdinator
X *	syd@dsinc.UUCP			dsinc!syd
X *
X *******************************************************************************
X * $Log:	limit.c,v $
X * Revision 2.1  88/07/21  09:58:51  edc
X * checked in with -k by syd at 88.09.15.20.28.48.
X * 
X * Revision 2.1  88/07/21  09:58:51  edc
X * Final hacks and cleanup to the 2.1 alpha test release.
X * 
X * Revision 2.0  88/06/27  17:25:14  edc
X * The original 2.0 gamma sources as leaked from HP
X * 
X *
X *
X ******************************************************************************/
X
X/** This stuff is inspired by MH and dmail and is used to 'select'
X    a subset of the existing mail in the folder based on one of a
X    number of criteria.  The basic tricks are pretty easy - we have
X    as status of VISIBLE associated with each header stored in the
X    (er) mind of the computer (!) and simply modify the commands to
X    check that flag...the global variable `selected' is set to the
X    number of messages currently selected, or ZERO if no select.
X**/
X
X#include "headers.h"
X
X#define TO		1
X#define FROM		2
X
Xchar *shift_lower();
X
Xint
Xlimit()
X{
X	/** returns non-zero if we did enough to redraw the screen **/
X	
X	char criteria[STRING], first[STRING], rest[STRING];
X	int  last_current;
X
X	if (selected) {
X	  PutLine1(LINES-2, 0, 
X		"Already have selection criteria - add more? (y/n) n%c",
X		BACKSPACE);
X	  criteria[0] = ReadCh();
X	  if (tolower(criteria[0]) == 'y') 
X	    PutLine0(LINES-3, COLUMNS-30, "Adding criteria...");
X	  else {
X	    selected = 0;
X	    PutLine0(LINES-3, COLUMNS-30, "Use '?' for help");
X	  }
X	  
X	}
X
X	PutLine1(LINES-2, 0, "Enter criteria: ");
X	CleartoEOLN();
X
X	criteria[0] = '\0';
X	optionally_enter(criteria, LINES-2, 16, FALSE);
X	
X	if (strlen(criteria) == 0) return(0);
X
X	split_word(criteria, first, rest);
X	
X	if (equal(first, "all")) {
X	   selected = 0;
X	   return(TRUE);
X	}
X
X	last_current = current;
X	current = -1;
X
X	if (equal(first, "subj") || equal(first, "subject"))
X	  selected = limit_selection(SUBJECT, rest, selected);
X	else if (equal(first, "to"))
X	  selected = limit_selection(TO, rest, selected);
X	else if (equal(first, "from"))
X	  selected = limit_selection(FROM, rest, selected);
X	else {
X	  selected = 0;
X	  error1("Don't understand \"%s\" as a selection criteria!", first);
X	  sleep(2);
X	}
X
X	if (! selected)
X	  current = last_current;
X	else
X	  current = visible_to_index(1)+1;	/* map it and shift up 1 */
X
X	if (! selected)
X	  set_error("no items selected");
X	else {
X	  sprintf(first, "%d items selected", selected);
X	  set_error(first);
X	}
X	
X	return(selected);
X}
X
Xint
Xlimit_selection(based_on, pattern, additional_criteria)
Xint based_on, additional_criteria;
Xchar *pattern;
X{
X	/** Given the type of criteria, and the pattern, mark all
X	    non-matching headers as ! VISIBLE.  If additional_criteria,
X	    don't mark as visible something that isn't currently!
X	**/
X
X	register int index, count = 0;
X
X	dprint(2, (debugfile, "\n\n\n**limit on %d - '%s' - (%s) **\n\n",
X		   based_on, pattern, additional_criteria?"add'tl":"base"));
X
X	if (based_on == SUBJECT) {
X	  for (index = 0; index < message_count; index++)
X	    if (! in_string(shift_lower(header_table[index].subject), pattern))
X	      header_table[index].status &= ~VISIBLE;
X	    else if (additional_criteria && 	
X		     header_table[index].status | VISIBLE)
X	      header_table[index].status &= ~VISIBLE;	/* shut down! */
X	    else { /* mark it as readable */
X	      header_table[index].status |= VISIBLE;
X	      count++;
X	      dprint(5, (debugfile,
X		     "  Message %d (%s from %s) marked as visible\n",
X			index, header_table[index].subject,
X			header_table[index].from));
X	    }
X	}
X	else if (based_on == FROM) {
X	  for (index = 0; index < message_count; index++)
X	    if (! in_string(shift_lower(header_table[index].from), pattern))
X	      header_table[index].status &= ~VISIBLE;
X	    else if (additional_criteria && 	
X		     header_table[index].status | VISIBLE)
X	      header_table[index].status &= ~VISIBLE;	/* shut down! */
X	    else { /* mark it as readable */
X	      header_table[index].status |= VISIBLE;
X	      count++;
X	      dprint(5, (debugfile, 
X			"  Message %d (%s from %s) marked as visible\n",
X			index, header_table[index].subject,
X			header_table[index].from));
X	    }
X	}
X	else if (based_on == TO) {
X	  for (index = 0; index < message_count; index++)
X	    if (! in_string(shift_lower(header_table[index].to), pattern))
X	      header_table[index].status &= ~VISIBLE;
X	    else if (additional_criteria && 	
X		     header_table[index].status | VISIBLE)
X	      header_table[index].status &= ~VISIBLE;	/* shut down! */
X	    else { /* mark it as readable */
X	      header_table[index].status |= VISIBLE;
X	      count++;
X	      dprint(5, (debugfile,
X			"  Message %d (%s from %s) marked as visible\n",
X			index, header_table[index].subject,
X			header_table[index].from));
X	    }
X	}
X
X	dprint(4, (debugfile, "\n** returning %d selected **\n\n\n", count));
X
X	return(count);
X}
X
Xint
Xnext_visible(index)
Xint index;
X{
X	/** Given 'index', this routine will return the actual index into the
X	    array of the NEXT visible message, or '-1' if none are visible 
X	**/
X
X	register int remember_for_debug;
X	remember_for_debug = index;
X
X	index--;	/* shift from 'current' to actual index  */
X	index++;	/* make sure we don't bump into ourself! */
X
X	while (index < message_count) {
X	  if (header_table[index].status & VISIBLE) {
X	    dprint(9, (debugfile, "[Next visible: given %d returning %d]\n", 
X		       remember_for_debug, index+1));
X	    return(index+1);
X	  }
X	  index++;
X	}
X
X	return(-1);
X}
X
Xint
Xprevious_visible(index)
Xint index;
X{
X	/** Just like 'next-visible', but backwards FIRST... */
X
X	register int remember_for_debug;
X	remember_for_debug = index;
X
X	index -= 2;	/* shift from 'current' to actual index, and skip us! */
X
X	while (index > -1) {
X	  if (header_table[index].status & VISIBLE) {
X	    dprint(9, (debugfile, "[previous visible: given %d returning %d]",
X		    remember_for_debug, index+1));
X	    return(index+1);
X	  }
X	  index--;
X	}
X
X	return(-1);
X}
X
Xint
Xcompute_visible(message)
Xint message;
X{
X	/** return the 'virtual' index of the specified message in the
X	    set of messages - that is, if we have the 25th message as
X	    the current one, but it's #2 based on our limit criteria,
X	    this routine, given 25, will return 2.
X	**/
X
X	register int index, count = 0;
X
X	if (! selected) return(message);
X
X	if (message < 0) message = 0;	/* normalize */
X
X	for (index = 0; index <= message; index++)
X	   if (header_table[index].status & VISIBLE) 
X	     count++;
X
X	dprint(4, (debugfile,
X		"[compute-visible: displayed message %d is actually %d]\n",
X		count, message));
X
X	return(count);
X}
X
Xint
Xvisible_to_index(message)
Xint message;
X{
X	/** Given a 'virtual' index, return a real one.  This is the
X	    flip-side of the routine above, and returns (message_count+1)
X	    if it cannot map the virtual index requested (too big) 
X	**/
X
X	register int index = 0, count = 0;
X
X	for (index = 0; index < message_count; index++) {
X	   if (header_table[index].status & VISIBLE) 
X	     count++;
X	   if (count == message) {
X	     dprint(4, (debugfile,
X		     "visible-to-index: (up) index %d is displayed as %d\n",
X		     message, index));
X	     return(index);
X	   }
X	}
X
X	dprint(4, (debugfile, "index %d is NOT displayed!\n", message));
X
X	return(message_count+1);
X}
SHAR_EOF
chmod 0444 src/limit.c || echo "restore of src/limit.c fails"
echo "x - extracting src/mailmsg1.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/mailmsg1.c &&
X
Xstatic char rcsid[] = "@(#)$Id: mailmsg1.c,v 2.1 88/09/15 20:28:51 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.1 $   $State: Exp $
X *
X * 			Copyright (c) 1986 Dave Taylor
X *******************************************************************************
X * Bug reports, patches, comments, suggetions should be sent to:
X *
X *	Syd Weinstein, Elm Corrdinator
X *	syd@dsinc.UUCP			dsinc!syd
X *
X *******************************************************************************
X * $Log:	mailmsg1.c,v $
X * Revision 2.1  88/09/15  20:28:51  syd
X * checked in with -k by syd at 88.09.15.20.28.51.
X * 
X * 88/09/13 Rob Bernardo <rob@pbhyf.PacBell.COM >
X * fixes how elm knows when to repaint the screen or not.
X *
X * 88/08/27 ssw
X *	add deluth patches
X *	add bcc strings always
X *
X * 88/08/27 ssw
X *	split tolower and ReadCh due to macro calls
X *
X * Revision 2.1  88/07/21  09:58:53  edc
X * Final hacks and cleanup to the 2.1 alpha test release.
X * 
X * Revision 2.0  88/06/27  17:25:15  edc
X * The original 2.0 gamma sources as leaked from HP
X * 
X *
X *
X ******************************************************************************/
X
X/** Interface to allow mail to be sent to users.  Part of ELM  **/
X
X
X#include "headers.h"
X
X/** strings defined for the hdrconfg routines **/
X
Xchar 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 *format_long(), *strip_commas(), *tail_of_string(), *strcpy();
Xunsigned long sleep();
X
Xint
Xsendmsg(given_to, given_cc, given_subject, edit_message, form_letter, replying)
Xchar *given_to, *given_cc, *given_subject;
Xint   edit_message, form_letter, replying;
X{
X	/** Prompt for fields and then call mail() to send the specified
X	    message.  If 'edit_message' is true then don't allow the
X            message to be edited. 'form_letter' can be "YES" "NO" or "MAYBE".
X	    if YES, then add the header.  If MAYBE, then add the M)ake form
X	    option to the last question (see mailsg2.c) etc. etc. 
X	    if (replying) then add an In-Reply-To: header...
X	    Return TRUE if the main part of the screen has been changed
X	    (useful for knowing whether a redraw is needed.
X	**/
X
X	int  copy_msg = FALSE, is_a_response = FALSE;
X
X	/* First: zero all current global message strings */
X
X	cc[0] = reply_to[0] = expires[0] = '\0';
X
X#ifdef ALLOW_BCC
X	bcc[0] = expanded_bcc[0] = '\0';
X#endif
X
X	in_reply_to[0] = expanded_to[0] = expanded_cc[0] = '\0';
X
X	strcpy(subject, given_subject);		/* copy given subject */
X	strcpy(to, given_to);			/* copy given to:     */
X	strcpy(cc, given_cc);			/*  and so on..       */
X
X	/******* And now the real stuff! *******/
X
X	copy_msg=copy_the_msg(&is_a_response); /* copy msg into edit buffer? */
X
X	if (get_to(to, expanded_to) == 0)   /* get the To: address and expand */
X	  return(0);
X
X	/** are we by any chance just checking the addresses? **/
X
X	if (check_only) {
X	  printf("Expands to: %s\n", format_long(expanded_to, 12));
X	  putchar('\r');	/* don't ask... */
X	  leave();
X	}
X
X	/** if we're batchmailing, let's send it and GET OUTTA HERE! **/
X
X	if (mail_only && strlen(batch_subject) > 0) { 
X	  strcpy(subject, batch_subject);	/* get the batch subject */
X	  return(mail(FALSE, FALSE, TRUE, form_letter));
X	}
X
X	display_to(expanded_to);	/* display the To: field on screen... */
X
X	dprint(3, (debugfile, "\nMailing to %s\n", expanded_to));
X  
X	if (get_subject(subject) == 0)	    /* get the Subject: field */
X	  return(0);
X
X	dprint(4, (debugfile, "Subject is %s\n", subject));
X
X	if (prompt_for_cc) {
X	  if (get_copies(cc, expanded_to, expanded_cc, copy_msg) == 0)
X	    return(0);
X
X	  if (strlen(cc) > 0)
X	    dprint(4, (debugfile, "Copies to %s\n", expanded_cc));
X	}
X
X	if (mail_only) 				/* indicate next step... */
X	  printf("\n\r");
X	else
X	  MoveCursor(LINES,0);	/* so you know you've hit <return> ! */
X
X	/** generate the In-Reply-To: header... **/
X
X	if (is_a_response && replying)
X	  generate_reply_to(current-1);
X
X	/* and mail that puppy outta here! */
X	
X	return(mail(copy_msg, edit_message, FALSE, form_letter));
X}
X
Xget_to(to_field, address)
Xchar *to_field, *address;
X{
X	/** prompt for the "To:" field, expanding into address if possible.
X	    This routine returns ZERO if errored, or non-zero if okay **/
X
X	if (strlen(to_field) == 0) {
X	  if (user_level < 2) {
X	    PutLine0(LINES-2, 0, "Send the message to: ");
X	    (void) optionally_enter(to_field, LINES-2, 21, FALSE); 
X	  }
X	  else {
X	    PutLine0(LINES-2, 0, "To: ");
X	    (void) optionally_enter(to_field, LINES-2, 4, FALSE); 
X	  }
X	  if (strlen(to_field) == 0) {
X	    ClearLine(LINES-2);	
X	    return(0);
X	  }
X	  (void) build_address(strip_commas(to_field), address); 
X	}
X	else if (mail_only) 
X	  (void) build_address(strip_commas(to_field), address); 
X	else 
X	  strcpy(address, to_field);
X	
X	if (strlen(address) == 0) {	/* bad address!  Removed!! */
X	  if (! mail_only)
X	    ClearLine(LINES-2);
X	  return(0);
X	}
X
X	return(1);		/* everything is okay... */
X}
X
Xget_subject(subject_field)
Xchar *subject_field;
X{
X	char	ch;
X
X	/** get the subject and return non-zero if all okay... **/
X	int len = 9;
X
X	if (mail_only) {
X	  printf("Subject: ");
X	  fflush(stdout);
X	}
X	else 
X	  if (user_level == 0) {
X	    PutLine0(LINES-2,0,"Subject of message: ");
X	    len = 20;
X	  }
X	  else
X	    PutLine0(LINES-2,0,"Subject: ");
X
X	CleartoEOLN();
X
X	if (optionally_enter(subject_field, LINES-2, len, TRUE) == -1) {
X	  /** User hit the BREAK key! **/
X	  MoveCursor(LINES-2,0); 	
X	  CleartoEOLN();
X	  error("mail not sent");
X	  return(0);
X	}
X
X	if (strlen(subject_field) == 0) {	/* zero length subject?? */
X	  if (mail_only) 
X	    {
X	    printf("\n\rNo subject - Continue with message? (y/n) n%c",
X		  BACKSPACE);
X	      fflush(stdout);
X	  }
X	  else
X	    PutLine1(LINES-2,0,"No subject - Continue with message? (y/n) n%c",
X		  BACKSPACE);
X
X	  ch = ReadCh();
X	  if (tolower(ch) != 'y') {	/* user says no! */
X	    if (mail_only) {
X	      printf("\n\r\n\rMail Cancelled!\n\r");
X	      fflush(stdout);
X	      return(0);
X	    }
X	    ClearLine(LINES-2);
X	    error("mail not sent");
X	    return(0);
X	  }
X	  else if (! mail_only) {
X	    PutLine0(LINES-2,0,"Subject: <none>");
X	    CleartoEOLN();
X	  }
X	}
X
X	return(1);		/** everything is cruising along okay **/
X}
X
Xget_copies(cc_field, address, addressII, copy_message)
Xchar *cc_field, *address, *addressII;
Xint   copy_message;
X{
X	/** Get the list of people that should be cc'd, returning ZERO if
X	    any problems arise.  Address and AddressII are for expanding
X	    the aliases out after entry! 
X	    If 'bounceback' is nonzero, add a cc to ourselves via the remote
X	    site, but only if hops to machine are > bounceback threshold.
X	    If copy-message, that means that we're going to have to invoke
X	    a screen editor, so we'll need to delay after displaying the
X	    possibly rewritten Cc: line...
X	**/
X
X	if (mail_only)
X	  printf("\n\rCopies To: ");
X	else
X	  PutLine0(LINES-1,0,"Copies To: ");
X
X	fflush(stdout);
X
X	if (optionally_enter(cc_field, LINES-1, 11, FALSE) == -1) {
X	  if (mail_only) {
X	    printf("\n\r\n\rMail not sent!\n\r");
X	    return(0);
X	  }
X	  ClearLine(LINES-2);
X	  ClearLine(LINES-1);
X	  
X	  error("mail not sent");
X	  return(0);
X	}
X	
X	/** The following test is that if the build_address routine had
X	    reason to rewrite the entry given, then, if we're mailing only
X	    print the new Cc line below the old one.  If we're not, then
X	    assume we're in screen mode and replace the incorrect entry on
X	    the line above where we are (e.g. where we originally prompted
X	    for the Cc: field).
X	**/
X
X	if (build_address(strip_commas(cc_field), addressII))
X	  if (mail_only) {
X	    printf("\rCopies To: %s\r\n", format_long(addressII, 4));
X	    fflush(stdout);
X	  }
X	  else {
X	    PutLine1(LINES-1, 11, "%s", addressII);
X	    if ((strcmp(editor, "builtin") != 0 && strcmp(editor, "none") != 0)
X		|| copy_message)
X	      sleep(2);
X	  }
X
X	if (strlen(address) + strlen(addressII) > VERY_LONG_STRING) {
X	  dprint(2, (debugfile, 
X		"String length of \"To:\" + \"Cc\" too long! (get_copies)\n"));
X	  error("Too many people.  Copies ignored");
X	  sleep(2);
X	  cc_field[0] = '\0';
X	}
X
X	return(1);		/* everything looks okay! */
X}
X	
Xint
Xcopy_the_msg(is_a_response)
Xint *is_a_response;
X{
X	/** Returns True iff the user wants to copy the message being
X	    replied to into the edit buffer before invoking the editor! 
X	    Sets "is_a_response" to true if message is a response...
X	**/
X
X	int answer = FALSE;
X
X	if (strlen(to) > 0 && !mail_only) {	/* predefined 'to' line! */
X	  if (auto_copy) 
X	    answer = TRUE;
X	  else 
X	    answer = (want_to("Copy message? (y/n) ", 'n', TRUE) == 'y');
X	  *is_a_response = TRUE;
X	}
X	else
X	  if (strlen(subject) > 0)  	/* predefined 'subject' (Forward) */
X	    answer = TRUE;
X
X	return(answer);
X}
X
Xdisplay_to(address)
Xchar *address;
X{
X	/** Simple routine to display the "To:" line according to the
X	    current configuration (etc) 			      
X	 **/
X	register int open_paren;
X
X	if (mail_only)
X	  printf("To: %s\n\r", format_long(address, 3));
X	else {
X	  if (names_only)
X	    if ((open_paren = chloc(address, '(')) > 0) {
X	      if (open_paren < chloc(address, ')')) {
X	        output_abbreviated_to(address);
X	        return;
X	      } 
X	     }
X	  if (strlen(address) > 45) 
X	    PutLine1(LINES-3, COLUMNS-50, "To: (%s)", 
X		tail_of_string(address, 40));
X	  else {
X	    if (strlen(address) > 30) 
X	      PutLine1(LINES-3, COLUMNS-50, "To: %s", address);
X	    else
X	      PutLine1(LINES-3, COLUMNS-50, "          To: %s", address);
X	    CleartoEOLN();
X	  }
X	}
X}
X
Xoutput_abbreviated_to(address)
Xchar *address;
X{
X	/** Output just the fields in parens, separated by commas if need
X	    be, and up to COLUMNS-50 characters...This is only used if the
X	    user is at level BEGINNER.
X	**/
X
X	char newaddress[LONG_STRING];
X	register int index, newindex = 0, in_paren = 0;
X
X	index = 0;
X
X	while (newindex < 55 && index < strlen(address)) {
X	  if (address[index] == '(') in_paren++;
X	  else if (address[index] == ')') { 
X	    in_paren--;
X	    if (index < strlen(address)-4) {
X	      newaddress[newindex++] = ',';
X	      newaddress[newindex++] = ' ';
X	    }
X	  }
X	  
X	  if (in_paren && address[index] != '(')
X	      newaddress[newindex++] = address[index];
X	     
X	  index++;
X	}
X
X	newaddress[newindex] = '\0';
X
X	if (strlen(newaddress) > 50) 
X	   PutLine1(LINES-3, COLUMNS-50, "To: (%s)", 
X	       tail_of_string(newaddress, 40));
X	 else {
X	   if (strlen(newaddress) > 30)
X	     PutLine1(LINES-3, COLUMNS-50, "To: %s", newaddress);
X	   else
X	     PutLine1(LINES-3, COLUMNS-50, "          To: %s", newaddress);
X	   CleartoEOLN();
X	 }
X
X	return;
X}
SHAR_EOF
chmod 0444 src/mailmsg1.c || echo "restore of src/mailmsg1.c fails"
echo "x - extracting src/mailmsg2.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/mailmsg2.c &&
X
Xstatic char rcsid[] = "@(#)$Id: mailmsg2.c,v 2.1 88/09/15 20:28:54 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.1 $   $State: Exp $
X *
X * 			Copyright (c) 1986 Dave Taylor
X *******************************************************************************
X * Bug reports, patches, comments, suggetions should be sent to:
X *
X *	Syd Weinstein, Elm Corrdinator
X *	syd@dsinc.UUCP			dsinc!syd
X *
X *******************************************************************************
X * $Log:	mailmsg2.c,v $
X * Revision 2.1  88/09/15  20:28:54  syd
X * checked in with -k by syd at 88.09.15.20.28.55.
X * 
X * 88/09/13 Rob Bernardo <rob@pbhyf.PacBell.COM >
X * fixes how elm knows when to repaint the screen or not.
X *
X * 88/09/02 Syd Weinstein
X *	added version buffer
X *
X * 88/08/27 ssw
X *	add deluth patches
X *
X * 88/08/27 ssw
X *	split tolower and ReadCh due to macro calls
X *
X * Revision 2.1  88/07/21  09:58:55  edc
X * Final hacks and cleanup to the 2.1 alpha test release.
X * 
X * Revision 2.0  88/06/27  17:25:17  edc
X * The original 2.0 gamma sources as leaked from HP
X * 
X *
X *
X ******************************************************************************/
X
X/** Interface to allow mail to be sent to users.  Part of ELM  **/
X
X
X#include "headers.h"
X#include <errno.h>
X
Xextern int errno;
Xextern char version_buff[];
X
Xchar *error_name(), *error_description(), *strip_parens();
Xchar *strcat(), *strcpy();
Xchar *format_long(), *strip_commas(), *tail_of_string(); 
X
Xunsigned long sleep();
X
X#ifdef SITE_HIDING 
X char *get_ctime_date();
X#endif
XFILE *write_header_info();
X
X/* these are all defined in the mailmsg1.c file! */
X
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
X#ifdef ALLOW_BCC
Xchar bcc[VERY_LONG_STRING], expanded_bcc[VERY_LONG_STRING];
X#endif
X
Xint gotten_key = 0;
X
Xchar *bounce_off_remote();
X
Xmail(copy_msg, edit_message, batch, form)
Xint  copy_msg, edit_message, batch, form;
X{
X	/** Given the addresses and various other miscellany (specifically, 
X	    'copy-msg' indicates whether a copy of the current message should 
X	    be included, 'edit_message' indicates whether the message should 
X	    be edited and 'batch' indicates that the message should be read 
X	    from stdin) this routine will invoke an editor for the user and 
X	    then actually mail off the message. 'form' can be YES, NO, or
X	    MAYBE.  YES=add "Content-Type: mailform" header, MAYBE=add the
X	    M)ake form option to last question, and NO=don't worry about it!
X	    Also, if 'copy_msg' = FORM, then grab the form temp file and use
X	    that...
X	    Return TRUE if the main part of the screen has been changed
X	    (useful for knowing whether a redraw is needed.
X	**/
X
X	FILE *reply, *real_reply; /* second is post-input buffer */
X	char filename[SLEN], filename2[SLEN], fname[SLEN],
X             very_long_buffer[VERY_LONG_STRING];
X	int ch;
X	register int retransmit = FALSE; 
X	int      already_has_text = FALSE;		/* we need an ADDRESS */
X	int	 old_raw;
X	int	 need_redraw = 0;
X
X	static int cancelled_msg = 0;
X
X	dprint(4, (debugfile, "\nMailing to \"%s\" (with%s editing)\n",
X		  expanded_to, edit_message? "" : "out"));
X	
X	/** first generate the temporary filename **/
X
X	sprintf(filename,"%s%d",temp_file, getpid());
X
X	/** if possible, let's try to recall the last message? **/
X
X	if (! batch && copy_msg != FORM && user_level != 0)
X	  retransmit = recall_last_msg(filename, copy_msg, &cancelled_msg, 
X		       &already_has_text);
X
X	/** if we're not retransmitting, create the file.. **/
X
X	if (! retransmit)
X	  if ((reply = fopen(filename,"w")) == NULL) {
X	    dprint(1, (debugfile, 
X               "Attempt to write to temp file %s failed with error %s (mail)\n",
X		 filename, error_name(errno)));
X	    error2("Could not create file %s (%s)",filename,
X		 error_name(errno));
X	    return(need_redraw);
X	  }
X
X	chown (filename, userid, groupid);
X
X	if (batch) {
X	  Raw(OFF);
X	  if (isatty(fileno(stdin))) {
X	    fclose(reply);	/* let edit-the-message open it! */
X	    printf("To: %s\nSubject: %s\n", expanded_to, subject);
X	    strcpy(editor, "none");	/* force inline editor */
X	    if (no_editor_edit_the_message(filename))
X	      return(need_redraw);/* confused?  edit_the_msg returns 1 if bad */
X
X	    batch = FALSE;		/* we've done it... **/
X	    edit_message = FALSE;		
X
X	    Raw(ON);
X	    goto top_of_verify_loop;
X	  }
X	  else {
X	    while (gets(very_long_buffer) != NULL) 
X	      fprintf(reply, "%s\n", very_long_buffer);
X	  }
X	}
X
X	if (copy_msg == FORM) {
X	  sprintf(fname, "%s%d", temp_form_file, getpid());
X	  fclose(reply);	/* we can't retransmit a form! */
X	  if (access(fname,ACCESS_EXISTS) != 0) {
X	    error("couldn't find forms file!");
X	    return(need_redraw);
X	  }
X	  unlink(filename);
X	  dprint(4, (debugfile, "-- linking existing file %s to file %s --\n",
X		  fname, filename));
X	  link(fname, filename);
X	  unlink(fname);
X	}
X	else if (copy_msg && ! retransmit)    /* if retransmit we have it! */
X	  if (edit_message) {
X	    copy_message(prefixchars, reply, noheader, FALSE);
X	    already_has_text = TRUE;	/* we just added it, right? */
X	  }
X	  else
X	    copy_message("", reply, noheader, FALSE);
X
X	if (!batch && ! retransmit && signature && copy_msg != FORM) {
X	  fprintf(reply, "\n--\n");	/* News 2.11 compatibility? */
X	  if (chloc(expanded_to, '!') == -1 && chloc(expanded_to, '@') == -1) {
X	    if (strlen(local_signature) > 0) {
X	      if (local_signature[0] != '/')
X	        sprintf(filename2, "%s/%s", home, local_signature);
X	      else	
X 	        strcpy(filename2, local_signature);
X	      (void) append(reply, filename2);
X	      already_has_text = TRUE;	/* added signature... */
X	    }
X	  }
X	  else {
X	    if (remote_signature[0] != '/')
X	      sprintf(filename2, "%s/%s", home, remote_signature);
X	    else	
X 	      strcpy(filename2, remote_signature);
X	    (void) append(reply, filename2);
X	    already_has_text = TRUE;	/* added signature... */
X	  }
X	}
X
X	if (! retransmit && copy_msg != FORM)
X	  if (reply != NULL)
X	    (void) fclose(reply);	/* on replies, it won't be open! */
X
X	/** Edit the message **/
X
X	if (edit_message)
X	  create_readmsg_file();	/* for "readmsg" routine */
X
Xtop_of_verify_loop:
X
X	ch = edit_message? 'e' : ' ';	/* drop through if needed... */
X
X	if (! batch) {
X	  do {
X	    switch (ch) {
X	      case 'e': if (edit_the_message(filename, already_has_text)) {
X			  cancelled_msg = TRUE;
X			  return(need_redraw);
X			}
X			need_redraw++;
X			break;
X
X	      case 'h': if (mail_only)
X			   batch_header_editor();
X			else
X			   edit_headers();
X			need_redraw++;
X			break;
X
X	      default : /* do nothing */ ;
X	    }
X
X	    /** ask that silly question again... **/
X  
X	    if ((ch = verify_transmission(filename, &form)) == 'f') {
X	      cancelled_msg = TRUE;
X	      return(need_redraw);
X	    }
X
X	  } while (ch != 's');
X
X	  if (form == YES) 
X	    if (format_form(filename) < 1) {
X	      cancelled_msg = TRUE;
X	      return(need_redraw);
X	    }
X
X	  if ((reply = fopen(filename,"r")) == NULL) {
X	      dprint(1, (debugfile,
X	    "Attempt to open file %s for reading failed with error %s (mail)\n",
X                filename, error_name(errno)));
X	      error1("Could not open reply file (%s)", error_name(errno));
X	      return(need_redraw);
X	  }
X	}
X	else if ((reply = fopen(filename,"r")) == NULL) {
X	  dprint(1, (debugfile, 
X	    "Attempt to open file %s for reading failed with error %s (mail)\n",
X             filename, error_name(errno)));
X	  error1("Could not open reply file (%s)", error_name(errno));
X	  return(need_redraw);
X	}
X
X	cancelled_msg = FALSE;	/* it ain't cancelled, is it? */
X
X	/** ask about bounceback if the user wants us to.... **/
X
X	if (uucp_hops(to) > bounceback && bounceback > 0 && copy_msg != FORM) 
X	  if (verify_bounceback() == TRUE) {
X	    if (strlen(cc) > 0) strcat(expanded_cc, ", ");
X	    strcat(expanded_cc, bounce_off_remote(to));
X	  }
X
X	/** grab a copy if the user so desires... **/
X
X	if (auto_cc) 
X	  save_copy(subject, expanded_to, expanded_cc, filename, to);
X
X	/** write all header information into real_reply **/
X
X	sprintf(filename2,"%s%d",temp_file, getpid()+1);
X	
X	/** try to write headers to new temp file **/
X
X	dprint(6, (debugfile, "Composition file='%s' and mail buffer='%s'\n", 
X		    filename, filename2));
X
X#ifdef ALLOW_BCC
X	dprint(2,(debugfile,"--\nTo: %s\nCc: %s\nBcc: %s\nSubject: %s\n---\n", 
X		  expanded_to, expanded_cc, expanded_bcc, subject));
X#else
X	dprint(2,(debugfile,"---\nTo: %s\nCc: %s\nSubject: %s\n---\n", 
X		  expanded_to, expanded_cc, subject));
X#endif
X
X	if ((real_reply=write_header_info(filename2, expanded_to, expanded_cc,
X#ifdef ALLOW_BCC
X				 	  expanded_bcc,
X#endif
X			                  form == YES)) == NULL) {
X
X	  /** IT FAILED!!  MEIN GOTT!  Use a dumb mailer instead! **/
X
X	  dprint(3, (debugfile, "** write_header failed: %s\n", 
X		 error_name(errno)));
X
X	  if (cc[0] != '\0')  		/* copies! */
X	    sprintf(expanded_to,"%s %s", expanded_to, expanded_cc);
X
X	  sprintf(very_long_buffer, "( (%s -s \"%s\" %s ; %s %s) & ) < %s",
X                  mailx, subject, strip_parens(strip_commas(expanded_to)), 
X		  remove, filename, filename);
X
X	  error1("Message sent using dumb mailer - %s", mailx);
X	  sleep(2);	/* ensure time to see this prompt! */
X
X	}
X	else {
X	  copy_message_across(reply, real_reply);
X
X	  fclose(real_reply);
X
X	  if (cc[0] != '\0')  				         /* copies! */
X	    sprintf(expanded_to,"%s %s", expanded_to, expanded_cc);
X
X#ifdef ALLOW_BCC
X	  if (bcc[0] != '\0') {
X	    strcat(expanded_to, " ");
X	    strcat(expanded_to, expanded_bcc);
X	  }
X#endif
X
X	  if (access(sendmail, EXECUTE_ACCESS) == 0 
X#ifdef SITE_HIDING
X	      && ! is_a_hidden_user(username))
X#else
X	     )
X#endif
X             if (!sendmail_verbose)
X             {
X   
X                sprintf(very_long_buffer,"( (%s %s %s ; %s %s) & ) < %s",
X                     sendmail, smflags, strip_parens(strip_commas(expanded_to)),
X                      remove, filename2, filename2);
X             }
X             else
X             {
X   
X                sprintf(very_long_buffer,"( (%s %s %s ; %s %s) & ) < %s",
X                     sendmail, smflagsv, strip_parens(strip_commas(expanded_to)),
X                      remove, filename2, filename2);
X             }
X	  else 				   /* oh well, use default mailer... */
X            sprintf(very_long_buffer,"( (%s %s ; %s %s) & ) < %s", 
X                  mailer, strip_parens(strip_commas(expanded_to)), 
X		  remove, filename2, filename2);
X	}
X	
X	fclose(reply);
X
X	if (mail_only) {
X	  printf("sending mail...");
X	  fflush(stdout);
X	}
X	else {	
X	  PutLine0(LINES,0,"sending mail...");
X	  CleartoEOLN();
X	}
X
X	system_call(very_long_buffer, SH);
X
X	if (mail_only) 
X	  printf("\rmail sent!      \n\r");
X	else 
X	  set_error("Mail sent!");
X
X	return(need_redraw);
X}
X
Xmail_form(address, subj)
Xchar *address, *subj;
X{
X	/** copy the appropriate variables to the shared space... */
X
X	strcpy(subject, subj);
X	strcpy(to, address);
X	strcpy(expanded_to, address);
X
X	return(mail(FORM, NO, NO, NO));
X}
X
Xint
Xrecall_last_msg(filename, copy_msg, cancelled_msg, already_has_text)
Xchar *filename;
Xint  copy_msg, *cancelled_msg, *already_has_text;
X{
X	char ch;
X
X	/** If filename exists and we've recently cancelled a message,
X	    the ask if the user wants to use that message instead!  This
X	    routine returns TRUE if the user wants to retransmit the last
X	    message, FALSE otherwise...
X	**/
X
X	register int retransmit = FALSE;
X
X	if (access(filename, EDIT_ACCESS) == 0 && *cancelled_msg) {
X	  Raw(ON);
X	  CleartoEOLN();
X	  if (copy_msg)
X	    PutLine1(LINES-1,0,"Recall last kept message instead? (y/n) y%c",
X		     BACKSPACE);
X	  else
X	    PutLine1(LINES-1,0,"Recall last kept message? (y/n) y%c", 
X		     BACKSPACE);
X	  fflush(stdout);
X	  ch = ReadCh();
X	  if (tolower(ch) != 'n') {
X	    Write_to_screen("Yes",0);	
X            retransmit++;
X	    *already_has_text = TRUE;
X	  }
X	  else 
X	    Write_to_screen("No",0);	
X
X	  fflush(stdout);
X
X	  *cancelled_msg = 0;
X	}
X
X	return(retransmit);
X}
X
Xint
Xverify_transmission(filename, form_letter)
Xchar *filename;
Xint  *form_letter;
X{
X	/** Ensure the user wants to send this.  This routine returns
X	    the character entered.  Modified compliments of Steve Wolf 
X	    to add the'dead.letter' feature.
X	    Also added form letter support... 
X	**/
X
X	FILE *deadfd, *messagefd;
X	char ch, buffer[LONG_SLEN], fname[SLEN];
X
X	if (mail_only) {
X	  if (isatty(fileno(stdin))) {
Xbatch_reprompt:
X	    printf("\n\rYour options now are:\n\r");
X	    printf(
X   "S)end the message, E)dit it again, change/add H)eaders or F)orget it\n\r");
X	    printf("\n\rWhat is your choice? s%c", BACKSPACE);
X	    fflush(stdin);				/* wait for answer! */
X	    fflush(stdout);
X	    ch = ReadCh();
X	    ch = tolower(ch);
X
X	    if (ch == 'f') { 		/* forget this message! */
X	      printf("Forget\n\r\n\r");
X	      /** try to save it as a dead letter file **/
SHAR_EOF
echo "End of part 14"
echo "File src/mailmsg2.c is continued in part 15"
echo "15" > s2_seq_.tmp
exit 0
-- 
=====================================================================
Sydney S. Weinstein, CDP, CCP                   Elm Coordinator
Datacomp Systems, Inc.				Voice: (215) 947-9900
{allegra,bellcore,bpa,vu-vlsi}!dsinc!syd	FAX:   (215) 938-0235