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

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

---- Cut Here and unpack ----
#!/bin/sh
# this is part 9 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file src/alias.c continued
#
CurArch=9
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/alias.c"
sed 's/^X//' << 'SHAR_EOF' >> src/alias.c
X
Xunsigned long sleep();
X
Xextern int errno;
X
Xextern int  findnode_has_been_initialized;
X
Xread_alias_files()
X{
X	/** read the system and user alias files, if present.
X	    Set the flags 'systemfiles' and 'userfiles' accordingly.
X	**/
X
X	char fname[SLEN];
X	int  hash;
X
X	if ((hash = open(system_hash_file, O_RDONLY)) == -1) {
X	  dprint(2, (debugfile,
X		"Warning: Can't read system hash file %s\n", system_hash_file));
X	  goto user;
X	}
X
X	read(hash, (char *) system_hash_table, sizeof system_hash_table);
X	close(hash);
X
X	/* and data file opened.. */
X
X	if ((system_data = open(system_data_file, O_RDONLY)) == -1) {
X	 dprint(1, (debugfile,
X               "Warning: Can't read system data file %s\n", system_data_file));
X	  goto user;
X	}
X
X	system_files++;	/* got the system files! */
X
Xuser:   sprintf(fname,  "%s/%s", home, ALIAS_HASH); 
X
X	if ((hash = open(fname, O_RDONLY)) == -1) {
X	 dprint(2,(debugfile, "Warning: Can't read user hash file %s\n",
X		  fname));
X	  return;
X	}
X
X	read(hash, (char *) user_hash_table, sizeof user_hash_table);
X	close(hash);
X
X	sprintf(fname,  "%s/%s", home, ALIAS_DATA); 
X
X	if ((user_data = open(fname, O_RDONLY)) == -1) {
X	  dprint(1, (debugfile,
X	         "Warning: can't read user data file %s\n", fname));
X	  return;
X	}
X
X	user_files++;	/* got user files too! */
X}
X
Xint
Xadd_alias()
X{
X	/** add an alias to the user alias text file.  Return zero 
X	    if alias not added in actuality **/
X
X	char name[SLEN], *address, address1[LONG_STRING];
X	char comment[SLEN];
X	char *strcpy();
X
X	PutLine0(LINES-2,0,"Enter alias name: ");
X	CleartoEOLN();
X	Raw(OFF);
X	gets(name);
X	Raw(ON);
X	if (strlen(name) == 0) 
X	  return(0);
X	if ((address = get_alias_address(name, 0, 0)) != NULL) {
X	  dprint(3, (debugfile, 
X		 "Attempt to add a duplicate alias [%s] in add_alias\n",
X		 address)); 
X	  if (address[0] == '!') {
X	    address[0] = ' ';
X	    error1("already a group with that name:%s", address);
X	  }
X	  else
X	    error1("already an alias for that: %s", address);
X	  return(0);
X	}
X	PutLine1(LINES-2,0,"Full name for %s: ", name);
X	CleartoEOLN();
X	Raw(OFF);
X	gets(comment);
X	Raw(ON);
X	if (strlen(comment) == 0) strcpy(comment, name);  
X	PutLine1(LINES-2,0,"Enter address for %s: ",name);
X	CleartoEOLN();
X	Raw(OFF);
X	gets(address1);
X	Raw(ON);
X	if (strlen(address1) == 0) {
X	  error("No address specified!");
X	  return(0);
X	}
X	add_to_alias_text(name, comment, address1);
X	return(1);
X}
X
Xint
Xadd_current_alias()
X{
X	/** alias the current message to the specified name and
X	    add it to the alias text file, for processing as
X	    the user leaves the program.  Returns non-zero iff
X	    alias actually added to file **/
X
X	char name[SLEN], address1[LONG_STRING], buffer[LONG_STRING], *address;
X	char comment[SLEN];
X
X	if (current == 0) {
X	 dprint(4, (debugfile, 
X		"Add current alias called without any current message!\n"));
X	 error("No message to alias to!");
X	 return(0);
X	}
X	
X	PutLine0(LINES-2,0,"Current message address aliased to: ");
X	CleartoEOLN();
X	Raw(OFF);
X	gets(name);
X	Raw(ON);
X	if (strlen(name) == 0)	/* cancelled... */
X	  return(0);
X	if ((address = get_alias_address(name, 0, 0)) != NULL) {
X	 dprint(3, (debugfile,
X	         "Attempt to add a duplicate alias [%s] in add_current_alias\n",
X		 address)); 
X	  if (address[1] == '!') {
X	    address[0] = ' ';
X	    error1("already a group with that name:%s", address);
X	  }
X	  else 
X	    error1("already an alias for that: %s", address); 
X          return(0);
X	}
X	PutLine1(LINES-2,0,"Full name of %s: ", name);
X	CleartoEOLN();
X	Raw(OFF);
X	gets(comment);
X	Raw(ON);
X	get_return(buffer);	/* grab the return address of this message */
X	strcpy(address1, strip_parens(buffer));	/* remove parens! */
X#ifdef OPTIMIZE_RETURN
X	optimize_return(address1);
X#endif
X	PutLine3(LINES-2,0,"%s (%s) = %s", comment, name, address1);
X	CleartoEOLN();
X	add_to_alias_text(name, comment, address1);
X	return(1);
X}
X
Xadd_to_alias_text(name, comment, address)
Xchar *name, *comment, *address;
X{
X	/** Add the data to the user alias text file.  Return zero if we
X	    succeeded, 1 if not **/
X	
X	FILE *file;
X	char fname[SLEN];
X	
X	sprintf(fname,"%s/%s", home, ALIAS_TEXT);
X	
X	if ((file = fopen(fname, "a")) == NULL) {
X	  dprint(2, (debugfile, 
X		 "Failure attempting to add alias to file %s within %s",
X		   fname, "add_to_alias_text"));
X	  dprint(2, (debugfile, "** %s - %s **\n", error_name(errno), 
X		   error_description(errno)));
X	  error1("couldn't open %s to add new alias!", fname);
X	  return(1);
X	}
X
X	fprintf(file,"%s = %s = %s\n", name, comment, address);
X	fclose(file);
X
X	chown(fname, userid, groupid);
X
X	return(0);
X}
X
Xshow_alias_menu()
X{
X	MoveCursor(LINES-7,0); CleartoEOLN();	
X	MoveCursor(LINES-6,0); CleartoEOLN();	
X	MoveCursor(LINES-5,0); CleartoEOLN();
X	
X	PutLine0(LINES-7,COLUMNS-45, "Alias commands");
X	Centerline(LINES-5,
X"A)lias current msg, Check a P)erson or S)ystem, M)ake new alias, or R)eturn"
X	);
X}
X
Xalias()
X{
X	/** work with alias commands... **/
X	/** return non-0 if main part of screen overwritten, else 0 **/
X
X	char name[NLEN], *address, ch, buffer[SLEN];
X	int  newaliases = 0, redraw = 0;
X
X	if (mini_menu)
X	  show_alias_menu();
X
X	/** now let's ensure that we've initialized everything! **/
X
X#ifndef DONT_TOUCH_ADDRESSES
X	
X	if (! findnode_has_been_initialized) {
X	  if (! mail_only && warnings)
X	    error("initializing internal tables...");
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#endif
X
X	define_softkeys(ALIAS);
X
X	while (1) {
X	  prompt("Alias: ");
X	  CleartoEOLN();
X	  ch = ReadCh();
X	  MoveCursor(LINES-1,0); CleartoEOS();
X	  
X	  dprint(3, (debugfile, "\n-- Alias command: %c\n\n", ch));
X
X	  switch (tolower(ch)) {
X	    case '?': redraw += alias_help();			break;
X
X	    case 'a': newaliases += add_current_alias();	break;
X	    case 'm': newaliases += add_alias(); 		break;
X
X	    case RETURN:
X	    case LINE_FEED:
X	    case 'q':
X	    case 'x':
X	    case 'r': if (newaliases) install_aliases();
X		      return(redraw);
X	    case 'p': if (newaliases) 
X			error("Warning: new aliases not installed yet!");
X		      PutLine0(LINES-2,0,"Check for person: ");
X		      CleartoEOLN();
X		      Raw(OFF);
X	              gets(name);
X		      Raw(ON);
X		      if ((address = get_alias_address(name, 0, 0))!=NULL) {
X	                if (address[0] == '!') {
X	                  address[0] = ' ';
X	                  PutLine1(LINES-1,0,"Group alias:%-60.60s", address);
X	                  CleartoEOLN();
X		        }
X			else
X			  PutLine1(LINES-1,0,"Aliased address: %-60.60s", 
X			  address);
X		      }
X	              else 
X			error("not found");
X		      break;
X
X	    case 's': PutLine0(LINES-2,0,"Check for system: ");
X		      CleartoEOS();
X		      Raw(OFF);
X	              gets(name);
X		      Raw(ON);
X		      if (talk_to(name)) 
X#ifdef INTERNET_ADDRESS_FORMAT
X			PutLine1(LINES-1,0,
X		"You have a direct connection - the address is USER@%s", 
X			name);
X#else
X			PutLine1(LINES-1,0,
X		"You have a direct connection - the address is %s!USER", 
X			name);
X#endif
X		      else {
X		        sprintf(buffer, "USER@%s", name);
X#ifdef DONT_TOUCH_ADDRESSES
X	 	        address = buffer;
X#else
X	 	        address = expand_system(buffer, FALSE);
X#endif
X		        if (strlen(address) > strlen(name) + 7)
X		          PutLine1(LINES-1,0,"Address is: %.65s", address);
X		        else
X		          error1("couldn't expand system '%s'", name);
X		      }
X		      break;
X
X	    case '@': PutLine0(LINES-2,0,"Fully expand alias: ");
X		      CleartoEOS();
X		      Raw(OFF);
X	              gets(name);
X		      Raw(ON);
X		      if ((address = get_alias_address(name, 1, 0)) != NULL) {
X	                ClearScreen();
X			PutLine1(3,0,"Aliased address:\n\r%s", address);
X	                PutLine0(LINES-1,0,"Press <return> to continue: ");
X			(void) getchar();
X		      }
X	              else 
X			error("not found");
X		      if (mini_menu) show_alias_menu();
X		      break;
X	    default : error("Invalid input!");
X	  }
X	}
X}
X
Xinstall_aliases()
X{
X	/** run the 'newalias' program and install the newly
X	    added aliases before going back to the main
X	    program! 
X	**/
X
X
X	error("Adding new aliases...");
X	sleep(2);
X
X	if (system_call(newalias, SH) == 0) {
X	  error("Re-reading the database in...");
X	  sleep(2);
X	  read_alias_files();
X	  set_error("New aliases installed successfully");
X	}
X	else
X	  set_error("'newalias' failed.  Please check alias_text");
X}
X
Xalias_help()
X{
X	/** help section for the alias menu... **/
X	/** return non-0 if main part of screen overwritten, else 0 */
X	
X	char ch;
X	int  redraw=0;
X
X	MoveCursor(LINES-3, 0);	CleartoEOS();
X
X	if (! mini_menu)
X	  lower_prompt("Key you want help for : ");
X	else {
X	  Centerline(LINES-3, 
X"Enter key you want help for, '?' for list or '.' to leave help");
X	  lower_prompt("Key : ");
X	}
X
X	while ((ch = ReadCh()) != '.') {
X	  ch = tolower(ch);
X	  switch(ch) {
X	    case '?' : display_helpfile(ALIAS_HELP);	
X		       redraw++;
X	               if (mini_menu) show_alias_menu();
X		       return(redraw);
X	    case 'a': error(
X"a = Add return address of current message to alias database");	break;
X	    case 'm': error(
X"m = Make new user alias, adding to alias database when done");	break;
X
X	    case RETURN:
X	    case LINE_FEED:
X	    case 'q':
X	    case 'x':
X	    case 'r': error("return from alias menu");		break;
X		      
X	    case 'p': error(
X"p = check for a person in the alias database");		break;
X	
X	    case 's': error(
X"s = check for a system in the host routing/domain database");	break;
X	
X	    default : error("That key isn't used in this section");	break;
X	  }
X	  if (! mini_menu)
X	    lower_prompt("Key you want help for : ");
X	  else 
X	    lower_prompt("Key : ");
X	}
X	return(redraw);
X}
SHAR_EOF
echo "File src/alias.c is complete"
chmod 0444 src/alias.c || echo "restore of src/alias.c fails"
echo "x - extracting src/aliasdb.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/aliasdb.c &&
X
Xstatic char rcsid[] = "@(#)$Id: aliasdb.c,v 2.1 88/07/21 09:57:50 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:	aliasdb.c,v $
X * Revision 2.1  88/07/21  09:57:50  edc
X * checked in with -k by syd at 88.09.15.20.27.26.
X * 
X * Revision 2.1  88/07/21  09:57:50  edc
X * Final hacks and cleanup to the 2.1 alpha test release.
X * 
X * Revision 2.0  88/06/27  17:24:47  edc
X * The original 2.0 gamma sources as leaked from HP
X * 
X *
X *
X ******************************************************************************/
X
X/** Alias database files...
X
X**/
X
X
X#include "headers.h"
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <errno.h>
X
Xextern int errno;
X
X#ifdef USE_DBM
X# include <dbm.h>
X#endif
X
X#define  absolute(x)		((x) > 0 ? x : -(x))
X
Xchar *shift_lower(), *find_path_to(), *strcat(), *strcpy();
Xunsigned long sleep();
X
Xint  findnode_has_been_initialized = FALSE;
X
Xfindnode(name, display_error)
Xchar *name;
Xint   display_error;
X{
X	/** break 'name' into machine!user or user@machine and then
X	    see if you can find 'machine' in the path database..
X	    If so, return name as the expanded address.  If not,
X	    return what was given to us!   If display_error, then
X	    do so...
X	**/
X
X#ifndef DONT_TOUCH_ADDRESSES
X	
X	char   old_name[SLEN];
X	char   address[SLEN];
X
X	if (strlen(name) == 0)
X	  return;
X	
X	if (! findnode_has_been_initialized) {
X	  if (! mail_only && warnings)
X	    error("initializing internal tables...");
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	        if (mail_only)
X	          printf("Warning: Couldn't expand system %s\n\r", name);
X	        else {
X	          error1("Couldn't expand system %s", name);
X	          sleep(1);
X	        }
X	    }
X	  }
X	  strcpy(name, old_name);	/* and restore... */
X	}
X	else
X	  strcpy(name, address);
X#endif
X	return;
X}
X
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, 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 **/
X
X	if ((i = chloc(cryptic, '(')) > -1) {
X	  comment[j++] = ' ';			/* leading space */
X	  for ( ;cryptic[i] != ')'; i++)
X  	    comment[j++] = cryptic[i];
X	  comment[j++] = ')';
X	  comment[j] = '\0';
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#endif
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}
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	return(-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	/* read until we hit an end-of-line */
X
X	while (getc(fileid) != '\n')
X	   ;
X
X	fscanf(fileid, "%s\t%s", machine, address);
X}
X
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
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[LONG_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
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 2.1 88/07/21 09:57:53 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:	aliaslib.c,v $
X * Revision 2.1  88/07/21  09:57:53  edc
X * checked in with -k by syd at 88.09.15.20.27.28.
X * 
X * Revision 2.1  88/07/21  09:57:53  edc
X * Final hacks and cleanup to the 2.1 alpha test release.
X * 
X * Revision 2.0  88/06/27  17:24:47  edc
X * The original 2.0 gamma sources as leaked from HP
X * 
X *
X *
X ******************************************************************************/
X
X/** Library of functions dealing with the alias system...
X
X **/
X
X#include "headers.h"
X
Xchar *expand_group(), *get_alias_address(), *expand_system();
Xchar *get_token(), *strpbrk();
Xlong lseek();
X
Xchar *get_alias_address(name, mailing, depth)
Xchar *name;
Xint   mailing, depth;
X{
X	/** return the line from either datafile that corresponds 
X	    to the specified name.  If 'mailing' specified, then
X	    fully expand group names.  Depth specifies the nesting
X	    depth - the routine should always initially be called
X	    with this equal 0.  Returns NULL if not found   **/
X
X	static char buffer[VERY_LONG_STRING];
X	int    loc;
X
X	if (strlen(name) == 0)
X	  return( (char *) NULL);
X
X	if (! read_in_aliases) {
X	  read_alias_files();
X	  read_in_aliases = TRUE;
X	}
X
X	if (user_files) 
X	  if ((loc = find(name, user_hash_table, MAX_UALIASES)) >= 0) {
X	    lseek(user_data, user_hash_table[loc].byte, 0L);
X	    get_line(user_data, buffer);
X	    if (buffer[0] == '!' && mailing)
X	      return(expand_group(buffer, depth));
X	    else if (strpbrk(buffer,"!@:") != NULL)	/* has a hostname */
X#ifdef DONT_TOUCH_ADDRESSES
X	      return((char *) buffer);
X#else
X	      return(expand_system(buffer, TRUE));
X#endif
X	    else
X	      return((char *) buffer);
X	  }
X	 
X	if (system_files) 
X	  if ((loc = find(name, system_hash_table, MAX_SALIASES)) >= 0) {
X	    lseek(system_data, system_hash_table[loc].byte, 0L);
X	    get_line(system_data, buffer);
X	    if (buffer[0] == '!' && mailing)
X	      return(expand_group(buffer, depth));
X	    else if (strpbrk(buffer,"!@:") != NULL)	/* has a hostname */
X#ifdef DONT_TOUCH_ADDRESSES
X	      return((char *) buffer);
X#else
X	      return(expand_system(buffer, TRUE));
X#endif
X	    else
X	      return((char *) buffer);
X	  }
X	
X	return( (char *) NULL);
X}
X
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	      
Xchar *expand_group(members, depth)
Xchar *members;
Xint  depth;
X{
X	/** Given a group of names separated by commas, this routine
X	    will return a string that is the full addresses of each
X	    member separated by spaces. Depth is an internal counter
X	    that keeps track of the depth of nesting that the routine
X	    is in...it's for the get_token routine!  **/
X
X	static char buffer[VERY_LONG_STRING];
X	char   buf[LONG_STRING], *word, *address, *bufptr;
X	char   *strcpy();
X
X	strcpy(buf, members); 			/* parameter safety! */
X	if (depth == 0) buffer[0] = '\0';	/* nothing in yet!   */
X	bufptr = (char *) buf;			/* grab the address  */
X	depth++;				/* one deeper!       */
X
X	while ((word = get_token(bufptr, "!, ", depth)) != NULL) {
X	  if ((address = get_alias_address(word, 1, depth)) == NULL) {
X	    if (! valid_name(word)) {
X	      dprint(3, (debugfile, "Encountered illegal address %s in %s\n",
X			word, "expand_group"));
X	      error1("%s is an illegal address!", word);
X	      return( (char *) NULL);
X	    }
X	    else if (strcmp(buffer, word) != 0)
X	      sprintf(buffer, "%s%s%s", buffer,
X		    (strlen(buffer) > 0)? ", ":"", word);
X	  }
X	  else if (strcmp(buffer, address) != 0)
X	    sprintf(buffer,"%s%s%s", buffer, 
X		    (strlen(buffer) > 0)? ", ":"", address);
X
X	  bufptr = NULL;
X	}
X
X	return( (char *) buffer);
X}
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 (strcmp(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
Xhash_it(string, table_size)
Xchar *string;
Xint   table_size;
X{
X	/** compute the hash function of the string, returning
X	    it (mod table_size) **/
X
X	register int i, sum = 0;
X	
X	for (i=0; string[i] != '\0'; i++)
X	  sum += (int) string[i];
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 2.1 88/09/15 20:27:30 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:	args.c,v $
X * Revision 2.1  88/09/15  20:27:30  syd
X * checked in with -k by syd at 88.09.15.20.27.30.
X * 
X * 88/09/01 Rob Bernardo <gatech!pbhyf.PacBell.COM!rob>
X *	1. It allows the user to use the -z flags and -f [filename] flag
X *	2. Puts elm in raw mode earlier on than before so that any commands
X *
X * 88/08/27 ssw
X *	add deluth patches
X *
X * Revision 2.1  88/07/21  09:57:55  edc
X * Final hacks and cleanup to the 2.1 alpha test release.
X * 
X * Revision 2.0  88/06/27  17:24:48  edc
X * The original 2.0 gamma sources as leaked from HP
X * 
X *
X *
X ******************************************************************************/
X
X/** starting argument parsing routines for ELM system...
X
X**/
X
X#include "headers.h"
X
X#define DONE		0
X#define ERROR		-1
X
Xextern char *optional_arg;		/* optional argument as we go */
Xextern int   opt_index;			/* argnum + 1 when we leave   */
X
Xvoid exit();	/* just keeping lint happy.... */
X
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 set "mail_only" to TRUE **/
X
X	register int c = 0;
X	char *strcpy();
X
X	infile[0] = '\0';
X	to_whom[0] = '\0';
X	batch_subject[0] = '\0';
X
X        while ((c = get_options(argc, argv, "?acd:f:hkKms:Vwz")) > 0) {
X	   switch (c) {
X	     case 'a' : arrow_cursor++;		break;
X	     case 'c' : check_only++;		break;
X	     case 'd' : debug = atoi(optional_arg);	break;
X	     case 'f' : strcpy(infile, optional_arg); 
X	                mbox_specified = 2;  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, optional_arg);	break;
X             case 'V' : sendmail_verbose++;     break;
X	     case 'w' : warnings = 0;	break;
X	     case 'z' : check_size++;   break;
X	    }
X	 }
X
X	 if (c == ERROR) {
X	   printf(
X          "Usage: %s [achkKmVwz] [-d level] [-f file] [-s subject] <names>\n\n",
X	     argv[0]);
X	   args_help();
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 (opt_index < argc) {
X	  while (opt_index < argc) {
X	    sprintf(to_whom, "%s%s%s", to_whom, 
X	            to_whom[0] != '\0'? " " : "", argv[opt_index]);
X	    mail_only++;
X	    opt_index++;
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)) && strlen(batch_subject) == 0 && !check_only)
X	  strcpy(batch_subject, DEFAULT_BATCH_SUBJECT);
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("\t -fx\t\tFile - read file 'x' rather than 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 -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}
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 2.1 88/07/21 09:57:57 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:	bouncebk.c,v $
X * Revision 2.1  88/07/21  09:57:57  edc
X * checked in with -k by syd at 88.09.15.20.27.33.
X * 
X * Revision 2.1  88/07/21  09:57:57  edc
X * Final hacks and cleanup to the 2.1 alpha test release.
X * 
X * Revision 2.0  88/06/27  17:24:49  edc
X * The original 2.0 gamma sources as leaked from HP
X * 
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, index;
X
X	for (index = 0; ! whitespace(to[index]) && to[index] != '\0'; index++) {
X	  if (to[index] == '!')
X	    hopcount++;
X	  else if (to[index] == '@' || to[index] == '%' || to[index] == ':')
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][SHORT_SLEN];	/* for breaking up addr */
X	register int hostcount = 0, hindex = 0, 
X	       index;
X
X	for (index = 0; !whitespace(to[index]) && to[index] != '\0'; index++) {
X	  if (to[index] == '!') {
X	    host[hostcount][hindex] = '\0';
X	    hostcount++;
X	    hindex = 0;
X	  }
X	  else 
X	    host[hostcount][hindex++] = to[index];
X	}
X
X	/* we have hostcount hosts... */
X
X	strcpy(address, host[0]);	/* initialize it! */
X
X	for (index=1; index < hostcount; index++) {
X	  strcat(address, "!");
X	  strcat(address, host[index]);
X	}
X	
X	/* and now the same thing backwards... */
X
X	for (index = hostcount -2; index > -1; index--) {
X	  strcat(address, "!");
X	  strcat(address, host[index]);
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 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:	builtin.c,v $
X * Revision 2.1  88/09/15  20:27:35  syd
X * checked in with -k by syd at 88.09.15.20.27.35.
X * 
X * 88/08/27 ssw
X *	add deluth patches
X *
X * Revision 2.1  88/07/21  09:57:58  edc
X * Final hacks and cleanup to the 2.1 alpha test release.
X * 
X * Revision 2.0  88/06/27  17:24:50  edc
X * The original 2.0 gamma sources as leaked from HP
X * 
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    Added the following functionality;
X
X	<number>s	skip <number> lines
X	<number>f	forward a page or <number> pages
X	/pattern	skip forward to pattern		
X
X    [ not really - the pattern matching isn't REALLY implemented!
X      the moral of this story, of course, is that you shouldn't
X      read the source code to ascertain what functions a program has! ]
X
X    [ oh - I almost forgot:  *grin* ]
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
X#ifdef BSD
X#  undef tolower
X#endif
X
Xint	lines_put_on_screen = 0,    /* number of lines displayed per screen */
X	lines_displayed = 0,	    /* 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	lines_to_ignore = 0;	    /* for 'f' and 's' functions...         */
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	lines_displayed = 0;
X	lines_put_on_screen = 0;
X	lines_to_ignore = 0;
X        pages_displayed = 1;
X
X	total_lines_to_display = lines_in_message;
X}
X
Xint
Xdisplay_line(line)
Xchar *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. 'q' or '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	register int lines_needed, okay_char, ch, len;
X	char     pattern[SLEN], display_buffer[SLEN], *p, *pend;
X	char     last_line[SLEN], line_before_that[SLEN];
X
X	if (lines_to_ignore != 0) {
X	   if (--lines_to_ignore <= 0) {
X	     putchar('\n');
X	     lines_to_ignore = 0;
X	   }
X	   return(0);
X	}
X
X	lines_needed = (int) (printable_chars(line)/COLUMNS); /* wraparound */
X
X	/* the next few lines are from Greg Laskin and speed things up a lot! */
X
X	pend = line + strlen(line);
X	for (p = line; p < pend; )
X	  if (*p++ == '\n') lines_needed++;
X
X	if (lines_needed + lines_put_on_screen > LINES-1) {
X	  StartBold();
X	  if (user_level == 0) 
X	    sprintf(display_buffer,
X" There are %d line%s left (%.2g%%) : press <space> for more, or 'q' to return ",
X		   total_lines_to_display - lines_displayed,
X		   plural(total_lines_to_display - lines_displayed),
X		   100.0*(1.0*lines_displayed) / (1.0*total_lines_to_display));
X	  else if (user_level == 1) 
X	    sprintf(display_buffer,
X" %d line%s more (%.2g%%) : Press <space> for more, 'q' to return ",
X		   total_lines_to_display - lines_displayed,
X		   plural(total_lines_to_display - lines_displayed),
X		   100.0*(1.0*lines_displayed) / (1.0*total_lines_to_display));
X	  else 
X	    sprintf(display_buffer," %d line%s more (you've seen %.2g%%) ",
X		   total_lines_to_display - lines_displayed,
X		   plural(total_lines_to_display - lines_displayed),
X		   100.0*(1.0*lines_displayed) / (1.0*total_lines_to_display));
X 
X	  len = strlen(display_buffer);
X        Write_to_screen(display_buffer,0, "", "", "");
X
X	  EndBold();
X	  okay_char = FALSE;
X	  do {
X	      ch =  ReadCh();
X	      ch =  tolower(ch);
X              switch (ch) {
X	       case '\n' : 
X	       case '\r' : /* <return> pressed... */
X			   lines_put_on_screen -= lines_needed;
X			   okay_char = TRUE;
X			   break;
X	       case ' '  : /* <space> pressed... */
X			   lines_put_on_screen = 0;
X			   okay_char = TRUE;
X			   break;
X	       case '/'  : putchar('/');fflush(stdout);
X			   optionally_enter(pattern,-1,-1,FALSE);
X			   CarriageReturn();
X			   CleartoEOLN();
X			   CarriageReturn();
X			   printf("...searching for pattern \"%s\"...",
X				  pattern);
X			   fflush(stdout);
X			   break;
X
X	       case 'i'  :
X	       case 'q'  :
X	       case 'Q'  : return(TRUE);	/* get OUTTA here! */
X
X	       default   : dprint(2,(debugfile, 
X			     "builtin is outta here, returning '%c' [%d]\n", 
X			     ch, ch));
X			   return(ch);
X	     }
X	  } while (! okay_char);
X
X	  if (clear_pages && lines_put_on_screen == 0) {   /* not for <ret> */
X	    ClearScreen();
X	    if (title_messages && filter) {
X	      title_for_page(++pages_displayed);
X	      display_line("\n");			/* blank line for fun */
X	    }
X	    if (strlen(line_before_that) > 0) {
X	      display_line(line_before_that);
X	      display_line(last_line);
X	    }
X	    else if (strlen(last_line) > 0)
X	      display_line(last_line);
X	  }
X	  else {
X	    CarriageReturn();           /* back up to the beginning of line */
X	    CleartoEOLN();
X	    CarriageReturn();
X	  }
X	}
X	else if (lines_needed + lines_put_on_screen > LINES-5) {
X	  strcpy(line_before_that, last_line);
X	  strcpy(last_line, line);
X	}
X
X	Write_to_screen("%s", 1, line);
X
X	lines_put_on_screen += lines_needed;	   /* read from file   */
X
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... **/
X
X	char *p, title[SLEN], title2[SLEN], from_buffer[50], from_buffer2[50];
X	register int padding, sl, mail_sent;
X
X	strncpy(from_buffer, header_table[current-1].from, 50);
X
X	tail_of(from_buffer, from_buffer2, TRUE);
X
X	mail_sent = (strncmp(header_table[current-1].from, "To:", 3) == 0);
X
X	sprintf(title, "%s #%d %s %s",
X	        header_table[current-1].status&FORM_LETTER ? "Form" : "Message",
X		current, 
X		mail_sent? "to" : "from", from_buffer2);
X
X	padding = COLUMNS - (sl = strlen(title)) - 
X		  (page < 10 ? 7 : page < 100 ? 8 : 9);
X	    
X	p = title + sl;
X	while (padding-- > 0)
X	  *p++ = ' ';
X	*p = '\0';  
X	
X	sprintf(title2, " Page %d\n", page);
X
X	strcat(title, title2);
X	
X	display_line(title);
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 2.1 88/07/21 09:58:00 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:	calendar.c,v $
X * Revision 2.1  88/07/21  09:58:00  edc
X * checked in with -k by syd at 88.09.15.20.27.38.
X * 
X * Revision 2.1  88/07/21  09:58:00  edc
X * Final hacks and cleanup to the 2.1 alpha test release.
X * 
X * Revision 2.0  88/06/27  17:24:51  edc
X * The original 2.0 gamma sources as leaked from HP
X * 
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    Never able to leave good-enough alone, I've extended this idea to a
X    further one - the knowledge of a different type of calendar program
X    too.  Specifically, the current message can contain either of;
X
X	-> Mon 04/21 1:00p meet with chairman candidate
X
X    or 
X
X	- >April 21
X	-   
X	-     1:00 pm: Meet with Chairman Candidate
X	-
X
X    The first type will have the leading '->' removed and all subsequent
X    white space, creating a simple one-line entry in the users calendar
X    file.   The second type will remove the '-' and the leading white
X    spaces and leave everything else intact (that is, the file in the
X    second example would be appended with ">April 21" followed by a
X    blank line, the 1:00 pm meeting info, and another blank line.
X	
X    The file to include this in is either the default as defined in the
X    sysdefs.h file (see CALENDAR_FILE) or a filename contained in the
X    users ".elm/elmrc" file, "calendar= <filename>".
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 celendar 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	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	chown(calendar_file, userid, groupid);	/* ensure owned by user */
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, ok = 1, lines, index, in_entry = FALSE;
X	char buffer[SLEN];
X
X    	/** get to the first line of the message desired **/
X
X    	if (fseek(mailfile, header_table[current-1].offset, 0) == -1) {
X       	  dprint(1,(debugfile, 
X		"ERROR: Attempt to seek %d bytes into file failed (%s)",
X		header_table[current-1].offset, "extract_info"));
X       	  error1("ELM [seek] failed trying to read %d bytes into file",
X	     	header_table[current-1].offset);
X       	  return(0);
X    	}
X
X        /* how many lines in message? */
X
X        lines = header_table[current-1].lines;
X
X        /* now while not EOF & still in message... scan it! */
X
X        while (ok && lines--) {
X          ok = (int) (fgets(buffer, LONG_SLEN, mailfile) != NULL);
X	  
X	  /* now let's see if it matches the basic pattern... */
X
X	  if ((index = calendar_line(buffer)) > -1) {
X
X	    if (buffer[index] == '>') {	/* single line entry */
X	      if (remove_through_ch(buffer, '>')) {
X	        fprintf(save_to_fd,"%s", buffer);
X	        entries++;
X	      }
X	    }
X	    else {				/* multi-line entry  */
X	        fprintf(save_to_fd, "%s", (char *) (buffer + index + 1));
X	        in_entry = TRUE;	
X	      }
X           }
X	   else if (in_entry) {
X	     in_entry = FALSE;
X	     entries++;
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
Xint
Xcalendar_line(string)
Xchar *string;
X{
X	/** Iff the input line is of the form;
X
X	      {white space} <one or more '-'> 
X	
X	    this routine will return the index of the NEXT character
X	    after the dashed sequence...If this pattern doesn't occur, 
X	    or if any other problems are encountered, it'll return "-1"
X	**/
X
X	register int loc = 0;
X
X	if (chloc(string,'-') == -1) 	  /* no dash??? */
X	  return(-1);			/* that was easy! */
X
X	/** skip leading white space... **/
X
X	while (whitespace(string[loc])) loc++;	   /* MUST have '-' too! */
X
X	if (string[loc] != '-')	return(-1);	   /* nice try, sleazo! */
X
X	while (string[loc] == '-') loc++;
X
X	if (loc >= strlen(string)) return(-1);	/* Empty line... */
X
X	/* otherwise.... */  
X
X	return(loc);
X}
X    
X
Xint
Xremove_through_ch(string, ch)
Xchar *string;
Xchar  ch;
X{
X	/** removes all characters from zero to ch in the string, and 
X	    any 'white-space' following the 'n'th char... if it hits a
X    	    NULL string, it returns FALSE, otherwise it'll return TRUE!
X	**/
X
X	char buffer[SLEN];
X	register int index = 0, i = 0;
X
X	while (string[index] != ch && string[index] != '\0')
X	  index++;
X	
X	if (index >= strlen(string)) 
X	  return(FALSE);	/* crash! burn! */
X
X	index++;	/* get past the 'ch' character... */
X
X	while (whitespace(string[index])) index++;
X
X	while (index < strlen(string))
X	  buffer[i++] = string[index++];
X
X	buffer[i] = '\0';
X
X	strcpy(string, buffer);
X	
X	return(TRUE);
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 2.1 88/07/21 09:58:03 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:	conn_to.c,v $
X * Revision 2.1  88/07/21  09:58:03  edc
X * checked in with -k by syd at 88.09.15.20.27.40.
X * 
X * Revision 2.1  88/07/21  09:58:03  edc
X * Final hacks and cleanup to the 2.1 alpha test release.
X * 
X * Revision 2.0  88/06/27  17:24:52  edc
X * The original 2.0 gamma sources as leaked from HP
X * 
X *
X *
X ******************************************************************************/
X
X/** This contains the routine(s) needed to have the Elm mailer figure
SHAR_EOF
echo "End of part 9"
echo "File src/conn_to.c is continued in part 10"
echo "10" > 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