[comp.sources.unix] v18i100: Elm mail system, release 2.2, Part21/24

rsalz@uunet.uu.net (Rich Salz) (04/14/89)

Submitted-by: dsinc!syd@uunet.UU.NET (Syd Weinstein)
Posting-number: Volume 18, Issue 100
Archive-name: elm2.2/part21

#!/bin/sh
# this is part 21 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file src/showmsg_c.c continued
#
CurArch=21
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.c"
sed 's/^X//' << 'SHAR_EOF' >> src/showmsg_c.c
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' : fflush(stdout); leave();
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 = GetPrompt();	/* 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
echo "File src/showmsg_c.c is complete"
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.5 89/03/25 21:47:23 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.5 $   $State: Exp $
X *
X * 			Copyright (c) 1986, 1987 Dave Taylor
X * 			Copyright (c) 1988, 1989 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X *	Syd Weinstein, Elm Coordinator
X *	elm@dsinc.UUCP			dsinc!elm
X *
X *******************************************************************************
X * $Log:	signals.c,v $
X * Revision 2.5  89/03/25  21:47:23  syd
X * Initial 2.2 Release checkin
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
X#ifdef VOIDSIG
Xvoid alarm_signal()
X#else
Xint alarm_signal()
X#endif
X{	
X	/** silently process alarm signal for timeouts... **/
X
X#ifdef VOIDSIG
X	void alarm_signal();
X#else
X	int alarm_signal();
X#endif
X
X	signal(SIGALRM, alarm_signal);
X}
X
X#ifdef VOIDSIG
Xvoid pipe_signal()
X#else
Xint pipe_signal()
X#endif
X{
X	/** silently process pipe signal... **/
X
X#ifdef VOIDSIG
X	void pipe_signal();
X#else
X	int pipe_signal();
X#endif
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
X#ifdef VOIDSIG
Xvoid sig_user_stop()
X#else
Xint sig_user_stop()
X#endif
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
Xsig_return_from_user_stop()
X{
X	/** this is called when returning from a ^Z stop **/
X
X#ifdef VOIDSIG
X	void sig_user_stop();
X#else
X	int sig_user_stop();
X#endif
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.8 89/03/25 21:47:25 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.8 $   $State: Exp $
X *
X * 			Copyright (c) 1986, 1987 Dave Taylor
X * 			Copyright (c) 1988, 1989 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X *	Syd Weinstein, Elm Coordinator
X *	elm@dsinc.UUCP			dsinc!elm
X *
X *******************************************************************************
X * $Log:	softkeys.c,v $
X * Revision 2.8  89/03/25  21:47:25  syd
X * Initial 2.2 Release checkin
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 2.7 89/03/25 21:47:26 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.7 $   $State: Exp $
X *
X * 			Copyright (c) 1986, 1987 Dave Taylor
X * 			Copyright (c) 1988, 1989 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X *	Syd Weinstein, Elm Coordinator
X *	elm@dsinc.UUCP			dsinc!elm
X *
X *******************************************************************************
X * $Log:	sort.c,v $
X * Revision 2.7  89/03/25  21:47:26  syd
X * Initial 2.2 Release checkin
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	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	
X	first = *p1;
X	second = *p2;
X
X	switch (abs(sortby)) {
X	case SENT_DATE:
X		ret = compare_dates(first, second);
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 2.3 89/03/25 21:47:28 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.3 $   $State: Exp $
X *
X * 			Copyright (c) 1986, 1987 Dave Taylor
X * 			Copyright (c) 1988, 1989 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X *	Syd Weinstein, Elm Coordinator
X *	elm@dsinc.UUCP			dsinc!elm
X *
X *******************************************************************************
X * $Log:	string2.c,v $
X * Revision 2.3  89/03/25  21:47:28  syd
X * Initial 2.2 Release checkin
X * 
X *
X ******************************************************************************/
X
X/** This file contains string functions that are shared throughout the
X    various ELM utilities...
X
X**/
X
X#ifndef TRUE
X#define TRUE		1
X#define FALSE		0
X#endif
X
X#define whitespace(c)		(c == ' ' || c == '\t')
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;
X
X	for (i=0; i<strlen(string); 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, i;
X
X	for (i=0; i<strlen(string); i++)
X	  if (string[i] == 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)-1; whitespace(string[i]); i--)
X		/** spin backwards **/
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 2.10 89/03/25 21:47:29 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.10 $   $State: Exp $
X *
X * 			Copyright (c) 1986, 1987 Dave Taylor
X * 			Copyright (c) 1988, 1989 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X *	Syd Weinstein, Elm Coordinator
X *	elm@dsinc.UUCP			dsinc!elm
X *
X *******************************************************************************
X * $Log:	strings.c,v $
X * Revision 2.10  89/03/25  21:47:29  syd
X * Initial 2.2 Release checkin
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(), *shift_lower(),
X     *get_token(), *strip_parens(), *argv_zero(), *strcpy(), *strncpy();
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
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%s", hostname, hostdomain);
X	if (chloc(from,'!') != -1 && in_string(from, buffer))
X	   from[strlen(from)-strlen(buffer)] = '\0';
X
X#endif
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
X	buffer[i] = '\0';
X
X	reverse(buffer);
X
X	if ((strncmp(buffer, username, strlen(username)) == 0) ||
X	  (strncmp(buffer, full_username, strlen(full_username)) == 0)) {
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            this is called while mailing without the overhead 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;
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); i<strlen(word); i++)
X	      ret_buffer[iindex++] = word[i];
X	    current_length = strlen(word) + 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); i<strlen(word); i++)
X	      ret_buffer[iindex++] = word[i];
X	    current_length += strlen(word);
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 int i;
X
X	for (i=0; i < strlen(string); i++)
X	  if (string[i] == COMMA)
X	    string[i] = 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 i, depth = 0, buffer_index = 0;
X
X	for (i=0; i < strlen(string); i++) {
X	  if (string[i] == '(')
X	    depth++;
X	  else if (string[i] == ')') 
X	    depth--;
X	  else if (depth == 0)
X	    buffer[buffer_index++] = string[i];
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	register int i, j = 0;
X
X	/** skip leading white space, just in case.. **/
X
X	for (i=0; whitespace(buffer[i]); i++)	;
X
X	/** now copy into 'first' until we hit white space or EOLN **/
X
X	for (j=0; i < strlen(buffer) && ! whitespace(buffer[i]); ++i)
X	  first[j++] = tolower(buffer[i]);
X
X	first[j] = '\0';
X	
X	while (whitespace(buffer[i])) i++;
X
X	for (j=0; i < strlen(buffer); i++)
X	  rest[j++] = tolower(buffer[i]);
X
X	rest[j] = '\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;
X
X	for (iindex=0;! whitespace(string[iindex]) && iindex < strlen(string); 
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
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[SLEN];
X	register int i;
X
X	for (i=0; i < strlen(string); i++)
X	  if (isupper(string[i]))
X	    buffer[i] = tolower(string[i]);
X	  else
X	    buffer[i] = string[i];
X	
X	buffer[strlen(string)] = 0;
X	
X	return( (char *) buffer);
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}
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 2.14 89/03/25 21:47:31 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.14 $   $State: Exp $
X *
X * 			Copyright (c) 1986, 1987 Dave Taylor
X * 			Copyright (c) 1988, 1989 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X *	Syd Weinstein, Elm Coordinator
X *	elm@dsinc.UUCP			dsinc!elm
X *
X *******************************************************************************
X * $Log:	syscall.c,v $
X * Revision 2.14  89/03/25  21:47:31  syd
X * Initial 2.2 Release checkin
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
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];
X	int  ret;
X	int  old_raw;
X
X	PutLine0(LINES-3,COLUMNS-40,"(Use the shell name for a shell.)");
X	PutLine0(LINES-2,0,"Shell command: ");
X	command[0] = '\0';
X	(void) optionally_enter(command, LINES-2, 15, FALSE, FALSE);
X	if (strlen(command) == 0) {
X	  MoveCursor(LINES-2,0);	CleartoEOLN();
X	  return(0);
X	}
X
X	MoveCursor(LINES,0); 	CleartoEOLN();
X	if (( old_raw = RawState()) == ON)
X	  Raw(OFF);
X	if (cursor_control)  transmit_functions(OFF);
X	
X	ret = system_call(command, USER_SHELL, TRUE);
X
X	PutLine0(LINES, 0, "\n\nPress any key to return to ELM.");
X
X	if (old_raw == ON)
X	  Raw(ON);
X	(void) getchar();
X	if (cursor_control)  transmit_functions(ON);
X
X	if (ret != 0) error1("Return code was %d.", ret);
X	return(1);
X}
X
Xsystem_call(string, shell_type, allow_signals)
Xchar *string;
Xint   shell_type, allow_signals;
X{
X	/** execute 'string', setting uid to userid... **/
X	/** if shell-type is "SH" /bin/sh is used regardless of the 
X	    users shell setting.  Otherwise, "USER_SHELL" is sent.
X	    If allow_signals is TRUE, then allow the executed
X	    command handle interrupt and hangup in its
X	    own way. This is useful for executed programs with
X	    user interaction that handle those signals on their
X	    own terms. It is especially important for vi, so that
X	    a message being edited when a user connection is
X	    dropped is recovered by vi's expreserve program **/
X
X	int stat = 0, pid, w;
X#ifdef BSD
X	union wait status;
X#else
X	int status;
X#endif
X#ifdef VOIDSIG
X	register void (*istat)(), (*qstat)();
X# ifdef SIGTSTP
X#  ifndef BSD
X	register void (*oldstop)(), (*oldstart)();
X#  endif
X# endif
X#else
X	register int (*istat)(), (*qstat)();
X# ifdef SIGTSTP
X#  ifndef BSD
X	register int (*oldstop)(), (*oldstart)();
X#  endif
X# endif 
X#endif
X	
X	dprint(2, (debugfile,
X		"System Call: %s\n\t%s\n", shell_type == SH? "/bin/sh" : shell,
X		string));
X
X	if ((pid = vfork()) == 0) {
X	  setgid(groupid);	/* and group id		    */
X	  setuid(userid);	/* back to the normal user! */
X
X	  if(allow_signals) {
X	    /* program to exec should handle interrupt, accidental hangup, and stop signals */
X	    (void)signal(SIGHUP, SIG_DFL);
X	    (void)signal(SIGINT, SIG_DFL);
X#ifdef SIGTSTP
X# ifndef BSD
X	    (void)signal(SIGTSTP, SIG_DFL);
X	    (void)signal(SIGCONT, SIG_DFL);
X# endif
X#endif
X	  } else {
X	    /* program to exec should ignore interrupt, accidental hangup, and stop signals */
X	    (void)signal(SIGHUP, SIG_IGN);
X	    (void)signal(SIGINT, SIG_IGN);
X#ifdef SIGTSTP
X# ifndef BSD
X	    (void)signal(SIGTSTP, SIG_IGN);
X	    (void)signal(SIGCONT, SIG_IGN);
X# endif
X#endif
X	  }
X
X	  if (strlen(shell) > 0 && shell_type == USER_SHELL) {
X	    execl(shell, argv_zero(shell), "-c", string, (char *) 0);
X	  }
X	  else 
X	    execl("/bin/sh", "sh", "-c", string, (char *) 0);
X	  _exit(127);
X	}
X
X	istat = signal(SIGINT, SIG_IGN);
X	qstat = signal(SIGQUIT, SIG_IGN);
X#ifdef SIGTSTP
X# ifndef BSD
X	oldstop = signal(SIGTSTP, SIG_IGN);
X	oldstart = signal(SIGCONT, SIG_IGN);
X# endif
X#endif
X
X	while ((w = wait(&status)) != pid && w != -1)
X		;
X
X#ifdef BSD
X	if (status.w_retcode != 0) stat = status.w_retcode;
X#else
X	if (w == -1) stat = status;
X#endif
X	
X	(void)signal(SIGINT, istat);
X	(void)signal(SIGQUIT, qstat);
X#ifdef SIGTSTP
X# ifndef BSD
X	(void)signal(SIGTSTP, oldstop);
X	(void)signal(SIGCONT, oldstart);
X# endif
X#endif
X
X	return(stat);
X}
X
Xint
Xdo_pipe()
X{
X	/** pipe the current message or tagged messages to
X	    the specified sequence.. **/
X
X	char command[SLEN], buffer[SLEN], message_list[SLEN];
X	register int  ret, to_pipe = 0, i;
X	int	old_raw;
X
X	message_list[0] = '\0';	/* NULL string to start... */
X
X	for (i=0; i < message_count; i++)
X	  if (ison(headers[i]->status, TAGGED)) {
X	    sprintf(message_list,"%s %d", message_list, 
X		    headers[i]->index_number);
X	    to_pipe++;
X	  }
X
X	if (!to_pipe) {
X	  sprintf(message_list,"%d", headers[current-1]->index_number);
X	  to_pipe = 1;
X	}
X	sprintf(buffer, "Pipe message%s to: ", plural(to_pipe));
X        PutLine0(LINES-2,0,buffer);
X
X	command[0] = '\0';
X
X	(void) optionally_enter(command, LINES-2, strlen(buffer), FALSE, FALSE);
X	if (strlen(command) == 0) {
X	  MoveCursor(LINES-2,0);	CleartoEOLN();
X	  return(0);
X	}
X
X	MoveCursor(LINES,0); 	CleartoEOLN();
X	if (( old_raw = RawState()) == ON)
X	  Raw(OFF);
X
X	if (cursor_control)  transmit_functions(OFF);
X	
X	sprintf(buffer, "%s -f %s -h %s | %s",
X		readmsg,
X		(folder_type == NON_SPOOL ? cur_folder : cur_tempfolder),
X		message_list,
X		command);
X	
X	ret = system_call(buffer, USER_SHELL, TRUE);
X
X	PutLine0(LINES, 0, "\n\nPress any key to return to ELM.");
X	if (old_raw == ON)
X	   Raw(ON);
X	(void) getchar();
X	if (cursor_control)  transmit_functions(ON);
X
X	if (ret != 0) error1("Return code was %d.", ret);
X	return(1);
X}
X
Xprint_msg()
X{
X	/** Print current message or tagged messages using 'printout' 
X	    variable.  Error message iff printout not defined! **/
X
X	char buffer[SLEN], filename[SLEN], printbuffer[SLEN];
X	char message_list[SLEN];
X	register int  retcode, to_print = 0, i;
X
X	if (strlen(printout) == 0) {
X	  error("Don't know how to print - option \"printmail\" undefined!");
X	  return;
X	}
X	
X	message_list[0] = '\0';	/* reset to null... */
X
X	for (i=0; i < message_count; i++) 
X	  if (headers[i]->status & TAGGED) {
X	    sprintf(message_list, "%s %d", message_list, 
X		    headers[i]->index_number);
X	    to_print++;
X	  }
X
X	if (! to_print) {
X	  sprintf(message_list," %d", headers[current-1]->index_number);
X	  to_print = 1;
X	}
X
X	sprintf(filename,"%s%d", temp_print, getpid());
X
X	if (in_string(printout, "%s"))
X	  sprintf(printbuffer, printout, filename);
X	else
X	  sprintf(printbuffer, "%s %s", printout, filename);
X
X	sprintf(buffer,"(%s -p -f %s%s > %s; %s 2>&1) > /dev/null",
X		readmsg,
X		(folder_type == NON_SPOOL ? cur_folder : cur_tempfolder),
X		message_list, 
X		filename,
X		printbuffer);
X	
X	dprint(2, (debugfile, "Printing system call...\n"));
X
X  	Centerline(LINES, "Queuing...");
X
X	if ((retcode = system_call(buffer, SH, FALSE)) == 0) {
X	  sprintf(buffer, "Message%s queued up to print.", plural(to_print));
X	  Centerline(LINES, buffer);
X	}
X	else
X	  error1("Printout failed with return code %d.", retcode);
X
X	unlink(filename);	/* remove da temp file! */
X}
X
Xlist_folders(numlines, helpmsg)
Xunsigned numlines;
Xchar *helpmsg;
X{
X	/** list the folders in the users FOLDERHOME directory.  This is
X	    simply a call to "ls -C"
X	    Numlines is the number of lines to scroll afterwards. This is
X	    useful when a portion of the screen needs to be cleared for
X	    subsequent prompts, but you don't want to overwrite the
X	    list of folders.
X	    Helpmsg is what should be printed before the listing if not NULL.
X	**/
X
X	char buffer[SLEN];
X
X	Raw(OFF);
X	ClearScreen();
X	MoveCursor(LINES, 0);
X	if(helpmsg)
X	  printf(helpmsg);
X	sprintf(buffer, "cd %s;ls -C", folders);
X	printf("\n\rContents of your folder directory:\n\r\n\r");
X	system_call(buffer, SH, FALSE); 
X	while(numlines--)
X	    printf("\n\r");
X	Raw(ON);
X}
SHAR_EOF
chmod 0444 src/syscall.c || echo "restore of src/syscall.c fails"
echo "x - extracting src/utils.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/utils.c &&
X
Xstatic char rcsid[] = "@(#)$Id: utils.c,v 2.22 89/03/25 21:47:33 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.22 $   $State: Exp $
X *
X * 			Copyright (c) 1986, 1987 Dave Taylor
X * 			Copyright (c) 1988, 1989 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X *	Syd Weinstein, Elm Coordinator
X *	elm@dsinc.UUCP			dsinc!elm
X *
X *******************************************************************************
X * $Log:	utils.c,v $
X * Revision 2.22  89/03/25  21:47:33  syd
X * Initial 2.2 Release checkin
X * 
X *
X ******************************************************************************/
X
X/** Utility routines for ELM 
X
X**/
X
X#include "headers.h"
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <ctype.h>
X#include <errno.h>
X
X#ifdef BSD
X#undef tolower
X#endif
X
X#include <signal.h>
X
Xextern int errno;
X
Xchar *error_name();
Xvoid   exit();
X
Xcreate_new_folders()
X{
X	/* this creates a new folders directory */
X
X	char source[SLEN];
X	char com[SLEN];
X
X
X	/** Some systems don't have a mkdir call - how inconvienient! **/
X
X#ifdef MKDIR
X	(void) mkdir(folders, 0700);
X#else
X	sprintf(com, "mkdir %s", folders);
X	system_call(com, SH, FALSE);
X	sprintf(com, "chmod 700 %s", folders);
X	system_call(com, SH, FALSE);
X#endif /* MKDIR */
X
X	chown( source, userid, groupid);
X}
X
Xcreate_new_elmdir()
X{
X	/** this routine is just for allowing new users who don't have the
X	    old elm files to create a new .elm directory **/
X
X	char source[SLEN];
X	char com[SLEN];
X
X
X	/** Some systems don't have a mkdir call - how inconvienient! **/
X
X#ifdef MKDIR
X	sprintf(source, "%s/.elm", home);
X	(void) mkdir(source, 0700);
X#else
X	sprintf(com, "mkdir %s/.elm", home);
X	system_call(com, SH, FALSE);
X	sprintf(com, "chmod 700 %s/.elm", home);
X	system_call(com, SH, FALSE);
X#endif /* MKDIR */
X
X	chown( source, userid, groupid);
X}
X
Xmove_old_files_to_new()
X{
X	/** this routine is just for allowing people to transition from
X	    the old Elm, where things are all kept in their $HOME dir,
X	    to the new one where everything is in $HOME/.elm... **/
X
X	char source[SLEN], dest[SLEN], temp[SLEN];
X	char com[SLEN];
X
X	/** simply go through all the files... **/
X
X	sprintf(source, "%s/.alias_text", home);
X	if (access(source, ACCESS_EXISTS) != -1) {
X	  sprintf(dest,   "%s/%s", home, ALIAS_TEXT);
X	  printf("\n\rCopying from: %s\n\rCopying to:   %s\n\r", source, dest);
X	
X	  sprintf(temp, "/tmp/%d", getpid());
X	  sprintf(com, "%s -e 's/:/=/g' %s > %s\n", sed_cmd, source, temp);
X	  (void) system_call(com, SH, FALSE);
X	  sprintf(com, "%s %s %s\n", move_cmd, temp, dest);
X	  (void) system_call(com, SH, FALSE);
X	  (void) system_call("newalias", SH, FALSE);
X	}
X
X	sprintf(source, "%s/.elmheaders", home);
X	if (access(source, ACCESS_EXISTS) != -1) {
X	  sprintf(dest,   "%s/%s", home, mailheaders);
X	  printf("\n\rCopying from: %s\n\rCopying to:   %s\n\r", source, dest);
X	  copy(source, dest);
X	}
X
X	sprintf(source, "%s/.elmrc", home);
X	if (access(source, ACCESS_EXISTS) != -1) {
X	  sprintf(dest,   "%s/%s", home, elmrcfile);
X	  printf("\n\rCopying from: %s\n\rCopying to:   %s\n\r", source, dest);
X	  copy(source, dest);
X	}
X
X	printf(
X	"\n\rWelcome to the new version of ELM!\n\n\rHit return to continue.");
X	getchar();
X}
X	
Xshow_mailfile_stats()
X{
X	/** when we're about to die, let's try to dump lots of good stuff
X	    to the debug file... **/
X
X	struct stat buffer;
X
X	if (debug == 0) return;		/* Damn!  Can't do it! */
X
X	if (fstat(fileno(mailfile), &buffer) == 0) {
SHAR_EOF
echo "End of part 21"
echo "File src/utils.c is continued in part 22"
echo "22" > s2_seq_.tmp
exit 0

-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.