[comp.sources.unix] v22i071: ELM mail syste, release 2.3, Part12/26

rsalz@bbn.com (Rich Salz) (05/31/90)

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

---- Cut Here and unpack ----
#!/bin/sh
# this is part 12 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file src/aliasdb.c continued
#
CurArch=12
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/aliasdb.c"
sed 's/^X//' << 'SHAR_EOF' >> src/aliasdb.c
X#ifndef USE_DBM
X	  get_connections();
X	  open_domain_file();
X#endif
X	  init_findnode();
X	  clear_error();
X          findnode_has_been_initialized = TRUE;
X	}
X
X	strcpy(old_name, name);		/* save what we were given */
X
X	if (expand_site(name, address) == -1) {
X          if (display_error && name[0] != '!') {
X	    dprint(3, (debugfile, "Couldn't expand host %s in address.\n",
X	             name));
X	    if (! check_only && warnings) {
X	      error1("Couldn't expand system %s.", name);
X	      sleep(1);
X	    }
X	  }
X	  strcpy(name, old_name);	/* and restore... */
X	}
X	else
X	  strcpy(name, address);
X#endif
X	return;
X}
X
X#if defined(OPTIMIZE_RETURN) || !defined(DONT_TOUCH_ADDRESSES)
Xint
Xexpand_site(cryptic, expanded)
Xchar *cryptic, *expanded;
X{
X
X	/** Given an address of the form 'xyz@site' or 'site!xyz'
X	    return an address of the form <expanded address for site>
X            with 'xyz' embedded according to the path database entry.
X	    Note that 'xyz' can be eiher a simple address (as in "joe")
X	    or a complex address (as in "joe%xerox.parc@Xerox.ARPA")!
X	    0 = found, -1 return means unknown site code 
X	
X	    Modified to strip out parenthetical comments...
X	**/
X
X#ifdef ACSNET
X
X	strcpy(expanded, cryptic);	/* fast and simple */
X	return(0);
X
X#else
X# ifdef USE_DBM
X	datum  key, contents;
X# endif
X
X	char   name[VERY_LONG_STRING], sitename[VERY_LONG_STRING], 
X               temp[VERY_LONG_STRING], old_name[VERY_LONG_STRING],
X	       comment[LONG_STRING];
X	char   *expand_domain(), *addr;
X	register int i = 0, j = 0, in_parens = 0, domain_name;
X
X	strcpy(old_name, cryptic);	/* remember what we were given */
X
X	/** break down **/
X
X	/** first, rip out the comment, if any, noting nested parens **/
X
X	if ((i = chloc(cryptic, '(')) > -1) {
X	  comment[j++] = ' ';			/* leading space */
X	  do {
X  	    switch(comment[j++] = cryptic[i++]) {
X	    case '(':	in_parens++;
X			break;
X	    case ')':	in_parens--;
X			break;
X	    }
X	  } while(in_parens && cryptic[i] != '\0');
X	  comment[j] = '\0';
X
X	  /* and remove this from cryptic string too... */
X	  if (cryptic[(j = chloc(cryptic,'('))-1] == ' ')
X	    cryptic[j-1] = '\0';
X	  else
X	    cryptic[j] = '\0';
X	}
X	else
X	  comment[0] = '\0';
X
X	i = j = 0;	/* reset */
X
X	while (cryptic[i] != AT_SIGN && cryptic[i] != BANG && 
X	       cryptic[i] != '\0' && cryptic[i] != '(')
X	  sitename[j++] = cryptic[i++];
X
X	sitename[j++] = '\0';
X
X	j = 0;
X	
X	if (cryptic[i] == '\0') return(-1);	/* nothing to expand! */
X
X	domain_name = (cryptic[i] == AT_SIGN);
X
X	i++;
X
X	while (cryptic[i] != '\0' && cryptic[i] != '(' && 
X               ! whitespace(cryptic[i]))
X	  name[j++] = cryptic[i++];
X
X	name[j] = '\0';
X
X	if (domain_name) {
X	  strcpy(temp, name);
X	  strcpy(name, sitename);
X	  strcpy(sitename, temp);
X	}
X
X	dprint(5, (debugfile, "\nBroke address into '%s' @ '%s' '%s'\n\n",
X		name, sitename, comment));
X
X#ifdef USE_DBM
X
X	if (size_of_pathfd == 0)
X	  return(-1);
X
X	key.dptr  = sitename;
X	key.dsize = strlen(sitename) + 1;
X
X	contents = fetch(key);
X
X	if (contents.dptr == 0) 
X	  return(-1);			/* can't find it! */
X
X	sprintf(expanded, contents.dptr, name);
X	strcat(expanded, " ");			/* add a single space... */
X	strcat(expanded, comment);		/*    ...and add comment */
X	return(0);
X#else
X
X#ifndef LOOK_CLOSE_AFTER_SEARCH
X
X	if (talk_to(sitename)) {
X	  strcpy(expanded, old_name);	/* restore! */
X	  return(0);
X	}
X#endif
X
X	if ((addr = find_path_to(sitename, TRUE)) == NULL) {
X
X#ifdef LOOK_CLOSE_AFTER_SEARCH
X
X	    if (talk_to(sitename)) {
X	      strcpy(expanded, old_name);	/* restore! */
X	      return(0);
X	    }
X	    else
X#endif
X	    if ((addr = expand_domain(cryptic)) != NULL) {
X	       strcpy(expanded, addr);	/* into THIS buffer */
X	       strcat(expanded, comment);	/* patch in comment */
X	       return(0);
X	    }
X	    else  if (size_of_pathfd == 0) {	/* no path database! */
X	      strcpy(expanded, old_name);	/* restore! */
X	      return(0);
X	    }
X	    else {			     /* We just can't get there! */
X	      strcpy(expanded, old_name);	/* restore! */
X	      return(-1);
X	    }
X	}
X	else {			/* search succeeded */
X	   sprintf(expanded, addr, name);
X	   strcat(expanded, comment);		/* add comment */
X	   return(0);
X	}
X#endif
X#endif
X}
X#endif /* defined(OPTIMIZE_RETURN) || !defined(DONT_TOUCH_ADDRESSES) */
X
Xint
Xbinary_search(name, address)
Xchar *name, *address;
X{
X	/* binary search file for name.  Return 0 if found, -1 if not */
X
X	char machine[40];
X	register long first = 0, last, middle;
X	register int  compare;
X
X	address[0] = '\0';
X
X	last = size_of_pathfd;
X
X	do {
X
X	  middle = (long) ((first+last) / 2);
X
X	  get_entry(machine, address, pathfd, middle);
X
X	  compare = strcmp(name, machine);
X
X	  if (compare < 0) 
X	    last = middle - 1;
X	  else if (compare == 0)
X	    return(0);
X	  else  /* greater */
X	    first = middle + 1; 
X	} while (absolute(last) - absolute(first) > FIND_DELTA);
X
X	/* It could be that our target entry lies exactly at `first'.
X	 * Since get_entry() compares at the entry beginning after
X	 * the passed offset (unless it's 0), we need to decrement it
X	 * (unless it's 0), and give it one more try.
X	 */
X	get_entry(machine, address, pathfd, (first == 0L ? first : --first));
X	compare = strcmp(name, machine);
X	return(compare == 0 ? 0 : -1);
X}
X
Xget_entry(machine, address, fileid, offset)
Xchar *machine, *address;
XFILE *fileid;
Xlong offset;
X{
X	/** get entry...return machine and address immediately
X	    following given offset in fileid.  **/
X
X	(void) fseek(fileid, offset, 0);
X
X	/* To get to the beginning of a record, if we are not at offset 0,
X	 * read until we hit an end-of-line */
X
X	if(offset != 0L)
X	  while (getc(fileid) != '\n')
X	     ;
X
X	fscanf(fileid, "%s\t%s", machine, address);
X}
X
X#ifndef DONT_TOUCH_ADDRESSES
Xinit_findnode()
X{
X	/** Initialize the FILE and 'size_of_file' values for the 
X	    findnode procedure **/
X
X	struct stat buffer;
X	char   *path_filename;
X
X#ifdef USE_DBM
X	char buf[BUFSIZ];
X
X	sprintf(buf,"%s.pag", pathfile);
X	path_filename = buf;
X#else
X	path_filename = pathfile;
X#endif
X
X	if (stat(path_filename, &buffer) == -1) {
X	  dprint(2, (debugfile, 
X		  "Warning: pathalias file \"%s\" wasn't found by %s\n", 
X		  path_filename, "init_findnode"));
X	  size_of_pathfd = 0;
X	  return;
X	}
X
X	size_of_pathfd = (long) buffer.st_size;
X
X#ifdef USE_DBM
X	
X	if (dbminit(pathfile) != 0) {
X	  dprint(2, (debugfile,
X		 "Warning: couldn't initialize DBM database %s\n", 
X		 pathfile));
X	  dprint(2, (debugfile, "** %s - %s **\n\n", error_name(errno),
X		     error_description(errno)));
X	  size_of_pathfd = 0;	/* error flag, in this case */
X	  return;
X	}
X 	
X	return;
X#else
X
X	if ((pathfd = fopen(pathfile,"r")) == NULL) {
X	  dprint(2, (debugfile,
X		"Warning: Can't read pathalias file \"%s\" within %s\n", 
X		   pathfile, "init_findnode"));
X	  size_of_pathfd = 0;
X	}
X	else
X	  dprint(3, (debugfile, "\nOpened '%s' as pathalias database.\n\n", 
X		  pathfile));
X#endif
X}
X#endif /* DONT_TOUCH_ADDRESSES */
X
Xchar *find_path_to(machine, printf_format)
Xchar *machine;
Xint   printf_format;
X{
X	/** Returns either the path to the specified machine or NULL if
X	    not found.  If "printf_format" is TRUE, then it leaves the
X	    '%s' intact, otherwise it assumes that the address is a uucp
X	    address for the domain expansion program and removes the
X	    last three characters of the expanded name ("!%s") since
X	    they're redundant with the expansion!
X        **/
X
X	static char buffer[SLEN];	/* space for path */
X
X	if (size_of_pathfd > 0)
X	  if (binary_search(machine, buffer) != -1) {   	/* found it! */
X	    if (! printf_format && strlen(buffer) > 3)
X	      buffer[strlen(buffer)-3] = '\0';
X	    return( (char *) buffer);
X	  }
X
X	return(NULL);			            /* failed if it's here! */
X}
SHAR_EOF
echo "File src/aliasdb.c is complete"
chmod 0444 src/aliasdb.c || echo "restore of src/aliasdb.c fails"
echo "x - extracting src/aliaslib.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/aliaslib.c &&
X
Xstatic char rcsid[] = "@(#)$Id: aliaslib.c,v 4.1 90/04/28 22:42:29 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
X *
X * 			Copyright (c) 1986, 1987 Dave Taylor
X * 			Copyright (c) 1988, 1989, 1990 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X *	Syd Weinstein, Elm Coordinator
X *	elm@DSI.COM			dsinc!elm
X *
X *******************************************************************************
X * $Log:	aliaslib.c,v $
X * Revision 4.1  90/04/28  22:42:29  syd
X * checkin of Elm 2.3 as of Release PL0
X * 
X *
X ******************************************************************************/
X
X/** Library of functions dealing with the alias system...
X
X **/
X
X#include "headers.h"
X#include <ctype.h>
X
Xchar *get_alias_address(), *get_token(), *strpbrk(), *index();
Xlong lseek();
X
X#ifdef DONT_TOUCH_ADDRESSES
Xchar *expand_system();
X#endif
X
X/*
X * Expand "name" as an alias and return a pointer to static data containing
X * the expansion.  If "name" is not an alias, then NULL is returned.
X */
Xchar *get_alias_address(name, mailing)
Xchar *name;	/* name to expand as an alias				*/
Xint mailing;	/* TRUE to fully expand group names & recursive aliases	*/
X{
X	static char buffer[VERY_LONG_STRING];
X	char *bufptr;
X	int bufsize;
X
X	/* reads files iff changed since last read */
X	read_alias_files();
X
X	/* if name is an alias then return its expansion */
X	bufptr = buffer;
X	bufsize = sizeof(buffer);
X	if ( do_get_alias(name, &bufptr, &bufsize, mailing, FALSE, 0) )
X	  return buffer+2;	/* skip comma/space from add_name_to_list() */
X
X	/* nope...not an alias */
X	return (char *) NULL;
X}
X
X
X/*
X * Determine if "name" is an alias, and if so expand it and store the result in
X * "*bufptr".  TRUE returned if any expansion occurs, else FALSE is returned.
X */
Xint do_get_alias(name, bufptr, bufsizep, mailing, sysalias, depth)
Xchar *name;	/* name to expand as an alias				*/
Xchar **bufptr;	/* place to store result of expansion			*/
Xint *bufsizep;	/* available space in the buffer			*/
Xint mailing;	/* TRUE to fully expand group names & recursive aliases	*/
Xint sysalias;	/* TRUE to suppress checks of the user's aliases	*/
Xint depth;	/* recursion depth - initially call at depth=0		*/
X{
X	char abuf[LONG_STRING];
X	int loc;
X
X	/* update the recursion depth counter */
X	++depth;
X
X	dprint(6, (debugfile, "%*s->attempting alias expansion on \"%s\"\n",
X		(depth*2), "", name));
X
X	/* strip out (comments) and leading/trailing whitespace */
X	remove_possible_trailing_spaces( name = strip_parens(name) );
X	for ( ; isspace(*name)  ; ++name ) ;
X
X	/* throw back empty addresses */
X	if ( *name == '\0' )
X	  return FALSE;
X
X	/* check for a user alias, unless in the midst of sys alias expansion */
X	if ( !sysalias && user_data != -1 ) {
X	  if ( (loc = find(name, user_hash_table, MAX_UALIASES)) >= 0 ) {
X	    lseek(user_data, ntohl(user_hash_table[loc].byte), 0L);
X	    get_line(user_data, abuf);
X	    goto do_expand;
X	  }
X	}
X
X	/* check for a system alias */
X	if ( system_data != -1 ) {
X	  if ( (loc = find(name, system_hash_table, MAX_SALIASES)) >= 0 ) {
X	    lseek(system_data, ntohl(system_hash_table[loc].byte), 0L);
X	    get_line(system_data, abuf);
X	    sysalias = TRUE;
X	    goto do_expand;
X	  }
X	}
X
X	/* nope...this name wasn't an alias */
X	return FALSE;
X
Xdo_expand:
X
X	/* at this point, alias is expanded into "abuf" - now what to do... */
X
X	dprint(7, (debugfile, "%*s  ->expanded alias to \"%s\"\n",
X	    (depth*2), "", abuf));
X
X	/* check for an exact match */
X	loc = strlen(name);
X	if (strncmp(name, abuf, loc) == 0 && (abuf[loc] == ' ' || abuf[loc] == '\0'))
X#ifdef DONT_TOUCH_ADDRESSES
X	  return add_name_to_list(abuf, bufptr, bufsizep);
X#else
X	  return add_name_to_list(expand_system(abuf, TRUE), bufptr, bufsizep);
X#endif
X
X	/* see if we are stuck in a loop */
X	if ( depth > 12 ) {
X	  dprint(2, (debugfile,
X	      "alias expansion loop detected at \"%s\" - bailing out\n", name));
X	    error1("Error expanding \"%s\" - probable alias definition loop.",
X	      name);
X	    return FALSE;
X	}
X
X	/* see if the alias equivalence is a group name */
X	if ( mailing && abuf[0] == '!' )
X	  return do_expand_group(abuf+1, bufptr, bufsizep, sysalias, depth);
X
X	/* see if the alias equivalence is an email address */
X	if ( strpbrk(abuf,"!@:") != NULL ) {
X#ifdef DONT_TOUCH_ADDRESSES
X	  return add_name_to_list(abuf, bufptr, bufsizep);
X#else
X	  return add_name_to_list(expand_system(abuf, TRUE), bufptr, bufsizep);
X#endif
X	}
X
X	/* see if the alias equivalence is itself an alias */
X	if ( mailing && do_get_alias(abuf,bufptr,bufsizep,TRUE,sysalias,depth) )
X	  return TRUE;
X
X	/* the alias equivalence must just be a local address */
X	return add_name_to_list(abuf, bufptr, bufsizep);
X}
X
X
X/*
X * Expand the comma-delimited group of names in "group", storing the result
X * in "*bufptr".  Returns TRUE if expansion occurs OK, else FALSE in the
X * event of errors.
X */
Xint do_expand_group(group, bufptr, bufsizep, sysalias, depth)
Xchar *group;	/* group list to expand					*/
Xchar **bufptr;	/* place to store result of expansion			*/
Xint *bufsizep;	/* available space in the buffer			*/
Xint sysalias;	/* TRUE to suppress checks of the user's aliases	*/
Xint depth;	/* nesting depth					*/
X{
X	char *name;
X
X	/* go through each comma-delimited name in the group */
X	while ( group != NULL ) {
X
X	  /* extract the next name from the list */
X	  for ( name = group ; isspace(*name) ; ++name ) ;
X	  if ( (group = index(name,',')) != NULL )
X	      *group++ = '\0';
X	  remove_possible_trailing_spaces(name);
X	  if ( *name == '\0' )
X	    continue;
X
X	  /* see if this name is really an alias */
X	  if ( do_get_alias(name, bufptr, bufsizep, TRUE, sysalias, depth) )
X	    continue;
X
X	  /* verify it is a valid address */
X	  if ( !valid_name(name) ) {
X	    dprint(3, (debugfile,
X		"Illegal address %s during list expansion in %s\n",
X		name, "do_get_alias"));
X	    error1("%s is an illegal address!", name);
X	    return FALSE;
X	  }
X
X	  /* add it to the list */
X	  if ( !add_name_to_list(name, bufptr, bufsizep) )
X	    return FALSE;
X
X	}
X
X	return TRUE;
X}
X
X
X/*
X * Append "<comma><space>name" to the list, checking to ensure the buffer
X * does not overflow.  Upon return, *bufptr and *bufsizep will be updated to
X * reflect the stuff added to the buffer.  If a buffer overflow would occur,
X * an error message is printed and FALSE is returned, else TRUE is returned.
X */
Xint add_name_to_list(name,bufptr,bufsizep)
Xregister char *name;	/* name to append to buffer			*/
Xchar **bufptr;		/* pointer to pointer to end of buffer		*/
Xint *bufsizep;		/* pointer to space remaining in buffer		*/
X{
X	register char *dest = *bufptr;
X	register int bufsize = *bufsizep;
X
X	if ( bufsize < 2 )
X	  return FALSE;
X	*dest++ = ','; --bufsize;
X	*dest++ = ' '; --bufsize;
X
X	while ( *name != '\0' && --bufsize > 0 )
X	  *dest++ = *name++ ;
X	*dest = '\0';
X
X	*bufptr = dest;
X	*bufsizep = bufsize;
X	if ( bufsize <= 0 ) {
X	  error("Alias expansion is too long.");
X	  return FALSE;
X	}
X
X	return TRUE;
X}
X
X
X
X#ifndef DONT_TOUCH_ADDRESSES
Xchar *expand_system(buffer, show_errors)
Xchar *buffer;
Xint   show_errors;
X{
X	/** This routine will check the first machine name in the given path
X	    (if any) and expand it out if it is an alias...if not, it will
X	    return what it was given.  If show_errors is false, it won't
X	    display errors encountered...
X	**/
X
X	dprint(6, (debugfile, "expand_system(%s, show-errors=%s)\n", buffer,
X		onoff(show_errors)));
X	findnode(buffer, show_errors);
X
X	return( (char *) buffer);
X}
X#endif
X
Xint
Xfind(word, table, size)
Xchar *word;
Xstruct alias_rec table[];
Xint size;
X{
X	/** find word and return loc, or -1 **/
X	register int loc;
X
X	if (strlen(word) > 20) {
X	  dprint(3, (debugfile, "Overly long alias name entered: %s\n", word));
X	  error1("Bad alias name: %s.  Too long.\n", word);
X	  return(-1);
X	}
X
X	loc = hash_it(word, size);
X
X	while (stricmp(word, table[loc].name) != 0) {
X	  if (table[loc].name[0] == '\0')
X	    return(-1);
X	  loc = (loc + 1) % size;
X	}
X
X	return(loc);
X}
X
Xint
Xstricmp(s1,s2)
Xregister char *s1, *s2;
X{
X	/* case insensitive comparison */
X	register int d;
X	for (;;) {
X	  d = ( isupper(*s1) ? tolower(*s1) : *s1 )
X		  - ( isupper(*s2) ? tolower(*s2) : *s2 ) ;
X	  if ( d != 0 || *s1 == '\0' || *s2 == '\0' )
X	    return d;
X	  ++s1;
X	  ++s2;
X	}
X	/*NOTREACHED*/
X}
X
Xint
Xhash_it(string, table_size)
Xregister char *string;
Xint   table_size;
X{
X	/** compute the hash function of the string, returning
X	    it (mod table_size) **/
X
X	register int sum = 0;
X	for ( ; *string != '\0' ; ++string )
X	  sum += (int) ( isupper(*string) ? tolower(*string) : *string );
X
X	return(sum % table_size);
X}
X
Xget_line(fd, buffer)
Xint fd;
Xchar *buffer;
X{
X	/* Read from file fd.  End read upon reading either
X	   EOF or '\n' character (this is where it differs
X	   from a straight 'read' command!) */
X
X	register int i= 0;
X	char     ch;
X
X	while (read(fd, &ch, 1) > 0)
X	  if (ch == '\n' || ch == '\r') {
X	    buffer[i] = 0;
X	    return;
X	  }
X	  else
X	    buffer[i++] = ch;
X}
SHAR_EOF
chmod 0444 src/aliaslib.c || echo "restore of src/aliaslib.c fails"
echo "x - extracting src/args.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/args.c &&
X
Xstatic char rcsid[] = "@(#)$Id: args.c,v 4.1 90/04/28 22:42:31 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
X *
X * 			Copyright (c) 1986, 1987 Dave Taylor
X * 			Copyright (c) 1988, 1989, 1990 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X *	Syd Weinstein, Elm Coordinator
X *	elm@DSI.COM			dsinc!elm
X *
X *******************************************************************************
X * $Log:	args.c,v $
X * Revision 4.1  90/04/28  22:42:31  syd
X * checkin of Elm 2.3 as of Release PL0
X * 
X *
X ******************************************************************************/
X
X/** starting argument parsing routines for ELM system...
X
X**/
X
X#include "headers.h"
X#include "patchlevel.h"
X
Xextern char *optarg;		/* optional argument as we go */
Xextern int   optind;			/* argnum + 1 when we leave   */
X
Xvoid exit();	/* just keeping lint happy.... */
X
Xchar *
Xparse_arguments(argc, argv, to_whom)
Xint argc;
Xchar *argv[], *to_whom;
X{
X	/** Set flags according to what was given to program.  If we are 
X	    fed a name or series of names, put them into the 'to_whom' buffer
X	    and if the check_only flag wasn't presented, set mail_only to ON,
X	    and if stdin is not a tty, set batch_only  to ON;
X	    Return req_mfile, which points to a named mail file or is empty.
X	    **/
X
X	register int c = 0;
X	char *strcpy();
X	static char req_mfile[SLEN];
X
X	to_whom[0] = '\0';
X	batch_subject[0] = '\0';
X
X        while ((c = getopt(argc, argv, "?acd:f:hkKms:Vvwz")) != EOF) {
X	   switch (c) {
X	     case 'a' : arrow_cursor++;		break;
X	     case 'c' : check_only++;		break;
X	     case 'd' : debug = atoi(optarg);	break;
X	     case 'f' : strcpy(req_mfile, optarg);	break;
X	     case '?' :
X	     case 'h' : args_help();
X	     case 'k' : hp_terminal++;	break;
X	     case 'K' : hp_terminal++; hp_softkeys++;	break;
X	     case 'm' : mini_menu = 0;	break;
X	     case 's' : strcpy(batch_subject, optarg);	break;
X             case 'V' : sendmail_verbose++;     break;
X	     case 'v' : args_version();
X	     case 'w' : warnings = 0;	break;
X	     case 'z' : check_size++;   break;
X	    }
X	 }
X
X
X#ifndef DEBUG
X	if (debug)
X	  printf(
X     "Warning: system created without debugging enabled - request ignored\n");
X	debug = 0;
X#endif
X
X	if (optind < argc) {
X	  while (optind < argc) {
X		if (strlen(to_whom) + strlen(to_whom[0] != '\0'? " " : "") +
X			strlen(argv[optind]) > SLEN)
X				exit(printf("\n\rToo many addresses, or addresses too long!\n\r"));
X
X	    sprintf(to_whom, "%s%s%s", to_whom, 
X	            to_whom[0] != '\0'? " " : "", argv[optind]);
X	    if(!check_only)
X	      mail_only++;
X	    optind++;
X	  }
X	  check_size = 0;	/* NEVER do this if we're mailing!! */
X	}
X
X	 if (strlen(batch_subject) > 0 && ! mail_only) 
X	   exit(printf(
X     "\n\rDon't understand specifying a subject and no-one to send to!\n\r"));
X
X	if (!isatty(fileno(stdin)) && !check_only) {
X	  batch_only = ON;
X	  if(*batch_subject == '\0')
X	    strcpy(batch_subject, DEFAULT_BATCH_SUBJECT);
X	}
X	return(req_mfile);
X
X
X}
X
Xargs_help()
X{
X	/**  print out possible starting arguments... **/
X
X	printf("\nPossible Starting Arguments for ELM program:\n\n");
X	printf("\targ\t\t\tMeaning\n");
X	printf("\t -a \t\tArrow - use the arrow pointer regardless\n");
X	printf("\t -c \t\tCheckalias - check the given aliases only\n");
X	printf("\t -dn\t\tDebug - set debug level to 'n'\n");
X	printf(
X	  "\t -fx\t\tFolder - read folder 'x' rather than incoming mailbox\n");
X	printf("\t -h \t\tHelp - give this list of options\n");
X	printf("\t -k \t\tKeypad - enable HP 2622 terminal keyboard\n");
X	printf("\t -K \t\tKeypad&softkeys - enable use of softkeys + \"-k\"\n");
X	printf("\t -m \t\tMenu - Turn off menu, using more of the screen\n");
X	printf("\t -sx\t\tSubject 'x' - for batchmailing\n");
X        printf("\t -V \t\tEnable sendmail voyeur mode.\n");
X	printf("\t -v \t\tPrint out ELM version information.\n");
X	printf("\t -w \t\tSupress warning messages...\n");
X	printf("\t -z \t\tZero - don't enter ELM if no mail is pending\n");
X	printf("\n");
X	printf("\n");
X	exit(1);
X}
X
Xargs_version()
X{
X	/** print out version information **/
X
X	printf("\nElm Version and Identification Information:\n\n");
X	printf("\tElm %s PL%d, of %s\n",VERSION,PATCHLEVEL,VERS_DATE);
X	printf("\t(C) Copyright 1986, 1987 Dave Taylor\n");
X	printf("\t(C) Copyright 1988, 1989, 1990 USENET Community Trust\n");
X	printf("\t----------------------------------\n");
X	printf("\tConfigured %s\n", CONFIGURE_DATE);
X	printf("\t----------------------------------\n");
X
X#ifdef USE_EMBEDDED_ADDRESSES
X	printf("\tFrom: and Reply-To: addresses are good: USE_EMBEDDED_ADDRESSES\n");
X#else /* USE_EMBEDDED_ADDRESSES */
X	printf("\tFrom: and Reply-To: addresses ignored: not USE_EMBEDDED_ADDRESSES\n");
X#endif /* USE_EMBEDDED_ADDRESSES */
X
X#ifdef OPTIMIZE_RETURN
X	printf("\tReturn addresses will be optimized: OPTIMIZE_RETURN\n");
X#else /* OPTIMIZE_RETURN */
X	printf("\tReturn addresses will not be optimized: not OPTIMIZE_RETURN\n");
X#endif
X
X#ifdef INTERNET
X	printf("\tPrefers Internet address formats: INTERNET\n");
X#else /* INTERNET */
X	printf("\tInternet address formats not used: not INTERNET\n");
X#endif /* INTERNET */
X
X#ifdef DEBUG
X	printf("\tDebug options are available: DEBUG\n");
X#else /* DEBUG */
X	printf("\tNo debug options are available: not DEBUG\n");
X#endif /* DEBUG */
X		
X#ifdef CRYPT
X	printf("\tCrypt function enabled: CRYPT\n");
X#else /* CRYPT */
X	printf("\tCrypt function disabled: not CRYPT\n");
X#endif /* CRYPT */
X
X#ifdef ALLOW_MAILBOX_EDITING
X	printf("\tMailbox editing included: ALLOW_MAILBOX_EDITING\n");
X#else /* ALLOW_MAILBOX_EDITING */
X	printf("\tMailbox editing not included: not ALLOW_MAILBOX_EDITING\n");
X#endif /* ALLOW_MAILBOX_EDITING */
X
X#ifdef ENABLE_CALENDAR
X	printf("\tCalendar file feature enabled: ENABLE_CALENDAR\n");
X	printf("\t\t(Default calendar file is %s)\n",dflt_calendar_file);
X#else /* ENABLE_CALENDAR */
X	printf("\tCalendar file feature disabled: not ENABLE_CALENDAR\n");
X#endif /* ENABLE_CALENDAR */
X
X	printf("\n\n");
X	exit(1);
X
X}
X
SHAR_EOF
chmod 0444 src/args.c || echo "restore of src/args.c fails"
echo "x - extracting src/bouncebk.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/bouncebk.c &&
X
Xstatic char rcsid[] = "@(#)$Id: bouncebk.c,v 4.1 90/04/28 22:42:33 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
X *
X * 			Copyright (c) 1986, 1987 Dave Taylor
X * 			Copyright (c) 1988, 1989, 1990 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X *	Syd Weinstein, Elm Coordinator
X *	elm@DSI.COM			dsinc!elm
X *
X *******************************************************************************
X * $Log:	bouncebk.c,v $
X * Revision 4.1  90/04/28  22:42:33  syd
X * checkin of Elm 2.3 as of Release PL0
X * 
X *
X ******************************************************************************/
X
X/** This set of routines implement the bounceback feature of the mailer.
X    This feature allows mail greater than 'n' hops away (n specified by
X    the user) to have a 'cc' to the user through the remote machine.  
X
X    Due to the vagaries of the Internet addressing (uucp -> internet -> uucp)
X    this will NOT generate bounceback copies with mail to an internet host!
X
X**/
X
X#include "headers.h"
X
Xchar *bounce_off_remote(),		/* forward declaration */
X     *strcat(), *strcpy();
X
Xint
Xuucp_hops(to)
Xchar *to;
X{	
X	/** Given the entire "To:" list, return the number of hops in the
X	    first address (a hop = a '!') or ZERO iff the address is to a
X  	    non uucp address.
X	**/
X
X	register int hopcount = 0, iindex;
X
X	for (iindex = 0; ! whitespace(to[iindex]) && to[iindex] != '\0'; iindex++) {
X	  if (to[iindex] == '!')
X	    hopcount++;
X	  else if (to[iindex] == '@' || to[iindex] == '%' || to[iindex] == ':')
X	    return(0);	/* don't continue! */
X	}
X
X	return(hopcount);
X}
X	
Xchar *bounce_off_remote(to)
Xchar *to;
X{
X	/** Return an address suitable for framing (no, that's not it...)
X	    Er, suitable for including in a 'cc' line so that it ends up
X	    with the bounceback address.  The method is to take the first 
X	    address in the To: entry and break it into machines, then 
X	    build a message up from that.  For example, consider the
X	    following address:
X			a!b!c!d!e!joe
X	    the bounceback address would be;
X			a!b!c!d!e!d!c!b!a!ourmachine!ourname
X	    simple, eh?
X	**/
X
X	static char address[LONG_STRING];	/* BEEG address buffer! */
X
X	char   host[MAX_HOPS][NLEN];	/* for breaking up addr */
X	register int hostcount = 0, hindex = 0, 
X	       iindex;
X
X	for (iindex = 0; !whitespace(to[iindex]) && to[iindex] != '\0'; iindex++) {
X	  if (to[iindex] == '!') {
X	    host[hostcount][hindex] = '\0';
X	    hostcount++;
X	    hindex = 0;
X	  }
X	  else 
X	    host[hostcount][hindex++] = to[iindex];
X	}
X
X	/* we have hostcount hosts... */
X
X	strcpy(address, host[0]);	/* initialize it! */
X
X	for (iindex=1; iindex < hostcount; iindex++) {
X	  strcat(address, "!");
X	  strcat(address, host[iindex]);
X	}
X	
X	/* and now the same thing backwards... */
X
X	for (iindex = hostcount -2; iindex > -1; iindex--) {
X	  strcat(address, "!");
X	  strcat(address, host[iindex]);
X	}
X
X	/* and finally, let's tack on our machine and login name */
X
X	strcat(address, "!");
X	strcat(address, hostname);
X	strcat(address, "!");
X	strcat(address, username);
X
X	/* and we're done!! */
X
X	return( (char *) address );
X}
SHAR_EOF
chmod 0444 src/bouncebk.c || echo "restore of src/bouncebk.c fails"
echo "x - extracting src/builtin.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/builtin.c &&
X
Xstatic char rcsid[] = "@(#)$Id: builtin.c,v 4.1 90/04/28 22:42:34 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
X *
X * 			Copyright (c) 1986, 1987 Dave Taylor
X * 			Copyright (c) 1988, 1989, 1990 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X *	Syd Weinstein, Elm Coordinator
X *	elm@DSI.COM			dsinc!elm
X *
X *******************************************************************************
X * $Log:	builtin.c,v $
X * Revision 4.1  90/04/28  22:42:34  syd
X * checkin of Elm 2.3 as of Release PL0
X * 
X *
X ******************************************************************************/
X
X/** This is the built-in pager for displaying messages while in the Elm
X    program.  It's a bare-bones pager with precious few options. The idea
X    is that those systems that are sufficiently slow that using an external
X    pager such as 'more' is too slow, then they can use this!
X
X    Also added support for the "builtin+" pager (clears the screen for
X    each new page) including a two-line overlap for context...
X
X**/
X
X#include "headers.h"
X#include <ctype.h>
X
X#define  BEEP		007		/* ASCII Bell character */
X
Xstatic	unfilled_lines,
X	form_title;
X
Xint	lines_displayed,	    /* total number of lines displayed      */
X	total_lines_to_display,	    /* total number of lines in message     */
X	pages_displayed; 	    /* for the nth page titles and all      */
X
Xstart_builtin(lines_in_message)
Xint lines_in_message;
X{
X	/** clears the screen and resets the internal counters... **/
X
X	dprint(8,(debugfile, 
X		"displaying %d lines from message using internal pager\n",
X		lines_in_message));
X
X	unfilled_lines = LINES;
X	form_title = 1;
X	lines_displayed = 0;
X        pages_displayed = 1;
X
X	total_lines_to_display = lines_in_message;
X}
X
Xextern int tabspacing;
X
Xint
Xnext_line(inputptr, output, width)
Xchar **inputptr, *output;
Xregister unsigned width;
X{
X	/* Copy characters from input to output and copy
X	 * remainder of output to output. In copying use ^X notation for
X	 * control characters, '?' non-ascii characters, expand tabs
X	 * to correct number of spaces till next tab stop.
X	 * Column zero of the next line is considered to be the tab stop
X	 * that follows the last one that fits on a line.
X	 * Copy until newline/return encountered, null char encountered,
X	 * width characters producted in output buffer.
X	 * Formfeed is handled exceptionally. If encountered it
X	 * is removed from input and 1 is returned. Otherwise 0 is returned.
X	 */
X
X	register char *optr, *iptr;
X	register unsigned chars_output, nt;
X	int ret_val;
X
X	optr = output;
X	iptr = *inputptr;
X	chars_output = 0;
X
X	ret_val = 0;	/* presume no formfeed */
X	while(1) {
X
X	  if(chars_output >= width) {		/* no more room on line */
X	    *optr++ = '\n';
X	    *optr++ = '\r';
X	    /* if next input character is newline or return,
X	     * we can skip over it since we are outputing a newline anyway */ 
X	    if((*iptr == '\n') || (*iptr == '\r'))
X	      iptr++;
X	    break;		
X	  } else if (*iptr == '\n' || *iptr == '\r') {	/*newline or return */
X	    *optr++ = '\n';
X	    *optr++ = '\r';
X	    iptr++;
X	    break;			/* end of line */
X	  } else if(*iptr == '\f') {		/* formfeed */
X	    /* if next input character is newline or return,
X	     * we can skip over it since we are outputing a formfeed anyway */ 
X	    if((*++iptr == '\n') || (*iptr == '\r'))
X	      iptr++;
X	    ret_val = 1;
X	    break;			/* leave rest of screen clear */
X	  } else if(*iptr == '\0') {		/* none left in input string */
X	    break;
X	  } else if(*iptr == '\t') {		/* tab stop */
X	    if((nt=next_tab(chars_output+1)) > width) {
X	      *optr++ = '\n';		/* won't fit on this line - autowrap */
X	      *optr++ = '\r';		/* tab by tabbing so-to-speak to 1st */
X	      iptr++;			/* column of next line */
X	      break;
X	    } else {		/* will fit - output proper num of spaces */
X	      while(chars_output < nt-1) {
X		chars_output++;
X		*optr++ = ' ';
X	      }
X	      iptr++;
X	    }
X	  } else if(isprint(*iptr)) {
X	    *optr++ = *iptr++;			/* printing character */
X	    chars_output++;
X	  } else {			/* non-white space control character */
X	    if(chars_output + 2 <= width) {
X	      *optr++ = '^';	
X	      *optr++ = (*iptr == '\177' ? '?' : (*iptr&0177) + 'A' - 1);
X	      iptr++;
X	      chars_output += 2;
X	    } else {			/* no space on line for both chars */
X	      break;
X	    }
X	  }
X	}
X	*optr = '\0';
X	*inputptr = iptr;
X	return(ret_val);
X}
X
X
Xint
Xdisplay_line(input_line)
Xchar *input_line;
X{
X	/** Display the given line on the screen, taking into account such
X	    dumbness as wraparound and such.  If displaying this would put
X	    us at the end of the screen, put out the "MORE" prompt and wait
X	    for some input.   Return non-zero if the user terminates the
X	    paging (e.g. 'i') or zero if we should continue. Also, 
X            this will pass back the value of any character the user types in 
X	    at the prompt instead, if needed... (e.g. if it can't deal with
X	    it at this point)
X	**/
X	
X	char *pending, footer[SLEN], display_buffer[SLEN], ch;
X	int formfeed, lines_more;
X
X#ifdef MMDF
X	if (strcmp(input_line, MSG_SEPERATOR) == 0)
X	  strcpy(input_line," ");
X#endif /* MMDF */
X	pending = input_line;
X	CarriageReturn();
X
X	do {
X
X	  /* while there is more space on the screen - leave prompt line free */
X	  while(unfilled_lines > 0) {
X
X	    /* display a screen's lineful of the input line
X	     * and reset pending to point to remainder of input line */
X	    formfeed = next_line(&pending, display_buffer, COLUMNS);
X
X	    if(*display_buffer == '\0') {	/* no line to display */
X	      if(!formfeed)	/* no "formfeed" to display
X	     			 * need more lines for screen */
X		return(FALSE);
X	    } else
X	      Write_to_screen(display_buffer, 0);
X
X	    /* if formfeed, clear remainder of screen */
X	    if(formfeed) {
X	      CleartoEOS();
X	      unfilled_lines=0;
X	    }
X	    else
X	      unfilled_lines--;
X
X	    /* if screen is not full (leave room for prompt)
X	     * but we've used up input line, return */
X
X	    if(unfilled_lines > 0 && *pending == '\0')
X	      return(FALSE);	/* we need more lines to fill screen */
X
X	    /* otherwise continue to display next part of input line */
X	  }
X
X	  /* screen is now full - prompt for user input */
X	  lines_more = total_lines_to_display - lines_displayed;
X	  sprintf(footer,
X		  ( (user_level == 0) ?
X  " There %s %d line%s left (%d%%). Press <space> for more, or 'i' to return. "
X		  : (user_level == 1) ?
X  " %s%d line%s more (%d%%). Press <space> for more, 'i' to return. "
X		  :
X  " %s%d line%s more (you've seen %d%%) "),
X		   (user_level == 0 ?
X		     (lines_more == 1 ? "is" : "are") : ""),
X		   lines_more, plural(lines_more),
X		   (int)((100L * lines_displayed) / total_lines_to_display));
X 
X	  MoveCursor(LINES, 0);
X	  StartBold();
X	  Write_to_screen(footer, 0);
X	  EndBold();
X
X	  switch(ch = ReadCh()) {
X
X	    case '\n':
X	    case '\r':	/* scroll down a line */
X			unfilled_lines = 1;
X			ClearLine(LINES);
X			break;
X
X	    case ' ':	/* scroll a screenful */
X			unfilled_lines = LINES;
X			if(clear_pages) {
X			  ClearScreen();
X			  MoveCursor(0,0);
X			  CarriageReturn();
X
X			  /* output title */
X			  if(title_messages && filter) {
X			    title_for_page(++pages_displayed);
X			    unfilled_lines -= 2;
X			  }
X			} else ClearLine(LINES);
X
X			/* and keep last line to be first line of next
X			 * screenful unless we had a formfeed */
X			if(!formfeed) {
X			  if(clear_pages)
X			    Write_to_screen(display_buffer, 0);
X			  unfilled_lines--;
X			}
X			break;
X
X	    default:	return(ch);
X	  }
X	  CarriageReturn();
X	} while(*pending);
X	return(FALSE);
X}
X	  
Xtitle_for_page(page)
Xint page;
X{
X	/** Output a nice title for the second thru last pages of the message 
X	    we're currently reading. Note - this code is very similar to
X	    that which produces the title for the first page, except that
X	    page number replaces the date and the method by which it
X	    gets to the screen **/
X
X	static char title1[SLEN], title2[SLEN];
X	char titlebuf[SLEN], title3[SLEN], who[SLEN];
X	static t1_len, t2_len;
X	register int padding, showing_to;
X
X	/* format those parts of the title that are constant for a message */
X	if(form_title) {
X
X	  showing_to = tail_of(headers[current-1]->from, who,
X	    headers[current-1]->to);
X
X	  sprintf(title1, "%s %d/%d  ",
X	      headers[current-1]->status & DELETED ? "[deleted]" :
X	      headers[current-1]->status & FORM_LETTER ? "Form": "Message",
X	      current, message_count);
X	  t1_len = strlen(title1);
X	  sprintf(title2, "%s %s", showing_to? "To" : "From", who);
X	  t2_len = strlen(title2);
X	}
X	/* format those parts of the title that vary between pages of a mesg */
X	sprintf(title3, "  Page %d", page);
X
X	/* truncate or pad title2 portion on the right
X	 * so that line fits exactly to the rightmost column */
X	padding = COLUMNS - (t1_len + t2_len + strlen(title3));
X
X	sprintf(titlebuf, "%s%-*.*s%s\n\r\n\r", title1, t2_len+padding,
X	    t2_len+padding, title2, title3);
X	    /* extra newline is to give a blank line after title */
X
X	Write_to_screen(titlebuf, 0);
X	form_title = 0;
X}
SHAR_EOF
chmod 0444 src/builtin.c || echo "restore of src/builtin.c fails"
echo "x - extracting src/calendar.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/calendar.c &&
X
Xstatic char rcsid[] = "@(#)$Id: calendar.c,v 4.1 90/04/28 22:42:36 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
X *
X * 			Copyright (c) 1986, 1987 Dave Taylor
X * 			Copyright (c) 1988, 1989, 1990 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X *	Syd Weinstein, Elm Coordinator
X *	elm@DSI.COM			dsinc!elm
X *
X *******************************************************************************
X * $Log:	calendar.c,v $
X * Revision 4.1  90/04/28  22:42:36  syd
X * checkin of Elm 2.3 as of Release PL0
X * 
X *
X ******************************************************************************/
X
X/** This routine implements a rather snazzy idea suggested by Warren
X    Carithers of the Rochester Institute of Technology that allows
X    mail to contain entries formatted in a manner that will allow direct
X    copying into a users calendar program.
X
X    All lines in the current message beginning with "->", e.g.
X
X	-> Mon 04/21 1:00p meet with chairman candidate
X
X    get copied into the user's calendar file.
X
X**/
X
X#include "headers.h"
X
X#ifdef ENABLE_CALENDAR		/* if not defined, this will be an empty file */
X
X#include <errno.h>
X
Xextern int errno;
X
Xchar *error_name(), *error_description(), *strcpy();
X
Xscan_calendar()
X{
X	FILE *calendar;
X	int  count;
X
X	/* First step is to open the calendar file for appending... **/
X
X	if (can_open(calendar_file, "a") != 0) {
X	  dprint(2, (debugfile,
X		  "Error: wrong permissions to append to calendar %s\n",
X		  calendar_file));
X	  dprint(2, (debugfile, "** %s - %s **\n",
X		  error_name(errno), error_description(errno)));
X	  error1("Not able to append to file %s!", calendar_file);
X	  return; 
X	}
X
X	save_file_stats(calendar_file);
X
X	if ((calendar = fopen(calendar_file,"a")) == NULL) {
X	  dprint(2, (debugfile, 
X		"Error: couldn't append to calendar file %s (scan)\n", 
X		calendar_file));
X	  dprint(2, (debugfile, "** %s - %s **\n",
X		  error_name(errno), error_description(errno)));
X	  error1("Couldn't append to file %s!", calendar_file);
X	  return; 
X	}
X	
X	count = extract_info(calendar);
X
X	fclose(calendar);
X
X	restore_file_stats(calendar_file);
X
X	if (count > 0)
X	  error2("%d entr%s saved in calendar file.", 
X		 count, count > 1 ? "ies" : "y");
X	else 
X	  error("No calendar entries found in that message.");
X
X	return;
X}
X
Xint
Xextract_info(save_to_fd)
XFILE *save_to_fd;
X{
X	/** Save the relevant parts of the current message to the given
X	    calendar file.  The only parameter is an opened file
X	    descriptor, positioned at the end of the existing file **/
X	    
X	register int entries = 0, lines;
X	char buffer[SLEN], *cp, *is_cal_entry();
X
X    	/** get to the first line of the message desired **/
X
X    	if (fseek(mailfile, headers[current-1]->offset, 0) == -1) {
X       	  dprint(1,(debugfile, 
X		"ERROR: Attempt to seek %d bytes into file failed (%s)",
X		headers[current-1]->offset, "extract_info"));
X       	  error1("ELM [seek] failed trying to read %d bytes into file.",
X	     	headers[current-1]->offset);
X       	  return(0);
X    	}
X
X        /* how many lines in message? */
X
X        lines = headers[current-1]->lines;
X
X        /* now while not EOF & still in message... scan it! */
X
X	while (lines) {
X
X          if(fgets(buffer, SLEN, mailfile) == NULL)
X	    break;
X
X	  if(buffer[strlen(buffer)-1] == '\n')
X	    lines--;					/* got a full line */
X
X	  if((cp = is_cal_entry(buffer)) != NULL) {
X	    entries++;
X	    fprintf(save_to_fd,"%s", cp);
X	  }
X
X	}
X	dprint(4,(debugfile,
X		"Got %d calender entr%s.\n", entries, entries > 1? "ies":"y"));
X
X	return(entries);
X}
X
Xchar *
Xis_cal_entry(string)
Xregister char *string;
X{
X	/* If string is of the form
X	 *	->{optional white space} {stuff}
X	 * return a pointer to stuff, otherwise return NULL.
X	 */
X	
X	if(strncmp(string, "->", 2) == 0) {
X	  for(string +=2 ; whitespace(*string); string++)
X		  ;
X	  return(string);
X	}
X	return(NULL);
X}
X
X#endif
SHAR_EOF
chmod 0444 src/calendar.c || echo "restore of src/calendar.c fails"
echo "x - extracting src/conn_to.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/conn_to.c &&
X
Xstatic char rcsid[] = "@(#)$Id: conn_to.c,v 4.1 90/04/28 22:42:37 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
X *
X * 			Copyright (c) 1986, 1987 Dave Taylor
X * 			Copyright (c) 1988, 1989, 1990 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X *	Syd Weinstein, Elm Coordinator
X *	elm@DSI.COM			dsinc!elm
X *
X *******************************************************************************
X * $Log:	conn_to.c,v $
X * Revision 4.1  90/04/28  22:42:37  syd
X * checkin of Elm 2.3 as of Release PL0
X * 
X *
X ******************************************************************************/
X
X/** This contains the routine(s) needed to have the Elm mailer figure
X    out what machines the current machine can talk to.
X    It will invoke uuname to a file, then read the file in!
X**/
X
X#include "headers.h"
X
Xchar *strcpy();
X
X#ifndef DONT_TOUCH_ADDRESSES
Xget_connections()
X{
X
X	/** get the direct connections that this machine has
X	    using the uuname routine to get the names.
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
X	if (! warnings) {		/* skip this - they don't care! */
X	  talk_to_sys = NULL;
X	  return;
X	}
X
X	if (strlen(uuname) == 0) {	/* skip this - no way to get connections */
X	  warnings = NO;
X	  talk_to_sys = NULL;
X	  dprint(1, (debugfile, "No uuname - clearing warnings\n"));
X	  error("Warning: no uuname command, clearing option warnings");
X	  return;
X	}
X
X	sprintf(filename, "%s%s%d", temp_dir, temp_uuname, getpid());
X	sprintf(buffer,"%s > %s", uuname, filename);
X
X	if (system_call(buffer, SH, FALSE, FALSE) != 0) {
X	  dprint(1, (debugfile, "Can't get uuname info - system() failed!\n"));
X	  goto unable_to_get;
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	  goto unable_to_get;
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;					/* it all went okay... */
X
Xunable_to_get:
X	unlink(filename);	/* insurance */
X	error("Warning: couldn't figure out system connections...");
X	talk_to_sys = NULL;
X}
X#endif
SHAR_EOF
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 4.1 90/04/28 22:42:39 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
X *
X * 			Copyright (c) 1986, 1987 Dave Taylor
X * 			Copyright (c) 1988, 1989, 1990 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X *	Syd Weinstein, Elm Coordinator
X *	elm@DSI.COM			dsinc!elm
X *
X *******************************************************************************
X * $Log:	curses.c,v $
X * Revision 4.1  90/04/28  22:42:39  syd
X * checkin of Elm 2.3 as of Release PL0
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**/
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 TERMIOS
X#  include <termios.h>
X# if __convex__
X#  include <sys/ioctl.h>	/* non-standard, for TIOCGWINSZ */
X# endif
X#else
X# ifdef TERMIO
X#  include <termio.h>
X# else
X#  include <sgtty.h>
X# endif
X#endif
X
X#include <ctype.h>
X
X#ifdef PTEM
X#  include <sys/types.h>
X#  include <sys/stream.h>
X#  include <sys/ptem.h>
X#endif
X
X#ifdef BSD
X#undef tolower
X#endif
X
X#define TTYIN	0
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 TERMIOS
Xstruct termios _raw_tty,
X	       _original_tty;
X#define	ttgetattr(fd,where)	tcgetattr((fd),(where))
X#define	ttsetattr(fd,where)	tcsetattr((fd),TCSADRAIN,(where))
X#else	/*TERMIOS*/
X# ifdef TERMIO
Xstruct termio _raw_tty, 
X              _original_tty;
X#define	ttgetattr(fd,where)	ioctl((fd),TCGETA,(where))
X#define	ttsetattr(fd,where)	ioctl((fd),TCSETAW,(where))
X# else
Xstruct sgttyb _raw_tty,
X	      _original_tty;
X#define	ttgetattr(fd,where)	ioctl((fd),TIOCGETP,(where))
X#define	ttsetattr(fd,where)	ioctl((fd),TIOCSETP,(where))
X# endif	/*TERMIO*/
X#endif	/*TERMIOS*/
X
Xstatic int _inraw = 0;                  /* are we IN rawmode?    */
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 int _lines, _columns, _automargin, _eatnewlineglitch;
Xint tabspacing;
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);
SHAR_EOF
echo "End of part 12"
echo "File src/curses.c is continued in part 13"
echo "13" > s2_seq_.tmp
exit 0

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