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


#!/bin/sh
# this is part.17 (part 17 of a multipart archive)
# do not concatenate these parts, unpack them in order with /bin/sh
# file src/save_opts.c continued
#
if test ! -r shar3_seq_.tmp; then
	echo "Please unpack part 1 first!"
	exit 1
fi
(read Scheck
 if test "$Scheck" != 17; then
	echo "Please unpack part $Scheck next!"
	exit 1
 else
	exit 0
 fi
) < shar3_seq_.tmp || exit 1
echo "x - Continuing file src/save_opts.c"
sed 's/^X//' << 'SHAR_EOF' >> src/save_opts.c &&
X
X	error1("Options saved in file %s.", newfname);
X}
X
Xsave_user_options(elminfo_fd, newelmrc)
XFILE *elminfo_fd, *newelmrc;
X{
X	/** save the information in the file.  If elminfo_fd == NULL don't look
X	    for comments!
X	**/
X
X	if (elminfo_fd != NULL) 
X	  build_offset_table(elminfo_fd);
X
X	fprintf(newelmrc, 	
X	      "#\n# .elm/elmrc - options file for the ELM mail system\n#\n");
X
X	if (strlen(full_username) > 0)
X	  fprintf(newelmrc, "# Saved automatically by ELM %s for %s\n#\n\n",
X		  version_buff, full_username);
X	else
X	  fprintf(newelmrc, "# Saved automatically by ELM %s\n#\n\n", version_buff);
X	fprintf(newelmrc,"# For yes/no settings with ?, ON means yes, OFF means no\n\n");
X
X	save_option_string(CALENDAR, raw_calendar_file, newelmrc, FALSE);
X	save_option_string(EDITOR, raw_editor, newelmrc, FALSE);
X
X	save_option_char(ESCAPECHAR, escape_char, newelmrc);
X
X	save_option_string(FULLNAME, full_username, newelmrc, FALSE);
X	save_option_string(RECEIVEDMAIL, raw_recvdmail, newelmrc, FALSE);
X	save_option_string(MAILDIR, raw_folders, newelmrc, FALSE);
X	save_option_string(TMPDIR, temp_dir, newelmrc, FALSE);
X	save_option_string(PAGER, raw_pager, newelmrc, FALSE);
X	save_option_string(PREFIX, prefixchars, newelmrc, TRUE);
X	save_option_string(PRINT, raw_printout, newelmrc, FALSE);
X	save_option_string(SENTMAIL, raw_sentmail, newelmrc, FALSE);
X	save_option_string(SHELL, raw_shell, newelmrc, FALSE);
X
X	save_option_string(LOCALSIGNATURE, raw_local_signature,
X 	  newelmrc, FALSE);
X	save_option_string(REMOTESIGNATURE, raw_remote_signature,
X	  newelmrc, FALSE);
X	save_option_on_off(SIGDASHES, sig_dashes, newelmrc);
X
X	save_option_sort(SORTBY, newelmrc);
X
X	save_option_on_off(ALWAYSDELETE, always_del, newelmrc);
X	save_option_on_off(ALWAYSSTORE, always_store, newelmrc);
X	save_option_on_off(ALWAYSKEEP, always_keep, newelmrc);
X	save_option_on_off(ARROW, arrow_cursor, newelmrc);
X	save_option_on_off(ASK, question_me, newelmrc);
X	save_option_on_off(ASKCC, prompt_for_cc, newelmrc);
X	save_option_string(ATTRIBUTION, attribution, newelmrc, FALSE);
X	save_option_on_off(AUTOCOPY, auto_copy, newelmrc);
X
X	save_option_number(BOUNCEBACK, bounceback, newelmrc);
X
X	save_option_on_off(COPY, auto_cc, newelmrc);
X	save_option_on_off(FORCENAME, force_name, newelmrc);
X	save_option_on_off(FORMS, (allow_forms != NO), newelmrc);
X	save_option_on_off(KEEPEMPTY, keep_empty_files, newelmrc);
X	save_option_on_off(KEYPAD, hp_terminal, newelmrc);
X	save_option_on_off(MENU, mini_menu, newelmrc);
X	save_option_on_off(MOVEPAGE, move_when_paged, newelmrc);
X	save_option_on_off(NAMES, names_only, newelmrc);
X	save_option_on_off(NOHEADER, noheader, newelmrc);
X	save_option_on_off(POINTNEW, point_to_new, newelmrc);
X	save_option_on_off(PROMPTAFTER, prompt_after_pager, newelmrc);
X	save_option_on_off(RESOLVE, resolve_mode, newelmrc);
X	save_option_on_off(SAVENAME, save_by_name, newelmrc);
X	save_option_on_off(SOFTKEYS, hp_softkeys, newelmrc);
X
X	save_option_number(TIMEOUT, (int) timeout, newelmrc);
X
X	save_option_on_off(TITLES, title_messages, newelmrc);
X
X	save_option_number(USERLEVEL, user_level, newelmrc);
X
X	save_option_on_off(WARNINGS, warnings, newelmrc);
X	save_option_on_off(WEED, filter, newelmrc);
X
X	save_option_weedlist(WEEDOUT, newelmrc);
X	save_option_alternatives(ALTERNATIVES, alternative_addresses, newelmrc);
X
X	fclose(newelmrc);
X	if ( elminfo_fd != NULL ) {
X	    fclose(elminfo_fd);
X	}
X}
X
Xsave_option_string(iindex, value, fd, underscores)
Xint iindex, underscores;
Xchar *value;
XFILE *fd;
X{
X	/** Save a string option to the file... only subtlety is when we
X	    save strings with spaces in 'em - translate to underscores!
X	**/
X
X	char     buffer[SLEN], *bufptr;
X	
X	add_comment(iindex, fd);
X	
X	strcpy(buffer, value);
X
X	if (underscores)
X	  for (bufptr = buffer; *bufptr; bufptr++)
X	    if (*bufptr == SPACE) *bufptr = '_';
X
X	fprintf(fd, "%s = %s\n\n", save_info[iindex].name, buffer);
X}
X	   
Xsave_option_sort(iindex, fd)
Xint iindex;
XFILE *fd;
X{
X	/** save the current sorting option to a file **/
X
X	add_comment(iindex, fd);
X
X	fprintf(fd, "%s = %s\n\n", save_info[iindex].name,
X		sort_name(SHORT));
X}
X
Xsave_option_char(iindex, value, fd)
Xint iindex;
Xchar value;
XFILE *fd;
X{
X	/** Save a character option to the file **/
X
X	add_comment(iindex, fd);
X	
X	fprintf(fd, "%s = %c\n\n", save_info[iindex].name, value);
X}
X
Xsave_option_number(iindex, value, fd)
Xint iindex, value;
XFILE *fd;
X{
X	/** Save a binary option to the file - boy is THIS easy!! **/
X
X	add_comment(iindex, fd);
X	
X	fprintf(fd, "%s = %d\n\n", save_info[iindex].name, value);
X}
X
Xsave_option_on_off(iindex, value, fd)
Xint iindex, value;
XFILE *fd;
X{
X	/** Save a binary option to the file - boy is THIS easy!! **/
X
X	add_comment(iindex, fd);
X	
X	fprintf(fd, "%s = %s\n\n", save_info[iindex].name, onoff(value));
X}
X
Xsave_option_weedlist(iindex, fd)
Xint iindex;
XFILE *fd;
X{
X	/** save a list of weedout headers to the file **/
X
X	int length_so_far = 0, i;
X
X	add_comment(iindex, fd);
X
X	length_so_far = strlen(save_info[iindex].name) + 4;
X
X	fprintf(fd, "%s = ", save_info[iindex].name);
X
X	/** first off, skip till we get past the default list **/
X
X	for (i = 0; i < weedcount; i++) 
X	  if (strcmp(weedlist[i],"*end-of-defaults*") == 0)
X	    break;
X
X	while (i < weedcount) {
X	  if (strcmp(weedlist[i], "*end-of-defaults*") != 0)
X	    break;
X	  i++;	/* and get PAST it too! */
X	}
X
X	while (i < weedcount) {
X	  if (strlen(weedlist[i]) + length_so_far > 78) {
X	    fprintf(fd, "\n\t");
X	    length_so_far = 8;
X	  }
X	  fprintf(fd, "\"%s\" ", weedlist[i]);
X	  length_so_far += (strlen(weedlist[i]) + 4);
X	  i++;
X	}
X	fprintf(fd, "\t\"*end-of-user-headers*\"\n\n");
X}
X
Xsave_option_alternatives(iindex, list, fd)
Xint iindex;
Xstruct addr_rec *list;
XFILE *fd;
X{
X	/** save a list of options to the file **/
X	int length_so_far = 0;
X	struct addr_rec     *alternate;
X
X	if (list == NULL) return;	/* nothing to do! */
X
X	add_comment(iindex, fd);
X
X	alternate = list;	/* don't LOSE the top!! */
X
X	length_so_far = strlen(save_info[iindex].name) + 4;
X
X	fprintf(fd, "%s = ", save_info[iindex].name);
X
X	while (alternate != NULL) {
X	  if (strlen(alternate->address) + length_so_far > 78) {
X	    fprintf(fd, "\n\t");
X	    length_so_far = 8;
X	  }
X	  fprintf(fd, "%s  ", alternate->address);
X	  length_so_far += (strlen(alternate->address) + 3);
X	  alternate = alternate->next;
X	}
X	fprintf(fd, "\n\n");
X}
X
Xadd_comment(iindex, fd)
Xint iindex;
XFILE *fd;
X{	
X	/** get to and add the comment to the file **/
X	char buffer[SLEN];
X
X	/** first off, add the comment from the comment file, if available **/
X
X	if (save_info[iindex].offset > 0L) {
X	  if (fseek(elminfo, save_info[iindex].offset, 0) == -1) {
X	    dprint(1,(debugfile,
X		   "** error %s seeking to %ld in elm-info file!\n",
X		   error_name(errno), save_info[iindex].offset));
X	  }
X	  else while (fgets(buffer, SLEN, elminfo) != NULL) {
X	    if (buffer[0] != '#') 
X	       break;
X	    else
X	       fprintf(fd, "%s", buffer);
X	  }
X	}
X}
X
Xbuild_offset_table(elminfo_fd)
XFILE *elminfo_fd;
X{
X	/** read in the info file and build the table of offsets.
X	    This is a rather laborious puppy, but at least we can
X	    do a binary search through the array for each element and
X	    then we have it all at once!
X	**/
X
X	char line_buffer[SLEN];
X	
X	while (fgets(line_buffer, SLEN, elminfo_fd) != NULL) {
X	  if (strlen(line_buffer) > 1)
X	    if (line_buffer[0] != '#' && !whitespace(line_buffer[0])) {
X	       no_ret(line_buffer);
X	       if (find_and_store_loc(line_buffer, ftell(elminfo_fd))) {
X	         dprint(1, (debugfile,"** Couldn't find and store \"%s\" **\n", 
X			 line_buffer));
X	       }
X	    }
X	}
X}
X
Xfind_and_store_loc(name, offset)
Xchar *name;
Xlong  offset;
X{
X	/** given the name and offset, find it in the table and store it **/
X
X	int first = 0, last, middle, compare;
X
X	last = NUMBER_OF_SAVEABLE_OPTIONS;
X
X	while (first <= last) {
X
X	  middle = (first+last) / 2;
X
X	  if ((compare = strcmp(name, save_info[middle].name)) < 0) /* a < b */
X	    last = middle - 1;
X	  else if (compare == 0) {				    /* a = b */
X	    save_info[middle].offset = offset;
X	    return(0);
X	  }
X	  else  /* greater */					    /* a > b */
X	    first = middle + 1; 
X	}
X
X	return(-1);
X}
SHAR_EOF
echo "File src/save_opts.c is complete" &&
# ============= src/savecopy.c ==============
echo "x - extracting src/savecopy.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/savecopy.c &&
X
Xstatic char rcsid[] = "@(#)$Id: savecopy.c,v 4.1 90/04/28 22:44:02 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:	savecopy.c,v $
X * Revision 4.1  90/04/28  22:44:02  syd
X * checkin of Elm 2.3 as of Release PL0
X * 
X *
X ******************************************************************************/
X
X/** Save a copy of the specified message in a folder.
X
X**/
X
X#include "headers.h"
X#ifdef I_TIME
X#  include <time.h>
X#endif
X#ifdef I_SYSTIME
X#  include <sys/time.h>
X#endif
X
X#include <errno.h>
X
Xchar *format_long();
Xchar *error_name(), *error_description();
Xchar *ctime();
X
Xextern char in_reply_to[SLEN];	/* In-Reply-To: string */
Xextern int errno;
X
Xchar *strcat(), *strcpy();
Xunsigned long sleep();
Xlong  time();
X
Xsave_copy(to, cc, bcc, filename, copy_file, form)
Xchar *to, *cc, *bcc, *filename, *copy_file;
Xint form;
X{
X	/** This routine appends a copy of the outgoing message to the
X	    file specified.  **/
X
X	FILE *save,		/* file id for file to save to */
X	     *message,		/* file id for file with message body */
X	     *write_header_info();
X	char  buffer[SLEN],	/* read buffer 		       */
X	      savename[SLEN];	/* name of file saving into    */
X  
X
X	/* presume copy_file is okay as is for now */
X	strcpy(savename, copy_file);
X
X	/* if save-by-name wanted */
X	if((strcmp(copy_file, "=") == 0)  || (strcmp(copy_file, "=?") == 0)) {
X
X	  get_return_name(to, buffer, TRUE);	/* determine 'to' login */
X	  if (strlen(buffer) == 0) {
X
X	    /* can't get file name from 'to' -- use sent_mail instead */
X	    dprint(3, (debugfile,
X		"Warning: get_return_name couldn't break down %s\n", to));
X	    error1(
X"Cannot determine `to' name to save by! Saving to \"sent\" folder %s instead.",
X	      sent_mail);
X	    strcpy(savename, "<");
X	    sleep(3);
X	  } else
X	    sprintf(savename, "=%s", buffer);		/* good! */
X	}
X
X	expand_filename(savename, TRUE);	/* expand special chars */
X
X	/* If saving conditionally by logname but folder doesn't exist
X	 * save to sent folder instead. */
X	if((strcmp(copy_file, "=?") == 0)
X	      && (access(savename, ACCESS_EXISTS) != 0)) {
X	  dprint(5, (debugfile,
X	    "Conditional save by name: file %s doesn't exist - using \"<\".\n",
X	    savename));
X	  strcpy(savename, "<");
X	  expand_filename(savename, TRUE);
X	}
X
X	if ((errno = can_open(savename, "a"))) {
X	  dprint(2, (debugfile,
X	  "Error: attempt to autosave to a file that can't be appended to!\n"));
X	  dprint(2, (debugfile, "\tfilename = \"%s\"\n", savename));
X	  dprint(2, (debugfile, "** %s - %s **\n", error_name(errno),
X		  error_description(errno)));
X
X	  /* Lets try sent_mail before giving up */
X	  if(strcmp(sent_mail, savename) == 0) {
X	    /* we are ALREADY using sent_mail! */
X	    error1("Cannot save to %s!", savename);
X	    sleep(3);
X	    return(FALSE);
X	  }
X
X	  if ((errno = can_open(sent_mail, "a"))) {
X	    dprint(2, (debugfile,
X	  "Error: attempt to autosave to a file that can't be appended to!\n"));
X	    dprint(2, (debugfile, "\tfilename = \"%s\"\n", sent_mail));
X	    dprint(2, (debugfile, "** %s - %s **\n", error_name(errno),
X		    error_description(errno)));
X	    error2("Cannot save to %s nor to \"sent\" folder %s!",
X		    savename, sent_mail);
X	    sleep(3);
X	    return(FALSE);
X	  }
X	  error2("Cannot save to %s! Saving to \"sent\" folder %s instead.",
X	      savename, sent_mail);
X	  sleep(3);
X	  strcpy(savename, sent_mail);
X	}
X
X	save_file_stats(savename);
X
X	/* Write header */
X	if ((save = write_header_info(savename, to, cc, bcc,
X	      form == YES, TRUE)) == NULL)
X	  return(FALSE);
X
X	/* Now add file with message as handed to mailer */
X	if ((message = fopen(filename, "r")) == NULL) {
X	  fclose(save);
X	  dprint(1, (debugfile,
X		 "Error: Couldn't read folder %s (save_copy)\n", filename));
X	  dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
X		  error_description(errno)));
X	  error1("Couldn't read folder %s!", filename);
X	  sleep(3);
X	  return(FALSE);
X	}
X
X        copy_message_across(message, save, TRUE);
X
X
X	fclose(save);
X	fclose(message);
X
X	restore_file_stats(savename);
X
X	return(TRUE);
X}
Xchar *
Xcf_english(fn)
Xchar *fn;
X{
X    /** Return "English" expansion for special copy file name abbreviations
X	or just the file name  **/
X
X    if(!*fn)
X      return("<no save>");
X    else if(!fn[1]) {
X      if(*fn == '=')
X	return("<unconditionally save by name>");
X      else if(*fn == '<')
X	return("<\"sent\" folder>");
X    } else if ((fn[0] == '=') && (fn[1] == '?'))
X      return("<conditionally save by name>");
X
X    return(fn);
X}
X
X#define NCF_PROMPT	"Save copy in (use '?' for help/to list folders): "
Xint
Xname_copy_file(fn)
Xchar *fn;
X{
X    /** Prompt user for name of file for saving copy of outbound msg to.
X	Return true if we need a redraw. **/
X
X    int redraw = 0;	/* set when we ask for help = need redraw */
X    char buffer[SLEN], origbuffer[SLEN];
X    static char helpmsg[LONG_STRING];
X
X    /* expand passed copy file name into English */
X    strcpy(buffer, cf_english(fn));
X
X    /* prepare screen with instructions */
X    MoveCursor(LINES-2, 0);
X    CleartoEOS();
X    PutLine0(LINES-2, 0, NCF_PROMPT);
X
X    while(1) {
X
X      /* get file name from user input */
X      strcpy(origbuffer, buffer);
X      optionally_enter(buffer, LINES-2, strlen(NCF_PROMPT), FALSE, FALSE);
X
X      if(strcmp(buffer, "?") != 0) { /* got what we wanted - non-help choice */
X
X	if(strcmp(origbuffer, buffer) != 0)
X	  /* user changed from our English expansion 
X	   * so we'd better copy user input to fn
X	   */
X	  strcpy(fn, buffer);
X
X	/* else user presumably left our English expansion - no change in fn */
X
X	/* display English expansion of new user input a while */
X	PutLine1(LINES-2, strlen(NCF_PROMPT), cf_english(fn));
X	MoveCursor(LINES, 0);
X	sleep(1);
X	MoveCursor(LINES-2, 0);
X	CleartoEOS();
X
X	return(redraw);
X      }
X
X      /* give help and list folders */
X      redraw = TRUE;
X      if(!*helpmsg) 	/* help message not yet formulated */
X        sprintf(helpmsg,
X	"\n\r%s\n\r%s%s%s\n\r%s\n\r%s\n\r%s\n\r%s\n\r%s\n\r\n\r",
X	"Enter: <nothing> to not save a copy of the message,",
X	"       '<'       to save in your \"sent\" folder (", sent_mail, "),",
X	"       '='       to save by name (the folder name depends on whom the",
X	"                     message is to, in the end),",
X	"       '=?'      to save by name if the folder already exists,",
X	"                     and if not, to your \"sent\" folder,",
X	"       or a filename (a leading '=' denotes your folder directory).");
X
X      list_folders(4, helpmsg);
X      PutLine0(LINES-2, 0, NCF_PROMPT);
X
X      /* restore as default to English version of the passed copy file name */
X      strcpy(buffer, cf_english(fn));
X
X    }
X}
SHAR_EOF
# ============= src/screen.c ==============
echo "x - extracting src/screen.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/screen.c &&
X
Xstatic char rcsid[] = "@(#)$Id: screen.c,v 4.1 90/04/28 22:44: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:	screen.c,v $
X * Revision 4.1  90/04/28  22:44:04  syd
X * checkin of Elm 2.3 as of Release PL0
X * 
X *
X ******************************************************************************/
X
X/**  screen display routines for ELM program 
X
X**/
X
X#include "headers.h"
X
X#define  minimum(a,b)	((a) < (b) ? (a) : (b))
X
Xstatic   int  last_current	 = -1;
X
Xchar *strcpy(), *strncpy(), *nameof(), *show_status(), *index();
X
Xextern char version_buff[];
X
Xshowscreen()
X{
X
X	ClearScreen();
X
X	update_title();
X
X	last_header_page = -1;	 	/* force a redraw regardless */
X	show_headers();
X
X	if (mini_menu)
X	  show_menu();
X
X	show_last_error();
X	
X	if (hp_terminal) 
X	  define_softkeys(MAIN);
X}
X
Xupdate_title()
X{
X	/** display a new title line, probably due to new mail arriving **/
X
X	char buffer[SLEN];
X
X	if (selected)
X	  sprintf(buffer, 
X	      "%s is '%s' with %d shown out of %d [ELM %s]",
X	      (folder_type == SPOOL ? "Mailbox" : "Folder"),
X	      nameof(cur_folder), selected, message_count, version_buff);
X	else
X	  sprintf(buffer, "%s is '%s' with %d message%s [ELM %s]",
X	      (folder_type == SPOOL ? "Mailbox" : "Folder"),
X	      nameof(cur_folder), message_count,
X	      plural(message_count), version_buff);
X
X	ClearLine(1);
X
X	Centerline(1, buffer);
X}
X
Xshow_menu()
X{
X	/** write main system menu... **/
X
X	if (user_level == 0) {	/* a rank beginner.  Give less options  */
X	  Centerline(LINES-7,
X  "You can use any of the following commands by pressing the first character;");
X          Centerline(LINES-6,
X"d)elete or u)ndelete mail,  m)ail a message,  r)eply or f)orward mail,  q)uit");
X	  Centerline(LINES-5,
X  "To read a message, press <return>.  j = move down, k = move up, ? = help");
X	} else {
X	Centerline(LINES-7,
X  "|=pipe, !=shell, ?=help, <n>=set current to n, /=search pattern");
X        Centerline(LINES-6,
X"a)lias, C)opy, c)hange folder, d)elete, e)dit, f)orward, g)roup reply, m)ail,"
X); 
X	Centerline(LINES-5,
X  "n)ext, o)ptions, p)rint, q)uit, r)eply, s)ave, t)ag, u)ndelete, or e(x)it");
X	}
X}
X
Xint
Xshow_headers()
X{
X	/** Display page of headers (10) if present.  First check to 
X	    ensure that header_page is in bounds, fixing silently if not.
X	    If out of bounds, return zero, else return non-zero 
X	    Modified to only show headers that are "visible" to ze human
X	    person using ze program, eh?
X	**/
X
X	register int this_msg = 0, line = 4, last = 0, last_line, 
X		     displayed = 0, using_to;
X	char newfrom[SLEN], buffer[SLEN];
X	
X	if (fix_header_page())
X	  return(FALSE);
X
X	if (selected) {
X	  if ((header_page*headers_per_page) > selected)
X	    return(FALSE); 	/* too far! too far! */
X
X	  this_msg = visible_to_index(header_page * headers_per_page + 1);
X	  displayed = header_page * headers_per_page;
X
X	  last = displayed+headers_per_page;
X
X	}
X	else {
X	  if (header_page == last_header_page) 	/* nothing to do! */
X	    return(FALSE);
X
X	  /** compute last header to display **/
X  
X	  this_msg = header_page * headers_per_page;
X	  last = this_msg + (headers_per_page - 1);
X	}
X
X	if (last >= message_count) last = message_count-1;
X
X	/** Okay, now let's show the header page! **/
X
X	ClearLine(line);	/* Clear the top line... */
X
X	MoveCursor(line, 0);	/* and move back to the top of the page... */
X
X	while ((selected && displayed < last) || this_msg <= last) {
X	  using_to = tail_of(headers[this_msg]->from, newfrom,
X	    headers[this_msg]->to); 
X
X	  if (this_msg == current-1) 
X	    build_header_line(buffer, headers[this_msg], this_msg+1,
X			    TRUE, newfrom, using_to);
X	  else
X	    build_header_line(buffer, headers[this_msg], 
X			    this_msg+1, FALSE, newfrom, using_to);
X	  if (selected) 
X	    displayed++;
X
X	  if (this_msg == current-1 && has_highlighting && ! arrow_cursor) {
X	      StartInverse();
X	      Write_to_screen("%s\n\r", 1, buffer);	/* avoid '%' probs */
X	      EndInverse();
X	  } else
X	      Write_to_screen("%s\n\r", 1, buffer);	/* avoid '%' probs */
X	  CleartoEOLN();
X	  line++;		/* for clearing up in a sec... */
X
X	  if (selected) {
X	    if ((this_msg = next_message(this_msg, FALSE)) < 0)
X	      break;	/* GET OUTTA HERE! */
X
X	    /* the preceeding looks gross because we're using an INDEX
X	       variable to pretend to be a "current" counter, and the 
X	       current counter is always 1 greater than the actual 
X	       index.  Does that make sense??
X	     */
X	  }
X	  else
X	    this_msg++;					/* even dumber...  */
X	}
X
X	/* clear unused lines */
X
X	if (mini_menu)
X	  last_line = LINES-8;
X	else
X	  last_line = LINES-4;
X
X	while (line < last_line) {
X	  CleartoEOLN();
X	  NewLine();
X	  line++;
X	}
X
X	display_central_message();
X
X	last_current = current;
X	last_header_page = header_page;
X
X	return(TRUE);
X}
X
Xshow_current()
X{
X	/** Show the new header, with all the usual checks **/
X
X	register int first = 0, last = 0, last_line, new_line, using_to;
X	char     newfrom[SLEN], old_buffer[SLEN], new_buffer[SLEN];
X
X	(void) fix_header_page();	/* Who cares what it does? ;-) */
X
X	/** compute the first and last header on this page **/
X	first = header_page * headers_per_page + 1;
X	last  = first + (headers_per_page - 1);
X
X	/* if not a full page adjust last to be the real last */
X	if (selected && last > selected)
X	  last = selected;
X	if (!selected && last > message_count) 
X	  last = message_count;
X
X	/** okay, now let's show the pointers... **/
X
X	/** have we changed??? **/
X	if (current == last_current) 
X	  return;
X
X	if (selected) {
X	  last_line = ((compute_visible(last_current)-1) %
X			 headers_per_page)+4;
X	  new_line  = ((compute_visible(current)-1) % headers_per_page)+4;
X	} else {
X	  last_line = ((last_current-1) % headers_per_page)+4;
X	  new_line  = ((current-1) % headers_per_page)+4;
X	}
X	
X	if (has_highlighting && ! arrow_cursor) {
X  
X	  using_to = tail_of(headers[current-1]->from, newfrom,
X	    headers[current-1]->to); 
X	  build_header_line(new_buffer, headers[current-1],  current,
X		  TRUE, newfrom, using_to);
X
X	  /* clear last current if it's in proper range */
X	  if (last_current > 0		/* not a dummy value */
X	      && compute_visible(last_current) <= last
X	      && compute_visible(last_current) >= first) {
X
X	    dprint(5, (debugfile, 
X		  "\nlast_current = %d ... clearing [1] before we add [2]\n", 
X		   last_current));
X	    dprint(5, (debugfile, "first = %d, and last = %d\n\n",
X		  first, last));
X
X	    using_to = tail_of(headers[last_current-1]->from, newfrom,
X	      headers[last_current-1]->to); 
X	    build_header_line(old_buffer, headers[last_current-1], 
X		 last_current, FALSE, newfrom, using_to);
X
X	    ClearLine(last_line);
X	    PutLine0(last_line, 0, old_buffer);
X	  }
X	  MoveCursor(new_line, 0);
X	  StartInverse();
X	  Write_to_screen("%s", 1, new_buffer);
X	  EndInverse();
X	}
X	else {
X	  if (on_page(last_current-1)) 
X	    PutLine0(last_line,0,"  ");	/* remove old pointer... */
X	  if (on_page(current-1))
X	    PutLine0(new_line, 0,"->");
X	}
X	
X	last_current = current;
X}
X
Xbuild_header_line(buffer, entry, message_number, highlight, from, really_to)
Xchar *buffer;
Xstruct header_rec *entry;
Xint message_number, highlight, really_to;
Xchar *from;
X{
X	/** Build in buffer the message header ... entry is the current
X	    message entry, 'from' is a modified (displayable) from line, 
X	    'highlight' is either TRUE or FALSE, and 'message_number'
X	    is the number of the message.
X	**/
X
X	/** Note: using 'strncpy' allows us to output as much of the
X	    subject line as possible given the dimensions of the screen.
X	    The key is that 'strncpy' returns a 'char *' to the string
X	    that it is handing to the dummy variable!  Neat, eh? **/
X	
X	int who_width = 18, subj_width;
X	char *dot = index(from, '.');
X	char *bang = index(from, '!');
X
X	/* truncate 'from' to 18 characters -
X	 * this includes the leading "To" if really_to is true.
X	 * Note:
X	 *	'from' is going to be of three forms
X	 *		- full name (truncate on the right for readability)
X	 *		- logname@machine (truncate on the right to preserve
X	 *			logname over machine name
X	 *		- machine!logname -- a more complex situation
X	 *			If this form doesn't fit, either machine
X	 *			or logname are long. If logname is long,
X	 *			we can stand to loose part of it, so we
X	 *			truncate on the right. If machine name is
X	 *			long, we'd better truncate on the left,
X	 *			to insure we get the logname. Now if the
X	 *			machine name is long, it will have "." in
X	 *			it.
X	 *	Therfore, we truncate on the left if there is a "." and a "!"
X	 *	in 'from', else we truncate on the right.
X	 */
X
X	/* Note that one huge sprintf() is too hard for some compilers. */
X	sprintf(buffer, "%s%s%c%-3d %3.3s %-2d ",
X		(highlight && arrow_cursor)? "->" : "  ",
X		show_status(entry->status),
X		(entry->status & TAGGED?  '+' : ' '),
X	        message_number,
X	        entry->month, 
X		atoi(entry->day));
X
X	/* show "To " in a way that it can never be truncated. */
X	if (really_to) {
X	  strcat(buffer, "To ");
X	  who_width -= 3;
X	}
X
X	/* truncate 'from' on left if needed.
X	 * sprintf will truncate on right afterward if needed. */
X	if ((strlen(from) > who_width) && dot && bang && (dot < bang)) {
X	  from += (strlen(from) - who_width);
X	}
X
X	/* Set the subject display width.
X	 * If it is too long, truncate it to fit.
X	 * If it is highlighted but not with the arrow  cursor,
X	 * expand it to fit so that the reverse video bar extends
X	 * aesthetically the full length of the line.
X	 */
X	if ((highlight && !arrow_cursor)
X		|| (COLUMNS-44 < (subj_width =strlen(entry->subject))))
X	    subj_width = COLUMNS-44;
X
X	/* complete line with sender, length and subject. */
X	sprintf(buffer + strlen(buffer), "%-*.*s (%d) %s%-*.*s",
X		/* give max and min width parameters for 'from' */
X		who_width,
X		who_width,
X		from,
X
X		entry->lines, 
X		(entry->lines / 1000   > 0? ""   :	/* spacing the  */
X		  entry->lines / 100   > 0? " "  :	/* same for the */
X		    entry->lines / 10  > 0? "  " :	/* lines in ()  */
X		                            "   "),     /*   [wierd]    */
X
X		subj_width, subj_width, entry->subject);
X}
X
Xint
Xfix_header_page()
X{
X	/** this routine will check and ensure that the current header
X	    page being displayed contains messages!  It will silently
X	    fix 'header-page' if wrong.  Returns TRUE if changed.  **/
X
X	int last_page, old_header;
X
X	old_header = header_page;
X
X	last_page = (int) ((message_count-1) / headers_per_page);
X 
X	if (header_page > last_page) 
X	  header_page = last_page;
X	else if (header_page < 0) 
X          header_page = 0;
X
X	return(old_header != header_page);
X}
X
Xint
Xon_page(message)
Xint message;
X{
X	/** Returns true iff the specified message is on the displayed page. **/
X
X	if (selected) message = compute_visible(message);
X
X	if (message >= header_page * headers_per_page)
X	  if (message < ((header_page+1) * headers_per_page))
X	    return(TRUE);
X
X	return(FALSE);
X}
X
Xchar *show_status(status)
Xint status;
X{
X	/** This routine returns a pair of characters indicative of
X	    the status of this message.  The first character represents
X	    the interim status of the message (e.g. the status within 
X	    the mail system):
X
X		E = Expired message
X		N = New message
X		O = Unread old message	dsi mailx emulation addition
X		D = Deleted message
X		_ = (space) default 
X
X	    and the second represents the permanent attributes of the
X	    message:
X
X		C = Company Confidential message
X	        U = Urgent (or Priority) message
X		P = Private message
X		A = Action associated with message
X		F = Form letter
X		_ = (space) default
X	**/
X
X	static char mybuffer[3];
X
X	/** the first character, please **/
X
X	     if (status & DELETED)	mybuffer[0] = 'D';
X	else if (status & EXPIRED)	mybuffer[0] = 'E';
X	else if (status & NEW)		mybuffer[0] = 'N';
X	else if (status & UNREAD)	mybuffer[0] = 'O';
X	else                            mybuffer[0] = ' ';
X
X	/** and the second... **/
X
X	     if (status & CONFIDENTIAL) mybuffer[1] = 'C';
X	else if (status & URGENT)       mybuffer[1] = 'U';
X	else if (status & PRIVATE)      mybuffer[1] = 'P';
X	else if (status & ACTION)       mybuffer[1] = 'A';
X	else if (status & FORM_LETTER)  mybuffer[1] = 'F';
X	else 			        mybuffer[1] = ' ';
X
X	mybuffer[2] = '\0';
X
X	return( (char *) mybuffer);
X}
SHAR_EOF
# ============= src/showmsg.c ==============
echo "x - extracting src/showmsg.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/showmsg.c &&
X
Xstatic char rcsid[] = "@(#)$Id: showmsg.c,v 4.1.1.1 90/07/12 23:04:26 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:	showmsg.c,v $
X * Revision 4.1.1.1  90/07/12  23:04:26  syd
X * Fix MMDF case, where MSG_SEPERATOR has newline, buffer check
X * didnt, thus it didnt detect the MSG_SEPERATOR.
X * From: jbwaters@bsu-cs.bsu.edu (J. Brian Waters)
X * 
X * Revision 4.1  90/04/28  22:44:06  syd
X * checkin of Elm 2.3 as of Release PL0
X * 
X *
X ******************************************************************************/
X
X/** This file contains all the routines needed to display the specified
X    message.
X**/
X
X#include "headers.h"
X#include <ctype.h>
X#include <errno.h>
X
X#ifdef BSD
X# include <sys/wait.h>
X# undef       tolower
X#endif
X
Xextern int errno;
X
Xchar *error_name(), *strcat(), *strcpy();
Xvoid   _exit();
X
Xint    memory_lock = FALSE;	/* is it available?? */
Xint    pipe_abort  = FALSE;	/* did we receive a SIGNAL(SIGPIPE)? */
X
XFILE *pipe_wr_fp;		/* file pointer to write to external pager */
Xextern int lines_displayed,	/* defined in "builtin" */	
X	   lines_put_on_screen;	/*    ditto too!        */
X
Xint
Xshow_msg(number)
Xint number;
X{
X	/*** Display number'th message.  Get starting and ending lines
X	     of message from headers data structure, then fly through
X	     the file, displaying only those lines that are between the
X	     two!
X
X	     Return 0 to return to the index screen or a character entered
X	     by the user to initiate a command without returning to
X	     the index screen (to be processed via process_showmsg_cmd()).
X	***/
X
X	char title1[SLEN], title2[SLEN], title3[SLEN], titlebuf[SLEN];
X	char who[LONG_STRING], buffer[VERY_LONG_STRING];
X#if defined(BSD) && !defined(WEXITSTATUS)
X	union wait wait_stat;
X#else
X	int wait_stat;
X#endif
X
X	int crypted = 0;			/* encryption */
X	int weed_header, weeding_out = 0;	/* weeding    */ 
X	int using_to,				/* misc use   */
X	    pipe_fd[2],				/* pipe file descriptors */
X	    new_pipe_fd,			/* dup'ed pipe fil des */
X	    lines,				/* num lines in msg */
X	    fork_ret,				/* fork return value */
X	    wait_ret,				/* wait return value */
X	    form_letter = FALSE,		/* Form ltr?  */
X	    form_letter_section = 0,		/* section    */
X	    padding = 0,			/*   counter  */
X	    builtin = FALSE,			/* our pager? */
X	    val = 0,				/* return val */
X	    buf_len;				/* line length */
X	struct header_rec *current_header = headers[number-1];
X
X
X	lines = current_header->lines; 
X
X	dprint(4, (debugfile,"displaying %d lines from message %d using %s\n", 
X		lines, number, pager));
X
X	if (number > message_count || number < 1)
X	  return(val);
X
X	if(ison(current_header->status, NEW)) {
X	  clearit(current_header->status, NEW);   /* it's been read now! */
X	  current_header->status_chgd = TRUE;
X	}
X	if(ison(current_header->status, UNREAD)) {
X	  clearit(current_header->status, UNREAD);   /* it's been read now! */
X	  current_header->status_chgd = TRUE;
X	}
X
X	memory_lock = FALSE;
X
X	/* some explanation for that last one - We COULD use memory locking
X	   to speed up the paging, but the action of "ClearScreen" on a screen
X	   with memory lock turned on seems to vary considerably (amazingly so)
X	   so it's safer to only allow memory lock to be a viable bit of
X	   trickery when dumping text to the screen in scroll mode.
X	   Philosophical arguments should be forwarded to Bruce at the 
X	   University of Walamazoo, Australia, via ACSNet  *wry chuckle* */
X
X	if (fseek(mailfile, current_header->offset, 0) == -1) {
X	  dprint(1, (debugfile,
X		  "Error: seek %d bytes into file, errno %s (show_message)\n",
X		  current_header->offset, error_name(errno)));
X	  error2("ELM failed seeking %d bytes into file (%s).",
X		  current_header->offset, error_name(errno));	
X	  return(val);
X	}
X	if(current_header->encrypted)
X	  getkey(OFF);
X
X	if(builtin=(first_word(pager,"builtin")||first_word(pager,"internal")))
X
X	  start_builtin(lines);
X
X	else {
X
X	  /* put terminal out of raw mode so external pager has normal env */
X	  Raw(OFF);
X
X	  /* create pipe for external pager and fork */
X
X	  if(pipe(pipe_fd) == -1) {
X	    dprint(1, (debugfile, "Error: pipe failed, errno %s (show_msg)\n",
X	      error_name(errno)));
X	    error1("Could not prepare for external pager(pipe()-%s).",
X	      error_name(errno));	
X	    Raw(ON);
X	    return(val);
X	  }
X
X	  if((fork_ret = fork()) == -1) {
X
X	    dprint(1, (debugfile, "Error: fork failed, errno %s (show_msg)\n",
X	      error_name(errno)));
X	    error1("Could not prepare for external pager(fork()-%s).",
X	      error_name(errno));	
X	    Raw(ON);
X	    return(val);
X
X	  } else if (fork_ret == 0) {
X
X	    /* child fork */
X
X	    /* close write-only pipe fd and fit read-only pipe fd to stdin */
X
X	    close(pipe_fd[1]);
X	    close(fileno(stdin));
X	    if((new_pipe_fd = dup(pipe_fd[0])) == -1) {
X	      dprint(1, (debugfile, "Error: dup failed, errno %s (show_msg)\n",
X		error_name(errno)));
X	      error1("Could not prepare for external pager(dup()-%s).",
X		error_name(errno));	
X	      _exit(errno);
X	    }
X	    close(pipe_fd[0]);	/* original pipe fd no longer needed */
X
X	    /* use stdio on new pipe fd */
X	    if(fdopen(new_pipe_fd, "r") == NULL) {
X	      dprint(1,
X		(debugfile, "Error: child fdopen failed, errno %s (show_msg)\n",
X		error_name(errno)));
X	      error1("Could not prepare for external pager(child fdopen()-%s).",
X		error_name(errno));	
X	      _exit(errno);
X	    }
X
X	    /* now execute pager and exit */
X	    
X	    /* system_call() will return user to user's normal permissions.
X	     * This is what makes this pipe secure - user won't have elm's
X	     * special setgid permissions (if so configured) and will only
X	     * be able to execute a pager that user normally has permission
X	     * to execute */
X
X	    _exit(system_call(pager, SH, TRUE, TRUE));
X	  
X	  } /* else this is the parent fork */
X
X	  /* close read-only pipe fd and do write-only with stdio */
X	  close(pipe_fd[0]);
X
X	  if((pipe_wr_fp = fdopen(pipe_fd[1], "w")) == NULL) {
X	    dprint(1,
X	      (debugfile, "Error: parent fdopen failed, errno %s (show_msg)\n",
X	      error_name(errno)));
X	    error1("Could not prepare for external pager(parent fdopen()-%s).",
X	      error_name(errno));	
X
X	    /* Failure - must close pipe and wait for child */
X	    close(pipe_fd[1]);
X	    while ((wait_ret = wait(&wait_stat)) != fork_ret && wait_ret!= -1)
X	      ;
X
X	    Raw(OFF);
X	    return(val);	/* pager may have already touched the screen */
X	  }
X
X	  /* and that's it! */
X	  lines_displayed = 0;
X	}
X
X	ClearScreen();
X
X	if (cursor_control) transmit_functions(OFF);
X
X	pipe_abort = FALSE;
X
X	if (form_letter = (current_header->status&FORM_LETTER)) {
X	  if (filter)
X	    form_letter_section = 1;	/* initialize to section 1 */
X	}
X
X	if (title_messages && filter) {
X
X	  using_to =
X	    tail_of(current_header->from, who, current_header->to);
X
X	  sprintf(title1, "%s %d/%d  ",
X		    headers[current-1]->status & DELETED ? "[deleted]" :
X		    form_letter ? "Form": "Message",
X		    number, message_count);
X	  sprintf(title2, "%s %s", using_to? "To" : "From", who);
X	  sprintf(title3, "  %s %s '%d at %s %s",
X     		   current_header->month, current_header->day, 
X	           atoi(current_header->year), current_header->time,
X		   current_header->time_zone);
X
X	  /* truncate or pad title2 portion on the right
X	   * so that line fits exactly */
X	  padding =
X	    COLUMNS -
X	    (strlen(title1) + (buf_len=strlen(title2)) + strlen(title3));
X
X	  sprintf(titlebuf, "%s%-*.*s%s\n", title1, buf_len+padding,
X	      buf_len+padding, title2, title3);
X
X	  if (builtin)
X	    display_line(titlebuf);
X	  else
X	    fprintf(pipe_wr_fp, "%s", titlebuf);
X
X	  /** if there's a subject, let's output it next,
X	      centered if it fits on a single line.  **/
X
X	  if ((buf_len = strlen(current_header->subject)) > 0 && 
X		matches_weedlist("Subject:")) {
X	    padding = (buf_len < COLUMNS ? COLUMNS - buf_len : 0);
X	    sprintf(buffer, "%*s%s\n", padding/2, "", current_header->subject);
X	  } else
X	    strcpy(buffer, "\n");
X
X	  if (builtin)
X	    display_line(buffer);
X	  else
X	    fprintf(pipe_wr_fp, "%s", buffer);
X	  
X	  /** was this message address to us?  if not, then to whom? **/
X
X	  if (! using_to && matches_weedlist("To:") && filter &&
X	      strcmp(current_header->to,username) != 0 &&
X	      strlen(current_header->to) > 0) {
X	    if (strlen(current_header->to) > 60)
X	      sprintf(buffer, "%s(message addressed to %.60s)\n", 
X	            strlen(current_header->subject) > 0 ? "\n" : "",
X		    current_header->to);
X	    else
X	      sprintf(buffer, "%s(message addressed to %s)\n", 
X	            strlen(current_header->subject) > 0 ? "\n" : "",
X		    current_header->to);
X	    if (builtin)
X	      display_line(buffer);
X	    else
X	      fprintf(pipe_wr_fp, "%s", buffer);
X	  }
X	
X	  /** The test above is: if we didn't originally send the mail
X	      (e.g. we're not reading "mail.sent") AND the user is currently
X	      weeding out the "To:" line (otherwise they'll get it twice!)
X	      AND the user is actually weeding out headers AND the message 
X	      wasn't addressed to the user AND the 'to' address is non-zero 
X	      (consider what happens when the message doesn't HAVE a "To:" 
X	      line...the value is NULL but it doesn't match the username 
X	      either.  We don't want to display something ugly like 
X	      "(message addressed to )" which will just clutter up the 
X	      screen!).
X
X	      And you thought programming was EASY!!!!
X	  **/
X
X	  /** one more friendly thing - output a line indicating what sort
X	      of status the message has (e.g. Urgent etc).  Mostly added
X	      for X.400 support, this is nonetheless generally useful to
X	      include...
X	  **/
X
X	  buffer[0] = '\0';
X
X	  /* we want to flag Urgent, Confidential, Private and Expired tags */
X
X	  if (current_header->status & PRIVATE)
X	    strcpy(buffer, "\n(** This message is tagged Private");
X	  else if (current_header->status & CONFIDENTIAL) 
X	    strcpy(buffer, "\n(** This message is tagged Company Confidential");
X
X	  if (current_header->status & URGENT) {
X	    if (buffer[0] == '\0')
X	      strcpy(buffer, "\n(** This message is tagged Urgent");
X	    else if (current_header->status & EXPIRED)
X	      strcat(buffer, ", Urgent");
X	    else
X	      strcat(buffer, " and Urgent");
X	  }
X
X	  if (current_header->status & EXPIRED) {
X	    if (buffer[0] == '\0')
X	      strcpy(buffer, "\n(** This message has Expired");
X	    else
X	      strcat(buffer, ", and has Expired");
X	  }
X
X	  if (buffer[0] != '\0') {
X	    strcat(buffer, " **)\n");
X	    if (builtin)
X	      display_line(buffer);
X	    else
X	      fprintf(pipe_wr_fp, buffer);
X	  }
X
X	  if (builtin)			/* this is for a one-line blank    */
X	    display_line("\n");		/*   separator between the title   */
X	  else				/*   stuff and the actual message  */
X	    fprintf(pipe_wr_fp, "\n");	/*   we're trying to display       */
X
X	}
X
X	weed_header = filter;	/* allow us to change it after header */
X
X	while (lines > 0 && pipe_abort == FALSE) {
X
X	    if (fgets(buffer, VERY_LONG_STRING, mailfile) == NULL) {
X
X	      dprint(1, (debugfile,
X		"Premature end of file! Lines left = %d msg = %s (show_msg)\n",
X		lines, number));
X
X	      error("Premature end of file!");
X	      sleep(2);
X	      break;
X	    }
X	    if ((buf_len=strlen(buffer)) > 0)  {
X	      if(buffer[buf_len - 1] == '\n') {
X	        lines--;
X	        lines_displayed++;
X		}
X              no_ret(buffer);
X	    }
X
X  	    if (strlen(buffer) == 0) {
X	      weed_header = 0;		/* past header! */
X	      weeding_out = 0;
X	    }
X
X	    if (form_letter && weed_header)
X		/* skip it.  NEVER display random headers in forms! */;
X	    else if (weed_header && matches_weedlist(buffer)) 
X	      weeding_out = 1;	 /* aha!  We don't want to see this! */
X	    else if (buffer[0] == '[') {
X	      if (strcmp(buffer, START_ENCODE)==0)
X	        crypted = ON;
X	      else if (strcmp(buffer, END_ENCODE)==0)
X	        crypted = OFF;
X	      else if (crypted) {
X                encode(buffer);
X	        val = show_line(buffer, builtin);
X	      }
X	      else
X	        val = show_line(buffer, builtin);
X	    } 
X	    else if (crypted) {
X	      encode(buffer);
X	      val = show_line(buffer, builtin); 
X	    }
X	    else if (weeding_out) {
X	      weeding_out = (whitespace(buffer[0]));	/* 'n' line weed */
X	      if (! weeding_out) 	/* just turned on! */
X	        val = show_line(buffer, builtin);
X	    } 
X	    else if (form_letter && first_word(buffer,"***") && filter) {
X	      strcpy(buffer,
X"\n------------------------------------------------------------------------------\n");
X	      val = show_line(buffer, builtin);	/* hide '***' */
X	      form_letter_section++;
X	    }
X	    else if (form_letter_section == 1 || form_letter_section == 3)
X	      /** skip this stuff - we can't deal with it... **/;
X	    else
X	      val = show_line(buffer, builtin);
X	
X	    if (val != 0)	/* discontinue the display */
X	      break;
X	}
X
X        if (cursor_control) transmit_functions(ON);
X
X	if (!builtin) {
X	  fclose(pipe_wr_fp);
X	  while ((wait_ret = wait(&wait_stat)) != fork_ret
X		  && wait_ret!= -1)
X	    ;
X	  /* turn raw on **after** child terminates in case child
X	   * doesn't put us back to cooked mode after we return ourselves
X	   * to raw.
X	   */
X	  Raw(ON);
X	}
X
X	/* If we are to prompt for a user input command and we don't
X	 * already have one */
X	if ((prompt_after_pager || builtin) && val == 0) {
X	  MoveCursor(LINES,0);
X	  StartBold();
X	  Write_to_screen(" Command ('i' to return to index): ", 0);
X	  EndBold();
X	  fflush(stdout);
X	  val = ReadCh();
X	}
X	
X	if (memory_lock) EndMemlock();	/* turn it off!! */
X
X	/* 'q' means quit current operation and pop back up to previous level -
X	 * in this case it therefore means return to index screen.
X	 */
X	return(val == 'i' || val == 'q' ? 0 : val);
X}
X
Xint
Xshow_line(buffer, builtin)
Xchar *buffer;
Xint  builtin;
X{
X	/** Hands the given line to the output pipe.  'builtin' is true if
X	    we're using the builtin pager.
X	    Return the character entered by the user to indicate
X	    a command other than continuing with the display (only possible
X	    with the builtin pager), otherwise 0. **/
X
X	strcat(buffer, "\n");
X#ifdef MMDF
X	if (strcmp(buffer, MSG_SEPERATOR) == 0)
X	  return(0);	/* no reason to show the ending terminator */
X#endif /* MMDF */
X	if (builtin) {
X	  return(display_line(buffer));
X	}
X	errno = 0;
X	fprintf(pipe_wr_fp, "%s", buffer);
X	if (errno != 0)
X	  dprint(1, (debugfile, "\terror %s hit!\n", error_name(errno)));
X	return(0);
X}
SHAR_EOF
# ============= src/showmsg_c.c ==============
echo "x - extracting src/showmsg_c.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/showmsg_c.c &&
X
Xstatic char rcsid[] = "@(#)$Id: showmsg_c.c,v 4.1 90/04/28 22:44: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:	showmsg_c.c,v $
X * Revision 4.1  90/04/28  22:44:08  syd
X * checkin of Elm 2.3 as of Release PL0
X * 
X *
X ******************************************************************************/
X
X/** This is an interface for the showmsg command line.  The possible
X    functions that could be invoked from the showmsg command line are
X    almost as numerous as those from the main command line and include
X    the following;
X
X	   |    = pipe this message to command...
X	   !    = call Unix command
X	   <    = scan message for calendar info
X	   b    = bounce (remail) message
X	   d    = mark message for deletion
X	   f    = forward message
X	   g    = group reply
X	   h    = redisplay this message from line #1, showing headers
X	   <CR> = redisplay this message from line #1, weeding out headers
X	   i,q  = move back to the index page (simply returns from function)
X	   J    = move to body of next message
X	   j,n  = move to body of next undeleted message
X	   K    = move to body of previous message
X	   k    = move to body of previous undeleted message
X	   m    = mail a message out to someone
X	   p    = print this (all tagged) message
X	   r    = reply to this message
X	   s    = save this message to a maibox/folder 
X	   t    = tag this message
X	   u    = undelete message
X	   x    = Exit Elm NOW 
X
X    all commands not explicitly listed here are beeped at.  Use i)ndex
X    to get back to the main index page, please.
X
X    This function returns when it is ready to go back to the index
X    page.
X**/
X
X#include "headers.h"
X
Xint	screen_mangled = 0;
Xchar    msg_line[SLEN];
X#define store_msg(a)	(void)strcpy(msg_line,a)
X#define put_prompt()	PutLine0(LINES-3, 0, "Command:")
X#define put_help()	PutLine0(LINES-3, 45, "(Use 'i' to return to index.)")
X#define POST_PROMPT_COL	strlen("Command: ")
X
X
Xint
Xprocess_showmsg_cmd(command)
Xint command;
X{
X	int     i, intbuf;		/* for dummy parameters...etc */
X	int 	ch;			/* for arrow keys */
X	int	key_offset;		/* for arrow keys */
X	int	istagged;		/* for tagging and subsequent msg */
X
X	Raw(ON);
X
X	while (TRUE) {
X	  clear_error();
X	  switch (command) {
X	    case '?' : if (help(TRUE)) {
X			 ClearScreen();
X			 build_bottom();
X		       } else screen_mangled = TRUE;
X		       break;
X
X	    case '|' : put_cmd_name("Pipe", TRUE);
X		       (void) do_pipe();     /* do pipe - ignore return val */
X		       ClearScreen();
X		       build_bottom();
X		       break; 
X
X#ifdef ALLOW_SUBSHELL
X	    case '!' : put_cmd_name("System call", TRUE);
X		       (void) subshell();
X		       ClearScreen();
X		       build_bottom();
X		       break;
X#endif
X
X	    case '<' : 
X#ifdef ENABLE_CALENDAR
X		       put_cmd_name("Scan messages for calendar entries", TRUE);
X		       scan_calendar();
X#else
X		       store_msg("Can't scan for calendar entries!");
X#endif
X		       break;
X
X	    case '%' : put_cmd_name("Display return address", TRUE);
X		       get_return(msg_line, current-1);
X		       break;
X
X	    case 'b' : put_cmd_name("Bounce message", TRUE);
X		       remail();
X		       break;
X  
X	    case 'd' : delete_msg(TRUE, FALSE); /* really delete it, silent */
X		       if (! resolve_mode)
X			 store_msg("Message marked for deletion.");
X		       else
X			 goto next_undel_msg;
X		       break;
X
X	    case 'f' : put_cmd_name("Forward message", TRUE);
X		       if(forward()) put_border();
X		       break;
X
X	    case 'g' : put_cmd_name("Group reply", TRUE);
X		       (void) reply_to_everyone();
X		       break;
X
X	    case 'h' : screen_mangled = 0;
X		       if (filter) { 
X		         filter = 0; 
X		         intbuf = show_msg(current); 
X		         filter = 1;
X			 return(intbuf);
X		       } else
X		         return(show_msg(current)); 
X
X	    case 'q' :
X	    case 'i' : (void) get_page(current);
X		       clear_error();		/* zero out pending msg   */
X		       if (cursor_control)
X			 transmit_functions(ON);
X		       screen_mangled = 0;
X		       return(0);		/* avoid <return> looping */
X 
Xnext_undel_msg :	/* a target for resolve mode actions */
X
X	    case ' ' :
X	    case 'j' :
X	    case 'n' : screen_mangled = 0;
X		       if((i=next_message(current-1, TRUE)) != -1)
X			 return(show_msg(current = i+1));
X		       else return(0);
X
Xnext_msg:
X	    case 'J' : screen_mangled = 0;
X		       if((i=next_message(current-1, FALSE)) != -1)
X			 return(show_msg(current = i+1));
X		       else return(0);
X
Xprev_undel_msg:
X	    case 'k' : screen_mangled = 0;
X		       if((i=prev_message(current-1, TRUE)) != -1)
X			 return(show_msg(current = i+1));
X		       else return(0);
X
X	    case 'K' : screen_mangled = 0;
X		       if((i=prev_message(current-1, FALSE)) != -1)
X			 return(show_msg(current = i+1));
X		       else return(0);
X
X	    case 'm' : put_cmd_name("Mail message", TRUE);
X		       if(sendmsg("","","", TRUE, allow_forms, FALSE))
X			 put_border();
X		       break;
X
X	    case 'p' : put_cmd_name("Print message", FALSE);
X		       print_msg();
X		       store_msg("Queued for printing.");
X		       break;
X
X	    case 'r' : put_cmd_name("Reply to message", TRUE);
X		       if(reply()) put_border();
X		       break;
X
X	    case '>' :
X	    case 'C' :
X	    case 's' : put_cmd_name((command != 'C' ? "Save" : "Copy"), TRUE);
X		       (void) save(&intbuf, TRUE, (command != 'C'));
X		       if (resolve_mode && command != 'C')
X			 goto next_undel_msg;
X		       break;
X
X	    case 't' : istagged=tag_message(FALSE);	
X		       if(istagged)
X			 store_msg("Message tagged.");
X		       else 
X			 store_msg("Message untagged.");
X		       break;
X
X	    case 'u' : undelete_msg(FALSE); /* undelete it, silently */
X		       if (! resolve_mode)
X			 store_msg("Message undeleted.");
X		       else {
X/******************************************************************************
X ** We're special casing the U)ndelete command here *not* to move to the next
X ** undeleted message ; instead it'll blindly move to the next message in the
X ** list.  See 'elm.c' and the command by "case 'u'" for further information.
X ** The old code was:
X			 goto next_undel_msg;
X*******************************************************************************/
X			 goto next_msg;
X		       }
X		       break;
X
X	    case 'x' : put_cmd_name("Exit", TRUE);
X		       exit_prog();
X		       break;
X	    
X	    case ctrl('J'):
X	    case ctrl('M'):  screen_mangled = 0;
X			     return(show_msg(current));
X
X
X            case ESCAPE : if (cursor_control) {
X  
X                            key_offset = 1;
X  
X                            ch = ReadCh(); 
X  
X                            if (ch == ESCAPE)
X                             ch = ReadCh();
X  
X                            if ( ch == '[' || ch == 'O') 
X                            {
X                              ch = ReadCh();
X                              key_offset++;
X                            }
X  
X                            if (ch == up[key_offset])
X			      goto prev_undel_msg;
X                            else if (ch == down[key_offset])
X			      goto next_undel_msg;
X                            else {
X			      screen_mangled = 0;
X                              return(0);
X			    }
X                          }
X                          else          /* Eat 2 chars for escape codes */
X                          {
X                            ch = ReadCh();
X                            ch = ReadCh();
X                            putchar((char) 007);
X                            fflush(stdout);
X			    screen_mangled = 0;
X                            return(0);
X                           }
X  
X	    default  : putchar((char) 007);	/* BEEP! */
X	  }
X
X	  /* display prompt */
X	  if (screen_mangled) {
X	    /* clear what was left over from previous command 
X	     * and display last generated message.
X	     */
X	    put_prompt();
X	    CleartoEOS();
X	    put_help();
X	    Centerline(LINES, msg_line);
X	    MoveCursor(LINES-3, POST_PROMPT_COL);
X	  } else {
X	    /* display bottom line prompt with last generated message */
X	    MoveCursor(LINES, 0);
X	    CleartoEOS();
X	    StartBold();
X	    Write_to_screen("%s Command ('i' to return to index): ",
X		1, msg_line);
X	    EndBold();
X	  }
X	  *msg_line = '\0';	/* null last generated message */
X
X	  command = ReadCh();	/* get next command from user */
X	}
X}
X
Xput_cmd_name(command, will_mangle)
Xchar *command;
Xint will_mangle;
X{
X
X	/* If screen is or will be mangled display the command name 
X	 * and erase the bottom of the screen.
X	 * But first if the border line hasn't yet been drawn, draw it.
X	 */
X	if(will_mangle && !screen_mangled) {
X	  build_bottom();
X	  screen_mangled = TRUE;
X	}
X	if(screen_mangled) {
X	  PutLine0(LINES-3, POST_PROMPT_COL, command);
X	  CleartoEOS();
X	}
X}
X
Xput_border()
X{
X	 PutLine0(LINES-4, 0, 
X"--------------------------------------------------------------------------\n");
X}
X
Xbuild_bottom()
X{
X	 MoveCursor(LINES-4, 0);
X	 CleartoEOS();
X	 put_border();
X	 put_prompt();
X	 put_help();
X}
SHAR_EOF
# ============= src/signals.c ==============
echo "x - extracting src/signals.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/signals.c &&
X
Xstatic char rcsid[] = "@(#)$Id: signals.c,v 4.1 90/04/28 22:44:10 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:	signals.c,v $
X * Revision 4.1  90/04/28  22:44:10  syd
X * checkin of Elm 2.3 as of Release PL0
X * 
X *
X ******************************************************************************/
X
X/** This set of routines traps various signals and informs the
X    user of the error, leaving the program in a nice, graceful
X    manner.
X
X**/
X
X#include "headers.h"
X#include <signal.h>
X
X#ifdef	VOIDSIG
Xtypedef	void	sighan_type;
X#else
Xtypedef	int	sighan_type;
X#endif
X
Xextern int pipe_abort;		/* set to TRUE if receive SIGPIPE */
X
Xsighan_type
Xquit_signal()
X{
X	dprint(1, (debugfile, "\n\n** Received SIGQUIT **\n\n\n\n"));
X	leave();
X}
X
Xsighan_type
Xhup_signal()
X{
X	dprint(1, (debugfile, "\n\n** Received SIGHUP **\n\n\n\n"));
X	leave();
X}
X
Xsighan_type
Xterm_signal() 
X{
X	dprint(1, (debugfile, "\n\n** Received SIGTERM **\n\n\n\n"));
X	leave();
X}
X
Xsighan_type
Xill_signal()
X{
X	dprint(1, (debugfile, "\n\n** Received SIGILL **\n\n\n\n"));
X	PutLine0(LINES, 0, "\n\nIllegal Instruction signal!\n\n");
X	emergency_exit();
X}
X
Xsighan_type
Xfpe_signal()  
X{
X	dprint(1, (debugfile, "\n\n** Received SIGFPE **\n\n\n\n"));
X	PutLine0(LINES, 0,"\n\nFloating Point Exception signal!\n\n");
X	emergency_exit();
X}
X
Xsighan_type
Xbus_signal()
X{
X	dprint(1, (debugfile, "\n\n** Received SIGBUS **\n\n\n\n"));
X	PutLine0(LINES, 0,"\n\nBus Error signal!\n\n");
X	emergency_exit();
X}
X
Xsighan_type
Xsegv_signal()
X{
X	dprint(1, (debugfile,"\n\n** Received SIGSEGV **\n\n\n\n"));
X	PutLine0(LINES, 0,"\n\nSegment Violation signal!\n\n");
X	emergency_exit();
X}
X
Xsighan_type
Xalarm_signal()
X{	
X	/** silently process alarm signal for timeouts... **/
X#ifdef	BSD
X	if (InGetPrompt)
X		longjmp(GetPromptBuf, 1);
X#else
X	signal(SIGALRM, alarm_signal);
X#endif
X}
X
Xsighan_type
Xpipe_signal()
X{
X	/** silently process pipe signal... **/
X	dprint(2, (debugfile, "*** received SIGPIPE ***\n\n"));
X	
X	pipe_abort = TRUE;	/* internal signal ... wheeee!  */
X
X	signal(SIGPIPE, pipe_signal);
X}
X
X#ifdef SIGTSTP
Xint was_in_raw_state;
X
Xsighan_type
Xsig_user_stop()
X{
X	/* This is called when the user presses a ^Z to stop the
X	   process within BSD 
X	*/
X	if (signal(SIGTSTP, SIG_DFL) != SIG_DFL)
X	  signal(SIGTSTP, SIG_DFL);
X
X	was_in_raw_state = RawState();
X	Raw(OFF);	/* turn it off regardless */
X
X	printf("\n\nStopped.  Use \"fg\" to return to ELM\n\n");
X
X	kill(0, SIGSTOP);
X}
X
Xsighan_type
Xsig_return_from_user_stop()
X{
X	/** this is called when returning from a ^Z stop **/
X
X	if (signal(SIGTSTP, sig_user_stop) == SIG_DFL)
X	  signal(SIGTSTP, sig_user_stop);
X
X	printf(
X	 "\nBack in ELM. (You might need to explicitly request a redraw.)\n\n");
X
X	if (was_in_raw_state)
X	  Raw(ON);
X
X#ifdef	BSD
X	if (InGetPrompt)
X		longjmp(GetPromptBuf, 1);
X#endif
X}
X#endif
SHAR_EOF
# ============= src/softkeys.c ==============
echo "x - extracting src/softkeys.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/softkeys.c &&
X
Xstatic char rcsid[] = "@(#)$Id: softkeys.c,v 4.1 90/04/28 22:44: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:	softkeys.c,v $
X * Revision 4.1  90/04/28  22:44:11  syd
X * checkin of Elm 2.3 as of Release PL0
X * 
X *
X *******************************************************************************
X */
X
X#include "headers.h"
X
Xdefine_softkeys(level)
Xint level;
X{
X	if (! hp_softkeys) return;
X
X	if (level == MAIN) {
X
X	  define_key(f1, " Display   Msg",   "\r");
X	  define_key(f2, "  Mail     Msg",   "m");
X	  define_key(f3, "  Reply  to Msg",  "r");
X
X	  if (user_level == 0) {
X	    define_key(f4, "  Save     Msg",   "s");
X	    define_key(f5, " Delete    Msg",   "d");
X	    define_key(f6, "Undelete   Msg",   "u");
X   	  }
X	  else {
X	    define_key(f4, " Change  Folder", "c");
X	    define_key(f5, "  Save     Msg",   "s");
X	    define_key(f6, " Delete/Undelete", "^");
X	  }
X
X	  define_key(f7, " Print     Msg",   "p");
X	  define_key(f8, "  Quit     ELM",   "q");
X	}
X	else if (level == ALIAS) {
X	  define_key(f1, " Alias  Current",  "a");
X	  define_key(f2, " Check  Person",   "p");
X	  define_key(f3, " Check  System",   "s");
X	  define_key(f4, " Make    Alias",   "m");
X	  clear_key(f5);
X	  clear_key(f6);
X	  clear_key(f7);
X	  define_key(f8, " Return  to ELM",  "r");
X	}
X	else if (level == YESNO) {
X	  define_key(f1, "  Yes",  "y");
X	  clear_key(f2);
X	  clear_key(f3);
X	  clear_key(f4);
X	  clear_key(f5);
X	  clear_key(f6);
X	  clear_key(f7);
X	  define_key(f8, "   No",  "n");
X	}
X	else if (level == READ) {
X	  define_key(f1, "  Next    Page  ", " ");
X	  clear_key(f2);
X	  define_key(f3, "  Next    Msg   ", "j");
X	  define_key(f4, "  Prev    Msg   ", "k");
X	  define_key(f5, "  Reply  to Msg ", "r");
X	  define_key(f6, " Delete   Msg   ", "d");
X	  define_key(f7, "  Send    Msg   ", "m");
X	  define_key(f8, " Return  to ELM ", "q");
X	}
X	else if (level == CHANGE) {
X	  define_key(f1, "  Mail  Directry", "=/");
X	  define_key(f2, "  Home  Directry", "~/");
X	  clear_key(f3);
X	  define_key(f4, "Incoming Mailbox", "!\n");
X	  define_key(f5, "\"Received\" Folder", ">\n");
X	  define_key(f6, "\"Sent\"   Folder ", "<\n");
X	  clear_key(f7);
X	  define_key(f8, " Cancel", "\n");
X	}
X
X	softkeys_on();
X}
X
Xdefine_key(key, display, send)
Xint key;
Xchar *display, *send;
X{
X
X	char buffer[30];
X
X	sprintf(buffer,"%s%s", display, send);
X
X	fprintf(stderr, "%c&f%dk%dd%dL%s", ESCAPE, key,
X		strlen(display), strlen(send), buffer);
X	fflush(stdout);
X}
X
Xsoftkeys_on()	
X{ 
X	/* enable (esc&s1A) turn on softkeys (esc&jB) and turn on MENU 
X	   and USER/SYSTEM options. */
X
X	if (hp_softkeys) {
X	  fprintf(stderr, "%c&s1A%c&jB%c&jR", ESCAPE, ESCAPE, ESCAPE); 
X	  fflush(stdout);
X	}
X	
X}
X
Xsoftkeys_off()	
X{ 
X	/* turn off softkeys (esc&j@) */
X
X	if (hp_softkeys) {
X	  fprintf(stderr, "%c&s0A%c&j@", ESCAPE, ESCAPE); 
X	  fflush(stdout);
X	}
X}
X
Xclear_key(key)  
X{ 	
X	/** set a key to nothing... **/
X
X	if (hp_softkeys) 
X	   define_key(key, "                ", ""); 
X}
SHAR_EOF
# ============= src/sort.c ==============
echo "x - extracting src/sort.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/sort.c &&
X
Xstatic char rcsid[] = "@(#)$Id: sort.c,v 4.1 90/04/28 22:44:12 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:	sort.c,v $
X * Revision 4.1  90/04/28  22:44:12  syd
X * checkin of Elm 2.3 as of Release PL0
X * 
X *
X ******************************************************************************/
X
X/** Sort folder header table by the field specified in the global
X    variable "sortby"...if we're sorting by something other than
X    the default SENT_DATE, also put some sort of indicator on the
X    screen.
X
X**/
X
X#include "headers.h"
X
Xchar *sort_name(), *skip_re();
Xvoid   qsort();
X
Xsort_mailbox(entries, visible)
Xint entries, visible;
X{
X	/** Sort the header_table definitions... If 'visible', then
X	    put the status lines etc **/
X	
X	int last_index = -1;
X	int compare_headers();	/* for sorting */
X
X	dprint(2, (debugfile, "\n** sorting folder by %s **\n\n", 
X		sort_name(FULL)));
X
X	/* Don't get last_index if no entries or no current. */
X	/* There would be no current if we are sorting a new mail file. */
X	if (entries > 0 && current > 0)
X	  last_index = headers[current-1]->index_number;
X
X	if (entries > 30 && visible)  
X	  error1("Sorting messages by %s...", sort_name(FULL));
X	
X	if (entries > 1)
X	  qsort(headers, (unsigned) entries, sizeof (struct header_rec *),
X	      compare_headers);
X
X	if (last_index > -1)
X	  find_old_current(last_index);
X
X	clear_error();
X}
X
Xint
Xcompare_headers(p1, p2)
Xstruct header_rec **p1, **p2;
X{
X	/** compare two headers according to the sortby value.
X
X	    Sent Date uses a routine to compare two dates,
X	    Received date is keyed on the file offsets (think about it)
SHAR_EOF
echo "End of  part 17"
echo "File src/sort.c is continued in part 18"
echo "18" > shar3_seq_.tmp
exit 0