From: sources@anomaly.sbs.risc.net
Subject: v01i116 - ELM v2.3.11, Electronic Mail Reader - Part 16/20
Reply-To: sources@anomaly.sbs.risc.net
Organization: The Rhode Island Internet Systems Cooperative Network
Date: Sun, 13 Sep 1992 17:45:16 GMT
Followup-To: biz.sco.general


#!/bin/sh
# this is part.16 (part 16 of a multipart archive)
# do not concatenate these parts, unpack them in order with /bin/sh
# file src/read_rc.c continued
#
if test ! -r shar3_seq_.tmp; then
	echo "Please unpack part 1 first!"
	exit 1
fi
(read Scheck
 if test "$Scheck" != 16; then
	echo "Please unpack part $Scheck next!"
	exit 1
 else
	exit 0
 fi
) < shar3_seq_.tmp || exit 1
echo "x - Continuing file src/read_rc.c"
sed 's/^X//' << 'SHAR_EOF' >> src/read_rc.c &&
X	shell   = <shell>
X	print   = <print command>
X	weedout = <list of headers to weed out>
X	prefix  = <copied message prefix string>
X	pager   = <command to use for displaying messages>
X	
X	escape  = <single character escape, default = '~' >
X
X--
X	signature = <.signature file for all outbound mail>
XOR:
X	localsignature = <.signature file for local mail>
X	remotesignature = <.signature file for non-local mail>
X--
X
X	bounceback= <hop count threshold, or zero to disable>
X	timeout = <seconds for main menu timeout or zero to disable>
X	userlevel = <0=amateur, 1=okay, 2 or greater = expert!>
X
X	sortby  = <sent, received, from, size, subject, mailbox, status>
X
X	alternatives = <list of addresses that forward to us>
X
X    and/or the logical arguments:
X	
X	autocopy    [on|off]
X	askcc	    [on|off]
X	copy        [on|off]	
X	resolve     [on|off]
X	weed        [on|off]
X	noheader    [on|off]
X	titles      [on|off]
X	savebyname  [on|off]
X	forcename   [on|off]
X	movepage    [on|off]
X	pointnew    [on|off]
X	hpkeypad    [on|off]
X	hpsoftkeys  [on|off]
X	alwayskeep [on|off]
X	alwaysstore [on|off]
X	alwaysdel   [on|off]
X	arrow	    [on|off]
X	menus	    [on|off]
X	forms	    [on|off]
X	warnings    [on|off]
X	names	    [on|off]
X	ask	    [on|off]
X	keepempty   [on|off]
X	promptafter[on|off]
X	sigdashes   [on|off]
X
X
X    Lines starting with '#' are considered comments and are not checked
X    any further!
X
X    Modified 10/85 to know about "Environment" variables..
X    Modified 12/85 for the 'prefix' option
X    Modified  2/86 for the new 3.3 flags
X    Modified  8/86 (was I supposed to be keeping this up to date?)
X**/
X
X#include <ctype.h>
X#include "headers.h"
X
X#ifdef BSD
X#undef tolower
X#endif
X
Xextern char *pmalloc();
Xextern int errno;
X
Xchar  *error_name(), *error_description(), *shift_lower(),
X      *strtok(), *getenv(), *strcpy();
Xvoid  exit();
X
X#define  metachar(c)	(c == '+' || c == '%' || c == '=')
X
X#define ASSIGNMENT      0
X#define WEEDOUT		1
X#define ALTERNATIVES	2
X
Xread_rc_file()
X{
X	/** this routine does all the actual work of reading in the
X	    .rc file... **/
X
X	FILE *file;
X	char buffer[SLEN], filename[SLEN], *cp, word1[SLEN], word2[SLEN];
X	int  i, ch, len,
X	  rc_has_recvdmail = 0, rc_has_sentmail = 0, lineno = 0, errors = 0;
X
X	/* Establish some defaults in case elmrc is incomplete or not there.
X	 * Defaults for other elmrc options were established in their
X	 * declaration - in elm.h.  And defaults for sent_mail and recvd_mail
X	 * are established after the elmrc is read in since these default
X	 * are based on the folders directory name, which may be given
X	 * in the emrc.
X	 * Also establish alternative_editor here since it is based on
X	 * the default editor and not on the one that might be given in the
X	 * elmrc.
X	 */
X	 
X	default_weedlist();
X
X	alternative_addresses = NULL; 	/* none yet! */
X
X	raw_local_signature[0] = raw_remote_signature[0] =
X		local_signature[0] = remote_signature[0] = '\0';
X		/* no defaults for those */
X
X	strcpy(raw_shell,((cp = getenv("SHELL")) == NULL)? default_shell : cp);
X	strcpy(shell, raw_shell);
X
X	strcpy(raw_pager,((cp = getenv("PAGER")) == NULL)? default_pager : cp);
X	strcpy(pager, raw_pager);
X
X	strcpy(raw_editor,((cp = getenv("EDITOR")) == NULL)? default_editor:cp);
X
X	strcpy(temp_dir,((cp = getenv("TMPDIR")) == NULL)? default_temp:cp);
X	if (temp_dir[strlen (temp_dir)-1] != '/')
X                strcat(temp_dir, "/");
X
X	strcpy(alternative_editor, raw_editor);
X	strcpy(editor, raw_editor);
X
X	strcpy(raw_printout, default_printout);
X	strcpy(printout, raw_printout);
X
X	sprintf(raw_folders, "%s/%s", home, default_folders);
X	strcpy(folders, raw_folders);
X
X	sprintf(raw_calendar_file, "%s/%s", home, dflt_calendar_file);
X	strcpy(calendar_file, raw_calendar_file);
X
X	/* see if the user has a $HOME/.elm directory */
X	sprintf(filename, "%s/.elm", home);
X	if (access(filename, 00) == -1) {
X	  if(batch_only)  {
X	    printf("\n\rNotice:\
X\n\rThis version of ELM requires the use of a .elm directory to store your\
X\n\relmrc and alias files. I'd like to create the directory .elm for you\
X\n\rand set it up, but I can't in \"batch mode\".\
X\n\rPlease run ELM in \"normal mode\" first.\n\r");
X	    exit(0);
X	  }
X
X	  printf("\n\rNotice:\
X\n\rThis version of ELM requires the use of a .elm directory in your home\
X\n\rdirectory to store your elmrc and alias files. Shall I create the\
X\n\rdirectory .elm for you and set it up (y/n)? y%c",BACKSPACE);
X
X	  fflush(stdout);
X	  ch=getchar();
X	  if (ch == 'n' || ch == 'N') {
X	    printf("No.\n\rVery well. I won't create it.\
X	    \n\rBut, you may run into difficulties later.\n\r");
X	    sleep(4);
X	  }
X	  else {
X	    printf("Yes.\n\rGreat! I'll do it now.\n\r");
X	    create_new_elmdir();
X	  }
X	}
X
X	/* Look for the elmrc file */
X	sprintf(filename,"%s/%s", home, elmrcfile);
X	if ((file = fopen(filename, "r")) == NULL) {
X	  dprint(2,(debugfile,"Warning:User has no \".elm/elmrc\" file\n\n"));
X
X	  /* look for old-style .elmrc file in $HOME */
X	  sprintf(filename, "%s/.elmrc", home);
X	  if (access(filename, 00) != -1) {
X	    move_old_files_to_new();
X
X	    /* try to open elmrc file again */
X	    sprintf(filename,"%s/%s", home, elmrcfile);
X	    if((file = fopen(filename, "r")) == NULL) {
X	      dprint(2, (debugfile,
X		"Warning: could not open new \".elm/elmrc\" file.\n"));
X	      dprint(2, (debugfile, "** %s - %s **\n", error_name(errno), 
X		   error_description(errno)));
X	      printf("Warning: could not open new \".elm/elmrc\" file!");
X	      printf(" Using default parameters.\n\r");
X	      sleep(4);
X	    }
X	  }
X	}
X
X	if(file) {
X	  int   last = ASSIGNMENT, this;
X
X	  while (fgets(buffer, SLEN, file) != NULL) {
X	    lineno++;
X	    no_ret(buffer);	 	/* remove return */
X	    if (buffer[0] == '#'        /* comment       */
X	     || strlen(buffer) < 2)     /* empty line    */
X	      continue;
X
X	    this = ASSIGNMENT;
X
X	    if(breakup(buffer, word1, word2) == -1)
X	      continue;		/* word2 is null - let default value stand */
X
X	    strcpy(word1, shift_lower(word1));	/* to lower case */
X
X	    if (equal(word1,"maildir") || equal(word1,"folders")) {
X	      strcpy(raw_folders, word2);
X	      expand_env(folders, word2);
X	    }
X	    else if (equal(word1,"tmpdir")) {
X	      expand_env(temp_dir, word2);
X	      if (temp_dir[strlen (temp_dir)-1] != '/')
X                strcat(temp_dir, "/");
X	    }
X	    else if (equal(word1, "fullname") || equal(word1,"username") ||
X		     equal(word1, "name")) {
X	      strcpy(full_username, word2);
X	    }
X	    else if (equal(word1, "prefix")) {
X	      for (i=0, len = strlen(word2); i < len; i++)
X		prefixchars[i] = (word2[i] == '_' ? ' ' : word2[i]);
X	      prefixchars[i] = '\0';
X	    }
X	    else if (equal(word1, "shell")) {
X	      strcpy(raw_shell, word2);
X	      expand_env(shell, word2);
X	    }
X	    else if (equal(word1, "sort") || equal(word1, "sortby")) {
X	      strcpy(word2, shift_lower(word2));
X	      if (equal(word2, "sent"))
X		 sortby = SENT_DATE;
X	      else if (equal(word2, "received") || equal(word2,"recieved"))
X		 sortby = RECEIVED_DATE;
X	      else if (equal(word2, "from") || equal(word2, "sender"))
X		 sortby = SENDER;
X	      else if (equal(word2, "size") || equal(word2, "lines"))
X		sortby = SIZE;
X	      else if (equal(word2, "subject"))
X		sortby = SUBJECT;
X	      else if (equal(word2, "mailbox") || equal(word2, "folder"))
X		sortby = MAILBOX_ORDER;
X	      else if (equal(word2, "status"))
X		sortby = STATUS;
X	      else if (equal(word2, "reverse-sent") || equal(word2,"rev-sent"))
X		 sortby = - SENT_DATE;
X	      else if (strncmp(word2, "reverse-rec",11) == 0 || 
X		       strncmp(word2,"rev-rec",7) == 0)
X		 sortby = - RECEIVED_DATE;
X	      else if (equal(word2, "reverse-from") || equal(word2, "rev-from")
X		    || equal(word2,"reverse-sender")||equal(word2,"rev-sender"))
X		 sortby = - SENDER;
X	      else if (equal(word2, "reverse-size") || equal(word2, "rev-size")
X		    || equal(word2, "reverse-lines")|| equal(word2,"rev-lines"))
X		sortby = - SIZE;
X	      else if (equal(word2, "reverse-subject") || 
X		       equal(word2, "rev-subject"))
X		sortby = - SUBJECT;
X	      else if (equal(word2, "reverse-mailbox") || 
X		       equal(word2, "rev-mailbox") ||
X		       equal(word2, "reverse-folder") || 
X		       equal(word2, "rev-folder"))
X		sortby = - MAILBOX_ORDER;
X	      else if (equal(word2, "reverse-status") || 
X		       equal(word2, "rev-status"))
X		sortby = - STATUS;
X	      else {
X		errors++;
X		printf(
X      "I can't understand sort key %s in line %d in your \".elm/elmrc\" file\n",
X		     word2, lineno);
X	        continue;
X	      }
X	    }
X	    else if (equal (word1, "receivedmail") || equal(word1, "mailbox")) {
X	      /* the last is an old name of this option - here for
X	       * compatibility in case the user has never written out
X	       * a new elmrc while in elm since the name change.
X	       */
X	      rc_has_recvdmail = TRUE;
X	      strcpy(raw_recvdmail, word2);
X	      expand_env(recvd_mail, word2);
X	    }
X	    else if (equal(word1, "editor") || equal(word1,"mailedit")) {
X	      strcpy(raw_editor, word2);
X	      expand_env(editor, word2);
X	    }
X	    else if (equal(word1, "sentmail") ||
X		equal(word1, "savemail") || equal(word1, "saveto")) {
X	      /* the last two were old names of this option - here for
X	       * compatibility in case the user has never written out
X	       * a new elmrc while in elm since the name change.
X	       */
X	      rc_has_sentmail = TRUE;
X	      strcpy(raw_sentmail, word2);
X	      expand_env(sent_mail, word2);
X	    }
X	    else if (equal(word1, "calendar")) {
X	      strcpy(raw_calendar_file, word2);
X	      expand_env(calendar_file, word2);
X	    }
X	    else if (equal(word1, "print") || equal(word1, "printmail")) {
X	      strcpy(raw_printout, word2);
X	      expand_env(printout, word2);
X	    }
X	    else if (equal(word1, "pager") || equal(word1, "page")) {
X	      strcpy(raw_pager, word2);
X	      expand_env(pager, word2);
X	      if (equal(pager,"builtin+") || equal(pager,"internal+"))
X		clear_pages++;
X	    }
X	    else if (equal(word1, "signature")) {
X	      if (equal(shift_lower(word2), "on") ||
X		  equal(shift_lower(word2), "off")) {
X		errors++;
X		printf(
X	"\"signature\" used in obsolete way in .elm/elmrc file. Ignored!\n\r");
X		printf(
X "\t(Signature should specify the filename to use rather than on/off.)\n\r\n");
X	      }
X	      else {
X		strcpy(raw_local_signature, word2);
X		strcpy(raw_remote_signature, raw_local_signature);
X		expand_env(local_signature, word2);
X		strcpy(remote_signature, local_signature);
X	      }
X	    }
X	    else if (equal(word1, "localsignature")) {
X	      strcpy(raw_local_signature, word2);
X	      expand_env(local_signature, word2);
X	    }
X	    else if (equal(word1, "remotesignature")) {
X	      strcpy(raw_remote_signature, word2);
X	      expand_env(remote_signature, word2);
X	    }
X	    else if (equal(word1, "sigdashes")) {
X	      sig_dashes = is_it_on(word2);
X	    }
X	    else if (equal(word1, "escape")) {
X	      escape_char = word2[0];
X	    }
X	    else if (equal(word1, "attribution")) {
X	      strcpy(attribution, word2);
X	    }
X	    else if (equal(word1, "autocopy")) {
X	      auto_copy = is_it_on(word2);
X	    }
X	    else if (equal(word1, "copy") || equal(word1, "auto_cc")) {
X	      auto_cc = is_it_on(word2);
X	    }
X	    else if (equal(word1, "names")) {
X	      names_only = is_it_on(word2);
X	    }
X	    else if (equal(word1, "resolve")) {
X	      resolve_mode = is_it_on(word2);
X	    }
X	    else if (equal(word1, "weed")) {
X	      filter = is_it_on(word2);
X	    }
X	    else if (equal(word1, "noheader")) {
X	      noheader = is_it_on(word2);
X	    }
X	    else if (equal(word1, "titles")) {
X	      title_messages = is_it_on(word2);
X	    }
X	    else if (equal(word1, "savebyname") || equal(word1, "savename")) {
X	      save_by_name = is_it_on(word2);
X	    }
X	    else if (equal(word1, "forcename")) {
X	      force_name = is_it_on(word2);
X	    }
X	    else if (equal(word1, "movepage") || equal(word1, "page") ||
X		     equal(word1, "movewhenpaged")) {
X	      move_when_paged = is_it_on(word2);
X	    }
X	    else if (equal(word1, "pointnew") || equal(word1, "pointtonew")) {
X	      point_to_new = is_it_on(word2);
X	    }
X	    else if (equal(word1, "keypad") || equal(word1, "hpkeypad")) {
X	      hp_terminal = is_it_on(word2);
X	    }
X	    else if (equal(word1, "softkeys") || equal(word1, "hpsoftkeys")) {
X	      if (hp_softkeys = is_it_on(word2))
X		hp_terminal = TRUE;	/* must be set also! */
X	    }
X	    else if (equal(word1, "arrow")) {
X	      arrow_cursor += is_it_on(word2);	/* may have been set already */
X	    }
X	    else if (strncmp(word1, "form", 4) == 0) {
X	      allow_forms = (is_it_on(word2)? MAYBE : NO);
X	    }
X	    else if (equal(word1, "promptafter")) {
X	      prompt_after_pager = is_it_on(word2);
X	    }
X	    else if (strncmp(word1, "menu", 4) == 0) {
X	      /* if not turned off by -m cmd line arg,
X	       * obey elmrc file setting */
X	      if(mini_menu)
X		mini_menu = is_it_on(word2);
X	    }
X	    else if (strncmp(word1, "warning", 7) == 0) {
X	      warnings = is_it_on(word2);
X	    }
X	    else if (equal(word1, "alwaysleave")) {
X	      /* this is an old option - here for
X	       * compatibility in case the user has never written out
X	       * a new elmrc while in elm since the split of
X	       * alwaysleave into alwayskeep and alwaysstore
X	       */
X	      always_keep = is_it_on(word2);
X	      always_store = !is_it_on(word2);
X	    }
X	    else if (equal(word1, "alwayskeep")) {
X	      always_keep = is_it_on(word2);
X	    }
X	    else if (equal(word1, "alwaysstore") || equal(word1, "store")) {
X	      always_store = is_it_on(word2);
X	    }
X	    else if (equal(word1, "alwaysdelete") || equal(word1, "delete")) {
X	      always_del = is_it_on(word2);
X	    }
X	    else if (equal(word1, "askcc") || equal(word1, "cc")) {
X	      prompt_for_cc = is_it_on(word2);
X	    }
X	    else if (equal(word1, "ask") || equal(word1, "question")) {
X	      question_me = is_it_on(word2);
X	    }
X	    else if (equal(word1, "keep") || equal(word1, "keepempty")) {
X	      keep_empty_files = is_it_on(word2);
X	    }
X	    else if (equal(word1, "bounce") || equal(word1, "bounceback")) {
X	      bounceback = atoi(word2);
X	      if (bounceback > MAX_HOPS) {
X		errors++;
X		printf(
X	"Warning: bounceback is set to greater than %d (max-hops). Ignored.\n",
X			 MAX_HOPS);
X		bounceback = 0;
X	      }
X	    }
X	    else if (equal(word1, "userlevel")) {
X	      user_level = atoi(word2);
X	    }
X	    else if (equal(word1, "timeout")) {
X	      timeout = atoi(word2);
X	      if (timeout < 10) {
X		errors++;
X		printf(
X	     "Warning: timeout is set to less than 10 seconds. Ignored.\n");
X		timeout = 0;
X	      }
X	    }
X	    else if (equal(word1, "weedout")) {
X	      weedout(word2);
X	      this = WEEDOUT;
X	    }
X	    else if (equal(word1, "alternatives")) {
X	      alternatives(word2);
X	      this = ALTERNATIVES;
X	    }
X	    else if (last == WEEDOUT) {
X	      weedout(buffer);
X	      this = WEEDOUT;
X	    }
X	    else if (last == ALTERNATIVES) {
X	      alternatives(buffer);
X	      this = ALTERNATIVES;
X	    }
X	    else {
X	      errors++;
X	      printf(
X	     "I can't understand line %d in your \".elm/elmrc\" file:\n> %s\n", 
X		     lineno, buffer);
X	    }
X	    last = this;
X	  }
X	  /* sleep two seconds for each error and then some so user
X	   * can read them before screen is cleared */
X	  if(errors)
X	    sleep((errors * 2) + 2);
X	}
X
X	/* see if the user has a folders directory */
X	if (access(folders, 00) == -1) {
X	  if(batch_only)  {
X	    printf("\n\rNotice:\
X\n\rELM requires the use of a folders directory to store your mail folders in.\
X\n\rI'd like to create the directory %s for you,\
X\n\rbut I can't in \"batch mode\". Please run ELM in \"normal mode\" first.\
X\n\r", folders);
X	    exit(0);
X	  }
X
X	  printf("\n\rNotice:\
X\n\rELM requires the use of a folders directory to store your mail folders in.\
X\n\rShall I create the directory %s for you (y/n)? y%c", folders, BACKSPACE);
X
X	  fflush(stdout);
X	  ch=getchar();
X	  if (ch == 'n' || ch == 'N') {
X	    printf("No.\n\rVery well. I won't create it.\
X	    \n\rBut, you may run into difficulties later.\n\r");
X	    sleep(4);
X	  }
X	  else {
X	    printf("Yes.\n\rGreat! I'll do it now.\n\r");
X	    create_new_folders();
X	  }
X	}
X
X	/* If recvd_mail or sent_mail havent't yet been established in
X	 * the elmrc, establish them from their defaults.
X	 * Then if they begin with a metacharacter, replace it with the
X	 * folders directory name.
X	 */
X	if(!rc_has_recvdmail) {
X	  strcpy(raw_recvdmail, default_recvdmail);
X	  strcpy(recvd_mail, raw_recvdmail);
X	}
X	if(metachar(recvd_mail[0])) {
X	  strcpy(buffer, &recvd_mail[1]);
X	  sprintf(recvd_mail, "%s/%s", folders, buffer);
X	}
X
X	if(!rc_has_sentmail) {
X	  sprintf(raw_sentmail, default_sentmail);
X	  sprintf(sent_mail, default_sentmail);
X	}
X	if(metachar(sent_mail[0])) {
X	  strcpy(buffer, &sent_mail[1]);
X	  sprintf(sent_mail, "%s/%s", folders, buffer);
X	}
X
X	if (debug > 10) 	/** only do this if we REALLY want debug! **/
X	  dump_rc_results();
X
X}
X	
Xweedout(string)
Xchar *string;
X{
X	/** This routine is called with a list of headers to weed out.   **/
X
X	char *strptr, *header;
X	register int i, len;
X
X	strptr = string;
X
X	while ((header = strtok(strptr, "\t ,\"'")) != NULL) {
X	  if (strlen(header) > 0) {
X	    if (! strcmp(header, "*end-of-user-headers*")) break;
X	    if (weedcount > MAX_IN_WEEDLIST) {
X	      printf("Too many weed headers!  Leaving...\n");
X	      exit(1);
X	    }
X	    if ((weedlist[weedcount] = pmalloc(strlen(header) + 1)) 
X		== NULL) {
X	      printf("Too many weed headers! Out of memory!  Leaving...\n");
X	      exit(1);
X	    }
X
X	    for (i=0, len = strlen(header); i< len; i++)
X	      if (header[i] == '_') header[i] = ' ';
X
X	    strcpy(weedlist[weedcount], header);
X	    weedcount++;
X	  }
X	  strptr = NULL;
X	}
X}
X
Xalternatives(string)
Xchar *string;
X{
X	/** This routine is called with a list of alternative addresses
X	    that you may receive mail from (forwarded) **/
X
X	char *strptr, *address;
X	struct addr_rec *current_record, *previous_record;
X
X	previous_record = alternative_addresses;	/* start 'er up! */
X	/* move to the END of the alternative addresses list */
X
X	if (previous_record != NULL)
X	  while (previous_record->next != NULL)
X	    previous_record = previous_record->next;
X
X	strptr = (char *) string;
X
X	while ((address = strtok(strptr, "\t ,\"'")) != NULL) {
X	  if (previous_record == NULL) {
X	    previous_record = (struct addr_rec *) pmalloc(sizeof 
X		*alternative_addresses);
X
X	    strcpy(previous_record->address, address);
X	    previous_record->next = NULL;
X	    alternative_addresses = previous_record;
X	  }
X	  else {
X	    current_record = (struct addr_rec *) pmalloc(sizeof 
X		*alternative_addresses);
X	  
X	    strcpy(current_record->address, address);
X	    current_record->next = NULL;
X	    previous_record->next = current_record;
X	    previous_record = current_record;
X	  }
X	  strptr = (char *) NULL;
X	}
X}
X
Xdefault_weedlist()
X{
X	/** Install the default headers to weed out!  Many gracious 
X	    thanks to John Lebovitz for this dynamic method of 
X	    allocation!
X	**/
X
X	static char *default_list[] = { ">From", "In-Reply-To:",
X		       "References:", "Newsgroups:", "Received:",
X		       "Apparently-To:", "Message-Id:", "Content-Type:",
X		       "From", "X-Mailer:", "Status:",
X		       "*end-of-defaults*", NULL
X		     };
X
X	for (weedcount = 0; default_list[weedcount] != (char *) 0;weedcount++){
X	  if ((weedlist[weedcount] = 
X	      pmalloc(strlen(default_list[weedcount]) + 1)) == NULL) {
X	    printf("\n\rNot enough memory for default weedlist. Leaving.\n\r");
X	    leave(1);
X	  }
X	  strcpy(weedlist[weedcount], default_list[weedcount]);
X	}
X}
X
Xint
Xmatches_weedlist(buffer)
Xchar *buffer;
X{
X	/** returns true iff the first 'n' characters of 'buffer' 
X	    match an entry of the weedlist **/
X	
X	register int i;
X
X	for (i=0;i < weedcount; i++)
X	  if (strncmp(buffer, weedlist[i], strlen(weedlist[i])) == 0) 
X	    return(1);
X
X	return(0);
X}
X
Xint
Xbreakup(buffer, word1, word2)
Xchar *buffer, *word1, *word2;
X{
X	/** This routine breaks buffer down into word1, word2 where 
X	    word1 is alpha characters only, and there is an equal
X	    sign delimiting the two...
X		alpha = beta
X	    For lines with more than one 'rhs', word2 is set to the
X	    entire string.
X	    Return -1 if word 2 is of zero length, else 0.
X	**/
X
X	register int i;
X	
X	for (i=0;buffer[i] != '\0' && ok_rc_char(buffer[i]); i++)
X	  if (buffer[i] == '_')
X	    word1[i] = '-';
X	  else if (isupper(buffer[i]))
X	    word1[i] = tolower(buffer[i]);
X	  else
X	    word1[i] = buffer[i];
X
X	word1[i++] = '\0';	/* that's the first word! */
X
X	/** spaces before equal sign? **/
X
X	while (whitespace(buffer[i])) i++;
X	if (buffer[i] == '=') i++;
X
X	/** spaces after equal sign? **/
X
X	while (whitespace(buffer[i])) i++;
X
X	if (buffer[i] != '\0')
X	  strcpy(word2, (char *) (buffer + i));
X	else
X	  word2[0] = '\0';
X
X	/* remove trailing spaces from word2! */
X	i = strlen(word2) - 1;
X	while(i && (whitespace(word2[i]) || word2[i] == '\n'))
X	  word2[i--] = '\0';
X
X	return(*word2 == '\0' ? -1 : 0 );
X
X}
X
Xexpand_env(dest, buffer)
Xchar *dest, *buffer;
X{
X	/** expand possible metacharacters in buffer and then copy
X	    to dest... 
X
X	    BEWARE!! Because strtok() is used on buffer, buffer may be changed.
X
X	    This routine knows about "~" being the home directory,
X	    and "$xxx" being an environment variable.
X	**/
X
X	char  *word, *string, next_word[SLEN];
X	
X	if (buffer[0] == '/') {
X	  dest[0] = '/';
X	  dest[1] = '\0';
X/* Added for Apollos - handle //node */
X	  if (buffer[1] == '/') {
X	    dest[1] = '/';
X	    dest[2] = '\0';
X	  }
X	}
X	else
X	  dest[0] = '\0';
X
X	string = (char *) buffer;
X
X	while ((word = strtok(string, "/")) != NULL) {
X	  if (word[0] == '$') {
X	    next_word[0] = '\0';
X	    if (getenv((char *) (word + 1)) != NULL)
X	    strcpy(next_word, getenv((char *) (word + 1)));
X	    if (strlen(next_word) == 0)
X	      leave(printf("\n\rCan't expand environment variable '%s'.\n\r",
X		    word));
X	  }
X	  else if (word[0] == '~' && word[1] == '\0')
X	    strcpy(next_word, home);
X	  else
X	    strcpy(next_word, word);
X
X	  sprintf(dest, "%s%s%s", dest, 
X		 (strlen(dest) > 0 && lastch(dest) != '/' ? "/":""),
X		 next_word);
X
X	  string = (char *) NULL;
X	}
X}
X
X#define on_off(s)	(s == 1? "ON " : "OFF")
Xdump_rc_results()
X{
X
X	register int i, len;
X
X	fprintf(debugfile, "folders = %s ", folders);
X	fprintf(debugfile, "temp_dir = %s ", temp_dir);
X	fprintf(debugfile, "recvd_mail = %s ", recvd_mail);
X	fprintf(debugfile, "editor = %s\n", editor);
X	fprintf(debugfile, "printout = %s ", printout);
X	fprintf(debugfile, "sent_mail = %s ", sent_mail);
X	fprintf(debugfile, "calendar_file = %s\n", calendar_file);
X	fprintf(debugfile, "prefixchars = %s ", prefixchars);
X	fprintf(debugfile, "shell = %s ", shell);
X	fprintf(debugfile, "pager = %s\n", pager);
X	fprintf(debugfile, "\n");
X	fprintf(debugfile, "escape = %c\n", escape_char);
X	fprintf(debugfile, "\n");
X
X	fprintf(debugfile, "mini_menu    = %s ", on_off(mini_menu));
X	fprintf(debugfile, "filter_hdrs  = %s ", on_off(filter));
X	fprintf(debugfile, "auto_copy      = %s\n", on_off(auto_copy));
X
X	fprintf(debugfile, "resolve_mode   = %s ", on_off(resolve_mode));
X	fprintf(debugfile, "auto_save_copy = %s ", on_off(auto_cc));
X	fprintf(debugfile, "noheader     = %s\n", on_off(noheader));
X
X	fprintf(debugfile, "title_msgs   = %s ", on_off(title_messages));
X	fprintf(debugfile, "hp_terminal    = %s ", on_off(hp_terminal));
X	fprintf(debugfile, "hp_softkeys    = %s\n", on_off(hp_softkeys));
X
X	fprintf(debugfile, "save_by_name = %s ", on_off(save_by_name));
X	fprintf(debugfile, "force_name = %s\n", on_off(force_name));
X
X	fprintf(debugfile, "move_paged   = %s ", on_off(move_when_paged));
X	fprintf(debugfile, "point_to_new   = %s ", on_off(point_to_new));
X	fprintf(debugfile, "prompt_after_pager   = %s ",
X	    on_off(prompt_after_pager));
X	fprintf(debugfile, "bounceback     = %s\n", on_off(bounceback));
X
X	fprintf(debugfile, "always_keep = %s ", on_off(always_keep));
X	fprintf(debugfile, "always_store = %s ", on_off(always_store));
X	fprintf(debugfile, "always_delete  = %s ", on_off(always_del));
X	fprintf(debugfile, "arrow_cursor   = %s ", on_off(arrow_cursor));
X	fprintf(debugfile, "names        = %s\n", on_off(names_only));
X
X	fprintf(debugfile, "warnings     = %s ", on_off(warnings));
X	fprintf(debugfile, "question_me    = %s ", on_off(question_me));
X	fprintf(debugfile, "keep_nil_files = %s\n\n", 
X			   on_off(keep_empty_files));
X
X	fprintf(debugfile, "local_signature  = %s\n", local_signature);
X	fprintf(debugfile, "remote_signature = %s\n", remote_signature);
X	fprintf(debugfile, "sig_dashes = %s\n", on_off(sig_dashes));
X
X	fprintf(debugfile, "Userlevel is set to %s user: %d\n", 
X		user_level == 0 ? "beginning" : 
X		 user_level > 1 ? "expert" : "intermediate", user_level);
X
X	fprintf(debugfile, "\nAnd we're skipping the following headers:\n\t");
X
X	for (len=8, i=0; i < weedcount; i++) {
X	  if (weedlist[i][0] == '*') continue;	/* skip '*end-of-defaults*' */
X	  if (len + strlen(weedlist[i]) > 80) {
X	    fprintf(debugfile, " \n\t");
X	    len = 8;
X	  }
X	  fprintf(debugfile, "%s  ", weedlist[i]);
X	  len += strlen(weedlist[i]) + 3;
X	}
X	
X	fprintf(debugfile, "\n\n");
X}
X
Xis_it_on(word)
Xchar *word;
X{
X	/** Returns TRUE if the specified word is either 'ON', 'YES'
X	    or 'TRUE', and FALSE otherwise.   We explicitly translate
X	    to lowercase here to ensure that we have the fastest
X	    routine possible - we really DON'T want to have this take
X	    a long time or our startup will be major pain each time.
X	**/
X
X	static char mybuffer[NLEN];
X	register int i, j;
X
X	for (i=0, j=0; word[i] != '\0'; i++)
X	  mybuffer[j++] = isupper(word[i]) ? tolower(word[i]) : word[i];
X	mybuffer[j] = '\0';
X
X	return(  (strncmp(mybuffer, "on",   2) == 0) ||
X		 (strncmp(mybuffer, "yes",  3) == 0) ||
X		 (strncmp(mybuffer, "true", 4) == 0)
X	      );
X}
SHAR_EOF
echo "File src/read_rc.c is complete" &&
# ============= src/remail.c ==============
echo "x - extracting src/remail.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/remail.c &&
X
Xstatic char rcsid[] = "@(#)$Id: remail.c,v 4.1.1.2 90/10/10 12:45:07 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 4.1.1.2 $   $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:	remail.c,v $
X * Revision 4.1.1.2  90/10/10  12:45:07  syd
X * Make the symbol look less like a typo, its real
X * From: Syd
X * 
X * Revision 4.1.1.1  90/10/07  19:48:15  syd
X * fix the bounce problem reported earlier when using MMDF submit as the MTA.
X * From: Jim Clausing <jac%brahms.tinton.ccur.com@RELAY.CS.NET>
X * 
X * Revision 4.1  90/04/28  22:43:50  syd
X * checkin of Elm 2.3 as of Release PL0
X * 
X *
X ******************************************************************************/
X
X/** For those cases when you want to have a message continue along
X    to another person in such a way as they end up receiving it with
X    the return address the person YOU received the mail from (does
X    this comment make any sense yet??)...
X
X**/
X
X#include "headers.h"
X#include <errno.h>
X
Xextern int errno;
X
Xchar *error_name(), *error_description();
X
Xint
Xremail()
X{
X	/** remail a message... returns TRUE if new foot needed ... **/
X	
X	FILE *mailfd;
X	char entered[VERY_LONG_STRING], expanded[VERY_LONG_STRING];
X	char *filename, buffer[VERY_LONG_STRING], ch;
X	char mailerflags[NLEN];
X	extern char *tempnam();
X
X	entered[0] = '\0';
X
X	get_to(entered, expanded);
X	if (strlen(entered) == 0)
X	  return(0);
X
X	display_to(expanded);
X
X	if((filename=tempnam(temp_dir, "snd.")) == NULL) {
X	  dprint(1, (debugfile, "couldn't make temp file nam! (remail)\n"));
X	  sprintf(buffer, "Sorry - couldn't make file temp file name.");
X	  set_error(buffer);
X	  return(1);
X	}
X
X	if ((mailfd = fopen(filename, "w")) == NULL) {
X	  dprint(1, (debugfile, "couldn't open temp file %s! (remail)\n", 
X		  filename));
X	  dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
X		  error_description(errno)));
X	  sprintf(buffer, "Sorry - couldn't open file %s for writing (%s).",
X		  error_name(errno));
X	  set_error(buffer);
X	  return(1);
X	}
X
X	/** now let's copy the message into the newly opened
X	    buffer... **/
X
X	chown (filename, userid, groupid);
X
X#ifdef MMDF
X	if (strcmp(submitmail, mailer) == 0)
X	  do_mmdf_addresses(mailfd, strip_parens(strip_commas(expanded)));
X#endif /* MMDF */
X
X	copy_message("", mailfd, FALSE, TRUE, FALSE, TRUE, TRUE);  
X
X	fclose(mailfd);
X
X	/** Got the messsage, now let's ensure the person really wants to 
X	    remail it... **/
X
X	ClearLine(LINES-1);
X	ClearLine(LINES);
X	PutLine1(LINES-1,0,
X	    "Are you sure you want to remail this message (y/n)? y%c",
X	    BACKSPACE);
X	fflush(stdin);
X	fflush(stdout);
X	ch = ReadCh();
X	if (tolower(ch) == 'n') { /* another day, another No... */
X	  Write_to_screen("No.", 0);
X	  set_error("Bounce of message cancelled.");
X	  (void) unlink(filename);
X	  return(1);
X	}
X	Write_to_screen("Yes.", 0);
X
X	if (strcmp(sendmail, mailer) == 0
X#ifdef SITE_HIDING
X	    && ! is_a_hidden_user(username))
X#else
X					 )
X#endif
X	  strcpy(mailerflags, (sendmail_verbose ? smflagsv : smflags));
X	else if (strcmp(submitmail, mailer) == 0) {
X	  strcpy(mailerflags, submitflags_s);
X	  strcpy(expanded, " ");
X	} else
X	  mailerflags[0] = '\0';
X	
X	sprintf(buffer,"( (%s %s %s ; %s %s) & ) < %s", 
X	      mailer, mailerflags, strip_parens(strip_commas(expanded)), 
X	      remove_cmd, filename, filename);
X
X	PutLine0(LINES,0,"Resending mail...");
X	system_call(buffer, SH, FALSE, FALSE);
X	set_error("Mail resent.");
X
X	return(1);
X}
X#ifdef MMDF
Xdo_mmdf_addresses(dest_file,buffer)
XFILE *dest_file;
Xchar *buffer;
X{
X	char old[VERY_LONG_STRING], first[VERY_LONG_STRING], 
X		rest[VERY_LONG_STRING];
X
X	strcpy(old,buffer);
X	split_word(old, first, rest);
X	while (strcmp(first, "") != 0) {
X	  fprintf(dest_file, "%s\n", first);
X	  strcpy(old, rest);
X	  split_word(old, first, rest);
X	}
X	fprintf(dest_file, "\n");
X}
X#endif /* MMDF */
SHAR_EOF
# ============= src/reply.c ==============
echo "x - extracting src/reply.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/reply.c &&
X
Xstatic char rcsid[] = "@(#)$Id: reply.c,v 4.1 90/04/28 22:43:51 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:	reply.c,v $
X * Revision 4.1  90/04/28  22:43:51  syd
X * checkin of Elm 2.3 as of Release PL0
X * 
X *
X ******************************************************************************/
X
X/*** routine allows replying to the sender of the current message 
X
X***/
X
X#include "headers.h"
X#include <errno.h>
X
X#ifndef BSD
X#  include <sys/types.h>
X# ifndef VMS
X#  include <sys/utsname.h>
X# endif
X#endif
X
X/** Note that this routine generates automatic header information
X    for the subject and (obviously) to lines, but that these can
X    be altered while in the editor composing the reply message! 
X**/
X
Xchar *strip_parens(), *get_token();
X
Xextern int errno;
X
Xchar *error_name(), *strcat(), *strcpy();
X
Xint
Xreply()
X{
X	/** Reply to the current message.  Returns non-zero iff
X	    the screen has to be rewritten. **/
X
X	char return_address[SLEN], subject[SLEN];
X	int  return_value, form_letter;
X
X	form_letter = (headers[current-1]->status & FORM_LETTER);
X
X	if (get_return(return_address, current-1)) {
X	  strcpy(subject, headers[current-1]->subject);
X	  if (form_letter)
X	    return_value = mail_filled_in_form(return_address, subject);
X	  else
X	    return_value = sendmsg(return_address, "", subject, TRUE, NO, TRUE);
X	}
X	else if (headers[current-1]->subject[0] != '\0') {
X	  if ((strncmp("Re:", headers[current-1]->subject, 3) == 0) ||
X	      (strncmp("RE:", headers[current-1]->subject, 3) == 0) ||
X	      (strncmp("re:", headers[current-1]->subject, 3) == 0)) 
X	    strcpy(subject, headers[current-1]->subject);
X	  else {
X	    strcpy(subject,"Re: ");
X	    strcat(subject,headers[current-1]->subject); 
X	  }
X	  if (form_letter)
X	    return_value = mail_filled_in_form(return_address, subject);
X	  else
X	    return_value = sendmsg(return_address, "", subject, TRUE, NO, TRUE);
X	}
X	else
X	  if (form_letter)
X	    return_value = mail_filled_in_form(return_address, 
X						"Filled in Form");
X	  else
X	    return_value = sendmsg(return_address, "", "Re: your mail", 
X				TRUE, NO, TRUE);
X
X	return(return_value);
X}
X
Xint
Xreply_to_everyone()
X{
X	/** Reply to everyone who received the current message.  
X	    This includes other people in the 'To:' line and people
X	    in the 'Cc:' line too.  Returns non-zero iff the screen 
X            has to be rewritten. **/
X
X	char return_address[SLEN], subject[SLEN];
X	char full_address[VERY_LONG_STRING];
X	int  return_value;
X
X	get_return(return_address, current-1);
X
X	full_address[0] = '\0';			/* no copies yet    */
X	get_and_expand_everyone(return_address, full_address);
X
X	if (headers[current-1]->subject[0] != '\0') {
X	  if ((strncmp("Re:", headers[current-1]->subject, 3) == 0) ||
X	      (strncmp("RE:", headers[current-1]->subject, 3) == 0) ||
X	      (strncmp("re:", headers[current-1]->subject, 3) == 0)) 
X	    strcpy(subject, headers[current-1]->subject);
X	  else {
X	    strcpy(subject,"Re: ");
X	    strcat(subject,headers[current-1]->subject); 
X	  }
X	  return_value = sendmsg(return_address, full_address, subject, 
X				 TRUE, NO, TRUE);
X	}
X	else
X	  return_value = sendmsg(return_address, full_address, 
X			      "Re: your mail", TRUE, NO, TRUE);
X
X	return(return_value);
X
X}
X
Xint
Xforward()
X{
X	/** Forward the current message.  What this actually does is
X	    to temporarily set forwarding to true, then call 'send' to
X	    get the address and route the mail.   Modified to also set
X	    'noheader' to FALSE also, so that the original headers
X	    of the message sent are included in the message body also.
X	    Return TRUE if the main part of the screen has been changed
X	    (useful for knowing whether a redraw is needed.
X	**/
X
X	char subject[SLEN], address[VERY_LONG_STRING];
X	int  results, edit_msg = FALSE;
X
X	forwarding = TRUE;
X
X	address[0] = '\0';
X
X	if (headers[current-1]->status & FORM_LETTER)
X	  PutLine0(LINES-3,COLUMNS-40,"<No editing allowed.>");
X	else {
X	  edit_msg = (want_to("Edit outgoing message? (y/n) ",'y') != 'n');
X	}
X
X	if (strlen(headers[current-1]->subject) > 0) {
X
X	  strcpy(subject, headers[current-1]->subject); 
X
X	  /* this next strange compare is to see if the last few chars are
X	     already '(fwd)' before we tack another on */
X
X	  if (strlen(subject) < 6 || (strcmp((char *) subject+strlen(subject)-5,
X					     "(fwd)") != 0))
X	    strcat(subject, " (fwd)");
X
X	  results = sendmsg(address, "", subject, edit_msg,
X	    headers[current-1]->status & FORM_LETTER? 
X	    PREFORMATTED : allow_forms, FALSE);
X	}
X	else
X	  results = sendmsg(address, "", "Forwarded mail...", edit_msg, 
X	    headers[current-1]->status & FORM_LETTER? 
X	    PREFORMATTED : allow_forms, FALSE);
X	
X	forwarding = FALSE;
X
X	return(results);
X}
X
Xget_and_expand_everyone(return_address, full_address)
Xchar *return_address, *full_address;
X{
X	/** Read the current message, extracting addresses from the 'To:'
X	    and 'Cc:' lines.   As each address is taken, ensure that it
X	    isn't to the author of the message NOR to us.  If neither,
X	    prepend with current return address and append to the 
X	    'full_address' string.
X	**/
X
X    char ret_address[SLEN], buf[SLEN], new_address[SLEN],
X	 address[SLEN], comment[SLEN];
X    int  in_message = 1, first_pass = 0, iindex, line_pending = 0;
X
X    /** First off, get to the first line of the message desired **/
X
X    if (fseek(mailfile, headers[current-1]->offset, 0) == -1) {
X	dprint(1,(debugfile,"Error: seek %ld resulted in errno %s (%s)\n", 
X		 headers[current-1]->offset, error_name(errno), 
X		 "get_and_expand_everyone"));
X	error2("ELM [seek] couldn't read %d bytes into file (%s).",
X	       headers[current-1]->offset, error_name(errno));
X	return;
X    }
X 
X    /** okay!  Now we're there!  **/
X
X    /** let's fix the ret_address to reflect the return address of this
X	message with '%s' instead of the persons login name... **/
X
X    translate_return(return_address, ret_address);
X
X    /** now let's parse the actual message! **/
X
X    while (in_message) {
X      if (! line_pending)
X        in_message = (int) (fgets(buf, SLEN, mailfile) != NULL);
X      line_pending = 0;
X      if (first_word(buf, "From ") && first_pass++ != 0) 
X	in_message = FALSE;
X      else if (first_word(buf, "To:") || first_word(buf, "Cc:") ||
X	       first_word(buf, "CC:") || first_word(buf, "cc:")) {
X	do {
X	  no_ret(buf);
X
X	  /** we have a buffer with a list of addresses, each of either the
X	      form "address (name)" or "name <address>".  Our mission, should
X	      we decide not to be too lazy, is to break it into the two parts.
X	  **/
X	      
X	  if (!whitespace(buf[0]))
X	    iindex = chloc(buf, ':')+1;		/* skip header field */
X	  else
X	    iindex = 0;				/* skip whitespace   */
X
X	  while (break_down_tolist(buf, &iindex, address, comment)) {
X
X	    if (okay_address(address, return_address)) {
X	      sprintf(new_address, ret_address, address);
X	      optimize_and_add(new_address, full_address);
X	    }
X	  }
X
X          in_message = (int) (fgets(buf, SLEN, mailfile) != NULL);
X
X	  if (in_message) dprint(2, (debugfile, "> %s", buf));
X	
X	} while (in_message && whitespace(buf[0]));
X	line_pending++;
X      }
X      else if (strlen(buf) < 2)	/* done with header */
X	 in_message = FALSE;
X    }
X}
X
Xint
Xokay_address(address, return_address)
Xchar *address, *return_address;
X{
X	/** This routine checks to ensure that the address we just got
X	    from the "To:" or "Cc:" line isn't us AND isn't the person	
X	    who sent the message.  Returns true iff neither is the case **/
X
X	char our_address[SLEN];
X	struct addr_rec  *alternatives;
X
X	if (in_list(address, return_address))
X	  return(FALSE);
X
X	if(in_list(address, username))
X	  return(FALSE);
X
X	sprintf(our_address, "%s!%s", hostname, username);
X	if (in_list(address, our_address))
X	  return(FALSE);
X
X	sprintf(our_address, "%s!%s", hostfullname, username);
X	if (in_list(address, our_address))
X	  return(FALSE);
X
X	sprintf(our_address, "%s@%s", username, hostname);
X	if (in_list(address, our_address))
X	  return(FALSE);
X
X	sprintf(our_address, "%s@%s", username, hostfullname);
X	if (in_list(address, our_address))
X	  return(FALSE);
X
X	alternatives = alternative_addresses;
X
X	while (alternatives != NULL) {
X	  if (in_list(address, alternatives->address))
X	    return(FALSE);
X	  alternatives = alternatives->next;
X	}
X
X	return(TRUE);
X}
X	    
Xoptimize_and_add(new_address, full_address)
Xchar *new_address, *full_address;
X{
X	/** This routine will add the new address to the list of addresses
X	    in the full address buffer IFF it doesn't already occur.  It
X	    will also try to fix dumb hops if possible, specifically hops
X	    of the form ...a!b...!a... and hops of the form a@b@b etc 
X	**/
X
X	register int len, host_count = 0, i;
X	char     hosts[MAX_HOPS][SLEN];	/* array of machine names */
X	char     *host, *addrptr;
X
X	if (in_list(full_address, new_address))
X	  return(1);	/* duplicate address */
X
X	/** optimize **/
X	/*  break down into a list of machine names, checking as we go along */
X	
X	addrptr = (char *) new_address;
X
X	while ((host = get_token(addrptr, "!", 1)) != NULL) {
X	  for (i = 0; i < host_count && ! equal(hosts[i], host); i++)
X	      ;
X
X	  if (i == host_count) {
X	    strcpy(hosts[host_count++], host);
X	    if (host_count == MAX_HOPS) {
X	       dprint(2, (debugfile,
X              "Error: hit max_hops limit trying to build return address (%s)\n",
X		      "optimize_and_add"));
X	       error("Can't build return address. Hit MAX_HOPS limit!");
X	       return(1);
X	    }
X	  }
X	  else 
X	    host_count = i + 1;
X	  addrptr = NULL;
X	}
X
X	/** fix the ARPA addresses, if needed **/
X	
X	if (chloc(hosts[host_count-1], '@') > -1)
X	  fix_arpa_address(hosts[host_count-1]);
X	  
X	/** rebuild the address.. **/
X
X	new_address[0] = '\0';
X
X	for (i = 0; i < host_count; i++)
X	  sprintf(new_address, "%s%s%s", new_address, 
X	          new_address[0] == '\0'? "" : "!",
X	          hosts[i]);
X
X	if (full_address[0] == '\0')
X	  strcpy(full_address, new_address);
X	else {
X	  len = strlen(full_address);
X	  full_address[len  ] = ',';
X	  full_address[len+1] = ' ';
X	  full_address[len+2] = '\0';
X	  strcat(full_address, new_address);
X	}
X
X	return(0);
X}
X
Xget_return_name(address, name, trans_to_lowercase)
Xchar *address, *name;
Xint   trans_to_lowercase;
X{
X	/** Given the address (either a single address or a combined list 
X	    of addresses) extract the login name of the first person on
X	    the list and return it as 'name'.  Modified to stop at
X	    any non-alphanumeric character. **/
X
X	/** An important note to remember is that it isn't vital that this
X	    always returns just the login name, but rather that it always
X	    returns the SAME name.  If the persons' login happens to be,
X	    for example, joe.richards, then it's arguable if the name 
X	    should be joe, or the full login.  It's really immaterial, as
X	    indicated before, so long as we ALWAYS return the same name! **/
X
X	/** Another note: modified to return the argument as all lowercase
X	    always, unless trans_to_lowercase is FALSE... **/
X
X	char single_address[SLEN];
X	register int i, loc, iindex = 0;
X
X	dprint(6, (debugfile,"get_return_name called with (%s, <>, shift=%s)\n",
X		   address, onoff(trans_to_lowercase)));
X
X	/* First step - copy address up to a comma, space, or EOLN */
X
X	for (i=0; address[i] != ',' && ! whitespace(address[i]) && 
X	     address[i] != '\0'; i++)
X	  single_address[i] = address[i];
X	single_address[i] = '\0';
X
X	/* Now is it an ARPA address?? */
X
X	if ((loc = chloc(single_address, '@')) != -1) {	  /* Yes */
X
X	  /* At this point the algorithm is to keep shifting our copy 
X	     window left until we hit a '!'.  The login name is then
X             located between the '!' and the first metacharacter to 
X	     it's right (ie '%', ':' or '@'). */
X
X	  for (i=loc; single_address[i] != '!' && i > -1; i--)
X	      if (single_address[i] == '%' || 
X	          single_address[i] == ':' ||
X		  single_address[i] == '@') loc = i-1;
X	
X	  if (i < 0 || single_address[i] == '!') i++;
X
X	  for (iindex = 0; iindex < loc - i + 1; iindex++)
X	    if (trans_to_lowercase)
X	      name[iindex] = tolower(single_address[iindex+i]);
X	    else
X	      name[iindex] = single_address[iindex+i];
X	  name[iindex] = '\0';
X	}
X	else {	/* easier - standard USENET address */
X
X	  /* This really is easier - we just cruise left from the end of
X	     the string until we hit either a '!' or the beginning of the
X             line.  No sweat. */
X
X	  loc = strlen(single_address)-1; 	/* last char */
X
X	  for (i = loc; single_address[i] != '!' && single_address[i] != '.' 
X	       && i > -1; i--)
X	     if (trans_to_lowercase)
X	       name[iindex++] = tolower(single_address[i]);
X	     else
X	       name[iindex++] = single_address[i];
X	  name[iindex] = '\0';
X	  reverse(name);
X	}
X}
X
Xint
Xbreak_down_tolist(buf, iindex, address, comment)
Xchar *buf, *address, *comment;
Xint  *iindex;
X{
X	/** This routine steps through "buf" and extracts a single address
X	    entry.  This entry can be of any of the following forms;
X
X		address (name)
X		name <address>
X		address
X	
X	    Once it's extracted a single entry, it will then return it as
X	    two tokens, with 'name' (e.g. comment) surrounded by parens.
X	    Returns ZERO if done with the string...
X	**/
X
X	char buffer[LONG_STRING];
X	register int i, loc = 0, hold_index, len;
X
X	if (*iindex > strlen(buf)) return(FALSE);
X
X	while (whitespace(buf[*iindex])) (*iindex)++;
X
X	if (*iindex > strlen(buf)) return(FALSE);
X
X	/** Now we're pointing at the first character of the token! **/
X
X	hold_index = *iindex;
X
X	while (buf[*iindex] != ',' && buf[*iindex] != '\0')
X	  buffer[loc++] = buf[(*iindex)++];
X
X	(*iindex)++;
X	buffer[loc] = '\0';
X
X	while (whitespace(buffer[loc])) 	/* remove trailing whitespace */
X	  buffer[--loc] = '\0';
X
X	if (strlen(buffer) == 0) return(FALSE);
X
X	dprint(5, (debugfile, "\n* got \"%s\"\n", buffer));
X
X	if (buffer[loc-1] == ')') {	/*   address (name)  format */
X	  for (loc = 0, len = strlen(buffer);buffer[loc] != '(' && loc < len; loc++)
X		/* get to the opening comment character... */ ;
X
X	  loc--;	/* back up to just before the paren */
X	  while (whitespace(buffer[loc])) loc--;	/* back up */
X
X	  /** get the address field... **/
X
X	  for (i=0; i <= loc; i++)
X	    address[i] = buffer[i];
X	  address[i] = '\0';
X
X	  /** now get the comment field, en toto! **/
X
X	  loc = 0;
X
X	  for (i = chloc(buffer, '('), len = strlen(buffer); i < len; i++)
X	    comment[loc++] = buffer[i];
X	  comment[loc] = '\0';
X	}
X	else if (buffer[loc-1] == '>') {	/*   name <address>  format */
X	  dprint(7, (debugfile, "\tcomment <address>\n"));
X	  for (loc = 0, len = strlen(buffer);buffer[loc] != '<' && loc < len; loc++)
X		/* get to the opening comment character... */ ;
X	  while (whitespace(buffer[loc])) loc--;	/* back up */
X
X	  /** get the comment field... **/
X
X	  comment[0] = '(';
X	  for (i=1; i < loc; i++)
X	    comment[i] = buffer[i-1];
X	  comment[i++] = ')';
X	  comment[i] = '\0';
X
X	  /** now get the address field, en toto! **/
X
X	  loc = 0;
X
X	  for (i = chloc(buffer,'<') + 1, len = strlen(buffer); i < len - 1; i++)
X	    address[loc++] = buffer[i];
X	
X	  address[loc] = '\0';
X	}
X	else {
X	  /** the next section is added so that all To: lines have commas
X	      in them accordingly **/
X
X	  for (i=0; buffer[i] != '\0'; i++)
X	    if (whitespace(buffer[i])) break;
X	  if (i < strlen(buffer)) {	/* shouldn't be whitespace */
X	    buffer[i] = '\0';
X	    *iindex = hold_index + strlen(buffer) + 1;
X	  }
X	  strcpy(address, buffer);
X	  comment[0] = '\0';
X	}
X
X	dprint(5, (debugfile, "-- returning '%s' '%s'\n", address, comment));
X
X	return(TRUE);
X}
SHAR_EOF
# ============= src/returnadd.c ==============
echo "x - extracting src/returnadd.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/returnadd.c &&
X
Xstatic char rcsid[] = "@(#)$Id: returnadd.c,v 4.1.1.3 90/12/11 15:35:56 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 4.1.1.3 $   $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:	returnadd.c,v $
X * Revision 4.1.1.3  90/12/11  15:35:56  syd
X * Add back missing  strlen line, fixes segv problem
X * From: Syd
X * 
X * Revision 4.1.1.2  90/12/05  22:33:58  syd
X * Fix missing close brace due to indention error
X * From: Syd
X * 
X * Revision 4.1.1.1  90/12/05  21:59:41  syd
X * Fix where header could be going past end on return due to line
X * combination on header continuation.
X * From: Syd via report from Tom Davis
X * 
X * Revision 4.1  90/04/28  22:43:54  syd
X * checkin of Elm 2.3 as of Release PL0
X * 
X * 
X ******************************************************************************/
X
X/** This set of routines is used to generate real return addresses
X    and also return addresses suitable for inclusion in a users
X    alias files (ie optimized based on the pathalias database).
X
X**/
X
X#include "headers.h"
X
X#include <errno.h>
X
X#include <sys/types.h>
X#include <sys/stat.h>
X
Xchar *shift_lower();
X
Xextern int errno;
X
Xchar *error_name(), *strcat(), *strcpy();
X
X#ifdef OPTIMIZE_RETURN
X
Xoptimize_return(address)
Xchar *address;
X{
X	/** This routine tries to create an optimized address, that is,
X	    an address that has the minimal information needed to 
X	    route a message to this person given the current path
X	    database...
X	**/
X
X#ifndef INTERNET
X	char    bogus_internet[SLEN];
X
X	sprintf(bogus_internet, "@%s", hostfullname);
X
X	/** first off, let's see if we need to strip off the localhost
X	    address crap... **/
X
X	/** if we have a uucp part (e.g.a!b) AND the bogus address...**/
X
X	if (chloc(address,'!') != -1 && in_string(address, bogus_internet))
X	  address[strlen(address)-strlen(bogus_internet)] = '\0';
X#endif
X
X	/** next step is to figure out what sort of address we have... **/
X
X	if (chloc(address, '%') != -1)
X	  optimize_cmplx_arpa(address);
X	else if (chloc(address, '@') != -1)
X	  optimize_arpa(address);
X	else
X	  optimize_usenet(address);
X}
X
Xoptimize_cmplx_arpa(address)
Xchar *address;
X{
X	/** Try to optimize a complex ARPA address.  A Complex address is one 
X	    that contains '%' (deferred '@').  For example:  
X		veeger!hpcnof!hplabs!joe%sytech@syte  
X	    is a complex address (no kidding, right?).  The algorithm for 
X	    trying to resolve it is to move all the way to the right, then 
X	    back up left until the first '!' then from there to the SECOND 
X	    metacharacter on the right is the name@host address...(in this 
X            example, it would be "joe%sytech").  Check this in the routing
X	    table.  If not present, keep backing out to the right until we
X	    find a host that is present, or we hit the '@' sign.  Once we
X	    have a 'normal' ARPA address, hand it to optimize_arpa().
X	**/
X
X	char name[NLEN], buffer[SLEN], junk[SLEN];
X	char host[NLEN], old_host[NLEN];
X	register int i, loc, nloc = 0, hloc = 0, passes = 1;
X
X	/** first off, get the name%host... **/
X
X	for (loc = strlen(address)-1; address[loc] != '!' && loc > -1; loc--)
X	   ;
X
X	while (address[loc] != '\0') {
X
X	  if (passes == 1) {
X	    loc++;
X
X	    while (address[loc] != '%' && address[loc] != '@')
X	      name[nloc++] = address[loc++];
X	  }
X	  else {
X	    for (i=0; old_host[i] != '\0'; i++)
X	      name[nloc++] = old_host[i];
X	  }
X
X	  loc++;
X  
X	  while (address[loc] != '%' && address[loc] != '@')
X	    host[hloc++] = address[loc++];
X  
X	  host[hloc] = name[nloc] = '\0';
X
X	  strcpy(old_host, host);
X
X	  sprintf(buffer, "%s@%s", name, shift_lower(host));
X
X	  if (expand_site(buffer, junk) == 0) {
X	    strcpy(address, buffer);
X	    return;
X	  }
X	  else if (address[loc] == '@') {
X	    optimize_arpa(address);
X	    return;
X	  }
X	  else
X	    name[nloc++] = '%';	/* for next pass through */
X
X	}
X}
X
Xoptimize_arpa(address)
Xchar *address;
X{
X	/** Get an arpa address and simplify it to the minimal
X	    route needed to get mail to this person... **/
X
X	char name[NLEN], buffer[SLEN], junk[SLEN];
X	char host[NLEN];
X	register int loc, nloc = 0, hloc = 0, at_sign = 0;
X
X	for (loc = strlen(address)-1; address[loc] != '!' && loc > -1; loc--) {
X	  if (address[loc] == '@')
X	     at_sign++;	/* remember this spot! */
X	  else if (at_sign)
X	    name[nloc++] = address[loc];
X	  else
X	    host[hloc++] = address[loc];
X	}
X
X	name[nloc] = host[hloc] = '\0';
X
X	reverse(name);
X	reverse(host);
X
X	sprintf(buffer,"%s@%s", name, shift_lower(host));
X
X	if (expand_site(buffer, junk) == 0) {
X	  strcpy(address, buffer);
X	  return;
X	}
X
X	optimize_usenet(address);	/* that didn't work... */
X}
X	
Xoptimize_usenet(address)
Xchar *address;
X{
X	/** optimize the return address IFF it's a standard usenet
X	    address...
X	**/
X
X	char name[NLEN],  new_address[SLEN], buffer[SLEN], junk[SLEN];
X	register int loc, nloc = 0, aloc = 0, passes = 1;
X
X	for (loc = strlen(address)-1; address[loc] != '!' && loc > -1; loc--) 
X	  name[nloc++] = address[loc];
X	name[nloc] = '\0';
X
X	reverse(name);
X
X	new_address[0] = '\0';	
X
X	/* got name, now get machine until we can get outta here */
X
X	while (loc > -1) {
X
X	  new_address[aloc++] = address[loc--];	/* the '!' char */
X
X	  while (address[loc] != '!' && loc > -1)
X	    new_address[aloc++] = address[loc--];
X
X	  new_address[aloc] = '\0';
X
X	  strcpy(buffer, new_address);
X	  reverse(buffer);
X	
X	  if (expand_site(buffer, junk) == 0) {
X	    if (passes == 1 && chloc(name, '@') == -1) {
X	      buffer[strlen(buffer) - 1] = '\0';	/* remove '!' */
X	      sprintf(address, "%s@%s", name, buffer);
X	    }
X	    else 
X	      sprintf(address, "%s%s", buffer, name);
X	    return;		/* success! */
X	  }
X	  passes++;
X	}
X
X	return;		/* nothing to do! */
X}
X
X#endif	/* OPTIMIZE_RETURN */
X
Xint
Xget_return(buffer, msgnum)
Xchar *buffer;
Xint msgnum;
X{
X	/** reads msgnum message again, building up the full return 
X	    address including all machines that might have forwarded 
X	    the message.  Returns whether it is using the To line **/
X
X	char buf[SLEN], name1[SLEN], name2[SLEN], lastname[SLEN];
X	char hold_return[SLEN], alt_name2[SLEN], buf2[SLEN];
X	int ok = 1, lines, len_buf, len_buf2;
X	int using_to = FALSE;
X
X	/* now initialize all the char buffers [thanks Keith!] */
X
X	buf[0] = name1[0] = name2[0] = lastname[0] = '\0';
X	hold_return[0] = alt_name2[0] = buf2[0] = '\0';
X
X	/** get to the first line of the message desired **/
X
X	if(msgnum < 0 || msgnum >= message_count || message_count < 1) {
X	  dprint(1, (debugfile,
X		"Error: %d not a valid message number message_count = %d (%s)",
X		msgnum, message_count, "get_return"));
X	  error1("%d not a valid message number!");
X	  return(using_to);
X	}
X
X	if (fseek(mailfile, headers[msgnum]->offset, 0) == -1) {
X	  dprint(1, (debugfile,
X		"Error: seek %ld bytes into file hit errno %s (%s)", 
X		headers[msgnum]->offset, error_name(errno), 
X	        "get_return"));
X	  error2("Couldn't seek %d bytes into file (%s).",
X	       headers[msgnum]->offset, error_name(errno));
X	  return(using_to);
X	}
X 
X	/** okay!  Now we're there!  **/
X
X	lines = headers[msgnum]->lines;
X
X	buffer[0] = '\0';
X
X	ok = (int) (fgets(buf2, SLEN, mailfile) != NULL);
X	if (ok) {
X	  len_buf2 = strlen(buf2);
X	  if(buf2[len_buf2-1] == '\n') lines--; /* got a full line */
X	}
X
X	while (ok && lines) {
X	  buf[0] = '\0';
X	  strncat(buf, buf2, SLEN);
X	  len_buf = strlen(buf);
X	  ok = (int) (fgets(buf2, SLEN, mailfile) != NULL);
X	  if (ok) {
X	    len_buf2 = strlen(buf2);
X	    if(buf2[len_buf2-1] == '\n') lines--; /* got a full line */
X	  }
X	  while (ok && lines && whitespace(buf2[0]) && len_buf >= 2) {
X	    if (buf[len_buf-1] == '\n') {
X	      len_buf--;
X	      buf[len_buf] = '\0';
X	    }
X	    strncat(buf, buf2, (SLEN-len_buf-1));
X	    len_buf = strlen(buf);
X	    ok = (int) (fgets(buf2, SLEN, mailfile) != NULL);
X	    if (ok) {
X	      len_buf2 = strlen(buf2);
X	      if(buf2[len_buf2-1] == '\n') lines--; /* got a full line */
X	    }
X	  }
X
X/* At this point, "buf" contains the unfolded header line, while "buf2" contains
X   the next single line of text from the mail file */
X
X	  if (first_word(buf, "From ")) 
X	    sscanf(buf, "%*s %s", hold_return);
X	  else if (first_word(buf, ">From")) {
X	    sscanf(buf,"%*s %s %*s %*s %*s %*s %*s %*s %*s %s %s", 
X	           name1, name2, alt_name2);
X	    if (strcmp(name2, "from") == 0)		/* remote from xyz  */
X	      strcpy(name2, alt_name2);
X	    else if (strcmp(name2, "by") == 0)	/* forwarded by xyz */
X	      strcpy(name2, alt_name2);
X	    add_site(buffer, name2, lastname);
X	  }
X
X#ifdef USE_EMBEDDED_ADDRESSES
X
X	  else if (first_word(buf, "From:")) {
X	    get_address_from("From:", buf, hold_return);
X	    buffer[0] = '\0';
X          }
X          else if (first_word(buf, "Reply-To:")) {
X	    get_address_from("Reply-To:", buf, buffer);
X	    return(using_to);
X          }
X
X#endif
X
X	  else if (len_buf < 2)	/* done with header */
X            lines = 0; /* let's get outta here!  We're done!!! */
X	}
X
X	if (buffer[0] == '\0')
X	  strcpy(buffer, hold_return); /* default address! */
X	else
X	  add_site(buffer, name1, lastname);	/* get the user name too! */
X
X	if (first_word(buffer, "To:")) {	/* for backward compatibility */
X	  get_existing_address(buffer,msgnum);
X	  using_to = TRUE;
X	}
X	else {
X	  /*
X	   * KLUDGE ALERT - DANGER WILL ROBINSON
X	   * We can't just leave a bare login name as the return address,
X	   * or it will be alias-expanded.
X	   * So we qualify it with the current host name (and, maybe, domain).
X	   * Sigh.
X	   */
X
X	  if (chloc(buffer, '@') < 0
X	   && chloc(buffer, '%') < 0
X	   && chloc(buffer, '!') < 0)
X	  {
X#ifdef INTERNET
X	    sprintf(buffer + strlen(buffer), "@%s", hostfullname);
X#else
X	    strcpy(buf, buffer);
X	    sprintf(buffer, "%s!%s", hostname, buf);
X#endif
X	  }
X
X	  /*
X	   * If we have a space character,
X	   * or we DON'T have '!' or '@' chars,
X	   * append the user-readable name.
X	   */
X	  if (chloc(headers[msgnum]->from, ' ') >= 0 ||
X	      (chloc(headers[msgnum]->from, '!') < 0 &&
X	       chloc(headers[msgnum]->from, '@') < 0)) {
X	       sprintf(buffer + strlen(buffer),
X		       " (%s)", headers[msgnum]->from);
X          }
X	}
X
X	return(using_to);
X}
X
Xget_existing_address(buffer, msgnum)
Xchar *buffer;
Xint msgnum;
X{
X	/** This routine is called when the message being responded to has
X	    "To:xyz" as the return address, signifying that this message is
X	    an automatically saved copy of a message previously sent.  The
X	    correct to address can be obtained fairly simply by reading the
X	    To: header from the message itself and (blindly) copying it to
X	    the given buffer.  Note that this header can be either a normal
X	    "To:" line (Elm) or "Originally-To:" (previous versions e.g.Msg)
X	**/
X
X	char mybuf[LONG_STRING];
X	register char ok = 1, in_to = 0;
X
X	buffer[0] = '\0';
X
X	/** first off, let's get to the beginning of the message... **/
X
X	if(msgnum < 0 || msgnum >= message_count || message_count < 1) {
X	  dprint(1, (debugfile,
X		"Error: %d not a valid message number message_count = %d (%s)",
X		msgnum, message_count, "get_existing_address"));
X	  error1("%d not a valid message number!");
X	  return;
X	}
X        if (fseek(mailfile, headers[msgnum]->offset, 0) == -1) {
X	    dprint(1, (debugfile, 
X		    "Error: seek %ld bytes into file hit errno %s (%s)", 
X		    headers[msgnum]->offset, error_name(errno), 
X		    "get_existing_address"));
X	    error2("Couldn't seek %d bytes into the file (%s).",
X	           headers[msgnum]->offset, error_name(errno));
X	    return;
X        }
X 
X        /** okay!  Now we're there!  **/
X
X        while (ok) {
X          ok = (int) (fgets(mybuf, LONG_STRING, mailfile) != NULL);
X	  no_ret(mybuf);	/* remove return character */
X
X          if (first_word(mybuf, "To: ")) {
X	    in_to = TRUE;
X	    strcpy(buffer, (char *) mybuf + strlen("To: "));
X          }
X	  else if (first_word(mybuf, "Original-To:")) {
X	    in_to = TRUE;
X	    strcpy(buffer, (char *) mybuf + strlen("Original-To:"));
X	  }
X	  else if (in_to && whitespace(mybuf[0])) {
X	    strcat(buffer, " ");		/* tag a space in   */
X	    strcat(buffer, (char *) mybuf + 1);	/* skip 1 whitespace */
X	  }
X	  else if (strlen(mybuf) < 2)
X	    return;				/* we're done for!  */
X	  else
X	    in_to = 0;
X      }
X}
SHAR_EOF
# ============= src/save_opts.c ==============
echo "x - extracting src/save_opts.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/save_opts.c &&
X
Xstatic char rcsid[] = "@(#)$Id: save_opts.c,v 4.1 90/04/28 22:44:00 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:	save_opts.c,v $
X * Revision 4.1  90/04/28  22:44:00  syd
X * checkin of Elm 2.3 as of Release PL0
X * 
X *
X ******************************************************************************/
X
X/** This file contains the routine needed to allow the users to change the
X    Elm parameters and then save the configuration in a ".elm/elmrc" file in
X    their home directory.  With any luck this will allow them never to have
X    to actually EDIT the file!!
X
X**/
X
X#include "headers.h"
X#include <errno.h>
X
X#undef onoff
X#define   onoff(n)	(n == 1? "ON":"OFF")
X
X#define absolute(x)		((x) < 0? -(x) : (x))
X
Xextern  int errno;
Xextern char version_buff[];
X
Xchar *error_name(), *sort_name();
Xlong  ftell();
X
X#include "save_opts.h"
X
XFILE *elminfo;		/* informational file as needed... */
X
Xsave_options()
X{
X	/** Save the options currently specified to a file.  This is a
X	    fairly complex routine since it tries to put in meaningful
X	    comments and such as it goes along.  The comments are
X	    extracted from the file ELMRC_INFO as defined in the sysdefs.h
X	    file.  THAT file has the format;
X
X		varname
X		  <comment>
X		  <comment>
X		<blank line>
X
X	    and each comment is written ABOVE the variable to be added.  This
X	    program also tries to make 'pretty' stuff like the alternatives
X	    and such.
X	**/
X
X	FILE *newelmrc; 
X	char  oldfname[SLEN], newfname[SLEN];
X
X	sprintf(newfname, "%s/%s", home, elmrcfile);
X	sprintf(oldfname, "%s/%s", home, old_elmrcfile);
X
X	/** first off, let's see if they already HAVE a .elm/elmrc file **/
X
X	save_file_stats(newfname);
X	if (access(newfname, ACCESS_EXISTS) != -1) {
X	  /** YES!  Copy it to the file ".old.elmrc".. **/
X	  if (rename(newfname, oldfname) < 0)
X	    dprint(2, (debugfile, "Unable to rename %s to %s\n", 
X		   newfname, oldfname));
X	  (void) chown(oldfname, userid, groupid);
X
X	}
X
X	/** now let's open the datafile if we can... **/
X
X	if ((elminfo = fopen(ELMRC_INFO, "r")) == NULL) 
X	  error1("Warning: saving without comments! Can't get to %s.", 
X		  ELMRC_INFO);
X
X	/** next, open the new .elm/elmrc file... **/
X
X	if ((newelmrc = fopen(newfname, "w")) == NULL) {
X	   error2("Can't save configuration! Can't write to %s [%s].",
X		   newfname, error_name(errno));
X	   return;
X	}
X	
X	save_user_options(elminfo, newelmrc);
X	restore_file_stats(newfname);
SHAR_EOF
echo "End of  part 16"
echo "File src/save_opts.c is continued in part 17"
echo "17" > shar3_seq_.tmp
exit 0