From: sources@anomaly.sbs.risc.net
Newsgroups: biz.sco.sources
Subject: v01i110 - ELM v2.3.11, Electronic Mail Reader - Part 10/20
Date: 13 Sep 92 17:41:59 GMT
Reply-To: sources@anomaly.sbs.risc.net
Followup-To: biz.sco.general
Organization: The Rhode Island Internet Systems Cooperative Network


#!/bin/sh
# this is part.10 (part 10 of a multipart archive)
# do not concatenate these parts, unpack them in order with /bin/sh
# file src/args.c continued
#
if test ! -r shar3_seq_.tmp; then
	echo "Please unpack part 1 first!"
	exit 1
fi
(read Scheck
 if test "$Scheck" != 10; then
	echo "Please unpack part $Scheck next!"
	exit 1
 else
	exit 0
 fi
) < shar3_seq_.tmp || exit 1
echo "x - Continuing file src/args.c"
sed 's/^X//' << 'SHAR_EOF' >> src/args.c &&
X
X/** starting argument parsing routines for ELM system...
X
X**/
X
X#include "headers.h"
X#include "patchlevel.h"
X
Xextern char *optarg;		/* optional argument as we go */
Xextern int   optind;			/* argnum + 1 when we leave   */
X
Xvoid exit();	/* just keeping lint happy.... */
X
Xchar *
Xparse_arguments(argc, argv, to_whom)
Xint argc;
Xchar *argv[], *to_whom;
X{
X	/** Set flags according to what was given to program.  If we are 
X	    fed a name or series of names, put them into the 'to_whom' buffer
X	    and if the check_only flag wasn't presented, set mail_only to ON,
X	    and if stdin is not a tty, set batch_only  to ON;
X	    Return req_mfile, which points to a named mail file or is empty.
X	    **/
X
X	register int c = 0;
X	char *strcpy();
X	static char req_mfile[SLEN];
X
X	to_whom[0] = '\0';
X	batch_subject[0] = '\0';
X
X        while ((c = getopt(argc, argv, "?acd:f:hkKms:Vvwz")) != EOF) {
X	   switch (c) {
X	     case 'a' : arrow_cursor++;		break;
X	     case 'c' : check_only++;		break;
X	     case 'd' : debug = atoi(optarg);	break;
X	     case 'f' : strcpy(req_mfile, optarg);	break;
X	     case '?' :
X	     case 'h' : args_help();
X	     case 'k' : hp_terminal++;	break;
X	     case 'K' : hp_terminal++; hp_softkeys++;	break;
X	     case 'm' : mini_menu = 0;	break;
X	     case 's' : strcpy(batch_subject, optarg);	break;
X             case 'V' : sendmail_verbose++;     break;
X	     case 'v' : args_version();
X	     case 'w' : warnings = 0;	break;
X	     case 'z' : check_size++;   break;
X	    }
X	 }
X
X
X#ifndef DEBUG
X	if (debug)
X	  printf(
X     "Warning: system created without debugging enabled - request ignored\n");
X	debug = 0;
X#endif
X
X	if (optind < argc) {
X	  while (optind < argc) {
X		if (strlen(to_whom) + strlen(to_whom[0] != '\0'? " " : "") +
X			strlen(argv[optind]) > SLEN)
X				exit(printf("\n\rToo many addresses, or addresses too long!\n\r"));
X
X	    sprintf(to_whom, "%s%s%s", to_whom, 
X	            to_whom[0] != '\0'? " " : "", argv[optind]);
X	    if(!check_only)
X	      mail_only++;
X	    optind++;
X	  }
X	  check_size = 0;	/* NEVER do this if we're mailing!! */
X	}
X
X	 if (strlen(batch_subject) > 0 && ! mail_only) 
X	   exit(printf(
X     "\n\rDon't understand specifying a subject and no-one to send to!\n\r"));
X
X	if (!isatty(fileno(stdin)) && !check_only) {
X	  batch_only = ON;
X	  if(*batch_subject == '\0')
X	    strcpy(batch_subject, DEFAULT_BATCH_SUBJECT);
X	}
X	return(req_mfile);
X
X
X}
X
Xargs_help()
X{
X	/**  print out possible starting arguments... **/
X
X	printf("\nPossible Starting Arguments for ELM program:\n\n");
X	printf("\targ\t\t\tMeaning\n");
X	printf("\t -a \t\tArrow - use the arrow pointer regardless\n");
X	printf("\t -c \t\tCheckalias - check the given aliases only\n");
X	printf("\t -dn\t\tDebug - set debug level to 'n'\n");
X	printf(
X	  "\t -fx\t\tFolder - read folder 'x' rather than incoming mailbox\n");
X	printf("\t -h \t\tHelp - give this list of options\n");
X	printf("\t -k \t\tKeypad - enable HP 2622 terminal keyboard\n");
X	printf("\t -K \t\tKeypad&softkeys - enable use of softkeys + \"-k\"\n");
X	printf("\t -m \t\tMenu - Turn off menu, using more of the screen\n");
X	printf("\t -sx\t\tSubject 'x' - for batchmailing\n");
X        printf("\t -V \t\tEnable sendmail voyeur mode.\n");
X	printf("\t -v \t\tPrint out ELM version information.\n");
X	printf("\t -w \t\tSupress warning messages...\n");
X	printf("\t -z \t\tZero - don't enter ELM if no mail is pending\n");
X	printf("\n");
X	printf("\n");
X	exit(1);
X}
X
Xargs_version()
X{
X	/** print out version information **/
X
X	printf("\nElm Version and Identification Information:\n\n");
X	printf("\tElm %s PL%d, of %s\n",VERSION,PATCHLEVEL,VERS_DATE);
X	printf("\t(C) Copyright 1986, 1987 Dave Taylor\n");
X	printf("\t(C) Copyright 1988, 1989, 1990 USENET Community Trust\n");
X	printf("\t----------------------------------\n");
X	printf("\tConfigured %s\n", CONFIGURE_DATE);
X	printf("\t----------------------------------\n");
X
X#ifdef USE_EMBEDDED_ADDRESSES
X	printf("\tFrom: and Reply-To: addresses are good: USE_EMBEDDED_ADDRESSES\n");
X#else /* USE_EMBEDDED_ADDRESSES */
X	printf("\tFrom: and Reply-To: addresses ignored: not USE_EMBEDDED_ADDRESSES\n");
X#endif /* USE_EMBEDDED_ADDRESSES */
X
X#ifdef OPTIMIZE_RETURN
X	printf("\tReturn addresses will be optimized: OPTIMIZE_RETURN\n");
X#else /* OPTIMIZE_RETURN */
X	printf("\tReturn addresses will not be optimized: not OPTIMIZE_RETURN\n");
X#endif
X
X#ifdef INTERNET
X	printf("\tPrefers Internet address formats: INTERNET\n");
X#else /* INTERNET */
X	printf("\tInternet address formats not used: not INTERNET\n");
X#endif /* INTERNET */
X
X#ifdef DEBUG
X	printf("\tDebug options are available: DEBUG\n");
X#else /* DEBUG */
X	printf("\tNo debug options are available: not DEBUG\n");
X#endif /* DEBUG */
X		
X#ifdef CRYPT
X	printf("\tCrypt function enabled: CRYPT\n");
X#else /* CRYPT */
X	printf("\tCrypt function disabled: not CRYPT\n");
X#endif /* CRYPT */
X
X#ifdef ALLOW_MAILBOX_EDITING
X	printf("\tMailbox editing included: ALLOW_MAILBOX_EDITING\n");
X#else /* ALLOW_MAILBOX_EDITING */
X	printf("\tMailbox editing not included: not ALLOW_MAILBOX_EDITING\n");
X#endif /* ALLOW_MAILBOX_EDITING */
X
X#ifdef ENABLE_CALENDAR
X	printf("\tCalendar file feature enabled: ENABLE_CALENDAR\n");
X	printf("\t\t(Default calendar file is %s)\n",dflt_calendar_file);
X#else /* ENABLE_CALENDAR */
X	printf("\tCalendar file feature disabled: not ENABLE_CALENDAR\n");
X#endif /* ENABLE_CALENDAR */
X
X	printf("\n\n");
X	exit(1);
X
X}
X
SHAR_EOF
echo "File src/args.c is complete" &&
# ============= src/bouncebk.c ==============
echo "x - extracting src/bouncebk.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/bouncebk.c &&
X
Xstatic char rcsid[] = "@(#)$Id: bouncebk.c,v 4.1 90/04/28 22:42:33 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
X *
X * 			Copyright (c) 1986, 1987 Dave Taylor
X * 			Copyright (c) 1988, 1989, 1990 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X *	Syd Weinstein, Elm Coordinator
X *	elm@DSI.COM			dsinc!elm
X *
X *******************************************************************************
X * $Log:	bouncebk.c,v $
X * Revision 4.1  90/04/28  22:42:33  syd
X * checkin of Elm 2.3 as of Release PL0
X * 
X *
X ******************************************************************************/
X
X/** This set of routines implement the bounceback feature of the mailer.
X    This feature allows mail greater than 'n' hops away (n specified by
X    the user) to have a 'cc' to the user through the remote machine.  
X
X    Due to the vagaries of the Internet addressing (uucp -> internet -> uucp)
X    this will NOT generate bounceback copies with mail to an internet host!
X
X**/
X
X#include "headers.h"
X
Xchar *bounce_off_remote(),		/* forward declaration */
X     *strcat(), *strcpy();
X
Xint
Xuucp_hops(to)
Xchar *to;
X{	
X	/** Given the entire "To:" list, return the number of hops in the
X	    first address (a hop = a '!') or ZERO iff the address is to a
X  	    non uucp address.
X	**/
X
X	register int hopcount = 0, iindex;
X
X	for (iindex = 0; ! whitespace(to[iindex]) && to[iindex] != '\0'; iindex++) {
X	  if (to[iindex] == '!')
X	    hopcount++;
X	  else if (to[iindex] == '@' || to[iindex] == '%' || to[iindex] == ':')
X	    return(0);	/* don't continue! */
X	}
X
X	return(hopcount);
X}
X	
Xchar *bounce_off_remote(to)
Xchar *to;
X{
X	/** Return an address suitable for framing (no, that's not it...)
X	    Er, suitable for including in a 'cc' line so that it ends up
X	    with the bounceback address.  The method is to take the first 
X	    address in the To: entry and break it into machines, then 
X	    build a message up from that.  For example, consider the
X	    following address:
X			a!b!c!d!e!joe
X	    the bounceback address would be;
X			a!b!c!d!e!d!c!b!a!ourmachine!ourname
X	    simple, eh?
X	**/
X
X	static char address[LONG_STRING];	/* BEEG address buffer! */
X
X	char   host[MAX_HOPS][NLEN];	/* for breaking up addr */
X	register int hostcount = 0, hindex = 0, 
X	       iindex;
X
X	for (iindex = 0; !whitespace(to[iindex]) && to[iindex] != '\0'; iindex++) {
X	  if (to[iindex] == '!') {
X	    host[hostcount][hindex] = '\0';
X	    hostcount++;
X	    hindex = 0;
X	  }
X	  else 
X	    host[hostcount][hindex++] = to[iindex];
X	}
X
X	/* we have hostcount hosts... */
X
X	strcpy(address, host[0]);	/* initialize it! */
X
X	for (iindex=1; iindex < hostcount; iindex++) {
X	  strcat(address, "!");
X	  strcat(address, host[iindex]);
X	}
X	
X	/* and now the same thing backwards... */
X
X	for (iindex = hostcount -2; iindex > -1; iindex--) {
X	  strcat(address, "!");
X	  strcat(address, host[iindex]);
X	}
X
X	/* and finally, let's tack on our machine and login name */
X
X	strcat(address, "!");
X	strcat(address, hostname);
X	strcat(address, "!");
X	strcat(address, username);
X
X	/* and we're done!! */
X
X	return( (char *) address );
X}
SHAR_EOF
# ============= src/builtin.c ==============
echo "x - extracting src/builtin.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/builtin.c &&
X
Xstatic char rcsid[] = "@(#)$Id: builtin.c,v 4.1 90/04/28 22:42:34 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
X *
X * 			Copyright (c) 1986, 1987 Dave Taylor
X * 			Copyright (c) 1988, 1989, 1990 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X *	Syd Weinstein, Elm Coordinator
X *	elm@DSI.COM			dsinc!elm
X *
X *******************************************************************************
X * $Log:	builtin.c,v $
X * Revision 4.1  90/04/28  22:42:34  syd
X * checkin of Elm 2.3 as of Release PL0
X * 
X *
X ******************************************************************************/
X
X/** This is the built-in pager for displaying messages while in the Elm
X    program.  It's a bare-bones pager with precious few options. The idea
X    is that those systems that are sufficiently slow that using an external
X    pager such as 'more' is too slow, then they can use this!
X
X    Also added support for the "builtin+" pager (clears the screen for
X    each new page) including a two-line overlap for context...
X
X**/
X
X#include "headers.h"
X#include <ctype.h>
X
X#define  BEEP		007		/* ASCII Bell character */
X
Xstatic	unfilled_lines,
X	form_title;
X
Xint	lines_displayed,	    /* total number of lines displayed      */
X	total_lines_to_display,	    /* total number of lines in message     */
X	pages_displayed; 	    /* for the nth page titles and all      */
X
Xstart_builtin(lines_in_message)
Xint lines_in_message;
X{
X	/** clears the screen and resets the internal counters... **/
X
X	dprint(8,(debugfile, 
X		"displaying %d lines from message using internal pager\n",
X		lines_in_message));
X
X	unfilled_lines = LINES;
X	form_title = 1;
X	lines_displayed = 0;
X        pages_displayed = 1;
X
X	total_lines_to_display = lines_in_message;
X}
X
Xextern int tabspacing;
X
Xint
Xnext_line(inputptr, output, width)
Xchar **inputptr, *output;
Xregister unsigned width;
X{
X	/* Copy characters from input to output and copy
X	 * remainder of output to output. In copying use ^X notation for
X	 * control characters, '?' non-ascii characters, expand tabs
X	 * to correct number of spaces till next tab stop.
X	 * Column zero of the next line is considered to be the tab stop
X	 * that follows the last one that fits on a line.
X	 * Copy until newline/return encountered, null char encountered,
X	 * width characters producted in output buffer.
X	 * Formfeed is handled exceptionally. If encountered it
X	 * is removed from input and 1 is returned. Otherwise 0 is returned.
X	 */
X
X	register char *optr, *iptr;
X	register unsigned chars_output, nt;
X	int ret_val;
X
X	optr = output;
X	iptr = *inputptr;
X	chars_output = 0;
X
X	ret_val = 0;	/* presume no formfeed */
X	while(1) {
X
X	  if(chars_output >= width) {		/* no more room on line */
X	    *optr++ = '\n';
X	    *optr++ = '\r';
X	    /* if next input character is newline or return,
X	     * we can skip over it since we are outputing a newline anyway */ 
X	    if((*iptr == '\n') || (*iptr == '\r'))
X	      iptr++;
X	    break;		
X	  } else if (*iptr == '\n' || *iptr == '\r') {	/*newline or return */
X	    *optr++ = '\n';
X	    *optr++ = '\r';
X	    iptr++;
X	    break;			/* end of line */
X	  } else if(*iptr == '\f') {		/* formfeed */
X	    /* if next input character is newline or return,
X	     * we can skip over it since we are outputing a formfeed anyway */ 
X	    if((*++iptr == '\n') || (*iptr == '\r'))
X	      iptr++;
X	    ret_val = 1;
X	    break;			/* leave rest of screen clear */
X	  } else if(*iptr == '\0') {		/* none left in input string */
X	    break;
X	  } else if(*iptr == '\t') {		/* tab stop */
X	    if((nt=next_tab(chars_output+1)) > width) {
X	      *optr++ = '\n';		/* won't fit on this line - autowrap */
X	      *optr++ = '\r';		/* tab by tabbing so-to-speak to 1st */
X	      iptr++;			/* column of next line */
X	      break;
X	    } else {		/* will fit - output proper num of spaces */
X	      while(chars_output < nt-1) {
X		chars_output++;
X		*optr++ = ' ';
X	      }
X	      iptr++;
X	    }
X	  } else if(isprint(*iptr)) {
X	    *optr++ = *iptr++;			/* printing character */
X	    chars_output++;
X	  } else {			/* non-white space control character */
X	    if(chars_output + 2 <= width) {
X	      *optr++ = '^';	
X	      *optr++ = (*iptr == '\177' ? '?' : (*iptr&0177) + 'A' - 1);
X	      iptr++;
X	      chars_output += 2;
X	    } else {			/* no space on line for both chars */
X	      break;
X	    }
X	  }
X	}
X	*optr = '\0';
X	*inputptr = iptr;
X	return(ret_val);
X}
X
X
Xint
Xdisplay_line(input_line)
Xchar *input_line;
X{
X	/** Display the given line on the screen, taking into account such
X	    dumbness as wraparound and such.  If displaying this would put
X	    us at the end of the screen, put out the "MORE" prompt and wait
X	    for some input.   Return non-zero if the user terminates the
X	    paging (e.g. 'i') or zero if we should continue. Also, 
X            this will pass back the value of any character the user types in 
X	    at the prompt instead, if needed... (e.g. if it can't deal with
X	    it at this point)
X	**/
X	
X	char *pending, footer[SLEN], display_buffer[SLEN], ch;
X	int formfeed, lines_more;
X
X#ifdef MMDF
X	if (strcmp(input_line, MSG_SEPERATOR) == 0)
X	  strcpy(input_line," ");
X#endif /* MMDF */
X	pending = input_line;
X	CarriageReturn();
X
X	do {
X
X	  /* while there is more space on the screen - leave prompt line free */
X	  while(unfilled_lines > 0) {
X
X	    /* display a screen's lineful of the input line
X	     * and reset pending to point to remainder of input line */
X	    formfeed = next_line(&pending, display_buffer, COLUMNS);
X
X	    if(*display_buffer == '\0') {	/* no line to display */
X	      if(!formfeed)	/* no "formfeed" to display
X	     			 * need more lines for screen */
X		return(FALSE);
X	    } else
X	      Write_to_screen(display_buffer, 0);
X
X	    /* if formfeed, clear remainder of screen */
X	    if(formfeed) {
X	      CleartoEOS();
X	      unfilled_lines=0;
X	    }
X	    else
X	      unfilled_lines--;
X
X	    /* if screen is not full (leave room for prompt)
X	     * but we've used up input line, return */
X
X	    if(unfilled_lines > 0 && *pending == '\0')
X	      return(FALSE);	/* we need more lines to fill screen */
X
X	    /* otherwise continue to display next part of input line */
X	  }
X
X	  /* screen is now full - prompt for user input */
X	  lines_more = total_lines_to_display - lines_displayed;
X	  sprintf(footer,
X		  ( (user_level == 0) ?
X  " There %s %d line%s left (%d%%). Press <space> for more, or 'i' to return. "
X		  : (user_level == 1) ?
X  " %s%d line%s more (%d%%). Press <space> for more, 'i' to return. "
X		  :
X  " %s%d line%s more (you've seen %d%%) "),
X		   (user_level == 0 ?
X		     (lines_more == 1 ? "is" : "are") : ""),
X		   lines_more, plural(lines_more),
X		   (int)((100L * lines_displayed) / total_lines_to_display));
X 
X	  MoveCursor(LINES, 0);
X	  StartBold();
X	  Write_to_screen(footer, 0);
X	  EndBold();
X
X	  switch(ch = ReadCh()) {
X
X	    case '\n':
X	    case '\r':	/* scroll down a line */
X			unfilled_lines = 1;
X			ClearLine(LINES);
X			break;
X
X	    case ' ':	/* scroll a screenful */
X			unfilled_lines = LINES;
X			if(clear_pages) {
X			  ClearScreen();
X			  MoveCursor(0,0);
X			  CarriageReturn();
X
X			  /* output title */
X			  if(title_messages && filter) {
X			    title_for_page(++pages_displayed);
X			    unfilled_lines -= 2;
X			  }
X			} else ClearLine(LINES);
X
X			/* and keep last line to be first line of next
X			 * screenful unless we had a formfeed */
X			if(!formfeed) {
X			  if(clear_pages)
X			    Write_to_screen(display_buffer, 0);
X			  unfilled_lines--;
X			}
X			break;
X
X	    default:	return(ch);
X	  }
X	  CarriageReturn();
X	} while(*pending);
X	return(FALSE);
X}
X	  
Xtitle_for_page(page)
Xint page;
X{
X	/** Output a nice title for the second thru last pages of the message 
X	    we're currently reading. Note - this code is very similar to
X	    that which produces the title for the first page, except that
X	    page number replaces the date and the method by which it
X	    gets to the screen **/
X
X	static char title1[SLEN], title2[SLEN];
X	char titlebuf[SLEN], title3[SLEN], who[SLEN];
X	static t1_len, t2_len;
X	register int padding, showing_to;
X
X	/* format those parts of the title that are constant for a message */
X	if(form_title) {
X
X	  showing_to = tail_of(headers[current-1]->from, who,
X	    headers[current-1]->to);
X
X	  sprintf(title1, "%s %d/%d  ",
X	      headers[current-1]->status & DELETED ? "[deleted]" :
X	      headers[current-1]->status & FORM_LETTER ? "Form": "Message",
X	      current, message_count);
X	  t1_len = strlen(title1);
X	  sprintf(title2, "%s %s", showing_to? "To" : "From", who);
X	  t2_len = strlen(title2);
X	}
X	/* format those parts of the title that vary between pages of a mesg */
X	sprintf(title3, "  Page %d", page);
X
X	/* truncate or pad title2 portion on the right
X	 * so that line fits exactly to the rightmost column */
X	padding = COLUMNS - (t1_len + t2_len + strlen(title3));
X
X	sprintf(titlebuf, "%s%-*.*s%s\n\r\n\r", title1, t2_len+padding,
X	    t2_len+padding, title2, title3);
X	    /* extra newline is to give a blank line after title */
X
X	Write_to_screen(titlebuf, 0);
X	form_title = 0;
X}
SHAR_EOF
# ============= src/calendar.c ==============
echo "x - extracting src/calendar.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/calendar.c &&
X
Xstatic char rcsid[] = "@(#)$Id: calendar.c,v 4.1.1.1 90/06/21 22:16:50 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 4.1.1.1 $   $State: Exp $
X *
X * 			Copyright (c) 1986, 1987 Dave Taylor
X * 			Copyright (c) 1988, 1989, 1990 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X *	Syd Weinstein, Elm Coordinator
X *	elm@DSI.COM			dsinc!elm
X *
X *******************************************************************************
X * $Log:	calendar.c,v $
X * Revision 4.1.1.1  90/06/21  22:16:50  syd
X * Add skip leading whitespace
X * From Jerry Pendergrafyt
X * 
X * Revision 4.1  90/04/28  22:42:36  syd
X * checkin of Elm 2.3 as of Release PL0
X * 
X *
X ******************************************************************************/
X
X/** This routine implements a rather snazzy idea suggested by Warren
X    Carithers of the Rochester Institute of Technology that allows
X    mail to contain entries formatted in a manner that will allow direct
X    copying into a users calendar program.
X
X    All lines in the current message beginning with "->", e.g.
X
X	-> Mon 04/21 1:00p meet with chairman candidate
X
X    get copied into the user's calendar file.
X
X**/
X
X#include "headers.h"
X
X#ifdef ENABLE_CALENDAR		/* if not defined, this will be an empty file */
X
X#include <errno.h>
X
Xextern int errno;
X
Xchar *error_name(), *error_description(), *strcpy();
X
Xscan_calendar()
X{
X	FILE *calendar;
X	int  count;
X
X	/* First step is to open the calendar file for appending... **/
X
X	if (can_open(calendar_file, "a") != 0) {
X	  dprint(2, (debugfile,
X		  "Error: wrong permissions to append to calendar %s\n",
X		  calendar_file));
X	  dprint(2, (debugfile, "** %s - %s **\n",
X		  error_name(errno), error_description(errno)));
X	  error1("Not able to append to file %s!", calendar_file);
X	  return; 
X	}
X
X	save_file_stats(calendar_file);
X
X	if ((calendar = fopen(calendar_file,"a")) == NULL) {
X	  dprint(2, (debugfile, 
X		"Error: couldn't append to calendar file %s (scan)\n", 
X		calendar_file));
X	  dprint(2, (debugfile, "** %s - %s **\n",
X		  error_name(errno), error_description(errno)));
X	  error1("Couldn't append to file %s!", calendar_file);
X	  return; 
X	}
X	
X	count = extract_info(calendar);
X
X	fclose(calendar);
X
X	restore_file_stats(calendar_file);
X
X	if (count > 0)
X	  error2("%d entr%s saved in calendar file.", 
X		 count, count > 1 ? "ies" : "y");
X	else 
X	  error("No calendar entries found in that message.");
X
X	return;
X}
X
Xint
Xextract_info(save_to_fd)
XFILE *save_to_fd;
X{
X	/** Save the relevant parts of the current message to the given
X	    calendar file.  The only parameter is an opened file
X	    descriptor, positioned at the end of the existing file **/
X	    
X	register int entries = 0, lines;
X	char buffer[SLEN], *cp, *is_cal_entry();
X
X    	/** get to the first line of the message desired **/
X
X    	if (fseek(mailfile, headers[current-1]->offset, 0) == -1) {
X       	  dprint(1,(debugfile, 
X		"ERROR: Attempt to seek %d bytes into file failed (%s)",
X		headers[current-1]->offset, "extract_info"));
X       	  error1("ELM [seek] failed trying to read %d bytes into file.",
X	     	headers[current-1]->offset);
X       	  return(0);
X    	}
X
X        /* how many lines in message? */
X
X        lines = headers[current-1]->lines;
X
X        /* now while not EOF & still in message... scan it! */
X
X	while (lines) {
X
X          if(fgets(buffer, SLEN, mailfile) == NULL)
X	    break;
X
X	  if(buffer[strlen(buffer)-1] == '\n')
X	    lines--;					/* got a full line */
X
X	  if((cp = is_cal_entry(buffer)) != NULL) {
X	    entries++;
X	    fprintf(save_to_fd,"%s", cp);
X	  }
X
X	}
X	dprint(4,(debugfile,
X		"Got %d calender entr%s.\n", entries, entries > 1? "ies":"y"));
X
X	return(entries);
X}
X
Xchar *
Xis_cal_entry(string)
Xregister char *string;
X{
X	/* If string is of the form
X         * {optional white space} ->{optional white space} {stuff}
X	 * return a pointer to stuff, otherwise return NULL.
X	 */
X	while( whitespace(*string) )
X	  string++;      /* strip leading W/S */
X	
X	if(strncmp(string, "->", 2) == 0) {
X	  for(string +=2 ; whitespace(*string); string++)
X		  ;
X	  return(string);
X	}
X	return(NULL);
X}
X
X#endif
SHAR_EOF
# ============= src/conn_to.c ==============
echo "x - extracting src/conn_to.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/conn_to.c &&
X
Xstatic char rcsid[] = "@(#)$Id: conn_to.c,v 4.1 90/04/28 22:42:37 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
X *
X * 			Copyright (c) 1986, 1987 Dave Taylor
X * 			Copyright (c) 1988, 1989, 1990 USENET Community Trust
X *******************************************************************************
X * Bug reports, patches, comments, suggestions should be sent to:
X *
X *	Syd Weinstein, Elm Coordinator
X *	elm@DSI.COM			dsinc!elm
X *
X *******************************************************************************
X * $Log:	conn_to.c,v $
X * Revision 4.1  90/04/28  22:42:37  syd
X * checkin of Elm 2.3 as of Release PL0
X * 
X *
X ******************************************************************************/
X
X/** This contains the routine(s) needed to have the Elm mailer figure
X    out what machines the current machine can talk to.
X    It will invoke uuname to a file, then read the file in!
X**/
X
X#include "headers.h"
X
Xchar *strcpy();
X
X#ifndef DONT_TOUCH_ADDRESSES
Xget_connections()
X{
X
X	/** get the direct connections that this machine has
X	    using the uuname routine to get the names.
X	**/
X
X	FILE *fd;
X	char  buffer[SLEN], filename[SLEN];
X	struct lsys_rec *system_record, *previous_record;
X	int   loc_on_line;
X
X
X	if (! warnings) {		/* skip this - they don't care! */
X	  talk_to_sys = NULL;
X	  return;
X	}
X
X	if (strlen(uuname) == 0) {	/* skip this - no way to get connections */
X	  warnings = NO;
X	  talk_to_sys = NULL;
X	  dprint(1, (debugfile, "No uuname - clearing warnings\n"));
X	  error("Warning: no uuname command, clearing option warnings");
X	  return;
X	}
X
X	sprintf(filename, "%s%s%d", temp_dir, temp_uuname, getpid());
X	sprintf(buffer,"%s > %s", uuname, filename);
X
X	if (system_call(buffer, SH, FALSE, FALSE) != 0) {
X	  dprint(1, (debugfile, "Can't get uuname info - system() failed!\n"));
X	  goto unable_to_get;
X	}
X	
X	if ((fd = fopen(filename, "r")) == NULL) {
X	  dprint(1, (debugfile,
X		"Can't get uuname info - can't open file %s for reading\n",
X		 filename));
X	  goto unable_to_get;
X	}
X	
X	previous_record = NULL;
X
X	while (fgets(buffer, SLEN, fd) != NULL) {
X	  no_ret(buffer);
X	  if (previous_record == NULL) {
X	    dprint(2, (debugfile, "uuname\tdirect connection to %s, ", buffer));
X	    loc_on_line = 30 + strlen(buffer);
X	    previous_record = (struct lsys_rec *) pmalloc(sizeof *talk_to_sys);
X
X	    strcpy(previous_record->name, buffer);
X	    previous_record->next = NULL;
X	    talk_to_sys = previous_record;
X	  }
X	  else {	/* don't have to check uniqueness - uuname does that! */
X	    if (loc_on_line + strlen(buffer) > 80) {
X	      dprint(2, (debugfile, "\n\t"));
X	      loc_on_line = 8;
X	    }
X	    dprint(2, (debugfile, "%s, ", buffer));
X	    loc_on_line += (strlen(buffer) + 2);
X	    system_record = (struct lsys_rec *) pmalloc(sizeof *talk_to_sys);
X	  
X	    strcpy(system_record->name, buffer);
X	    system_record->next = NULL;
X	    previous_record->next = system_record;
X	    previous_record = system_record;
X	  }
X	}
X
X	fclose(fd);
X
X	(void) unlink(filename);		/* kill da temp file!! */
X
X	dprint(2, (debugfile, "\n"));		/* for a nice format! Yeah! */
X
X	return;					/* it all went okay... */
X
Xunable_to_get:
X	unlink(filename);	/* insurance */
X	error("Warning: couldn't figure out system connections...");
X	talk_to_sys = NULL;
X}
X#endif
SHAR_EOF
# ============= src/curses.c ==============
echo "x - extracting src/curses.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/curses.c &&
X
Xstatic char rcsid[] = "@(#)$Id: curses.c,v 4.1.1.3 90/07/12 20:18:02 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:	curses.c,v $
X * Revision 4.1.1.3  90/07/12  20:18:02  syd
X * Be sure that output characters are not negative integers.
X * From: tct!chip@uunet.UU.NET (Chip Salzenberg)
X * 
X * Revision 4.1.1.2  90/06/26  20:09:09  syd
X * Add 8 bit support via ascii_ctype
X * From: Robert Claeson <prc@erbe.se>
X * 
X * Revision 4.1.1.1  90/06/05  21:05:22  syd
X * Fixes where src/curses.c attempts to set the screen size via the ioctl
X * TIOCGWINSIZ if it exsists. It should only use the row or col size as
X * returned from the ioctl if they are not 0.
X * From: muller%sdcc10@ucsd.edu (Keith Muller)
X * 
X * Revision 4.1  90/04/28  22:42:39  syd
X * checkin of Elm 2.3 as of Release PL0
X * 
X *
X ******************************************************************************/
X
X/**  This library gives programs the ability to easily access the
X     termcap information and write screen oriented and raw input
X     programs.  The routines can be called as needed, except that
X     to use the cursor / screen routines there must be a call to
X     InitScreen() first.  The 'Raw' input routine can be used
X     independently, however.
X
X**/
X
X/** NOTE THE ADDITION OF: the #ifndef ELM stuff around routines that
X    we don't use.  This is for code size and compile time speed...
X**/
X
X#include "headers.h"
X
X#ifdef TERMIOS
X#  include <termios.h>
X# if __convex__
X#  include <sys/ioctl.h>	/* non-standard, for TIOCGWINSZ */
X# endif
X#else
X# ifdef TERMIO
X#  include <termio.h>
X# else
X#  include <sgtty.h>
X# endif
X#endif
X
X#include <ctype.h>
X
X#ifdef PTEM
X#  include <sys/types.h>
X#  include <sys/stream.h>
X#  include <sys/ptem.h>
X#endif
X
X#ifdef BSD
X#undef tolower
X#endif
X
X#define TTYIN	0
X
X#ifdef SHORTNAMES
X# define _clearinverse	_clrinv
X# define _cleartoeoln	_clrtoeoln
X# define _cleartoeos	_clr2eos
X# define _transmit_off	xmit_off
X# define _transmit_on	xmit_on
X#endif
X
X#ifdef TERMIOS
Xstruct termios _raw_tty,
X	       _original_tty;
X#define	ttgetattr(fd,where)	tcgetattr((fd),(where))
X#define	ttsetattr(fd,where)	tcsetattr((fd),TCSADRAIN,(where))
X#else	/*TERMIOS*/
X# ifdef TERMIO
Xstruct termio _raw_tty, 
X              _original_tty;
X#define	ttgetattr(fd,where)	ioctl((fd),TCGETA,(where))
X#define	ttsetattr(fd,where)	ioctl((fd),TCSETAW,(where))
X# else
Xstruct sgttyb _raw_tty,
X	      _original_tty;
X#define	ttgetattr(fd,where)	ioctl((fd),TIOCGETP,(where))
X#define	ttsetattr(fd,where)	ioctl((fd),TIOCSETP,(where))
X# endif	/*TERMIO*/
X#endif	/*TERMIOS*/
X
Xstatic int _inraw = 0;                  /* are we IN rawmode?    */
X
X#define DEFAULT_LINES_ON_TERMINAL	24
X#define DEFAULT_COLUMNS_ON_TERMINAL	80
X
Xstatic int _memory_locked = 0;		/* are we IN memlock??   */
Xstatic int _line  = -1,			/* initialize to "trash" */
X           _col   = -1;
X
Xstatic int _intransmit;			/* are we transmitting keys? */
X
Xstatic
Xchar *_clearscreen, *_moveto, *_up, *_down, *_right, *_left,
X     *_setbold, *_clearbold, *_setunderline, *_clearunderline, 
X     *_sethalfbright, *_clearhalfbright, *_setinverse, *_clearinverse,
X     *_cleartoeoln, *_cleartoeos, *_transmit_on, *_transmit_off,
X     *_set_memlock, *_clear_memlock;
X
Xstatic int _lines, _columns, _automargin, _eatnewlineglitch;
Xint tabspacing;
X
Xstatic char _terminal[1024];              /* Storage for terminal entry */
Xstatic char _capabilities[1024];           /* String for cursor motion */
X
Xstatic char *ptr = _capabilities;	/* for buffering         */
X
Xint    outchar();			/* char output for tputs */
Xchar  *tgetstr(),     		       /* Get termcap capability */
X      *tgoto();				/* and the goto stuff    */
X
XInitScreen()
X{
X	/* Set up all this fun stuff: returns zero if all okay, or;
X        -1 indicating no terminal name associated with this shell,
X        -2..-n  No termcap for this terminal type known
X   */
X
X	int  tgetent(),      /* get termcap entry */
X	     err;
X	char termname[40];
X	char *strcpy(), *getenv();
X	
X	if (getenv("TERM") == NULL) return(-1);
X
X	if (strcpy(termname, getenv("TERM")) == NULL)
X		return(-1);
X
X	if ((err = tgetent(_terminal, termname)) != 1)
X		return(err-2);
X
X	_line  =  0;		/* where are we right now?? */
X	_col   =  0;		/* assume zero, zero...     */
X
X	/* load in all those pesky values */
X	_clearscreen       = tgetstr("cl", &ptr);
X	_moveto            = tgetstr("cm", &ptr);
X	_up                = tgetstr("up", &ptr);
X	_down              = tgetstr("do", &ptr);
X	_right             = tgetstr("nd", &ptr);
X	_left              = tgetstr("bs", &ptr);
X	_setbold           = tgetstr("so", &ptr);
X	_clearbold         = tgetstr("se", &ptr);
X	_setunderline      = tgetstr("us", &ptr);
X	_clearunderline    = tgetstr("ue", &ptr);
X	_setinverse        = tgetstr("so", &ptr);
X	_clearinverse      = tgetstr("se", &ptr);
X	_sethalfbright     = tgetstr("hs", &ptr);
X	_clearhalfbright   = tgetstr("he", &ptr);
X	_cleartoeoln       = tgetstr("ce", &ptr);
X	_cleartoeos        = tgetstr("cd", &ptr);
X	_lines	      	   = tgetnum("li");
X	_columns	   = tgetnum("co");
X	tabspacing	   = ((tabspacing=tgetnum("it"))==-1 ? 8 : tabspacing);
X	_automargin	   = tgetflag("am");
X	_eatnewlineglitch   = tgetflag("xn");
X	_transmit_on	   = tgetstr("ks", &ptr);
X	_transmit_off      = tgetstr("ke", &ptr);
X	_set_memlock	   = tgetstr("ml", &ptr);
X	_clear_memlock	   = tgetstr("mu", &ptr);
X
X
X	if (!_left) {
X		_left = "\b";
X	}
X
X	return(0);
X}
X
Xchar *return_value_of(termcap_label)
Xchar *termcap_label;
X{
X	/** This will return the string kept by termcap for the 
X	    specified capability. Modified to ensure that if 
X	    tgetstr returns a pointer to a transient address	
X	    that we won't bomb out with a later segmentation
X	    fault (thanks to Dave@Infopro for this one!)
X
X	    Tweaked to remove padding sequences.
X	 **/
X
X	static char escape_sequence[20];
X	register int i=0,j=0;
X	char buffer[20];
X	char *myptr, *tgetstr();     		/* Get termcap capability */
X
X	if (strlen(termcap_label) < 2)
X	  return(NULL);
X
X	if (termcap_label[0] == 's' && termcap_label[1] == 'o')
X	  {
X	  if (_setinverse)
X	    strcpy(escape_sequence, _setinverse);
X	  else
X	    return( (char *) NULL );
X	  }
X	else if (termcap_label[0] == 's' && termcap_label[1] == 'e')
X	  {
X	  if (_clearinverse)
X	    strcpy(escape_sequence, _clearinverse);
X	  else
X	    return( (char *) NULL );
X	  }
X	else if ((myptr = tgetstr(termcap_label, &ptr)) == NULL)
X	  return( (char *) NULL );
X	else
X	  strcpy(escape_sequence, myptr);
X
X	if (chloc(escape_sequence, '$') != -1) {
X	  while (escape_sequence[i] != '\0') {
X	    while (escape_sequence[i] != '$' && escape_sequence[i] != '\0')
X	      buffer[j++] = escape_sequence[i++];
X	    if (escape_sequence[i] == '$') {
X	      while (escape_sequence[i] != '>') i++;
X	      i++;
X	    }
X	  }
X	  buffer[j] = '\0';
X	  strcpy(escape_sequence, buffer);
X	}
X
X	return( (char *) escape_sequence);
X}
X
Xtransmit_functions(newstate)
Xint newstate;
X{
X	/** turn function key transmission to ON | OFF **/
X
X	if (newstate != _intransmit) {
X		_intransmit = ! _intransmit;
X		if (newstate == ON)
X		  tputs(_transmit_on, 1, outchar);
X		else 
X		  tputs(_transmit_off, 1, outchar);
X		fflush(stdout);      /* clear the output buffer */
X	}
X}
X
X/****** now into the 'meat' of the routines...the cursor stuff ******/
X
XScreenSize(lines, columns)
Xint *lines, *columns;
X{
X	/** returns the number of lines and columns on the display. **/
X
X#ifdef TIOCGWINSZ
X	struct winsize w;
X
X	if (ioctl(1,TIOCGWINSZ,&w) != -1) {
X		if (w.ws_row > 0)
X			_lines = w.ws_row;
X		if (w.ws_col > 0)
X			_columns = w.ws_col;
X	}
X#endif
X
X	if (_lines == 0) _lines = DEFAULT_LINES_ON_TERMINAL;
X	if (_columns == 0) _columns = DEFAULT_COLUMNS_ON_TERMINAL;
X
X	*lines = _lines - 1;		/* assume index from zero */
X	*columns = _columns;
X}
X
XSetXYLocation(x,y)
Xint x,y;
X{
X	/* declare where the cursor is on the screen - useful after using
X	 * a function that moves cursor in predictable fasion but doesn't
X	 * set the static x and y variables used in this source file -
X	 * e.g. getpass().
X	 */
X
X	_line = x;
X	_col = y;
X}
X
XGetXYLocation(x,y)
Xint *x,*y;
X{
X	/* return the current cursor location on the screen */
X
X	*x = _line;
X	*y = _col;
X}
X
XClearScreen()
X{
X	/* clear the screen: returns -1 if not capable */
X
X	_line = 0;	/* clear leaves us at top... */
X	_col  = 0;
X
X	if (!_clearscreen)
X		return(-1);
X
X	tputs(_clearscreen, 1, outchar);
X	fflush(stdout);      /* clear the output buffer */
X	return(0);
X}
X
Xstatic
XCursorUp(n)
Xint n;
X{
X	/** move the cursor up 'n' lines **/
X	/** Calling function must check that _up is not null before calling **/
X
X	_line = (_line-n > 0? _line - n: 0);	/* up 'n' lines... */
X
X	while (n-- > 0)
X		tputs(_up, 1, outchar);
X
X	fflush(stdout);
X	return(0);
X}
X
X
Xstatic
XCursorDown(n)
Xint n;
X{
X	/** move the cursor down 'n' lines **/
X	/** Caller must check that _down is not null before calling **/
X
X	_line = (_line+n <= LINES? _line + n: LINES);    /* down 'n' lines... */
X
X	while (n-- > 0)
X		tputs(_down, 1, outchar);
X
X	fflush(stdout);
X	return(0);
X}
X
X
Xstatic
XCursorLeft(n)
Xint n;
X{
X	/** move the cursor 'n' characters to the left **/
X	/** Caller must check that _left is not null before calling **/
X
X	_col = (_col - n> 0? _col - n: 0);	/* left 'n' chars... */
X
X	while (n-- > 0)
X		tputs(_left, 1, outchar);
X
X	fflush(stdout);
X	return(0);
X}
X
X
Xstatic
XCursorRight(n)
Xint n;
X{
X	/** move the cursor 'n' characters to the right (nondestructive) **/
X	/** Caller must check that _right is not null before calling **/
X
X	_col = (_col+n < COLUMNS? _col + n: COLUMNS);	/* right 'n' chars... */
X
X	while (n-- > 0)
X		tputs(_right, 1, outchar);
X
X	fflush(stdout);
X	return(0);
X}
X
Xstatic
Xmoveabsolute(col, row)
X{
X
X	char *stuff, *tgoto();
X
X	stuff = tgoto(_moveto, col, row);
X	tputs(stuff, 1, outchar);
X	fflush(stdout);
X}
X
XMoveCursor(row, col)
Xint row, col;
X{
X	/** move cursor to the specified row column on the screen.
X            0,0 is the top left! **/
X
X	int scrollafter = 0;
X
X	/* we don't want to change "rows" or we'll mangle scrolling... */
X
X	if (col < 0)
X	  col = 0;
X	if (col >= COLUMNS)
X	  col = COLUMNS - 1;
X	if (row < 0)
X	  row = 0;
X	if (row > LINES) {
X	  if (col == 0)
X	    scrollafter = row - LINES;
X	  row = LINES;
X	}
X
X	if (!_moveto)
X		return(-1);
X
X	if (row == _line) {
X	  if (col == _col)
X	    return(0);				/* already there! */
X
X	  else if (abs(col - _col) < 5) {	/* within 5 spaces... */
X	    if (col > _col && _right)
X	      CursorRight(col - _col);
X	    else if (col < _col &&  _left)
X	      CursorLeft(_col - col);
X	    else
X	      moveabsolute(col, row);
X          }
X	  else 		/* move along to the new x,y loc */
X	    moveabsolute(col, row);
X	}
X	else if (_line == row-1 && col == 0) {
X	  if (_col != 0)
X	    putchar('\r');
X	  putchar('\n');
X	  fflush(stdout);
X	}
X	else if (col == _col && abs(row - _line) < 5) {
X	  if (row < _line && _up)
X	    CursorUp(_line - row);
X	  else if (row > _line && _down)
X	    CursorDown(row - _line);
X	  else
X	    moveabsolute(col, row);
X	}
X	else 
X	  moveabsolute(col, row);
X
X	_line = row;	/* to ensure we're really there... */
X	_col  = col;
X
X	if (scrollafter) {
X	  putchar('\r');
X	  while (scrollafter--)
X	    putchar('\n');
X	}
X
X	return(0);
X}
X
XCarriageReturn()
X{
X	/** move the cursor to the beginning of the current line **/
X	Writechar('\r');
X}
X
XNewLine()
X{
X	/** move the cursor to the beginning of the next line **/
X
X	Writechar('\r');
X	Writechar('\n');
X}
X
XStartBold()
X{
X	/** start boldface/standout mode **/
X
X	if (!_setbold)
X		return(-1);
X
X	tputs(_setbold, 1, outchar);
X	fflush(stdout);
X	return(0);
X}
X
X
XEndBold()
X{
X	/** compliment of startbold **/
X
X	if (!_clearbold)
X		return(-1);
X
X	tputs(_clearbold, 1, outchar);
X	fflush(stdout);
X	return(0);
X}
X
X#ifndef ELM
X
XStartUnderline()
X{
X	/** start underline mode **/
X
X	if (!_setunderline)
X		return(-1);
X
X	tputs(_setunderline, 1, outchar);
X	fflush(stdout);
X	return(0);
X}
X
X
XEndUnderline()
X{
X	/** the compliment of start underline mode **/
X
X	if (!_clearunderline)
X		return(-1);
X
X	tputs(_clearunderline, 1, outchar);
X	fflush(stdout);
X	return(0);
X}
X
X
XStartHalfbright()
X{
X	/** start half intensity mode **/
X
X	if (!_sethalfbright)
X		return(-1);
X
X	tputs(_sethalfbright, 1, outchar);
X	fflush(stdout);
X	return(0);
X}
X
XEndHalfbright()
X{
X	/** compliment of starthalfbright **/
X
X	if (!_clearhalfbright)
X		return(-1);
X
X	tputs(_clearhalfbright, 1, outchar);
X	fflush(stdout);
X	return(0);
X}
X
XStartInverse()
X{
X	/** set inverse video mode **/
X
X	if (!_setinverse)
X		return(-1);
X
X	tputs(_setinverse, 1, outchar);
X	fflush(stdout);
X	return(0);
X}
X
X
XEndInverse()
X{
X	/** compliment of startinverse **/
X
X	if (!_clearinverse)
X		return(-1);
X
X	tputs(_clearinverse, 1, outchar);
X	fflush(stdout);
X	return(0);
X}
X
Xint
XHasMemlock()
X{
X	/** returns TRUE iff memory locking is available (a terminal
X	    feature that allows a specified portion of the screen to
X	    be "locked" & not cleared/scrolled... **/
X
X	return ( _set_memlock && _clear_memlock );
X}
X
Xstatic int _old_LINES;
X
Xint
XStartMemlock()
X{
X	/** mark the current line as the "last" line of the portion to 
X	    be memory locked (always relative to the top line of the
X	    screen) Note that this will alter LINES so that it knows
X	    the top is locked.  This means that (plus) the program 
X	    will scroll nicely but (minus) End memlock MUST be called
X	    whenever we leave the locked-memory part of the program! **/
X
X	if (! _set_memlock)
X	  return(-1);
X
X	if (! _memory_locked) {
X
X	  _old_LINES = LINES;
X	  LINES -= _line;		/* we can't use this for scrolling */
X
X	  tputs(_set_memlock, 1, outchar);
X	  fflush(stdout);
X	  _memory_locked = TRUE;
X	}
X
X	return(0);
X}
X
Xint
XEndMemlock()
X{
X	/** Clear the locked memory condition...  **/
X
X	if (! _set_memlock)
X	  return(-1);
X
X	if (_memory_locked) {
X	  LINES = _old_LINES;		/* back to old setting */
X  
X	  tputs(_clear_memlock, 1, outchar);
X	  fflush(stdout);
X	  _memory_locked = FALSE;
X	}
X	return(0);
X}
X
X#endif /* ndef ELM */
X
XWritechar(ch)
Xregister int ch;
X{
X	/** write a character to the current screen location. **/
X
X	static int wrappedlastchar = 0;
X	int justwrapped, nt;
X
X	ch &= 0xFF;
X	justwrapped = 0;
X
X	/* if return, just go to left column. */
X	if(ch == '\r') {
X	  if (wrappedlastchar)
X	    justwrapped = 1;                /* preserve wrap flag */
X	  else {
X	    putchar('\r');
X	    _col = 0;
X	  }
X	}
X
X	/* if newline and terminal just did a newline without our asking,
X	 * do nothing, else output a newline and increment the line count */
X	else if (ch == '\n') {
X	  if (!wrappedlastchar) {
X	    putchar('\n');
X	    if (_line < LINES)
X	      ++_line;
X	  }
X	}
X
X	/* if backspace, move back  one space  if not already in column 0 */
X	else if (ch == BACKSPACE) {
X	  if(_col != 0) {
X	    putchar('\b');
X	    _col--;
X	  } /* else BACKSPACE does nothing */
X	}
X
X	/* if bell, ring the bell but don't advance the column */
X	else if (ch == '\007') {
X	  putchar(ch);
X	}
X
X	/* if a tab, output it */
X	else if (ch == '\t') {
X	  putchar(ch);
X	  if((nt=next_tab(_col+1)) > prev_tab(COLUMNS))
X	    _col = COLUMNS-1;
X	  else
X	    _col = nt-1;
X	}
X
X	else {
X	  /* if some kind of non-printable character change to a '?' */
X#ifdef ASCII_CTYPE
X	  if(!isascii(ch) || !isprint(ch))
X#else
X	  if(!isprint(ch))
X#endif
X	    ch = '?';
X
X	  /* if we only have one column left, simulate automargins if
X	   * the terminal doesn't have them */
X	  if (_col == COLUMNS - 1) {
X	    putchar(ch);
X	    if (!_automargin || _eatnewlineglitch) {
X	      putchar('\r');
X	      putchar('\n');
X	    }
X	    if (_line < LINES)
X	      ++_line;
X	    _col = 0;
X	    justwrapped = 1;
X	  }
X
X	  /* if we are here this means we have no interference from the
X	   * right margin - just output the character and increment the
X	   * column position. */
X	  else {
X	    putchar(ch);
X	    _col++;
X	  }
X	}
X
X	wrappedlastchar = justwrapped;
X
X	return(0);
X}
X
X/*VARARGS2*/
X
XWrite_to_screen(line, argcount, arg1, arg2, arg3)
Xchar *line;
Xint   argcount; 
Xchar *arg1, *arg2, *arg3;
X{
X	/** This routine writes to the screen at the current location.
X  	    when done, it increments lines & columns accordingly by
X	    looking for "\n" sequences... **/
X
X	switch (argcount) {
X	case 0 :
X		PutLine0(_line, _col, line);
X		break;
X	case 1 :
X		PutLine1(_line, _col, line, arg1);
X		break;
X	case 2 :
X		PutLine2(_line, _col, line, arg1, arg2);
X		break;
X	case 3 :
X		PutLine3(_line, _col, line, arg1, arg2, arg3);
X		break;
X	}
X}
X
XPutLine0(x, y, line)
Xint x,y;
Xregister char *line;
X{
X	/** Write a zero argument line at location x,y **/
X
X	MoveCursor(x,y);
X	while(*line)
X	  Writechar(*line++);
X	fflush(stdout);
X}
X
X/*VARARGS2*/
XPutLine1(x,y, line, arg1)
Xint x,y;
Xchar *line;
Xchar *arg1;
X{
X	/** write line at location x,y - one argument... **/
X
X	char buffer[VERY_LONG_STRING];
X
X	sprintf(buffer, line, arg1);
X
X	PutLine0(x, y, buffer);
X        fflush(stdout);
X}
X
X/*VARARGS2*/
XPutLine2(x,y, line, arg1, arg2)
Xint x,y;
Xchar *line;
Xchar *arg1, *arg2;
X{
X	/** write line at location x,y - one argument... **/
X
X	char buffer[VERY_LONG_STRING];
X
X	sprintf(buffer, line, arg1, arg2);
X
X	PutLine0(x, y, buffer);
X        fflush(stdout);
X}
X
X/*VARARGS2*/
XPutLine3(x,y, line, arg1, arg2, arg3)
Xint x,y;
Xchar *line;
Xchar *arg1, *arg2, *arg3;
X{
X	/** write line at location x,y - one argument... **/
X
X	char buffer[VERY_LONG_STRING];
X
X	sprintf(buffer, line, arg1, arg2, arg3);
X
X	PutLine0(x, y, buffer);
X        fflush(stdout);
X}
X
XCleartoEOLN()
X{
X	/** clear to end of line **/
X
X	if (!_cleartoeoln)
X		return(-1);
X
X	tputs(_cleartoeoln, 1, outchar);
X	fflush(stdout);  /* clear the output buffer */
X	return(0);
X}
X
XCleartoEOS()
X{
X	/** clear to end of screen **/
X
X	if (!_cleartoeos)
X		return(-1);
X
X	tputs(_cleartoeos, 1, outchar);
X	fflush(stdout);  /* clear the output buffer */
X	return(0);
X}
X
X
XRawState()
X{
X	/** returns either 1 or 0, for ON or OFF **/
X
X	return( _inraw );
X}
X
XRaw(state)
Xint state;
X{
X	/** state is either ON or OFF, as indicated by call **/
X
X	if (state == OFF && _inraw) {
X	  (void) ttsetattr(TTYIN,&_original_tty);
X	  _inraw = 0;
X	}
X	else if (state == ON && ! _inraw) {
X
X	  (void) ttgetattr(TTYIN, &_original_tty);
X	  (void) ttgetattr(TTYIN, &_raw_tty);    /** again! **/
X
X#if !defined(TERMIO) && !defined(TERMIOS)
X	  _raw_tty.sg_flags &= ~(ECHO);	/* echo off */
X	  _raw_tty.sg_flags |= CBREAK;	/* raw on    */
X#else
X	  _raw_tty.c_lflag &= ~(ICANON | ECHO);	/* noecho raw mode        */
X
X	  _raw_tty.c_cc[VMIN] = '\01';	/* minimum # of chars to queue    */
X	  _raw_tty.c_cc[VTIME] = '\0';	/* minimum time to wait for input */
X
X#endif
X	  (void) ttsetattr(TTYIN, &_raw_tty);
X	  _inraw = 1;
X	}
X}
X
Xint
XReadCh()
X{
X	/** read a character with Raw mode set! **/
X
X	register int result;
X	char ch;
X	result = read(0, &ch, 1);
X        return((result <= 0 ) ? EOF : ch);
X}
X
Xoutchar(c)
Xchar c;
X{
X	/** output the given character.  From tputs... **/
X	/** Note: this CANNOT be a macro!              **/
X
X	putc(c, stdout);
X}
X
SHAR_EOF
# ============= src/date.c ==============
echo "x - extracting src/date.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/date.c &&
X
Xstatic char rcsid[] = "@(#)$Id: date.c,v 4.1 90/04/28 22:42:41 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:	date.c,v $
X * Revision 4.1  90/04/28  22:42:41  syd
X * checkin of Elm 2.3 as of Release PL0
X * 
X *
X ******************************************************************************/
X
X/** return the current date and time in a readable format! **/
X/** also returns an ARPA RFC-822 format date...            **/
X
X
X#include "headers.h"
X
X#ifdef I_TIME
X#  include <time.h>
X#endif
X#ifdef I_SYSTIME
X#  include <sys/time.h>
X#endif
X#ifdef BSD
X#  include <sys/types.h>
X#  include <sys/timeb.h>
X#endif
X
X#include <ctype.h>
X
X#ifndef	_POSIX_SOURCE
Xextern struct tm *localtime();
Xextern long	  time();
X#endif
X
X#ifdef BSD
X#undef toupper
X#undef tolower
X#endif
X
X#define MONTHS_IN_YEAR	11	/* 0-11 equals 12 months! */
X#define FEB		 1	/* 0 = January 		  */
X#define DAYS_IN_LEAP_FEB 29	/* leap year only 	  */
X
X#define ampm(n)		(n > 12? n - 12 : n)
X#define am_or_pm(n)	(n > 11? (n > 23? "am" : "pm") : "am")
X#define leapyear(year)	((year % 4 == 0) && (year % 100 != 0))
X
Xchar *arpa_dayname[] = { "Sun", "Mon", "Tue", "Wed", "Thu",
X		  "Fri", "Sat", "" };
X
Xchar *arpa_monname[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
X		  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""};
X
Xint  days_in_month[] = { 31,    28,    31,    30,    31,     30, 
X		  31,     31,    30,   31,    30,     31,  -1};
X
X#ifdef BSD
X  char *timezone();
X#else
X  extern char *tzname[];
X#endif
X
Xchar *get_arpa_date()
X{
X	/** returns an ARPA standard date.  The format for the date
X	    according to DARPA document RFC-822 is exemplified by;
X
X	       	      Mon, 12 Aug 85 6:29:08 MST
X
X	**/
X
X	static char buffer[SLEN];	/* static character buffer       */
X	struct tm *the_time;		/* Time structure, see CTIME(3C) */
X	long	   junk;		/* time in seconds....		 */
X
X#ifdef BSD
X# ifndef TZ_MINUTESWEST
X	struct timeb	loc_time;
X
X	junk = time((long *) 0);
X	ftime(&loc_time);
X# else
X	struct  timeval  time_val;		
X	struct  timezone time_zone;
X
X	gettimeofday(&time_val, &time_zone);
X	junk = time_val.tv_sec;
X# endif
X
X#else
X	junk = time((long *) 0);	/* this must be here for it to work! */
X#endif
X
X	the_time = localtime(&junk);
X
X	sprintf(buffer, "%s, %d %s %d %d:%02d:%02d %s",
X	  arpa_dayname[the_time->tm_wday],
X	  the_time->tm_mday % 32,
X	  arpa_monname[the_time->tm_mon],
X	  the_time->tm_year % 100,
X	  the_time->tm_hour % 24,
X	  the_time->tm_min  % 61,
X	  the_time->tm_sec  % 61,
X#ifdef BSD
X#ifdef TZ_MINUTESWEST
X# ifdef GOULD_NP1
X	  the_time->tm_zone);
X# else
X	  timezone(time_zone.tz_minuteswest, the_time->tm_isdst));
X# endif
X#else
X	  timezone(loc_time.timezone, the_time->tm_isdst));
X#endif
X#else
X	  tzname[the_time->tm_isdst]);
X#endif
X	
X	return( (char *) buffer);
X}
X
Xdays_ahead(days, buffer)
Xint days;
Xchar *buffer;
X{
X	/** return in buffer the date (Day, Mon Day, Year) of the date
X	    'days' days after today.  
X	**/
X
X	struct tm *the_time;		/* Time structure, see CTIME(3C) */
X	long	   junk;		/* time in seconds....		 */
X
X	junk = time((long *) 0);	/* this must be here for it to work! */
X	the_time = localtime(&junk);
X
X	/* increment the day of the week */
X
X	the_time->tm_wday = (the_time->tm_wday + days) % 7;
X
X	/* the day of the month... */
X	the_time->tm_mday += days;
X	
X        while (the_time->tm_mday > days_in_month[the_time->tm_mon]) {
X          if (the_time->tm_mon == FEB && leapyear(the_time->tm_year)) {
X            if (the_time->tm_mday > DAYS_IN_LEAP_FEB) {
X              the_time->tm_mday -= DAYS_IN_LEAP_FEB;
X              the_time->tm_mon += 1;
X            }
X            else
X              break;            /* Is Feb 29, so leave */
X          }
X          else {
X            the_time->tm_mday -= days_in_month[the_time->tm_mon];
X            the_time->tm_mon += 1;
X          }
X
X          /* check the month of the year */
X          if (the_time->tm_mon > MONTHS_IN_YEAR) {
X            the_time->tm_mon -= (MONTHS_IN_YEAR + 1);
X            the_time->tm_year += 1;
X          }
X        }
X  
X        /* now, finally, build the actual date string */
X
X	sprintf(buffer, "%s, %d %s %d",
X	  arpa_dayname[the_time->tm_wday],
X	  the_time->tm_mday % 32,
X	  arpa_monname[the_time->tm_mon],
X	  the_time->tm_year % 100);
X}
X
Xfix_date(entry)
Xstruct header_rec *entry;
X{
X	/** This routine will 'fix' the date entry for the specified
X	    message.  This consists of 1) adjusting the year to 0-99
X	    and 2) altering time from HH:MM:SS to HH:MM am|pm **/ 
X
X	if (atoi(entry->year) > 99) 	
X	  sprintf(entry->year,"%d", atoi(entry->year) - 1900);
X
X	fix_time(entry->time);
X}
X
Xfix_time(timestring)
Xchar *timestring;
X{
X	/** Timestring in format HH:MM:SS (24 hour time).  This routine
X	    will fix it to display as: HH:MM [am|pm] **/
X
X	int hour, minute;
X
X	sscanf(timestring, "%d:%d", &hour, &minute);
X
X	if (hour < 1 || hour == 24) 
X	  sprintf(timestring, "12:%02d am", minute);
X	else if (hour < 12)
X	  sprintf(timestring, "%d:%02d am", hour, minute);
X	else if (hour == 12)
X	  sprintf(timestring, "12:%02d pm", minute);
X	else if (hour < 24)
X	  sprintf(timestring, "%d:%02d pm", hour-12, minute);
X}
X
Xint
Xcompare_parsed_dates(rec1, rec2)
Xstruct date_rec rec1, rec2;
X{
X	/** This function is very similar to the compare_dates
X	    function but assumes that the two record structures
X	    are already parsed and stored in "date_rec" format.
X	**/
X
X	if (rec1.year != rec2.year)
X	  return( rec1.year - rec2.year );
X	
X	if (rec1.month != rec2.month)
X	  return( rec1.month - rec2.month );
X
X	if (rec1.day != rec2.day)
X	  return( rec1.day - rec2.day );
X
X	if (rec1.hour != rec2.hour)
X	  return( rec1.hour - rec2.hour );
X
X	return( rec1.minute - rec2.minute );		/* ignore seconds... */
X}
X
Xint
Xmonth_number(name)
Xchar *name;
X{
X	/** return the month number given the month name... **/
X
X	char ch;
X
X	switch (tolower(name[0])) {
X	 case 'a' : if ((ch = tolower(name[1])) == 'p')	return(APRIL);
X		    else if (ch == 'u') return(AUGUST);
X		    else return(-1);	/* error! */
X	
X	 case 'd' : return(DECEMBER);
X	 case 'f' : return(FEBRUARY);
X	 case 'j' : if ((ch = tolower(name[1])) == 'a') return(JANUARY);
X		    else if (ch == 'u') {
X	              if ((ch = tolower(name[2])) == 'n') return(JUNE);
X		      else if (ch == 'l') return(JULY);
X		      else return(-1);		/* error! */
X	            }
X		    else return(-1);		/* error */
X	 case 'm' : if ((ch = tolower(name[2])) == 'r') return(MARCH);
X		    else if (ch == 'y') return(MAY);
X		    else return(-1);		/* error! */
X	 case 'n' : return(NOVEMBER);
X	 case 'o' : return(OCTOBER);
X	 case 's' : return(SEPTEMBER);
X	 default  : return(-1);
X	}
X}
X
X#ifdef SITE_HIDING
X
Xchar *get_ctime_date()
X{
X	/** returns a ctime() format date, but a few minutes in the 
X	    past...(more cunningness to implement hidden sites) **/
X
X	static char buffer[SLEN];	/* static character buffer       */
X	struct tm *the_time;		/* Time structure, see CTIME(3C) */
X	long	   junk;		/* time in seconds....		 */
X
X#ifdef BSD
X	struct  timeval  time_val;		
X	struct  timezone time_zone;
X#endif
X
X#ifdef BSD
X	gettimeofday(&time_val, &time_zone);
X	junk = time_val.tv_sec;
X#else
X	junk = time((long *) 0);	/* this must be here for it to work! */
X#endif
X	the_time = localtime(&junk);
X
X	sprintf(buffer, "%s %s %d %02d:%02d:%02d %d",
X	  arpa_dayname[the_time->tm_wday],
X	  arpa_monname[the_time->tm_mon],
X	  the_time->tm_mday % 32,
X	  min(the_time->tm_hour % 24, (rand() % 24)),
X	  min(abs(the_time->tm_min  % 61 - (rand() % 60)), (rand() % 60)),
X	  min(abs(the_time->tm_sec  % 61 - (rand() % 60)), (rand() % 60)),
X	  the_time->tm_year % 100 + 1900);
X	
X	return( (char *) buffer);
X}
X
X#endif
SHAR_EOF
# ============= src/delete.c ==============
echo "x - extracting src/delete.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/delete.c &&
X
Xstatic char rcsid[] = "@(#)$Id: delete.c,v 4.1 90/04/28 22:42:43 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:	delete.c,v $
X * Revision 4.1  90/04/28  22:42:43  syd
X * checkin of Elm 2.3 as of Release PL0
X * 
X *
X ******************************************************************************/
X
X/**  Delete or undelete files: just set flag in header record! 
X     Also tags specified message(s)...
X
X**/
X
X#include "headers.h"
X
Xchar *show_status();
X
Xdelete_msg(real_del, update_screen)
Xint real_del, update_screen;
X{
X	/** Delete current message.  If real-del is false, then we're
X	    actually requested to toggle the state of the current
X	    message... **/
X
X	if (real_del)
X	  headers[current-1]->status |= DELETED;
X	else if (ison(headers[current-1]->status, DELETED))
X	  clearit(headers[current-1]->status, DELETED);
X	else
X	  setit(headers[current-1]->status, DELETED);
X
X	if (update_screen)
X	  show_msg_status(current-1);
X}
X
Xundelete_msg(update_screen)
Xint update_screen;
X{
X	/** clear the deleted message flag **/
X
X	clearit(headers[current-1]->status, DELETED);
X
X	if (update_screen)
X	  show_msg_status(current-1);
X}
X
Xshow_msg_status(msg)
Xint msg;
X{
X	/** show the status of the current message only.  **/
X
X	char tempbuf[3];
X
X	strcpy(tempbuf, show_status(headers[msg]->status));
X
X	if (on_page(msg)) {
X	  MoveCursor(((compute_visible(msg+1)-1) % headers_per_page) + 4, 2);
X	  if (msg+1 == current && !arrow_cursor) {
X	    StartBold();
X	    Writechar( tempbuf[0] );
X	    EndBold();
X	  }
X	  else
X	    Writechar( tempbuf[0] );
X	}
X}
X
Xint
Xtag_message(update_screen)
Xint update_screen;
X{
X	/** Tag current message and return TRUE.
X	    If already tagged, untag it and return FALSE. **/
X
X	int istagged;
X
X	if (ison(headers[current-1]->status, TAGGED)) {
X	  clearit(headers[current-1]->status, TAGGED);
X	  istagged = FALSE;
X	} else {
X	  setit(headers[current-1]->status, TAGGED);
X	  istagged = TRUE;
X	}
X
X	if(update_screen)
X	    show_msg_tag(current-1);
X	return(istagged);
X}
X
Xshow_msg_tag(msg)
Xint msg;
X{
X	/** show the tag status of the current message only.  **/
X
X	if (on_page(msg)) {
X	  MoveCursor(((compute_visible(msg+1)-1) % headers_per_page) + 4, 4);
X	  if (msg+1 == current && !arrow_cursor) {
X	    StartBold();
X	    Writechar( ison(headers[msg]->status, TAGGED)? '+' : ' ');
X	    EndBold();
X	  }
X	  else
X	    Writechar( ison(headers[msg]->status, TAGGED)? '+' : ' ');
X	}	
X}
X
Xshow_new_status(msg)
Xint msg;
X{
X	/** If the specified message is on this screen, show
X	    the new status (could be marked for deletion now,
X	    and could have tag removed...)
X	**/
X
X	if (on_page(msg)) 
X	  if (msg+1 == current && !arrow_cursor) {
X	    StartBold();
X	    PutLine2(((compute_visible(msg+1)-1) % headers_per_page) + 4,
X		   2, "%s%c", show_status(headers[msg]->status),
X		   ison(headers[msg]->status, TAGGED )? '+' : ' ');
X	    EndBold();
X	  }
X	  else
X	    PutLine2(((compute_visible(msg+1)-1) % headers_per_page) + 4,
X		   2, "%s%c", show_status(headers[msg]->status),
X		   ison(headers[msg]->status, TAGGED )? '+' : ' ');
X}
SHAR_EOF
# ============= src/domains.c ==============
echo "x - extracting src/domains.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > src/domains.c &&
X
Xstatic char rcsid[] = "@(#)$Id: domains.c,v 4.1.1.1 90/07/12 23:19:14 syd Exp $";
X
X/*******************************************************************************
X *  The Elm Mail System  -  $Revision: 4.1.1.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:	domains.c,v $
X * Revision 4.1.1.1  90/07/12  23:19:14  syd
X * Make domain name checking case independent
X * From: Syd, reported by Steven Baur
X * 
X * Revision 4.1  90/04/28  22:42:44  syd
X * checkin of Elm 2.3 as of Release PL0
X * 
X *
X ******************************************************************************/
X
X/** This file contains all the code dealing with the expansion of 
X    domain based addresses in Elm.  It uses the file "domains" as
X    defined in the sysdefs.h file.
X
X    From a file format and idea in "uumail" - designed by Stan Barber.
X**/
X
X#if defined(OPTIMIZE_RETURN) || !defined(DONT_TOUCH_ADDRESSES)
X
X#include <ctype.h>
X
X#include "headers.h"
X
X#ifdef BSD
X# undef toupper
X# undef tolower
X#endif
X
X/** define the various characters that we can encounter after a "%" sign
X    in the template file...
X**/
X
X#define USERNAME	'U'	/* %U = the name of the remote user */
X#define RMTMNAME	'N'	/* %N = the remote machine name     */
X#define FULLNAME	'D'	/* %D = %N + domain info given      */
X#define NPATH		'R'	/* %R = path to %N from pathalias   */
X#define PPATH		'P'	/* %P = path to 'P' from pathalias  */
X#define OBSOLETE	'S'	/* %S = (used to be suffix string)  */
X
X/** and finally some characters that are allowed in user/machine names **/
X
X#define okay_others(c)	(c == '-' || c == '^' || c == '$' || c == '_')
X
X/** and some allowed ONLY in the username field **/
X
X#define special_chars(c)	(c == '%' || c == ':')
X
Xchar *find_path_to(), *expand_domain(), *match_and_expand_domain();
Xchar *strcpy(), *strcat(), *strtok();
Xvoid rewind();
X	      
Xopen_domain_file()
X{
X	if ((domainfd = fopen(domains, "r")) == NULL) {
X	  dprint(2, (debugfile,"Warning: can't open file %s as domains file\n", 
X		domains));
X	}
X	else {
X	  dprint(3, (debugfile, 
X            "Opened '%s' as the domain database\n\n", domains));
X	}
X	
X	/* if it fails it'll instantiate domainfd to NULL which is
X	   exactly what we want to have happen!! */
X}
X
Xchar *expand_domain(buffer)
Xchar *buffer;
X{
X	/** Expand the address 'buffer' based on the domain information, 
X	    if any.  Returns NULL if it can't expand it for any reason.
X	**/
X
X	char name[NLEN], address[NLEN], domain[NLEN];
X	char *match_and_expand_domain();
X
X	if (domainfd == NULL) return(NULL);	/* no file present! */
X
X	if (explode(buffer, name, address, domain)) 
X	  return( match_and_expand_domain(domain, name, address) );
X	else {	/* invalid format - not "user@host.domain" */
X	  dprint(2,  (debugfile,
X		 "Invalid format for domain expansion: %s (expand_domain)\n", 
X		   buffer));
X	  return(NULL);
X	}
X}	
X
Xint
Xexplode(buffer, name, address, domain)
Xchar *buffer, *name, *address, *domain;
X{
X	/** Break buffer, if in format name@machine.domain, into the
X	    component parts, otherwise return ZERO and don't worry
X	    about the values of the parameters!
X	**/
X	
X	register int i, j = 0;
X
X	/** First get the name... **/
X
X	for (i=0; buffer[i] != '@'; i++) {
X	  if (! isalnum(buffer[i]) && ! okay_others(buffer[i]) && ! 
X		special_chars(buffer[i]))
X	    return(0);			/* invalid character in string! */
X	  name[i] = buffer[i];
X	}
X
X	name[i++] = '\0';
X
X	/** now let's get the machinename **/
X
X	while (buffer[i] != '.') {
X	  if (! isalnum(buffer[i]) && ! okay_others(buffer[i]))
X	     return(0);			/* invalid character in string! */
X	  address[j++] = buffer[i++];
X	}
X	address[j] = '\0';
X
X	j = 0;
X
X	/** finally let's get the domain information (there better be some!) **/
X
X	while (buffer[i] != '\0') {
X	  if (! isalnum(buffer[i]) && ! okay_others(buffer[i]) && 
X	        buffer[i] != '.')
X	    return(0);		      /* an you fail again, bozo! */
X	  domain[j++] = toupper(buffer[i]);
X	  i++;
X	}
X
X	domain[j] = '\0';
X	
X	return(j);		/* if j == 0 there's no domain info! */
SHAR_EOF
echo "End of  part 10"
echo "File src/domains.c is continued in part 11"
echo "11" > shar3_seq_.tmp
exit 0
Newsgroups: biz.sco.sources