[comp.sources.unix] v18i097: Elm mail system, release 2.2, Part18/24

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

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

#!/bin/sh
# this is part 18 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file src/opt_utils.c continued
#
CurArch=18
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/opt_utils.c"
sed 's/^X//' << 'SHAR_EOF' >> src/opt_utils.c
Xint size;
X{
X	/** Return the name of the current host machine. **/
X
X#ifdef XENIX
X	char    buf[32];
X	FILE    *fp;
X	char    *p;
X	char	*strchr();
X
X	if ((fp = fopen("/etc/systemid", "r")) != 0) {
X	  fgets(buf, sizeof(buf) - 1, fp);
X	  fclose(fp);
X	  if ((p = strchr(buf, '\n')) != NULL)
X	    *p = '\0';
X	  (void) strncpy(hostname, buf, size - 1);
X	  hostname[size - 1] = '\0';
X	  return 0;
X	}
X
X#else   /* XENIX */
X
X#ifdef DOUNAME
X	/** This routine compliments of Scott McGregor at the HP
X	    Corporate Computing Center **/
X     
X	int uname();
X	struct utsname name;
X
X	(void) uname(&name);
X	(void) strncpy(hostname,name.nodename,size-1);
X#else
X	(void) strncpy(hostname, HOSTNAME, size-1);
X#endif	/* DOUNAME */
X
X	hostname[size - 1] = '\0';
X	return 0;
X
X#endif  /* XENIX */
X}
X
X#endif  /* GETHOSTNAME */
X
X
Xgethostdomain(hostdom, size)    /* get domain of current host */
Xchar *hostdom;
Xint size;
X{
X	char    buf[32];
X	FILE    *fp;
X	char    *p;
X	char	*strchr();
X
X	if ((fp = fopen(hostdomfile, "r")) != 0) {
X	  fgets(buf, sizeof(buf) - 1, fp);
X	  fclose(fp);
X	  if ((p = strchr(buf, '\n')) != NULL)
X	    *p = '\0';
X	  if (buf[0] != '.') {
X	    *hostdom++ = '.';
X	    --size;
X	  }
X	  (void) strncpy(hostdom, buf, size - 1);
X	  hostdom[size - 1] = '\0';
X	}
X	else {
X	  (void) strncpy(hostdom, DEFAULT_DOMAIN, size - 1);
X	  hostdom[size - 1] = '\0';
X	}
X
X	return 0;
X}
X
X
X#ifdef NEED_CUSERID
X
Xchar *cuserid(uname)
X     char *uname;
X{
X	/** Added for compatibility with Bell systems, this is the last-ditch
X	    attempt to get the users login name, after getlogin() fails.  It
X	    instantiates "uname" to the name of the user...(it also tries
X	    to use "getlogin" again, just for luck)
X	**/
X	/** This wasn't really compatible.  According to our man page, 
X	 ** It was inconsistent.  If the parameter is NULL then you return
X	 ** the name in a static area.  Else the ptr is supposed to be a
X	 ** pointer to l_cuserid bytes of memory [probally 9 bytes]...
X	 ** It's not mention what it should return if you copy the name
X	 ** into the array, so I chose NULL.
X	 ** 					Sept 20, 1988
X	 **					**WJL**
X	 **/
X
X  struct passwd *password_entry, *getpwuid();
X  char   *name, *getlogin();
X  static char buf[10];
X  register returnonly = 0;
X  
X  if (uname == NULL) ++returnonly;
X  
X  if ((name = getlogin()) != NULL) {
X    if (returnonly) {
X      return(name);
X    } else {
X      strcpy(uname, name);
X      return name;
X    }
X  } 
X  else 
X    if (( password_entry = getpwuid(getuid())) != NULL) 
X      {
X	if (returnonly) 
X	  {
X	    return(password_entry->pw_name);
X	  }
X	else 
X	  {
X	    strcpy(uname, password_entry->pw_name);
X	    return name;
X	  }
X      } 
X    else 
X      {
X	return NULL;
X      }
X}
X
X#endif
X
X#ifdef BSD
X
X/** some supplementary string functions for Berkeley Unix systems **/
X
Xint
Xtolower(ch)
Xchar ch;
X{
X	/** This should be a macro call, but if you use this as a macro
X	    calls to 'tolower' where the argument is a function call will
X	    cause the function to be called TWICE which is obviously the
X	    wrong behaviour.  On the other hand, to just blindly translate
X	    assuming the character is always uppercase can cause BIG
X	    problems, so...
X	**/
X
X	return ( isupper(ch) ? ch - 'A' + 'a' : ch );
X}
X
Xint
Xtoupper(ch)
Xchar ch;
X{
X	/** see comment for above routine - tolower() **/
X
X	return ( islower(ch) ? ch - 'a' + 'A' : ch );
X}
X
Xstrspn(source, keys)
Xchar *source, *keys;
X{
X	/** This function returns the length of the substring of
X	    'source' (starting at zero) that consists ENTIRELY of
X	    characters from 'keys'.  This is used to skip over a
X	    defined set of characters with parsing, usually. 
X	**/
X
X	register int loc = 0, key_index = 0;
X
X	while (source[loc] != '\0') {
X	  key_index = 0;
X	  while (keys[key_index] != source[loc])
X	    if (keys[key_index++] == '\0')
X	      return(loc);
X	  loc++;
X	}
X
X	return(loc);
X}
X
Xstrcspn(source, keys)
Xchar *source, *keys;
X{
X	/** This function returns the length of the substring of
X	    'source' (starting at zero) that consists entirely of
X	    characters NOT from 'keys'.  This is used to skip to a
X	    defined set of characters with parsing, usually. 
X	    NOTE that this is the opposite of strspn() above
X	**/
X
X	register int loc = 0, key_index = 0;
X
X	while (source[loc] != '\0') {
X	  key_index = 0;
X	  while (keys[key_index] != '\0')
X	    if (keys[key_index++] == source[loc])
X	      return(loc);
X	  loc++;
X	}
X
X	return(loc);
X}
X
Xchar *strtok(source, keys)
Xchar *source, *keys;
X{
X	/** This function returns a pointer to the next word in source
X	    with the string considered broken up at the characters 
X	    contained in 'keys'.  Source should be a character pointer
X	    when this routine is first called, then NULL subsequently.
X	    When strtok has exhausted the source string, it will 
X	    return NULL as the next word. 
X
X	    WARNING: This routine will DESTROY the string pointed to
X	    by 'source' when first invoked.  If you want to keep the
X	    string, make a copy before using this routine!!
X	 **/
X
X	register int  last_ch;
X	static   char *sourceptr;
X		 char *return_value;
X
X	if (source != NULL)
X	  sourceptr = source;
X	
X	if (*sourceptr == '\0') 
X	  return(NULL);		/* we hit end-of-string last time!? */
X
X	sourceptr += strspn(sourceptr, keys);	/* skip leading crap */
X	
X	if (*sourceptr == '\0') 
X	  return(NULL);		/* we've hit end-of-string */
X
X	last_ch = strcspn(sourceptr, keys);	/* end of good stuff */
X
X	return_value = sourceptr;		/* and get the ret   */
X
X	sourceptr += last_ch;			/* ...value 	     */
X
X	if (*sourceptr != '\0')		/* don't forget if we're at END! */
X	  sourceptr++;			   /* and skipping for next time */
X
X	return_value[last_ch] = '\0';		/* ..ending right    */
X	
X	return((char *) return_value);		/* and we're outta here! */
X}
X
Xchar *strpbrk(source, keys)
Xchar *source, *keys;
X{
X	/** Returns a pointer to the first character of source that is any
X	    of the specified keys, or NULL if none of the keys are present
X	    in the source string. 
X	**/
X
X	register int loc = 0, key_index = 0;
X
X	while (source[loc] != '\0') {
X	  key_index = 0;
X	  while (keys[key_index] != '\0')
X	    if (keys[key_index++] == source[loc])
X	      return((char *) (source + loc));
X	  loc++;
X	}
X	
X	return(NULL);
X}
X
Xchar *strchr(buffer, ch)
Xchar *buffer, ch;
X{
X	/** Returns a pointer to the first occurance of the character
X	    'ch' in the specified string or NULL if it doesn't occur **/
X
X	char *address;
X
X	address = buffer;
X
X	while (*address != ch) {
X	  if (*address == '\0')
X	    return (NULL);
X	  address++;
X	}
X
X	return ( (char *) address);
X}
X
Xchar *strrchr(buffer, ch)
Xchar *buffer, ch;
X{
X	/** Returns a pointer to the last occurance of the character
X	    'ch' in the specified string or NULL if it doesn't occur **/
X
X	char *address;
X
X	address = buffer + strlen(buffer) - 1;
X
X	while (*address != ch) {
X	  if (address == buffer)
X	    return (NULL);
X	  address--;
X	}
X
X	return ( (char *) address);
X}
X
X#endif
X
X#ifndef TEMPNAM
X/* and a tempnam for temporary files */
Xstatic int cnt = 0;
X
Xchar *tempnam( dir, pfx)
X char *dir, *pfx;
X{
X	char space[SLEN];
X	char *newspace;
X
X	char	*malloc();
X
X	if (dir == NULL) {
X		dir = "/usr/tmp";
X	} else if (*dir == '\0') {
X		dir = "/usr/tmp";
X	}
X	
X	if (pfx == NULL) {
X		pfx = "";
X	}
X
X	sprintf(space, "%s%s%d.%d", dir, pfx, getpid(), cnt);
X	cnt++;
X	
X	newspace = malloc(strlen(space) + 1);
X	if (newspace != NULL) {
X		strcpy(newspace, space);
X	}
X	return newspace;
X}
X
X#endif
X
X#ifndef GETOPT
X
X/*LINTLIBRARY*/
X#define NULL	0
X#define EOF	(-1)
X#define ERR(s, c)	if(opterr){\
X	extern int strlen(), write();\
X	char errbuf[2];\
X	errbuf[0] = c; errbuf[1] = '\n';\
X	(void) write(2, argv[0], (unsigned)strlen(argv[0]));\
X	(void) write(2, s, (unsigned)strlen(s));\
X	(void) write(2, errbuf, 2);}
X
Xextern int strcmp();
Xextern char *index();
X
Xint	opterr = 1;
Xint	optind = 1;
Xint	optopt;
Xchar	*optarg;
X
Xint
Xgetopt(argc, argv, opts)
Xint	argc;
Xchar	**argv, *opts;
X{
X	static int sp = 1;
X	register int c;
X	register char *cp;
X
X	if(sp == 1)
X		if(optind >= argc ||
X		   argv[optind][0] != '-' || argv[optind][1] == '\0')
X			return(EOF);
X		else if(strcmp(argv[optind], "--") == NULL) {
X			optind++;
X			return(EOF);
X		}
X	optopt = c = argv[optind][sp];
X	if(c == ':' || (cp=index(opts, c)) == NULL) {
X		ERR(": illegal option -- ", c);
X		if(argv[optind][++sp] == '\0') {
X			optind++;
X			sp = 1;
X		}
X		return('?');
X	}
X	if(*++cp == ':') {
X		if(argv[optind][sp+1] != '\0')
X			optarg = &argv[optind++][sp+1];
X		else if(++optind >= argc) {
X			ERR(": option requires an argument -- ", c);
X			sp = 1;
X			return('?');
X		} else
X			optarg = argv[optind++];
X		sp = 1;
X	} else {
X		if(argv[optind][++sp] == '\0') {
X			sp = 1;
X			optind++;
X		}
X		optarg = NULL;
X	}
X	return(c);
X}
X
X#endif
X
X#ifndef RENAME
Xint rename(tmpfname, fname)
Xchar *tmpfname, *fname;
X{
X	int status;
X
X	(void) unlink(fname);
X	if ((status = link(tmpfname, fname)) != 0)
X		return(status);
X	(void) unlink(tmpfname);
X	return(0);
X}
X#endif
SHAR_EOF
echo "File src/opt_utils.c is complete"
chmod 0444 src/opt_utils.c || echo "restore of src/opt_utils.c fails"
echo "x - extracting src/options.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/options.c &&
X
Xstatic char rcsid[] = "@(#)$Id: options.c,v 2.9 89/03/25 21:46:54 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.9 $   $State: Exp $
X *
X * 			Copyright (c) 1986, 1987 Dave Taylor
X * 			Copyright (c) 1988, 1989 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X *	Syd Weinstein, Elm Coordinator
X *	elm@dsinc.UUCP			dsinc!elm
X *
X *******************************************************************************
X * $Log:	options.c,v $
X * Revision 2.9  89/03/25  21:46:54  syd
X * Initial 2.2 Release checkin
X * 
X *
X ******************************************************************************/
X
X/** This set of routines allows the alteration of a number of paramaters
X    in the Elm mailer, including the following;
X
X	calendar-file	<where to put calendar entries>
X	display pager	<how to page messages>
X	editor		<name of composition editor>
X	folder-dir	<folder directory>
X	sort-by		<how to sort folders>
X	sent-mail	<file to save outbound message copies to>
X	printmail	<how to print messages>
X	full_username	<your full user name for outgoing mail>
X
X	arrow-cursor	<on or off>
X	menu-display    <on or off>
X
X	user-level	<BEGINNER|INTERMEDIATE|EXPERT>
X        names-only      <on or off>
X	
X    And others as they seem useful.
X
X**/
X
X#include "headers.h"
X
X#ifdef BSD
X#undef tolower
X#endif
X
X#undef onoff
X#define   onoff(n)	(n == 1? "ON ":"OFF")
X
Xchar *one_liner_for(), *level_name();
Xunsigned long sleep();
X
Xoptions()
X{
X	/** change options... **/
X	/* return:
X	 *	> 0	if restort was done - to indicate we might need to
X	 *	 	change the page of our headers as a consequence
X	 *		of the new sort order
X	 *	< 0	if user entered 'x' to quit elm immediately
X	 *	0	otherwise
X	 */
X
X	int	ch,
X	     	resort = 0;
X	char	*strcpy(),
X	     	temp[SLEN];	/* needed when an option is run through
X				 * expand_env(), because that function
X				 * is destructive of the original
X				 */
X
X	display_options();
X
X	clearerr(stdin);
X
X	while(1) {
X	  ClearLine(LINES-4);
X
X	  Centerline(LINES-4,
X "Select first letter of option line, '>' to save, or 'i' to return to index.");
X
X	  PutLine0(LINES-2, 0, "Command: ");
X
X	  ch = ReadCh();
X	  ch = tolower(ch);
X
X	  clear_error();	/* remove possible "sorting" message etc... */ 
X
X	  one_liner(one_liner_for(ch));
X
X	  switch (ch) {
X	    case 'c' : optionally_enter(raw_calendar_file, 2, 23, FALSE, FALSE);
X		       strcpy(temp, raw_calendar_file);
X		       expand_env(calendar_file, temp);
X		       break;
X	    case 'd' : optionally_enter(raw_pager, 3, 23, FALSE, FALSE); 
X		       strcpy(temp, raw_pager);
X		       expand_env(pager, temp);
X		       clear_pages = (equal(pager, "builtin+") || 
X			             equal(pager, "internal+")); 
X		       break;
X	    case 'e' : optionally_enter(raw_editor, 4, 23, FALSE, FALSE);
X		       strcpy(temp, raw_editor);
X		       expand_env(editor, temp);
X	               break;
X	    case 'f' : optionally_enter(raw_folders, 5, 23, FALSE, FALSE);
X		       strcpy(temp, raw_folders);
X		       expand_env(folders, temp);
X		       break;
X	    case 's' : if(change_sort(6,23)) resort++;			break;
X	    case 'o' : optionally_enter(raw_sentmail, 7, 23, FALSE, FALSE);
X		       strcpy(temp, raw_sentmail);
X		       expand_env(sent_mail, temp);
X		       break;
X	    case 'p' : optionally_enter(raw_printout, 8, 23, FALSE, FALSE);
X		       strcpy(temp, raw_printout);
X		       expand_env(printout, temp);
X		       break;
X	    case 'y' : optionally_enter(full_username, 9, 23, FALSE, FALSE);
X		       break;
X	    case 'a' : on_or_off(&arrow_cursor, 12, 23); 		break;
X	    case 'm' : on_or_off(&mini_menu, 13, 23);			
X		       headers_per_page = LINES - (mini_menu ? 13 : 8); break;
X
X	    case 'u' : switch_user_level(&user_level,15, 23);		break;
X	    case 'n' : on_or_off(&names_only, 16, 23);			break;
X	
X	    case '?' : options_help(); 
X	               PutLine0(LINES-2,0,"Command: ");			break;
X	   
X	    case '>' : printf("Save options in .elm/elmrc...");
X		       fflush(stdout);    save_options();		break;
X
X	    case 'x' :	return(-1);	/* exit elm */
X	    case 'q' :	/* pop back up to previous level, in this case == 'i' */
X	    case 'i' :  /* return to index screen */
X			return(resort ? 1 : 0);
X	    case ctrl('L'): display_options();				break;
X	    default: error("Command unknown!");
X	  }
X
X	}
X}
X	
Xdisplay_options()
X{
X	/** Display all the available options.. **/
X	
X	char *sort_name();
X	
X	ClearScreen();
X	Centerline(0,"-- ELM Options Editor --");
X
X#ifdef ENABLE_CALENDAR
X	PutLine1(2, 0, "C)alendar file       : %s", raw_calendar_file);
X#endif
X	PutLine1(3, 0, "D)isplay mail using  : %s", raw_pager);
X	PutLine1(4, 0, "E)ditor              : %s", raw_editor);
X	PutLine1(5, 0, "F)older directory    : %s", raw_folders);
X	PutLine1(6, 0, "S)orting criteria    : %s", sort_name(FULL));
X	PutLine1(7, 0, "O)utbound mail saved : %s", raw_sentmail);
X	PutLine1(8, 0, "P)rint mail using    : %s", raw_printout);
X	PutLine1(9, 0, "Y)our full name      : %s", full_username);
X
X	PutLine1(12,0, "A)rrow cursor        : %s", onoff(arrow_cursor));
X	PutLine1(13,0, "M)enu display        : %s", onoff(mini_menu));
X
X	PutLine1(15,0, "U)ser level          : %s", level_name(user_level));
X	PutLine1(16,0, "N)ames only          : %s", onoff(names_only));
X}
X
Xon_or_off(var, x, y)
Xint *var, x,y;
X{
X	/** 'var' field at x.y toggles between on and off... **/
X
X	char ch;
X
X     	PutLine0(x, y+6, 
X		"(use <space> to toggle, any other key to leave)");
X
X	MoveCursor(x,y+3);	/* at end of value... */
X
X	do {
X	  ch = ReadCh();
X
X	  if (ch == SPACE) {
X	    *var = ! *var;
X	    PutLine0(x,y, onoff(*var));
X	  }
X	} while (ch == SPACE);
X
X	MoveCursor(x,y+4); 	CleartoEOLN();	/* remove help prompt */
X}
X
X
Xswitch_user_level(ulevel, x, y)
Xint *ulevel, x, y;
X{
X	/** step through possible user levels... **/
X
X     	PutLine0(x, y+20, "<space> to change");
X
X	MoveCursor(x,y);	/* at end of value... */
X
X	while (ReadCh() == ' ') {
X	  *ulevel = (*ulevel >= 2? 0 : *ulevel + 1);
X	  PutLine1(x,y, "%s", level_name(*ulevel));
X	}
X
X	MoveCursor(x,y+20); 	CleartoEOLN();	/* remove help prompt */
X}
X	
Xchange_sort(x, y)
Xint x,y;
X{
X	/** change the sorting scheme... **/
X	/** return !0 if new sort order, else 0 **/
X	
X	int last_sortby,	/* so we know if it changes... */
X	    sign = 1;		/* are we reverse sorting??    */
X	int ch;			/* character typed in ...      */
X
X	last_sortby = sortby;	/* remember current ordering   */
X
X	PutLine0(x, COLUMNS-29, "(SPACE for next, or R)everse)");
X	sort_one_liner(sortby);
X	MoveCursor(x, y);
X
X	do {
X	  ch = ReadCh();
X	  ch = tolower(ch);
X	  switch (ch) {
X	    case SPACE : if (sortby < 0) { 
X	    		   sign = -1; 
X	    		   sortby = - sortby; 
X	  		 }
X			 else sign = 1;		/* insurance! */
X	  		 sortby = sign * ((sortby + 1) % (STATUS+2));
X			 if (sortby == 0) sortby = sign;  /* snicker */
X	  		 PutLine0(x, y, sort_name(PAD));
X			 sort_one_liner(sortby);
X	  		 MoveCursor(x, y);
X			 break;
X
X	    case 'r'   : sortby = - sortby;
X	  		 PutLine0(x, y, sort_name(PAD));
X			 sort_one_liner(sortby);
X	  		 MoveCursor(x, y);
X	 }
X        } while (ch == SPACE || ch == 'r');
X
X	MoveCursor(x, COLUMNS-30);	CleartoEOLN();
X
X	if (sortby != last_sortby) {
X	  error("Resorting folder...");
X	  sleep(1);
X	  sort_mailbox(message_count, 0);
X	}
X	ClearLine(LINES-2);		/* clear sort_one_liner()! */
X	return(sortby-last_sortby);
X}
X
Xone_liner(string)
Xchar *string;
X{
X	/** A single-line description of the selected item... **/
X
X	ClearLine(LINES-4);
X	Centerline(LINES-4, string);
X}
X
Xsort_one_liner(sorting_by)
Xint sorting_by;
X{
X	/** A one line summary of the particular sorting scheme... **/
X
X	ClearLine(LINES-2);
X
X	switch (sorting_by) {
X	  
X	  case -SENT_DATE : Centerline(LINES-2,
X"This sort will order most-recently-sent to least-recently-sent");	break;
X	  case -RECEIVED_DATE : Centerline(LINES-2,
X"This sort will order most-recently-received to least-recently-received");
X		 	    break;
X	  case -MAILBOX_ORDER : Centerline(LINES-2,
X"This sort will order most-recently-added-to-folder to least-recently");
X		 	    break;
X	  case -SENDER : Centerline(LINES-2,
X"This sort will order by sender name, in reverse alphabetical order");	break;
X	  case -SIZE   : Centerline(LINES-2,
X"This sort will order messages by longest to shortest");		break;
X	  case -SUBJECT : Centerline(LINES-2,
X"This sort will order by subject, in reverse alphabetical order");	break;
X	  case -STATUS  : Centerline(LINES-2,
X"This sort will order by reverse status - Deleted through Tagged...");	break;
X
X	  case SENT_DATE : Centerline(LINES-2,
X"This sort will order least-recently-sent to most-recently-sent");	break;
X	  case RECEIVED_DATE : Centerline(LINES-2,
X"This sort will order least-recently-received to most-recently-received");
X	                    break;
X	  case MAILBOX_ORDER : Centerline(LINES-2,
X"This sort will order least-recently-added-to-folder to most-recently");
X		 	    break;
X	  case SENDER : Centerline(LINES-2,
X		        "This sort will order by sender name");	break;
X	  case SIZE   : Centerline(LINES-2,
X		        "This sort will order messages by shortest to longest");
X			break;
X	  case SUBJECT : Centerline(LINES-2,
X            		"This sort will order messages by subject");	break;
X	  case STATUS  : Centerline(LINES-2,
X"This sort will order by status - Tagged through Deleted...");		break;
X	}
X}
X
Xchar *one_liner_for(c)
Xchar c;
X{
X	/** returns the one-line description of the command char... **/
X
X	switch (c) {
X	    case 'c' : return(
X"This is the file where calendar entries from messages are saved.");
X
X	    case 'd' : return(
X"This is the program invoked to display individual messages (try 'builtin')");
X
X	    case 'e' : return(
X"This is the editor that will be used for sending messages, etc.");
X
X	    case 'f' : return(
X"This is the folders directory used when '=' (etc) is used in filenames");
X
X	    case 'm' : return(
X"This determines if you have the mini-menu displayed or not");
X
X	    case 'n' : return(
X"Whether to display the names and addresses on mail, or names only");
X	    case 'o' : return(
X"This is where copies of outbound messages are saved automatically.");
X
X	    case 'p' : return(
X"This is how printouts are generated.  \"%s\" will be replaced by the filename.");
X
X	    case 's' : return(
X"This is used to specify the sorting criteria for the folders");
X
X	    case 'y' : return(
X"When mail is sent out, this is what your full name will be recorded as.");
X
X	    case 'a' : return(
X"This defines whether the ELM cursor is an arrow or a highlight bar.");
X
X	   case 'u' : return(
X"The level of knowledge you have about the ELM mail system.");
X
X	    default : return("");	/* nothing if we don't know! */
X	}
X}
X
Xoptions_help()
X{
X	/** help menu for the options screen... **/
X
X	char c, *ptr;
X
X	Centerline(LINES-3,
X     "Enter the key you want help on, '?' for a list, or '.' to exit help");
X
X	lower_prompt("Key : ");
X
X	while ((c = ReadCh()) != '.') {
X	  c = tolower(c);
X	  if (c == '?') {
X	     display_helpfile(OPTIONS_HELP);
X	     display_options();
X	     return;
X	  }
X	  if ((ptr = one_liner_for(c)) != NULL)
X	    error2("%c = %s.", c, ptr);
X	  else
X	    error1("%c isn't used in this section.", c);
X	  lower_prompt("Key : ");
X	}
X}
X
Xchar *level_name(n)
Xint n;
X{
X	/** return the 'name' of the level... **/
X
X	switch (n) {
X	  case 0 : return("Beginning User   ");
X	  case 1 : return("Intermediate User");
X	  default: return("Expert User      ");
X	}
X}
SHAR_EOF
chmod 0444 src/options.c || echo "restore of src/options.c fails"
echo "x - extracting src/out_utils.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/out_utils.c &&
X
Xstatic char rcsid[] = "@(#)$Id: out_utils.c,v 2.5 89/03/25 21:46:56 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.5 $   $State: Exp $
X *
X * 			Copyright (c) 1986, 1987 Dave Taylor
X * 			Copyright (c) 1988, 1989 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X *	Syd Weinstein, Elm Coordinator
X *	elm@dsinc.UUCP			dsinc!elm
X *
X *******************************************************************************
X * $Log:	out_utils.c,v $
X * Revision 2.5  89/03/25  21:46:56  syd
X * Initial 2.2 Release checkin
X * 
X *
X ******************************************************************************/
X
X/** This file contains routines used for output in the ELM program.
X
X**/
X
X#include "headers.h"
X
X
Xstatic char err_buffer[SLEN];		/* store last error message */
X
Xstatic char central_message_buffer[SLEN];
X
Xchar *strcpy();
X
Xshow_last_error()
X{
X	/** rewrite last error message! **/
X
X	error(err_buffer);
X}
X
Xclear_error()
X{
X	MoveCursor(LINES,0);
X	CleartoEOLN();
X	err_buffer[0] = '\0';
X}
X
Xset_error(s)
Xchar *s;
X{
X	strcpy(err_buffer, s);
X}
X
Xerror(s)
Xchar *s;
X{
X	/** outputs error 's' to screen at line 22, centered! **/
X
X	if(batch_only)
X	  printf("%s\n\r", s);
X	else {
X	  MoveCursor(LINES,0);
X	  CleartoEOLN();
X	  PutLine0(LINES,(COLUMNS-strlen(s))/2,s);
X	  fflush(stdout);
X	}
X	strcpy(err_buffer, s);	/* save it too! */
X}
X
X/*VARARGS1*/
X
Xerror1(s, a)
Xchar *s, *a;
X{
X	/** same as error, but with a 'printf' argument **/
X	char buffer[SLEN];
X
X	sprintf(buffer,s,a);
X	error(buffer);
X}
X
X/*VARARGS1*/
X
Xerror2(s, a1, a2)
Xchar *s, *a1, *a2;
X{
X	/** same as error, but with two 'printf' arguments **/
X	char buffer[SLEN];
X
X	sprintf(buffer,s, a1, a2);
X	error(buffer);
X}
X
X/*VARARGS1*/
X
Xerror3(s, a1, a2, a3)
Xchar *s, *a1, *a2, *a3;
X{
X	/** same as error, but with three 'printf' arguments **/
X	char buffer[SLEN];
X
X	sprintf(buffer,s, a1, a2, a3);
X	error(buffer);
X}
X
Xlower_prompt(s)
Xchar *s;
X{
X	/** prompt user for input on LINES-1 line, left justified **/
X
X	PutLine0(LINES-1,0,s);
X	CleartoEOLN();
X}
X
Xprompt(s)
Xchar *s;
X{
X	/** prompt user for input on LINES-3 line, left justified **/
X
X	PutLine0(LINES-3,0,s);
X	CleartoEOLN();
X}
X
X
Xset_central_message(string, arg)
Xchar *string, *arg;
X{
X	/** set up the given message to be displayed in the center of
X	    the current window **/ 
X
X	sprintf(central_message_buffer, string, arg);
X}
X
Xdisplay_central_message()
X{
X	/** display the message if set... **/
X
X	if (central_message_buffer[0] != '\0') {
X	  ClearLine(LINES-15);
X	  Centerline(LINES-15, central_message_buffer);
X	  fflush(stdout);
X	}
X}
X
Xclear_central_message()
X{
X	/** clear the central message buffer **/
X
X	central_message_buffer[0] = '\0';
X}
SHAR_EOF
chmod 0444 src/out_utils.c || echo "restore of src/out_utils.c fails"
echo "x - extracting src/pattern.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/pattern.c &&
X
Xstatic char rcsid[] = "@(#)$Id: pattern.c,v 2.10 89/03/25 21:46:57 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.10 $   $State: Exp $
X *
X * 			Copyright (c) 1986, 1987 Dave Taylor
X * 			Copyright (c) 1988, 1989 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X *	Syd Weinstein, Elm Coordinator
X *	elm@dsinc.UUCP			dsinc!elm
X *
X *******************************************************************************
X * $Log:	pattern.c,v $
X * Revision 2.10  89/03/25  21:46:57  syd
X * Initial 2.2 Release checkin
X * 
X *
X ******************************************************************************/
X
X/**    General pattern matching for the ELM mailer.     
X
X**/
X
X#include <errno.h>
X
X#include "headers.h"
X
Xstatic char pattern[SLEN] = { "" };
Xstatic char alt_pattern[SLEN] = { "" };
X
Xextern int errno;
X
Xchar *error_name(), *shift_lower(), *strcpy();
X
Xint
Xmeta_match(function)
Xint function;
X{
X	char	ch;
X
X	/** Perform specific function based on whether an entered string 
X	    matches either the From or Subject lines.. 
X	    Return TRUE if the current message was matched, else FALSE.
X	**/
X
X	register int i, tagged=0, count=0, curtag = 0;
X	static char     meta_pattern[SLEN];
X
X	PutLine1(LINES-3, strlen("Command: "), 
X	     "%s messages that match pattern...", 
X	     function==TAGGED?"Tag": function==DELETED?"Delete":"Undelete");
X
X	if (function == TAGGED) {	/* are messages already tagged??? */
X	  for (i=0; i < message_count; i++)
X	    if (ison(headers[i]->status,TAGGED))
X	      tagged++;
X
X	  if (tagged) {
X	    if (tagged > 2) 
X	      PutLine0(LINES-2,0, "Some messages are already tagged.");
X	    else
X	      PutLine0(LINES-2,0, "A message is already tagged.");
X	
X	    Write_to_screen("Remove tag%s? y%c", 2, plural(tagged),BACKSPACE);
X
X	    ch = ReadCh();
X	    if (tolower(ch) != 'n') {	/* remove tags... */
X	      Write_to_screen("Yes.", 0);
X	      for (i=0; i < message_count; i++) {
X	        clearit(headers[i]->status,TAGGED);
X		show_new_status(i);
X	      }
X	    } else
X	      Write_to_screen("No.", 0);
X	  }
X	}
X	
X	PutLine0(LINES-2,0, "Enter pattern: "); CleartoEOLN();
X
X	optionally_enter(meta_pattern, LINES-2, strlen("Enter pattern: "),
X	  FALSE, FALSE);
X
X	if (strlen(meta_pattern) == 0) {
X	  ClearLine(LINES-2);
X	  return(curtag);
X	}
X
X	strcpy(meta_pattern, shift_lower(meta_pattern));   /* lowercase it */
X
X	for (i = 0; i < message_count; i++) {
X	  if (from_matches(i, meta_pattern)) {
X	    if ((selected && headers[i]->status & VISIBLE) || ! selected) {
X	      if (function == UNDELETE)
X	        clearit(headers[i]->status, DELETED);
X	      else
X	        setit(headers[i]->status, function);
X	      show_new_status(i);
X	      if(i == current - 1) curtag++;
X	      count++;
X	    }
X	  }
X	  else if (subject_matches(i, meta_pattern)) {
X	    if ((selected && headers[i]->status & VISIBLE) || ! selected) {
X	      if (function == UNDELETE)
X	        clearit(headers[i]->status, DELETED);
X	      else
X	        setit(headers[i]->status, function);
X	      show_new_status(i);
X	      if(i == current - 1) curtag++;
X	      count++;
X	    }
X	  }
X	}
X
X	ClearLine(LINES-2);	/* remove "pattern: " prompt */
X	
X	if (count > 0)
X	  error3("%s %d messsage%s.", 
X	         function==TAGGED? "Tagged" : 
X		   function==DELETED? "Marked for deletion" : "Undeleted",
X		 count, plural(count));
X	else
X	  error1("No matches. No messages %s.",
X		 function==TAGGED? "tagged" : 
X		   function==DELETED? "marked for deletion": "undeleted");
X
X	return(curtag);
X}
X	  
Xint
Xpattern_match()
X{
X	/** Get a pattern from the user and try to match it with the
X	    from/subject lines being displayed.  If matched (ignoring
X	    case), move current message pointer to that message, if
X	    not, error and return ZERO **/
X
X	register int i;
X
X	PutLine0(LINES-3,40,"/ = Match anywhere in messages.");
X	
X	PutLine0(LINES-1,0, "Match pattern:");
X
X	if (pattern_enter(pattern, alt_pattern, LINES-1, 16, 
X	    "Match pattern (in entire folder):"))
X	  if (strlen(alt_pattern) > 0) {
X	    strcpy(alt_pattern, shift_lower(alt_pattern));
X	    return(match_in_message(alt_pattern));
X	  }
X	  else
X	    return(1);
X	  
X	if (strlen(pattern) == 0) 
X	  return(0);
X	else
X	  strcpy(pattern, shift_lower(pattern));
X
X	for (i = current; i < message_count; i++) {
X	  if (from_matches(i, pattern)) {
X	    if (!selected || (selected && headers[i]->status & VISIBLE)) {
X	      current = ++i;
X	      return(1);
X	    }
X	  }
X	  else if (subject_matches(i, pattern)) {
X	    if (!selected || (selected && headers[i]->status & VISIBLE)) {
X	      current = ++i;
X	      return(1);
X	    }
X	  }
X	}
X
X	return(0);
X}
X
Xint
Xfrom_matches(message_number, pat)
Xint message_number;
Xchar *pat;
X{
X	/** Returns true iff the pattern occurs in it's entirety
X	    in the from line of the indicated message **/
X
X	return( in_string(shift_lower(headers[message_number]->from), 
X		pat) );
X}
X
Xint
Xsubject_matches(message_number, pat)
Xint message_number;
Xchar *pat;
X{
X	/** Returns true iff the pattern occurs in it's entirety
X	    in the subject line of the indicated message **/
X
X	return( in_string(shift_lower(headers[message_number]->subject), 
X		pat) );
X}
X
Xmatch_in_message(pat)
Xchar *pat;
X{
X	/** Match a string INSIDE a message...starting at the current 
X	    message read each line and try to find the pattern.  As
X	    soon as we do, set current and leave! 
X	    Returns 1 if found, 0 if not
X	**/
X
X	char buffer[LONG_STRING];
X	int  message_number, lines, line;
X
X	message_number = current-1;
X
X	error("Searching folder for pattern...");
X
X	while (message_number < message_count) {
X
X	  if (fseek(mailfile, headers[message_number]->offset, 0L) == -1) {
X
X	    dprint(1, (debugfile,
X		"Error: seek %ld bytes into file failed. errno %d (%s)\n",
X		headers[message_number]->offset, errno, 
X		"match_in_message"));
X	    error2("ELM [match] failed looking %ld bytes into file (%s).",
X		   headers[message_number]->offset, error_name(errno));
X	    return(1);	/* fake it out to avoid replacing error message */
X	  }
X
X	  line = 0;
X	  lines = headers[message_number]->lines;
X
X	  while (fgets(buffer, LONG_STRING, mailfile) != NULL && line < lines) {
X	
X	    if(buffer[strlen(buffer)-1] == '\n') line++;
X
X	    if (in_string(shift_lower(buffer), pat)) {
X	      current = message_number+1; 
X	      clear_error();
X	      return(1);
X	    }
X	  }
X
X	  /** now we've passed the end of THIS message...increment and 
X	      continue the search with the next message! **/
X
X	  message_number++;
X	}
X
X	return(0);
X}
SHAR_EOF
chmod 0444 src/pattern.c || echo "restore of src/pattern.c fails"
echo "x - extracting src/pmalloc.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/pmalloc.c &&
X
Xstatic char rcsid[] = "@(#)$Id: pmalloc.c,v 2.3 89/03/25 21:46:59 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.3 $   $State: Exp $
X *
X * 			Copyright (c) 1986, 1987 Dave Taylor
X * 			Copyright (c) 1988, 1989 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X *	Syd Weinstein, Elm Coordinator
X *	elm@dsinc.UUCP			dsinc!elm
X *
X *******************************************************************************
X * $Log:	pmalloc.c,v $
X * Revision 2.3  89/03/25  21:46:59  syd
X * Initial 2.2 Release checkin
X * 
X *
X ******************************************************************************/
X
X/** This routine contains a cheap permanent version of the malloc call to 
X    speed up the initial allocation of the weedout headers and the uuname 
X    data.  
X
X      This routine is originally from Jim Davis of HP Labs, with some 
X    mods by me.
X**/
X
X#include <stdio.h>
X#include "defs.h"
X
X/*VARARGS0*/
X
Xchar *pmalloc(size)
Xint size; 
X{
X	/** return the address of a specified block **/
X
X	static char *our_block = NULL;
X	static int   free_mem  = 0;
X
X	char   *return_value, *malloc();
X
X	/** if bigger than our threshold, just do the real thing! **/
X
X	if (size > PMALLOC_THRESHOLD) 
X	   return(malloc(size));
X
X	/** if bigger than available space, get more, tossing what's left **/
X
X	if (size > free_mem) {
X	  if ((our_block = malloc(PMALLOC_BUFFER_SIZE)) == NULL) {
X	    fprintf(stderr, "\n\r\n\rCouldn't malloc %d bytes!!\n\r\n\r",
X		    PMALLOC_BUFFER_SIZE);
X	    leave();	
X          }
X	  our_block += 4;  /* just for safety, don't give back true address */
X	  free_mem = PMALLOC_BUFFER_SIZE-4;
X	}
X	
X	return_value  = our_block;	/* get the memory */
X	size = ((size+3)/4)*4;		/* Go to quad byte boundary */
X	our_block += size;		/* use it up      */
X	free_mem  -= size;		/*  and decrement */
X
X	return( (char *) return_value);
X}
SHAR_EOF
chmod 0444 src/pmalloc.c || echo "restore of src/pmalloc.c fails"
echo "x - extracting src/quit.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/quit.c &&
X
Xstatic char rcsid[] = "@(#)$Id: quit.c,v 2.15 89/03/25 21:47:00 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.15 $   $State: Exp $
X *
X * 			Copyright (c) 1986, 1987 Dave Taylor
X * 			Copyright (c) 1988, 1989 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X *	Syd Weinstein, Elm Coordinator
X *	elm@dsinc.UUCP			dsinc!elm
X *
X *******************************************************************************
X * $Log:	quit.c,v $
X * Revision 2.15  89/03/25  21:47:00  syd
X * Initial 2.2 Release checkin
X * 
X *
X ******************************************************************************/
X
X/** quit: leave the current folder and quit the program.
X  
X**/
X
X#include "headers.h"
X
Xlong bytes();
X
Xquit(prompt)
Xint prompt;
X{
X	/* a wonderfully short routine!! */
X
X	if (leave_mbox(FALSE, TRUE, prompt) == -1)
X	  /* new mail - leave not done - can't change to another file yet
X	   * check for change in mailfile_size in main() will do the work
X	   * of calling newmbox to add in the new messages to the current
X	   * file and fix the sorting sequence that leave_mbox may have
X	   * changed for its own purposes */
X	  return;
X
X	leave();
X}
X
Xint
Xresync()
X{
X	/** Resync on the current folder. Leave current and read it back in.
X	    Return indicates whether a redraw of the screen is needed.
X	 **/
X
X	  if(leave_mbox(TRUE, FALSE, TRUE) ==-1)
X	    /* new mail - leave not done - can't change to another file yet
X	     * check for change in mailfile_size in main() will do the work
X	     * of calling newmbox to add in the new messages to the current
X	     * file and fix the sorting sequence that leave_mbox may have
X	     * changed for its own purposes */
X	    return(FALSE);
X
X	  newmbox(cur_folder, FALSE);
X	  return(TRUE);
X}
X
Xchange_file()
X{
X	  /* Prompt user for name of folder to change to.
X	   * If all okay with that folder, leave the current folder.
X	   * If leave goes okay (i.e. no new messages in current folder),
X	   * change to the folder that the user specified.
X	   *
X	   * Return value indicates whether a redraw is needed.
X	   */
X
X	  int redraw = FALSE;
X	  char newfile[SLEN];
X	  static char helpmsg[LONG_STRING];
X
X	  char	*nameof();
X
X
X	  /* get new file name */
X
X	  MoveCursor(LINES-3, 30);
X	  CleartoEOS();
X	  PutLine0(LINES-3, 38, "(Use '?' for help/to list your folders.)");
X	  PutLine0(LINES-2,0,"Name of new folder: ");
X	  while(1) {
X	    newfile[0] = '\0';
X	    (void) optionally_enter(newfile, LINES-2, 21, FALSE, FALSE);
X	    clear_error();
X
X	    if(*newfile == '\0') {	/* if user didn't enter a file name */
X	      MoveCursor(LINES-3, 30);	/* abort changing file process */
X	      CleartoEOS();
X	      return(redraw);
X
X	    } else if (strcmp(newfile, "?") == 0) {
X
X	      /* user wants to list folders */
X	      if(!*helpmsg)	/* format helpmsg if not yet done */
X
X		strcpy(helpmsg,
X		  "\n\r\n\rEnter: <nothing> to not change to a new folder,");
X		strcat(helpmsg,
X		  "\n\r       '!' to change to your incoming mailbox (");
X		strcat(helpmsg, defaultfile);
X		strcat(helpmsg,
X		  ")\n\r       '>' to change to your \"received\" folder (");
X		strcat(helpmsg, nameof(recvd_mail));
X		strcat(helpmsg,
X		  ")\n\r       '<' to change to your \"sent\" folder (");
X		strcat(helpmsg, nameof(sent_mail));
X		strcat(helpmsg, ")\n\r       or a filename");
X		strcat(helpmsg,
X		  " (leading '=' denotes your folder directory ");
X		strcat(helpmsg, folders);
X		strcat(helpmsg, ").\n\r");
X
X	      list_folders(4, helpmsg);
X	      PutLine0(LINES-2,0,"Name of new folder: ");	/* reprompt */
X	      redraw = TRUE;		/* we'll need to clean the screen */
X
X	    } else {
X
X	      /* user entered a file name - expand it */
X	      if (! expand_filename(newfile, TRUE))
X		continue;	/* prompt again */
X
X	      /* don't accept the same file as the current */
X	      if (strcmp(newfile, cur_folder) == 0) {
X		error("Already reading that folder!");
X		continue;	/* prompt again */
X	      }
X
X	      /* Make sure this is a file the user can open, unless it's the
X	       * default mailfile, which is openable even if empty */
X	      if (strcmp(newfile, defaultfile) != 0) {
X		if (can_access(newfile, READ_ACCESS)) {
X		  error1("Can't open folder '%s' for reading!", newfile);
X		  continue; 	/* prompt again */
X		}
X	      }
X	      break;	/* exit loop - we got the name of a good file */
X	    }
X	  }
X
X	  /* All's clear with the new file to go ahead and leave the current. */
X	  MoveCursor(LINES-3, 30);
X	  CleartoEOS();
X
X	  if(leave_mbox(FALSE, FALSE, TRUE) ==-1) {
X	    /* new mail - leave not done - can't change to another file yet
X	     * check for change in mailfile_size in main() will do the work
X	     * of calling newmbox to add in the new messages to the current
X	     * file and fix the sorting sequence that leave_mbox may have
X	     * changed for its own purposes */
X	    return(redraw);
X	  }
X
X	  redraw = 1;
X	  newmbox(newfile, FALSE);
X	  return(redraw);
X}
SHAR_EOF
chmod 0444 src/quit.c || echo "restore of src/quit.c fails"
echo "x - extracting src/read_rc.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/read_rc.c &&
X
Xstatic char rcsid[] = "@(#)$Id: read_rc.c,v 2.26 89/03/29 15:47:27 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 2.26 $   $State: Exp $
X *
X * 			Copyright (c) 1986, 1987 Dave Taylor
X * 			Copyright (c) 1988, 1989 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X *	Syd Weinstein, Elm Coordinator
X *	elm@dsinc.UUCP			dsinc!elm
X *
X *******************************************************************************
X * $Log:	read_rc.c,v $
X * Revision 2.26  89/03/29  15:47:27  syd
X * Enable backwards compatibility with the elmrc option "alwaysleave"
X * that we obsoleted recently.
X * From: Rob Bernardo <rob@pbhyf.PacBell.COM>
X * 
X * Revision 2.25  89/03/25  21:47:01  syd
X * Initial 2.2 Release checkin
X * 
X *
X ******************************************************************************/
X
X/** This file contains programs to allow the user to have a .elm/elmrc file
X    in their home directory containing any of the following: 
X
X	fullname= <username string>
X	maildir = <directory>
X	sentmail = <file>
X	editor  = <editor>
X	receviedmail= <file>
X	calendar= <calendar file name>
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	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
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 NOTWEEDOUT	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	register int  i, last = NOTWEEDOUT, lineno = 0, ch,
X	  rc_has_recvdmail = 0, rc_has_sentmail = 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	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	  while (fgets(buffer, SLEN, file) != NULL) {
X	    lineno++;
X	    no_ret(buffer);	 	/* remove return */
X	    if (buffer[0] == '#') { 	/* comment       */
X	      last = NOTWEEDOUT;
X	      continue;
X	    }
X	    if (strlen(buffer) < 2) {	/* empty line    */
X	      last = NOTWEEDOUT;
X	      continue;
X	    }
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	      last = NOTWEEDOUT;
X	    }
X	    else if (equal(word1, "fullname") || equal(word1,"username") ||
X		     equal(word1, "name")) {
X	      strcpy(full_username, word2);
X	      last = NOTWEEDOUT;
X	    }
X	    else if (equal(word1, "prefix")) {
X	      for (i=0; i < strlen(word2); i++)
X		prefixchars[i] = (word2[i] == '_' ? ' ' : word2[i]);
X	      prefixchars[i] = '\0';
X	     
X	      last = NOTWEEDOUT;
X	    }
X	    else if (equal(word1, "shell")) {
X	      strcpy(raw_shell, word2);
X	      expand_env(shell, word2);
X	      last = NOTWEEDOUT;
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;
SHAR_EOF
echo "End of part 18"
echo "File src/read_rc.c is continued in part 19"
echo "19" > s2_seq_.tmp
exit 0

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