[comp.mail.elm] Elm 2.1 PL1 part 18 of 22

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

---- Cut Here and unpack ----
#!/bin/sh
# this is part 18 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file src/screen.c continued
#
CurArch=18
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/screen.c"
sed 's/^X//' << 'SHAR_EOF' >> src/screen.c
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	  tail_of(header_table[this_msg].from, newfrom, TRUE); 
X
X	  if (selected) {
X	    if (this_msg == current-1) 
X	      build_header_line(buffer, &header_table[this_msg], ++displayed,
X			      TRUE, newfrom);
X	    else
X	      build_header_line(buffer, &header_table[this_msg], 
X			      ++displayed, FALSE, newfrom);
X	  } 
X	  else {
X	    if (this_msg == current-1) 
X	      build_header_line(buffer, &header_table[this_msg], this_msg+1, 
X		              TRUE, newfrom);
X	    else
X	      build_header_line(buffer, &header_table[this_msg], 
X			      this_msg+1, FALSE, newfrom);
X	  }
X
X	  if (this_msg == current-1 && has_highlighting && ! arrow_cursor) {
X	      StartInverse();
X	      Write_to_screen("%s\r\n", 1, buffer);	/* avoid '%' probs */
X	      EndInverse();
X	  } else
X	      Write_to_screen("%s\r\n", 1, buffer);	/* avoid '%' probs */
X	  CleartoEOLN();
X	  line++;		/* for clearing up in a sec... */
X
X	  if (selected) {
X	    if ((this_msg = next_visible(this_msg+1)-1) < 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	if (mini_menu)
X	  last_line = LINES-8;
X	else
X	  last_line = LINES-4;
X
X	while (line < last_line) {
X	  CleartoEOLN();
X	  Writechar('\r');
X	  Writechar('\n');
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, i=0, j=0;
X	char     newfrom[SLEN], old_buffer[SLEN], new_buffer[SLEN];
X
X	(void) fix_header_page();	/* Who cares what it does? ;-) */
X
X	/** compute last header to display **/
X
X	first = header_page * headers_per_page;
X	last  = first + (headers_per_page - 1);
X
X	if (last > message_count) 
X	  last = message_count;
X
X	/** okay, now let's show the pointers... **/
X
X	/** have we changed??? **/
X
X	if (current == last_current) 
X	  return;
X
X	if (selected) {
X	  last_line = ((i=compute_visible(last_current-1)-1) %
X			 headers_per_page)+4;
X	  new_line  = ((j=compute_visible(current-1)-1) % headers_per_page)+4;
X	}
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	  /** build the old and new header lines... **/
X  
X	  tail_of(header_table[current-1].from, newfrom, TRUE); 
X	  build_header_line(new_buffer, &header_table[current-1], 
X	         (selected? compute_visible(current-1) : current), 
X		  TRUE, newfrom);
X
X	  if (last_current > 0 && 
X	      (last_current-1 <= last && 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	    tail_of(header_table[last_current-1].from, newfrom, TRUE); 
X	    build_header_line(old_buffer, &header_table[last_current-1], 
X	         (selected? compute_visible(last_current-1) : last_current), 
X		  FALSE, newfrom);
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)) 
X	    PutLine0(last_line,0,"  ");	/* remove old pointer... */
X	  if (on_page(current))
X	    PutLine0(new_line, 0,"->");
X	}
X	
X	last_current = current;
X}
X
Xbuild_header_line(buffer, entry, message_number, highlight, from)
Xchar *buffer;
Xstruct header_rec *entry;
Xint message_number, highlight;
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	char subj[LONG_SLEN];		/* to output subject */
X
X	strncpy(subj, entry->subject, COLUMNS-44);
X
X	subj[COLUMNS-45] = '\0';	/* insurance, eh? */
X
X	/* now THIS is a frightening format statement!!!  */
X
X	sprintf(buffer, "%s%s%c%-3d %3.3s %-2d %-18.18s (%d) %s%s", 
X		(highlight && arrow_cursor)? "->" : "  ",
X		show_status(entry->status),
X		(entry->status & TAGGED?  '+' : ' '),
X	        message_number,
X	        entry->month, 
X		atoi(entry->day), 
X		from, 
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		subj);
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-1);
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		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                            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
echo "File src/screen.c is complete"
chmod 0444 src/screen.c || echo "restore of src/screen.c fails"
echo "x - extracting src/showmsg.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/showmsg.c &&
X
Xstatic char rcsid[] = "@(#)$Id: showmsg.c,v 2.1.1.2 88/09/23 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:	showmsg.c,v $
X * Revision 2.1  88/09/15  20:29:43  syd
X * checked in with -k by syd at 88.09.15.20.29.43.
X * 
X * 88/08/27 ssw
X *	add deluth patches
X *
X * Revision 2.1  88/07/21  09:59:34  edc
X * Final hacks and cleanup to the 2.1 alpha test release.
X * 
X * Revision 2.0  88/06/27  17:25:36  edc
X * The original 2.0 gamma sources as leaked from HP
X * 
X *
X *
X ******************************************************************************/
X
X/** This file contains all the routines needed to display the specified
X    message.
X
X
X   Modified 6/86 to use pager variable!!!   Hurrah!!!!
X   Modified 7/86 to have secure pipes.. *sigh*
X   and again 10/87 to do more interesting things with the screen w.r.t.
X     end of message prompting and so on...
X**/
X
X#include "headers.h"
X#include <ctype.h>
X#include <errno.h>
X#include <signal.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
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		Returns non-zero iff the screen was changed, or the
X	     character pressed at the 'end-of-screen' prompt (to be
X	     processed via process_showmsg_cmd()).
X	***/
X
X	dprint(8, (debugfile, "show_msg called\n"));
X
X	if (number > message_count) {
X	  error1("Only %d messages!", message_count);
X	  return(0);
X	}
X	else if (number < 1) {
X	  error("you can't read THAT message!");
X	  return(0);
X	}
X
X	clearit(header_table[number-1].status, NEW);   /* it's been read now! */
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	return(show_message(header_table[number-1].lines, 
X	       header_table[number-1].offset,number));
X}
X
Xint
Xshow_message(lines, file_loc, msgnumber)
Xint lines, msgnumber;
Xlong file_loc;
X{
X	/*** Show the indicated range of lines from mailfile
X	     for message 'msgnumber' by using 'display'
X	     Returns non-zero iff screen was altered, or the char
X	     pressed (see previous routine header comment).
X	***/
X	int  retval;
X
X	dprint(9, (debugfile, "show_message(%d,%ld,%d)\n", 
X	 	lines, file_loc, msgnumber));
X
X	if (fseek(mailfile, file_loc, 0) == -1) {
X	  dprint(1, (debugfile,
X		  "Error: seek %d bytes into file, errno %s (show_message)\n",
X		  file_loc, error_name(errno)));
X	  error2("ELM failed seeking %d bytes into file (%s)",
X		  file_loc, error_name(errno));	
X	  return(0);
X	}
X
X	if (feof(mailfile))
X	  dprint(1, (debugfile, "\n*** seek put us at END OF FILE!!! ***\n"));
X
X
X	/* next read will get 'this' line so must be at end of previous */
X
X	if (first_word(pager,"builtin") || first_word(pager,"internal"))
X	  retval = display(lines, msgnumber);
X	else
X	  retval = secure_display(lines, msgnumber);
X
X	if (memory_lock) EndMemlock();	/* turn it off!! */
X
X	return(retval == 0? 1 : retval);	/* we did it boss! */
X}
X	
X
X/** This next one is the 'pipe' file descriptor for writing to the 
X    pager process... **/
X
XFILE   *output_pipe, *popen();
X
Xint
Xdisplay(lines, msgnum)
Xint lines, msgnum;
X{
X	/** Display specified number of lines from file mailfile.
X	    Note: This routine MUST be placed at the first line 
X	    of the input file! 
X	    Returns the same as the routine above (namely zero or one)
X	**/
X
X	char title1[SLEN], title2[SLEN], *p;
X	char from_buffer[LONG_STRING], buffer[VERY_LONG_STRING];
X
X	int crypted = 0, gotten_key = 0;	/* encryption */
X	int weed_header, weeding_out = 0;	/* weeding    */ 
X	int mail_sent,				/* misc use   */
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
X	dprint(4, (debugfile,"displaying %d lines from message %d using %s\n", 
X		lines, msgnum, pager));
X
X	ClearScreen();
X
X	if (cursor_control) transmit_functions(OFF);
X
X	pipe_abort = FALSE;
X
X	builtin =(first_word(pager,"builtin") || first_word(pager,"internal"));
X
X	if (form_letter = (header_table[msgnum-1].status&FORM_LETTER)) {
X	  if (filter)
X	    form_letter_section = 1;	/* initialize to section 1 */
X	}
X
X	if (builtin)
X	  start_builtin(lines);
X	else {
X	  lines_displayed = 0;
X	  Raw(OFF);
X	  if ((output_pipe = popen(pager,"w")) == NULL) {
X	    error2("Can't create pipe to %s [%s]", pager, 
X		    error_name(errno));
X	    dprint(1, (debugfile, 
X		    "\n*** Can't create pipe to %s - error %s ***\n\n",
X	   	    pager, error_name(errno)));
X	    Raw(ON);
X	    return(0);
X	  }
X	  dprint(4, (debugfile, 
X		 "Opened a write-only pipe to pager %s \n", pager));
X	}
X
X	if (title_messages && filter) {
X
X	  mail_sent = (strncmp(header_table[msgnum-1].from, "To:", 3) == 0);
X
X	  tail_of(header_table[msgnum-1].from, from_buffer, FALSE);
X
X	  sprintf(title1, "%s %d/%d %s %s%s",
X		    header_table[msgnum-1].status & DELETED ? "[deleted]" :
X		      form_letter? "Form": "Message",
X		    msgnum, message_count,
X		    mail_sent? "to" : "from", from_buffer,
X		    strlen(from_buffer) > 26? "\n": "");
X
X	  sprintf(title2, " %s %s '%d at %s\n",
X     		   header_table[msgnum-1].month, 
X		   header_table[msgnum-1].day, 
X	           atoi(header_table[msgnum-1].year),
X	           header_table[msgnum-1].time);
X
X	  /** and now let's add some spaces between the two parts, please **/
X
X	  if (strlen(from_buffer) > 26) {
X	    if (builtin)
X	      display_line(title1);
X	    else
X	      fprintf(output_pipe, "%s", title1);
X	    title1[0] = '\0';
X	    padding = COLUMNS - strlen(title2) - 1;
X	  }
X	  else 
X	    padding = COLUMNS - strlen(title1) - strlen(title2) - 1;
X
X	  p = title1 + strlen(title1);
X	  while (padding-- > 0)
X	    *p++ = ' ';
X	  *p = '\0';
X	  strcat(title1, title2);
X
X	  if (builtin)
X	    display_line(title1);
X	  else
X	    fprintf(output_pipe, "%s", title1);
X
X	  /** if there's a subject, let's next output it, centered.  **/
X
X	  if (strlen(header_table[current-1].subject) > 0 && 
X		matches_weedlist("Subject:")) {
X	    padding = (COLUMNS - strlen(header_table[current-1].subject)) / 2;
X	    p = buffer;
X	    while (padding-- > 0)
X	      *p++ = ' ';
X	    *p = '\0';
X	    strcat(buffer, header_table[current-1].subject);
X	    strcat(buffer, "\n");
X	  }
X	  else
X	    strcpy(buffer, "\n");
X
X	  if (builtin)
X	    display_line(buffer);
X	  else
X	    fprintf(output_pipe, "%s", buffer);
X	  
X	  /** was this message address to us?  if not, then to whom? **/
X
X	  if (! mail_sent && matches_weedlist("To:") && filter &&
X	      strcmp(header_table[current-1].to,username) != 0 &&
X	      strlen(header_table[current-1].to) > 0) {
X	    if (strlen(header_table[current-1].to) > 60)
X	      sprintf(buffer, "%s(message addressed to %.60s)\n", 
X	            strlen(header_table[current-1].subject) > 0 ? "\n" : "",
X		    header_table[current-1].to);
X	    else
X	      sprintf(buffer, "%s(message addressed to %s)\n", 
X	            strlen(header_table[current-1].subject) > 0 ? "\n" : "",
X		    header_table[current-1].to);
X	    if (builtin)
X	      display_line(buffer);
X	    else
X	      fprintf(output_pipe, "%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 (header_table[current-1].status & PRIVATE)
X	    strcpy(buffer, "\n(** This message is tagged Private");
X	  else if (header_table[current-1].status & CONFIDENTIAL) 
X	    strcpy(buffer, "\n(** This message is tagged Company Confidential");
X
X	  if (header_table[current-1].status & URGENT) {
X	    if (buffer[0] == '\0')
X	      strcpy(buffer, "\n(** This message is tagged Urgent");
X	    else if (header_table[current-1].status & EXPIRED)
X	      strcat(buffer, ", Urgent");
X	    else
X	      strcat(buffer, " and Urgent");
X	  }
X
X	  if (header_table[current-1].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(output_pipe, 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(output_pipe, "\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	      if (lines_displayed == 0) {
X
X		/* AUGH!  Why do we get this occasionally???  */
X
X	        dprint(1, (debugfile, 
X	         "\n\n** Out of Sync!!  EOF with nothing read (display) **\n"));
X		dprint(1, (debugfile,
X		 "** closing and reopening mailfile... **\n\n"));
X
X		if (!builtin) {
X		  pclose(output_pipe);      /* close pipe NOW! */
X		  Raw(ON);
X		}
X
X		if (mailfile != NULL)
X		  fclose(mailfile);		/* huh? */
X
X		if ((mailfile = fopen(infile, "r")) == NULL) {
X		  error("Sync error: can't re-open mailbox!!");
X		  show_mailfile_stats();
X		  emergency_exit();
X	        }
X	        return(show_message(lines, 
X			            header_table[msgnum-1].offset,
X				    msgnum));
X	      }
X
X	      if (!builtin) {
X	        pclose(output_pipe);
X		Raw(ON);
X	      }
X
X	      if (lines == 0 && pipe_abort == FALSE) {	/* displayed it all */
X	        MoveCursor(LINES,0);
X		StartBold();
X		Write_to_screen(" Please press <return> to return to Elm : ",0);
X	        EndBold();
X		fflush(stdout);
X	        val = ReadCh();
X	      }
X	      return(val);
X	    }
X
X	    if (strlen(buffer) > 0) 
X              no_ret(buffer);
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++;
X	      else if (strcmp(buffer, END_ENCODE)==0)
X	        crypted--;
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	      if (! gotten_key++) getkey(OFF);
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) {	/* let's get back to the top level ... */
X	      if (! builtin) {
X		pclose(output_pipe);
X		Raw(ON);
X	      }
X	      return(val);
X	    }
X
X	    lines--;
X	    lines_displayed++;
X	}
X
X        if (cursor_control) transmit_functions(ON);
X
X	if (! builtin) {
X	  pclose(output_pipe);
X	  Raw(ON);
X	}
X
X	if (lines == 0 && pipe_abort == FALSE) {  	/* displayed it all! */
X	  MoveCursor(LINES,0);
X	  StartBold();
X	  Write_to_screen(" Please press <return> to return to Elm : ", 0);
X	  EndBold();
X	  fflush(stdout);
X	  val = ReadCh();
X	}
X	
X	return(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.  We will return 'val' as the
X            intermediate value from the builtin pager if the user chooses
X	    to do something else at the end-of-page prompt! **/
X
X	register int val;
X	
X	if (builtin) {
X	  strcat(buffer, "\n");
X	  if ((val = display_line(buffer)) > 1) {
X	    return(val);
X	  }
X	  else	    
X	    pipe_abort = val;
X	  
X	}
X	else {
X	  errno = 0;
X	  fprintf(output_pipe, "%s\n", buffer);
X	
X	  if (errno != 0)
X	    dprint(1, (debugfile, "\terror %s hit!\n", error_name(errno)));
X	}
X
X	return(0);
X}
X
Xint
Xsecure_display(lines, msgnumber)
Xint lines, msgnumber;
X{
X	/** This is the cheap way to implement secure pipes - spawn a
X	    child process running under the old userid, then open the
X	    pager and feed the message to it.  When the subprocess ends
X	    (the routine returns) simply return.  Simple and effective.
X	    (too bad it's this much of a hassle to implement secure
X	    pipes, though - I can imagine it being a constant problem!)
X	**/
X
X	int pid, w;
X#ifdef BSD
X	union wait status;
X#else
X	int status;
X#endif
X	register int (*istat)(), (*qstat)();
X	
X#ifdef NO_VM		/* machine without virtual memory! */
X	if ((pid = fork()) == 0) {
X#else
X#  ifdef hp9000s500			/* done this way for portability */
X	if ((pid = fork()) == 0) {
X#  else
X	if ((pid = vfork()) == 0) {
X#  endif
X#endif
X
X	  setgid(groupid);	/* and group id		    */
X	  setuid(userid);	/* back to the normal user! */
X
X	  _exit(display(lines, msgnumber));
X	}
X
X	istat = signal(SIGINT, SIG_IGN);
X	qstat = signal(SIGQUIT, SIG_IGN);
X
X	while ((w = wait(&status)) != pid && w != -1)
X		;
X
X	signal(SIGINT, istat);
X	signal(SIGQUIT, qstat);
X
X	/** used to return status, but who cares?  Just get BACK! **/
X
X	return(0);
X}
SHAR_EOF
chmod 0444 src/showmsg.c || echo "restore of src/showmsg.c fails"
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 2.1 88/09/15 20:29:46 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:	showmsg_c.c,v $
X * Revision 2.1  88/09/15  20:29:46  syd
X * checked in with -k by syd at 88.09.15.20.29.46.
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:59:37  edc
X * Final hacks and cleanup to the 2.1 alpha test release.
X * 
X * Revision 2.0  88/06/27  17:25:38  edc
X * The original 2.0 gamma sources as leaked from HP
X * 
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	   i    = move back to the index page (simply returns from function)
X	   j,n  = move to body of next message
X	   k    = move to body of previous 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
X#ifdef BSD
X#undef tolower
X#endif
X
Xint screen_mangled = 0;
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	char    error_line[SLEN];	/* for stat line messsages    */
X
X	Raw(ON);
X
X	while (TRUE) {
X	  clear_error();
X	  switch (command) {
X	    case '|' : clear_bottom_of_screen();
X		       PutLine0(LINES-3,0,"Command: pipe");
X		       (void) do_pipe();     /* do pipe - ignore return val */
X		       break; 
X
X	    case '!' : clear_bottom_of_screen();
X		       PutLine0(LINES-3,0,"Command: system call");
X		       (void) subshell();	     /* do shell regardless */
X		       break;
X
X	    case '<' : 
X#ifdef ENABLE_CALENDAR
X		       scan_calendar();
X#else
X		       strcpy(error_line, "can't scan for calendar entries!");
X		       goto show_prompt_again;
X#endif
X		       break;
X
X	    case '%' : clear_bottom_of_screen();
X		       get_return(error_line);
X		       error1("%s", error_line);
X/*
X		       PutLine1(LINES-3, (COLUMNS-strlen(error_line))/2,
X				"%78s", error_line);
X*/
X		       goto show_prompt_again;
X		       break;
X
X	    case 'b' : clear_bottom_of_screen();
X		       PutLine0(LINES-3,0,"Command: bounce message");
X		       remail();
X		       break;
X  
X	    case 'd' : delete_msg(TRUE, FALSE); /* really delete it, silent */
X		       if (! resolve_mode) {
X		         if (screen_mangled) 
X		           strcpy(error_line,"message marked for deletion");
X		         else {
X			   ClearLine(LINES-1);
X		           PutLine0(LINES-1, 0, 
X			      "Message marked for deletion.  Command ? ");
X		           CleartoEOLN();
X		         }
X		       } else goto move_to_next_message;
X		       break;
X
X	    case 'f' : clear_bottom_of_screen();
X		       PutLine0(LINES-3,0,"Command: forward message");
X		       (void) forward();
X		       break;
X
X	    case 'g' : clear_bottom_of_screen();
X		       PutLine0(LINES-3,0,"Command: group reply");
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		       }
X		       else
X		         return(show_msg(current)); 
X 
Xmove_to_next_message :	/* a target for resolve mode actions */
X
X	    case 'j' :
X	    case 'n' : if (current < message_count) {
X	                 screen_mangled = 0;
X			 i = current;
X			 while (++current <= message_count &&
X				header_table[current-1].status & DELETED)
X		           /* continue looking... */ ;
X			 if (current > message_count) {
X			   current = i;
X			   return(0);	/* no more! */
X			 }
X			 else
X		           return(show_msg(current));
X		       }
X		       else 
X			 return(0);
X
X	    case 'J' : if (current < message_count) {
X			 screen_mangled = 0;
X			 return(show_msg(++current));
X		       }
X		       else
X			 return(0);
X
X	    case 'k' : if (current > 0) {
X			 screen_mangled = 0;
X			 i = current;
X			 while (--current > 0 &&
X				header_table[current-1].status & DELETED)
X		           /* continue looking... */ ;
X			 if (current <= 0) {
X			   current = i;
X			   return(0);	/* no more! */
X			 }
X			 else
X		           return(show_msg(current));
X		       }
X		       else 
X			 return(0);
X
X	    case 'K' : if (current > 0) {
X			 screen_mangled = 0;
X			 return(show_msg(--current));
X		       }
X		       else
X			 return(0);
X
X	    case 'm' : clear_bottom_of_screen();
X		       PutLine0(LINES-3,0,"Command: Mail message");
X		       (void) sendmsg("","","", TRUE, allow_forms, FALSE);
X		       break;
X
X	    case 'p' : print_msg();	
X		       if (screen_mangled) {
X		         strcpy(error_line, "queued for printing");
X		         goto show_prompt_again;
X		       }
X		       else {
X			 ClearLine(LINES-1);
X		         PutLine0(LINES-1, 0, 
X			    "Queued for printing.  Command ? ");
X			 CleartoEOLN();
X		       }
X		       break;
X
X	    case 'r' : clear_bottom_of_screen();
X		       PutLine0(LINES-3,0,"Command: reply to message");
X		       (void) reply();
X		       break;
X
X	    case 's' : clear_bottom_of_screen();
X		       PutLine0(LINES-3,0,"Command: save message");
X		       (void) save(&intbuf, TRUE);
X		       if (resolve_mode) goto move_to_next_message;
X		       break;
X
X	    case 't' : tag_message();	
X		       if (screen_mangled) {
X		         strcpy(error_line, "message tagged");
X		         goto show_prompt_again;
X		       }
X		       else {
X			 ClearLine(LINES-1);
X		         PutLine0(LINES-1, 0, 
X			    "Message tagged.  Command ? ");
X	   	         CleartoEOLN();
X	 	       }
X		       break;
X
X	    case 'u' : undelete_msg(FALSE); /* undelete it, silently */
X		       if (! resolve_mode) {
X		         if (screen_mangled) 
X		           strcpy(error_line, "message undeleted");
X		         else {
X		           ClearLine(LINES-1);
X		           PutLine0(LINES-1, 0, 
X			      "Message undeleted.  Command ? ");
X			   CleartoEOLN();
X		         }
X		       } 
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 move_to_next_message;
X*******************************************************************************/
X			 if (current == message_count)
X			   return(0);	/* we're at the last message! */
X			 else
X		           return(show_msg(++current));	 /* move forward 1 */
X		       }
X		       break;
X
X	    case 'x' : fflush(stdout); leave();
X
X	    case 'q' :
X	    case 'i' : 
X	    case ' ' :
X	    case '\n':
X	    case '\r': (void) get_page(current);
X		       clear_error();		/* zero out pending msg   */
X		       if (cursor_control)
X			 transmit_functions(ON);
X		       return(0);		/* avoid <return> looping */
X
X	    case ctrl('L') : screen_mangled = 0;
X			     return(show_msg(current));
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                             if (current > 0) {
X                               screen_mangled = 0;
X                               return(show_msg(--current));
X                             }
X                             else 
X                               return(0);
X              
X                            }
X                            else if (ch == down[key_offset]) {
X                             if (current < message_count) {
X                               screen_mangled = 0;
X                               return(show_msg(++current));
X                             }
X                             else 
X                               return(0);
X  
X                            }
X                            else
X                            {
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                            return(0);
X                           }
X                           break;
X  
X	    default  : putchar((char) 007);	/* BEEP! */
X		       fflush(stdout);
X	  }
X
X	  if (screen_mangled) {
X	     clear_bottom_of_screen();
Xshow_prompt_again:
X	     PutLine0(LINES-3, 0, "Request (return to I)ndex page) ? ");
X/**
X	     if (error_line[0] != '\0')
X	       error(error_line);
X**/
X	  }
X
X	  command = GetPrompt();
X	  command = tolower(command);
X	}
X}
X
Xclear_bottom_of_screen()
X{
X	/** clear the last 4 lines of the screen... **/
X
X	screen_mangled = 1;
X
X	MoveCursor(LINES-4, 0);
X	CleartoEOS();
X	PutLine0(LINES-4, 0, 
X"--------------------------------------------------------------------------\n");
X
X	show_last_error();
X}
SHAR_EOF
chmod 0444 src/showmsg_c.c || echo "restore of src/showmsg_c.c fails"
echo "x - extracting src/signals.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/signals.c &&
X
Xstatic char rcsid[] = "@(#)$Id: signals.c,v 2.1 88/07/21 09:59:39 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:	signals.c,v $
X * Revision 2.1  88/07/21  09:59:39  edc
X * checked in with -k by syd at 88.09.15.20.29.49.
X * 
X * Revision 2.1  88/07/21  09:59:39  edc
X * Final hacks and cleanup to the 2.1 alpha test release.
X * 
X * Revision 2.0  88/06/27  17:25:39  edc
X * The original 2.0 gamma sources as leaked from HP
X * 
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
Xextern int pipe_abort;		/* set to TRUE if receive SIGPIPE */
X
Xquit_signal()
X{
X	dprint(1, (debugfile, "\n\n** Received SIGQUIT **\n\n\n\n"));
X	leave();
X}
X
Xhup_signal()
X{
X	dprint(1, (debugfile, "\n\n** Received SIGHUP **\n\n\n\n"));
X	leave();
X}
X
Xterm_signal() 
X{
X	dprint(1, (debugfile, "\n\n** Received SIGTERM **\n\n\n\n"));
X	leave();
X}
X
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
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
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
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
Xalarm_signal()
X{	
X	/** silently process alarm signal for timeouts... **/
X
X	int alarm_signal();
X
X	signal(SIGALRM, alarm_signal);
X}
X
Xpipe_signal()
X{
X	/** silently process pipe signal... **/
X
X	int pipe_signal();
X
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
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	  was_in_raw_state = RawState();
X	}
X
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
Xsig_return_from_user_stop()
X{
X	/** this is called when returning from a ^Z stop **/
X
X	int sig_user_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#endif
SHAR_EOF
chmod 0444 src/signals.c || echo "restore of src/signals.c fails"
echo "x - extracting src/softkeys.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/softkeys.c &&
X
Xstatic char rcsid[] = "@(#)$Id: softkeys.c,v 2.1 88/07/21 09:59:40 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:	softkeys.c,v $
X * Revision 2.1  88/07/21  09:59:40  edc
X * checked in with -k by syd at 88.09.15.20.29.51.
X * 
X * Revision 2.1  88/07/21  09:59:40  edc
X * Final hacks and cleanup to the 2.1 alpha test release.
X * 
X * Revision 2.0  88/06/27  17:25:40  edc
X * The original 2.0 gamma sources as leaked from HP
X * 
X *
X *
X ******************************************************************************/
X
X
X#include <stdio.h>
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, "  Read     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  Mailbox", "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	  clear_key(f5);
X	  clear_key(f6);
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
chmod 0444 src/softkeys.c || echo "restore of src/softkeys.c fails"
echo "x - extracting src/sort.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/sort.c &&
X
Xstatic char rcsid[] = "@(#)$Id: sort.c,v 2.1 88/09/15 20:29:53 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:	sort.c,v $
X * Revision 2.1  88/09/15  20:29:53  syd
X * checked in with -k by syd at 88.09.15.20.29.53.
X * 
X * 88/09/01 Rob Bernardo <gatech!pbhyf.PacBell.COM!rob>
X *	fix mismatch between the displayed sort criteria and the
X *	actual criteria used and listed
X *
X * Revision 2.1  88/07/21  09:59:41  edc
X * Final hacks and cleanup to the 2.1 alpha test release.
X * 
X * Revision 2.0  88/06/27  17:25:41  edc
X * The original 2.0 gamma sources as leaked from HP
X * 
X *
X *
X ******************************************************************************/
X
X/** Sort mailbox 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 mailbox by %s **\n\n", 
X		sort_name(FULL)));
X
X	if (entries > 0)
X	  last_index = header_table[current-1].index_number;
X
X	if (entries > 30 && visible)  
X	  error1("sorting messages by %s", sort_name(FULL));
X	
X	qsort(header_table, (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(first, second)
Xstruct header_rec *first, *second;
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)
X	    Sender uses the truncated from line, same as "build headers",
X	    and size and subject are trivially obvious!!
X	    (actually, subject has been modified to ignore any leading
X	    patterns [rR][eE]*:[ \t] so that replies to messages are
X	    sorted with the message (though a reply will always sort to
X	    be 'greater' than the basenote)
X	 **/
X
X	char from1[SLEN], from2[SLEN];	/* sorting buffers... */
X	int  sign = 1;
X	
X	if (sortby < 0)
X	  sign = -1;
X
X	switch (abs(sortby)) {
X
X	  case SENT_DATE : return( sign*compare_dates(first, second));
X
X	  case RECEIVED_DATE: return( sign*
X			              compare_parsed_dates(first->received, 
X				           second->received));
X
X	  case SENDER    : tail_of(first->from, from1, TRUE);
X			   tail_of(second->from, from2, TRUE);
X	  		   return( sign*strcmp(from1, from2));
X
X	  case SIZE      : return( sign*(first->lines - second->lines));
X
X	  case MAILBOX_ORDER  : return( sign*
X				  (first->index_number - second->index_number));
X
X	  case SUBJECT   : /* need some extra work 'cause of STATIC buffers */
X	                   strcpy(from1, skip_re(shift_lower(first->subject)));
X			   return( sign*
X			      strcmp(from1, 
X				       skip_re(shift_lower(second->subject))));
X
X	  case STATUS    : return( sign*(first->status - second->status));
X	}
X
X	return(0);	/* never get this! */
X}
X
Xchar *sort_name(type)
Xint type;
X{
X	/** return the name of the current sort option...
X	    type can be "FULL", "SHORT" or "PAD"
X	**/
X	int pad, abr;
X	
X	pad = (type == PAD);
X	abr = (type == SHORT);
X
X	if (sortby < 0) {
X	  switch (- sortby) {
X	    case SENT_DATE    : return( 
X		              pad?     "Reverse Date Mail Sent  " : 
X			      abr?     "Reverse-Sent" :
X				       "Reverse Date Mail Sent");
X	    case RECEIVED_DATE: return(
X			      abr?     "Reverse-Received":
X			      "Reverse Date Mail Rec'vd" );
X
X	    case MAILBOX_ORDER: return(
X			      pad?     "Reverse Mailbox Order   " :
X			      abr?     "Reverse-Mailbox":
X			               "Reverse Mailbox Order");
X
X	    case SENDER       : return(
X			      pad?     "Reverse Message Sender  " : 
X			      abr?     "Reverse-From":
X				       "Reverse Message Sender");
X	    case SIZE         : return(
X			      abr?     "Reverse-Lines" : 
X				       "Reverse Lines in Message");
X	    case SUBJECT      : return(
X			      pad?     "Reverse Message Subject " : 
X			      abr?     "Reverse-Subject" : 
X				       "Reverse Message Subject");
X	    case STATUS	      : return(
X			      pad?     "Reverse Message Status  " :
X			      abr?     "Reverse-Status":
X			               "Reverse Message Status");
X	  }
X	}
X	else {
X	  switch (sortby) {
X	    case SENT_DATE    : return( 
X		                pad?   "Date Mail Sent          " : 
X		                abr?   "Sent" : 
X				       "Date Mail Sent");
X	    case RECEIVED_DATE: return(
X	                        pad?   "Date Mail Rec'vd        " :
X	                        abr?   "Received" :
X				       "Date Mail Rec'vd");
X	    case MAILBOX_ORDER: return(
X	                        pad?   "Mailbox Order           " :
X	                        abr?   "Mailbox" :
X	                               "Mailbox Order");
X	    case SENDER       : return(
X			        pad?   "Message Sender          " : 
X			        abr?   "From" : 
X				       "Message Sender");
X	    case SIZE         : return(
X	    			pad?   "Lines in Message        " :
X	    			abr?   "Lines" :
X	    			       "Lines in Message");
X	    case SUBJECT      : return(
X			        pad?   "Message Subject         " : 
X			        abr?   "Subject" : 
X				       "Message Subject");
X	    case STATUS	      : return(
X			        pad?   "Message Status          " :
X			        abr?   "Status" :
X			               "Message Status");
X	  }
X	}
X
X	return("*UNKNOWN-SORT-PARAMETER*");
X}
X
Xfind_old_current(index)
Xint index;
X{
X	/** Set current to the message that has "index" as it's 
X	    index number.  This is to track the current message
X	    when we resync... **/
X
X	register int i;
X
X	dprint(4, (debugfile, "find-old-current(%d)\n", index));
X
X	for (i = 0; i < message_count; i++)
X	  if (header_table[i].index_number == index) {
X	    current = i+1;
X	    dprint(4, (debugfile, "\tset current to %d!\n", current));
X	    return;
X	  }
X
X	dprint(4, (debugfile, 
X		"\tcouldn't find current index.  Current left as %d\n",
X		current));
X	return;		/* can't be found.  Leave it alone, then */
X}
X
Xchar *skip_re(string)
Xchar *string;
X{
X	/** this routine returns the given string minus any sort of
SHAR_EOF
echo "End of part 18"
echo "File src/sort.c is continued in part 19"
echo "19" > 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