[comp.sources.unix] v22i081: ELM mail syste, release 2.3, Part22/26

rsalz@bbn.com (Rich Salz) (06/06/90)

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

---- Cut Here and unpack ----
#!/bin/sh
# this is part 22 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file src/showmsg.c continued
#
CurArch=22
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/showmsg.c"
sed 's/^X//' << 'SHAR_EOF' >> src/showmsg.c
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#ifdef MMDF
X	if (strcmp(buffer, MSG_SEPERATOR) == 0)
X	  strcpy(buffer," ");
X#endif /* MMDF */
X	if (builtin) {
X	  strcat(buffer, "\n");
X	  return(display_line(buffer));
X	}
X	errno = 0;
X	fprintf(pipe_wr_fp, "%s\n", buffer);
X	if (errno != 0)
X	  dprint(1, (debugfile, "\terror %s hit!\n", error_name(errno)));
X	return(0);
X}
SHAR_EOF
echo "File src/showmsg.c is complete"
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 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
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 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
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 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
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 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)
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	struct header_rec *first, *second;
X	int ret;
X	long diff;
X	
X	first = *p1;
X	second = *p2;
X
X	switch (abs(sortby)) {
X	case SENT_DATE:
X 		diff = first->time_sent - second->time_sent;
X 		if ( diff < 0 )	ret = -1;
X 		else if ( diff > 0 ) ret = 1;
X 		else ret = 0;
X  		break;
X
X	case RECEIVED_DATE:
X		ret = compare_parsed_dates(first->received, second->received);
X		break;
X
X	case SENDER:
X		tail_of(first->from, from1, first->to);
X		tail_of(second->from, from2, second->to);
X		ret = strcmp(from1, from2);
X		break;
X
X	case SIZE:
X		ret = (first->lines - second->lines);
X		break;
X
X	case MAILBOX_ORDER:
X		ret = (first->index_number - second->index_number);
X		break;
X
X	case SUBJECT:
X		/* need some extra work 'cause of STATIC buffers */
X		strcpy(from1, skip_re(shift_lower(first->subject)));
X		ret = strcmp(from1, skip_re(shift_lower(second->subject)));
X		break;
X
X	case STATUS:
X		ret = (first->status - second->status);
X		break;
X
X	default:
X		/* never get this! */
X		ret = 0;
X		break;
X	}
X
X	if (sortby < 0)
X	  ret = -ret;
X
X	return ret;
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(iindex)
Xint iindex;
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", iindex));
X
X	for (i = 0; i < message_count; i++)
X	  if (headers[i]->index_number == iindex) {
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
X	    "re:" prefix.  specifically, it looks for, and will
X	    remove, any of the pattern:
X
X		( [Rr][Ee][^:]:[ ] ) *
X
X	    If it doesn't find a ':' in the line it will return it
X	    intact, just in case!
X	**/
X
X	static char buffer[SLEN];
X	register int i=0;
X
X	while (whitespace(string[i])) i++;
X
X	do {
X	  if (string[i] == '\0') return( (char *) string);	/* forget it */
X
X	  if (string[i] != 'r' || string[i+1] != 'e') 
X	    return( (char *) string);				/*   ditto   */
X
X	  i += 2;	/* skip the "re" */
X
X	  while (string[i] != ':') 
X	    if (string[i] == '\0')
X	      return( (char *) string);		      /* no colon in string! */
X	    else
X	      i++;
X
X	  /* now we've gotten to the colon, skip to the next non-whitespace  */
X
X	  i++;	/* past the colon */
X
X	  while (whitespace(string[i])) i++;
X
X	} while (string[i] == 'r' && string[i+1] == 'e');
X 
X	/* and now copy it into the buffer and sent it along... */
X
X	strcpy(buffer, (char *) string + i);
X
X	return( (char *) buffer);
X}
SHAR_EOF
chmod 0444 src/sort.c || echo "restore of src/sort.c fails"
echo "x - extracting src/string2.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/string2.c &&
X
Xstatic char rcsid[] = "@(#)$Id: string2.c,v 4.1 90/04/28 22:44:14 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:	string2.c,v $
X * Revision 4.1  90/04/28  22:44:14  syd
X * checkin of Elm 2.3 as of Release PL0
X * 
X *
X ******************************************************************************/
X
X/** This file contains string functions that are shared throughout the
X    various ELM utilities...
X
X**/
X
X#include "headers.h"
X#include <ctype.h>
X
X#ifdef BSD
X#undef tolower
X#undef toupper
X#endif
X
Xchar *shift_lower(string)
Xchar *string;
X{
X	/** return 'string' shifted to lower case.  Do NOT touch the
X	    actual string handed to us! **/
X
X	static char buffer[VERY_LONG_STRING];
X	register char *bufptr = buffer;
X
X	for (; *string; string++, bufptr++)
X	  if (isupper(*string))
X	    *bufptr = tolower(*string);
X	  else
X	    *bufptr = *string;
X	
X	*bufptr = 0;
X	
X	return( (char *) buffer);
X}
X
X
Xint
Xin_list(list, target)
Xchar *list, *target;
X
X{
X	/* Returns TRUE iff target is an item in the list - case ignored.
X	 * If target is simple (an atom of an address) match must be exact.
X	 * If target is complex (contains a special character that separates
X	 * address atoms), the target need only match a whole number of atoms
X	 * at the right end of an item in the list. E.g.
X	 * target:	item:			match:
X	 * joe		joe			yes
X	 * joe		jojoe			no (wrong logname)
X	 * joe		machine!joe		no (similar logname on a perhaps
X	 *					   different machine - to
X	 *					   test this sort of item the 
X	 *					   passed target must include
X	 *					   proper machine name, is
X	 *					   in next two examples)
X	 * machine!joe	diffmachine!joe		no  "
X	 * machine!joe	diffmachine!machine!joe	yes
X	 * joe@machine	jojoe@machine		no  (wrong logname)
X	 * joe@machine	diffmachine!joe@machine	yes
X	 */
X
X	register char	*rest_of_list,
X			*next_item,
X			ch;
X	int		offset;
X	char		*shift_lower(),
X				lower_list[VERY_LONG_STRING],
X				lower_target[SLEN];
X
X	rest_of_list = strcpy(lower_list, shift_lower(list));
X	strcpy(lower_target, shift_lower(target));
X	while((next_item = strtok(rest_of_list, ", \t\n")) != NULL) {
X	    /* see if target matches the whole item */
X	    if(strcmp(next_item, lower_target) == 0)
X		return(TRUE);
X
X	    if(strpbrk(lower_target,"!@%:") != NULL) {
X
X	      /* Target is complex */
X
X	      if((offset = strlen(next_item) - strlen(lower_target)) > 0) {
X
X		/* compare target against right end of next item */
X		if(strcmp(&next_item[offset], lower_target) == 0) {
X
X		  /* make sure we are comparing whole atoms */
X		  ch=next_item[offset-1];
X		  if(ch == '!' || ch == '@' || ch == '%' || ch == ':')
X		    return(TRUE);
X		}
X	      }
X	    }
X	    rest_of_list = NULL;
X	}
X	return(FALSE);
X}
X	
X
Xint 
Xin_string(buffer, pattern)
Xchar *buffer, *pattern;
X{
X	/** Returns TRUE iff pattern occurs IN IT'S ENTIRETY in buffer. **/ 
X
X	register int i = 0, j = 0;
X	
X	while (buffer[i] != '\0') {
X	  while (buffer[i++] == pattern[j++]) 
X	    if (pattern[j] == '\0') 
X	      return(TRUE);
X	  i = i - j + 1;
X	  j = 0;
X	}
X	return(FALSE);
X}
X
Xint
Xchloc(string, ch)
Xchar *string, ch;
X{
X	/** returns the index of ch in string, or -1 if not in string **/
X	register int i, len;
X
X	for (i=0, len = strlen(string); i<len; i++)
X	  if (string[i] == ch) return(i);
X	return(-1);
X}
X
Xint
Xoccurances_of(ch, string)
Xchar ch, *string;
X{
X	/** returns the number of occurances of 'ch' in string 'string' **/
X
X	register int count = 0;
X
X	for (; *string; string++)
X	  if (*string == ch) count++;
X
X	return(count);
X}
X
Xremove_possible_trailing_spaces(string)
Xchar *string;
X{
X	/** an incredibly simple routine that will read backwards through
X	    a string and remove all trailing whitespace.
X	**/
X
X	register int i;
X
X	for ( i = strlen(string); --i >= 0 && whitespace(string[i]); )
X		/** spin backwards, semicolon intented **/ ;
X
X	string[i+1] = '\0';	/* note that even in the worst case when there
X				   are no trailing spaces at all, we'll simply
X				   end up replacing the existing '\0' with
X				   another one!  No worries, as M.G. would say
X				*/
X}
SHAR_EOF
chmod 0444 src/string2.c || echo "restore of src/string2.c fails"
echo "x - extracting src/strings.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/strings.c &&
X
Xstatic char rcsid[] = "@(#)$Id: strings.c,v 4.1 90/04/28 22:44:16 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:	strings.c,v $
X * Revision 4.1  90/04/28  22:44:16  syd
X * checkin of Elm 2.3 as of Release PL0
X * 
X *
X ******************************************************************************/
X
X/** This file contains all the string oriented functions for the
X    ELM Mailer, and lots of other generally useful string functions! 
X
X    For BSD systems, this file also includes the function "tolower"
X    to translate the given character from upper case to lower case.
X
X**/
X
X#include "headers.h"
X#include <ctype.h>
X
X#ifdef BSD
X#undef tolower
X#undef toupper
X#endif
X
X/** forward declarations **/
X
Xchar *format_long(), *strip_commas(), *tail_of_string(),
X     *get_token(), *strip_parens(), *argv_zero(), *strcpy(), *strncpy();
X
Xchar *index();
X
X
Xcopy_sans_escape(dest, source, len)
Xchar *dest, *source;
Xint  len;
X{
X	/** this performs the same function that strncpy() does, but
X	    also will translate any escape character to a printable
X	    format (e.g. ^(char value + 32))
X	**/
X
X	register int i = 0, j = 0;
X
X	while (i < len && source[i] != '\0') {
X	  if (iscntrl(source[i]) && source[i] != '\t') {
X	     dest[j++] = '^';
X	     dest[j++] = source[i++] + 'A' - 1;
X	  }
X	  else
X	    dest[j++] = source[i++];
X	}
X
X	dest[j] = '\0';
X}
X
X/**
X    This routine will return true if the "addr" contains the "user" subject
X    to the following contstraints:  (1) either the "user" is at the front
X    of "addr" or it is preceded by an appropriate meta-char, and (2)
X    either the "user" is at the end of "addr" or it is suceeded by an
X    appropriate meta-char.
X**/
Xint addr_matches_user(addr,user)
Xregister char *addr, *user;
X{
X	int len = strlen(user);
X	static char c_before[] = "!:%";	/* these can appear before a username */
X	static char c_after[] = ":%@";	/* these can appear after a username  */
X
X	do {
X	  if ( strncmp(addr,user,len) == 0 ) {
X	    if ( addr[len] == '\0' || index(c_after,addr[len]) != NULL )
X	      return TRUE;
X	  }
X	} while ( (addr=strpbrk(addr,c_before)) != NULL && *++addr != '\0' ) ;
X	return FALSE;
X}
X
Xint
Xtail_of(from, buffer, to)
Xchar *from, *buffer, *to;
X{
X	/** Return last two words of 'from'.  This is to allow
X	    painless display of long return addresses as simply the
X	    machine!username. 
X	    Or if the first word of the 'from' address is username or
X	    full_username and 'to' is not NULL, then use the 'to' line
X	    instead of the 'from' line.
X	    If the 'to' line is used, return 1, else return 0.
X
X	    Also modified to know about X.400 addresses (sigh) and
X	    that when we ask for the tail of an address similar to
X	    a%b@c we want to get back a@b ...
X	**/
X
X	/** Note: '!' delimits Usenet nodes, '@' delimits ARPA nodes,
X	          ':' delimits CSNet & Bitnet nodes, '%' delimits multi-
X		  stage ARPA hops, and '/' delimits X.400 addresses...
X	          (it is fortunate that the ASCII character set only has
X	   	  so many metacharacters, as I think we're probably using
X		  them all!!) **/
X
X	register int loc, i = 0, cnt = 0, using_to = 0;
X	
X#ifndef INTERNET
X	
X	/** let's see if we have an address appropriate for hacking: 
X	    what this actually does is remove the spuriously added
X	    local bogus Internet header if we have one and the message
X	    has some sort of UUCP component too...
X	**/
X
X	sprintf(buffer, "@%s", hostfullname); 
X	if (chloc(from,'!') != -1 && in_string(from, buffer))
X	   from[strlen(from)-strlen(buffer)] = '\0';
X
X#endif
X
X	/**
X	    Produce a simplified version of the from into buffer.  If the
X	    from is just "username" or "Full Username" it will be preserved.
X	    If it is an address, the rightmost "stuff!stuff", "stuff@stuff",
X	    or "stuff:stuff" will be used.
X	**/
X	for (loc = strlen(from)-1; loc >= 0 && cnt < 2; loc--) {
X	  if (from[loc] == BANG || from[loc] == AT_SIGN ||
X	      from[loc] == COLON) cnt++;
X	  if (cnt < 2) buffer[i++] = from[loc];
X	}
X	buffer[i] = '\0';
X	reverse(buffer);
X
X#ifdef MMDF
X	if (strlen(buffer) == 0) {
X	  if(to && *to != '\0') {
X	    tail_of(to, buffer, (char *)0);
X	    using_to = 1;
X	  } else
X	    strcpy(buffer, full_username);
X        }
X#endif /* MMDF */
X
X	if ( strcmp(buffer,full_username) == 0 ||
X	  addr_matches_user(buffer,username) ) {
X
X	  /* This message is from the user, so use the "to" header instead
X	   * if possible, to be more informative. Otherwise be nice and
X	   * use full_username rather than the bare username even if
X	   * we've only matched on the bare username.
X	   */
X
X	  if(to && *to != '\0') {
X	    tail_of(to, buffer, (char *)0);
X	    using_to = 1;
X	  } else
X	    strcpy(buffer, full_username);
X
X	} else {					/* user%host@host? */
X
X	  /** The logic here is that we're going to use 'loc' as a handy
X	      flag to indicate if we've hit a '%' or not.  If we have,
X	      we'll rewrite it as an '@' sign and then when we hit the
X	      REAL at sign (we must have one) we'll simply replace it
X	      with a NULL character, thereby ending the string there.
X	  **/
X
X	  loc = 0;
X
X	  for (i=0; buffer[i] != '\0'; i++)
X	    if (buffer[i] == '%') {
X	      buffer[i] = AT_SIGN;
X	      loc++;
X	    }
X	    else if (buffer[i] == AT_SIGN && loc)
X	      buffer[i] = '\0';
X	}
X	return(using_to);
X
X}
X
Xchar *format_long(inbuff, init_len)
Xchar *inbuff;
Xint   init_len;
X{
X	/** Return buffer with \n\t sequences added at each point where it 
X	    would be more than 80 chars long.  It only allows the breaks at 
X	    legal points (ie commas followed by white spaces).  init-len is 
X	    the characters already on the first line...  Changed so that if 
X     head of "elm", it'll 
X            include "\r\n\t" instead.
X	    Changed to use ',' as a separator and to REPLACE it after it's
X	    found in the output stream...
X	**/
X
X	static char ret_buffer[VERY_LONG_STRING];
X	register int iindex = 0, current_length = 0, depth=15, i, len;
X	char     buffer[VERY_LONG_STRING];
X	char     *word, *bufptr;
X
X	strcpy(buffer, inbuff);
X
X	bufptr = (char *) buffer;
X
X	current_length = init_len + 2;	/* for luck */
X
X	while ((word = get_token(bufptr,",", depth)) != NULL) {
X
X	    /* first, decide what sort of separator we need, if any... */
X
X	  if (strlen(word) + current_length > 80) {
X	    if (iindex > 0) {
X	      ret_buffer[iindex++] = ',';	/* close 'er up, doctor! */
X	      ret_buffer[iindex++] = '\n';
X	      ret_buffer[iindex++] = '\t';
X	    }
X	    
X	    /* now add this pup! */
X
X	    for (i=(word[0] == ' '? 1:0), len = strlen(word); i<len; i++)
X	      ret_buffer[iindex++] = word[i];
X	    current_length = len + 8;	/* 8 = TAB */
X	  }
X
X	  else {	/* just add this address to the list.. */
X
X	    if (iindex > 0) {
X	      ret_buffer[iindex++] = ',';	/* comma added! */
X	      ret_buffer[iindex++] = ' ';
X	      current_length += 2;
X	    }
X	    for (i=(word[0] == ' '? 1:0), len = strlen(word); i<len; i++)
X	      ret_buffer[iindex++] = word[i];
X	    current_length += len;
X	  }
X	
X	  bufptr = NULL;
X	}
X	
X	ret_buffer[iindex] = '\0';
X
X	return( (char *) ret_buffer);
X}
X
Xchar *strip_commas(string)
Xchar *string;
X{
X	/** return string with all commas changed to spaces.  This IS
X	    destructive and will permanently change the input string.. **/
X
X	register char *strptr = string;
X
X	for (; *strptr; strptr++)
X	  if (*strptr == COMMA)
X	    *strptr = SPACE;
X
X	return( (char *) string);
X}
X
Xchar *strip_parens(string)
Xchar *string;
X{
X	/** Return string with all parenthesized information removed.
X	    This is a non-destructive algorithm... **/
X
X	static char  buffer[VERY_LONG_STRING];
X	register int depth = 0, buffer_index = 0;
X
X	for (; *string; string++) {
X	  if (*string == '(')
X	    depth++;
X	  else if (*string == ')') 
X	    depth--;
X	  else if (depth == 0)
X	    buffer[buffer_index++] = *string;
X	}
X	
X	buffer[buffer_index] = '\0';
X
X	return( (char *) buffer);
X}
X
Xmove_left(string, chars)
Xchar string[];
Xint  chars;
X{
X	/** moves string chars characters to the left DESTRUCTIVELY **/
X
X	register int i;
X
X	/*  chars--; /* index starting at zero! */
X
X	for (i=chars; string[i] != '\0' && string[i] != '\n'; i++)
X	  string[i-chars] = string[i];
X
X	string[i-chars] = '\0';
X}
X
Xremove_first_word(string)
Xchar *string;
X{	/** removes first word of string, ie up to first non-white space
X	    following a white space! **/
X
X	register int loc;
X
X	for (loc = 0; string[loc] != ' ' && string[loc] != '\0'; loc++) 
X	    ;
X
X	while (string[loc] == ' ' || string[loc] == '\t')
X	  loc++;
X	
X	move_left(string, loc);
X}
X
Xsplit_word(buffer, first, rest)
Xchar *buffer, *first, *rest;
X{
X	/** Rip the buffer into first word and rest of word, translating it
X	    all to lower case as we go along..
X	**/
X
X	/** skip leading white space, just in case.. **/
X
X	while(whitespace(*buffer)) buffer++;
X
X	/** now copy into 'first' until we hit white space or EOLN **/
X
X	for (; *buffer && ! whitespace(*buffer); buffer++, first++)
X	  if (islower(*buffer))
X	    *first = tolower(*buffer);
X	  else
X	    *first = *buffer;
X
X	*first = '\0';
X	
X	while (whitespace(*buffer)) buffer++;
X
X	for (; *buffer; buffer++, rest++)
X	  if (islower(*buffer))
X	    *rest = tolower(*buffer);
X	  else
X	    *rest = *buffer;
X
X	*rest = '\0';
X
X	return;
X}
X
Xchar *tail_of_string(string, maxchars)
Xchar *string;
Xint  maxchars;
X{
X	/** Return a string that is the last 'maxchars' characters of the
X	    given string.  This is only used if the first word of the string
X	    is longer than maxchars, else it will return what is given to
X	    it... 
X	**/
X
X	static char buffer[SLEN];
X	register int iindex, i, len;
X
X	for (iindex=0, len = strlen(string);! whitespace(string[iindex]) && iindex < len; 
X	     iindex++)
X	  ;
X
X	if (iindex < maxchars) {
X	  strncpy(buffer, string, maxchars-2);	/* word too short */
X	  buffer[maxchars-2] = '.';
X	  buffer[maxchars-1] = '.';
X	  buffer[maxchars]   = '.';
X	  buffer[maxchars+1] = '\0';
X	} 
X	else {
X	  i = maxchars;
X	  buffer[i--] = '\0';
X	  while (i > 1) 
X	    buffer[i--] = string[iindex--];
X	  buffer[2] = '.';
X	  buffer[1] = '.';
X	  buffer[0] = '.';
X	}
X
X	return( (char *) buffer);
X}
X
Xreverse(string)
Xchar *string;
X{
X	/** reverse string... pretty trivial routine, actually! **/
X
X	char buffer[SLEN];
X	register int i, j = 0;
X
X	for (i = strlen(string)-1; i >= 0; i--)
X	  buffer[j++] = string[i];
X
X	buffer[j] = '\0';
X
X	strcpy(string, buffer);
X}
X
Xint
Xget_word(buffer, start, word)
Xchar *buffer, *word;
Xint start;
X{
X	/**	return next word in buffer, starting at 'start'.
X		delimiter is space or end-of-line.  Returns the
X		location of the next word, or -1 if returning
X		the last word in the buffer.  -2 indicates empty
X		buffer!  **/
X
X	register int loc = 0;
X
X	while (buffer[start] == ' ' && buffer[start] != '\0')
X	  start++;
X
X	if (buffer[start] == '\0') return(-2);	 /* nothing IN buffer! */
X
X	while (buffer[start] != ' ' && buffer[start] != '\0')
X	  word[loc++] = buffer[start++];
X
X	word[loc] = '\0';
X	return(start);
X}
X
XCenterline(line, string)
Xint line;
Xchar *string;
X{
X	/** Output 'string' on the given line, centered. **/
X
X	register int length, col;
X
X	length = strlen(string);
X
X	if (length > COLUMNS)
X	  col = 0;
X	else
X	  col = (COLUMNS - length) / 2;
X
X	PutLine0(line, col, string);
X}
X
Xchar *argv_zero(string)
Xchar *string;
X{
X	/** given a string of the form "/something/name" return a
X	    string of the form "name"... **/
X
X	static char buffer[NLEN];
X	register int i, j=0;
X
X	for (i=strlen(string)-1; string[i] != '/'; i--)
X	  buffer[j++] = string[i];
X	buffer[j] = '\0';
X
X	reverse(buffer);
X
X	return( (char *) buffer);
X}
X
X#define MAX_RECURSION		20		/* up to 20 deep recursion */
X
Xchar *get_token(source, keys, depth)
Xchar *source, *keys;
Xint   depth;
X{
X	/** This function is similar to strtok() (see "opt_utils")
X	    but allows nesting of calls via pointers... 
X	**/
X
X	register int  last_ch;
X	static   char *buffers[MAX_RECURSION];
X	char     *return_value, *sourceptr;
X
X	if (depth > MAX_RECURSION) {
X	   error1("Get_token calls nested greater than %d deep!", 
X		  MAX_RECURSION);
X	   emergency_exit();
X	}
X
X	if (source != NULL)
X	  buffers[depth] = source;
X	
X	sourceptr = buffers[depth];
X	
X	if (*sourceptr == '\0') 
X	  return(NULL);		/* we hit end-of-string last time!? */
X
X	sourceptr += strspn(sourceptr, keys);	  /* skip the bad.. */
X	
X	if (*sourceptr == '\0') {
X	  buffers[depth] = sourceptr;
X	  return(NULL);			/* we've hit end-of-string   */
X	}
X
X	last_ch = strcspn(sourceptr, keys);   /* end of good stuff   */
X
X	return_value = sourceptr;	      /* and get the ret     */
X
X	sourceptr += last_ch;		      /* ...value            */
X
X	if (*sourceptr != '\0')		/** don't forget if we're at end! **/
X	  sourceptr++;			      
X	
X	return_value[last_ch] = '\0';	      /* ..ending right      */
X
X	buffers[depth] = sourceptr;	      /* save this, mate!    */
X
X	return((char *) return_value);	     /* and we're outta here! */
X}
X
X
Xquote_args(out_string,in_string)
Xregister char *out_string, *in_string;
X{
X	/** Copy from "in_string" to "out_string", collapsing multiple
X	    white space and quoting each word.  Returns a pointer to
X	    the resulting word.
X	**/
X
X	int empty_string = TRUE;
X
X	while ( *in_string != '\0' ) {
X
X	    /**	If this is a space then advance to the start of the next word.
X		Otherwise, copy through the word surrounded by quotes.
X	    **/
X
X	    if ( isspace(*in_string) ) {
X		while ( isspace(*in_string) )
X			++in_string;
X	    } else {
X		*out_string++ = '"';
X		while ( *in_string != '\0' && !isspace(*in_string) )
X			*out_string++ = *in_string++;
X		*out_string++ = '"';
X		*out_string++ = ' ';
X		empty_string = FALSE;
X	    }
X
X    }
X
X    if ( !empty_string )
X	--out_string;
X    *out_string = '\0';
X}
X
SHAR_EOF
chmod 0444 src/strings.c || echo "restore of src/strings.c fails"
echo "x - extracting src/syscall.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/syscall.c &&
X
Xstatic char rcsid[] = "@(#)$Id: syscall.c,v 4.1 90/04/28 22:44:18 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
X *
X * 			Copyright (c) 1986, 1987 Dave Taylor
X * 			Copyright (c) 1988, 1989, 1990 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X *	Syd Weinstein, Elm Coordinator
X *	elm@DSI.COM			dsinc!elm
X *
X *******************************************************************************
X * $Log:	syscall.c,v $
X * Revision 4.1  90/04/28  22:44:18  syd
X * checkin of Elm 2.3 as of Release PL0
X * 
X *
X ******************************************************************************/
X
X/** These routines are used for user-level system calls, including the
X    '!' command and the '|' commands...
X
X**/
X
X#include "headers.h"
X
X#include <signal.h>
X
X#ifdef BSD
X#  include <sys/wait.h>
X#endif
X
Xchar *argv_zero();	
Xvoid  _exit();
X
X#ifdef ALLOW_SUBSHELL
X
Xint
Xsubshell()
X{
X	/** spawn a subshell with either the specified command
X	    returns non-zero if screen rewrite needed
X	**/
X
X	char command[SLEN];
SHAR_EOF
echo "End of part 22"
echo "File src/syscall.c is continued in part 23"
echo "23" > s2_seq_.tmp
exit 0

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