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

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

---- Cut Here and unpack ----
#!/bin/sh
# this is part 10 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file src/conn_to.c continued
#
CurArch=10
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/conn_to.c"
sed 's/^X//' << 'SHAR_EOF' >> src/conn_to.c
X    out what machines the current machine can talk to.   This can be
X    done in one of two ways - either the program can read the L.sys
X    file, or (if it fails or "UUNAME" define is present) will invoke
X    uuname to a file, then read the file in!
X
X**/
X
X#include "headers.h"
X
Xchar *strcpy();
X
Xget_connections()
X{
X
X	/** get the direct connections that this machine has, by hook
X	    or by crook (so to speak) 
X	**/
X
X#ifndef USE_UUNAME
X	FILE *lsysfile;
X	char  buffer[SLEN], sysname[NLEN];
X	struct lsys_rec *system_record, *previous_record;
X	int    loc_on_line;
X#endif
X
X	if (! warnings) {		/* skip this - they don't care! */
X	  talk_to_sys = NULL;
X	  return;
X	}
X
X#ifndef USE_UUNAME
X
X	previous_record = NULL;
X	if ((lsysfile = fopen(Lsys,"r")) == NULL) {
X	  dprint(1, (debugfile, 
X		"Warning: Can't open L.sys file %s (read_lsys)\n", Lsys));
X#endif
X
X	  if (read_uuname() == -1) {
X	    error("Warning: couldn't figure out system connections...");
X	    talk_to_sys = NULL;
X	  }
X
X#ifndef USE_UUNAME
X	  /** ELSE: already read in uuname() output if we're here!! **/
X	  return;
X	}
X
X	while (fgets(buffer, SLEN, lsysfile) != NULL) {
X	  sscanf(buffer,"%s", sysname);
X
X	  if (previous_record == NULL) {
X	    dprint(2, (debugfile, 
X		"L.sys\tdirect connection to %s, ", sysname));
X	    loc_on_line = 30 + strlen(sysname);  
X	    previous_record = (struct lsys_rec *) pmalloc(sizeof *talk_to_sys);
X
X	    strcpy(previous_record->name, sysname);
X	    previous_record->next = NULL;
X	    talk_to_sys = previous_record;
X	  }
X	  else if (! talk_to(sysname) && sysname[0] != '#') {
X	    if (loc_on_line + strlen(sysname) > 80) {
X	      dprint(2, (debugfile, "\n\t"));
X	      loc_on_line = 8;
X	    }
X	    dprint(2, (debugfile, "%s, ", sysname));
X	    loc_on_line += (strlen(sysname) + 2);
X	    system_record = (struct lsys_rec *) pmalloc(sizeof *talk_to_sys);
X	  
X	    strcpy(system_record->name, sysname);
X	    system_record->next = NULL;
X	    previous_record->next = system_record;
X	    previous_record = system_record;
X	  }
X	}
X
X	fclose(lsysfile);
X
X	if (loc_on_line != 8)
X	  dprint(2, (debugfile, "\n"));
X
X	dprint(2, (debugfile, "\n"));	/* for an even nicer format... */
X#endif
X}
X
Xint
Xread_uuname()
X{
X	/** This routine trys to use the uuname routine to get the names of
X	    all the machines that this machine connects to...it returns
X	    -1 on failure.
X	**/
X
X	FILE *fd;
X	char  buffer[SLEN], filename[SLEN];
X	struct lsys_rec *system_record, *previous_record;
X	int   loc_on_line;
X
X	sprintf(filename, "%s%d", temp_uuname, getpid());
X	sprintf(buffer,"%s > %s", uuname, filename);
X
X	if (system_call(buffer, SH) != 0) {
X	  dprint(1, (debugfile, "Can't get uuname info - system() failed!\n"));
X	  unlink(filename);	/* insurance */
X	  return(-1);
X	}
X	
X	if ((fd = fopen(filename, "r")) == NULL) {
X	  dprint(1, (debugfile,
X		"Can't get uuname info - can't open file %s for reading\n",
X		 filename));
X	  unlink(filename);	/* insurance */
X	  return(-1);
X	}
X	
X	previous_record = NULL;
X
X	while (fgets(buffer, SLEN, fd) != NULL) {
X	  no_ret(buffer);
X	  if (previous_record == NULL) {
X	    dprint(2, (debugfile, "uuname\tdirect connection to %s, ", buffer));
X	    loc_on_line = 30 + strlen(buffer);
X	    previous_record = (struct lsys_rec *) pmalloc(sizeof *talk_to_sys);
X
X	    strcpy(previous_record->name, buffer);
X	    previous_record->next = NULL;
X	    talk_to_sys = previous_record;
X	  }
X	  else {	/* don't have to check uniqueness - uuname does that! */
X	    if (loc_on_line + strlen(buffer) > 80) {
X	      dprint(2, (debugfile, "\n\t"));
X	      loc_on_line = 8;
X	    }
X	    dprint(2, (debugfile, "%s, ", buffer));
X	    loc_on_line += (strlen(buffer) + 2);
X	    system_record = (struct lsys_rec *) pmalloc(sizeof *talk_to_sys);
X	  
X	    strcpy(system_record->name, buffer);
X	    system_record->next = NULL;
X	    previous_record->next = system_record;
X	    previous_record = system_record;
X	  }
X	}
X
X	fclose(fd);
X
X	(void) unlink(filename);		/* kill da temp file!! */
X
X	dprint(2, (debugfile, "\n"));		/* for a nice format! Yeah! */
X
X	return(0);				/* it all went okay... */
X}
SHAR_EOF
echo "File src/conn_to.c is complete"
chmod 0444 src/conn_to.c || echo "restore of src/conn_to.c fails"
echo "x - extracting src/curses.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/curses.c &&
X
Xstatic char rcsid[] = "@(#)$Id: curses.c,v 2.1.1.2 88/09/23 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.1 $   $State: Exp $
X *
X * 			Copyright (c) 1986 Dave Taylor
X *******************************************************************************
X * Bug reports, patches, comments, suggetions should be sent to:
X *
X *	Syd Weinstein, Elm Corrdinator
X *	syd@dsinc.UUCP			dsinc!syd
X *
X *******************************************************************************
X * $Log:	curses.c,v $
X * Revision 2.1  88/09/15  20:27:44  syd
X * checked in with -k by syd at 88.09.15.20.27.44.
X * 
X * 88/09/01 Rob Bernardo <gatech!pbhyf.PacBell.COM!rob>
X *	There were *two* bugs causing the "command:" prompt to appear
X *	on the wrong line under a limited set of circumstances.
X *
X * 88/08/27 ssw
X *	add deluth patches
X *
X * 88/08/27 BLA
X * count backspaces
X *
X * Revision 2.1  88/07/21  09:58:05  edc
X * Final hacks and cleanup to the 2.1 alpha test release.
X * 
X * Revision 2.0  88/06/27  17:24:53  edc
X * The original 2.0 gamma sources as leaked from HP
X * 
X *
X *
X ******************************************************************************/
X
X/**  This library gives programs the ability to easily access the
X     termcap information and write screen oriented and raw input
X     programs.  The routines can be called as needed, except that
X     to use the cursor / screen routines there must be a call to
X     InitScreen() first.  The 'Raw' input routine can be used
X     independently, however.
X
X     Modified 2/86 to work (hopefully) on Berkeley systems.  If
X     there are any problems with BSD Unix, please report them to
X     the author at taylor@hplabs (fixed, if possible!)
X
X     Modified 5/86 to add memory lock support, thanks to the
X     suggested code by Steve Wolf.
X
X     Modified (as if I'm keeping track) to add 24,80 defaults
X
X**/
X
X/** NOTE THE ADDITION OF: the #ifndef ELM stuff around routines that
X    we don't use.  This is for code size and compile time speed...
X**/
X
X#include "headers.h"
X
X#ifdef RAWMODE
X# ifdef BSD
X#  ifndef BSD4_1
X#    include <sgtty.h>
X#  else
X#    include <termio.h>
X#  endif
X# else
X#  include <termio.h>
X# endif
X#endif
X
X#include <ctype.h>
X
X#ifdef BSD
X#undef tolower
X#endif
X#include "curses.h"
X
X#ifdef RAWMODE
X# define TTYIN	0
X#endif
X
X#ifdef SHORTNAMES
X# define _clearinverse	_clrinv
X# define _cleartoeoln	_clrtoeoln
X# define _cleartoeos	_clr2eos
X# define _transmit_off	xmit_off
X# define _transmit_on	xmit_on
X#endif
X
X#ifdef RAWMODE
X#  ifndef BSD
Xstruct termio _raw_tty, 
X              _original_tty;
X#  else
X#    define TCGETA	TIOCGETP
X#    define TCSETAW	TIOCSETP
X
Xstruct sgttyb _raw_tty,
X	      _original_tty;
X#  endif
X
Xstatic int _inraw = 0;                  /* are we IN rawmode?    */
X
X#endif
X
X#define DEFAULT_LINES_ON_TERMINAL	24
X#define DEFAULT_COLUMNS_ON_TERMINAL	80
X
Xstatic int _memory_locked = 0;		/* are we IN memlock??   */
Xstatic int _line  = -1,			/* initialize to "trash" */
X           _col   = -1;
X
Xstatic int _intransmit;			/* are we transmitting keys? */
X
Xstatic
Xchar *_clearscreen, *_moveto, *_up, *_down, *_right, *_left,
X     *_setbold, *_clearbold, *_setunderline, *_clearunderline, 
X     *_sethalfbright, *_clearhalfbright, *_setinverse, *_clearinverse,
X     *_cleartoeoln, *_cleartoeos, *_transmit_on, *_transmit_off,
X     *_set_memlock, *_clear_memlock;
X
Xstatic
Xint _lines, _columns;
X
Xstatic char _terminal[1024];              /* Storage for terminal entry */
Xstatic char _capabilities[1024];           /* String for cursor motion */
X
Xstatic char *ptr = _capabilities;	/* for buffering         */
X
Xint    outchar();			/* char output for tputs */
Xchar  *tgetstr(),     		       /* Get termcap capability */
X      *tgoto();				/* and the goto stuff    */
X
XInitScreen()
X{
X	/* Set up all this fun stuff: returns zero if all okay, or;
X        -1 indicating no terminal name associated with this shell,
X        -2..-n  No termcap for this terminal type known
X   */
X
X	int  tgetent(),      /* get termcap entry */
X	     err;
X	char termname[40];
X	char *strcpy(), *getenv();
X	
X	if (getenv("TERM") == NULL) return(-1);
X
X	if (strcpy(termname, getenv("TERM")) == NULL)
X		return(-1);
X
X	if ((err = tgetent(_terminal, termname)) != 1)
X		return(err-2);
X
X	_line  =  0;		/* where are we right now?? */
X	_col   =  0;		/* assume zero, zero...     */
X
X	/* load in all those pesky values */
X	_clearscreen       = tgetstr("cl", &ptr);
X	_moveto            = tgetstr("cm", &ptr);
X	_up                = tgetstr("up", &ptr);
X	_down              = tgetstr("do", &ptr);
X	_right             = tgetstr("nd", &ptr);
X	_left              = tgetstr("bs", &ptr);
X	_setbold           = tgetstr("so", &ptr);
X	_clearbold         = tgetstr("se", &ptr);
X	_setunderline      = tgetstr("us", &ptr);
X	_clearunderline    = tgetstr("ue", &ptr);
X	_setinverse        = tgetstr("so", &ptr);
X	_clearinverse      = tgetstr("se", &ptr);
X	_sethalfbright     = tgetstr("hs", &ptr);
X	_clearhalfbright   = tgetstr("he", &ptr);
X	_cleartoeoln       = tgetstr("ce", &ptr);
X	_cleartoeos        = tgetstr("cd", &ptr);
X	_lines	      	   = tgetnum("li");
X	_columns	   = tgetnum("co");
X	_transmit_on	   = tgetstr("ks", &ptr);
X	_transmit_off      = tgetstr("ke", &ptr);
X	_set_memlock	   = tgetstr("ml", &ptr);
X	_clear_memlock	   = tgetstr("mu", &ptr);
X
X
X	if (!_left) {
X		_left = ptr;
X		*ptr++ = '\b';
X		*ptr++ = '\0';
X	}
X
X	return(0);
X}
X
Xchar *return_value_of(termcap_label)
Xchar *termcap_label;
X{
X	/** This will return the string kept by termcap for the 
X	    specified capability. Modified to ensure that if 
X	    tgetstr returns a pointer to a transient address	
X	    that we won't bomb out with a later segmentation
X	    fault (thanks to Dave@Infopro for this one!)
X
X	    Tweaked to remove padding sequences.
X	 **/
X
X	static char escape_sequence[20];
X	register int i=0,j=0;
X	char buffer[20];
X	char *myptr, *tgetstr();     		/* Get termcap capability */
X
X	if (strlen(termcap_label) < 2)
X	  return(NULL);
X
X	if (termcap_label[0] == 's' && termcap_label[1] == 'o')
X	  strcpy(escape_sequence, _setinverse);
X	else if (termcap_label[0] == 's' && termcap_label[1] == 'e')
X	  strcpy(escape_sequence, _clearinverse);
X	else if ((myptr = tgetstr(termcap_label, &ptr)) == NULL)
X	  return( (char *) NULL );
X	else
X	  strcpy(escape_sequence, myptr);
X
X	if (chloc(escape_sequence, '$') != -1) {
X	  while (escape_sequence[i] != '\0') {
X	    while (escape_sequence[i] != '$' && escape_sequence[i] != '\0')
X	      buffer[j++] = escape_sequence[i++];
X	    if (escape_sequence[i] == '$') {
X	      while (escape_sequence[i] != '>') i++;
X	      i++;
X	    }
X	  }
X	  buffer[j] = '\0';
X	  strcpy(escape_sequence, buffer);
X	}
X
X	return( (char *) escape_sequence);
X}
X
Xtransmit_functions(newstate)
Xint newstate;
X{
X	/** turn function key transmission to ON | OFF **/
X
X	if (newstate != _intransmit) {
X		_intransmit = ! _intransmit;
X		if (newstate == ON)
X		  tputs(_transmit_on, 1, outchar);
X		else 
X		  tputs(_transmit_off, 1, outchar);
X		fflush(stdout);      /* clear the output buffer */
X	}
X}
X
X/****** now into the 'meat' of the routines...the cursor stuff ******/
X
XScreenSize(lines, columns)
Xint *lines, *columns;
X{
X	/** returns the number of lines and columns on the display. **/
X
X	if (_lines == 0) _lines = DEFAULT_LINES_ON_TERMINAL;
X	if (_columns == 0) _columns = DEFAULT_COLUMNS_ON_TERMINAL;
X
X	*lines = _lines - 1;		/* assume index from zero */
X	*columns = _columns;
X}
X
XGetXYLocation(x,y)
Xint *x,*y;
X{
X	/* return the current cursor location on the screen */
X
X	*x = _line;
X	*y = _col;
X}
X
XClearScreen()
X{
X	/* clear the screen: returns -1 if not capable */
X
X	_line = 0;	/* clear leaves us at top... */
X	_col  = 0;
X
X	if (!_clearscreen)
X		return(-1);
X
X	tputs(_clearscreen, 1, outchar);
X	fflush(stdout);      /* clear the output buffer */
X	return(0);
X}
X
XMoveCursor(row, col)
Xint row, col;
X{
X	/** move cursor to the specified row column on the screen.
X            0,0 is the top left! **/
X
X	char *stuff, *tgoto();
X	int scrollafter = 0;
X
X	/* we don't want to change "rows" or we'll mangle scrolling... */
X
X	if (col < 0)
X	  col = 0;
X	if (col >= COLUMNS)
X	  col = COLUMNS - 1;
X	if (row < 0)
X	  row = 0;
X	if (row > LINES) {
X	  if (col == 0)
X	    scrollafter = row - LINES;
X	  row = LINES;
X	}
X
X	if (!_moveto)
X		return(-1);
X
X	if (row == _line) {
X	  if (col == _col)
X	    return(0);				/* already there! */
X
X	  else if (abs(col - _col) < 5) {	/* within 5 spaces... */
X	    if (col > _col)
X	      CursorRight(col - _col);
X	    else 
X	      CursorLeft(_col - col);
X          }
X	  else {		/* move along to the new x,y loc */
X	    stuff = tgoto(_moveto, col, row);
X	    tputs(stuff, 1, outchar);
X	    fflush(stdout);
X	  }
X	}
X	else if (col == _col && abs(row - _line) < 5) {
X	  if (row < _line)
X	    CursorUp(_line - row);
X	  else
X	    CursorDown(row - _line);
X	}
X	else if (_line == row-1 && col == 0) {
X	  putchar('\n');	/* that's */
X	  putchar('\r');	/*  easy! */
X	  fflush(stdout);
X	}
X	else {
X	  stuff = tgoto(_moveto, col, row);
X	  tputs(stuff, 1, outchar);
X	  fflush(stdout);
X	}
X
X	_line = row;	/* to ensure we're really there... */
X	_col  = col;
X
X	if (scrollafter) {
X	  while (scrollafter--)
X	    putchar('\n');
X	  putchar('\r');
X	}
X
X	return(0);
X}
X
XCarriageReturn()
X{
X	/** move the cursor to the beginning of the current line **/
X
X	_col = 0;
X
X	putchar('\r');
X}
X
XNewLine()
X{
X	/** move the cursor to the beginning of the next line **/
X
X	_col = 0;
X	if (_line < LINES)
X	  _line++;
X
X	putchar('\r');
X	putchar('\n');
X}
X
XCursorUp(n)
Xint n;
X{
X	/** move the cursor up 'n' lines **/
X
X	_line = (_line-n > 0? _line - n: 0);	/* up 'n' lines... */
X
X	if (!_up)
X		return(-1);
X
X	while (n-- > 0)
X		tputs(_up, 1, outchar);
X
X	fflush(stdout);
X	return(0);
X}
X
X
XCursorDown(n)
Xint n;
X{
X	/** move the cursor down 'n' lines **/
X
X	_line = (_line+n < LINES? _line + n: LINES);	/* down 'n' lines... */
X
X	if (!_down)
X		return(-1);
X
X	while (n-- > 0)
X		tputs(_down, 1, outchar);
X
X	fflush(stdout);
X	return(0);
X}
X
X
XCursorLeft(n)
Xint n;
X{
X	/** move the cursor 'n' characters to the left **/
X
X	_col = (_col - n> 0? _col - n: 0);	/* left 'n' chars... */
X
X	if (!_left)
X		return(-1);
X
X	while (n-- > 0)
X		tputs(_left, 1, outchar);
X
X	fflush(stdout);
X	return(0);
X}
X
X
XCursorRight(n)
Xint n;
X{
X	/** move the cursor 'n' characters to the right (nondestructive) **/
X
X	_col = (_col+n < COLUMNS? _col + n: COLUMNS);	/* right 'n' chars... */
X
X	if (!_right)
X		return(-1);
X
X	while (n-- > 0)
X		tputs(_right, 1, outchar);
X
X	fflush(stdout);
X	return(0);
X}
X
X
XStartBold()
X{
X	/** start boldface/standout mode **/
X
X	if (!_setbold)
X		return(-1);
X
X	tputs(_setbold, 1, outchar);
X	fflush(stdout);
X	return(0);
X}
X
X
XEndBold()
X{
X	/** compliment of startbold **/
X
X	if (!_clearbold)
X		return(-1);
X
X	tputs(_clearbold, 1, outchar);
X	fflush(stdout);
X	return(0);
X}
X
X#ifndef ELM
X
XStartUnderline()
X{
X	/** start underline mode **/
X
X	if (!_setunderline)
X		return(-1);
X
X	tputs(_setunderline, 1, outchar);
X	fflush(stdout);
X	return(0);
X}
X
X
XEndUnderline()
X{
X	/** the compliment of start underline mode **/
X
X	if (!_clearunderline)
X		return(-1);
X
X	tputs(_clearunderline, 1, outchar);
X	fflush(stdout);
X	return(0);
X}
X
X
XStartHalfbright()
X{
X	/** start half intensity mode **/
X
X	if (!_sethalfbright)
X		return(-1);
X
X	tputs(_sethalfbright, 1, outchar);
X	fflush(stdout);
X	return(0);
X}
X
XEndHalfbright()
X{
X	/** compliment of starthalfbright **/
X
X	if (!_clearhalfbright)
X		return(-1);
X
X	tputs(_clearhalfbright, 1, outchar);
X	fflush(stdout);
X	return(0);
X}
X
XStartInverse()
X{
X	/** set inverse video mode **/
X
X	if (!_setinverse)
X		return(-1);
X
X	tputs(_setinverse, 1, outchar);
X	fflush(stdout);
X	return(0);
X}
X
X
XEndInverse()
X{
X	/** compliment of startinverse **/
X
X	if (!_clearinverse)
X		return(-1);
X
X	tputs(_clearinverse, 1, outchar);
X	fflush(stdout);
X	return(0);
X}
X
Xint
XHasMemlock()
X{
X	/** returns TRUE iff memory locking is available (a terminal
X	    feature that allows a specified portion of the screen to
X	    be "locked" & not cleared/scrolled... **/
X
X	return ( _set_memlock && _clear_memlock );
X}
X
Xstatic int _old_LINES;
X
Xint
XStartMemlock()
X{
X	/** mark the current line as the "last" line of the portion to 
X	    be memory locked (always relative to the top line of the
X	    screen) Note that this will alter LINES so that it knows
X	    the top is locked.  This means that (plus) the program 
X	    will scroll nicely but (minus) End memlock MUST be called
X	    whenever we leave the locked-memory part of the program! **/
X
X	if (! _set_memlock)
X	  return(-1);
X
X	if (! _memory_locked) {
X
X	  _old_LINES = LINES;
X	  LINES -= _line;		/* we can't use this for scrolling */
X
X	  tputs(_set_memlock, 1, outchar);
X	  fflush(stdout);
X	  _memory_locked = TRUE;
X	}
X
X	return(0);
X}
X
Xint
XEndMemlock()
X{
X	/** Clear the locked memory condition...  **/
X
X	if (! _set_memlock)
X	  return(-1);
X
X	if (_memory_locked) {
X	  LINES = _old_LINES;		/* back to old setting */
X  
X	  tputs(_clear_memlock, 1, outchar);
X	  fflush(stdout);
X	  _memory_locked = FALSE;
X	}
X	return(0);
X}
X
X#endif ndef ELM
X
XWritechar(ch)
Xchar ch;
X{
X	/** write a character to the current screen location. **/
X
X	putchar(ch);
X
X	if (ch == BACKSPACE)	/* moved BACK one! */
X		_col--;
X	else if (ch == '\r')	/* moved BACK to col 0! */
X		_col = 0;
X	else if (ch == '\n')	/* moved DOWN one! */
X		_line++;
X	else if (ch >= ' ')	/* moved FORWARD one! */
X		_col++;
X}
X
X/*VARARGS2*/
X
XWrite_to_screen(line, argcount, arg1, arg2, arg3)
Xchar *line;
Xint   argcount; 
Xchar *arg1, *arg2, *arg3;
X{
X	/** This routine writes to the screen at the current location.
X  	    when done, it increments lines & columns accordingly by
X	    looking for "\n" sequences... **/
X
X	switch (argcount) {
X	case 0 :
X		PutLine0(_line, _col, line);
X		break;
X	case 1 :
X		PutLine1(_line, _col, line, arg1);
X		break;
X	case 2 :
X		PutLine2(_line, _col, line, arg1, arg2);
X		break;
X	case 3 :
X		PutLine3(_line, _col, line, arg1, arg2, arg3);
X		break;
X	}
X}
X
XPutLine0(x, y, line)
Xint x,y;
Xchar *line;
X{
X	/** Write a zero argument line at location x,y **/
X
X	char     *p, *pend;
X
X	MoveCursor(x,y);
X	printf("%s", line);	/* to avoid '%' problems */
X	fflush(stdout);
X	_col += printable_chars(line);
X
X	while (_col > COLUMNS) { 	/* line wrapped around?? */
X		_col -= COLUMNS;
X              (_line < LINES) ? _line++: _line;
X	}
X
X	/** now let's figure out if we're supposed to do a "<return>" **/
X
X	pend = line + strlen(line);
X	for (p = line; p < pend; ) {
X	  if (*p == '\b')
X		_col--;
X	  if (*p++ == '\n') {
X                     (_line < LINES) ? _line++: _line;
X			_col = 0;		/* on new line! */
X		}
X	  }
X}
X
X/*VARARGS2*/
XPutLine1(x,y, line, arg1)
Xint x,y;
Xchar *line;
Xchar *arg1;
X{
X	/** write line at location x,y - one argument... **/
X
X	char buffer[VERY_LONG_STRING];
X
X	sprintf(buffer, line, arg1);
X
X	PutLine0(x, y, buffer);
X        fflush(stdout);
X}
X
X/*VARARGS2*/
XPutLine2(x,y, line, arg1, arg2)
Xint x,y;
Xchar *line;
Xchar *arg1, *arg2;
X{
X	/** write line at location x,y - one argument... **/
X
X	char buffer[VERY_LONG_STRING];
X
X	sprintf(buffer, line, arg1, arg2);
X
X	PutLine0(x, y, buffer);
X        fflush(stdout);
X}
X
X/*VARARGS2*/
XPutLine3(x,y, line, arg1, arg2, arg3)
Xint x,y;
Xchar *line;
Xchar *arg1, *arg2, *arg3;
X{
X	/** write line at location x,y - one argument... **/
X
X	char buffer[VERY_LONG_STRING];
X
X	sprintf(buffer, line, arg1, arg2, arg3);
X
X	PutLine0(x, y, buffer);
X        fflush(stdout);
X}
X
XCleartoEOLN()
X{
X	/** clear to end of line **/
X
X	if (!_cleartoeoln)
X		return(-1);
X
X	tputs(_cleartoeoln, 1, outchar);
X	fflush(stdout);  /* clear the output buffer */
X	return(0);
X}
X
XCleartoEOS()
X{
X	/** clear to end of screen **/
X
X	if (!_cleartoeos)
X		return(-1);
X
X	tputs(_cleartoeos, 1, outchar);
X	fflush(stdout);  /* clear the output buffer */
X	return(0);
X}
X
X#ifdef RAWMODE
X
XRawState()
X{
X	/** returns either 1 or 0, for ON or OFF **/
X
X	return( _inraw );
X}
X
XRaw(state)
Xint state;
X{
X	/** state is either ON or OFF, as indicated by call **/
X
X	if (state == OFF && _inraw) {
X	  (void) ioctl(TTYIN, TCSETAW, &_original_tty);
X	  _inraw = 0;
X	}
X	else if (state == ON && ! _inraw) {
X
X	  (void) ioctl(TTYIN, TCGETA, &_original_tty);	/** current setting **/
X
X	  (void) ioctl(TTYIN, TCGETA, &_raw_tty);    /** again! **/
X#ifdef BSD
X	  _raw_tty.sg_flags &= ~(ECHO | CRMOD);	/* echo off */
X	  _raw_tty.sg_flags |= CBREAK;	/* raw on    */
X#else
X	  _raw_tty.c_lflag &= ~(ICANON | ECHO);	/* noecho raw mode        */
X
X	  _raw_tty.c_cc[VMIN] = '\01';	/* minimum # of chars to queue    */
X	  _raw_tty.c_cc[VTIME] = '\0';	/* minimum time to wait for input */
X
X#endif
X	  (void) ioctl(TTYIN, TCSETAW, &_raw_tty);
X
X	  _inraw = 1;
X	}
X}
X
Xint
XReadCh()
X{
X	/** read a character with Raw mode set! **/
X
X	register int result;
X	char ch;
X	result = read(0, &ch, 1);
X        return((result <= 0 ) ? EOF : ch);
X}
X
X#endif
X
Xoutchar(c)
Xchar c;
X{
X	/** output the given character.  From tputs... **/
X	/** Note: this CANNOT be a macro!              **/
X
X	putc(c, stdout);
X}
SHAR_EOF
chmod 0444 src/curses.c || echo "restore of src/curses.c fails"
echo "x - extracting src/date.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/date.c &&
X
Xstatic char rcsid[] = "@(#)$Id: date.c,v 2.1 88/09/15 20:27:47 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.1 $   $State: Exp $
X *
X * 			Copyright (c) 1985 Dave Taylor
X *******************************************************************************
X * Bug reports, patches, comments, suggetions should be sent to:
X *
X *	Syd Weinstein, Elm Corrdinator
X *	syd@dsinc.UUCP			dsinc!syd
X *
X *******************************************************************************
X * $Log:	date.c,v $
X * Revision 2.1  88/09/15  20:27:47  syd
X * checked in with -k by syd at 88.09.15.20.27.47.
X * 
X * 88/08/27 ssw
X * Bug fixes from alpha test at dsinc
X *	fix bug with compares of 12pm vs 12am, old code added 12 for pm
X *	but 12:01pm is 12 pm not 24 pm.  needs to check if == 12, if
X *	so, for pm leave alone for am subtract 12.
X *
X * Revision 2.1  88/07/21  09:58:08  edc
X * Final hacks and cleanup to the 2.1 alpha test release.
X * 
X * Revision 2.0  88/06/27  17:24:54  edc
X * The original 2.0 gamma sources as leaked from HP
X * 
X *
X *
X ******************************************************************************/
X
X/** return the current date and time in a readable format! **/
X/** also returns an ARPA RFC-822 format date...            **/
X
X
X#include "headers.h"
X
X#ifdef BSD
X#  ifndef BSD4_1
X#    include <sys/time.h>
X#  else
X#    include <time.h>
X#    include <sys/types.h>
X#    include <sys/timeb.h>
X#  endif
X#else
X#  include <time.h>
X#endif
X
X#include <ctype.h>
X
X#ifdef BSD
X#undef toupper
X#undef tolower
X#endif
X
X#define MONTHS_IN_YEAR	11	/* 0-11 equals 12 months! */
X#define FEB		 1	/* 0 = January 		  */
X#define DAYS_IN_LEAP_FEB 29	/* leap year only 	  */
X
X#define ampm(n)		(n > 12? n - 12 : n)
X#define am_or_pm(n)	(n > 11? (n > 23? "am" : "pm") : "am")
X#define leapyear(year)	((year % 4 == 0) && (year % 100 != 0))
X
Xchar *arpa_dayname[] = { "Sun", "Mon", "Tue", "Wed", "Thu",
X		  "Fri", "Sat", "" };
X
Xchar *arpa_monname[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
X		  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""};
X
Xint  days_in_month[] = { 31,    28,    31,    30,    31,     30, 
X		  31,     31,    30,   31,    30,     31,  -1};
X
X#ifdef BSD
X  char *timezone();
X#else
X  extern char *tzname[];
X#endif
X
Xchar *shift_lower(), *strcpy(), *strncpy();
X
Xchar *get_arpa_date()
X{
X	/** returns an ARPA standard date.  The format for the date
X	    according to DARPA document RFC-822 is exemplified by;
X
X	       	      Mon, 12 Aug 85 6:29:08 MST
X
X	**/
X
X	static char buffer[SLEN];	/* static character buffer       */
X	struct tm *the_time,		/* Time structure, see CTIME(3C) */
X		  *localtime();
X	long	   junk,		/* time in seconds....		 */
X	    	   time();
X
X#ifdef BSD
X# ifdef BSD4_1
X	struct timeb	loc_time;
X
X	junk = time(long *) 0);
X	ftime(&loc_time);
X# else
X	struct  timeval  time_val;		
X	struct  timezone time_zone;
X
X	gettimeofday(&time_val, &time_zone);
X	junk = time_val.tv_sec;
X# endif
X
X#else
X	junk = time((long *) 0);	/* this must be here for it to work! */
X#endif
X
X	the_time = localtime(&junk);
X
X	sprintf(buffer, "%s, %d %s %d %d:%02d:%02d %s",
X	  arpa_dayname[the_time->tm_wday],
X	  the_time->tm_mday % 32,
X	  arpa_monname[the_time->tm_mon],
X	  the_time->tm_year % 100,
X	  the_time->tm_hour % 24,
X	  the_time->tm_min  % 61,
X	  the_time->tm_sec  % 61,
X#ifdef BSD
X# ifdef BSD4_1
X	  timezone(time_zone.timezone, the_time->tm_isdst));
X# else
X	  timezone(time_zone.tz_minuteswest, time_zone.tz_dsttime));
X# endif
X#else
X	  tzname[the_time->tm_isdst]);
X#endif
X	
X	return( (char *) buffer);
X}
X
Xdays_ahead(days, buffer)
Xint days;
Xchar *buffer;
X{
X	/** return in buffer the date (Day, Mon Day, Year) of the date
X	    'days' days after today.  
X	**/
X
X	struct tm *the_time,		/* Time structure, see CTIME(3C) */
X		  *localtime();
X	long	   junk,		/* time in seconds....		 */
X		   time();
X
X	junk = time((long *) 0);	/* this must be here for it to work! */
X	the_time = localtime(&junk);
X
X	/* increment the day of the week */
X
X	the_time->tm_wday = (the_time->tm_wday + days) % 7;
X
X	/* the day of the month... */
X	the_time->tm_mday += days;
X	
X	if (the_time->tm_mday > days_in_month[the_time->tm_mon]) {
X	  if (the_time->tm_mon == FEB && leapyear(the_time->tm_year)) {
X	    if (the_time->tm_mday > DAYS_IN_LEAP_FEB) {
X	      the_time->tm_mday -= days_in_month[the_time->tm_mon];
X	      the_time->tm_mon += 1;
X	    }
X	  }
X	  else {
X	    the_time->tm_mday -= days_in_month[the_time->tm_mon];
X	    the_time->tm_mon += 1;
X	  }
X	}
X
X	/* check the month of the year */
X	if (the_time->tm_mon > MONTHS_IN_YEAR) {
X	  the_time->tm_mon -= MONTHS_IN_YEAR;
X	  the_time->tm_year += 1;
X	}
X
X	/* now, finally, build the actual date string */
X
X	sprintf(buffer, "%s, %d %s %d",
X	  arpa_dayname[the_time->tm_wday],
X	  the_time->tm_mday % 32,
X	  arpa_monname[the_time->tm_mon],
X	  the_time->tm_year % 100);
X}
X
Xint
Xvalid_date(day, mon, year)
Xchar *day, *mon, *year;
X{
X	/** Validate the given date - returns TRUE iff the date
X	    handed is reasonable and valid.  
X	    Ignore month param, okay? 
X	**/
X
X	register int daynum, yearnum;
X
X	daynum = atoi(day);
X	yearnum = atoi(year);
X	
X	if (daynum < 1 || daynum > 31) {
X	  dprint(3, (debugfile, 
X		  "Error: day %d is obviously wrong! (valid_date)\n", 
X	          daynum));
X	  return(0);
X	}
X	
X	if (yearnum < 1 || (yearnum > 100 && yearnum < 1900) ||
X	    yearnum > 2000) {
X	  dprint(3, (debugfile, 
X		"Error: year %d is obviously wrong! (valid_date)\n", 
X		yearnum));
X	  return(0);
X	}
X	
X	return(1);
X}
X
Xfix_date(entry)
Xstruct header_rec *entry;
X{
X	/** This routine will 'fix' the date entry for the specified
X	    message.  This consists of 1) adjusting the year to 0-99
X	    and 2) altering time from HH:MM:SS to HH:MM am|pm **/ 
X
X	if (atoi(entry->year) > 99) 	
X	  sprintf(entry->year,"%d", atoi(entry->year) - 1900);
X
X	fix_time(entry->time);
X}
X
Xfix_time(timestring)
Xchar *timestring;
X{
X	/** Timestring in format HH:MM:SS (24 hour time).  This routine
X	    will fix it to display as: HH:MM [am|pm] **/
X
X	int hour, minute;
X
X	sscanf(timestring, "%d:%d", &hour, &minute);
X
X	if (hour < 1 || hour == 24) 
X	  sprintf(timestring, "12:%02d (midnight)", minute);
X	else if (hour < 12)
X	  sprintf(timestring, "%d:%02d am", hour, minute);
X	else if (hour == 12)
X	  sprintf(timestring, "%d:%02d (noon)", hour, minute);
X	else if (hour < 24)
X	  sprintf(timestring, "%d:%02d pm", hour-12, minute);
X}
X
Xint
Xcompare_dates(rec1, rec2)
Xstruct header_rec *rec1, *rec2;
X{
X	/** This function works similarly to the "strcmp" function, but
X	    has lots of knowledge about the internal date format...
X	    Apologies to those who "know a better way"...
X	**/
X
X	int month1, day1, year1, hour1, minute1,
X	    month2, day2, year2, hour2, minute2;
X
X	year1 = atoi(rec1->year);
X	year2 = atoi(rec2->year);
X
X	if (year1 != year2)
X	  return( year1 - year2 );
X
X	/* And HERE's where the performance of this sort dies... */
X
X	month1 = month_number(rec1->month);	/* retch...  gag....  */
X	month2 = month_number(rec2->month);	/*    puke...         */
X
X	if (month1 == -1) 
X	  dprint(2, (debugfile,
X		"month_number failed on month '%s'\n", rec1->month));
X
X	if (month2 == -1) 
X	  dprint(2, (debugfile,
X		"month_number failed on month '%s'\n", rec2->month));
X
X	if (month1 != month2)
X	  return( month1 - month2 );
X
X	/* back and cruisin' now, though... */
X
X	day1 = atoi(rec1->day);	 /* unfortunately, 2 is greater than 19  */
X	day2 = atoi(rec2->day);  /* on a dump string-only compare...     */
X
X	if (day1 != day2)
X	  return( day1 - day2 );
X
X	/* we're really slowing down now... */
X
X	minute1 = minute2 = -1;
X
X	sscanf(rec1->time, "%d:%d", &hour1, &minute1);
X	sscanf(rec2->time, "%d:%d", &hour2, &minute2);
X
X	/* did we get the time?  If not, try again */
X
X	if (minute1 < 0)
X	  sscanf(rec1->time, "%2d%2d", &hour1, &minute1);
X
X	if (minute2 < 0)
X	  sscanf(rec2->time, "%2d%2d", &hour2, &minute2);
X
X	/** deal with am/pm, if present... **/
X
X	if (strlen(rec1->time) > 3)
X	  if (rec1->time[strlen(rec1->time)-2] == 'p') {
X	   if (hour1 != 12)
X	    hour1 += 12;
X	   }
X	  else {
X	   if (hour1 == 12)
X	    hour1 = 0;
X	   }
X
X	if (strlen(rec2->time) > 3)
X	  if (rec2->time[strlen(rec2->time)-2] == 'p') {
X	   if (hour2 != 12)
X	    hour2 += 12;
X	   }
X	  else {
X	   if (hour2 == 12)
X	    hour2 = 0;
X	   }
X
X	if (hour1 != hour2)
X	  return( hour1 - hour2 );
X
X	return( minute1 - minute2 );		/* ignore seconds... */
X}
X
Xint
Xcompare_parsed_dates(rec1, rec2)
Xstruct date_rec rec1, rec2;
X{
X	/** This function is very similar to the compare_dates
X	    function but assumes that the two record structures
X	    are already parsed and stored in "date_rec" format.
X	**/
X
X	if (rec1.year != rec2.year)
X	  return( rec1.year - rec2.year );
X	
X	if (rec1.month != rec2.month)
X	  return( rec1.month - rec2.month );
X
X	if (rec1.day != rec2.day)
X	  return( rec1.day - rec2.day );
X
X	if (rec1.hour != rec2.hour)
X	  return( rec1.hour - rec2.hour );
X
X	return( rec1.minute - rec2.minute );		/* ignore seconds... */
X}
X
Xint
Xmonth_number(name)
Xchar *name;
X{
X	/** return the month number given the month name... **/
X
X	char ch;
X
X	switch (tolower(name[0])) {
X	 case 'a' : if ((ch = tolower(name[1])) == 'p')	return(APRIL);
X		    else if (ch == 'u') return(AUGUST);
X		    else return(-1);	/* error! */
X	
X	 case 'd' : return(DECEMBER);
X	 case 'f' : return(FEBRUARY);
X	 case 'j' : if ((ch = tolower(name[1])) == 'a') return(JANUARY);
X		    else if (ch == 'u') {
X	              if ((ch = tolower(name[2])) == 'n') return(JUNE);
X		      else if (ch == 'l') return(JULY);
X		      else return(-1);		/* error! */
X	            }
X		    else return(-1);		/* error */
X	 case 'm' : if ((ch = tolower(name[2])) == 'r') return(MARCH);
X		    else if (ch == 'y') return(MAY);
X		    else return(-1);		/* error! */
X	 case 'n' : return(NOVEMBER);
X	 case 'o' : return(OCTOBER);
X	 case 's' : return(SEPTEMBER);
X	 default  : return(-1);
X	}
X}
X
X#ifdef SITE_HIDING
X
Xchar *get_ctime_date()
X{
X	/** returns a ctime() format date, but a few minutes in the 
X	    past...(more cunningness to implement hidden sites) **/
X
X	static char buffer[SLEN];	/* static character buffer       */
X	struct tm *the_time,		/* Time structure, see CTIME(3C) */
X		  *localtime();
X	long	   junk,		/* time in seconds....		 */
X		   time();
X#ifdef BSD
X	struct  timeval  time_val;		
X	struct  timezone time_zone;
X#endif
X
X#ifdef BSD
X	gettimeofday(&time_val, &time_zone);
X	junk = time_val.tv_sec;
X#else
X	junk = time((long *) 0);	/* this must be here for it to work! */
X#endif
X	the_time = localtime(&junk);
X
X	sprintf(buffer, "%s %s %d %02d:%02d:%02d %d",
X	  arpa_dayname[the_time->tm_wday],
X	  arpa_monname[the_time->tm_mon],
X	  the_time->tm_mday % 32,
X	  min(the_time->tm_hour % 24, (rand() % 24)),
X	  min(abs(the_time->tm_min  % 61 - (rand() % 60)), (rand() % 60)),
X	  min(abs(the_time->tm_sec  % 61 - (rand() % 60)), (rand() % 60)),
X	  the_time->tm_year % 100 + 1900);
X	
X	return( (char *) buffer);
X}
X
X#endif
SHAR_EOF
chmod 0444 src/date.c || echo "restore of src/date.c fails"
echo "x - extracting src/delete.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/delete.c &&
X
Xstatic char rcsid[] = "@(#)$Id: delete.c,v 2.1 88/09/15 20:27:51 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.1 $   $State: Exp $
X *
X * 			Copyright (c) 1985 Dave Taylor
X *******************************************************************************
X * Bug reports, patches, comments, suggetions should be sent to:
X *
X *	Syd Weinstein, Elm Corrdinator
X *	syd@dsinc.UUCP			dsinc!syd
X *
X *******************************************************************************
X * $Log:	delete.c,v $
X * Revision 2.1  88/09/15  20:27:51  syd
X * checked in with -k by syd at 88.09.15.20.27.51.
X * 
X * 88/08/27  Rob Bernardo <gatech!pbhyf.PacBell.COM!rob>
X *	fix inverse video bar
X *
X * Revision 2.1  88/07/21  09:58:10  edc
X * Final hacks and cleanup to the 2.1 alpha test release.
X * 
X * Revision 2.0  88/06/27  17:24:55  edc
X * The original 2.0 gamma sources as leaked from HP
X * 
X *
X *
X ******************************************************************************/
X
X/**  Delete or undelete files: just set flag in header record! 
X     Also tags specified message(s)...
X
X**/
X
X#include "headers.h"
X
Xchar *show_status();
X
Xdelete_msg(real_del, update_screen)
Xint real_del, update_screen;
X{
X	/** Delete current message.  If real-del is false, then we're
X	    actually requested to toggle the state of the current
X	    message... **/
X
X	if (real_del)
X	  header_table[current-1].status |= DELETED;
X	else if (ison(header_table[current-1].status, DELETED))
X	  clearit(header_table[current-1].status, DELETED);
X	else
X	  setit(header_table[current-1].status, DELETED);
X
X	if (update_screen)
X	  show_msg_status(current-1);
X}
X
Xundelete_msg(update_screen)
Xint update_screen;
X{
X	/** clear the deleted message flag **/
X
X	clearit(header_table[current-1].status, DELETED);
X
X	if (update_screen)
X	  show_msg_status(current-1);
X}
X
Xshow_msg_status(msg)
Xint msg;
X{
X	/** show the status of the current message only.  **/
X
X	char tempbuf[3];
X
X	strcpy(tempbuf, show_status(header_table[msg].status));
X
X	if (on_page(msg)) {
X	  MoveCursor((msg % headers_per_page) + 4, 2);
X	  if (msg+1 == current && !arrow_cursor) {
X	    StartBold();
X	    Writechar( tempbuf[0] );
X	    EndBold();
X	  }
X	  else
X	    Writechar( tempbuf[0] );
X	}
X}
X
Xtag_message()
X{
X	/** Tag current message.  If already tagged, untag it. **/
X
X	if (ison(header_table[current-1].status, TAGGED))
X	  clearit(header_table[current-1].status, TAGGED);
X	else
X	  setit(header_table[current-1].status, TAGGED);
X
X	show_msg_tag(current-1);
X}
X
Xshow_msg_tag(msg)
Xint msg;
X{
X	/** show the tag status of the current message only.  **/
X
X	if (on_page(msg)) {
X	  MoveCursor((msg % headers_per_page) + 4, 4);
X	  if (msg+1 == current && !arrow_cursor) {
X	    StartBold();
X	    Writechar( ison(header_table[msg].status, TAGGED)? '+' : ' ');
X	    EndBold();
X	  }
X	  else
X	    Writechar( ison(header_table[msg].status, TAGGED)? '+' : ' ');
X	}	
X}
X
Xshow_new_status(msg)
Xint msg;
X{
X	/** If the specified message is on this screen, show
X	    the new status (could be marked for deletion now,
X	    and could have tag removed...)
X	**/
X
X	if (on_page(msg)) 
X	  if (msg+1 == current && !arrow_cursor) {
X	    StartBold();
X	    PutLine2((msg % headers_per_page) + 4, 2, "%s%c",
X		   show_status(header_table[msg].status),
X		   ison(header_table[msg].status, TAGGED )? '+' : ' ');
X	    EndBold();
X	  }
X	  else
X	    PutLine2((msg % headers_per_page) + 4, 2, "%s%c",
X		   show_status(header_table[msg].status),
X		   ison(header_table[msg].status, TAGGED )? '+' : ' ');
X}
SHAR_EOF
chmod 0444 src/delete.c || echo "restore of src/delete.c fails"
echo "x - extracting src/domains.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/domains.c &&
X
Xstatic char rcsid[] = "@(#)$Id: domains.c,v 2.1 88/07/21 09:58:11 edc Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.1 $   $State: Exp $
X *
X * 			Copyright (c) 1986 Dave Taylor
X *******************************************************************************
X * Bug reports, patches, comments, suggetions should be sent to:
X *
X *	Syd Weinstein, Elm Corrdinator
X *	syd@dsinc.UUCP			dsinc!syd
X *
X *******************************************************************************
X * $Log:	domains.c,v $
X * Revision 2.1  88/07/21  09:58:11  edc
X * checked in with -k by syd at 88.09.15.20.27.54.
X * 
X * Revision 2.1  88/07/21  09:58:11  edc
X * Final hacks and cleanup to the 2.1 alpha test release.
X * 
X * Revision 2.0  88/06/27  17:24:56  edc
X * The original 2.0 gamma sources as leaked from HP
X * 
X *
X *
X ******************************************************************************/
X
X/** This file contains all the code dealing with the expansion of 
X    domain based addresses in Elm.  It uses the file "domains" as
X    defined in the sysdefs.h file.
X
X    From a file format and idea in "uumail" - designed by Stan Barber.
X**/
X
X#include <stdio.h>
X#include <ctype.h>
X
X#include "headers.h"
X
X#ifdef BSD
X# undef toupper
X# undef tolower
X#endif
X
X/** define the various characters that we can encounter after a "%" sign
X    in the template file...
X**/
X
X#define USERNAME	'U'	/* %U = the name of the remote user */
X#define HOSTNAME	'N'	/* %N = the remote machine name     */
X#define FULLNAME	'D'	/* %D = %N + domain info given      */
X#define NPATH		'R'	/* %R = path to %N from pathalias   */
X#define PPATH		'P'	/* %P = path to 'P' from pathalias  */
X#define OBSOLETE	'S'	/* %S = (used to be suffix string)  */
X
X/** and finally some characters that are allowed in user/machine names **/
X
X#define okay_others(c)	(c == '-' || c == '^' || c == '$' || c == '_')
X
X/** and some allowed ONLY in the username field **/
X
X#define special_chars(c)	(c == '%' || c == ':')
X
Xchar *find_path_to(), *expand_domain(), *match_and_expand_domain();
Xchar *strcpy(), *strcat(), *strtok();
Xunsigned long sleep();
Xvoid rewind();
X	      
Xopen_domain_file()
X{
X	if ((domainfd = fopen(domains, "r")) == NULL) {
X	  dprint(2, (debugfile,"Warning: can't open file %s as domains file\n", 
X		domains));
X	}
X	else {
X	  dprint(3, (debugfile, 
X            "Opened '%s' as the domain database\n\n", domains));
X	}
X	
X	/* if it fails it'll instantiate domainfd to NULL which is
X	   exactly what we want to have happen!! */
X}
X
Xchar *expand_domain(buffer)
Xchar *buffer;
X{
X	/** Expand the address 'buffer' based on the domain information, 
X	    if any.  Returns NULL if it can't expand it for any reason.
X	**/
X
X	char name[2*NLEN], address[2*NLEN], domain[2*NLEN];
X	char *match_and_expand_domain();
X
X	if (domainfd == NULL) return(NULL);	/* no file present! */
X
X	if (explode(buffer, name, address, domain)) 
X	  return( match_and_expand_domain(domain, name, address) );
X	else {	/* invalid format - not "user@host.domain" */
X	  dprint(2,  (debugfile,
X		 "Invalid format for domain expansion: %s (expand_domain)\n", 
X		   buffer));
X	  return(NULL);
X	}
X}	
X
Xint
Xexplode(buffer, name, address, domain)
Xchar *buffer, *name, *address, *domain;
X{
X	/** Break buffer, if in format name@machine.domain, into the
X	    component parts, otherwise return ZERO and don't worry
X	    about the values of the parameters!
X	**/
X	
X	register int i, j = 0;
X
X	/** First get the name... **/
X
X	for (i=0; buffer[i] != '@'; i++) {
X	  if (! isalnum(buffer[i]) && ! okay_others(buffer[i]) && ! 
X		special_chars(buffer[i]))
X	    return(0);			/* invalid character in string! */
X	  name[i] = buffer[i];
X	}
X
X	name[i++] = '\0';
X
X	/** now let's get the machinename **/
X
X	while (buffer[i] != '.') {
X	  if (! isalnum(buffer[i]) && ! okay_others(buffer[i]))
X	     return(0);			/* invalid character in string! */
X	  address[j++] = buffer[i++];
X	}
X	address[j] = '\0';
X
X	j = 0;
X
X	/** finally let's get the domain information (there better be some!) **/
X
X	while (buffer[i] != '\0') {
X	  if (! isalnum(buffer[i]) && ! okay_others(buffer[i]) && 
X	        buffer[i] != '.')
X	    return(0);		      /* an you fail again, bozo! */
X	  domain[j++] = toupper(buffer[i]);
X	  i++;
X	}
X
X	domain[j] = '\0';
X	
X	return(j);		/* if j == 0 there's no domain info! */
X}
X        
Xchar *match_and_expand_domain(domain, name, machine)
Xchar *domain, *name, *machine;
X{
X	/** Given the domain, try to find it in the domain file and
X   	    if found expand the entry and return the result as a 
X	    character string...
X	**/
X
X	static char address[SLEN];
X	char   buffer[SLEN], domainbuff[NLEN];
X	char   field1[2*NLEN], field2[2*NLEN], field3[2*NLEN];
X	char   *path, *template, *expanded, *mydomain, *strtok();
X	int    matched = 0, in_percent = 0;
X	register int i, j = 0;
X
X	address[j] = '\0';
X
X	domainbuff[0] = '\0';
X	mydomain = (char *) domainbuff;		    /* set up buffer etc */
X
X	do { 
X	  rewind(domainfd);		           /* back to ground zero! */
X
X	  if (strlen(mydomain) > 0) {		   /* already in a domain! */
X	    mydomain++;		 		      /* skip leading '.' */
X	    while (*mydomain != '.' && *mydomain != ',') 
X	      mydomain++;	 		      /* next character   */
X	    if (*mydomain == ',')
X	      return (NULL);  			  /* didn't find domain!  */
X	  }
X	  else
X	    sprintf(mydomain, "%s,", domain);		/* match ENTIRELY! */
X
X	/* whip through file looking for the entry, please... */
X
X	while (fgets(buffer, SLEN, domainfd) != NULL) {
X	  if (buffer[0] == '#')				  /* skip comments */
X	    continue;
X	  if (strncmp(buffer, mydomain, strlen(mydomain)) == 0) { /* match? */
X	     matched++;	/* Gotcha!  Remember this momentous event! */
X	     break;
X	  }
X	}
X
X	if (! matched) 
X	   continue;		/* Nothing.  Not a sausage!  Step through! */
X
X	/** We've matched the domain! **/
X
X	no_ret(buffer);
X
X	(void) strtok(buffer, ",");	/* skip the domain info */
X
X	strcpy(field1, strtok(NULL, ","));	/* fun 		*/
X	strcpy(field2, strtok(NULL, ","));	/*    stuff     */
X	strcpy(field3, strtok(NULL, ","));	/*       eh?    */
X	
X	path = (char *) NULL;
X
X	/* now we merely need to figure out what permutation this is! */
X
X	if (field3 == NULL || strlen(field3) == 0)
X	  if (field2 == NULL || strlen(field2) == 0)
X	    template = (char *) field1;
X	  else {
X	    path     = (char *) field1;
X	    template = (char *) field2;
X	  }
X	else {
X	  dprint(1, (debugfile,
X		   "Domain info for %s from file broken into THREE fields!!\n",
X		   domain));
X	  dprint(1, (debugfile,
X		   "-> %s\n-> %s\n-> %s\n", field1, field2, field3));
X	  dprint(1, (debugfile, "(this means it's using a defunct field)\n"));
X	  error1("Warning: domain %s uses a defunct field!!", domain);
X	  sleep(2);
X	  path     = (char *) field1;
X	  template = (char *) field3;
X	}
X
X	if (strlen(path) > 0 && path[0] == '>') 
X	   path++;	/* skip the '>' character, okay? */
X
X	j = 0;		 	/* address is zero, right now, right?? */
X	address[j] = '\0';	      /* make sure string is too! */
X
X	for (i=0; i < strlen(template); i++) {
X	  if (template[i] == '%') {
X	    if (! in_percent)			   /* just hit a NEW percent! */
X	      in_percent = 1;
X	    else {		  /* just another percent sign on the wall... */
X	      address[j++] = '%';
X	      address[j] = '\0';		     /* ALWAYS NULL terminate */
X	      in_percent = 0;
X	    }
X	  }
X	  else if (in_percent) {	       /* Hey! a real command string */
X	    in_percent = 0;
X	    switch (template[i]) {
X	      case USERNAME: strcat(address, name);		break;
X	      case HOSTNAME: strcat(address, machine);		break;
X	      case FULLNAME: strcat(address, machine);
X			     strcat(address, domain);		break;
X	      case NPATH   : 
X
X		 if ((expanded = find_path_to(machine, FALSE)) == NULL) {
X		    dprint(3, (debugfile,
X			    "\nCouldn't expand system path '%s' (%s)\n\n",
X			    machine, "domains"));
X	            error1("Couldn't find a path to %s!", machine);
X	            sleep(2);
X	            return(NULL);	/* failed!! */
X	         }
X	         strcat(address, expanded);	/* isn't this fun??? */
X
X	         break;
X
X	      case PPATH   : 
X
X		 if ((expanded = find_path_to(path, FALSE)) == NULL) {
X		    dprint(3, (debugfile,
X			"\nCouldn't expand system path '%s' (%s)\n\n",
X			path, "domains"));
X	            error1("I Couldn't find a path to %s!", path);
X	            sleep(2);
X	            return(NULL);	/* failed!! */
X	         }
X	         strcat(address, expanded);	/* isn't this fun??? */
X
X	         break;
X
X	      case OBSOLETE:	/* fall through.. */
X	      default      : dprint(1, (debugfile,
X	     "\nError: Bad sequence in template file for domain '%s': %%%c\n\n",
X			domain, template[i]));
X	    }
X	    j = strlen(address);
X	  }
X	  else {
X	    address[j++] = template[i];
X	    address[j] = '\0';			/* null terminate */
X	  }
X	}	
X
X	address[j] = '\0';
X
X	} while (strlen(address) < 1);
X
X	return( (char *) address);
X}
SHAR_EOF
chmod 0444 src/domains.c || echo "restore of src/domains.c fails"
echo "x - extracting src/edit.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/edit.c &&
X
Xstatic char rcsid[] = "@(#)$Id: edit.c,v 2.1 88/09/15 20:27:57 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.1 $   $State: Exp $
X *
X * 			Copyright (c) 1986 Dave Taylor
X *******************************************************************************
X * Bug reports, patches, comments, suggetions should be sent to:
X *
X *	Syd Weinstein, Elm Corrdinator
X *	syd@dsinc.UUCP			dsinc!syd
X *
X *******************************************************************************
X * $Log:	edit.c,v $
X * Revision 2.1  88/09/15  20:27:57  syd
X * checked in with -k by syd at 88.09.15.20.27.57.
X * 
X * 88/09/01 Rob Bernardo <rob@pbhyf.PacBell.COM>
X *	fix resync after edit
X *
X * 88/08/27 ssw
X *	add deluth patches
X *
X * 88/08/27 ssw
X * Bug fixes from alpha test at dsinc
X *	problems with linking across file systems fixed.
X *
X * Revision 2.1  88/07/21  09:58:13  edc
X * Final hacks and cleanup to the 2.1 alpha test release.
X * 
X * Revision 2.0  88/06/27  17:24:57  edc
X * The original 2.0 gamma sources as leaked from HP
X * 
X *
X *
X ******************************************************************************/
X
X/** This routine is for allowing the user to edit their current mailbox
X    as they wish. 
X
X**/
X
X#include "headers.h"
X#include <errno.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X
Xextern int errno;
X
Xchar   *error_name(), *error_description(), *strcpy();
Xlong   bytes();
Xunsigned long sleep();
X
X#ifdef ALLOW_MAILBOX_EDITING
X
Xedit_mailbox()
X{
X	/** Allow the user to edit their mailbox, always resynchronizing
X	    afterwards.   Due to intense laziness on the part of the
X	    programmer, this routine will invoke $EDITOR on the entire
X	    file.  The mailer will ALWAYS resync on the mailbox file
X	    even if nothing has changed since, not unreasonably, it's
X	    hard to figure out what occurred in the edit session...
X	
X	    Also note that if the user wants to edit their incoming
X	    mailbox they'll actually be editing the tempfile that is
X	    an exact copy.  More on how we resync in that case later
X	    in this code.
X	**/
X
X	FILE     *real_mailbox, *temp_mailbox;
X	char     filename[SLEN], buffer[LONG_SLEN], temp_infile[SLEN];
X	struct   stat stat_buffer;
X	int      loaded_stat_buffer = FALSE;
X
X	PutLine0(LINES-1,0,"invoking editor...");
X
X	if (mbox_specified == 0) {
X	  sprintf(filename, "%s%s", temp_mbox, username);
X	  chown(filename, userid, groupid);		/* make sure we can! */
X	}
X	else 
X	  strcpy(filename, infile);
X
X	/** now get and save the ownership and permissions... **/
X
X	if (stat(infile, &stat_buffer)) {
X	  error("Warning: couldn't 'stat' file, perms might get mangled");
X	  sleep(2);
X	}
X	else
X	  loaded_stat_buffer = TRUE;
X
X	sprintf(buffer, "%s %s", alternative_editor, filename);
X
X	Raw(OFF);
X
X	if (system_call(buffer, SH) != 0) {
X	  error1("Problems invoking editor %s!", alternative_editor);
SHAR_EOF
echo "End of part 10"
echo "File src/edit.c is continued in part 11"
echo "11" > s2_seq_.tmp
exit 0
-- 
=====================================================================
Sydney S. Weinstein, CDP, CCP                   Elm Coordinator
Datacomp Systems, Inc.				Voice: (215) 947-9900
{allegra,bellcore,bpa,vu-vlsi}!dsinc!syd	FAX:   (215) 938-0235