#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	./c-client/makefile.s53
#	./c-client/os_s53.c
#	./c-client/os_s53.h
#	./pico/Makefile.s53
#	./pine/makefile.s53
#	./pine/os-s53.c
#	./pine/os-s53.h
#	./regexp/Makefile
# This archive created: Mon Apr 27 22:49:35 1992
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f './c-client/makefile.s53'
then
	echo shar: "will not over-write existing file './c-client/makefile.s53'"
else
cat << \SHAR_EOF > './c-client/makefile.s53'
# Program:	Portable C client makefile -- Dynix version
#
# Author:	Mark Crispin
#		Networks and Distributed Computing
#		Computing & Communications
#		University of Washington
#		Administration Building, AG-44
#		Seattle, WA  98195
#		Internet: MRC@CAC.Washington.EDU
#
# Date:		11 May 1989
# Last Edited:	9 January 1992
#
# Copyright 1992 by the University of Washington
#
#  Permission to use, copy, modify, and distribute this software and its
# documentation for any purpose and without fee is hereby granted, provided
# that the above copyright notice appears in all copies and that both the
# above copyright notice and this permission notice appear in supporting
# documentation, and that the name of the University of Washington not be
# used in advertising or publicity pertaining to distribution of the software
# without specific, written prior permission.  This software is made
# available "as is", and
# THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
# WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
# NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
# INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
# (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.


OPTIMIZE=	-O
DEBUG=		-g -DDEBUG
#PROFILE=	-p
REGEXPINC=	-I../regexp

CFLAGS=		-D_SYSV3 $(OPTIMIZE) $(REGEXPINC) $(DEBUG) $(PROFILE)

CLIB=		c-client.a
LIBS=		../regexp/libregexp.a -linet -lcposix
LDFLAGS=	$(PROFILE) $(LIBS)

mtest: mtest.o c-client.a
	echo $(CFLAGS) > CFLAGS
	echo $(LDFLAGS) > LDFLAGS
	$(CC) $(CFLAGS) -o mtest mtest.o c-client.a $(LDFLAGS)

clean:
	rm -f *.o mtest c-client.a osdep.* CFLAGS LDFLAGS

mtest.o: mail.h smtp.h misc.h osdep.h

$(CLIB):			\
	$(CLIB)(mail.o)		\
	$(CLIB)(bezerk.o)	\
	$(CLIB)(tenex.o)	\
	$(CLIB)(imap2.o)	\
	$(CLIB)(news.o)		\
	$(CLIB)(dummy.o)	\
	$(CLIB)(smtp.o)		\
	$(CLIB)(rfc822.o)	\
	$(CLIB)(misc.o)		\
	$(CLIB)(os_s53.o)

mail.o: mail.h misc.h osdep.h

bezerk.o: mail.h bezerk.h rfc822.h misc.h osdep.h

tenex.o: mail.h tenex.h rfc822.h misc.h osdep.h

imap2.o: mail.h imap2.h misc.h osdep.h

news.o: mail.h news.h misc.h osdep.h

dummy.o: mail.h dummy.h misc.h osdep.h

smtp.o: mail.h smtp.h rfc822.h misc.h osdep.h

rfc822.o: mail.h rfc822.h misc.h

misc.o: mail.h misc.h osdep.h

osdep.o: mail.h osdep.h os_s53.c
	$(CC) $(CFLAGS) -c os_s53.c
	mv os_s53.o osdep.o

osdep.h: os_s53.h
	rm -f osdep.h
	ln os_s53.h osdep.h

# A monument to a hack of long ago and far away...
love:
	@echo 'not war?'
SHAR_EOF
if test 2740 -ne "`wc -c < './c-client/makefile.s53'`"
then
	echo shar: "error transmitting './c-client/makefile.s53'" '(should have been 2740 characters)'
fi
chmod 644 './c-client/makefile.s53'
fi
if test -f './c-client/os_s53.c'
then
	echo shar: "will not over-write existing file './c-client/os_s53.c'"
else
cat << \SHAR_EOF > './c-client/os_s53.c'
/*
 * Program:	Operating-system dependent routines -- Dynix version
 *
 * Author:	Mark Crispin
 *		Networks and Distributed Computing
 *		Computing & Communications
 *		University of Washington
 *		Administration Building, AG-44
 *		Seattle, WA  98195
 *		Internet: MRC@CAC.Washington.EDU
 *
 * Date:	1 August 1988
 * Last Edited:	7 January 1992
 *
 * Sponsorship:	The original version of this work was developed in the
 *		Symbolic Systems Resources Group of the Knowledge Systems
 *		Laboratory at Stanford University in 1987-88, and was funded
 *		by the Biomedical Research Technology Program of the National
 *		Institutes of Health under grant number RR-00785.
 *
 * Original version Copyright 1988 by The Leland Stanford Junior University.
 * Copyright 1992 by the University of Washington.
 *
 *  Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose and without fee is hereby granted, provided
 * that the above copyright notices appear in all copies and that both the
 * above copyright notices and this permission notice appear in supporting
 * documentation, and that the name of the University of Washington or The
 * Leland Stanford Junior University not be used in advertising or publicity
 * pertaining to distribution of the software without specific, written prior
 * permission.  This software is made available "as is", and
 * THE UNIVERSITY OF WASHINGTON AND THE LELAND STANFORD JUNIOR UNIVERSITY
 * DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD TO THIS SOFTWARE,
 * INCLUDING WITHOUT LIMITATION ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE, AND IN NO EVENT SHALL THE UNIVERSITY OF
 * WASHINGTON OR THE LELAND STANFORD JUNIOR UNIVERSITY BE LIABLE FOR ANY
 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
 * CONTRACT, TORT (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

/* TCP input buffer */

#define BUFLEN 8192


/* TCP I/O stream (must be before osdep.h is included) */

#define TCPSTREAM struct tcp_stream
TCPSTREAM {
  char *host;			/* host name */
  char *localhost;		/* local host name */
  int tcpsi;			/* input socket */
  int tcpso;			/* output socket */
  int ictr;			/* input counter */
  char *iptr;			/* input pointer */
  char ibuf[BUFLEN];		/* input buffer */
};


#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <string.h>
#include <ctype.h>
#include <sys/time.h>
#ifdef	_SYSV3
#include <time.h>
#endif
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <ctype.h>
#include <errno.h>
extern int errno;		/* just in case */
#include <pwd.h>
#include <syslog.h>
#include "osdep.h"
#include "mail.h"
#include "misc.h"

#ifndef	_SYSV3
extern char *timezone  ();
#endif
extern int sys_nerr;
extern char *sys_errlist[];

#define toint(c)	((c)-'0')
#define isodigit(c)	(((unsigned)(c)>=060)&((unsigned)(c)<=067))

/* Write current time in RFC 822 format
 * Accepts: destination string
 */

char *days[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};

void rfc822_date (date)
	char *date;
{
  int zone;
  char *zonename;
  struct tm *t;
  struct timeval tv;
  struct timezone tz;
  gettimeofday (&tv,&tz);	/* get time and timezone poop */
  t = localtime (&tv.tv_sec);	/* convert to individual items */
				/* use this for older systems */
  zone = (t->tm_isdst ? 60 : 0) -tz.tz_minuteswest;
#ifdef	_SYSV3
  zonename = tzname[t->tm_isdst != 0];
#else
  zonename = timezone (tz.tz_minuteswest,t->tm_isdst);
#endif
				/* and output it */
  sprintf (date,"%s, %d %s %d %02d:%02d:%02d %+03d%02d (%s)",
	   days[t->tm_wday],t->tm_mday,months[t->tm_mon],t->tm_year+1900,
	   t->tm_hour,t->tm_min,t->tm_sec,zone/60,abs (zone) % 60,zonename);
}

/* Get a block of free storage
 * Accepts: size of desired block
 * Returns: free storage block
 */

void *fs_get (size)
	size_t size;
{
  void *block = malloc (size);
  if (!block) fatal ("Out of free storage");
  return (block);
}


/* Resize a block of free storage
 * Accepts: ** pointer to current block
 *	    new size
 */

void fs_resize (block,size)
	void **block;
	size_t size;
{
  if (!(*block = realloc (*block,size))) fatal ("Can't resize free storage");
}


/* Return a block of free storage
 * Accepts: ** pointer to free storage block
 */

void fs_give (block)
	void **block;
{
  free (*block);
  *block = NIL;
}


/* Report a fatal error
 * Accepts: string to output
 */

void fatal (string)
	char *string;
{
  mm_fatal (string);		/* output the string */
  syslog (LOG_ALERT,"IMAP C-Client crash: %s",string);
  abort ();			/* die horribly */
}

/* Copy string with CRLF newlines
 * Accepts: destination string
 *	    pointer to size of destination string
 *	    source string
 *	    length of source string
 */

char *strcrlfcpy (dst,dstl,src,srcl)
	char **dst;
	unsigned long *dstl;
	char *src;
	unsigned long srcl;
{
  long i,j;
  char *d = src;
				/* count number of LF's in source string(s) */
  for (i = srcl,j = 0; j < srcl; j++) if (*d++ == '\012') i++;
				/* resize if not enough space */
  if (i > *dstl) fs_resize ((void **) dst,(*dstl = i) + 1);
  d = *dst;			/* destination string */
				/* copy strings, inserting CR's before LF's */
  while (srcl--) switch (*src) {
  case '\015':			/* unlikely carriage return */
    *d++ = *src++;		/* copy it and any succeeding linefeed */
    if (srcl && *src == '\012') {
      *d++ = *src++;
      srcl--;
    }
    break;
  case '\012':			/* line feed? */
    *d++ ='\015';		/* yes, prepend a CR, drop into default case */
  default:			/* ordinary chararacter */
    *d++ = *src++;		/* just copy character */
    break;
  }
  *d = '\0';			/* tie off destination */
  return *dst;			/* return destination */
}


/* Length of string after strcrlflen applied
 * Accepts: source string
 *	    length of source string
 */

unsigned long strcrlflen (src,srcl)
	char *src;
	unsigned long srcl;
{
  long i = srcl;		/* look for LF's */
  while (srcl--) switch (*src++) {
  case '\015':			/* unlikely carriage return */
    if (srcl && *src == '\012') { src++; srcl--; }
    break;
  case '\012':			/* line feed? */
    i++;
  default:			/* ordinary chararacter */
    break;
  }
  return i;
}

/* Server log in
 * Accepts: user name string
 *	    password string
 *	    optional place to return home directory
 * Returns: T if password validated, NIL otherwise
 */

int server_login (user,pass,home)
	char *user;
	char *pass;
	char **home;
{
  struct passwd *pw = getpwnam (lcase (user));
				/* no entry for this user or root */
  if (!(pw && pw->pw_uid)) return NIL;
				/* validate password */
  if (strcmp (pw->pw_passwd,(char *) crypt (pass,pw->pw_passwd))) return NIL;
  setgid (pw->pw_gid);		/* all OK, login in as that user */
  setuid (pw->pw_uid);
				/* note home directory */
  if (home) *home = cpystr (pw->pw_dir);
  return T;
}

/* TCP/IP open
 * Accepts: host name
 *	    contact port number
 * Returns: TCP/IP stream if success else NIL
 */

TCPSTREAM *tcp_open (host,port)
	char *host;
	int port;
{
  TCPSTREAM *stream = NIL;
  int sock;
  char *s;
  struct sockaddr_in sin;
  struct hostent *host_name;
  char hostname[MAILTMPLEN];
  char tmp[MAILTMPLEN];
  /* The domain literal form is used (rather than simply the dotted decimal
     as with other Unix programs) because it has to be a valid "host name"
     in mailsystem terminology. */
				/* look like domain literal? */
  if (host[0] == '[' && host[(strlen (host))-1] == ']') {
    strcpy (hostname,host+1);	/* yes, copy number part */
    hostname[(strlen (hostname))-1] = '\0';
    if ((sin.sin_addr.s_addr = inet_addr (hostname)) != -1) {
      sin.sin_family = AF_INET;	/* family is always Internet */
      strcpy (hostname,host);	/* hostname is user's argument */
    }
    else {
      sprintf (tmp,"Bad format domain-literal: %s",host);
      mm_log (tmp,ERROR);
      return NIL;
    }
  }

  else {			/* lookup host name, note that brain-dead Unix
				   requires lowercase! */
    strcpy (hostname,host);	/* in case host is in write-protected memory */
    if ((host_name = gethostbyname (lcase (hostname)))) {
				/* copy address type */
      sin.sin_family = host_name->h_addrtype;
				/* copy host name */
      strcpy (hostname,host_name->h_name);
				/* copy host addresses */
      memcpy (&sin.sin_addr,host_name->h_addr,host_name->h_length);
    }
    else {
      sprintf (tmp,"No such host as %s",host);
      mm_log (tmp,ERROR);
      return NIL;
    }
  }

				/* copy port number in network format */
  if (!(sin.sin_port = htons (port))) fatal ("Bad port argument to tcp_open");
				/* get a TCP stream */
  if ((sock = socket (sin.sin_family,SOCK_STREAM,0)) < 0) {
    sprintf (tmp,"Unable to create TCP socket: %s",strerror (errno));
    mm_log (tmp,ERROR);
    return NIL;
  }
				/* open connection */
  if (connect (sock,(struct sockaddr *)&sin,sizeof (sin)) < 0) {
    sprintf (tmp,"Can't connect to %s,%d: %s",hostname,port,strerror (errno));
    mm_log (tmp,ERROR);
    return NIL;
  }
				/* create TCP/IP stream */
  stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM));
				/* copy official host name */
  stream->host = cpystr (hostname);
				/* get local name */
  gethostname (tmp,MAILTMPLEN-1);
  stream->localhost = cpystr ((host_name = gethostbyname (tmp)) ?
			      host_name->h_name : tmp);
				/* init sockets */
  stream->tcpsi = stream->tcpso = sock;
  stream->ictr = 0;		/* init input counter */
  return stream;		/* return success */
}

/* TCP/IP authenticated open
 * Accepts: host name
 *	    service name
 * Returns: TCP/IP stream if success else NIL
 */

TCPSTREAM *tcp_aopen (host,service)
	char *host;
	char *service;
{
  TCPSTREAM *stream = NIL;
  struct hostent *host_name;
  char hostname[MAILTMPLEN];
  int i;
  int pipei[2],pipeo[2];
  /* The domain literal form is used (rather than simply the dotted decimal
     as with other Unix programs) because it has to be a valid "host name"
     in mailsystem terminology. */
				/* look like domain literal? */
  if (host[0] == '[' && host[i = (strlen (host))-1] == ']') {
    strcpy (hostname,host+1);	/* yes, copy without brackets */
    hostname[i-1] = '\0';
  }
				/* note that Unix requires lowercase! */
  else if (host_name = gethostbyname (lcase (strcpy (hostname,host))))
    strcpy (hostname,host_name->h_name);
				/* make command pipes */
  if (pipe (pipei) < 0) return NIL;
  if (pipe (pipeo) < 0) {
    close (pipei[0]); close (pipei[1]);
    return NIL;
  }
  if ((i = fork ()) < 0) {	/* make inferior process */
    close (pipei[0]); close (pipei[1]);
    close (pipeo[0]); close (pipeo[1]);
    return NIL;
  }
  if (i) {			/* parent? */
    close (pipei[1]);		/* close child's side of the pipes */
    close (pipeo[0]);
  }
  else {			/* child */
    dup2 (pipei[1],1);		/* parent's input is my output */
    dup2 (pipei[1],2);		/* parent's input is my error output too */
    close (pipei[0]); close (pipei[1]);
    dup2 (pipeo[0],0);		/* parent's output is my input */
    close (pipeo[0]); close (pipeo[1]);
				/* now run it */
    execl ("/usr/ucb/rsh","rsh",hostname,"exec",service,0);
    _exit (1);			/* spazzed */
  }

				/* create TCP/IP stream */
  stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM));
				/* copy official host name */
  stream->host = cpystr (hostname);
				/* get local name */
  gethostname (hostname,MAILTMPLEN-1);
  stream->localhost = cpystr ((host_name = gethostbyname (hostname)) ?
			      host_name->h_name : hostname);
  stream->tcpsi = pipei[0];	/* init sockets */
  stream->tcpso = pipeo[1];
  stream->ictr = 0;		/* init input counter */
  return stream;		/* return success */
}

/* TCP/IP receive line
 * Accepts: TCP/IP stream
 * Returns: text line string or NIL if failure
 */

char *tcp_getline (stream)
	TCPSTREAM *stream;
{
  int n,m;
  char *st;
  char *ret;
  char *stp;
  char tmp[2];
  fd_set fds;
  FD_ZERO (&fds);		/* initialize selection vector */
  if (stream->tcpsi < 0) return NIL;
  while (stream->ictr < 1) {	/* if nothing in the buffer */
    FD_SET (stream->tcpsi,&fds);/* set bit in selection vector */
				/* block and read */
    if ((select (stream->tcpsi+1,&fds,0,0,0) < 0) ||
	((stream->ictr = read (stream->tcpsi,stream->ibuf,BUFLEN)) < 1)) {
      close (stream->tcpsi);	/* nuke the socket */
      if (stream->tcpsi != stream->tcpso) close (stream->tcpso);
      stream->tcpsi = stream->tcpso = -1;
      return NIL;
    }
    stream->iptr = stream->ibuf;/* point at TCP buffer */
  }
  st = stream->iptr;		/* save start of string */
  n = 0;			/* init string count */
  while (stream->ictr--) {	/* look for end of line */
				/* saw the trailing CR? */
    if (stream->iptr++[0] == '\015') {
      ret = (char *) fs_get (n+1);
      memcpy (ret,st,n);	/* copy into a free storage string */
      ret[n] = '\0';		/* tie off string with null */
				/* eat the line feed */
      tcp_getbuffer (stream,1,tmp);
      return ret;		/* return it to caller */
    }
    ++n;			/* else count and try next character */
  }
  stp = (char *) fs_get (n);	/* copy first part of string */
  memcpy (stp,st,n);
				/* recurse to get remainder */
  if (st = tcp_getline (stream)) {
				/* build total string */
    ret = (char *) fs_get (n+1+(m = strlen (st)));
    memcpy (ret,stp,n);		/* copy first part */
    memcpy (ret+n,st,m);	/* and second part */
    ret[n+m] = '\0';		/* tie off string with null */
    fs_give ((void **) &st);	/* flush partial string */
    fs_give ((void **) &stp);	/* flush initial fragment */
  }
  else ret = stp;		/* return the fragment */
  return ret;
}

/* TCP/IP receive buffer
 * Accepts: TCP/IP stream
 *	    size in bytes
 *	    buffer to read into
 * Returns: T if success, NIL otherwise
 */

int tcp_getbuffer (stream,size,buffer)
	TCPSTREAM *stream;
	unsigned long size;
	char *buffer;
{
  unsigned long n;
  char *bufptr = buffer;
  fd_set fds;
  FD_ZERO (&fds);		/* initialize selection vector */
  if (stream->tcpsi < 0) return NIL;
  while (size > 0) {		/* until request satisfied */
    while (stream->ictr < 1) {	/* if nothing in the buffer */
      FD_SET (stream->tcpsi,&fds);
				/* block and read */
      if ((select (stream->tcpsi+1,&fds,0,0,0) < 0) ||
	  ((stream->ictr = read (stream->tcpsi,stream->ibuf,BUFLEN)) < 1)) {
	close (stream->tcpsi);	/* nuke the socket */
	if (stream->tcpsi != stream->tcpso) close (stream->tcpso);
	stream->tcpsi = stream->tcpso = -1;
	return NIL;
      }
				/* point at TCP buffer */
      stream->iptr = stream->ibuf;
    }
    n = min (size,stream->ictr);/* number of bytes to transfer */
				/* do the copy */
    memcpy (bufptr,stream->iptr,n);
    bufptr += n;		/* update pointer */
    stream->iptr +=n;
    size -= n;			/* update # of bytes to do */
    stream->ictr -=n;
  }
  bufptr[0] = '\0';		/* tie off string */
  return T;
}

/* TCP/IP send string as record
 * Accepts: TCP/IP stream
 * Returns: T if success else NIL
 */

int tcp_soutr (stream,string)
	TCPSTREAM *stream;
	char *string;
{
  int i;
  unsigned long size = strlen (string);
  fd_set fds;
  FD_ZERO (&fds);		/* initialize selection vector */
  if (stream->tcpso < 0) return NIL;
  while (size > 0) {		/* until request satisfied */
    FD_SET (stream->tcpso,&fds);/* set bit in selection vector */
    if ((select (stream->tcpso+1,0,&fds,0,0) < 0) ||
	((i = write (stream->tcpso,string,size)) < 0)) {
      puts (strerror (errno));
      close (stream->tcpsi);	/* nuke the socket */
      if (stream->tcpsi != stream->tcpso) close (stream->tcpso);
      stream->tcpsi = stream->tcpso = -1;
      return NIL;
    }
    size -= i;			/* count this size */
    string += i;
  }
  return T;			/* all done */
}


/* TCP/IP close
 * Accepts: TCP/IP stream
 */

void tcp_close (stream)
	TCPSTREAM *stream;
{

  if (stream->tcpsi >= 0) {	/* no-op if no socket */
    close (stream->tcpsi);	/* nuke the socket */
    if (stream->tcpsi != stream->tcpso) close (stream->tcpso);
    stream->tcpsi = stream->tcpso = -1;
  }
				/* flush host names */
  fs_give ((void **) &stream->host);
  fs_give ((void **) &stream->localhost);
  fs_give ((void **) &stream);	/* flush the stream */
}

/* TCP/IP get host name
 * Accepts: TCP/IP stream
 * Returns: host name for this stream
 */

char *tcp_host (stream)
	TCPSTREAM *stream;
{
  return stream->host;		/* return host name */
}


/* TCP/IP get local host name
 * Accepts: TCP/IP stream
 * Returns: local host name
 */

char *tcp_localhost (stream)
	TCPSTREAM *stream;
{
  return stream->localhost;	/* return local host name */
}


/* Copy memory block
 * Accepts: destination pointer
 *	    source pointer
 *	    length
 * Returns: destination pointer
 */

char *memmove (s,ct,n)
     char *s;
     char *ct;
     int n;
{
  bcopy (ct,s,n);		/* they should have this one */
  return ct;
}
/*
 * This works only on System V Release 3.1 and greater, and relies on an
 * undocumented fcntl.  Use at your own risk.  This facility will be
 * documented in System V Release 4.0.
 */

#ifdef	flock		/* undef this for now */
#undef	flock
#endif

ftruncate(f, l)
int	f;
long	l;
{
	struct	flock fl;

	fl.l_whence = 0;
	fl.l_len = 0;
	fl.l_start = l;
	fl.l_type = F_WRLCK;

	return(fcntl(f, F_FREESP, &fl));
}


/*
 * Copyright (c) 1983 Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)random.c	5.9 (Berkeley) 2/23/91";
#endif /* LIBC_SCCS and not lint */

/*
typedef unsigned int	u_int;
 */

/*
 * random.c:
 *
 * An improved random number generation package.  In addition to the standard
 * rand()/srand() like interface, this package also has a special state info
 * interface.  The initstate() routine is called with a seed, an array of
 * bytes, and a count of how many bytes are being passed in; this array is
 * then initialized to contain information for random number generation with
 * that much state information.  Good sizes for the amount of state
 * information are 32, 64, 128, and 256 bytes.  The state can be switched by
 * calling the setstate() routine with the same array as was initiallized
 * with initstate().  By default, the package runs with 128 bytes of state
 * information and generates far better random numbers than a linear
 * congruential generator.  If the amount of state information is less than
 * 32 bytes, a simple linear congruential R.N.G. is used.
 *
 * Internally, the state information is treated as an array of longs; the
 * zeroeth element of the array is the type of R.N.G. being used (small
 * integer); the remainder of the array is the state information for the
 * R.N.G.  Thus, 32 bytes of state information will give 7 longs worth of
 * state information, which will allow a degree seven polynomial.  (Note:
 * the zeroeth word of state information also has some other information
 * stored in it -- see setstate() for details).
 * 
 * The random number generation technique is a linear feedback shift register
 * approach, employing trinomials (since there are fewer terms to sum up that
 * way).  In this approach, the least significant bit of all the numbers in
 * the state table will act as a linear feedback shift register, and will
 * have period 2^deg - 1 (where deg is the degree of the polynomial being
 * used, assuming that the polynomial is irreducible and primitive).  The
 * higher order bits will have longer periods, since their values are also
 * influenced by pseudo-random carries out of the lower bits.  The total
 * period of the generator is approximately deg*(2**deg - 1); thus doubling
 * the amount of state information has a vast influence on the period of the
 * generator.  Note: the deg*(2**deg - 1) is an approximation only good for
 * large deg, when the period of the shift register is the dominant factor.
 * With deg equal to seven, the period is actually much longer than the
 * 7*(2**7 - 1) predicted by this formula.
 */

/*
 * For each of the currently supported random number generators, we have a
 * break value on the amount of state information (you need at least this
 * many bytes of state info to support this random number generator), a degree
 * for the polynomial (actually a trinomial) that the R.N.G. is based on, and
 * the separation between the two lower order coefficients of the trinomial.
 */
#define	TYPE_0		0		/* linear congruential */
#define	BREAK_0		8
#define	DEG_0		0
#define	SEP_0		0

#define	TYPE_1		1		/* x**7 + x**3 + 1 */
#define	BREAK_1		32
#define	DEG_1		7
#define	SEP_1		3

#define	TYPE_2		2		/* x**15 + x + 1 */
#define	BREAK_2		64
#define	DEG_2		15
#define	SEP_2		1

#define	TYPE_3		3		/* x**31 + x**3 + 1 */
#define	BREAK_3		128
#define	DEG_3		31
#define	SEP_3		3

#define	TYPE_4		4		/* x**63 + x + 1 */
#define	BREAK_4		256
#define	DEG_4		63
#define	SEP_4		1

/*
 * Array versions of the above information to make code run faster --
 * relies on fact that TYPE_i == i.
 */
#define	MAX_TYPES	5		/* max number of types above */

static int degrees[MAX_TYPES] =	{ DEG_0, DEG_1, DEG_2, DEG_3, DEG_4 };
static int seps [MAX_TYPES] =	{ SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 };

/*
 * Initially, everything is set up as if from:
 *
 *	initstate(1, &randtbl, 128);
 *
 * Note that this initialization takes advantage of the fact that srandom()
 * advances the front and rear pointers 10*rand_deg times, and hence the
 * rear pointer which starts at 0 will also end up at zero; thus the zeroeth
 * element of the state information, which contains info about the current
 * position of the rear pointer is just
 *
 *	MAX_TYPES * (rptr - state) + TYPE_3 == TYPE_3.
 */

static long randtbl[DEG_3 + 1] = {
	TYPE_3,
	0x9a319039, 0x32d9c024, 0x9b663182, 0x5da1f342, 0xde3b81e0, 0xdf0a6fb5,
	0xf103bc02, 0x48f340fb, 0x7449e56b, 0xbeb1dbb0, 0xab5c5918, 0x946554fd,
	0x8c2e680f, 0xeb3d799f, 0xb11ee0b7, 0x2d436b86, 0xda672e2a, 0x1588ca88,
	0xe369735d, 0x904f35f7, 0xd7158fd6, 0x6fa6f051, 0x616e6b96, 0xac94efdc,
	0x36413f93, 0xc622c298, 0xf5a42ab8, 0x8a88d77b, 0xf5ad9d0e, 0x8999220b,
	0x27fb47b9,
};

/*
 * fptr and rptr are two pointers into the state info, a front and a rear
 * pointer.  These two pointers are always rand_sep places aparts, as they
 * cycle cyclically through the state information.  (Yes, this does mean we
 * could get away with just one pointer, but the code for random() is more
 * efficient this way).  The pointers are left positioned as they would be
 * from the call
 *
 *	initstate(1, randtbl, 128);
 *
 * (The position of the rear pointer, rptr, is really 0 (as explained above
 * in the initialization of randtbl) because the state table pointer is set
 * to point to randtbl[1] (as explained below).
 */
static long *fptr = &randtbl[SEP_3 + 1];
static long *rptr = &randtbl[1];

/*
 * The following things are the pointer to the state information table, the
 * type of the current generator, the degree of the current polynomial being
 * used, and the separation between the two pointers.  Note that for efficiency
 * of random(), we remember the first location of the state information, not
 * the zeroeth.  Hence it is valid to access state[-1], which is used to
 * store the type of the R.N.G.  Also, we remember the last location, since
 * this is more efficient than indexing every time to find the address of
 * the last element to see if the front and rear pointers have wrapped.
 */
static long *state = &randtbl[1];
static int rand_type = TYPE_3;
static int rand_deg = DEG_3;
static int rand_sep = SEP_3;
static long *end_ptr = &randtbl[DEG_3 + 1];

/*
 * srandom:
 *
 * Initialize the random number generator based on the given seed.  If the
 * type is the trivial no-state-information type, just remember the seed.
 * Otherwise, initializes state[] based on the given "seed" via a linear
 * congruential generator.  Then, the pointers are set to known locations
 * that are exactly rand_sep places apart.  Lastly, it cycles the state
 * information a given number of times to get rid of any initial dependencies
 * introduced by the L.C.R.N.G.  Note that the initialization of randtbl[]
 * for default usage relies on values produced by this routine.
 */
void
srandom(x)
	u_int x;
{
	register int i, j;

	if (rand_type == TYPE_0)
		state[0] = x;
	else {
		j = 1;
		state[0] = x;
		for (i = 1; i < rand_deg; i++)
			state[i] = 1103515245 * state[i - 1] + 12345;
		fptr = &state[rand_sep];
		rptr = &state[0];
		for (i = 0; i < 10 * rand_deg; i++)
			(void)random();
	}
}

/*
 * initstate:
 *
 * Initialize the state information in the given array of n bytes for future
 * random number generation.  Based on the number of bytes we are given, and
 * the break values for the different R.N.G.'s, we choose the best (largest)
 * one we can and set things up for it.  srandom() is then called to
 * initialize the state information.
 * 
 * Note that on return from srandom(), we set state[-1] to be the type
 * multiplexed with the current value of the rear pointer; this is so
 * successive calls to initstate() won't lose this information and will be
 * able to restart with setstate().
 * 
 * Note: the first thing we do is save the current state, if any, just like
 * setstate() so that it doesn't matter when initstate is called.
 *
 * Returns a pointer to the old state.
 */
char *
initstate(seed, arg_state, n)
	u_int seed;			/* seed for R.N.G. */
	char *arg_state;		/* pointer to state array */
	int n;				/* # bytes of state info */
{
	register char *ostate = (char *)(&state[-1]);

	if (rand_type == TYPE_0)
		state[-1] = rand_type;
	else
		state[-1] = MAX_TYPES * (rptr - state) + rand_type;
	if (n < BREAK_0) {
		(void)fprintf(stderr,
		    "random: not enough state (%d bytes); ignored.\n", n);
		return(0);
	}
	if (n < BREAK_1) {
		rand_type = TYPE_0;
		rand_deg = DEG_0;
		rand_sep = SEP_0;
	} else if (n < BREAK_2) {
		rand_type = TYPE_1;
		rand_deg = DEG_1;
		rand_sep = SEP_1;
	} else if (n < BREAK_3) {
		rand_type = TYPE_2;
		rand_deg = DEG_2;
		rand_sep = SEP_2;
	} else if (n < BREAK_4) {
		rand_type = TYPE_3;
		rand_deg = DEG_3;
		rand_sep = SEP_3;
	} else {
		rand_type = TYPE_4;
		rand_deg = DEG_4;
		rand_sep = SEP_4;
	}
	state = &(((long *)arg_state)[1]);	/* first location */
	end_ptr = &state[rand_deg];	/* must set end_ptr before srandom */
	srandom(seed);
	if (rand_type == TYPE_0)
		state[-1] = rand_type;
	else
		state[-1] = MAX_TYPES*(rptr - state) + rand_type;
	return(ostate);
}

/*
 * setstate:
 *
 * Restore the state from the given state array.
 *
 * Note: it is important that we also remember the locations of the pointers
 * in the current state information, and restore the locations of the pointers
 * from the old state information.  This is done by multiplexing the pointer
 * location into the zeroeth word of the state information.
 *
 * Note that due to the order in which things are done, it is OK to call
 * setstate() with the same state as the current state.
 *
 * Returns a pointer to the old state information.
 */
char *
setstate(arg_state)
	char *arg_state;
{
	register long *new_state = (long *)arg_state;
	register int type = new_state[0] % MAX_TYPES;
	register int rear = new_state[0] / MAX_TYPES;
	char *ostate = (char *)(&state[-1]);

	if (rand_type == TYPE_0)
		state[-1] = rand_type;
	else
		state[-1] = MAX_TYPES * (rptr - state) + rand_type;
	switch(type) {
	case TYPE_0:
	case TYPE_1:
	case TYPE_2:
	case TYPE_3:
	case TYPE_4:
		rand_type = type;
		rand_deg = degrees[type];
		rand_sep = seps[type];
		break;
	default:
		(void)fprintf(stderr,
		    "random: state info corrupted; not changed.\n");
	}
	state = &new_state[1];
	if (rand_type != TYPE_0) {
		rptr = &state[rear];
		fptr = &state[(rear + rand_sep) % rand_deg];
	}
	end_ptr = &state[rand_deg];		/* set end_ptr too */
	return(ostate);
}

/*
 * random:
 *
 * If we are using the trivial TYPE_0 R.N.G., just do the old linear
 * congruential bit.  Otherwise, we do our fancy trinomial stuff, which is
 * the same in all the other cases due to all the global variables that have
 * been set up.  The basic operation is to add the number at the rear pointer
 * into the one at the front pointer.  Then both pointers are advanced to
 * the next location cyclically in the table.  The value returned is the sum
 * generated, reduced to 31 bits by throwing away the "least random" low bit.
 *
 * Note: the code takes advantage of the fact that both the front and
 * rear pointers can't wrap on the same call by not testing the rear
 * pointer if the front one has wrapped.
 *
 * Returns a 31-bit random number.
 */
long
random()
{
	long i;

	if (rand_type == TYPE_0)
		i = state[0] = (state[0] * 1103515245 + 12345) & 0x7fffffff;
	else {
		*fptr += *rptr;
		i = (*fptr >> 1) & 0x7fffffff;	/* chucking least random bit */
		if (++fptr >= end_ptr) {
			fptr = state;
			++rptr;
		} else if (++rptr >= end_ptr)
			rptr = state;
	}
	return(i);
}


/*
 * Copyright (c) 1983 Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)scandir.c	5.10 (Berkeley) 2/23/91";
#endif /* LIBC_SCCS and not lint */

/*
 * Scan the directory dirname calling select to make a list of selected
 * directory entries then sort using qsort and compare routine dcomp.
 * Returns the number of entries and a pointer to a list of pointers to
 * struct dirent (through namelist). Returns -1 if there were any errors.
 */

#define	const

/*
 * The DIRSIZ macro gives the minimum record length which will hold
 * the directory entry.  This requires the amount of space in struct dirent
 * without the d_name field, plus enough space for the name with a terminating
 * null byte (strlen(dp->d_name)+1), rounded up to a 4 byte boundary.
 */
#undef DIRSIZ
#define DIRSIZ(dp) \
    ((sizeof (struct dirent) - (MAXNAMLEN+1)) + ((strlen(dp->d_name)+1 + 3) &~ 3))

int
scandir(dirname, namelist, select, dcomp)
	const char *dirname;
	struct dirent ***namelist;
	int (*select)();
	int (*dcomp)();
{
	register struct dirent *d, *p, **names;
	register size_t nitems;
	struct stat stb;
	long arraysz;
	DIR *dirp;

	if ((dirp = opendir(dirname)) == NULL)
		return(-1);
	if (fstat(dirp->dd_fd, &stb) < 0)
		return(-1);

	/*
	 * estimate the array size by taking the size of the directory file
	 * and dividing it by a multiple of the minimum size entry. 
	 */
	arraysz = (stb.st_size / 24);
	names = (struct dirent **)malloc(arraysz * sizeof(struct dirent *));
	if (names == NULL)
		return(-1);

	nitems = 0;
	while ((d = readdir(dirp)) != NULL) {
		if (select != NULL && !(*select)(d))
			continue;	/* just selected names */
		/*
		 * Make a minimum size copy of the data
		 */
		p = (struct dirent *)malloc(DIRSIZ(d));
		if (p == NULL)
			return(-1);
		p->d_ino = d->d_ino;
		p->d_reclen = d->d_reclen;
		bcopy(d->d_name, p->d_name, strlen(d->d_name) + 1);
		/*
		 * Check to make sure the array has space left and
		 * realloc the maximum size.
		 */
		if (++nitems >= arraysz) {
			if (fstat(dirp->dd_fd, &stb) < 0)
				return(-1);	/* just might have grown */
			arraysz = stb.st_size / 12;
			names = (struct dirent **)realloc((char *)names,
				arraysz * sizeof(struct dirent *));
			if (names == NULL)
				return(-1);
		}
		names[nitems-1] = p;
	}
	closedir(dirp);
	if (nitems && dcomp != NULL)
		qsort(names, nitems, sizeof(struct dirent *), dcomp);
	*namelist = names;
	return(nitems);
}

/*
 * Alphabetic order comparison routine for those who want it.
 */
int
alphasort(d1, d2)
	const void *d1;
	const void *d2;
{
	return(strcmp((*(struct dirent **)d1)->d_name,
	    (*(struct dirent **)d2)->d_name));
}

/*
 * use ftruncate in c-client library
 */

void	truncate(filename, start_of_append)
char	*filename;
long	start_of_append;
{
	int	fd = open(filename, 0);

	if(fd < 0)
		return;

	ftruncate(fd, start_of_append);
	close(fd);
}
SHAR_EOF
if test 35476 -ne "`wc -c < './c-client/os_s53.c'`"
then
	echo shar: "error transmitting './c-client/os_s53.c'" '(should have been 35476 characters)'
fi
chmod 644 './c-client/os_s53.c'
fi
if test -f './c-client/os_s53.h'
then
	echo shar: "will not over-write existing file './c-client/os_s53.h'"
else
cat << \SHAR_EOF > './c-client/os_s53.h'
/*
 * Program:	Operating-system dependent routines -- Dynix version
 *
 * Author:	Mark Crispin
 *		Networks and Distributed Computing
 *		Computing & Communications
 *		University of Washington
 *		Administration Building, AG-44
 *		Seattle, WA  98195
 *		Internet: MRC@CAC.Washington.EDU
 *
 * Date:	11 May 1989
 * Last Edited:	15 December 1991
 *
 * Copyright 1991 by the University of Washington
 *
 *  Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose and without fee is hereby granted, provided
 * that the above copyright notice appears in all copies and that both the
 * above copyright notice and this permission notice appear in supporting
 * documentation, and that the name of the University of Washington not be
 * used in advertising or publicity pertaining to distribution of the software
 * without specific, written prior permission.  This software is made
 * available "as is", and
 * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
 * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
 * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
 *(INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include <strings.h>

#if	!defined(_SYSV3)
#define	_SYSV3
#endif

#define	const

extern char	*malloc();
extern char	*realloc();
extern void	free();
extern int	errno;
extern long	strtol();

/* Coddle certain compilers' 6-character symbol limitation */

#ifdef	__COMPILER_KCC__
#define	rfc822_date	r8date
#define	fs_get		fsget
#define	fs_resize	fsrsiz
#define	fs_give		fsgive
#define	strcrlfcpy	stclcp
#define	server_login	slogin
#define	tcp_open	topen
#define	tcp_getline	tgline
#define	tcp_getbuffer	tgbuf
#define	tcp_soutr	tsoutr
#define	tcp_close	tclose
#define	tcp_host	thost
#define	tcp_localhost	tlocal
#endif


/* Dummy definition overridden by TCP routines */

#ifndef	TCPSTREAM
#define	TCPSTREAM void
#endif


/* Function prototypes */

void	rfc822_date();
void	*fs_get();
void	fs_resize();
void	fs_give();
void	fatal();
char	*strcrlfcpy();
unsigned long	strcrlflen();
int	server_login();
TCPSTREAM *tcp_open();
TCPSTREAM *tcp_aopen();
char	*tcp_getline();
int	tcp_getbuffer();
int	tcp_soutr();
void	tcp_close();
char	*tcp_host();
char	*tcp_localhost();

/* for lseek() */

#define	L_SET		SEEK_SET
SHAR_EOF
if test 2649 -ne "`wc -c < './c-client/os_s53.h'`"
then
	echo shar: "error transmitting './c-client/os_s53.h'" '(should have been 2649 characters)'
fi
chmod 644 './c-client/os_s53.h'
fi
if test -f './pico/Makefile.s53'
then
	echo shar: "will not over-write existing file './pico/Makefile.s53'"
else
cat << \SHAR_EOF > './pico/Makefile.s53'
#
# Makefile for Dynix 3.0 version of the PINE composer library and 
# stand-alone editor pico.
#


OPTIMIZE=	-O
DEBUG=		-g -DDEBUG
#PROFILE=	-p

CFLAGS=		-D_SYSV3 $(OPTIMIZE) $(DEBUG) $(PROFILE)
LDFLAGS=	$(PROFILE)

# switches for library building
LIB=ar
LIBARGS=ru

OFILES=		ansi.o basic.o bind.o buffer.o composer.o display.o \
		file.o fileio.o line.o osdep.o pico.o random.o search.o \
		spell.o tcap.o window.o word.o

CFILES=		ansi.c basic.c bind.c buffer.c composer.c display.c \
		file.c fileio.c line.c osdep.c pico.c random.c search.c \
		spell.c tcap.c window.c word.c

HFILES=		estruct.h edef.h efunc.h ebind.h pico.h

#
# dependencies for the Unix versions of pico and libpico.a
#
all:		pico

osdep.c:	os_unix.c
		rm -f osdep.c
		cp os_unix.c osdep.c

osdep.h:	os_unix.h
		rm -f osdep.h
		cp os_unix.h osdep.h

libpico.a:	osdep.c osdep.h $(OFILES)
		$(LIB) $(LIBARGS) libpico.a $(OFILES)

pico:		main.c libpico.a
		$(CC) $(CFLAGS) main.c libpico.a -ltermcap -linet -o pico

.c.o:		; $(CC) -c $(CFLAGS) $(DASHO) $*.c

$(OFILES):	$(HFILES)

clean:
		rm -f *.a *.o *~ osdep.c osdep.h
SHAR_EOF
if test 1095 -ne "`wc -c < './pico/Makefile.s53'`"
then
	echo shar: "error transmitting './pico/Makefile.s53'" '(should have been 1095 characters)'
fi
chmod 644 './pico/Makefile.s53'
fi
if test -f './pine/makefile.s53'
then
	echo shar: "will not over-write existing file './pine/makefile.s53'"
else
cat << \SHAR_EOF > './pine/makefile.s53'
#
#            T H E    P I N E    M A I L   S Y S T E M
#
#   Laurence Lundblade and Mike Seibel
#   Networks and Distributed Computing
#   Computing and Communications
#   University of Washington
#   Administration Building, AG-44
#   Seattle, Washington, 98195, USA
#   Internet: lgl@CAC.Washington.EDU
#             mikes@CAC.Washington.EDU
#
#   Please address all bugs and comments to "pine-bugs@cac.washington.edu"
#
#   Date:
#   Last Edited:
#
#   Copyright 1989, 1990, 1991, 1992  University of Washington
#
#    Permission to use, copy, modify, and distribute this software and its
#   documentation for any purpose and without fee is hereby granted, provided
#   that the above copyright notice appears in all copies and that both the
#   above copyright notice and this permission notice appear in supporting
#   documentation, and that the name of the University of Washington not be
#   used in advertising or publicity pertaining to distribution of the software
#   without specific, written prior permission.  This software is made
#   available "as is", and
#   THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
#   WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
#   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
#   NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
#   INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
#   LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
#   (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
#   WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
#
#   Pine is in part based on The Elm Mail System:
#    ***********************************************************************
#    *  The Elm Mail System  -  $Revision: 2.13 $   $State: Exp $          *
#    *                                                                     *
#    * 			Copyright (c) 1986, 1987 Dave Taylor              *
#    * 			Copyright (c) 1988, 1989 USENET Community Trust   *
#    ***********************************************************************
#
#


#
#     Generic makefile for the Pine mail system
#      (A good place to start a new port)
#


#
#   Most commonly fiddled flags for compiler.
#   Uncomment the setttings desired here
#

OPTIMIZE=	-O
DEBUG=		-g -DDEBUG
#PROFILE=	-p

CFLAGS=		-D_SYSV3 $(OPTIMIZE) $(DEBUG) $(PROFILE)
LDFLAGS=	$(PROFILE)

LIBES=		-ltermlib
PLIBS=		../pico/libpico.a ../c-client/c-client.a ../regexp/libregexp.a
STLIB=		-linet -lcposix


obj=    helptext.o addrbook.o addrutil.o adrbklib.o args.o \
	compile.o pine.o \
	folder.o help.o imap.o init.o \
	mailcmd.o mailindx.o mailview.o \
	newmail.o other.o print.o \
	reply.o screen.o send.o signals.o  status.o \
	strings.o ttyout.o ttyin.o os.o


cfiles= helptext.c addrbook.c addrutil.c adrbklib.o args.c compile.c \
	pine.c \
	folder.c help.c imap.c init.c \
	mailcmd.c mailindx.c mailview.c \
	newmail.c other.c print.c \
	reply.c screen.c \
	send.c signals.c  status.c  strings.c \
	ttyout.c ttyin.c os.c



pine:  ${obj}
	awk '{printf "int COMPILE= %d ;\n",$$3+1}' <compile.c > tmp.c
	cp tmp.c compile.c
	rm -f tmp.c
	- chmod 666 compile.c
	cc -c $(CFLAGS) compile.c
	cc ${LDFLAGS} $(CFLAGS) -o pine ${obj} $(PLIBS) $(STLIB) $(LIBES)

clean:
	rm -f *.o os.c os.h helptext.c helptext.h *~


saber_src:	$(cfiles)
	#load $(CFLAGS) $(cfiles)
saber_obj:	$(obj)
	#load $(CFLAGS) $(obj)


HEADERS= headers.h pine.h os.h ../c-client/mail.h

addrbook.o:	addrbook.c  $(HEADERS)
addrutil.o:	addrutil.c  $(HEADERS)
args.o:		args.c      $(HEADERS)
compile.o:	compile.c
pine.o:		pine.c      $(HEADERS)
folder.o:	folder.c    $(HEADERS)
help.o:		help.c      $(HEADERS)
helptext.o:	helptext.c
imap.o:	        imap.c      $(HEADERS)
init.o:		init.c      $(HEADERS)
mailcmd.o:	mailcmd.c   $(HEADERS)
mailindx.o:	mailindx.c  $(HEADERS)
mailview.o:	mailview.c  $(HEADERS)
newmail.o:	newmail.c   $(HEADERS)
other.o:	other.c     $(HEADERS)
print.o:	print.c     $(HEADERS)
reply.o:	reply.c     $(HEADERS)
screen.o:	screen.c    $(HEADERS)
send.o:	        send.c      $(HEADERS)
signals.o:	signals.c   $(HEADERS)
status.o:	status.c    $(HEADERS)
strings.o:	strings.c   $(HEADERS)
ttyout.o:	ttyout.c    $(HEADERS)
ttyin.o:	ttyin.c     $(HEADERS)
os.o:	        os-s53.c    $(HEADERS)

os.c:		$(HEADERS)
	-ln os-s53.c os.c

helptext.c:	pine.hlp
		./cmplhelp.sh  < pine.hlp > helptext.c
		./cmplhlp2.sh  < pine.hlp > helptext.h

helptext.h:	pine.hlp
		./cmplhlp2.sh  <  pine.hlp > helptext.h

os.h:	os-s53.h
	ln os-s53.h os.h

compile.c:
	echo "int COMPILE= 1 ;" > compile.c ; chmod 666 compile.c


SHAR_EOF
if test 4666 -ne "`wc -c < './pine/makefile.s53'`"
then
	echo shar: "error transmitting './pine/makefile.s53'" '(should have been 4666 characters)'
fi
chmod 644 './pine/makefile.s53'
fi
if test -f './pine/os-s53.c'
then
	echo shar: "will not over-write existing file './pine/os-s53.c'"
else
cat << \SHAR_EOF > './pine/os-s53.c'
/*----------------------------------------------------------------------

            T H E    P I N E    M A I L   S Y S T E M

   Laurence Lundblade and Mike Seibel
   Networks and Distributed Computing
   Computing and Communications
   University of Washington
   Administration Building, AG-44
   Seattle, Washington, 98195, USA
   Internet: lgl@CAC.Washington.EDU
             mikes@CAC.Washington.EDU

   Please address all bugs and comments to "pine-bugs@cac.washington.edu"

   Date:
   Last Edited:
      
   Copyright 1989, 1990, 1991, 1992  University of Washington

    Permission to use, copy, modify, and distribute this software and its
   documentation for any purpose and without fee is hereby granted, provided
   that the above copyright notice appears in all copies and that both the
   above copyright notice and this permission notice appear in supporting
   documentation, and that the name of the University of Washington not be
   used in advertising or publicity pertaining to distribution of the software
   without specific, written prior permission.  This software is made
   available "as is", and
   THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
   WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
   NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
   INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
   LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
   (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
   WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  

   Pine is in part based on The Elm Mail System:
    ***********************************************************************
    *  The Elm Mail System  -  $Revision: 2.13 $   $State: Exp $          *
    *                                                                     *
    * 			Copyright (c) 1986, 1987 Dave Taylor              *
    * 			Copyright (c) 1988, 1989 USENET Community Trust   *
    ***********************************************************************
  ----------------------------------------------------------------------*/

/*======================================================================
      os-unx.c

 This contains most of Pine's interface to the local operating system
and hardware. Hopefully this file, os-xxx.h and makefile.xxx are the
only one that have to be modified for any port. signals.c, ttyin.c,
and ttyout.c also have some dependencies. See the doc/tech-notes for
notes on porting Pine to other platforms.


        File System Access
           can_access      -- See if a file can be accessed
           file_size       -- Return the number of bytes in the file
           is_writetable   -- Check to see id directory exists and is writable
           create_mail_dir -- what to do if there's not mkdir function
           create_folder   -- create an empty folder
           rename_file     -- replacement for rename system call
           build_path      -- Put together a file system path
           expand_foldername -- Expand a folder name to full path
           fnexpand        -- Do filename exansion for csh style "~"
           filter_filename -- Make sure file name hasn't got weird chars
           disk_space      -- Count up the disk space free for a given path
           disk_quota      -- Find out the users disk quota
           simple_opendir  -- Open a directory 
           simple_readdir  -- Read file names out of ope directory
           simple_closedir -- Close directory
           read_file       -- Read whole file into memory (for small files)

        Abort
           coredump        -- Abort running Pine dumping core if possible

        System Name and Domain
           gethostname     -- Figure out the systems host name, however
           gethostdomain   -- Figure out the systems domain name

        Berkeley UNIX Job Control
           have_job_control-- Returns 1 if job control exists
           stop_process    -- What to do to stop process when it's time to stop

        System Error Messages (in case given one is a problem)
           error_name      -- Return short string describing error
           error_description -- Return strings describing error

        System Password and Accounts
           get_system_login    -- Returns userid 
           get_system_fullname -- Returns full name 
           get_system_homedir  -- Returns users home directoru
           get_system_passwd   -- Returns enscrypted password
           gcos_name           -- Parses full name from system
           local_name_lookup   -- Get full name of user on system
           chagne_passwd       -- Calls system password change

  ====*/


#include "headers.h"
#include <pwd.h>
#include <sys/wait.h>
#include <sys/types.h> 
#include <sys/stat.h>
#include <fcntl.h>

#if (defined(DYN) || defined(SUN)) && defined(USE_QUOTAS)
char *device_name();
#endif





/*----------------------------------------------------------------------
       Check if we can access a file in a given way

   Args: filename  -- The file name to check
         mode      -- The mode ala the access() system call
 

 Result: returns 0 if the user can access the file
         errno if he can't. This routine used to fork of process and
         change uid and gid to make sure all went well. This was because
         elm, could be installed setuid. Pine cannot be. Maybe we'll need 
         more here some day.
 ----*/
int
can_access(file, mode)
char *file; 
int   mode;
{
	 return(access(file, mode));
}



/*----------------------------------------------------------------------
      Return the number of bytes in given file

    Args: name -- file name

  Result: the number of bytes in the file is returned or
          -1 on error in which case errno is valid
  ----------------------------------------------------------------------*/
long
file_size(name)
char *name;
{
    struct stat buffer;

    if (stat(name, &buffer) != 0)
        return(-1);
    return(buffer.st_size);
}



/*----------------------------------------------------------------------
      Check to see if a directory exists and is writable by us

   Args:  directory name

 Result:       returns 0 if it exists and is writable
                       1 if it is a directory, but is not writable
                       2 if it is not a directory
                       3 it doesn't exist.
  ----*/
is_writable_dir(file)
     char *file;
{
    struct stat sb;

   if(stat(file, &sb) < 0)
     /*--- It doesn't exist ---*/
     return(3);


   if(!(sb.st_mode & S_IFDIR))
     /*---- it's not a directory ---*/
     return(2);


   if(access(file, 07))
     return(1);
   else
     return(0);
}



/*----------------------------------------------------------------------
      Create the mail subdirectory.

  Args: dir -- Name of the directory to make
 
 Result: Directory is created.
  ----*/
create_mail_dir(dir)
     char *dir;
{
    if(mkdir(dir, 0700) < 0)
      return(-1);

    chmod(dir, 0700);
    /* Some systems need this, on others we don't care if it fails */
    chown(dir, getuid(), getgid());
    return(0);
}



/*----------------------------------------------------------------------
      Create a folder (create a specific named file)

   Args dir  --  Directory to create folder in
        file --  File name to create

 ----*/
create_folder(dir, file)
    char *dir, *file;
{
    /* this creates a new folders directory */
    char  fn[MAXPATH+1];
    int   x;

    if(strlen(dir) + strlen(file) + 1 > MAXPATH) {
        q_status_message1(2,4,
           "\007Error creating folder: full path name would be longer than %d",
                          (char *)MAXPATH);
    }
    build_path(fn, dir, file);
    x = creat(fn, 0600);
    if(x < 0) {
        q_status_message2(2, 4,"\007Error creating \"%s\" : %s\n",
                          pretty_fn(fn), error_description(errno));
    } else {
        close(x);
    }
}



/*----------------------------------------------------------------------
      Rename a file. This is mostly a replacement for the rename system call.
If the system call exists we just use it.
  ----*/

int
rename_file(tmpfname, fname)
char *tmpfname, *fname;
{
#ifdef	    NO_KNOWN_SYSTEM_YET
	int status;

	(void) unlink(fname);
	if ((status = link(tmpfname, fname)) != 0)
		return(status);
	(void) unlink(tmpfname);
	return(0);
#else
        return(rename(tmpfname, fname));
#endif
}



/*----------------------------------------------------------------------
   Isolate the putting a path name together so other file systems like DOS can 
   be dealt with easily

   Args: pathbuf -- Buffer to return formatted path in. Better be big enough!
         first_part - First part of path to construct
         second_part - second part, usually the file name

BUGS this is a first stab at dealing fs naming dependencies, and others 
still exist
 ----*/
void
build_path(pathbuf, first_part, second_part)
     char *pathbuf, *first_part, *second_part;
{
    sprintf(pathbuf, "%s/%s", first_part, second_part);
}



/*----------------------------------------------------------------------
        expand the given file name considering ~ and the folders_dir

   Args: filename  -- The file/path name to expand (in place)

 Result: returns 0 and q's status message if unsuccessful.
         Input string is over written with expanded name.
         Returns 1 if successful

BUG should limit length to MAXPATH
  ----*/
int
expand_foldername(filename)
     char *filename;
{
    char         temp_filename[MAXPATH+1];

    dprint(5, (debugfile, "=== expand_foldername called (%s) ===\n",filename));

    if(filename[0] != '{') {
        char *ill = filter_filename(filename);
        if(ill != NULL) {
            q_status_message1(1,3, "%s in folder name", ill);
            return(0);
        }
    }

    strcpy(temp_filename, filename);
    if(strucmp(temp_filename, "inbox") == 0) {
        strcpy(filename, ps_global->VAR_INBOX_PATH == NULL ? "inbox" :
               ps_global->VAR_INBOX_PATH);
    } else if(temp_filename[0] == '{') {
        strcpy(filename, temp_filename);
    } else if(strindex("./~", temp_filename[0]) != NULL 
	      && ps_global->restricted){
	q_status_message(1,3,"Pine demo only opens local folders");
	return(0);
    } else if(temp_filename[0] == '*') {
        strcpy(filename, temp_filename);
    } else if (temp_filename[0] == '~'){
        if(fnexpand(temp_filename, sizeof(temp_filename)) == NULL) {
            char *p = strindex(temp_filename, '/');
    	    if(p != NULL)
    	      *p = '\0';
    	    q_status_message1(1,2,
                    "Error expanding folder name: \"%s\" unknown user",
    	       temp_filename);
    	    return(0);
        }
        strcpy(filename, temp_filename);
    } else if(temp_filename[0] == '/') {
        strcpy(filename, temp_filename);
    } else {
        sprintf(filename,"%s/%s", ps_global->folders_dir, temp_filename);
    }
    dprint(5, (debugfile, "returning \"%s\"\n", filename));    
    return(1);
}



struct passwd *getpwnam();

/*----------------------------------------------------------------------
       Expand the ~ in a file ala the csh (as home directory)

   Args: buf --  The filename to expand (nothing happens unless begins with ~)
         len --  The length of the buffer passed in (expansion is in place)

 Result: expanded string is returned using same storage as passed in
         if expansion fails, NULL is returned
 ----*/

char *
fnexpand(buf, len)
     char *buf;
     int len;
{
    struct passwd *pw;
    register char *x,*y;
    char name[20];
    
    if(*buf == '~') {
        for(x = buf+1, y = name; *x != '/' && *x != '\0'; *y++ = *x++);
        *y = '\0';
        if(x == buf + 1) 
          pw = getpwuid(getuid());
        else
          pw = getpwnam(name);
        if(pw == NULL)
          return(NULL);
        if(strlen(pw->pw_dir) + strlen(buf) > len) {
            return(NULL);
        }
        rplstr(buf, x - buf, pw->pw_dir);
    }
    return(len ? buf : NULL);
}



/*----------------------------------------------------------------------
    Filter file names for strange characters

   Args:  file  -- the file name to check
 
 Result: Returns NULL if file name is OK
         Returns formatted error message if it is not

  ----*/

char *
filter_filename(file)
     char *file;
{
#ifdef	ALLOW_WEIRD
    static char illegal[] = {'\177', '\0'};
#else
    static char illegal[] = {'"', '#', '$', '%', '&', '\'','(', ')','*',
                          ',', ':', ';', '<', '=', '>', '?', '[', ']',
                          '\\', '^', '|', '\177', '\0'};
#endif
    static char error[100];
    char ill_file[MAXPATH+1], *ill_char, *ptr, e2[10];

    ptr = file;
    while (*ptr == ' ') ptr++;	/* leading spaces GONE! */

    if(*ptr == '*')
      ptr++; /* Allow * at beginning for news groups */

    while(*ptr && *ptr > ' ' && strindex(illegal, *ptr) == 0)
      ptr++;

    if(*ptr != '\0') {
        if(*ptr == ' ') {
            ill_char = "<space>";
        } else if(*ptr == '\n') {
            ill_char = "<newline>";
        } else if(*ptr == '\r') {
            ill_char = "<carriage return>";
        } else if(*ptr == '\t') {
    	    ill_char = "<tab>";
        } else if(*ptr < ' ') {
            sprintf(e2, "control-%c", *ptr + '@');
            ill_char = e2;
        } else if (*ptr == '\177') {
    	    ill_char = "<del>";
        } else {
    	    e2[0] = *ptr;
    	    e2[1] = '\0';
    	    ill_char = e2;
        }
        if(ptr != file) {
            strncpy(ill_file, file, ptr - file);
            ill_file[ptr - file] = '\0';
            sprintf(error,"Character \"%s\" after \"%s\" not allowed",ill_char,
                    ill_file);
        } else {
            sprintf(error,
                    "First character, \"%s\", not allowed",
                    ill_char);
        }
            
        return(error);
    }
    return(NULL);
}
        


FILE *fdopen();

/*----------------------------------------------------------------------
       find how much free disk space is on a named paritition

    Args: The name of the device or name of file on which device of concern is
 
  Result: returns number of K bytes of free space

   Return the free space on the named disk in 1K blocks
  by running df(1). This is of course sensitive to the output of df
  which changes from one UNIX to another. We try to avoid this by
  looking for the first line beginning with a '/' which is the
  first line that's not header. (The main variation is header length)
  -----*/

disk_space(device_name)
     char *device_name;
{
    int            pipe_ends[2], pid, child;
    int            n;
#ifdef	DPX
    int            stx;
#else
    union wait     stx;
#endif
    FILE          *df_s;
    register char *p;
    register char *q;
    char           buf[1000];

    /*---- The number of lines to skip in the header -----*/
#ifdef	ULT
    n = 2;
#else
    n = 1;
#endif


    if(pipe(pipe_ends)< 0) {
        perror("pipe");
        return(-1);
    }

    if((child = fork()) == 0) {
	close(1);
	dup2(pipe_ends[1], 1);
	if(execl("/bin/df","df", device_name, NULL) < 0)
	  perror("exec df");
    }

    close(pipe_ends[1]);
    df_s = fdopen(pipe_ends[0], "r");
    while(n >= 0) {
	if(fgets(buf, sizeof(buf), df_s) == NULL)
	  return(-2);
	n--;
    }
    
    dprint(8, (debugfile, "DF output, --%s--\n", buf));
    /* Skip the filesystem */
    p = buf;
    for(;*p != ' '; p++);
    for(;*p == ' '; p++);
    /* Skip over the Kbytes field */
    for(;*p != ' '; p++);
    for(;*p == ' '; p++);
    /* Skip over used field */
#ifndef AIX370
    for(;*p != ' '; p++);
    for(;*p == ' '; p++);
#endif

    for(q = p;*q != ' ';q++);
    *q = '\0';


    pid = 0;
    while(pid != child)
        pid = wait(&stx);

    fclose(df_s);
    dprint(8, (debugfile, "Disk ready for atoi  --%s--\n", p));
    return(atoi(p));
}


    
#if defined(USE_QUOTAS)

#if defined(DYN) || defined(SUN)
#include <ufs/quota.h>
#else
#include <sys/stat.h>    
#include <sys/param.h>
#include <sys/quota.h>
#endif

/*----------------------------------------------------------------------
   Return space left in disk quota on file system given files is in

    Args: path - Path name of file or directory on file system of concern
                   (any file will do)
          over - pointer to flag that is set if the user is over quota


 Returns: The number of bytes free in disk quota as per the soft limit.
          -1 is returned on an error looking up quota
           0 is returned if there is no quota

BUG:  If there's more than 2.1Gb free this function will break
  ----*/
long
disk_quota(path, over)
     char *path;
     int  *over;
{
    struct stat statx;
    struct dqblk quotax;
    long         q;
#if defined(DYN) || defined(SUN)
    char        *dname;
#endif

    dprint(5, (debugfile, "quota_check path: %s\n", path));
    if(stat(path, &statx) < 0) {
        return(-1);
    }

    *over = 0;
    errno = 0;
#ifdef	NXT
    return(0); /* No quotas on the next, at least no documented quotas */
#else
#if !defined(DYN) && !defined(SUN)

    dprint(7, (debugfile, "Quota check: UID:%d  stat: %d %x\n", 
           getuid(), statx.st_dev, statx.st_dev));
    if(quota(Q_GETDLIM, getuid(), statx.st_dev, &quotax) < 0) {
        dprint(5, (debugfile, "Quota failed : %s\n",
                   error_description(errno)));
        if(errno == ESRCH)
          return(0); /* No limit */
        else
          return(-1); /* Some thing went wrong */
    }

    dprint(5,(debugfile,"Quota: bsoftlimit:%d  bhardlimit:%d  curblock:%d\n",
          quotax.dqb_bsoftlimit, quotax.dqb_bhardlimit, quotax.dqb_curblocks));

    /* Some confusion on the type of bsoftlimit. The include file says
       unsigned, but -1 seems to indicate no quota */
    if(quotax.dqb_bsoftlimit == 0 || (long)quotax.dqb_bsoftlimit == -1) 
      return(0);

    q = (quotax.dqb_bsoftlimit - quotax.dqb_curblocks) * 1024;
#else 
    dname = device_name(statx.st_dev);
    if(dname == NULL)
      return(-1);

    dprint(7, (debugfile, "Quota check: UID:%d  device: %s\n", 
           getuid(), dname));
    if(quotactl(Q_GETQUOTA, dname, getuid(), &quotax) < 0) {
        dprint(5, (debugfile, "Dynix3 Quota failed : %s\n",
                   error_description(errno)));
        return(-1); /* Some thing went wrong */
    }

    dprint(5,(debugfile,"Quota: bsoftlimit:%d  bhardlimit:%d  curblock:%d\n",
          quotax.dqb_bsoftlimit, quotax.dqb_bhardlimit, quotax.dqb_curblocks));

    if(quotax.dqb_bsoftlimit == -1)
      return(-1);

    q = (quotax.dqb_bsoftlimit - quotax.dqb_curblocks) * 512;    
#endif
    if(q < 0) {
        q = -q;
        *over = 1;
    }
    dprint(5, (debugfile, "disk_quota returning :%d,  over:%d\n", q, *over));
    return(q);
#endif	/* NXT */
}



#if   defined(DYN) || defined(SUN)

/*----------------------------------------------------------------------
 *		devNumToName
 *
 *	This routine is here so that ex can get a device name to check
 *	disk quotas.  One might wonder, why not use getmntent(), rather
 *	than read /etc/mtab in this crude way?  The problem with getmntent
 *	is that it uses stdio, and ex/vi pointedly doesn't.
 ----*/

static  char
*device_name(st_devArg)
     dev_t st_devArg;
{
#define	MTABNAME "/etc/mtab"
    char *mtab;
    int tableUnit = -1;
    static char devName[48];
    static char *answer = (char *) 0;
    struct stat devStat;
    static dev_t st_dev;
    int nb, cur, bol;
    char c;
    int dname;

    if (st_devArg == st_dev)
      return answer;

    mtab = read_file(MTABNAME);
    if(mtab == NULL)
      return(NULL);

    /* Initialize save data. */
    st_dev = st_devArg;
    answer = (char *) 0;
    nb = strlen(mtab);

    for (cur=bol=0, dname=1; cur < nb; ++cur) {

	if (dname && (mtab[cur] <= ' ')) {
	/*	Space, tab or other such character has been found,
		presumably marking the end of the device name string. */
	
	    dname = 0;
	    c = mtab[cur];	/* Save current character. */
	    mtab[cur] = 0;	/* C zero-terminated string. */

	    /*	Get device number, via stat().  If it's the right
		number, copy the string and return its address. */
	    if (stat (&mtab[bol], &devStat) == 0) {
		if (devStat.st_rdev == st_dev) {
		    if ((cur - bol + 1) < sizeof (devName)) {
			strcpy (devName, &mtab[bol]);
                        answer = &devName[0];
			return(answer);
		    }
		}
	    }
	    mtab[cur] = c;
	}
	if (mtab[cur] == '\n') {
	    dname = 1;
	    bol = cur + 1;
	}
    }
    answer = NULL;

    return(answer);
}

#endif /*DYN */
#endif /* USE_QUOTAS */




/*----------------------------------------------------------------------
      Very simple, minimal and machine independent directory access
  
  This just allows opening of one directory at a time and getting the 
files in that directory.
 ----*/

#ifdef	DPX
#include <dirent.h>
#else
#include <sys/dir.h>
#endif


static DIR *directory;

/*----------------------------------------------------------------------
     Open a directory for subsequent reading of filenames within  

    Args: dir -- The name of the directory to open

  Result: 0 is successful, -1 if not
  ---*/
simple_opendir(dir)
     char *dir;
{
    directory = opendir(dir);
    if(directory == NULL)
      return(-1);
    return(0);
}

/*----------------------------------------------------------------------
    Returns the next file name in the directory opened by simple_opendir

     Args:  

  Returns: string with name of file or NULL
 ----*/
char *
simple_readdir()
{
#if defined(DPX) || defined(AIX) 
    register struct dirent    *dp;
#else
    register struct direct    *dp;
#endif

    if(directory == NULL)
      return(NULL);
    dp = readdir(directory);
    if(dp == NULL)
      return(NULL);
    return(dp->d_name);
}

/*----------------------------------------------------------------------
   Close the currently open directory  
 ----*/
void
simple_closedir()
{
    closedir(directory);
}





/*----------------------------------------------------------------------
    Read whole file into memory

  Args: filename -- path name of file to read

  Result: Returns pointer to malloced memory with the contents of the file
          or NULL

This won't work very well if the file has NULLs in it and is mostly
intended for fairly small text files.
  ----------------------------------------------------------------------*/
char *
read_file(filename)
     char *filename;
{
    int         fd;
    struct stat statbuf;
    char       *buf;

    fd = open(filename, O_RDONLY);
    if(fd < 0)
      return(NULL);

    fstat(fd, &statbuf);

    buf = fs_get(statbuf.st_size + 1);

    if(read(fd, buf, statbuf.st_size) != statbuf.st_size) {
        close(fd);
        return(NULL);
    }
    close(fd);

    buf[statbuf.st_size]= '\0';

    return(buf);
}








/*----------------------------------------------------------------------
     Abort with a core dump

  Some systems can't abort() from a signal handler if the signal handler installed catchs the signal abort() uses to actually to the abort. That is even resetting the signal default doesn't occur until the program leaves the handler routine. This winds up causing infinite loops. To avoid this we just never catch SIGFPE which is assumed to be very rare in Pine and just kill ourselves with it when we want to abort with a core dump.
 ----*/
void
coredump()
{
#if  defined(ULT) || defined(DYN) || defined(SUN)
    kill(0, SIGFPE);
    exit(0); /* Just in case */
#else
    abort();
#endif
}
    







#ifdef	NO_SYSTEM_KNOWN_YET
/*----------------------------------------------------------------------
       Supplimentary gethostname if the system doesn't have one

  Args: hostname -- buffer to return host name in 
        size     -- Size of buffer hostname is to be returned in
 Result:
  ----------------------------------------------------------------------*/
static 
gethostname(hostname,size) 
     char *hostname;
     int size;
{
	/** Return the name of the current host machine. **/

#ifdef	SYSTEMID
	char    buf[32];
	FILE    *fp;
	char    *p;

	if ((fp = fopen("/etc/systemid", "r")) != 0) {
	  fgets(buf, sizeof(buf) - 1, fp);
	  fclose(fp);
	  if ((p = strindex(buf, '\n')) != NULL)
	    *p = '\0';
	  (void) strncpy(hostname, buf, size - 1);
	  hostname[size - 1] = '\0';
	  return 0;
	}

#else   /* SYSTEMID */

#ifdef	DOUNAME
	/** This routine compliments of Scott McGregor at the HP
	    Corporate Computing Center **/
     
	int uname();
	struct utsname name;

	(void) uname(&name);
	(void) strncpy(hostname,name.nodename,size-1);
#else
	(void) strncpy(hostname, HOSTNAME, size-1);
#endif	/* DOUNAME */

	hostname[size - 1] = '\0';
	return 0;

#endif  /* XENIX */
}
#endif



#include <netdb.h>

/*----------------------------------------------------------------------
       Get the current host and domain names

    Args: hostname   -- buffer to return the hostname in
          hsize      -- size of buffer above
          domainname -- buffer to return domain name in
          dsize      -- size of buffer above

  Result: The system host and domain names are returned. If the full host
          name is akbar.cac.washington.edu then the hostname is
          cac.washington.edu.

On Internet connected hosts this look up uses /etc/hosts and DNS to
figure all this out. On other less well connected machines some other
file may be read. If there is no notion of a domain name the domain
name maybe left blank. On a PC where there really isn't a host name
this should return blank strings. The .pinerc will take care of
configuring the domain names. That is this should only return the
native systems idea of what the names are if the system has such

The unused routine above might provide some clues for Xenix and such.
 ----*/
void
getdomainnames(hostname, hsize, domainname, dsize)
     char *hostname, *domainname;
     int   hsize, dsize;
{
    char           *dn, hname[MAX_ADDRESS+1];
    struct hostent *he;

    gethostname(hname, MAX_ADDRESS);

    he = gethostbyname(hname);

    if(he == NULL && strlen(hname) == 0) {
        strcpy(hostname, "");
    } else if(he == NULL) {
        strncpy(hostname, hname, hsize - 1);
    } else {
        strncpy(hostname, he->h_name, hsize-1);
    }
    hostname[hsize-1] = '\0';


    if((dn = strindex(hostname, '.')) != NULL) {
        strncpy(domainname, dn+1, dsize-1);
    } else {
        strncpy(domainname, hostname, dsize-1);
    }
    domainname[dsize-1] = '\0';

}









/*----------------------------------------------------------------------
     This routine returns 1 if jobs control SIGTSTP / ^Z is available
  ----*/
have_job_control()
{
    return(1);
}
  


/*----------------------------------------------------------------------
    If we don't have job control, this routine is never called.
  ----*/
stop_process()
{
    kill(0, SIGSTOP); 
}








/*----------------------------------------------------------------------
   This is here in case errno on your system is so brain damaged that it's 
 unusuable. Hopefully it'll get very little use.


    This routine maps error numbers to error names and error messages.
    These are all directly ripped out of the include file errno.h, and
    are HOPEFULLY standardized across the different breeds of Unix!!

    If (alas) yours are different, you should be able to use awk to
    mangle your errno.h file quite simply...

**/

extern char *sys_errlist[];

#ifdef	NO_KNOWN_SYSTEM_WITHOUT_ERRNO_YET

char *err_name[] = { 
/* 0 */	        "NOERROR", "No error status currently",
/* 1 */		"EPERM",   "Not super-user",
/* 2 */		"ENOENT",  "No such file or directory",
/* 3 */		"ESRCH",   "No such process",
/* 4 */		"EINTR",   "Interrupted system call",
/* 5 */		"EIO",     "I/O error",
/* 6 */		"ENXIO",   "No such device or address",
/* 7 */		"E2BIG",   "Arg list too long",
/* 8 */		"ENOEXEC", "Exec format error",
/* 9 */		"EBADF",   "Bad file number",
/* 10 */	"ECHILD",  "No children",
/* 11 */	"EAGAIN",  "No more processes",
/* 12 */	"ENOMEM",  "Not enough core",
/* 13 */	"EACCES",  "Permission denied",
/* 14 */	"EFAULT",  "Bad address",
/* 15 */	"ENOTBLK", "Block device required",
/* 16 */	"EBUSY",   "Mount device busy",
/* 17 */	"EEXIST",  "File exists",
/* 18 */	"EXDEV",   "Cross-device link",
/* 19 */	"ENODEV",  "No such device",
/* 20 */	"ENOTDIR", "Not a directory",
/* 21 */	"EISDIR",  "Is a directory",
/* 22 */	"EINVAL",  "Invalid argument",
/* 23 */	"ENFILE",  "File table overflow",
/* 24 */	"EMFILE",  "Too many open files",
/* 25 */	"ENOTTY",  "Not a typewriter",
/* 26 */	"ETXTBSY", "Text file busy",
/* 27 */	"EFBIG",   "File too large",
/* 28 */	"ENOSPC",  "No space left on device",
/* 29 */	"ESPIPE",  "Illegal seek",
/* 30 */	"EROFS",   "Read only file system",
/* 31 */	"EMLINK",  "Too many links",
/* 32 */	"EPIPE",   "Broken pipe",
/* 33 */	"EDOM",    "Math arg out of domain of func",
/* 34 */	"ERANGE",  "Math result not representable",
/* 35 */	"ENOMSG",  "No message of desired type",
/* 36 */	"EIDRM",   "Identifier removed"
	};
#endif

char *strcpy();

/*----------------------------------------------------------------------
      Return short error name string for error number
 
   Args: errnumber -- The system error number (errno)

 Result: error name
  ----*/
char *error_name(errnumber)
int errnumber;
{
    static char buffer[50];
#ifdef	NO_KNOWN_SYSTEM_WITHOUT_ERRNO_YET
    if (errnumber < 0 || errnumber > 36) 
#endif
      sprintf(buffer,"ERR-UNKNOWN (%d)", errnumber);
#ifdef	NO_KNOWN_SYSTEM_WITHOUT_ERRNO_YET
    else
      strcpy(buffer, err_name[2*errnumber]);
#endif

    return( (char *) buffer);
}



/*----------------------------------------------------------------------
       return string describing the error

   Args: errnumber -- The system error number (errno)(

 Result:  sentence long string describing the error 
  ----*/

char *error_description(errnumber)
int errnumber;
{
    static char buffer[50];

#ifdef	NO_KNOWN_SYSTEM_WITHOUT_ERRNO_YET
    if (errnumber < 0 || errnumber > 36) 
      sprintf(buffer,"Unknown error - %d - No description", errnumber);
    else
      strcpy(buffer, err_name[2*errnumber + 1]);
#else
    strcpy(buffer, sys_errlist[errnumber]);
#endif

    return ( (char *) buffer);
}








/*----------------------------------------------------------------------
  This collection of routines looks up the login name and password on the
system. For things like PC's it's OK for these to return NULL system there
is no system login. Other code will figure out who the user actually is.
  ----*/
static struct passwd *unix_pwd = NULL;
static int            pwd_looked_up = 0;

#ifdef	ANSI
static char *gcos_name(char *, char *);
#else
static char *gcos_name();
#endif

char *
get_system_login()
{
    if(unix_pwd == NULL) {
        if(!pwd_looked_up) {
            unix_pwd = getpwuid(getuid());
            pwd_looked_up = 1;
        }
        if(unix_pwd == NULL)
          return(NULL);
    }
    return(unix_pwd->pw_name);
}

char *
get_system_fullname()
{
    if(unix_pwd == NULL) {
        if(!pwd_looked_up) {
            unix_pwd = getpwuid(getuid());
            pwd_looked_up = 1;
        }
        if(unix_pwd == NULL)
          return(NULL);
    }
    return(gcos_name(unix_pwd->pw_gecos, unix_pwd->pw_name));
}

char *
get_system_homedir()
{
    if(unix_pwd == NULL) {
        if(!pwd_looked_up){
            unix_pwd = getpwuid(getuid());
            pwd_looked_up = 1;
        }
        if(unix_pwd == NULL)
          return(NULL);
    }
    return(unix_pwd->pw_dir);
}

char *
get_system_passwd()
{
    if(unix_pwd == NULL) {
        if(!pwd_looked_up) {
            unix_pwd = getpwuid(getuid());
            pwd_looked_up = 1;
        }
        if(unix_pwd == NULL)
          return(NULL);
    }
    return(unix_pwd->pw_passwd);
}



/*----------------------------------------------------------------------
      Pull the name out of the gcos field if we have that sort of /etc/passwd

   Args: gcos_field --  The long name or GCOS field to be parsed
         logname    --  Replaces occurances of & with logname string

 Result: returns pointer to buffer with name
  ----*/
static char *
gcos_name(gcos_field, logname)
char *logname, *gcos_field;
{


#ifdef	NO_USG_SYSTEMS_KNOWN_YET

    char *firstcp, *lastcp;

    /* The last character of the full name is the one preceding the first
     * '('. If there is no '(', then the full name ends at the end of the
     * gcos field.
     */
    if(lastcp = strindex(gcos_field, '('))
	*lastcp = '\0';

    /* The first character of the full name is the one following the 
     * last '-' before that ending character. NOTE: that's why we
     * establish the ending character first!
     * If there is no '-' before the ending character, then the fullname
     * begins at the beginning of the gcos field.
     */
    if(firstcp = strrindex(gcos_field, '-'))
	firstcp++;
    else
	firstcp = gcos_field;

    return(firstcp);

#else	/* NO_USG_SYSTEMS_KNOWN_YET */

#ifdef	NO_PLAIN_SYSTEMS_KNOWN_YET
    /*---- Default case -- use full gcos field ----*/
    return(gcos_field);
#else	/* NO_PLAIN_SYSTEMS_KNOWN_YET */

    /*----- Berkeley style long names  (default) ------*/ 

    static char fullname[MAX_FULLNAME+1];
    register char *fncp, *gcoscp, *lncp, *end;


    /* full name is all chars up to first ',' (or whole gcos, if no ',') */
    /* replace any & with logname in upper case */

    for(fncp = fullname, gcoscp= gcos_field, end = fullname + MAX_FULLNAME - 1;
        (*gcoscp != ',' && *gcoscp != '\0' && fncp != end);
	gcoscp++) {

	if(*gcoscp == '&') {
	    for(lncp = logname; *lncp; fncp++, lncp++)
		*fncp = toupper(*lncp);
	} else {
	    *fncp++ = *gcoscp;
	}
    }
    
    *fncp = '\0';
    return(fullname);
#endif	/* NO_PLAIN_SYSTEMS_KNOWN_YET */
#endif	/* NO_USG_SYSTEMS_KNOWN_YET */
}

    

/*----------------------------------------------------------------------
      Look up a userid on the local system and return rfc822 address

 Args: name  -- possible login name on local system

 Result: returns NULL or pointer to static string rfc822 address.
  ----*/
char *
local_name_lookup(name)
     char *name;
{
    struct passwd *pw;
    static char    buf[100];

    pw = getpwnam(name);
    if(pw == NULL)
      return(NULL);

    strcpy(buf, gcos_name(pw->pw_gecos, name));

    return(buf);
}



/*----------------------------------------------------------------------
       Call the system to change the passwd
 
It would be nice to talk to the passwd program via a pipe or ptty so the
user interface could be consistent, but we can't count on the the prompts
and responses from the passwd program to be regular so we just let the user 
type at the passwd program with some screen space, hope he doesn't scroll 
off the top and repaint when he's done.
 ----*/        
change_passwd()
{
    char cmd_buf[100];

    int i;
    for(i = 1; i < ps_global->ttyo->screen_rows; i ++) {
        MoveCursor(i, 0);
        CleartoEOLN();
    }

    MoveCursor(5, 0);
    fflush(stdout);

    Raw(0);
#ifdef	NXT     
    sprintf(cmd_buf, "passwd %s" , ps_global->VAR_USER_ID);
#else
    strcpy(cmd_buf, "passwd");
#endif
    system(cmd_buf);
    sleep(3);
    Raw(1);
    init_username(ps_global);
}


    
SHAR_EOF
if test 35497 -ne "`wc -c < './pine/os-s53.c'`"
then
	echo shar: "error transmitting './pine/os-s53.c'" '(should have been 35497 characters)'
fi
chmod 644 './pine/os-s53.c'
fi
if test -f './pine/os-s53.h'
then
	echo shar: "will not over-write existing file './pine/os-s53.h'"
else
cat << \SHAR_EOF > './pine/os-s53.h'
/*----------------------------------------------------------------------

            T H E    P I N E    M A I L   S Y S T E M

   Laurence Lundblade and Mike Seibel
   Networks and Distributed Computing
   Computing and Communications
   University of Washington
   Administration Building, AG-44
   Seattle, Washington, 98195, USA
   Internet: lgl@CAC.Washington.EDU
             mikes@CAC.Washington.EDU

   Please address all bugs and comments to "pine-bugs@cac.washington.edu"

   Date:
   Last Edited:
      
   Copyright 1989, 1990, 1991  University of Washington

    Permission to use, copy, modify, and distribute this software and its
   documentation for any purpose and without fee is hereby granted, provided
   that the above copyright notice appears in all copies and that both the
   above copyright notice and this permission notice appear in supporting
   documentation, and that the name of the University of Washington not be
   used in advertising or publicity pertaining to distribution of the software
   without specific, written prior permission.  This software is made
   available "as is", and
   THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
   WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
   NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
   INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
   LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
   (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
   WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  

   Pine is in part based on The Elm Mail System:
    ***********************************************************************
    *  The Elm Mail System  -  $Revision: 2.13 $   $State: Exp $          *
    *                                                                     *
    * 			Copyright (c) 1986, 1987 Dave Taylor              *
    * 			Copyright (c) 1988, 1989 USENET Community Trust   *
    ***********************************************************************
 

  ----------------------------------------------------------------------*/


/*----------------- Are we ANSI? ------------------*/
#if defined(NXT) || defined(AIX)
#define ANSI
#endif



/*------- Include standard/strings library -------*/
#ifdef DYN

#include <strings.h>

#else

#include <string.h>

#ifndef     BSD
#ifdef      MEMLOG
#undef      malloc
#endif

#if            defined(ANSI) || defined(ULT)
#include       <stdlib.h>
#endif

#endif

#endif



/*----------------- time.h -----------------------*/
#include <time.h>



/*--------------- signals.h ----------------------*/
#ifdef NXT
#include <sys/signal.h>
#else
#include <signal.h>
#endif

#if defined(DYN)
#define SigType int
#else
#define SigType void
#endif



/*-------------- qsort arguments type ------------*/
#ifdef NXT
#define QSType void
#else
#define QSType int
#endif



/*----------------- errno and syserlist ----------*/
#ifdef BSD
extern int errno;
extern char *syserr_list[];
#endif


#define	DPX


/*--------- plain time.h isn't enough on some systems ------*/
#if defined(NXT) || defined(SUN)
#include <sys/time.h> /* For struct timeval usually in time.h */
#endif



#define RESIZING



/*----------------------------------------------------------------------
    Turn on if you want the disk item on the "other" menu to check and
 report disk quotas. This will only work if the system actually supports
 quotas and the config.h file mentions it.
 ----*/
#undef USE_QUOTAS


#define ANSI_PRINTER "attached-to-ansi"


/*----------------------------------------------------------------------
 *  The default printer when pine starts up for the first time with no printer
 */
#define DF_DEFAULT_PRINTER ANSI_PRINTER



/*----------------------------------------------------------------------
 *  Standard printer 
 */
#define DF_STANDARD_PRINTER "lpr"



/*----------------------------------------------------------------------
 *   If turned on the News features will show on the main menu, so the
 * user may read news about the latest versions of Pine or other notes
 */
#define SHOW_NEWS 


/*----------------------------------------------------------------------
 *
 */
#define WHO_FILE1 "/usr/lib/pine.info"
#define WHO_FILE2 "/usr/local/lib/pine.info"
#define SYSTEM_PINERC "/usr/local/lib/pine.conf"



/*----------------------------------------------------------------------
  Where to put the output of the pine in debug mode. Files are created
 in users home directory and have a number appended to them when there 
 are more than one.
 ----*/
#define DEBUGFILE	".pine-debug"



/*----------------------------------------------------------------------
   The number of .debug files to save in the users home diretory. The files
 are useful for figuring out what a user did when he complains that something
 went wrong. It's important to keep a bunch around, usually 4, so that the
 debug file in questions will still be around when the problem gets 
 invesitagated. Users tend to go in and out of Pine a few times and there
 is one file for each pine invocation
 ----*/
#define NUMDEBUGFILES 4


/*----------------------------------------------------------------------
   The default debug level to set:
       1 logs only highest level events and errors
       2 logs events like file writes
       3
       4 logs each command
       5
       6 
       7 logs details of command execution (7 is highest to run any production)
       8
       9 logs gross details of command execution
  ----*/
#define DEFAULT_DEBUG 2



/*----------------------------------------------------------------------
    The usual sendmail configuration for sending mail
 ----*/
#define SENDMAIL	"/usr/lib/sendmail"
#define SENDMAILFLAGS	"-oi -oem -t"	/* ignore dots and mail back errors
					   and read message for recpeients.*/


/*----------------------------------------------------------------------
    Various maximum string sizes 
 ------*/
#define MAXPATH        (512)    /* Longest pathname we ever expect */
#define MAXFOLDER      (64)     /* Longest foldername we ever expect */  

/* Note to reduce stack consumption, one can reduce the size of MAXPATH,
  the current system permitting. Currently the larges functions use
  about 2 * MAXPATH + 200 bytes. Reducing MAX_SCREEN_COLS is a can
  help reduce stack consumption too. Ofcourse this is only of concern for
  things like PC's.
*/
/*
  Maximum lengths of the fields. In practice the address field is limited
  by the screen width when used on an 80 column screen. These are usually
  entered with the optionally_enter() function which must fit the prompt
  and the field in the number of columns on the screen. If the length
  given it is wider than the screen is just stops at the screen width
 */
#define MAX_FULLNAME  (50) 
#define MAX_NICKNAME  (20)
#define MAX_ADDRESS   (100)
#define MAX_NEW_LIST  (100)  /* Max addresses to be added when creating list */
#define MAX_SEARCH    (100)  /* Long possible string to search for */
#define MAX_ADDR_EXPN (1000)  /* Longest single expanded address to expect */
#define MAX_ADDR_FIELD (10000) /* Longest address fully expanded field */



/*==========  Time outs, check pointing  ==========*/
#define NEW_MAIL_TIME  (30) /* How often to check for new mail. There's 
                               some expense in doing this so it shouldn't
                               be done too frequently 
                             */
#define CHECK_POINT_TIME (5*60)  /* Minimum time to wait before forcing
                                      a check point if there has been at 
                                      least one change, but not
                                      CHECK_POINT_FREQ changes.
                                    */
                                     
#define CHECK_POINT_FREQ (10) /* Do a check point if there have been this
                                 many (status) changes to the current mail
                                 file.
                               */



/*----------------------------------------------------------------------
   The largest screen pine will display on. Used to define some array sizes
 so increases here will make Pine larger and use more stack space.
 ---*/
#define MAX_SCREEN_COLS  (170) 
#define MAX_SCREEN_ROWS  (200) 


/*----------------------------------------------------------------------
   When no screen size can be discovered this is the size used
 ----*/
#define DEFAULT_LINES_ON_TERMINAL	(24)
#define DEFAULT_COLUMNS_ON_TERMINAL	(80)


/*----------------------------------------------------------------------
 In scrolling through text, the number of lines from the previous
 screen to overlap when showing the next screen
 ----*/
#define	OVERLAP		(2) 



/*----------------------------------------------------------------------
   The default folder names and folder directories
 ----*/
#define DF_DEFAULT_FCC   "sent-mail"
#define DEFAULT_SAVE     "saved-messages"
#define POSTPONED_MAIL   "postponed-mail"
#define INTERRUPTED_MAIL "interrupted-mail"
#define DEFAULT_MAIL_DIR "mail"
#define INBOX_NAME       "inbox"
#define SIGNATURE_FILE   ".signature"


SHAR_EOF
if test 9317 -ne "`wc -c < './pine/os-s53.h'`"
then
	echo shar: "error transmitting './pine/os-s53.h'" '(should have been 9317 characters)'
fi
chmod 644 './pine/os-s53.h'
fi
if test -f './regexp/Makefile'
then
	echo shar: "will not over-write existing file './regexp/Makefile'"
else
cat << \SHAR_EOF > './regexp/Makefile'
LIB=		libregexp.a
CC=		cc
CFLAGS=		-g -O

all:		$(LIB)

$(LIB):					\
		$(LIB)(regerror.o)	\
		$(LIB)(regexp.o)	\
		$(LIB)(regsub.o)

clean:
		rm -f $(LIB) *.o
SHAR_EOF
if test 160 -ne "`wc -c < './regexp/Makefile'`"
then
	echo shar: "error transmitting './regexp/Makefile'" '(should have been 160 characters)'
fi
chmod 644 './regexp/Makefile'
fi
exit 0
#	End of shell archive
